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; 546431Sigor@sysoev.ru nxt_timer_add(task->thread->engine, &rc->ap->timer, 547425Smax.romanov@nginx.com rc->app->timeout); 548425Smax.romanov@nginx.com } 549425Smax.romanov@nginx.com 550423Smax.romanov@nginx.com ra->app_port = NULL; 551423Smax.romanov@nginx.com ra->msg_info.buf = NULL; 552423Smax.romanov@nginx.com } 553343Smax.romanov@nginx.com 554343Smax.romanov@nginx.com rc->ra = NULL; 555343Smax.romanov@nginx.com ra->rc = NULL; 556343Smax.romanov@nginx.com } 557343Smax.romanov@nginx.com 558343Smax.romanov@nginx.com if (ra->app_port != NULL) { 559343Smax.romanov@nginx.com nxt_router_app_port_release(task, ra->app_port, 0, 1); 560343Smax.romanov@nginx.com 561343Smax.romanov@nginx.com ra->app_port = NULL; 562167Smax.romanov@nginx.com } 563167Smax.romanov@nginx.com 564423Smax.romanov@nginx.com nxt_router_msg_cancel(task, &ra->msg_info, ra->stream); 565423Smax.romanov@nginx.com 566430Sigor@sysoev.ru mp = ra->mem_pool; 567430Sigor@sysoev.ru 568430Sigor@sysoev.ru if (mp != NULL) { 569430Sigor@sysoev.ru nxt_mp_free(mp, ra); 570430Sigor@sysoev.ru nxt_mp_release(mp); 571351Smax.romanov@nginx.com } 572167Smax.romanov@nginx.com } 573167Smax.romanov@nginx.com 574167Smax.romanov@nginx.com 575425Smax.romanov@nginx.com static void 576425Smax.romanov@nginx.com nxt_router_ra_release_handler(nxt_task_t *task, void *obj, void *data) 577425Smax.romanov@nginx.com { 578425Smax.romanov@nginx.com nxt_req_app_link_t *ra; 579425Smax.romanov@nginx.com 580425Smax.romanov@nginx.com ra = obj; 581425Smax.romanov@nginx.com 582425Smax.romanov@nginx.com nxt_assert(ra->work.data == data); 583425Smax.romanov@nginx.com 584425Smax.romanov@nginx.com nxt_atomic_fetch_add(&ra->use_count, -1); 585425Smax.romanov@nginx.com 586425Smax.romanov@nginx.com nxt_router_ra_release(task, ra); 587425Smax.romanov@nginx.com } 588425Smax.romanov@nginx.com 589425Smax.romanov@nginx.com 590425Smax.romanov@nginx.com static void 591425Smax.romanov@nginx.com nxt_router_ra_use(nxt_task_t *task, nxt_req_app_link_t *ra, int i) 592425Smax.romanov@nginx.com { 593425Smax.romanov@nginx.com int c; 594425Smax.romanov@nginx.com nxt_event_engine_t *engine; 595425Smax.romanov@nginx.com 596425Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&ra->use_count, i); 597425Smax.romanov@nginx.com 598425Smax.romanov@nginx.com if (i < 0 && c == -i) { 599425Smax.romanov@nginx.com engine = ra->work.data; 600425Smax.romanov@nginx.com 601425Smax.romanov@nginx.com if (task->thread->engine == engine) { 602425Smax.romanov@nginx.com nxt_router_ra_release(task, ra); 603425Smax.romanov@nginx.com 604425Smax.romanov@nginx.com return; 605425Smax.romanov@nginx.com } 606425Smax.romanov@nginx.com 607425Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 608425Smax.romanov@nginx.com 609425Smax.romanov@nginx.com ra->work.handler = nxt_router_ra_release_handler; 610425Smax.romanov@nginx.com ra->work.task = &engine->task; 611425Smax.romanov@nginx.com ra->work.next = NULL; 612425Smax.romanov@nginx.com 613425Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD post release to %p", 614425Smax.romanov@nginx.com ra->stream, engine); 615425Smax.romanov@nginx.com 616425Smax.romanov@nginx.com nxt_event_engine_post(engine, &ra->work); 617425Smax.romanov@nginx.com } 618425Smax.romanov@nginx.com } 619425Smax.romanov@nginx.com 620425Smax.romanov@nginx.com 621423Smax.romanov@nginx.com nxt_inline void 622521Szelenkov@nginx.com nxt_router_ra_error(nxt_req_app_link_t *ra, int code, const char *str) 623345Smax.romanov@nginx.com { 624423Smax.romanov@nginx.com ra->app_port = NULL; 625423Smax.romanov@nginx.com ra->err_code = code; 626423Smax.romanov@nginx.com ra->err_str = str; 627345Smax.romanov@nginx.com } 628345Smax.romanov@nginx.com 629345Smax.romanov@nginx.com 630427Smax.romanov@nginx.com nxt_inline void 631427Smax.romanov@nginx.com nxt_router_ra_pending(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra) 632427Smax.romanov@nginx.com { 633427Smax.romanov@nginx.com nxt_queue_insert_tail(&ra->app_port->pending_requests, 634427Smax.romanov@nginx.com &ra->link_port_pending); 635427Smax.romanov@nginx.com nxt_queue_insert_tail(&app->pending, &ra->link_app_pending); 636427Smax.romanov@nginx.com 637427Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 638427Smax.romanov@nginx.com 639427Smax.romanov@nginx.com ra->res_time = nxt_thread_monotonic_time(task->thread) + app->res_timeout; 640427Smax.romanov@nginx.com 641427Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD enqueue to pending_requests", ra->stream); 642427Smax.romanov@nginx.com } 643427Smax.romanov@nginx.com 644427Smax.romanov@nginx.com 645425Smax.romanov@nginx.com nxt_inline nxt_bool_t 646425Smax.romanov@nginx.com nxt_queue_chk_remove(nxt_queue_link_t *lnk) 647425Smax.romanov@nginx.com { 648425Smax.romanov@nginx.com if (lnk->next != NULL) { 649425Smax.romanov@nginx.com nxt_queue_remove(lnk); 650425Smax.romanov@nginx.com 651425Smax.romanov@nginx.com lnk->next = NULL; 652425Smax.romanov@nginx.com 653425Smax.romanov@nginx.com return 1; 654425Smax.romanov@nginx.com } 655425Smax.romanov@nginx.com 656425Smax.romanov@nginx.com return 0; 657425Smax.romanov@nginx.com } 658425Smax.romanov@nginx.com 659425Smax.romanov@nginx.com 660343Smax.romanov@nginx.com nxt_inline void 661343Smax.romanov@nginx.com nxt_router_rc_unlink(nxt_task_t *task, nxt_req_conn_link_t *rc) 662343Smax.romanov@nginx.com { 663425Smax.romanov@nginx.com int ra_use_delta; 664343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 665343Smax.romanov@nginx.com 666343Smax.romanov@nginx.com if (rc->app_port != NULL) { 667343Smax.romanov@nginx.com nxt_router_app_port_release(task, rc->app_port, 0, 1); 668343Smax.romanov@nginx.com 669343Smax.romanov@nginx.com rc->app_port = NULL; 670343Smax.romanov@nginx.com } 671343Smax.romanov@nginx.com 672423Smax.romanov@nginx.com nxt_router_msg_cancel(task, &rc->msg_info, rc->stream); 673423Smax.romanov@nginx.com 674343Smax.romanov@nginx.com ra = rc->ra; 675343Smax.romanov@nginx.com 676343Smax.romanov@nginx.com if (ra != NULL) { 677343Smax.romanov@nginx.com rc->ra = NULL; 678343Smax.romanov@nginx.com ra->rc = NULL; 679343Smax.romanov@nginx.com 680425Smax.romanov@nginx.com ra_use_delta = 0; 681425Smax.romanov@nginx.com 682343Smax.romanov@nginx.com nxt_thread_mutex_lock(&rc->app->mutex); 683343Smax.romanov@nginx.com 684425Smax.romanov@nginx.com if (ra->link_app_requests.next == NULL 685427Smax.romanov@nginx.com && ra->link_port_pending.next == NULL 686427Smax.romanov@nginx.com && ra->link_app_pending.next == NULL) 687425Smax.romanov@nginx.com { 688425Smax.romanov@nginx.com ra = NULL; 689343Smax.romanov@nginx.com 690343Smax.romanov@nginx.com } else { 691425Smax.romanov@nginx.com ra_use_delta -= nxt_queue_chk_remove(&ra->link_app_requests); 692425Smax.romanov@nginx.com ra_use_delta -= nxt_queue_chk_remove(&ra->link_port_pending); 693427Smax.romanov@nginx.com nxt_queue_chk_remove(&ra->link_app_pending); 694343Smax.romanov@nginx.com } 695343Smax.romanov@nginx.com 696343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&rc->app->mutex); 697425Smax.romanov@nginx.com 698425Smax.romanov@nginx.com if (ra != NULL) { 699425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, ra_use_delta); 700425Smax.romanov@nginx.com } 701343Smax.romanov@nginx.com } 702343Smax.romanov@nginx.com 703343Smax.romanov@nginx.com if (rc->app != NULL) { 704343Smax.romanov@nginx.com nxt_router_app_use(task, rc->app, -1); 705343Smax.romanov@nginx.com 706343Smax.romanov@nginx.com rc->app = NULL; 707343Smax.romanov@nginx.com } 708343Smax.romanov@nginx.com 709346Smax.romanov@nginx.com if (rc->ap != NULL) { 710346Smax.romanov@nginx.com nxt_app_http_req_done(task, rc->ap); 711346Smax.romanov@nginx.com 712346Smax.romanov@nginx.com rc->ap = NULL; 713346Smax.romanov@nginx.com } 714343Smax.romanov@nginx.com } 715343Smax.romanov@nginx.com 716343Smax.romanov@nginx.com 717141Smax.romanov@nginx.com void 718141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 719141Smax.romanov@nginx.com { 720141Smax.romanov@nginx.com nxt_port_new_port_handler(task, msg); 721141Smax.romanov@nginx.com 722192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 723141Smax.romanov@nginx.com return; 724141Smax.romanov@nginx.com } 725141Smax.romanov@nginx.com 726426Smax.romanov@nginx.com if (msg->u.new_port == NULL 727426Smax.romanov@nginx.com || msg->u.new_port->type != NXT_PROCESS_WORKER) 728347Smax.romanov@nginx.com { 729192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 730141Smax.romanov@nginx.com } 731192Smax.romanov@nginx.com 732192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 733141Smax.romanov@nginx.com } 734141Smax.romanov@nginx.com 735141Smax.romanov@nginx.com 736139Sigor@sysoev.ru void 737139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 738115Sigor@sysoev.ru { 739198Sigor@sysoev.ru nxt_int_t ret; 740139Sigor@sysoev.ru nxt_buf_t *b; 741139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 742139Sigor@sysoev.ru 743139Sigor@sysoev.ru tmcf = nxt_router_temp_conf(task); 744139Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 745139Sigor@sysoev.ru return; 74653Sigor@sysoev.ru } 74753Sigor@sysoev.ru 748494Spluknet@nginx.com nxt_debug(task, "nxt_router_conf_data_handler(%O): %*s", 749423Smax.romanov@nginx.com nxt_buf_used_size(msg->buf), 750493Spluknet@nginx.com (size_t) nxt_buf_used_size(msg->buf), msg->buf->mem.pos); 751423Smax.romanov@nginx.com 752*591Sigor@sysoev.ru tmcf->router_conf->router = nxt_router; 753139Sigor@sysoev.ru tmcf->stream = msg->port_msg.stream; 754139Sigor@sysoev.ru tmcf->port = nxt_runtime_port_find(task->thread->runtime, 755198Sigor@sysoev.ru msg->port_msg.pid, 756198Sigor@sysoev.ru msg->port_msg.reply_port); 757198Sigor@sysoev.ru 758*591Sigor@sysoev.ru b = nxt_buf_chk_make_plain(tmcf->router_conf->mem_pool, 759*591Sigor@sysoev.ru msg->buf, msg->size); 760551Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 761551Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 762551Smax.romanov@nginx.com 763551Smax.romanov@nginx.com return; 764551Smax.romanov@nginx.com } 765551Smax.romanov@nginx.com 766198Sigor@sysoev.ru ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free); 767198Sigor@sysoev.ru 768198Sigor@sysoev.ru if (nxt_fast_path(ret == NXT_OK)) { 769198Sigor@sysoev.ru nxt_router_conf_apply(task, tmcf, NULL); 770198Sigor@sysoev.ru 771198Sigor@sysoev.ru } else { 772198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 773139Sigor@sysoev.ru } 77453Sigor@sysoev.ru } 77553Sigor@sysoev.ru 77653Sigor@sysoev.ru 777347Smax.romanov@nginx.com static void 778507Smax.romanov@nginx.com nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port, 779507Smax.romanov@nginx.com void *data) 780347Smax.romanov@nginx.com { 781347Smax.romanov@nginx.com union { 782347Smax.romanov@nginx.com nxt_pid_t removed_pid; 783347Smax.romanov@nginx.com void *data; 784347Smax.romanov@nginx.com } u; 785347Smax.romanov@nginx.com 786347Smax.romanov@nginx.com u.data = data; 787347Smax.romanov@nginx.com 788347Smax.romanov@nginx.com nxt_port_rpc_remove_peer(task, port, u.removed_pid); 789347Smax.romanov@nginx.com } 790347Smax.romanov@nginx.com 791347Smax.romanov@nginx.com 792192Smax.romanov@nginx.com void 793192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 794192Smax.romanov@nginx.com { 795347Smax.romanov@nginx.com nxt_event_engine_t *engine; 796318Smax.romanov@nginx.com 797192Smax.romanov@nginx.com nxt_port_remove_pid_handler(task, msg); 798192Smax.romanov@nginx.com 799192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 800192Smax.romanov@nginx.com return; 801192Smax.romanov@nginx.com } 802192Smax.romanov@nginx.com 803318Smax.romanov@nginx.com nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0) 804318Smax.romanov@nginx.com { 805507Smax.romanov@nginx.com nxt_port_post(task, engine->port, nxt_router_app_process_remove_pid, 806347Smax.romanov@nginx.com msg->u.data); 807318Smax.romanov@nginx.com } 808318Smax.romanov@nginx.com nxt_queue_loop; 809318Smax.romanov@nginx.com 810192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 811192Smax.romanov@nginx.com 812192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 813192Smax.romanov@nginx.com } 814192Smax.romanov@nginx.com 815192Smax.romanov@nginx.com 81653Sigor@sysoev.ru static nxt_router_temp_conf_t * 817139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task) 81853Sigor@sysoev.ru { 81965Sigor@sysoev.ru nxt_mp_t *mp, *tmp; 82053Sigor@sysoev.ru nxt_router_conf_t *rtcf; 82153Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 82253Sigor@sysoev.ru 82365Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 82453Sigor@sysoev.ru if (nxt_slow_path(mp == NULL)) { 82553Sigor@sysoev.ru return NULL; 82653Sigor@sysoev.ru } 82753Sigor@sysoev.ru 82865Sigor@sysoev.ru rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t)); 82953Sigor@sysoev.ru if (nxt_slow_path(rtcf == NULL)) { 83053Sigor@sysoev.ru goto fail; 83153Sigor@sysoev.ru } 83253Sigor@sysoev.ru 83353Sigor@sysoev.ru rtcf->mem_pool = mp; 83453Sigor@sysoev.ru 83565Sigor@sysoev.ru tmp = nxt_mp_create(1024, 128, 256, 32); 83653Sigor@sysoev.ru if (nxt_slow_path(tmp == NULL)) { 83753Sigor@sysoev.ru goto fail; 83853Sigor@sysoev.ru } 83953Sigor@sysoev.ru 84065Sigor@sysoev.ru tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t)); 84153Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 84253Sigor@sysoev.ru goto temp_fail; 84353Sigor@sysoev.ru } 84453Sigor@sysoev.ru 84553Sigor@sysoev.ru tmcf->mem_pool = tmp; 846*591Sigor@sysoev.ru tmcf->router_conf = rtcf; 847139Sigor@sysoev.ru tmcf->count = 1; 848139Sigor@sysoev.ru tmcf->engine = task->thread->engine; 84953Sigor@sysoev.ru 85053Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, 4, 85153Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 85253Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 85353Sigor@sysoev.ru goto temp_fail; 85453Sigor@sysoev.ru } 85553Sigor@sysoev.ru 85653Sigor@sysoev.ru nxt_queue_init(&tmcf->deleting); 85753Sigor@sysoev.ru nxt_queue_init(&tmcf->keeping); 85853Sigor@sysoev.ru nxt_queue_init(&tmcf->updating); 85953Sigor@sysoev.ru nxt_queue_init(&tmcf->pending); 86053Sigor@sysoev.ru nxt_queue_init(&tmcf->creating); 861416Smax.romanov@nginx.com 862133Sigor@sysoev.ru nxt_queue_init(&tmcf->apps); 863133Sigor@sysoev.ru nxt_queue_init(&tmcf->previous); 86453Sigor@sysoev.ru 86553Sigor@sysoev.ru return tmcf; 86653Sigor@sysoev.ru 86753Sigor@sysoev.ru temp_fail: 86853Sigor@sysoev.ru 86965Sigor@sysoev.ru nxt_mp_destroy(tmp); 87053Sigor@sysoev.ru 87153Sigor@sysoev.ru fail: 87253Sigor@sysoev.ru 87365Sigor@sysoev.ru nxt_mp_destroy(mp); 87453Sigor@sysoev.ru 87553Sigor@sysoev.ru return NULL; 87653Sigor@sysoev.ru } 87753Sigor@sysoev.ru 87853Sigor@sysoev.ru 879507Smax.romanov@nginx.com nxt_inline nxt_bool_t 880507Smax.romanov@nginx.com nxt_router_app_can_start(nxt_app_t *app) 881507Smax.romanov@nginx.com { 882507Smax.romanov@nginx.com return app->processes + app->pending_processes < app->max_processes 883507Smax.romanov@nginx.com && app->pending_processes < app->max_pending_processes; 884507Smax.romanov@nginx.com } 885507Smax.romanov@nginx.com 886507Smax.romanov@nginx.com 887507Smax.romanov@nginx.com nxt_inline nxt_bool_t 888507Smax.romanov@nginx.com nxt_router_app_need_start(nxt_app_t *app) 889507Smax.romanov@nginx.com { 890507Smax.romanov@nginx.com return app->idle_processes + app->pending_processes 891507Smax.romanov@nginx.com < app->spare_processes; 892507Smax.romanov@nginx.com } 893507Smax.romanov@nginx.com 894507Smax.romanov@nginx.com 895198Sigor@sysoev.ru static void 896198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data) 897139Sigor@sysoev.ru { 898139Sigor@sysoev.ru nxt_int_t ret; 899507Smax.romanov@nginx.com nxt_app_t *app; 900139Sigor@sysoev.ru nxt_router_t *router; 901139Sigor@sysoev.ru nxt_runtime_t *rt; 902198Sigor@sysoev.ru nxt_queue_link_t *qlk; 903198Sigor@sysoev.ru nxt_socket_conf_t *skcf; 904198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 905139Sigor@sysoev.ru const nxt_event_interface_t *interface; 906139Sigor@sysoev.ru 907198Sigor@sysoev.ru tmcf = obj; 908198Sigor@sysoev.ru 909198Sigor@sysoev.ru qlk = nxt_queue_first(&tmcf->pending); 910198Sigor@sysoev.ru 911198Sigor@sysoev.ru if (qlk != nxt_queue_tail(&tmcf->pending)) { 912198Sigor@sysoev.ru nxt_queue_remove(qlk); 913198Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->creating, qlk); 914198Sigor@sysoev.ru 915198Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 916198Sigor@sysoev.ru 917198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(task, tmcf, skcf); 918198Sigor@sysoev.ru 919198Sigor@sysoev.ru return; 920139Sigor@sysoev.ru } 921139Sigor@sysoev.ru 922507Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 923507Smax.romanov@nginx.com 924507Smax.romanov@nginx.com if (nxt_router_app_need_start(app)) { 925507Smax.romanov@nginx.com nxt_router_app_rpc_create(task, tmcf, app); 926507Smax.romanov@nginx.com return; 927507Smax.romanov@nginx.com } 928507Smax.romanov@nginx.com 929507Smax.romanov@nginx.com } nxt_queue_loop; 930507Smax.romanov@nginx.com 931139Sigor@sysoev.ru rt = task->thread->runtime; 932139Sigor@sysoev.ru 933139Sigor@sysoev.ru interface = nxt_service_get(rt->services, "engine", NULL); 934139Sigor@sysoev.ru 935*591Sigor@sysoev.ru router = tmcf->router_conf->router; 936198Sigor@sysoev.ru 937139Sigor@sysoev.ru ret = nxt_router_engines_create(task, router, tmcf, interface); 938139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 939198Sigor@sysoev.ru goto fail; 940139Sigor@sysoev.ru } 941139Sigor@sysoev.ru 942139Sigor@sysoev.ru ret = nxt_router_threads_create(task, rt, tmcf); 943139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 944198Sigor@sysoev.ru goto fail; 945139Sigor@sysoev.ru } 946139Sigor@sysoev.ru 947343Smax.romanov@nginx.com nxt_router_apps_sort(task, router, tmcf); 948139Sigor@sysoev.ru 949315Sigor@sysoev.ru nxt_router_engines_post(router, tmcf); 950139Sigor@sysoev.ru 951139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->updating); 952139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->creating); 953139Sigor@sysoev.ru 954198Sigor@sysoev.ru nxt_router_conf_ready(task, tmcf); 955198Sigor@sysoev.ru 956198Sigor@sysoev.ru return; 957198Sigor@sysoev.ru 958198Sigor@sysoev.ru fail: 959198Sigor@sysoev.ru 960198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 961198Sigor@sysoev.ru 962198Sigor@sysoev.ru return; 963139Sigor@sysoev.ru } 964139Sigor@sysoev.ru 965139Sigor@sysoev.ru 966139Sigor@sysoev.ru static void 967139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data) 968139Sigor@sysoev.ru { 969153Sigor@sysoev.ru nxt_joint_job_t *job; 970153Sigor@sysoev.ru 971153Sigor@sysoev.ru job = obj; 972153Sigor@sysoev.ru 973198Sigor@sysoev.ru nxt_router_conf_ready(task, job->tmcf); 974139Sigor@sysoev.ru } 975139Sigor@sysoev.ru 976139Sigor@sysoev.ru 977139Sigor@sysoev.ru static void 978198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 979139Sigor@sysoev.ru { 980139Sigor@sysoev.ru nxt_debug(task, "temp conf count:%D", tmcf->count); 981139Sigor@sysoev.ru 982139Sigor@sysoev.ru if (--tmcf->count == 0) { 983193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST); 984139Sigor@sysoev.ru } 985139Sigor@sysoev.ru } 986139Sigor@sysoev.ru 987139Sigor@sysoev.ru 988139Sigor@sysoev.ru static void 989139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 990139Sigor@sysoev.ru { 991507Smax.romanov@nginx.com nxt_app_t *app; 992568Smax.romanov@nginx.com nxt_queue_t new_socket_confs; 993148Sigor@sysoev.ru nxt_socket_t s; 994149Sigor@sysoev.ru nxt_router_t *router; 995148Sigor@sysoev.ru nxt_queue_link_t *qlk; 996148Sigor@sysoev.ru nxt_socket_conf_t *skcf; 997148Sigor@sysoev.ru 998564Svbart@nginx.com nxt_alert(task, "failed to apply new conf"); 999198Sigor@sysoev.ru 1000148Sigor@sysoev.ru for (qlk = nxt_queue_first(&tmcf->creating); 1001148Sigor@sysoev.ru qlk != nxt_queue_tail(&tmcf->creating); 1002148Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 1003148Sigor@sysoev.ru { 1004148Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1005359Sigor@sysoev.ru s = skcf->listen->socket; 1006148Sigor@sysoev.ru 1007148Sigor@sysoev.ru if (s != -1) { 1008148Sigor@sysoev.ru nxt_socket_close(task, s); 1009148Sigor@sysoev.ru } 1010148Sigor@sysoev.ru 1011359Sigor@sysoev.ru nxt_free(skcf->listen); 1012148Sigor@sysoev.ru } 1013148Sigor@sysoev.ru 1014568Smax.romanov@nginx.com nxt_queue_init(&new_socket_confs); 1015568Smax.romanov@nginx.com nxt_queue_add(&new_socket_confs, &tmcf->updating); 1016568Smax.romanov@nginx.com nxt_queue_add(&new_socket_confs, &tmcf->pending); 1017568Smax.romanov@nginx.com nxt_queue_add(&new_socket_confs, &tmcf->creating); 1018568Smax.romanov@nginx.com 1019568Smax.romanov@nginx.com nxt_queue_each(skcf, &new_socket_confs, nxt_socket_conf_t, link) { 1020568Smax.romanov@nginx.com 1021568Smax.romanov@nginx.com if (skcf->application != NULL) { 1022568Smax.romanov@nginx.com nxt_router_app_use(task, skcf->application, -1); 1023568Smax.romanov@nginx.com skcf->application = NULL; 1024568Smax.romanov@nginx.com } 1025568Smax.romanov@nginx.com 1026568Smax.romanov@nginx.com } nxt_queue_loop; 1027568Smax.romanov@nginx.com 1028507Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1029507Smax.romanov@nginx.com 1030507Smax.romanov@nginx.com nxt_router_app_quit(task, app); 1031507Smax.romanov@nginx.com 1032507Smax.romanov@nginx.com } nxt_queue_loop; 1033507Smax.romanov@nginx.com 1034*591Sigor@sysoev.ru router = tmcf->router_conf->router; 1035149Sigor@sysoev.ru 1036149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->keeping); 1037149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->deleting); 1038149Sigor@sysoev.ru 1039416Smax.romanov@nginx.com nxt_queue_add(&router->apps, &tmcf->previous); 1040416Smax.romanov@nginx.com 1041148Sigor@sysoev.ru // TODO: new engines and threads 1042148Sigor@sysoev.ru 1043*591Sigor@sysoev.ru nxt_mp_destroy(tmcf->router_conf->mem_pool); 1044139Sigor@sysoev.ru 1045193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR); 1046139Sigor@sysoev.ru } 1047139Sigor@sysoev.ru 1048139Sigor@sysoev.ru 1049139Sigor@sysoev.ru static void 1050139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1051193Smax.romanov@nginx.com nxt_port_msg_type_t type) 1052139Sigor@sysoev.ru { 1053193Smax.romanov@nginx.com nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL); 1054139Sigor@sysoev.ru } 1055139Sigor@sysoev.ru 1056139Sigor@sysoev.ru 1057115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_conf[] = { 1058115Sigor@sysoev.ru { 1059133Sigor@sysoev.ru nxt_string("listeners_threads"), 1060115Sigor@sysoev.ru NXT_CONF_MAP_INT32, 1061115Sigor@sysoev.ru offsetof(nxt_router_conf_t, threads), 1062115Sigor@sysoev.ru }, 1063115Sigor@sysoev.ru }; 1064115Sigor@sysoev.ru 1065115Sigor@sysoev.ru 1066133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_app_conf[] = { 1067115Sigor@sysoev.ru { 1068133Sigor@sysoev.ru nxt_string("type"), 1069115Sigor@sysoev.ru NXT_CONF_MAP_STR, 1070133Sigor@sysoev.ru offsetof(nxt_router_app_conf_t, type), 1071115Sigor@sysoev.ru }, 1072115Sigor@sysoev.ru 1073115Sigor@sysoev.ru { 1074507Smax.romanov@nginx.com nxt_string("limits"), 1075507Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 1076507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, limits_value), 1077133Sigor@sysoev.ru }, 1078318Smax.romanov@nginx.com 1079318Smax.romanov@nginx.com { 1080507Smax.romanov@nginx.com nxt_string("processes"), 1081507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1082507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, processes), 1083507Smax.romanov@nginx.com }, 1084507Smax.romanov@nginx.com 1085507Smax.romanov@nginx.com { 1086507Smax.romanov@nginx.com nxt_string("processes"), 1087318Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 1088507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, processes_value), 1089318Smax.romanov@nginx.com }, 1090318Smax.romanov@nginx.com }; 1091318Smax.romanov@nginx.com 1092318Smax.romanov@nginx.com 1093318Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_limits_conf[] = { 1094318Smax.romanov@nginx.com { 1095318Smax.romanov@nginx.com nxt_string("timeout"), 1096318Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1097318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, timeout), 1098318Smax.romanov@nginx.com }, 1099318Smax.romanov@nginx.com 1100318Smax.romanov@nginx.com { 1101427Smax.romanov@nginx.com nxt_string("reschedule_timeout"), 1102427Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1103427Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, res_timeout), 1104427Smax.romanov@nginx.com }, 1105427Smax.romanov@nginx.com 1106427Smax.romanov@nginx.com { 1107318Smax.romanov@nginx.com nxt_string("requests"), 1108318Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1109318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, requests), 1110318Smax.romanov@nginx.com }, 1111133Sigor@sysoev.ru }; 1112133Sigor@sysoev.ru 1113133Sigor@sysoev.ru 1114507Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_processes_conf[] = { 1115507Smax.romanov@nginx.com { 1116507Smax.romanov@nginx.com nxt_string("spare"), 1117507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1118507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, spare_processes), 1119507Smax.romanov@nginx.com }, 1120507Smax.romanov@nginx.com 1121507Smax.romanov@nginx.com { 1122507Smax.romanov@nginx.com nxt_string("max"), 1123507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1124507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, max_processes), 1125507Smax.romanov@nginx.com }, 1126507Smax.romanov@nginx.com 1127507Smax.romanov@nginx.com { 1128507Smax.romanov@nginx.com nxt_string("idle_timeout"), 1129507Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1130507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, idle_timeout), 1131507Smax.romanov@nginx.com }, 1132507Smax.romanov@nginx.com }; 1133507Smax.romanov@nginx.com 1134507Smax.romanov@nginx.com 1135133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_listener_conf[] = { 1136133Sigor@sysoev.ru { 1137133Sigor@sysoev.ru nxt_string("application"), 1138133Sigor@sysoev.ru NXT_CONF_MAP_STR, 1139133Sigor@sysoev.ru offsetof(nxt_router_listener_conf_t, application), 1140115Sigor@sysoev.ru }, 1141115Sigor@sysoev.ru }; 1142115Sigor@sysoev.ru 1143115Sigor@sysoev.ru 1144115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_http_conf[] = { 1145115Sigor@sysoev.ru { 1146115Sigor@sysoev.ru nxt_string("header_buffer_size"), 1147115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 1148115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_buffer_size), 1149115Sigor@sysoev.ru }, 1150115Sigor@sysoev.ru 1151115Sigor@sysoev.ru { 1152115Sigor@sysoev.ru nxt_string("large_header_buffer_size"), 1153115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 1154115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, large_header_buffer_size), 1155115Sigor@sysoev.ru }, 1156115Sigor@sysoev.ru 1157115Sigor@sysoev.ru { 1158206Smax.romanov@nginx.com nxt_string("large_header_buffers"), 1159206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1160206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, large_header_buffers), 1161206Smax.romanov@nginx.com }, 1162206Smax.romanov@nginx.com 1163206Smax.romanov@nginx.com { 1164206Smax.romanov@nginx.com nxt_string("body_buffer_size"), 1165206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1166206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_buffer_size), 1167206Smax.romanov@nginx.com }, 1168206Smax.romanov@nginx.com 1169206Smax.romanov@nginx.com { 1170206Smax.romanov@nginx.com nxt_string("max_body_size"), 1171206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1172206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, max_body_size), 1173206Smax.romanov@nginx.com }, 1174206Smax.romanov@nginx.com 1175206Smax.romanov@nginx.com { 1176431Sigor@sysoev.ru nxt_string("idle_timeout"), 1177431Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1178431Sigor@sysoev.ru offsetof(nxt_socket_conf_t, idle_timeout), 1179431Sigor@sysoev.ru }, 1180431Sigor@sysoev.ru 1181431Sigor@sysoev.ru { 1182115Sigor@sysoev.ru nxt_string("header_read_timeout"), 1183115Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1184115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_read_timeout), 1185115Sigor@sysoev.ru }, 1186206Smax.romanov@nginx.com 1187206Smax.romanov@nginx.com { 1188206Smax.romanov@nginx.com nxt_string("body_read_timeout"), 1189206Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1190206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_read_timeout), 1191206Smax.romanov@nginx.com }, 1192431Sigor@sysoev.ru 1193431Sigor@sysoev.ru { 1194431Sigor@sysoev.ru nxt_string("send_timeout"), 1195431Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1196431Sigor@sysoev.ru offsetof(nxt_socket_conf_t, send_timeout), 1197431Sigor@sysoev.ru }, 1198115Sigor@sysoev.ru }; 1199115Sigor@sysoev.ru 1200115Sigor@sysoev.ru 120153Sigor@sysoev.ru static nxt_int_t 1202115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1203115Sigor@sysoev.ru u_char *start, u_char *end) 120453Sigor@sysoev.ru { 1205133Sigor@sysoev.ru u_char *p; 1206133Sigor@sysoev.ru size_t size; 1207115Sigor@sysoev.ru nxt_mp_t *mp; 1208115Sigor@sysoev.ru uint32_t next; 1209115Sigor@sysoev.ru nxt_int_t ret; 1210115Sigor@sysoev.ru nxt_str_t name; 1211133Sigor@sysoev.ru nxt_app_t *app, *prev; 1212359Sigor@sysoev.ru nxt_router_t *router; 1213133Sigor@sysoev.ru nxt_conf_value_t *conf, *http; 1214133Sigor@sysoev.ru nxt_conf_value_t *applications, *application; 1215133Sigor@sysoev.ru nxt_conf_value_t *listeners, *listener; 1216115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1217507Smax.romanov@nginx.com nxt_event_engine_t *engine; 1218216Sigor@sysoev.ru nxt_app_lang_module_t *lang; 1219133Sigor@sysoev.ru nxt_router_app_conf_t apcf; 1220115Sigor@sysoev.ru nxt_router_listener_conf_t lscf; 1221115Sigor@sysoev.ru 1222115Sigor@sysoev.ru static nxt_str_t http_path = nxt_string("/http"); 1223133Sigor@sysoev.ru static nxt_str_t applications_path = nxt_string("/applications"); 1224115Sigor@sysoev.ru static nxt_str_t listeners_path = nxt_string("/listeners"); 1225115Sigor@sysoev.ru 1226208Svbart@nginx.com conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL); 1227115Sigor@sysoev.ru if (conf == NULL) { 1228564Svbart@nginx.com nxt_alert(task, "configuration parsing error"); 1229115Sigor@sysoev.ru return NXT_ERROR; 1230115Sigor@sysoev.ru } 1231115Sigor@sysoev.ru 1232*591Sigor@sysoev.ru mp = tmcf->router_conf->mem_pool; 1233213Svbart@nginx.com 1234213Svbart@nginx.com ret = nxt_conf_map_object(mp, conf, nxt_router_conf, 1235*591Sigor@sysoev.ru nxt_nitems(nxt_router_conf), tmcf->router_conf); 1236115Sigor@sysoev.ru if (ret != NXT_OK) { 1237564Svbart@nginx.com nxt_alert(task, "root map error"); 1238115Sigor@sysoev.ru return NXT_ERROR; 1239115Sigor@sysoev.ru } 1240115Sigor@sysoev.ru 1241*591Sigor@sysoev.ru if (tmcf->router_conf->threads == 0) { 1242*591Sigor@sysoev.ru tmcf->router_conf->threads = nxt_ncpu; 1243117Sigor@sysoev.ru } 1244117Sigor@sysoev.ru 1245133Sigor@sysoev.ru applications = nxt_conf_get_path(conf, &applications_path); 1246133Sigor@sysoev.ru if (applications == NULL) { 1247564Svbart@nginx.com nxt_alert(task, "no \"applications\" block"); 1248115Sigor@sysoev.ru return NXT_ERROR; 1249115Sigor@sysoev.ru } 1250115Sigor@sysoev.ru 1251*591Sigor@sysoev.ru router = tmcf->router_conf->router; 1252359Sigor@sysoev.ru 1253133Sigor@sysoev.ru next = 0; 1254133Sigor@sysoev.ru 1255133Sigor@sysoev.ru for ( ;; ) { 1256133Sigor@sysoev.ru application = nxt_conf_next_object_member(applications, &name, &next); 1257133Sigor@sysoev.ru if (application == NULL) { 1258133Sigor@sysoev.ru break; 1259133Sigor@sysoev.ru } 1260133Sigor@sysoev.ru 1261133Sigor@sysoev.ru nxt_debug(task, "application \"%V\"", &name); 1262133Sigor@sysoev.ru 1263144Smax.romanov@nginx.com size = nxt_conf_json_length(application, NULL); 1264144Smax.romanov@nginx.com 1265144Smax.romanov@nginx.com app = nxt_malloc(sizeof(nxt_app_t) + name.length + size); 1266133Sigor@sysoev.ru if (app == NULL) { 1267133Sigor@sysoev.ru goto fail; 1268133Sigor@sysoev.ru } 1269133Sigor@sysoev.ru 1270144Smax.romanov@nginx.com nxt_memzero(app, sizeof(nxt_app_t)); 1271144Smax.romanov@nginx.com 1272144Smax.romanov@nginx.com app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t)); 1273144Smax.romanov@nginx.com app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length); 1274133Sigor@sysoev.ru 1275133Sigor@sysoev.ru p = nxt_conf_json_print(app->conf.start, application, NULL); 1276133Sigor@sysoev.ru app->conf.length = p - app->conf.start; 1277133Sigor@sysoev.ru 1278144Smax.romanov@nginx.com nxt_assert(app->conf.length <= size); 1279144Smax.romanov@nginx.com 1280133Sigor@sysoev.ru nxt_debug(task, "application conf \"%V\"", &app->conf); 1281133Sigor@sysoev.ru 1282359Sigor@sysoev.ru prev = nxt_router_app_find(&router->apps, &name); 1283133Sigor@sysoev.ru 1284133Sigor@sysoev.ru if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) { 1285133Sigor@sysoev.ru nxt_free(app); 1286133Sigor@sysoev.ru 1287133Sigor@sysoev.ru nxt_queue_remove(&prev->link); 1288133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->previous, &prev->link); 1289133Sigor@sysoev.ru continue; 1290133Sigor@sysoev.ru } 1291133Sigor@sysoev.ru 1292507Smax.romanov@nginx.com apcf.processes = 1; 1293507Smax.romanov@nginx.com apcf.max_processes = 1; 1294537Svbart@nginx.com apcf.spare_processes = 0; 1295318Smax.romanov@nginx.com apcf.timeout = 0; 1296427Smax.romanov@nginx.com apcf.res_timeout = 1000; 1297507Smax.romanov@nginx.com apcf.idle_timeout = 15000; 1298318Smax.romanov@nginx.com apcf.requests = 0; 1299318Smax.romanov@nginx.com apcf.limits_value = NULL; 1300507Smax.romanov@nginx.com apcf.processes_value = NULL; 1301263Smax.romanov@nginx.com 1302213Svbart@nginx.com ret = nxt_conf_map_object(mp, application, nxt_router_app_conf, 1303136Svbart@nginx.com nxt_nitems(nxt_router_app_conf), &apcf); 1304133Sigor@sysoev.ru if (ret != NXT_OK) { 1305564Svbart@nginx.com nxt_alert(task, "application map error"); 1306133Sigor@sysoev.ru goto app_fail; 1307133Sigor@sysoev.ru } 1308115Sigor@sysoev.ru 1309318Smax.romanov@nginx.com if (apcf.limits_value != NULL) { 1310318Smax.romanov@nginx.com 1311318Smax.romanov@nginx.com if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) { 1312564Svbart@nginx.com nxt_alert(task, "application limits is not object"); 1313318Smax.romanov@nginx.com goto app_fail; 1314318Smax.romanov@nginx.com } 1315318Smax.romanov@nginx.com 1316318Smax.romanov@nginx.com ret = nxt_conf_map_object(mp, apcf.limits_value, 1317318Smax.romanov@nginx.com nxt_router_app_limits_conf, 1318318Smax.romanov@nginx.com nxt_nitems(nxt_router_app_limits_conf), 1319318Smax.romanov@nginx.com &apcf); 1320318Smax.romanov@nginx.com if (ret != NXT_OK) { 1321564Svbart@nginx.com nxt_alert(task, "application limits map error"); 1322318Smax.romanov@nginx.com goto app_fail; 1323318Smax.romanov@nginx.com } 1324318Smax.romanov@nginx.com } 1325318Smax.romanov@nginx.com 1326507Smax.romanov@nginx.com if (apcf.processes_value != NULL 1327507Smax.romanov@nginx.com && nxt_conf_type(apcf.processes_value) == NXT_CONF_OBJECT) 1328507Smax.romanov@nginx.com { 1329507Smax.romanov@nginx.com ret = nxt_conf_map_object(mp, apcf.processes_value, 1330507Smax.romanov@nginx.com nxt_router_app_processes_conf, 1331507Smax.romanov@nginx.com nxt_nitems(nxt_router_app_processes_conf), 1332507Smax.romanov@nginx.com &apcf); 1333507Smax.romanov@nginx.com if (ret != NXT_OK) { 1334564Svbart@nginx.com nxt_alert(task, "application processes map error"); 1335507Smax.romanov@nginx.com goto app_fail; 1336507Smax.romanov@nginx.com } 1337507Smax.romanov@nginx.com 1338507Smax.romanov@nginx.com } else { 1339507Smax.romanov@nginx.com apcf.max_processes = apcf.processes; 1340507Smax.romanov@nginx.com apcf.spare_processes = apcf.processes; 1341507Smax.romanov@nginx.com } 1342507Smax.romanov@nginx.com 1343133Sigor@sysoev.ru nxt_debug(task, "application type: %V", &apcf.type); 1344507Smax.romanov@nginx.com nxt_debug(task, "application processes: %D", apcf.processes); 1345507Smax.romanov@nginx.com nxt_debug(task, "application request timeout: %M", apcf.timeout); 1346507Smax.romanov@nginx.com nxt_debug(task, "application reschedule timeout: %M", apcf.res_timeout); 1347318Smax.romanov@nginx.com nxt_debug(task, "application requests: %D", apcf.requests); 1348133Sigor@sysoev.ru 1349216Sigor@sysoev.ru lang = nxt_app_lang_module(task->thread->runtime, &apcf.type); 1350216Sigor@sysoev.ru 1351216Sigor@sysoev.ru if (lang == NULL) { 1352564Svbart@nginx.com nxt_alert(task, "unknown application type: \"%V\"", &apcf.type); 1353141Smax.romanov@nginx.com goto app_fail; 1354141Smax.romanov@nginx.com } 1355141Smax.romanov@nginx.com 1356216Sigor@sysoev.ru nxt_debug(task, "application language module: \"%s\"", lang->file); 1357216Sigor@sysoev.ru 1358133Sigor@sysoev.ru ret = nxt_thread_mutex_create(&app->mutex); 1359133Sigor@sysoev.ru if (ret != NXT_OK) { 1360133Sigor@sysoev.ru goto app_fail; 1361133Sigor@sysoev.ru } 1362133Sigor@sysoev.ru 1363141Smax.romanov@nginx.com nxt_queue_init(&app->ports); 1364507Smax.romanov@nginx.com nxt_queue_init(&app->spare_ports); 1365507Smax.romanov@nginx.com nxt_queue_init(&app->idle_ports); 1366141Smax.romanov@nginx.com nxt_queue_init(&app->requests); 1367427Smax.romanov@nginx.com nxt_queue_init(&app->pending); 1368141Smax.romanov@nginx.com 1369144Smax.romanov@nginx.com app->name.length = name.length; 1370144Smax.romanov@nginx.com nxt_memcpy(app->name.start, name.start, name.length); 1371144Smax.romanov@nginx.com 1372356Svbart@nginx.com app->type = lang->type; 1373507Smax.romanov@nginx.com app->max_processes = apcf.max_processes; 1374507Smax.romanov@nginx.com app->spare_processes = apcf.spare_processes; 1375507Smax.romanov@nginx.com app->max_pending_processes = apcf.spare_processes 1376507Smax.romanov@nginx.com ? apcf.spare_processes : 1; 1377318Smax.romanov@nginx.com app->timeout = apcf.timeout; 1378427Smax.romanov@nginx.com app->res_timeout = apcf.res_timeout * 1000000; 1379507Smax.romanov@nginx.com app->idle_timeout = apcf.idle_timeout; 1380133Sigor@sysoev.ru app->live = 1; 1381343Smax.romanov@nginx.com app->max_pending_responses = 2; 1382428Smax.romanov@nginx.com app->max_requests = apcf.requests; 1383356Svbart@nginx.com app->prepare_msg = nxt_app_prepare_msg[lang->type]; 1384133Sigor@sysoev.ru 1385507Smax.romanov@nginx.com engine = task->thread->engine; 1386507Smax.romanov@nginx.com 1387507Smax.romanov@nginx.com app->engine = engine; 1388507Smax.romanov@nginx.com 1389507Smax.romanov@nginx.com app->idle_timer.precision = NXT_TIMER_DEFAULT_PRECISION; 1390507Smax.romanov@nginx.com app->idle_timer.work_queue = &engine->fast_work_queue; 1391507Smax.romanov@nginx.com app->idle_timer.handler = nxt_router_app_idle_timeout; 1392507Smax.romanov@nginx.com app->idle_timer.task = &engine->task; 1393507Smax.romanov@nginx.com app->idle_timer.log = app->idle_timer.task->log; 1394507Smax.romanov@nginx.com 1395507Smax.romanov@nginx.com app->adjust_idle_work.handler = nxt_router_adjust_idle_timer; 1396507Smax.romanov@nginx.com app->adjust_idle_work.task = &engine->task; 1397507Smax.romanov@nginx.com app->adjust_idle_work.obj = app; 1398507Smax.romanov@nginx.com 1399133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->apps, &app->link); 1400343Smax.romanov@nginx.com 1401343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 1402133Sigor@sysoev.ru } 1403133Sigor@sysoev.ru 1404133Sigor@sysoev.ru http = nxt_conf_get_path(conf, &http_path); 1405133Sigor@sysoev.ru #if 0 1406133Sigor@sysoev.ru if (http == NULL) { 1407564Svbart@nginx.com nxt_alert(task, "no \"http\" block"); 1408133Sigor@sysoev.ru return NXT_ERROR; 1409133Sigor@sysoev.ru } 1410133Sigor@sysoev.ru #endif 1411133Sigor@sysoev.ru 1412133Sigor@sysoev.ru listeners = nxt_conf_get_path(conf, &listeners_path); 1413115Sigor@sysoev.ru if (listeners == NULL) { 1414564Svbart@nginx.com nxt_alert(task, "no \"listeners\" block"); 1415115Sigor@sysoev.ru return NXT_ERROR; 1416115Sigor@sysoev.ru } 141753Sigor@sysoev.ru 1418133Sigor@sysoev.ru next = 0; 141953Sigor@sysoev.ru 1420115Sigor@sysoev.ru for ( ;; ) { 1421115Sigor@sysoev.ru listener = nxt_conf_next_object_member(listeners, &name, &next); 1422115Sigor@sysoev.ru if (listener == NULL) { 1423115Sigor@sysoev.ru break; 1424115Sigor@sysoev.ru } 142553Sigor@sysoev.ru 1426359Sigor@sysoev.ru skcf = nxt_router_socket_conf(task, tmcf, &name); 1427115Sigor@sysoev.ru if (skcf == NULL) { 1428133Sigor@sysoev.ru goto fail; 1429115Sigor@sysoev.ru } 143053Sigor@sysoev.ru 1431213Svbart@nginx.com ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf, 1432136Svbart@nginx.com nxt_nitems(nxt_router_listener_conf), &lscf); 1433115Sigor@sysoev.ru if (ret != NXT_OK) { 1434564Svbart@nginx.com nxt_alert(task, "listener map error"); 1435133Sigor@sysoev.ru goto fail; 1436115Sigor@sysoev.ru } 143753Sigor@sysoev.ru 1438133Sigor@sysoev.ru nxt_debug(task, "application: %V", &lscf.application); 1439133Sigor@sysoev.ru 1440133Sigor@sysoev.ru // STUB, default values if http block is not defined. 1441133Sigor@sysoev.ru skcf->header_buffer_size = 2048; 1442133Sigor@sysoev.ru skcf->large_header_buffer_size = 8192; 1443206Smax.romanov@nginx.com skcf->large_header_buffers = 4; 1444206Smax.romanov@nginx.com skcf->body_buffer_size = 16 * 1024; 1445206Smax.romanov@nginx.com skcf->max_body_size = 2 * 1024 * 1024; 1446431Sigor@sysoev.ru skcf->idle_timeout = 65000; 1447133Sigor@sysoev.ru skcf->header_read_timeout = 5000; 1448206Smax.romanov@nginx.com skcf->body_read_timeout = 5000; 1449431Sigor@sysoev.ru skcf->send_timeout = 5000; 145053Sigor@sysoev.ru 1451133Sigor@sysoev.ru if (http != NULL) { 1452213Svbart@nginx.com ret = nxt_conf_map_object(mp, http, nxt_router_http_conf, 1453136Svbart@nginx.com nxt_nitems(nxt_router_http_conf), skcf); 1454133Sigor@sysoev.ru if (ret != NXT_OK) { 1455564Svbart@nginx.com nxt_alert(task, "http map error"); 1456133Sigor@sysoev.ru goto fail; 1457133Sigor@sysoev.ru } 1458115Sigor@sysoev.ru } 1459115Sigor@sysoev.ru 1460431Sigor@sysoev.ru skcf->listen->handler = nxt_http_conn_init; 1461*591Sigor@sysoev.ru skcf->router_conf = tmcf->router_conf; 1462160Sigor@sysoev.ru skcf->router_conf->count++; 1463133Sigor@sysoev.ru skcf->application = nxt_router_listener_application(tmcf, 1464133Sigor@sysoev.ru &lscf.application); 1465567Smax.romanov@nginx.com nxt_router_app_use(task, skcf->application, 1); 1466115Sigor@sysoev.ru } 146753Sigor@sysoev.ru 1468359Sigor@sysoev.ru nxt_queue_add(&tmcf->deleting, &router->sockets); 1469359Sigor@sysoev.ru nxt_queue_init(&router->sockets); 1470198Sigor@sysoev.ru 147153Sigor@sysoev.ru return NXT_OK; 1472133Sigor@sysoev.ru 1473133Sigor@sysoev.ru app_fail: 1474133Sigor@sysoev.ru 1475133Sigor@sysoev.ru nxt_free(app); 1476133Sigor@sysoev.ru 1477133Sigor@sysoev.ru fail: 1478133Sigor@sysoev.ru 1479141Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1480141Smax.romanov@nginx.com 1481141Smax.romanov@nginx.com nxt_queue_remove(&app->link); 1482133Sigor@sysoev.ru nxt_thread_mutex_destroy(&app->mutex); 1483133Sigor@sysoev.ru nxt_free(app); 1484141Smax.romanov@nginx.com 1485141Smax.romanov@nginx.com } nxt_queue_loop; 1486133Sigor@sysoev.ru 1487133Sigor@sysoev.ru return NXT_ERROR; 1488133Sigor@sysoev.ru } 1489133Sigor@sysoev.ru 1490133Sigor@sysoev.ru 1491133Sigor@sysoev.ru static nxt_app_t * 1492133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name) 1493133Sigor@sysoev.ru { 1494141Smax.romanov@nginx.com nxt_app_t *app; 1495141Smax.romanov@nginx.com 1496141Smax.romanov@nginx.com nxt_queue_each(app, queue, nxt_app_t, link) { 1497133Sigor@sysoev.ru 1498133Sigor@sysoev.ru if (nxt_strstr_eq(name, &app->name)) { 1499133Sigor@sysoev.ru return app; 1500133Sigor@sysoev.ru } 1501141Smax.romanov@nginx.com 1502141Smax.romanov@nginx.com } nxt_queue_loop; 1503133Sigor@sysoev.ru 1504133Sigor@sysoev.ru return NULL; 1505133Sigor@sysoev.ru } 1506133Sigor@sysoev.ru 1507133Sigor@sysoev.ru 1508133Sigor@sysoev.ru static nxt_app_t * 1509133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name) 1510133Sigor@sysoev.ru { 1511133Sigor@sysoev.ru nxt_app_t *app; 1512133Sigor@sysoev.ru 1513133Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->apps, name); 1514133Sigor@sysoev.ru 1515133Sigor@sysoev.ru if (app == NULL) { 1516134Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->previous, name); 1517133Sigor@sysoev.ru } 1518133Sigor@sysoev.ru 1519133Sigor@sysoev.ru return app; 152053Sigor@sysoev.ru } 152153Sigor@sysoev.ru 152253Sigor@sysoev.ru 152353Sigor@sysoev.ru static nxt_socket_conf_t * 1524359Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1525359Sigor@sysoev.ru nxt_str_t *name) 152653Sigor@sysoev.ru { 1527359Sigor@sysoev.ru size_t size; 1528359Sigor@sysoev.ru nxt_int_t ret; 1529359Sigor@sysoev.ru nxt_bool_t wildcard; 1530359Sigor@sysoev.ru nxt_sockaddr_t *sa; 1531359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1532359Sigor@sysoev.ru nxt_listen_socket_t *ls; 1533359Sigor@sysoev.ru 1534359Sigor@sysoev.ru sa = nxt_sockaddr_parse(tmcf->mem_pool, name); 1535359Sigor@sysoev.ru if (nxt_slow_path(sa == NULL)) { 1536564Svbart@nginx.com nxt_alert(task, "invalid listener \"%V\"", name); 1537359Sigor@sysoev.ru return NULL; 1538359Sigor@sysoev.ru } 1539359Sigor@sysoev.ru 1540359Sigor@sysoev.ru sa->type = SOCK_STREAM; 1541359Sigor@sysoev.ru 1542359Sigor@sysoev.ru nxt_debug(task, "router listener: \"%*s\"", 1543493Spluknet@nginx.com (size_t) sa->length, nxt_sockaddr_start(sa)); 1544359Sigor@sysoev.ru 1545*591Sigor@sysoev.ru skcf = nxt_mp_zget(tmcf->router_conf->mem_pool, sizeof(nxt_socket_conf_t)); 1546163Smax.romanov@nginx.com if (nxt_slow_path(skcf == NULL)) { 154753Sigor@sysoev.ru return NULL; 154853Sigor@sysoev.ru } 154953Sigor@sysoev.ru 1550359Sigor@sysoev.ru size = nxt_sockaddr_size(sa); 1551359Sigor@sysoev.ru 1552359Sigor@sysoev.ru ret = nxt_router_listen_socket_find(tmcf, skcf, sa); 1553359Sigor@sysoev.ru 1554359Sigor@sysoev.ru if (ret != NXT_OK) { 1555359Sigor@sysoev.ru 1556359Sigor@sysoev.ru ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size); 1557359Sigor@sysoev.ru if (nxt_slow_path(ls == NULL)) { 1558359Sigor@sysoev.ru return NULL; 1559359Sigor@sysoev.ru } 1560359Sigor@sysoev.ru 1561359Sigor@sysoev.ru skcf->listen = ls; 1562359Sigor@sysoev.ru 1563359Sigor@sysoev.ru ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t)); 1564359Sigor@sysoev.ru nxt_memcpy(ls->sockaddr, sa, size); 1565359Sigor@sysoev.ru 1566359Sigor@sysoev.ru nxt_listen_socket_remote_size(ls); 1567359Sigor@sysoev.ru 1568359Sigor@sysoev.ru ls->socket = -1; 1569359Sigor@sysoev.ru ls->backlog = NXT_LISTEN_BACKLOG; 1570359Sigor@sysoev.ru ls->flags = NXT_NONBLOCK; 1571359Sigor@sysoev.ru ls->read_after_accept = 1; 1572359Sigor@sysoev.ru } 1573359Sigor@sysoev.ru 1574359Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) { 1575359Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 1576359Sigor@sysoev.ru case AF_UNIX: 1577359Sigor@sysoev.ru wildcard = 0; 1578359Sigor@sysoev.ru break; 1579359Sigor@sysoev.ru #endif 1580359Sigor@sysoev.ru #if (NXT_INET6) 1581359Sigor@sysoev.ru case AF_INET6: 1582359Sigor@sysoev.ru wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr); 1583359Sigor@sysoev.ru break; 1584359Sigor@sysoev.ru #endif 1585359Sigor@sysoev.ru case AF_INET: 1586359Sigor@sysoev.ru default: 1587359Sigor@sysoev.ru wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY); 1588359Sigor@sysoev.ru break; 1589359Sigor@sysoev.ru } 1590359Sigor@sysoev.ru 1591359Sigor@sysoev.ru if (!wildcard) { 1592*591Sigor@sysoev.ru skcf->sockaddr = nxt_mp_zget(tmcf->router_conf->mem_pool, size); 1593359Sigor@sysoev.ru if (nxt_slow_path(skcf->sockaddr == NULL)) { 1594359Sigor@sysoev.ru return NULL; 1595359Sigor@sysoev.ru } 1596359Sigor@sysoev.ru 1597359Sigor@sysoev.ru nxt_memcpy(skcf->sockaddr, sa, size); 1598359Sigor@sysoev.ru } 1599163Smax.romanov@nginx.com 1600163Smax.romanov@nginx.com return skcf; 160153Sigor@sysoev.ru } 160253Sigor@sysoev.ru 160353Sigor@sysoev.ru 1604359Sigor@sysoev.ru static nxt_int_t 1605359Sigor@sysoev.ru nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, 1606359Sigor@sysoev.ru nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa) 160753Sigor@sysoev.ru { 1608359Sigor@sysoev.ru nxt_router_t *router; 1609359Sigor@sysoev.ru nxt_queue_link_t *qlk; 1610359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1611359Sigor@sysoev.ru 1612*591Sigor@sysoev.ru router = tmcf->router_conf->router; 1613359Sigor@sysoev.ru 1614359Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->sockets); 1615359Sigor@sysoev.ru qlk != nxt_queue_tail(&router->sockets); 1616359Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 161753Sigor@sysoev.ru { 1618359Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1619359Sigor@sysoev.ru 1620359Sigor@sysoev.ru if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) { 1621359Sigor@sysoev.ru nskcf->listen = skcf->listen; 1622359Sigor@sysoev.ru 1623359Sigor@sysoev.ru nxt_queue_remove(qlk); 1624359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->keeping, qlk); 1625359Sigor@sysoev.ru 1626359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->updating, &nskcf->link); 1627359Sigor@sysoev.ru 1628359Sigor@sysoev.ru return NXT_OK; 162953Sigor@sysoev.ru } 163053Sigor@sysoev.ru } 163153Sigor@sysoev.ru 1632359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->pending, &nskcf->link); 1633359Sigor@sysoev.ru 1634359Sigor@sysoev.ru return NXT_DECLINED; 163553Sigor@sysoev.ru } 163653Sigor@sysoev.ru 163753Sigor@sysoev.ru 1638198Sigor@sysoev.ru static void 1639198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task, 1640198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf) 1641198Sigor@sysoev.ru { 1642358Sigor@sysoev.ru size_t size; 1643198Sigor@sysoev.ru uint32_t stream; 1644198Sigor@sysoev.ru nxt_buf_t *b; 1645198Sigor@sysoev.ru nxt_port_t *main_port, *router_port; 1646198Sigor@sysoev.ru nxt_runtime_t *rt; 1647198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 1648198Sigor@sysoev.ru 1649198Sigor@sysoev.ru rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t)); 1650198Sigor@sysoev.ru if (rpc == NULL) { 1651198Sigor@sysoev.ru goto fail; 1652198Sigor@sysoev.ru } 1653198Sigor@sysoev.ru 1654198Sigor@sysoev.ru rpc->socket_conf = skcf; 1655198Sigor@sysoev.ru rpc->temp_conf = tmcf; 1656198Sigor@sysoev.ru 1657359Sigor@sysoev.ru size = nxt_sockaddr_size(skcf->listen->sockaddr); 1658358Sigor@sysoev.ru 1659358Sigor@sysoev.ru b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 1660198Sigor@sysoev.ru if (b == NULL) { 1661198Sigor@sysoev.ru goto fail; 1662198Sigor@sysoev.ru } 1663198Sigor@sysoev.ru 1664359Sigor@sysoev.ru b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size); 1665198Sigor@sysoev.ru 1666198Sigor@sysoev.ru rt = task->thread->runtime; 1667240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1668198Sigor@sysoev.ru router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 1669198Sigor@sysoev.ru 1670198Sigor@sysoev.ru stream = nxt_port_rpc_register_handler(task, router_port, 1671198Sigor@sysoev.ru nxt_router_listen_socket_ready, 1672198Sigor@sysoev.ru nxt_router_listen_socket_error, 1673198Sigor@sysoev.ru main_port->pid, rpc); 1674198Sigor@sysoev.ru if (stream == 0) { 1675198Sigor@sysoev.ru goto fail; 1676198Sigor@sysoev.ru } 1677198Sigor@sysoev.ru 1678198Sigor@sysoev.ru nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1, 1679198Sigor@sysoev.ru stream, router_port->id, b); 1680198Sigor@sysoev.ru 1681198Sigor@sysoev.ru return; 1682198Sigor@sysoev.ru 1683198Sigor@sysoev.ru fail: 1684198Sigor@sysoev.ru 1685198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 1686198Sigor@sysoev.ru } 1687198Sigor@sysoev.ru 1688198Sigor@sysoev.ru 1689198Sigor@sysoev.ru static void 1690198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1691198Sigor@sysoev.ru void *data) 169253Sigor@sysoev.ru { 1693359Sigor@sysoev.ru nxt_int_t ret; 1694359Sigor@sysoev.ru nxt_socket_t s; 1695359Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 169653Sigor@sysoev.ru 1697198Sigor@sysoev.ru rpc = data; 1698198Sigor@sysoev.ru 1699198Sigor@sysoev.ru s = msg->fd; 1700198Sigor@sysoev.ru 1701198Sigor@sysoev.ru ret = nxt_socket_nonblocking(task, s); 1702198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1703198Sigor@sysoev.ru goto fail; 170453Sigor@sysoev.ru } 170553Sigor@sysoev.ru 1706359Sigor@sysoev.ru nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr); 1707198Sigor@sysoev.ru 1708198Sigor@sysoev.ru ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG); 1709198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1710198Sigor@sysoev.ru goto fail; 1711198Sigor@sysoev.ru } 1712198Sigor@sysoev.ru 1713359Sigor@sysoev.ru rpc->socket_conf->listen->socket = s; 1714198Sigor@sysoev.ru 1715198Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 1716198Sigor@sysoev.ru nxt_router_conf_apply, task, rpc->temp_conf, NULL); 1717198Sigor@sysoev.ru 1718198Sigor@sysoev.ru return; 1719148Sigor@sysoev.ru 1720148Sigor@sysoev.ru fail: 1721148Sigor@sysoev.ru 1722148Sigor@sysoev.ru nxt_socket_close(task, s); 1723148Sigor@sysoev.ru 1724198Sigor@sysoev.ru nxt_router_conf_error(task, rpc->temp_conf); 1725198Sigor@sysoev.ru } 1726198Sigor@sysoev.ru 1727198Sigor@sysoev.ru 1728198Sigor@sysoev.ru static void 1729198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1730198Sigor@sysoev.ru void *data) 1731198Sigor@sysoev.ru { 1732198Sigor@sysoev.ru u_char *p; 1733198Sigor@sysoev.ru size_t size; 1734198Sigor@sysoev.ru uint8_t error; 1735198Sigor@sysoev.ru nxt_buf_t *in, *out; 1736198Sigor@sysoev.ru nxt_sockaddr_t *sa; 1737198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 1738198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 1739198Sigor@sysoev.ru 1740198Sigor@sysoev.ru static nxt_str_t socket_errors[] = { 1741198Sigor@sysoev.ru nxt_string("ListenerSystem"), 1742198Sigor@sysoev.ru nxt_string("ListenerNoIPv6"), 1743198Sigor@sysoev.ru nxt_string("ListenerPort"), 1744198Sigor@sysoev.ru nxt_string("ListenerInUse"), 1745198Sigor@sysoev.ru nxt_string("ListenerNoAddress"), 1746198Sigor@sysoev.ru nxt_string("ListenerNoAccess"), 1747198Sigor@sysoev.ru nxt_string("ListenerPath"), 1748198Sigor@sysoev.ru }; 1749198Sigor@sysoev.ru 1750198Sigor@sysoev.ru rpc = data; 1751359Sigor@sysoev.ru sa = rpc->socket_conf->listen->sockaddr; 1752352Smax.romanov@nginx.com tmcf = rpc->temp_conf; 1753352Smax.romanov@nginx.com 1754352Smax.romanov@nginx.com in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size); 1755352Smax.romanov@nginx.com 1756551Smax.romanov@nginx.com if (nxt_slow_path(in == NULL)) { 1757551Smax.romanov@nginx.com return; 1758551Smax.romanov@nginx.com } 1759352Smax.romanov@nginx.com 1760198Sigor@sysoev.ru p = in->mem.pos; 1761198Sigor@sysoev.ru 1762198Sigor@sysoev.ru error = *p++; 1763198Sigor@sysoev.ru 1764198Sigor@sysoev.ru size = sizeof("listen socket error: ") - 1 1765198Sigor@sysoev.ru + sizeof("{listener: \"\", code:\"\", message: \"\"}") - 1 1766198Sigor@sysoev.ru + sa->length + socket_errors[error].length + (in->mem.free - p); 1767198Sigor@sysoev.ru 1768198Sigor@sysoev.ru out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 1769198Sigor@sysoev.ru if (nxt_slow_path(out == NULL)) { 1770198Sigor@sysoev.ru return; 1771198Sigor@sysoev.ru } 1772198Sigor@sysoev.ru 1773198Sigor@sysoev.ru out->mem.free = nxt_sprintf(out->mem.free, out->mem.end, 1774198Sigor@sysoev.ru "listen socket error: " 1775198Sigor@sysoev.ru "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}", 1776493Spluknet@nginx.com (size_t) sa->length, nxt_sockaddr_start(sa), 1777198Sigor@sysoev.ru &socket_errors[error], in->mem.free - p, p); 1778198Sigor@sysoev.ru 1779198Sigor@sysoev.ru nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos); 1780198Sigor@sysoev.ru 1781198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 178253Sigor@sysoev.ru } 178353Sigor@sysoev.ru 178453Sigor@sysoev.ru 1785507Smax.romanov@nginx.com static void 1786507Smax.romanov@nginx.com nxt_router_app_rpc_create(nxt_task_t *task, 1787507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_app_t *app) 1788507Smax.romanov@nginx.com { 1789507Smax.romanov@nginx.com size_t size; 1790507Smax.romanov@nginx.com uint32_t stream; 1791507Smax.romanov@nginx.com nxt_buf_t *b; 1792507Smax.romanov@nginx.com nxt_port_t *main_port, *router_port; 1793507Smax.romanov@nginx.com nxt_runtime_t *rt; 1794507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 1795507Smax.romanov@nginx.com 1796507Smax.romanov@nginx.com rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_app_rpc_t)); 1797507Smax.romanov@nginx.com if (rpc == NULL) { 1798507Smax.romanov@nginx.com goto fail; 1799507Smax.romanov@nginx.com } 1800507Smax.romanov@nginx.com 1801507Smax.romanov@nginx.com rpc->app = app; 1802507Smax.romanov@nginx.com rpc->temp_conf = tmcf; 1803507Smax.romanov@nginx.com 1804507Smax.romanov@nginx.com nxt_debug(task, "app '%V' prefork", &app->name); 1805507Smax.romanov@nginx.com 1806507Smax.romanov@nginx.com size = app->name.length + 1 + app->conf.length; 1807507Smax.romanov@nginx.com 1808507Smax.romanov@nginx.com b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 1809507Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 1810507Smax.romanov@nginx.com goto fail; 1811507Smax.romanov@nginx.com } 1812507Smax.romanov@nginx.com 1813507Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->name); 1814507Smax.romanov@nginx.com *b->mem.free++ = '\0'; 1815507Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 1816507Smax.romanov@nginx.com 1817507Smax.romanov@nginx.com rt = task->thread->runtime; 1818507Smax.romanov@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1819507Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 1820507Smax.romanov@nginx.com 1821507Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 1822507Smax.romanov@nginx.com nxt_router_app_prefork_ready, 1823507Smax.romanov@nginx.com nxt_router_app_prefork_error, 1824507Smax.romanov@nginx.com -1, rpc); 1825507Smax.romanov@nginx.com if (nxt_slow_path(stream == 0)) { 1826507Smax.romanov@nginx.com goto fail; 1827507Smax.romanov@nginx.com } 1828507Smax.romanov@nginx.com 1829507Smax.romanov@nginx.com app->pending_processes++; 1830507Smax.romanov@nginx.com 1831507Smax.romanov@nginx.com nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1, 1832507Smax.romanov@nginx.com stream, router_port->id, b); 1833507Smax.romanov@nginx.com 1834507Smax.romanov@nginx.com return; 1835507Smax.romanov@nginx.com 1836507Smax.romanov@nginx.com fail: 1837507Smax.romanov@nginx.com 1838507Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 1839507Smax.romanov@nginx.com } 1840507Smax.romanov@nginx.com 1841507Smax.romanov@nginx.com 1842507Smax.romanov@nginx.com static void 1843507Smax.romanov@nginx.com nxt_router_app_prefork_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1844507Smax.romanov@nginx.com void *data) 1845507Smax.romanov@nginx.com { 1846507Smax.romanov@nginx.com nxt_app_t *app; 1847507Smax.romanov@nginx.com nxt_port_t *port; 1848507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 1849507Smax.romanov@nginx.com nxt_event_engine_t *engine; 1850507Smax.romanov@nginx.com 1851507Smax.romanov@nginx.com rpc = data; 1852507Smax.romanov@nginx.com app = rpc->app; 1853507Smax.romanov@nginx.com 1854507Smax.romanov@nginx.com port = msg->u.new_port; 1855507Smax.romanov@nginx.com port->app = app; 1856507Smax.romanov@nginx.com 1857507Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 1858507Smax.romanov@nginx.com 1859507Smax.romanov@nginx.com app->pending_processes--; 1860507Smax.romanov@nginx.com app->processes++; 1861507Smax.romanov@nginx.com app->idle_processes++; 1862507Smax.romanov@nginx.com 1863507Smax.romanov@nginx.com engine = task->thread->engine; 1864507Smax.romanov@nginx.com 1865507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &port->app_link); 1866507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, &port->idle_link); 1867507Smax.romanov@nginx.com 1868507Smax.romanov@nginx.com port->idle_start = 0; 1869507Smax.romanov@nginx.com 1870507Smax.romanov@nginx.com nxt_port_inc_use(port); 1871507Smax.romanov@nginx.com 1872507Smax.romanov@nginx.com nxt_work_queue_add(&engine->fast_work_queue, 1873507Smax.romanov@nginx.com nxt_router_conf_apply, task, rpc->temp_conf, NULL); 1874507Smax.romanov@nginx.com } 1875507Smax.romanov@nginx.com 1876507Smax.romanov@nginx.com 1877507Smax.romanov@nginx.com static void 1878507Smax.romanov@nginx.com nxt_router_app_prefork_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1879507Smax.romanov@nginx.com void *data) 1880507Smax.romanov@nginx.com { 1881507Smax.romanov@nginx.com nxt_app_t *app; 1882507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 1883507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf; 1884507Smax.romanov@nginx.com 1885507Smax.romanov@nginx.com rpc = data; 1886507Smax.romanov@nginx.com app = rpc->app; 1887507Smax.romanov@nginx.com tmcf = rpc->temp_conf; 1888507Smax.romanov@nginx.com 1889507Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, "failed to start application \"%V\"", 1890507Smax.romanov@nginx.com &app->name); 1891507Smax.romanov@nginx.com 1892507Smax.romanov@nginx.com app->pending_processes--; 1893507Smax.romanov@nginx.com 1894507Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 1895507Smax.romanov@nginx.com } 1896507Smax.romanov@nginx.com 1897507Smax.romanov@nginx.com 189853Sigor@sysoev.ru static nxt_int_t 189953Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router, 190053Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface) 190153Sigor@sysoev.ru { 190253Sigor@sysoev.ru nxt_int_t ret; 190353Sigor@sysoev.ru nxt_uint_t n, threads; 190453Sigor@sysoev.ru nxt_queue_link_t *qlk; 190553Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 190653Sigor@sysoev.ru 1907*591Sigor@sysoev.ru threads = tmcf->router_conf->threads; 190853Sigor@sysoev.ru 190953Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, threads, 191053Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 191153Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 191253Sigor@sysoev.ru return NXT_ERROR; 191353Sigor@sysoev.ru } 191453Sigor@sysoev.ru 191553Sigor@sysoev.ru n = 0; 191653Sigor@sysoev.ru 191753Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->engines); 191853Sigor@sysoev.ru qlk != nxt_queue_tail(&router->engines); 191953Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 192053Sigor@sysoev.ru { 192153Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 192253Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 192353Sigor@sysoev.ru return NXT_ERROR; 192453Sigor@sysoev.ru } 192553Sigor@sysoev.ru 1926115Sigor@sysoev.ru recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0); 192753Sigor@sysoev.ru 192853Sigor@sysoev.ru if (n < threads) { 1929315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_KEEP; 1930115Sigor@sysoev.ru ret = nxt_router_engine_conf_update(tmcf, recf); 193153Sigor@sysoev.ru 193253Sigor@sysoev.ru } else { 1933315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_DELETE; 1934115Sigor@sysoev.ru ret = nxt_router_engine_conf_delete(tmcf, recf); 193553Sigor@sysoev.ru } 193653Sigor@sysoev.ru 193753Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 193853Sigor@sysoev.ru return ret; 193953Sigor@sysoev.ru } 194053Sigor@sysoev.ru 194153Sigor@sysoev.ru n++; 194253Sigor@sysoev.ru } 194353Sigor@sysoev.ru 194453Sigor@sysoev.ru tmcf->new_threads = n; 194553Sigor@sysoev.ru 194653Sigor@sysoev.ru while (n < threads) { 194753Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 194853Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 194953Sigor@sysoev.ru return NXT_ERROR; 195053Sigor@sysoev.ru } 195153Sigor@sysoev.ru 1952315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_ADD; 1953315Sigor@sysoev.ru 195453Sigor@sysoev.ru recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0); 195553Sigor@sysoev.ru if (nxt_slow_path(recf->engine == NULL)) { 195653Sigor@sysoev.ru return NXT_ERROR; 195753Sigor@sysoev.ru } 195853Sigor@sysoev.ru 1959115Sigor@sysoev.ru ret = nxt_router_engine_conf_create(tmcf, recf); 196053Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 196153Sigor@sysoev.ru return ret; 196253Sigor@sysoev.ru } 196353Sigor@sysoev.ru 196453Sigor@sysoev.ru n++; 196553Sigor@sysoev.ru } 196653Sigor@sysoev.ru 196753Sigor@sysoev.ru return NXT_OK; 196853Sigor@sysoev.ru } 196953Sigor@sysoev.ru 197053Sigor@sysoev.ru 197153Sigor@sysoev.ru static nxt_int_t 1972115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 1973115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 197453Sigor@sysoev.ru { 1975359Sigor@sysoev.ru nxt_int_t ret; 197653Sigor@sysoev.ru 1977154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 1978154Sigor@sysoev.ru nxt_router_listen_socket_create); 1979115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1980115Sigor@sysoev.ru return ret; 1981115Sigor@sysoev.ru } 1982115Sigor@sysoev.ru 1983154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 1984154Sigor@sysoev.ru nxt_router_listen_socket_create); 198553Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 198653Sigor@sysoev.ru return ret; 198753Sigor@sysoev.ru } 198853Sigor@sysoev.ru 1989115Sigor@sysoev.ru return ret; 199053Sigor@sysoev.ru } 199153Sigor@sysoev.ru 199253Sigor@sysoev.ru 199353Sigor@sysoev.ru static nxt_int_t 1994115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 1995115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 199653Sigor@sysoev.ru { 1997359Sigor@sysoev.ru nxt_int_t ret; 199853Sigor@sysoev.ru 1999154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 2000154Sigor@sysoev.ru nxt_router_listen_socket_create); 200153Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 200253Sigor@sysoev.ru return ret; 200353Sigor@sysoev.ru } 200453Sigor@sysoev.ru 2005154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 2006154Sigor@sysoev.ru nxt_router_listen_socket_update); 200753Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 200853Sigor@sysoev.ru return ret; 200953Sigor@sysoev.ru } 201053Sigor@sysoev.ru 2011139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 2012115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2013115Sigor@sysoev.ru return ret; 2014115Sigor@sysoev.ru } 2015115Sigor@sysoev.ru 2016115Sigor@sysoev.ru return ret; 201753Sigor@sysoev.ru } 201853Sigor@sysoev.ru 201953Sigor@sysoev.ru 202053Sigor@sysoev.ru static nxt_int_t 2021115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 2022115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 202353Sigor@sysoev.ru { 202453Sigor@sysoev.ru nxt_int_t ret; 202553Sigor@sysoev.ru 2026313Sigor@sysoev.ru ret = nxt_router_engine_quit(tmcf, recf); 2027313Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2028313Sigor@sysoev.ru return ret; 2029313Sigor@sysoev.ru } 2030313Sigor@sysoev.ru 2031139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating); 203253Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 203353Sigor@sysoev.ru return ret; 203453Sigor@sysoev.ru } 203553Sigor@sysoev.ru 2036139Sigor@sysoev.ru return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 203753Sigor@sysoev.ru } 203853Sigor@sysoev.ru 203953Sigor@sysoev.ru 204053Sigor@sysoev.ru static nxt_int_t 2041154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 2042154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 204353Sigor@sysoev.ru nxt_work_handler_t handler) 204453Sigor@sysoev.ru { 2045153Sigor@sysoev.ru nxt_joint_job_t *job; 204653Sigor@sysoev.ru nxt_queue_link_t *qlk; 2047155Sigor@sysoev.ru nxt_socket_conf_t *skcf; 204853Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 204953Sigor@sysoev.ru 205053Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 205153Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 205253Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 205353Sigor@sysoev.ru { 2054154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2055153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2056139Sigor@sysoev.ru return NXT_ERROR; 2057139Sigor@sysoev.ru } 2058139Sigor@sysoev.ru 2059154Sigor@sysoev.ru job->work.next = recf->jobs; 2060154Sigor@sysoev.ru recf->jobs = &job->work; 2061154Sigor@sysoev.ru 2062153Sigor@sysoev.ru job->task = tmcf->engine->task; 2063153Sigor@sysoev.ru job->work.handler = handler; 2064153Sigor@sysoev.ru job->work.task = &job->task; 2065153Sigor@sysoev.ru job->work.obj = job; 2066153Sigor@sysoev.ru job->tmcf = tmcf; 206753Sigor@sysoev.ru 2068154Sigor@sysoev.ru tmcf->count++; 2069154Sigor@sysoev.ru 2070*591Sigor@sysoev.ru joint = nxt_mp_alloc(tmcf->router_conf->mem_pool, 2071154Sigor@sysoev.ru sizeof(nxt_socket_conf_joint_t)); 207253Sigor@sysoev.ru if (nxt_slow_path(joint == NULL)) { 207353Sigor@sysoev.ru return NXT_ERROR; 207453Sigor@sysoev.ru } 207553Sigor@sysoev.ru 2076153Sigor@sysoev.ru job->work.data = joint; 207753Sigor@sysoev.ru 207853Sigor@sysoev.ru joint->count = 1; 2079155Sigor@sysoev.ru 2080155Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 2081155Sigor@sysoev.ru skcf->count++; 2082155Sigor@sysoev.ru joint->socket_conf = skcf; 2083155Sigor@sysoev.ru 208488Smax.romanov@nginx.com joint->engine = recf->engine; 208553Sigor@sysoev.ru } 208653Sigor@sysoev.ru 208720Sigor@sysoev.ru return NXT_OK; 208820Sigor@sysoev.ru } 208920Sigor@sysoev.ru 209020Sigor@sysoev.ru 209120Sigor@sysoev.ru static nxt_int_t 2092313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 2093313Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 2094313Sigor@sysoev.ru { 2095313Sigor@sysoev.ru nxt_joint_job_t *job; 2096313Sigor@sysoev.ru 2097313Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2098313Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2099313Sigor@sysoev.ru return NXT_ERROR; 2100313Sigor@sysoev.ru } 2101313Sigor@sysoev.ru 2102313Sigor@sysoev.ru job->work.next = recf->jobs; 2103313Sigor@sysoev.ru recf->jobs = &job->work; 2104313Sigor@sysoev.ru 2105313Sigor@sysoev.ru job->task = tmcf->engine->task; 2106313Sigor@sysoev.ru job->work.handler = nxt_router_worker_thread_quit; 2107313Sigor@sysoev.ru job->work.task = &job->task; 2108313Sigor@sysoev.ru job->work.obj = NULL; 2109313Sigor@sysoev.ru job->work.data = NULL; 2110313Sigor@sysoev.ru job->tmcf = NULL; 2111313Sigor@sysoev.ru 2112313Sigor@sysoev.ru return NXT_OK; 2113313Sigor@sysoev.ru } 2114313Sigor@sysoev.ru 2115313Sigor@sysoev.ru 2116313Sigor@sysoev.ru static nxt_int_t 2117139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 2118139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets) 211920Sigor@sysoev.ru { 2120153Sigor@sysoev.ru nxt_joint_job_t *job; 212153Sigor@sysoev.ru nxt_queue_link_t *qlk; 212220Sigor@sysoev.ru 212353Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 212453Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 212553Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 212653Sigor@sysoev.ru { 2127154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2128153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2129139Sigor@sysoev.ru return NXT_ERROR; 2130139Sigor@sysoev.ru } 2131139Sigor@sysoev.ru 2132154Sigor@sysoev.ru job->work.next = recf->jobs; 2133154Sigor@sysoev.ru recf->jobs = &job->work; 2134154Sigor@sysoev.ru 2135153Sigor@sysoev.ru job->task = tmcf->engine->task; 2136153Sigor@sysoev.ru job->work.handler = nxt_router_listen_socket_delete; 2137153Sigor@sysoev.ru job->work.task = &job->task; 2138153Sigor@sysoev.ru job->work.obj = job; 2139153Sigor@sysoev.ru job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 2140153Sigor@sysoev.ru job->tmcf = tmcf; 2141154Sigor@sysoev.ru 2142154Sigor@sysoev.ru tmcf->count++; 214320Sigor@sysoev.ru } 214420Sigor@sysoev.ru 214553Sigor@sysoev.ru return NXT_OK; 214653Sigor@sysoev.ru } 214720Sigor@sysoev.ru 214820Sigor@sysoev.ru 214953Sigor@sysoev.ru static nxt_int_t 215053Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 215153Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 215253Sigor@sysoev.ru { 215353Sigor@sysoev.ru nxt_int_t ret; 215453Sigor@sysoev.ru nxt_uint_t i, threads; 215553Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 215620Sigor@sysoev.ru 215753Sigor@sysoev.ru recf = tmcf->engines->elts; 2158*591Sigor@sysoev.ru threads = tmcf->router_conf->threads; 215920Sigor@sysoev.ru 216053Sigor@sysoev.ru for (i = tmcf->new_threads; i < threads; i++) { 216153Sigor@sysoev.ru ret = nxt_router_thread_create(task, rt, recf[i].engine); 216253Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 216353Sigor@sysoev.ru return ret; 216453Sigor@sysoev.ru } 216520Sigor@sysoev.ru } 216620Sigor@sysoev.ru 216720Sigor@sysoev.ru return NXT_OK; 216820Sigor@sysoev.ru } 216953Sigor@sysoev.ru 217053Sigor@sysoev.ru 217153Sigor@sysoev.ru static nxt_int_t 217253Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 217353Sigor@sysoev.ru nxt_event_engine_t *engine) 217453Sigor@sysoev.ru { 217553Sigor@sysoev.ru nxt_int_t ret; 217653Sigor@sysoev.ru nxt_thread_link_t *link; 217753Sigor@sysoev.ru nxt_thread_handle_t handle; 217853Sigor@sysoev.ru 217953Sigor@sysoev.ru link = nxt_zalloc(sizeof(nxt_thread_link_t)); 218053Sigor@sysoev.ru 218153Sigor@sysoev.ru if (nxt_slow_path(link == NULL)) { 218253Sigor@sysoev.ru return NXT_ERROR; 218353Sigor@sysoev.ru } 218453Sigor@sysoev.ru 218553Sigor@sysoev.ru link->start = nxt_router_thread_start; 218653Sigor@sysoev.ru link->engine = engine; 218753Sigor@sysoev.ru link->work.handler = nxt_router_thread_exit_handler; 218853Sigor@sysoev.ru link->work.task = task; 218953Sigor@sysoev.ru link->work.data = link; 219053Sigor@sysoev.ru 219153Sigor@sysoev.ru nxt_queue_insert_tail(&rt->engines, &engine->link); 219253Sigor@sysoev.ru 219353Sigor@sysoev.ru ret = nxt_thread_create(&handle, link); 219453Sigor@sysoev.ru 219553Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 219653Sigor@sysoev.ru nxt_queue_remove(&engine->link); 219753Sigor@sysoev.ru } 219853Sigor@sysoev.ru 219953Sigor@sysoev.ru return ret; 220053Sigor@sysoev.ru } 220153Sigor@sysoev.ru 220253Sigor@sysoev.ru 220353Sigor@sysoev.ru static void 2204343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 2205343Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf) 2206133Sigor@sysoev.ru { 2207507Smax.romanov@nginx.com nxt_app_t *app; 2208141Smax.romanov@nginx.com 2209141Smax.romanov@nginx.com nxt_queue_each(app, &router->apps, nxt_app_t, link) { 2210133Sigor@sysoev.ru 2211507Smax.romanov@nginx.com nxt_router_app_quit(task, app); 2212343Smax.romanov@nginx.com 2213141Smax.romanov@nginx.com } nxt_queue_loop; 2214133Sigor@sysoev.ru 2215133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->previous); 2216133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->apps); 2217133Sigor@sysoev.ru } 2218133Sigor@sysoev.ru 2219133Sigor@sysoev.ru 2220133Sigor@sysoev.ru static void 2221315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf) 222253Sigor@sysoev.ru { 222353Sigor@sysoev.ru nxt_uint_t n; 2224315Sigor@sysoev.ru nxt_event_engine_t *engine; 222553Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 222653Sigor@sysoev.ru 222753Sigor@sysoev.ru recf = tmcf->engines->elts; 222853Sigor@sysoev.ru 222953Sigor@sysoev.ru for (n = tmcf->engines->nelts; n != 0; n--) { 2230315Sigor@sysoev.ru engine = recf->engine; 2231315Sigor@sysoev.ru 2232315Sigor@sysoev.ru switch (recf->action) { 2233315Sigor@sysoev.ru 2234315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_KEEP: 2235315Sigor@sysoev.ru break; 2236315Sigor@sysoev.ru 2237315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_ADD: 2238315Sigor@sysoev.ru nxt_queue_insert_tail(&router->engines, &engine->link0); 2239315Sigor@sysoev.ru break; 2240315Sigor@sysoev.ru 2241315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_DELETE: 2242315Sigor@sysoev.ru nxt_queue_remove(&engine->link0); 2243315Sigor@sysoev.ru break; 2244315Sigor@sysoev.ru } 2245315Sigor@sysoev.ru 2246316Sigor@sysoev.ru nxt_router_engine_post(engine, recf->jobs); 2247316Sigor@sysoev.ru 224853Sigor@sysoev.ru recf++; 224953Sigor@sysoev.ru } 225053Sigor@sysoev.ru } 225153Sigor@sysoev.ru 225253Sigor@sysoev.ru 225353Sigor@sysoev.ru static void 2254315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs) 225553Sigor@sysoev.ru { 2256154Sigor@sysoev.ru nxt_work_t *work, *next; 2257154Sigor@sysoev.ru 2258315Sigor@sysoev.ru for (work = jobs; work != NULL; work = next) { 2259154Sigor@sysoev.ru next = work->next; 2260154Sigor@sysoev.ru work->next = NULL; 2261154Sigor@sysoev.ru 2262315Sigor@sysoev.ru nxt_event_engine_post(engine, work); 226353Sigor@sysoev.ru } 226453Sigor@sysoev.ru } 226553Sigor@sysoev.ru 226653Sigor@sysoev.ru 2267320Smax.romanov@nginx.com static nxt_port_handlers_t nxt_router_app_port_handlers = { 2268320Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 2269320Smax.romanov@nginx.com .data = nxt_port_rpc_handler, 227088Smax.romanov@nginx.com }; 227188Smax.romanov@nginx.com 227288Smax.romanov@nginx.com 227388Smax.romanov@nginx.com static void 227453Sigor@sysoev.ru nxt_router_thread_start(void *data) 227553Sigor@sysoev.ru { 2276141Smax.romanov@nginx.com nxt_int_t ret; 2277141Smax.romanov@nginx.com nxt_port_t *port; 227888Smax.romanov@nginx.com nxt_task_t *task; 227953Sigor@sysoev.ru nxt_thread_t *thread; 228053Sigor@sysoev.ru nxt_thread_link_t *link; 228153Sigor@sysoev.ru nxt_event_engine_t *engine; 228253Sigor@sysoev.ru 228353Sigor@sysoev.ru link = data; 228453Sigor@sysoev.ru engine = link->engine; 228588Smax.romanov@nginx.com task = &engine->task; 228653Sigor@sysoev.ru 228753Sigor@sysoev.ru thread = nxt_thread(); 228853Sigor@sysoev.ru 2289165Smax.romanov@nginx.com nxt_event_engine_thread_adopt(engine); 2290165Smax.romanov@nginx.com 229153Sigor@sysoev.ru /* STUB */ 229253Sigor@sysoev.ru thread->runtime = engine->task.thread->runtime; 229353Sigor@sysoev.ru 229453Sigor@sysoev.ru engine->task.thread = thread; 229553Sigor@sysoev.ru engine->task.log = thread->log; 229653Sigor@sysoev.ru thread->engine = engine; 229763Sigor@sysoev.ru thread->task = &engine->task; 2298326Svbart@nginx.com #if 0 229953Sigor@sysoev.ru thread->fiber = &engine->fibers->fiber; 2300326Svbart@nginx.com #endif 230153Sigor@sysoev.ru 230263Sigor@sysoev.ru engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64); 2303337Sigor@sysoev.ru if (nxt_slow_path(engine->mem_pool == NULL)) { 2304337Sigor@sysoev.ru return; 2305337Sigor@sysoev.ru } 230653Sigor@sysoev.ru 2307197Smax.romanov@nginx.com port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid, 2308197Smax.romanov@nginx.com NXT_PROCESS_ROUTER); 2309141Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 2310141Smax.romanov@nginx.com return; 2311141Smax.romanov@nginx.com } 2312141Smax.romanov@nginx.com 2313141Smax.romanov@nginx.com ret = nxt_port_socket_init(task, port, 0); 2314141Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2315343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 2316141Smax.romanov@nginx.com return; 2317141Smax.romanov@nginx.com } 2318141Smax.romanov@nginx.com 2319141Smax.romanov@nginx.com engine->port = port; 2320141Smax.romanov@nginx.com 2321320Smax.romanov@nginx.com nxt_port_enable(task, port, &nxt_router_app_port_handlers); 2322141Smax.romanov@nginx.com 232353Sigor@sysoev.ru nxt_event_engine_start(engine); 232453Sigor@sysoev.ru } 232553Sigor@sysoev.ru 232653Sigor@sysoev.ru 232753Sigor@sysoev.ru static void 232853Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data) 232953Sigor@sysoev.ru { 2330153Sigor@sysoev.ru nxt_joint_job_t *job; 2331359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2332359Sigor@sysoev.ru nxt_listen_event_t *lev; 233353Sigor@sysoev.ru nxt_listen_socket_t *ls; 2334359Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 233553Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 233653Sigor@sysoev.ru 2337153Sigor@sysoev.ru job = obj; 233853Sigor@sysoev.ru joint = data; 233953Sigor@sysoev.ru 2340159Sigor@sysoev.ru nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link); 2341159Sigor@sysoev.ru 2342359Sigor@sysoev.ru skcf = joint->socket_conf; 2343359Sigor@sysoev.ru ls = skcf->listen; 2344359Sigor@sysoev.ru 2345359Sigor@sysoev.ru lev = nxt_listen_event(task, ls); 2346359Sigor@sysoev.ru if (nxt_slow_path(lev == NULL)) { 2347359Sigor@sysoev.ru nxt_router_listen_socket_release(task, skcf); 234853Sigor@sysoev.ru return; 234953Sigor@sysoev.ru } 235053Sigor@sysoev.ru 2351359Sigor@sysoev.ru lev->socket.data = joint; 2352359Sigor@sysoev.ru 2353359Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 2354359Sigor@sysoev.ru 2355359Sigor@sysoev.ru nxt_thread_spin_lock(lock); 2356359Sigor@sysoev.ru ls->count++; 2357359Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 2358139Sigor@sysoev.ru 2359153Sigor@sysoev.ru job->work.next = NULL; 2360153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2361153Sigor@sysoev.ru 2362153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 236353Sigor@sysoev.ru } 236453Sigor@sysoev.ru 236553Sigor@sysoev.ru 236653Sigor@sysoev.ru nxt_inline nxt_listen_event_t * 236753Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections, 236853Sigor@sysoev.ru nxt_socket_conf_t *skcf) 236953Sigor@sysoev.ru { 2370115Sigor@sysoev.ru nxt_socket_t fd; 2371115Sigor@sysoev.ru nxt_queue_link_t *qlk; 2372359Sigor@sysoev.ru nxt_listen_event_t *lev; 2373359Sigor@sysoev.ru 2374359Sigor@sysoev.ru fd = skcf->listen->socket; 237553Sigor@sysoev.ru 2376115Sigor@sysoev.ru for (qlk = nxt_queue_first(listen_connections); 2377115Sigor@sysoev.ru qlk != nxt_queue_tail(listen_connections); 2378115Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 237953Sigor@sysoev.ru { 2380359Sigor@sysoev.ru lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link); 2381359Sigor@sysoev.ru 2382359Sigor@sysoev.ru if (fd == lev->socket.fd) { 2383359Sigor@sysoev.ru return lev; 238453Sigor@sysoev.ru } 238553Sigor@sysoev.ru } 238653Sigor@sysoev.ru 238753Sigor@sysoev.ru return NULL; 238853Sigor@sysoev.ru } 238953Sigor@sysoev.ru 239053Sigor@sysoev.ru 239153Sigor@sysoev.ru static void 239253Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data) 239353Sigor@sysoev.ru { 2394153Sigor@sysoev.ru nxt_joint_job_t *job; 239553Sigor@sysoev.ru nxt_event_engine_t *engine; 2396359Sigor@sysoev.ru nxt_listen_event_t *lev; 239753Sigor@sysoev.ru nxt_socket_conf_joint_t *joint, *old; 239853Sigor@sysoev.ru 2399153Sigor@sysoev.ru job = obj; 240053Sigor@sysoev.ru joint = data; 240153Sigor@sysoev.ru 2402139Sigor@sysoev.ru engine = task->thread->engine; 2403139Sigor@sysoev.ru 2404159Sigor@sysoev.ru nxt_queue_insert_tail(&engine->joints, &joint->link); 2405159Sigor@sysoev.ru 2406359Sigor@sysoev.ru lev = nxt_router_listen_event(&engine->listen_connections, 2407359Sigor@sysoev.ru joint->socket_conf); 2408359Sigor@sysoev.ru 2409359Sigor@sysoev.ru old = lev->socket.data; 2410359Sigor@sysoev.ru lev->socket.data = joint; 2411359Sigor@sysoev.ru lev->listen = joint->socket_conf->listen; 241253Sigor@sysoev.ru 2413153Sigor@sysoev.ru job->work.next = NULL; 2414153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2415153Sigor@sysoev.ru 2416153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 2417139Sigor@sysoev.ru 2418181Smax.romanov@nginx.com /* 2419181Smax.romanov@nginx.com * The task is allocated from configuration temporary 2420181Smax.romanov@nginx.com * memory pool so it can be freed after engine post operation. 2421181Smax.romanov@nginx.com */ 2422181Smax.romanov@nginx.com 2423181Smax.romanov@nginx.com nxt_router_conf_release(&engine->task, old); 242453Sigor@sysoev.ru } 242553Sigor@sysoev.ru 242653Sigor@sysoev.ru 242753Sigor@sysoev.ru static void 242853Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data) 242953Sigor@sysoev.ru { 2430153Sigor@sysoev.ru nxt_joint_job_t *job; 2431153Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2432359Sigor@sysoev.ru nxt_listen_event_t *lev; 2433153Sigor@sysoev.ru nxt_event_engine_t *engine; 2434153Sigor@sysoev.ru 2435153Sigor@sysoev.ru job = obj; 243653Sigor@sysoev.ru skcf = data; 243753Sigor@sysoev.ru 2438139Sigor@sysoev.ru engine = task->thread->engine; 2439139Sigor@sysoev.ru 2440359Sigor@sysoev.ru lev = nxt_router_listen_event(&engine->listen_connections, skcf); 2441359Sigor@sysoev.ru 2442359Sigor@sysoev.ru nxt_fd_event_delete(engine, &lev->socket); 244353Sigor@sysoev.ru 2444163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket delete: %d", engine, 2445359Sigor@sysoev.ru lev->socket.fd); 2446359Sigor@sysoev.ru 2447359Sigor@sysoev.ru lev->timer.handler = nxt_router_listen_socket_close; 2448359Sigor@sysoev.ru lev->timer.work_queue = &engine->fast_work_queue; 2449359Sigor@sysoev.ru 2450359Sigor@sysoev.ru nxt_timer_add(engine, &lev->timer, 0); 2451139Sigor@sysoev.ru 2452153Sigor@sysoev.ru job->work.next = NULL; 2453153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2454153Sigor@sysoev.ru 2455153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 245653Sigor@sysoev.ru } 245753Sigor@sysoev.ru 245853Sigor@sysoev.ru 245953Sigor@sysoev.ru static void 2460313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data) 2461313Sigor@sysoev.ru { 2462313Sigor@sysoev.ru nxt_event_engine_t *engine; 2463313Sigor@sysoev.ru 2464313Sigor@sysoev.ru nxt_debug(task, "router worker thread quit"); 2465313Sigor@sysoev.ru 2466313Sigor@sysoev.ru engine = task->thread->engine; 2467313Sigor@sysoev.ru 2468313Sigor@sysoev.ru engine->shutdown = 1; 2469313Sigor@sysoev.ru 2470313Sigor@sysoev.ru if (nxt_queue_is_empty(&engine->joints)) { 2471313Sigor@sysoev.ru nxt_thread_exit(task->thread); 2472313Sigor@sysoev.ru } 2473313Sigor@sysoev.ru } 2474313Sigor@sysoev.ru 2475313Sigor@sysoev.ru 2476313Sigor@sysoev.ru static void 247753Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data) 247853Sigor@sysoev.ru { 247953Sigor@sysoev.ru nxt_timer_t *timer; 2480359Sigor@sysoev.ru nxt_listen_event_t *lev; 248153Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 248253Sigor@sysoev.ru 248353Sigor@sysoev.ru timer = obj; 2484359Sigor@sysoev.ru lev = nxt_timer_data(timer, nxt_listen_event_t, timer); 2485359Sigor@sysoev.ru joint = lev->socket.data; 248653Sigor@sysoev.ru 2487163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine, 2488359Sigor@sysoev.ru lev->socket.fd); 2489359Sigor@sysoev.ru 2490359Sigor@sysoev.ru nxt_queue_remove(&lev->link); 2491359Sigor@sysoev.ru 2492359Sigor@sysoev.ru /* 'task' refers to lev->task and we cannot use after nxt_free() */ 2493123Smax.romanov@nginx.com task = &task->thread->engine->task; 2494123Smax.romanov@nginx.com 2495359Sigor@sysoev.ru nxt_router_listen_socket_release(task, joint->socket_conf); 2496359Sigor@sysoev.ru 2497359Sigor@sysoev.ru nxt_free(lev); 2498359Sigor@sysoev.ru 2499359Sigor@sysoev.ru nxt_router_conf_release(task, joint); 250053Sigor@sysoev.ru } 250153Sigor@sysoev.ru 250253Sigor@sysoev.ru 250353Sigor@sysoev.ru static void 2504359Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf) 250553Sigor@sysoev.ru { 2506359Sigor@sysoev.ru nxt_listen_socket_t *ls; 250753Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 250853Sigor@sysoev.ru 2509359Sigor@sysoev.ru ls = skcf->listen; 2510118Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 251153Sigor@sysoev.ru 251253Sigor@sysoev.ru nxt_thread_spin_lock(lock); 251353Sigor@sysoev.ru 2514359Sigor@sysoev.ru nxt_debug(task, "engine %p: listen socket release: ls->count %D", 2515359Sigor@sysoev.ru task->thread->engine, ls->count); 2516359Sigor@sysoev.ru 2517359Sigor@sysoev.ru if (--ls->count != 0) { 2518359Sigor@sysoev.ru ls = NULL; 251953Sigor@sysoev.ru } 252053Sigor@sysoev.ru 252153Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 252253Sigor@sysoev.ru 2523359Sigor@sysoev.ru if (ls != NULL) { 2524359Sigor@sysoev.ru nxt_socket_close(task, ls->socket); 2525359Sigor@sysoev.ru nxt_free(ls); 252653Sigor@sysoev.ru } 252753Sigor@sysoev.ru } 252853Sigor@sysoev.ru 252953Sigor@sysoev.ru 253053Sigor@sysoev.ru static void 253153Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint) 253253Sigor@sysoev.ru { 2533567Smax.romanov@nginx.com nxt_app_t *app; 253453Sigor@sysoev.ru nxt_socket_conf_t *skcf; 253553Sigor@sysoev.ru nxt_router_conf_t *rtcf; 2536313Sigor@sysoev.ru nxt_event_engine_t *engine; 253753Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 253853Sigor@sysoev.ru 2539163Smax.romanov@nginx.com nxt_debug(task, "conf joint %p count: %D", joint, joint->count); 254053Sigor@sysoev.ru 254153Sigor@sysoev.ru if (--joint->count != 0) { 254253Sigor@sysoev.ru return; 254353Sigor@sysoev.ru } 254453Sigor@sysoev.ru 254553Sigor@sysoev.ru nxt_queue_remove(&joint->link); 254653Sigor@sysoev.ru 2547530Sigor@sysoev.ru /* 2548530Sigor@sysoev.ru * The joint content can not be safely used after the critical 2549530Sigor@sysoev.ru * section protected by the spinlock because its memory pool may 2550530Sigor@sysoev.ru * be already destroyed by another thread. 2551530Sigor@sysoev.ru */ 2552530Sigor@sysoev.ru engine = joint->engine; 2553530Sigor@sysoev.ru 255453Sigor@sysoev.ru skcf = joint->socket_conf; 2555567Smax.romanov@nginx.com app = skcf->application; 255653Sigor@sysoev.ru rtcf = skcf->router_conf; 255753Sigor@sysoev.ru lock = &rtcf->router->lock; 255853Sigor@sysoev.ru 255953Sigor@sysoev.ru nxt_thread_spin_lock(lock); 256053Sigor@sysoev.ru 2561163Smax.romanov@nginx.com nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count, 2562163Smax.romanov@nginx.com rtcf, rtcf->count); 2563163Smax.romanov@nginx.com 256453Sigor@sysoev.ru if (--skcf->count != 0) { 256553Sigor@sysoev.ru rtcf = NULL; 2566567Smax.romanov@nginx.com app = NULL; 256753Sigor@sysoev.ru 256853Sigor@sysoev.ru } else { 256953Sigor@sysoev.ru nxt_queue_remove(&skcf->link); 257053Sigor@sysoev.ru 257153Sigor@sysoev.ru if (--rtcf->count != 0) { 257253Sigor@sysoev.ru rtcf = NULL; 257353Sigor@sysoev.ru } 257453Sigor@sysoev.ru } 257553Sigor@sysoev.ru 257653Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 257753Sigor@sysoev.ru 2578567Smax.romanov@nginx.com if (app != NULL) { 2579567Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 2580567Smax.romanov@nginx.com } 2581567Smax.romanov@nginx.com 2582141Smax.romanov@nginx.com /* TODO remove engine->port */ 2583141Smax.romanov@nginx.com /* TODO excude from connected ports */ 2584141Smax.romanov@nginx.com 258553Sigor@sysoev.ru if (rtcf != NULL) { 2586115Sigor@sysoev.ru nxt_debug(task, "old router conf is destroyed"); 2587131Smax.romanov@nginx.com 2588131Smax.romanov@nginx.com nxt_mp_thread_adopt(rtcf->mem_pool); 2589131Smax.romanov@nginx.com 259065Sigor@sysoev.ru nxt_mp_destroy(rtcf->mem_pool); 259153Sigor@sysoev.ru } 259253Sigor@sysoev.ru 2593530Sigor@sysoev.ru if (engine->shutdown && nxt_queue_is_empty(&engine->joints)) { 259453Sigor@sysoev.ru nxt_thread_exit(task->thread); 259553Sigor@sysoev.ru } 259653Sigor@sysoev.ru } 259753Sigor@sysoev.ru 259853Sigor@sysoev.ru 259953Sigor@sysoev.ru static void 260053Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data) 260153Sigor@sysoev.ru { 2602141Smax.romanov@nginx.com nxt_port_t *port; 260353Sigor@sysoev.ru nxt_thread_link_t *link; 260453Sigor@sysoev.ru nxt_event_engine_t *engine; 260553Sigor@sysoev.ru nxt_thread_handle_t handle; 260653Sigor@sysoev.ru 260758Svbart@nginx.com handle = (nxt_thread_handle_t) obj; 260853Sigor@sysoev.ru link = data; 260953Sigor@sysoev.ru 261053Sigor@sysoev.ru nxt_thread_wait(handle); 261153Sigor@sysoev.ru 261253Sigor@sysoev.ru engine = link->engine; 261353Sigor@sysoev.ru 261453Sigor@sysoev.ru nxt_queue_remove(&engine->link); 261553Sigor@sysoev.ru 2616141Smax.romanov@nginx.com port = engine->port; 2617141Smax.romanov@nginx.com 2618141Smax.romanov@nginx.com // TODO notify all apps 2619141Smax.romanov@nginx.com 2620343Smax.romanov@nginx.com port->engine = task->thread->engine; 2621163Smax.romanov@nginx.com nxt_mp_thread_adopt(port->mem_pool); 2622343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 2623163Smax.romanov@nginx.com 2624163Smax.romanov@nginx.com nxt_mp_thread_adopt(engine->mem_pool); 262563Sigor@sysoev.ru nxt_mp_destroy(engine->mem_pool); 262653Sigor@sysoev.ru 262753Sigor@sysoev.ru nxt_event_engine_free(engine); 262853Sigor@sysoev.ru 262953Sigor@sysoev.ru nxt_free(link); 263053Sigor@sysoev.ru } 263153Sigor@sysoev.ru 263253Sigor@sysoev.ru 263353Sigor@sysoev.ru static void 2634318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2635318Smax.romanov@nginx.com void *data) 263688Smax.romanov@nginx.com { 263788Smax.romanov@nginx.com size_t dump_size; 2638431Sigor@sysoev.ru nxt_int_t ret; 2639194Smax.romanov@nginx.com nxt_buf_t *b, *last; 2640431Sigor@sysoev.ru nxt_http_request_t *r; 264188Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 2642431Sigor@sysoev.ru nxt_app_parse_ctx_t *ar; 264388Smax.romanov@nginx.com 264488Smax.romanov@nginx.com b = msg->buf; 2645318Smax.romanov@nginx.com rc = data; 264688Smax.romanov@nginx.com 264788Smax.romanov@nginx.com dump_size = nxt_buf_used_size(b); 264888Smax.romanov@nginx.com 264988Smax.romanov@nginx.com if (dump_size > 300) { 265088Smax.romanov@nginx.com dump_size = 300; 265188Smax.romanov@nginx.com } 265288Smax.romanov@nginx.com 2653494Spluknet@nginx.com nxt_debug(task, "%srouter app data (%uz): %*s", 265488Smax.romanov@nginx.com msg->port_msg.last ? "last " : "", msg->size, dump_size, 265588Smax.romanov@nginx.com b->mem.pos); 265688Smax.romanov@nginx.com 265788Smax.romanov@nginx.com if (msg->size == 0) { 265888Smax.romanov@nginx.com b = NULL; 265988Smax.romanov@nginx.com } 266088Smax.romanov@nginx.com 2661431Sigor@sysoev.ru ar = rc->ap; 2662570Smax.romanov@nginx.com if (nxt_slow_path(ar == NULL)) { 2663570Smax.romanov@nginx.com return; 2664570Smax.romanov@nginx.com } 2665425Smax.romanov@nginx.com 266688Smax.romanov@nginx.com if (msg->port_msg.last != 0) { 266788Smax.romanov@nginx.com nxt_debug(task, "router data create last buf"); 266888Smax.romanov@nginx.com 2669431Sigor@sysoev.ru last = nxt_http_request_last_buffer(task, ar->request); 267088Smax.romanov@nginx.com if (nxt_slow_path(last == NULL)) { 2671431Sigor@sysoev.ru nxt_app_http_req_done(task, ar); 2672431Sigor@sysoev.ru nxt_router_rc_unlink(task, rc); 2673431Sigor@sysoev.ru return; 267488Smax.romanov@nginx.com } 267588Smax.romanov@nginx.com 267688Smax.romanov@nginx.com nxt_buf_chain_add(&b, last); 2677167Smax.romanov@nginx.com 2678343Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 2679425Smax.romanov@nginx.com 2680425Smax.romanov@nginx.com } else { 2681425Smax.romanov@nginx.com if (rc->app->timeout != 0) { 2682431Sigor@sysoev.ru ar->timer.handler = nxt_router_app_timeout; 2683431Sigor@sysoev.ru nxt_timer_add(task->thread->engine, &ar->timer, rc->app->timeout); 2684425Smax.romanov@nginx.com } 268588Smax.romanov@nginx.com } 268688Smax.romanov@nginx.com 268788Smax.romanov@nginx.com if (b == NULL) { 268888Smax.romanov@nginx.com return; 268988Smax.romanov@nginx.com } 269088Smax.romanov@nginx.com 2691206Smax.romanov@nginx.com if (msg->buf == b) { 2692206Smax.romanov@nginx.com /* Disable instant buffer completion/re-using by port. */ 2693206Smax.romanov@nginx.com msg->buf = NULL; 2694206Smax.romanov@nginx.com } 2695194Smax.romanov@nginx.com 2696431Sigor@sysoev.ru r = ar->request; 2697431Sigor@sysoev.ru 2698431Sigor@sysoev.ru if (r->header_sent) { 2699431Sigor@sysoev.ru nxt_buf_chain_add(&r->out, b); 2700431Sigor@sysoev.ru nxt_http_request_send_body(task, r, NULL); 2701277Sigor@sysoev.ru 270288Smax.romanov@nginx.com } else { 2703431Sigor@sysoev.ru ret = nxt_http_parse_fields(&ar->resp_parser, &b->mem); 2704431Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_DONE)) { 2705431Sigor@sysoev.ru goto fail; 2706431Sigor@sysoev.ru } 2707431Sigor@sysoev.ru 2708431Sigor@sysoev.ru r->resp.fields = ar->resp_parser.fields; 2709431Sigor@sysoev.ru 2710431Sigor@sysoev.ru ret = nxt_http_fields_process(r->resp.fields, 2711431Sigor@sysoev.ru &nxt_response_fields_hash, r); 2712431Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2713431Sigor@sysoev.ru goto fail; 2714431Sigor@sysoev.ru } 2715431Sigor@sysoev.ru 2716435Sigor@sysoev.ru if (nxt_buf_mem_used_size(&b->mem) == 0) { 2717435Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 2718435Sigor@sysoev.ru b->completion_handler, task, b, b->parent); 2719507Smax.romanov@nginx.com 2720520Smax.romanov@nginx.com b = b->next; 2721520Smax.romanov@nginx.com } 2722520Smax.romanov@nginx.com 2723520Smax.romanov@nginx.com if (b != NULL) { 2724431Sigor@sysoev.ru nxt_buf_chain_add(&r->out, b); 2725431Sigor@sysoev.ru } 2726431Sigor@sysoev.ru 2727431Sigor@sysoev.ru r->state = &nxt_http_request_send_state; 2728431Sigor@sysoev.ru 2729431Sigor@sysoev.ru nxt_http_request_header_send(task, r); 2730431Sigor@sysoev.ru } 2731431Sigor@sysoev.ru 2732431Sigor@sysoev.ru return; 2733431Sigor@sysoev.ru 2734431Sigor@sysoev.ru fail: 2735431Sigor@sysoev.ru 2736431Sigor@sysoev.ru nxt_app_http_req_done(task, ar); 2737431Sigor@sysoev.ru nxt_router_rc_unlink(task, rc); 2738431Sigor@sysoev.ru 2739431Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE); 2740431Sigor@sysoev.ru } 2741431Sigor@sysoev.ru 2742431Sigor@sysoev.ru 2743431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_send_state 2744431Sigor@sysoev.ru nxt_aligned(64) = 2745431Sigor@sysoev.ru { 2746431Sigor@sysoev.ru .ready_handler = nxt_http_request_send_body, 2747431Sigor@sysoev.ru .error_handler = nxt_http_request_close_handler, 2748431Sigor@sysoev.ru }; 2749431Sigor@sysoev.ru 2750431Sigor@sysoev.ru 2751431Sigor@sysoev.ru static void 2752431Sigor@sysoev.ru nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data) 2753431Sigor@sysoev.ru { 2754431Sigor@sysoev.ru nxt_buf_t *out; 2755431Sigor@sysoev.ru nxt_http_request_t *r; 2756431Sigor@sysoev.ru 2757431Sigor@sysoev.ru r = obj; 2758431Sigor@sysoev.ru 2759431Sigor@sysoev.ru out = r->out; 2760431Sigor@sysoev.ru 2761431Sigor@sysoev.ru if (out != NULL) { 2762431Sigor@sysoev.ru r->out = NULL; 2763431Sigor@sysoev.ru nxt_http_request_send(task, r, out); 276488Smax.romanov@nginx.com } 276588Smax.romanov@nginx.com } 276688Smax.romanov@nginx.com 2767277Sigor@sysoev.ru 2768318Smax.romanov@nginx.com static void 2769318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2770318Smax.romanov@nginx.com void *data) 2771318Smax.romanov@nginx.com { 2772425Smax.romanov@nginx.com nxt_int_t res; 2773425Smax.romanov@nginx.com nxt_port_t *port; 2774425Smax.romanov@nginx.com nxt_bool_t cancelled; 2775425Smax.romanov@nginx.com nxt_req_app_link_t *ra; 2776318Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 2777318Smax.romanov@nginx.com 2778318Smax.romanov@nginx.com rc = data; 2779318Smax.romanov@nginx.com 2780425Smax.romanov@nginx.com ra = rc->ra; 2781425Smax.romanov@nginx.com 2782425Smax.romanov@nginx.com if (ra != NULL) { 2783425Smax.romanov@nginx.com cancelled = nxt_router_msg_cancel(task, &ra->msg_info, ra->stream); 2784425Smax.romanov@nginx.com 2785425Smax.romanov@nginx.com if (cancelled) { 2786425Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 2787425Smax.romanov@nginx.com 2788427Smax.romanov@nginx.com res = nxt_router_app_port(task, rc->app, ra); 2789425Smax.romanov@nginx.com 2790425Smax.romanov@nginx.com if (res == NXT_OK) { 2791425Smax.romanov@nginx.com port = ra->app_port; 2792425Smax.romanov@nginx.com 2793551Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 2794551Smax.romanov@nginx.com nxt_log(task, NXT_LOG_ERR, "port is NULL in cancelled ra"); 2795551Smax.romanov@nginx.com return; 2796551Smax.romanov@nginx.com } 2797425Smax.romanov@nginx.com 2798425Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, task->thread->engine->port, rc, 2799425Smax.romanov@nginx.com port->pid); 2800425Smax.romanov@nginx.com 2801425Smax.romanov@nginx.com nxt_router_app_prepare_request(task, ra); 2802425Smax.romanov@nginx.com } 2803425Smax.romanov@nginx.com 2804425Smax.romanov@nginx.com msg->port_msg.last = 0; 2805425Smax.romanov@nginx.com 2806425Smax.romanov@nginx.com return; 2807425Smax.romanov@nginx.com } 2808425Smax.romanov@nginx.com } 2809425Smax.romanov@nginx.com 2810431Sigor@sysoev.ru nxt_http_request_error(task, rc->ap->request, NXT_HTTP_SERVICE_UNAVAILABLE); 2811318Smax.romanov@nginx.com 2812343Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 2813318Smax.romanov@nginx.com } 2814318Smax.romanov@nginx.com 2815318Smax.romanov@nginx.com 2816141Smax.romanov@nginx.com static void 2817343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2818343Smax.romanov@nginx.com void *data) 2819192Smax.romanov@nginx.com { 2820343Smax.romanov@nginx.com nxt_app_t *app; 2821343Smax.romanov@nginx.com nxt_port_t *port; 2822343Smax.romanov@nginx.com 2823343Smax.romanov@nginx.com app = data; 2824347Smax.romanov@nginx.com port = msg->u.new_port; 2825343Smax.romanov@nginx.com 2826343Smax.romanov@nginx.com nxt_assert(app != NULL); 2827343Smax.romanov@nginx.com nxt_assert(port != NULL); 2828343Smax.romanov@nginx.com 2829343Smax.romanov@nginx.com port->app = app; 2830343Smax.romanov@nginx.com 2831343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2832343Smax.romanov@nginx.com 2833507Smax.romanov@nginx.com nxt_assert(app->pending_processes != 0); 2834507Smax.romanov@nginx.com 2835507Smax.romanov@nginx.com app->pending_processes--; 2836507Smax.romanov@nginx.com app->processes++; 2837343Smax.romanov@nginx.com 2838343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2839343Smax.romanov@nginx.com 2840507Smax.romanov@nginx.com nxt_debug(task, "app '%V' new port ready, pid %PI, %d/%d", 2841507Smax.romanov@nginx.com &app->name, port->pid, app->processes, app->pending_processes); 2842343Smax.romanov@nginx.com 2843343Smax.romanov@nginx.com nxt_router_app_port_release(task, port, 0, 0); 2844192Smax.romanov@nginx.com } 2845192Smax.romanov@nginx.com 2846192Smax.romanov@nginx.com 2847192Smax.romanov@nginx.com static void 2848343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2849343Smax.romanov@nginx.com void *data) 2850192Smax.romanov@nginx.com { 2851318Smax.romanov@nginx.com nxt_app_t *app; 2852318Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2853318Smax.romanov@nginx.com nxt_req_app_link_t *ra; 2854343Smax.romanov@nginx.com 2855343Smax.romanov@nginx.com app = data; 2856343Smax.romanov@nginx.com 2857343Smax.romanov@nginx.com nxt_assert(app != NULL); 2858343Smax.romanov@nginx.com 2859343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start error", &app->name, app); 2860343Smax.romanov@nginx.com 2861343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2862343Smax.romanov@nginx.com 2863507Smax.romanov@nginx.com nxt_assert(app->pending_processes != 0); 2864507Smax.romanov@nginx.com 2865507Smax.romanov@nginx.com app->pending_processes--; 2866318Smax.romanov@nginx.com 2867318Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->requests)) { 2868318Smax.romanov@nginx.com lnk = nxt_queue_last(&app->requests); 2869318Smax.romanov@nginx.com nxt_queue_remove(lnk); 2870343Smax.romanov@nginx.com lnk->next = NULL; 2871318Smax.romanov@nginx.com 2872425Smax.romanov@nginx.com ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_requests); 2873318Smax.romanov@nginx.com 2874343Smax.romanov@nginx.com } else { 2875343Smax.romanov@nginx.com ra = NULL; 2876343Smax.romanov@nginx.com } 2877343Smax.romanov@nginx.com 2878343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2879343Smax.romanov@nginx.com 2880343Smax.romanov@nginx.com if (ra != NULL) { 2881318Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p abort next stream #%uD", 2882318Smax.romanov@nginx.com &app->name, app, ra->stream); 2883318Smax.romanov@nginx.com 2884507Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, "Failed to start application process"); 2885425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 2886318Smax.romanov@nginx.com } 2887192Smax.romanov@nginx.com 2888343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 2889192Smax.romanov@nginx.com } 2890192Smax.romanov@nginx.com 2891192Smax.romanov@nginx.com 2892343Smax.romanov@nginx.com void 2893343Smax.romanov@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i) 2894141Smax.romanov@nginx.com { 2895343Smax.romanov@nginx.com int c; 2896343Smax.romanov@nginx.com 2897343Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&app->use_count, i); 2898343Smax.romanov@nginx.com 2899343Smax.romanov@nginx.com if (i < 0 && c == -i) { 2900343Smax.romanov@nginx.com 2901343Smax.romanov@nginx.com nxt_assert(app->live == 0); 2902507Smax.romanov@nginx.com nxt_assert(app->processes == 0); 2903507Smax.romanov@nginx.com nxt_assert(app->idle_processes == 0); 2904507Smax.romanov@nginx.com nxt_assert(app->pending_processes == 0); 2905551Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->requests)); 2906551Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->ports)); 2907551Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->spare_ports)); 2908551Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->idle_ports)); 2909343Smax.romanov@nginx.com 2910163Smax.romanov@nginx.com nxt_thread_mutex_destroy(&app->mutex); 2911163Smax.romanov@nginx.com nxt_free(app); 2912163Smax.romanov@nginx.com } 2913343Smax.romanov@nginx.com } 2914343Smax.romanov@nginx.com 2915343Smax.romanov@nginx.com 2916424Smax.romanov@nginx.com nxt_inline nxt_bool_t 2917424Smax.romanov@nginx.com nxt_router_app_first_port_busy(nxt_app_t *app) 2918424Smax.romanov@nginx.com { 2919424Smax.romanov@nginx.com nxt_port_t *port; 2920424Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2921424Smax.romanov@nginx.com 2922424Smax.romanov@nginx.com lnk = nxt_queue_first(&app->ports); 2923424Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, app_link); 2924424Smax.romanov@nginx.com 2925424Smax.romanov@nginx.com return port->app_pending_responses > 0; 2926424Smax.romanov@nginx.com } 2927424Smax.romanov@nginx.com 2928424Smax.romanov@nginx.com 2929343Smax.romanov@nginx.com nxt_inline nxt_port_t * 2930427Smax.romanov@nginx.com nxt_router_pop_first_port(nxt_app_t *app) 2931343Smax.romanov@nginx.com { 2932343Smax.romanov@nginx.com nxt_port_t *port; 2933343Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2934343Smax.romanov@nginx.com 2935343Smax.romanov@nginx.com lnk = nxt_queue_first(&app->ports); 2936343Smax.romanov@nginx.com nxt_queue_remove(lnk); 2937343Smax.romanov@nginx.com 2938343Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, app_link); 2939343Smax.romanov@nginx.com 2940424Smax.romanov@nginx.com port->app_pending_responses++; 2941424Smax.romanov@nginx.com 2942507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 2943507Smax.romanov@nginx.com app->idle_processes--; 2944507Smax.romanov@nginx.com 2945507Smax.romanov@nginx.com if (port->idle_start == 0) { 2946507Smax.romanov@nginx.com nxt_assert(app->idle_processes < app->spare_processes); 2947507Smax.romanov@nginx.com 2948507Smax.romanov@nginx.com } else { 2949507Smax.romanov@nginx.com nxt_assert(app->idle_processes >= app->spare_processes); 2950507Smax.romanov@nginx.com 2951507Smax.romanov@nginx.com port->idle_start = 0; 2952507Smax.romanov@nginx.com } 2953507Smax.romanov@nginx.com } 2954507Smax.romanov@nginx.com 2955428Smax.romanov@nginx.com if ((app->max_pending_responses == 0 2956428Smax.romanov@nginx.com || port->app_pending_responses < app->max_pending_responses) 2957428Smax.romanov@nginx.com && (app->max_requests == 0 2958428Smax.romanov@nginx.com || port->app_responses + port->app_pending_responses 2959428Smax.romanov@nginx.com < app->max_requests)) 2960277Sigor@sysoev.ru { 2961343Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, lnk); 2962343Smax.romanov@nginx.com 2963425Smax.romanov@nginx.com nxt_port_inc_use(port); 2964425Smax.romanov@nginx.com 2965343Smax.romanov@nginx.com } else { 2966343Smax.romanov@nginx.com lnk->next = NULL; 2967167Smax.romanov@nginx.com } 2968167Smax.romanov@nginx.com 2969343Smax.romanov@nginx.com return port; 2970163Smax.romanov@nginx.com } 2971163Smax.romanov@nginx.com 2972163Smax.romanov@nginx.com 2973507Smax.romanov@nginx.com nxt_inline nxt_port_t * 2974507Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app) 2975141Smax.romanov@nginx.com { 2976343Smax.romanov@nginx.com nxt_port_t *port; 2977141Smax.romanov@nginx.com 2978141Smax.romanov@nginx.com port = NULL; 2979141Smax.romanov@nginx.com 2980141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2981141Smax.romanov@nginx.com 2982343Smax.romanov@nginx.com nxt_queue_each(port, &app->ports, nxt_port_t, app_link) { 2983343Smax.romanov@nginx.com 2984424Smax.romanov@nginx.com if (port->app_pending_responses > 0) { 2985343Smax.romanov@nginx.com port = NULL; 2986343Smax.romanov@nginx.com 2987343Smax.romanov@nginx.com continue; 2988343Smax.romanov@nginx.com } 2989343Smax.romanov@nginx.com 2990507Smax.romanov@nginx.com /* Caller is responsible to decrease port use count. */ 2991507Smax.romanov@nginx.com nxt_queue_chk_remove(&port->app_link); 2992507Smax.romanov@nginx.com 2993507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 2994507Smax.romanov@nginx.com app->idle_processes--; 2995507Smax.romanov@nginx.com } 2996507Smax.romanov@nginx.com 2997507Smax.romanov@nginx.com /* Caller is responsible to decrease app use count. */ 2998507Smax.romanov@nginx.com port->app = NULL; 2999507Smax.romanov@nginx.com app->processes--; 3000343Smax.romanov@nginx.com 3001343Smax.romanov@nginx.com break; 3002343Smax.romanov@nginx.com 3003343Smax.romanov@nginx.com } nxt_queue_loop; 3004141Smax.romanov@nginx.com 3005141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3006141Smax.romanov@nginx.com 3007141Smax.romanov@nginx.com return port; 3008141Smax.romanov@nginx.com } 3009141Smax.romanov@nginx.com 3010141Smax.romanov@nginx.com 3011141Smax.romanov@nginx.com static void 3012507Smax.romanov@nginx.com nxt_router_app_quit(nxt_task_t *task, nxt_app_t *app) 3013507Smax.romanov@nginx.com { 3014507Smax.romanov@nginx.com nxt_port_t *port; 3015507Smax.romanov@nginx.com 3016507Smax.romanov@nginx.com nxt_queue_remove(&app->link); 3017507Smax.romanov@nginx.com 3018507Smax.romanov@nginx.com app->live = 0; 3019507Smax.romanov@nginx.com 3020507Smax.romanov@nginx.com for ( ;; ) { 3021507Smax.romanov@nginx.com port = nxt_router_app_get_port_for_quit(app); 3022507Smax.romanov@nginx.com if (port == NULL) { 3023507Smax.romanov@nginx.com break; 3024507Smax.romanov@nginx.com } 3025507Smax.romanov@nginx.com 3026507Smax.romanov@nginx.com nxt_debug(task, "send QUIT to app '%V' pid %PI", &app->name, port->pid); 3027507Smax.romanov@nginx.com 3028507Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 3029507Smax.romanov@nginx.com 3030507Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3031507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 3032507Smax.romanov@nginx.com } 3033507Smax.romanov@nginx.com 3034507Smax.romanov@nginx.com if (nxt_timer_is_in_tree(&app->idle_timer)) { 3035507Smax.romanov@nginx.com nxt_assert(app->engine == task->thread->engine); 3036507Smax.romanov@nginx.com 3037507Smax.romanov@nginx.com app->idle_timer.handler = nxt_router_app_release_handler; 3038507Smax.romanov@nginx.com nxt_timer_add(app->engine, &app->idle_timer, 0); 3039507Smax.romanov@nginx.com 3040507Smax.romanov@nginx.com } else { 3041507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 3042507Smax.romanov@nginx.com } 3043507Smax.romanov@nginx.com } 3044507Smax.romanov@nginx.com 3045507Smax.romanov@nginx.com 3046507Smax.romanov@nginx.com static void 3047343Smax.romanov@nginx.com nxt_router_app_process_request(nxt_task_t *task, void *obj, void *data) 3048141Smax.romanov@nginx.com { 3049343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 3050343Smax.romanov@nginx.com 3051538Svbart@nginx.com ra = data; 3052538Svbart@nginx.com 3053538Svbart@nginx.com #if (NXT_DEBUG) 3054538Svbart@nginx.com { 3055538Svbart@nginx.com nxt_app_t *app; 3056538Svbart@nginx.com 3057343Smax.romanov@nginx.com app = obj; 3058141Smax.romanov@nginx.com 3059141Smax.romanov@nginx.com nxt_assert(app != NULL); 3060343Smax.romanov@nginx.com nxt_assert(ra != NULL); 3061343Smax.romanov@nginx.com nxt_assert(ra->app_port != NULL); 3062343Smax.romanov@nginx.com 3063343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p process next stream #%uD", 3064343Smax.romanov@nginx.com &app->name, app, ra->stream); 3065538Svbart@nginx.com } 3066538Svbart@nginx.com #endif 3067343Smax.romanov@nginx.com 3068425Smax.romanov@nginx.com nxt_router_app_prepare_request(task, ra); 3069343Smax.romanov@nginx.com } 3070343Smax.romanov@nginx.com 3071343Smax.romanov@nginx.com 3072343Smax.romanov@nginx.com static void 3073343Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port, 3074343Smax.romanov@nginx.com uint32_t request_failed, uint32_t got_response) 3075343Smax.romanov@nginx.com { 3076427Smax.romanov@nginx.com nxt_app_t *app; 3077507Smax.romanov@nginx.com nxt_bool_t port_unchained; 3078507Smax.romanov@nginx.com nxt_bool_t send_quit, cancelled, adjust_idle_timer; 3079427Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3080427Smax.romanov@nginx.com nxt_req_app_link_t *ra, *pending_ra, *re_ra; 3081427Smax.romanov@nginx.com nxt_port_select_state_t state; 3082343Smax.romanov@nginx.com 3083343Smax.romanov@nginx.com nxt_assert(port != NULL); 3084343Smax.romanov@nginx.com nxt_assert(port->app != NULL); 3085343Smax.romanov@nginx.com 3086427Smax.romanov@nginx.com ra = NULL; 3087427Smax.romanov@nginx.com 3088343Smax.romanov@nginx.com app = port->app; 3089343Smax.romanov@nginx.com 3090343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3091343Smax.romanov@nginx.com 3092424Smax.romanov@nginx.com port->app_pending_responses -= request_failed + got_response; 3093343Smax.romanov@nginx.com port->app_responses += got_response; 3094343Smax.romanov@nginx.com 3095427Smax.romanov@nginx.com if (nxt_slow_path(app->live == 0)) { 3096427Smax.romanov@nginx.com goto app_dead; 3097427Smax.romanov@nginx.com } 3098427Smax.romanov@nginx.com 3099427Smax.romanov@nginx.com if (port->pair[1] != -1 3100426Smax.romanov@nginx.com && (app->max_pending_responses == 0 3101428Smax.romanov@nginx.com || port->app_pending_responses < app->max_pending_responses) 3102428Smax.romanov@nginx.com && (app->max_requests == 0 3103428Smax.romanov@nginx.com || port->app_responses + port->app_pending_responses 3104428Smax.romanov@nginx.com < app->max_requests)) 3105343Smax.romanov@nginx.com { 3106424Smax.romanov@nginx.com if (port->app_link.next == NULL) { 3107424Smax.romanov@nginx.com if (port->app_pending_responses > 0) { 3108424Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &port->app_link); 3109424Smax.romanov@nginx.com 3110424Smax.romanov@nginx.com } else { 3111424Smax.romanov@nginx.com nxt_queue_insert_head(&app->ports, &port->app_link); 3112424Smax.romanov@nginx.com } 3113424Smax.romanov@nginx.com 3114425Smax.romanov@nginx.com nxt_port_inc_use(port); 3115424Smax.romanov@nginx.com 3116424Smax.romanov@nginx.com } else { 3117424Smax.romanov@nginx.com if (port->app_pending_responses == 0 3118424Smax.romanov@nginx.com && nxt_queue_first(&app->ports) != &port->app_link) 3119424Smax.romanov@nginx.com { 3120424Smax.romanov@nginx.com nxt_queue_remove(&port->app_link); 3121424Smax.romanov@nginx.com nxt_queue_insert_head(&app->ports, &port->app_link); 3122424Smax.romanov@nginx.com } 3123424Smax.romanov@nginx.com } 3124141Smax.romanov@nginx.com } 3125141Smax.romanov@nginx.com 3126427Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->ports) 3127426Smax.romanov@nginx.com && !nxt_queue_is_empty(&app->requests)) 3128343Smax.romanov@nginx.com { 3129141Smax.romanov@nginx.com lnk = nxt_queue_first(&app->requests); 3130141Smax.romanov@nginx.com nxt_queue_remove(lnk); 3131343Smax.romanov@nginx.com lnk->next = NULL; 3132141Smax.romanov@nginx.com 3133425Smax.romanov@nginx.com ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_requests); 3134425Smax.romanov@nginx.com 3135427Smax.romanov@nginx.com ra->app_port = nxt_router_pop_first_port(app); 3136425Smax.romanov@nginx.com 3137425Smax.romanov@nginx.com if (ra->app_port->app_pending_responses > 1) { 3138427Smax.romanov@nginx.com nxt_router_ra_pending(task, app, ra); 3139425Smax.romanov@nginx.com } 3140425Smax.romanov@nginx.com } 3141425Smax.romanov@nginx.com 3142427Smax.romanov@nginx.com app_dead: 3143427Smax.romanov@nginx.com 3144427Smax.romanov@nginx.com /* Pop first pending request for this port. */ 3145425Smax.romanov@nginx.com if ((request_failed > 0 || got_response > 0) 3146425Smax.romanov@nginx.com && !nxt_queue_is_empty(&port->pending_requests)) 3147425Smax.romanov@nginx.com { 3148425Smax.romanov@nginx.com lnk = nxt_queue_first(&port->pending_requests); 3149425Smax.romanov@nginx.com nxt_queue_remove(lnk); 3150425Smax.romanov@nginx.com lnk->next = NULL; 3151425Smax.romanov@nginx.com 3152427Smax.romanov@nginx.com pending_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, 3153427Smax.romanov@nginx.com link_port_pending); 3154427Smax.romanov@nginx.com 3155427Smax.romanov@nginx.com nxt_assert(pending_ra->link_app_pending.next != NULL); 3156427Smax.romanov@nginx.com 3157427Smax.romanov@nginx.com nxt_queue_remove(&pending_ra->link_app_pending); 3158427Smax.romanov@nginx.com pending_ra->link_app_pending.next = NULL; 3159425Smax.romanov@nginx.com 3160425Smax.romanov@nginx.com } else { 3161427Smax.romanov@nginx.com pending_ra = NULL; 3162141Smax.romanov@nginx.com } 3163141Smax.romanov@nginx.com 3164427Smax.romanov@nginx.com /* Try to cancel and re-schedule first stalled request for this app. */ 3165427Smax.romanov@nginx.com if (got_response > 0 && !nxt_queue_is_empty(&app->pending)) { 3166427Smax.romanov@nginx.com lnk = nxt_queue_first(&app->pending); 3167427Smax.romanov@nginx.com 3168427Smax.romanov@nginx.com re_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_pending); 3169427Smax.romanov@nginx.com 3170427Smax.romanov@nginx.com if (re_ra->res_time <= nxt_thread_monotonic_time(task->thread)) { 3171427Smax.romanov@nginx.com 3172427Smax.romanov@nginx.com nxt_debug(task, "app '%V' stalled request #%uD detected", 3173427Smax.romanov@nginx.com &app->name, re_ra->stream); 3174427Smax.romanov@nginx.com 3175427Smax.romanov@nginx.com cancelled = nxt_router_msg_cancel(task, &re_ra->msg_info, 3176427Smax.romanov@nginx.com re_ra->stream); 3177427Smax.romanov@nginx.com 3178427Smax.romanov@nginx.com if (cancelled) { 3179427Smax.romanov@nginx.com nxt_router_ra_inc_use(re_ra); 3180427Smax.romanov@nginx.com 3181427Smax.romanov@nginx.com state.ra = re_ra; 3182427Smax.romanov@nginx.com state.app = app; 3183427Smax.romanov@nginx.com 3184427Smax.romanov@nginx.com nxt_router_port_select(task, &state); 3185427Smax.romanov@nginx.com 3186427Smax.romanov@nginx.com goto re_ra_cancelled; 3187427Smax.romanov@nginx.com } 3188427Smax.romanov@nginx.com } 3189427Smax.romanov@nginx.com } 3190427Smax.romanov@nginx.com 3191427Smax.romanov@nginx.com re_ra = NULL; 3192427Smax.romanov@nginx.com 3193427Smax.romanov@nginx.com re_ra_cancelled: 3194427Smax.romanov@nginx.com 3195507Smax.romanov@nginx.com send_quit = (app->live == 0 && port->app_pending_responses == 0) 3196428Smax.romanov@nginx.com || (app->max_requests > 0 && port->app_pending_responses == 0 3197428Smax.romanov@nginx.com && port->app_responses >= app->max_requests); 3198367Smax.romanov@nginx.com 3199507Smax.romanov@nginx.com if (send_quit) { 3200507Smax.romanov@nginx.com port_unchained = nxt_queue_chk_remove(&port->app_link); 3201507Smax.romanov@nginx.com 3202507Smax.romanov@nginx.com port->app = NULL; 3203507Smax.romanov@nginx.com app->processes--; 3204507Smax.romanov@nginx.com 3205507Smax.romanov@nginx.com } else { 3206507Smax.romanov@nginx.com port_unchained = 0; 3207507Smax.romanov@nginx.com } 3208507Smax.romanov@nginx.com 3209507Smax.romanov@nginx.com adjust_idle_timer = 0; 3210507Smax.romanov@nginx.com 3211571Smax.romanov@nginx.com if (port->pair[1] != -1 && !send_quit && port->app_pending_responses == 0) { 3212507Smax.romanov@nginx.com nxt_assert(port->idle_link.next == NULL); 3213507Smax.romanov@nginx.com 3214507Smax.romanov@nginx.com if (app->idle_processes == app->spare_processes 3215507Smax.romanov@nginx.com && app->adjust_idle_work.data == NULL) 3216507Smax.romanov@nginx.com { 3217507Smax.romanov@nginx.com adjust_idle_timer = 1; 3218507Smax.romanov@nginx.com app->adjust_idle_work.data = app; 3219507Smax.romanov@nginx.com app->adjust_idle_work.next = NULL; 3220507Smax.romanov@nginx.com } 3221507Smax.romanov@nginx.com 3222507Smax.romanov@nginx.com if (app->idle_processes < app->spare_processes) { 3223507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, &port->idle_link); 3224507Smax.romanov@nginx.com 3225507Smax.romanov@nginx.com } else { 3226507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->idle_ports, &port->idle_link); 3227507Smax.romanov@nginx.com 3228507Smax.romanov@nginx.com port->idle_start = task->thread->engine->timers.now; 3229507Smax.romanov@nginx.com } 3230507Smax.romanov@nginx.com 3231507Smax.romanov@nginx.com app->idle_processes++; 3232507Smax.romanov@nginx.com } 3233507Smax.romanov@nginx.com 3234343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3235343Smax.romanov@nginx.com 3236507Smax.romanov@nginx.com if (adjust_idle_timer) { 3237507Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 3238507Smax.romanov@nginx.com nxt_event_engine_post(app->engine, &app->adjust_idle_work); 3239507Smax.romanov@nginx.com } 3240507Smax.romanov@nginx.com 3241427Smax.romanov@nginx.com if (pending_ra != NULL) { 3242427Smax.romanov@nginx.com nxt_router_ra_use(task, pending_ra, -1); 3243427Smax.romanov@nginx.com } 3244427Smax.romanov@nginx.com 3245427Smax.romanov@nginx.com if (re_ra != NULL) { 3246427Smax.romanov@nginx.com if (nxt_router_port_post_select(task, &state) == NXT_OK) { 3247427Smax.romanov@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 3248427Smax.romanov@nginx.com nxt_router_app_process_request, 3249427Smax.romanov@nginx.com &task->thread->engine->task, app, re_ra); 3250427Smax.romanov@nginx.com } 3251425Smax.romanov@nginx.com } 3252425Smax.romanov@nginx.com 3253343Smax.romanov@nginx.com if (ra != NULL) { 3254425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 3255425Smax.romanov@nginx.com 3256343Smax.romanov@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 3257343Smax.romanov@nginx.com nxt_router_app_process_request, 3258343Smax.romanov@nginx.com &task->thread->engine->task, app, ra); 3259343Smax.romanov@nginx.com 3260343Smax.romanov@nginx.com goto adjust_use; 3261343Smax.romanov@nginx.com } 3262343Smax.romanov@nginx.com 3263343Smax.romanov@nginx.com /* ? */ 3264163Smax.romanov@nginx.com if (port->pair[1] == -1) { 3265343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)", 3266343Smax.romanov@nginx.com &app->name, app, port, port->pid); 3267343Smax.romanov@nginx.com 3268343Smax.romanov@nginx.com goto adjust_use; 3269163Smax.romanov@nginx.com } 3270163Smax.romanov@nginx.com 3271367Smax.romanov@nginx.com if (send_quit) { 3272507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p send QUIT to port", 3273167Smax.romanov@nginx.com &app->name, app); 3274163Smax.romanov@nginx.com 3275163Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, 3276163Smax.romanov@nginx.com -1, 0, 0, NULL); 3277163Smax.romanov@nginx.com 3278507Smax.romanov@nginx.com if (port_unchained) { 3279507Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3280507Smax.romanov@nginx.com } 3281507Smax.romanov@nginx.com 3282507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 3283507Smax.romanov@nginx.com 3284343Smax.romanov@nginx.com goto adjust_use; 3285163Smax.romanov@nginx.com } 3286163Smax.romanov@nginx.com 3287167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p requests queue is empty, keep the port", 3288167Smax.romanov@nginx.com &app->name, app); 3289141Smax.romanov@nginx.com 3290343Smax.romanov@nginx.com adjust_use: 3291343Smax.romanov@nginx.com 3292425Smax.romanov@nginx.com if (request_failed > 0 || got_response > 0) { 3293425Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3294343Smax.romanov@nginx.com } 3295141Smax.romanov@nginx.com } 3296141Smax.romanov@nginx.com 3297141Smax.romanov@nginx.com 3298343Smax.romanov@nginx.com void 3299343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port) 3300141Smax.romanov@nginx.com { 3301507Smax.romanov@nginx.com nxt_app_t *app; 3302507Smax.romanov@nginx.com nxt_bool_t unchain, start_process; 3303507Smax.romanov@nginx.com nxt_port_t *idle_port; 3304507Smax.romanov@nginx.com nxt_queue_link_t *idle_lnk; 3305141Smax.romanov@nginx.com 3306141Smax.romanov@nginx.com app = port->app; 3307343Smax.romanov@nginx.com 3308343Smax.romanov@nginx.com nxt_assert(app != NULL); 3309141Smax.romanov@nginx.com 3310141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3311141Smax.romanov@nginx.com 3312507Smax.romanov@nginx.com unchain = nxt_queue_chk_remove(&port->app_link); 3313507Smax.romanov@nginx.com 3314507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 3315507Smax.romanov@nginx.com app->idle_processes--; 3316507Smax.romanov@nginx.com 3317507Smax.romanov@nginx.com if (port->idle_start == 0 3318507Smax.romanov@nginx.com && app->idle_processes >= app->spare_processes) 3319507Smax.romanov@nginx.com { 3320507Smax.romanov@nginx.com nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); 3321507Smax.romanov@nginx.com 3322507Smax.romanov@nginx.com idle_lnk = nxt_queue_last(&app->idle_ports); 3323507Smax.romanov@nginx.com idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link); 3324507Smax.romanov@nginx.com nxt_queue_remove(idle_lnk); 3325507Smax.romanov@nginx.com 3326507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, idle_lnk); 3327507Smax.romanov@nginx.com 3328507Smax.romanov@nginx.com idle_port->idle_start = 0; 3329507Smax.romanov@nginx.com } 3330343Smax.romanov@nginx.com } 3331343Smax.romanov@nginx.com 3332507Smax.romanov@nginx.com app->processes--; 3333507Smax.romanov@nginx.com 3334507Smax.romanov@nginx.com start_process = app->live != 0 3335507Smax.romanov@nginx.com && !task->thread->engine->shutdown 3336507Smax.romanov@nginx.com && nxt_router_app_can_start(app) 3337507Smax.romanov@nginx.com && (!nxt_queue_is_empty(&app->requests) 3338507Smax.romanov@nginx.com || nxt_router_app_need_start(app)); 3339507Smax.romanov@nginx.com 3340507Smax.romanov@nginx.com if (start_process) { 3341507Smax.romanov@nginx.com app->pending_processes++; 3342163Smax.romanov@nginx.com } 3343141Smax.romanov@nginx.com 3344141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3345163Smax.romanov@nginx.com 3346507Smax.romanov@nginx.com nxt_debug(task, "app '%V' pid %PI closed", &app->name, port->pid); 3347343Smax.romanov@nginx.com 3348343Smax.romanov@nginx.com if (unchain) { 3349343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3350163Smax.romanov@nginx.com } 3351163Smax.romanov@nginx.com 3352507Smax.romanov@nginx.com if (start_process) { 3353507Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 3354507Smax.romanov@nginx.com } 3355507Smax.romanov@nginx.com } 3356507Smax.romanov@nginx.com 3357507Smax.romanov@nginx.com 3358507Smax.romanov@nginx.com static void 3359507Smax.romanov@nginx.com nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, void *data) 3360507Smax.romanov@nginx.com { 3361507Smax.romanov@nginx.com nxt_app_t *app; 3362507Smax.romanov@nginx.com nxt_bool_t queued; 3363507Smax.romanov@nginx.com nxt_port_t *port; 3364507Smax.romanov@nginx.com nxt_msec_t timeout, threshold; 3365507Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3366507Smax.romanov@nginx.com nxt_event_engine_t *engine; 3367507Smax.romanov@nginx.com 3368507Smax.romanov@nginx.com app = obj; 3369507Smax.romanov@nginx.com queued = (data == app); 3370507Smax.romanov@nginx.com 3371507Smax.romanov@nginx.com nxt_debug(task, "nxt_router_adjust_idle_timer: app \"%V\", queued %b", 3372507Smax.romanov@nginx.com &app->name, queued); 3373507Smax.romanov@nginx.com 3374507Smax.romanov@nginx.com engine = task->thread->engine; 3375507Smax.romanov@nginx.com 3376507Smax.romanov@nginx.com nxt_assert(app->engine == engine); 3377507Smax.romanov@nginx.com 3378507Smax.romanov@nginx.com threshold = engine->timers.now + app->idle_timer.precision; 3379507Smax.romanov@nginx.com timeout = 0; 3380507Smax.romanov@nginx.com 3381507Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3382507Smax.romanov@nginx.com 3383507Smax.romanov@nginx.com if (queued) { 3384507Smax.romanov@nginx.com app->adjust_idle_work.data = NULL; 3385343Smax.romanov@nginx.com } 3386507Smax.romanov@nginx.com 3387507Smax.romanov@nginx.com while (app->idle_processes > app->spare_processes) { 3388507Smax.romanov@nginx.com 3389551Smax.romanov@nginx.com nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); 3390507Smax.romanov@nginx.com 3391507Smax.romanov@nginx.com lnk = nxt_queue_first(&app->idle_ports); 3392507Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, idle_link); 3393507Smax.romanov@nginx.com 3394507Smax.romanov@nginx.com timeout = port->idle_start + app->idle_timeout; 3395507Smax.romanov@nginx.com 3396507Smax.romanov@nginx.com if (timeout > threshold) { 3397507Smax.romanov@nginx.com break; 3398507Smax.romanov@nginx.com } 3399507Smax.romanov@nginx.com 3400507Smax.romanov@nginx.com nxt_queue_remove(lnk); 3401507Smax.romanov@nginx.com lnk->next = NULL; 3402507Smax.romanov@nginx.com 3403507Smax.romanov@nginx.com nxt_queue_chk_remove(&port->app_link); 3404507Smax.romanov@nginx.com 3405507Smax.romanov@nginx.com app->idle_processes--; 3406507Smax.romanov@nginx.com app->processes--; 3407507Smax.romanov@nginx.com port->app = NULL; 3408507Smax.romanov@nginx.com 3409507Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3410507Smax.romanov@nginx.com 3411507Smax.romanov@nginx.com nxt_debug(task, "app '%V' send QUIT to idle port %PI", 3412507Smax.romanov@nginx.com &app->name, port->pid); 3413507Smax.romanov@nginx.com 3414507Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 3415507Smax.romanov@nginx.com 3416507Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3417507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 3418507Smax.romanov@nginx.com 3419507Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3420507Smax.romanov@nginx.com } 3421507Smax.romanov@nginx.com 3422507Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3423507Smax.romanov@nginx.com 3424507Smax.romanov@nginx.com if (timeout > threshold) { 3425507Smax.romanov@nginx.com nxt_timer_add(engine, &app->idle_timer, timeout - threshold); 3426507Smax.romanov@nginx.com 3427507Smax.romanov@nginx.com } else { 3428507Smax.romanov@nginx.com nxt_timer_disable(engine, &app->idle_timer); 3429507Smax.romanov@nginx.com } 3430507Smax.romanov@nginx.com 3431507Smax.romanov@nginx.com if (queued) { 3432507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 3433507Smax.romanov@nginx.com } 3434507Smax.romanov@nginx.com } 3435507Smax.romanov@nginx.com 3436507Smax.romanov@nginx.com 3437507Smax.romanov@nginx.com static void 3438507Smax.romanov@nginx.com nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, void *data) 3439507Smax.romanov@nginx.com { 3440507Smax.romanov@nginx.com nxt_app_t *app; 3441507Smax.romanov@nginx.com nxt_timer_t *timer; 3442507Smax.romanov@nginx.com 3443507Smax.romanov@nginx.com timer = obj; 3444507Smax.romanov@nginx.com app = nxt_container_of(timer, nxt_app_t, idle_timer); 3445507Smax.romanov@nginx.com 3446507Smax.romanov@nginx.com nxt_router_adjust_idle_timer(task, app, NULL); 3447507Smax.romanov@nginx.com } 3448507Smax.romanov@nginx.com 3449507Smax.romanov@nginx.com 3450507Smax.romanov@nginx.com static void 3451507Smax.romanov@nginx.com nxt_router_app_release_handler(nxt_task_t *task, void *obj, void *data) 3452507Smax.romanov@nginx.com { 3453507Smax.romanov@nginx.com nxt_app_t *app; 3454507Smax.romanov@nginx.com nxt_timer_t *timer; 3455507Smax.romanov@nginx.com 3456507Smax.romanov@nginx.com timer = obj; 3457507Smax.romanov@nginx.com app = nxt_container_of(timer, nxt_app_t, idle_timer); 3458507Smax.romanov@nginx.com 3459507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 3460141Smax.romanov@nginx.com } 3461141Smax.romanov@nginx.com 3462141Smax.romanov@nginx.com 3463427Smax.romanov@nginx.com static void 3464427Smax.romanov@nginx.com nxt_router_port_select(nxt_task_t *task, nxt_port_select_state_t *state) 3465141Smax.romanov@nginx.com { 3466427Smax.romanov@nginx.com nxt_app_t *app; 3467507Smax.romanov@nginx.com nxt_bool_t can_start_process; 3468427Smax.romanov@nginx.com nxt_req_app_link_t *ra; 3469427Smax.romanov@nginx.com 3470427Smax.romanov@nginx.com ra = state->ra; 3471427Smax.romanov@nginx.com app = state->app; 3472427Smax.romanov@nginx.com 3473427Smax.romanov@nginx.com state->failed_port_use_delta = 0; 3474343Smax.romanov@nginx.com 3475425Smax.romanov@nginx.com if (nxt_queue_chk_remove(&ra->link_app_requests)) 3476425Smax.romanov@nginx.com { 3477425Smax.romanov@nginx.com nxt_router_ra_dec_use(ra); 3478425Smax.romanov@nginx.com } 3479425Smax.romanov@nginx.com 3480425Smax.romanov@nginx.com if (nxt_queue_chk_remove(&ra->link_port_pending)) 3481425Smax.romanov@nginx.com { 3482427Smax.romanov@nginx.com nxt_assert(ra->link_app_pending.next != NULL); 3483427Smax.romanov@nginx.com 3484427Smax.romanov@nginx.com nxt_queue_remove(&ra->link_app_pending); 3485427Smax.romanov@nginx.com ra->link_app_pending.next = NULL; 3486427Smax.romanov@nginx.com 3487425Smax.romanov@nginx.com nxt_router_ra_dec_use(ra); 3488425Smax.romanov@nginx.com } 3489425Smax.romanov@nginx.com 3490427Smax.romanov@nginx.com state->failed_port = ra->app_port; 3491427Smax.romanov@nginx.com 3492425Smax.romanov@nginx.com if (ra->app_port != NULL) { 3493427Smax.romanov@nginx.com state->failed_port_use_delta--; 3494427Smax.romanov@nginx.com 3495427Smax.romanov@nginx.com state->failed_port->app_pending_responses--; 3496427Smax.romanov@nginx.com 3497427Smax.romanov@nginx.com if (nxt_queue_chk_remove(&state->failed_port->app_link)) { 3498427Smax.romanov@nginx.com state->failed_port_use_delta--; 3499427Smax.romanov@nginx.com } 3500427Smax.romanov@nginx.com 3501427Smax.romanov@nginx.com ra->app_port = NULL; 3502427Smax.romanov@nginx.com } 3503427Smax.romanov@nginx.com 3504507Smax.romanov@nginx.com can_start_process = nxt_router_app_can_start(app); 3505507Smax.romanov@nginx.com 3506427Smax.romanov@nginx.com state->port = NULL; 3507507Smax.romanov@nginx.com state->start_process = 0; 3508427Smax.romanov@nginx.com 3509427Smax.romanov@nginx.com if (nxt_queue_is_empty(&app->ports) 3510507Smax.romanov@nginx.com || (can_start_process && nxt_router_app_first_port_busy(app)) ) 3511427Smax.romanov@nginx.com { 3512427Smax.romanov@nginx.com ra = nxt_router_ra_create(task, ra); 3513427Smax.romanov@nginx.com 3514427Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 3515427Smax.romanov@nginx.com goto fail; 3516427Smax.romanov@nginx.com } 3517427Smax.romanov@nginx.com 3518427Smax.romanov@nginx.com if (nxt_slow_path(state->failed_port != NULL)) { 3519427Smax.romanov@nginx.com nxt_queue_insert_head(&app->requests, &ra->link_app_requests); 3520427Smax.romanov@nginx.com 3521427Smax.romanov@nginx.com } else { 3522427Smax.romanov@nginx.com nxt_queue_insert_tail(&app->requests, &ra->link_app_requests); 3523427Smax.romanov@nginx.com } 3524427Smax.romanov@nginx.com 3525427Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 3526427Smax.romanov@nginx.com 3527427Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD enqueue to app->requests", ra->stream); 3528427Smax.romanov@nginx.com 3529507Smax.romanov@nginx.com if (can_start_process) { 3530507Smax.romanov@nginx.com app->pending_processes++; 3531507Smax.romanov@nginx.com state->start_process = 1; 3532425Smax.romanov@nginx.com } 3533425Smax.romanov@nginx.com 3534425Smax.romanov@nginx.com } else { 3535427Smax.romanov@nginx.com state->port = nxt_router_pop_first_port(app); 3536427Smax.romanov@nginx.com 3537427Smax.romanov@nginx.com if (state->port->app_pending_responses > 1) { 3538427Smax.romanov@nginx.com ra = nxt_router_ra_create(task, ra); 3539427Smax.romanov@nginx.com 3540427Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 3541427Smax.romanov@nginx.com goto fail; 3542351Smax.romanov@nginx.com } 3543427Smax.romanov@nginx.com 3544427Smax.romanov@nginx.com ra->app_port = state->port; 3545427Smax.romanov@nginx.com 3546427Smax.romanov@nginx.com nxt_router_ra_pending(task, app, ra); 3547425Smax.romanov@nginx.com } 3548507Smax.romanov@nginx.com 3549507Smax.romanov@nginx.com if (can_start_process && nxt_router_app_need_start(app)) { 3550507Smax.romanov@nginx.com app->pending_processes++; 3551507Smax.romanov@nginx.com state->start_process = 1; 3552507Smax.romanov@nginx.com } 3553343Smax.romanov@nginx.com } 3554343Smax.romanov@nginx.com 3555427Smax.romanov@nginx.com fail: 3556427Smax.romanov@nginx.com 3557427Smax.romanov@nginx.com state->shared_ra = ra; 3558427Smax.romanov@nginx.com } 3559427Smax.romanov@nginx.com 3560427Smax.romanov@nginx.com 3561427Smax.romanov@nginx.com static nxt_int_t 3562427Smax.romanov@nginx.com nxt_router_port_post_select(nxt_task_t *task, nxt_port_select_state_t *state) 3563427Smax.romanov@nginx.com { 3564427Smax.romanov@nginx.com nxt_int_t res; 3565427Smax.romanov@nginx.com nxt_app_t *app; 3566427Smax.romanov@nginx.com nxt_req_app_link_t *ra; 3567427Smax.romanov@nginx.com 3568427Smax.romanov@nginx.com ra = state->shared_ra; 3569427Smax.romanov@nginx.com app = state->app; 3570427Smax.romanov@nginx.com 3571427Smax.romanov@nginx.com if (state->failed_port_use_delta != 0) { 3572427Smax.romanov@nginx.com nxt_port_use(task, state->failed_port, state->failed_port_use_delta); 3573425Smax.romanov@nginx.com } 3574425Smax.romanov@nginx.com 3575351Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 3576427Smax.romanov@nginx.com if (state->port != NULL) { 3577427Smax.romanov@nginx.com nxt_port_use(task, state->port, -1); 3578425Smax.romanov@nginx.com } 3579425Smax.romanov@nginx.com 3580427Smax.romanov@nginx.com nxt_router_ra_error(state->ra, 500, 3581427Smax.romanov@nginx.com "Failed to allocate shared req<->app link"); 3582427Smax.romanov@nginx.com nxt_router_ra_use(task, state->ra, -1); 3583427Smax.romanov@nginx.com 3584351Smax.romanov@nginx.com return NXT_ERROR; 3585351Smax.romanov@nginx.com } 3586351Smax.romanov@nginx.com 3587427Smax.romanov@nginx.com if (state->port != NULL) { 3588343Smax.romanov@nginx.com nxt_debug(task, "already have port for app '%V' %p ", &app->name, app); 3589163Smax.romanov@nginx.com 3590427Smax.romanov@nginx.com ra->app_port = state->port; 3591343Smax.romanov@nginx.com 3592507Smax.romanov@nginx.com if (state->start_process) { 3593507Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 3594507Smax.romanov@nginx.com } 3595507Smax.romanov@nginx.com 3596141Smax.romanov@nginx.com return NXT_OK; 3597141Smax.romanov@nginx.com } 3598141Smax.romanov@nginx.com 3599507Smax.romanov@nginx.com if (!state->start_process) { 3600507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p too many running or pending processes", 3601343Smax.romanov@nginx.com &app->name, app); 3602343Smax.romanov@nginx.com 3603343Smax.romanov@nginx.com return NXT_AGAIN; 3604343Smax.romanov@nginx.com } 3605343Smax.romanov@nginx.com 3606507Smax.romanov@nginx.com res = nxt_router_start_app_process(task, app); 3607343Smax.romanov@nginx.com 3608343Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3609507Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, "Failed to start app process"); 3610427Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 3611343Smax.romanov@nginx.com 3612141Smax.romanov@nginx.com return NXT_ERROR; 3613141Smax.romanov@nginx.com } 3614141Smax.romanov@nginx.com 3615141Smax.romanov@nginx.com return NXT_AGAIN; 361688Smax.romanov@nginx.com } 361788Smax.romanov@nginx.com 361888Smax.romanov@nginx.com 3619427Smax.romanov@nginx.com static nxt_int_t 3620427Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra) 3621427Smax.romanov@nginx.com { 3622427Smax.romanov@nginx.com nxt_port_select_state_t state; 3623427Smax.romanov@nginx.com 3624427Smax.romanov@nginx.com state.ra = ra; 3625427Smax.romanov@nginx.com state.app = app; 3626427Smax.romanov@nginx.com 3627427Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3628427Smax.romanov@nginx.com 3629427Smax.romanov@nginx.com nxt_router_port_select(task, &state); 3630427Smax.romanov@nginx.com 3631427Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3632427Smax.romanov@nginx.com 3633427Smax.romanov@nginx.com return nxt_router_port_post_select(task, &state); 3634427Smax.romanov@nginx.com } 3635427Smax.romanov@nginx.com 3636427Smax.romanov@nginx.com 3637431Sigor@sysoev.ru void 3638431Sigor@sysoev.ru nxt_router_process_http_request(nxt_task_t *task, nxt_app_parse_ctx_t *ar) 363953Sigor@sysoev.ru { 3640431Sigor@sysoev.ru nxt_int_t res; 3641431Sigor@sysoev.ru nxt_app_t *app; 3642431Sigor@sysoev.ru nxt_port_t *port; 3643431Sigor@sysoev.ru nxt_event_engine_t *engine; 3644431Sigor@sysoev.ru nxt_http_request_t *r; 3645431Sigor@sysoev.ru nxt_req_app_link_t ra_local, *ra; 3646431Sigor@sysoev.ru nxt_req_conn_link_t *rc; 3647431Sigor@sysoev.ru 3648431Sigor@sysoev.ru r = ar->request; 3649431Sigor@sysoev.ru app = r->socket_conf->application; 3650425Smax.romanov@nginx.com 3651425Smax.romanov@nginx.com if (app == NULL) { 3652431Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 3653425Smax.romanov@nginx.com return; 3654425Smax.romanov@nginx.com } 365588Smax.romanov@nginx.com 365688Smax.romanov@nginx.com engine = task->thread->engine; 365788Smax.romanov@nginx.com 3658318Smax.romanov@nginx.com rc = nxt_port_rpc_register_handler_ex(task, engine->port, 3659318Smax.romanov@nginx.com nxt_router_response_ready_handler, 3660318Smax.romanov@nginx.com nxt_router_response_error_handler, 3661318Smax.romanov@nginx.com sizeof(nxt_req_conn_link_t)); 3662122Smax.romanov@nginx.com 366388Smax.romanov@nginx.com if (nxt_slow_path(rc == NULL)) { 3664431Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 3665141Smax.romanov@nginx.com return; 366688Smax.romanov@nginx.com } 366788Smax.romanov@nginx.com 3668318Smax.romanov@nginx.com rc->stream = nxt_port_rpc_ex_stream(rc); 3669425Smax.romanov@nginx.com rc->app = app; 3670425Smax.romanov@nginx.com 3671425Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 3672425Smax.romanov@nginx.com 3673431Sigor@sysoev.ru rc->ap = ar; 3674346Smax.romanov@nginx.com 3675351Smax.romanov@nginx.com ra = &ra_local; 3676351Smax.romanov@nginx.com nxt_router_ra_init(task, ra, rc); 3677167Smax.romanov@nginx.com 3678427Smax.romanov@nginx.com res = nxt_router_app_port(task, app, ra); 3679141Smax.romanov@nginx.com 3680141Smax.romanov@nginx.com if (res != NXT_OK) { 3681141Smax.romanov@nginx.com return; 3682141Smax.romanov@nginx.com } 3683141Smax.romanov@nginx.com 3684425Smax.romanov@nginx.com ra = rc->ra; 3685167Smax.romanov@nginx.com port = ra->app_port; 3686141Smax.romanov@nginx.com 3687425Smax.romanov@nginx.com nxt_assert(port != NULL); 3688141Smax.romanov@nginx.com 3689318Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, engine->port, rc, port->pid); 3690318Smax.romanov@nginx.com 3691425Smax.romanov@nginx.com nxt_router_app_prepare_request(task, ra); 3692167Smax.romanov@nginx.com } 3693167Smax.romanov@nginx.com 3694167Smax.romanov@nginx.com 3695167Smax.romanov@nginx.com static void 3696423Smax.romanov@nginx.com nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj, void *data) 3697423Smax.romanov@nginx.com { 3698423Smax.romanov@nginx.com } 3699423Smax.romanov@nginx.com 3700423Smax.romanov@nginx.com 3701423Smax.romanov@nginx.com static void 3702425Smax.romanov@nginx.com nxt_router_app_prepare_request(nxt_task_t *task, nxt_req_app_link_t *ra) 3703167Smax.romanov@nginx.com { 3704343Smax.romanov@nginx.com uint32_t request_failed; 3705423Smax.romanov@nginx.com nxt_buf_t *b; 3706167Smax.romanov@nginx.com nxt_int_t res; 3707343Smax.romanov@nginx.com nxt_port_t *port, *c_port, *reply_port; 3708167Smax.romanov@nginx.com nxt_app_wmsg_t wmsg; 3709167Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 3710167Smax.romanov@nginx.com 3711343Smax.romanov@nginx.com nxt_assert(ra->app_port != NULL); 3712343Smax.romanov@nginx.com 3713343Smax.romanov@nginx.com port = ra->app_port; 3714167Smax.romanov@nginx.com reply_port = ra->reply_port; 3715167Smax.romanov@nginx.com ap = ra->ap; 3716141Smax.romanov@nginx.com 3717343Smax.romanov@nginx.com request_failed = 1; 3718343Smax.romanov@nginx.com 3719141Smax.romanov@nginx.com c_port = nxt_process_connected_port_find(port->process, reply_port->pid, 3720141Smax.romanov@nginx.com reply_port->id); 3721141Smax.romanov@nginx.com if (nxt_slow_path(c_port != reply_port)) { 3722141Smax.romanov@nginx.com res = nxt_port_send_port(task, port, reply_port, 0); 3723122Smax.romanov@nginx.com 3724122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3725423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 3726345Smax.romanov@nginx.com "Failed to send reply port to application"); 3727343Smax.romanov@nginx.com goto release_port; 3728122Smax.romanov@nginx.com } 3729122Smax.romanov@nginx.com 3730141Smax.romanov@nginx.com nxt_process_connected_port_add(port->process, reply_port); 373188Smax.romanov@nginx.com } 373288Smax.romanov@nginx.com 373388Smax.romanov@nginx.com wmsg.port = port; 373488Smax.romanov@nginx.com wmsg.write = NULL; 373588Smax.romanov@nginx.com wmsg.buf = &wmsg.write; 3736318Smax.romanov@nginx.com wmsg.stream = ra->stream; 3737167Smax.romanov@nginx.com 3738216Sigor@sysoev.ru res = port->app->prepare_msg(task, &ap->r, &wmsg); 3739122Smax.romanov@nginx.com 3740122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3741423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 3742345Smax.romanov@nginx.com "Failed to prepare message for application"); 3743343Smax.romanov@nginx.com goto release_port; 3744122Smax.romanov@nginx.com } 374588Smax.romanov@nginx.com 3746507Smax.romanov@nginx.com nxt_debug(task, "about to send %O bytes buffer to app process port %d", 374788Smax.romanov@nginx.com nxt_buf_used_size(wmsg.write), 374888Smax.romanov@nginx.com wmsg.port->socket.fd); 374988Smax.romanov@nginx.com 3750343Smax.romanov@nginx.com request_failed = 0; 3751343Smax.romanov@nginx.com 3752423Smax.romanov@nginx.com ra->msg_info.buf = wmsg.write; 3753423Smax.romanov@nginx.com ra->msg_info.completion_handler = wmsg.write->completion_handler; 3754423Smax.romanov@nginx.com 3755423Smax.romanov@nginx.com for (b = wmsg.write; b != NULL; b = b->next) { 3756423Smax.romanov@nginx.com b->completion_handler = nxt_router_dummy_buf_completion; 3757423Smax.romanov@nginx.com } 3758423Smax.romanov@nginx.com 3759423Smax.romanov@nginx.com res = nxt_port_mmap_get_tracking(task, port, &ra->msg_info.tracking, 3760423Smax.romanov@nginx.com ra->stream); 3761423Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3762423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 3763423Smax.romanov@nginx.com "Failed to get tracking area"); 3764423Smax.romanov@nginx.com goto release_port; 3765423Smax.romanov@nginx.com } 3766423Smax.romanov@nginx.com 3767423Smax.romanov@nginx.com res = nxt_port_socket_twrite(task, wmsg.port, NXT_PORT_MSG_DATA, 3768423Smax.romanov@nginx.com -1, ra->stream, reply_port->id, wmsg.write, 3769423Smax.romanov@nginx.com &ra->msg_info.tracking); 3770122Smax.romanov@nginx.com 3771122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3772423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 3773345Smax.romanov@nginx.com "Failed to send message to application"); 3774343Smax.romanov@nginx.com goto release_port; 3775122Smax.romanov@nginx.com } 3776343Smax.romanov@nginx.com 3777343Smax.romanov@nginx.com release_port: 3778343Smax.romanov@nginx.com 3779345Smax.romanov@nginx.com nxt_router_app_port_release(task, port, request_failed, 0); 3780345Smax.romanov@nginx.com 3781425Smax.romanov@nginx.com nxt_router_ra_update_peer(task, ra); 378253Sigor@sysoev.ru } 378353Sigor@sysoev.ru 378453Sigor@sysoev.ru 3785216Sigor@sysoev.ru static nxt_int_t 3786216Sigor@sysoev.ru nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 3787216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg) 3788216Sigor@sysoev.ru { 3789216Sigor@sysoev.ru nxt_int_t rc; 3790216Sigor@sysoev.ru nxt_buf_t *b; 3791216Sigor@sysoev.ru nxt_http_field_t *field; 3792216Sigor@sysoev.ru nxt_app_request_header_t *h; 3793216Sigor@sysoev.ru 3794216Sigor@sysoev.ru static const nxt_str_t prefix = nxt_string("HTTP_"); 3795216Sigor@sysoev.ru static const nxt_str_t eof = nxt_null_string; 3796216Sigor@sysoev.ru 3797216Sigor@sysoev.ru h = &r->header; 3798216Sigor@sysoev.ru 3799216Sigor@sysoev.ru #define RC(S) \ 3800216Sigor@sysoev.ru do { \ 3801216Sigor@sysoev.ru rc = (S); \ 3802216Sigor@sysoev.ru if (nxt_slow_path(rc != NXT_OK)) { \ 3803216Sigor@sysoev.ru goto fail; \ 3804216Sigor@sysoev.ru } \ 3805216Sigor@sysoev.ru } while(0) 3806216Sigor@sysoev.ru 3807216Sigor@sysoev.ru #define NXT_WRITE(N) \ 3808216Sigor@sysoev.ru RC(nxt_app_msg_write_str(task, wmsg, N)) 3809216Sigor@sysoev.ru 3810216Sigor@sysoev.ru /* TODO error handle, async mmap buffer assignment */ 3811216Sigor@sysoev.ru 3812216Sigor@sysoev.ru NXT_WRITE(&h->method); 3813216Sigor@sysoev.ru NXT_WRITE(&h->target); 3814277Sigor@sysoev.ru 3815216Sigor@sysoev.ru if (h->path.start == h->target.start) { 3816216Sigor@sysoev.ru NXT_WRITE(&eof); 3817277Sigor@sysoev.ru 3818216Sigor@sysoev.ru } else { 3819216Sigor@sysoev.ru NXT_WRITE(&h->path); 3820216Sigor@sysoev.ru } 3821216Sigor@sysoev.ru 3822216Sigor@sysoev.ru if (h->query.start != NULL) { 3823216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 3824216Sigor@sysoev.ru h->query.start - h->target.start + 1)); 3825216Sigor@sysoev.ru } else { 3826216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 0)); 3827216Sigor@sysoev.ru } 3828216Sigor@sysoev.ru 3829216Sigor@sysoev.ru NXT_WRITE(&h->version); 3830216Sigor@sysoev.ru 3831216Sigor@sysoev.ru NXT_WRITE(&r->remote); 3832268Sigor@sysoev.ru NXT_WRITE(&r->local); 3833216Sigor@sysoev.ru 3834216Sigor@sysoev.ru NXT_WRITE(&h->host); 3835216Sigor@sysoev.ru NXT_WRITE(&h->content_type); 3836216Sigor@sysoev.ru NXT_WRITE(&h->content_length); 3837216Sigor@sysoev.ru 3838216Sigor@sysoev.ru nxt_list_each(field, h->fields) { 3839417Svbart@nginx.com RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, &prefix, field->name, 3840417Svbart@nginx.com field->name_length)); 3841417Svbart@nginx.com RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length)); 3842216Sigor@sysoev.ru 3843216Sigor@sysoev.ru } nxt_list_loop; 3844216Sigor@sysoev.ru 3845216Sigor@sysoev.ru /* end-of-headers mark */ 3846216Sigor@sysoev.ru NXT_WRITE(&eof); 3847216Sigor@sysoev.ru 3848216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 3849216Sigor@sysoev.ru 3850510Salexander.borisov@nginx.com for (b = r->body.buf; b != NULL; b = b->next) { 3851216Sigor@sysoev.ru RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3852216Sigor@sysoev.ru nxt_buf_mem_used_size(&b->mem))); 3853216Sigor@sysoev.ru } 3854216Sigor@sysoev.ru 3855216Sigor@sysoev.ru #undef NXT_WRITE 3856216Sigor@sysoev.ru #undef RC 3857216Sigor@sysoev.ru 3858216Sigor@sysoev.ru return NXT_OK; 3859216Sigor@sysoev.ru 3860216Sigor@sysoev.ru fail: 3861216Sigor@sysoev.ru 3862216Sigor@sysoev.ru return NXT_ERROR; 3863216Sigor@sysoev.ru } 3864216Sigor@sysoev.ru 3865216Sigor@sysoev.ru 3866216Sigor@sysoev.ru static nxt_int_t 3867216Sigor@sysoev.ru nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 3868216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg) 3869216Sigor@sysoev.ru { 3870216Sigor@sysoev.ru nxt_int_t rc; 3871216Sigor@sysoev.ru nxt_buf_t *b; 3872305Smax.romanov@nginx.com nxt_bool_t method_is_post; 3873216Sigor@sysoev.ru nxt_http_field_t *field; 3874216Sigor@sysoev.ru nxt_app_request_header_t *h; 3875216Sigor@sysoev.ru 3876216Sigor@sysoev.ru static const nxt_str_t prefix = nxt_string("HTTP_"); 3877216Sigor@sysoev.ru static const nxt_str_t eof = nxt_null_string; 3878216Sigor@sysoev.ru 3879216Sigor@sysoev.ru h = &r->header; 3880216Sigor@sysoev.ru 3881216Sigor@sysoev.ru #define RC(S) \ 3882216Sigor@sysoev.ru do { \ 3883216Sigor@sysoev.ru rc = (S); \ 3884216Sigor@sysoev.ru if (nxt_slow_path(rc != NXT_OK)) { \ 3885216Sigor@sysoev.ru goto fail; \ 3886216Sigor@sysoev.ru } \ 3887216Sigor@sysoev.ru } while(0) 3888216Sigor@sysoev.ru 3889216Sigor@sysoev.ru #define NXT_WRITE(N) \ 3890216Sigor@sysoev.ru RC(nxt_app_msg_write_str(task, wmsg, N)) 3891216Sigor@sysoev.ru 3892216Sigor@sysoev.ru /* TODO error handle, async mmap buffer assignment */ 3893216Sigor@sysoev.ru 3894216Sigor@sysoev.ru NXT_WRITE(&h->method); 3895216Sigor@sysoev.ru NXT_WRITE(&h->target); 3896277Sigor@sysoev.ru 3897216Sigor@sysoev.ru if (h->path.start == h->target.start) { 3898216Sigor@sysoev.ru NXT_WRITE(&eof); 3899277Sigor@sysoev.ru 3900216Sigor@sysoev.ru } else { 3901216Sigor@sysoev.ru NXT_WRITE(&h->path); 3902216Sigor@sysoev.ru } 3903216Sigor@sysoev.ru 3904216Sigor@sysoev.ru if (h->query.start != NULL) { 3905216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 3906216Sigor@sysoev.ru h->query.start - h->target.start + 1)); 3907216Sigor@sysoev.ru } else { 3908216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 0)); 3909216Sigor@sysoev.ru } 3910216Sigor@sysoev.ru 3911216Sigor@sysoev.ru NXT_WRITE(&h->version); 3912216Sigor@sysoev.ru 3913216Sigor@sysoev.ru // PHP_SELF 3914216Sigor@sysoev.ru // SCRIPT_NAME 3915216Sigor@sysoev.ru // SCRIPT_FILENAME 3916216Sigor@sysoev.ru // DOCUMENT_ROOT 3917216Sigor@sysoev.ru 3918216Sigor@sysoev.ru NXT_WRITE(&r->remote); 3919268Sigor@sysoev.ru NXT_WRITE(&r->local); 3920216Sigor@sysoev.ru 3921216Sigor@sysoev.ru NXT_WRITE(&h->host); 3922216Sigor@sysoev.ru NXT_WRITE(&h->cookie); 3923216Sigor@sysoev.ru NXT_WRITE(&h->content_type); 3924216Sigor@sysoev.ru NXT_WRITE(&h->content_length); 3925216Sigor@sysoev.ru 3926216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length)); 3927305Smax.romanov@nginx.com RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 3928305Smax.romanov@nginx.com 3929426Smax.romanov@nginx.com method_is_post = h->method.length == 4 3930426Smax.romanov@nginx.com && h->method.start[0] == 'P' 3931426Smax.romanov@nginx.com && h->method.start[1] == 'O' 3932426Smax.romanov@nginx.com && h->method.start[2] == 'S' 3933426Smax.romanov@nginx.com && h->method.start[3] == 'T'; 3934305Smax.romanov@nginx.com 3935305Smax.romanov@nginx.com if (method_is_post) { 3936510Salexander.borisov@nginx.com for (b = r->body.buf; b != NULL; b = b->next) { 3937305Smax.romanov@nginx.com RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3938305Smax.romanov@nginx.com nxt_buf_mem_used_size(&b->mem))); 3939305Smax.romanov@nginx.com } 3940305Smax.romanov@nginx.com } 3941216Sigor@sysoev.ru 3942216Sigor@sysoev.ru nxt_list_each(field, h->fields) { 3943417Svbart@nginx.com RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, &prefix, field->name, 3944417Svbart@nginx.com field->name_length)); 3945417Svbart@nginx.com RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length)); 3946216Sigor@sysoev.ru 3947216Sigor@sysoev.ru } nxt_list_loop; 3948216Sigor@sysoev.ru 3949216Sigor@sysoev.ru /* end-of-headers mark */ 3950216Sigor@sysoev.ru NXT_WRITE(&eof); 3951216Sigor@sysoev.ru 3952305Smax.romanov@nginx.com if (!method_is_post) { 3953510Salexander.borisov@nginx.com for (b = r->body.buf; b != NULL; b = b->next) { 3954305Smax.romanov@nginx.com RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3955305Smax.romanov@nginx.com nxt_buf_mem_used_size(&b->mem))); 3956305Smax.romanov@nginx.com } 3957216Sigor@sysoev.ru } 3958216Sigor@sysoev.ru 3959216Sigor@sysoev.ru #undef NXT_WRITE 3960216Sigor@sysoev.ru #undef RC 3961216Sigor@sysoev.ru 3962216Sigor@sysoev.ru return NXT_OK; 3963216Sigor@sysoev.ru 3964216Sigor@sysoev.ru fail: 3965216Sigor@sysoev.ru 3966216Sigor@sysoev.ru return NXT_ERROR; 3967216Sigor@sysoev.ru } 3968216Sigor@sysoev.ru 3969216Sigor@sysoev.ru 3970216Sigor@sysoev.ru static nxt_int_t 3971216Sigor@sysoev.ru nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, nxt_app_wmsg_t *wmsg) 3972216Sigor@sysoev.ru { 3973216Sigor@sysoev.ru nxt_int_t rc; 3974216Sigor@sysoev.ru nxt_buf_t *b; 3975216Sigor@sysoev.ru nxt_http_field_t *field; 3976216Sigor@sysoev.ru nxt_app_request_header_t *h; 3977216Sigor@sysoev.ru 3978216Sigor@sysoev.ru static const nxt_str_t eof = nxt_null_string; 3979216Sigor@sysoev.ru 3980216Sigor@sysoev.ru h = &r->header; 3981216Sigor@sysoev.ru 3982216Sigor@sysoev.ru #define RC(S) \ 3983216Sigor@sysoev.ru do { \ 3984216Sigor@sysoev.ru rc = (S); \ 3985216Sigor@sysoev.ru if (nxt_slow_path(rc != NXT_OK)) { \ 3986216Sigor@sysoev.ru goto fail; \ 3987216Sigor@sysoev.ru } \ 3988216Sigor@sysoev.ru } while(0) 3989216Sigor@sysoev.ru 3990216Sigor@sysoev.ru #define NXT_WRITE(N) \ 3991216Sigor@sysoev.ru RC(nxt_app_msg_write_str(task, wmsg, N)) 3992216Sigor@sysoev.ru 3993216Sigor@sysoev.ru /* TODO error handle, async mmap buffer assignment */ 3994216Sigor@sysoev.ru 3995216Sigor@sysoev.ru NXT_WRITE(&h->method); 3996216Sigor@sysoev.ru NXT_WRITE(&h->target); 3997277Sigor@sysoev.ru 3998216Sigor@sysoev.ru if (h->path.start == h->target.start) { 3999216Sigor@sysoev.ru NXT_WRITE(&eof); 4000277Sigor@sysoev.ru 4001216Sigor@sysoev.ru } else { 4002216Sigor@sysoev.ru NXT_WRITE(&h->path); 4003216Sigor@sysoev.ru } 4004216Sigor@sysoev.ru 4005216Sigor@sysoev.ru if (h->query.start != NULL) { 4006216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 4007216Sigor@sysoev.ru h->query.start - h->target.start + 1)); 4008216Sigor@sysoev.ru } else { 4009216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 0)); 4010216Sigor@sysoev.ru } 4011216Sigor@sysoev.ru 4012216Sigor@sysoev.ru NXT_WRITE(&h->version); 4013253Smax.romanov@nginx.com NXT_WRITE(&r->remote); 4014216Sigor@sysoev.ru 4015216Sigor@sysoev.ru NXT_WRITE(&h->host); 4016216Sigor@sysoev.ru NXT_WRITE(&h->cookie); 4017216Sigor@sysoev.ru NXT_WRITE(&h->content_type); 4018216Sigor@sysoev.ru NXT_WRITE(&h->content_length); 4019216Sigor@sysoev.ru 4020216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length)); 4021216Sigor@sysoev.ru 4022216Sigor@sysoev.ru nxt_list_each(field, h->fields) { 4023417Svbart@nginx.com RC(nxt_app_msg_write(task, wmsg, field->name, field->name_length)); 4024417Svbart@nginx.com RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length)); 4025216Sigor@sysoev.ru 4026216Sigor@sysoev.ru } nxt_list_loop; 4027216Sigor@sysoev.ru 4028216Sigor@sysoev.ru /* end-of-headers mark */ 4029216Sigor@sysoev.ru NXT_WRITE(&eof); 4030216Sigor@sysoev.ru 4031216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 4032216Sigor@sysoev.ru 4033510Salexander.borisov@nginx.com for (b = r->body.buf; b != NULL; b = b->next) { 4034510Salexander.borisov@nginx.com RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 4035510Salexander.borisov@nginx.com nxt_buf_mem_used_size(&b->mem))); 4036510Salexander.borisov@nginx.com } 4037510Salexander.borisov@nginx.com 4038510Salexander.borisov@nginx.com #undef NXT_WRITE 4039510Salexander.borisov@nginx.com #undef RC 4040510Salexander.borisov@nginx.com 4041510Salexander.borisov@nginx.com return NXT_OK; 4042510Salexander.borisov@nginx.com 4043510Salexander.borisov@nginx.com fail: 4044510Salexander.borisov@nginx.com 4045510Salexander.borisov@nginx.com return NXT_ERROR; 4046510Salexander.borisov@nginx.com } 4047510Salexander.borisov@nginx.com 4048510Salexander.borisov@nginx.com 4049510Salexander.borisov@nginx.com static nxt_int_t 4050510Salexander.borisov@nginx.com nxt_perl_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 4051510Salexander.borisov@nginx.com nxt_app_wmsg_t *wmsg) 4052510Salexander.borisov@nginx.com { 4053510Salexander.borisov@nginx.com nxt_int_t rc; 4054510Salexander.borisov@nginx.com nxt_str_t str; 4055510Salexander.borisov@nginx.com nxt_buf_t *b; 4056510Salexander.borisov@nginx.com nxt_http_field_t *field; 4057510Salexander.borisov@nginx.com nxt_app_request_header_t *h; 4058510Salexander.borisov@nginx.com 4059510Salexander.borisov@nginx.com static const nxt_str_t prefix = nxt_string("HTTP_"); 4060510Salexander.borisov@nginx.com static const nxt_str_t eof = nxt_null_string; 4061510Salexander.borisov@nginx.com 4062510Salexander.borisov@nginx.com h = &r->header; 4063510Salexander.borisov@nginx.com 4064510Salexander.borisov@nginx.com #define RC(S) \ 4065510Salexander.borisov@nginx.com do { \ 4066510Salexander.borisov@nginx.com rc = (S); \ 4067510Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { \ 4068510Salexander.borisov@nginx.com goto fail; \ 4069510Salexander.borisov@nginx.com } \ 4070510Salexander.borisov@nginx.com } while(0) 4071510Salexander.borisov@nginx.com 4072510Salexander.borisov@nginx.com #define NXT_WRITE(N) \ 4073510Salexander.borisov@nginx.com RC(nxt_app_msg_write_str(task, wmsg, N)) 4074510Salexander.borisov@nginx.com 4075510Salexander.borisov@nginx.com /* TODO error handle, async mmap buffer assignment */ 4076510Salexander.borisov@nginx.com 4077510Salexander.borisov@nginx.com NXT_WRITE(&h->method); 4078510Salexander.borisov@nginx.com NXT_WRITE(&h->target); 4079510Salexander.borisov@nginx.com 4080510Salexander.borisov@nginx.com if (h->query.length) { 4081510Salexander.borisov@nginx.com str.start = h->target.start; 4082510Salexander.borisov@nginx.com str.length = (h->target.length - h->query.length) - 1; 4083510Salexander.borisov@nginx.com 4084510Salexander.borisov@nginx.com RC(nxt_app_msg_write_str(task, wmsg, &str)); 4085510Salexander.borisov@nginx.com 4086510Salexander.borisov@nginx.com } else { 4087510Salexander.borisov@nginx.com NXT_WRITE(&eof); 4088510Salexander.borisov@nginx.com } 4089510Salexander.borisov@nginx.com 4090510Salexander.borisov@nginx.com if (h->query.start != NULL) { 4091510Salexander.borisov@nginx.com RC(nxt_app_msg_write_size(task, wmsg, 4092510Salexander.borisov@nginx.com h->query.start - h->target.start + 1)); 4093510Salexander.borisov@nginx.com } else { 4094510Salexander.borisov@nginx.com RC(nxt_app_msg_write_size(task, wmsg, 0)); 4095510Salexander.borisov@nginx.com } 4096510Salexander.borisov@nginx.com 4097510Salexander.borisov@nginx.com NXT_WRITE(&h->version); 4098510Salexander.borisov@nginx.com 4099510Salexander.borisov@nginx.com NXT_WRITE(&r->remote); 4100510Salexander.borisov@nginx.com NXT_WRITE(&r->local); 4101510Salexander.borisov@nginx.com 4102510Salexander.borisov@nginx.com NXT_WRITE(&h->host); 4103510Salexander.borisov@nginx.com NXT_WRITE(&h->content_type); 4104510Salexander.borisov@nginx.com NXT_WRITE(&h->content_length); 4105510Salexander.borisov@nginx.com 4106510Salexander.borisov@nginx.com nxt_list_each(field, h->fields) { 4107510Salexander.borisov@nginx.com RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, &prefix, 4108510Salexander.borisov@nginx.com field->name, field->name_length)); 4109510Salexander.borisov@nginx.com RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length)); 4110510Salexander.borisov@nginx.com } nxt_list_loop; 4111510Salexander.borisov@nginx.com 4112510Salexander.borisov@nginx.com /* end-of-headers mark */ 4113510Salexander.borisov@nginx.com NXT_WRITE(&eof); 4114510Salexander.borisov@nginx.com 4115510Salexander.borisov@nginx.com RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 4116510Salexander.borisov@nginx.com 4117510Salexander.borisov@nginx.com for (b = r->body.buf; b != NULL; b = b->next) { 4118510Salexander.borisov@nginx.com 4119216Sigor@sysoev.ru RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 4120216Sigor@sysoev.ru nxt_buf_mem_used_size(&b->mem))); 4121216Sigor@sysoev.ru } 4122216Sigor@sysoev.ru 4123216Sigor@sysoev.ru #undef NXT_WRITE 4124216Sigor@sysoev.ru #undef RC 4125216Sigor@sysoev.ru 4126216Sigor@sysoev.ru return NXT_OK; 4127216Sigor@sysoev.ru 4128216Sigor@sysoev.ru fail: 4129216Sigor@sysoev.ru 4130216Sigor@sysoev.ru return NXT_ERROR; 4131216Sigor@sysoev.ru } 4132216Sigor@sysoev.ru 4133216Sigor@sysoev.ru 4134584Salexander.borisov@nginx.com static nxt_int_t 4135584Salexander.borisov@nginx.com nxt_ruby_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 4136584Salexander.borisov@nginx.com nxt_app_wmsg_t *wmsg) 4137584Salexander.borisov@nginx.com { 4138584Salexander.borisov@nginx.com nxt_int_t rc; 4139584Salexander.borisov@nginx.com nxt_str_t str; 4140584Salexander.borisov@nginx.com nxt_buf_t *b; 4141584Salexander.borisov@nginx.com nxt_http_field_t *field; 4142584Salexander.borisov@nginx.com nxt_app_request_header_t *h; 4143584Salexander.borisov@nginx.com 4144584Salexander.borisov@nginx.com static const nxt_str_t prefix = nxt_string("HTTP_"); 4145584Salexander.borisov@nginx.com static const nxt_str_t eof = nxt_null_string; 4146584Salexander.borisov@nginx.com 4147584Salexander.borisov@nginx.com h = &r->header; 4148584Salexander.borisov@nginx.com 4149584Salexander.borisov@nginx.com #define RC(S) \ 4150584Salexander.borisov@nginx.com do { \ 4151584Salexander.borisov@nginx.com rc = (S); \ 4152584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { \ 4153584Salexander.borisov@nginx.com goto fail; \ 4154584Salexander.borisov@nginx.com } \ 4155584Salexander.borisov@nginx.com } while(0) 4156584Salexander.borisov@nginx.com 4157584Salexander.borisov@nginx.com #define NXT_WRITE(N) \ 4158584Salexander.borisov@nginx.com RC(nxt_app_msg_write_str(task, wmsg, N)) 4159584Salexander.borisov@nginx.com 4160584Salexander.borisov@nginx.com /* TODO error handle, async mmap buffer assignment */ 4161584Salexander.borisov@nginx.com 4162584Salexander.borisov@nginx.com NXT_WRITE(&h->method); 4163584Salexander.borisov@nginx.com NXT_WRITE(&h->target); 4164584Salexander.borisov@nginx.com 4165584Salexander.borisov@nginx.com if (h->query.length) { 4166584Salexander.borisov@nginx.com str.start = h->target.start; 4167584Salexander.borisov@nginx.com str.length = (h->target.length - h->query.length) - 1; 4168584Salexander.borisov@nginx.com 4169584Salexander.borisov@nginx.com RC(nxt_app_msg_write_str(task, wmsg, &str)); 4170584Salexander.borisov@nginx.com 4171584Salexander.borisov@nginx.com } else { 4172584Salexander.borisov@nginx.com NXT_WRITE(&eof); 4173584Salexander.borisov@nginx.com } 4174584Salexander.borisov@nginx.com 4175584Salexander.borisov@nginx.com if (h->query.start != NULL) { 4176584Salexander.borisov@nginx.com RC(nxt_app_msg_write_size(task, wmsg, 4177584Salexander.borisov@nginx.com h->query.start - h->target.start + 1)); 4178584Salexander.borisov@nginx.com } else { 4179584Salexander.borisov@nginx.com RC(nxt_app_msg_write_size(task, wmsg, 0)); 4180584Salexander.borisov@nginx.com } 4181584Salexander.borisov@nginx.com 4182584Salexander.borisov@nginx.com NXT_WRITE(&h->version); 4183584Salexander.borisov@nginx.com 4184584Salexander.borisov@nginx.com NXT_WRITE(&r->remote); 4185584Salexander.borisov@nginx.com NXT_WRITE(&r->local); 4186584Salexander.borisov@nginx.com 4187584Salexander.borisov@nginx.com NXT_WRITE(&h->host); 4188584Salexander.borisov@nginx.com NXT_WRITE(&h->content_type); 4189584Salexander.borisov@nginx.com NXT_WRITE(&h->content_length); 4190584Salexander.borisov@nginx.com 4191584Salexander.borisov@nginx.com nxt_list_each(field, h->fields) { 4192584Salexander.borisov@nginx.com RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, &prefix, 4193584Salexander.borisov@nginx.com field->name, field->name_length)); 4194584Salexander.borisov@nginx.com RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length)); 4195584Salexander.borisov@nginx.com } nxt_list_loop; 4196584Salexander.borisov@nginx.com 4197584Salexander.borisov@nginx.com /* end-of-headers mark */ 4198584Salexander.borisov@nginx.com NXT_WRITE(&eof); 4199584Salexander.borisov@nginx.com 4200584Salexander.borisov@nginx.com RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 4201584Salexander.borisov@nginx.com 4202584Salexander.borisov@nginx.com for (b = r->body.buf; b != NULL; b = b->next) { 4203584Salexander.borisov@nginx.com 4204584Salexander.borisov@nginx.com RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 4205584Salexander.borisov@nginx.com nxt_buf_mem_used_size(&b->mem))); 4206584Salexander.borisov@nginx.com } 4207584Salexander.borisov@nginx.com 4208584Salexander.borisov@nginx.com #undef NXT_WRITE 4209584Salexander.borisov@nginx.com #undef RC 4210584Salexander.borisov@nginx.com 4211584Salexander.borisov@nginx.com return NXT_OK; 4212584Salexander.borisov@nginx.com 4213584Salexander.borisov@nginx.com fail: 4214584Salexander.borisov@nginx.com 4215584Salexander.borisov@nginx.com return NXT_ERROR; 4216584Salexander.borisov@nginx.com } 4217584Salexander.borisov@nginx.com 4218584Salexander.borisov@nginx.com 4219431Sigor@sysoev.ru const nxt_conn_state_t nxt_router_conn_close_state 422053Sigor@sysoev.ru nxt_aligned(64) = 422153Sigor@sysoev.ru { 422253Sigor@sysoev.ru .ready_handler = nxt_router_conn_free, 422353Sigor@sysoev.ru }; 422453Sigor@sysoev.ru 422553Sigor@sysoev.ru 422653Sigor@sysoev.ru static void 4227164Smax.romanov@nginx.com nxt_router_conn_mp_cleanup(nxt_task_t *task, void *obj, void *data) 4228164Smax.romanov@nginx.com { 4229164Smax.romanov@nginx.com nxt_socket_conf_joint_t *joint; 4230164Smax.romanov@nginx.com 4231164Smax.romanov@nginx.com joint = obj; 4232164Smax.romanov@nginx.com 4233164Smax.romanov@nginx.com nxt_router_conf_release(task, joint); 4234164Smax.romanov@nginx.com } 4235164Smax.romanov@nginx.com 4236164Smax.romanov@nginx.com 4237164Smax.romanov@nginx.com static void 423853Sigor@sysoev.ru nxt_router_conn_free(nxt_task_t *task, void *obj, void *data) 423953Sigor@sysoev.ru { 424062Sigor@sysoev.ru nxt_conn_t *c; 4241337Sigor@sysoev.ru nxt_event_engine_t *engine; 424253Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 424353Sigor@sysoev.ru 424453Sigor@sysoev.ru c = obj; 424553Sigor@sysoev.ru 424653Sigor@sysoev.ru nxt_debug(task, "router conn close done"); 424753Sigor@sysoev.ru 4248122Smax.romanov@nginx.com nxt_queue_remove(&c->link); 4249122Smax.romanov@nginx.com 4250337Sigor@sysoev.ru engine = task->thread->engine; 4251337Sigor@sysoev.ru 4252337Sigor@sysoev.ru nxt_sockaddr_cache_free(engine, c); 4253337Sigor@sysoev.ru 4254359Sigor@sysoev.ru joint = c->joint; 4255131Smax.romanov@nginx.com 4256337Sigor@sysoev.ru nxt_mp_cleanup(c->mem_pool, nxt_router_conn_mp_cleanup, 4257337Sigor@sysoev.ru &engine->task, joint, NULL); 4258164Smax.romanov@nginx.com 4259386Sigor@sysoev.ru nxt_conn_free(task, c); 426053Sigor@sysoev.ru } 426153Sigor@sysoev.ru 426253Sigor@sysoev.ru 426353Sigor@sysoev.ru static void 4264318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data) 4265318Smax.romanov@nginx.com { 4266431Sigor@sysoev.ru nxt_timer_t *timer; 4267431Sigor@sysoev.ru nxt_app_parse_ctx_t *ar; 4268318Smax.romanov@nginx.com 4269318Smax.romanov@nginx.com timer = obj; 4270318Smax.romanov@nginx.com 4271318Smax.romanov@nginx.com nxt_debug(task, "router app timeout"); 4272318Smax.romanov@nginx.com 4273431Sigor@sysoev.ru ar = nxt_timer_data(timer, nxt_app_parse_ctx_t, timer); 4274431Sigor@sysoev.ru 4275431Sigor@sysoev.ru if (!ar->request->header_sent) { 4276431Sigor@sysoev.ru nxt_http_request_error(task, ar->request, NXT_HTTP_SERVICE_UNAVAILABLE); 4277431Sigor@sysoev.ru } 4278318Smax.romanov@nginx.com } 4279