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> 1120Sigor@sysoev.ru 1220Sigor@sysoev.ru 13115Sigor@sysoev.ru typedef struct { 14318Smax.romanov@nginx.com nxt_str_t type; 15507Smax.romanov@nginx.com uint32_t processes; 16507Smax.romanov@nginx.com uint32_t max_processes; 17507Smax.romanov@nginx.com uint32_t spare_processes; 18318Smax.romanov@nginx.com nxt_msec_t timeout; 19427Smax.romanov@nginx.com nxt_msec_t res_timeout; 20507Smax.romanov@nginx.com nxt_msec_t idle_timeout; 21318Smax.romanov@nginx.com uint32_t requests; 22318Smax.romanov@nginx.com nxt_conf_value_t *limits_value; 23507Smax.romanov@nginx.com nxt_conf_value_t *processes_value; 24133Sigor@sysoev.ru } nxt_router_app_conf_t; 25133Sigor@sysoev.ru 26133Sigor@sysoev.ru 27133Sigor@sysoev.ru typedef struct { 28133Sigor@sysoev.ru nxt_str_t application; 29115Sigor@sysoev.ru } nxt_router_listener_conf_t; 30115Sigor@sysoev.ru 31115Sigor@sysoev.ru 32423Smax.romanov@nginx.com typedef struct nxt_msg_info_s { 33423Smax.romanov@nginx.com nxt_buf_t *buf; 34423Smax.romanov@nginx.com nxt_port_mmap_tracking_t tracking; 35423Smax.romanov@nginx.com nxt_work_handler_t completion_handler; 36423Smax.romanov@nginx.com } nxt_msg_info_t; 37423Smax.romanov@nginx.com 38423Smax.romanov@nginx.com 39167Smax.romanov@nginx.com typedef struct nxt_req_app_link_s nxt_req_app_link_t; 40141Smax.romanov@nginx.com 41141Smax.romanov@nginx.com 42318Smax.romanov@nginx.com typedef struct { 43431Sigor@sysoev.ru uint32_t stream; 44431Sigor@sysoev.ru nxt_app_t *app; 45431Sigor@sysoev.ru nxt_port_t *app_port; 46431Sigor@sysoev.ru nxt_app_parse_ctx_t *ap; 47431Sigor@sysoev.ru nxt_msg_info_t msg_info; 48431Sigor@sysoev.ru nxt_req_app_link_t *ra; 49431Sigor@sysoev.ru 50431Sigor@sysoev.ru nxt_queue_link_t link; /* for nxt_conn_t.requests */ 51318Smax.romanov@nginx.com } nxt_req_conn_link_t; 52318Smax.romanov@nginx.com 53318Smax.romanov@nginx.com 54167Smax.romanov@nginx.com struct nxt_req_app_link_s { 55318Smax.romanov@nginx.com uint32_t stream; 56425Smax.romanov@nginx.com nxt_atomic_t use_count; 57167Smax.romanov@nginx.com nxt_port_t *app_port; 58167Smax.romanov@nginx.com nxt_port_t *reply_port; 59167Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 60423Smax.romanov@nginx.com nxt_msg_info_t msg_info; 61167Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 62167Smax.romanov@nginx.com 63427Smax.romanov@nginx.com nxt_nsec_t res_time; 64427Smax.romanov@nginx.com 65425Smax.romanov@nginx.com nxt_queue_link_t link_app_requests; /* for nxt_app_t.requests */ 66425Smax.romanov@nginx.com nxt_queue_link_t link_port_pending; /* for nxt_port_t.pending_requests */ 67427Smax.romanov@nginx.com nxt_queue_link_t link_app_pending; /* for nxt_app_t.pending */ 68167Smax.romanov@nginx.com 69167Smax.romanov@nginx.com nxt_mp_t *mem_pool; 70167Smax.romanov@nginx.com nxt_work_t work; 71345Smax.romanov@nginx.com 72345Smax.romanov@nginx.com int err_code; 73345Smax.romanov@nginx.com const char *err_str; 74167Smax.romanov@nginx.com }; 75167Smax.romanov@nginx.com 76167Smax.romanov@nginx.com 77198Sigor@sysoev.ru typedef struct { 78198Sigor@sysoev.ru nxt_socket_conf_t *socket_conf; 79198Sigor@sysoev.ru nxt_router_temp_conf_t *temp_conf; 80198Sigor@sysoev.ru } nxt_socket_rpc_t; 81198Sigor@sysoev.ru 82198Sigor@sysoev.ru 83507Smax.romanov@nginx.com typedef struct { 84507Smax.romanov@nginx.com nxt_app_t *app; 85507Smax.romanov@nginx.com nxt_router_temp_conf_t *temp_conf; 86507Smax.romanov@nginx.com } nxt_app_rpc_t; 87507Smax.romanov@nginx.com 88507Smax.romanov@nginx.com 89427Smax.romanov@nginx.com struct nxt_port_select_state_s { 90427Smax.romanov@nginx.com nxt_app_t *app; 91427Smax.romanov@nginx.com nxt_req_app_link_t *ra; 92427Smax.romanov@nginx.com 93427Smax.romanov@nginx.com nxt_port_t *failed_port; 94427Smax.romanov@nginx.com int failed_port_use_delta; 95427Smax.romanov@nginx.com 96507Smax.romanov@nginx.com uint8_t start_process; /* 1 bit */ 97427Smax.romanov@nginx.com nxt_req_app_link_t *shared_ra; 98427Smax.romanov@nginx.com nxt_port_t *port; 99427Smax.romanov@nginx.com }; 100427Smax.romanov@nginx.com 101427Smax.romanov@nginx.com typedef struct nxt_port_select_state_s nxt_port_select_state_t; 102427Smax.romanov@nginx.com 103427Smax.romanov@nginx.com static void nxt_router_port_select(nxt_task_t *task, 104427Smax.romanov@nginx.com nxt_port_select_state_t *state); 105427Smax.romanov@nginx.com 106427Smax.romanov@nginx.com static nxt_int_t nxt_router_port_post_select(nxt_task_t *task, 107427Smax.romanov@nginx.com nxt_port_select_state_t *state); 108427Smax.romanov@nginx.com 109507Smax.romanov@nginx.com static nxt_int_t nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app); 110343Smax.romanov@nginx.com 111425Smax.romanov@nginx.com nxt_inline void 112425Smax.romanov@nginx.com nxt_router_ra_inc_use(nxt_req_app_link_t *ra) 113425Smax.romanov@nginx.com { 114425Smax.romanov@nginx.com nxt_atomic_fetch_add(&ra->use_count, 1); 115425Smax.romanov@nginx.com } 116425Smax.romanov@nginx.com 117425Smax.romanov@nginx.com nxt_inline void 118425Smax.romanov@nginx.com nxt_router_ra_dec_use(nxt_req_app_link_t *ra) 119425Smax.romanov@nginx.com { 120538Svbart@nginx.com #if (NXT_DEBUG) 121425Smax.romanov@nginx.com int c; 122425Smax.romanov@nginx.com 123425Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&ra->use_count, -1); 124425Smax.romanov@nginx.com 125425Smax.romanov@nginx.com nxt_assert(c > 1); 126538Svbart@nginx.com #else 127538Svbart@nginx.com (void) nxt_atomic_fetch_add(&ra->use_count, -1); 128538Svbart@nginx.com #endif 129425Smax.romanov@nginx.com } 130425Smax.romanov@nginx.com 131425Smax.romanov@nginx.com static void nxt_router_ra_use(nxt_task_t *task, nxt_req_app_link_t *ra, int i); 132425Smax.romanov@nginx.com 133139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task); 134198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data); 135198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task, 136139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 137139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task, 138139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 139139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task, 140193Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type); 14153Sigor@sysoev.ru 142115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task, 143115Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end); 144133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name); 145133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, 146133Sigor@sysoev.ru nxt_str_t *name); 147198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task, 148198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf); 149198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task, 150198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 151198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task, 152198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 153507Smax.romanov@nginx.com static void nxt_router_app_rpc_create(nxt_task_t *task, 154507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_app_t *app); 155507Smax.romanov@nginx.com static void nxt_router_app_prefork_ready(nxt_task_t *task, 156507Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 157507Smax.romanov@nginx.com static void nxt_router_app_prefork_error(nxt_task_t *task, 158507Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 159359Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, 160359Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_str_t *name); 161359Sigor@sysoev.ru static nxt_int_t nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, 162359Sigor@sysoev.ru nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa); 16353Sigor@sysoev.ru 16453Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task, 16553Sigor@sysoev.ru nxt_router_t *router, nxt_router_temp_conf_t *tmcf, 16653Sigor@sysoev.ru const nxt_event_interface_t *interface); 167115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 168115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 169115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 170115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 171115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 172115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 173154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 174154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 175154Sigor@sysoev.ru nxt_work_handler_t handler); 176313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 177313Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 178139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 179139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets); 18053Sigor@sysoev.ru 18153Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 18253Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 18353Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 18453Sigor@sysoev.ru nxt_event_engine_t *engine); 185343Smax.romanov@nginx.com static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 186133Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 18753Sigor@sysoev.ru 188315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router, 189315Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 190315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine, 191315Sigor@sysoev.ru nxt_work_t *jobs); 19253Sigor@sysoev.ru 19353Sigor@sysoev.ru static void nxt_router_thread_start(void *data); 19453Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj, 19553Sigor@sysoev.ru void *data); 19653Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj, 19753Sigor@sysoev.ru void *data); 19853Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, 19953Sigor@sysoev.ru void *data); 200313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, 201313Sigor@sysoev.ru void *data); 20253Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj, 20353Sigor@sysoev.ru void *data); 20453Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, 20553Sigor@sysoev.ru void *data); 206359Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task, 207359Sigor@sysoev.ru nxt_socket_conf_t *skcf); 20853Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task, 20953Sigor@sysoev.ru nxt_socket_conf_joint_t *joint); 21053Sigor@sysoev.ru 211343Smax.romanov@nginx.com static void nxt_router_app_port_ready(nxt_task_t *task, 212343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 213343Smax.romanov@nginx.com static void nxt_router_app_port_error(nxt_task_t *task, 214343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 215343Smax.romanov@nginx.com 216507Smax.romanov@nginx.com static void nxt_router_app_quit(nxt_task_t *task, nxt_app_t *app); 217343Smax.romanov@nginx.com static void nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port, 218343Smax.romanov@nginx.com uint32_t request_failed, uint32_t got_response); 219427Smax.romanov@nginx.com static nxt_int_t nxt_router_app_port(nxt_task_t *task, nxt_app_t *app, 220427Smax.romanov@nginx.com nxt_req_app_link_t *ra); 221141Smax.romanov@nginx.com 222425Smax.romanov@nginx.com static void nxt_router_app_prepare_request(nxt_task_t *task, 223343Smax.romanov@nginx.com nxt_req_app_link_t *ra); 224216Sigor@sysoev.ru static nxt_int_t nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 225216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg); 226216Sigor@sysoev.ru static nxt_int_t nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 227216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg); 228216Sigor@sysoev.ru static nxt_int_t nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 229216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg); 230510Salexander.borisov@nginx.com static nxt_int_t nxt_perl_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 231510Salexander.borisov@nginx.com nxt_app_wmsg_t *wmsg); 232584Salexander.borisov@nginx.com static nxt_int_t nxt_ruby_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 233584Salexander.borisov@nginx.com nxt_app_wmsg_t *wmsg); 234510Salexander.borisov@nginx.com 23553Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data); 236318Smax.romanov@nginx.com static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data); 237507Smax.romanov@nginx.com static void nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, 238507Smax.romanov@nginx.com void *data); 239507Smax.romanov@nginx.com static void nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, 240507Smax.romanov@nginx.com void *data); 241507Smax.romanov@nginx.com static void nxt_router_app_release_handler(nxt_task_t *task, void *obj, 242507Smax.romanov@nginx.com void *data); 243431Sigor@sysoev.ru 244431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_send_state; 245431Sigor@sysoev.ru static void nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data); 246141Smax.romanov@nginx.com 247119Smax.romanov@nginx.com static nxt_router_t *nxt_router; 24820Sigor@sysoev.ru 249216Sigor@sysoev.ru 250216Sigor@sysoev.ru static nxt_app_prepare_msg_t nxt_app_prepare_msg[] = { 251216Sigor@sysoev.ru nxt_python_prepare_msg, 252216Sigor@sysoev.ru nxt_php_prepare_msg, 253216Sigor@sysoev.ru nxt_go_prepare_msg, 254510Salexander.borisov@nginx.com nxt_perl_prepare_msg, 255584Salexander.borisov@nginx.com nxt_ruby_prepare_msg, 256216Sigor@sysoev.ru }; 257216Sigor@sysoev.ru 258216Sigor@sysoev.ru 25920Sigor@sysoev.ru nxt_int_t 260141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data) 26120Sigor@sysoev.ru { 262141Smax.romanov@nginx.com nxt_int_t ret; 263141Smax.romanov@nginx.com nxt_router_t *router; 264141Smax.romanov@nginx.com nxt_runtime_t *rt; 265141Smax.romanov@nginx.com 266141Smax.romanov@nginx.com rt = task->thread->runtime; 26753Sigor@sysoev.ru 268431Sigor@sysoev.ru ret = nxt_http_init(task, rt); 26988Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 27088Smax.romanov@nginx.com return ret; 27188Smax.romanov@nginx.com } 27288Smax.romanov@nginx.com 27353Sigor@sysoev.ru router = nxt_zalloc(sizeof(nxt_router_t)); 27453Sigor@sysoev.ru if (nxt_slow_path(router == NULL)) { 27553Sigor@sysoev.ru return NXT_ERROR; 27653Sigor@sysoev.ru } 27753Sigor@sysoev.ru 27853Sigor@sysoev.ru nxt_queue_init(&router->engines); 27953Sigor@sysoev.ru nxt_queue_init(&router->sockets); 280133Sigor@sysoev.ru nxt_queue_init(&router->apps); 28153Sigor@sysoev.ru 282119Smax.romanov@nginx.com nxt_router = router; 283119Smax.romanov@nginx.com 284115Sigor@sysoev.ru return NXT_OK; 285115Sigor@sysoev.ru } 286115Sigor@sysoev.ru 287115Sigor@sysoev.ru 288343Smax.romanov@nginx.com static void 289507Smax.romanov@nginx.com nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port, 290507Smax.romanov@nginx.com void *data) 291167Smax.romanov@nginx.com { 292343Smax.romanov@nginx.com size_t size; 293343Smax.romanov@nginx.com uint32_t stream; 294430Sigor@sysoev.ru nxt_mp_t *mp; 295343Smax.romanov@nginx.com nxt_app_t *app; 296343Smax.romanov@nginx.com nxt_buf_t *b; 297343Smax.romanov@nginx.com nxt_port_t *main_port; 298343Smax.romanov@nginx.com nxt_runtime_t *rt; 299343Smax.romanov@nginx.com 300343Smax.romanov@nginx.com app = data; 301167Smax.romanov@nginx.com 302167Smax.romanov@nginx.com rt = task->thread->runtime; 303240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 304167Smax.romanov@nginx.com 305507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start process", &app->name, app); 306343Smax.romanov@nginx.com 307343Smax.romanov@nginx.com size = app->name.length + 1 + app->conf.length; 308343Smax.romanov@nginx.com 309343Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size); 310343Smax.romanov@nginx.com 311343Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 312343Smax.romanov@nginx.com goto failed; 313167Smax.romanov@nginx.com } 314167Smax.romanov@nginx.com 315343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->name); 316343Smax.romanov@nginx.com *b->mem.free++ = '\0'; 317343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 318343Smax.romanov@nginx.com 319343Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, port, 320343Smax.romanov@nginx.com nxt_router_app_port_ready, 321343Smax.romanov@nginx.com nxt_router_app_port_error, 322343Smax.romanov@nginx.com -1, app); 323343Smax.romanov@nginx.com 324343Smax.romanov@nginx.com if (nxt_slow_path(stream == 0)) { 325430Sigor@sysoev.ru mp = b->data; 326430Sigor@sysoev.ru nxt_mp_free(mp, b); 327430Sigor@sysoev.ru nxt_mp_release(mp); 328343Smax.romanov@nginx.com 329343Smax.romanov@nginx.com goto failed; 330343Smax.romanov@nginx.com } 331343Smax.romanov@nginx.com 332343Smax.romanov@nginx.com nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1, 333343Smax.romanov@nginx.com stream, port->id, b); 334343Smax.romanov@nginx.com 335343Smax.romanov@nginx.com return; 336343Smax.romanov@nginx.com 337343Smax.romanov@nginx.com failed: 338343Smax.romanov@nginx.com 339343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 340343Smax.romanov@nginx.com 341507Smax.romanov@nginx.com app->pending_processes--; 342343Smax.romanov@nginx.com 343343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 344343Smax.romanov@nginx.com 345343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 346167Smax.romanov@nginx.com } 347167Smax.romanov@nginx.com 348167Smax.romanov@nginx.com 349343Smax.romanov@nginx.com static nxt_int_t 350507Smax.romanov@nginx.com nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app) 351141Smax.romanov@nginx.com { 352343Smax.romanov@nginx.com nxt_int_t res; 353343Smax.romanov@nginx.com nxt_port_t *router_port; 354343Smax.romanov@nginx.com nxt_runtime_t *rt; 355343Smax.romanov@nginx.com 356343Smax.romanov@nginx.com rt = task->thread->runtime; 357343Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 358343Smax.romanov@nginx.com 359343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 360343Smax.romanov@nginx.com 361507Smax.romanov@nginx.com res = nxt_port_post(task, router_port, nxt_router_start_app_process_handler, 362343Smax.romanov@nginx.com app); 363343Smax.romanov@nginx.com 364343Smax.romanov@nginx.com if (res == NXT_OK) { 365343Smax.romanov@nginx.com return res; 366318Smax.romanov@nginx.com } 367318Smax.romanov@nginx.com 368343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 369343Smax.romanov@nginx.com 370507Smax.romanov@nginx.com app->pending_processes--; 371343Smax.romanov@nginx.com 372343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 373343Smax.romanov@nginx.com 374343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 375343Smax.romanov@nginx.com 376343Smax.romanov@nginx.com return NXT_ERROR; 377318Smax.romanov@nginx.com } 378318Smax.romanov@nginx.com 379318Smax.romanov@nginx.com 380351Smax.romanov@nginx.com nxt_inline void 381351Smax.romanov@nginx.com nxt_router_ra_init(nxt_task_t *task, nxt_req_app_link_t *ra, 382351Smax.romanov@nginx.com nxt_req_conn_link_t *rc) 383167Smax.romanov@nginx.com { 384318Smax.romanov@nginx.com nxt_event_engine_t *engine; 385351Smax.romanov@nginx.com 386318Smax.romanov@nginx.com engine = task->thread->engine; 387167Smax.romanov@nginx.com 388167Smax.romanov@nginx.com nxt_memzero(ra, sizeof(nxt_req_app_link_t)); 389167Smax.romanov@nginx.com 390318Smax.romanov@nginx.com ra->stream = rc->stream; 391425Smax.romanov@nginx.com ra->use_count = 1; 392167Smax.romanov@nginx.com ra->rc = rc; 393318Smax.romanov@nginx.com rc->ra = ra; 394318Smax.romanov@nginx.com ra->reply_port = engine->port; 395351Smax.romanov@nginx.com ra->ap = rc->ap; 396167Smax.romanov@nginx.com 397167Smax.romanov@nginx.com ra->work.handler = NULL; 398318Smax.romanov@nginx.com ra->work.task = &engine->task; 399167Smax.romanov@nginx.com ra->work.obj = ra; 400318Smax.romanov@nginx.com ra->work.data = engine; 401351Smax.romanov@nginx.com } 402351Smax.romanov@nginx.com 403351Smax.romanov@nginx.com 404351Smax.romanov@nginx.com nxt_inline nxt_req_app_link_t * 405351Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_app_link_t *ra_src) 406351Smax.romanov@nginx.com { 407351Smax.romanov@nginx.com nxt_mp_t *mp; 408351Smax.romanov@nginx.com nxt_req_app_link_t *ra; 409351Smax.romanov@nginx.com 410425Smax.romanov@nginx.com if (ra_src->mem_pool != NULL) { 411425Smax.romanov@nginx.com return ra_src; 412425Smax.romanov@nginx.com } 413425Smax.romanov@nginx.com 414351Smax.romanov@nginx.com mp = ra_src->ap->mem_pool; 415351Smax.romanov@nginx.com 416430Sigor@sysoev.ru ra = nxt_mp_alloc(mp, sizeof(nxt_req_app_link_t)); 417351Smax.romanov@nginx.com 418351Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 419351Smax.romanov@nginx.com 420351Smax.romanov@nginx.com ra_src->rc->ra = NULL; 421351Smax.romanov@nginx.com ra_src->rc = NULL; 422351Smax.romanov@nginx.com 423351Smax.romanov@nginx.com return NULL; 424351Smax.romanov@nginx.com } 425351Smax.romanov@nginx.com 426430Sigor@sysoev.ru nxt_mp_retain(mp); 427430Sigor@sysoev.ru 428351Smax.romanov@nginx.com nxt_router_ra_init(task, ra, ra_src->rc); 429351Smax.romanov@nginx.com 430351Smax.romanov@nginx.com ra->mem_pool = mp; 431167Smax.romanov@nginx.com 432167Smax.romanov@nginx.com return ra; 433167Smax.romanov@nginx.com } 434167Smax.romanov@nginx.com 435167Smax.romanov@nginx.com 436423Smax.romanov@nginx.com nxt_inline nxt_bool_t 437423Smax.romanov@nginx.com nxt_router_msg_cancel(nxt_task_t *task, nxt_msg_info_t *msg_info, 438423Smax.romanov@nginx.com uint32_t stream) 439423Smax.romanov@nginx.com { 440423Smax.romanov@nginx.com nxt_buf_t *b, *next; 441423Smax.romanov@nginx.com nxt_bool_t cancelled; 442423Smax.romanov@nginx.com 443423Smax.romanov@nginx.com if (msg_info->buf == NULL) { 444423Smax.romanov@nginx.com return 0; 445423Smax.romanov@nginx.com } 446423Smax.romanov@nginx.com 447423Smax.romanov@nginx.com cancelled = nxt_port_mmap_tracking_cancel(task, &msg_info->tracking, 448423Smax.romanov@nginx.com stream); 449423Smax.romanov@nginx.com 450423Smax.romanov@nginx.com if (cancelled) { 451423Smax.romanov@nginx.com nxt_debug(task, "stream #%uD: cancelled by router", stream); 452423Smax.romanov@nginx.com } 453423Smax.romanov@nginx.com 454423Smax.romanov@nginx.com for (b = msg_info->buf; b != NULL; b = next) { 455423Smax.romanov@nginx.com next = b->next; 456423Smax.romanov@nginx.com 457423Smax.romanov@nginx.com b->completion_handler = msg_info->completion_handler; 458423Smax.romanov@nginx.com 459423Smax.romanov@nginx.com if (b->is_port_mmap_sent) { 460423Smax.romanov@nginx.com b->is_port_mmap_sent = cancelled == 0; 461423Smax.romanov@nginx.com b->completion_handler(task, b, b->parent); 462423Smax.romanov@nginx.com } 463423Smax.romanov@nginx.com } 464423Smax.romanov@nginx.com 465423Smax.romanov@nginx.com msg_info->buf = NULL; 466423Smax.romanov@nginx.com 467423Smax.romanov@nginx.com return cancelled; 468423Smax.romanov@nginx.com } 469423Smax.romanov@nginx.com 470423Smax.romanov@nginx.com 471167Smax.romanov@nginx.com static void 472425Smax.romanov@nginx.com nxt_router_ra_update_peer(nxt_task_t *task, nxt_req_app_link_t *ra); 473425Smax.romanov@nginx.com 474425Smax.romanov@nginx.com 475425Smax.romanov@nginx.com static void 476425Smax.romanov@nginx.com nxt_router_ra_update_peer_handler(nxt_task_t *task, void *obj, void *data) 477167Smax.romanov@nginx.com { 478425Smax.romanov@nginx.com nxt_req_app_link_t *ra; 479425Smax.romanov@nginx.com 480425Smax.romanov@nginx.com ra = obj; 481425Smax.romanov@nginx.com 482425Smax.romanov@nginx.com nxt_router_ra_update_peer(task, ra); 483425Smax.romanov@nginx.com 484425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 485425Smax.romanov@nginx.com } 486425Smax.romanov@nginx.com 487425Smax.romanov@nginx.com 488425Smax.romanov@nginx.com static void 489425Smax.romanov@nginx.com nxt_router_ra_update_peer(nxt_task_t *task, nxt_req_app_link_t *ra) 490425Smax.romanov@nginx.com { 491343Smax.romanov@nginx.com nxt_event_engine_t *engine; 492343Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 493318Smax.romanov@nginx.com 494425Smax.romanov@nginx.com engine = ra->work.data; 495318Smax.romanov@nginx.com 496343Smax.romanov@nginx.com if (task->thread->engine != engine) { 497425Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 498425Smax.romanov@nginx.com 499425Smax.romanov@nginx.com ra->work.handler = nxt_router_ra_update_peer_handler; 500318Smax.romanov@nginx.com ra->work.task = &engine->task; 501318Smax.romanov@nginx.com ra->work.next = NULL; 502318Smax.romanov@nginx.com 503425Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD post update peer to %p", 504318Smax.romanov@nginx.com ra->stream, engine); 505318Smax.romanov@nginx.com 506318Smax.romanov@nginx.com nxt_event_engine_post(engine, &ra->work); 507318Smax.romanov@nginx.com 508318Smax.romanov@nginx.com return; 509318Smax.romanov@nginx.com } 510318Smax.romanov@nginx.com 511425Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD update peer", ra->stream); 512425Smax.romanov@nginx.com 513425Smax.romanov@nginx.com rc = ra->rc; 514425Smax.romanov@nginx.com 515425Smax.romanov@nginx.com if (rc != NULL && ra->app_port != NULL) { 516425Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, engine->port, rc, ra->app_port->pid); 517425Smax.romanov@nginx.com } 518425Smax.romanov@nginx.com 519425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 520425Smax.romanov@nginx.com } 521425Smax.romanov@nginx.com 522425Smax.romanov@nginx.com 523425Smax.romanov@nginx.com static void 524425Smax.romanov@nginx.com nxt_router_ra_release(nxt_task_t *task, nxt_req_app_link_t *ra) 525425Smax.romanov@nginx.com { 526431Sigor@sysoev.ru nxt_mp_t *mp; 527431Sigor@sysoev.ru nxt_req_conn_link_t *rc; 528425Smax.romanov@nginx.com 529425Smax.romanov@nginx.com nxt_assert(task->thread->engine == ra->work.data); 530425Smax.romanov@nginx.com nxt_assert(ra->use_count == 0); 531425Smax.romanov@nginx.com 532343Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD release", ra->stream); 533343Smax.romanov@nginx.com 534343Smax.romanov@nginx.com rc = ra->rc; 535343Smax.romanov@nginx.com 536343Smax.romanov@nginx.com if (rc != NULL) { 537423Smax.romanov@nginx.com if (nxt_slow_path(ra->err_code != 0)) { 538431Sigor@sysoev.ru nxt_http_request_error(task, rc->ap->request, ra->err_code); 539423Smax.romanov@nginx.com 540423Smax.romanov@nginx.com } else { 541423Smax.romanov@nginx.com rc->app_port = ra->app_port; 542423Smax.romanov@nginx.com rc->msg_info = ra->msg_info; 543423Smax.romanov@nginx.com 544425Smax.romanov@nginx.com if (rc->app->timeout != 0) { 545431Sigor@sysoev.ru rc->ap->timer.handler = nxt_router_app_timeout; 546*615Smax.romanov@nginx.com rc->ap->timer_data = rc; 547431Sigor@sysoev.ru nxt_timer_add(task->thread->engine, &rc->ap->timer, 548425Smax.romanov@nginx.com rc->app->timeout); 549425Smax.romanov@nginx.com } 550425Smax.romanov@nginx.com 551423Smax.romanov@nginx.com ra->app_port = NULL; 552423Smax.romanov@nginx.com ra->msg_info.buf = NULL; 553423Smax.romanov@nginx.com } 554343Smax.romanov@nginx.com 555343Smax.romanov@nginx.com rc->ra = NULL; 556343Smax.romanov@nginx.com ra->rc = NULL; 557343Smax.romanov@nginx.com } 558343Smax.romanov@nginx.com 559343Smax.romanov@nginx.com if (ra->app_port != NULL) { 560343Smax.romanov@nginx.com nxt_router_app_port_release(task, ra->app_port, 0, 1); 561343Smax.romanov@nginx.com 562343Smax.romanov@nginx.com ra->app_port = NULL; 563167Smax.romanov@nginx.com } 564167Smax.romanov@nginx.com 565423Smax.romanov@nginx.com nxt_router_msg_cancel(task, &ra->msg_info, ra->stream); 566423Smax.romanov@nginx.com 567430Sigor@sysoev.ru mp = ra->mem_pool; 568430Sigor@sysoev.ru 569430Sigor@sysoev.ru if (mp != NULL) { 570430Sigor@sysoev.ru nxt_mp_free(mp, ra); 571430Sigor@sysoev.ru nxt_mp_release(mp); 572351Smax.romanov@nginx.com } 573167Smax.romanov@nginx.com } 574167Smax.romanov@nginx.com 575167Smax.romanov@nginx.com 576425Smax.romanov@nginx.com static void 577425Smax.romanov@nginx.com nxt_router_ra_release_handler(nxt_task_t *task, void *obj, void *data) 578425Smax.romanov@nginx.com { 579425Smax.romanov@nginx.com nxt_req_app_link_t *ra; 580425Smax.romanov@nginx.com 581425Smax.romanov@nginx.com ra = obj; 582425Smax.romanov@nginx.com 583425Smax.romanov@nginx.com nxt_assert(ra->work.data == data); 584425Smax.romanov@nginx.com 585425Smax.romanov@nginx.com nxt_atomic_fetch_add(&ra->use_count, -1); 586425Smax.romanov@nginx.com 587425Smax.romanov@nginx.com nxt_router_ra_release(task, ra); 588425Smax.romanov@nginx.com } 589425Smax.romanov@nginx.com 590425Smax.romanov@nginx.com 591425Smax.romanov@nginx.com static void 592425Smax.romanov@nginx.com nxt_router_ra_use(nxt_task_t *task, nxt_req_app_link_t *ra, int i) 593425Smax.romanov@nginx.com { 594425Smax.romanov@nginx.com int c; 595425Smax.romanov@nginx.com nxt_event_engine_t *engine; 596425Smax.romanov@nginx.com 597425Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&ra->use_count, i); 598425Smax.romanov@nginx.com 599425Smax.romanov@nginx.com if (i < 0 && c == -i) { 600425Smax.romanov@nginx.com engine = ra->work.data; 601425Smax.romanov@nginx.com 602425Smax.romanov@nginx.com if (task->thread->engine == engine) { 603425Smax.romanov@nginx.com nxt_router_ra_release(task, ra); 604425Smax.romanov@nginx.com 605425Smax.romanov@nginx.com return; 606425Smax.romanov@nginx.com } 607425Smax.romanov@nginx.com 608425Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 609425Smax.romanov@nginx.com 610425Smax.romanov@nginx.com ra->work.handler = nxt_router_ra_release_handler; 611425Smax.romanov@nginx.com ra->work.task = &engine->task; 612425Smax.romanov@nginx.com ra->work.next = NULL; 613425Smax.romanov@nginx.com 614425Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD post release to %p", 615425Smax.romanov@nginx.com ra->stream, engine); 616425Smax.romanov@nginx.com 617425Smax.romanov@nginx.com nxt_event_engine_post(engine, &ra->work); 618425Smax.romanov@nginx.com } 619425Smax.romanov@nginx.com } 620425Smax.romanov@nginx.com 621425Smax.romanov@nginx.com 622423Smax.romanov@nginx.com nxt_inline void 623521Szelenkov@nginx.com nxt_router_ra_error(nxt_req_app_link_t *ra, int code, const char *str) 624345Smax.romanov@nginx.com { 625423Smax.romanov@nginx.com ra->app_port = NULL; 626423Smax.romanov@nginx.com ra->err_code = code; 627423Smax.romanov@nginx.com ra->err_str = str; 628345Smax.romanov@nginx.com } 629345Smax.romanov@nginx.com 630345Smax.romanov@nginx.com 631427Smax.romanov@nginx.com nxt_inline void 632427Smax.romanov@nginx.com nxt_router_ra_pending(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra) 633427Smax.romanov@nginx.com { 634427Smax.romanov@nginx.com nxt_queue_insert_tail(&ra->app_port->pending_requests, 635427Smax.romanov@nginx.com &ra->link_port_pending); 636427Smax.romanov@nginx.com nxt_queue_insert_tail(&app->pending, &ra->link_app_pending); 637427Smax.romanov@nginx.com 638427Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 639427Smax.romanov@nginx.com 640427Smax.romanov@nginx.com ra->res_time = nxt_thread_monotonic_time(task->thread) + app->res_timeout; 641427Smax.romanov@nginx.com 642427Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD enqueue to pending_requests", ra->stream); 643427Smax.romanov@nginx.com } 644427Smax.romanov@nginx.com 645427Smax.romanov@nginx.com 646425Smax.romanov@nginx.com nxt_inline nxt_bool_t 647425Smax.romanov@nginx.com nxt_queue_chk_remove(nxt_queue_link_t *lnk) 648425Smax.romanov@nginx.com { 649425Smax.romanov@nginx.com if (lnk->next != NULL) { 650425Smax.romanov@nginx.com nxt_queue_remove(lnk); 651425Smax.romanov@nginx.com 652425Smax.romanov@nginx.com lnk->next = NULL; 653425Smax.romanov@nginx.com 654425Smax.romanov@nginx.com return 1; 655425Smax.romanov@nginx.com } 656425Smax.romanov@nginx.com 657425Smax.romanov@nginx.com return 0; 658425Smax.romanov@nginx.com } 659425Smax.romanov@nginx.com 660425Smax.romanov@nginx.com 661343Smax.romanov@nginx.com nxt_inline void 662343Smax.romanov@nginx.com nxt_router_rc_unlink(nxt_task_t *task, nxt_req_conn_link_t *rc) 663343Smax.romanov@nginx.com { 664425Smax.romanov@nginx.com int ra_use_delta; 665343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 666343Smax.romanov@nginx.com 667343Smax.romanov@nginx.com if (rc->app_port != NULL) { 668343Smax.romanov@nginx.com nxt_router_app_port_release(task, rc->app_port, 0, 1); 669343Smax.romanov@nginx.com 670343Smax.romanov@nginx.com rc->app_port = NULL; 671343Smax.romanov@nginx.com } 672343Smax.romanov@nginx.com 673423Smax.romanov@nginx.com nxt_router_msg_cancel(task, &rc->msg_info, rc->stream); 674423Smax.romanov@nginx.com 675343Smax.romanov@nginx.com ra = rc->ra; 676343Smax.romanov@nginx.com 677343Smax.romanov@nginx.com if (ra != NULL) { 678343Smax.romanov@nginx.com rc->ra = NULL; 679343Smax.romanov@nginx.com ra->rc = NULL; 680343Smax.romanov@nginx.com 681425Smax.romanov@nginx.com ra_use_delta = 0; 682425Smax.romanov@nginx.com 683343Smax.romanov@nginx.com nxt_thread_mutex_lock(&rc->app->mutex); 684343Smax.romanov@nginx.com 685425Smax.romanov@nginx.com if (ra->link_app_requests.next == NULL 686427Smax.romanov@nginx.com && ra->link_port_pending.next == NULL 687427Smax.romanov@nginx.com && ra->link_app_pending.next == NULL) 688425Smax.romanov@nginx.com { 689425Smax.romanov@nginx.com ra = NULL; 690343Smax.romanov@nginx.com 691343Smax.romanov@nginx.com } else { 692425Smax.romanov@nginx.com ra_use_delta -= nxt_queue_chk_remove(&ra->link_app_requests); 693425Smax.romanov@nginx.com ra_use_delta -= nxt_queue_chk_remove(&ra->link_port_pending); 694427Smax.romanov@nginx.com nxt_queue_chk_remove(&ra->link_app_pending); 695343Smax.romanov@nginx.com } 696343Smax.romanov@nginx.com 697343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&rc->app->mutex); 698425Smax.romanov@nginx.com 699425Smax.romanov@nginx.com if (ra != NULL) { 700425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, ra_use_delta); 701425Smax.romanov@nginx.com } 702343Smax.romanov@nginx.com } 703343Smax.romanov@nginx.com 704343Smax.romanov@nginx.com if (rc->app != NULL) { 705343Smax.romanov@nginx.com nxt_router_app_use(task, rc->app, -1); 706343Smax.romanov@nginx.com 707343Smax.romanov@nginx.com rc->app = NULL; 708343Smax.romanov@nginx.com } 709343Smax.romanov@nginx.com 710346Smax.romanov@nginx.com if (rc->ap != NULL) { 711*615Smax.romanov@nginx.com rc->ap->timer_data = NULL; 712*615Smax.romanov@nginx.com 713346Smax.romanov@nginx.com nxt_app_http_req_done(task, rc->ap); 714346Smax.romanov@nginx.com 715346Smax.romanov@nginx.com rc->ap = NULL; 716346Smax.romanov@nginx.com } 717343Smax.romanov@nginx.com } 718343Smax.romanov@nginx.com 719343Smax.romanov@nginx.com 720141Smax.romanov@nginx.com void 721141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 722141Smax.romanov@nginx.com { 723141Smax.romanov@nginx.com nxt_port_new_port_handler(task, msg); 724141Smax.romanov@nginx.com 725192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 726141Smax.romanov@nginx.com return; 727141Smax.romanov@nginx.com } 728141Smax.romanov@nginx.com 729426Smax.romanov@nginx.com if (msg->u.new_port == NULL 730426Smax.romanov@nginx.com || msg->u.new_port->type != NXT_PROCESS_WORKER) 731347Smax.romanov@nginx.com { 732192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 733141Smax.romanov@nginx.com } 734192Smax.romanov@nginx.com 735192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 736141Smax.romanov@nginx.com } 737141Smax.romanov@nginx.com 738141Smax.romanov@nginx.com 739139Sigor@sysoev.ru void 740139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 741115Sigor@sysoev.ru { 742198Sigor@sysoev.ru nxt_int_t ret; 743139Sigor@sysoev.ru nxt_buf_t *b; 744139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 745139Sigor@sysoev.ru 746139Sigor@sysoev.ru tmcf = nxt_router_temp_conf(task); 747139Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 748139Sigor@sysoev.ru return; 74953Sigor@sysoev.ru } 75053Sigor@sysoev.ru 751494Spluknet@nginx.com nxt_debug(task, "nxt_router_conf_data_handler(%O): %*s", 752423Smax.romanov@nginx.com nxt_buf_used_size(msg->buf), 753493Spluknet@nginx.com (size_t) nxt_buf_used_size(msg->buf), msg->buf->mem.pos); 754423Smax.romanov@nginx.com 755591Sigor@sysoev.ru tmcf->router_conf->router = nxt_router; 756139Sigor@sysoev.ru tmcf->stream = msg->port_msg.stream; 757139Sigor@sysoev.ru tmcf->port = nxt_runtime_port_find(task->thread->runtime, 758198Sigor@sysoev.ru msg->port_msg.pid, 759198Sigor@sysoev.ru msg->port_msg.reply_port); 760198Sigor@sysoev.ru 761591Sigor@sysoev.ru b = nxt_buf_chk_make_plain(tmcf->router_conf->mem_pool, 762591Sigor@sysoev.ru msg->buf, msg->size); 763551Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 764551Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 765551Smax.romanov@nginx.com 766551Smax.romanov@nginx.com return; 767551Smax.romanov@nginx.com } 768551Smax.romanov@nginx.com 769198Sigor@sysoev.ru ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free); 770198Sigor@sysoev.ru 771198Sigor@sysoev.ru if (nxt_fast_path(ret == NXT_OK)) { 772198Sigor@sysoev.ru nxt_router_conf_apply(task, tmcf, NULL); 773198Sigor@sysoev.ru 774198Sigor@sysoev.ru } else { 775198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 776139Sigor@sysoev.ru } 77753Sigor@sysoev.ru } 77853Sigor@sysoev.ru 77953Sigor@sysoev.ru 780347Smax.romanov@nginx.com static void 781507Smax.romanov@nginx.com nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port, 782507Smax.romanov@nginx.com void *data) 783347Smax.romanov@nginx.com { 784347Smax.romanov@nginx.com union { 785347Smax.romanov@nginx.com nxt_pid_t removed_pid; 786347Smax.romanov@nginx.com void *data; 787347Smax.romanov@nginx.com } u; 788347Smax.romanov@nginx.com 789347Smax.romanov@nginx.com u.data = data; 790347Smax.romanov@nginx.com 791347Smax.romanov@nginx.com nxt_port_rpc_remove_peer(task, port, u.removed_pid); 792347Smax.romanov@nginx.com } 793347Smax.romanov@nginx.com 794347Smax.romanov@nginx.com 795192Smax.romanov@nginx.com void 796192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 797192Smax.romanov@nginx.com { 798347Smax.romanov@nginx.com nxt_event_engine_t *engine; 799318Smax.romanov@nginx.com 800192Smax.romanov@nginx.com nxt_port_remove_pid_handler(task, msg); 801192Smax.romanov@nginx.com 802192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 803192Smax.romanov@nginx.com return; 804192Smax.romanov@nginx.com } 805192Smax.romanov@nginx.com 806318Smax.romanov@nginx.com nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0) 807318Smax.romanov@nginx.com { 808507Smax.romanov@nginx.com nxt_port_post(task, engine->port, nxt_router_app_process_remove_pid, 809347Smax.romanov@nginx.com msg->u.data); 810318Smax.romanov@nginx.com } 811318Smax.romanov@nginx.com nxt_queue_loop; 812318Smax.romanov@nginx.com 813192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 814192Smax.romanov@nginx.com 815192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 816192Smax.romanov@nginx.com } 817192Smax.romanov@nginx.com 818192Smax.romanov@nginx.com 81953Sigor@sysoev.ru static nxt_router_temp_conf_t * 820139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task) 82153Sigor@sysoev.ru { 82265Sigor@sysoev.ru nxt_mp_t *mp, *tmp; 82353Sigor@sysoev.ru nxt_router_conf_t *rtcf; 82453Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 82553Sigor@sysoev.ru 82665Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 82753Sigor@sysoev.ru if (nxt_slow_path(mp == NULL)) { 82853Sigor@sysoev.ru return NULL; 82953Sigor@sysoev.ru } 83053Sigor@sysoev.ru 83165Sigor@sysoev.ru rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t)); 83253Sigor@sysoev.ru if (nxt_slow_path(rtcf == NULL)) { 83353Sigor@sysoev.ru goto fail; 83453Sigor@sysoev.ru } 83553Sigor@sysoev.ru 83653Sigor@sysoev.ru rtcf->mem_pool = mp; 83753Sigor@sysoev.ru 83865Sigor@sysoev.ru tmp = nxt_mp_create(1024, 128, 256, 32); 83953Sigor@sysoev.ru if (nxt_slow_path(tmp == NULL)) { 84053Sigor@sysoev.ru goto fail; 84153Sigor@sysoev.ru } 84253Sigor@sysoev.ru 84365Sigor@sysoev.ru tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t)); 84453Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 84553Sigor@sysoev.ru goto temp_fail; 84653Sigor@sysoev.ru } 84753Sigor@sysoev.ru 84853Sigor@sysoev.ru tmcf->mem_pool = tmp; 849591Sigor@sysoev.ru tmcf->router_conf = rtcf; 850139Sigor@sysoev.ru tmcf->count = 1; 851139Sigor@sysoev.ru tmcf->engine = task->thread->engine; 85253Sigor@sysoev.ru 85353Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, 4, 85453Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 85553Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 85653Sigor@sysoev.ru goto temp_fail; 85753Sigor@sysoev.ru } 85853Sigor@sysoev.ru 85953Sigor@sysoev.ru nxt_queue_init(&tmcf->deleting); 86053Sigor@sysoev.ru nxt_queue_init(&tmcf->keeping); 86153Sigor@sysoev.ru nxt_queue_init(&tmcf->updating); 86253Sigor@sysoev.ru nxt_queue_init(&tmcf->pending); 86353Sigor@sysoev.ru nxt_queue_init(&tmcf->creating); 864416Smax.romanov@nginx.com 865133Sigor@sysoev.ru nxt_queue_init(&tmcf->apps); 866133Sigor@sysoev.ru nxt_queue_init(&tmcf->previous); 86753Sigor@sysoev.ru 86853Sigor@sysoev.ru return tmcf; 86953Sigor@sysoev.ru 87053Sigor@sysoev.ru temp_fail: 87153Sigor@sysoev.ru 87265Sigor@sysoev.ru nxt_mp_destroy(tmp); 87353Sigor@sysoev.ru 87453Sigor@sysoev.ru fail: 87553Sigor@sysoev.ru 87665Sigor@sysoev.ru nxt_mp_destroy(mp); 87753Sigor@sysoev.ru 87853Sigor@sysoev.ru return NULL; 87953Sigor@sysoev.ru } 88053Sigor@sysoev.ru 88153Sigor@sysoev.ru 882507Smax.romanov@nginx.com nxt_inline nxt_bool_t 883507Smax.romanov@nginx.com nxt_router_app_can_start(nxt_app_t *app) 884507Smax.romanov@nginx.com { 885507Smax.romanov@nginx.com return app->processes + app->pending_processes < app->max_processes 886507Smax.romanov@nginx.com && app->pending_processes < app->max_pending_processes; 887507Smax.romanov@nginx.com } 888507Smax.romanov@nginx.com 889507Smax.romanov@nginx.com 890507Smax.romanov@nginx.com nxt_inline nxt_bool_t 891507Smax.romanov@nginx.com nxt_router_app_need_start(nxt_app_t *app) 892507Smax.romanov@nginx.com { 893507Smax.romanov@nginx.com return app->idle_processes + app->pending_processes 894507Smax.romanov@nginx.com < app->spare_processes; 895507Smax.romanov@nginx.com } 896507Smax.romanov@nginx.com 897507Smax.romanov@nginx.com 898198Sigor@sysoev.ru static void 899198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data) 900139Sigor@sysoev.ru { 901139Sigor@sysoev.ru nxt_int_t ret; 902507Smax.romanov@nginx.com nxt_app_t *app; 903139Sigor@sysoev.ru nxt_router_t *router; 904139Sigor@sysoev.ru nxt_runtime_t *rt; 905198Sigor@sysoev.ru nxt_queue_link_t *qlk; 906198Sigor@sysoev.ru nxt_socket_conf_t *skcf; 907198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 908139Sigor@sysoev.ru const nxt_event_interface_t *interface; 909139Sigor@sysoev.ru 910198Sigor@sysoev.ru tmcf = obj; 911198Sigor@sysoev.ru 912198Sigor@sysoev.ru qlk = nxt_queue_first(&tmcf->pending); 913198Sigor@sysoev.ru 914198Sigor@sysoev.ru if (qlk != nxt_queue_tail(&tmcf->pending)) { 915198Sigor@sysoev.ru nxt_queue_remove(qlk); 916198Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->creating, qlk); 917198Sigor@sysoev.ru 918198Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 919198Sigor@sysoev.ru 920198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(task, tmcf, skcf); 921198Sigor@sysoev.ru 922198Sigor@sysoev.ru return; 923139Sigor@sysoev.ru } 924139Sigor@sysoev.ru 925507Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 926507Smax.romanov@nginx.com 927507Smax.romanov@nginx.com if (nxt_router_app_need_start(app)) { 928507Smax.romanov@nginx.com nxt_router_app_rpc_create(task, tmcf, app); 929507Smax.romanov@nginx.com return; 930507Smax.romanov@nginx.com } 931507Smax.romanov@nginx.com 932507Smax.romanov@nginx.com } nxt_queue_loop; 933507Smax.romanov@nginx.com 934139Sigor@sysoev.ru rt = task->thread->runtime; 935139Sigor@sysoev.ru 936139Sigor@sysoev.ru interface = nxt_service_get(rt->services, "engine", NULL); 937139Sigor@sysoev.ru 938591Sigor@sysoev.ru router = tmcf->router_conf->router; 939198Sigor@sysoev.ru 940139Sigor@sysoev.ru ret = nxt_router_engines_create(task, router, tmcf, interface); 941139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 942198Sigor@sysoev.ru goto fail; 943139Sigor@sysoev.ru } 944139Sigor@sysoev.ru 945139Sigor@sysoev.ru ret = nxt_router_threads_create(task, rt, tmcf); 946139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 947198Sigor@sysoev.ru goto fail; 948139Sigor@sysoev.ru } 949139Sigor@sysoev.ru 950343Smax.romanov@nginx.com nxt_router_apps_sort(task, router, tmcf); 951139Sigor@sysoev.ru 952315Sigor@sysoev.ru nxt_router_engines_post(router, tmcf); 953139Sigor@sysoev.ru 954139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->updating); 955139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->creating); 956139Sigor@sysoev.ru 957198Sigor@sysoev.ru nxt_router_conf_ready(task, tmcf); 958198Sigor@sysoev.ru 959198Sigor@sysoev.ru return; 960198Sigor@sysoev.ru 961198Sigor@sysoev.ru fail: 962198Sigor@sysoev.ru 963198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 964198Sigor@sysoev.ru 965198Sigor@sysoev.ru return; 966139Sigor@sysoev.ru } 967139Sigor@sysoev.ru 968139Sigor@sysoev.ru 969139Sigor@sysoev.ru static void 970139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data) 971139Sigor@sysoev.ru { 972153Sigor@sysoev.ru nxt_joint_job_t *job; 973153Sigor@sysoev.ru 974153Sigor@sysoev.ru job = obj; 975153Sigor@sysoev.ru 976198Sigor@sysoev.ru nxt_router_conf_ready(task, job->tmcf); 977139Sigor@sysoev.ru } 978139Sigor@sysoev.ru 979139Sigor@sysoev.ru 980139Sigor@sysoev.ru static void 981198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 982139Sigor@sysoev.ru { 983139Sigor@sysoev.ru nxt_debug(task, "temp conf count:%D", tmcf->count); 984139Sigor@sysoev.ru 985139Sigor@sysoev.ru if (--tmcf->count == 0) { 986193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST); 987139Sigor@sysoev.ru } 988139Sigor@sysoev.ru } 989139Sigor@sysoev.ru 990139Sigor@sysoev.ru 991139Sigor@sysoev.ru static void 992139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 993139Sigor@sysoev.ru { 994507Smax.romanov@nginx.com nxt_app_t *app; 995568Smax.romanov@nginx.com nxt_queue_t new_socket_confs; 996148Sigor@sysoev.ru nxt_socket_t s; 997149Sigor@sysoev.ru nxt_router_t *router; 998148Sigor@sysoev.ru nxt_queue_link_t *qlk; 999148Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1000148Sigor@sysoev.ru 1001564Svbart@nginx.com nxt_alert(task, "failed to apply new conf"); 1002198Sigor@sysoev.ru 1003148Sigor@sysoev.ru for (qlk = nxt_queue_first(&tmcf->creating); 1004148Sigor@sysoev.ru qlk != nxt_queue_tail(&tmcf->creating); 1005148Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 1006148Sigor@sysoev.ru { 1007148Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1008359Sigor@sysoev.ru s = skcf->listen->socket; 1009148Sigor@sysoev.ru 1010148Sigor@sysoev.ru if (s != -1) { 1011148Sigor@sysoev.ru nxt_socket_close(task, s); 1012148Sigor@sysoev.ru } 1013148Sigor@sysoev.ru 1014359Sigor@sysoev.ru nxt_free(skcf->listen); 1015148Sigor@sysoev.ru } 1016148Sigor@sysoev.ru 1017568Smax.romanov@nginx.com nxt_queue_init(&new_socket_confs); 1018568Smax.romanov@nginx.com nxt_queue_add(&new_socket_confs, &tmcf->updating); 1019568Smax.romanov@nginx.com nxt_queue_add(&new_socket_confs, &tmcf->pending); 1020568Smax.romanov@nginx.com nxt_queue_add(&new_socket_confs, &tmcf->creating); 1021568Smax.romanov@nginx.com 1022568Smax.romanov@nginx.com nxt_queue_each(skcf, &new_socket_confs, nxt_socket_conf_t, link) { 1023568Smax.romanov@nginx.com 1024568Smax.romanov@nginx.com if (skcf->application != NULL) { 1025568Smax.romanov@nginx.com nxt_router_app_use(task, skcf->application, -1); 1026568Smax.romanov@nginx.com skcf->application = NULL; 1027568Smax.romanov@nginx.com } 1028568Smax.romanov@nginx.com 1029568Smax.romanov@nginx.com } nxt_queue_loop; 1030568Smax.romanov@nginx.com 1031507Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1032507Smax.romanov@nginx.com 1033507Smax.romanov@nginx.com nxt_router_app_quit(task, app); 1034507Smax.romanov@nginx.com 1035507Smax.romanov@nginx.com } nxt_queue_loop; 1036507Smax.romanov@nginx.com 1037591Sigor@sysoev.ru router = tmcf->router_conf->router; 1038149Sigor@sysoev.ru 1039149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->keeping); 1040149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->deleting); 1041149Sigor@sysoev.ru 1042416Smax.romanov@nginx.com nxt_queue_add(&router->apps, &tmcf->previous); 1043416Smax.romanov@nginx.com 1044148Sigor@sysoev.ru // TODO: new engines and threads 1045148Sigor@sysoev.ru 1046591Sigor@sysoev.ru nxt_mp_destroy(tmcf->router_conf->mem_pool); 1047139Sigor@sysoev.ru 1048193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR); 1049139Sigor@sysoev.ru } 1050139Sigor@sysoev.ru 1051139Sigor@sysoev.ru 1052139Sigor@sysoev.ru static void 1053139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1054193Smax.romanov@nginx.com nxt_port_msg_type_t type) 1055139Sigor@sysoev.ru { 1056193Smax.romanov@nginx.com nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL); 1057139Sigor@sysoev.ru } 1058139Sigor@sysoev.ru 1059139Sigor@sysoev.ru 1060115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_conf[] = { 1061115Sigor@sysoev.ru { 1062133Sigor@sysoev.ru nxt_string("listeners_threads"), 1063115Sigor@sysoev.ru NXT_CONF_MAP_INT32, 1064115Sigor@sysoev.ru offsetof(nxt_router_conf_t, threads), 1065115Sigor@sysoev.ru }, 1066115Sigor@sysoev.ru }; 1067115Sigor@sysoev.ru 1068115Sigor@sysoev.ru 1069133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_app_conf[] = { 1070115Sigor@sysoev.ru { 1071133Sigor@sysoev.ru nxt_string("type"), 1072115Sigor@sysoev.ru NXT_CONF_MAP_STR, 1073133Sigor@sysoev.ru offsetof(nxt_router_app_conf_t, type), 1074115Sigor@sysoev.ru }, 1075115Sigor@sysoev.ru 1076115Sigor@sysoev.ru { 1077507Smax.romanov@nginx.com nxt_string("limits"), 1078507Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 1079507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, limits_value), 1080133Sigor@sysoev.ru }, 1081318Smax.romanov@nginx.com 1082318Smax.romanov@nginx.com { 1083507Smax.romanov@nginx.com nxt_string("processes"), 1084507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1085507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, processes), 1086507Smax.romanov@nginx.com }, 1087507Smax.romanov@nginx.com 1088507Smax.romanov@nginx.com { 1089507Smax.romanov@nginx.com nxt_string("processes"), 1090318Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 1091507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, processes_value), 1092318Smax.romanov@nginx.com }, 1093318Smax.romanov@nginx.com }; 1094318Smax.romanov@nginx.com 1095318Smax.romanov@nginx.com 1096318Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_limits_conf[] = { 1097318Smax.romanov@nginx.com { 1098318Smax.romanov@nginx.com nxt_string("timeout"), 1099318Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1100318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, timeout), 1101318Smax.romanov@nginx.com }, 1102318Smax.romanov@nginx.com 1103318Smax.romanov@nginx.com { 1104427Smax.romanov@nginx.com nxt_string("reschedule_timeout"), 1105427Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1106427Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, res_timeout), 1107427Smax.romanov@nginx.com }, 1108427Smax.romanov@nginx.com 1109427Smax.romanov@nginx.com { 1110318Smax.romanov@nginx.com nxt_string("requests"), 1111318Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1112318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, requests), 1113318Smax.romanov@nginx.com }, 1114133Sigor@sysoev.ru }; 1115133Sigor@sysoev.ru 1116133Sigor@sysoev.ru 1117507Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_processes_conf[] = { 1118507Smax.romanov@nginx.com { 1119507Smax.romanov@nginx.com nxt_string("spare"), 1120507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1121507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, spare_processes), 1122507Smax.romanov@nginx.com }, 1123507Smax.romanov@nginx.com 1124507Smax.romanov@nginx.com { 1125507Smax.romanov@nginx.com nxt_string("max"), 1126507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1127507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, max_processes), 1128507Smax.romanov@nginx.com }, 1129507Smax.romanov@nginx.com 1130507Smax.romanov@nginx.com { 1131507Smax.romanov@nginx.com nxt_string("idle_timeout"), 1132507Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1133507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, idle_timeout), 1134507Smax.romanov@nginx.com }, 1135507Smax.romanov@nginx.com }; 1136507Smax.romanov@nginx.com 1137507Smax.romanov@nginx.com 1138133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_listener_conf[] = { 1139133Sigor@sysoev.ru { 1140133Sigor@sysoev.ru nxt_string("application"), 1141133Sigor@sysoev.ru NXT_CONF_MAP_STR, 1142133Sigor@sysoev.ru offsetof(nxt_router_listener_conf_t, application), 1143115Sigor@sysoev.ru }, 1144115Sigor@sysoev.ru }; 1145115Sigor@sysoev.ru 1146115Sigor@sysoev.ru 1147115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_http_conf[] = { 1148115Sigor@sysoev.ru { 1149115Sigor@sysoev.ru nxt_string("header_buffer_size"), 1150115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 1151115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_buffer_size), 1152115Sigor@sysoev.ru }, 1153115Sigor@sysoev.ru 1154115Sigor@sysoev.ru { 1155115Sigor@sysoev.ru nxt_string("large_header_buffer_size"), 1156115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 1157115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, large_header_buffer_size), 1158115Sigor@sysoev.ru }, 1159115Sigor@sysoev.ru 1160115Sigor@sysoev.ru { 1161206Smax.romanov@nginx.com nxt_string("large_header_buffers"), 1162206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1163206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, large_header_buffers), 1164206Smax.romanov@nginx.com }, 1165206Smax.romanov@nginx.com 1166206Smax.romanov@nginx.com { 1167206Smax.romanov@nginx.com nxt_string("body_buffer_size"), 1168206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1169206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_buffer_size), 1170206Smax.romanov@nginx.com }, 1171206Smax.romanov@nginx.com 1172206Smax.romanov@nginx.com { 1173206Smax.romanov@nginx.com nxt_string("max_body_size"), 1174206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1175206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, max_body_size), 1176206Smax.romanov@nginx.com }, 1177206Smax.romanov@nginx.com 1178206Smax.romanov@nginx.com { 1179431Sigor@sysoev.ru nxt_string("idle_timeout"), 1180431Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1181431Sigor@sysoev.ru offsetof(nxt_socket_conf_t, idle_timeout), 1182431Sigor@sysoev.ru }, 1183431Sigor@sysoev.ru 1184431Sigor@sysoev.ru { 1185115Sigor@sysoev.ru nxt_string("header_read_timeout"), 1186115Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1187115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_read_timeout), 1188115Sigor@sysoev.ru }, 1189206Smax.romanov@nginx.com 1190206Smax.romanov@nginx.com { 1191206Smax.romanov@nginx.com nxt_string("body_read_timeout"), 1192206Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1193206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_read_timeout), 1194206Smax.romanov@nginx.com }, 1195431Sigor@sysoev.ru 1196431Sigor@sysoev.ru { 1197431Sigor@sysoev.ru nxt_string("send_timeout"), 1198431Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1199431Sigor@sysoev.ru offsetof(nxt_socket_conf_t, send_timeout), 1200431Sigor@sysoev.ru }, 1201115Sigor@sysoev.ru }; 1202115Sigor@sysoev.ru 1203115Sigor@sysoev.ru 120453Sigor@sysoev.ru static nxt_int_t 1205115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1206115Sigor@sysoev.ru u_char *start, u_char *end) 120753Sigor@sysoev.ru { 1208133Sigor@sysoev.ru u_char *p; 1209133Sigor@sysoev.ru size_t size; 1210115Sigor@sysoev.ru nxt_mp_t *mp; 1211115Sigor@sysoev.ru uint32_t next; 1212115Sigor@sysoev.ru nxt_int_t ret; 1213115Sigor@sysoev.ru nxt_str_t name; 1214133Sigor@sysoev.ru nxt_app_t *app, *prev; 1215359Sigor@sysoev.ru nxt_router_t *router; 1216133Sigor@sysoev.ru nxt_conf_value_t *conf, *http; 1217133Sigor@sysoev.ru nxt_conf_value_t *applications, *application; 1218133Sigor@sysoev.ru nxt_conf_value_t *listeners, *listener; 1219115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1220507Smax.romanov@nginx.com nxt_event_engine_t *engine; 1221216Sigor@sysoev.ru nxt_app_lang_module_t *lang; 1222133Sigor@sysoev.ru nxt_router_app_conf_t apcf; 1223115Sigor@sysoev.ru nxt_router_listener_conf_t lscf; 1224115Sigor@sysoev.ru 1225115Sigor@sysoev.ru static nxt_str_t http_path = nxt_string("/http"); 1226133Sigor@sysoev.ru static nxt_str_t applications_path = nxt_string("/applications"); 1227115Sigor@sysoev.ru static nxt_str_t listeners_path = nxt_string("/listeners"); 1228115Sigor@sysoev.ru 1229208Svbart@nginx.com conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL); 1230115Sigor@sysoev.ru if (conf == NULL) { 1231564Svbart@nginx.com nxt_alert(task, "configuration parsing error"); 1232115Sigor@sysoev.ru return NXT_ERROR; 1233115Sigor@sysoev.ru } 1234115Sigor@sysoev.ru 1235591Sigor@sysoev.ru mp = tmcf->router_conf->mem_pool; 1236213Svbart@nginx.com 1237213Svbart@nginx.com ret = nxt_conf_map_object(mp, conf, nxt_router_conf, 1238591Sigor@sysoev.ru nxt_nitems(nxt_router_conf), tmcf->router_conf); 1239115Sigor@sysoev.ru if (ret != NXT_OK) { 1240564Svbart@nginx.com nxt_alert(task, "root map error"); 1241115Sigor@sysoev.ru return NXT_ERROR; 1242115Sigor@sysoev.ru } 1243115Sigor@sysoev.ru 1244591Sigor@sysoev.ru if (tmcf->router_conf->threads == 0) { 1245591Sigor@sysoev.ru tmcf->router_conf->threads = nxt_ncpu; 1246117Sigor@sysoev.ru } 1247117Sigor@sysoev.ru 1248133Sigor@sysoev.ru applications = nxt_conf_get_path(conf, &applications_path); 1249133Sigor@sysoev.ru if (applications == NULL) { 1250564Svbart@nginx.com nxt_alert(task, "no \"applications\" block"); 1251115Sigor@sysoev.ru return NXT_ERROR; 1252115Sigor@sysoev.ru } 1253115Sigor@sysoev.ru 1254591Sigor@sysoev.ru router = tmcf->router_conf->router; 1255359Sigor@sysoev.ru 1256133Sigor@sysoev.ru next = 0; 1257133Sigor@sysoev.ru 1258133Sigor@sysoev.ru for ( ;; ) { 1259133Sigor@sysoev.ru application = nxt_conf_next_object_member(applications, &name, &next); 1260133Sigor@sysoev.ru if (application == NULL) { 1261133Sigor@sysoev.ru break; 1262133Sigor@sysoev.ru } 1263133Sigor@sysoev.ru 1264133Sigor@sysoev.ru nxt_debug(task, "application \"%V\"", &name); 1265133Sigor@sysoev.ru 1266144Smax.romanov@nginx.com size = nxt_conf_json_length(application, NULL); 1267144Smax.romanov@nginx.com 1268144Smax.romanov@nginx.com app = nxt_malloc(sizeof(nxt_app_t) + name.length + size); 1269133Sigor@sysoev.ru if (app == NULL) { 1270133Sigor@sysoev.ru goto fail; 1271133Sigor@sysoev.ru } 1272133Sigor@sysoev.ru 1273144Smax.romanov@nginx.com nxt_memzero(app, sizeof(nxt_app_t)); 1274144Smax.romanov@nginx.com 1275144Smax.romanov@nginx.com app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t)); 1276144Smax.romanov@nginx.com app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length); 1277133Sigor@sysoev.ru 1278133Sigor@sysoev.ru p = nxt_conf_json_print(app->conf.start, application, NULL); 1279133Sigor@sysoev.ru app->conf.length = p - app->conf.start; 1280133Sigor@sysoev.ru 1281144Smax.romanov@nginx.com nxt_assert(app->conf.length <= size); 1282144Smax.romanov@nginx.com 1283133Sigor@sysoev.ru nxt_debug(task, "application conf \"%V\"", &app->conf); 1284133Sigor@sysoev.ru 1285359Sigor@sysoev.ru prev = nxt_router_app_find(&router->apps, &name); 1286133Sigor@sysoev.ru 1287133Sigor@sysoev.ru if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) { 1288133Sigor@sysoev.ru nxt_free(app); 1289133Sigor@sysoev.ru 1290133Sigor@sysoev.ru nxt_queue_remove(&prev->link); 1291133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->previous, &prev->link); 1292133Sigor@sysoev.ru continue; 1293133Sigor@sysoev.ru } 1294133Sigor@sysoev.ru 1295507Smax.romanov@nginx.com apcf.processes = 1; 1296507Smax.romanov@nginx.com apcf.max_processes = 1; 1297537Svbart@nginx.com apcf.spare_processes = 0; 1298318Smax.romanov@nginx.com apcf.timeout = 0; 1299427Smax.romanov@nginx.com apcf.res_timeout = 1000; 1300507Smax.romanov@nginx.com apcf.idle_timeout = 15000; 1301318Smax.romanov@nginx.com apcf.requests = 0; 1302318Smax.romanov@nginx.com apcf.limits_value = NULL; 1303507Smax.romanov@nginx.com apcf.processes_value = NULL; 1304263Smax.romanov@nginx.com 1305213Svbart@nginx.com ret = nxt_conf_map_object(mp, application, nxt_router_app_conf, 1306136Svbart@nginx.com nxt_nitems(nxt_router_app_conf), &apcf); 1307133Sigor@sysoev.ru if (ret != NXT_OK) { 1308564Svbart@nginx.com nxt_alert(task, "application map error"); 1309133Sigor@sysoev.ru goto app_fail; 1310133Sigor@sysoev.ru } 1311115Sigor@sysoev.ru 1312318Smax.romanov@nginx.com if (apcf.limits_value != NULL) { 1313318Smax.romanov@nginx.com 1314318Smax.romanov@nginx.com if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) { 1315564Svbart@nginx.com nxt_alert(task, "application limits is not object"); 1316318Smax.romanov@nginx.com goto app_fail; 1317318Smax.romanov@nginx.com } 1318318Smax.romanov@nginx.com 1319318Smax.romanov@nginx.com ret = nxt_conf_map_object(mp, apcf.limits_value, 1320318Smax.romanov@nginx.com nxt_router_app_limits_conf, 1321318Smax.romanov@nginx.com nxt_nitems(nxt_router_app_limits_conf), 1322318Smax.romanov@nginx.com &apcf); 1323318Smax.romanov@nginx.com if (ret != NXT_OK) { 1324564Svbart@nginx.com nxt_alert(task, "application limits map error"); 1325318Smax.romanov@nginx.com goto app_fail; 1326318Smax.romanov@nginx.com } 1327318Smax.romanov@nginx.com } 1328318Smax.romanov@nginx.com 1329507Smax.romanov@nginx.com if (apcf.processes_value != NULL 1330507Smax.romanov@nginx.com && nxt_conf_type(apcf.processes_value) == NXT_CONF_OBJECT) 1331507Smax.romanov@nginx.com { 1332507Smax.romanov@nginx.com ret = nxt_conf_map_object(mp, apcf.processes_value, 1333507Smax.romanov@nginx.com nxt_router_app_processes_conf, 1334507Smax.romanov@nginx.com nxt_nitems(nxt_router_app_processes_conf), 1335507Smax.romanov@nginx.com &apcf); 1336507Smax.romanov@nginx.com if (ret != NXT_OK) { 1337564Svbart@nginx.com nxt_alert(task, "application processes map error"); 1338507Smax.romanov@nginx.com goto app_fail; 1339507Smax.romanov@nginx.com } 1340507Smax.romanov@nginx.com 1341507Smax.romanov@nginx.com } else { 1342507Smax.romanov@nginx.com apcf.max_processes = apcf.processes; 1343507Smax.romanov@nginx.com apcf.spare_processes = apcf.processes; 1344507Smax.romanov@nginx.com } 1345507Smax.romanov@nginx.com 1346133Sigor@sysoev.ru nxt_debug(task, "application type: %V", &apcf.type); 1347507Smax.romanov@nginx.com nxt_debug(task, "application processes: %D", apcf.processes); 1348507Smax.romanov@nginx.com nxt_debug(task, "application request timeout: %M", apcf.timeout); 1349507Smax.romanov@nginx.com nxt_debug(task, "application reschedule timeout: %M", apcf.res_timeout); 1350318Smax.romanov@nginx.com nxt_debug(task, "application requests: %D", apcf.requests); 1351133Sigor@sysoev.ru 1352216Sigor@sysoev.ru lang = nxt_app_lang_module(task->thread->runtime, &apcf.type); 1353216Sigor@sysoev.ru 1354216Sigor@sysoev.ru if (lang == NULL) { 1355564Svbart@nginx.com nxt_alert(task, "unknown application type: \"%V\"", &apcf.type); 1356141Smax.romanov@nginx.com goto app_fail; 1357141Smax.romanov@nginx.com } 1358141Smax.romanov@nginx.com 1359216Sigor@sysoev.ru nxt_debug(task, "application language module: \"%s\"", lang->file); 1360216Sigor@sysoev.ru 1361133Sigor@sysoev.ru ret = nxt_thread_mutex_create(&app->mutex); 1362133Sigor@sysoev.ru if (ret != NXT_OK) { 1363133Sigor@sysoev.ru goto app_fail; 1364133Sigor@sysoev.ru } 1365133Sigor@sysoev.ru 1366141Smax.romanov@nginx.com nxt_queue_init(&app->ports); 1367507Smax.romanov@nginx.com nxt_queue_init(&app->spare_ports); 1368507Smax.romanov@nginx.com nxt_queue_init(&app->idle_ports); 1369141Smax.romanov@nginx.com nxt_queue_init(&app->requests); 1370427Smax.romanov@nginx.com nxt_queue_init(&app->pending); 1371141Smax.romanov@nginx.com 1372144Smax.romanov@nginx.com app->name.length = name.length; 1373144Smax.romanov@nginx.com nxt_memcpy(app->name.start, name.start, name.length); 1374144Smax.romanov@nginx.com 1375356Svbart@nginx.com app->type = lang->type; 1376507Smax.romanov@nginx.com app->max_processes = apcf.max_processes; 1377507Smax.romanov@nginx.com app->spare_processes = apcf.spare_processes; 1378507Smax.romanov@nginx.com app->max_pending_processes = apcf.spare_processes 1379507Smax.romanov@nginx.com ? apcf.spare_processes : 1; 1380318Smax.romanov@nginx.com app->timeout = apcf.timeout; 1381427Smax.romanov@nginx.com app->res_timeout = apcf.res_timeout * 1000000; 1382507Smax.romanov@nginx.com app->idle_timeout = apcf.idle_timeout; 1383133Sigor@sysoev.ru app->live = 1; 1384343Smax.romanov@nginx.com app->max_pending_responses = 2; 1385428Smax.romanov@nginx.com app->max_requests = apcf.requests; 1386356Svbart@nginx.com app->prepare_msg = nxt_app_prepare_msg[lang->type]; 1387133Sigor@sysoev.ru 1388507Smax.romanov@nginx.com engine = task->thread->engine; 1389507Smax.romanov@nginx.com 1390507Smax.romanov@nginx.com app->engine = engine; 1391507Smax.romanov@nginx.com 1392507Smax.romanov@nginx.com app->idle_timer.precision = NXT_TIMER_DEFAULT_PRECISION; 1393507Smax.romanov@nginx.com app->idle_timer.work_queue = &engine->fast_work_queue; 1394507Smax.romanov@nginx.com app->idle_timer.handler = nxt_router_app_idle_timeout; 1395507Smax.romanov@nginx.com app->idle_timer.task = &engine->task; 1396507Smax.romanov@nginx.com app->idle_timer.log = app->idle_timer.task->log; 1397507Smax.romanov@nginx.com 1398507Smax.romanov@nginx.com app->adjust_idle_work.handler = nxt_router_adjust_idle_timer; 1399507Smax.romanov@nginx.com app->adjust_idle_work.task = &engine->task; 1400507Smax.romanov@nginx.com app->adjust_idle_work.obj = app; 1401507Smax.romanov@nginx.com 1402133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->apps, &app->link); 1403343Smax.romanov@nginx.com 1404343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 1405133Sigor@sysoev.ru } 1406133Sigor@sysoev.ru 1407133Sigor@sysoev.ru http = nxt_conf_get_path(conf, &http_path); 1408133Sigor@sysoev.ru #if 0 1409133Sigor@sysoev.ru if (http == NULL) { 1410564Svbart@nginx.com nxt_alert(task, "no \"http\" block"); 1411133Sigor@sysoev.ru return NXT_ERROR; 1412133Sigor@sysoev.ru } 1413133Sigor@sysoev.ru #endif 1414133Sigor@sysoev.ru 1415133Sigor@sysoev.ru listeners = nxt_conf_get_path(conf, &listeners_path); 1416115Sigor@sysoev.ru if (listeners == NULL) { 1417564Svbart@nginx.com nxt_alert(task, "no \"listeners\" block"); 1418115Sigor@sysoev.ru return NXT_ERROR; 1419115Sigor@sysoev.ru } 142053Sigor@sysoev.ru 1421133Sigor@sysoev.ru next = 0; 142253Sigor@sysoev.ru 1423115Sigor@sysoev.ru for ( ;; ) { 1424115Sigor@sysoev.ru listener = nxt_conf_next_object_member(listeners, &name, &next); 1425115Sigor@sysoev.ru if (listener == NULL) { 1426115Sigor@sysoev.ru break; 1427115Sigor@sysoev.ru } 142853Sigor@sysoev.ru 1429359Sigor@sysoev.ru skcf = nxt_router_socket_conf(task, tmcf, &name); 1430115Sigor@sysoev.ru if (skcf == NULL) { 1431133Sigor@sysoev.ru goto fail; 1432115Sigor@sysoev.ru } 143353Sigor@sysoev.ru 1434213Svbart@nginx.com ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf, 1435136Svbart@nginx.com nxt_nitems(nxt_router_listener_conf), &lscf); 1436115Sigor@sysoev.ru if (ret != NXT_OK) { 1437564Svbart@nginx.com nxt_alert(task, "listener map error"); 1438133Sigor@sysoev.ru goto fail; 1439115Sigor@sysoev.ru } 144053Sigor@sysoev.ru 1441133Sigor@sysoev.ru nxt_debug(task, "application: %V", &lscf.application); 1442133Sigor@sysoev.ru 1443133Sigor@sysoev.ru // STUB, default values if http block is not defined. 1444133Sigor@sysoev.ru skcf->header_buffer_size = 2048; 1445133Sigor@sysoev.ru skcf->large_header_buffer_size = 8192; 1446206Smax.romanov@nginx.com skcf->large_header_buffers = 4; 1447206Smax.romanov@nginx.com skcf->body_buffer_size = 16 * 1024; 1448206Smax.romanov@nginx.com skcf->max_body_size = 2 * 1024 * 1024; 1449431Sigor@sysoev.ru skcf->idle_timeout = 65000; 1450133Sigor@sysoev.ru skcf->header_read_timeout = 5000; 1451206Smax.romanov@nginx.com skcf->body_read_timeout = 5000; 1452431Sigor@sysoev.ru skcf->send_timeout = 5000; 145353Sigor@sysoev.ru 1454133Sigor@sysoev.ru if (http != NULL) { 1455213Svbart@nginx.com ret = nxt_conf_map_object(mp, http, nxt_router_http_conf, 1456136Svbart@nginx.com nxt_nitems(nxt_router_http_conf), skcf); 1457133Sigor@sysoev.ru if (ret != NXT_OK) { 1458564Svbart@nginx.com nxt_alert(task, "http map error"); 1459133Sigor@sysoev.ru goto fail; 1460133Sigor@sysoev.ru } 1461115Sigor@sysoev.ru } 1462115Sigor@sysoev.ru 1463431Sigor@sysoev.ru skcf->listen->handler = nxt_http_conn_init; 1464591Sigor@sysoev.ru skcf->router_conf = tmcf->router_conf; 1465160Sigor@sysoev.ru skcf->router_conf->count++; 1466133Sigor@sysoev.ru skcf->application = nxt_router_listener_application(tmcf, 1467133Sigor@sysoev.ru &lscf.application); 1468567Smax.romanov@nginx.com nxt_router_app_use(task, skcf->application, 1); 1469115Sigor@sysoev.ru } 147053Sigor@sysoev.ru 1471359Sigor@sysoev.ru nxt_queue_add(&tmcf->deleting, &router->sockets); 1472359Sigor@sysoev.ru nxt_queue_init(&router->sockets); 1473198Sigor@sysoev.ru 147453Sigor@sysoev.ru return NXT_OK; 1475133Sigor@sysoev.ru 1476133Sigor@sysoev.ru app_fail: 1477133Sigor@sysoev.ru 1478133Sigor@sysoev.ru nxt_free(app); 1479133Sigor@sysoev.ru 1480133Sigor@sysoev.ru fail: 1481133Sigor@sysoev.ru 1482141Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1483141Smax.romanov@nginx.com 1484141Smax.romanov@nginx.com nxt_queue_remove(&app->link); 1485133Sigor@sysoev.ru nxt_thread_mutex_destroy(&app->mutex); 1486133Sigor@sysoev.ru nxt_free(app); 1487141Smax.romanov@nginx.com 1488141Smax.romanov@nginx.com } nxt_queue_loop; 1489133Sigor@sysoev.ru 1490133Sigor@sysoev.ru return NXT_ERROR; 1491133Sigor@sysoev.ru } 1492133Sigor@sysoev.ru 1493133Sigor@sysoev.ru 1494133Sigor@sysoev.ru static nxt_app_t * 1495133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name) 1496133Sigor@sysoev.ru { 1497141Smax.romanov@nginx.com nxt_app_t *app; 1498141Smax.romanov@nginx.com 1499141Smax.romanov@nginx.com nxt_queue_each(app, queue, nxt_app_t, link) { 1500133Sigor@sysoev.ru 1501133Sigor@sysoev.ru if (nxt_strstr_eq(name, &app->name)) { 1502133Sigor@sysoev.ru return app; 1503133Sigor@sysoev.ru } 1504141Smax.romanov@nginx.com 1505141Smax.romanov@nginx.com } nxt_queue_loop; 1506133Sigor@sysoev.ru 1507133Sigor@sysoev.ru return NULL; 1508133Sigor@sysoev.ru } 1509133Sigor@sysoev.ru 1510133Sigor@sysoev.ru 1511133Sigor@sysoev.ru static nxt_app_t * 1512133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name) 1513133Sigor@sysoev.ru { 1514133Sigor@sysoev.ru nxt_app_t *app; 1515133Sigor@sysoev.ru 1516133Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->apps, name); 1517133Sigor@sysoev.ru 1518133Sigor@sysoev.ru if (app == NULL) { 1519134Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->previous, name); 1520133Sigor@sysoev.ru } 1521133Sigor@sysoev.ru 1522133Sigor@sysoev.ru return app; 152353Sigor@sysoev.ru } 152453Sigor@sysoev.ru 152553Sigor@sysoev.ru 152653Sigor@sysoev.ru static nxt_socket_conf_t * 1527359Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1528359Sigor@sysoev.ru nxt_str_t *name) 152953Sigor@sysoev.ru { 1530359Sigor@sysoev.ru size_t size; 1531359Sigor@sysoev.ru nxt_int_t ret; 1532359Sigor@sysoev.ru nxt_bool_t wildcard; 1533359Sigor@sysoev.ru nxt_sockaddr_t *sa; 1534359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1535359Sigor@sysoev.ru nxt_listen_socket_t *ls; 1536359Sigor@sysoev.ru 1537359Sigor@sysoev.ru sa = nxt_sockaddr_parse(tmcf->mem_pool, name); 1538359Sigor@sysoev.ru if (nxt_slow_path(sa == NULL)) { 1539564Svbart@nginx.com nxt_alert(task, "invalid listener \"%V\"", name); 1540359Sigor@sysoev.ru return NULL; 1541359Sigor@sysoev.ru } 1542359Sigor@sysoev.ru 1543359Sigor@sysoev.ru sa->type = SOCK_STREAM; 1544359Sigor@sysoev.ru 1545359Sigor@sysoev.ru nxt_debug(task, "router listener: \"%*s\"", 1546493Spluknet@nginx.com (size_t) sa->length, nxt_sockaddr_start(sa)); 1547359Sigor@sysoev.ru 1548591Sigor@sysoev.ru skcf = nxt_mp_zget(tmcf->router_conf->mem_pool, sizeof(nxt_socket_conf_t)); 1549163Smax.romanov@nginx.com if (nxt_slow_path(skcf == NULL)) { 155053Sigor@sysoev.ru return NULL; 155153Sigor@sysoev.ru } 155253Sigor@sysoev.ru 1553359Sigor@sysoev.ru size = nxt_sockaddr_size(sa); 1554359Sigor@sysoev.ru 1555359Sigor@sysoev.ru ret = nxt_router_listen_socket_find(tmcf, skcf, sa); 1556359Sigor@sysoev.ru 1557359Sigor@sysoev.ru if (ret != NXT_OK) { 1558359Sigor@sysoev.ru 1559359Sigor@sysoev.ru ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size); 1560359Sigor@sysoev.ru if (nxt_slow_path(ls == NULL)) { 1561359Sigor@sysoev.ru return NULL; 1562359Sigor@sysoev.ru } 1563359Sigor@sysoev.ru 1564359Sigor@sysoev.ru skcf->listen = ls; 1565359Sigor@sysoev.ru 1566359Sigor@sysoev.ru ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t)); 1567359Sigor@sysoev.ru nxt_memcpy(ls->sockaddr, sa, size); 1568359Sigor@sysoev.ru 1569359Sigor@sysoev.ru nxt_listen_socket_remote_size(ls); 1570359Sigor@sysoev.ru 1571359Sigor@sysoev.ru ls->socket = -1; 1572359Sigor@sysoev.ru ls->backlog = NXT_LISTEN_BACKLOG; 1573359Sigor@sysoev.ru ls->flags = NXT_NONBLOCK; 1574359Sigor@sysoev.ru ls->read_after_accept = 1; 1575359Sigor@sysoev.ru } 1576359Sigor@sysoev.ru 1577359Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) { 1578359Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 1579359Sigor@sysoev.ru case AF_UNIX: 1580359Sigor@sysoev.ru wildcard = 0; 1581359Sigor@sysoev.ru break; 1582359Sigor@sysoev.ru #endif 1583359Sigor@sysoev.ru #if (NXT_INET6) 1584359Sigor@sysoev.ru case AF_INET6: 1585359Sigor@sysoev.ru wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr); 1586359Sigor@sysoev.ru break; 1587359Sigor@sysoev.ru #endif 1588359Sigor@sysoev.ru case AF_INET: 1589359Sigor@sysoev.ru default: 1590359Sigor@sysoev.ru wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY); 1591359Sigor@sysoev.ru break; 1592359Sigor@sysoev.ru } 1593359Sigor@sysoev.ru 1594359Sigor@sysoev.ru if (!wildcard) { 1595591Sigor@sysoev.ru skcf->sockaddr = nxt_mp_zget(tmcf->router_conf->mem_pool, size); 1596359Sigor@sysoev.ru if (nxt_slow_path(skcf->sockaddr == NULL)) { 1597359Sigor@sysoev.ru return NULL; 1598359Sigor@sysoev.ru } 1599359Sigor@sysoev.ru 1600359Sigor@sysoev.ru nxt_memcpy(skcf->sockaddr, sa, size); 1601359Sigor@sysoev.ru } 1602163Smax.romanov@nginx.com 1603163Smax.romanov@nginx.com return skcf; 160453Sigor@sysoev.ru } 160553Sigor@sysoev.ru 160653Sigor@sysoev.ru 1607359Sigor@sysoev.ru static nxt_int_t 1608359Sigor@sysoev.ru nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, 1609359Sigor@sysoev.ru nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa) 161053Sigor@sysoev.ru { 1611359Sigor@sysoev.ru nxt_router_t *router; 1612359Sigor@sysoev.ru nxt_queue_link_t *qlk; 1613359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1614359Sigor@sysoev.ru 1615591Sigor@sysoev.ru router = tmcf->router_conf->router; 1616359Sigor@sysoev.ru 1617359Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->sockets); 1618359Sigor@sysoev.ru qlk != nxt_queue_tail(&router->sockets); 1619359Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 162053Sigor@sysoev.ru { 1621359Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1622359Sigor@sysoev.ru 1623359Sigor@sysoev.ru if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) { 1624359Sigor@sysoev.ru nskcf->listen = skcf->listen; 1625359Sigor@sysoev.ru 1626359Sigor@sysoev.ru nxt_queue_remove(qlk); 1627359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->keeping, qlk); 1628359Sigor@sysoev.ru 1629359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->updating, &nskcf->link); 1630359Sigor@sysoev.ru 1631359Sigor@sysoev.ru return NXT_OK; 163253Sigor@sysoev.ru } 163353Sigor@sysoev.ru } 163453Sigor@sysoev.ru 1635359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->pending, &nskcf->link); 1636359Sigor@sysoev.ru 1637359Sigor@sysoev.ru return NXT_DECLINED; 163853Sigor@sysoev.ru } 163953Sigor@sysoev.ru 164053Sigor@sysoev.ru 1641198Sigor@sysoev.ru static void 1642198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task, 1643198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf) 1644198Sigor@sysoev.ru { 1645358Sigor@sysoev.ru size_t size; 1646198Sigor@sysoev.ru uint32_t stream; 1647198Sigor@sysoev.ru nxt_buf_t *b; 1648198Sigor@sysoev.ru nxt_port_t *main_port, *router_port; 1649198Sigor@sysoev.ru nxt_runtime_t *rt; 1650198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 1651198Sigor@sysoev.ru 1652198Sigor@sysoev.ru rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t)); 1653198Sigor@sysoev.ru if (rpc == NULL) { 1654198Sigor@sysoev.ru goto fail; 1655198Sigor@sysoev.ru } 1656198Sigor@sysoev.ru 1657198Sigor@sysoev.ru rpc->socket_conf = skcf; 1658198Sigor@sysoev.ru rpc->temp_conf = tmcf; 1659198Sigor@sysoev.ru 1660359Sigor@sysoev.ru size = nxt_sockaddr_size(skcf->listen->sockaddr); 1661358Sigor@sysoev.ru 1662358Sigor@sysoev.ru b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 1663198Sigor@sysoev.ru if (b == NULL) { 1664198Sigor@sysoev.ru goto fail; 1665198Sigor@sysoev.ru } 1666198Sigor@sysoev.ru 1667359Sigor@sysoev.ru b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size); 1668198Sigor@sysoev.ru 1669198Sigor@sysoev.ru rt = task->thread->runtime; 1670240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1671198Sigor@sysoev.ru router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 1672198Sigor@sysoev.ru 1673198Sigor@sysoev.ru stream = nxt_port_rpc_register_handler(task, router_port, 1674198Sigor@sysoev.ru nxt_router_listen_socket_ready, 1675198Sigor@sysoev.ru nxt_router_listen_socket_error, 1676198Sigor@sysoev.ru main_port->pid, rpc); 1677198Sigor@sysoev.ru if (stream == 0) { 1678198Sigor@sysoev.ru goto fail; 1679198Sigor@sysoev.ru } 1680198Sigor@sysoev.ru 1681198Sigor@sysoev.ru nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1, 1682198Sigor@sysoev.ru stream, router_port->id, b); 1683198Sigor@sysoev.ru 1684198Sigor@sysoev.ru return; 1685198Sigor@sysoev.ru 1686198Sigor@sysoev.ru fail: 1687198Sigor@sysoev.ru 1688198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 1689198Sigor@sysoev.ru } 1690198Sigor@sysoev.ru 1691198Sigor@sysoev.ru 1692198Sigor@sysoev.ru static void 1693198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1694198Sigor@sysoev.ru void *data) 169553Sigor@sysoev.ru { 1696359Sigor@sysoev.ru nxt_int_t ret; 1697359Sigor@sysoev.ru nxt_socket_t s; 1698359Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 169953Sigor@sysoev.ru 1700198Sigor@sysoev.ru rpc = data; 1701198Sigor@sysoev.ru 1702198Sigor@sysoev.ru s = msg->fd; 1703198Sigor@sysoev.ru 1704198Sigor@sysoev.ru ret = nxt_socket_nonblocking(task, s); 1705198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1706198Sigor@sysoev.ru goto fail; 170753Sigor@sysoev.ru } 170853Sigor@sysoev.ru 1709359Sigor@sysoev.ru nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr); 1710198Sigor@sysoev.ru 1711198Sigor@sysoev.ru ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG); 1712198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1713198Sigor@sysoev.ru goto fail; 1714198Sigor@sysoev.ru } 1715198Sigor@sysoev.ru 1716359Sigor@sysoev.ru rpc->socket_conf->listen->socket = s; 1717198Sigor@sysoev.ru 1718198Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 1719198Sigor@sysoev.ru nxt_router_conf_apply, task, rpc->temp_conf, NULL); 1720198Sigor@sysoev.ru 1721198Sigor@sysoev.ru return; 1722148Sigor@sysoev.ru 1723148Sigor@sysoev.ru fail: 1724148Sigor@sysoev.ru 1725148Sigor@sysoev.ru nxt_socket_close(task, s); 1726148Sigor@sysoev.ru 1727198Sigor@sysoev.ru nxt_router_conf_error(task, rpc->temp_conf); 1728198Sigor@sysoev.ru } 1729198Sigor@sysoev.ru 1730198Sigor@sysoev.ru 1731198Sigor@sysoev.ru static void 1732198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1733198Sigor@sysoev.ru void *data) 1734198Sigor@sysoev.ru { 1735198Sigor@sysoev.ru u_char *p; 1736198Sigor@sysoev.ru size_t size; 1737198Sigor@sysoev.ru uint8_t error; 1738198Sigor@sysoev.ru nxt_buf_t *in, *out; 1739198Sigor@sysoev.ru nxt_sockaddr_t *sa; 1740198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 1741198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 1742198Sigor@sysoev.ru 1743198Sigor@sysoev.ru static nxt_str_t socket_errors[] = { 1744198Sigor@sysoev.ru nxt_string("ListenerSystem"), 1745198Sigor@sysoev.ru nxt_string("ListenerNoIPv6"), 1746198Sigor@sysoev.ru nxt_string("ListenerPort"), 1747198Sigor@sysoev.ru nxt_string("ListenerInUse"), 1748198Sigor@sysoev.ru nxt_string("ListenerNoAddress"), 1749198Sigor@sysoev.ru nxt_string("ListenerNoAccess"), 1750198Sigor@sysoev.ru nxt_string("ListenerPath"), 1751198Sigor@sysoev.ru }; 1752198Sigor@sysoev.ru 1753198Sigor@sysoev.ru rpc = data; 1754359Sigor@sysoev.ru sa = rpc->socket_conf->listen->sockaddr; 1755352Smax.romanov@nginx.com tmcf = rpc->temp_conf; 1756352Smax.romanov@nginx.com 1757352Smax.romanov@nginx.com in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size); 1758352Smax.romanov@nginx.com 1759551Smax.romanov@nginx.com if (nxt_slow_path(in == NULL)) { 1760551Smax.romanov@nginx.com return; 1761551Smax.romanov@nginx.com } 1762352Smax.romanov@nginx.com 1763198Sigor@sysoev.ru p = in->mem.pos; 1764198Sigor@sysoev.ru 1765198Sigor@sysoev.ru error = *p++; 1766198Sigor@sysoev.ru 1767198Sigor@sysoev.ru size = sizeof("listen socket error: ") - 1 1768198Sigor@sysoev.ru + sizeof("{listener: \"\", code:\"\", message: \"\"}") - 1 1769198Sigor@sysoev.ru + sa->length + socket_errors[error].length + (in->mem.free - p); 1770198Sigor@sysoev.ru 1771198Sigor@sysoev.ru out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 1772198Sigor@sysoev.ru if (nxt_slow_path(out == NULL)) { 1773198Sigor@sysoev.ru return; 1774198Sigor@sysoev.ru } 1775198Sigor@sysoev.ru 1776198Sigor@sysoev.ru out->mem.free = nxt_sprintf(out->mem.free, out->mem.end, 1777198Sigor@sysoev.ru "listen socket error: " 1778198Sigor@sysoev.ru "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}", 1779493Spluknet@nginx.com (size_t) sa->length, nxt_sockaddr_start(sa), 1780198Sigor@sysoev.ru &socket_errors[error], in->mem.free - p, p); 1781198Sigor@sysoev.ru 1782198Sigor@sysoev.ru nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos); 1783198Sigor@sysoev.ru 1784198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 178553Sigor@sysoev.ru } 178653Sigor@sysoev.ru 178753Sigor@sysoev.ru 1788507Smax.romanov@nginx.com static void 1789507Smax.romanov@nginx.com nxt_router_app_rpc_create(nxt_task_t *task, 1790507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_app_t *app) 1791507Smax.romanov@nginx.com { 1792507Smax.romanov@nginx.com size_t size; 1793507Smax.romanov@nginx.com uint32_t stream; 1794507Smax.romanov@nginx.com nxt_buf_t *b; 1795507Smax.romanov@nginx.com nxt_port_t *main_port, *router_port; 1796507Smax.romanov@nginx.com nxt_runtime_t *rt; 1797507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 1798507Smax.romanov@nginx.com 1799507Smax.romanov@nginx.com rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_app_rpc_t)); 1800507Smax.romanov@nginx.com if (rpc == NULL) { 1801507Smax.romanov@nginx.com goto fail; 1802507Smax.romanov@nginx.com } 1803507Smax.romanov@nginx.com 1804507Smax.romanov@nginx.com rpc->app = app; 1805507Smax.romanov@nginx.com rpc->temp_conf = tmcf; 1806507Smax.romanov@nginx.com 1807507Smax.romanov@nginx.com nxt_debug(task, "app '%V' prefork", &app->name); 1808507Smax.romanov@nginx.com 1809507Smax.romanov@nginx.com size = app->name.length + 1 + app->conf.length; 1810507Smax.romanov@nginx.com 1811507Smax.romanov@nginx.com b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 1812507Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 1813507Smax.romanov@nginx.com goto fail; 1814507Smax.romanov@nginx.com } 1815507Smax.romanov@nginx.com 1816507Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->name); 1817507Smax.romanov@nginx.com *b->mem.free++ = '\0'; 1818507Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 1819507Smax.romanov@nginx.com 1820507Smax.romanov@nginx.com rt = task->thread->runtime; 1821507Smax.romanov@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1822507Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 1823507Smax.romanov@nginx.com 1824507Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 1825507Smax.romanov@nginx.com nxt_router_app_prefork_ready, 1826507Smax.romanov@nginx.com nxt_router_app_prefork_error, 1827507Smax.romanov@nginx.com -1, rpc); 1828507Smax.romanov@nginx.com if (nxt_slow_path(stream == 0)) { 1829507Smax.romanov@nginx.com goto fail; 1830507Smax.romanov@nginx.com } 1831507Smax.romanov@nginx.com 1832507Smax.romanov@nginx.com app->pending_processes++; 1833507Smax.romanov@nginx.com 1834507Smax.romanov@nginx.com nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1, 1835507Smax.romanov@nginx.com stream, router_port->id, b); 1836507Smax.romanov@nginx.com 1837507Smax.romanov@nginx.com return; 1838507Smax.romanov@nginx.com 1839507Smax.romanov@nginx.com fail: 1840507Smax.romanov@nginx.com 1841507Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 1842507Smax.romanov@nginx.com } 1843507Smax.romanov@nginx.com 1844507Smax.romanov@nginx.com 1845507Smax.romanov@nginx.com static void 1846507Smax.romanov@nginx.com nxt_router_app_prefork_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1847507Smax.romanov@nginx.com void *data) 1848507Smax.romanov@nginx.com { 1849507Smax.romanov@nginx.com nxt_app_t *app; 1850507Smax.romanov@nginx.com nxt_port_t *port; 1851507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 1852507Smax.romanov@nginx.com nxt_event_engine_t *engine; 1853507Smax.romanov@nginx.com 1854507Smax.romanov@nginx.com rpc = data; 1855507Smax.romanov@nginx.com app = rpc->app; 1856507Smax.romanov@nginx.com 1857507Smax.romanov@nginx.com port = msg->u.new_port; 1858507Smax.romanov@nginx.com port->app = app; 1859507Smax.romanov@nginx.com 1860507Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 1861507Smax.romanov@nginx.com 1862507Smax.romanov@nginx.com app->pending_processes--; 1863507Smax.romanov@nginx.com app->processes++; 1864507Smax.romanov@nginx.com app->idle_processes++; 1865507Smax.romanov@nginx.com 1866507Smax.romanov@nginx.com engine = task->thread->engine; 1867507Smax.romanov@nginx.com 1868507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &port->app_link); 1869507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, &port->idle_link); 1870507Smax.romanov@nginx.com 1871507Smax.romanov@nginx.com port->idle_start = 0; 1872507Smax.romanov@nginx.com 1873507Smax.romanov@nginx.com nxt_port_inc_use(port); 1874507Smax.romanov@nginx.com 1875507Smax.romanov@nginx.com nxt_work_queue_add(&engine->fast_work_queue, 1876507Smax.romanov@nginx.com nxt_router_conf_apply, task, rpc->temp_conf, NULL); 1877507Smax.romanov@nginx.com } 1878507Smax.romanov@nginx.com 1879507Smax.romanov@nginx.com 1880507Smax.romanov@nginx.com static void 1881507Smax.romanov@nginx.com nxt_router_app_prefork_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1882507Smax.romanov@nginx.com void *data) 1883507Smax.romanov@nginx.com { 1884507Smax.romanov@nginx.com nxt_app_t *app; 1885507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 1886507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf; 1887507Smax.romanov@nginx.com 1888507Smax.romanov@nginx.com rpc = data; 1889507Smax.romanov@nginx.com app = rpc->app; 1890507Smax.romanov@nginx.com tmcf = rpc->temp_conf; 1891507Smax.romanov@nginx.com 1892507Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, "failed to start application \"%V\"", 1893507Smax.romanov@nginx.com &app->name); 1894507Smax.romanov@nginx.com 1895507Smax.romanov@nginx.com app->pending_processes--; 1896507Smax.romanov@nginx.com 1897507Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 1898507Smax.romanov@nginx.com } 1899507Smax.romanov@nginx.com 1900507Smax.romanov@nginx.com 190153Sigor@sysoev.ru static nxt_int_t 190253Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router, 190353Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface) 190453Sigor@sysoev.ru { 190553Sigor@sysoev.ru nxt_int_t ret; 190653Sigor@sysoev.ru nxt_uint_t n, threads; 190753Sigor@sysoev.ru nxt_queue_link_t *qlk; 190853Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 190953Sigor@sysoev.ru 1910591Sigor@sysoev.ru threads = tmcf->router_conf->threads; 191153Sigor@sysoev.ru 191253Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, threads, 191353Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 191453Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 191553Sigor@sysoev.ru return NXT_ERROR; 191653Sigor@sysoev.ru } 191753Sigor@sysoev.ru 191853Sigor@sysoev.ru n = 0; 191953Sigor@sysoev.ru 192053Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->engines); 192153Sigor@sysoev.ru qlk != nxt_queue_tail(&router->engines); 192253Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 192353Sigor@sysoev.ru { 192453Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 192553Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 192653Sigor@sysoev.ru return NXT_ERROR; 192753Sigor@sysoev.ru } 192853Sigor@sysoev.ru 1929115Sigor@sysoev.ru recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0); 193053Sigor@sysoev.ru 193153Sigor@sysoev.ru if (n < threads) { 1932315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_KEEP; 1933115Sigor@sysoev.ru ret = nxt_router_engine_conf_update(tmcf, recf); 193453Sigor@sysoev.ru 193553Sigor@sysoev.ru } else { 1936315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_DELETE; 1937115Sigor@sysoev.ru ret = nxt_router_engine_conf_delete(tmcf, recf); 193853Sigor@sysoev.ru } 193953Sigor@sysoev.ru 194053Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 194153Sigor@sysoev.ru return ret; 194253Sigor@sysoev.ru } 194353Sigor@sysoev.ru 194453Sigor@sysoev.ru n++; 194553Sigor@sysoev.ru } 194653Sigor@sysoev.ru 194753Sigor@sysoev.ru tmcf->new_threads = n; 194853Sigor@sysoev.ru 194953Sigor@sysoev.ru while (n < threads) { 195053Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 195153Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 195253Sigor@sysoev.ru return NXT_ERROR; 195353Sigor@sysoev.ru } 195453Sigor@sysoev.ru 1955315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_ADD; 1956315Sigor@sysoev.ru 195753Sigor@sysoev.ru recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0); 195853Sigor@sysoev.ru if (nxt_slow_path(recf->engine == NULL)) { 195953Sigor@sysoev.ru return NXT_ERROR; 196053Sigor@sysoev.ru } 196153Sigor@sysoev.ru 1962115Sigor@sysoev.ru ret = nxt_router_engine_conf_create(tmcf, recf); 196353Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 196453Sigor@sysoev.ru return ret; 196553Sigor@sysoev.ru } 196653Sigor@sysoev.ru 196753Sigor@sysoev.ru n++; 196853Sigor@sysoev.ru } 196953Sigor@sysoev.ru 197053Sigor@sysoev.ru return NXT_OK; 197153Sigor@sysoev.ru } 197253Sigor@sysoev.ru 197353Sigor@sysoev.ru 197453Sigor@sysoev.ru static nxt_int_t 1975115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 1976115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 197753Sigor@sysoev.ru { 1978359Sigor@sysoev.ru nxt_int_t ret; 197953Sigor@sysoev.ru 1980154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 1981154Sigor@sysoev.ru nxt_router_listen_socket_create); 1982115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1983115Sigor@sysoev.ru return ret; 1984115Sigor@sysoev.ru } 1985115Sigor@sysoev.ru 1986154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 1987154Sigor@sysoev.ru nxt_router_listen_socket_create); 198853Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 198953Sigor@sysoev.ru return ret; 199053Sigor@sysoev.ru } 199153Sigor@sysoev.ru 1992115Sigor@sysoev.ru return ret; 199353Sigor@sysoev.ru } 199453Sigor@sysoev.ru 199553Sigor@sysoev.ru 199653Sigor@sysoev.ru static nxt_int_t 1997115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 1998115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 199953Sigor@sysoev.ru { 2000359Sigor@sysoev.ru nxt_int_t ret; 200153Sigor@sysoev.ru 2002154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 2003154Sigor@sysoev.ru nxt_router_listen_socket_create); 200453Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 200553Sigor@sysoev.ru return ret; 200653Sigor@sysoev.ru } 200753Sigor@sysoev.ru 2008154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 2009154Sigor@sysoev.ru nxt_router_listen_socket_update); 201053Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 201153Sigor@sysoev.ru return ret; 201253Sigor@sysoev.ru } 201353Sigor@sysoev.ru 2014139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 2015115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2016115Sigor@sysoev.ru return ret; 2017115Sigor@sysoev.ru } 2018115Sigor@sysoev.ru 2019115Sigor@sysoev.ru return ret; 202053Sigor@sysoev.ru } 202153Sigor@sysoev.ru 202253Sigor@sysoev.ru 202353Sigor@sysoev.ru static nxt_int_t 2024115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 2025115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 202653Sigor@sysoev.ru { 202753Sigor@sysoev.ru nxt_int_t ret; 202853Sigor@sysoev.ru 2029313Sigor@sysoev.ru ret = nxt_router_engine_quit(tmcf, recf); 2030313Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2031313Sigor@sysoev.ru return ret; 2032313Sigor@sysoev.ru } 2033313Sigor@sysoev.ru 2034139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating); 203553Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 203653Sigor@sysoev.ru return ret; 203753Sigor@sysoev.ru } 203853Sigor@sysoev.ru 2039139Sigor@sysoev.ru return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 204053Sigor@sysoev.ru } 204153Sigor@sysoev.ru 204253Sigor@sysoev.ru 204353Sigor@sysoev.ru static nxt_int_t 2044154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 2045154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 204653Sigor@sysoev.ru nxt_work_handler_t handler) 204753Sigor@sysoev.ru { 2048153Sigor@sysoev.ru nxt_joint_job_t *job; 204953Sigor@sysoev.ru nxt_queue_link_t *qlk; 2050155Sigor@sysoev.ru nxt_socket_conf_t *skcf; 205153Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 205253Sigor@sysoev.ru 205353Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 205453Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 205553Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 205653Sigor@sysoev.ru { 2057154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2058153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2059139Sigor@sysoev.ru return NXT_ERROR; 2060139Sigor@sysoev.ru } 2061139Sigor@sysoev.ru 2062154Sigor@sysoev.ru job->work.next = recf->jobs; 2063154Sigor@sysoev.ru recf->jobs = &job->work; 2064154Sigor@sysoev.ru 2065153Sigor@sysoev.ru job->task = tmcf->engine->task; 2066153Sigor@sysoev.ru job->work.handler = handler; 2067153Sigor@sysoev.ru job->work.task = &job->task; 2068153Sigor@sysoev.ru job->work.obj = job; 2069153Sigor@sysoev.ru job->tmcf = tmcf; 207053Sigor@sysoev.ru 2071154Sigor@sysoev.ru tmcf->count++; 2072154Sigor@sysoev.ru 2073591Sigor@sysoev.ru joint = nxt_mp_alloc(tmcf->router_conf->mem_pool, 2074154Sigor@sysoev.ru sizeof(nxt_socket_conf_joint_t)); 207553Sigor@sysoev.ru if (nxt_slow_path(joint == NULL)) { 207653Sigor@sysoev.ru return NXT_ERROR; 207753Sigor@sysoev.ru } 207853Sigor@sysoev.ru 2079153Sigor@sysoev.ru job->work.data = joint; 208053Sigor@sysoev.ru 208153Sigor@sysoev.ru joint->count = 1; 2082155Sigor@sysoev.ru 2083155Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 2084155Sigor@sysoev.ru skcf->count++; 2085155Sigor@sysoev.ru joint->socket_conf = skcf; 2086155Sigor@sysoev.ru 208788Smax.romanov@nginx.com joint->engine = recf->engine; 208853Sigor@sysoev.ru } 208953Sigor@sysoev.ru 209020Sigor@sysoev.ru return NXT_OK; 209120Sigor@sysoev.ru } 209220Sigor@sysoev.ru 209320Sigor@sysoev.ru 209420Sigor@sysoev.ru static nxt_int_t 2095313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 2096313Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 2097313Sigor@sysoev.ru { 2098313Sigor@sysoev.ru nxt_joint_job_t *job; 2099313Sigor@sysoev.ru 2100313Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2101313Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2102313Sigor@sysoev.ru return NXT_ERROR; 2103313Sigor@sysoev.ru } 2104313Sigor@sysoev.ru 2105313Sigor@sysoev.ru job->work.next = recf->jobs; 2106313Sigor@sysoev.ru recf->jobs = &job->work; 2107313Sigor@sysoev.ru 2108313Sigor@sysoev.ru job->task = tmcf->engine->task; 2109313Sigor@sysoev.ru job->work.handler = nxt_router_worker_thread_quit; 2110313Sigor@sysoev.ru job->work.task = &job->task; 2111313Sigor@sysoev.ru job->work.obj = NULL; 2112313Sigor@sysoev.ru job->work.data = NULL; 2113313Sigor@sysoev.ru job->tmcf = NULL; 2114313Sigor@sysoev.ru 2115313Sigor@sysoev.ru return NXT_OK; 2116313Sigor@sysoev.ru } 2117313Sigor@sysoev.ru 2118313Sigor@sysoev.ru 2119313Sigor@sysoev.ru static nxt_int_t 2120139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 2121139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets) 212220Sigor@sysoev.ru { 2123153Sigor@sysoev.ru nxt_joint_job_t *job; 212453Sigor@sysoev.ru nxt_queue_link_t *qlk; 212520Sigor@sysoev.ru 212653Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 212753Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 212853Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 212953Sigor@sysoev.ru { 2130154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2131153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2132139Sigor@sysoev.ru return NXT_ERROR; 2133139Sigor@sysoev.ru } 2134139Sigor@sysoev.ru 2135154Sigor@sysoev.ru job->work.next = recf->jobs; 2136154Sigor@sysoev.ru recf->jobs = &job->work; 2137154Sigor@sysoev.ru 2138153Sigor@sysoev.ru job->task = tmcf->engine->task; 2139153Sigor@sysoev.ru job->work.handler = nxt_router_listen_socket_delete; 2140153Sigor@sysoev.ru job->work.task = &job->task; 2141153Sigor@sysoev.ru job->work.obj = job; 2142153Sigor@sysoev.ru job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 2143153Sigor@sysoev.ru job->tmcf = tmcf; 2144154Sigor@sysoev.ru 2145154Sigor@sysoev.ru tmcf->count++; 214620Sigor@sysoev.ru } 214720Sigor@sysoev.ru 214853Sigor@sysoev.ru return NXT_OK; 214953Sigor@sysoev.ru } 215020Sigor@sysoev.ru 215120Sigor@sysoev.ru 215253Sigor@sysoev.ru static nxt_int_t 215353Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 215453Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 215553Sigor@sysoev.ru { 215653Sigor@sysoev.ru nxt_int_t ret; 215753Sigor@sysoev.ru nxt_uint_t i, threads; 215853Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 215920Sigor@sysoev.ru 216053Sigor@sysoev.ru recf = tmcf->engines->elts; 2161591Sigor@sysoev.ru threads = tmcf->router_conf->threads; 216220Sigor@sysoev.ru 216353Sigor@sysoev.ru for (i = tmcf->new_threads; i < threads; i++) { 216453Sigor@sysoev.ru ret = nxt_router_thread_create(task, rt, recf[i].engine); 216553Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 216653Sigor@sysoev.ru return ret; 216753Sigor@sysoev.ru } 216820Sigor@sysoev.ru } 216920Sigor@sysoev.ru 217020Sigor@sysoev.ru return NXT_OK; 217120Sigor@sysoev.ru } 217253Sigor@sysoev.ru 217353Sigor@sysoev.ru 217453Sigor@sysoev.ru static nxt_int_t 217553Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 217653Sigor@sysoev.ru nxt_event_engine_t *engine) 217753Sigor@sysoev.ru { 217853Sigor@sysoev.ru nxt_int_t ret; 217953Sigor@sysoev.ru nxt_thread_link_t *link; 218053Sigor@sysoev.ru nxt_thread_handle_t handle; 218153Sigor@sysoev.ru 218253Sigor@sysoev.ru link = nxt_zalloc(sizeof(nxt_thread_link_t)); 218353Sigor@sysoev.ru 218453Sigor@sysoev.ru if (nxt_slow_path(link == NULL)) { 218553Sigor@sysoev.ru return NXT_ERROR; 218653Sigor@sysoev.ru } 218753Sigor@sysoev.ru 218853Sigor@sysoev.ru link->start = nxt_router_thread_start; 218953Sigor@sysoev.ru link->engine = engine; 219053Sigor@sysoev.ru link->work.handler = nxt_router_thread_exit_handler; 219153Sigor@sysoev.ru link->work.task = task; 219253Sigor@sysoev.ru link->work.data = link; 219353Sigor@sysoev.ru 219453Sigor@sysoev.ru nxt_queue_insert_tail(&rt->engines, &engine->link); 219553Sigor@sysoev.ru 219653Sigor@sysoev.ru ret = nxt_thread_create(&handle, link); 219753Sigor@sysoev.ru 219853Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 219953Sigor@sysoev.ru nxt_queue_remove(&engine->link); 220053Sigor@sysoev.ru } 220153Sigor@sysoev.ru 220253Sigor@sysoev.ru return ret; 220353Sigor@sysoev.ru } 220453Sigor@sysoev.ru 220553Sigor@sysoev.ru 220653Sigor@sysoev.ru static void 2207343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 2208343Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf) 2209133Sigor@sysoev.ru { 2210507Smax.romanov@nginx.com nxt_app_t *app; 2211141Smax.romanov@nginx.com 2212141Smax.romanov@nginx.com nxt_queue_each(app, &router->apps, nxt_app_t, link) { 2213133Sigor@sysoev.ru 2214507Smax.romanov@nginx.com nxt_router_app_quit(task, app); 2215343Smax.romanov@nginx.com 2216141Smax.romanov@nginx.com } nxt_queue_loop; 2217133Sigor@sysoev.ru 2218133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->previous); 2219133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->apps); 2220133Sigor@sysoev.ru } 2221133Sigor@sysoev.ru 2222133Sigor@sysoev.ru 2223133Sigor@sysoev.ru static void 2224315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf) 222553Sigor@sysoev.ru { 222653Sigor@sysoev.ru nxt_uint_t n; 2227315Sigor@sysoev.ru nxt_event_engine_t *engine; 222853Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 222953Sigor@sysoev.ru 223053Sigor@sysoev.ru recf = tmcf->engines->elts; 223153Sigor@sysoev.ru 223253Sigor@sysoev.ru for (n = tmcf->engines->nelts; n != 0; n--) { 2233315Sigor@sysoev.ru engine = recf->engine; 2234315Sigor@sysoev.ru 2235315Sigor@sysoev.ru switch (recf->action) { 2236315Sigor@sysoev.ru 2237315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_KEEP: 2238315Sigor@sysoev.ru break; 2239315Sigor@sysoev.ru 2240315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_ADD: 2241315Sigor@sysoev.ru nxt_queue_insert_tail(&router->engines, &engine->link0); 2242315Sigor@sysoev.ru break; 2243315Sigor@sysoev.ru 2244315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_DELETE: 2245315Sigor@sysoev.ru nxt_queue_remove(&engine->link0); 2246315Sigor@sysoev.ru break; 2247315Sigor@sysoev.ru } 2248315Sigor@sysoev.ru 2249316Sigor@sysoev.ru nxt_router_engine_post(engine, recf->jobs); 2250316Sigor@sysoev.ru 225153Sigor@sysoev.ru recf++; 225253Sigor@sysoev.ru } 225353Sigor@sysoev.ru } 225453Sigor@sysoev.ru 225553Sigor@sysoev.ru 225653Sigor@sysoev.ru static void 2257315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs) 225853Sigor@sysoev.ru { 2259154Sigor@sysoev.ru nxt_work_t *work, *next; 2260154Sigor@sysoev.ru 2261315Sigor@sysoev.ru for (work = jobs; work != NULL; work = next) { 2262154Sigor@sysoev.ru next = work->next; 2263154Sigor@sysoev.ru work->next = NULL; 2264154Sigor@sysoev.ru 2265315Sigor@sysoev.ru nxt_event_engine_post(engine, work); 226653Sigor@sysoev.ru } 226753Sigor@sysoev.ru } 226853Sigor@sysoev.ru 226953Sigor@sysoev.ru 2270320Smax.romanov@nginx.com static nxt_port_handlers_t nxt_router_app_port_handlers = { 2271320Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 2272320Smax.romanov@nginx.com .data = nxt_port_rpc_handler, 227388Smax.romanov@nginx.com }; 227488Smax.romanov@nginx.com 227588Smax.romanov@nginx.com 227688Smax.romanov@nginx.com static void 227753Sigor@sysoev.ru nxt_router_thread_start(void *data) 227853Sigor@sysoev.ru { 2279141Smax.romanov@nginx.com nxt_int_t ret; 2280141Smax.romanov@nginx.com nxt_port_t *port; 228188Smax.romanov@nginx.com nxt_task_t *task; 228253Sigor@sysoev.ru nxt_thread_t *thread; 228353Sigor@sysoev.ru nxt_thread_link_t *link; 228453Sigor@sysoev.ru nxt_event_engine_t *engine; 228553Sigor@sysoev.ru 228653Sigor@sysoev.ru link = data; 228753Sigor@sysoev.ru engine = link->engine; 228888Smax.romanov@nginx.com task = &engine->task; 228953Sigor@sysoev.ru 229053Sigor@sysoev.ru thread = nxt_thread(); 229153Sigor@sysoev.ru 2292165Smax.romanov@nginx.com nxt_event_engine_thread_adopt(engine); 2293165Smax.romanov@nginx.com 229453Sigor@sysoev.ru /* STUB */ 229553Sigor@sysoev.ru thread->runtime = engine->task.thread->runtime; 229653Sigor@sysoev.ru 229753Sigor@sysoev.ru engine->task.thread = thread; 229853Sigor@sysoev.ru engine->task.log = thread->log; 229953Sigor@sysoev.ru thread->engine = engine; 230063Sigor@sysoev.ru thread->task = &engine->task; 2301326Svbart@nginx.com #if 0 230253Sigor@sysoev.ru thread->fiber = &engine->fibers->fiber; 2303326Svbart@nginx.com #endif 230453Sigor@sysoev.ru 230563Sigor@sysoev.ru engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64); 2306337Sigor@sysoev.ru if (nxt_slow_path(engine->mem_pool == NULL)) { 2307337Sigor@sysoev.ru return; 2308337Sigor@sysoev.ru } 230953Sigor@sysoev.ru 2310197Smax.romanov@nginx.com port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid, 2311197Smax.romanov@nginx.com NXT_PROCESS_ROUTER); 2312141Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 2313141Smax.romanov@nginx.com return; 2314141Smax.romanov@nginx.com } 2315141Smax.romanov@nginx.com 2316141Smax.romanov@nginx.com ret = nxt_port_socket_init(task, port, 0); 2317141Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2318343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 2319141Smax.romanov@nginx.com return; 2320141Smax.romanov@nginx.com } 2321141Smax.romanov@nginx.com 2322141Smax.romanov@nginx.com engine->port = port; 2323141Smax.romanov@nginx.com 2324320Smax.romanov@nginx.com nxt_port_enable(task, port, &nxt_router_app_port_handlers); 2325141Smax.romanov@nginx.com 232653Sigor@sysoev.ru nxt_event_engine_start(engine); 232753Sigor@sysoev.ru } 232853Sigor@sysoev.ru 232953Sigor@sysoev.ru 233053Sigor@sysoev.ru static void 233153Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data) 233253Sigor@sysoev.ru { 2333153Sigor@sysoev.ru nxt_joint_job_t *job; 2334359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2335359Sigor@sysoev.ru nxt_listen_event_t *lev; 233653Sigor@sysoev.ru nxt_listen_socket_t *ls; 2337359Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 233853Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 233953Sigor@sysoev.ru 2340153Sigor@sysoev.ru job = obj; 234153Sigor@sysoev.ru joint = data; 234253Sigor@sysoev.ru 2343159Sigor@sysoev.ru nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link); 2344159Sigor@sysoev.ru 2345359Sigor@sysoev.ru skcf = joint->socket_conf; 2346359Sigor@sysoev.ru ls = skcf->listen; 2347359Sigor@sysoev.ru 2348359Sigor@sysoev.ru lev = nxt_listen_event(task, ls); 2349359Sigor@sysoev.ru if (nxt_slow_path(lev == NULL)) { 2350359Sigor@sysoev.ru nxt_router_listen_socket_release(task, skcf); 235153Sigor@sysoev.ru return; 235253Sigor@sysoev.ru } 235353Sigor@sysoev.ru 2354359Sigor@sysoev.ru lev->socket.data = joint; 2355359Sigor@sysoev.ru 2356359Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 2357359Sigor@sysoev.ru 2358359Sigor@sysoev.ru nxt_thread_spin_lock(lock); 2359359Sigor@sysoev.ru ls->count++; 2360359Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 2361139Sigor@sysoev.ru 2362153Sigor@sysoev.ru job->work.next = NULL; 2363153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2364153Sigor@sysoev.ru 2365153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 236653Sigor@sysoev.ru } 236753Sigor@sysoev.ru 236853Sigor@sysoev.ru 236953Sigor@sysoev.ru nxt_inline nxt_listen_event_t * 237053Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections, 237153Sigor@sysoev.ru nxt_socket_conf_t *skcf) 237253Sigor@sysoev.ru { 2373115Sigor@sysoev.ru nxt_socket_t fd; 2374115Sigor@sysoev.ru nxt_queue_link_t *qlk; 2375359Sigor@sysoev.ru nxt_listen_event_t *lev; 2376359Sigor@sysoev.ru 2377359Sigor@sysoev.ru fd = skcf->listen->socket; 237853Sigor@sysoev.ru 2379115Sigor@sysoev.ru for (qlk = nxt_queue_first(listen_connections); 2380115Sigor@sysoev.ru qlk != nxt_queue_tail(listen_connections); 2381115Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 238253Sigor@sysoev.ru { 2383359Sigor@sysoev.ru lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link); 2384359Sigor@sysoev.ru 2385359Sigor@sysoev.ru if (fd == lev->socket.fd) { 2386359Sigor@sysoev.ru return lev; 238753Sigor@sysoev.ru } 238853Sigor@sysoev.ru } 238953Sigor@sysoev.ru 239053Sigor@sysoev.ru return NULL; 239153Sigor@sysoev.ru } 239253Sigor@sysoev.ru 239353Sigor@sysoev.ru 239453Sigor@sysoev.ru static void 239553Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data) 239653Sigor@sysoev.ru { 2397153Sigor@sysoev.ru nxt_joint_job_t *job; 239853Sigor@sysoev.ru nxt_event_engine_t *engine; 2399359Sigor@sysoev.ru nxt_listen_event_t *lev; 240053Sigor@sysoev.ru nxt_socket_conf_joint_t *joint, *old; 240153Sigor@sysoev.ru 2402153Sigor@sysoev.ru job = obj; 240353Sigor@sysoev.ru joint = data; 240453Sigor@sysoev.ru 2405139Sigor@sysoev.ru engine = task->thread->engine; 2406139Sigor@sysoev.ru 2407159Sigor@sysoev.ru nxt_queue_insert_tail(&engine->joints, &joint->link); 2408159Sigor@sysoev.ru 2409359Sigor@sysoev.ru lev = nxt_router_listen_event(&engine->listen_connections, 2410359Sigor@sysoev.ru joint->socket_conf); 2411359Sigor@sysoev.ru 2412359Sigor@sysoev.ru old = lev->socket.data; 2413359Sigor@sysoev.ru lev->socket.data = joint; 2414359Sigor@sysoev.ru lev->listen = joint->socket_conf->listen; 241553Sigor@sysoev.ru 2416153Sigor@sysoev.ru job->work.next = NULL; 2417153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2418153Sigor@sysoev.ru 2419153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 2420139Sigor@sysoev.ru 2421181Smax.romanov@nginx.com /* 2422181Smax.romanov@nginx.com * The task is allocated from configuration temporary 2423181Smax.romanov@nginx.com * memory pool so it can be freed after engine post operation. 2424181Smax.romanov@nginx.com */ 2425181Smax.romanov@nginx.com 2426181Smax.romanov@nginx.com nxt_router_conf_release(&engine->task, old); 242753Sigor@sysoev.ru } 242853Sigor@sysoev.ru 242953Sigor@sysoev.ru 243053Sigor@sysoev.ru static void 243153Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data) 243253Sigor@sysoev.ru { 2433153Sigor@sysoev.ru nxt_joint_job_t *job; 2434153Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2435359Sigor@sysoev.ru nxt_listen_event_t *lev; 2436153Sigor@sysoev.ru nxt_event_engine_t *engine; 2437153Sigor@sysoev.ru 2438153Sigor@sysoev.ru job = obj; 243953Sigor@sysoev.ru skcf = data; 244053Sigor@sysoev.ru 2441139Sigor@sysoev.ru engine = task->thread->engine; 2442139Sigor@sysoev.ru 2443359Sigor@sysoev.ru lev = nxt_router_listen_event(&engine->listen_connections, skcf); 2444359Sigor@sysoev.ru 2445359Sigor@sysoev.ru nxt_fd_event_delete(engine, &lev->socket); 244653Sigor@sysoev.ru 2447163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket delete: %d", engine, 2448359Sigor@sysoev.ru lev->socket.fd); 2449359Sigor@sysoev.ru 2450359Sigor@sysoev.ru lev->timer.handler = nxt_router_listen_socket_close; 2451359Sigor@sysoev.ru lev->timer.work_queue = &engine->fast_work_queue; 2452359Sigor@sysoev.ru 2453359Sigor@sysoev.ru nxt_timer_add(engine, &lev->timer, 0); 2454139Sigor@sysoev.ru 2455153Sigor@sysoev.ru job->work.next = NULL; 2456153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2457153Sigor@sysoev.ru 2458153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 245953Sigor@sysoev.ru } 246053Sigor@sysoev.ru 246153Sigor@sysoev.ru 246253Sigor@sysoev.ru static void 2463313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data) 2464313Sigor@sysoev.ru { 2465313Sigor@sysoev.ru nxt_event_engine_t *engine; 2466313Sigor@sysoev.ru 2467313Sigor@sysoev.ru nxt_debug(task, "router worker thread quit"); 2468313Sigor@sysoev.ru 2469313Sigor@sysoev.ru engine = task->thread->engine; 2470313Sigor@sysoev.ru 2471313Sigor@sysoev.ru engine->shutdown = 1; 2472313Sigor@sysoev.ru 2473313Sigor@sysoev.ru if (nxt_queue_is_empty(&engine->joints)) { 2474313Sigor@sysoev.ru nxt_thread_exit(task->thread); 2475313Sigor@sysoev.ru } 2476313Sigor@sysoev.ru } 2477313Sigor@sysoev.ru 2478313Sigor@sysoev.ru 2479313Sigor@sysoev.ru static void 248053Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data) 248153Sigor@sysoev.ru { 248253Sigor@sysoev.ru nxt_timer_t *timer; 2483359Sigor@sysoev.ru nxt_listen_event_t *lev; 248453Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 248553Sigor@sysoev.ru 248653Sigor@sysoev.ru timer = obj; 2487359Sigor@sysoev.ru lev = nxt_timer_data(timer, nxt_listen_event_t, timer); 2488359Sigor@sysoev.ru joint = lev->socket.data; 248953Sigor@sysoev.ru 2490163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine, 2491359Sigor@sysoev.ru lev->socket.fd); 2492359Sigor@sysoev.ru 2493359Sigor@sysoev.ru nxt_queue_remove(&lev->link); 2494359Sigor@sysoev.ru 2495359Sigor@sysoev.ru /* 'task' refers to lev->task and we cannot use after nxt_free() */ 2496123Smax.romanov@nginx.com task = &task->thread->engine->task; 2497123Smax.romanov@nginx.com 2498359Sigor@sysoev.ru nxt_router_listen_socket_release(task, joint->socket_conf); 2499359Sigor@sysoev.ru 2500359Sigor@sysoev.ru nxt_free(lev); 2501359Sigor@sysoev.ru 2502359Sigor@sysoev.ru nxt_router_conf_release(task, joint); 250353Sigor@sysoev.ru } 250453Sigor@sysoev.ru 250553Sigor@sysoev.ru 250653Sigor@sysoev.ru static void 2507359Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf) 250853Sigor@sysoev.ru { 2509359Sigor@sysoev.ru nxt_listen_socket_t *ls; 251053Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 251153Sigor@sysoev.ru 2512359Sigor@sysoev.ru ls = skcf->listen; 2513118Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 251453Sigor@sysoev.ru 251553Sigor@sysoev.ru nxt_thread_spin_lock(lock); 251653Sigor@sysoev.ru 2517359Sigor@sysoev.ru nxt_debug(task, "engine %p: listen socket release: ls->count %D", 2518359Sigor@sysoev.ru task->thread->engine, ls->count); 2519359Sigor@sysoev.ru 2520359Sigor@sysoev.ru if (--ls->count != 0) { 2521359Sigor@sysoev.ru ls = NULL; 252253Sigor@sysoev.ru } 252353Sigor@sysoev.ru 252453Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 252553Sigor@sysoev.ru 2526359Sigor@sysoev.ru if (ls != NULL) { 2527359Sigor@sysoev.ru nxt_socket_close(task, ls->socket); 2528359Sigor@sysoev.ru nxt_free(ls); 252953Sigor@sysoev.ru } 253053Sigor@sysoev.ru } 253153Sigor@sysoev.ru 253253Sigor@sysoev.ru 253353Sigor@sysoev.ru static void 253453Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint) 253553Sigor@sysoev.ru { 2536567Smax.romanov@nginx.com nxt_app_t *app; 253753Sigor@sysoev.ru nxt_socket_conf_t *skcf; 253853Sigor@sysoev.ru nxt_router_conf_t *rtcf; 2539313Sigor@sysoev.ru nxt_event_engine_t *engine; 254053Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 254153Sigor@sysoev.ru 2542163Smax.romanov@nginx.com nxt_debug(task, "conf joint %p count: %D", joint, joint->count); 254353Sigor@sysoev.ru 254453Sigor@sysoev.ru if (--joint->count != 0) { 254553Sigor@sysoev.ru return; 254653Sigor@sysoev.ru } 254753Sigor@sysoev.ru 254853Sigor@sysoev.ru nxt_queue_remove(&joint->link); 254953Sigor@sysoev.ru 2550530Sigor@sysoev.ru /* 2551530Sigor@sysoev.ru * The joint content can not be safely used after the critical 2552530Sigor@sysoev.ru * section protected by the spinlock because its memory pool may 2553530Sigor@sysoev.ru * be already destroyed by another thread. 2554530Sigor@sysoev.ru */ 2555530Sigor@sysoev.ru engine = joint->engine; 2556530Sigor@sysoev.ru 255753Sigor@sysoev.ru skcf = joint->socket_conf; 2558567Smax.romanov@nginx.com app = skcf->application; 255953Sigor@sysoev.ru rtcf = skcf->router_conf; 256053Sigor@sysoev.ru lock = &rtcf->router->lock; 256153Sigor@sysoev.ru 256253Sigor@sysoev.ru nxt_thread_spin_lock(lock); 256353Sigor@sysoev.ru 2564163Smax.romanov@nginx.com nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count, 2565163Smax.romanov@nginx.com rtcf, rtcf->count); 2566163Smax.romanov@nginx.com 256753Sigor@sysoev.ru if (--skcf->count != 0) { 256853Sigor@sysoev.ru rtcf = NULL; 2569567Smax.romanov@nginx.com app = NULL; 257053Sigor@sysoev.ru 257153Sigor@sysoev.ru } else { 257253Sigor@sysoev.ru nxt_queue_remove(&skcf->link); 257353Sigor@sysoev.ru 257453Sigor@sysoev.ru if (--rtcf->count != 0) { 257553Sigor@sysoev.ru rtcf = NULL; 257653Sigor@sysoev.ru } 257753Sigor@sysoev.ru } 257853Sigor@sysoev.ru 257953Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 258053Sigor@sysoev.ru 2581567Smax.romanov@nginx.com if (app != NULL) { 2582567Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 2583567Smax.romanov@nginx.com } 2584567Smax.romanov@nginx.com 2585141Smax.romanov@nginx.com /* TODO remove engine->port */ 2586141Smax.romanov@nginx.com /* TODO excude from connected ports */ 2587141Smax.romanov@nginx.com 258853Sigor@sysoev.ru if (rtcf != NULL) { 2589115Sigor@sysoev.ru nxt_debug(task, "old router conf is destroyed"); 2590131Smax.romanov@nginx.com 2591131Smax.romanov@nginx.com nxt_mp_thread_adopt(rtcf->mem_pool); 2592131Smax.romanov@nginx.com 259365Sigor@sysoev.ru nxt_mp_destroy(rtcf->mem_pool); 259453Sigor@sysoev.ru } 259553Sigor@sysoev.ru 2596530Sigor@sysoev.ru if (engine->shutdown && nxt_queue_is_empty(&engine->joints)) { 259753Sigor@sysoev.ru nxt_thread_exit(task->thread); 259853Sigor@sysoev.ru } 259953Sigor@sysoev.ru } 260053Sigor@sysoev.ru 260153Sigor@sysoev.ru 260253Sigor@sysoev.ru static void 260353Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data) 260453Sigor@sysoev.ru { 2605141Smax.romanov@nginx.com nxt_port_t *port; 260653Sigor@sysoev.ru nxt_thread_link_t *link; 260753Sigor@sysoev.ru nxt_event_engine_t *engine; 260853Sigor@sysoev.ru nxt_thread_handle_t handle; 260953Sigor@sysoev.ru 261058Svbart@nginx.com handle = (nxt_thread_handle_t) obj; 261153Sigor@sysoev.ru link = data; 261253Sigor@sysoev.ru 261353Sigor@sysoev.ru nxt_thread_wait(handle); 261453Sigor@sysoev.ru 261553Sigor@sysoev.ru engine = link->engine; 261653Sigor@sysoev.ru 261753Sigor@sysoev.ru nxt_queue_remove(&engine->link); 261853Sigor@sysoev.ru 2619141Smax.romanov@nginx.com port = engine->port; 2620141Smax.romanov@nginx.com 2621141Smax.romanov@nginx.com // TODO notify all apps 2622141Smax.romanov@nginx.com 2623343Smax.romanov@nginx.com port->engine = task->thread->engine; 2624163Smax.romanov@nginx.com nxt_mp_thread_adopt(port->mem_pool); 2625343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 2626163Smax.romanov@nginx.com 2627163Smax.romanov@nginx.com nxt_mp_thread_adopt(engine->mem_pool); 262863Sigor@sysoev.ru nxt_mp_destroy(engine->mem_pool); 262953Sigor@sysoev.ru 263053Sigor@sysoev.ru nxt_event_engine_free(engine); 263153Sigor@sysoev.ru 263253Sigor@sysoev.ru nxt_free(link); 263353Sigor@sysoev.ru } 263453Sigor@sysoev.ru 263553Sigor@sysoev.ru 263653Sigor@sysoev.ru static void 2637318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2638318Smax.romanov@nginx.com void *data) 263988Smax.romanov@nginx.com { 264088Smax.romanov@nginx.com size_t dump_size; 2641431Sigor@sysoev.ru nxt_int_t ret; 2642608Sigor@sysoev.ru nxt_buf_t *b; 2643431Sigor@sysoev.ru nxt_http_request_t *r; 264488Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 2645431Sigor@sysoev.ru nxt_app_parse_ctx_t *ar; 264688Smax.romanov@nginx.com 264788Smax.romanov@nginx.com b = msg->buf; 2648318Smax.romanov@nginx.com rc = data; 264988Smax.romanov@nginx.com 265088Smax.romanov@nginx.com dump_size = nxt_buf_used_size(b); 265188Smax.romanov@nginx.com 265288Smax.romanov@nginx.com if (dump_size > 300) { 265388Smax.romanov@nginx.com dump_size = 300; 265488Smax.romanov@nginx.com } 265588Smax.romanov@nginx.com 2656494Spluknet@nginx.com nxt_debug(task, "%srouter app data (%uz): %*s", 265788Smax.romanov@nginx.com msg->port_msg.last ? "last " : "", msg->size, dump_size, 265888Smax.romanov@nginx.com b->mem.pos); 265988Smax.romanov@nginx.com 266088Smax.romanov@nginx.com if (msg->size == 0) { 266188Smax.romanov@nginx.com b = NULL; 266288Smax.romanov@nginx.com } 266388Smax.romanov@nginx.com 2664431Sigor@sysoev.ru ar = rc->ap; 2665570Smax.romanov@nginx.com if (nxt_slow_path(ar == NULL)) { 2666570Smax.romanov@nginx.com return; 2667570Smax.romanov@nginx.com } 2668425Smax.romanov@nginx.com 2669608Sigor@sysoev.ru if (ar->request->error) { 2670608Sigor@sysoev.ru nxt_router_rc_unlink(task, rc); 2671608Sigor@sysoev.ru return; 2672608Sigor@sysoev.ru } 2673608Sigor@sysoev.ru 267488Smax.romanov@nginx.com if (msg->port_msg.last != 0) { 267588Smax.romanov@nginx.com nxt_debug(task, "router data create last buf"); 267688Smax.romanov@nginx.com 2677608Sigor@sysoev.ru nxt_buf_chain_add(&b, nxt_http_buf_last(ar->request)); 2678167Smax.romanov@nginx.com 2679343Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 2680425Smax.romanov@nginx.com 2681425Smax.romanov@nginx.com } else { 2682*615Smax.romanov@nginx.com if (rc->app != NULL && rc->app->timeout != 0) { 2683431Sigor@sysoev.ru ar->timer.handler = nxt_router_app_timeout; 2684*615Smax.romanov@nginx.com ar->timer_data = rc; 2685431Sigor@sysoev.ru nxt_timer_add(task->thread->engine, &ar->timer, rc->app->timeout); 2686425Smax.romanov@nginx.com } 268788Smax.romanov@nginx.com } 268888Smax.romanov@nginx.com 268988Smax.romanov@nginx.com if (b == NULL) { 269088Smax.romanov@nginx.com return; 269188Smax.romanov@nginx.com } 269288Smax.romanov@nginx.com 2693206Smax.romanov@nginx.com if (msg->buf == b) { 2694206Smax.romanov@nginx.com /* Disable instant buffer completion/re-using by port. */ 2695206Smax.romanov@nginx.com msg->buf = NULL; 2696206Smax.romanov@nginx.com } 2697194Smax.romanov@nginx.com 2698431Sigor@sysoev.ru r = ar->request; 2699431Sigor@sysoev.ru 2700431Sigor@sysoev.ru if (r->header_sent) { 2701431Sigor@sysoev.ru nxt_buf_chain_add(&r->out, b); 2702431Sigor@sysoev.ru nxt_http_request_send_body(task, r, NULL); 2703277Sigor@sysoev.ru 270488Smax.romanov@nginx.com } else { 2705431Sigor@sysoev.ru ret = nxt_http_parse_fields(&ar->resp_parser, &b->mem); 2706431Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_DONE)) { 2707431Sigor@sysoev.ru goto fail; 2708431Sigor@sysoev.ru } 2709431Sigor@sysoev.ru 2710431Sigor@sysoev.ru r->resp.fields = ar->resp_parser.fields; 2711431Sigor@sysoev.ru 2712431Sigor@sysoev.ru ret = nxt_http_fields_process(r->resp.fields, 2713431Sigor@sysoev.ru &nxt_response_fields_hash, r); 2714431Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2715431Sigor@sysoev.ru goto fail; 2716431Sigor@sysoev.ru } 2717431Sigor@sysoev.ru 2718435Sigor@sysoev.ru if (nxt_buf_mem_used_size(&b->mem) == 0) { 2719435Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 2720435Sigor@sysoev.ru b->completion_handler, task, b, b->parent); 2721507Smax.romanov@nginx.com 2722520Smax.romanov@nginx.com b = b->next; 2723520Smax.romanov@nginx.com } 2724520Smax.romanov@nginx.com 2725520Smax.romanov@nginx.com if (b != NULL) { 2726431Sigor@sysoev.ru nxt_buf_chain_add(&r->out, b); 2727431Sigor@sysoev.ru } 2728431Sigor@sysoev.ru 2729431Sigor@sysoev.ru r->state = &nxt_http_request_send_state; 2730431Sigor@sysoev.ru 2731431Sigor@sysoev.ru nxt_http_request_header_send(task, r); 2732431Sigor@sysoev.ru } 2733431Sigor@sysoev.ru 2734431Sigor@sysoev.ru return; 2735431Sigor@sysoev.ru 2736431Sigor@sysoev.ru fail: 2737431Sigor@sysoev.ru 2738*615Smax.romanov@nginx.com nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE); 2739*615Smax.romanov@nginx.com 2740431Sigor@sysoev.ru nxt_router_rc_unlink(task, rc); 2741431Sigor@sysoev.ru } 2742431Sigor@sysoev.ru 2743431Sigor@sysoev.ru 2744431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_send_state 2745431Sigor@sysoev.ru nxt_aligned(64) = 2746431Sigor@sysoev.ru { 2747431Sigor@sysoev.ru .ready_handler = nxt_http_request_send_body, 2748431Sigor@sysoev.ru .error_handler = nxt_http_request_close_handler, 2749431Sigor@sysoev.ru }; 2750431Sigor@sysoev.ru 2751431Sigor@sysoev.ru 2752431Sigor@sysoev.ru static void 2753431Sigor@sysoev.ru nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data) 2754431Sigor@sysoev.ru { 2755431Sigor@sysoev.ru nxt_buf_t *out; 2756431Sigor@sysoev.ru nxt_http_request_t *r; 2757431Sigor@sysoev.ru 2758431Sigor@sysoev.ru r = obj; 2759431Sigor@sysoev.ru 2760431Sigor@sysoev.ru out = r->out; 2761431Sigor@sysoev.ru 2762431Sigor@sysoev.ru if (out != NULL) { 2763431Sigor@sysoev.ru r->out = NULL; 2764431Sigor@sysoev.ru nxt_http_request_send(task, r, out); 276588Smax.romanov@nginx.com } 276688Smax.romanov@nginx.com } 276788Smax.romanov@nginx.com 2768277Sigor@sysoev.ru 2769318Smax.romanov@nginx.com static void 2770318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2771318Smax.romanov@nginx.com void *data) 2772318Smax.romanov@nginx.com { 2773425Smax.romanov@nginx.com nxt_int_t res; 2774425Smax.romanov@nginx.com nxt_port_t *port; 2775425Smax.romanov@nginx.com nxt_bool_t cancelled; 2776425Smax.romanov@nginx.com nxt_req_app_link_t *ra; 2777318Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 2778318Smax.romanov@nginx.com 2779318Smax.romanov@nginx.com rc = data; 2780318Smax.romanov@nginx.com 2781425Smax.romanov@nginx.com ra = rc->ra; 2782425Smax.romanov@nginx.com 2783425Smax.romanov@nginx.com if (ra != NULL) { 2784425Smax.romanov@nginx.com cancelled = nxt_router_msg_cancel(task, &ra->msg_info, ra->stream); 2785425Smax.romanov@nginx.com 2786425Smax.romanov@nginx.com if (cancelled) { 2787425Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 2788425Smax.romanov@nginx.com 2789427Smax.romanov@nginx.com res = nxt_router_app_port(task, rc->app, ra); 2790425Smax.romanov@nginx.com 2791425Smax.romanov@nginx.com if (res == NXT_OK) { 2792425Smax.romanov@nginx.com port = ra->app_port; 2793425Smax.romanov@nginx.com 2794551Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 2795551Smax.romanov@nginx.com nxt_log(task, NXT_LOG_ERR, "port is NULL in cancelled ra"); 2796551Smax.romanov@nginx.com return; 2797551Smax.romanov@nginx.com } 2798425Smax.romanov@nginx.com 2799425Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, task->thread->engine->port, rc, 2800425Smax.romanov@nginx.com port->pid); 2801425Smax.romanov@nginx.com 2802425Smax.romanov@nginx.com nxt_router_app_prepare_request(task, ra); 2803425Smax.romanov@nginx.com } 2804425Smax.romanov@nginx.com 2805425Smax.romanov@nginx.com msg->port_msg.last = 0; 2806425Smax.romanov@nginx.com 2807425Smax.romanov@nginx.com return; 2808425Smax.romanov@nginx.com } 2809425Smax.romanov@nginx.com } 2810425Smax.romanov@nginx.com 2811431Sigor@sysoev.ru nxt_http_request_error(task, rc->ap->request, NXT_HTTP_SERVICE_UNAVAILABLE); 2812318Smax.romanov@nginx.com 2813343Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 2814318Smax.romanov@nginx.com } 2815318Smax.romanov@nginx.com 2816318Smax.romanov@nginx.com 2817141Smax.romanov@nginx.com static void 2818343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2819343Smax.romanov@nginx.com void *data) 2820192Smax.romanov@nginx.com { 2821343Smax.romanov@nginx.com nxt_app_t *app; 2822343Smax.romanov@nginx.com nxt_port_t *port; 2823343Smax.romanov@nginx.com 2824343Smax.romanov@nginx.com app = data; 2825347Smax.romanov@nginx.com port = msg->u.new_port; 2826343Smax.romanov@nginx.com 2827343Smax.romanov@nginx.com nxt_assert(app != NULL); 2828343Smax.romanov@nginx.com nxt_assert(port != NULL); 2829343Smax.romanov@nginx.com 2830343Smax.romanov@nginx.com port->app = app; 2831343Smax.romanov@nginx.com 2832343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2833343Smax.romanov@nginx.com 2834507Smax.romanov@nginx.com nxt_assert(app->pending_processes != 0); 2835507Smax.romanov@nginx.com 2836507Smax.romanov@nginx.com app->pending_processes--; 2837507Smax.romanov@nginx.com app->processes++; 2838343Smax.romanov@nginx.com 2839343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2840343Smax.romanov@nginx.com 2841507Smax.romanov@nginx.com nxt_debug(task, "app '%V' new port ready, pid %PI, %d/%d", 2842507Smax.romanov@nginx.com &app->name, port->pid, app->processes, app->pending_processes); 2843343Smax.romanov@nginx.com 2844343Smax.romanov@nginx.com nxt_router_app_port_release(task, port, 0, 0); 2845192Smax.romanov@nginx.com } 2846192Smax.romanov@nginx.com 2847192Smax.romanov@nginx.com 2848192Smax.romanov@nginx.com static void 2849343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2850343Smax.romanov@nginx.com void *data) 2851192Smax.romanov@nginx.com { 2852318Smax.romanov@nginx.com nxt_app_t *app; 2853318Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2854318Smax.romanov@nginx.com nxt_req_app_link_t *ra; 2855343Smax.romanov@nginx.com 2856343Smax.romanov@nginx.com app = data; 2857343Smax.romanov@nginx.com 2858343Smax.romanov@nginx.com nxt_assert(app != NULL); 2859343Smax.romanov@nginx.com 2860343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start error", &app->name, app); 2861343Smax.romanov@nginx.com 2862343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2863343Smax.romanov@nginx.com 2864507Smax.romanov@nginx.com nxt_assert(app->pending_processes != 0); 2865507Smax.romanov@nginx.com 2866507Smax.romanov@nginx.com app->pending_processes--; 2867318Smax.romanov@nginx.com 2868318Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->requests)) { 2869318Smax.romanov@nginx.com lnk = nxt_queue_last(&app->requests); 2870318Smax.romanov@nginx.com nxt_queue_remove(lnk); 2871343Smax.romanov@nginx.com lnk->next = NULL; 2872318Smax.romanov@nginx.com 2873425Smax.romanov@nginx.com ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_requests); 2874318Smax.romanov@nginx.com 2875343Smax.romanov@nginx.com } else { 2876343Smax.romanov@nginx.com ra = NULL; 2877343Smax.romanov@nginx.com } 2878343Smax.romanov@nginx.com 2879343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2880343Smax.romanov@nginx.com 2881343Smax.romanov@nginx.com if (ra != NULL) { 2882318Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p abort next stream #%uD", 2883318Smax.romanov@nginx.com &app->name, app, ra->stream); 2884318Smax.romanov@nginx.com 2885507Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, "Failed to start application process"); 2886425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 2887318Smax.romanov@nginx.com } 2888192Smax.romanov@nginx.com 2889343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 2890192Smax.romanov@nginx.com } 2891192Smax.romanov@nginx.com 2892192Smax.romanov@nginx.com 2893343Smax.romanov@nginx.com void 2894343Smax.romanov@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i) 2895141Smax.romanov@nginx.com { 2896343Smax.romanov@nginx.com int c; 2897343Smax.romanov@nginx.com 2898343Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&app->use_count, i); 2899343Smax.romanov@nginx.com 2900343Smax.romanov@nginx.com if (i < 0 && c == -i) { 2901343Smax.romanov@nginx.com 2902343Smax.romanov@nginx.com nxt_assert(app->live == 0); 2903507Smax.romanov@nginx.com nxt_assert(app->processes == 0); 2904507Smax.romanov@nginx.com nxt_assert(app->idle_processes == 0); 2905507Smax.romanov@nginx.com nxt_assert(app->pending_processes == 0); 2906551Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->requests)); 2907551Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->ports)); 2908551Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->spare_ports)); 2909551Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->idle_ports)); 2910343Smax.romanov@nginx.com 2911163Smax.romanov@nginx.com nxt_thread_mutex_destroy(&app->mutex); 2912163Smax.romanov@nginx.com nxt_free(app); 2913163Smax.romanov@nginx.com } 2914343Smax.romanov@nginx.com } 2915343Smax.romanov@nginx.com 2916343Smax.romanov@nginx.com 2917424Smax.romanov@nginx.com nxt_inline nxt_bool_t 2918424Smax.romanov@nginx.com nxt_router_app_first_port_busy(nxt_app_t *app) 2919424Smax.romanov@nginx.com { 2920424Smax.romanov@nginx.com nxt_port_t *port; 2921424Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2922424Smax.romanov@nginx.com 2923424Smax.romanov@nginx.com lnk = nxt_queue_first(&app->ports); 2924424Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, app_link); 2925424Smax.romanov@nginx.com 2926424Smax.romanov@nginx.com return port->app_pending_responses > 0; 2927424Smax.romanov@nginx.com } 2928424Smax.romanov@nginx.com 2929424Smax.romanov@nginx.com 2930343Smax.romanov@nginx.com nxt_inline nxt_port_t * 2931427Smax.romanov@nginx.com nxt_router_pop_first_port(nxt_app_t *app) 2932343Smax.romanov@nginx.com { 2933343Smax.romanov@nginx.com nxt_port_t *port; 2934343Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2935343Smax.romanov@nginx.com 2936343Smax.romanov@nginx.com lnk = nxt_queue_first(&app->ports); 2937343Smax.romanov@nginx.com nxt_queue_remove(lnk); 2938343Smax.romanov@nginx.com 2939343Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, app_link); 2940343Smax.romanov@nginx.com 2941424Smax.romanov@nginx.com port->app_pending_responses++; 2942424Smax.romanov@nginx.com 2943507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 2944507Smax.romanov@nginx.com app->idle_processes--; 2945507Smax.romanov@nginx.com 2946507Smax.romanov@nginx.com if (port->idle_start == 0) { 2947507Smax.romanov@nginx.com nxt_assert(app->idle_processes < app->spare_processes); 2948507Smax.romanov@nginx.com 2949507Smax.romanov@nginx.com } else { 2950507Smax.romanov@nginx.com nxt_assert(app->idle_processes >= app->spare_processes); 2951507Smax.romanov@nginx.com 2952507Smax.romanov@nginx.com port->idle_start = 0; 2953507Smax.romanov@nginx.com } 2954507Smax.romanov@nginx.com } 2955507Smax.romanov@nginx.com 2956428Smax.romanov@nginx.com if ((app->max_pending_responses == 0 2957428Smax.romanov@nginx.com || port->app_pending_responses < app->max_pending_responses) 2958428Smax.romanov@nginx.com && (app->max_requests == 0 2959428Smax.romanov@nginx.com || port->app_responses + port->app_pending_responses 2960428Smax.romanov@nginx.com < app->max_requests)) 2961277Sigor@sysoev.ru { 2962343Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, lnk); 2963343Smax.romanov@nginx.com 2964425Smax.romanov@nginx.com nxt_port_inc_use(port); 2965425Smax.romanov@nginx.com 2966343Smax.romanov@nginx.com } else { 2967343Smax.romanov@nginx.com lnk->next = NULL; 2968167Smax.romanov@nginx.com } 2969167Smax.romanov@nginx.com 2970343Smax.romanov@nginx.com return port; 2971163Smax.romanov@nginx.com } 2972163Smax.romanov@nginx.com 2973163Smax.romanov@nginx.com 2974507Smax.romanov@nginx.com nxt_inline nxt_port_t * 2975507Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app) 2976141Smax.romanov@nginx.com { 2977343Smax.romanov@nginx.com nxt_port_t *port; 2978141Smax.romanov@nginx.com 2979141Smax.romanov@nginx.com port = NULL; 2980141Smax.romanov@nginx.com 2981141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2982141Smax.romanov@nginx.com 2983343Smax.romanov@nginx.com nxt_queue_each(port, &app->ports, nxt_port_t, app_link) { 2984343Smax.romanov@nginx.com 2985424Smax.romanov@nginx.com if (port->app_pending_responses > 0) { 2986343Smax.romanov@nginx.com port = NULL; 2987343Smax.romanov@nginx.com 2988343Smax.romanov@nginx.com continue; 2989343Smax.romanov@nginx.com } 2990343Smax.romanov@nginx.com 2991507Smax.romanov@nginx.com /* Caller is responsible to decrease port use count. */ 2992507Smax.romanov@nginx.com nxt_queue_chk_remove(&port->app_link); 2993507Smax.romanov@nginx.com 2994507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 2995507Smax.romanov@nginx.com app->idle_processes--; 2996507Smax.romanov@nginx.com } 2997507Smax.romanov@nginx.com 2998507Smax.romanov@nginx.com /* Caller is responsible to decrease app use count. */ 2999507Smax.romanov@nginx.com port->app = NULL; 3000507Smax.romanov@nginx.com app->processes--; 3001343Smax.romanov@nginx.com 3002343Smax.romanov@nginx.com break; 3003343Smax.romanov@nginx.com 3004343Smax.romanov@nginx.com } nxt_queue_loop; 3005141Smax.romanov@nginx.com 3006141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3007141Smax.romanov@nginx.com 3008141Smax.romanov@nginx.com return port; 3009141Smax.romanov@nginx.com } 3010141Smax.romanov@nginx.com 3011141Smax.romanov@nginx.com 3012141Smax.romanov@nginx.com static void 3013507Smax.romanov@nginx.com nxt_router_app_quit(nxt_task_t *task, nxt_app_t *app) 3014507Smax.romanov@nginx.com { 3015507Smax.romanov@nginx.com nxt_port_t *port; 3016507Smax.romanov@nginx.com 3017507Smax.romanov@nginx.com nxt_queue_remove(&app->link); 3018507Smax.romanov@nginx.com 3019507Smax.romanov@nginx.com app->live = 0; 3020507Smax.romanov@nginx.com 3021507Smax.romanov@nginx.com for ( ;; ) { 3022507Smax.romanov@nginx.com port = nxt_router_app_get_port_for_quit(app); 3023507Smax.romanov@nginx.com if (port == NULL) { 3024507Smax.romanov@nginx.com break; 3025507Smax.romanov@nginx.com } 3026507Smax.romanov@nginx.com 3027507Smax.romanov@nginx.com nxt_debug(task, "send QUIT to app '%V' pid %PI", &app->name, port->pid); 3028507Smax.romanov@nginx.com 3029507Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 3030507Smax.romanov@nginx.com 3031507Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3032507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 3033507Smax.romanov@nginx.com } 3034507Smax.romanov@nginx.com 3035507Smax.romanov@nginx.com if (nxt_timer_is_in_tree(&app->idle_timer)) { 3036507Smax.romanov@nginx.com nxt_assert(app->engine == task->thread->engine); 3037507Smax.romanov@nginx.com 3038507Smax.romanov@nginx.com app->idle_timer.handler = nxt_router_app_release_handler; 3039507Smax.romanov@nginx.com nxt_timer_add(app->engine, &app->idle_timer, 0); 3040507Smax.romanov@nginx.com 3041507Smax.romanov@nginx.com } else { 3042507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 3043507Smax.romanov@nginx.com } 3044507Smax.romanov@nginx.com } 3045507Smax.romanov@nginx.com 3046507Smax.romanov@nginx.com 3047507Smax.romanov@nginx.com static void 3048343Smax.romanov@nginx.com nxt_router_app_process_request(nxt_task_t *task, void *obj, void *data) 3049141Smax.romanov@nginx.com { 3050343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 3051343Smax.romanov@nginx.com 3052538Svbart@nginx.com ra = data; 3053538Svbart@nginx.com 3054538Svbart@nginx.com #if (NXT_DEBUG) 3055538Svbart@nginx.com { 3056538Svbart@nginx.com nxt_app_t *app; 3057538Svbart@nginx.com 3058343Smax.romanov@nginx.com app = obj; 3059141Smax.romanov@nginx.com 3060141Smax.romanov@nginx.com nxt_assert(app != NULL); 3061343Smax.romanov@nginx.com nxt_assert(ra != NULL); 3062343Smax.romanov@nginx.com nxt_assert(ra->app_port != NULL); 3063343Smax.romanov@nginx.com 3064343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p process next stream #%uD", 3065343Smax.romanov@nginx.com &app->name, app, ra->stream); 3066538Svbart@nginx.com } 3067538Svbart@nginx.com #endif 3068343Smax.romanov@nginx.com 3069425Smax.romanov@nginx.com nxt_router_app_prepare_request(task, ra); 3070343Smax.romanov@nginx.com } 3071343Smax.romanov@nginx.com 3072343Smax.romanov@nginx.com 3073343Smax.romanov@nginx.com static void 3074343Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port, 3075343Smax.romanov@nginx.com uint32_t request_failed, uint32_t got_response) 3076343Smax.romanov@nginx.com { 3077427Smax.romanov@nginx.com nxt_app_t *app; 3078507Smax.romanov@nginx.com nxt_bool_t port_unchained; 3079507Smax.romanov@nginx.com nxt_bool_t send_quit, cancelled, adjust_idle_timer; 3080427Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3081427Smax.romanov@nginx.com nxt_req_app_link_t *ra, *pending_ra, *re_ra; 3082427Smax.romanov@nginx.com nxt_port_select_state_t state; 3083343Smax.romanov@nginx.com 3084343Smax.romanov@nginx.com nxt_assert(port != NULL); 3085343Smax.romanov@nginx.com nxt_assert(port->app != NULL); 3086343Smax.romanov@nginx.com 3087427Smax.romanov@nginx.com ra = NULL; 3088427Smax.romanov@nginx.com 3089343Smax.romanov@nginx.com app = port->app; 3090343Smax.romanov@nginx.com 3091343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3092343Smax.romanov@nginx.com 3093424Smax.romanov@nginx.com port->app_pending_responses -= request_failed + got_response; 3094343Smax.romanov@nginx.com port->app_responses += got_response; 3095343Smax.romanov@nginx.com 3096427Smax.romanov@nginx.com if (nxt_slow_path(app->live == 0)) { 3097427Smax.romanov@nginx.com goto app_dead; 3098427Smax.romanov@nginx.com } 3099427Smax.romanov@nginx.com 3100427Smax.romanov@nginx.com if (port->pair[1] != -1 3101426Smax.romanov@nginx.com && (app->max_pending_responses == 0 3102428Smax.romanov@nginx.com || port->app_pending_responses < app->max_pending_responses) 3103428Smax.romanov@nginx.com && (app->max_requests == 0 3104428Smax.romanov@nginx.com || port->app_responses + port->app_pending_responses 3105428Smax.romanov@nginx.com < app->max_requests)) 3106343Smax.romanov@nginx.com { 3107424Smax.romanov@nginx.com if (port->app_link.next == NULL) { 3108424Smax.romanov@nginx.com if (port->app_pending_responses > 0) { 3109424Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &port->app_link); 3110424Smax.romanov@nginx.com 3111424Smax.romanov@nginx.com } else { 3112424Smax.romanov@nginx.com nxt_queue_insert_head(&app->ports, &port->app_link); 3113424Smax.romanov@nginx.com } 3114424Smax.romanov@nginx.com 3115425Smax.romanov@nginx.com nxt_port_inc_use(port); 3116424Smax.romanov@nginx.com 3117424Smax.romanov@nginx.com } else { 3118424Smax.romanov@nginx.com if (port->app_pending_responses == 0 3119424Smax.romanov@nginx.com && nxt_queue_first(&app->ports) != &port->app_link) 3120424Smax.romanov@nginx.com { 3121424Smax.romanov@nginx.com nxt_queue_remove(&port->app_link); 3122424Smax.romanov@nginx.com nxt_queue_insert_head(&app->ports, &port->app_link); 3123424Smax.romanov@nginx.com } 3124424Smax.romanov@nginx.com } 3125141Smax.romanov@nginx.com } 3126141Smax.romanov@nginx.com 3127427Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->ports) 3128426Smax.romanov@nginx.com && !nxt_queue_is_empty(&app->requests)) 3129343Smax.romanov@nginx.com { 3130141Smax.romanov@nginx.com lnk = nxt_queue_first(&app->requests); 3131141Smax.romanov@nginx.com nxt_queue_remove(lnk); 3132343Smax.romanov@nginx.com lnk->next = NULL; 3133141Smax.romanov@nginx.com 3134425Smax.romanov@nginx.com ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_requests); 3135425Smax.romanov@nginx.com 3136427Smax.romanov@nginx.com ra->app_port = nxt_router_pop_first_port(app); 3137425Smax.romanov@nginx.com 3138425Smax.romanov@nginx.com if (ra->app_port->app_pending_responses > 1) { 3139427Smax.romanov@nginx.com nxt_router_ra_pending(task, app, ra); 3140425Smax.romanov@nginx.com } 3141425Smax.romanov@nginx.com } 3142425Smax.romanov@nginx.com 3143427Smax.romanov@nginx.com app_dead: 3144427Smax.romanov@nginx.com 3145427Smax.romanov@nginx.com /* Pop first pending request for this port. */ 3146425Smax.romanov@nginx.com if ((request_failed > 0 || got_response > 0) 3147425Smax.romanov@nginx.com && !nxt_queue_is_empty(&port->pending_requests)) 3148425Smax.romanov@nginx.com { 3149425Smax.romanov@nginx.com lnk = nxt_queue_first(&port->pending_requests); 3150425Smax.romanov@nginx.com nxt_queue_remove(lnk); 3151425Smax.romanov@nginx.com lnk->next = NULL; 3152425Smax.romanov@nginx.com 3153427Smax.romanov@nginx.com pending_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, 3154427Smax.romanov@nginx.com link_port_pending); 3155427Smax.romanov@nginx.com 3156427Smax.romanov@nginx.com nxt_assert(pending_ra->link_app_pending.next != NULL); 3157427Smax.romanov@nginx.com 3158427Smax.romanov@nginx.com nxt_queue_remove(&pending_ra->link_app_pending); 3159427Smax.romanov@nginx.com pending_ra->link_app_pending.next = NULL; 3160425Smax.romanov@nginx.com 3161425Smax.romanov@nginx.com } else { 3162427Smax.romanov@nginx.com pending_ra = NULL; 3163141Smax.romanov@nginx.com } 3164141Smax.romanov@nginx.com 3165427Smax.romanov@nginx.com /* Try to cancel and re-schedule first stalled request for this app. */ 3166427Smax.romanov@nginx.com if (got_response > 0 && !nxt_queue_is_empty(&app->pending)) { 3167427Smax.romanov@nginx.com lnk = nxt_queue_first(&app->pending); 3168427Smax.romanov@nginx.com 3169427Smax.romanov@nginx.com re_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_pending); 3170427Smax.romanov@nginx.com 3171427Smax.romanov@nginx.com if (re_ra->res_time <= nxt_thread_monotonic_time(task->thread)) { 3172427Smax.romanov@nginx.com 3173427Smax.romanov@nginx.com nxt_debug(task, "app '%V' stalled request #%uD detected", 3174427Smax.romanov@nginx.com &app->name, re_ra->stream); 3175427Smax.romanov@nginx.com 3176427Smax.romanov@nginx.com cancelled = nxt_router_msg_cancel(task, &re_ra->msg_info, 3177427Smax.romanov@nginx.com re_ra->stream); 3178427Smax.romanov@nginx.com 3179427Smax.romanov@nginx.com if (cancelled) { 3180427Smax.romanov@nginx.com nxt_router_ra_inc_use(re_ra); 3181427Smax.romanov@nginx.com 3182427Smax.romanov@nginx.com state.ra = re_ra; 3183427Smax.romanov@nginx.com state.app = app; 3184427Smax.romanov@nginx.com 3185427Smax.romanov@nginx.com nxt_router_port_select(task, &state); 3186427Smax.romanov@nginx.com 3187427Smax.romanov@nginx.com goto re_ra_cancelled; 3188427Smax.romanov@nginx.com } 3189427Smax.romanov@nginx.com } 3190427Smax.romanov@nginx.com } 3191427Smax.romanov@nginx.com 3192427Smax.romanov@nginx.com re_ra = NULL; 3193427Smax.romanov@nginx.com 3194427Smax.romanov@nginx.com re_ra_cancelled: 3195427Smax.romanov@nginx.com 3196507Smax.romanov@nginx.com send_quit = (app->live == 0 && port->app_pending_responses == 0) 3197428Smax.romanov@nginx.com || (app->max_requests > 0 && port->app_pending_responses == 0 3198428Smax.romanov@nginx.com && port->app_responses >= app->max_requests); 3199367Smax.romanov@nginx.com 3200507Smax.romanov@nginx.com if (send_quit) { 3201507Smax.romanov@nginx.com port_unchained = nxt_queue_chk_remove(&port->app_link); 3202507Smax.romanov@nginx.com 3203507Smax.romanov@nginx.com port->app = NULL; 3204507Smax.romanov@nginx.com app->processes--; 3205507Smax.romanov@nginx.com 3206507Smax.romanov@nginx.com } else { 3207507Smax.romanov@nginx.com port_unchained = 0; 3208507Smax.romanov@nginx.com } 3209507Smax.romanov@nginx.com 3210507Smax.romanov@nginx.com adjust_idle_timer = 0; 3211507Smax.romanov@nginx.com 3212571Smax.romanov@nginx.com if (port->pair[1] != -1 && !send_quit && port->app_pending_responses == 0) { 3213507Smax.romanov@nginx.com nxt_assert(port->idle_link.next == NULL); 3214507Smax.romanov@nginx.com 3215507Smax.romanov@nginx.com if (app->idle_processes == app->spare_processes 3216507Smax.romanov@nginx.com && app->adjust_idle_work.data == NULL) 3217507Smax.romanov@nginx.com { 3218507Smax.romanov@nginx.com adjust_idle_timer = 1; 3219507Smax.romanov@nginx.com app->adjust_idle_work.data = app; 3220507Smax.romanov@nginx.com app->adjust_idle_work.next = NULL; 3221507Smax.romanov@nginx.com } 3222507Smax.romanov@nginx.com 3223507Smax.romanov@nginx.com if (app->idle_processes < app->spare_processes) { 3224507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, &port->idle_link); 3225507Smax.romanov@nginx.com 3226507Smax.romanov@nginx.com } else { 3227507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->idle_ports, &port->idle_link); 3228507Smax.romanov@nginx.com 3229507Smax.romanov@nginx.com port->idle_start = task->thread->engine->timers.now; 3230507Smax.romanov@nginx.com } 3231507Smax.romanov@nginx.com 3232507Smax.romanov@nginx.com app->idle_processes++; 3233507Smax.romanov@nginx.com } 3234507Smax.romanov@nginx.com 3235343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3236343Smax.romanov@nginx.com 3237507Smax.romanov@nginx.com if (adjust_idle_timer) { 3238507Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 3239507Smax.romanov@nginx.com nxt_event_engine_post(app->engine, &app->adjust_idle_work); 3240507Smax.romanov@nginx.com } 3241507Smax.romanov@nginx.com 3242427Smax.romanov@nginx.com if (pending_ra != NULL) { 3243427Smax.romanov@nginx.com nxt_router_ra_use(task, pending_ra, -1); 3244427Smax.romanov@nginx.com } 3245427Smax.romanov@nginx.com 3246427Smax.romanov@nginx.com if (re_ra != NULL) { 3247427Smax.romanov@nginx.com if (nxt_router_port_post_select(task, &state) == NXT_OK) { 3248427Smax.romanov@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 3249427Smax.romanov@nginx.com nxt_router_app_process_request, 3250427Smax.romanov@nginx.com &task->thread->engine->task, app, re_ra); 3251427Smax.romanov@nginx.com } 3252425Smax.romanov@nginx.com } 3253425Smax.romanov@nginx.com 3254343Smax.romanov@nginx.com if (ra != NULL) { 3255425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 3256425Smax.romanov@nginx.com 3257343Smax.romanov@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 3258343Smax.romanov@nginx.com nxt_router_app_process_request, 3259343Smax.romanov@nginx.com &task->thread->engine->task, app, ra); 3260343Smax.romanov@nginx.com 3261343Smax.romanov@nginx.com goto adjust_use; 3262343Smax.romanov@nginx.com } 3263343Smax.romanov@nginx.com 3264343Smax.romanov@nginx.com /* ? */ 3265163Smax.romanov@nginx.com if (port->pair[1] == -1) { 3266343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)", 3267343Smax.romanov@nginx.com &app->name, app, port, port->pid); 3268343Smax.romanov@nginx.com 3269343Smax.romanov@nginx.com goto adjust_use; 3270163Smax.romanov@nginx.com } 3271163Smax.romanov@nginx.com 3272367Smax.romanov@nginx.com if (send_quit) { 3273507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p send QUIT to port", 3274167Smax.romanov@nginx.com &app->name, app); 3275163Smax.romanov@nginx.com 3276163Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, 3277163Smax.romanov@nginx.com -1, 0, 0, NULL); 3278163Smax.romanov@nginx.com 3279507Smax.romanov@nginx.com if (port_unchained) { 3280507Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3281507Smax.romanov@nginx.com } 3282507Smax.romanov@nginx.com 3283507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 3284507Smax.romanov@nginx.com 3285343Smax.romanov@nginx.com goto adjust_use; 3286163Smax.romanov@nginx.com } 3287163Smax.romanov@nginx.com 3288167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p requests queue is empty, keep the port", 3289167Smax.romanov@nginx.com &app->name, app); 3290141Smax.romanov@nginx.com 3291343Smax.romanov@nginx.com adjust_use: 3292343Smax.romanov@nginx.com 3293425Smax.romanov@nginx.com if (request_failed > 0 || got_response > 0) { 3294425Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3295343Smax.romanov@nginx.com } 3296141Smax.romanov@nginx.com } 3297141Smax.romanov@nginx.com 3298141Smax.romanov@nginx.com 3299343Smax.romanov@nginx.com void 3300343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port) 3301141Smax.romanov@nginx.com { 3302507Smax.romanov@nginx.com nxt_app_t *app; 3303507Smax.romanov@nginx.com nxt_bool_t unchain, start_process; 3304507Smax.romanov@nginx.com nxt_port_t *idle_port; 3305507Smax.romanov@nginx.com nxt_queue_link_t *idle_lnk; 3306141Smax.romanov@nginx.com 3307141Smax.romanov@nginx.com app = port->app; 3308343Smax.romanov@nginx.com 3309343Smax.romanov@nginx.com nxt_assert(app != NULL); 3310141Smax.romanov@nginx.com 3311141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3312141Smax.romanov@nginx.com 3313507Smax.romanov@nginx.com unchain = nxt_queue_chk_remove(&port->app_link); 3314507Smax.romanov@nginx.com 3315507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 3316507Smax.romanov@nginx.com app->idle_processes--; 3317507Smax.romanov@nginx.com 3318507Smax.romanov@nginx.com if (port->idle_start == 0 3319507Smax.romanov@nginx.com && app->idle_processes >= app->spare_processes) 3320507Smax.romanov@nginx.com { 3321507Smax.romanov@nginx.com nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); 3322507Smax.romanov@nginx.com 3323507Smax.romanov@nginx.com idle_lnk = nxt_queue_last(&app->idle_ports); 3324507Smax.romanov@nginx.com idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link); 3325507Smax.romanov@nginx.com nxt_queue_remove(idle_lnk); 3326507Smax.romanov@nginx.com 3327507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, idle_lnk); 3328507Smax.romanov@nginx.com 3329507Smax.romanov@nginx.com idle_port->idle_start = 0; 3330507Smax.romanov@nginx.com } 3331343Smax.romanov@nginx.com } 3332343Smax.romanov@nginx.com 3333507Smax.romanov@nginx.com app->processes--; 3334507Smax.romanov@nginx.com 3335507Smax.romanov@nginx.com start_process = app->live != 0 3336507Smax.romanov@nginx.com && !task->thread->engine->shutdown 3337507Smax.romanov@nginx.com && nxt_router_app_can_start(app) 3338507Smax.romanov@nginx.com && (!nxt_queue_is_empty(&app->requests) 3339507Smax.romanov@nginx.com || nxt_router_app_need_start(app)); 3340507Smax.romanov@nginx.com 3341507Smax.romanov@nginx.com if (start_process) { 3342507Smax.romanov@nginx.com app->pending_processes++; 3343163Smax.romanov@nginx.com } 3344141Smax.romanov@nginx.com 3345141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3346163Smax.romanov@nginx.com 3347507Smax.romanov@nginx.com nxt_debug(task, "app '%V' pid %PI closed", &app->name, port->pid); 3348343Smax.romanov@nginx.com 3349343Smax.romanov@nginx.com if (unchain) { 3350343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3351163Smax.romanov@nginx.com } 3352163Smax.romanov@nginx.com 3353507Smax.romanov@nginx.com if (start_process) { 3354507Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 3355507Smax.romanov@nginx.com } 3356507Smax.romanov@nginx.com } 3357507Smax.romanov@nginx.com 3358507Smax.romanov@nginx.com 3359507Smax.romanov@nginx.com static void 3360507Smax.romanov@nginx.com nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, void *data) 3361507Smax.romanov@nginx.com { 3362507Smax.romanov@nginx.com nxt_app_t *app; 3363507Smax.romanov@nginx.com nxt_bool_t queued; 3364507Smax.romanov@nginx.com nxt_port_t *port; 3365507Smax.romanov@nginx.com nxt_msec_t timeout, threshold; 3366507Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3367507Smax.romanov@nginx.com nxt_event_engine_t *engine; 3368507Smax.romanov@nginx.com 3369507Smax.romanov@nginx.com app = obj; 3370507Smax.romanov@nginx.com queued = (data == app); 3371507Smax.romanov@nginx.com 3372507Smax.romanov@nginx.com nxt_debug(task, "nxt_router_adjust_idle_timer: app \"%V\", queued %b", 3373507Smax.romanov@nginx.com &app->name, queued); 3374507Smax.romanov@nginx.com 3375507Smax.romanov@nginx.com engine = task->thread->engine; 3376507Smax.romanov@nginx.com 3377507Smax.romanov@nginx.com nxt_assert(app->engine == engine); 3378507Smax.romanov@nginx.com 3379507Smax.romanov@nginx.com threshold = engine->timers.now + app->idle_timer.precision; 3380507Smax.romanov@nginx.com timeout = 0; 3381507Smax.romanov@nginx.com 3382507Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3383507Smax.romanov@nginx.com 3384507Smax.romanov@nginx.com if (queued) { 3385507Smax.romanov@nginx.com app->adjust_idle_work.data = NULL; 3386343Smax.romanov@nginx.com } 3387507Smax.romanov@nginx.com 3388507Smax.romanov@nginx.com while (app->idle_processes > app->spare_processes) { 3389507Smax.romanov@nginx.com 3390551Smax.romanov@nginx.com nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); 3391507Smax.romanov@nginx.com 3392507Smax.romanov@nginx.com lnk = nxt_queue_first(&app->idle_ports); 3393507Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, idle_link); 3394507Smax.romanov@nginx.com 3395507Smax.romanov@nginx.com timeout = port->idle_start + app->idle_timeout; 3396507Smax.romanov@nginx.com 3397507Smax.romanov@nginx.com if (timeout > threshold) { 3398507Smax.romanov@nginx.com break; 3399507Smax.romanov@nginx.com } 3400507Smax.romanov@nginx.com 3401507Smax.romanov@nginx.com nxt_queue_remove(lnk); 3402507Smax.romanov@nginx.com lnk->next = NULL; 3403507Smax.romanov@nginx.com 3404507Smax.romanov@nginx.com nxt_queue_chk_remove(&port->app_link); 3405507Smax.romanov@nginx.com 3406507Smax.romanov@nginx.com app->idle_processes--; 3407507Smax.romanov@nginx.com app->processes--; 3408507Smax.romanov@nginx.com port->app = NULL; 3409507Smax.romanov@nginx.com 3410507Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3411507Smax.romanov@nginx.com 3412507Smax.romanov@nginx.com nxt_debug(task, "app '%V' send QUIT to idle port %PI", 3413507Smax.romanov@nginx.com &app->name, port->pid); 3414507Smax.romanov@nginx.com 3415507Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 3416507Smax.romanov@nginx.com 3417507Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3418507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 3419507Smax.romanov@nginx.com 3420507Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3421507Smax.romanov@nginx.com } 3422507Smax.romanov@nginx.com 3423507Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3424507Smax.romanov@nginx.com 3425507Smax.romanov@nginx.com if (timeout > threshold) { 3426507Smax.romanov@nginx.com nxt_timer_add(engine, &app->idle_timer, timeout - threshold); 3427507Smax.romanov@nginx.com 3428507Smax.romanov@nginx.com } else { 3429507Smax.romanov@nginx.com nxt_timer_disable(engine, &app->idle_timer); 3430507Smax.romanov@nginx.com } 3431507Smax.romanov@nginx.com 3432507Smax.romanov@nginx.com if (queued) { 3433507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 3434507Smax.romanov@nginx.com } 3435507Smax.romanov@nginx.com } 3436507Smax.romanov@nginx.com 3437507Smax.romanov@nginx.com 3438507Smax.romanov@nginx.com static void 3439507Smax.romanov@nginx.com nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, void *data) 3440507Smax.romanov@nginx.com { 3441507Smax.romanov@nginx.com nxt_app_t *app; 3442507Smax.romanov@nginx.com nxt_timer_t *timer; 3443507Smax.romanov@nginx.com 3444507Smax.romanov@nginx.com timer = obj; 3445507Smax.romanov@nginx.com app = nxt_container_of(timer, nxt_app_t, idle_timer); 3446507Smax.romanov@nginx.com 3447507Smax.romanov@nginx.com nxt_router_adjust_idle_timer(task, app, NULL); 3448507Smax.romanov@nginx.com } 3449507Smax.romanov@nginx.com 3450507Smax.romanov@nginx.com 3451507Smax.romanov@nginx.com static void 3452507Smax.romanov@nginx.com nxt_router_app_release_handler(nxt_task_t *task, void *obj, void *data) 3453507Smax.romanov@nginx.com { 3454507Smax.romanov@nginx.com nxt_app_t *app; 3455507Smax.romanov@nginx.com nxt_timer_t *timer; 3456507Smax.romanov@nginx.com 3457507Smax.romanov@nginx.com timer = obj; 3458507Smax.romanov@nginx.com app = nxt_container_of(timer, nxt_app_t, idle_timer); 3459507Smax.romanov@nginx.com 3460507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 3461141Smax.romanov@nginx.com } 3462141Smax.romanov@nginx.com 3463141Smax.romanov@nginx.com 3464427Smax.romanov@nginx.com static void 3465427Smax.romanov@nginx.com nxt_router_port_select(nxt_task_t *task, nxt_port_select_state_t *state) 3466141Smax.romanov@nginx.com { 3467427Smax.romanov@nginx.com nxt_app_t *app; 3468507Smax.romanov@nginx.com nxt_bool_t can_start_process; 3469427Smax.romanov@nginx.com nxt_req_app_link_t *ra; 3470427Smax.romanov@nginx.com 3471427Smax.romanov@nginx.com ra = state->ra; 3472427Smax.romanov@nginx.com app = state->app; 3473427Smax.romanov@nginx.com 3474427Smax.romanov@nginx.com state->failed_port_use_delta = 0; 3475343Smax.romanov@nginx.com 3476425Smax.romanov@nginx.com if (nxt_queue_chk_remove(&ra->link_app_requests)) 3477425Smax.romanov@nginx.com { 3478425Smax.romanov@nginx.com nxt_router_ra_dec_use(ra); 3479425Smax.romanov@nginx.com } 3480425Smax.romanov@nginx.com 3481425Smax.romanov@nginx.com if (nxt_queue_chk_remove(&ra->link_port_pending)) 3482425Smax.romanov@nginx.com { 3483427Smax.romanov@nginx.com nxt_assert(ra->link_app_pending.next != NULL); 3484427Smax.romanov@nginx.com 3485427Smax.romanov@nginx.com nxt_queue_remove(&ra->link_app_pending); 3486427Smax.romanov@nginx.com ra->link_app_pending.next = NULL; 3487427Smax.romanov@nginx.com 3488425Smax.romanov@nginx.com nxt_router_ra_dec_use(ra); 3489425Smax.romanov@nginx.com } 3490425Smax.romanov@nginx.com 3491427Smax.romanov@nginx.com state->failed_port = ra->app_port; 3492427Smax.romanov@nginx.com 3493425Smax.romanov@nginx.com if (ra->app_port != NULL) { 3494427Smax.romanov@nginx.com state->failed_port_use_delta--; 3495427Smax.romanov@nginx.com 3496427Smax.romanov@nginx.com state->failed_port->app_pending_responses--; 3497427Smax.romanov@nginx.com 3498427Smax.romanov@nginx.com if (nxt_queue_chk_remove(&state->failed_port->app_link)) { 3499427Smax.romanov@nginx.com state->failed_port_use_delta--; 3500427Smax.romanov@nginx.com } 3501427Smax.romanov@nginx.com 3502427Smax.romanov@nginx.com ra->app_port = NULL; 3503427Smax.romanov@nginx.com } 3504427Smax.romanov@nginx.com 3505507Smax.romanov@nginx.com can_start_process = nxt_router_app_can_start(app); 3506507Smax.romanov@nginx.com 3507427Smax.romanov@nginx.com state->port = NULL; 3508507Smax.romanov@nginx.com state->start_process = 0; 3509427Smax.romanov@nginx.com 3510427Smax.romanov@nginx.com if (nxt_queue_is_empty(&app->ports) 3511507Smax.romanov@nginx.com || (can_start_process && nxt_router_app_first_port_busy(app)) ) 3512427Smax.romanov@nginx.com { 3513427Smax.romanov@nginx.com ra = nxt_router_ra_create(task, ra); 3514427Smax.romanov@nginx.com 3515427Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 3516427Smax.romanov@nginx.com goto fail; 3517427Smax.romanov@nginx.com } 3518427Smax.romanov@nginx.com 3519427Smax.romanov@nginx.com if (nxt_slow_path(state->failed_port != NULL)) { 3520427Smax.romanov@nginx.com nxt_queue_insert_head(&app->requests, &ra->link_app_requests); 3521427Smax.romanov@nginx.com 3522427Smax.romanov@nginx.com } else { 3523427Smax.romanov@nginx.com nxt_queue_insert_tail(&app->requests, &ra->link_app_requests); 3524427Smax.romanov@nginx.com } 3525427Smax.romanov@nginx.com 3526427Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 3527427Smax.romanov@nginx.com 3528427Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD enqueue to app->requests", ra->stream); 3529427Smax.romanov@nginx.com 3530507Smax.romanov@nginx.com if (can_start_process) { 3531507Smax.romanov@nginx.com app->pending_processes++; 3532507Smax.romanov@nginx.com state->start_process = 1; 3533425Smax.romanov@nginx.com } 3534425Smax.romanov@nginx.com 3535425Smax.romanov@nginx.com } else { 3536427Smax.romanov@nginx.com state->port = nxt_router_pop_first_port(app); 3537427Smax.romanov@nginx.com 3538427Smax.romanov@nginx.com if (state->port->app_pending_responses > 1) { 3539427Smax.romanov@nginx.com ra = nxt_router_ra_create(task, ra); 3540427Smax.romanov@nginx.com 3541427Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 3542427Smax.romanov@nginx.com goto fail; 3543351Smax.romanov@nginx.com } 3544427Smax.romanov@nginx.com 3545427Smax.romanov@nginx.com ra->app_port = state->port; 3546427Smax.romanov@nginx.com 3547427Smax.romanov@nginx.com nxt_router_ra_pending(task, app, ra); 3548425Smax.romanov@nginx.com } 3549507Smax.romanov@nginx.com 3550507Smax.romanov@nginx.com if (can_start_process && nxt_router_app_need_start(app)) { 3551507Smax.romanov@nginx.com app->pending_processes++; 3552507Smax.romanov@nginx.com state->start_process = 1; 3553507Smax.romanov@nginx.com } 3554343Smax.romanov@nginx.com } 3555343Smax.romanov@nginx.com 3556427Smax.romanov@nginx.com fail: 3557427Smax.romanov@nginx.com 3558427Smax.romanov@nginx.com state->shared_ra = ra; 3559427Smax.romanov@nginx.com } 3560427Smax.romanov@nginx.com 3561427Smax.romanov@nginx.com 3562427Smax.romanov@nginx.com static nxt_int_t 3563427Smax.romanov@nginx.com nxt_router_port_post_select(nxt_task_t *task, nxt_port_select_state_t *state) 3564427Smax.romanov@nginx.com { 3565427Smax.romanov@nginx.com nxt_int_t res; 3566427Smax.romanov@nginx.com nxt_app_t *app; 3567427Smax.romanov@nginx.com nxt_req_app_link_t *ra; 3568427Smax.romanov@nginx.com 3569427Smax.romanov@nginx.com ra = state->shared_ra; 3570427Smax.romanov@nginx.com app = state->app; 3571427Smax.romanov@nginx.com 3572427Smax.romanov@nginx.com if (state->failed_port_use_delta != 0) { 3573427Smax.romanov@nginx.com nxt_port_use(task, state->failed_port, state->failed_port_use_delta); 3574425Smax.romanov@nginx.com } 3575425Smax.romanov@nginx.com 3576351Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 3577427Smax.romanov@nginx.com if (state->port != NULL) { 3578427Smax.romanov@nginx.com nxt_port_use(task, state->port, -1); 3579425Smax.romanov@nginx.com } 3580425Smax.romanov@nginx.com 3581427Smax.romanov@nginx.com nxt_router_ra_error(state->ra, 500, 3582427Smax.romanov@nginx.com "Failed to allocate shared req<->app link"); 3583427Smax.romanov@nginx.com nxt_router_ra_use(task, state->ra, -1); 3584427Smax.romanov@nginx.com 3585351Smax.romanov@nginx.com return NXT_ERROR; 3586351Smax.romanov@nginx.com } 3587351Smax.romanov@nginx.com 3588427Smax.romanov@nginx.com if (state->port != NULL) { 3589343Smax.romanov@nginx.com nxt_debug(task, "already have port for app '%V' %p ", &app->name, app); 3590163Smax.romanov@nginx.com 3591427Smax.romanov@nginx.com ra->app_port = state->port; 3592343Smax.romanov@nginx.com 3593507Smax.romanov@nginx.com if (state->start_process) { 3594507Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 3595507Smax.romanov@nginx.com } 3596507Smax.romanov@nginx.com 3597141Smax.romanov@nginx.com return NXT_OK; 3598141Smax.romanov@nginx.com } 3599141Smax.romanov@nginx.com 3600507Smax.romanov@nginx.com if (!state->start_process) { 3601507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p too many running or pending processes", 3602343Smax.romanov@nginx.com &app->name, app); 3603343Smax.romanov@nginx.com 3604343Smax.romanov@nginx.com return NXT_AGAIN; 3605343Smax.romanov@nginx.com } 3606343Smax.romanov@nginx.com 3607507Smax.romanov@nginx.com res = nxt_router_start_app_process(task, app); 3608343Smax.romanov@nginx.com 3609343Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3610507Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, "Failed to start app process"); 3611427Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 3612343Smax.romanov@nginx.com 3613141Smax.romanov@nginx.com return NXT_ERROR; 3614141Smax.romanov@nginx.com } 3615141Smax.romanov@nginx.com 3616141Smax.romanov@nginx.com return NXT_AGAIN; 361788Smax.romanov@nginx.com } 361888Smax.romanov@nginx.com 361988Smax.romanov@nginx.com 3620427Smax.romanov@nginx.com static nxt_int_t 3621427Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra) 3622427Smax.romanov@nginx.com { 3623427Smax.romanov@nginx.com nxt_port_select_state_t state; 3624427Smax.romanov@nginx.com 3625427Smax.romanov@nginx.com state.ra = ra; 3626427Smax.romanov@nginx.com state.app = app; 3627427Smax.romanov@nginx.com 3628427Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3629427Smax.romanov@nginx.com 3630427Smax.romanov@nginx.com nxt_router_port_select(task, &state); 3631427Smax.romanov@nginx.com 3632427Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3633427Smax.romanov@nginx.com 3634427Smax.romanov@nginx.com return nxt_router_port_post_select(task, &state); 3635427Smax.romanov@nginx.com } 3636427Smax.romanov@nginx.com 3637427Smax.romanov@nginx.com 3638431Sigor@sysoev.ru void 3639431Sigor@sysoev.ru nxt_router_process_http_request(nxt_task_t *task, nxt_app_parse_ctx_t *ar) 364053Sigor@sysoev.ru { 3641431Sigor@sysoev.ru nxt_int_t res; 3642431Sigor@sysoev.ru nxt_app_t *app; 3643431Sigor@sysoev.ru nxt_port_t *port; 3644431Sigor@sysoev.ru nxt_event_engine_t *engine; 3645431Sigor@sysoev.ru nxt_http_request_t *r; 3646431Sigor@sysoev.ru nxt_req_app_link_t ra_local, *ra; 3647431Sigor@sysoev.ru nxt_req_conn_link_t *rc; 3648431Sigor@sysoev.ru 3649431Sigor@sysoev.ru r = ar->request; 3650431Sigor@sysoev.ru app = r->socket_conf->application; 3651425Smax.romanov@nginx.com 3652425Smax.romanov@nginx.com if (app == NULL) { 3653431Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 3654425Smax.romanov@nginx.com return; 3655425Smax.romanov@nginx.com } 365688Smax.romanov@nginx.com 365788Smax.romanov@nginx.com engine = task->thread->engine; 365888Smax.romanov@nginx.com 3659318Smax.romanov@nginx.com rc = nxt_port_rpc_register_handler_ex(task, engine->port, 3660318Smax.romanov@nginx.com nxt_router_response_ready_handler, 3661318Smax.romanov@nginx.com nxt_router_response_error_handler, 3662318Smax.romanov@nginx.com sizeof(nxt_req_conn_link_t)); 3663122Smax.romanov@nginx.com 366488Smax.romanov@nginx.com if (nxt_slow_path(rc == NULL)) { 3665431Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 3666141Smax.romanov@nginx.com return; 366788Smax.romanov@nginx.com } 366888Smax.romanov@nginx.com 3669318Smax.romanov@nginx.com rc->stream = nxt_port_rpc_ex_stream(rc); 3670425Smax.romanov@nginx.com rc->app = app; 3671425Smax.romanov@nginx.com 3672425Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 3673425Smax.romanov@nginx.com 3674431Sigor@sysoev.ru rc->ap = ar; 3675346Smax.romanov@nginx.com 3676351Smax.romanov@nginx.com ra = &ra_local; 3677351Smax.romanov@nginx.com nxt_router_ra_init(task, ra, rc); 3678167Smax.romanov@nginx.com 3679427Smax.romanov@nginx.com res = nxt_router_app_port(task, app, ra); 3680141Smax.romanov@nginx.com 3681141Smax.romanov@nginx.com if (res != NXT_OK) { 3682141Smax.romanov@nginx.com return; 3683141Smax.romanov@nginx.com } 3684141Smax.romanov@nginx.com 3685425Smax.romanov@nginx.com ra = rc->ra; 3686167Smax.romanov@nginx.com port = ra->app_port; 3687141Smax.romanov@nginx.com 3688425Smax.romanov@nginx.com nxt_assert(port != NULL); 3689141Smax.romanov@nginx.com 3690318Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, engine->port, rc, port->pid); 3691318Smax.romanov@nginx.com 3692425Smax.romanov@nginx.com nxt_router_app_prepare_request(task, ra); 3693167Smax.romanov@nginx.com } 3694167Smax.romanov@nginx.com 3695167Smax.romanov@nginx.com 3696167Smax.romanov@nginx.com static void 3697423Smax.romanov@nginx.com nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj, void *data) 3698423Smax.romanov@nginx.com { 3699423Smax.romanov@nginx.com } 3700423Smax.romanov@nginx.com 3701423Smax.romanov@nginx.com 3702423Smax.romanov@nginx.com static void 3703425Smax.romanov@nginx.com nxt_router_app_prepare_request(nxt_task_t *task, nxt_req_app_link_t *ra) 3704167Smax.romanov@nginx.com { 3705343Smax.romanov@nginx.com uint32_t request_failed; 3706423Smax.romanov@nginx.com nxt_buf_t *b; 3707167Smax.romanov@nginx.com nxt_int_t res; 3708343Smax.romanov@nginx.com nxt_port_t *port, *c_port, *reply_port; 3709167Smax.romanov@nginx.com nxt_app_wmsg_t wmsg; 3710167Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 3711167Smax.romanov@nginx.com 3712343Smax.romanov@nginx.com nxt_assert(ra->app_port != NULL); 3713343Smax.romanov@nginx.com 3714343Smax.romanov@nginx.com port = ra->app_port; 3715167Smax.romanov@nginx.com reply_port = ra->reply_port; 3716167Smax.romanov@nginx.com ap = ra->ap; 3717141Smax.romanov@nginx.com 3718343Smax.romanov@nginx.com request_failed = 1; 3719343Smax.romanov@nginx.com 3720141Smax.romanov@nginx.com c_port = nxt_process_connected_port_find(port->process, reply_port->pid, 3721141Smax.romanov@nginx.com reply_port->id); 3722141Smax.romanov@nginx.com if (nxt_slow_path(c_port != reply_port)) { 3723141Smax.romanov@nginx.com res = nxt_port_send_port(task, port, reply_port, 0); 3724122Smax.romanov@nginx.com 3725122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3726423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 3727345Smax.romanov@nginx.com "Failed to send reply port to application"); 3728343Smax.romanov@nginx.com goto release_port; 3729122Smax.romanov@nginx.com } 3730122Smax.romanov@nginx.com 3731141Smax.romanov@nginx.com nxt_process_connected_port_add(port->process, reply_port); 373288Smax.romanov@nginx.com } 373388Smax.romanov@nginx.com 373488Smax.romanov@nginx.com wmsg.port = port; 373588Smax.romanov@nginx.com wmsg.write = NULL; 373688Smax.romanov@nginx.com wmsg.buf = &wmsg.write; 3737318Smax.romanov@nginx.com wmsg.stream = ra->stream; 3738167Smax.romanov@nginx.com 3739216Sigor@sysoev.ru res = port->app->prepare_msg(task, &ap->r, &wmsg); 3740122Smax.romanov@nginx.com 3741122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3742423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 3743345Smax.romanov@nginx.com "Failed to prepare message for application"); 3744343Smax.romanov@nginx.com goto release_port; 3745122Smax.romanov@nginx.com } 374688Smax.romanov@nginx.com 3747507Smax.romanov@nginx.com nxt_debug(task, "about to send %O bytes buffer to app process port %d", 374888Smax.romanov@nginx.com nxt_buf_used_size(wmsg.write), 374988Smax.romanov@nginx.com wmsg.port->socket.fd); 375088Smax.romanov@nginx.com 3751343Smax.romanov@nginx.com request_failed = 0; 3752343Smax.romanov@nginx.com 3753423Smax.romanov@nginx.com ra->msg_info.buf = wmsg.write; 3754423Smax.romanov@nginx.com ra->msg_info.completion_handler = wmsg.write->completion_handler; 3755423Smax.romanov@nginx.com 3756423Smax.romanov@nginx.com for (b = wmsg.write; b != NULL; b = b->next) { 3757423Smax.romanov@nginx.com b->completion_handler = nxt_router_dummy_buf_completion; 3758423Smax.romanov@nginx.com } 3759423Smax.romanov@nginx.com 3760423Smax.romanov@nginx.com res = nxt_port_mmap_get_tracking(task, port, &ra->msg_info.tracking, 3761423Smax.romanov@nginx.com ra->stream); 3762423Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3763423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 3764423Smax.romanov@nginx.com "Failed to get tracking area"); 3765423Smax.romanov@nginx.com goto release_port; 3766423Smax.romanov@nginx.com } 3767423Smax.romanov@nginx.com 3768423Smax.romanov@nginx.com res = nxt_port_socket_twrite(task, wmsg.port, NXT_PORT_MSG_DATA, 3769423Smax.romanov@nginx.com -1, ra->stream, reply_port->id, wmsg.write, 3770423Smax.romanov@nginx.com &ra->msg_info.tracking); 3771122Smax.romanov@nginx.com 3772122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3773423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 3774345Smax.romanov@nginx.com "Failed to send message to application"); 3775343Smax.romanov@nginx.com goto release_port; 3776122Smax.romanov@nginx.com } 3777343Smax.romanov@nginx.com 3778343Smax.romanov@nginx.com release_port: 3779343Smax.romanov@nginx.com 3780345Smax.romanov@nginx.com nxt_router_app_port_release(task, port, request_failed, 0); 3781345Smax.romanov@nginx.com 3782425Smax.romanov@nginx.com nxt_router_ra_update_peer(task, ra); 378353Sigor@sysoev.ru } 378453Sigor@sysoev.ru 378553Sigor@sysoev.ru 3786216Sigor@sysoev.ru static nxt_int_t 3787216Sigor@sysoev.ru nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 3788216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg) 3789216Sigor@sysoev.ru { 3790216Sigor@sysoev.ru nxt_int_t rc; 3791216Sigor@sysoev.ru nxt_buf_t *b; 3792216Sigor@sysoev.ru nxt_http_field_t *field; 3793216Sigor@sysoev.ru nxt_app_request_header_t *h; 3794216Sigor@sysoev.ru 3795216Sigor@sysoev.ru static const nxt_str_t prefix = nxt_string("HTTP_"); 3796216Sigor@sysoev.ru static const nxt_str_t eof = nxt_null_string; 3797216Sigor@sysoev.ru 3798216Sigor@sysoev.ru h = &r->header; 3799216Sigor@sysoev.ru 3800216Sigor@sysoev.ru #define RC(S) \ 3801216Sigor@sysoev.ru do { \ 3802216Sigor@sysoev.ru rc = (S); \ 3803216Sigor@sysoev.ru if (nxt_slow_path(rc != NXT_OK)) { \ 3804216Sigor@sysoev.ru goto fail; \ 3805216Sigor@sysoev.ru } \ 3806216Sigor@sysoev.ru } while(0) 3807216Sigor@sysoev.ru 3808216Sigor@sysoev.ru #define NXT_WRITE(N) \ 3809216Sigor@sysoev.ru RC(nxt_app_msg_write_str(task, wmsg, N)) 3810216Sigor@sysoev.ru 3811216Sigor@sysoev.ru /* TODO error handle, async mmap buffer assignment */ 3812216Sigor@sysoev.ru 3813216Sigor@sysoev.ru NXT_WRITE(&h->method); 3814216Sigor@sysoev.ru NXT_WRITE(&h->target); 3815277Sigor@sysoev.ru 3816216Sigor@sysoev.ru if (h->path.start == h->target.start) { 3817216Sigor@sysoev.ru NXT_WRITE(&eof); 3818277Sigor@sysoev.ru 3819216Sigor@sysoev.ru } else { 3820216Sigor@sysoev.ru NXT_WRITE(&h->path); 3821216Sigor@sysoev.ru } 3822216Sigor@sysoev.ru 3823216Sigor@sysoev.ru if (h->query.start != NULL) { 3824216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 3825216Sigor@sysoev.ru h->query.start - h->target.start + 1)); 3826216Sigor@sysoev.ru } else { 3827216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 0)); 3828216Sigor@sysoev.ru } 3829216Sigor@sysoev.ru 3830216Sigor@sysoev.ru NXT_WRITE(&h->version); 3831216Sigor@sysoev.ru 3832216Sigor@sysoev.ru NXT_WRITE(&r->remote); 3833268Sigor@sysoev.ru NXT_WRITE(&r->local); 3834216Sigor@sysoev.ru 3835216Sigor@sysoev.ru NXT_WRITE(&h->host); 3836216Sigor@sysoev.ru NXT_WRITE(&h->content_type); 3837216Sigor@sysoev.ru NXT_WRITE(&h->content_length); 3838216Sigor@sysoev.ru 3839216Sigor@sysoev.ru nxt_list_each(field, h->fields) { 3840417Svbart@nginx.com RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, &prefix, field->name, 3841417Svbart@nginx.com field->name_length)); 3842417Svbart@nginx.com RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length)); 3843216Sigor@sysoev.ru 3844216Sigor@sysoev.ru } nxt_list_loop; 3845216Sigor@sysoev.ru 3846216Sigor@sysoev.ru /* end-of-headers mark */ 3847216Sigor@sysoev.ru NXT_WRITE(&eof); 3848216Sigor@sysoev.ru 3849216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 3850216Sigor@sysoev.ru 3851510Salexander.borisov@nginx.com for (b = r->body.buf; b != NULL; b = b->next) { 3852216Sigor@sysoev.ru RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3853216Sigor@sysoev.ru nxt_buf_mem_used_size(&b->mem))); 3854216Sigor@sysoev.ru } 3855216Sigor@sysoev.ru 3856216Sigor@sysoev.ru #undef NXT_WRITE 3857216Sigor@sysoev.ru #undef RC 3858216Sigor@sysoev.ru 3859216Sigor@sysoev.ru return NXT_OK; 3860216Sigor@sysoev.ru 3861216Sigor@sysoev.ru fail: 3862216Sigor@sysoev.ru 3863216Sigor@sysoev.ru return NXT_ERROR; 3864216Sigor@sysoev.ru } 3865216Sigor@sysoev.ru 3866216Sigor@sysoev.ru 3867216Sigor@sysoev.ru static nxt_int_t 3868216Sigor@sysoev.ru nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 3869216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg) 3870216Sigor@sysoev.ru { 3871216Sigor@sysoev.ru nxt_int_t rc; 3872216Sigor@sysoev.ru nxt_buf_t *b; 3873305Smax.romanov@nginx.com nxt_bool_t method_is_post; 3874216Sigor@sysoev.ru nxt_http_field_t *field; 3875216Sigor@sysoev.ru nxt_app_request_header_t *h; 3876216Sigor@sysoev.ru 3877216Sigor@sysoev.ru static const nxt_str_t prefix = nxt_string("HTTP_"); 3878216Sigor@sysoev.ru static const nxt_str_t eof = nxt_null_string; 3879216Sigor@sysoev.ru 3880216Sigor@sysoev.ru h = &r->header; 3881216Sigor@sysoev.ru 3882216Sigor@sysoev.ru #define RC(S) \ 3883216Sigor@sysoev.ru do { \ 3884216Sigor@sysoev.ru rc = (S); \ 3885216Sigor@sysoev.ru if (nxt_slow_path(rc != NXT_OK)) { \ 3886216Sigor@sysoev.ru goto fail; \ 3887216Sigor@sysoev.ru } \ 3888216Sigor@sysoev.ru } while(0) 3889216Sigor@sysoev.ru 3890216Sigor@sysoev.ru #define NXT_WRITE(N) \ 3891216Sigor@sysoev.ru RC(nxt_app_msg_write_str(task, wmsg, N)) 3892216Sigor@sysoev.ru 3893216Sigor@sysoev.ru /* TODO error handle, async mmap buffer assignment */ 3894216Sigor@sysoev.ru 3895216Sigor@sysoev.ru NXT_WRITE(&h->method); 3896216Sigor@sysoev.ru NXT_WRITE(&h->target); 3897277Sigor@sysoev.ru 3898216Sigor@sysoev.ru if (h->path.start == h->target.start) { 3899216Sigor@sysoev.ru NXT_WRITE(&eof); 3900277Sigor@sysoev.ru 3901216Sigor@sysoev.ru } else { 3902216Sigor@sysoev.ru NXT_WRITE(&h->path); 3903216Sigor@sysoev.ru } 3904216Sigor@sysoev.ru 3905216Sigor@sysoev.ru if (h->query.start != NULL) { 3906216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 3907216Sigor@sysoev.ru h->query.start - h->target.start + 1)); 3908216Sigor@sysoev.ru } else { 3909216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 0)); 3910216Sigor@sysoev.ru } 3911216Sigor@sysoev.ru 3912216Sigor@sysoev.ru NXT_WRITE(&h->version); 3913216Sigor@sysoev.ru 3914216Sigor@sysoev.ru // PHP_SELF 3915216Sigor@sysoev.ru // SCRIPT_NAME 3916216Sigor@sysoev.ru // SCRIPT_FILENAME 3917216Sigor@sysoev.ru // DOCUMENT_ROOT 3918216Sigor@sysoev.ru 3919216Sigor@sysoev.ru NXT_WRITE(&r->remote); 3920268Sigor@sysoev.ru NXT_WRITE(&r->local); 3921216Sigor@sysoev.ru 3922216Sigor@sysoev.ru NXT_WRITE(&h->host); 3923216Sigor@sysoev.ru NXT_WRITE(&h->cookie); 3924216Sigor@sysoev.ru NXT_WRITE(&h->content_type); 3925216Sigor@sysoev.ru NXT_WRITE(&h->content_length); 3926216Sigor@sysoev.ru 3927216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length)); 3928305Smax.romanov@nginx.com RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 3929305Smax.romanov@nginx.com 3930426Smax.romanov@nginx.com method_is_post = h->method.length == 4 3931426Smax.romanov@nginx.com && h->method.start[0] == 'P' 3932426Smax.romanov@nginx.com && h->method.start[1] == 'O' 3933426Smax.romanov@nginx.com && h->method.start[2] == 'S' 3934426Smax.romanov@nginx.com && h->method.start[3] == 'T'; 3935305Smax.romanov@nginx.com 3936305Smax.romanov@nginx.com if (method_is_post) { 3937510Salexander.borisov@nginx.com for (b = r->body.buf; b != NULL; b = b->next) { 3938305Smax.romanov@nginx.com RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3939305Smax.romanov@nginx.com nxt_buf_mem_used_size(&b->mem))); 3940305Smax.romanov@nginx.com } 3941305Smax.romanov@nginx.com } 3942216Sigor@sysoev.ru 3943216Sigor@sysoev.ru nxt_list_each(field, h->fields) { 3944417Svbart@nginx.com RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, &prefix, field->name, 3945417Svbart@nginx.com field->name_length)); 3946417Svbart@nginx.com RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length)); 3947216Sigor@sysoev.ru 3948216Sigor@sysoev.ru } nxt_list_loop; 3949216Sigor@sysoev.ru 3950216Sigor@sysoev.ru /* end-of-headers mark */ 3951216Sigor@sysoev.ru NXT_WRITE(&eof); 3952216Sigor@sysoev.ru 3953305Smax.romanov@nginx.com if (!method_is_post) { 3954510Salexander.borisov@nginx.com for (b = r->body.buf; b != NULL; b = b->next) { 3955305Smax.romanov@nginx.com RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3956305Smax.romanov@nginx.com nxt_buf_mem_used_size(&b->mem))); 3957305Smax.romanov@nginx.com } 3958216Sigor@sysoev.ru } 3959216Sigor@sysoev.ru 3960216Sigor@sysoev.ru #undef NXT_WRITE 3961216Sigor@sysoev.ru #undef RC 3962216Sigor@sysoev.ru 3963216Sigor@sysoev.ru return NXT_OK; 3964216Sigor@sysoev.ru 3965216Sigor@sysoev.ru fail: 3966216Sigor@sysoev.ru 3967216Sigor@sysoev.ru return NXT_ERROR; 3968216Sigor@sysoev.ru } 3969216Sigor@sysoev.ru 3970216Sigor@sysoev.ru 3971216Sigor@sysoev.ru static nxt_int_t 3972216Sigor@sysoev.ru nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, nxt_app_wmsg_t *wmsg) 3973216Sigor@sysoev.ru { 3974216Sigor@sysoev.ru nxt_int_t rc; 3975216Sigor@sysoev.ru nxt_buf_t *b; 3976216Sigor@sysoev.ru nxt_http_field_t *field; 3977216Sigor@sysoev.ru nxt_app_request_header_t *h; 3978216Sigor@sysoev.ru 3979216Sigor@sysoev.ru static const nxt_str_t eof = nxt_null_string; 3980216Sigor@sysoev.ru 3981216Sigor@sysoev.ru h = &r->header; 3982216Sigor@sysoev.ru 3983216Sigor@sysoev.ru #define RC(S) \ 3984216Sigor@sysoev.ru do { \ 3985216Sigor@sysoev.ru rc = (S); \ 3986216Sigor@sysoev.ru if (nxt_slow_path(rc != NXT_OK)) { \ 3987216Sigor@sysoev.ru goto fail; \ 3988216Sigor@sysoev.ru } \ 3989216Sigor@sysoev.ru } while(0) 3990216Sigor@sysoev.ru 3991216Sigor@sysoev.ru #define NXT_WRITE(N) \ 3992216Sigor@sysoev.ru RC(nxt_app_msg_write_str(task, wmsg, N)) 3993216Sigor@sysoev.ru 3994216Sigor@sysoev.ru /* TODO error handle, async mmap buffer assignment */ 3995216Sigor@sysoev.ru 3996216Sigor@sysoev.ru NXT_WRITE(&h->method); 3997216Sigor@sysoev.ru NXT_WRITE(&h->target); 3998277Sigor@sysoev.ru 3999216Sigor@sysoev.ru if (h->path.start == h->target.start) { 4000216Sigor@sysoev.ru NXT_WRITE(&eof); 4001277Sigor@sysoev.ru 4002216Sigor@sysoev.ru } else { 4003216Sigor@sysoev.ru NXT_WRITE(&h->path); 4004216Sigor@sysoev.ru } 4005216Sigor@sysoev.ru 4006216Sigor@sysoev.ru if (h->query.start != NULL) { 4007216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 4008216Sigor@sysoev.ru h->query.start - h->target.start + 1)); 4009216Sigor@sysoev.ru } else { 4010216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 0)); 4011216Sigor@sysoev.ru } 4012216Sigor@sysoev.ru 4013216Sigor@sysoev.ru NXT_WRITE(&h->version); 4014253Smax.romanov@nginx.com NXT_WRITE(&r->remote); 4015216Sigor@sysoev.ru 4016216Sigor@sysoev.ru NXT_WRITE(&h->host); 4017216Sigor@sysoev.ru NXT_WRITE(&h->cookie); 4018216Sigor@sysoev.ru NXT_WRITE(&h->content_type); 4019216Sigor@sysoev.ru NXT_WRITE(&h->content_length); 4020216Sigor@sysoev.ru 4021216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length)); 4022216Sigor@sysoev.ru 4023216Sigor@sysoev.ru nxt_list_each(field, h->fields) { 4024417Svbart@nginx.com RC(nxt_app_msg_write(task, wmsg, field->name, field->name_length)); 4025417Svbart@nginx.com RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length)); 4026216Sigor@sysoev.ru 4027216Sigor@sysoev.ru } nxt_list_loop; 4028216Sigor@sysoev.ru 4029216Sigor@sysoev.ru /* end-of-headers mark */ 4030216Sigor@sysoev.ru NXT_WRITE(&eof); 4031216Sigor@sysoev.ru 4032216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 4033216Sigor@sysoev.ru 4034510Salexander.borisov@nginx.com for (b = r->body.buf; b != NULL; b = b->next) { 4035510Salexander.borisov@nginx.com RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 4036510Salexander.borisov@nginx.com nxt_buf_mem_used_size(&b->mem))); 4037510Salexander.borisov@nginx.com } 4038510Salexander.borisov@nginx.com 4039510Salexander.borisov@nginx.com #undef NXT_WRITE 4040510Salexander.borisov@nginx.com #undef RC 4041510Salexander.borisov@nginx.com 4042510Salexander.borisov@nginx.com return NXT_OK; 4043510Salexander.borisov@nginx.com 4044510Salexander.borisov@nginx.com fail: 4045510Salexander.borisov@nginx.com 4046510Salexander.borisov@nginx.com return NXT_ERROR; 4047510Salexander.borisov@nginx.com } 4048510Salexander.borisov@nginx.com 4049510Salexander.borisov@nginx.com 4050510Salexander.borisov@nginx.com static nxt_int_t 4051510Salexander.borisov@nginx.com nxt_perl_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 4052510Salexander.borisov@nginx.com nxt_app_wmsg_t *wmsg) 4053510Salexander.borisov@nginx.com { 4054510Salexander.borisov@nginx.com nxt_int_t rc; 4055510Salexander.borisov@nginx.com nxt_str_t str; 4056510Salexander.borisov@nginx.com nxt_buf_t *b; 4057510Salexander.borisov@nginx.com nxt_http_field_t *field; 4058510Salexander.borisov@nginx.com nxt_app_request_header_t *h; 4059510Salexander.borisov@nginx.com 4060510Salexander.borisov@nginx.com static const nxt_str_t prefix = nxt_string("HTTP_"); 4061510Salexander.borisov@nginx.com static const nxt_str_t eof = nxt_null_string; 4062510Salexander.borisov@nginx.com 4063510Salexander.borisov@nginx.com h = &r->header; 4064510Salexander.borisov@nginx.com 4065510Salexander.borisov@nginx.com #define RC(S) \ 4066510Salexander.borisov@nginx.com do { \ 4067510Salexander.borisov@nginx.com rc = (S); \ 4068510Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { \ 4069510Salexander.borisov@nginx.com goto fail; \ 4070510Salexander.borisov@nginx.com } \ 4071510Salexander.borisov@nginx.com } while(0) 4072510Salexander.borisov@nginx.com 4073510Salexander.borisov@nginx.com #define NXT_WRITE(N) \ 4074510Salexander.borisov@nginx.com RC(nxt_app_msg_write_str(task, wmsg, N)) 4075510Salexander.borisov@nginx.com 4076510Salexander.borisov@nginx.com /* TODO error handle, async mmap buffer assignment */ 4077510Salexander.borisov@nginx.com 4078510Salexander.borisov@nginx.com NXT_WRITE(&h->method); 4079510Salexander.borisov@nginx.com NXT_WRITE(&h->target); 4080510Salexander.borisov@nginx.com 4081510Salexander.borisov@nginx.com if (h->query.length) { 4082510Salexander.borisov@nginx.com str.start = h->target.start; 4083510Salexander.borisov@nginx.com str.length = (h->target.length - h->query.length) - 1; 4084510Salexander.borisov@nginx.com 4085510Salexander.borisov@nginx.com RC(nxt_app_msg_write_str(task, wmsg, &str)); 4086510Salexander.borisov@nginx.com 4087510Salexander.borisov@nginx.com } else { 4088510Salexander.borisov@nginx.com NXT_WRITE(&eof); 4089510Salexander.borisov@nginx.com } 4090510Salexander.borisov@nginx.com 4091510Salexander.borisov@nginx.com if (h->query.start != NULL) { 4092510Salexander.borisov@nginx.com RC(nxt_app_msg_write_size(task, wmsg, 4093510Salexander.borisov@nginx.com h->query.start - h->target.start + 1)); 4094510Salexander.borisov@nginx.com } else { 4095510Salexander.borisov@nginx.com RC(nxt_app_msg_write_size(task, wmsg, 0)); 4096510Salexander.borisov@nginx.com } 4097510Salexander.borisov@nginx.com 4098510Salexander.borisov@nginx.com NXT_WRITE(&h->version); 4099510Salexander.borisov@nginx.com 4100510Salexander.borisov@nginx.com NXT_WRITE(&r->remote); 4101510Salexander.borisov@nginx.com NXT_WRITE(&r->local); 4102510Salexander.borisov@nginx.com 4103510Salexander.borisov@nginx.com NXT_WRITE(&h->host); 4104510Salexander.borisov@nginx.com NXT_WRITE(&h->content_type); 4105510Salexander.borisov@nginx.com NXT_WRITE(&h->content_length); 4106510Salexander.borisov@nginx.com 4107510Salexander.borisov@nginx.com nxt_list_each(field, h->fields) { 4108510Salexander.borisov@nginx.com RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, &prefix, 4109510Salexander.borisov@nginx.com field->name, field->name_length)); 4110510Salexander.borisov@nginx.com RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length)); 4111510Salexander.borisov@nginx.com } nxt_list_loop; 4112510Salexander.borisov@nginx.com 4113510Salexander.borisov@nginx.com /* end-of-headers mark */ 4114510Salexander.borisov@nginx.com NXT_WRITE(&eof); 4115510Salexander.borisov@nginx.com 4116510Salexander.borisov@nginx.com RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 4117510Salexander.borisov@nginx.com 4118510Salexander.borisov@nginx.com for (b = r->body.buf; b != NULL; b = b->next) { 4119510Salexander.borisov@nginx.com 4120216Sigor@sysoev.ru RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 4121216Sigor@sysoev.ru nxt_buf_mem_used_size(&b->mem))); 4122216Sigor@sysoev.ru } 4123216Sigor@sysoev.ru 4124216Sigor@sysoev.ru #undef NXT_WRITE 4125216Sigor@sysoev.ru #undef RC 4126216Sigor@sysoev.ru 4127216Sigor@sysoev.ru return NXT_OK; 4128216Sigor@sysoev.ru 4129216Sigor@sysoev.ru fail: 4130216Sigor@sysoev.ru 4131216Sigor@sysoev.ru return NXT_ERROR; 4132216Sigor@sysoev.ru } 4133216Sigor@sysoev.ru 4134216Sigor@sysoev.ru 4135584Salexander.borisov@nginx.com static nxt_int_t 4136584Salexander.borisov@nginx.com nxt_ruby_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 4137584Salexander.borisov@nginx.com nxt_app_wmsg_t *wmsg) 4138584Salexander.borisov@nginx.com { 4139584Salexander.borisov@nginx.com nxt_int_t rc; 4140584Salexander.borisov@nginx.com nxt_str_t str; 4141584Salexander.borisov@nginx.com nxt_buf_t *b; 4142584Salexander.borisov@nginx.com nxt_http_field_t *field; 4143584Salexander.borisov@nginx.com nxt_app_request_header_t *h; 4144584Salexander.borisov@nginx.com 4145584Salexander.borisov@nginx.com static const nxt_str_t prefix = nxt_string("HTTP_"); 4146584Salexander.borisov@nginx.com static const nxt_str_t eof = nxt_null_string; 4147584Salexander.borisov@nginx.com 4148584Salexander.borisov@nginx.com h = &r->header; 4149584Salexander.borisov@nginx.com 4150584Salexander.borisov@nginx.com #define RC(S) \ 4151584Salexander.borisov@nginx.com do { \ 4152584Salexander.borisov@nginx.com rc = (S); \ 4153584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { \ 4154584Salexander.borisov@nginx.com goto fail; \ 4155584Salexander.borisov@nginx.com } \ 4156584Salexander.borisov@nginx.com } while(0) 4157584Salexander.borisov@nginx.com 4158584Salexander.borisov@nginx.com #define NXT_WRITE(N) \ 4159584Salexander.borisov@nginx.com RC(nxt_app_msg_write_str(task, wmsg, N)) 4160584Salexander.borisov@nginx.com 4161584Salexander.borisov@nginx.com /* TODO error handle, async mmap buffer assignment */ 4162584Salexander.borisov@nginx.com 4163584Salexander.borisov@nginx.com NXT_WRITE(&h->method); 4164584Salexander.borisov@nginx.com NXT_WRITE(&h->target); 4165584Salexander.borisov@nginx.com 4166584Salexander.borisov@nginx.com if (h->query.length) { 4167584Salexander.borisov@nginx.com str.start = h->target.start; 4168584Salexander.borisov@nginx.com str.length = (h->target.length - h->query.length) - 1; 4169584Salexander.borisov@nginx.com 4170584Salexander.borisov@nginx.com RC(nxt_app_msg_write_str(task, wmsg, &str)); 4171584Salexander.borisov@nginx.com 4172584Salexander.borisov@nginx.com } else { 4173584Salexander.borisov@nginx.com NXT_WRITE(&eof); 4174584Salexander.borisov@nginx.com } 4175584Salexander.borisov@nginx.com 4176584Salexander.borisov@nginx.com if (h->query.start != NULL) { 4177584Salexander.borisov@nginx.com RC(nxt_app_msg_write_size(task, wmsg, 4178584Salexander.borisov@nginx.com h->query.start - h->target.start + 1)); 4179584Salexander.borisov@nginx.com } else { 4180584Salexander.borisov@nginx.com RC(nxt_app_msg_write_size(task, wmsg, 0)); 4181584Salexander.borisov@nginx.com } 4182584Salexander.borisov@nginx.com 4183584Salexander.borisov@nginx.com NXT_WRITE(&h->version); 4184584Salexander.borisov@nginx.com 4185584Salexander.borisov@nginx.com NXT_WRITE(&r->remote); 4186584Salexander.borisov@nginx.com NXT_WRITE(&r->local); 4187584Salexander.borisov@nginx.com 4188584Salexander.borisov@nginx.com NXT_WRITE(&h->host); 4189584Salexander.borisov@nginx.com NXT_WRITE(&h->content_type); 4190584Salexander.borisov@nginx.com NXT_WRITE(&h->content_length); 4191584Salexander.borisov@nginx.com 4192584Salexander.borisov@nginx.com nxt_list_each(field, h->fields) { 4193584Salexander.borisov@nginx.com RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, &prefix, 4194584Salexander.borisov@nginx.com field->name, field->name_length)); 4195584Salexander.borisov@nginx.com RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length)); 4196584Salexander.borisov@nginx.com } nxt_list_loop; 4197584Salexander.borisov@nginx.com 4198584Salexander.borisov@nginx.com /* end-of-headers mark */ 4199584Salexander.borisov@nginx.com NXT_WRITE(&eof); 4200584Salexander.borisov@nginx.com 4201584Salexander.borisov@nginx.com RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 4202584Salexander.borisov@nginx.com 4203584Salexander.borisov@nginx.com for (b = r->body.buf; b != NULL; b = b->next) { 4204584Salexander.borisov@nginx.com 4205584Salexander.borisov@nginx.com RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 4206584Salexander.borisov@nginx.com nxt_buf_mem_used_size(&b->mem))); 4207584Salexander.borisov@nginx.com } 4208584Salexander.borisov@nginx.com 4209584Salexander.borisov@nginx.com #undef NXT_WRITE 4210584Salexander.borisov@nginx.com #undef RC 4211584Salexander.borisov@nginx.com 4212584Salexander.borisov@nginx.com return NXT_OK; 4213584Salexander.borisov@nginx.com 4214584Salexander.borisov@nginx.com fail: 4215584Salexander.borisov@nginx.com 4216584Salexander.borisov@nginx.com return NXT_ERROR; 4217584Salexander.borisov@nginx.com } 4218584Salexander.borisov@nginx.com 4219584Salexander.borisov@nginx.com 4220431Sigor@sysoev.ru const nxt_conn_state_t nxt_router_conn_close_state 422153Sigor@sysoev.ru nxt_aligned(64) = 422253Sigor@sysoev.ru { 422353Sigor@sysoev.ru .ready_handler = nxt_router_conn_free, 422453Sigor@sysoev.ru }; 422553Sigor@sysoev.ru 422653Sigor@sysoev.ru 422753Sigor@sysoev.ru static void 4228164Smax.romanov@nginx.com nxt_router_conn_mp_cleanup(nxt_task_t *task, void *obj, void *data) 4229164Smax.romanov@nginx.com { 4230164Smax.romanov@nginx.com nxt_socket_conf_joint_t *joint; 4231164Smax.romanov@nginx.com 4232164Smax.romanov@nginx.com joint = obj; 4233164Smax.romanov@nginx.com 4234164Smax.romanov@nginx.com nxt_router_conf_release(task, joint); 4235164Smax.romanov@nginx.com } 4236164Smax.romanov@nginx.com 4237164Smax.romanov@nginx.com 4238164Smax.romanov@nginx.com static void 423953Sigor@sysoev.ru nxt_router_conn_free(nxt_task_t *task, void *obj, void *data) 424053Sigor@sysoev.ru { 424162Sigor@sysoev.ru nxt_conn_t *c; 4242337Sigor@sysoev.ru nxt_event_engine_t *engine; 424353Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 424453Sigor@sysoev.ru 424553Sigor@sysoev.ru c = obj; 424653Sigor@sysoev.ru 424753Sigor@sysoev.ru nxt_debug(task, "router conn close done"); 424853Sigor@sysoev.ru 4249122Smax.romanov@nginx.com nxt_queue_remove(&c->link); 4250122Smax.romanov@nginx.com 4251337Sigor@sysoev.ru engine = task->thread->engine; 4252337Sigor@sysoev.ru 4253337Sigor@sysoev.ru nxt_sockaddr_cache_free(engine, c); 4254337Sigor@sysoev.ru 4255359Sigor@sysoev.ru joint = c->joint; 4256131Smax.romanov@nginx.com 4257337Sigor@sysoev.ru nxt_mp_cleanup(c->mem_pool, nxt_router_conn_mp_cleanup, 4258337Sigor@sysoev.ru &engine->task, joint, NULL); 4259164Smax.romanov@nginx.com 4260386Sigor@sysoev.ru nxt_conn_free(task, c); 426153Sigor@sysoev.ru } 426253Sigor@sysoev.ru 426353Sigor@sysoev.ru 426453Sigor@sysoev.ru static void 4265318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data) 4266318Smax.romanov@nginx.com { 4267*615Smax.romanov@nginx.com nxt_app_t *app; 4268*615Smax.romanov@nginx.com nxt_bool_t cancelled, unlinked; 4269*615Smax.romanov@nginx.com nxt_port_t *port; 4270*615Smax.romanov@nginx.com nxt_timer_t *timer; 4271*615Smax.romanov@nginx.com nxt_queue_link_t *lnk; 4272*615Smax.romanov@nginx.com nxt_req_app_link_t *pending_ra; 4273*615Smax.romanov@nginx.com nxt_app_parse_ctx_t *ar; 4274*615Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 4275*615Smax.romanov@nginx.com nxt_port_select_state_t state; 4276318Smax.romanov@nginx.com 4277318Smax.romanov@nginx.com timer = obj; 4278318Smax.romanov@nginx.com 4279318Smax.romanov@nginx.com nxt_debug(task, "router app timeout"); 4280318Smax.romanov@nginx.com 4281431Sigor@sysoev.ru ar = nxt_timer_data(timer, nxt_app_parse_ctx_t, timer); 4282*615Smax.romanov@nginx.com rc = ar->timer_data; 4283*615Smax.romanov@nginx.com app = rc->app; 4284*615Smax.romanov@nginx.com 4285*615Smax.romanov@nginx.com if (app == NULL) { 4286*615Smax.romanov@nginx.com goto generate_error; 4287*615Smax.romanov@nginx.com } 4288*615Smax.romanov@nginx.com 4289*615Smax.romanov@nginx.com port = NULL; 4290*615Smax.romanov@nginx.com pending_ra = NULL; 4291*615Smax.romanov@nginx.com 4292*615Smax.romanov@nginx.com if (rc->app_port != NULL) { 4293*615Smax.romanov@nginx.com port = rc->app_port; 4294*615Smax.romanov@nginx.com rc->app_port = NULL; 4295*615Smax.romanov@nginx.com } 4296*615Smax.romanov@nginx.com 4297*615Smax.romanov@nginx.com if (port == NULL && rc->ra != NULL && rc->ra->app_port != NULL) { 4298*615Smax.romanov@nginx.com port = rc->ra->app_port; 4299*615Smax.romanov@nginx.com rc->ra->app_port = NULL; 4300*615Smax.romanov@nginx.com } 4301*615Smax.romanov@nginx.com 4302*615Smax.romanov@nginx.com if (port == NULL) { 4303*615Smax.romanov@nginx.com goto generate_error; 4304431Sigor@sysoev.ru } 4305*615Smax.romanov@nginx.com 4306*615Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4307*615Smax.romanov@nginx.com 4308*615Smax.romanov@nginx.com unlinked = nxt_queue_chk_remove(&port->app_link); 4309*615Smax.romanov@nginx.com 4310*615Smax.romanov@nginx.com if (!nxt_queue_is_empty(&port->pending_requests)) { 4311*615Smax.romanov@nginx.com lnk = nxt_queue_first(&port->pending_requests); 4312*615Smax.romanov@nginx.com 4313*615Smax.romanov@nginx.com pending_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, 4314*615Smax.romanov@nginx.com link_port_pending); 4315*615Smax.romanov@nginx.com 4316*615Smax.romanov@nginx.com nxt_assert(pending_ra->link_app_pending.next != NULL); 4317*615Smax.romanov@nginx.com 4318*615Smax.romanov@nginx.com nxt_debug(task, "app '%V' pending request #%uD found", 4319*615Smax.romanov@nginx.com &app->name, pending_ra->stream); 4320*615Smax.romanov@nginx.com 4321*615Smax.romanov@nginx.com cancelled = nxt_router_msg_cancel(task, &pending_ra->msg_info, 4322*615Smax.romanov@nginx.com pending_ra->stream); 4323*615Smax.romanov@nginx.com 4324*615Smax.romanov@nginx.com if (cancelled) { 4325*615Smax.romanov@nginx.com nxt_router_ra_inc_use(pending_ra); 4326*615Smax.romanov@nginx.com 4327*615Smax.romanov@nginx.com state.ra = pending_ra; 4328*615Smax.romanov@nginx.com state.app = app; 4329*615Smax.romanov@nginx.com 4330*615Smax.romanov@nginx.com nxt_router_port_select(task, &state); 4331*615Smax.romanov@nginx.com 4332*615Smax.romanov@nginx.com } else { 4333*615Smax.romanov@nginx.com pending_ra = NULL; 4334*615Smax.romanov@nginx.com } 4335*615Smax.romanov@nginx.com } 4336*615Smax.romanov@nginx.com 4337*615Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4338*615Smax.romanov@nginx.com 4339*615Smax.romanov@nginx.com if (pending_ra != NULL 4340*615Smax.romanov@nginx.com && nxt_router_port_post_select(task, &state) == NXT_OK) 4341*615Smax.romanov@nginx.com { 4342*615Smax.romanov@nginx.com nxt_router_app_prepare_request(task, pending_ra); 4343*615Smax.romanov@nginx.com } 4344*615Smax.romanov@nginx.com 4345*615Smax.romanov@nginx.com nxt_debug(task, "send quit to app '%V' pid %PI", &app->name, port->pid); 4346*615Smax.romanov@nginx.com 4347*615Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 4348*615Smax.romanov@nginx.com 4349*615Smax.romanov@nginx.com nxt_port_use(task, port, unlinked ? -2 : -1); 4350*615Smax.romanov@nginx.com 4351*615Smax.romanov@nginx.com generate_error: 4352*615Smax.romanov@nginx.com 4353*615Smax.romanov@nginx.com nxt_http_request_error(task, ar->request, NXT_HTTP_SERVICE_UNAVAILABLE); 4354*615Smax.romanov@nginx.com 4355*615Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 4356318Smax.romanov@nginx.com } 4357