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 { 120425Smax.romanov@nginx.com int c; 121425Smax.romanov@nginx.com 122425Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&ra->use_count, -1); 123425Smax.romanov@nginx.com 124425Smax.romanov@nginx.com nxt_assert(c > 1); 125425Smax.romanov@nginx.com } 126425Smax.romanov@nginx.com 127425Smax.romanov@nginx.com static void nxt_router_ra_use(nxt_task_t *task, nxt_req_app_link_t *ra, int i); 128425Smax.romanov@nginx.com 129139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task); 130198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data); 131198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task, 132139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 133139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task, 134139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 135139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task, 136193Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type); 13753Sigor@sysoev.ru 138115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task, 139115Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end); 140133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name); 141133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, 142133Sigor@sysoev.ru nxt_str_t *name); 143198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task, 144198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf); 145198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task, 146198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 147198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task, 148198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 149507Smax.romanov@nginx.com static void nxt_router_app_rpc_create(nxt_task_t *task, 150507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_app_t *app); 151507Smax.romanov@nginx.com static void nxt_router_app_prefork_ready(nxt_task_t *task, 152507Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 153507Smax.romanov@nginx.com static void nxt_router_app_prefork_error(nxt_task_t *task, 154507Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 155359Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, 156359Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_str_t *name); 157359Sigor@sysoev.ru static nxt_int_t nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, 158359Sigor@sysoev.ru nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa); 15953Sigor@sysoev.ru 16053Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task, 16153Sigor@sysoev.ru nxt_router_t *router, nxt_router_temp_conf_t *tmcf, 16253Sigor@sysoev.ru const nxt_event_interface_t *interface); 163115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 164115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 165115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 166115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 167115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 168115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 169154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 170154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 171154Sigor@sysoev.ru nxt_work_handler_t handler); 172313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 173313Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 174139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 175139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets); 17653Sigor@sysoev.ru 17753Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 17853Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 17953Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 18053Sigor@sysoev.ru nxt_event_engine_t *engine); 181343Smax.romanov@nginx.com static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 182133Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 18353Sigor@sysoev.ru 184315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router, 185315Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 186315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine, 187315Sigor@sysoev.ru nxt_work_t *jobs); 18853Sigor@sysoev.ru 18953Sigor@sysoev.ru static void nxt_router_thread_start(void *data); 19053Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj, 19153Sigor@sysoev.ru void *data); 19253Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj, 19353Sigor@sysoev.ru void *data); 19453Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, 19553Sigor@sysoev.ru void *data); 196313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, 197313Sigor@sysoev.ru void *data); 19853Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj, 19953Sigor@sysoev.ru void *data); 20053Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, 20153Sigor@sysoev.ru void *data); 202359Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task, 203359Sigor@sysoev.ru nxt_socket_conf_t *skcf); 20453Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task, 20553Sigor@sysoev.ru nxt_socket_conf_joint_t *joint); 20653Sigor@sysoev.ru 207343Smax.romanov@nginx.com static void nxt_router_app_port_ready(nxt_task_t *task, 208343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 209343Smax.romanov@nginx.com static void nxt_router_app_port_error(nxt_task_t *task, 210343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 211343Smax.romanov@nginx.com 212507Smax.romanov@nginx.com static void nxt_router_app_quit(nxt_task_t *task, nxt_app_t *app); 213343Smax.romanov@nginx.com static void nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port, 214343Smax.romanov@nginx.com uint32_t request_failed, uint32_t got_response); 215427Smax.romanov@nginx.com static nxt_int_t nxt_router_app_port(nxt_task_t *task, nxt_app_t *app, 216427Smax.romanov@nginx.com nxt_req_app_link_t *ra); 217141Smax.romanov@nginx.com 218425Smax.romanov@nginx.com static void nxt_router_app_prepare_request(nxt_task_t *task, 219343Smax.romanov@nginx.com nxt_req_app_link_t *ra); 220216Sigor@sysoev.ru static nxt_int_t nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 221216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg); 222216Sigor@sysoev.ru static nxt_int_t nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 223216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg); 224216Sigor@sysoev.ru static nxt_int_t nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 225216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg); 226*510Salexander.borisov@nginx.com static nxt_int_t nxt_perl_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 227*510Salexander.borisov@nginx.com nxt_app_wmsg_t *wmsg); 228*510Salexander.borisov@nginx.com 22953Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data); 230318Smax.romanov@nginx.com static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data); 231507Smax.romanov@nginx.com static void nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, 232507Smax.romanov@nginx.com void *data); 233507Smax.romanov@nginx.com static void nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, 234507Smax.romanov@nginx.com void *data); 235507Smax.romanov@nginx.com static void nxt_router_app_release_handler(nxt_task_t *task, void *obj, 236507Smax.romanov@nginx.com void *data); 237431Sigor@sysoev.ru 238431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_send_state; 239431Sigor@sysoev.ru static void nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data); 240141Smax.romanov@nginx.com 241119Smax.romanov@nginx.com static nxt_router_t *nxt_router; 24220Sigor@sysoev.ru 243216Sigor@sysoev.ru 244216Sigor@sysoev.ru static nxt_app_prepare_msg_t nxt_app_prepare_msg[] = { 245216Sigor@sysoev.ru nxt_python_prepare_msg, 246216Sigor@sysoev.ru nxt_php_prepare_msg, 247216Sigor@sysoev.ru nxt_go_prepare_msg, 248*510Salexander.borisov@nginx.com nxt_perl_prepare_msg, 249216Sigor@sysoev.ru }; 250216Sigor@sysoev.ru 251216Sigor@sysoev.ru 25220Sigor@sysoev.ru nxt_int_t 253141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data) 25420Sigor@sysoev.ru { 255141Smax.romanov@nginx.com nxt_int_t ret; 256141Smax.romanov@nginx.com nxt_router_t *router; 257141Smax.romanov@nginx.com nxt_runtime_t *rt; 258141Smax.romanov@nginx.com 259141Smax.romanov@nginx.com rt = task->thread->runtime; 26053Sigor@sysoev.ru 261431Sigor@sysoev.ru ret = nxt_http_init(task, rt); 26288Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 26388Smax.romanov@nginx.com return ret; 26488Smax.romanov@nginx.com } 26588Smax.romanov@nginx.com 26653Sigor@sysoev.ru router = nxt_zalloc(sizeof(nxt_router_t)); 26753Sigor@sysoev.ru if (nxt_slow_path(router == NULL)) { 26853Sigor@sysoev.ru return NXT_ERROR; 26953Sigor@sysoev.ru } 27053Sigor@sysoev.ru 27153Sigor@sysoev.ru nxt_queue_init(&router->engines); 27253Sigor@sysoev.ru nxt_queue_init(&router->sockets); 273133Sigor@sysoev.ru nxt_queue_init(&router->apps); 27453Sigor@sysoev.ru 275119Smax.romanov@nginx.com nxt_router = router; 276119Smax.romanov@nginx.com 277115Sigor@sysoev.ru return NXT_OK; 278115Sigor@sysoev.ru } 279115Sigor@sysoev.ru 280115Sigor@sysoev.ru 281343Smax.romanov@nginx.com static void 282507Smax.romanov@nginx.com nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port, 283507Smax.romanov@nginx.com void *data) 284167Smax.romanov@nginx.com { 285343Smax.romanov@nginx.com size_t size; 286343Smax.romanov@nginx.com uint32_t stream; 287430Sigor@sysoev.ru nxt_mp_t *mp; 288343Smax.romanov@nginx.com nxt_app_t *app; 289343Smax.romanov@nginx.com nxt_buf_t *b; 290343Smax.romanov@nginx.com nxt_port_t *main_port; 291343Smax.romanov@nginx.com nxt_runtime_t *rt; 292343Smax.romanov@nginx.com 293343Smax.romanov@nginx.com app = data; 294167Smax.romanov@nginx.com 295167Smax.romanov@nginx.com rt = task->thread->runtime; 296240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 297167Smax.romanov@nginx.com 298507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start process", &app->name, app); 299343Smax.romanov@nginx.com 300343Smax.romanov@nginx.com size = app->name.length + 1 + app->conf.length; 301343Smax.romanov@nginx.com 302343Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size); 303343Smax.romanov@nginx.com 304343Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 305343Smax.romanov@nginx.com goto failed; 306167Smax.romanov@nginx.com } 307167Smax.romanov@nginx.com 308343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->name); 309343Smax.romanov@nginx.com *b->mem.free++ = '\0'; 310343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 311343Smax.romanov@nginx.com 312343Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, port, 313343Smax.romanov@nginx.com nxt_router_app_port_ready, 314343Smax.romanov@nginx.com nxt_router_app_port_error, 315343Smax.romanov@nginx.com -1, app); 316343Smax.romanov@nginx.com 317343Smax.romanov@nginx.com if (nxt_slow_path(stream == 0)) { 318430Sigor@sysoev.ru mp = b->data; 319430Sigor@sysoev.ru nxt_mp_free(mp, b); 320430Sigor@sysoev.ru nxt_mp_release(mp); 321343Smax.romanov@nginx.com 322343Smax.romanov@nginx.com goto failed; 323343Smax.romanov@nginx.com } 324343Smax.romanov@nginx.com 325343Smax.romanov@nginx.com nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1, 326343Smax.romanov@nginx.com stream, port->id, b); 327343Smax.romanov@nginx.com 328343Smax.romanov@nginx.com return; 329343Smax.romanov@nginx.com 330343Smax.romanov@nginx.com failed: 331343Smax.romanov@nginx.com 332343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 333343Smax.romanov@nginx.com 334507Smax.romanov@nginx.com app->pending_processes--; 335343Smax.romanov@nginx.com 336343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 337343Smax.romanov@nginx.com 338343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 339167Smax.romanov@nginx.com } 340167Smax.romanov@nginx.com 341167Smax.romanov@nginx.com 342343Smax.romanov@nginx.com static nxt_int_t 343507Smax.romanov@nginx.com nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app) 344141Smax.romanov@nginx.com { 345343Smax.romanov@nginx.com nxt_int_t res; 346343Smax.romanov@nginx.com nxt_port_t *router_port; 347343Smax.romanov@nginx.com nxt_runtime_t *rt; 348343Smax.romanov@nginx.com 349343Smax.romanov@nginx.com rt = task->thread->runtime; 350343Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 351343Smax.romanov@nginx.com 352343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 353343Smax.romanov@nginx.com 354507Smax.romanov@nginx.com res = nxt_port_post(task, router_port, nxt_router_start_app_process_handler, 355343Smax.romanov@nginx.com app); 356343Smax.romanov@nginx.com 357343Smax.romanov@nginx.com if (res == NXT_OK) { 358343Smax.romanov@nginx.com return res; 359318Smax.romanov@nginx.com } 360318Smax.romanov@nginx.com 361343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 362343Smax.romanov@nginx.com 363507Smax.romanov@nginx.com app->pending_processes--; 364343Smax.romanov@nginx.com 365343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 366343Smax.romanov@nginx.com 367343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 368343Smax.romanov@nginx.com 369343Smax.romanov@nginx.com return NXT_ERROR; 370318Smax.romanov@nginx.com } 371318Smax.romanov@nginx.com 372318Smax.romanov@nginx.com 373351Smax.romanov@nginx.com nxt_inline void 374351Smax.romanov@nginx.com nxt_router_ra_init(nxt_task_t *task, nxt_req_app_link_t *ra, 375351Smax.romanov@nginx.com nxt_req_conn_link_t *rc) 376167Smax.romanov@nginx.com { 377318Smax.romanov@nginx.com nxt_event_engine_t *engine; 378351Smax.romanov@nginx.com 379318Smax.romanov@nginx.com engine = task->thread->engine; 380167Smax.romanov@nginx.com 381167Smax.romanov@nginx.com nxt_memzero(ra, sizeof(nxt_req_app_link_t)); 382167Smax.romanov@nginx.com 383318Smax.romanov@nginx.com ra->stream = rc->stream; 384425Smax.romanov@nginx.com ra->use_count = 1; 385167Smax.romanov@nginx.com ra->rc = rc; 386318Smax.romanov@nginx.com rc->ra = ra; 387318Smax.romanov@nginx.com ra->reply_port = engine->port; 388351Smax.romanov@nginx.com ra->ap = rc->ap; 389167Smax.romanov@nginx.com 390167Smax.romanov@nginx.com ra->work.handler = NULL; 391318Smax.romanov@nginx.com ra->work.task = &engine->task; 392167Smax.romanov@nginx.com ra->work.obj = ra; 393318Smax.romanov@nginx.com ra->work.data = engine; 394351Smax.romanov@nginx.com } 395351Smax.romanov@nginx.com 396351Smax.romanov@nginx.com 397351Smax.romanov@nginx.com nxt_inline nxt_req_app_link_t * 398351Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_app_link_t *ra_src) 399351Smax.romanov@nginx.com { 400351Smax.romanov@nginx.com nxt_mp_t *mp; 401351Smax.romanov@nginx.com nxt_req_app_link_t *ra; 402351Smax.romanov@nginx.com 403425Smax.romanov@nginx.com if (ra_src->mem_pool != NULL) { 404425Smax.romanov@nginx.com return ra_src; 405425Smax.romanov@nginx.com } 406425Smax.romanov@nginx.com 407351Smax.romanov@nginx.com mp = ra_src->ap->mem_pool; 408351Smax.romanov@nginx.com 409430Sigor@sysoev.ru ra = nxt_mp_alloc(mp, sizeof(nxt_req_app_link_t)); 410351Smax.romanov@nginx.com 411351Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 412351Smax.romanov@nginx.com 413351Smax.romanov@nginx.com ra_src->rc->ra = NULL; 414351Smax.romanov@nginx.com ra_src->rc = NULL; 415351Smax.romanov@nginx.com 416351Smax.romanov@nginx.com return NULL; 417351Smax.romanov@nginx.com } 418351Smax.romanov@nginx.com 419430Sigor@sysoev.ru nxt_mp_retain(mp); 420430Sigor@sysoev.ru 421351Smax.romanov@nginx.com nxt_router_ra_init(task, ra, ra_src->rc); 422351Smax.romanov@nginx.com 423351Smax.romanov@nginx.com ra->mem_pool = mp; 424167Smax.romanov@nginx.com 425167Smax.romanov@nginx.com return ra; 426167Smax.romanov@nginx.com } 427167Smax.romanov@nginx.com 428167Smax.romanov@nginx.com 429423Smax.romanov@nginx.com nxt_inline nxt_bool_t 430423Smax.romanov@nginx.com nxt_router_msg_cancel(nxt_task_t *task, nxt_msg_info_t *msg_info, 431423Smax.romanov@nginx.com uint32_t stream) 432423Smax.romanov@nginx.com { 433423Smax.romanov@nginx.com nxt_buf_t *b, *next; 434423Smax.romanov@nginx.com nxt_bool_t cancelled; 435423Smax.romanov@nginx.com 436423Smax.romanov@nginx.com if (msg_info->buf == NULL) { 437423Smax.romanov@nginx.com return 0; 438423Smax.romanov@nginx.com } 439423Smax.romanov@nginx.com 440423Smax.romanov@nginx.com cancelled = nxt_port_mmap_tracking_cancel(task, &msg_info->tracking, 441423Smax.romanov@nginx.com stream); 442423Smax.romanov@nginx.com 443423Smax.romanov@nginx.com if (cancelled) { 444423Smax.romanov@nginx.com nxt_debug(task, "stream #%uD: cancelled by router", stream); 445423Smax.romanov@nginx.com } 446423Smax.romanov@nginx.com 447423Smax.romanov@nginx.com for (b = msg_info->buf; b != NULL; b = next) { 448423Smax.romanov@nginx.com next = b->next; 449423Smax.romanov@nginx.com 450423Smax.romanov@nginx.com b->completion_handler = msg_info->completion_handler; 451423Smax.romanov@nginx.com 452423Smax.romanov@nginx.com if (b->is_port_mmap_sent) { 453423Smax.romanov@nginx.com b->is_port_mmap_sent = cancelled == 0; 454423Smax.romanov@nginx.com b->completion_handler(task, b, b->parent); 455423Smax.romanov@nginx.com } 456423Smax.romanov@nginx.com } 457423Smax.romanov@nginx.com 458423Smax.romanov@nginx.com msg_info->buf = NULL; 459423Smax.romanov@nginx.com 460423Smax.romanov@nginx.com return cancelled; 461423Smax.romanov@nginx.com } 462423Smax.romanov@nginx.com 463423Smax.romanov@nginx.com 464167Smax.romanov@nginx.com static void 465425Smax.romanov@nginx.com nxt_router_ra_update_peer(nxt_task_t *task, nxt_req_app_link_t *ra); 466425Smax.romanov@nginx.com 467425Smax.romanov@nginx.com 468425Smax.romanov@nginx.com static void 469425Smax.romanov@nginx.com nxt_router_ra_update_peer_handler(nxt_task_t *task, void *obj, void *data) 470167Smax.romanov@nginx.com { 471425Smax.romanov@nginx.com nxt_req_app_link_t *ra; 472425Smax.romanov@nginx.com 473425Smax.romanov@nginx.com ra = obj; 474425Smax.romanov@nginx.com 475425Smax.romanov@nginx.com nxt_router_ra_update_peer(task, ra); 476425Smax.romanov@nginx.com 477425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 478425Smax.romanov@nginx.com } 479425Smax.romanov@nginx.com 480425Smax.romanov@nginx.com 481425Smax.romanov@nginx.com static void 482425Smax.romanov@nginx.com nxt_router_ra_update_peer(nxt_task_t *task, nxt_req_app_link_t *ra) 483425Smax.romanov@nginx.com { 484343Smax.romanov@nginx.com nxt_event_engine_t *engine; 485343Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 486318Smax.romanov@nginx.com 487425Smax.romanov@nginx.com engine = ra->work.data; 488318Smax.romanov@nginx.com 489343Smax.romanov@nginx.com if (task->thread->engine != engine) { 490425Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 491425Smax.romanov@nginx.com 492425Smax.romanov@nginx.com ra->work.handler = nxt_router_ra_update_peer_handler; 493318Smax.romanov@nginx.com ra->work.task = &engine->task; 494318Smax.romanov@nginx.com ra->work.next = NULL; 495318Smax.romanov@nginx.com 496425Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD post update peer to %p", 497318Smax.romanov@nginx.com ra->stream, engine); 498318Smax.romanov@nginx.com 499318Smax.romanov@nginx.com nxt_event_engine_post(engine, &ra->work); 500318Smax.romanov@nginx.com 501318Smax.romanov@nginx.com return; 502318Smax.romanov@nginx.com } 503318Smax.romanov@nginx.com 504425Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD update peer", ra->stream); 505425Smax.romanov@nginx.com 506425Smax.romanov@nginx.com rc = ra->rc; 507425Smax.romanov@nginx.com 508425Smax.romanov@nginx.com if (rc != NULL && ra->app_port != NULL) { 509425Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, engine->port, rc, ra->app_port->pid); 510425Smax.romanov@nginx.com } 511425Smax.romanov@nginx.com 512425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 513425Smax.romanov@nginx.com } 514425Smax.romanov@nginx.com 515425Smax.romanov@nginx.com 516425Smax.romanov@nginx.com static void 517425Smax.romanov@nginx.com nxt_router_ra_release(nxt_task_t *task, nxt_req_app_link_t *ra) 518425Smax.romanov@nginx.com { 519431Sigor@sysoev.ru nxt_mp_t *mp; 520431Sigor@sysoev.ru nxt_req_conn_link_t *rc; 521425Smax.romanov@nginx.com 522425Smax.romanov@nginx.com nxt_assert(task->thread->engine == ra->work.data); 523425Smax.romanov@nginx.com nxt_assert(ra->use_count == 0); 524425Smax.romanov@nginx.com 525343Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD release", ra->stream); 526343Smax.romanov@nginx.com 527343Smax.romanov@nginx.com rc = ra->rc; 528343Smax.romanov@nginx.com 529343Smax.romanov@nginx.com if (rc != NULL) { 530423Smax.romanov@nginx.com if (nxt_slow_path(ra->err_code != 0)) { 531431Sigor@sysoev.ru nxt_http_request_error(task, rc->ap->request, ra->err_code); 532423Smax.romanov@nginx.com 533423Smax.romanov@nginx.com } else { 534423Smax.romanov@nginx.com rc->app_port = ra->app_port; 535423Smax.romanov@nginx.com rc->msg_info = ra->msg_info; 536423Smax.romanov@nginx.com 537425Smax.romanov@nginx.com if (rc->app->timeout != 0) { 538431Sigor@sysoev.ru rc->ap->timer.handler = nxt_router_app_timeout; 539431Sigor@sysoev.ru nxt_timer_add(task->thread->engine, &rc->ap->timer, 540425Smax.romanov@nginx.com rc->app->timeout); 541425Smax.romanov@nginx.com } 542425Smax.romanov@nginx.com 543423Smax.romanov@nginx.com ra->app_port = NULL; 544423Smax.romanov@nginx.com ra->msg_info.buf = NULL; 545423Smax.romanov@nginx.com } 546343Smax.romanov@nginx.com 547343Smax.romanov@nginx.com rc->ra = NULL; 548343Smax.romanov@nginx.com ra->rc = NULL; 549343Smax.romanov@nginx.com } 550343Smax.romanov@nginx.com 551343Smax.romanov@nginx.com if (ra->app_port != NULL) { 552343Smax.romanov@nginx.com nxt_router_app_port_release(task, ra->app_port, 0, 1); 553343Smax.romanov@nginx.com 554343Smax.romanov@nginx.com ra->app_port = NULL; 555167Smax.romanov@nginx.com } 556167Smax.romanov@nginx.com 557423Smax.romanov@nginx.com nxt_router_msg_cancel(task, &ra->msg_info, ra->stream); 558423Smax.romanov@nginx.com 559430Sigor@sysoev.ru mp = ra->mem_pool; 560430Sigor@sysoev.ru 561430Sigor@sysoev.ru if (mp != NULL) { 562430Sigor@sysoev.ru nxt_mp_free(mp, ra); 563430Sigor@sysoev.ru nxt_mp_release(mp); 564351Smax.romanov@nginx.com } 565167Smax.romanov@nginx.com } 566167Smax.romanov@nginx.com 567167Smax.romanov@nginx.com 568425Smax.romanov@nginx.com static void 569425Smax.romanov@nginx.com nxt_router_ra_release_handler(nxt_task_t *task, void *obj, void *data) 570425Smax.romanov@nginx.com { 571425Smax.romanov@nginx.com nxt_req_app_link_t *ra; 572425Smax.romanov@nginx.com 573425Smax.romanov@nginx.com ra = obj; 574425Smax.romanov@nginx.com 575425Smax.romanov@nginx.com nxt_assert(ra->work.data == data); 576425Smax.romanov@nginx.com 577425Smax.romanov@nginx.com nxt_atomic_fetch_add(&ra->use_count, -1); 578425Smax.romanov@nginx.com 579425Smax.romanov@nginx.com nxt_router_ra_release(task, ra); 580425Smax.romanov@nginx.com } 581425Smax.romanov@nginx.com 582425Smax.romanov@nginx.com 583425Smax.romanov@nginx.com static void 584425Smax.romanov@nginx.com nxt_router_ra_use(nxt_task_t *task, nxt_req_app_link_t *ra, int i) 585425Smax.romanov@nginx.com { 586425Smax.romanov@nginx.com int c; 587425Smax.romanov@nginx.com nxt_event_engine_t *engine; 588425Smax.romanov@nginx.com 589425Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&ra->use_count, i); 590425Smax.romanov@nginx.com 591425Smax.romanov@nginx.com if (i < 0 && c == -i) { 592425Smax.romanov@nginx.com engine = ra->work.data; 593425Smax.romanov@nginx.com 594425Smax.romanov@nginx.com if (task->thread->engine == engine) { 595425Smax.romanov@nginx.com nxt_router_ra_release(task, ra); 596425Smax.romanov@nginx.com 597425Smax.romanov@nginx.com return; 598425Smax.romanov@nginx.com } 599425Smax.romanov@nginx.com 600425Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 601425Smax.romanov@nginx.com 602425Smax.romanov@nginx.com ra->work.handler = nxt_router_ra_release_handler; 603425Smax.romanov@nginx.com ra->work.task = &engine->task; 604425Smax.romanov@nginx.com ra->work.next = NULL; 605425Smax.romanov@nginx.com 606425Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD post release to %p", 607425Smax.romanov@nginx.com ra->stream, engine); 608425Smax.romanov@nginx.com 609425Smax.romanov@nginx.com nxt_event_engine_post(engine, &ra->work); 610425Smax.romanov@nginx.com } 611425Smax.romanov@nginx.com } 612425Smax.romanov@nginx.com 613425Smax.romanov@nginx.com 614423Smax.romanov@nginx.com nxt_inline void 615423Smax.romanov@nginx.com nxt_router_ra_error(nxt_req_app_link_t *ra, int code, const char* str) 616345Smax.romanov@nginx.com { 617423Smax.romanov@nginx.com ra->app_port = NULL; 618423Smax.romanov@nginx.com ra->err_code = code; 619423Smax.romanov@nginx.com ra->err_str = str; 620345Smax.romanov@nginx.com } 621345Smax.romanov@nginx.com 622345Smax.romanov@nginx.com 623427Smax.romanov@nginx.com nxt_inline void 624427Smax.romanov@nginx.com nxt_router_ra_pending(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra) 625427Smax.romanov@nginx.com { 626427Smax.romanov@nginx.com nxt_queue_insert_tail(&ra->app_port->pending_requests, 627427Smax.romanov@nginx.com &ra->link_port_pending); 628427Smax.romanov@nginx.com nxt_queue_insert_tail(&app->pending, &ra->link_app_pending); 629427Smax.romanov@nginx.com 630427Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 631427Smax.romanov@nginx.com 632427Smax.romanov@nginx.com ra->res_time = nxt_thread_monotonic_time(task->thread) + app->res_timeout; 633427Smax.romanov@nginx.com 634427Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD enqueue to pending_requests", ra->stream); 635427Smax.romanov@nginx.com } 636427Smax.romanov@nginx.com 637427Smax.romanov@nginx.com 638425Smax.romanov@nginx.com nxt_inline nxt_bool_t 639425Smax.romanov@nginx.com nxt_queue_chk_remove(nxt_queue_link_t *lnk) 640425Smax.romanov@nginx.com { 641425Smax.romanov@nginx.com if (lnk->next != NULL) { 642425Smax.romanov@nginx.com nxt_queue_remove(lnk); 643425Smax.romanov@nginx.com 644425Smax.romanov@nginx.com lnk->next = NULL; 645425Smax.romanov@nginx.com 646425Smax.romanov@nginx.com return 1; 647425Smax.romanov@nginx.com } 648425Smax.romanov@nginx.com 649425Smax.romanov@nginx.com return 0; 650425Smax.romanov@nginx.com } 651425Smax.romanov@nginx.com 652425Smax.romanov@nginx.com 653343Smax.romanov@nginx.com nxt_inline void 654343Smax.romanov@nginx.com nxt_router_rc_unlink(nxt_task_t *task, nxt_req_conn_link_t *rc) 655343Smax.romanov@nginx.com { 656425Smax.romanov@nginx.com int ra_use_delta; 657343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 658343Smax.romanov@nginx.com 659343Smax.romanov@nginx.com if (rc->app_port != NULL) { 660343Smax.romanov@nginx.com nxt_router_app_port_release(task, rc->app_port, 0, 1); 661343Smax.romanov@nginx.com 662343Smax.romanov@nginx.com rc->app_port = NULL; 663343Smax.romanov@nginx.com } 664343Smax.romanov@nginx.com 665423Smax.romanov@nginx.com nxt_router_msg_cancel(task, &rc->msg_info, rc->stream); 666423Smax.romanov@nginx.com 667343Smax.romanov@nginx.com ra = rc->ra; 668343Smax.romanov@nginx.com 669343Smax.romanov@nginx.com if (ra != NULL) { 670343Smax.romanov@nginx.com rc->ra = NULL; 671343Smax.romanov@nginx.com ra->rc = NULL; 672343Smax.romanov@nginx.com 673425Smax.romanov@nginx.com ra_use_delta = 0; 674425Smax.romanov@nginx.com 675343Smax.romanov@nginx.com nxt_thread_mutex_lock(&rc->app->mutex); 676343Smax.romanov@nginx.com 677425Smax.romanov@nginx.com if (ra->link_app_requests.next == NULL 678427Smax.romanov@nginx.com && ra->link_port_pending.next == NULL 679427Smax.romanov@nginx.com && ra->link_app_pending.next == NULL) 680425Smax.romanov@nginx.com { 681425Smax.romanov@nginx.com ra = NULL; 682343Smax.romanov@nginx.com 683343Smax.romanov@nginx.com } else { 684425Smax.romanov@nginx.com ra_use_delta -= nxt_queue_chk_remove(&ra->link_app_requests); 685425Smax.romanov@nginx.com ra_use_delta -= nxt_queue_chk_remove(&ra->link_port_pending); 686427Smax.romanov@nginx.com nxt_queue_chk_remove(&ra->link_app_pending); 687343Smax.romanov@nginx.com } 688343Smax.romanov@nginx.com 689343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&rc->app->mutex); 690425Smax.romanov@nginx.com 691425Smax.romanov@nginx.com if (ra != NULL) { 692425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, ra_use_delta); 693425Smax.romanov@nginx.com } 694343Smax.romanov@nginx.com } 695343Smax.romanov@nginx.com 696343Smax.romanov@nginx.com if (rc->app != NULL) { 697343Smax.romanov@nginx.com nxt_router_app_use(task, rc->app, -1); 698343Smax.romanov@nginx.com 699343Smax.romanov@nginx.com rc->app = NULL; 700343Smax.romanov@nginx.com } 701343Smax.romanov@nginx.com 702346Smax.romanov@nginx.com if (rc->ap != NULL) { 703346Smax.romanov@nginx.com nxt_app_http_req_done(task, rc->ap); 704346Smax.romanov@nginx.com 705346Smax.romanov@nginx.com rc->ap = NULL; 706346Smax.romanov@nginx.com } 707343Smax.romanov@nginx.com } 708343Smax.romanov@nginx.com 709343Smax.romanov@nginx.com 710141Smax.romanov@nginx.com void 711141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 712141Smax.romanov@nginx.com { 713141Smax.romanov@nginx.com nxt_port_new_port_handler(task, msg); 714141Smax.romanov@nginx.com 715192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 716141Smax.romanov@nginx.com return; 717141Smax.romanov@nginx.com } 718141Smax.romanov@nginx.com 719426Smax.romanov@nginx.com if (msg->u.new_port == NULL 720426Smax.romanov@nginx.com || msg->u.new_port->type != NXT_PROCESS_WORKER) 721347Smax.romanov@nginx.com { 722192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 723141Smax.romanov@nginx.com } 724192Smax.romanov@nginx.com 725192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 726141Smax.romanov@nginx.com } 727141Smax.romanov@nginx.com 728141Smax.romanov@nginx.com 729139Sigor@sysoev.ru void 730139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 731115Sigor@sysoev.ru { 732198Sigor@sysoev.ru nxt_int_t ret; 733139Sigor@sysoev.ru nxt_buf_t *b; 734139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 735139Sigor@sysoev.ru 736139Sigor@sysoev.ru tmcf = nxt_router_temp_conf(task); 737139Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 738139Sigor@sysoev.ru return; 73953Sigor@sysoev.ru } 74053Sigor@sysoev.ru 741494Spluknet@nginx.com nxt_debug(task, "nxt_router_conf_data_handler(%O): %*s", 742423Smax.romanov@nginx.com nxt_buf_used_size(msg->buf), 743493Spluknet@nginx.com (size_t) nxt_buf_used_size(msg->buf), msg->buf->mem.pos); 744423Smax.romanov@nginx.com 745352Smax.romanov@nginx.com b = nxt_buf_chk_make_plain(tmcf->conf->mem_pool, msg->buf, msg->size); 746352Smax.romanov@nginx.com 747352Smax.romanov@nginx.com nxt_assert(b != NULL); 748352Smax.romanov@nginx.com 749139Sigor@sysoev.ru tmcf->conf->router = nxt_router; 750139Sigor@sysoev.ru tmcf->stream = msg->port_msg.stream; 751139Sigor@sysoev.ru tmcf->port = nxt_runtime_port_find(task->thread->runtime, 752198Sigor@sysoev.ru msg->port_msg.pid, 753198Sigor@sysoev.ru msg->port_msg.reply_port); 754198Sigor@sysoev.ru 755198Sigor@sysoev.ru ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free); 756198Sigor@sysoev.ru 757198Sigor@sysoev.ru if (nxt_fast_path(ret == NXT_OK)) { 758198Sigor@sysoev.ru nxt_router_conf_apply(task, tmcf, NULL); 759198Sigor@sysoev.ru 760198Sigor@sysoev.ru } else { 761198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 762139Sigor@sysoev.ru } 76353Sigor@sysoev.ru } 76453Sigor@sysoev.ru 76553Sigor@sysoev.ru 766347Smax.romanov@nginx.com static void 767507Smax.romanov@nginx.com nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port, 768507Smax.romanov@nginx.com void *data) 769347Smax.romanov@nginx.com { 770347Smax.romanov@nginx.com union { 771347Smax.romanov@nginx.com nxt_pid_t removed_pid; 772347Smax.romanov@nginx.com void *data; 773347Smax.romanov@nginx.com } u; 774347Smax.romanov@nginx.com 775347Smax.romanov@nginx.com u.data = data; 776347Smax.romanov@nginx.com 777347Smax.romanov@nginx.com nxt_port_rpc_remove_peer(task, port, u.removed_pid); 778347Smax.romanov@nginx.com } 779347Smax.romanov@nginx.com 780347Smax.romanov@nginx.com 781192Smax.romanov@nginx.com void 782192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 783192Smax.romanov@nginx.com { 784347Smax.romanov@nginx.com nxt_event_engine_t *engine; 785318Smax.romanov@nginx.com 786192Smax.romanov@nginx.com nxt_port_remove_pid_handler(task, msg); 787192Smax.romanov@nginx.com 788192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 789192Smax.romanov@nginx.com return; 790192Smax.romanov@nginx.com } 791192Smax.romanov@nginx.com 792318Smax.romanov@nginx.com nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0) 793318Smax.romanov@nginx.com { 794507Smax.romanov@nginx.com nxt_port_post(task, engine->port, nxt_router_app_process_remove_pid, 795347Smax.romanov@nginx.com msg->u.data); 796318Smax.romanov@nginx.com } 797318Smax.romanov@nginx.com nxt_queue_loop; 798318Smax.romanov@nginx.com 799192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 800192Smax.romanov@nginx.com 801192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 802192Smax.romanov@nginx.com } 803192Smax.romanov@nginx.com 804192Smax.romanov@nginx.com 80553Sigor@sysoev.ru static nxt_router_temp_conf_t * 806139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task) 80753Sigor@sysoev.ru { 80865Sigor@sysoev.ru nxt_mp_t *mp, *tmp; 80953Sigor@sysoev.ru nxt_router_conf_t *rtcf; 81053Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 81153Sigor@sysoev.ru 81265Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 81353Sigor@sysoev.ru if (nxt_slow_path(mp == NULL)) { 81453Sigor@sysoev.ru return NULL; 81553Sigor@sysoev.ru } 81653Sigor@sysoev.ru 81765Sigor@sysoev.ru rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t)); 81853Sigor@sysoev.ru if (nxt_slow_path(rtcf == NULL)) { 81953Sigor@sysoev.ru goto fail; 82053Sigor@sysoev.ru } 82153Sigor@sysoev.ru 82253Sigor@sysoev.ru rtcf->mem_pool = mp; 82353Sigor@sysoev.ru 82465Sigor@sysoev.ru tmp = nxt_mp_create(1024, 128, 256, 32); 82553Sigor@sysoev.ru if (nxt_slow_path(tmp == NULL)) { 82653Sigor@sysoev.ru goto fail; 82753Sigor@sysoev.ru } 82853Sigor@sysoev.ru 82965Sigor@sysoev.ru tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t)); 83053Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 83153Sigor@sysoev.ru goto temp_fail; 83253Sigor@sysoev.ru } 83353Sigor@sysoev.ru 83453Sigor@sysoev.ru tmcf->mem_pool = tmp; 83553Sigor@sysoev.ru tmcf->conf = rtcf; 836139Sigor@sysoev.ru tmcf->count = 1; 837139Sigor@sysoev.ru tmcf->engine = task->thread->engine; 83853Sigor@sysoev.ru 83953Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, 4, 84053Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 84153Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 84253Sigor@sysoev.ru goto temp_fail; 84353Sigor@sysoev.ru } 84453Sigor@sysoev.ru 84553Sigor@sysoev.ru nxt_queue_init(&tmcf->deleting); 84653Sigor@sysoev.ru nxt_queue_init(&tmcf->keeping); 84753Sigor@sysoev.ru nxt_queue_init(&tmcf->updating); 84853Sigor@sysoev.ru nxt_queue_init(&tmcf->pending); 84953Sigor@sysoev.ru nxt_queue_init(&tmcf->creating); 850416Smax.romanov@nginx.com 851133Sigor@sysoev.ru nxt_queue_init(&tmcf->apps); 852133Sigor@sysoev.ru nxt_queue_init(&tmcf->previous); 85353Sigor@sysoev.ru 85453Sigor@sysoev.ru return tmcf; 85553Sigor@sysoev.ru 85653Sigor@sysoev.ru temp_fail: 85753Sigor@sysoev.ru 85865Sigor@sysoev.ru nxt_mp_destroy(tmp); 85953Sigor@sysoev.ru 86053Sigor@sysoev.ru fail: 86153Sigor@sysoev.ru 86265Sigor@sysoev.ru nxt_mp_destroy(mp); 86353Sigor@sysoev.ru 86453Sigor@sysoev.ru return NULL; 86553Sigor@sysoev.ru } 86653Sigor@sysoev.ru 86753Sigor@sysoev.ru 868507Smax.romanov@nginx.com nxt_inline nxt_bool_t 869507Smax.romanov@nginx.com nxt_router_app_can_start(nxt_app_t *app) 870507Smax.romanov@nginx.com { 871507Smax.romanov@nginx.com return app->processes + app->pending_processes < app->max_processes 872507Smax.romanov@nginx.com && app->pending_processes < app->max_pending_processes; 873507Smax.romanov@nginx.com } 874507Smax.romanov@nginx.com 875507Smax.romanov@nginx.com 876507Smax.romanov@nginx.com nxt_inline nxt_bool_t 877507Smax.romanov@nginx.com nxt_router_app_need_start(nxt_app_t *app) 878507Smax.romanov@nginx.com { 879507Smax.romanov@nginx.com return app->idle_processes + app->pending_processes 880507Smax.romanov@nginx.com < app->spare_processes; 881507Smax.romanov@nginx.com } 882507Smax.romanov@nginx.com 883507Smax.romanov@nginx.com 884198Sigor@sysoev.ru static void 885198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data) 886139Sigor@sysoev.ru { 887139Sigor@sysoev.ru nxt_int_t ret; 888507Smax.romanov@nginx.com nxt_app_t *app; 889139Sigor@sysoev.ru nxt_router_t *router; 890139Sigor@sysoev.ru nxt_runtime_t *rt; 891198Sigor@sysoev.ru nxt_queue_link_t *qlk; 892198Sigor@sysoev.ru nxt_socket_conf_t *skcf; 893198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 894139Sigor@sysoev.ru const nxt_event_interface_t *interface; 895139Sigor@sysoev.ru 896198Sigor@sysoev.ru tmcf = obj; 897198Sigor@sysoev.ru 898198Sigor@sysoev.ru qlk = nxt_queue_first(&tmcf->pending); 899198Sigor@sysoev.ru 900198Sigor@sysoev.ru if (qlk != nxt_queue_tail(&tmcf->pending)) { 901198Sigor@sysoev.ru nxt_queue_remove(qlk); 902198Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->creating, qlk); 903198Sigor@sysoev.ru 904198Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 905198Sigor@sysoev.ru 906198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(task, tmcf, skcf); 907198Sigor@sysoev.ru 908198Sigor@sysoev.ru return; 909139Sigor@sysoev.ru } 910139Sigor@sysoev.ru 911507Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 912507Smax.romanov@nginx.com 913507Smax.romanov@nginx.com if (nxt_router_app_need_start(app)) { 914507Smax.romanov@nginx.com nxt_router_app_rpc_create(task, tmcf, app); 915507Smax.romanov@nginx.com return; 916507Smax.romanov@nginx.com } 917507Smax.romanov@nginx.com 918507Smax.romanov@nginx.com } nxt_queue_loop; 919507Smax.romanov@nginx.com 920139Sigor@sysoev.ru rt = task->thread->runtime; 921139Sigor@sysoev.ru 922139Sigor@sysoev.ru interface = nxt_service_get(rt->services, "engine", NULL); 923139Sigor@sysoev.ru 924198Sigor@sysoev.ru router = tmcf->conf->router; 925198Sigor@sysoev.ru 926139Sigor@sysoev.ru ret = nxt_router_engines_create(task, router, tmcf, interface); 927139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 928198Sigor@sysoev.ru goto fail; 929139Sigor@sysoev.ru } 930139Sigor@sysoev.ru 931139Sigor@sysoev.ru ret = nxt_router_threads_create(task, rt, tmcf); 932139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 933198Sigor@sysoev.ru goto fail; 934139Sigor@sysoev.ru } 935139Sigor@sysoev.ru 936343Smax.romanov@nginx.com nxt_router_apps_sort(task, router, tmcf); 937139Sigor@sysoev.ru 938315Sigor@sysoev.ru nxt_router_engines_post(router, tmcf); 939139Sigor@sysoev.ru 940139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->updating); 941139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->creating); 942139Sigor@sysoev.ru 943198Sigor@sysoev.ru nxt_router_conf_ready(task, tmcf); 944198Sigor@sysoev.ru 945198Sigor@sysoev.ru return; 946198Sigor@sysoev.ru 947198Sigor@sysoev.ru fail: 948198Sigor@sysoev.ru 949198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 950198Sigor@sysoev.ru 951198Sigor@sysoev.ru return; 952139Sigor@sysoev.ru } 953139Sigor@sysoev.ru 954139Sigor@sysoev.ru 955139Sigor@sysoev.ru static void 956139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data) 957139Sigor@sysoev.ru { 958153Sigor@sysoev.ru nxt_joint_job_t *job; 959153Sigor@sysoev.ru 960153Sigor@sysoev.ru job = obj; 961153Sigor@sysoev.ru 962198Sigor@sysoev.ru nxt_router_conf_ready(task, job->tmcf); 963139Sigor@sysoev.ru } 964139Sigor@sysoev.ru 965139Sigor@sysoev.ru 966139Sigor@sysoev.ru static void 967198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 968139Sigor@sysoev.ru { 969139Sigor@sysoev.ru nxt_debug(task, "temp conf count:%D", tmcf->count); 970139Sigor@sysoev.ru 971139Sigor@sysoev.ru if (--tmcf->count == 0) { 972193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST); 973139Sigor@sysoev.ru } 974139Sigor@sysoev.ru } 975139Sigor@sysoev.ru 976139Sigor@sysoev.ru 977139Sigor@sysoev.ru static void 978139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 979139Sigor@sysoev.ru { 980507Smax.romanov@nginx.com nxt_app_t *app; 981148Sigor@sysoev.ru nxt_socket_t s; 982149Sigor@sysoev.ru nxt_router_t *router; 983148Sigor@sysoev.ru nxt_queue_link_t *qlk; 984148Sigor@sysoev.ru nxt_socket_conf_t *skcf; 985148Sigor@sysoev.ru 986198Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "failed to apply new conf"); 987198Sigor@sysoev.ru 988148Sigor@sysoev.ru for (qlk = nxt_queue_first(&tmcf->creating); 989148Sigor@sysoev.ru qlk != nxt_queue_tail(&tmcf->creating); 990148Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 991148Sigor@sysoev.ru { 992148Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 993359Sigor@sysoev.ru s = skcf->listen->socket; 994148Sigor@sysoev.ru 995148Sigor@sysoev.ru if (s != -1) { 996148Sigor@sysoev.ru nxt_socket_close(task, s); 997148Sigor@sysoev.ru } 998148Sigor@sysoev.ru 999359Sigor@sysoev.ru nxt_free(skcf->listen); 1000148Sigor@sysoev.ru } 1001148Sigor@sysoev.ru 1002507Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1003507Smax.romanov@nginx.com 1004507Smax.romanov@nginx.com nxt_router_app_quit(task, app); 1005507Smax.romanov@nginx.com 1006507Smax.romanov@nginx.com } nxt_queue_loop; 1007507Smax.romanov@nginx.com 1008149Sigor@sysoev.ru router = tmcf->conf->router; 1009149Sigor@sysoev.ru 1010149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->keeping); 1011149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->deleting); 1012149Sigor@sysoev.ru 1013416Smax.romanov@nginx.com nxt_queue_add(&router->apps, &tmcf->previous); 1014416Smax.romanov@nginx.com 1015148Sigor@sysoev.ru // TODO: new engines and threads 1016148Sigor@sysoev.ru 1017139Sigor@sysoev.ru nxt_mp_destroy(tmcf->conf->mem_pool); 1018139Sigor@sysoev.ru 1019193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR); 1020139Sigor@sysoev.ru } 1021139Sigor@sysoev.ru 1022139Sigor@sysoev.ru 1023139Sigor@sysoev.ru static void 1024139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1025193Smax.romanov@nginx.com nxt_port_msg_type_t type) 1026139Sigor@sysoev.ru { 1027193Smax.romanov@nginx.com nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL); 1028139Sigor@sysoev.ru } 1029139Sigor@sysoev.ru 1030139Sigor@sysoev.ru 1031115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_conf[] = { 1032115Sigor@sysoev.ru { 1033133Sigor@sysoev.ru nxt_string("listeners_threads"), 1034115Sigor@sysoev.ru NXT_CONF_MAP_INT32, 1035115Sigor@sysoev.ru offsetof(nxt_router_conf_t, threads), 1036115Sigor@sysoev.ru }, 1037115Sigor@sysoev.ru }; 1038115Sigor@sysoev.ru 1039115Sigor@sysoev.ru 1040133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_app_conf[] = { 1041115Sigor@sysoev.ru { 1042133Sigor@sysoev.ru nxt_string("type"), 1043115Sigor@sysoev.ru NXT_CONF_MAP_STR, 1044133Sigor@sysoev.ru offsetof(nxt_router_app_conf_t, type), 1045115Sigor@sysoev.ru }, 1046115Sigor@sysoev.ru 1047115Sigor@sysoev.ru { 1048507Smax.romanov@nginx.com nxt_string("limits"), 1049507Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 1050507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, limits_value), 1051133Sigor@sysoev.ru }, 1052318Smax.romanov@nginx.com 1053318Smax.romanov@nginx.com { 1054507Smax.romanov@nginx.com nxt_string("processes"), 1055507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1056507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, processes), 1057507Smax.romanov@nginx.com }, 1058507Smax.romanov@nginx.com 1059507Smax.romanov@nginx.com { 1060507Smax.romanov@nginx.com nxt_string("processes"), 1061318Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 1062507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, processes_value), 1063318Smax.romanov@nginx.com }, 1064318Smax.romanov@nginx.com }; 1065318Smax.romanov@nginx.com 1066318Smax.romanov@nginx.com 1067318Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_limits_conf[] = { 1068318Smax.romanov@nginx.com { 1069318Smax.romanov@nginx.com nxt_string("timeout"), 1070318Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1071318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, timeout), 1072318Smax.romanov@nginx.com }, 1073318Smax.romanov@nginx.com 1074318Smax.romanov@nginx.com { 1075427Smax.romanov@nginx.com nxt_string("reschedule_timeout"), 1076427Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1077427Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, res_timeout), 1078427Smax.romanov@nginx.com }, 1079427Smax.romanov@nginx.com 1080427Smax.romanov@nginx.com { 1081318Smax.romanov@nginx.com nxt_string("requests"), 1082318Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1083318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, requests), 1084318Smax.romanov@nginx.com }, 1085133Sigor@sysoev.ru }; 1086133Sigor@sysoev.ru 1087133Sigor@sysoev.ru 1088507Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_processes_conf[] = { 1089507Smax.romanov@nginx.com { 1090507Smax.romanov@nginx.com nxt_string("spare"), 1091507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1092507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, spare_processes), 1093507Smax.romanov@nginx.com }, 1094507Smax.romanov@nginx.com 1095507Smax.romanov@nginx.com { 1096507Smax.romanov@nginx.com nxt_string("max"), 1097507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1098507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, max_processes), 1099507Smax.romanov@nginx.com }, 1100507Smax.romanov@nginx.com 1101507Smax.romanov@nginx.com { 1102507Smax.romanov@nginx.com nxt_string("idle_timeout"), 1103507Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1104507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, idle_timeout), 1105507Smax.romanov@nginx.com }, 1106507Smax.romanov@nginx.com }; 1107507Smax.romanov@nginx.com 1108507Smax.romanov@nginx.com 1109133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_listener_conf[] = { 1110133Sigor@sysoev.ru { 1111133Sigor@sysoev.ru nxt_string("application"), 1112133Sigor@sysoev.ru NXT_CONF_MAP_STR, 1113133Sigor@sysoev.ru offsetof(nxt_router_listener_conf_t, application), 1114115Sigor@sysoev.ru }, 1115115Sigor@sysoev.ru }; 1116115Sigor@sysoev.ru 1117115Sigor@sysoev.ru 1118115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_http_conf[] = { 1119115Sigor@sysoev.ru { 1120115Sigor@sysoev.ru nxt_string("header_buffer_size"), 1121115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 1122115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_buffer_size), 1123115Sigor@sysoev.ru }, 1124115Sigor@sysoev.ru 1125115Sigor@sysoev.ru { 1126115Sigor@sysoev.ru nxt_string("large_header_buffer_size"), 1127115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 1128115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, large_header_buffer_size), 1129115Sigor@sysoev.ru }, 1130115Sigor@sysoev.ru 1131115Sigor@sysoev.ru { 1132206Smax.romanov@nginx.com nxt_string("large_header_buffers"), 1133206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1134206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, large_header_buffers), 1135206Smax.romanov@nginx.com }, 1136206Smax.romanov@nginx.com 1137206Smax.romanov@nginx.com { 1138206Smax.romanov@nginx.com nxt_string("body_buffer_size"), 1139206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1140206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_buffer_size), 1141206Smax.romanov@nginx.com }, 1142206Smax.romanov@nginx.com 1143206Smax.romanov@nginx.com { 1144206Smax.romanov@nginx.com nxt_string("max_body_size"), 1145206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1146206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, max_body_size), 1147206Smax.romanov@nginx.com }, 1148206Smax.romanov@nginx.com 1149206Smax.romanov@nginx.com { 1150431Sigor@sysoev.ru nxt_string("idle_timeout"), 1151431Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1152431Sigor@sysoev.ru offsetof(nxt_socket_conf_t, idle_timeout), 1153431Sigor@sysoev.ru }, 1154431Sigor@sysoev.ru 1155431Sigor@sysoev.ru { 1156115Sigor@sysoev.ru nxt_string("header_read_timeout"), 1157115Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1158115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_read_timeout), 1159115Sigor@sysoev.ru }, 1160206Smax.romanov@nginx.com 1161206Smax.romanov@nginx.com { 1162206Smax.romanov@nginx.com nxt_string("body_read_timeout"), 1163206Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1164206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_read_timeout), 1165206Smax.romanov@nginx.com }, 1166431Sigor@sysoev.ru 1167431Sigor@sysoev.ru { 1168431Sigor@sysoev.ru nxt_string("send_timeout"), 1169431Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1170431Sigor@sysoev.ru offsetof(nxt_socket_conf_t, send_timeout), 1171431Sigor@sysoev.ru }, 1172115Sigor@sysoev.ru }; 1173115Sigor@sysoev.ru 1174115Sigor@sysoev.ru 117553Sigor@sysoev.ru static nxt_int_t 1176115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1177115Sigor@sysoev.ru u_char *start, u_char *end) 117853Sigor@sysoev.ru { 1179133Sigor@sysoev.ru u_char *p; 1180133Sigor@sysoev.ru size_t size; 1181115Sigor@sysoev.ru nxt_mp_t *mp; 1182115Sigor@sysoev.ru uint32_t next; 1183115Sigor@sysoev.ru nxt_int_t ret; 1184115Sigor@sysoev.ru nxt_str_t name; 1185133Sigor@sysoev.ru nxt_app_t *app, *prev; 1186359Sigor@sysoev.ru nxt_router_t *router; 1187133Sigor@sysoev.ru nxt_conf_value_t *conf, *http; 1188133Sigor@sysoev.ru nxt_conf_value_t *applications, *application; 1189133Sigor@sysoev.ru nxt_conf_value_t *listeners, *listener; 1190115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1191507Smax.romanov@nginx.com nxt_event_engine_t *engine; 1192216Sigor@sysoev.ru nxt_app_lang_module_t *lang; 1193133Sigor@sysoev.ru nxt_router_app_conf_t apcf; 1194115Sigor@sysoev.ru nxt_router_listener_conf_t lscf; 1195115Sigor@sysoev.ru 1196115Sigor@sysoev.ru static nxt_str_t http_path = nxt_string("/http"); 1197133Sigor@sysoev.ru static nxt_str_t applications_path = nxt_string("/applications"); 1198115Sigor@sysoev.ru static nxt_str_t listeners_path = nxt_string("/listeners"); 1199115Sigor@sysoev.ru 1200208Svbart@nginx.com conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL); 1201115Sigor@sysoev.ru if (conf == NULL) { 1202115Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "configuration parsing error"); 1203115Sigor@sysoev.ru return NXT_ERROR; 1204115Sigor@sysoev.ru } 1205115Sigor@sysoev.ru 1206213Svbart@nginx.com mp = tmcf->conf->mem_pool; 1207213Svbart@nginx.com 1208213Svbart@nginx.com ret = nxt_conf_map_object(mp, conf, nxt_router_conf, 1209136Svbart@nginx.com nxt_nitems(nxt_router_conf), tmcf->conf); 1210115Sigor@sysoev.ru if (ret != NXT_OK) { 1211133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "root map error"); 1212115Sigor@sysoev.ru return NXT_ERROR; 1213115Sigor@sysoev.ru } 1214115Sigor@sysoev.ru 1215117Sigor@sysoev.ru if (tmcf->conf->threads == 0) { 1216117Sigor@sysoev.ru tmcf->conf->threads = nxt_ncpu; 1217117Sigor@sysoev.ru } 1218117Sigor@sysoev.ru 1219133Sigor@sysoev.ru applications = nxt_conf_get_path(conf, &applications_path); 1220133Sigor@sysoev.ru if (applications == NULL) { 1221133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block"); 1222115Sigor@sysoev.ru return NXT_ERROR; 1223115Sigor@sysoev.ru } 1224115Sigor@sysoev.ru 1225359Sigor@sysoev.ru router = tmcf->conf->router; 1226359Sigor@sysoev.ru 1227133Sigor@sysoev.ru next = 0; 1228133Sigor@sysoev.ru 1229133Sigor@sysoev.ru for ( ;; ) { 1230133Sigor@sysoev.ru application = nxt_conf_next_object_member(applications, &name, &next); 1231133Sigor@sysoev.ru if (application == NULL) { 1232133Sigor@sysoev.ru break; 1233133Sigor@sysoev.ru } 1234133Sigor@sysoev.ru 1235133Sigor@sysoev.ru nxt_debug(task, "application \"%V\"", &name); 1236133Sigor@sysoev.ru 1237144Smax.romanov@nginx.com size = nxt_conf_json_length(application, NULL); 1238144Smax.romanov@nginx.com 1239144Smax.romanov@nginx.com app = nxt_malloc(sizeof(nxt_app_t) + name.length + size); 1240133Sigor@sysoev.ru if (app == NULL) { 1241133Sigor@sysoev.ru goto fail; 1242133Sigor@sysoev.ru } 1243133Sigor@sysoev.ru 1244144Smax.romanov@nginx.com nxt_memzero(app, sizeof(nxt_app_t)); 1245144Smax.romanov@nginx.com 1246144Smax.romanov@nginx.com app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t)); 1247144Smax.romanov@nginx.com app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length); 1248133Sigor@sysoev.ru 1249133Sigor@sysoev.ru p = nxt_conf_json_print(app->conf.start, application, NULL); 1250133Sigor@sysoev.ru app->conf.length = p - app->conf.start; 1251133Sigor@sysoev.ru 1252144Smax.romanov@nginx.com nxt_assert(app->conf.length <= size); 1253144Smax.romanov@nginx.com 1254133Sigor@sysoev.ru nxt_debug(task, "application conf \"%V\"", &app->conf); 1255133Sigor@sysoev.ru 1256359Sigor@sysoev.ru prev = nxt_router_app_find(&router->apps, &name); 1257133Sigor@sysoev.ru 1258133Sigor@sysoev.ru if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) { 1259133Sigor@sysoev.ru nxt_free(app); 1260133Sigor@sysoev.ru 1261133Sigor@sysoev.ru nxt_queue_remove(&prev->link); 1262133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->previous, &prev->link); 1263133Sigor@sysoev.ru continue; 1264133Sigor@sysoev.ru } 1265133Sigor@sysoev.ru 1266507Smax.romanov@nginx.com apcf.processes = 1; 1267507Smax.romanov@nginx.com apcf.max_processes = 1; 1268507Smax.romanov@nginx.com apcf.spare_processes = 1; 1269318Smax.romanov@nginx.com apcf.timeout = 0; 1270427Smax.romanov@nginx.com apcf.res_timeout = 1000; 1271507Smax.romanov@nginx.com apcf.idle_timeout = 15000; 1272318Smax.romanov@nginx.com apcf.requests = 0; 1273318Smax.romanov@nginx.com apcf.limits_value = NULL; 1274507Smax.romanov@nginx.com apcf.processes_value = NULL; 1275263Smax.romanov@nginx.com 1276213Svbart@nginx.com ret = nxt_conf_map_object(mp, application, nxt_router_app_conf, 1277136Svbart@nginx.com nxt_nitems(nxt_router_app_conf), &apcf); 1278133Sigor@sysoev.ru if (ret != NXT_OK) { 1279133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "application map error"); 1280133Sigor@sysoev.ru goto app_fail; 1281133Sigor@sysoev.ru } 1282115Sigor@sysoev.ru 1283318Smax.romanov@nginx.com if (apcf.limits_value != NULL) { 1284318Smax.romanov@nginx.com 1285318Smax.romanov@nginx.com if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) { 1286318Smax.romanov@nginx.com nxt_log(task, NXT_LOG_CRIT, "application limits is not object"); 1287318Smax.romanov@nginx.com goto app_fail; 1288318Smax.romanov@nginx.com } 1289318Smax.romanov@nginx.com 1290318Smax.romanov@nginx.com ret = nxt_conf_map_object(mp, apcf.limits_value, 1291318Smax.romanov@nginx.com nxt_router_app_limits_conf, 1292318Smax.romanov@nginx.com nxt_nitems(nxt_router_app_limits_conf), 1293318Smax.romanov@nginx.com &apcf); 1294318Smax.romanov@nginx.com if (ret != NXT_OK) { 1295318Smax.romanov@nginx.com nxt_log(task, NXT_LOG_CRIT, "application limits map error"); 1296318Smax.romanov@nginx.com goto app_fail; 1297318Smax.romanov@nginx.com } 1298318Smax.romanov@nginx.com } 1299318Smax.romanov@nginx.com 1300507Smax.romanov@nginx.com if (apcf.processes_value != NULL 1301507Smax.romanov@nginx.com && nxt_conf_type(apcf.processes_value) == NXT_CONF_OBJECT) 1302507Smax.romanov@nginx.com { 1303507Smax.romanov@nginx.com ret = nxt_conf_map_object(mp, apcf.processes_value, 1304507Smax.romanov@nginx.com nxt_router_app_processes_conf, 1305507Smax.romanov@nginx.com nxt_nitems(nxt_router_app_processes_conf), 1306507Smax.romanov@nginx.com &apcf); 1307507Smax.romanov@nginx.com if (ret != NXT_OK) { 1308507Smax.romanov@nginx.com nxt_log(task, NXT_LOG_CRIT, "application processes map error"); 1309507Smax.romanov@nginx.com goto app_fail; 1310507Smax.romanov@nginx.com } 1311507Smax.romanov@nginx.com 1312507Smax.romanov@nginx.com } else { 1313507Smax.romanov@nginx.com apcf.max_processes = apcf.processes; 1314507Smax.romanov@nginx.com apcf.spare_processes = apcf.processes; 1315507Smax.romanov@nginx.com } 1316507Smax.romanov@nginx.com 1317133Sigor@sysoev.ru nxt_debug(task, "application type: %V", &apcf.type); 1318507Smax.romanov@nginx.com nxt_debug(task, "application processes: %D", apcf.processes); 1319507Smax.romanov@nginx.com nxt_debug(task, "application request timeout: %M", apcf.timeout); 1320507Smax.romanov@nginx.com nxt_debug(task, "application reschedule timeout: %M", apcf.res_timeout); 1321318Smax.romanov@nginx.com nxt_debug(task, "application requests: %D", apcf.requests); 1322133Sigor@sysoev.ru 1323216Sigor@sysoev.ru lang = nxt_app_lang_module(task->thread->runtime, &apcf.type); 1324216Sigor@sysoev.ru 1325216Sigor@sysoev.ru if (lang == NULL) { 1326141Smax.romanov@nginx.com nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"", 1327141Smax.romanov@nginx.com &apcf.type); 1328141Smax.romanov@nginx.com goto app_fail; 1329141Smax.romanov@nginx.com } 1330141Smax.romanov@nginx.com 1331216Sigor@sysoev.ru nxt_debug(task, "application language module: \"%s\"", lang->file); 1332216Sigor@sysoev.ru 1333133Sigor@sysoev.ru ret = nxt_thread_mutex_create(&app->mutex); 1334133Sigor@sysoev.ru if (ret != NXT_OK) { 1335133Sigor@sysoev.ru goto app_fail; 1336133Sigor@sysoev.ru } 1337133Sigor@sysoev.ru 1338141Smax.romanov@nginx.com nxt_queue_init(&app->ports); 1339507Smax.romanov@nginx.com nxt_queue_init(&app->spare_ports); 1340507Smax.romanov@nginx.com nxt_queue_init(&app->idle_ports); 1341141Smax.romanov@nginx.com nxt_queue_init(&app->requests); 1342427Smax.romanov@nginx.com nxt_queue_init(&app->pending); 1343141Smax.romanov@nginx.com 1344144Smax.romanov@nginx.com app->name.length = name.length; 1345144Smax.romanov@nginx.com nxt_memcpy(app->name.start, name.start, name.length); 1346144Smax.romanov@nginx.com 1347356Svbart@nginx.com app->type = lang->type; 1348507Smax.romanov@nginx.com app->max_processes = apcf.max_processes; 1349507Smax.romanov@nginx.com app->spare_processes = apcf.spare_processes; 1350507Smax.romanov@nginx.com app->max_pending_processes = apcf.spare_processes 1351507Smax.romanov@nginx.com ? apcf.spare_processes : 1; 1352318Smax.romanov@nginx.com app->timeout = apcf.timeout; 1353427Smax.romanov@nginx.com app->res_timeout = apcf.res_timeout * 1000000; 1354507Smax.romanov@nginx.com app->idle_timeout = apcf.idle_timeout; 1355133Sigor@sysoev.ru app->live = 1; 1356343Smax.romanov@nginx.com app->max_pending_responses = 2; 1357428Smax.romanov@nginx.com app->max_requests = apcf.requests; 1358356Svbart@nginx.com app->prepare_msg = nxt_app_prepare_msg[lang->type]; 1359133Sigor@sysoev.ru 1360507Smax.romanov@nginx.com engine = task->thread->engine; 1361507Smax.romanov@nginx.com 1362507Smax.romanov@nginx.com app->engine = engine; 1363507Smax.romanov@nginx.com 1364507Smax.romanov@nginx.com app->idle_timer.precision = NXT_TIMER_DEFAULT_PRECISION; 1365507Smax.romanov@nginx.com app->idle_timer.work_queue = &engine->fast_work_queue; 1366507Smax.romanov@nginx.com app->idle_timer.handler = nxt_router_app_idle_timeout; 1367507Smax.romanov@nginx.com app->idle_timer.task = &engine->task; 1368507Smax.romanov@nginx.com app->idle_timer.log = app->idle_timer.task->log; 1369507Smax.romanov@nginx.com 1370507Smax.romanov@nginx.com app->adjust_idle_work.handler = nxt_router_adjust_idle_timer; 1371507Smax.romanov@nginx.com app->adjust_idle_work.task = &engine->task; 1372507Smax.romanov@nginx.com app->adjust_idle_work.obj = app; 1373507Smax.romanov@nginx.com 1374133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->apps, &app->link); 1375343Smax.romanov@nginx.com 1376343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 1377133Sigor@sysoev.ru } 1378133Sigor@sysoev.ru 1379133Sigor@sysoev.ru http = nxt_conf_get_path(conf, &http_path); 1380133Sigor@sysoev.ru #if 0 1381133Sigor@sysoev.ru if (http == NULL) { 1382133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "no \"http\" block"); 1383133Sigor@sysoev.ru return NXT_ERROR; 1384133Sigor@sysoev.ru } 1385133Sigor@sysoev.ru #endif 1386133Sigor@sysoev.ru 1387133Sigor@sysoev.ru listeners = nxt_conf_get_path(conf, &listeners_path); 1388115Sigor@sysoev.ru if (listeners == NULL) { 1389133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block"); 1390115Sigor@sysoev.ru return NXT_ERROR; 1391115Sigor@sysoev.ru } 139253Sigor@sysoev.ru 1393133Sigor@sysoev.ru next = 0; 139453Sigor@sysoev.ru 1395115Sigor@sysoev.ru for ( ;; ) { 1396115Sigor@sysoev.ru listener = nxt_conf_next_object_member(listeners, &name, &next); 1397115Sigor@sysoev.ru if (listener == NULL) { 1398115Sigor@sysoev.ru break; 1399115Sigor@sysoev.ru } 140053Sigor@sysoev.ru 1401359Sigor@sysoev.ru skcf = nxt_router_socket_conf(task, tmcf, &name); 1402115Sigor@sysoev.ru if (skcf == NULL) { 1403133Sigor@sysoev.ru goto fail; 1404115Sigor@sysoev.ru } 140553Sigor@sysoev.ru 1406213Svbart@nginx.com ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf, 1407136Svbart@nginx.com nxt_nitems(nxt_router_listener_conf), &lscf); 1408115Sigor@sysoev.ru if (ret != NXT_OK) { 1409115Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "listener map error"); 1410133Sigor@sysoev.ru goto fail; 1411115Sigor@sysoev.ru } 141253Sigor@sysoev.ru 1413133Sigor@sysoev.ru nxt_debug(task, "application: %V", &lscf.application); 1414133Sigor@sysoev.ru 1415133Sigor@sysoev.ru // STUB, default values if http block is not defined. 1416133Sigor@sysoev.ru skcf->header_buffer_size = 2048; 1417133Sigor@sysoev.ru skcf->large_header_buffer_size = 8192; 1418206Smax.romanov@nginx.com skcf->large_header_buffers = 4; 1419206Smax.romanov@nginx.com skcf->body_buffer_size = 16 * 1024; 1420206Smax.romanov@nginx.com skcf->max_body_size = 2 * 1024 * 1024; 1421431Sigor@sysoev.ru skcf->idle_timeout = 65000; 1422133Sigor@sysoev.ru skcf->header_read_timeout = 5000; 1423206Smax.romanov@nginx.com skcf->body_read_timeout = 5000; 1424431Sigor@sysoev.ru skcf->send_timeout = 5000; 142553Sigor@sysoev.ru 1426133Sigor@sysoev.ru if (http != NULL) { 1427213Svbart@nginx.com ret = nxt_conf_map_object(mp, http, nxt_router_http_conf, 1428136Svbart@nginx.com nxt_nitems(nxt_router_http_conf), skcf); 1429133Sigor@sysoev.ru if (ret != NXT_OK) { 1430133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "http map error"); 1431133Sigor@sysoev.ru goto fail; 1432133Sigor@sysoev.ru } 1433115Sigor@sysoev.ru } 1434115Sigor@sysoev.ru 1435431Sigor@sysoev.ru skcf->listen->handler = nxt_http_conn_init; 1436115Sigor@sysoev.ru skcf->router_conf = tmcf->conf; 1437160Sigor@sysoev.ru skcf->router_conf->count++; 1438133Sigor@sysoev.ru skcf->application = nxt_router_listener_application(tmcf, 1439133Sigor@sysoev.ru &lscf.application); 1440115Sigor@sysoev.ru } 144153Sigor@sysoev.ru 1442359Sigor@sysoev.ru nxt_queue_add(&tmcf->deleting, &router->sockets); 1443359Sigor@sysoev.ru nxt_queue_init(&router->sockets); 1444198Sigor@sysoev.ru 144553Sigor@sysoev.ru return NXT_OK; 1446133Sigor@sysoev.ru 1447133Sigor@sysoev.ru app_fail: 1448133Sigor@sysoev.ru 1449133Sigor@sysoev.ru nxt_free(app); 1450133Sigor@sysoev.ru 1451133Sigor@sysoev.ru fail: 1452133Sigor@sysoev.ru 1453141Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1454141Smax.romanov@nginx.com 1455141Smax.romanov@nginx.com nxt_queue_remove(&app->link); 1456133Sigor@sysoev.ru nxt_thread_mutex_destroy(&app->mutex); 1457133Sigor@sysoev.ru nxt_free(app); 1458141Smax.romanov@nginx.com 1459141Smax.romanov@nginx.com } nxt_queue_loop; 1460133Sigor@sysoev.ru 1461133Sigor@sysoev.ru return NXT_ERROR; 1462133Sigor@sysoev.ru } 1463133Sigor@sysoev.ru 1464133Sigor@sysoev.ru 1465133Sigor@sysoev.ru static nxt_app_t * 1466133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name) 1467133Sigor@sysoev.ru { 1468141Smax.romanov@nginx.com nxt_app_t *app; 1469141Smax.romanov@nginx.com 1470141Smax.romanov@nginx.com nxt_queue_each(app, queue, nxt_app_t, link) { 1471133Sigor@sysoev.ru 1472133Sigor@sysoev.ru if (nxt_strstr_eq(name, &app->name)) { 1473133Sigor@sysoev.ru return app; 1474133Sigor@sysoev.ru } 1475141Smax.romanov@nginx.com 1476141Smax.romanov@nginx.com } nxt_queue_loop; 1477133Sigor@sysoev.ru 1478133Sigor@sysoev.ru return NULL; 1479133Sigor@sysoev.ru } 1480133Sigor@sysoev.ru 1481133Sigor@sysoev.ru 1482133Sigor@sysoev.ru static nxt_app_t * 1483133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name) 1484133Sigor@sysoev.ru { 1485133Sigor@sysoev.ru nxt_app_t *app; 1486133Sigor@sysoev.ru 1487133Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->apps, name); 1488133Sigor@sysoev.ru 1489133Sigor@sysoev.ru if (app == NULL) { 1490134Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->previous, name); 1491133Sigor@sysoev.ru } 1492133Sigor@sysoev.ru 1493133Sigor@sysoev.ru return app; 149453Sigor@sysoev.ru } 149553Sigor@sysoev.ru 149653Sigor@sysoev.ru 149753Sigor@sysoev.ru static nxt_socket_conf_t * 1498359Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1499359Sigor@sysoev.ru nxt_str_t *name) 150053Sigor@sysoev.ru { 1501359Sigor@sysoev.ru size_t size; 1502359Sigor@sysoev.ru nxt_int_t ret; 1503359Sigor@sysoev.ru nxt_bool_t wildcard; 1504359Sigor@sysoev.ru nxt_sockaddr_t *sa; 1505359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1506359Sigor@sysoev.ru nxt_listen_socket_t *ls; 1507359Sigor@sysoev.ru 1508359Sigor@sysoev.ru sa = nxt_sockaddr_parse(tmcf->mem_pool, name); 1509359Sigor@sysoev.ru if (nxt_slow_path(sa == NULL)) { 1510359Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", name); 1511359Sigor@sysoev.ru return NULL; 1512359Sigor@sysoev.ru } 1513359Sigor@sysoev.ru 1514359Sigor@sysoev.ru sa->type = SOCK_STREAM; 1515359Sigor@sysoev.ru 1516359Sigor@sysoev.ru nxt_debug(task, "router listener: \"%*s\"", 1517493Spluknet@nginx.com (size_t) sa->length, nxt_sockaddr_start(sa)); 1518359Sigor@sysoev.ru 1519359Sigor@sysoev.ru skcf = nxt_mp_zget(tmcf->conf->mem_pool, sizeof(nxt_socket_conf_t)); 1520163Smax.romanov@nginx.com if (nxt_slow_path(skcf == NULL)) { 152153Sigor@sysoev.ru return NULL; 152253Sigor@sysoev.ru } 152353Sigor@sysoev.ru 1524359Sigor@sysoev.ru size = nxt_sockaddr_size(sa); 1525359Sigor@sysoev.ru 1526359Sigor@sysoev.ru ret = nxt_router_listen_socket_find(tmcf, skcf, sa); 1527359Sigor@sysoev.ru 1528359Sigor@sysoev.ru if (ret != NXT_OK) { 1529359Sigor@sysoev.ru 1530359Sigor@sysoev.ru ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size); 1531359Sigor@sysoev.ru if (nxt_slow_path(ls == NULL)) { 1532359Sigor@sysoev.ru return NULL; 1533359Sigor@sysoev.ru } 1534359Sigor@sysoev.ru 1535359Sigor@sysoev.ru skcf->listen = ls; 1536359Sigor@sysoev.ru 1537359Sigor@sysoev.ru ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t)); 1538359Sigor@sysoev.ru nxt_memcpy(ls->sockaddr, sa, size); 1539359Sigor@sysoev.ru 1540359Sigor@sysoev.ru nxt_listen_socket_remote_size(ls); 1541359Sigor@sysoev.ru 1542359Sigor@sysoev.ru ls->socket = -1; 1543359Sigor@sysoev.ru ls->backlog = NXT_LISTEN_BACKLOG; 1544359Sigor@sysoev.ru ls->flags = NXT_NONBLOCK; 1545359Sigor@sysoev.ru ls->read_after_accept = 1; 1546359Sigor@sysoev.ru } 1547359Sigor@sysoev.ru 1548359Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) { 1549359Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 1550359Sigor@sysoev.ru case AF_UNIX: 1551359Sigor@sysoev.ru wildcard = 0; 1552359Sigor@sysoev.ru break; 1553359Sigor@sysoev.ru #endif 1554359Sigor@sysoev.ru #if (NXT_INET6) 1555359Sigor@sysoev.ru case AF_INET6: 1556359Sigor@sysoev.ru wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr); 1557359Sigor@sysoev.ru break; 1558359Sigor@sysoev.ru #endif 1559359Sigor@sysoev.ru case AF_INET: 1560359Sigor@sysoev.ru default: 1561359Sigor@sysoev.ru wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY); 1562359Sigor@sysoev.ru break; 1563359Sigor@sysoev.ru } 1564359Sigor@sysoev.ru 1565359Sigor@sysoev.ru if (!wildcard) { 1566359Sigor@sysoev.ru skcf->sockaddr = nxt_mp_zget(tmcf->conf->mem_pool, size); 1567359Sigor@sysoev.ru if (nxt_slow_path(skcf->sockaddr == NULL)) { 1568359Sigor@sysoev.ru return NULL; 1569359Sigor@sysoev.ru } 1570359Sigor@sysoev.ru 1571359Sigor@sysoev.ru nxt_memcpy(skcf->sockaddr, sa, size); 1572359Sigor@sysoev.ru } 1573163Smax.romanov@nginx.com 1574163Smax.romanov@nginx.com return skcf; 157553Sigor@sysoev.ru } 157653Sigor@sysoev.ru 157753Sigor@sysoev.ru 1578359Sigor@sysoev.ru static nxt_int_t 1579359Sigor@sysoev.ru nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, 1580359Sigor@sysoev.ru nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa) 158153Sigor@sysoev.ru { 1582359Sigor@sysoev.ru nxt_router_t *router; 1583359Sigor@sysoev.ru nxt_queue_link_t *qlk; 1584359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1585359Sigor@sysoev.ru 1586359Sigor@sysoev.ru router = tmcf->conf->router; 1587359Sigor@sysoev.ru 1588359Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->sockets); 1589359Sigor@sysoev.ru qlk != nxt_queue_tail(&router->sockets); 1590359Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 159153Sigor@sysoev.ru { 1592359Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1593359Sigor@sysoev.ru 1594359Sigor@sysoev.ru if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) { 1595359Sigor@sysoev.ru nskcf->listen = skcf->listen; 1596359Sigor@sysoev.ru 1597359Sigor@sysoev.ru nxt_queue_remove(qlk); 1598359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->keeping, qlk); 1599359Sigor@sysoev.ru 1600359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->updating, &nskcf->link); 1601359Sigor@sysoev.ru 1602359Sigor@sysoev.ru return NXT_OK; 160353Sigor@sysoev.ru } 160453Sigor@sysoev.ru } 160553Sigor@sysoev.ru 1606359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->pending, &nskcf->link); 1607359Sigor@sysoev.ru 1608359Sigor@sysoev.ru return NXT_DECLINED; 160953Sigor@sysoev.ru } 161053Sigor@sysoev.ru 161153Sigor@sysoev.ru 1612198Sigor@sysoev.ru static void 1613198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task, 1614198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf) 1615198Sigor@sysoev.ru { 1616358Sigor@sysoev.ru size_t size; 1617198Sigor@sysoev.ru uint32_t stream; 1618198Sigor@sysoev.ru nxt_buf_t *b; 1619198Sigor@sysoev.ru nxt_port_t *main_port, *router_port; 1620198Sigor@sysoev.ru nxt_runtime_t *rt; 1621198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 1622198Sigor@sysoev.ru 1623198Sigor@sysoev.ru rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t)); 1624198Sigor@sysoev.ru if (rpc == NULL) { 1625198Sigor@sysoev.ru goto fail; 1626198Sigor@sysoev.ru } 1627198Sigor@sysoev.ru 1628198Sigor@sysoev.ru rpc->socket_conf = skcf; 1629198Sigor@sysoev.ru rpc->temp_conf = tmcf; 1630198Sigor@sysoev.ru 1631359Sigor@sysoev.ru size = nxt_sockaddr_size(skcf->listen->sockaddr); 1632358Sigor@sysoev.ru 1633358Sigor@sysoev.ru b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 1634198Sigor@sysoev.ru if (b == NULL) { 1635198Sigor@sysoev.ru goto fail; 1636198Sigor@sysoev.ru } 1637198Sigor@sysoev.ru 1638359Sigor@sysoev.ru b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size); 1639198Sigor@sysoev.ru 1640198Sigor@sysoev.ru rt = task->thread->runtime; 1641240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1642198Sigor@sysoev.ru router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 1643198Sigor@sysoev.ru 1644198Sigor@sysoev.ru stream = nxt_port_rpc_register_handler(task, router_port, 1645198Sigor@sysoev.ru nxt_router_listen_socket_ready, 1646198Sigor@sysoev.ru nxt_router_listen_socket_error, 1647198Sigor@sysoev.ru main_port->pid, rpc); 1648198Sigor@sysoev.ru if (stream == 0) { 1649198Sigor@sysoev.ru goto fail; 1650198Sigor@sysoev.ru } 1651198Sigor@sysoev.ru 1652198Sigor@sysoev.ru nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1, 1653198Sigor@sysoev.ru stream, router_port->id, b); 1654198Sigor@sysoev.ru 1655198Sigor@sysoev.ru return; 1656198Sigor@sysoev.ru 1657198Sigor@sysoev.ru fail: 1658198Sigor@sysoev.ru 1659198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 1660198Sigor@sysoev.ru } 1661198Sigor@sysoev.ru 1662198Sigor@sysoev.ru 1663198Sigor@sysoev.ru static void 1664198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1665198Sigor@sysoev.ru void *data) 166653Sigor@sysoev.ru { 1667359Sigor@sysoev.ru nxt_int_t ret; 1668359Sigor@sysoev.ru nxt_socket_t s; 1669359Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 167053Sigor@sysoev.ru 1671198Sigor@sysoev.ru rpc = data; 1672198Sigor@sysoev.ru 1673198Sigor@sysoev.ru s = msg->fd; 1674198Sigor@sysoev.ru 1675198Sigor@sysoev.ru ret = nxt_socket_nonblocking(task, s); 1676198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1677198Sigor@sysoev.ru goto fail; 167853Sigor@sysoev.ru } 167953Sigor@sysoev.ru 1680359Sigor@sysoev.ru nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr); 1681198Sigor@sysoev.ru 1682198Sigor@sysoev.ru ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG); 1683198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1684198Sigor@sysoev.ru goto fail; 1685198Sigor@sysoev.ru } 1686198Sigor@sysoev.ru 1687359Sigor@sysoev.ru rpc->socket_conf->listen->socket = s; 1688198Sigor@sysoev.ru 1689198Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 1690198Sigor@sysoev.ru nxt_router_conf_apply, task, rpc->temp_conf, NULL); 1691198Sigor@sysoev.ru 1692198Sigor@sysoev.ru return; 1693148Sigor@sysoev.ru 1694148Sigor@sysoev.ru fail: 1695148Sigor@sysoev.ru 1696148Sigor@sysoev.ru nxt_socket_close(task, s); 1697148Sigor@sysoev.ru 1698198Sigor@sysoev.ru nxt_router_conf_error(task, rpc->temp_conf); 1699198Sigor@sysoev.ru } 1700198Sigor@sysoev.ru 1701198Sigor@sysoev.ru 1702198Sigor@sysoev.ru static void 1703198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1704198Sigor@sysoev.ru void *data) 1705198Sigor@sysoev.ru { 1706198Sigor@sysoev.ru u_char *p; 1707198Sigor@sysoev.ru size_t size; 1708198Sigor@sysoev.ru uint8_t error; 1709198Sigor@sysoev.ru nxt_buf_t *in, *out; 1710198Sigor@sysoev.ru nxt_sockaddr_t *sa; 1711198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 1712198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 1713198Sigor@sysoev.ru 1714198Sigor@sysoev.ru static nxt_str_t socket_errors[] = { 1715198Sigor@sysoev.ru nxt_string("ListenerSystem"), 1716198Sigor@sysoev.ru nxt_string("ListenerNoIPv6"), 1717198Sigor@sysoev.ru nxt_string("ListenerPort"), 1718198Sigor@sysoev.ru nxt_string("ListenerInUse"), 1719198Sigor@sysoev.ru nxt_string("ListenerNoAddress"), 1720198Sigor@sysoev.ru nxt_string("ListenerNoAccess"), 1721198Sigor@sysoev.ru nxt_string("ListenerPath"), 1722198Sigor@sysoev.ru }; 1723198Sigor@sysoev.ru 1724198Sigor@sysoev.ru rpc = data; 1725359Sigor@sysoev.ru sa = rpc->socket_conf->listen->sockaddr; 1726352Smax.romanov@nginx.com tmcf = rpc->temp_conf; 1727352Smax.romanov@nginx.com 1728352Smax.romanov@nginx.com in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size); 1729352Smax.romanov@nginx.com 1730352Smax.romanov@nginx.com nxt_assert(in != NULL); 1731352Smax.romanov@nginx.com 1732198Sigor@sysoev.ru p = in->mem.pos; 1733198Sigor@sysoev.ru 1734198Sigor@sysoev.ru error = *p++; 1735198Sigor@sysoev.ru 1736198Sigor@sysoev.ru size = sizeof("listen socket error: ") - 1 1737198Sigor@sysoev.ru + sizeof("{listener: \"\", code:\"\", message: \"\"}") - 1 1738198Sigor@sysoev.ru + sa->length + socket_errors[error].length + (in->mem.free - p); 1739198Sigor@sysoev.ru 1740198Sigor@sysoev.ru out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 1741198Sigor@sysoev.ru if (nxt_slow_path(out == NULL)) { 1742198Sigor@sysoev.ru return; 1743198Sigor@sysoev.ru } 1744198Sigor@sysoev.ru 1745198Sigor@sysoev.ru out->mem.free = nxt_sprintf(out->mem.free, out->mem.end, 1746198Sigor@sysoev.ru "listen socket error: " 1747198Sigor@sysoev.ru "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}", 1748493Spluknet@nginx.com (size_t) sa->length, nxt_sockaddr_start(sa), 1749198Sigor@sysoev.ru &socket_errors[error], in->mem.free - p, p); 1750198Sigor@sysoev.ru 1751198Sigor@sysoev.ru nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos); 1752198Sigor@sysoev.ru 1753198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 175453Sigor@sysoev.ru } 175553Sigor@sysoev.ru 175653Sigor@sysoev.ru 1757507Smax.romanov@nginx.com static void 1758507Smax.romanov@nginx.com nxt_router_app_rpc_create(nxt_task_t *task, 1759507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_app_t *app) 1760507Smax.romanov@nginx.com { 1761507Smax.romanov@nginx.com size_t size; 1762507Smax.romanov@nginx.com uint32_t stream; 1763507Smax.romanov@nginx.com nxt_buf_t *b; 1764507Smax.romanov@nginx.com nxt_port_t *main_port, *router_port; 1765507Smax.romanov@nginx.com nxt_runtime_t *rt; 1766507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 1767507Smax.romanov@nginx.com 1768507Smax.romanov@nginx.com rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_app_rpc_t)); 1769507Smax.romanov@nginx.com if (rpc == NULL) { 1770507Smax.romanov@nginx.com goto fail; 1771507Smax.romanov@nginx.com } 1772507Smax.romanov@nginx.com 1773507Smax.romanov@nginx.com rpc->app = app; 1774507Smax.romanov@nginx.com rpc->temp_conf = tmcf; 1775507Smax.romanov@nginx.com 1776507Smax.romanov@nginx.com nxt_debug(task, "app '%V' prefork", &app->name); 1777507Smax.romanov@nginx.com 1778507Smax.romanov@nginx.com size = app->name.length + 1 + app->conf.length; 1779507Smax.romanov@nginx.com 1780507Smax.romanov@nginx.com b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 1781507Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 1782507Smax.romanov@nginx.com goto fail; 1783507Smax.romanov@nginx.com } 1784507Smax.romanov@nginx.com 1785507Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->name); 1786507Smax.romanov@nginx.com *b->mem.free++ = '\0'; 1787507Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 1788507Smax.romanov@nginx.com 1789507Smax.romanov@nginx.com rt = task->thread->runtime; 1790507Smax.romanov@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1791507Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 1792507Smax.romanov@nginx.com 1793507Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 1794507Smax.romanov@nginx.com nxt_router_app_prefork_ready, 1795507Smax.romanov@nginx.com nxt_router_app_prefork_error, 1796507Smax.romanov@nginx.com -1, rpc); 1797507Smax.romanov@nginx.com if (nxt_slow_path(stream == 0)) { 1798507Smax.romanov@nginx.com goto fail; 1799507Smax.romanov@nginx.com } 1800507Smax.romanov@nginx.com 1801507Smax.romanov@nginx.com app->pending_processes++; 1802507Smax.romanov@nginx.com 1803507Smax.romanov@nginx.com nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1, 1804507Smax.romanov@nginx.com stream, router_port->id, b); 1805507Smax.romanov@nginx.com 1806507Smax.romanov@nginx.com return; 1807507Smax.romanov@nginx.com 1808507Smax.romanov@nginx.com fail: 1809507Smax.romanov@nginx.com 1810507Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 1811507Smax.romanov@nginx.com } 1812507Smax.romanov@nginx.com 1813507Smax.romanov@nginx.com 1814507Smax.romanov@nginx.com static void 1815507Smax.romanov@nginx.com nxt_router_app_prefork_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1816507Smax.romanov@nginx.com void *data) 1817507Smax.romanov@nginx.com { 1818507Smax.romanov@nginx.com nxt_app_t *app; 1819507Smax.romanov@nginx.com nxt_port_t *port; 1820507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 1821507Smax.romanov@nginx.com nxt_event_engine_t *engine; 1822507Smax.romanov@nginx.com 1823507Smax.romanov@nginx.com rpc = data; 1824507Smax.romanov@nginx.com app = rpc->app; 1825507Smax.romanov@nginx.com 1826507Smax.romanov@nginx.com port = msg->u.new_port; 1827507Smax.romanov@nginx.com port->app = app; 1828507Smax.romanov@nginx.com 1829507Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 1830507Smax.romanov@nginx.com 1831507Smax.romanov@nginx.com app->pending_processes--; 1832507Smax.romanov@nginx.com app->processes++; 1833507Smax.romanov@nginx.com app->idle_processes++; 1834507Smax.romanov@nginx.com 1835507Smax.romanov@nginx.com engine = task->thread->engine; 1836507Smax.romanov@nginx.com 1837507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &port->app_link); 1838507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, &port->idle_link); 1839507Smax.romanov@nginx.com 1840507Smax.romanov@nginx.com port->idle_start = 0; 1841507Smax.romanov@nginx.com 1842507Smax.romanov@nginx.com nxt_port_inc_use(port); 1843507Smax.romanov@nginx.com 1844507Smax.romanov@nginx.com nxt_work_queue_add(&engine->fast_work_queue, 1845507Smax.romanov@nginx.com nxt_router_conf_apply, task, rpc->temp_conf, NULL); 1846507Smax.romanov@nginx.com } 1847507Smax.romanov@nginx.com 1848507Smax.romanov@nginx.com 1849507Smax.romanov@nginx.com static void 1850507Smax.romanov@nginx.com nxt_router_app_prefork_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1851507Smax.romanov@nginx.com void *data) 1852507Smax.romanov@nginx.com { 1853507Smax.romanov@nginx.com nxt_app_t *app; 1854507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 1855507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf; 1856507Smax.romanov@nginx.com 1857507Smax.romanov@nginx.com rpc = data; 1858507Smax.romanov@nginx.com app = rpc->app; 1859507Smax.romanov@nginx.com tmcf = rpc->temp_conf; 1860507Smax.romanov@nginx.com 1861507Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, "failed to start application \"%V\"", 1862507Smax.romanov@nginx.com &app->name); 1863507Smax.romanov@nginx.com 1864507Smax.romanov@nginx.com app->pending_processes--; 1865507Smax.romanov@nginx.com 1866507Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 1867507Smax.romanov@nginx.com } 1868507Smax.romanov@nginx.com 1869507Smax.romanov@nginx.com 187053Sigor@sysoev.ru static nxt_int_t 187153Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router, 187253Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface) 187353Sigor@sysoev.ru { 187453Sigor@sysoev.ru nxt_int_t ret; 187553Sigor@sysoev.ru nxt_uint_t n, threads; 187653Sigor@sysoev.ru nxt_queue_link_t *qlk; 187753Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 187853Sigor@sysoev.ru 187953Sigor@sysoev.ru threads = tmcf->conf->threads; 188053Sigor@sysoev.ru 188153Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, threads, 188253Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 188353Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 188453Sigor@sysoev.ru return NXT_ERROR; 188553Sigor@sysoev.ru } 188653Sigor@sysoev.ru 188753Sigor@sysoev.ru n = 0; 188853Sigor@sysoev.ru 188953Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->engines); 189053Sigor@sysoev.ru qlk != nxt_queue_tail(&router->engines); 189153Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 189253Sigor@sysoev.ru { 189353Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 189453Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 189553Sigor@sysoev.ru return NXT_ERROR; 189653Sigor@sysoev.ru } 189753Sigor@sysoev.ru 1898115Sigor@sysoev.ru recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0); 189953Sigor@sysoev.ru 190053Sigor@sysoev.ru if (n < threads) { 1901315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_KEEP; 1902115Sigor@sysoev.ru ret = nxt_router_engine_conf_update(tmcf, recf); 190353Sigor@sysoev.ru 190453Sigor@sysoev.ru } else { 1905315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_DELETE; 1906115Sigor@sysoev.ru ret = nxt_router_engine_conf_delete(tmcf, recf); 190753Sigor@sysoev.ru } 190853Sigor@sysoev.ru 190953Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 191053Sigor@sysoev.ru return ret; 191153Sigor@sysoev.ru } 191253Sigor@sysoev.ru 191353Sigor@sysoev.ru n++; 191453Sigor@sysoev.ru } 191553Sigor@sysoev.ru 191653Sigor@sysoev.ru tmcf->new_threads = n; 191753Sigor@sysoev.ru 191853Sigor@sysoev.ru while (n < threads) { 191953Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 192053Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 192153Sigor@sysoev.ru return NXT_ERROR; 192253Sigor@sysoev.ru } 192353Sigor@sysoev.ru 1924315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_ADD; 1925315Sigor@sysoev.ru 192653Sigor@sysoev.ru recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0); 192753Sigor@sysoev.ru if (nxt_slow_path(recf->engine == NULL)) { 192853Sigor@sysoev.ru return NXT_ERROR; 192953Sigor@sysoev.ru } 193053Sigor@sysoev.ru 1931115Sigor@sysoev.ru ret = nxt_router_engine_conf_create(tmcf, recf); 193253Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 193353Sigor@sysoev.ru return ret; 193453Sigor@sysoev.ru } 193553Sigor@sysoev.ru 193653Sigor@sysoev.ru n++; 193753Sigor@sysoev.ru } 193853Sigor@sysoev.ru 193953Sigor@sysoev.ru return NXT_OK; 194053Sigor@sysoev.ru } 194153Sigor@sysoev.ru 194253Sigor@sysoev.ru 194353Sigor@sysoev.ru static nxt_int_t 1944115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 1945115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 194653Sigor@sysoev.ru { 1947359Sigor@sysoev.ru nxt_int_t ret; 194853Sigor@sysoev.ru 1949154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 1950154Sigor@sysoev.ru nxt_router_listen_socket_create); 1951115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1952115Sigor@sysoev.ru return ret; 1953115Sigor@sysoev.ru } 1954115Sigor@sysoev.ru 1955154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 1956154Sigor@sysoev.ru nxt_router_listen_socket_create); 195753Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 195853Sigor@sysoev.ru return ret; 195953Sigor@sysoev.ru } 196053Sigor@sysoev.ru 1961115Sigor@sysoev.ru return ret; 196253Sigor@sysoev.ru } 196353Sigor@sysoev.ru 196453Sigor@sysoev.ru 196553Sigor@sysoev.ru static nxt_int_t 1966115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 1967115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 196853Sigor@sysoev.ru { 1969359Sigor@sysoev.ru nxt_int_t ret; 197053Sigor@sysoev.ru 1971154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 1972154Sigor@sysoev.ru nxt_router_listen_socket_create); 197353Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 197453Sigor@sysoev.ru return ret; 197553Sigor@sysoev.ru } 197653Sigor@sysoev.ru 1977154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 1978154Sigor@sysoev.ru nxt_router_listen_socket_update); 197953Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 198053Sigor@sysoev.ru return ret; 198153Sigor@sysoev.ru } 198253Sigor@sysoev.ru 1983139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 1984115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1985115Sigor@sysoev.ru return ret; 1986115Sigor@sysoev.ru } 1987115Sigor@sysoev.ru 1988115Sigor@sysoev.ru return ret; 198953Sigor@sysoev.ru } 199053Sigor@sysoev.ru 199153Sigor@sysoev.ru 199253Sigor@sysoev.ru static nxt_int_t 1993115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 1994115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 199553Sigor@sysoev.ru { 199653Sigor@sysoev.ru nxt_int_t ret; 199753Sigor@sysoev.ru 1998313Sigor@sysoev.ru ret = nxt_router_engine_quit(tmcf, recf); 1999313Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2000313Sigor@sysoev.ru return ret; 2001313Sigor@sysoev.ru } 2002313Sigor@sysoev.ru 2003139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating); 200453Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 200553Sigor@sysoev.ru return ret; 200653Sigor@sysoev.ru } 200753Sigor@sysoev.ru 2008139Sigor@sysoev.ru return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 200953Sigor@sysoev.ru } 201053Sigor@sysoev.ru 201153Sigor@sysoev.ru 201253Sigor@sysoev.ru static nxt_int_t 2013154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 2014154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 201553Sigor@sysoev.ru nxt_work_handler_t handler) 201653Sigor@sysoev.ru { 2017153Sigor@sysoev.ru nxt_joint_job_t *job; 201853Sigor@sysoev.ru nxt_queue_link_t *qlk; 2019155Sigor@sysoev.ru nxt_socket_conf_t *skcf; 202053Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 202153Sigor@sysoev.ru 202253Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 202353Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 202453Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 202553Sigor@sysoev.ru { 2026154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2027153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2028139Sigor@sysoev.ru return NXT_ERROR; 2029139Sigor@sysoev.ru } 2030139Sigor@sysoev.ru 2031154Sigor@sysoev.ru job->work.next = recf->jobs; 2032154Sigor@sysoev.ru recf->jobs = &job->work; 2033154Sigor@sysoev.ru 2034153Sigor@sysoev.ru job->task = tmcf->engine->task; 2035153Sigor@sysoev.ru job->work.handler = handler; 2036153Sigor@sysoev.ru job->work.task = &job->task; 2037153Sigor@sysoev.ru job->work.obj = job; 2038153Sigor@sysoev.ru job->tmcf = tmcf; 203953Sigor@sysoev.ru 2040154Sigor@sysoev.ru tmcf->count++; 2041154Sigor@sysoev.ru 2042154Sigor@sysoev.ru joint = nxt_mp_alloc(tmcf->conf->mem_pool, 2043154Sigor@sysoev.ru sizeof(nxt_socket_conf_joint_t)); 204453Sigor@sysoev.ru if (nxt_slow_path(joint == NULL)) { 204553Sigor@sysoev.ru return NXT_ERROR; 204653Sigor@sysoev.ru } 204753Sigor@sysoev.ru 2048153Sigor@sysoev.ru job->work.data = joint; 204953Sigor@sysoev.ru 205053Sigor@sysoev.ru joint->count = 1; 2051155Sigor@sysoev.ru 2052155Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 2053155Sigor@sysoev.ru skcf->count++; 2054155Sigor@sysoev.ru joint->socket_conf = skcf; 2055155Sigor@sysoev.ru 205688Smax.romanov@nginx.com joint->engine = recf->engine; 205753Sigor@sysoev.ru } 205853Sigor@sysoev.ru 205920Sigor@sysoev.ru return NXT_OK; 206020Sigor@sysoev.ru } 206120Sigor@sysoev.ru 206220Sigor@sysoev.ru 206320Sigor@sysoev.ru static nxt_int_t 2064313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 2065313Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 2066313Sigor@sysoev.ru { 2067313Sigor@sysoev.ru nxt_joint_job_t *job; 2068313Sigor@sysoev.ru 2069313Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2070313Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2071313Sigor@sysoev.ru return NXT_ERROR; 2072313Sigor@sysoev.ru } 2073313Sigor@sysoev.ru 2074313Sigor@sysoev.ru job->work.next = recf->jobs; 2075313Sigor@sysoev.ru recf->jobs = &job->work; 2076313Sigor@sysoev.ru 2077313Sigor@sysoev.ru job->task = tmcf->engine->task; 2078313Sigor@sysoev.ru job->work.handler = nxt_router_worker_thread_quit; 2079313Sigor@sysoev.ru job->work.task = &job->task; 2080313Sigor@sysoev.ru job->work.obj = NULL; 2081313Sigor@sysoev.ru job->work.data = NULL; 2082313Sigor@sysoev.ru job->tmcf = NULL; 2083313Sigor@sysoev.ru 2084313Sigor@sysoev.ru return NXT_OK; 2085313Sigor@sysoev.ru } 2086313Sigor@sysoev.ru 2087313Sigor@sysoev.ru 2088313Sigor@sysoev.ru static nxt_int_t 2089139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 2090139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets) 209120Sigor@sysoev.ru { 2092153Sigor@sysoev.ru nxt_joint_job_t *job; 209353Sigor@sysoev.ru nxt_queue_link_t *qlk; 209420Sigor@sysoev.ru 209553Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 209653Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 209753Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 209853Sigor@sysoev.ru { 2099154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2100153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2101139Sigor@sysoev.ru return NXT_ERROR; 2102139Sigor@sysoev.ru } 2103139Sigor@sysoev.ru 2104154Sigor@sysoev.ru job->work.next = recf->jobs; 2105154Sigor@sysoev.ru recf->jobs = &job->work; 2106154Sigor@sysoev.ru 2107153Sigor@sysoev.ru job->task = tmcf->engine->task; 2108153Sigor@sysoev.ru job->work.handler = nxt_router_listen_socket_delete; 2109153Sigor@sysoev.ru job->work.task = &job->task; 2110153Sigor@sysoev.ru job->work.obj = job; 2111153Sigor@sysoev.ru job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 2112153Sigor@sysoev.ru job->tmcf = tmcf; 2113154Sigor@sysoev.ru 2114154Sigor@sysoev.ru tmcf->count++; 211520Sigor@sysoev.ru } 211620Sigor@sysoev.ru 211753Sigor@sysoev.ru return NXT_OK; 211853Sigor@sysoev.ru } 211920Sigor@sysoev.ru 212020Sigor@sysoev.ru 212153Sigor@sysoev.ru static nxt_int_t 212253Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 212353Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 212453Sigor@sysoev.ru { 212553Sigor@sysoev.ru nxt_int_t ret; 212653Sigor@sysoev.ru nxt_uint_t i, threads; 212753Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 212820Sigor@sysoev.ru 212953Sigor@sysoev.ru recf = tmcf->engines->elts; 213053Sigor@sysoev.ru threads = tmcf->conf->threads; 213120Sigor@sysoev.ru 213253Sigor@sysoev.ru for (i = tmcf->new_threads; i < threads; i++) { 213353Sigor@sysoev.ru ret = nxt_router_thread_create(task, rt, recf[i].engine); 213453Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 213553Sigor@sysoev.ru return ret; 213653Sigor@sysoev.ru } 213720Sigor@sysoev.ru } 213820Sigor@sysoev.ru 213920Sigor@sysoev.ru return NXT_OK; 214020Sigor@sysoev.ru } 214153Sigor@sysoev.ru 214253Sigor@sysoev.ru 214353Sigor@sysoev.ru static nxt_int_t 214453Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 214553Sigor@sysoev.ru nxt_event_engine_t *engine) 214653Sigor@sysoev.ru { 214753Sigor@sysoev.ru nxt_int_t ret; 214853Sigor@sysoev.ru nxt_thread_link_t *link; 214953Sigor@sysoev.ru nxt_thread_handle_t handle; 215053Sigor@sysoev.ru 215153Sigor@sysoev.ru link = nxt_zalloc(sizeof(nxt_thread_link_t)); 215253Sigor@sysoev.ru 215353Sigor@sysoev.ru if (nxt_slow_path(link == NULL)) { 215453Sigor@sysoev.ru return NXT_ERROR; 215553Sigor@sysoev.ru } 215653Sigor@sysoev.ru 215753Sigor@sysoev.ru link->start = nxt_router_thread_start; 215853Sigor@sysoev.ru link->engine = engine; 215953Sigor@sysoev.ru link->work.handler = nxt_router_thread_exit_handler; 216053Sigor@sysoev.ru link->work.task = task; 216153Sigor@sysoev.ru link->work.data = link; 216253Sigor@sysoev.ru 216353Sigor@sysoev.ru nxt_queue_insert_tail(&rt->engines, &engine->link); 216453Sigor@sysoev.ru 216553Sigor@sysoev.ru ret = nxt_thread_create(&handle, link); 216653Sigor@sysoev.ru 216753Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 216853Sigor@sysoev.ru nxt_queue_remove(&engine->link); 216953Sigor@sysoev.ru } 217053Sigor@sysoev.ru 217153Sigor@sysoev.ru return ret; 217253Sigor@sysoev.ru } 217353Sigor@sysoev.ru 217453Sigor@sysoev.ru 217553Sigor@sysoev.ru static void 2176343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 2177343Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf) 2178133Sigor@sysoev.ru { 2179507Smax.romanov@nginx.com nxt_app_t *app; 2180141Smax.romanov@nginx.com 2181141Smax.romanov@nginx.com nxt_queue_each(app, &router->apps, nxt_app_t, link) { 2182133Sigor@sysoev.ru 2183507Smax.romanov@nginx.com nxt_router_app_quit(task, app); 2184343Smax.romanov@nginx.com 2185141Smax.romanov@nginx.com } nxt_queue_loop; 2186133Sigor@sysoev.ru 2187133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->previous); 2188133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->apps); 2189133Sigor@sysoev.ru } 2190133Sigor@sysoev.ru 2191133Sigor@sysoev.ru 2192133Sigor@sysoev.ru static void 2193315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf) 219453Sigor@sysoev.ru { 219553Sigor@sysoev.ru nxt_uint_t n; 2196315Sigor@sysoev.ru nxt_event_engine_t *engine; 219753Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 219853Sigor@sysoev.ru 219953Sigor@sysoev.ru recf = tmcf->engines->elts; 220053Sigor@sysoev.ru 220153Sigor@sysoev.ru for (n = tmcf->engines->nelts; n != 0; n--) { 2202315Sigor@sysoev.ru engine = recf->engine; 2203315Sigor@sysoev.ru 2204315Sigor@sysoev.ru switch (recf->action) { 2205315Sigor@sysoev.ru 2206315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_KEEP: 2207315Sigor@sysoev.ru break; 2208315Sigor@sysoev.ru 2209315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_ADD: 2210315Sigor@sysoev.ru nxt_queue_insert_tail(&router->engines, &engine->link0); 2211315Sigor@sysoev.ru break; 2212315Sigor@sysoev.ru 2213315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_DELETE: 2214315Sigor@sysoev.ru nxt_queue_remove(&engine->link0); 2215315Sigor@sysoev.ru break; 2216315Sigor@sysoev.ru } 2217315Sigor@sysoev.ru 2218316Sigor@sysoev.ru nxt_router_engine_post(engine, recf->jobs); 2219316Sigor@sysoev.ru 222053Sigor@sysoev.ru recf++; 222153Sigor@sysoev.ru } 222253Sigor@sysoev.ru } 222353Sigor@sysoev.ru 222453Sigor@sysoev.ru 222553Sigor@sysoev.ru static void 2226315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs) 222753Sigor@sysoev.ru { 2228154Sigor@sysoev.ru nxt_work_t *work, *next; 2229154Sigor@sysoev.ru 2230315Sigor@sysoev.ru for (work = jobs; work != NULL; work = next) { 2231154Sigor@sysoev.ru next = work->next; 2232154Sigor@sysoev.ru work->next = NULL; 2233154Sigor@sysoev.ru 2234315Sigor@sysoev.ru nxt_event_engine_post(engine, work); 223553Sigor@sysoev.ru } 223653Sigor@sysoev.ru } 223753Sigor@sysoev.ru 223853Sigor@sysoev.ru 2239320Smax.romanov@nginx.com static nxt_port_handlers_t nxt_router_app_port_handlers = { 2240320Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 2241320Smax.romanov@nginx.com .data = nxt_port_rpc_handler, 224288Smax.romanov@nginx.com }; 224388Smax.romanov@nginx.com 224488Smax.romanov@nginx.com 224588Smax.romanov@nginx.com static void 224653Sigor@sysoev.ru nxt_router_thread_start(void *data) 224753Sigor@sysoev.ru { 2248141Smax.romanov@nginx.com nxt_int_t ret; 2249141Smax.romanov@nginx.com nxt_port_t *port; 225088Smax.romanov@nginx.com nxt_task_t *task; 225153Sigor@sysoev.ru nxt_thread_t *thread; 225253Sigor@sysoev.ru nxt_thread_link_t *link; 225353Sigor@sysoev.ru nxt_event_engine_t *engine; 225453Sigor@sysoev.ru 225553Sigor@sysoev.ru link = data; 225653Sigor@sysoev.ru engine = link->engine; 225788Smax.romanov@nginx.com task = &engine->task; 225853Sigor@sysoev.ru 225953Sigor@sysoev.ru thread = nxt_thread(); 226053Sigor@sysoev.ru 2261165Smax.romanov@nginx.com nxt_event_engine_thread_adopt(engine); 2262165Smax.romanov@nginx.com 226353Sigor@sysoev.ru /* STUB */ 226453Sigor@sysoev.ru thread->runtime = engine->task.thread->runtime; 226553Sigor@sysoev.ru 226653Sigor@sysoev.ru engine->task.thread = thread; 226753Sigor@sysoev.ru engine->task.log = thread->log; 226853Sigor@sysoev.ru thread->engine = engine; 226963Sigor@sysoev.ru thread->task = &engine->task; 2270326Svbart@nginx.com #if 0 227153Sigor@sysoev.ru thread->fiber = &engine->fibers->fiber; 2272326Svbart@nginx.com #endif 227353Sigor@sysoev.ru 227463Sigor@sysoev.ru engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64); 2275337Sigor@sysoev.ru if (nxt_slow_path(engine->mem_pool == NULL)) { 2276337Sigor@sysoev.ru return; 2277337Sigor@sysoev.ru } 227853Sigor@sysoev.ru 2279197Smax.romanov@nginx.com port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid, 2280197Smax.romanov@nginx.com NXT_PROCESS_ROUTER); 2281141Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 2282141Smax.romanov@nginx.com return; 2283141Smax.romanov@nginx.com } 2284141Smax.romanov@nginx.com 2285141Smax.romanov@nginx.com ret = nxt_port_socket_init(task, port, 0); 2286141Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2287343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 2288141Smax.romanov@nginx.com return; 2289141Smax.romanov@nginx.com } 2290141Smax.romanov@nginx.com 2291141Smax.romanov@nginx.com engine->port = port; 2292141Smax.romanov@nginx.com 2293320Smax.romanov@nginx.com nxt_port_enable(task, port, &nxt_router_app_port_handlers); 2294141Smax.romanov@nginx.com 229553Sigor@sysoev.ru nxt_event_engine_start(engine); 229653Sigor@sysoev.ru } 229753Sigor@sysoev.ru 229853Sigor@sysoev.ru 229953Sigor@sysoev.ru static void 230053Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data) 230153Sigor@sysoev.ru { 2302153Sigor@sysoev.ru nxt_joint_job_t *job; 2303359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2304359Sigor@sysoev.ru nxt_listen_event_t *lev; 230553Sigor@sysoev.ru nxt_listen_socket_t *ls; 2306359Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 230753Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 230853Sigor@sysoev.ru 2309153Sigor@sysoev.ru job = obj; 231053Sigor@sysoev.ru joint = data; 231153Sigor@sysoev.ru 2312159Sigor@sysoev.ru nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link); 2313159Sigor@sysoev.ru 2314359Sigor@sysoev.ru skcf = joint->socket_conf; 2315359Sigor@sysoev.ru ls = skcf->listen; 2316359Sigor@sysoev.ru 2317359Sigor@sysoev.ru lev = nxt_listen_event(task, ls); 2318359Sigor@sysoev.ru if (nxt_slow_path(lev == NULL)) { 2319359Sigor@sysoev.ru nxt_router_listen_socket_release(task, skcf); 232053Sigor@sysoev.ru return; 232153Sigor@sysoev.ru } 232253Sigor@sysoev.ru 2323359Sigor@sysoev.ru lev->socket.data = joint; 2324359Sigor@sysoev.ru 2325359Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 2326359Sigor@sysoev.ru 2327359Sigor@sysoev.ru nxt_thread_spin_lock(lock); 2328359Sigor@sysoev.ru ls->count++; 2329359Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 2330139Sigor@sysoev.ru 2331153Sigor@sysoev.ru job->work.next = NULL; 2332153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2333153Sigor@sysoev.ru 2334153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 233553Sigor@sysoev.ru } 233653Sigor@sysoev.ru 233753Sigor@sysoev.ru 233853Sigor@sysoev.ru nxt_inline nxt_listen_event_t * 233953Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections, 234053Sigor@sysoev.ru nxt_socket_conf_t *skcf) 234153Sigor@sysoev.ru { 2342115Sigor@sysoev.ru nxt_socket_t fd; 2343115Sigor@sysoev.ru nxt_queue_link_t *qlk; 2344359Sigor@sysoev.ru nxt_listen_event_t *lev; 2345359Sigor@sysoev.ru 2346359Sigor@sysoev.ru fd = skcf->listen->socket; 234753Sigor@sysoev.ru 2348115Sigor@sysoev.ru for (qlk = nxt_queue_first(listen_connections); 2349115Sigor@sysoev.ru qlk != nxt_queue_tail(listen_connections); 2350115Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 235153Sigor@sysoev.ru { 2352359Sigor@sysoev.ru lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link); 2353359Sigor@sysoev.ru 2354359Sigor@sysoev.ru if (fd == lev->socket.fd) { 2355359Sigor@sysoev.ru return lev; 235653Sigor@sysoev.ru } 235753Sigor@sysoev.ru } 235853Sigor@sysoev.ru 235953Sigor@sysoev.ru return NULL; 236053Sigor@sysoev.ru } 236153Sigor@sysoev.ru 236253Sigor@sysoev.ru 236353Sigor@sysoev.ru static void 236453Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data) 236553Sigor@sysoev.ru { 2366153Sigor@sysoev.ru nxt_joint_job_t *job; 236753Sigor@sysoev.ru nxt_event_engine_t *engine; 2368359Sigor@sysoev.ru nxt_listen_event_t *lev; 236953Sigor@sysoev.ru nxt_socket_conf_joint_t *joint, *old; 237053Sigor@sysoev.ru 2371153Sigor@sysoev.ru job = obj; 237253Sigor@sysoev.ru joint = data; 237353Sigor@sysoev.ru 2374139Sigor@sysoev.ru engine = task->thread->engine; 2375139Sigor@sysoev.ru 2376159Sigor@sysoev.ru nxt_queue_insert_tail(&engine->joints, &joint->link); 2377159Sigor@sysoev.ru 2378359Sigor@sysoev.ru lev = nxt_router_listen_event(&engine->listen_connections, 2379359Sigor@sysoev.ru joint->socket_conf); 2380359Sigor@sysoev.ru 2381359Sigor@sysoev.ru old = lev->socket.data; 2382359Sigor@sysoev.ru lev->socket.data = joint; 2383359Sigor@sysoev.ru lev->listen = joint->socket_conf->listen; 238453Sigor@sysoev.ru 2385153Sigor@sysoev.ru job->work.next = NULL; 2386153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2387153Sigor@sysoev.ru 2388153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 2389139Sigor@sysoev.ru 2390181Smax.romanov@nginx.com /* 2391181Smax.romanov@nginx.com * The task is allocated from configuration temporary 2392181Smax.romanov@nginx.com * memory pool so it can be freed after engine post operation. 2393181Smax.romanov@nginx.com */ 2394181Smax.romanov@nginx.com 2395181Smax.romanov@nginx.com nxt_router_conf_release(&engine->task, old); 239653Sigor@sysoev.ru } 239753Sigor@sysoev.ru 239853Sigor@sysoev.ru 239953Sigor@sysoev.ru static void 240053Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data) 240153Sigor@sysoev.ru { 2402153Sigor@sysoev.ru nxt_joint_job_t *job; 2403153Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2404359Sigor@sysoev.ru nxt_listen_event_t *lev; 2405153Sigor@sysoev.ru nxt_event_engine_t *engine; 2406153Sigor@sysoev.ru 2407153Sigor@sysoev.ru job = obj; 240853Sigor@sysoev.ru skcf = data; 240953Sigor@sysoev.ru 2410139Sigor@sysoev.ru engine = task->thread->engine; 2411139Sigor@sysoev.ru 2412359Sigor@sysoev.ru lev = nxt_router_listen_event(&engine->listen_connections, skcf); 2413359Sigor@sysoev.ru 2414359Sigor@sysoev.ru nxt_fd_event_delete(engine, &lev->socket); 241553Sigor@sysoev.ru 2416163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket delete: %d", engine, 2417359Sigor@sysoev.ru lev->socket.fd); 2418359Sigor@sysoev.ru 2419359Sigor@sysoev.ru lev->timer.handler = nxt_router_listen_socket_close; 2420359Sigor@sysoev.ru lev->timer.work_queue = &engine->fast_work_queue; 2421359Sigor@sysoev.ru 2422359Sigor@sysoev.ru nxt_timer_add(engine, &lev->timer, 0); 2423139Sigor@sysoev.ru 2424153Sigor@sysoev.ru job->work.next = NULL; 2425153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2426153Sigor@sysoev.ru 2427153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 242853Sigor@sysoev.ru } 242953Sigor@sysoev.ru 243053Sigor@sysoev.ru 243153Sigor@sysoev.ru static void 2432313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data) 2433313Sigor@sysoev.ru { 2434313Sigor@sysoev.ru nxt_event_engine_t *engine; 2435313Sigor@sysoev.ru 2436313Sigor@sysoev.ru nxt_debug(task, "router worker thread quit"); 2437313Sigor@sysoev.ru 2438313Sigor@sysoev.ru engine = task->thread->engine; 2439313Sigor@sysoev.ru 2440313Sigor@sysoev.ru engine->shutdown = 1; 2441313Sigor@sysoev.ru 2442313Sigor@sysoev.ru if (nxt_queue_is_empty(&engine->joints)) { 2443313Sigor@sysoev.ru nxt_thread_exit(task->thread); 2444313Sigor@sysoev.ru } 2445313Sigor@sysoev.ru } 2446313Sigor@sysoev.ru 2447313Sigor@sysoev.ru 2448313Sigor@sysoev.ru static void 244953Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data) 245053Sigor@sysoev.ru { 245153Sigor@sysoev.ru nxt_timer_t *timer; 2452359Sigor@sysoev.ru nxt_listen_event_t *lev; 245353Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 245453Sigor@sysoev.ru 245553Sigor@sysoev.ru timer = obj; 2456359Sigor@sysoev.ru lev = nxt_timer_data(timer, nxt_listen_event_t, timer); 2457359Sigor@sysoev.ru joint = lev->socket.data; 245853Sigor@sysoev.ru 2459163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine, 2460359Sigor@sysoev.ru lev->socket.fd); 2461359Sigor@sysoev.ru 2462359Sigor@sysoev.ru nxt_queue_remove(&lev->link); 2463359Sigor@sysoev.ru 2464359Sigor@sysoev.ru /* 'task' refers to lev->task and we cannot use after nxt_free() */ 2465123Smax.romanov@nginx.com task = &task->thread->engine->task; 2466123Smax.romanov@nginx.com 2467359Sigor@sysoev.ru nxt_router_listen_socket_release(task, joint->socket_conf); 2468359Sigor@sysoev.ru 2469359Sigor@sysoev.ru nxt_free(lev); 2470359Sigor@sysoev.ru 2471359Sigor@sysoev.ru nxt_router_conf_release(task, joint); 247253Sigor@sysoev.ru } 247353Sigor@sysoev.ru 247453Sigor@sysoev.ru 247553Sigor@sysoev.ru static void 2476359Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf) 247753Sigor@sysoev.ru { 2478359Sigor@sysoev.ru nxt_listen_socket_t *ls; 247953Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 248053Sigor@sysoev.ru 2481359Sigor@sysoev.ru ls = skcf->listen; 2482118Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 248353Sigor@sysoev.ru 248453Sigor@sysoev.ru nxt_thread_spin_lock(lock); 248553Sigor@sysoev.ru 2486359Sigor@sysoev.ru nxt_debug(task, "engine %p: listen socket release: ls->count %D", 2487359Sigor@sysoev.ru task->thread->engine, ls->count); 2488359Sigor@sysoev.ru 2489359Sigor@sysoev.ru if (--ls->count != 0) { 2490359Sigor@sysoev.ru ls = NULL; 249153Sigor@sysoev.ru } 249253Sigor@sysoev.ru 249353Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 249453Sigor@sysoev.ru 2495359Sigor@sysoev.ru if (ls != NULL) { 2496359Sigor@sysoev.ru nxt_socket_close(task, ls->socket); 2497359Sigor@sysoev.ru nxt_free(ls); 249853Sigor@sysoev.ru } 249953Sigor@sysoev.ru } 250053Sigor@sysoev.ru 250153Sigor@sysoev.ru 250253Sigor@sysoev.ru static void 250353Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint) 250453Sigor@sysoev.ru { 2505156Sigor@sysoev.ru nxt_bool_t exit; 250653Sigor@sysoev.ru nxt_socket_conf_t *skcf; 250753Sigor@sysoev.ru nxt_router_conf_t *rtcf; 2508313Sigor@sysoev.ru nxt_event_engine_t *engine; 250953Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 251053Sigor@sysoev.ru 2511163Smax.romanov@nginx.com nxt_debug(task, "conf joint %p count: %D", joint, joint->count); 251253Sigor@sysoev.ru 251353Sigor@sysoev.ru if (--joint->count != 0) { 251453Sigor@sysoev.ru return; 251553Sigor@sysoev.ru } 251653Sigor@sysoev.ru 251753Sigor@sysoev.ru nxt_queue_remove(&joint->link); 251853Sigor@sysoev.ru 251953Sigor@sysoev.ru skcf = joint->socket_conf; 252053Sigor@sysoev.ru rtcf = skcf->router_conf; 252153Sigor@sysoev.ru lock = &rtcf->router->lock; 252253Sigor@sysoev.ru 252353Sigor@sysoev.ru nxt_thread_spin_lock(lock); 252453Sigor@sysoev.ru 2525163Smax.romanov@nginx.com nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count, 2526163Smax.romanov@nginx.com rtcf, rtcf->count); 2527163Smax.romanov@nginx.com 252853Sigor@sysoev.ru if (--skcf->count != 0) { 252953Sigor@sysoev.ru rtcf = NULL; 253053Sigor@sysoev.ru 253153Sigor@sysoev.ru } else { 253253Sigor@sysoev.ru nxt_queue_remove(&skcf->link); 253353Sigor@sysoev.ru 253453Sigor@sysoev.ru if (--rtcf->count != 0) { 253553Sigor@sysoev.ru rtcf = NULL; 253653Sigor@sysoev.ru } 253753Sigor@sysoev.ru } 253853Sigor@sysoev.ru 253953Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 254053Sigor@sysoev.ru 2541141Smax.romanov@nginx.com /* TODO remove engine->port */ 2542141Smax.romanov@nginx.com /* TODO excude from connected ports */ 2543141Smax.romanov@nginx.com 2544156Sigor@sysoev.ru /* The joint content can be used before memory pool destruction. */ 2545313Sigor@sysoev.ru engine = joint->engine; 2546313Sigor@sysoev.ru exit = (engine->shutdown && nxt_queue_is_empty(&engine->joints)); 2547156Sigor@sysoev.ru 254853Sigor@sysoev.ru if (rtcf != NULL) { 2549115Sigor@sysoev.ru nxt_debug(task, "old router conf is destroyed"); 2550131Smax.romanov@nginx.com 2551131Smax.romanov@nginx.com nxt_mp_thread_adopt(rtcf->mem_pool); 2552131Smax.romanov@nginx.com 255365Sigor@sysoev.ru nxt_mp_destroy(rtcf->mem_pool); 255453Sigor@sysoev.ru } 255553Sigor@sysoev.ru 2556156Sigor@sysoev.ru if (exit) { 255753Sigor@sysoev.ru nxt_thread_exit(task->thread); 255853Sigor@sysoev.ru } 255953Sigor@sysoev.ru } 256053Sigor@sysoev.ru 256153Sigor@sysoev.ru 256253Sigor@sysoev.ru static void 256353Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data) 256453Sigor@sysoev.ru { 2565141Smax.romanov@nginx.com nxt_port_t *port; 256653Sigor@sysoev.ru nxt_thread_link_t *link; 256753Sigor@sysoev.ru nxt_event_engine_t *engine; 256853Sigor@sysoev.ru nxt_thread_handle_t handle; 256953Sigor@sysoev.ru 257058Svbart@nginx.com handle = (nxt_thread_handle_t) obj; 257153Sigor@sysoev.ru link = data; 257253Sigor@sysoev.ru 257353Sigor@sysoev.ru nxt_thread_wait(handle); 257453Sigor@sysoev.ru 257553Sigor@sysoev.ru engine = link->engine; 257653Sigor@sysoev.ru 257753Sigor@sysoev.ru nxt_queue_remove(&engine->link); 257853Sigor@sysoev.ru 2579141Smax.romanov@nginx.com port = engine->port; 2580141Smax.romanov@nginx.com 2581141Smax.romanov@nginx.com // TODO notify all apps 2582141Smax.romanov@nginx.com 2583343Smax.romanov@nginx.com port->engine = task->thread->engine; 2584163Smax.romanov@nginx.com nxt_mp_thread_adopt(port->mem_pool); 2585343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 2586163Smax.romanov@nginx.com 2587163Smax.romanov@nginx.com nxt_mp_thread_adopt(engine->mem_pool); 258863Sigor@sysoev.ru nxt_mp_destroy(engine->mem_pool); 258953Sigor@sysoev.ru 259053Sigor@sysoev.ru nxt_event_engine_free(engine); 259153Sigor@sysoev.ru 259253Sigor@sysoev.ru nxt_free(link); 259353Sigor@sysoev.ru } 259453Sigor@sysoev.ru 259553Sigor@sysoev.ru 259653Sigor@sysoev.ru static void 2597318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2598318Smax.romanov@nginx.com void *data) 259988Smax.romanov@nginx.com { 260088Smax.romanov@nginx.com size_t dump_size; 2601431Sigor@sysoev.ru nxt_int_t ret; 2602194Smax.romanov@nginx.com nxt_buf_t *b, *last; 2603431Sigor@sysoev.ru nxt_http_request_t *r; 260488Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 2605431Sigor@sysoev.ru nxt_app_parse_ctx_t *ar; 260688Smax.romanov@nginx.com 260788Smax.romanov@nginx.com b = msg->buf; 2608318Smax.romanov@nginx.com rc = data; 260988Smax.romanov@nginx.com 261088Smax.romanov@nginx.com dump_size = nxt_buf_used_size(b); 261188Smax.romanov@nginx.com 261288Smax.romanov@nginx.com if (dump_size > 300) { 261388Smax.romanov@nginx.com dump_size = 300; 261488Smax.romanov@nginx.com } 261588Smax.romanov@nginx.com 2616494Spluknet@nginx.com nxt_debug(task, "%srouter app data (%uz): %*s", 261788Smax.romanov@nginx.com msg->port_msg.last ? "last " : "", msg->size, dump_size, 261888Smax.romanov@nginx.com b->mem.pos); 261988Smax.romanov@nginx.com 262088Smax.romanov@nginx.com if (msg->size == 0) { 262188Smax.romanov@nginx.com b = NULL; 262288Smax.romanov@nginx.com } 262388Smax.romanov@nginx.com 2624431Sigor@sysoev.ru ar = rc->ap; 2625425Smax.romanov@nginx.com 262688Smax.romanov@nginx.com if (msg->port_msg.last != 0) { 262788Smax.romanov@nginx.com nxt_debug(task, "router data create last buf"); 262888Smax.romanov@nginx.com 2629431Sigor@sysoev.ru last = nxt_http_request_last_buffer(task, ar->request); 263088Smax.romanov@nginx.com if (nxt_slow_path(last == NULL)) { 2631431Sigor@sysoev.ru nxt_app_http_req_done(task, ar); 2632431Sigor@sysoev.ru nxt_router_rc_unlink(task, rc); 2633431Sigor@sysoev.ru return; 263488Smax.romanov@nginx.com } 263588Smax.romanov@nginx.com 263688Smax.romanov@nginx.com nxt_buf_chain_add(&b, last); 2637167Smax.romanov@nginx.com 2638343Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 2639425Smax.romanov@nginx.com 2640425Smax.romanov@nginx.com } else { 2641425Smax.romanov@nginx.com if (rc->app->timeout != 0) { 2642431Sigor@sysoev.ru ar->timer.handler = nxt_router_app_timeout; 2643431Sigor@sysoev.ru nxt_timer_add(task->thread->engine, &ar->timer, rc->app->timeout); 2644425Smax.romanov@nginx.com } 264588Smax.romanov@nginx.com } 264688Smax.romanov@nginx.com 264788Smax.romanov@nginx.com if (b == NULL) { 264888Smax.romanov@nginx.com return; 264988Smax.romanov@nginx.com } 265088Smax.romanov@nginx.com 2651206Smax.romanov@nginx.com if (msg->buf == b) { 2652206Smax.romanov@nginx.com /* Disable instant buffer completion/re-using by port. */ 2653206Smax.romanov@nginx.com msg->buf = NULL; 2654206Smax.romanov@nginx.com } 2655194Smax.romanov@nginx.com 2656431Sigor@sysoev.ru r = ar->request; 2657431Sigor@sysoev.ru 2658431Sigor@sysoev.ru if (r->header_sent) { 2659431Sigor@sysoev.ru nxt_buf_chain_add(&r->out, b); 2660431Sigor@sysoev.ru nxt_http_request_send_body(task, r, NULL); 2661277Sigor@sysoev.ru 266288Smax.romanov@nginx.com } else { 2663431Sigor@sysoev.ru ret = nxt_http_parse_fields(&ar->resp_parser, &b->mem); 2664431Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_DONE)) { 2665431Sigor@sysoev.ru goto fail; 2666431Sigor@sysoev.ru } 2667431Sigor@sysoev.ru 2668431Sigor@sysoev.ru r->resp.fields = ar->resp_parser.fields; 2669431Sigor@sysoev.ru 2670431Sigor@sysoev.ru ret = nxt_http_fields_process(r->resp.fields, 2671431Sigor@sysoev.ru &nxt_response_fields_hash, r); 2672431Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2673431Sigor@sysoev.ru goto fail; 2674431Sigor@sysoev.ru } 2675431Sigor@sysoev.ru 2676435Sigor@sysoev.ru if (nxt_buf_mem_used_size(&b->mem) == 0) { 2677435Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 2678435Sigor@sysoev.ru b->completion_handler, task, b, b->parent); 2679507Smax.romanov@nginx.com 2680435Sigor@sysoev.ru } else { 2681431Sigor@sysoev.ru nxt_buf_chain_add(&r->out, b); 2682431Sigor@sysoev.ru } 2683431Sigor@sysoev.ru 2684431Sigor@sysoev.ru r->state = &nxt_http_request_send_state; 2685431Sigor@sysoev.ru 2686431Sigor@sysoev.ru nxt_http_request_header_send(task, r); 2687431Sigor@sysoev.ru } 2688431Sigor@sysoev.ru 2689431Sigor@sysoev.ru return; 2690431Sigor@sysoev.ru 2691431Sigor@sysoev.ru fail: 2692431Sigor@sysoev.ru 2693431Sigor@sysoev.ru nxt_app_http_req_done(task, ar); 2694431Sigor@sysoev.ru nxt_router_rc_unlink(task, rc); 2695431Sigor@sysoev.ru 2696431Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE); 2697431Sigor@sysoev.ru } 2698431Sigor@sysoev.ru 2699431Sigor@sysoev.ru 2700431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_send_state 2701431Sigor@sysoev.ru nxt_aligned(64) = 2702431Sigor@sysoev.ru { 2703431Sigor@sysoev.ru .ready_handler = nxt_http_request_send_body, 2704431Sigor@sysoev.ru .error_handler = nxt_http_request_close_handler, 2705431Sigor@sysoev.ru }; 2706431Sigor@sysoev.ru 2707431Sigor@sysoev.ru 2708431Sigor@sysoev.ru static void 2709431Sigor@sysoev.ru nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data) 2710431Sigor@sysoev.ru { 2711431Sigor@sysoev.ru nxt_buf_t *out; 2712431Sigor@sysoev.ru nxt_http_request_t *r; 2713431Sigor@sysoev.ru 2714431Sigor@sysoev.ru r = obj; 2715431Sigor@sysoev.ru 2716431Sigor@sysoev.ru out = r->out; 2717431Sigor@sysoev.ru 2718431Sigor@sysoev.ru if (out != NULL) { 2719431Sigor@sysoev.ru r->out = NULL; 2720431Sigor@sysoev.ru nxt_http_request_send(task, r, out); 272188Smax.romanov@nginx.com } 272288Smax.romanov@nginx.com } 272388Smax.romanov@nginx.com 2724277Sigor@sysoev.ru 2725318Smax.romanov@nginx.com static void 2726318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2727318Smax.romanov@nginx.com void *data) 2728318Smax.romanov@nginx.com { 2729425Smax.romanov@nginx.com nxt_int_t res; 2730425Smax.romanov@nginx.com nxt_port_t *port; 2731425Smax.romanov@nginx.com nxt_bool_t cancelled; 2732425Smax.romanov@nginx.com nxt_req_app_link_t *ra; 2733318Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 2734318Smax.romanov@nginx.com 2735318Smax.romanov@nginx.com rc = data; 2736318Smax.romanov@nginx.com 2737425Smax.romanov@nginx.com ra = rc->ra; 2738425Smax.romanov@nginx.com 2739425Smax.romanov@nginx.com if (ra != NULL) { 2740425Smax.romanov@nginx.com cancelled = nxt_router_msg_cancel(task, &ra->msg_info, ra->stream); 2741425Smax.romanov@nginx.com 2742425Smax.romanov@nginx.com if (cancelled) { 2743425Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 2744425Smax.romanov@nginx.com 2745427Smax.romanov@nginx.com res = nxt_router_app_port(task, rc->app, ra); 2746425Smax.romanov@nginx.com 2747425Smax.romanov@nginx.com if (res == NXT_OK) { 2748425Smax.romanov@nginx.com port = ra->app_port; 2749425Smax.romanov@nginx.com 2750425Smax.romanov@nginx.com nxt_assert(port != NULL); 2751425Smax.romanov@nginx.com 2752425Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, task->thread->engine->port, rc, 2753425Smax.romanov@nginx.com port->pid); 2754425Smax.romanov@nginx.com 2755425Smax.romanov@nginx.com nxt_router_app_prepare_request(task, ra); 2756425Smax.romanov@nginx.com } 2757425Smax.romanov@nginx.com 2758425Smax.romanov@nginx.com msg->port_msg.last = 0; 2759425Smax.romanov@nginx.com 2760425Smax.romanov@nginx.com return; 2761425Smax.romanov@nginx.com } 2762425Smax.romanov@nginx.com } 2763425Smax.romanov@nginx.com 2764431Sigor@sysoev.ru nxt_http_request_error(task, rc->ap->request, NXT_HTTP_SERVICE_UNAVAILABLE); 2765318Smax.romanov@nginx.com 2766343Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 2767318Smax.romanov@nginx.com } 2768318Smax.romanov@nginx.com 2769318Smax.romanov@nginx.com 2770141Smax.romanov@nginx.com static void 2771343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2772343Smax.romanov@nginx.com void *data) 2773192Smax.romanov@nginx.com { 2774343Smax.romanov@nginx.com nxt_app_t *app; 2775343Smax.romanov@nginx.com nxt_port_t *port; 2776343Smax.romanov@nginx.com 2777343Smax.romanov@nginx.com app = data; 2778347Smax.romanov@nginx.com port = msg->u.new_port; 2779343Smax.romanov@nginx.com 2780343Smax.romanov@nginx.com nxt_assert(app != NULL); 2781343Smax.romanov@nginx.com nxt_assert(port != NULL); 2782343Smax.romanov@nginx.com 2783343Smax.romanov@nginx.com port->app = app; 2784343Smax.romanov@nginx.com 2785343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2786343Smax.romanov@nginx.com 2787507Smax.romanov@nginx.com nxt_assert(app->pending_processes != 0); 2788507Smax.romanov@nginx.com 2789507Smax.romanov@nginx.com app->pending_processes--; 2790507Smax.romanov@nginx.com app->processes++; 2791343Smax.romanov@nginx.com 2792343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2793343Smax.romanov@nginx.com 2794507Smax.romanov@nginx.com nxt_debug(task, "app '%V' new port ready, pid %PI, %d/%d", 2795507Smax.romanov@nginx.com &app->name, port->pid, app->processes, app->pending_processes); 2796343Smax.romanov@nginx.com 2797343Smax.romanov@nginx.com nxt_router_app_port_release(task, port, 0, 0); 2798192Smax.romanov@nginx.com } 2799192Smax.romanov@nginx.com 2800192Smax.romanov@nginx.com 2801192Smax.romanov@nginx.com static void 2802343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2803343Smax.romanov@nginx.com void *data) 2804192Smax.romanov@nginx.com { 2805318Smax.romanov@nginx.com nxt_app_t *app; 2806318Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2807318Smax.romanov@nginx.com nxt_req_app_link_t *ra; 2808343Smax.romanov@nginx.com 2809343Smax.romanov@nginx.com app = data; 2810343Smax.romanov@nginx.com 2811343Smax.romanov@nginx.com nxt_assert(app != NULL); 2812343Smax.romanov@nginx.com 2813343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start error", &app->name, app); 2814343Smax.romanov@nginx.com 2815343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2816343Smax.romanov@nginx.com 2817507Smax.romanov@nginx.com nxt_assert(app->pending_processes != 0); 2818507Smax.romanov@nginx.com 2819507Smax.romanov@nginx.com app->pending_processes--; 2820318Smax.romanov@nginx.com 2821318Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->requests)) { 2822318Smax.romanov@nginx.com lnk = nxt_queue_last(&app->requests); 2823318Smax.romanov@nginx.com nxt_queue_remove(lnk); 2824343Smax.romanov@nginx.com lnk->next = NULL; 2825318Smax.romanov@nginx.com 2826425Smax.romanov@nginx.com ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_requests); 2827318Smax.romanov@nginx.com 2828343Smax.romanov@nginx.com } else { 2829343Smax.romanov@nginx.com ra = NULL; 2830343Smax.romanov@nginx.com } 2831343Smax.romanov@nginx.com 2832343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2833343Smax.romanov@nginx.com 2834343Smax.romanov@nginx.com if (ra != NULL) { 2835318Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p abort next stream #%uD", 2836318Smax.romanov@nginx.com &app->name, app, ra->stream); 2837318Smax.romanov@nginx.com 2838507Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, "Failed to start application process"); 2839425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 2840318Smax.romanov@nginx.com } 2841192Smax.romanov@nginx.com 2842343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 2843192Smax.romanov@nginx.com } 2844192Smax.romanov@nginx.com 2845192Smax.romanov@nginx.com 2846343Smax.romanov@nginx.com void 2847343Smax.romanov@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i) 2848141Smax.romanov@nginx.com { 2849343Smax.romanov@nginx.com int c; 2850343Smax.romanov@nginx.com 2851343Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&app->use_count, i); 2852343Smax.romanov@nginx.com 2853343Smax.romanov@nginx.com if (i < 0 && c == -i) { 2854343Smax.romanov@nginx.com 2855343Smax.romanov@nginx.com nxt_assert(app->live == 0); 2856507Smax.romanov@nginx.com nxt_assert(app->processes == 0); 2857507Smax.romanov@nginx.com nxt_assert(app->idle_processes == 0); 2858507Smax.romanov@nginx.com nxt_assert(app->pending_processes == 0); 2859343Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->requests) != 0); 2860343Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->ports) != 0); 2861507Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->spare_ports) != 0); 2862507Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->idle_ports) != 0); 2863343Smax.romanov@nginx.com 2864163Smax.romanov@nginx.com nxt_thread_mutex_destroy(&app->mutex); 2865163Smax.romanov@nginx.com nxt_free(app); 2866163Smax.romanov@nginx.com } 2867343Smax.romanov@nginx.com } 2868343Smax.romanov@nginx.com 2869343Smax.romanov@nginx.com 2870424Smax.romanov@nginx.com nxt_inline nxt_bool_t 2871424Smax.romanov@nginx.com nxt_router_app_first_port_busy(nxt_app_t *app) 2872424Smax.romanov@nginx.com { 2873424Smax.romanov@nginx.com nxt_port_t *port; 2874424Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2875424Smax.romanov@nginx.com 2876424Smax.romanov@nginx.com lnk = nxt_queue_first(&app->ports); 2877424Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, app_link); 2878424Smax.romanov@nginx.com 2879424Smax.romanov@nginx.com return port->app_pending_responses > 0; 2880424Smax.romanov@nginx.com } 2881424Smax.romanov@nginx.com 2882424Smax.romanov@nginx.com 2883343Smax.romanov@nginx.com nxt_inline nxt_port_t * 2884427Smax.romanov@nginx.com nxt_router_pop_first_port(nxt_app_t *app) 2885343Smax.romanov@nginx.com { 2886343Smax.romanov@nginx.com nxt_port_t *port; 2887343Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2888343Smax.romanov@nginx.com 2889343Smax.romanov@nginx.com lnk = nxt_queue_first(&app->ports); 2890343Smax.romanov@nginx.com nxt_queue_remove(lnk); 2891343Smax.romanov@nginx.com 2892343Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, app_link); 2893343Smax.romanov@nginx.com 2894424Smax.romanov@nginx.com port->app_pending_responses++; 2895424Smax.romanov@nginx.com 2896507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 2897507Smax.romanov@nginx.com app->idle_processes--; 2898507Smax.romanov@nginx.com 2899507Smax.romanov@nginx.com if (port->idle_start == 0) { 2900507Smax.romanov@nginx.com nxt_assert(app->idle_processes < app->spare_processes); 2901507Smax.romanov@nginx.com 2902507Smax.romanov@nginx.com } else { 2903507Smax.romanov@nginx.com nxt_assert(app->idle_processes >= app->spare_processes); 2904507Smax.romanov@nginx.com 2905507Smax.romanov@nginx.com port->idle_start = 0; 2906507Smax.romanov@nginx.com } 2907507Smax.romanov@nginx.com } 2908507Smax.romanov@nginx.com 2909428Smax.romanov@nginx.com if ((app->max_pending_responses == 0 2910428Smax.romanov@nginx.com || port->app_pending_responses < app->max_pending_responses) 2911428Smax.romanov@nginx.com && (app->max_requests == 0 2912428Smax.romanov@nginx.com || port->app_responses + port->app_pending_responses 2913428Smax.romanov@nginx.com < app->max_requests)) 2914277Sigor@sysoev.ru { 2915343Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, lnk); 2916343Smax.romanov@nginx.com 2917425Smax.romanov@nginx.com nxt_port_inc_use(port); 2918425Smax.romanov@nginx.com 2919343Smax.romanov@nginx.com } else { 2920343Smax.romanov@nginx.com lnk->next = NULL; 2921167Smax.romanov@nginx.com } 2922167Smax.romanov@nginx.com 2923343Smax.romanov@nginx.com return port; 2924163Smax.romanov@nginx.com } 2925163Smax.romanov@nginx.com 2926163Smax.romanov@nginx.com 2927507Smax.romanov@nginx.com nxt_inline nxt_port_t * 2928507Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app) 2929141Smax.romanov@nginx.com { 2930343Smax.romanov@nginx.com nxt_port_t *port; 2931141Smax.romanov@nginx.com 2932141Smax.romanov@nginx.com port = NULL; 2933141Smax.romanov@nginx.com 2934141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2935141Smax.romanov@nginx.com 2936343Smax.romanov@nginx.com nxt_queue_each(port, &app->ports, nxt_port_t, app_link) { 2937343Smax.romanov@nginx.com 2938424Smax.romanov@nginx.com if (port->app_pending_responses > 0) { 2939343Smax.romanov@nginx.com port = NULL; 2940343Smax.romanov@nginx.com 2941343Smax.romanov@nginx.com continue; 2942343Smax.romanov@nginx.com } 2943343Smax.romanov@nginx.com 2944507Smax.romanov@nginx.com /* Caller is responsible to decrease port use count. */ 2945507Smax.romanov@nginx.com nxt_queue_chk_remove(&port->app_link); 2946507Smax.romanov@nginx.com 2947507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 2948507Smax.romanov@nginx.com app->idle_processes--; 2949507Smax.romanov@nginx.com } 2950507Smax.romanov@nginx.com 2951507Smax.romanov@nginx.com /* Caller is responsible to decrease app use count. */ 2952507Smax.romanov@nginx.com port->app = NULL; 2953507Smax.romanov@nginx.com app->processes--; 2954343Smax.romanov@nginx.com 2955343Smax.romanov@nginx.com break; 2956343Smax.romanov@nginx.com 2957343Smax.romanov@nginx.com } nxt_queue_loop; 2958141Smax.romanov@nginx.com 2959141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2960141Smax.romanov@nginx.com 2961141Smax.romanov@nginx.com return port; 2962141Smax.romanov@nginx.com } 2963141Smax.romanov@nginx.com 2964141Smax.romanov@nginx.com 2965141Smax.romanov@nginx.com static void 2966507Smax.romanov@nginx.com nxt_router_app_quit(nxt_task_t *task, nxt_app_t *app) 2967507Smax.romanov@nginx.com { 2968507Smax.romanov@nginx.com nxt_port_t *port; 2969507Smax.romanov@nginx.com 2970507Smax.romanov@nginx.com nxt_queue_remove(&app->link); 2971507Smax.romanov@nginx.com 2972507Smax.romanov@nginx.com app->live = 0; 2973507Smax.romanov@nginx.com 2974507Smax.romanov@nginx.com for ( ;; ) { 2975507Smax.romanov@nginx.com port = nxt_router_app_get_port_for_quit(app); 2976507Smax.romanov@nginx.com if (port == NULL) { 2977507Smax.romanov@nginx.com break; 2978507Smax.romanov@nginx.com } 2979507Smax.romanov@nginx.com 2980507Smax.romanov@nginx.com nxt_debug(task, "send QUIT to app '%V' pid %PI", &app->name, port->pid); 2981507Smax.romanov@nginx.com 2982507Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 2983507Smax.romanov@nginx.com 2984507Smax.romanov@nginx.com nxt_port_use(task, port, -1); 2985507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 2986507Smax.romanov@nginx.com } 2987507Smax.romanov@nginx.com 2988507Smax.romanov@nginx.com if (nxt_timer_is_in_tree(&app->idle_timer)) { 2989507Smax.romanov@nginx.com nxt_assert(app->engine == task->thread->engine); 2990507Smax.romanov@nginx.com 2991507Smax.romanov@nginx.com app->idle_timer.handler = nxt_router_app_release_handler; 2992507Smax.romanov@nginx.com nxt_timer_add(app->engine, &app->idle_timer, 0); 2993507Smax.romanov@nginx.com 2994507Smax.romanov@nginx.com } else { 2995507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 2996507Smax.romanov@nginx.com } 2997507Smax.romanov@nginx.com } 2998507Smax.romanov@nginx.com 2999507Smax.romanov@nginx.com 3000507Smax.romanov@nginx.com static void 3001343Smax.romanov@nginx.com nxt_router_app_process_request(nxt_task_t *task, void *obj, void *data) 3002141Smax.romanov@nginx.com { 3003343Smax.romanov@nginx.com nxt_app_t *app; 3004343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 3005343Smax.romanov@nginx.com 3006343Smax.romanov@nginx.com app = obj; 3007343Smax.romanov@nginx.com ra = data; 3008141Smax.romanov@nginx.com 3009141Smax.romanov@nginx.com nxt_assert(app != NULL); 3010343Smax.romanov@nginx.com nxt_assert(ra != NULL); 3011343Smax.romanov@nginx.com nxt_assert(ra->app_port != NULL); 3012343Smax.romanov@nginx.com 3013343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p process next stream #%uD", 3014343Smax.romanov@nginx.com &app->name, app, ra->stream); 3015343Smax.romanov@nginx.com 3016425Smax.romanov@nginx.com nxt_router_app_prepare_request(task, ra); 3017343Smax.romanov@nginx.com } 3018343Smax.romanov@nginx.com 3019343Smax.romanov@nginx.com 3020343Smax.romanov@nginx.com static void 3021343Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port, 3022343Smax.romanov@nginx.com uint32_t request_failed, uint32_t got_response) 3023343Smax.romanov@nginx.com { 3024427Smax.romanov@nginx.com nxt_app_t *app; 3025507Smax.romanov@nginx.com nxt_bool_t port_unchained; 3026507Smax.romanov@nginx.com nxt_bool_t send_quit, cancelled, adjust_idle_timer; 3027427Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3028427Smax.romanov@nginx.com nxt_req_app_link_t *ra, *pending_ra, *re_ra; 3029427Smax.romanov@nginx.com nxt_port_select_state_t state; 3030343Smax.romanov@nginx.com 3031343Smax.romanov@nginx.com nxt_assert(port != NULL); 3032343Smax.romanov@nginx.com nxt_assert(port->app != NULL); 3033343Smax.romanov@nginx.com 3034427Smax.romanov@nginx.com ra = NULL; 3035427Smax.romanov@nginx.com 3036343Smax.romanov@nginx.com app = port->app; 3037343Smax.romanov@nginx.com 3038343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3039343Smax.romanov@nginx.com 3040424Smax.romanov@nginx.com port->app_pending_responses -= request_failed + got_response; 3041343Smax.romanov@nginx.com port->app_responses += got_response; 3042343Smax.romanov@nginx.com 3043427Smax.romanov@nginx.com if (nxt_slow_path(app->live == 0)) { 3044427Smax.romanov@nginx.com goto app_dead; 3045427Smax.romanov@nginx.com } 3046427Smax.romanov@nginx.com 3047427Smax.romanov@nginx.com if (port->pair[1] != -1 3048426Smax.romanov@nginx.com && (app->max_pending_responses == 0 3049428Smax.romanov@nginx.com || port->app_pending_responses < app->max_pending_responses) 3050428Smax.romanov@nginx.com && (app->max_requests == 0 3051428Smax.romanov@nginx.com || port->app_responses + port->app_pending_responses 3052428Smax.romanov@nginx.com < app->max_requests)) 3053343Smax.romanov@nginx.com { 3054424Smax.romanov@nginx.com if (port->app_link.next == NULL) { 3055424Smax.romanov@nginx.com if (port->app_pending_responses > 0) { 3056424Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &port->app_link); 3057424Smax.romanov@nginx.com 3058424Smax.romanov@nginx.com } else { 3059424Smax.romanov@nginx.com nxt_queue_insert_head(&app->ports, &port->app_link); 3060424Smax.romanov@nginx.com } 3061424Smax.romanov@nginx.com 3062425Smax.romanov@nginx.com nxt_port_inc_use(port); 3063424Smax.romanov@nginx.com 3064424Smax.romanov@nginx.com } else { 3065424Smax.romanov@nginx.com if (port->app_pending_responses == 0 3066424Smax.romanov@nginx.com && nxt_queue_first(&app->ports) != &port->app_link) 3067424Smax.romanov@nginx.com { 3068424Smax.romanov@nginx.com nxt_queue_remove(&port->app_link); 3069424Smax.romanov@nginx.com nxt_queue_insert_head(&app->ports, &port->app_link); 3070424Smax.romanov@nginx.com } 3071424Smax.romanov@nginx.com } 3072141Smax.romanov@nginx.com } 3073141Smax.romanov@nginx.com 3074427Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->ports) 3075426Smax.romanov@nginx.com && !nxt_queue_is_empty(&app->requests)) 3076343Smax.romanov@nginx.com { 3077141Smax.romanov@nginx.com lnk = nxt_queue_first(&app->requests); 3078141Smax.romanov@nginx.com nxt_queue_remove(lnk); 3079343Smax.romanov@nginx.com lnk->next = NULL; 3080141Smax.romanov@nginx.com 3081425Smax.romanov@nginx.com ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_requests); 3082425Smax.romanov@nginx.com 3083427Smax.romanov@nginx.com ra->app_port = nxt_router_pop_first_port(app); 3084425Smax.romanov@nginx.com 3085425Smax.romanov@nginx.com if (ra->app_port->app_pending_responses > 1) { 3086427Smax.romanov@nginx.com nxt_router_ra_pending(task, app, ra); 3087425Smax.romanov@nginx.com } 3088425Smax.romanov@nginx.com } 3089425Smax.romanov@nginx.com 3090427Smax.romanov@nginx.com app_dead: 3091427Smax.romanov@nginx.com 3092427Smax.romanov@nginx.com /* Pop first pending request for this port. */ 3093425Smax.romanov@nginx.com if ((request_failed > 0 || got_response > 0) 3094425Smax.romanov@nginx.com && !nxt_queue_is_empty(&port->pending_requests)) 3095425Smax.romanov@nginx.com { 3096425Smax.romanov@nginx.com lnk = nxt_queue_first(&port->pending_requests); 3097425Smax.romanov@nginx.com nxt_queue_remove(lnk); 3098425Smax.romanov@nginx.com lnk->next = NULL; 3099425Smax.romanov@nginx.com 3100427Smax.romanov@nginx.com pending_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, 3101427Smax.romanov@nginx.com link_port_pending); 3102427Smax.romanov@nginx.com 3103427Smax.romanov@nginx.com nxt_assert(pending_ra->link_app_pending.next != NULL); 3104427Smax.romanov@nginx.com 3105427Smax.romanov@nginx.com nxt_queue_remove(&pending_ra->link_app_pending); 3106427Smax.romanov@nginx.com pending_ra->link_app_pending.next = NULL; 3107425Smax.romanov@nginx.com 3108425Smax.romanov@nginx.com } else { 3109427Smax.romanov@nginx.com pending_ra = NULL; 3110141Smax.romanov@nginx.com } 3111141Smax.romanov@nginx.com 3112427Smax.romanov@nginx.com /* Try to cancel and re-schedule first stalled request for this app. */ 3113427Smax.romanov@nginx.com if (got_response > 0 && !nxt_queue_is_empty(&app->pending)) { 3114427Smax.romanov@nginx.com lnk = nxt_queue_first(&app->pending); 3115427Smax.romanov@nginx.com 3116427Smax.romanov@nginx.com re_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_pending); 3117427Smax.romanov@nginx.com 3118427Smax.romanov@nginx.com if (re_ra->res_time <= nxt_thread_monotonic_time(task->thread)) { 3119427Smax.romanov@nginx.com 3120427Smax.romanov@nginx.com nxt_debug(task, "app '%V' stalled request #%uD detected", 3121427Smax.romanov@nginx.com &app->name, re_ra->stream); 3122427Smax.romanov@nginx.com 3123427Smax.romanov@nginx.com cancelled = nxt_router_msg_cancel(task, &re_ra->msg_info, 3124427Smax.romanov@nginx.com re_ra->stream); 3125427Smax.romanov@nginx.com 3126427Smax.romanov@nginx.com if (cancelled) { 3127427Smax.romanov@nginx.com nxt_router_ra_inc_use(re_ra); 3128427Smax.romanov@nginx.com 3129427Smax.romanov@nginx.com state.ra = re_ra; 3130427Smax.romanov@nginx.com state.app = app; 3131427Smax.romanov@nginx.com 3132427Smax.romanov@nginx.com nxt_router_port_select(task, &state); 3133427Smax.romanov@nginx.com 3134427Smax.romanov@nginx.com goto re_ra_cancelled; 3135427Smax.romanov@nginx.com } 3136427Smax.romanov@nginx.com } 3137427Smax.romanov@nginx.com } 3138427Smax.romanov@nginx.com 3139427Smax.romanov@nginx.com re_ra = NULL; 3140427Smax.romanov@nginx.com 3141427Smax.romanov@nginx.com re_ra_cancelled: 3142427Smax.romanov@nginx.com 3143507Smax.romanov@nginx.com send_quit = (app->live == 0 && port->app_pending_responses == 0) 3144428Smax.romanov@nginx.com || (app->max_requests > 0 && port->app_pending_responses == 0 3145428Smax.romanov@nginx.com && port->app_responses >= app->max_requests); 3146367Smax.romanov@nginx.com 3147507Smax.romanov@nginx.com if (send_quit) { 3148507Smax.romanov@nginx.com port_unchained = nxt_queue_chk_remove(&port->app_link); 3149507Smax.romanov@nginx.com 3150507Smax.romanov@nginx.com port->app = NULL; 3151507Smax.romanov@nginx.com app->processes--; 3152507Smax.romanov@nginx.com 3153507Smax.romanov@nginx.com } else { 3154507Smax.romanov@nginx.com port_unchained = 0; 3155507Smax.romanov@nginx.com } 3156507Smax.romanov@nginx.com 3157507Smax.romanov@nginx.com adjust_idle_timer = 0; 3158507Smax.romanov@nginx.com 3159507Smax.romanov@nginx.com if (!send_quit && port->app_pending_responses == 0) { 3160507Smax.romanov@nginx.com nxt_assert(port->idle_link.next == NULL); 3161507Smax.romanov@nginx.com 3162507Smax.romanov@nginx.com if (app->idle_processes == app->spare_processes 3163507Smax.romanov@nginx.com && app->adjust_idle_work.data == NULL) 3164507Smax.romanov@nginx.com { 3165507Smax.romanov@nginx.com adjust_idle_timer = 1; 3166507Smax.romanov@nginx.com app->adjust_idle_work.data = app; 3167507Smax.romanov@nginx.com app->adjust_idle_work.next = NULL; 3168507Smax.romanov@nginx.com } 3169507Smax.romanov@nginx.com 3170507Smax.romanov@nginx.com if (app->idle_processes < app->spare_processes) { 3171507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, &port->idle_link); 3172507Smax.romanov@nginx.com 3173507Smax.romanov@nginx.com } else { 3174507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->idle_ports, &port->idle_link); 3175507Smax.romanov@nginx.com 3176507Smax.romanov@nginx.com port->idle_start = task->thread->engine->timers.now; 3177507Smax.romanov@nginx.com } 3178507Smax.romanov@nginx.com 3179507Smax.romanov@nginx.com app->idle_processes++; 3180507Smax.romanov@nginx.com } 3181507Smax.romanov@nginx.com 3182343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3183343Smax.romanov@nginx.com 3184507Smax.romanov@nginx.com if (adjust_idle_timer) { 3185507Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 3186507Smax.romanov@nginx.com nxt_event_engine_post(app->engine, &app->adjust_idle_work); 3187507Smax.romanov@nginx.com } 3188507Smax.romanov@nginx.com 3189427Smax.romanov@nginx.com if (pending_ra != NULL) { 3190427Smax.romanov@nginx.com nxt_router_ra_use(task, pending_ra, -1); 3191427Smax.romanov@nginx.com } 3192427Smax.romanov@nginx.com 3193427Smax.romanov@nginx.com if (re_ra != NULL) { 3194427Smax.romanov@nginx.com if (nxt_router_port_post_select(task, &state) == NXT_OK) { 3195427Smax.romanov@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 3196427Smax.romanov@nginx.com nxt_router_app_process_request, 3197427Smax.romanov@nginx.com &task->thread->engine->task, app, re_ra); 3198427Smax.romanov@nginx.com } 3199425Smax.romanov@nginx.com } 3200425Smax.romanov@nginx.com 3201343Smax.romanov@nginx.com if (ra != NULL) { 3202425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 3203425Smax.romanov@nginx.com 3204343Smax.romanov@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 3205343Smax.romanov@nginx.com nxt_router_app_process_request, 3206343Smax.romanov@nginx.com &task->thread->engine->task, app, ra); 3207343Smax.romanov@nginx.com 3208343Smax.romanov@nginx.com goto adjust_use; 3209343Smax.romanov@nginx.com } 3210343Smax.romanov@nginx.com 3211343Smax.romanov@nginx.com /* ? */ 3212163Smax.romanov@nginx.com if (port->pair[1] == -1) { 3213343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)", 3214343Smax.romanov@nginx.com &app->name, app, port, port->pid); 3215343Smax.romanov@nginx.com 3216343Smax.romanov@nginx.com goto adjust_use; 3217163Smax.romanov@nginx.com } 3218163Smax.romanov@nginx.com 3219367Smax.romanov@nginx.com if (send_quit) { 3220507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p send QUIT to port", 3221167Smax.romanov@nginx.com &app->name, app); 3222163Smax.romanov@nginx.com 3223163Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, 3224163Smax.romanov@nginx.com -1, 0, 0, NULL); 3225163Smax.romanov@nginx.com 3226507Smax.romanov@nginx.com if (port_unchained) { 3227507Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3228507Smax.romanov@nginx.com } 3229507Smax.romanov@nginx.com 3230507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 3231507Smax.romanov@nginx.com 3232343Smax.romanov@nginx.com goto adjust_use; 3233163Smax.romanov@nginx.com } 3234163Smax.romanov@nginx.com 3235167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p requests queue is empty, keep the port", 3236167Smax.romanov@nginx.com &app->name, app); 3237141Smax.romanov@nginx.com 3238343Smax.romanov@nginx.com adjust_use: 3239343Smax.romanov@nginx.com 3240425Smax.romanov@nginx.com if (request_failed > 0 || got_response > 0) { 3241425Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3242343Smax.romanov@nginx.com } 3243141Smax.romanov@nginx.com } 3244141Smax.romanov@nginx.com 3245141Smax.romanov@nginx.com 3246343Smax.romanov@nginx.com void 3247343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port) 3248141Smax.romanov@nginx.com { 3249507Smax.romanov@nginx.com nxt_app_t *app; 3250507Smax.romanov@nginx.com nxt_bool_t unchain, start_process; 3251507Smax.romanov@nginx.com nxt_port_t *idle_port; 3252507Smax.romanov@nginx.com nxt_queue_link_t *idle_lnk; 3253141Smax.romanov@nginx.com 3254141Smax.romanov@nginx.com app = port->app; 3255343Smax.romanov@nginx.com 3256343Smax.romanov@nginx.com nxt_assert(app != NULL); 3257141Smax.romanov@nginx.com 3258141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3259141Smax.romanov@nginx.com 3260507Smax.romanov@nginx.com unchain = nxt_queue_chk_remove(&port->app_link); 3261507Smax.romanov@nginx.com 3262507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 3263507Smax.romanov@nginx.com app->idle_processes--; 3264507Smax.romanov@nginx.com 3265507Smax.romanov@nginx.com if (port->idle_start == 0 3266507Smax.romanov@nginx.com && app->idle_processes >= app->spare_processes) 3267507Smax.romanov@nginx.com { 3268507Smax.romanov@nginx.com nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); 3269507Smax.romanov@nginx.com 3270507Smax.romanov@nginx.com idle_lnk = nxt_queue_last(&app->idle_ports); 3271507Smax.romanov@nginx.com idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link); 3272507Smax.romanov@nginx.com nxt_queue_remove(idle_lnk); 3273507Smax.romanov@nginx.com 3274507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, idle_lnk); 3275507Smax.romanov@nginx.com 3276507Smax.romanov@nginx.com idle_port->idle_start = 0; 3277507Smax.romanov@nginx.com } 3278343Smax.romanov@nginx.com } 3279343Smax.romanov@nginx.com 3280507Smax.romanov@nginx.com app->processes--; 3281507Smax.romanov@nginx.com 3282507Smax.romanov@nginx.com start_process = app->live != 0 3283507Smax.romanov@nginx.com && !task->thread->engine->shutdown 3284507Smax.romanov@nginx.com && nxt_router_app_can_start(app) 3285507Smax.romanov@nginx.com && (!nxt_queue_is_empty(&app->requests) 3286507Smax.romanov@nginx.com || nxt_router_app_need_start(app)); 3287507Smax.romanov@nginx.com 3288507Smax.romanov@nginx.com if (start_process) { 3289507Smax.romanov@nginx.com app->pending_processes++; 3290163Smax.romanov@nginx.com } 3291141Smax.romanov@nginx.com 3292141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3293163Smax.romanov@nginx.com 3294507Smax.romanov@nginx.com nxt_debug(task, "app '%V' pid %PI closed", &app->name, port->pid); 3295343Smax.romanov@nginx.com 3296343Smax.romanov@nginx.com if (unchain) { 3297343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3298163Smax.romanov@nginx.com } 3299163Smax.romanov@nginx.com 3300507Smax.romanov@nginx.com if (start_process) { 3301507Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 3302507Smax.romanov@nginx.com } 3303507Smax.romanov@nginx.com } 3304507Smax.romanov@nginx.com 3305507Smax.romanov@nginx.com 3306507Smax.romanov@nginx.com static void 3307507Smax.romanov@nginx.com nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, void *data) 3308507Smax.romanov@nginx.com { 3309507Smax.romanov@nginx.com nxt_app_t *app; 3310507Smax.romanov@nginx.com nxt_bool_t queued; 3311507Smax.romanov@nginx.com nxt_port_t *port; 3312507Smax.romanov@nginx.com nxt_msec_t timeout, threshold; 3313507Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3314507Smax.romanov@nginx.com nxt_event_engine_t *engine; 3315507Smax.romanov@nginx.com 3316507Smax.romanov@nginx.com app = obj; 3317507Smax.romanov@nginx.com queued = (data == app); 3318507Smax.romanov@nginx.com 3319507Smax.romanov@nginx.com nxt_debug(task, "nxt_router_adjust_idle_timer: app \"%V\", queued %b", 3320507Smax.romanov@nginx.com &app->name, queued); 3321507Smax.romanov@nginx.com 3322507Smax.romanov@nginx.com engine = task->thread->engine; 3323507Smax.romanov@nginx.com 3324507Smax.romanov@nginx.com nxt_assert(app->engine == engine); 3325507Smax.romanov@nginx.com 3326507Smax.romanov@nginx.com threshold = engine->timers.now + app->idle_timer.precision; 3327507Smax.romanov@nginx.com timeout = 0; 3328507Smax.romanov@nginx.com 3329507Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3330507Smax.romanov@nginx.com 3331507Smax.romanov@nginx.com if (queued) { 3332507Smax.romanov@nginx.com app->adjust_idle_work.data = NULL; 3333343Smax.romanov@nginx.com } 3334507Smax.romanov@nginx.com 3335507Smax.romanov@nginx.com while (app->idle_processes > app->spare_processes) { 3336507Smax.romanov@nginx.com 3337507Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->idle_ports) == 0); 3338507Smax.romanov@nginx.com 3339507Smax.romanov@nginx.com lnk = nxt_queue_first(&app->idle_ports); 3340507Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, idle_link); 3341507Smax.romanov@nginx.com 3342507Smax.romanov@nginx.com timeout = port->idle_start + app->idle_timeout; 3343507Smax.romanov@nginx.com 3344507Smax.romanov@nginx.com if (timeout > threshold) { 3345507Smax.romanov@nginx.com break; 3346507Smax.romanov@nginx.com } 3347507Smax.romanov@nginx.com 3348507Smax.romanov@nginx.com nxt_queue_remove(lnk); 3349507Smax.romanov@nginx.com lnk->next = NULL; 3350507Smax.romanov@nginx.com 3351507Smax.romanov@nginx.com nxt_queue_chk_remove(&port->app_link); 3352507Smax.romanov@nginx.com 3353507Smax.romanov@nginx.com app->idle_processes--; 3354507Smax.romanov@nginx.com app->processes--; 3355507Smax.romanov@nginx.com port->app = NULL; 3356507Smax.romanov@nginx.com 3357507Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3358507Smax.romanov@nginx.com 3359507Smax.romanov@nginx.com nxt_debug(task, "app '%V' send QUIT to idle port %PI", 3360507Smax.romanov@nginx.com &app->name, port->pid); 3361507Smax.romanov@nginx.com 3362507Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 3363507Smax.romanov@nginx.com 3364507Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3365507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 3366507Smax.romanov@nginx.com 3367507Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3368507Smax.romanov@nginx.com } 3369507Smax.romanov@nginx.com 3370507Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3371507Smax.romanov@nginx.com 3372507Smax.romanov@nginx.com if (timeout > threshold) { 3373507Smax.romanov@nginx.com nxt_timer_add(engine, &app->idle_timer, timeout - threshold); 3374507Smax.romanov@nginx.com 3375507Smax.romanov@nginx.com } else { 3376507Smax.romanov@nginx.com nxt_timer_disable(engine, &app->idle_timer); 3377507Smax.romanov@nginx.com } 3378507Smax.romanov@nginx.com 3379507Smax.romanov@nginx.com if (queued) { 3380507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 3381507Smax.romanov@nginx.com } 3382507Smax.romanov@nginx.com } 3383507Smax.romanov@nginx.com 3384507Smax.romanov@nginx.com 3385507Smax.romanov@nginx.com static void 3386507Smax.romanov@nginx.com nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, void *data) 3387507Smax.romanov@nginx.com { 3388507Smax.romanov@nginx.com nxt_app_t *app; 3389507Smax.romanov@nginx.com nxt_timer_t *timer; 3390507Smax.romanov@nginx.com 3391507Smax.romanov@nginx.com timer = obj; 3392507Smax.romanov@nginx.com app = nxt_container_of(timer, nxt_app_t, idle_timer); 3393507Smax.romanov@nginx.com 3394507Smax.romanov@nginx.com nxt_router_adjust_idle_timer(task, app, NULL); 3395507Smax.romanov@nginx.com } 3396507Smax.romanov@nginx.com 3397507Smax.romanov@nginx.com 3398507Smax.romanov@nginx.com static void 3399507Smax.romanov@nginx.com nxt_router_app_release_handler(nxt_task_t *task, void *obj, void *data) 3400507Smax.romanov@nginx.com { 3401507Smax.romanov@nginx.com nxt_app_t *app; 3402507Smax.romanov@nginx.com nxt_timer_t *timer; 3403507Smax.romanov@nginx.com 3404507Smax.romanov@nginx.com timer = obj; 3405507Smax.romanov@nginx.com app = nxt_container_of(timer, nxt_app_t, idle_timer); 3406507Smax.romanov@nginx.com 3407507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 3408141Smax.romanov@nginx.com } 3409141Smax.romanov@nginx.com 3410141Smax.romanov@nginx.com 3411427Smax.romanov@nginx.com static void 3412427Smax.romanov@nginx.com nxt_router_port_select(nxt_task_t *task, nxt_port_select_state_t *state) 3413141Smax.romanov@nginx.com { 3414427Smax.romanov@nginx.com nxt_app_t *app; 3415507Smax.romanov@nginx.com nxt_bool_t can_start_process; 3416427Smax.romanov@nginx.com nxt_req_app_link_t *ra; 3417427Smax.romanov@nginx.com 3418427Smax.romanov@nginx.com ra = state->ra; 3419427Smax.romanov@nginx.com app = state->app; 3420427Smax.romanov@nginx.com 3421427Smax.romanov@nginx.com state->failed_port_use_delta = 0; 3422343Smax.romanov@nginx.com 3423425Smax.romanov@nginx.com if (nxt_queue_chk_remove(&ra->link_app_requests)) 3424425Smax.romanov@nginx.com { 3425425Smax.romanov@nginx.com nxt_router_ra_dec_use(ra); 3426425Smax.romanov@nginx.com } 3427425Smax.romanov@nginx.com 3428425Smax.romanov@nginx.com if (nxt_queue_chk_remove(&ra->link_port_pending)) 3429425Smax.romanov@nginx.com { 3430427Smax.romanov@nginx.com nxt_assert(ra->link_app_pending.next != NULL); 3431427Smax.romanov@nginx.com 3432427Smax.romanov@nginx.com nxt_queue_remove(&ra->link_app_pending); 3433427Smax.romanov@nginx.com ra->link_app_pending.next = NULL; 3434427Smax.romanov@nginx.com 3435425Smax.romanov@nginx.com nxt_router_ra_dec_use(ra); 3436425Smax.romanov@nginx.com } 3437425Smax.romanov@nginx.com 3438427Smax.romanov@nginx.com state->failed_port = ra->app_port; 3439427Smax.romanov@nginx.com 3440425Smax.romanov@nginx.com if (ra->app_port != NULL) { 3441427Smax.romanov@nginx.com state->failed_port_use_delta--; 3442427Smax.romanov@nginx.com 3443427Smax.romanov@nginx.com state->failed_port->app_pending_responses--; 3444427Smax.romanov@nginx.com 3445427Smax.romanov@nginx.com if (nxt_queue_chk_remove(&state->failed_port->app_link)) { 3446427Smax.romanov@nginx.com state->failed_port_use_delta--; 3447427Smax.romanov@nginx.com } 3448427Smax.romanov@nginx.com 3449427Smax.romanov@nginx.com ra->app_port = NULL; 3450427Smax.romanov@nginx.com } 3451427Smax.romanov@nginx.com 3452507Smax.romanov@nginx.com can_start_process = nxt_router_app_can_start(app); 3453507Smax.romanov@nginx.com 3454427Smax.romanov@nginx.com state->port = NULL; 3455507Smax.romanov@nginx.com state->start_process = 0; 3456427Smax.romanov@nginx.com 3457427Smax.romanov@nginx.com if (nxt_queue_is_empty(&app->ports) 3458507Smax.romanov@nginx.com || (can_start_process && nxt_router_app_first_port_busy(app)) ) 3459427Smax.romanov@nginx.com { 3460427Smax.romanov@nginx.com ra = nxt_router_ra_create(task, ra); 3461427Smax.romanov@nginx.com 3462427Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 3463427Smax.romanov@nginx.com goto fail; 3464427Smax.romanov@nginx.com } 3465427Smax.romanov@nginx.com 3466427Smax.romanov@nginx.com if (nxt_slow_path(state->failed_port != NULL)) { 3467427Smax.romanov@nginx.com nxt_queue_insert_head(&app->requests, &ra->link_app_requests); 3468427Smax.romanov@nginx.com 3469427Smax.romanov@nginx.com } else { 3470427Smax.romanov@nginx.com nxt_queue_insert_tail(&app->requests, &ra->link_app_requests); 3471427Smax.romanov@nginx.com } 3472427Smax.romanov@nginx.com 3473427Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 3474427Smax.romanov@nginx.com 3475427Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD enqueue to app->requests", ra->stream); 3476427Smax.romanov@nginx.com 3477507Smax.romanov@nginx.com if (can_start_process) { 3478507Smax.romanov@nginx.com app->pending_processes++; 3479507Smax.romanov@nginx.com state->start_process = 1; 3480425Smax.romanov@nginx.com } 3481425Smax.romanov@nginx.com 3482425Smax.romanov@nginx.com } else { 3483427Smax.romanov@nginx.com state->port = nxt_router_pop_first_port(app); 3484427Smax.romanov@nginx.com 3485427Smax.romanov@nginx.com if (state->port->app_pending_responses > 1) { 3486427Smax.romanov@nginx.com ra = nxt_router_ra_create(task, ra); 3487427Smax.romanov@nginx.com 3488427Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 3489427Smax.romanov@nginx.com goto fail; 3490351Smax.romanov@nginx.com } 3491427Smax.romanov@nginx.com 3492427Smax.romanov@nginx.com ra->app_port = state->port; 3493427Smax.romanov@nginx.com 3494427Smax.romanov@nginx.com nxt_router_ra_pending(task, app, ra); 3495425Smax.romanov@nginx.com } 3496507Smax.romanov@nginx.com 3497507Smax.romanov@nginx.com if (can_start_process && nxt_router_app_need_start(app)) { 3498507Smax.romanov@nginx.com app->pending_processes++; 3499507Smax.romanov@nginx.com state->start_process = 1; 3500507Smax.romanov@nginx.com } 3501343Smax.romanov@nginx.com } 3502343Smax.romanov@nginx.com 3503427Smax.romanov@nginx.com fail: 3504427Smax.romanov@nginx.com 3505427Smax.romanov@nginx.com state->shared_ra = ra; 3506427Smax.romanov@nginx.com } 3507427Smax.romanov@nginx.com 3508427Smax.romanov@nginx.com 3509427Smax.romanov@nginx.com static nxt_int_t 3510427Smax.romanov@nginx.com nxt_router_port_post_select(nxt_task_t *task, nxt_port_select_state_t *state) 3511427Smax.romanov@nginx.com { 3512427Smax.romanov@nginx.com nxt_int_t res; 3513427Smax.romanov@nginx.com nxt_app_t *app; 3514427Smax.romanov@nginx.com nxt_req_app_link_t *ra; 3515427Smax.romanov@nginx.com 3516427Smax.romanov@nginx.com ra = state->shared_ra; 3517427Smax.romanov@nginx.com app = state->app; 3518427Smax.romanov@nginx.com 3519427Smax.romanov@nginx.com if (state->failed_port_use_delta != 0) { 3520427Smax.romanov@nginx.com nxt_port_use(task, state->failed_port, state->failed_port_use_delta); 3521425Smax.romanov@nginx.com } 3522425Smax.romanov@nginx.com 3523351Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 3524427Smax.romanov@nginx.com if (state->port != NULL) { 3525427Smax.romanov@nginx.com nxt_port_use(task, state->port, -1); 3526425Smax.romanov@nginx.com } 3527425Smax.romanov@nginx.com 3528427Smax.romanov@nginx.com nxt_router_ra_error(state->ra, 500, 3529427Smax.romanov@nginx.com "Failed to allocate shared req<->app link"); 3530427Smax.romanov@nginx.com nxt_router_ra_use(task, state->ra, -1); 3531427Smax.romanov@nginx.com 3532351Smax.romanov@nginx.com return NXT_ERROR; 3533351Smax.romanov@nginx.com } 3534351Smax.romanov@nginx.com 3535427Smax.romanov@nginx.com if (state->port != NULL) { 3536343Smax.romanov@nginx.com nxt_debug(task, "already have port for app '%V' %p ", &app->name, app); 3537163Smax.romanov@nginx.com 3538427Smax.romanov@nginx.com ra->app_port = state->port; 3539343Smax.romanov@nginx.com 3540507Smax.romanov@nginx.com if (state->start_process) { 3541507Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 3542507Smax.romanov@nginx.com } 3543507Smax.romanov@nginx.com 3544141Smax.romanov@nginx.com return NXT_OK; 3545141Smax.romanov@nginx.com } 3546141Smax.romanov@nginx.com 3547507Smax.romanov@nginx.com if (!state->start_process) { 3548507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p too many running or pending processes", 3549343Smax.romanov@nginx.com &app->name, app); 3550343Smax.romanov@nginx.com 3551343Smax.romanov@nginx.com return NXT_AGAIN; 3552343Smax.romanov@nginx.com } 3553343Smax.romanov@nginx.com 3554507Smax.romanov@nginx.com res = nxt_router_start_app_process(task, app); 3555343Smax.romanov@nginx.com 3556343Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3557507Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, "Failed to start app process"); 3558427Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 3559343Smax.romanov@nginx.com 3560141Smax.romanov@nginx.com return NXT_ERROR; 3561141Smax.romanov@nginx.com } 3562141Smax.romanov@nginx.com 3563141Smax.romanov@nginx.com return NXT_AGAIN; 356488Smax.romanov@nginx.com } 356588Smax.romanov@nginx.com 356688Smax.romanov@nginx.com 3567427Smax.romanov@nginx.com static nxt_int_t 3568427Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra) 3569427Smax.romanov@nginx.com { 3570427Smax.romanov@nginx.com nxt_port_select_state_t state; 3571427Smax.romanov@nginx.com 3572427Smax.romanov@nginx.com state.ra = ra; 3573427Smax.romanov@nginx.com state.app = app; 3574427Smax.romanov@nginx.com 3575427Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3576427Smax.romanov@nginx.com 3577427Smax.romanov@nginx.com nxt_router_port_select(task, &state); 3578427Smax.romanov@nginx.com 3579427Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3580427Smax.romanov@nginx.com 3581427Smax.romanov@nginx.com return nxt_router_port_post_select(task, &state); 3582427Smax.romanov@nginx.com } 3583427Smax.romanov@nginx.com 3584427Smax.romanov@nginx.com 3585431Sigor@sysoev.ru void 3586431Sigor@sysoev.ru nxt_router_process_http_request(nxt_task_t *task, nxt_app_parse_ctx_t *ar) 358753Sigor@sysoev.ru { 3588431Sigor@sysoev.ru nxt_int_t res; 3589431Sigor@sysoev.ru nxt_app_t *app; 3590431Sigor@sysoev.ru nxt_port_t *port; 3591431Sigor@sysoev.ru nxt_event_engine_t *engine; 3592431Sigor@sysoev.ru nxt_http_request_t *r; 3593431Sigor@sysoev.ru nxt_req_app_link_t ra_local, *ra; 3594431Sigor@sysoev.ru nxt_req_conn_link_t *rc; 3595431Sigor@sysoev.ru 3596431Sigor@sysoev.ru r = ar->request; 3597431Sigor@sysoev.ru app = r->socket_conf->application; 3598425Smax.romanov@nginx.com 3599425Smax.romanov@nginx.com if (app == NULL) { 3600431Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 3601425Smax.romanov@nginx.com return; 3602425Smax.romanov@nginx.com } 360388Smax.romanov@nginx.com 360488Smax.romanov@nginx.com engine = task->thread->engine; 360588Smax.romanov@nginx.com 3606318Smax.romanov@nginx.com rc = nxt_port_rpc_register_handler_ex(task, engine->port, 3607318Smax.romanov@nginx.com nxt_router_response_ready_handler, 3608318Smax.romanov@nginx.com nxt_router_response_error_handler, 3609318Smax.romanov@nginx.com sizeof(nxt_req_conn_link_t)); 3610122Smax.romanov@nginx.com 361188Smax.romanov@nginx.com if (nxt_slow_path(rc == NULL)) { 3612431Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 3613141Smax.romanov@nginx.com return; 361488Smax.romanov@nginx.com } 361588Smax.romanov@nginx.com 3616318Smax.romanov@nginx.com rc->stream = nxt_port_rpc_ex_stream(rc); 3617425Smax.romanov@nginx.com rc->app = app; 3618425Smax.romanov@nginx.com 3619425Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 3620425Smax.romanov@nginx.com 3621431Sigor@sysoev.ru rc->ap = ar; 3622346Smax.romanov@nginx.com 3623351Smax.romanov@nginx.com ra = &ra_local; 3624351Smax.romanov@nginx.com nxt_router_ra_init(task, ra, rc); 3625167Smax.romanov@nginx.com 3626427Smax.romanov@nginx.com res = nxt_router_app_port(task, app, ra); 3627141Smax.romanov@nginx.com 3628141Smax.romanov@nginx.com if (res != NXT_OK) { 3629141Smax.romanov@nginx.com return; 3630141Smax.romanov@nginx.com } 3631141Smax.romanov@nginx.com 3632425Smax.romanov@nginx.com ra = rc->ra; 3633167Smax.romanov@nginx.com port = ra->app_port; 3634141Smax.romanov@nginx.com 3635425Smax.romanov@nginx.com nxt_assert(port != NULL); 3636141Smax.romanov@nginx.com 3637318Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, engine->port, rc, port->pid); 3638318Smax.romanov@nginx.com 3639425Smax.romanov@nginx.com nxt_router_app_prepare_request(task, ra); 3640167Smax.romanov@nginx.com } 3641167Smax.romanov@nginx.com 3642167Smax.romanov@nginx.com 3643167Smax.romanov@nginx.com static void 3644423Smax.romanov@nginx.com nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj, void *data) 3645423Smax.romanov@nginx.com { 3646423Smax.romanov@nginx.com } 3647423Smax.romanov@nginx.com 3648423Smax.romanov@nginx.com 3649423Smax.romanov@nginx.com static void 3650425Smax.romanov@nginx.com nxt_router_app_prepare_request(nxt_task_t *task, nxt_req_app_link_t *ra) 3651167Smax.romanov@nginx.com { 3652343Smax.romanov@nginx.com uint32_t request_failed; 3653423Smax.romanov@nginx.com nxt_buf_t *b; 3654167Smax.romanov@nginx.com nxt_int_t res; 3655343Smax.romanov@nginx.com nxt_port_t *port, *c_port, *reply_port; 3656167Smax.romanov@nginx.com nxt_app_wmsg_t wmsg; 3657167Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 3658167Smax.romanov@nginx.com 3659343Smax.romanov@nginx.com nxt_assert(ra->app_port != NULL); 3660343Smax.romanov@nginx.com 3661343Smax.romanov@nginx.com port = ra->app_port; 3662167Smax.romanov@nginx.com reply_port = ra->reply_port; 3663167Smax.romanov@nginx.com ap = ra->ap; 3664141Smax.romanov@nginx.com 3665343Smax.romanov@nginx.com request_failed = 1; 3666343Smax.romanov@nginx.com 3667141Smax.romanov@nginx.com c_port = nxt_process_connected_port_find(port->process, reply_port->pid, 3668141Smax.romanov@nginx.com reply_port->id); 3669141Smax.romanov@nginx.com if (nxt_slow_path(c_port != reply_port)) { 3670141Smax.romanov@nginx.com res = nxt_port_send_port(task, port, reply_port, 0); 3671122Smax.romanov@nginx.com 3672122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3673423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 3674345Smax.romanov@nginx.com "Failed to send reply port to application"); 3675343Smax.romanov@nginx.com goto release_port; 3676122Smax.romanov@nginx.com } 3677122Smax.romanov@nginx.com 3678141Smax.romanov@nginx.com nxt_process_connected_port_add(port->process, reply_port); 367988Smax.romanov@nginx.com } 368088Smax.romanov@nginx.com 368188Smax.romanov@nginx.com wmsg.port = port; 368288Smax.romanov@nginx.com wmsg.write = NULL; 368388Smax.romanov@nginx.com wmsg.buf = &wmsg.write; 3684318Smax.romanov@nginx.com wmsg.stream = ra->stream; 3685167Smax.romanov@nginx.com 3686216Sigor@sysoev.ru res = port->app->prepare_msg(task, &ap->r, &wmsg); 3687122Smax.romanov@nginx.com 3688122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3689423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 3690345Smax.romanov@nginx.com "Failed to prepare message for application"); 3691343Smax.romanov@nginx.com goto release_port; 3692122Smax.romanov@nginx.com } 369388Smax.romanov@nginx.com 3694507Smax.romanov@nginx.com nxt_debug(task, "about to send %O bytes buffer to app process port %d", 369588Smax.romanov@nginx.com nxt_buf_used_size(wmsg.write), 369688Smax.romanov@nginx.com wmsg.port->socket.fd); 369788Smax.romanov@nginx.com 3698343Smax.romanov@nginx.com request_failed = 0; 3699343Smax.romanov@nginx.com 3700423Smax.romanov@nginx.com ra->msg_info.buf = wmsg.write; 3701423Smax.romanov@nginx.com ra->msg_info.completion_handler = wmsg.write->completion_handler; 3702423Smax.romanov@nginx.com 3703423Smax.romanov@nginx.com for (b = wmsg.write; b != NULL; b = b->next) { 3704423Smax.romanov@nginx.com b->completion_handler = nxt_router_dummy_buf_completion; 3705423Smax.romanov@nginx.com } 3706423Smax.romanov@nginx.com 3707423Smax.romanov@nginx.com res = nxt_port_mmap_get_tracking(task, port, &ra->msg_info.tracking, 3708423Smax.romanov@nginx.com ra->stream); 3709423Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3710423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 3711423Smax.romanov@nginx.com "Failed to get tracking area"); 3712423Smax.romanov@nginx.com goto release_port; 3713423Smax.romanov@nginx.com } 3714423Smax.romanov@nginx.com 3715423Smax.romanov@nginx.com res = nxt_port_socket_twrite(task, wmsg.port, NXT_PORT_MSG_DATA, 3716423Smax.romanov@nginx.com -1, ra->stream, reply_port->id, wmsg.write, 3717423Smax.romanov@nginx.com &ra->msg_info.tracking); 3718122Smax.romanov@nginx.com 3719122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3720423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 3721345Smax.romanov@nginx.com "Failed to send message to application"); 3722343Smax.romanov@nginx.com goto release_port; 3723122Smax.romanov@nginx.com } 3724343Smax.romanov@nginx.com 3725343Smax.romanov@nginx.com release_port: 3726343Smax.romanov@nginx.com 3727345Smax.romanov@nginx.com nxt_router_app_port_release(task, port, request_failed, 0); 3728345Smax.romanov@nginx.com 3729425Smax.romanov@nginx.com nxt_router_ra_update_peer(task, ra); 373053Sigor@sysoev.ru } 373153Sigor@sysoev.ru 373253Sigor@sysoev.ru 3733216Sigor@sysoev.ru static nxt_int_t 3734216Sigor@sysoev.ru nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 3735216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg) 3736216Sigor@sysoev.ru { 3737216Sigor@sysoev.ru nxt_int_t rc; 3738216Sigor@sysoev.ru nxt_buf_t *b; 3739216Sigor@sysoev.ru nxt_http_field_t *field; 3740216Sigor@sysoev.ru nxt_app_request_header_t *h; 3741216Sigor@sysoev.ru 3742216Sigor@sysoev.ru static const nxt_str_t prefix = nxt_string("HTTP_"); 3743216Sigor@sysoev.ru static const nxt_str_t eof = nxt_null_string; 3744216Sigor@sysoev.ru 3745216Sigor@sysoev.ru h = &r->header; 3746216Sigor@sysoev.ru 3747216Sigor@sysoev.ru #define RC(S) \ 3748216Sigor@sysoev.ru do { \ 3749216Sigor@sysoev.ru rc = (S); \ 3750216Sigor@sysoev.ru if (nxt_slow_path(rc != NXT_OK)) { \ 3751216Sigor@sysoev.ru goto fail; \ 3752216Sigor@sysoev.ru } \ 3753216Sigor@sysoev.ru } while(0) 3754216Sigor@sysoev.ru 3755216Sigor@sysoev.ru #define NXT_WRITE(N) \ 3756216Sigor@sysoev.ru RC(nxt_app_msg_write_str(task, wmsg, N)) 3757216Sigor@sysoev.ru 3758216Sigor@sysoev.ru /* TODO error handle, async mmap buffer assignment */ 3759216Sigor@sysoev.ru 3760216Sigor@sysoev.ru NXT_WRITE(&h->method); 3761216Sigor@sysoev.ru NXT_WRITE(&h->target); 3762277Sigor@sysoev.ru 3763216Sigor@sysoev.ru if (h->path.start == h->target.start) { 3764216Sigor@sysoev.ru NXT_WRITE(&eof); 3765277Sigor@sysoev.ru 3766216Sigor@sysoev.ru } else { 3767216Sigor@sysoev.ru NXT_WRITE(&h->path); 3768216Sigor@sysoev.ru } 3769216Sigor@sysoev.ru 3770216Sigor@sysoev.ru if (h->query.start != NULL) { 3771216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 3772216Sigor@sysoev.ru h->query.start - h->target.start + 1)); 3773216Sigor@sysoev.ru } else { 3774216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 0)); 3775216Sigor@sysoev.ru } 3776216Sigor@sysoev.ru 3777216Sigor@sysoev.ru NXT_WRITE(&h->version); 3778216Sigor@sysoev.ru 3779216Sigor@sysoev.ru NXT_WRITE(&r->remote); 3780268Sigor@sysoev.ru NXT_WRITE(&r->local); 3781216Sigor@sysoev.ru 3782216Sigor@sysoev.ru NXT_WRITE(&h->host); 3783216Sigor@sysoev.ru NXT_WRITE(&h->content_type); 3784216Sigor@sysoev.ru NXT_WRITE(&h->content_length); 3785216Sigor@sysoev.ru 3786216Sigor@sysoev.ru nxt_list_each(field, h->fields) { 3787417Svbart@nginx.com RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, &prefix, field->name, 3788417Svbart@nginx.com field->name_length)); 3789417Svbart@nginx.com RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length)); 3790216Sigor@sysoev.ru 3791216Sigor@sysoev.ru } nxt_list_loop; 3792216Sigor@sysoev.ru 3793216Sigor@sysoev.ru /* end-of-headers mark */ 3794216Sigor@sysoev.ru NXT_WRITE(&eof); 3795216Sigor@sysoev.ru 3796216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 3797216Sigor@sysoev.ru 3798*510Salexander.borisov@nginx.com for (b = r->body.buf; b != NULL; b = b->next) { 3799216Sigor@sysoev.ru RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3800216Sigor@sysoev.ru nxt_buf_mem_used_size(&b->mem))); 3801216Sigor@sysoev.ru } 3802216Sigor@sysoev.ru 3803216Sigor@sysoev.ru #undef NXT_WRITE 3804216Sigor@sysoev.ru #undef RC 3805216Sigor@sysoev.ru 3806216Sigor@sysoev.ru return NXT_OK; 3807216Sigor@sysoev.ru 3808216Sigor@sysoev.ru fail: 3809216Sigor@sysoev.ru 3810216Sigor@sysoev.ru return NXT_ERROR; 3811216Sigor@sysoev.ru } 3812216Sigor@sysoev.ru 3813216Sigor@sysoev.ru 3814216Sigor@sysoev.ru static nxt_int_t 3815216Sigor@sysoev.ru nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 3816216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg) 3817216Sigor@sysoev.ru { 3818216Sigor@sysoev.ru nxt_int_t rc; 3819216Sigor@sysoev.ru nxt_buf_t *b; 3820305Smax.romanov@nginx.com nxt_bool_t method_is_post; 3821216Sigor@sysoev.ru nxt_http_field_t *field; 3822216Sigor@sysoev.ru nxt_app_request_header_t *h; 3823216Sigor@sysoev.ru 3824216Sigor@sysoev.ru static const nxt_str_t prefix = nxt_string("HTTP_"); 3825216Sigor@sysoev.ru static const nxt_str_t eof = nxt_null_string; 3826216Sigor@sysoev.ru 3827216Sigor@sysoev.ru h = &r->header; 3828216Sigor@sysoev.ru 3829216Sigor@sysoev.ru #define RC(S) \ 3830216Sigor@sysoev.ru do { \ 3831216Sigor@sysoev.ru rc = (S); \ 3832216Sigor@sysoev.ru if (nxt_slow_path(rc != NXT_OK)) { \ 3833216Sigor@sysoev.ru goto fail; \ 3834216Sigor@sysoev.ru } \ 3835216Sigor@sysoev.ru } while(0) 3836216Sigor@sysoev.ru 3837216Sigor@sysoev.ru #define NXT_WRITE(N) \ 3838216Sigor@sysoev.ru RC(nxt_app_msg_write_str(task, wmsg, N)) 3839216Sigor@sysoev.ru 3840216Sigor@sysoev.ru /* TODO error handle, async mmap buffer assignment */ 3841216Sigor@sysoev.ru 3842216Sigor@sysoev.ru NXT_WRITE(&h->method); 3843216Sigor@sysoev.ru NXT_WRITE(&h->target); 3844277Sigor@sysoev.ru 3845216Sigor@sysoev.ru if (h->path.start == h->target.start) { 3846216Sigor@sysoev.ru NXT_WRITE(&eof); 3847277Sigor@sysoev.ru 3848216Sigor@sysoev.ru } else { 3849216Sigor@sysoev.ru NXT_WRITE(&h->path); 3850216Sigor@sysoev.ru } 3851216Sigor@sysoev.ru 3852216Sigor@sysoev.ru if (h->query.start != NULL) { 3853216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 3854216Sigor@sysoev.ru h->query.start - h->target.start + 1)); 3855216Sigor@sysoev.ru } else { 3856216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 0)); 3857216Sigor@sysoev.ru } 3858216Sigor@sysoev.ru 3859216Sigor@sysoev.ru NXT_WRITE(&h->version); 3860216Sigor@sysoev.ru 3861216Sigor@sysoev.ru // PHP_SELF 3862216Sigor@sysoev.ru // SCRIPT_NAME 3863216Sigor@sysoev.ru // SCRIPT_FILENAME 3864216Sigor@sysoev.ru // DOCUMENT_ROOT 3865216Sigor@sysoev.ru 3866216Sigor@sysoev.ru NXT_WRITE(&r->remote); 3867268Sigor@sysoev.ru NXT_WRITE(&r->local); 3868216Sigor@sysoev.ru 3869216Sigor@sysoev.ru NXT_WRITE(&h->host); 3870216Sigor@sysoev.ru NXT_WRITE(&h->cookie); 3871216Sigor@sysoev.ru NXT_WRITE(&h->content_type); 3872216Sigor@sysoev.ru NXT_WRITE(&h->content_length); 3873216Sigor@sysoev.ru 3874216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length)); 3875305Smax.romanov@nginx.com RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 3876305Smax.romanov@nginx.com 3877426Smax.romanov@nginx.com method_is_post = h->method.length == 4 3878426Smax.romanov@nginx.com && h->method.start[0] == 'P' 3879426Smax.romanov@nginx.com && h->method.start[1] == 'O' 3880426Smax.romanov@nginx.com && h->method.start[2] == 'S' 3881426Smax.romanov@nginx.com && h->method.start[3] == 'T'; 3882305Smax.romanov@nginx.com 3883305Smax.romanov@nginx.com if (method_is_post) { 3884*510Salexander.borisov@nginx.com for (b = r->body.buf; b != NULL; b = b->next) { 3885305Smax.romanov@nginx.com RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3886305Smax.romanov@nginx.com nxt_buf_mem_used_size(&b->mem))); 3887305Smax.romanov@nginx.com } 3888305Smax.romanov@nginx.com } 3889216Sigor@sysoev.ru 3890216Sigor@sysoev.ru nxt_list_each(field, h->fields) { 3891417Svbart@nginx.com RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, &prefix, field->name, 3892417Svbart@nginx.com field->name_length)); 3893417Svbart@nginx.com RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length)); 3894216Sigor@sysoev.ru 3895216Sigor@sysoev.ru } nxt_list_loop; 3896216Sigor@sysoev.ru 3897216Sigor@sysoev.ru /* end-of-headers mark */ 3898216Sigor@sysoev.ru NXT_WRITE(&eof); 3899216Sigor@sysoev.ru 3900305Smax.romanov@nginx.com if (!method_is_post) { 3901*510Salexander.borisov@nginx.com for (b = r->body.buf; b != NULL; b = b->next) { 3902305Smax.romanov@nginx.com RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3903305Smax.romanov@nginx.com nxt_buf_mem_used_size(&b->mem))); 3904305Smax.romanov@nginx.com } 3905216Sigor@sysoev.ru } 3906216Sigor@sysoev.ru 3907216Sigor@sysoev.ru #undef NXT_WRITE 3908216Sigor@sysoev.ru #undef RC 3909216Sigor@sysoev.ru 3910216Sigor@sysoev.ru return NXT_OK; 3911216Sigor@sysoev.ru 3912216Sigor@sysoev.ru fail: 3913216Sigor@sysoev.ru 3914216Sigor@sysoev.ru return NXT_ERROR; 3915216Sigor@sysoev.ru } 3916216Sigor@sysoev.ru 3917216Sigor@sysoev.ru 3918216Sigor@sysoev.ru static nxt_int_t 3919216Sigor@sysoev.ru nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, nxt_app_wmsg_t *wmsg) 3920216Sigor@sysoev.ru { 3921216Sigor@sysoev.ru nxt_int_t rc; 3922216Sigor@sysoev.ru nxt_buf_t *b; 3923216Sigor@sysoev.ru nxt_http_field_t *field; 3924216Sigor@sysoev.ru nxt_app_request_header_t *h; 3925216Sigor@sysoev.ru 3926216Sigor@sysoev.ru static const nxt_str_t eof = nxt_null_string; 3927216Sigor@sysoev.ru 3928216Sigor@sysoev.ru h = &r->header; 3929216Sigor@sysoev.ru 3930216Sigor@sysoev.ru #define RC(S) \ 3931216Sigor@sysoev.ru do { \ 3932216Sigor@sysoev.ru rc = (S); \ 3933216Sigor@sysoev.ru if (nxt_slow_path(rc != NXT_OK)) { \ 3934216Sigor@sysoev.ru goto fail; \ 3935216Sigor@sysoev.ru } \ 3936216Sigor@sysoev.ru } while(0) 3937216Sigor@sysoev.ru 3938216Sigor@sysoev.ru #define NXT_WRITE(N) \ 3939216Sigor@sysoev.ru RC(nxt_app_msg_write_str(task, wmsg, N)) 3940216Sigor@sysoev.ru 3941216Sigor@sysoev.ru /* TODO error handle, async mmap buffer assignment */ 3942216Sigor@sysoev.ru 3943216Sigor@sysoev.ru NXT_WRITE(&h->method); 3944216Sigor@sysoev.ru NXT_WRITE(&h->target); 3945277Sigor@sysoev.ru 3946216Sigor@sysoev.ru if (h->path.start == h->target.start) { 3947216Sigor@sysoev.ru NXT_WRITE(&eof); 3948277Sigor@sysoev.ru 3949216Sigor@sysoev.ru } else { 3950216Sigor@sysoev.ru NXT_WRITE(&h->path); 3951216Sigor@sysoev.ru } 3952216Sigor@sysoev.ru 3953216Sigor@sysoev.ru if (h->query.start != NULL) { 3954216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 3955216Sigor@sysoev.ru h->query.start - h->target.start + 1)); 3956216Sigor@sysoev.ru } else { 3957216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 0)); 3958216Sigor@sysoev.ru } 3959216Sigor@sysoev.ru 3960216Sigor@sysoev.ru NXT_WRITE(&h->version); 3961253Smax.romanov@nginx.com NXT_WRITE(&r->remote); 3962216Sigor@sysoev.ru 3963216Sigor@sysoev.ru NXT_WRITE(&h->host); 3964216Sigor@sysoev.ru NXT_WRITE(&h->cookie); 3965216Sigor@sysoev.ru NXT_WRITE(&h->content_type); 3966216Sigor@sysoev.ru NXT_WRITE(&h->content_length); 3967216Sigor@sysoev.ru 3968216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length)); 3969216Sigor@sysoev.ru 3970216Sigor@sysoev.ru nxt_list_each(field, h->fields) { 3971417Svbart@nginx.com RC(nxt_app_msg_write(task, wmsg, field->name, field->name_length)); 3972417Svbart@nginx.com RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length)); 3973216Sigor@sysoev.ru 3974216Sigor@sysoev.ru } nxt_list_loop; 3975216Sigor@sysoev.ru 3976216Sigor@sysoev.ru /* end-of-headers mark */ 3977216Sigor@sysoev.ru NXT_WRITE(&eof); 3978216Sigor@sysoev.ru 3979216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 3980216Sigor@sysoev.ru 3981*510Salexander.borisov@nginx.com for (b = r->body.buf; b != NULL; b = b->next) { 3982*510Salexander.borisov@nginx.com RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3983*510Salexander.borisov@nginx.com nxt_buf_mem_used_size(&b->mem))); 3984*510Salexander.borisov@nginx.com } 3985*510Salexander.borisov@nginx.com 3986*510Salexander.borisov@nginx.com #undef NXT_WRITE 3987*510Salexander.borisov@nginx.com #undef RC 3988*510Salexander.borisov@nginx.com 3989*510Salexander.borisov@nginx.com return NXT_OK; 3990*510Salexander.borisov@nginx.com 3991*510Salexander.borisov@nginx.com fail: 3992*510Salexander.borisov@nginx.com 3993*510Salexander.borisov@nginx.com return NXT_ERROR; 3994*510Salexander.borisov@nginx.com } 3995*510Salexander.borisov@nginx.com 3996*510Salexander.borisov@nginx.com 3997*510Salexander.borisov@nginx.com static nxt_int_t 3998*510Salexander.borisov@nginx.com nxt_perl_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 3999*510Salexander.borisov@nginx.com nxt_app_wmsg_t *wmsg) 4000*510Salexander.borisov@nginx.com { 4001*510Salexander.borisov@nginx.com nxt_int_t rc; 4002*510Salexander.borisov@nginx.com nxt_str_t str; 4003*510Salexander.borisov@nginx.com nxt_buf_t *b; 4004*510Salexander.borisov@nginx.com nxt_http_field_t *field; 4005*510Salexander.borisov@nginx.com nxt_app_request_header_t *h; 4006*510Salexander.borisov@nginx.com 4007*510Salexander.borisov@nginx.com static const nxt_str_t prefix = nxt_string("HTTP_"); 4008*510Salexander.borisov@nginx.com static const nxt_str_t eof = nxt_null_string; 4009*510Salexander.borisov@nginx.com 4010*510Salexander.borisov@nginx.com h = &r->header; 4011*510Salexander.borisov@nginx.com 4012*510Salexander.borisov@nginx.com #define RC(S) \ 4013*510Salexander.borisov@nginx.com do { \ 4014*510Salexander.borisov@nginx.com rc = (S); \ 4015*510Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { \ 4016*510Salexander.borisov@nginx.com goto fail; \ 4017*510Salexander.borisov@nginx.com } \ 4018*510Salexander.borisov@nginx.com } while(0) 4019*510Salexander.borisov@nginx.com 4020*510Salexander.borisov@nginx.com #define NXT_WRITE(N) \ 4021*510Salexander.borisov@nginx.com RC(nxt_app_msg_write_str(task, wmsg, N)) 4022*510Salexander.borisov@nginx.com 4023*510Salexander.borisov@nginx.com /* TODO error handle, async mmap buffer assignment */ 4024*510Salexander.borisov@nginx.com 4025*510Salexander.borisov@nginx.com NXT_WRITE(&h->method); 4026*510Salexander.borisov@nginx.com NXT_WRITE(&h->target); 4027*510Salexander.borisov@nginx.com 4028*510Salexander.borisov@nginx.com if (h->query.length) { 4029*510Salexander.borisov@nginx.com str.start = h->target.start; 4030*510Salexander.borisov@nginx.com str.length = (h->target.length - h->query.length) - 1; 4031*510Salexander.borisov@nginx.com 4032*510Salexander.borisov@nginx.com RC(nxt_app_msg_write_str(task, wmsg, &str)); 4033*510Salexander.borisov@nginx.com 4034*510Salexander.borisov@nginx.com } else { 4035*510Salexander.borisov@nginx.com NXT_WRITE(&eof); 4036*510Salexander.borisov@nginx.com } 4037*510Salexander.borisov@nginx.com 4038*510Salexander.borisov@nginx.com if (h->query.start != NULL) { 4039*510Salexander.borisov@nginx.com RC(nxt_app_msg_write_size(task, wmsg, 4040*510Salexander.borisov@nginx.com h->query.start - h->target.start + 1)); 4041*510Salexander.borisov@nginx.com } else { 4042*510Salexander.borisov@nginx.com RC(nxt_app_msg_write_size(task, wmsg, 0)); 4043*510Salexander.borisov@nginx.com } 4044*510Salexander.borisov@nginx.com 4045*510Salexander.borisov@nginx.com NXT_WRITE(&h->version); 4046*510Salexander.borisov@nginx.com 4047*510Salexander.borisov@nginx.com NXT_WRITE(&r->remote); 4048*510Salexander.borisov@nginx.com NXT_WRITE(&r->local); 4049*510Salexander.borisov@nginx.com 4050*510Salexander.borisov@nginx.com NXT_WRITE(&h->host); 4051*510Salexander.borisov@nginx.com NXT_WRITE(&h->content_type); 4052*510Salexander.borisov@nginx.com NXT_WRITE(&h->content_length); 4053*510Salexander.borisov@nginx.com 4054*510Salexander.borisov@nginx.com nxt_list_each(field, h->fields) { 4055*510Salexander.borisov@nginx.com RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, &prefix, 4056*510Salexander.borisov@nginx.com field->name, field->name_length)); 4057*510Salexander.borisov@nginx.com RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length)); 4058*510Salexander.borisov@nginx.com } nxt_list_loop; 4059*510Salexander.borisov@nginx.com 4060*510Salexander.borisov@nginx.com /* end-of-headers mark */ 4061*510Salexander.borisov@nginx.com NXT_WRITE(&eof); 4062*510Salexander.borisov@nginx.com 4063*510Salexander.borisov@nginx.com RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 4064*510Salexander.borisov@nginx.com 4065*510Salexander.borisov@nginx.com for (b = r->body.buf; b != NULL; b = b->next) { 4066*510Salexander.borisov@nginx.com 4067216Sigor@sysoev.ru RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 4068216Sigor@sysoev.ru nxt_buf_mem_used_size(&b->mem))); 4069216Sigor@sysoev.ru } 4070216Sigor@sysoev.ru 4071216Sigor@sysoev.ru #undef NXT_WRITE 4072216Sigor@sysoev.ru #undef RC 4073216Sigor@sysoev.ru 4074216Sigor@sysoev.ru return NXT_OK; 4075216Sigor@sysoev.ru 4076216Sigor@sysoev.ru fail: 4077216Sigor@sysoev.ru 4078216Sigor@sysoev.ru return NXT_ERROR; 4079216Sigor@sysoev.ru } 4080216Sigor@sysoev.ru 4081216Sigor@sysoev.ru 4082431Sigor@sysoev.ru const nxt_conn_state_t nxt_router_conn_close_state 408353Sigor@sysoev.ru nxt_aligned(64) = 408453Sigor@sysoev.ru { 408553Sigor@sysoev.ru .ready_handler = nxt_router_conn_free, 408653Sigor@sysoev.ru }; 408753Sigor@sysoev.ru 408853Sigor@sysoev.ru 408953Sigor@sysoev.ru static void 4090164Smax.romanov@nginx.com nxt_router_conn_mp_cleanup(nxt_task_t *task, void *obj, void *data) 4091164Smax.romanov@nginx.com { 4092164Smax.romanov@nginx.com nxt_socket_conf_joint_t *joint; 4093164Smax.romanov@nginx.com 4094164Smax.romanov@nginx.com joint = obj; 4095164Smax.romanov@nginx.com 4096164Smax.romanov@nginx.com nxt_router_conf_release(task, joint); 4097164Smax.romanov@nginx.com } 4098164Smax.romanov@nginx.com 4099164Smax.romanov@nginx.com 4100164Smax.romanov@nginx.com static void 410153Sigor@sysoev.ru nxt_router_conn_free(nxt_task_t *task, void *obj, void *data) 410253Sigor@sysoev.ru { 410362Sigor@sysoev.ru nxt_conn_t *c; 4104337Sigor@sysoev.ru nxt_event_engine_t *engine; 410553Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 410653Sigor@sysoev.ru 410753Sigor@sysoev.ru c = obj; 410853Sigor@sysoev.ru 410953Sigor@sysoev.ru nxt_debug(task, "router conn close done"); 411053Sigor@sysoev.ru 4111122Smax.romanov@nginx.com nxt_queue_remove(&c->link); 4112122Smax.romanov@nginx.com 4113337Sigor@sysoev.ru engine = task->thread->engine; 4114337Sigor@sysoev.ru 4115337Sigor@sysoev.ru nxt_sockaddr_cache_free(engine, c); 4116337Sigor@sysoev.ru 4117359Sigor@sysoev.ru joint = c->joint; 4118131Smax.romanov@nginx.com 4119337Sigor@sysoev.ru nxt_mp_cleanup(c->mem_pool, nxt_router_conn_mp_cleanup, 4120337Sigor@sysoev.ru &engine->task, joint, NULL); 4121164Smax.romanov@nginx.com 4122386Sigor@sysoev.ru nxt_conn_free(task, c); 412353Sigor@sysoev.ru } 412453Sigor@sysoev.ru 412553Sigor@sysoev.ru 412653Sigor@sysoev.ru static void 4127318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data) 4128318Smax.romanov@nginx.com { 4129431Sigor@sysoev.ru nxt_timer_t *timer; 4130431Sigor@sysoev.ru nxt_app_parse_ctx_t *ar; 4131318Smax.romanov@nginx.com 4132318Smax.romanov@nginx.com timer = obj; 4133318Smax.romanov@nginx.com 4134318Smax.romanov@nginx.com nxt_debug(task, "router app timeout"); 4135318Smax.romanov@nginx.com 4136431Sigor@sysoev.ru ar = nxt_timer_data(timer, nxt_app_parse_ctx_t, timer); 4137431Sigor@sysoev.ru 4138431Sigor@sysoev.ru if (!ar->request->header_sent) { 4139431Sigor@sysoev.ru nxt_http_request_error(task, ar->request, NXT_HTTP_SERVICE_UNAVAILABLE); 4140431Sigor@sysoev.ru } 4141318Smax.romanov@nginx.com } 4142