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> 1020Sigor@sysoev.ru 1120Sigor@sysoev.ru 12115Sigor@sysoev.ru typedef struct { 13318Smax.romanov@nginx.com nxt_str_t type; 14318Smax.romanov@nginx.com uint32_t workers; 15318Smax.romanov@nginx.com nxt_msec_t timeout; 16318Smax.romanov@nginx.com uint32_t requests; 17318Smax.romanov@nginx.com nxt_conf_value_t *limits_value; 18133Sigor@sysoev.ru } nxt_router_app_conf_t; 19133Sigor@sysoev.ru 20133Sigor@sysoev.ru 21133Sigor@sysoev.ru typedef struct { 22133Sigor@sysoev.ru nxt_str_t application; 23115Sigor@sysoev.ru } nxt_router_listener_conf_t; 24115Sigor@sysoev.ru 25115Sigor@sysoev.ru 26167Smax.romanov@nginx.com typedef struct nxt_req_app_link_s nxt_req_app_link_t; 27141Smax.romanov@nginx.com 28141Smax.romanov@nginx.com 29318Smax.romanov@nginx.com typedef struct { 30318Smax.romanov@nginx.com uint32_t stream; 31318Smax.romanov@nginx.com nxt_conn_t *conn; 32343Smax.romanov@nginx.com nxt_app_t *app; 33318Smax.romanov@nginx.com nxt_port_t *app_port; 34318Smax.romanov@nginx.com nxt_req_app_link_t *ra; 35318Smax.romanov@nginx.com 36318Smax.romanov@nginx.com nxt_queue_link_t link; /* for nxt_conn_t.requests */ 37318Smax.romanov@nginx.com } nxt_req_conn_link_t; 38318Smax.romanov@nginx.com 39318Smax.romanov@nginx.com 40167Smax.romanov@nginx.com struct nxt_req_app_link_s { 41318Smax.romanov@nginx.com uint32_t stream; 42167Smax.romanov@nginx.com nxt_port_t *app_port; 43318Smax.romanov@nginx.com nxt_pid_t app_pid; 44167Smax.romanov@nginx.com nxt_port_t *reply_port; 45167Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 46167Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 47167Smax.romanov@nginx.com 48167Smax.romanov@nginx.com nxt_queue_link_t link; /* for nxt_app_t.requests */ 49167Smax.romanov@nginx.com 50167Smax.romanov@nginx.com nxt_mp_t *mem_pool; 51167Smax.romanov@nginx.com nxt_work_t work; 52*345Smax.romanov@nginx.com 53*345Smax.romanov@nginx.com int err_code; 54*345Smax.romanov@nginx.com const char *err_str; 55167Smax.romanov@nginx.com }; 56167Smax.romanov@nginx.com 57167Smax.romanov@nginx.com 58198Sigor@sysoev.ru typedef struct { 59198Sigor@sysoev.ru nxt_socket_conf_t *socket_conf; 60198Sigor@sysoev.ru nxt_router_temp_conf_t *temp_conf; 61198Sigor@sysoev.ru } nxt_socket_rpc_t; 62198Sigor@sysoev.ru 63198Sigor@sysoev.ru 64318Smax.romanov@nginx.com typedef struct { 65318Smax.romanov@nginx.com nxt_mp_t *mem_pool; 66318Smax.romanov@nginx.com nxt_port_recv_msg_t msg; 67318Smax.romanov@nginx.com nxt_work_t work; 68318Smax.romanov@nginx.com } nxt_remove_pid_msg_t; 69318Smax.romanov@nginx.com 70318Smax.romanov@nginx.com 71343Smax.romanov@nginx.com static nxt_int_t nxt_router_start_worker(nxt_task_t *task, nxt_app_t *app); 72343Smax.romanov@nginx.com 73*345Smax.romanov@nginx.com static void nxt_router_ra_error(nxt_task_t *task, nxt_req_app_link_t *ra, 74*345Smax.romanov@nginx.com int code, const char* str); 75*345Smax.romanov@nginx.com 76318Smax.romanov@nginx.com static void nxt_router_worker_remove_pid_handler(nxt_task_t *task, void *obj, 77318Smax.romanov@nginx.com void *data); 78318Smax.romanov@nginx.com static void nxt_router_worker_remove_pid_done(nxt_task_t *task, void *obj, 79318Smax.romanov@nginx.com void *data); 80318Smax.romanov@nginx.com 81139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task); 82198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data); 83198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task, 84139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 85139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task, 86139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 87139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task, 88193Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type); 8953Sigor@sysoev.ru static void nxt_router_listen_sockets_sort(nxt_router_t *router, 9053Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 9153Sigor@sysoev.ru 92115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task, 93115Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end); 94133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name); 95133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, 96133Sigor@sysoev.ru nxt_str_t *name); 97198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task, 98198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf); 99198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task, 100198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 101198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task, 102198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 10365Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, 10465Sigor@sysoev.ru nxt_sockaddr_t *sa); 10553Sigor@sysoev.ru 10653Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task, 10753Sigor@sysoev.ru nxt_router_t *router, nxt_router_temp_conf_t *tmcf, 10853Sigor@sysoev.ru const nxt_event_interface_t *interface); 109115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 110115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 111115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 112115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 113115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 114115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 115115Sigor@sysoev.ru static void nxt_router_engine_socket_count(nxt_queue_t *sockets); 116154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 117154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 118154Sigor@sysoev.ru nxt_work_handler_t handler); 119313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 120313Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 121139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 122139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets); 12353Sigor@sysoev.ru 12453Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 12553Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 12653Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 12753Sigor@sysoev.ru nxt_event_engine_t *engine); 128343Smax.romanov@nginx.com static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 129133Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 13053Sigor@sysoev.ru 131315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router, 132315Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 133315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine, 134315Sigor@sysoev.ru nxt_work_t *jobs); 13553Sigor@sysoev.ru 13653Sigor@sysoev.ru static void nxt_router_thread_start(void *data); 13753Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj, 13853Sigor@sysoev.ru void *data); 13953Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj, 14053Sigor@sysoev.ru void *data); 14153Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, 14253Sigor@sysoev.ru void *data); 143313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, 144313Sigor@sysoev.ru void *data); 14553Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj, 14653Sigor@sysoev.ru void *data); 14753Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task, 14853Sigor@sysoev.ru nxt_socket_conf_joint_t *joint); 14953Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, 15053Sigor@sysoev.ru void *data); 15153Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task, 15253Sigor@sysoev.ru nxt_socket_conf_joint_t *joint); 15353Sigor@sysoev.ru 154343Smax.romanov@nginx.com static void nxt_router_app_port_ready(nxt_task_t *task, 155343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 156343Smax.romanov@nginx.com static void nxt_router_app_port_error(nxt_task_t *task, 157343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 158343Smax.romanov@nginx.com 159343Smax.romanov@nginx.com static nxt_port_t * nxt_router_app_get_idle_port(nxt_app_t *app); 160343Smax.romanov@nginx.com static void nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port, 161343Smax.romanov@nginx.com uint32_t request_failed, uint32_t got_response); 162141Smax.romanov@nginx.com 16353Sigor@sysoev.ru static void nxt_router_conn_init(nxt_task_t *task, void *obj, void *data); 16453Sigor@sysoev.ru static void nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, 16553Sigor@sysoev.ru void *data); 166206Smax.romanov@nginx.com static void nxt_router_conn_http_body_read(nxt_task_t *task, void *obj, 167206Smax.romanov@nginx.com void *data); 16888Smax.romanov@nginx.com static void nxt_router_process_http_request(nxt_task_t *task, 16988Smax.romanov@nginx.com nxt_conn_t *c, nxt_app_parse_ctx_t *ap); 170141Smax.romanov@nginx.com static void nxt_router_process_http_request_mp(nxt_task_t *task, 171343Smax.romanov@nginx.com nxt_req_app_link_t *ra); 172216Sigor@sysoev.ru static nxt_int_t nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 173216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg); 174216Sigor@sysoev.ru static nxt_int_t nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 175216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg); 176216Sigor@sysoev.ru static nxt_int_t nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 177216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg); 17888Smax.romanov@nginx.com static void nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data); 17953Sigor@sysoev.ru static void nxt_router_conn_close(nxt_task_t *task, void *obj, void *data); 18053Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data); 18153Sigor@sysoev.ru static void nxt_router_conn_error(nxt_task_t *task, void *obj, void *data); 18253Sigor@sysoev.ru static void nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data); 183318Smax.romanov@nginx.com static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data); 18462Sigor@sysoev.ru static nxt_msec_t nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data); 18520Sigor@sysoev.ru 186141Smax.romanov@nginx.com static void nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code, 187*345Smax.romanov@nginx.com const char* str); 188141Smax.romanov@nginx.com 189119Smax.romanov@nginx.com static nxt_router_t *nxt_router; 19020Sigor@sysoev.ru 191216Sigor@sysoev.ru 192216Sigor@sysoev.ru static nxt_app_prepare_msg_t nxt_app_prepare_msg[] = { 193216Sigor@sysoev.ru nxt_python_prepare_msg, 194216Sigor@sysoev.ru nxt_php_prepare_msg, 195216Sigor@sysoev.ru nxt_go_prepare_msg, 196216Sigor@sysoev.ru }; 197216Sigor@sysoev.ru 198216Sigor@sysoev.ru 19920Sigor@sysoev.ru nxt_int_t 200141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data) 20120Sigor@sysoev.ru { 202141Smax.romanov@nginx.com nxt_int_t ret; 203141Smax.romanov@nginx.com nxt_router_t *router; 204141Smax.romanov@nginx.com nxt_runtime_t *rt; 205141Smax.romanov@nginx.com 206141Smax.romanov@nginx.com rt = task->thread->runtime; 20753Sigor@sysoev.ru 20888Smax.romanov@nginx.com ret = nxt_app_http_init(task, rt); 20988Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 21088Smax.romanov@nginx.com return ret; 21188Smax.romanov@nginx.com } 21288Smax.romanov@nginx.com 21353Sigor@sysoev.ru router = nxt_zalloc(sizeof(nxt_router_t)); 21453Sigor@sysoev.ru if (nxt_slow_path(router == NULL)) { 21553Sigor@sysoev.ru return NXT_ERROR; 21653Sigor@sysoev.ru } 21753Sigor@sysoev.ru 21853Sigor@sysoev.ru nxt_queue_init(&router->engines); 21953Sigor@sysoev.ru nxt_queue_init(&router->sockets); 220133Sigor@sysoev.ru nxt_queue_init(&router->apps); 22153Sigor@sysoev.ru 222119Smax.romanov@nginx.com nxt_router = router; 223119Smax.romanov@nginx.com 224115Sigor@sysoev.ru return NXT_OK; 225115Sigor@sysoev.ru } 226115Sigor@sysoev.ru 227115Sigor@sysoev.ru 228343Smax.romanov@nginx.com static void 229343Smax.romanov@nginx.com nxt_router_start_worker_handler(nxt_task_t *task, nxt_port_t *port, void *data) 230167Smax.romanov@nginx.com { 231343Smax.romanov@nginx.com size_t size; 232343Smax.romanov@nginx.com uint32_t stream; 233343Smax.romanov@nginx.com nxt_app_t *app; 234343Smax.romanov@nginx.com nxt_buf_t *b; 235343Smax.romanov@nginx.com nxt_port_t *main_port; 236343Smax.romanov@nginx.com nxt_runtime_t *rt; 237343Smax.romanov@nginx.com 238343Smax.romanov@nginx.com app = data; 239167Smax.romanov@nginx.com 240167Smax.romanov@nginx.com rt = task->thread->runtime; 241240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 242167Smax.romanov@nginx.com 243343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start worker", &app->name, app); 244343Smax.romanov@nginx.com 245343Smax.romanov@nginx.com size = app->name.length + 1 + app->conf.length; 246343Smax.romanov@nginx.com 247343Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size); 248343Smax.romanov@nginx.com 249343Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 250343Smax.romanov@nginx.com goto failed; 251167Smax.romanov@nginx.com } 252167Smax.romanov@nginx.com 253343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->name); 254343Smax.romanov@nginx.com *b->mem.free++ = '\0'; 255343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 256343Smax.romanov@nginx.com 257343Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, port, 258343Smax.romanov@nginx.com nxt_router_app_port_ready, 259343Smax.romanov@nginx.com nxt_router_app_port_error, 260343Smax.romanov@nginx.com -1, app); 261343Smax.romanov@nginx.com 262343Smax.romanov@nginx.com if (nxt_slow_path(stream == 0)) { 263343Smax.romanov@nginx.com nxt_mp_release(b->data, b); 264343Smax.romanov@nginx.com 265343Smax.romanov@nginx.com goto failed; 266343Smax.romanov@nginx.com } 267343Smax.romanov@nginx.com 268343Smax.romanov@nginx.com nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1, 269343Smax.romanov@nginx.com stream, port->id, b); 270343Smax.romanov@nginx.com 271343Smax.romanov@nginx.com return; 272343Smax.romanov@nginx.com 273343Smax.romanov@nginx.com failed: 274343Smax.romanov@nginx.com 275343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 276343Smax.romanov@nginx.com 277343Smax.romanov@nginx.com app->pending_workers--; 278343Smax.romanov@nginx.com 279343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 280343Smax.romanov@nginx.com 281343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 282167Smax.romanov@nginx.com } 283167Smax.romanov@nginx.com 284167Smax.romanov@nginx.com 285343Smax.romanov@nginx.com static nxt_int_t 286343Smax.romanov@nginx.com nxt_router_start_worker(nxt_task_t *task, nxt_app_t *app) 287141Smax.romanov@nginx.com { 288343Smax.romanov@nginx.com nxt_int_t res; 289343Smax.romanov@nginx.com nxt_port_t *router_port; 290343Smax.romanov@nginx.com nxt_runtime_t *rt; 291343Smax.romanov@nginx.com 292343Smax.romanov@nginx.com rt = task->thread->runtime; 293343Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 294343Smax.romanov@nginx.com 295343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 296343Smax.romanov@nginx.com 297343Smax.romanov@nginx.com res = nxt_port_post(task, router_port, nxt_router_start_worker_handler, 298343Smax.romanov@nginx.com app); 299343Smax.romanov@nginx.com 300343Smax.romanov@nginx.com if (res == NXT_OK) { 301343Smax.romanov@nginx.com return res; 302318Smax.romanov@nginx.com } 303318Smax.romanov@nginx.com 304343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 305343Smax.romanov@nginx.com 306343Smax.romanov@nginx.com app->pending_workers--; 307343Smax.romanov@nginx.com 308343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 309343Smax.romanov@nginx.com 310343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 311343Smax.romanov@nginx.com 312343Smax.romanov@nginx.com return NXT_ERROR; 313318Smax.romanov@nginx.com } 314318Smax.romanov@nginx.com 315318Smax.romanov@nginx.com 316167Smax.romanov@nginx.com static nxt_req_app_link_t * 317167Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_conn_link_t *rc) 318167Smax.romanov@nginx.com { 319167Smax.romanov@nginx.com nxt_mp_t *mp; 320318Smax.romanov@nginx.com nxt_event_engine_t *engine; 321167Smax.romanov@nginx.com nxt_req_app_link_t *ra; 322167Smax.romanov@nginx.com 323167Smax.romanov@nginx.com mp = rc->conn->mem_pool; 324318Smax.romanov@nginx.com engine = task->thread->engine; 325167Smax.romanov@nginx.com 326167Smax.romanov@nginx.com ra = nxt_mp_retain(mp, sizeof(nxt_req_app_link_t)); 327167Smax.romanov@nginx.com 328167Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 329167Smax.romanov@nginx.com return NULL; 330167Smax.romanov@nginx.com } 331167Smax.romanov@nginx.com 332318Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD create", rc->stream); 333167Smax.romanov@nginx.com 334167Smax.romanov@nginx.com nxt_memzero(ra, sizeof(nxt_req_app_link_t)); 335167Smax.romanov@nginx.com 336318Smax.romanov@nginx.com ra->stream = rc->stream; 337318Smax.romanov@nginx.com ra->app_pid = -1; 338167Smax.romanov@nginx.com ra->rc = rc; 339318Smax.romanov@nginx.com rc->ra = ra; 340318Smax.romanov@nginx.com ra->reply_port = engine->port; 341167Smax.romanov@nginx.com 342167Smax.romanov@nginx.com ra->mem_pool = mp; 343167Smax.romanov@nginx.com 344167Smax.romanov@nginx.com ra->work.handler = NULL; 345318Smax.romanov@nginx.com ra->work.task = &engine->task; 346167Smax.romanov@nginx.com ra->work.obj = ra; 347318Smax.romanov@nginx.com ra->work.data = engine; 348167Smax.romanov@nginx.com 349167Smax.romanov@nginx.com return ra; 350167Smax.romanov@nginx.com } 351167Smax.romanov@nginx.com 352167Smax.romanov@nginx.com 353167Smax.romanov@nginx.com static void 354167Smax.romanov@nginx.com nxt_router_ra_release(nxt_task_t *task, void *obj, void *data) 355167Smax.romanov@nginx.com { 356343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 357343Smax.romanov@nginx.com nxt_event_engine_t *engine; 358343Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 359318Smax.romanov@nginx.com 360318Smax.romanov@nginx.com ra = obj; 361318Smax.romanov@nginx.com engine = data; 362318Smax.romanov@nginx.com 363343Smax.romanov@nginx.com if (task->thread->engine != engine) { 364343Smax.romanov@nginx.com if (ra->app_port != NULL) { 365343Smax.romanov@nginx.com ra->app_pid = ra->app_port->pid; 366318Smax.romanov@nginx.com } 367318Smax.romanov@nginx.com 368318Smax.romanov@nginx.com ra->work.handler = nxt_router_ra_release; 369318Smax.romanov@nginx.com ra->work.task = &engine->task; 370318Smax.romanov@nginx.com ra->work.next = NULL; 371318Smax.romanov@nginx.com 372318Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD post release to %p", 373318Smax.romanov@nginx.com ra->stream, engine); 374318Smax.romanov@nginx.com 375318Smax.romanov@nginx.com nxt_event_engine_post(engine, &ra->work); 376318Smax.romanov@nginx.com 377318Smax.romanov@nginx.com return; 378318Smax.romanov@nginx.com } 379318Smax.romanov@nginx.com 380343Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD release", ra->stream); 381343Smax.romanov@nginx.com 382343Smax.romanov@nginx.com rc = ra->rc; 383343Smax.romanov@nginx.com 384343Smax.romanov@nginx.com if (rc != NULL) { 385343Smax.romanov@nginx.com if (ra->app_pid != -1) { 386343Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, engine->port, rc, ra->app_pid); 387343Smax.romanov@nginx.com } 388343Smax.romanov@nginx.com 389343Smax.romanov@nginx.com rc->app_port = ra->app_port; 390343Smax.romanov@nginx.com 391343Smax.romanov@nginx.com ra->app_port = NULL; 392343Smax.romanov@nginx.com rc->ra = NULL; 393343Smax.romanov@nginx.com ra->rc = NULL; 394318Smax.romanov@nginx.com } 395318Smax.romanov@nginx.com 396343Smax.romanov@nginx.com if (ra->app_port != NULL) { 397343Smax.romanov@nginx.com nxt_router_app_port_release(task, ra->app_port, 0, 1); 398343Smax.romanov@nginx.com 399343Smax.romanov@nginx.com ra->app_port = NULL; 400343Smax.romanov@nginx.com } 401318Smax.romanov@nginx.com 402318Smax.romanov@nginx.com nxt_mp_release(ra->mem_pool, ra); 403318Smax.romanov@nginx.com } 404318Smax.romanov@nginx.com 405318Smax.romanov@nginx.com 406318Smax.romanov@nginx.com static void 407318Smax.romanov@nginx.com nxt_router_ra_abort(nxt_task_t *task, void *obj, void *data) 408318Smax.romanov@nginx.com { 409343Smax.romanov@nginx.com nxt_conn_t *c; 410343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 411343Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 412343Smax.romanov@nginx.com nxt_event_engine_t *engine; 413167Smax.romanov@nginx.com 414167Smax.romanov@nginx.com ra = obj; 415167Smax.romanov@nginx.com engine = data; 416167Smax.romanov@nginx.com 417167Smax.romanov@nginx.com if (task->thread->engine != engine) { 418318Smax.romanov@nginx.com ra->work.handler = nxt_router_ra_abort; 419167Smax.romanov@nginx.com ra->work.task = &engine->task; 420167Smax.romanov@nginx.com ra->work.next = NULL; 421167Smax.romanov@nginx.com 422318Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD post abort to %p", ra->stream, engine); 423167Smax.romanov@nginx.com 424167Smax.romanov@nginx.com nxt_event_engine_post(engine, &ra->work); 425167Smax.romanov@nginx.com 426167Smax.romanov@nginx.com return; 427167Smax.romanov@nginx.com } 428167Smax.romanov@nginx.com 429318Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD abort", ra->stream); 430318Smax.romanov@nginx.com 431343Smax.romanov@nginx.com rc = ra->rc; 432343Smax.romanov@nginx.com 433343Smax.romanov@nginx.com if (rc != NULL) { 434343Smax.romanov@nginx.com c = rc->conn; 435318Smax.romanov@nginx.com 436318Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, 437318Smax.romanov@nginx.com "Failed to start application worker"); 438343Smax.romanov@nginx.com 439343Smax.romanov@nginx.com rc->ra = NULL; 440343Smax.romanov@nginx.com ra->rc = NULL; 441343Smax.romanov@nginx.com } 442343Smax.romanov@nginx.com 443343Smax.romanov@nginx.com if (ra->app_port != NULL) { 444343Smax.romanov@nginx.com nxt_router_app_port_release(task, ra->app_port, 0, 1); 445343Smax.romanov@nginx.com 446343Smax.romanov@nginx.com ra->app_port = NULL; 447167Smax.romanov@nginx.com } 448167Smax.romanov@nginx.com 449167Smax.romanov@nginx.com nxt_mp_release(ra->mem_pool, ra); 450167Smax.romanov@nginx.com } 451167Smax.romanov@nginx.com 452167Smax.romanov@nginx.com 453*345Smax.romanov@nginx.com static void 454*345Smax.romanov@nginx.com nxt_router_ra_error_handler(nxt_task_t *task, void *obj, void *data) 455*345Smax.romanov@nginx.com { 456*345Smax.romanov@nginx.com nxt_req_app_link_t *ra; 457*345Smax.romanov@nginx.com 458*345Smax.romanov@nginx.com ra = obj; 459*345Smax.romanov@nginx.com 460*345Smax.romanov@nginx.com nxt_router_ra_error(task, ra, ra->err_code, ra->err_str); 461*345Smax.romanov@nginx.com } 462*345Smax.romanov@nginx.com 463*345Smax.romanov@nginx.com 464*345Smax.romanov@nginx.com static void 465*345Smax.romanov@nginx.com nxt_router_ra_error(nxt_task_t *task, nxt_req_app_link_t *ra, int code, 466*345Smax.romanov@nginx.com const char* str) 467*345Smax.romanov@nginx.com { 468*345Smax.romanov@nginx.com nxt_conn_t *c; 469*345Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 470*345Smax.romanov@nginx.com nxt_event_engine_t *engine; 471*345Smax.romanov@nginx.com 472*345Smax.romanov@nginx.com engine = ra->work.data; 473*345Smax.romanov@nginx.com 474*345Smax.romanov@nginx.com if (task->thread->engine != engine) { 475*345Smax.romanov@nginx.com ra->err_code = code; 476*345Smax.romanov@nginx.com ra->err_str = str; 477*345Smax.romanov@nginx.com 478*345Smax.romanov@nginx.com ra->work.handler = nxt_router_ra_error_handler; 479*345Smax.romanov@nginx.com ra->work.task = &engine->task; 480*345Smax.romanov@nginx.com ra->work.next = NULL; 481*345Smax.romanov@nginx.com 482*345Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD post error to %p", ra->stream, engine); 483*345Smax.romanov@nginx.com 484*345Smax.romanov@nginx.com nxt_event_engine_post(engine, &ra->work); 485*345Smax.romanov@nginx.com 486*345Smax.romanov@nginx.com return; 487*345Smax.romanov@nginx.com } 488*345Smax.romanov@nginx.com 489*345Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD error", ra->stream); 490*345Smax.romanov@nginx.com 491*345Smax.romanov@nginx.com rc = ra->rc; 492*345Smax.romanov@nginx.com 493*345Smax.romanov@nginx.com if (rc != NULL) { 494*345Smax.romanov@nginx.com c = rc->conn; 495*345Smax.romanov@nginx.com 496*345Smax.romanov@nginx.com nxt_router_gen_error(task, c, code, str); 497*345Smax.romanov@nginx.com 498*345Smax.romanov@nginx.com rc->ra = NULL; 499*345Smax.romanov@nginx.com ra->rc = NULL; 500*345Smax.romanov@nginx.com } 501*345Smax.romanov@nginx.com 502*345Smax.romanov@nginx.com if (ra->app_port != NULL) { 503*345Smax.romanov@nginx.com nxt_router_app_port_release(task, ra->app_port, 0, 1); 504*345Smax.romanov@nginx.com 505*345Smax.romanov@nginx.com ra->app_port = NULL; 506*345Smax.romanov@nginx.com } 507*345Smax.romanov@nginx.com 508*345Smax.romanov@nginx.com nxt_mp_release(ra->mem_pool, ra); 509*345Smax.romanov@nginx.com } 510*345Smax.romanov@nginx.com 511*345Smax.romanov@nginx.com 512343Smax.romanov@nginx.com nxt_inline void 513343Smax.romanov@nginx.com nxt_router_rc_unlink(nxt_task_t *task, nxt_req_conn_link_t *rc) 514343Smax.romanov@nginx.com { 515343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 516343Smax.romanov@nginx.com 517343Smax.romanov@nginx.com if (rc->app_port != NULL) { 518343Smax.romanov@nginx.com nxt_router_app_port_release(task, rc->app_port, 0, 1); 519343Smax.romanov@nginx.com 520343Smax.romanov@nginx.com rc->app_port = NULL; 521343Smax.romanov@nginx.com } 522343Smax.romanov@nginx.com 523343Smax.romanov@nginx.com ra = rc->ra; 524343Smax.romanov@nginx.com 525343Smax.romanov@nginx.com if (ra != NULL) { 526343Smax.romanov@nginx.com rc->ra = NULL; 527343Smax.romanov@nginx.com ra->rc = NULL; 528343Smax.romanov@nginx.com 529343Smax.romanov@nginx.com nxt_thread_mutex_lock(&rc->app->mutex); 530343Smax.romanov@nginx.com 531343Smax.romanov@nginx.com if (ra->link.next != NULL) { 532343Smax.romanov@nginx.com nxt_queue_remove(&ra->link); 533343Smax.romanov@nginx.com 534343Smax.romanov@nginx.com ra->link.next = NULL; 535343Smax.romanov@nginx.com 536343Smax.romanov@nginx.com } else { 537343Smax.romanov@nginx.com ra = NULL; 538343Smax.romanov@nginx.com } 539343Smax.romanov@nginx.com 540343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&rc->app->mutex); 541343Smax.romanov@nginx.com } 542343Smax.romanov@nginx.com 543343Smax.romanov@nginx.com if (ra != NULL) { 544343Smax.romanov@nginx.com nxt_router_ra_release(task, ra, ra->work.data); 545343Smax.romanov@nginx.com } 546343Smax.romanov@nginx.com 547343Smax.romanov@nginx.com if (rc->app != NULL) { 548343Smax.romanov@nginx.com nxt_router_app_use(task, rc->app, -1); 549343Smax.romanov@nginx.com 550343Smax.romanov@nginx.com rc->app = NULL; 551343Smax.romanov@nginx.com } 552343Smax.romanov@nginx.com 553343Smax.romanov@nginx.com nxt_queue_remove(&rc->link); 554343Smax.romanov@nginx.com 555343Smax.romanov@nginx.com rc->conn = NULL; 556343Smax.romanov@nginx.com } 557343Smax.romanov@nginx.com 558343Smax.romanov@nginx.com 559141Smax.romanov@nginx.com void 560141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 561141Smax.romanov@nginx.com { 562141Smax.romanov@nginx.com nxt_port_new_port_handler(task, msg); 563141Smax.romanov@nginx.com 564192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 565141Smax.romanov@nginx.com return; 566141Smax.romanov@nginx.com } 567141Smax.romanov@nginx.com 568192Smax.romanov@nginx.com if (msg->new_port == NULL || msg->new_port->type != NXT_PROCESS_WORKER) { 569192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 570141Smax.romanov@nginx.com } 571192Smax.romanov@nginx.com 572192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 573141Smax.romanov@nginx.com } 574141Smax.romanov@nginx.com 575141Smax.romanov@nginx.com 576139Sigor@sysoev.ru void 577139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 578115Sigor@sysoev.ru { 579139Sigor@sysoev.ru size_t dump_size; 580198Sigor@sysoev.ru nxt_int_t ret; 581139Sigor@sysoev.ru nxt_buf_t *b; 582139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 583139Sigor@sysoev.ru 584139Sigor@sysoev.ru b = msg->buf; 585139Sigor@sysoev.ru 586139Sigor@sysoev.ru dump_size = nxt_buf_used_size(b); 587139Sigor@sysoev.ru 588139Sigor@sysoev.ru if (dump_size > 300) { 589139Sigor@sysoev.ru dump_size = 300; 59053Sigor@sysoev.ru } 59153Sigor@sysoev.ru 592139Sigor@sysoev.ru nxt_debug(task, "router conf data (%z): %*s", 593139Sigor@sysoev.ru msg->size, dump_size, b->mem.pos); 594139Sigor@sysoev.ru 595139Sigor@sysoev.ru tmcf = nxt_router_temp_conf(task); 596139Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 597139Sigor@sysoev.ru return; 59853Sigor@sysoev.ru } 59953Sigor@sysoev.ru 600139Sigor@sysoev.ru tmcf->conf->router = nxt_router; 601139Sigor@sysoev.ru tmcf->stream = msg->port_msg.stream; 602139Sigor@sysoev.ru tmcf->port = nxt_runtime_port_find(task->thread->runtime, 603198Sigor@sysoev.ru msg->port_msg.pid, 604198Sigor@sysoev.ru msg->port_msg.reply_port); 605198Sigor@sysoev.ru 606198Sigor@sysoev.ru ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free); 607198Sigor@sysoev.ru 608198Sigor@sysoev.ru if (nxt_fast_path(ret == NXT_OK)) { 609198Sigor@sysoev.ru nxt_router_conf_apply(task, tmcf, NULL); 610198Sigor@sysoev.ru 611198Sigor@sysoev.ru } else { 612198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 613139Sigor@sysoev.ru } 61453Sigor@sysoev.ru } 61553Sigor@sysoev.ru 61653Sigor@sysoev.ru 617192Smax.romanov@nginx.com void 618192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 619192Smax.romanov@nginx.com { 620318Smax.romanov@nginx.com nxt_mp_t *mp; 621318Smax.romanov@nginx.com nxt_buf_t *buf; 622318Smax.romanov@nginx.com nxt_event_engine_t *engine; 623318Smax.romanov@nginx.com nxt_remove_pid_msg_t *rp; 624318Smax.romanov@nginx.com 625192Smax.romanov@nginx.com nxt_port_remove_pid_handler(task, msg); 626192Smax.romanov@nginx.com 627192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 628192Smax.romanov@nginx.com return; 629192Smax.romanov@nginx.com } 630192Smax.romanov@nginx.com 631318Smax.romanov@nginx.com mp = nxt_mp_create(1024, 128, 256, 32); 632318Smax.romanov@nginx.com 633318Smax.romanov@nginx.com buf = nxt_buf_mem_alloc(mp, nxt_buf_used_size(msg->buf), 0); 634318Smax.romanov@nginx.com buf->mem.free = nxt_cpymem(buf->mem.free, msg->buf->mem.pos, 635318Smax.romanov@nginx.com nxt_buf_used_size(msg->buf)); 636318Smax.romanov@nginx.com 637318Smax.romanov@nginx.com nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0) 638318Smax.romanov@nginx.com { 639318Smax.romanov@nginx.com rp = nxt_mp_retain(mp, sizeof(nxt_remove_pid_msg_t)); 640318Smax.romanov@nginx.com 641318Smax.romanov@nginx.com rp->mem_pool = mp; 642318Smax.romanov@nginx.com 643318Smax.romanov@nginx.com rp->msg.fd = msg->fd; 644318Smax.romanov@nginx.com rp->msg.buf = buf; 645318Smax.romanov@nginx.com rp->msg.port = engine->port; 646318Smax.romanov@nginx.com rp->msg.port_msg = msg->port_msg; 647318Smax.romanov@nginx.com rp->msg.size = msg->size; 648318Smax.romanov@nginx.com rp->msg.new_port = NULL; 649318Smax.romanov@nginx.com 650318Smax.romanov@nginx.com rp->work.handler = nxt_router_worker_remove_pid_handler; 651318Smax.romanov@nginx.com rp->work.task = &engine->task; 652318Smax.romanov@nginx.com rp->work.obj = rp; 653318Smax.romanov@nginx.com rp->work.data = task->thread->engine; 654318Smax.romanov@nginx.com rp->work.next = NULL; 655318Smax.romanov@nginx.com 656318Smax.romanov@nginx.com nxt_event_engine_post(engine, &rp->work); 657318Smax.romanov@nginx.com } 658318Smax.romanov@nginx.com nxt_queue_loop; 659318Smax.romanov@nginx.com 660340Smax.romanov@nginx.com nxt_mp_release(mp, NULL); 661340Smax.romanov@nginx.com 662192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 663192Smax.romanov@nginx.com 664192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 665192Smax.romanov@nginx.com } 666192Smax.romanov@nginx.com 667192Smax.romanov@nginx.com 668318Smax.romanov@nginx.com static void 669318Smax.romanov@nginx.com nxt_router_worker_remove_pid_handler(nxt_task_t *task, void *obj, void *data) 670318Smax.romanov@nginx.com { 671343Smax.romanov@nginx.com nxt_pid_t pid; 672343Smax.romanov@nginx.com nxt_buf_t *buf; 673318Smax.romanov@nginx.com nxt_event_engine_t *engine; 674318Smax.romanov@nginx.com nxt_remove_pid_msg_t *rp; 675318Smax.romanov@nginx.com 676318Smax.romanov@nginx.com rp = obj; 677318Smax.romanov@nginx.com 678343Smax.romanov@nginx.com buf = rp->msg.buf; 679343Smax.romanov@nginx.com 680343Smax.romanov@nginx.com nxt_assert(nxt_buf_used_size(buf) == sizeof(pid)); 681343Smax.romanov@nginx.com 682343Smax.romanov@nginx.com nxt_memcpy(&pid, buf->mem.pos, sizeof(pid)); 683343Smax.romanov@nginx.com 684343Smax.romanov@nginx.com nxt_port_rpc_remove_peer(task, rp->msg.port, pid); 685318Smax.romanov@nginx.com 686318Smax.romanov@nginx.com engine = rp->work.data; 687318Smax.romanov@nginx.com 688318Smax.romanov@nginx.com rp->work.handler = nxt_router_worker_remove_pid_done; 689318Smax.romanov@nginx.com rp->work.task = &engine->task; 690318Smax.romanov@nginx.com rp->work.next = NULL; 691318Smax.romanov@nginx.com 692318Smax.romanov@nginx.com nxt_event_engine_post(engine, &rp->work); 693318Smax.romanov@nginx.com } 694318Smax.romanov@nginx.com 695318Smax.romanov@nginx.com 696318Smax.romanov@nginx.com static void 697318Smax.romanov@nginx.com nxt_router_worker_remove_pid_done(nxt_task_t *task, void *obj, void *data) 698318Smax.romanov@nginx.com { 699318Smax.romanov@nginx.com nxt_remove_pid_msg_t *rp; 700318Smax.romanov@nginx.com 701318Smax.romanov@nginx.com rp = obj; 702318Smax.romanov@nginx.com 703318Smax.romanov@nginx.com nxt_mp_release(rp->mem_pool, rp); 704318Smax.romanov@nginx.com } 705318Smax.romanov@nginx.com 706318Smax.romanov@nginx.com 70753Sigor@sysoev.ru static nxt_router_temp_conf_t * 708139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task) 70953Sigor@sysoev.ru { 71065Sigor@sysoev.ru nxt_mp_t *mp, *tmp; 71153Sigor@sysoev.ru nxt_router_conf_t *rtcf; 71253Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 71353Sigor@sysoev.ru 71465Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 71553Sigor@sysoev.ru if (nxt_slow_path(mp == NULL)) { 71653Sigor@sysoev.ru return NULL; 71753Sigor@sysoev.ru } 71853Sigor@sysoev.ru 71965Sigor@sysoev.ru rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t)); 72053Sigor@sysoev.ru if (nxt_slow_path(rtcf == NULL)) { 72153Sigor@sysoev.ru goto fail; 72253Sigor@sysoev.ru } 72353Sigor@sysoev.ru 72453Sigor@sysoev.ru rtcf->mem_pool = mp; 72553Sigor@sysoev.ru 72665Sigor@sysoev.ru tmp = nxt_mp_create(1024, 128, 256, 32); 72753Sigor@sysoev.ru if (nxt_slow_path(tmp == NULL)) { 72853Sigor@sysoev.ru goto fail; 72953Sigor@sysoev.ru } 73053Sigor@sysoev.ru 73165Sigor@sysoev.ru tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t)); 73253Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 73353Sigor@sysoev.ru goto temp_fail; 73453Sigor@sysoev.ru } 73553Sigor@sysoev.ru 73653Sigor@sysoev.ru tmcf->mem_pool = tmp; 73753Sigor@sysoev.ru tmcf->conf = rtcf; 738139Sigor@sysoev.ru tmcf->count = 1; 739139Sigor@sysoev.ru tmcf->engine = task->thread->engine; 74053Sigor@sysoev.ru 74153Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, 4, 74253Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 74353Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 74453Sigor@sysoev.ru goto temp_fail; 74553Sigor@sysoev.ru } 74653Sigor@sysoev.ru 74753Sigor@sysoev.ru nxt_queue_init(&tmcf->deleting); 74853Sigor@sysoev.ru nxt_queue_init(&tmcf->keeping); 74953Sigor@sysoev.ru nxt_queue_init(&tmcf->updating); 75053Sigor@sysoev.ru nxt_queue_init(&tmcf->pending); 75153Sigor@sysoev.ru nxt_queue_init(&tmcf->creating); 752133Sigor@sysoev.ru nxt_queue_init(&tmcf->apps); 753133Sigor@sysoev.ru nxt_queue_init(&tmcf->previous); 75453Sigor@sysoev.ru 75553Sigor@sysoev.ru return tmcf; 75653Sigor@sysoev.ru 75753Sigor@sysoev.ru temp_fail: 75853Sigor@sysoev.ru 75965Sigor@sysoev.ru nxt_mp_destroy(tmp); 76053Sigor@sysoev.ru 76153Sigor@sysoev.ru fail: 76253Sigor@sysoev.ru 76365Sigor@sysoev.ru nxt_mp_destroy(mp); 76453Sigor@sysoev.ru 76553Sigor@sysoev.ru return NULL; 76653Sigor@sysoev.ru } 76753Sigor@sysoev.ru 76853Sigor@sysoev.ru 769198Sigor@sysoev.ru static void 770198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data) 771139Sigor@sysoev.ru { 772139Sigor@sysoev.ru nxt_int_t ret; 773139Sigor@sysoev.ru nxt_router_t *router; 774139Sigor@sysoev.ru nxt_runtime_t *rt; 775198Sigor@sysoev.ru nxt_queue_link_t *qlk; 776198Sigor@sysoev.ru nxt_socket_conf_t *skcf; 777198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 778139Sigor@sysoev.ru const nxt_event_interface_t *interface; 779139Sigor@sysoev.ru 780198Sigor@sysoev.ru tmcf = obj; 781198Sigor@sysoev.ru 782198Sigor@sysoev.ru qlk = nxt_queue_first(&tmcf->pending); 783198Sigor@sysoev.ru 784198Sigor@sysoev.ru if (qlk != nxt_queue_tail(&tmcf->pending)) { 785198Sigor@sysoev.ru nxt_queue_remove(qlk); 786198Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->creating, qlk); 787198Sigor@sysoev.ru 788198Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 789198Sigor@sysoev.ru 790198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(task, tmcf, skcf); 791198Sigor@sysoev.ru 792198Sigor@sysoev.ru return; 793139Sigor@sysoev.ru } 794139Sigor@sysoev.ru 795139Sigor@sysoev.ru rt = task->thread->runtime; 796139Sigor@sysoev.ru 797139Sigor@sysoev.ru interface = nxt_service_get(rt->services, "engine", NULL); 798139Sigor@sysoev.ru 799198Sigor@sysoev.ru router = tmcf->conf->router; 800198Sigor@sysoev.ru 801139Sigor@sysoev.ru ret = nxt_router_engines_create(task, router, tmcf, interface); 802139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 803198Sigor@sysoev.ru goto fail; 804139Sigor@sysoev.ru } 805139Sigor@sysoev.ru 806139Sigor@sysoev.ru ret = nxt_router_threads_create(task, rt, tmcf); 807139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 808198Sigor@sysoev.ru goto fail; 809139Sigor@sysoev.ru } 810139Sigor@sysoev.ru 811343Smax.romanov@nginx.com nxt_router_apps_sort(task, router, tmcf); 812139Sigor@sysoev.ru 813315Sigor@sysoev.ru nxt_router_engines_post(router, tmcf); 814139Sigor@sysoev.ru 815139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->updating); 816139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->creating); 817139Sigor@sysoev.ru 818198Sigor@sysoev.ru nxt_router_conf_ready(task, tmcf); 819198Sigor@sysoev.ru 820198Sigor@sysoev.ru return; 821198Sigor@sysoev.ru 822198Sigor@sysoev.ru fail: 823198Sigor@sysoev.ru 824198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 825198Sigor@sysoev.ru 826198Sigor@sysoev.ru return; 827139Sigor@sysoev.ru } 828139Sigor@sysoev.ru 829139Sigor@sysoev.ru 830139Sigor@sysoev.ru static void 831139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data) 832139Sigor@sysoev.ru { 833153Sigor@sysoev.ru nxt_joint_job_t *job; 834153Sigor@sysoev.ru 835153Sigor@sysoev.ru job = obj; 836153Sigor@sysoev.ru 837198Sigor@sysoev.ru nxt_router_conf_ready(task, job->tmcf); 838139Sigor@sysoev.ru } 839139Sigor@sysoev.ru 840139Sigor@sysoev.ru 841139Sigor@sysoev.ru static void 842198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 843139Sigor@sysoev.ru { 844139Sigor@sysoev.ru nxt_debug(task, "temp conf count:%D", tmcf->count); 845139Sigor@sysoev.ru 846139Sigor@sysoev.ru if (--tmcf->count == 0) { 847193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST); 848139Sigor@sysoev.ru } 849139Sigor@sysoev.ru } 850139Sigor@sysoev.ru 851139Sigor@sysoev.ru 852139Sigor@sysoev.ru static void 853139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 854139Sigor@sysoev.ru { 855148Sigor@sysoev.ru nxt_socket_t s; 856149Sigor@sysoev.ru nxt_router_t *router; 857148Sigor@sysoev.ru nxt_queue_link_t *qlk; 858148Sigor@sysoev.ru nxt_socket_conf_t *skcf; 859148Sigor@sysoev.ru 860198Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "failed to apply new conf"); 861198Sigor@sysoev.ru 862148Sigor@sysoev.ru for (qlk = nxt_queue_first(&tmcf->creating); 863148Sigor@sysoev.ru qlk != nxt_queue_tail(&tmcf->creating); 864148Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 865148Sigor@sysoev.ru { 866148Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 867148Sigor@sysoev.ru s = skcf->listen.socket; 868148Sigor@sysoev.ru 869148Sigor@sysoev.ru if (s != -1) { 870148Sigor@sysoev.ru nxt_socket_close(task, s); 871148Sigor@sysoev.ru } 872148Sigor@sysoev.ru 873148Sigor@sysoev.ru nxt_free(skcf->socket); 874148Sigor@sysoev.ru } 875148Sigor@sysoev.ru 876149Sigor@sysoev.ru router = tmcf->conf->router; 877149Sigor@sysoev.ru 878149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->keeping); 879149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->deleting); 880149Sigor@sysoev.ru 881148Sigor@sysoev.ru // TODO: new engines and threads 882148Sigor@sysoev.ru 883139Sigor@sysoev.ru nxt_mp_destroy(tmcf->conf->mem_pool); 884139Sigor@sysoev.ru 885193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR); 886139Sigor@sysoev.ru } 887139Sigor@sysoev.ru 888139Sigor@sysoev.ru 889139Sigor@sysoev.ru static void 890139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 891193Smax.romanov@nginx.com nxt_port_msg_type_t type) 892139Sigor@sysoev.ru { 893193Smax.romanov@nginx.com nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL); 894139Sigor@sysoev.ru } 895139Sigor@sysoev.ru 896139Sigor@sysoev.ru 897115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_conf[] = { 898115Sigor@sysoev.ru { 899133Sigor@sysoev.ru nxt_string("listeners_threads"), 900115Sigor@sysoev.ru NXT_CONF_MAP_INT32, 901115Sigor@sysoev.ru offsetof(nxt_router_conf_t, threads), 902115Sigor@sysoev.ru }, 903115Sigor@sysoev.ru }; 904115Sigor@sysoev.ru 905115Sigor@sysoev.ru 906133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_app_conf[] = { 907115Sigor@sysoev.ru { 908133Sigor@sysoev.ru nxt_string("type"), 909115Sigor@sysoev.ru NXT_CONF_MAP_STR, 910133Sigor@sysoev.ru offsetof(nxt_router_app_conf_t, type), 911115Sigor@sysoev.ru }, 912115Sigor@sysoev.ru 913115Sigor@sysoev.ru { 914133Sigor@sysoev.ru nxt_string("workers"), 915115Sigor@sysoev.ru NXT_CONF_MAP_INT32, 916133Sigor@sysoev.ru offsetof(nxt_router_app_conf_t, workers), 917133Sigor@sysoev.ru }, 918318Smax.romanov@nginx.com 919318Smax.romanov@nginx.com { 920318Smax.romanov@nginx.com nxt_string("limits"), 921318Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 922318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, limits_value), 923318Smax.romanov@nginx.com }, 924318Smax.romanov@nginx.com }; 925318Smax.romanov@nginx.com 926318Smax.romanov@nginx.com 927318Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_limits_conf[] = { 928318Smax.romanov@nginx.com { 929318Smax.romanov@nginx.com nxt_string("timeout"), 930318Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 931318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, timeout), 932318Smax.romanov@nginx.com }, 933318Smax.romanov@nginx.com 934318Smax.romanov@nginx.com { 935318Smax.romanov@nginx.com nxt_string("requests"), 936318Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 937318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, requests), 938318Smax.romanov@nginx.com }, 939133Sigor@sysoev.ru }; 940133Sigor@sysoev.ru 941133Sigor@sysoev.ru 942133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_listener_conf[] = { 943133Sigor@sysoev.ru { 944133Sigor@sysoev.ru nxt_string("application"), 945133Sigor@sysoev.ru NXT_CONF_MAP_STR, 946133Sigor@sysoev.ru offsetof(nxt_router_listener_conf_t, application), 947115Sigor@sysoev.ru }, 948115Sigor@sysoev.ru }; 949115Sigor@sysoev.ru 950115Sigor@sysoev.ru 951115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_http_conf[] = { 952115Sigor@sysoev.ru { 953115Sigor@sysoev.ru nxt_string("header_buffer_size"), 954115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 955115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_buffer_size), 956115Sigor@sysoev.ru }, 957115Sigor@sysoev.ru 958115Sigor@sysoev.ru { 959115Sigor@sysoev.ru nxt_string("large_header_buffer_size"), 960115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 961115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, large_header_buffer_size), 962115Sigor@sysoev.ru }, 963115Sigor@sysoev.ru 964115Sigor@sysoev.ru { 965206Smax.romanov@nginx.com nxt_string("large_header_buffers"), 966206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 967206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, large_header_buffers), 968206Smax.romanov@nginx.com }, 969206Smax.romanov@nginx.com 970206Smax.romanov@nginx.com { 971206Smax.romanov@nginx.com nxt_string("body_buffer_size"), 972206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 973206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_buffer_size), 974206Smax.romanov@nginx.com }, 975206Smax.romanov@nginx.com 976206Smax.romanov@nginx.com { 977206Smax.romanov@nginx.com nxt_string("max_body_size"), 978206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 979206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, max_body_size), 980206Smax.romanov@nginx.com }, 981206Smax.romanov@nginx.com 982206Smax.romanov@nginx.com { 983115Sigor@sysoev.ru nxt_string("header_read_timeout"), 984115Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 985115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_read_timeout), 986115Sigor@sysoev.ru }, 987206Smax.romanov@nginx.com 988206Smax.romanov@nginx.com { 989206Smax.romanov@nginx.com nxt_string("body_read_timeout"), 990206Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 991206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_read_timeout), 992206Smax.romanov@nginx.com }, 993115Sigor@sysoev.ru }; 994115Sigor@sysoev.ru 995115Sigor@sysoev.ru 99653Sigor@sysoev.ru static nxt_int_t 997115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 998115Sigor@sysoev.ru u_char *start, u_char *end) 99953Sigor@sysoev.ru { 1000133Sigor@sysoev.ru u_char *p; 1001133Sigor@sysoev.ru size_t size; 1002115Sigor@sysoev.ru nxt_mp_t *mp; 1003115Sigor@sysoev.ru uint32_t next; 1004115Sigor@sysoev.ru nxt_int_t ret; 1005115Sigor@sysoev.ru nxt_str_t name; 1006133Sigor@sysoev.ru nxt_app_t *app, *prev; 1007133Sigor@sysoev.ru nxt_app_type_t type; 1008115Sigor@sysoev.ru nxt_sockaddr_t *sa; 1009133Sigor@sysoev.ru nxt_conf_value_t *conf, *http; 1010133Sigor@sysoev.ru nxt_conf_value_t *applications, *application; 1011133Sigor@sysoev.ru nxt_conf_value_t *listeners, *listener; 1012115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1013216Sigor@sysoev.ru nxt_app_lang_module_t *lang; 1014133Sigor@sysoev.ru nxt_router_app_conf_t apcf; 1015115Sigor@sysoev.ru nxt_router_listener_conf_t lscf; 1016115Sigor@sysoev.ru 1017115Sigor@sysoev.ru static nxt_str_t http_path = nxt_string("/http"); 1018133Sigor@sysoev.ru static nxt_str_t applications_path = nxt_string("/applications"); 1019115Sigor@sysoev.ru static nxt_str_t listeners_path = nxt_string("/listeners"); 1020115Sigor@sysoev.ru 1021208Svbart@nginx.com conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL); 1022115Sigor@sysoev.ru if (conf == NULL) { 1023115Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "configuration parsing error"); 1024115Sigor@sysoev.ru return NXT_ERROR; 1025115Sigor@sysoev.ru } 1026115Sigor@sysoev.ru 1027213Svbart@nginx.com mp = tmcf->conf->mem_pool; 1028213Svbart@nginx.com 1029213Svbart@nginx.com ret = nxt_conf_map_object(mp, conf, nxt_router_conf, 1030136Svbart@nginx.com nxt_nitems(nxt_router_conf), tmcf->conf); 1031115Sigor@sysoev.ru if (ret != NXT_OK) { 1032133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "root map error"); 1033115Sigor@sysoev.ru return NXT_ERROR; 1034115Sigor@sysoev.ru } 1035115Sigor@sysoev.ru 1036117Sigor@sysoev.ru if (tmcf->conf->threads == 0) { 1037117Sigor@sysoev.ru tmcf->conf->threads = nxt_ncpu; 1038117Sigor@sysoev.ru } 1039117Sigor@sysoev.ru 1040133Sigor@sysoev.ru applications = nxt_conf_get_path(conf, &applications_path); 1041133Sigor@sysoev.ru if (applications == NULL) { 1042133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block"); 1043115Sigor@sysoev.ru return NXT_ERROR; 1044115Sigor@sysoev.ru } 1045115Sigor@sysoev.ru 1046133Sigor@sysoev.ru next = 0; 1047133Sigor@sysoev.ru 1048133Sigor@sysoev.ru for ( ;; ) { 1049133Sigor@sysoev.ru application = nxt_conf_next_object_member(applications, &name, &next); 1050133Sigor@sysoev.ru if (application == NULL) { 1051133Sigor@sysoev.ru break; 1052133Sigor@sysoev.ru } 1053133Sigor@sysoev.ru 1054133Sigor@sysoev.ru nxt_debug(task, "application \"%V\"", &name); 1055133Sigor@sysoev.ru 1056144Smax.romanov@nginx.com size = nxt_conf_json_length(application, NULL); 1057144Smax.romanov@nginx.com 1058144Smax.romanov@nginx.com app = nxt_malloc(sizeof(nxt_app_t) + name.length + size); 1059133Sigor@sysoev.ru if (app == NULL) { 1060133Sigor@sysoev.ru goto fail; 1061133Sigor@sysoev.ru } 1062133Sigor@sysoev.ru 1063144Smax.romanov@nginx.com nxt_memzero(app, sizeof(nxt_app_t)); 1064144Smax.romanov@nginx.com 1065144Smax.romanov@nginx.com app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t)); 1066144Smax.romanov@nginx.com app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length); 1067133Sigor@sysoev.ru 1068133Sigor@sysoev.ru p = nxt_conf_json_print(app->conf.start, application, NULL); 1069133Sigor@sysoev.ru app->conf.length = p - app->conf.start; 1070133Sigor@sysoev.ru 1071144Smax.romanov@nginx.com nxt_assert(app->conf.length <= size); 1072144Smax.romanov@nginx.com 1073133Sigor@sysoev.ru nxt_debug(task, "application conf \"%V\"", &app->conf); 1074133Sigor@sysoev.ru 1075133Sigor@sysoev.ru prev = nxt_router_app_find(&tmcf->conf->router->apps, &name); 1076133Sigor@sysoev.ru 1077133Sigor@sysoev.ru if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) { 1078133Sigor@sysoev.ru nxt_free(app); 1079133Sigor@sysoev.ru 1080133Sigor@sysoev.ru nxt_queue_remove(&prev->link); 1081133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->previous, &prev->link); 1082133Sigor@sysoev.ru continue; 1083133Sigor@sysoev.ru } 1084133Sigor@sysoev.ru 1085263Smax.romanov@nginx.com apcf.workers = 1; 1086318Smax.romanov@nginx.com apcf.timeout = 0; 1087318Smax.romanov@nginx.com apcf.requests = 0; 1088318Smax.romanov@nginx.com apcf.limits_value = NULL; 1089263Smax.romanov@nginx.com 1090213Svbart@nginx.com ret = nxt_conf_map_object(mp, application, nxt_router_app_conf, 1091136Svbart@nginx.com nxt_nitems(nxt_router_app_conf), &apcf); 1092133Sigor@sysoev.ru if (ret != NXT_OK) { 1093133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "application map error"); 1094133Sigor@sysoev.ru goto app_fail; 1095133Sigor@sysoev.ru } 1096115Sigor@sysoev.ru 1097318Smax.romanov@nginx.com if (apcf.limits_value != NULL) { 1098318Smax.romanov@nginx.com 1099318Smax.romanov@nginx.com if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) { 1100318Smax.romanov@nginx.com nxt_log(task, NXT_LOG_CRIT, "application limits is not object"); 1101318Smax.romanov@nginx.com goto app_fail; 1102318Smax.romanov@nginx.com } 1103318Smax.romanov@nginx.com 1104318Smax.romanov@nginx.com ret = nxt_conf_map_object(mp, apcf.limits_value, 1105318Smax.romanov@nginx.com nxt_router_app_limits_conf, 1106318Smax.romanov@nginx.com nxt_nitems(nxt_router_app_limits_conf), 1107318Smax.romanov@nginx.com &apcf); 1108318Smax.romanov@nginx.com if (ret != NXT_OK) { 1109318Smax.romanov@nginx.com nxt_log(task, NXT_LOG_CRIT, "application limits map error"); 1110318Smax.romanov@nginx.com goto app_fail; 1111318Smax.romanov@nginx.com } 1112318Smax.romanov@nginx.com } 1113318Smax.romanov@nginx.com 1114133Sigor@sysoev.ru nxt_debug(task, "application type: %V", &apcf.type); 1115133Sigor@sysoev.ru nxt_debug(task, "application workers: %D", apcf.workers); 1116318Smax.romanov@nginx.com nxt_debug(task, "application timeout: %D", apcf.timeout); 1117318Smax.romanov@nginx.com nxt_debug(task, "application requests: %D", apcf.requests); 1118133Sigor@sysoev.ru 1119216Sigor@sysoev.ru lang = nxt_app_lang_module(task->thread->runtime, &apcf.type); 1120216Sigor@sysoev.ru 1121216Sigor@sysoev.ru if (lang == NULL) { 1122141Smax.romanov@nginx.com nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"", 1123141Smax.romanov@nginx.com &apcf.type); 1124141Smax.romanov@nginx.com goto app_fail; 1125141Smax.romanov@nginx.com } 1126141Smax.romanov@nginx.com 1127216Sigor@sysoev.ru nxt_debug(task, "application language module: \"%s\"", lang->file); 1128216Sigor@sysoev.ru 1129216Sigor@sysoev.ru type = nxt_app_parse_type(&lang->type); 1130216Sigor@sysoev.ru 1131216Sigor@sysoev.ru if (type == NXT_APP_UNKNOWN) { 1132216Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"", 1133216Sigor@sysoev.ru &lang->type); 1134216Sigor@sysoev.ru goto app_fail; 1135216Sigor@sysoev.ru } 1136216Sigor@sysoev.ru 1137216Sigor@sysoev.ru if (nxt_app_prepare_msg[type] == NULL) { 1138133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "unsupported application type: \"%V\"", 1139216Sigor@sysoev.ru &lang->type); 1140133Sigor@sysoev.ru goto app_fail; 1141133Sigor@sysoev.ru } 1142133Sigor@sysoev.ru 1143133Sigor@sysoev.ru ret = nxt_thread_mutex_create(&app->mutex); 1144133Sigor@sysoev.ru if (ret != NXT_OK) { 1145133Sigor@sysoev.ru goto app_fail; 1146133Sigor@sysoev.ru } 1147133Sigor@sysoev.ru 1148141Smax.romanov@nginx.com nxt_queue_init(&app->ports); 1149141Smax.romanov@nginx.com nxt_queue_init(&app->requests); 1150141Smax.romanov@nginx.com 1151144Smax.romanov@nginx.com app->name.length = name.length; 1152144Smax.romanov@nginx.com nxt_memcpy(app->name.start, name.start, name.length); 1153144Smax.romanov@nginx.com 1154133Sigor@sysoev.ru app->type = type; 1155133Sigor@sysoev.ru app->max_workers = apcf.workers; 1156318Smax.romanov@nginx.com app->timeout = apcf.timeout; 1157133Sigor@sysoev.ru app->live = 1; 1158343Smax.romanov@nginx.com app->max_pending_responses = 2; 1159216Sigor@sysoev.ru app->prepare_msg = nxt_app_prepare_msg[type]; 1160133Sigor@sysoev.ru 1161133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->apps, &app->link); 1162343Smax.romanov@nginx.com 1163343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 1164133Sigor@sysoev.ru } 1165133Sigor@sysoev.ru 1166133Sigor@sysoev.ru http = nxt_conf_get_path(conf, &http_path); 1167133Sigor@sysoev.ru #if 0 1168133Sigor@sysoev.ru if (http == NULL) { 1169133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "no \"http\" block"); 1170133Sigor@sysoev.ru return NXT_ERROR; 1171133Sigor@sysoev.ru } 1172133Sigor@sysoev.ru #endif 1173133Sigor@sysoev.ru 1174133Sigor@sysoev.ru listeners = nxt_conf_get_path(conf, &listeners_path); 1175115Sigor@sysoev.ru if (listeners == NULL) { 1176133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block"); 1177115Sigor@sysoev.ru return NXT_ERROR; 1178115Sigor@sysoev.ru } 117953Sigor@sysoev.ru 1180133Sigor@sysoev.ru next = 0; 118153Sigor@sysoev.ru 1182115Sigor@sysoev.ru for ( ;; ) { 1183115Sigor@sysoev.ru listener = nxt_conf_next_object_member(listeners, &name, &next); 1184115Sigor@sysoev.ru if (listener == NULL) { 1185115Sigor@sysoev.ru break; 1186115Sigor@sysoev.ru } 118753Sigor@sysoev.ru 1188115Sigor@sysoev.ru sa = nxt_sockaddr_parse(mp, &name); 1189115Sigor@sysoev.ru if (sa == NULL) { 1190115Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", &name); 1191133Sigor@sysoev.ru goto fail; 1192115Sigor@sysoev.ru } 1193115Sigor@sysoev.ru 1194115Sigor@sysoev.ru sa->type = SOCK_STREAM; 1195115Sigor@sysoev.ru 1196115Sigor@sysoev.ru nxt_debug(task, "router listener: \"%*s\"", 1197115Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa)); 119853Sigor@sysoev.ru 1199115Sigor@sysoev.ru skcf = nxt_router_socket_conf(task, mp, sa); 1200115Sigor@sysoev.ru if (skcf == NULL) { 1201133Sigor@sysoev.ru goto fail; 1202115Sigor@sysoev.ru } 120353Sigor@sysoev.ru 1204213Svbart@nginx.com ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf, 1205136Svbart@nginx.com nxt_nitems(nxt_router_listener_conf), &lscf); 1206115Sigor@sysoev.ru if (ret != NXT_OK) { 1207115Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "listener map error"); 1208133Sigor@sysoev.ru goto fail; 1209115Sigor@sysoev.ru } 121053Sigor@sysoev.ru 1211133Sigor@sysoev.ru nxt_debug(task, "application: %V", &lscf.application); 1212133Sigor@sysoev.ru 1213133Sigor@sysoev.ru // STUB, default values if http block is not defined. 1214133Sigor@sysoev.ru skcf->header_buffer_size = 2048; 1215133Sigor@sysoev.ru skcf->large_header_buffer_size = 8192; 1216206Smax.romanov@nginx.com skcf->large_header_buffers = 4; 1217206Smax.romanov@nginx.com skcf->body_buffer_size = 16 * 1024; 1218206Smax.romanov@nginx.com skcf->max_body_size = 2 * 1024 * 1024; 1219133Sigor@sysoev.ru skcf->header_read_timeout = 5000; 1220206Smax.romanov@nginx.com skcf->body_read_timeout = 5000; 122153Sigor@sysoev.ru 1222133Sigor@sysoev.ru if (http != NULL) { 1223213Svbart@nginx.com ret = nxt_conf_map_object(mp, http, nxt_router_http_conf, 1224136Svbart@nginx.com nxt_nitems(nxt_router_http_conf), skcf); 1225133Sigor@sysoev.ru if (ret != NXT_OK) { 1226133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "http map error"); 1227133Sigor@sysoev.ru goto fail; 1228133Sigor@sysoev.ru } 1229115Sigor@sysoev.ru } 1230115Sigor@sysoev.ru 1231115Sigor@sysoev.ru skcf->listen.handler = nxt_router_conn_init; 1232115Sigor@sysoev.ru skcf->router_conf = tmcf->conf; 1233160Sigor@sysoev.ru skcf->router_conf->count++; 1234133Sigor@sysoev.ru skcf->application = nxt_router_listener_application(tmcf, 1235133Sigor@sysoev.ru &lscf.application); 1236115Sigor@sysoev.ru 1237115Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->pending, &skcf->link); 1238115Sigor@sysoev.ru } 123953Sigor@sysoev.ru 1240198Sigor@sysoev.ru nxt_router_listen_sockets_sort(tmcf->conf->router, tmcf); 1241198Sigor@sysoev.ru 124253Sigor@sysoev.ru return NXT_OK; 1243133Sigor@sysoev.ru 1244133Sigor@sysoev.ru app_fail: 1245133Sigor@sysoev.ru 1246133Sigor@sysoev.ru nxt_free(app); 1247133Sigor@sysoev.ru 1248133Sigor@sysoev.ru fail: 1249133Sigor@sysoev.ru 1250141Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1251141Smax.romanov@nginx.com 1252141Smax.romanov@nginx.com nxt_queue_remove(&app->link); 1253133Sigor@sysoev.ru nxt_thread_mutex_destroy(&app->mutex); 1254133Sigor@sysoev.ru nxt_free(app); 1255141Smax.romanov@nginx.com 1256141Smax.romanov@nginx.com } nxt_queue_loop; 1257133Sigor@sysoev.ru 1258133Sigor@sysoev.ru return NXT_ERROR; 1259133Sigor@sysoev.ru } 1260133Sigor@sysoev.ru 1261133Sigor@sysoev.ru 1262133Sigor@sysoev.ru static nxt_app_t * 1263133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name) 1264133Sigor@sysoev.ru { 1265141Smax.romanov@nginx.com nxt_app_t *app; 1266141Smax.romanov@nginx.com 1267141Smax.romanov@nginx.com nxt_queue_each(app, queue, nxt_app_t, link) { 1268133Sigor@sysoev.ru 1269133Sigor@sysoev.ru if (nxt_strstr_eq(name, &app->name)) { 1270133Sigor@sysoev.ru return app; 1271133Sigor@sysoev.ru } 1272141Smax.romanov@nginx.com 1273141Smax.romanov@nginx.com } nxt_queue_loop; 1274133Sigor@sysoev.ru 1275133Sigor@sysoev.ru return NULL; 1276133Sigor@sysoev.ru } 1277133Sigor@sysoev.ru 1278133Sigor@sysoev.ru 1279133Sigor@sysoev.ru static nxt_app_t * 1280133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name) 1281133Sigor@sysoev.ru { 1282133Sigor@sysoev.ru nxt_app_t *app; 1283133Sigor@sysoev.ru 1284133Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->apps, name); 1285133Sigor@sysoev.ru 1286133Sigor@sysoev.ru if (app == NULL) { 1287134Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->previous, name); 1288133Sigor@sysoev.ru } 1289133Sigor@sysoev.ru 1290133Sigor@sysoev.ru return app; 129153Sigor@sysoev.ru } 129253Sigor@sysoev.ru 129353Sigor@sysoev.ru 129453Sigor@sysoev.ru static nxt_socket_conf_t * 129565Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, nxt_sockaddr_t *sa) 129653Sigor@sysoev.ru { 1297163Smax.romanov@nginx.com nxt_socket_conf_t *skcf; 1298163Smax.romanov@nginx.com 1299163Smax.romanov@nginx.com skcf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_t)); 1300163Smax.romanov@nginx.com if (nxt_slow_path(skcf == NULL)) { 130153Sigor@sysoev.ru return NULL; 130253Sigor@sysoev.ru } 130353Sigor@sysoev.ru 1304163Smax.romanov@nginx.com skcf->sockaddr = sa; 1305163Smax.romanov@nginx.com 1306163Smax.romanov@nginx.com skcf->listen.sockaddr = sa; 1307312Sigor@sysoev.ru 1308312Sigor@sysoev.ru nxt_listen_socket_remote_size(&skcf->listen, sa); 1309163Smax.romanov@nginx.com 1310163Smax.romanov@nginx.com skcf->listen.socket = -1; 1311163Smax.romanov@nginx.com skcf->listen.backlog = NXT_LISTEN_BACKLOG; 1312163Smax.romanov@nginx.com skcf->listen.flags = NXT_NONBLOCK; 1313163Smax.romanov@nginx.com skcf->listen.read_after_accept = 1; 1314163Smax.romanov@nginx.com 1315163Smax.romanov@nginx.com return skcf; 131653Sigor@sysoev.ru } 131753Sigor@sysoev.ru 131853Sigor@sysoev.ru 131953Sigor@sysoev.ru static void 132053Sigor@sysoev.ru nxt_router_listen_sockets_sort(nxt_router_t *router, 132153Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 132253Sigor@sysoev.ru { 132353Sigor@sysoev.ru nxt_queue_link_t *nqlk, *oqlk, *next; 132453Sigor@sysoev.ru nxt_socket_conf_t *nskcf, *oskcf; 132553Sigor@sysoev.ru 132653Sigor@sysoev.ru for (nqlk = nxt_queue_first(&tmcf->pending); 132753Sigor@sysoev.ru nqlk != nxt_queue_tail(&tmcf->pending); 132853Sigor@sysoev.ru nqlk = next) 132953Sigor@sysoev.ru { 133053Sigor@sysoev.ru next = nxt_queue_next(nqlk); 133153Sigor@sysoev.ru nskcf = nxt_queue_link_data(nqlk, nxt_socket_conf_t, link); 133253Sigor@sysoev.ru 133353Sigor@sysoev.ru for (oqlk = nxt_queue_first(&router->sockets); 133453Sigor@sysoev.ru oqlk != nxt_queue_tail(&router->sockets); 133553Sigor@sysoev.ru oqlk = nxt_queue_next(oqlk)) 133653Sigor@sysoev.ru { 133753Sigor@sysoev.ru oskcf = nxt_queue_link_data(oqlk, nxt_socket_conf_t, link); 133853Sigor@sysoev.ru 1339115Sigor@sysoev.ru if (nxt_sockaddr_cmp(nskcf->sockaddr, oskcf->sockaddr)) { 1340115Sigor@sysoev.ru nskcf->socket = oskcf->socket; 1341115Sigor@sysoev.ru nskcf->listen.socket = oskcf->listen.socket; 1342115Sigor@sysoev.ru 134353Sigor@sysoev.ru nxt_queue_remove(oqlk); 134453Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->keeping, oqlk); 134553Sigor@sysoev.ru 134653Sigor@sysoev.ru nxt_queue_remove(nqlk); 134753Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->updating, nqlk); 134853Sigor@sysoev.ru 134953Sigor@sysoev.ru break; 135053Sigor@sysoev.ru } 135153Sigor@sysoev.ru } 135253Sigor@sysoev.ru } 135353Sigor@sysoev.ru 135453Sigor@sysoev.ru nxt_queue_add(&tmcf->deleting, &router->sockets); 1355115Sigor@sysoev.ru nxt_queue_init(&router->sockets); 135653Sigor@sysoev.ru } 135753Sigor@sysoev.ru 135853Sigor@sysoev.ru 1359198Sigor@sysoev.ru static void 1360198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task, 1361198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf) 1362198Sigor@sysoev.ru { 1363198Sigor@sysoev.ru uint32_t stream; 1364198Sigor@sysoev.ru nxt_buf_t *b; 1365198Sigor@sysoev.ru nxt_port_t *main_port, *router_port; 1366198Sigor@sysoev.ru nxt_runtime_t *rt; 1367198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 1368198Sigor@sysoev.ru 1369198Sigor@sysoev.ru rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t)); 1370198Sigor@sysoev.ru if (rpc == NULL) { 1371198Sigor@sysoev.ru goto fail; 1372198Sigor@sysoev.ru } 1373198Sigor@sysoev.ru 1374198Sigor@sysoev.ru rpc->socket_conf = skcf; 1375198Sigor@sysoev.ru rpc->temp_conf = tmcf; 1376198Sigor@sysoev.ru 1377198Sigor@sysoev.ru b = nxt_buf_mem_alloc(tmcf->mem_pool, skcf->sockaddr->sockaddr_size, 0); 1378198Sigor@sysoev.ru if (b == NULL) { 1379198Sigor@sysoev.ru goto fail; 1380198Sigor@sysoev.ru } 1381198Sigor@sysoev.ru 1382198Sigor@sysoev.ru b->mem.free = nxt_cpymem(b->mem.free, skcf->sockaddr, 1383198Sigor@sysoev.ru skcf->sockaddr->sockaddr_size); 1384198Sigor@sysoev.ru 1385198Sigor@sysoev.ru rt = task->thread->runtime; 1386240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1387198Sigor@sysoev.ru router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 1388198Sigor@sysoev.ru 1389198Sigor@sysoev.ru stream = nxt_port_rpc_register_handler(task, router_port, 1390198Sigor@sysoev.ru nxt_router_listen_socket_ready, 1391198Sigor@sysoev.ru nxt_router_listen_socket_error, 1392198Sigor@sysoev.ru main_port->pid, rpc); 1393198Sigor@sysoev.ru if (stream == 0) { 1394198Sigor@sysoev.ru goto fail; 1395198Sigor@sysoev.ru } 1396198Sigor@sysoev.ru 1397198Sigor@sysoev.ru nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1, 1398198Sigor@sysoev.ru stream, router_port->id, b); 1399198Sigor@sysoev.ru 1400198Sigor@sysoev.ru return; 1401198Sigor@sysoev.ru 1402198Sigor@sysoev.ru fail: 1403198Sigor@sysoev.ru 1404198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 1405198Sigor@sysoev.ru } 1406198Sigor@sysoev.ru 1407198Sigor@sysoev.ru 1408198Sigor@sysoev.ru static void 1409198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1410198Sigor@sysoev.ru void *data) 141153Sigor@sysoev.ru { 1412115Sigor@sysoev.ru nxt_int_t ret; 1413115Sigor@sysoev.ru nxt_socket_t s; 1414198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 1415115Sigor@sysoev.ru nxt_router_socket_t *rtsk; 141653Sigor@sysoev.ru 1417198Sigor@sysoev.ru rpc = data; 1418198Sigor@sysoev.ru 1419198Sigor@sysoev.ru s = msg->fd; 1420198Sigor@sysoev.ru 1421198Sigor@sysoev.ru ret = nxt_socket_nonblocking(task, s); 1422198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1423198Sigor@sysoev.ru goto fail; 142453Sigor@sysoev.ru } 142553Sigor@sysoev.ru 1426229Sigor@sysoev.ru nxt_socket_defer_accept(task, s, rpc->socket_conf->sockaddr); 1427198Sigor@sysoev.ru 1428198Sigor@sysoev.ru ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG); 1429198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1430198Sigor@sysoev.ru goto fail; 1431198Sigor@sysoev.ru } 1432198Sigor@sysoev.ru 1433198Sigor@sysoev.ru rtsk = nxt_malloc(sizeof(nxt_router_socket_t)); 1434198Sigor@sysoev.ru if (nxt_slow_path(rtsk == NULL)) { 1435198Sigor@sysoev.ru goto fail; 1436198Sigor@sysoev.ru } 1437198Sigor@sysoev.ru 1438198Sigor@sysoev.ru rtsk->count = 0; 1439198Sigor@sysoev.ru rtsk->fd = s; 1440198Sigor@sysoev.ru 1441198Sigor@sysoev.ru rpc->socket_conf->listen.socket = s; 1442198Sigor@sysoev.ru rpc->socket_conf->socket = rtsk; 1443198Sigor@sysoev.ru 1444198Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 1445198Sigor@sysoev.ru nxt_router_conf_apply, task, rpc->temp_conf, NULL); 1446198Sigor@sysoev.ru 1447198Sigor@sysoev.ru return; 1448148Sigor@sysoev.ru 1449148Sigor@sysoev.ru fail: 1450148Sigor@sysoev.ru 1451148Sigor@sysoev.ru nxt_socket_close(task, s); 1452148Sigor@sysoev.ru 1453198Sigor@sysoev.ru nxt_router_conf_error(task, rpc->temp_conf); 1454198Sigor@sysoev.ru } 1455198Sigor@sysoev.ru 1456198Sigor@sysoev.ru 1457198Sigor@sysoev.ru static void 1458198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1459198Sigor@sysoev.ru void *data) 1460198Sigor@sysoev.ru { 1461198Sigor@sysoev.ru u_char *p; 1462198Sigor@sysoev.ru size_t size; 1463198Sigor@sysoev.ru uint8_t error; 1464198Sigor@sysoev.ru nxt_buf_t *in, *out; 1465198Sigor@sysoev.ru nxt_sockaddr_t *sa; 1466198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 1467198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 1468198Sigor@sysoev.ru 1469198Sigor@sysoev.ru static nxt_str_t socket_errors[] = { 1470198Sigor@sysoev.ru nxt_string("ListenerSystem"), 1471198Sigor@sysoev.ru nxt_string("ListenerNoIPv6"), 1472198Sigor@sysoev.ru nxt_string("ListenerPort"), 1473198Sigor@sysoev.ru nxt_string("ListenerInUse"), 1474198Sigor@sysoev.ru nxt_string("ListenerNoAddress"), 1475198Sigor@sysoev.ru nxt_string("ListenerNoAccess"), 1476198Sigor@sysoev.ru nxt_string("ListenerPath"), 1477198Sigor@sysoev.ru }; 1478198Sigor@sysoev.ru 1479198Sigor@sysoev.ru rpc = data; 1480198Sigor@sysoev.ru sa = rpc->socket_conf->sockaddr; 1481198Sigor@sysoev.ru 1482198Sigor@sysoev.ru in = msg->buf; 1483198Sigor@sysoev.ru p = in->mem.pos; 1484198Sigor@sysoev.ru 1485198Sigor@sysoev.ru error = *p++; 1486198Sigor@sysoev.ru 1487198Sigor@sysoev.ru size = sizeof("listen socket error: ") - 1 1488198Sigor@sysoev.ru + sizeof("{listener: \"\", code:\"\", message: \"\"}") - 1 1489198Sigor@sysoev.ru + sa->length + socket_errors[error].length + (in->mem.free - p); 1490198Sigor@sysoev.ru 1491198Sigor@sysoev.ru tmcf = rpc->temp_conf; 1492198Sigor@sysoev.ru 1493198Sigor@sysoev.ru out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 1494198Sigor@sysoev.ru if (nxt_slow_path(out == NULL)) { 1495198Sigor@sysoev.ru return; 1496198Sigor@sysoev.ru } 1497198Sigor@sysoev.ru 1498198Sigor@sysoev.ru out->mem.free = nxt_sprintf(out->mem.free, out->mem.end, 1499198Sigor@sysoev.ru "listen socket error: " 1500198Sigor@sysoev.ru "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}", 1501198Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa), 1502198Sigor@sysoev.ru &socket_errors[error], in->mem.free - p, p); 1503198Sigor@sysoev.ru 1504198Sigor@sysoev.ru nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos); 1505198Sigor@sysoev.ru 1506198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 150753Sigor@sysoev.ru } 150853Sigor@sysoev.ru 150953Sigor@sysoev.ru 151053Sigor@sysoev.ru static nxt_int_t 151153Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router, 151253Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface) 151353Sigor@sysoev.ru { 151453Sigor@sysoev.ru nxt_int_t ret; 151553Sigor@sysoev.ru nxt_uint_t n, threads; 151653Sigor@sysoev.ru nxt_queue_link_t *qlk; 151753Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 151853Sigor@sysoev.ru 151953Sigor@sysoev.ru threads = tmcf->conf->threads; 152053Sigor@sysoev.ru 152153Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, threads, 152253Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 152353Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 152453Sigor@sysoev.ru return NXT_ERROR; 152553Sigor@sysoev.ru } 152653Sigor@sysoev.ru 152753Sigor@sysoev.ru n = 0; 152853Sigor@sysoev.ru 152953Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->engines); 153053Sigor@sysoev.ru qlk != nxt_queue_tail(&router->engines); 153153Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 153253Sigor@sysoev.ru { 153353Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 153453Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 153553Sigor@sysoev.ru return NXT_ERROR; 153653Sigor@sysoev.ru } 153753Sigor@sysoev.ru 1538115Sigor@sysoev.ru recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0); 153953Sigor@sysoev.ru 154053Sigor@sysoev.ru if (n < threads) { 1541315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_KEEP; 1542115Sigor@sysoev.ru ret = nxt_router_engine_conf_update(tmcf, recf); 154353Sigor@sysoev.ru 154453Sigor@sysoev.ru } else { 1545315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_DELETE; 1546115Sigor@sysoev.ru ret = nxt_router_engine_conf_delete(tmcf, recf); 154753Sigor@sysoev.ru } 154853Sigor@sysoev.ru 154953Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 155053Sigor@sysoev.ru return ret; 155153Sigor@sysoev.ru } 155253Sigor@sysoev.ru 155353Sigor@sysoev.ru n++; 155453Sigor@sysoev.ru } 155553Sigor@sysoev.ru 155653Sigor@sysoev.ru tmcf->new_threads = n; 155753Sigor@sysoev.ru 155853Sigor@sysoev.ru while (n < threads) { 155953Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 156053Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 156153Sigor@sysoev.ru return NXT_ERROR; 156253Sigor@sysoev.ru } 156353Sigor@sysoev.ru 1564315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_ADD; 1565315Sigor@sysoev.ru 156653Sigor@sysoev.ru recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0); 156753Sigor@sysoev.ru if (nxt_slow_path(recf->engine == NULL)) { 156853Sigor@sysoev.ru return NXT_ERROR; 156953Sigor@sysoev.ru } 157053Sigor@sysoev.ru 1571115Sigor@sysoev.ru ret = nxt_router_engine_conf_create(tmcf, recf); 157253Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 157353Sigor@sysoev.ru return ret; 157453Sigor@sysoev.ru } 157553Sigor@sysoev.ru 157653Sigor@sysoev.ru n++; 157753Sigor@sysoev.ru } 157853Sigor@sysoev.ru 157953Sigor@sysoev.ru return NXT_OK; 158053Sigor@sysoev.ru } 158153Sigor@sysoev.ru 158253Sigor@sysoev.ru 158353Sigor@sysoev.ru static nxt_int_t 1584115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 1585115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 158653Sigor@sysoev.ru { 1587115Sigor@sysoev.ru nxt_int_t ret; 1588115Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 158953Sigor@sysoev.ru 1590154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 1591154Sigor@sysoev.ru nxt_router_listen_socket_create); 1592115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1593115Sigor@sysoev.ru return ret; 1594115Sigor@sysoev.ru } 1595115Sigor@sysoev.ru 1596154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 1597154Sigor@sysoev.ru nxt_router_listen_socket_create); 159853Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 159953Sigor@sysoev.ru return ret; 160053Sigor@sysoev.ru } 160153Sigor@sysoev.ru 1602115Sigor@sysoev.ru lock = &tmcf->conf->router->lock; 1603115Sigor@sysoev.ru 1604115Sigor@sysoev.ru nxt_thread_spin_lock(lock); 1605115Sigor@sysoev.ru 1606115Sigor@sysoev.ru nxt_router_engine_socket_count(&tmcf->creating); 1607115Sigor@sysoev.ru nxt_router_engine_socket_count(&tmcf->updating); 1608115Sigor@sysoev.ru 1609115Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 1610115Sigor@sysoev.ru 1611115Sigor@sysoev.ru return ret; 161253Sigor@sysoev.ru } 161353Sigor@sysoev.ru 161453Sigor@sysoev.ru 161553Sigor@sysoev.ru static nxt_int_t 1616115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 1617115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 161853Sigor@sysoev.ru { 1619115Sigor@sysoev.ru nxt_int_t ret; 1620115Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 162153Sigor@sysoev.ru 1622154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 1623154Sigor@sysoev.ru nxt_router_listen_socket_create); 162453Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 162553Sigor@sysoev.ru return ret; 162653Sigor@sysoev.ru } 162753Sigor@sysoev.ru 1628154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 1629154Sigor@sysoev.ru nxt_router_listen_socket_update); 163053Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 163153Sigor@sysoev.ru return ret; 163253Sigor@sysoev.ru } 163353Sigor@sysoev.ru 1634139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 1635115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1636115Sigor@sysoev.ru return ret; 1637115Sigor@sysoev.ru } 1638115Sigor@sysoev.ru 1639115Sigor@sysoev.ru lock = &tmcf->conf->router->lock; 1640115Sigor@sysoev.ru 1641115Sigor@sysoev.ru nxt_thread_spin_lock(lock); 1642115Sigor@sysoev.ru 1643115Sigor@sysoev.ru nxt_router_engine_socket_count(&tmcf->creating); 1644115Sigor@sysoev.ru 1645115Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 1646115Sigor@sysoev.ru 1647115Sigor@sysoev.ru return ret; 164853Sigor@sysoev.ru } 164953Sigor@sysoev.ru 165053Sigor@sysoev.ru 165153Sigor@sysoev.ru static nxt_int_t 1652115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 1653115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 165453Sigor@sysoev.ru { 165553Sigor@sysoev.ru nxt_int_t ret; 165653Sigor@sysoev.ru 1657313Sigor@sysoev.ru ret = nxt_router_engine_quit(tmcf, recf); 1658313Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1659313Sigor@sysoev.ru return ret; 1660313Sigor@sysoev.ru } 1661313Sigor@sysoev.ru 1662139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating); 166353Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 166453Sigor@sysoev.ru return ret; 166553Sigor@sysoev.ru } 166653Sigor@sysoev.ru 1667139Sigor@sysoev.ru return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 166853Sigor@sysoev.ru } 166953Sigor@sysoev.ru 167053Sigor@sysoev.ru 167153Sigor@sysoev.ru static nxt_int_t 1672154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 1673154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 167453Sigor@sysoev.ru nxt_work_handler_t handler) 167553Sigor@sysoev.ru { 1676153Sigor@sysoev.ru nxt_joint_job_t *job; 167753Sigor@sysoev.ru nxt_queue_link_t *qlk; 1678155Sigor@sysoev.ru nxt_socket_conf_t *skcf; 167953Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 168053Sigor@sysoev.ru 168153Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 168253Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 168353Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 168453Sigor@sysoev.ru { 1685154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 1686153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 1687139Sigor@sysoev.ru return NXT_ERROR; 1688139Sigor@sysoev.ru } 1689139Sigor@sysoev.ru 1690154Sigor@sysoev.ru job->work.next = recf->jobs; 1691154Sigor@sysoev.ru recf->jobs = &job->work; 1692154Sigor@sysoev.ru 1693153Sigor@sysoev.ru job->task = tmcf->engine->task; 1694153Sigor@sysoev.ru job->work.handler = handler; 1695153Sigor@sysoev.ru job->work.task = &job->task; 1696153Sigor@sysoev.ru job->work.obj = job; 1697153Sigor@sysoev.ru job->tmcf = tmcf; 169853Sigor@sysoev.ru 1699154Sigor@sysoev.ru tmcf->count++; 1700154Sigor@sysoev.ru 1701154Sigor@sysoev.ru joint = nxt_mp_alloc(tmcf->conf->mem_pool, 1702154Sigor@sysoev.ru sizeof(nxt_socket_conf_joint_t)); 170353Sigor@sysoev.ru if (nxt_slow_path(joint == NULL)) { 170453Sigor@sysoev.ru return NXT_ERROR; 170553Sigor@sysoev.ru } 170653Sigor@sysoev.ru 1707153Sigor@sysoev.ru job->work.data = joint; 170853Sigor@sysoev.ru 170953Sigor@sysoev.ru joint->count = 1; 1710155Sigor@sysoev.ru 1711155Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1712155Sigor@sysoev.ru skcf->count++; 1713155Sigor@sysoev.ru joint->socket_conf = skcf; 1714155Sigor@sysoev.ru 171588Smax.romanov@nginx.com joint->engine = recf->engine; 171653Sigor@sysoev.ru } 171753Sigor@sysoev.ru 171820Sigor@sysoev.ru return NXT_OK; 171920Sigor@sysoev.ru } 172020Sigor@sysoev.ru 172120Sigor@sysoev.ru 1722115Sigor@sysoev.ru static void 1723115Sigor@sysoev.ru nxt_router_engine_socket_count(nxt_queue_t *sockets) 1724115Sigor@sysoev.ru { 1725115Sigor@sysoev.ru nxt_queue_link_t *qlk; 1726115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1727115Sigor@sysoev.ru 1728115Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 1729115Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 1730115Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 1731115Sigor@sysoev.ru { 1732115Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1733115Sigor@sysoev.ru skcf->socket->count++; 1734115Sigor@sysoev.ru } 1735115Sigor@sysoev.ru } 1736115Sigor@sysoev.ru 1737115Sigor@sysoev.ru 173820Sigor@sysoev.ru static nxt_int_t 1739313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 1740313Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 1741313Sigor@sysoev.ru { 1742313Sigor@sysoev.ru nxt_joint_job_t *job; 1743313Sigor@sysoev.ru 1744313Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 1745313Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 1746313Sigor@sysoev.ru return NXT_ERROR; 1747313Sigor@sysoev.ru } 1748313Sigor@sysoev.ru 1749313Sigor@sysoev.ru job->work.next = recf->jobs; 1750313Sigor@sysoev.ru recf->jobs = &job->work; 1751313Sigor@sysoev.ru 1752313Sigor@sysoev.ru job->task = tmcf->engine->task; 1753313Sigor@sysoev.ru job->work.handler = nxt_router_worker_thread_quit; 1754313Sigor@sysoev.ru job->work.task = &job->task; 1755313Sigor@sysoev.ru job->work.obj = NULL; 1756313Sigor@sysoev.ru job->work.data = NULL; 1757313Sigor@sysoev.ru job->tmcf = NULL; 1758313Sigor@sysoev.ru 1759313Sigor@sysoev.ru return NXT_OK; 1760313Sigor@sysoev.ru } 1761313Sigor@sysoev.ru 1762313Sigor@sysoev.ru 1763313Sigor@sysoev.ru static nxt_int_t 1764139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 1765139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets) 176620Sigor@sysoev.ru { 1767153Sigor@sysoev.ru nxt_joint_job_t *job; 176853Sigor@sysoev.ru nxt_queue_link_t *qlk; 176920Sigor@sysoev.ru 177053Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 177153Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 177253Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 177353Sigor@sysoev.ru { 1774154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 1775153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 1776139Sigor@sysoev.ru return NXT_ERROR; 1777139Sigor@sysoev.ru } 1778139Sigor@sysoev.ru 1779154Sigor@sysoev.ru job->work.next = recf->jobs; 1780154Sigor@sysoev.ru recf->jobs = &job->work; 1781154Sigor@sysoev.ru 1782153Sigor@sysoev.ru job->task = tmcf->engine->task; 1783153Sigor@sysoev.ru job->work.handler = nxt_router_listen_socket_delete; 1784153Sigor@sysoev.ru job->work.task = &job->task; 1785153Sigor@sysoev.ru job->work.obj = job; 1786153Sigor@sysoev.ru job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1787153Sigor@sysoev.ru job->tmcf = tmcf; 1788154Sigor@sysoev.ru 1789154Sigor@sysoev.ru tmcf->count++; 179020Sigor@sysoev.ru } 179120Sigor@sysoev.ru 179253Sigor@sysoev.ru return NXT_OK; 179353Sigor@sysoev.ru } 179420Sigor@sysoev.ru 179520Sigor@sysoev.ru 179653Sigor@sysoev.ru static nxt_int_t 179753Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 179853Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 179953Sigor@sysoev.ru { 180053Sigor@sysoev.ru nxt_int_t ret; 180153Sigor@sysoev.ru nxt_uint_t i, threads; 180253Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 180320Sigor@sysoev.ru 180453Sigor@sysoev.ru recf = tmcf->engines->elts; 180553Sigor@sysoev.ru threads = tmcf->conf->threads; 180620Sigor@sysoev.ru 180753Sigor@sysoev.ru for (i = tmcf->new_threads; i < threads; i++) { 180853Sigor@sysoev.ru ret = nxt_router_thread_create(task, rt, recf[i].engine); 180953Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 181053Sigor@sysoev.ru return ret; 181153Sigor@sysoev.ru } 181220Sigor@sysoev.ru } 181320Sigor@sysoev.ru 181420Sigor@sysoev.ru return NXT_OK; 181520Sigor@sysoev.ru } 181653Sigor@sysoev.ru 181753Sigor@sysoev.ru 181853Sigor@sysoev.ru static nxt_int_t 181953Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 182053Sigor@sysoev.ru nxt_event_engine_t *engine) 182153Sigor@sysoev.ru { 182253Sigor@sysoev.ru nxt_int_t ret; 182353Sigor@sysoev.ru nxt_thread_link_t *link; 182453Sigor@sysoev.ru nxt_thread_handle_t handle; 182553Sigor@sysoev.ru 182653Sigor@sysoev.ru link = nxt_zalloc(sizeof(nxt_thread_link_t)); 182753Sigor@sysoev.ru 182853Sigor@sysoev.ru if (nxt_slow_path(link == NULL)) { 182953Sigor@sysoev.ru return NXT_ERROR; 183053Sigor@sysoev.ru } 183153Sigor@sysoev.ru 183253Sigor@sysoev.ru link->start = nxt_router_thread_start; 183353Sigor@sysoev.ru link->engine = engine; 183453Sigor@sysoev.ru link->work.handler = nxt_router_thread_exit_handler; 183553Sigor@sysoev.ru link->work.task = task; 183653Sigor@sysoev.ru link->work.data = link; 183753Sigor@sysoev.ru 183853Sigor@sysoev.ru nxt_queue_insert_tail(&rt->engines, &engine->link); 183953Sigor@sysoev.ru 184053Sigor@sysoev.ru ret = nxt_thread_create(&handle, link); 184153Sigor@sysoev.ru 184253Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 184353Sigor@sysoev.ru nxt_queue_remove(&engine->link); 184453Sigor@sysoev.ru } 184553Sigor@sysoev.ru 184653Sigor@sysoev.ru return ret; 184753Sigor@sysoev.ru } 184853Sigor@sysoev.ru 184953Sigor@sysoev.ru 185053Sigor@sysoev.ru static void 1851343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 1852343Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf) 1853133Sigor@sysoev.ru { 1854343Smax.romanov@nginx.com nxt_app_t *app; 1855343Smax.romanov@nginx.com nxt_port_t *port; 1856141Smax.romanov@nginx.com 1857141Smax.romanov@nginx.com nxt_queue_each(app, &router->apps, nxt_app_t, link) { 1858133Sigor@sysoev.ru 1859133Sigor@sysoev.ru nxt_queue_remove(&app->link); 1860133Sigor@sysoev.ru 1861343Smax.romanov@nginx.com nxt_debug(task, "about to free app '%V' %p", &app->name, app); 1862167Smax.romanov@nginx.com 1863163Smax.romanov@nginx.com app->live = 0; 1864163Smax.romanov@nginx.com 1865167Smax.romanov@nginx.com do { 1866343Smax.romanov@nginx.com port = nxt_router_app_get_idle_port(app); 1867167Smax.romanov@nginx.com if (port == NULL) { 1868167Smax.romanov@nginx.com break; 1869167Smax.romanov@nginx.com } 1870167Smax.romanov@nginx.com 1871343Smax.romanov@nginx.com nxt_debug(task, "port %p send quit", port); 1872343Smax.romanov@nginx.com 1873343Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, 1874343Smax.romanov@nginx.com NULL); 1875343Smax.romanov@nginx.com 1876343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 1877167Smax.romanov@nginx.com } while (1); 1878167Smax.romanov@nginx.com 1879343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 1880343Smax.romanov@nginx.com 1881141Smax.romanov@nginx.com } nxt_queue_loop; 1882133Sigor@sysoev.ru 1883133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->previous); 1884133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->apps); 1885133Sigor@sysoev.ru } 1886133Sigor@sysoev.ru 1887133Sigor@sysoev.ru 1888133Sigor@sysoev.ru static void 1889315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf) 189053Sigor@sysoev.ru { 189153Sigor@sysoev.ru nxt_uint_t n; 1892315Sigor@sysoev.ru nxt_event_engine_t *engine; 189353Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 189453Sigor@sysoev.ru 189553Sigor@sysoev.ru recf = tmcf->engines->elts; 189653Sigor@sysoev.ru 189753Sigor@sysoev.ru for (n = tmcf->engines->nelts; n != 0; n--) { 1898315Sigor@sysoev.ru engine = recf->engine; 1899315Sigor@sysoev.ru 1900315Sigor@sysoev.ru switch (recf->action) { 1901315Sigor@sysoev.ru 1902315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_KEEP: 1903315Sigor@sysoev.ru break; 1904315Sigor@sysoev.ru 1905315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_ADD: 1906315Sigor@sysoev.ru nxt_queue_insert_tail(&router->engines, &engine->link0); 1907315Sigor@sysoev.ru break; 1908315Sigor@sysoev.ru 1909315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_DELETE: 1910315Sigor@sysoev.ru nxt_queue_remove(&engine->link0); 1911315Sigor@sysoev.ru break; 1912315Sigor@sysoev.ru } 1913315Sigor@sysoev.ru 1914316Sigor@sysoev.ru nxt_router_engine_post(engine, recf->jobs); 1915316Sigor@sysoev.ru 191653Sigor@sysoev.ru recf++; 191753Sigor@sysoev.ru } 191853Sigor@sysoev.ru } 191953Sigor@sysoev.ru 192053Sigor@sysoev.ru 192153Sigor@sysoev.ru static void 1922315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs) 192353Sigor@sysoev.ru { 1924154Sigor@sysoev.ru nxt_work_t *work, *next; 1925154Sigor@sysoev.ru 1926315Sigor@sysoev.ru for (work = jobs; work != NULL; work = next) { 1927154Sigor@sysoev.ru next = work->next; 1928154Sigor@sysoev.ru work->next = NULL; 1929154Sigor@sysoev.ru 1930315Sigor@sysoev.ru nxt_event_engine_post(engine, work); 193153Sigor@sysoev.ru } 193253Sigor@sysoev.ru } 193353Sigor@sysoev.ru 193453Sigor@sysoev.ru 1935320Smax.romanov@nginx.com static nxt_port_handlers_t nxt_router_app_port_handlers = { 1936320Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 1937320Smax.romanov@nginx.com .data = nxt_port_rpc_handler, 193888Smax.romanov@nginx.com }; 193988Smax.romanov@nginx.com 194088Smax.romanov@nginx.com 194188Smax.romanov@nginx.com static void 194253Sigor@sysoev.ru nxt_router_thread_start(void *data) 194353Sigor@sysoev.ru { 1944141Smax.romanov@nginx.com nxt_int_t ret; 1945141Smax.romanov@nginx.com nxt_port_t *port; 194688Smax.romanov@nginx.com nxt_task_t *task; 194753Sigor@sysoev.ru nxt_thread_t *thread; 194853Sigor@sysoev.ru nxt_thread_link_t *link; 194953Sigor@sysoev.ru nxt_event_engine_t *engine; 195053Sigor@sysoev.ru 195153Sigor@sysoev.ru link = data; 195253Sigor@sysoev.ru engine = link->engine; 195388Smax.romanov@nginx.com task = &engine->task; 195453Sigor@sysoev.ru 195553Sigor@sysoev.ru thread = nxt_thread(); 195653Sigor@sysoev.ru 1957165Smax.romanov@nginx.com nxt_event_engine_thread_adopt(engine); 1958165Smax.romanov@nginx.com 195953Sigor@sysoev.ru /* STUB */ 196053Sigor@sysoev.ru thread->runtime = engine->task.thread->runtime; 196153Sigor@sysoev.ru 196253Sigor@sysoev.ru engine->task.thread = thread; 196353Sigor@sysoev.ru engine->task.log = thread->log; 196453Sigor@sysoev.ru thread->engine = engine; 196563Sigor@sysoev.ru thread->task = &engine->task; 1966326Svbart@nginx.com #if 0 196753Sigor@sysoev.ru thread->fiber = &engine->fibers->fiber; 1968326Svbart@nginx.com #endif 196953Sigor@sysoev.ru 197063Sigor@sysoev.ru engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64); 1971337Sigor@sysoev.ru if (nxt_slow_path(engine->mem_pool == NULL)) { 1972337Sigor@sysoev.ru return; 1973337Sigor@sysoev.ru } 197453Sigor@sysoev.ru 1975197Smax.romanov@nginx.com port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid, 1976197Smax.romanov@nginx.com NXT_PROCESS_ROUTER); 1977141Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 1978141Smax.romanov@nginx.com return; 1979141Smax.romanov@nginx.com } 1980141Smax.romanov@nginx.com 1981141Smax.romanov@nginx.com ret = nxt_port_socket_init(task, port, 0); 1982141Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 1983343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 1984141Smax.romanov@nginx.com return; 1985141Smax.romanov@nginx.com } 1986141Smax.romanov@nginx.com 1987141Smax.romanov@nginx.com engine->port = port; 1988141Smax.romanov@nginx.com 1989320Smax.romanov@nginx.com nxt_port_enable(task, port, &nxt_router_app_port_handlers); 1990141Smax.romanov@nginx.com 199153Sigor@sysoev.ru nxt_event_engine_start(engine); 199253Sigor@sysoev.ru } 199353Sigor@sysoev.ru 199453Sigor@sysoev.ru 199553Sigor@sysoev.ru static void 199653Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data) 199753Sigor@sysoev.ru { 1998153Sigor@sysoev.ru nxt_joint_job_t *job; 199953Sigor@sysoev.ru nxt_listen_event_t *listen; 200053Sigor@sysoev.ru nxt_listen_socket_t *ls; 200153Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 200253Sigor@sysoev.ru 2003153Sigor@sysoev.ru job = obj; 200453Sigor@sysoev.ru joint = data; 200553Sigor@sysoev.ru 200653Sigor@sysoev.ru ls = &joint->socket_conf->listen; 200753Sigor@sysoev.ru 2008159Sigor@sysoev.ru nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link); 2009159Sigor@sysoev.ru 201053Sigor@sysoev.ru listen = nxt_listen_event(task, ls); 201153Sigor@sysoev.ru if (nxt_slow_path(listen == NULL)) { 201253Sigor@sysoev.ru nxt_router_listen_socket_release(task, joint); 201353Sigor@sysoev.ru return; 201453Sigor@sysoev.ru } 201553Sigor@sysoev.ru 201653Sigor@sysoev.ru listen->socket.data = joint; 2017139Sigor@sysoev.ru 2018153Sigor@sysoev.ru job->work.next = NULL; 2019153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2020153Sigor@sysoev.ru 2021153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 202253Sigor@sysoev.ru } 202353Sigor@sysoev.ru 202453Sigor@sysoev.ru 202553Sigor@sysoev.ru nxt_inline nxt_listen_event_t * 202653Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections, 202753Sigor@sysoev.ru nxt_socket_conf_t *skcf) 202853Sigor@sysoev.ru { 2029115Sigor@sysoev.ru nxt_socket_t fd; 2030115Sigor@sysoev.ru nxt_queue_link_t *qlk; 203153Sigor@sysoev.ru nxt_listen_event_t *listen; 203253Sigor@sysoev.ru 2033115Sigor@sysoev.ru fd = skcf->socket->fd; 203453Sigor@sysoev.ru 2035115Sigor@sysoev.ru for (qlk = nxt_queue_first(listen_connections); 2036115Sigor@sysoev.ru qlk != nxt_queue_tail(listen_connections); 2037115Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 203853Sigor@sysoev.ru { 2039115Sigor@sysoev.ru listen = nxt_queue_link_data(qlk, nxt_listen_event_t, link); 204053Sigor@sysoev.ru 2041115Sigor@sysoev.ru if (fd == listen->socket.fd) { 204253Sigor@sysoev.ru return listen; 204353Sigor@sysoev.ru } 204453Sigor@sysoev.ru } 204553Sigor@sysoev.ru 204653Sigor@sysoev.ru return NULL; 204753Sigor@sysoev.ru } 204853Sigor@sysoev.ru 204953Sigor@sysoev.ru 205053Sigor@sysoev.ru static void 205153Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data) 205253Sigor@sysoev.ru { 2053153Sigor@sysoev.ru nxt_joint_job_t *job; 205453Sigor@sysoev.ru nxt_event_engine_t *engine; 205553Sigor@sysoev.ru nxt_listen_event_t *listen; 205653Sigor@sysoev.ru nxt_socket_conf_joint_t *joint, *old; 205753Sigor@sysoev.ru 2058153Sigor@sysoev.ru job = obj; 205953Sigor@sysoev.ru joint = data; 206053Sigor@sysoev.ru 2061139Sigor@sysoev.ru engine = task->thread->engine; 2062139Sigor@sysoev.ru 2063159Sigor@sysoev.ru nxt_queue_insert_tail(&engine->joints, &joint->link); 2064159Sigor@sysoev.ru 206553Sigor@sysoev.ru listen = nxt_router_listen_event(&engine->listen_connections, 206653Sigor@sysoev.ru joint->socket_conf); 206753Sigor@sysoev.ru 206853Sigor@sysoev.ru old = listen->socket.data; 206953Sigor@sysoev.ru listen->socket.data = joint; 2070177Sigor@sysoev.ru listen->listen = &joint->socket_conf->listen; 207153Sigor@sysoev.ru 2072153Sigor@sysoev.ru job->work.next = NULL; 2073153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2074153Sigor@sysoev.ru 2075153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 2076139Sigor@sysoev.ru 2077181Smax.romanov@nginx.com /* 2078181Smax.romanov@nginx.com * The task is allocated from configuration temporary 2079181Smax.romanov@nginx.com * memory pool so it can be freed after engine post operation. 2080181Smax.romanov@nginx.com */ 2081181Smax.romanov@nginx.com 2082181Smax.romanov@nginx.com nxt_router_conf_release(&engine->task, old); 208353Sigor@sysoev.ru } 208453Sigor@sysoev.ru 208553Sigor@sysoev.ru 208653Sigor@sysoev.ru static void 208753Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data) 208853Sigor@sysoev.ru { 2089153Sigor@sysoev.ru nxt_joint_job_t *job; 2090153Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2091153Sigor@sysoev.ru nxt_listen_event_t *listen; 2092153Sigor@sysoev.ru nxt_event_engine_t *engine; 2093153Sigor@sysoev.ru 2094153Sigor@sysoev.ru job = obj; 209553Sigor@sysoev.ru skcf = data; 209653Sigor@sysoev.ru 2097139Sigor@sysoev.ru engine = task->thread->engine; 2098139Sigor@sysoev.ru 209953Sigor@sysoev.ru listen = nxt_router_listen_event(&engine->listen_connections, skcf); 210053Sigor@sysoev.ru 210153Sigor@sysoev.ru nxt_fd_event_delete(engine, &listen->socket); 210253Sigor@sysoev.ru 2103163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket delete: %d", engine, 2104163Smax.romanov@nginx.com listen->socket.fd); 2105163Smax.romanov@nginx.com 210653Sigor@sysoev.ru listen->timer.handler = nxt_router_listen_socket_close; 210753Sigor@sysoev.ru listen->timer.work_queue = &engine->fast_work_queue; 210853Sigor@sysoev.ru 210953Sigor@sysoev.ru nxt_timer_add(engine, &listen->timer, 0); 2110139Sigor@sysoev.ru 2111153Sigor@sysoev.ru job->work.next = NULL; 2112153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2113153Sigor@sysoev.ru 2114153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 211553Sigor@sysoev.ru } 211653Sigor@sysoev.ru 211753Sigor@sysoev.ru 211853Sigor@sysoev.ru static void 2119313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data) 2120313Sigor@sysoev.ru { 2121313Sigor@sysoev.ru nxt_event_engine_t *engine; 2122313Sigor@sysoev.ru 2123313Sigor@sysoev.ru nxt_debug(task, "router worker thread quit"); 2124313Sigor@sysoev.ru 2125313Sigor@sysoev.ru engine = task->thread->engine; 2126313Sigor@sysoev.ru 2127313Sigor@sysoev.ru engine->shutdown = 1; 2128313Sigor@sysoev.ru 2129313Sigor@sysoev.ru if (nxt_queue_is_empty(&engine->joints)) { 2130313Sigor@sysoev.ru nxt_thread_exit(task->thread); 2131313Sigor@sysoev.ru } 2132313Sigor@sysoev.ru } 2133313Sigor@sysoev.ru 2134313Sigor@sysoev.ru 2135313Sigor@sysoev.ru static void 213653Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data) 213753Sigor@sysoev.ru { 213853Sigor@sysoev.ru nxt_timer_t *timer; 213953Sigor@sysoev.ru nxt_listen_event_t *listen; 214053Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 214153Sigor@sysoev.ru 214253Sigor@sysoev.ru timer = obj; 214353Sigor@sysoev.ru listen = nxt_timer_data(timer, nxt_listen_event_t, timer); 214453Sigor@sysoev.ru joint = listen->socket.data; 214553Sigor@sysoev.ru 2146163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine, 2147163Smax.romanov@nginx.com listen->socket.fd); 2148163Smax.romanov@nginx.com 214953Sigor@sysoev.ru nxt_queue_remove(&listen->link); 2150123Smax.romanov@nginx.com 2151123Smax.romanov@nginx.com /* 'task' refers to listen->task and we cannot use after nxt_free() */ 2152123Smax.romanov@nginx.com task = &task->thread->engine->task; 2153123Smax.romanov@nginx.com 215453Sigor@sysoev.ru nxt_free(listen); 215553Sigor@sysoev.ru 215653Sigor@sysoev.ru nxt_router_listen_socket_release(task, joint); 215753Sigor@sysoev.ru } 215853Sigor@sysoev.ru 215953Sigor@sysoev.ru 216053Sigor@sysoev.ru static void 216153Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, 216253Sigor@sysoev.ru nxt_socket_conf_joint_t *joint) 216353Sigor@sysoev.ru { 2164118Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2165115Sigor@sysoev.ru nxt_router_socket_t *rtsk; 216653Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 216753Sigor@sysoev.ru 2168118Sigor@sysoev.ru skcf = joint->socket_conf; 2169118Sigor@sysoev.ru rtsk = skcf->socket; 2170118Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 217153Sigor@sysoev.ru 217253Sigor@sysoev.ru nxt_thread_spin_lock(lock); 217353Sigor@sysoev.ru 2174163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket release: rtsk->count %D", 2175163Smax.romanov@nginx.com task->thread->engine, rtsk->count); 2176163Smax.romanov@nginx.com 2177115Sigor@sysoev.ru if (--rtsk->count != 0) { 2178115Sigor@sysoev.ru rtsk = NULL; 217953Sigor@sysoev.ru } 218053Sigor@sysoev.ru 218153Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 218253Sigor@sysoev.ru 2183115Sigor@sysoev.ru if (rtsk != NULL) { 2184115Sigor@sysoev.ru nxt_socket_close(task, rtsk->fd); 2185115Sigor@sysoev.ru nxt_free(rtsk); 2186118Sigor@sysoev.ru skcf->socket = NULL; 218753Sigor@sysoev.ru } 218853Sigor@sysoev.ru 218953Sigor@sysoev.ru nxt_router_conf_release(task, joint); 219053Sigor@sysoev.ru } 219153Sigor@sysoev.ru 219253Sigor@sysoev.ru 219353Sigor@sysoev.ru static void 219453Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint) 219553Sigor@sysoev.ru { 2196156Sigor@sysoev.ru nxt_bool_t exit; 219753Sigor@sysoev.ru nxt_socket_conf_t *skcf; 219853Sigor@sysoev.ru nxt_router_conf_t *rtcf; 2199313Sigor@sysoev.ru nxt_event_engine_t *engine; 220053Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 220153Sigor@sysoev.ru 2202163Smax.romanov@nginx.com nxt_debug(task, "conf joint %p count: %D", joint, joint->count); 220353Sigor@sysoev.ru 220453Sigor@sysoev.ru if (--joint->count != 0) { 220553Sigor@sysoev.ru return; 220653Sigor@sysoev.ru } 220753Sigor@sysoev.ru 220853Sigor@sysoev.ru nxt_queue_remove(&joint->link); 220953Sigor@sysoev.ru 221053Sigor@sysoev.ru skcf = joint->socket_conf; 221153Sigor@sysoev.ru rtcf = skcf->router_conf; 221253Sigor@sysoev.ru lock = &rtcf->router->lock; 221353Sigor@sysoev.ru 221453Sigor@sysoev.ru nxt_thread_spin_lock(lock); 221553Sigor@sysoev.ru 2216163Smax.romanov@nginx.com nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count, 2217163Smax.romanov@nginx.com rtcf, rtcf->count); 2218163Smax.romanov@nginx.com 221953Sigor@sysoev.ru if (--skcf->count != 0) { 222053Sigor@sysoev.ru rtcf = NULL; 222153Sigor@sysoev.ru 222253Sigor@sysoev.ru } else { 222353Sigor@sysoev.ru nxt_queue_remove(&skcf->link); 222453Sigor@sysoev.ru 222553Sigor@sysoev.ru if (--rtcf->count != 0) { 222653Sigor@sysoev.ru rtcf = NULL; 222753Sigor@sysoev.ru } 222853Sigor@sysoev.ru } 222953Sigor@sysoev.ru 223053Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 223153Sigor@sysoev.ru 2232141Smax.romanov@nginx.com /* TODO remove engine->port */ 2233141Smax.romanov@nginx.com /* TODO excude from connected ports */ 2234141Smax.romanov@nginx.com 2235156Sigor@sysoev.ru /* The joint content can be used before memory pool destruction. */ 2236313Sigor@sysoev.ru engine = joint->engine; 2237313Sigor@sysoev.ru exit = (engine->shutdown && nxt_queue_is_empty(&engine->joints)); 2238156Sigor@sysoev.ru 223953Sigor@sysoev.ru if (rtcf != NULL) { 2240115Sigor@sysoev.ru nxt_debug(task, "old router conf is destroyed"); 2241131Smax.romanov@nginx.com 2242131Smax.romanov@nginx.com nxt_mp_thread_adopt(rtcf->mem_pool); 2243131Smax.romanov@nginx.com 224465Sigor@sysoev.ru nxt_mp_destroy(rtcf->mem_pool); 224553Sigor@sysoev.ru } 224653Sigor@sysoev.ru 2247156Sigor@sysoev.ru if (exit) { 224853Sigor@sysoev.ru nxt_thread_exit(task->thread); 224953Sigor@sysoev.ru } 225053Sigor@sysoev.ru } 225153Sigor@sysoev.ru 225253Sigor@sysoev.ru 225353Sigor@sysoev.ru static void 225453Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data) 225553Sigor@sysoev.ru { 2256141Smax.romanov@nginx.com nxt_port_t *port; 225753Sigor@sysoev.ru nxt_thread_link_t *link; 225853Sigor@sysoev.ru nxt_event_engine_t *engine; 225953Sigor@sysoev.ru nxt_thread_handle_t handle; 226053Sigor@sysoev.ru 226158Svbart@nginx.com handle = (nxt_thread_handle_t) obj; 226253Sigor@sysoev.ru link = data; 226353Sigor@sysoev.ru 226453Sigor@sysoev.ru nxt_thread_wait(handle); 226553Sigor@sysoev.ru 226653Sigor@sysoev.ru engine = link->engine; 226753Sigor@sysoev.ru 226853Sigor@sysoev.ru nxt_queue_remove(&engine->link); 226953Sigor@sysoev.ru 2270141Smax.romanov@nginx.com port = engine->port; 2271141Smax.romanov@nginx.com 2272141Smax.romanov@nginx.com // TODO notify all apps 2273141Smax.romanov@nginx.com 2274343Smax.romanov@nginx.com port->engine = task->thread->engine; 2275163Smax.romanov@nginx.com nxt_mp_thread_adopt(port->mem_pool); 2276343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 2277163Smax.romanov@nginx.com 2278163Smax.romanov@nginx.com nxt_mp_thread_adopt(engine->mem_pool); 227963Sigor@sysoev.ru nxt_mp_destroy(engine->mem_pool); 228053Sigor@sysoev.ru 228153Sigor@sysoev.ru nxt_event_engine_free(engine); 228253Sigor@sysoev.ru 228353Sigor@sysoev.ru nxt_free(link); 228453Sigor@sysoev.ru } 228553Sigor@sysoev.ru 228653Sigor@sysoev.ru 2287206Smax.romanov@nginx.com static const nxt_conn_state_t nxt_router_conn_read_header_state 228853Sigor@sysoev.ru nxt_aligned(64) = 228953Sigor@sysoev.ru { 229053Sigor@sysoev.ru .ready_handler = nxt_router_conn_http_header_parse, 229153Sigor@sysoev.ru .close_handler = nxt_router_conn_close, 229253Sigor@sysoev.ru .error_handler = nxt_router_conn_error, 229353Sigor@sysoev.ru 229453Sigor@sysoev.ru .timer_handler = nxt_router_conn_timeout, 229553Sigor@sysoev.ru .timer_value = nxt_router_conn_timeout_value, 229653Sigor@sysoev.ru .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout), 229753Sigor@sysoev.ru }; 229853Sigor@sysoev.ru 229953Sigor@sysoev.ru 2300206Smax.romanov@nginx.com static const nxt_conn_state_t nxt_router_conn_read_body_state 2301206Smax.romanov@nginx.com nxt_aligned(64) = 2302206Smax.romanov@nginx.com { 2303206Smax.romanov@nginx.com .ready_handler = nxt_router_conn_http_body_read, 2304206Smax.romanov@nginx.com .close_handler = nxt_router_conn_close, 2305206Smax.romanov@nginx.com .error_handler = nxt_router_conn_error, 2306206Smax.romanov@nginx.com 2307206Smax.romanov@nginx.com .timer_handler = nxt_router_conn_timeout, 2308206Smax.romanov@nginx.com .timer_value = nxt_router_conn_timeout_value, 2309206Smax.romanov@nginx.com .timer_data = offsetof(nxt_socket_conf_t, body_read_timeout), 2310206Smax.romanov@nginx.com .timer_autoreset = 1, 2311206Smax.romanov@nginx.com }; 2312206Smax.romanov@nginx.com 2313206Smax.romanov@nginx.com 231453Sigor@sysoev.ru static void 231553Sigor@sysoev.ru nxt_router_conn_init(nxt_task_t *task, void *obj, void *data) 231653Sigor@sysoev.ru { 231753Sigor@sysoev.ru size_t size; 231862Sigor@sysoev.ru nxt_conn_t *c; 231953Sigor@sysoev.ru nxt_event_engine_t *engine; 232053Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 232153Sigor@sysoev.ru 232253Sigor@sysoev.ru c = obj; 232353Sigor@sysoev.ru joint = data; 232453Sigor@sysoev.ru 232553Sigor@sysoev.ru nxt_debug(task, "router conn init"); 232653Sigor@sysoev.ru 232753Sigor@sysoev.ru joint->count++; 232853Sigor@sysoev.ru 232953Sigor@sysoev.ru size = joint->socket_conf->header_buffer_size; 233053Sigor@sysoev.ru c->read = nxt_buf_mem_alloc(c->mem_pool, size, 0); 233153Sigor@sysoev.ru 233253Sigor@sysoev.ru c->socket.data = NULL; 233353Sigor@sysoev.ru 233453Sigor@sysoev.ru engine = task->thread->engine; 233553Sigor@sysoev.ru c->read_work_queue = &engine->fast_work_queue; 233653Sigor@sysoev.ru c->write_work_queue = &engine->fast_work_queue; 233753Sigor@sysoev.ru 2338206Smax.romanov@nginx.com c->read_state = &nxt_router_conn_read_header_state; 233953Sigor@sysoev.ru 234062Sigor@sysoev.ru nxt_conn_read(engine, c); 234153Sigor@sysoev.ru } 234253Sigor@sysoev.ru 234353Sigor@sysoev.ru 234462Sigor@sysoev.ru static const nxt_conn_state_t nxt_router_conn_write_state 234553Sigor@sysoev.ru nxt_aligned(64) = 234653Sigor@sysoev.ru { 234788Smax.romanov@nginx.com .ready_handler = nxt_router_conn_ready, 234853Sigor@sysoev.ru .close_handler = nxt_router_conn_close, 234953Sigor@sysoev.ru .error_handler = nxt_router_conn_error, 235053Sigor@sysoev.ru }; 235153Sigor@sysoev.ru 235253Sigor@sysoev.ru 235353Sigor@sysoev.ru static void 2354318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2355318Smax.romanov@nginx.com void *data) 235688Smax.romanov@nginx.com { 235788Smax.romanov@nginx.com size_t dump_size; 2358194Smax.romanov@nginx.com nxt_buf_t *b, *last; 235988Smax.romanov@nginx.com nxt_conn_t *c; 236088Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 236188Smax.romanov@nginx.com 236288Smax.romanov@nginx.com b = msg->buf; 2363318Smax.romanov@nginx.com rc = data; 236488Smax.romanov@nginx.com 236588Smax.romanov@nginx.com c = rc->conn; 236688Smax.romanov@nginx.com 236788Smax.romanov@nginx.com dump_size = nxt_buf_used_size(b); 236888Smax.romanov@nginx.com 236988Smax.romanov@nginx.com if (dump_size > 300) { 237088Smax.romanov@nginx.com dump_size = 300; 237188Smax.romanov@nginx.com } 237288Smax.romanov@nginx.com 2373119Smax.romanov@nginx.com nxt_debug(task, "%srouter app data (%z): %*s", 237488Smax.romanov@nginx.com msg->port_msg.last ? "last " : "", msg->size, dump_size, 237588Smax.romanov@nginx.com b->mem.pos); 237688Smax.romanov@nginx.com 237788Smax.romanov@nginx.com if (msg->size == 0) { 237888Smax.romanov@nginx.com b = NULL; 237988Smax.romanov@nginx.com } 238088Smax.romanov@nginx.com 238188Smax.romanov@nginx.com if (msg->port_msg.last != 0) { 238288Smax.romanov@nginx.com nxt_debug(task, "router data create last buf"); 238388Smax.romanov@nginx.com 238488Smax.romanov@nginx.com last = nxt_buf_sync_alloc(c->mem_pool, NXT_BUF_SYNC_LAST); 238588Smax.romanov@nginx.com if (nxt_slow_path(last == NULL)) { 238688Smax.romanov@nginx.com /* TODO pogorevaTb */ 238788Smax.romanov@nginx.com } 238888Smax.romanov@nginx.com 238988Smax.romanov@nginx.com nxt_buf_chain_add(&b, last); 2390167Smax.romanov@nginx.com 2391343Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 239288Smax.romanov@nginx.com } 239388Smax.romanov@nginx.com 239488Smax.romanov@nginx.com if (b == NULL) { 239588Smax.romanov@nginx.com return; 239688Smax.romanov@nginx.com } 239788Smax.romanov@nginx.com 2398206Smax.romanov@nginx.com if (msg->buf == b) { 2399206Smax.romanov@nginx.com /* Disable instant buffer completion/re-using by port. */ 2400206Smax.romanov@nginx.com msg->buf = NULL; 2401206Smax.romanov@nginx.com } 2402194Smax.romanov@nginx.com 240388Smax.romanov@nginx.com if (c->write == NULL) { 240488Smax.romanov@nginx.com c->write = b; 240588Smax.romanov@nginx.com c->write_state = &nxt_router_conn_write_state; 240688Smax.romanov@nginx.com 240788Smax.romanov@nginx.com nxt_conn_write(task->thread->engine, c); 2408277Sigor@sysoev.ru 240988Smax.romanov@nginx.com } else { 241088Smax.romanov@nginx.com nxt_debug(task, "router data attach out bufs to existing chain"); 241188Smax.romanov@nginx.com 241288Smax.romanov@nginx.com nxt_buf_chain_add(&c->write, b); 241388Smax.romanov@nginx.com } 241488Smax.romanov@nginx.com } 241588Smax.romanov@nginx.com 2416277Sigor@sysoev.ru 2417318Smax.romanov@nginx.com static void 2418318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2419318Smax.romanov@nginx.com void *data) 2420318Smax.romanov@nginx.com { 2421318Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 2422318Smax.romanov@nginx.com 2423318Smax.romanov@nginx.com rc = data; 2424318Smax.romanov@nginx.com 2425318Smax.romanov@nginx.com nxt_router_gen_error(task, rc->conn, 500, 2426318Smax.romanov@nginx.com "Application terminated unexpectedly"); 2427318Smax.romanov@nginx.com 2428343Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 2429318Smax.romanov@nginx.com } 2430318Smax.romanov@nginx.com 2431318Smax.romanov@nginx.com 2432141Smax.romanov@nginx.com nxt_inline const char * 2433141Smax.romanov@nginx.com nxt_router_text_by_code(int code) 2434141Smax.romanov@nginx.com { 2435141Smax.romanov@nginx.com switch (code) { 2436141Smax.romanov@nginx.com case 400: return "Bad request"; 2437141Smax.romanov@nginx.com case 404: return "Not found"; 2438141Smax.romanov@nginx.com case 403: return "Forbidden"; 2439206Smax.romanov@nginx.com case 408: return "Request Timeout"; 2440206Smax.romanov@nginx.com case 411: return "Length Required"; 2441206Smax.romanov@nginx.com case 413: return "Request Entity Too Large"; 2442141Smax.romanov@nginx.com case 500: 2443141Smax.romanov@nginx.com default: return "Internal server error"; 2444141Smax.romanov@nginx.com } 2445141Smax.romanov@nginx.com } 2446141Smax.romanov@nginx.com 2447163Smax.romanov@nginx.com 2448163Smax.romanov@nginx.com static nxt_buf_t * 2449163Smax.romanov@nginx.com nxt_router_get_error_buf(nxt_task_t *task, nxt_mp_t *mp, int code, 2450*345Smax.romanov@nginx.com const char* str) 245188Smax.romanov@nginx.com { 2452*345Smax.romanov@nginx.com nxt_buf_t *b, *last; 2453*345Smax.romanov@nginx.com 2454*345Smax.romanov@nginx.com b = nxt_buf_mem_alloc(mp, 16384, 0); 2455141Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 2456163Smax.romanov@nginx.com return NULL; 2457141Smax.romanov@nginx.com } 2458141Smax.romanov@nginx.com 2459141Smax.romanov@nginx.com b->mem.free = nxt_sprintf(b->mem.free, b->mem.end, 2460141Smax.romanov@nginx.com "HTTP/1.0 %d %s\r\n" 2461141Smax.romanov@nginx.com "Content-Type: text/plain\r\n" 2462141Smax.romanov@nginx.com "Connection: close\r\n\r\n", 2463141Smax.romanov@nginx.com code, nxt_router_text_by_code(code)); 2464141Smax.romanov@nginx.com 2465*345Smax.romanov@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str, nxt_strlen(str)); 2466*345Smax.romanov@nginx.com 2467*345Smax.romanov@nginx.com nxt_log_alert(task->log, "error %d: %s", code, str); 2468*345Smax.romanov@nginx.com 2469*345Smax.romanov@nginx.com last = nxt_buf_sync_alloc(mp, NXT_BUF_SYNC_LAST); 2470163Smax.romanov@nginx.com 2471141Smax.romanov@nginx.com if (nxt_slow_path(last == NULL)) { 2472*345Smax.romanov@nginx.com nxt_mp_free(mp, b); 2473163Smax.romanov@nginx.com return NULL; 2474141Smax.romanov@nginx.com } 2475141Smax.romanov@nginx.com 2476141Smax.romanov@nginx.com nxt_buf_chain_add(&b, last); 2477141Smax.romanov@nginx.com 2478163Smax.romanov@nginx.com return b; 2479163Smax.romanov@nginx.com } 2480163Smax.romanov@nginx.com 2481163Smax.romanov@nginx.com 2482163Smax.romanov@nginx.com 2483163Smax.romanov@nginx.com static void 2484163Smax.romanov@nginx.com nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code, 2485*345Smax.romanov@nginx.com const char* str) 2486163Smax.romanov@nginx.com { 2487318Smax.romanov@nginx.com nxt_mp_t *mp; 2488163Smax.romanov@nginx.com nxt_buf_t *b; 2489163Smax.romanov@nginx.com 2490318Smax.romanov@nginx.com /* TODO: fix when called in the middle of response */ 2491318Smax.romanov@nginx.com 2492*345Smax.romanov@nginx.com mp = c->mem_pool; 2493*345Smax.romanov@nginx.com 2494*345Smax.romanov@nginx.com b = nxt_router_get_error_buf(task, mp, code, str); 2495163Smax.romanov@nginx.com 2496273Smax.romanov@nginx.com if (c->socket.fd == -1) { 2497*345Smax.romanov@nginx.com nxt_mp_free(mp, b->next); 2498*345Smax.romanov@nginx.com nxt_mp_free(mp, b); 2499273Smax.romanov@nginx.com return; 2500273Smax.romanov@nginx.com } 2501273Smax.romanov@nginx.com 2502141Smax.romanov@nginx.com if (c->write == NULL) { 2503141Smax.romanov@nginx.com c->write = b; 2504141Smax.romanov@nginx.com c->write_state = &nxt_router_conn_write_state; 2505141Smax.romanov@nginx.com 2506141Smax.romanov@nginx.com nxt_conn_write(task->thread->engine, c); 2507277Sigor@sysoev.ru 2508141Smax.romanov@nginx.com } else { 2509141Smax.romanov@nginx.com nxt_debug(task, "router data attach out bufs to existing chain"); 2510141Smax.romanov@nginx.com 2511141Smax.romanov@nginx.com nxt_buf_chain_add(&c->write, b); 2512141Smax.romanov@nginx.com } 2513141Smax.romanov@nginx.com } 2514141Smax.romanov@nginx.com 2515141Smax.romanov@nginx.com 2516141Smax.romanov@nginx.com static void 2517343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2518343Smax.romanov@nginx.com void *data) 2519192Smax.romanov@nginx.com { 2520343Smax.romanov@nginx.com nxt_app_t *app; 2521343Smax.romanov@nginx.com nxt_port_t *port; 2522343Smax.romanov@nginx.com 2523343Smax.romanov@nginx.com app = data; 2524343Smax.romanov@nginx.com port = msg->new_port; 2525343Smax.romanov@nginx.com 2526343Smax.romanov@nginx.com nxt_assert(app != NULL); 2527343Smax.romanov@nginx.com nxt_assert(port != NULL); 2528343Smax.romanov@nginx.com 2529343Smax.romanov@nginx.com port->app = app; 2530343Smax.romanov@nginx.com 2531343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2532343Smax.romanov@nginx.com 2533343Smax.romanov@nginx.com nxt_assert(app->pending_workers != 0); 2534343Smax.romanov@nginx.com 2535343Smax.romanov@nginx.com app->pending_workers--; 2536343Smax.romanov@nginx.com app->workers++; 2537343Smax.romanov@nginx.com 2538343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2539343Smax.romanov@nginx.com 2540343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p new port ready", &app->name, app); 2541343Smax.romanov@nginx.com 2542343Smax.romanov@nginx.com nxt_router_app_port_release(task, port, 0, 0); 2543192Smax.romanov@nginx.com } 2544192Smax.romanov@nginx.com 2545192Smax.romanov@nginx.com 2546192Smax.romanov@nginx.com static void 2547343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2548343Smax.romanov@nginx.com void *data) 2549192Smax.romanov@nginx.com { 2550318Smax.romanov@nginx.com nxt_app_t *app; 2551318Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2552318Smax.romanov@nginx.com nxt_req_app_link_t *ra; 2553343Smax.romanov@nginx.com 2554343Smax.romanov@nginx.com app = data; 2555343Smax.romanov@nginx.com 2556343Smax.romanov@nginx.com nxt_assert(app != NULL); 2557343Smax.romanov@nginx.com 2558343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start error", &app->name, app); 2559343Smax.romanov@nginx.com 2560343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2561343Smax.romanov@nginx.com 2562343Smax.romanov@nginx.com nxt_assert(app->pending_workers != 0); 2563343Smax.romanov@nginx.com 2564343Smax.romanov@nginx.com app->pending_workers--; 2565318Smax.romanov@nginx.com 2566318Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->requests)) { 2567318Smax.romanov@nginx.com lnk = nxt_queue_last(&app->requests); 2568318Smax.romanov@nginx.com nxt_queue_remove(lnk); 2569343Smax.romanov@nginx.com lnk->next = NULL; 2570318Smax.romanov@nginx.com 2571318Smax.romanov@nginx.com ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link); 2572318Smax.romanov@nginx.com 2573343Smax.romanov@nginx.com } else { 2574343Smax.romanov@nginx.com ra = NULL; 2575343Smax.romanov@nginx.com } 2576343Smax.romanov@nginx.com 2577343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2578343Smax.romanov@nginx.com 2579343Smax.romanov@nginx.com if (ra != NULL) { 2580318Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p abort next stream #%uD", 2581318Smax.romanov@nginx.com &app->name, app, ra->stream); 2582318Smax.romanov@nginx.com 2583318Smax.romanov@nginx.com nxt_router_ra_abort(task, ra, ra->work.data); 2584318Smax.romanov@nginx.com } 2585192Smax.romanov@nginx.com 2586343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 2587192Smax.romanov@nginx.com } 2588192Smax.romanov@nginx.com 2589192Smax.romanov@nginx.com 2590343Smax.romanov@nginx.com void 2591343Smax.romanov@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i) 2592141Smax.romanov@nginx.com { 2593343Smax.romanov@nginx.com int c; 2594343Smax.romanov@nginx.com 2595343Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&app->use_count, i); 2596343Smax.romanov@nginx.com 2597343Smax.romanov@nginx.com if (i < 0 && c == -i) { 2598343Smax.romanov@nginx.com 2599343Smax.romanov@nginx.com nxt_assert(app->live == 0); 2600343Smax.romanov@nginx.com nxt_assert(app->workers == 0); 2601343Smax.romanov@nginx.com nxt_assert(app->pending_workers == 0); 2602343Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->requests) != 0); 2603343Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->ports) != 0); 2604343Smax.romanov@nginx.com 2605163Smax.romanov@nginx.com nxt_thread_mutex_destroy(&app->mutex); 2606163Smax.romanov@nginx.com nxt_free(app); 2607163Smax.romanov@nginx.com } 2608343Smax.romanov@nginx.com } 2609343Smax.romanov@nginx.com 2610343Smax.romanov@nginx.com 2611343Smax.romanov@nginx.com nxt_inline nxt_port_t * 2612343Smax.romanov@nginx.com nxt_router_app_get_port_unsafe(nxt_app_t *app, int *use_delta) 2613343Smax.romanov@nginx.com { 2614343Smax.romanov@nginx.com nxt_port_t *port; 2615343Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2616343Smax.romanov@nginx.com 2617343Smax.romanov@nginx.com lnk = nxt_queue_first(&app->ports); 2618343Smax.romanov@nginx.com nxt_queue_remove(lnk); 2619343Smax.romanov@nginx.com 2620343Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, app_link); 2621343Smax.romanov@nginx.com 2622343Smax.romanov@nginx.com port->app_requests++; 2623343Smax.romanov@nginx.com 2624343Smax.romanov@nginx.com if (app->live && 2625343Smax.romanov@nginx.com (app->max_pending_responses == 0 || 2626343Smax.romanov@nginx.com (port->app_requests - port->app_responses) < 2627343Smax.romanov@nginx.com app->max_pending_responses) ) 2628277Sigor@sysoev.ru { 2629343Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, lnk); 2630343Smax.romanov@nginx.com 2631343Smax.romanov@nginx.com } else { 2632343Smax.romanov@nginx.com lnk->next = NULL; 2633343Smax.romanov@nginx.com 2634343Smax.romanov@nginx.com (*use_delta)--; 2635167Smax.romanov@nginx.com } 2636167Smax.romanov@nginx.com 2637343Smax.romanov@nginx.com return port; 2638163Smax.romanov@nginx.com } 2639163Smax.romanov@nginx.com 2640163Smax.romanov@nginx.com 2641141Smax.romanov@nginx.com static nxt_port_t * 2642343Smax.romanov@nginx.com nxt_router_app_get_idle_port(nxt_app_t *app) 2643141Smax.romanov@nginx.com { 2644343Smax.romanov@nginx.com nxt_port_t *port; 2645141Smax.romanov@nginx.com 2646141Smax.romanov@nginx.com port = NULL; 2647141Smax.romanov@nginx.com 2648141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2649141Smax.romanov@nginx.com 2650343Smax.romanov@nginx.com nxt_queue_each(port, &app->ports, nxt_port_t, app_link) { 2651343Smax.romanov@nginx.com 2652343Smax.romanov@nginx.com if (port->app_requests > port->app_responses) { 2653343Smax.romanov@nginx.com port = NULL; 2654343Smax.romanov@nginx.com 2655343Smax.romanov@nginx.com continue; 2656343Smax.romanov@nginx.com } 2657343Smax.romanov@nginx.com 2658343Smax.romanov@nginx.com nxt_queue_remove(&port->app_link); 2659343Smax.romanov@nginx.com port->app_link.next = NULL; 2660343Smax.romanov@nginx.com 2661343Smax.romanov@nginx.com break; 2662343Smax.romanov@nginx.com 2663343Smax.romanov@nginx.com } nxt_queue_loop; 2664141Smax.romanov@nginx.com 2665141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2666141Smax.romanov@nginx.com 2667141Smax.romanov@nginx.com return port; 2668141Smax.romanov@nginx.com } 2669141Smax.romanov@nginx.com 2670141Smax.romanov@nginx.com 2671141Smax.romanov@nginx.com static void 2672343Smax.romanov@nginx.com nxt_router_app_process_request(nxt_task_t *task, void *obj, void *data) 2673141Smax.romanov@nginx.com { 2674343Smax.romanov@nginx.com nxt_app_t *app; 2675343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 2676343Smax.romanov@nginx.com 2677343Smax.romanov@nginx.com app = obj; 2678343Smax.romanov@nginx.com ra = data; 2679141Smax.romanov@nginx.com 2680141Smax.romanov@nginx.com nxt_assert(app != NULL); 2681343Smax.romanov@nginx.com nxt_assert(ra != NULL); 2682343Smax.romanov@nginx.com nxt_assert(ra->app_port != NULL); 2683343Smax.romanov@nginx.com 2684343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p process next stream #%uD", 2685343Smax.romanov@nginx.com &app->name, app, ra->stream); 2686343Smax.romanov@nginx.com 2687343Smax.romanov@nginx.com nxt_router_process_http_request_mp(task, ra); 2688343Smax.romanov@nginx.com } 2689343Smax.romanov@nginx.com 2690343Smax.romanov@nginx.com 2691343Smax.romanov@nginx.com static void 2692343Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port, 2693343Smax.romanov@nginx.com uint32_t request_failed, uint32_t got_response) 2694343Smax.romanov@nginx.com { 2695343Smax.romanov@nginx.com int use_delta, ra_use_delta; 2696343Smax.romanov@nginx.com nxt_app_t *app; 2697343Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2698343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 2699343Smax.romanov@nginx.com 2700343Smax.romanov@nginx.com nxt_assert(port != NULL); 2701343Smax.romanov@nginx.com nxt_assert(port->app != NULL); 2702343Smax.romanov@nginx.com 2703343Smax.romanov@nginx.com app = port->app; 2704343Smax.romanov@nginx.com 2705343Smax.romanov@nginx.com use_delta = (request_failed == 0 && got_response == 0) ? 0 : -1; 2706343Smax.romanov@nginx.com 2707343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2708343Smax.romanov@nginx.com 2709343Smax.romanov@nginx.com port->app_requests -= request_failed; 2710343Smax.romanov@nginx.com port->app_responses += got_response; 2711343Smax.romanov@nginx.com 2712343Smax.romanov@nginx.com if (app->live != 0 && 2713343Smax.romanov@nginx.com port->pair[1] != -1 && 2714343Smax.romanov@nginx.com port->app_link.next == NULL && 2715343Smax.romanov@nginx.com (app->max_pending_responses == 0 || 2716343Smax.romanov@nginx.com (port->app_requests - port->app_responses) < 2717343Smax.romanov@nginx.com app->max_pending_responses) ) 2718343Smax.romanov@nginx.com { 2719343Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &port->app_link); 2720343Smax.romanov@nginx.com use_delta++; 2721141Smax.romanov@nginx.com } 2722141Smax.romanov@nginx.com 2723343Smax.romanov@nginx.com if (app->live != 0 && 2724343Smax.romanov@nginx.com !nxt_queue_is_empty(&app->ports) && 2725343Smax.romanov@nginx.com !nxt_queue_is_empty(&app->requests)) 2726343Smax.romanov@nginx.com { 2727141Smax.romanov@nginx.com lnk = nxt_queue_first(&app->requests); 2728141Smax.romanov@nginx.com nxt_queue_remove(lnk); 2729343Smax.romanov@nginx.com lnk->next = NULL; 2730141Smax.romanov@nginx.com 2731167Smax.romanov@nginx.com ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link); 2732167Smax.romanov@nginx.com 2733343Smax.romanov@nginx.com ra_use_delta = 1; 2734343Smax.romanov@nginx.com ra->app_port = nxt_router_app_get_port_unsafe(app, &ra_use_delta); 2735343Smax.romanov@nginx.com 2736343Smax.romanov@nginx.com } else { 2737343Smax.romanov@nginx.com ra = NULL; 2738343Smax.romanov@nginx.com ra_use_delta = 0; 2739141Smax.romanov@nginx.com } 2740141Smax.romanov@nginx.com 2741343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2742343Smax.romanov@nginx.com 2743343Smax.romanov@nginx.com if (ra != NULL) { 2744343Smax.romanov@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 2745343Smax.romanov@nginx.com nxt_router_app_process_request, 2746343Smax.romanov@nginx.com &task->thread->engine->task, app, ra); 2747343Smax.romanov@nginx.com 2748343Smax.romanov@nginx.com goto adjust_use; 2749343Smax.romanov@nginx.com } 2750343Smax.romanov@nginx.com 2751343Smax.romanov@nginx.com /* ? */ 2752163Smax.romanov@nginx.com if (port->pair[1] == -1) { 2753343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)", 2754343Smax.romanov@nginx.com &app->name, app, port, port->pid); 2755343Smax.romanov@nginx.com 2756343Smax.romanov@nginx.com goto adjust_use; 2757163Smax.romanov@nginx.com } 2758163Smax.romanov@nginx.com 2759343Smax.romanov@nginx.com if (app->live == 0) { 2760167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p is not alive, send QUIT to port", 2761167Smax.romanov@nginx.com &app->name, app); 2762163Smax.romanov@nginx.com 2763163Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, 2764163Smax.romanov@nginx.com -1, 0, 0, NULL); 2765163Smax.romanov@nginx.com 2766343Smax.romanov@nginx.com goto adjust_use; 2767163Smax.romanov@nginx.com } 2768163Smax.romanov@nginx.com 2769167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p requests queue is empty, keep the port", 2770167Smax.romanov@nginx.com &app->name, app); 2771141Smax.romanov@nginx.com 2772343Smax.romanov@nginx.com adjust_use: 2773343Smax.romanov@nginx.com 2774343Smax.romanov@nginx.com if (use_delta != 0) { 2775343Smax.romanov@nginx.com nxt_port_use(task, port, use_delta); 2776343Smax.romanov@nginx.com } 2777343Smax.romanov@nginx.com 2778343Smax.romanov@nginx.com if (ra_use_delta != 0) { 2779343Smax.romanov@nginx.com nxt_port_use(task, ra->app_port, ra_use_delta); 2780343Smax.romanov@nginx.com } 2781141Smax.romanov@nginx.com } 2782141Smax.romanov@nginx.com 2783141Smax.romanov@nginx.com 2784343Smax.romanov@nginx.com void 2785343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port) 2786141Smax.romanov@nginx.com { 2787163Smax.romanov@nginx.com nxt_app_t *app; 2788343Smax.romanov@nginx.com nxt_bool_t unchain, start_worker; 2789141Smax.romanov@nginx.com 2790141Smax.romanov@nginx.com app = port->app; 2791343Smax.romanov@nginx.com 2792343Smax.romanov@nginx.com nxt_assert(app != NULL); 2793141Smax.romanov@nginx.com 2794141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2795141Smax.romanov@nginx.com 2796343Smax.romanov@nginx.com unchain = port->app_link.next != NULL; 2797343Smax.romanov@nginx.com 2798343Smax.romanov@nginx.com if (unchain) { 2799163Smax.romanov@nginx.com nxt_queue_remove(&port->app_link); 2800163Smax.romanov@nginx.com port->app_link.next = NULL; 2801343Smax.romanov@nginx.com } 2802343Smax.romanov@nginx.com 2803343Smax.romanov@nginx.com app->workers--; 2804343Smax.romanov@nginx.com 2805343Smax.romanov@nginx.com start_worker = app->live != 0 && 2806343Smax.romanov@nginx.com nxt_queue_is_empty(&app->requests) == 0 && 2807343Smax.romanov@nginx.com app->workers + app->pending_workers < app->max_workers; 2808343Smax.romanov@nginx.com 2809343Smax.romanov@nginx.com if (start_worker) { 2810343Smax.romanov@nginx.com app->pending_workers++; 2811163Smax.romanov@nginx.com } 2812141Smax.romanov@nginx.com 2813141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2814163Smax.romanov@nginx.com 2815343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p port %p close", &app->name, app, port); 2816343Smax.romanov@nginx.com 2817343Smax.romanov@nginx.com if (unchain) { 2818343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 2819163Smax.romanov@nginx.com } 2820163Smax.romanov@nginx.com 2821343Smax.romanov@nginx.com if (start_worker) { 2822343Smax.romanov@nginx.com nxt_router_start_worker(task, app); 2823343Smax.romanov@nginx.com } 2824141Smax.romanov@nginx.com } 2825141Smax.romanov@nginx.com 2826141Smax.romanov@nginx.com 2827167Smax.romanov@nginx.com static nxt_int_t 2828167Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_req_app_link_t *ra) 2829141Smax.romanov@nginx.com { 2830343Smax.romanov@nginx.com int use_delta; 2831343Smax.romanov@nginx.com nxt_int_t res; 2832141Smax.romanov@nginx.com nxt_app_t *app; 2833343Smax.romanov@nginx.com nxt_bool_t can_start_worker; 2834141Smax.romanov@nginx.com nxt_conn_t *c; 2835167Smax.romanov@nginx.com nxt_port_t *port; 2836318Smax.romanov@nginx.com nxt_event_engine_t *engine; 2837141Smax.romanov@nginx.com nxt_socket_conf_joint_t *joint; 2838141Smax.romanov@nginx.com 2839141Smax.romanov@nginx.com port = NULL; 2840343Smax.romanov@nginx.com use_delta = 1; 2841167Smax.romanov@nginx.com c = ra->rc->conn; 2842141Smax.romanov@nginx.com 2843141Smax.romanov@nginx.com joint = c->listen->socket.data; 2844141Smax.romanov@nginx.com app = joint->socket_conf->application; 2845141Smax.romanov@nginx.com 2846141Smax.romanov@nginx.com if (app == NULL) { 2847167Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, 2848141Smax.romanov@nginx.com "Application is NULL in socket_conf"); 2849141Smax.romanov@nginx.com return NXT_ERROR; 2850141Smax.romanov@nginx.com } 2851141Smax.romanov@nginx.com 2852343Smax.romanov@nginx.com ra->rc->app = app; 2853343Smax.romanov@nginx.com 2854343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 2855343Smax.romanov@nginx.com 2856318Smax.romanov@nginx.com engine = task->thread->engine; 2857318Smax.romanov@nginx.com 2858318Smax.romanov@nginx.com nxt_timer_disable(engine, &c->read_timer); 2859318Smax.romanov@nginx.com 2860318Smax.romanov@nginx.com if (app->timeout != 0) { 2861318Smax.romanov@nginx.com c->read_timer.handler = nxt_router_app_timeout; 2862318Smax.romanov@nginx.com nxt_timer_add(engine, &c->read_timer, app->timeout); 2863318Smax.romanov@nginx.com } 2864318Smax.romanov@nginx.com 2865343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2866343Smax.romanov@nginx.com 2867343Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->ports)) { 2868343Smax.romanov@nginx.com port = nxt_router_app_get_port_unsafe(app, &use_delta); 2869343Smax.romanov@nginx.com 2870343Smax.romanov@nginx.com can_start_worker = 0; 2871343Smax.romanov@nginx.com 2872343Smax.romanov@nginx.com } else { 2873343Smax.romanov@nginx.com nxt_queue_insert_tail(&app->requests, &ra->link); 2874343Smax.romanov@nginx.com 2875343Smax.romanov@nginx.com can_start_worker = (app->workers + app->pending_workers) < 2876343Smax.romanov@nginx.com app->max_workers; 2877343Smax.romanov@nginx.com if (can_start_worker) { 2878343Smax.romanov@nginx.com app->pending_workers++; 2879343Smax.romanov@nginx.com } 2880343Smax.romanov@nginx.com 2881343Smax.romanov@nginx.com port = NULL; 2882343Smax.romanov@nginx.com } 2883343Smax.romanov@nginx.com 2884343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2885141Smax.romanov@nginx.com 2886141Smax.romanov@nginx.com if (port != NULL) { 2887343Smax.romanov@nginx.com nxt_debug(task, "already have port for app '%V' %p ", &app->name, app); 2888163Smax.romanov@nginx.com 2889167Smax.romanov@nginx.com ra->app_port = port; 2890343Smax.romanov@nginx.com 2891343Smax.romanov@nginx.com if (use_delta != 0) { 2892343Smax.romanov@nginx.com nxt_port_use(task, port, use_delta); 2893343Smax.romanov@nginx.com } 2894141Smax.romanov@nginx.com return NXT_OK; 2895141Smax.romanov@nginx.com } 2896141Smax.romanov@nginx.com 2897343Smax.romanov@nginx.com if (!can_start_worker) { 2898343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p too many running or pending workers", 2899343Smax.romanov@nginx.com &app->name, app); 2900343Smax.romanov@nginx.com 2901343Smax.romanov@nginx.com return NXT_AGAIN; 2902343Smax.romanov@nginx.com } 2903343Smax.romanov@nginx.com 2904343Smax.romanov@nginx.com res = nxt_router_start_worker(task, app); 2905343Smax.romanov@nginx.com 2906343Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 2907343Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Failed to start worker"); 2908343Smax.romanov@nginx.com 2909141Smax.romanov@nginx.com return NXT_ERROR; 2910141Smax.romanov@nginx.com } 2911141Smax.romanov@nginx.com 2912141Smax.romanov@nginx.com return NXT_AGAIN; 291388Smax.romanov@nginx.com } 291488Smax.romanov@nginx.com 291588Smax.romanov@nginx.com 291688Smax.romanov@nginx.com static void 291753Sigor@sysoev.ru nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, void *data) 291853Sigor@sysoev.ru { 2919206Smax.romanov@nginx.com size_t size; 292053Sigor@sysoev.ru nxt_int_t ret; 2921206Smax.romanov@nginx.com nxt_buf_t *buf; 292262Sigor@sysoev.ru nxt_conn_t *c; 2923268Sigor@sysoev.ru nxt_sockaddr_t *local; 292488Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 2925206Smax.romanov@nginx.com nxt_app_request_body_t *b; 292653Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 292788Smax.romanov@nginx.com nxt_app_request_header_t *h; 292853Sigor@sysoev.ru 292953Sigor@sysoev.ru c = obj; 293088Smax.romanov@nginx.com ap = data; 2931206Smax.romanov@nginx.com buf = c->read; 2932206Smax.romanov@nginx.com joint = c->listen->socket.data; 293353Sigor@sysoev.ru 293453Sigor@sysoev.ru nxt_debug(task, "router conn http header parse"); 293553Sigor@sysoev.ru 293688Smax.romanov@nginx.com if (ap == NULL) { 2937319Smax.romanov@nginx.com ap = nxt_app_http_req_init(task); 293888Smax.romanov@nginx.com if (nxt_slow_path(ap == NULL)) { 2939319Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, 2940319Smax.romanov@nginx.com "Failed to allocate parse context"); 294161Sigor@sysoev.ru return; 294261Sigor@sysoev.ru } 294388Smax.romanov@nginx.com 294488Smax.romanov@nginx.com c->socket.data = ap; 2945113Smax.romanov@nginx.com 2946113Smax.romanov@nginx.com ap->r.remote.start = nxt_sockaddr_address(c->remote); 2947113Smax.romanov@nginx.com ap->r.remote.length = c->remote->address_length; 2948206Smax.romanov@nginx.com 2949268Sigor@sysoev.ru local = joint->socket_conf->sockaddr; 2950268Sigor@sysoev.ru ap->r.local.start = nxt_sockaddr_address(local); 2951268Sigor@sysoev.ru ap->r.local.length = local->address_length; 2952268Sigor@sysoev.ru 2953206Smax.romanov@nginx.com ap->r.header.buf = buf; 295453Sigor@sysoev.ru } 295553Sigor@sysoev.ru 295688Smax.romanov@nginx.com h = &ap->r.header; 2957206Smax.romanov@nginx.com b = &ap->r.body; 2958206Smax.romanov@nginx.com 2959206Smax.romanov@nginx.com ret = nxt_app_http_req_header_parse(task, ap, buf); 2960206Smax.romanov@nginx.com 2961206Smax.romanov@nginx.com nxt_debug(task, "http parse request header: %d", ret); 296253Sigor@sysoev.ru 296353Sigor@sysoev.ru switch (nxt_expect(NXT_DONE, ret)) { 296453Sigor@sysoev.ru 296553Sigor@sysoev.ru case NXT_DONE: 296688Smax.romanov@nginx.com nxt_debug(task, "router request header parsing complete, " 296788Smax.romanov@nginx.com "content length: %O, preread: %uz", 2968206Smax.romanov@nginx.com h->parsed_content_length, nxt_buf_mem_used_size(&buf->mem)); 2969206Smax.romanov@nginx.com 2970206Smax.romanov@nginx.com if (b->done) { 2971206Smax.romanov@nginx.com nxt_router_process_http_request(task, c, ap); 2972206Smax.romanov@nginx.com 2973206Smax.romanov@nginx.com return; 2974206Smax.romanov@nginx.com } 2975206Smax.romanov@nginx.com 2976277Sigor@sysoev.ru if (joint->socket_conf->max_body_size > 0 2977277Sigor@sysoev.ru && (size_t) h->parsed_content_length 2978277Sigor@sysoev.ru > joint->socket_conf->max_body_size) 2979277Sigor@sysoev.ru { 2980206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 413, "Content-Length too big"); 2981206Smax.romanov@nginx.com return; 2982206Smax.romanov@nginx.com } 2983206Smax.romanov@nginx.com 2984206Smax.romanov@nginx.com if (nxt_buf_mem_free_size(&buf->mem) == 0) { 2985206Smax.romanov@nginx.com size = nxt_min(joint->socket_conf->body_buffer_size, 2986206Smax.romanov@nginx.com (size_t) h->parsed_content_length); 2987206Smax.romanov@nginx.com 2988206Smax.romanov@nginx.com buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0); 2989206Smax.romanov@nginx.com if (nxt_slow_path(buf->next == NULL)) { 2990206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Failed to allocate " 2991206Smax.romanov@nginx.com "buffer for request body"); 2992206Smax.romanov@nginx.com return; 2993206Smax.romanov@nginx.com } 2994206Smax.romanov@nginx.com 2995206Smax.romanov@nginx.com c->read = buf->next; 2996206Smax.romanov@nginx.com 2997206Smax.romanov@nginx.com b->preread_size += nxt_buf_mem_used_size(&buf->mem); 2998206Smax.romanov@nginx.com } 2999206Smax.romanov@nginx.com 3000206Smax.romanov@nginx.com if (b->buf == NULL) { 3001206Smax.romanov@nginx.com b->buf = c->read; 3002206Smax.romanov@nginx.com } 3003206Smax.romanov@nginx.com 3004206Smax.romanov@nginx.com c->read_state = &nxt_router_conn_read_body_state; 3005206Smax.romanov@nginx.com break; 3006206Smax.romanov@nginx.com 3007206Smax.romanov@nginx.com case NXT_ERROR: 3008206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 400, "Request header parse error"); 3009206Smax.romanov@nginx.com return; 3010206Smax.romanov@nginx.com 3011206Smax.romanov@nginx.com default: /* NXT_AGAIN */ 3012206Smax.romanov@nginx.com 3013206Smax.romanov@nginx.com if (c->read->mem.free == c->read->mem.end) { 3014206Smax.romanov@nginx.com size = joint->socket_conf->large_header_buffer_size; 3015206Smax.romanov@nginx.com 3016277Sigor@sysoev.ru if (size <= (size_t) nxt_buf_mem_used_size(&buf->mem) 3017277Sigor@sysoev.ru || ap->r.header.bufs 3018277Sigor@sysoev.ru >= joint->socket_conf->large_header_buffers) 3019277Sigor@sysoev.ru { 3020206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 413, 3021206Smax.romanov@nginx.com "Too long request headers"); 3022206Smax.romanov@nginx.com return; 3023206Smax.romanov@nginx.com } 3024206Smax.romanov@nginx.com 3025206Smax.romanov@nginx.com buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0); 3026206Smax.romanov@nginx.com if (nxt_slow_path(buf->next == NULL)) { 3027206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, 3028206Smax.romanov@nginx.com "Failed to allocate large header " 3029206Smax.romanov@nginx.com "buffer"); 3030206Smax.romanov@nginx.com return; 3031206Smax.romanov@nginx.com } 3032206Smax.romanov@nginx.com 3033206Smax.romanov@nginx.com ap->r.header.bufs++; 3034206Smax.romanov@nginx.com 3035206Smax.romanov@nginx.com size = c->read->mem.free - c->read->mem.pos; 3036206Smax.romanov@nginx.com 3037206Smax.romanov@nginx.com c->read = nxt_buf_cpy(buf->next, c->read->mem.pos, size); 3038206Smax.romanov@nginx.com } 3039206Smax.romanov@nginx.com 3040206Smax.romanov@nginx.com } 3041206Smax.romanov@nginx.com 3042206Smax.romanov@nginx.com nxt_conn_read(task->thread->engine, c); 3043206Smax.romanov@nginx.com } 3044206Smax.romanov@nginx.com 3045206Smax.romanov@nginx.com 3046206Smax.romanov@nginx.com static void 3047206Smax.romanov@nginx.com nxt_router_conn_http_body_read(nxt_task_t *task, void *obj, void *data) 3048206Smax.romanov@nginx.com { 3049206Smax.romanov@nginx.com size_t size; 3050206Smax.romanov@nginx.com nxt_int_t ret; 3051206Smax.romanov@nginx.com nxt_buf_t *buf; 3052206Smax.romanov@nginx.com nxt_conn_t *c; 3053206Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 3054206Smax.romanov@nginx.com nxt_app_request_body_t *b; 3055206Smax.romanov@nginx.com nxt_socket_conf_joint_t *joint; 3056206Smax.romanov@nginx.com nxt_app_request_header_t *h; 3057206Smax.romanov@nginx.com 3058206Smax.romanov@nginx.com c = obj; 3059206Smax.romanov@nginx.com ap = data; 3060206Smax.romanov@nginx.com buf = c->read; 3061206Smax.romanov@nginx.com 3062206Smax.romanov@nginx.com nxt_debug(task, "router conn http body read"); 3063206Smax.romanov@nginx.com 3064206Smax.romanov@nginx.com nxt_assert(ap != NULL); 3065206Smax.romanov@nginx.com 3066206Smax.romanov@nginx.com b = &ap->r.body; 3067206Smax.romanov@nginx.com h = &ap->r.header; 3068206Smax.romanov@nginx.com 3069206Smax.romanov@nginx.com ret = nxt_app_http_req_body_read(task, ap, buf); 3070206Smax.romanov@nginx.com 3071206Smax.romanov@nginx.com nxt_debug(task, "http read request body: %d", ret); 3072206Smax.romanov@nginx.com 3073206Smax.romanov@nginx.com switch (nxt_expect(NXT_DONE, ret)) { 3074206Smax.romanov@nginx.com 3075206Smax.romanov@nginx.com case NXT_DONE: 307688Smax.romanov@nginx.com nxt_router_process_http_request(task, c, ap); 307788Smax.romanov@nginx.com return; 307853Sigor@sysoev.ru 307953Sigor@sysoev.ru case NXT_ERROR: 3080206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Read body error"); 308153Sigor@sysoev.ru return; 308253Sigor@sysoev.ru 308353Sigor@sysoev.ru default: /* NXT_AGAIN */ 308453Sigor@sysoev.ru 3085206Smax.romanov@nginx.com if (nxt_buf_mem_free_size(&buf->mem) == 0) { 3086206Smax.romanov@nginx.com joint = c->listen->socket.data; 3087206Smax.romanov@nginx.com 3088206Smax.romanov@nginx.com b->preread_size += nxt_buf_mem_used_size(&buf->mem); 3089206Smax.romanov@nginx.com 3090206Smax.romanov@nginx.com size = nxt_min(joint->socket_conf->body_buffer_size, 3091206Smax.romanov@nginx.com (size_t) h->parsed_content_length - b->preread_size); 3092206Smax.romanov@nginx.com 3093206Smax.romanov@nginx.com buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0); 3094206Smax.romanov@nginx.com if (nxt_slow_path(buf->next == NULL)) { 3095206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Failed to allocate " 3096206Smax.romanov@nginx.com "buffer for request body"); 3097206Smax.romanov@nginx.com return; 309888Smax.romanov@nginx.com } 3099206Smax.romanov@nginx.com 3100206Smax.romanov@nginx.com c->read = buf->next; 310188Smax.romanov@nginx.com } 310288Smax.romanov@nginx.com 3103206Smax.romanov@nginx.com nxt_debug(task, "router request body read again, rest: %uz", 3104206Smax.romanov@nginx.com h->parsed_content_length - b->preread_size); 310588Smax.romanov@nginx.com } 310688Smax.romanov@nginx.com 310788Smax.romanov@nginx.com nxt_conn_read(task->thread->engine, c); 310888Smax.romanov@nginx.com } 310988Smax.romanov@nginx.com 311088Smax.romanov@nginx.com 311188Smax.romanov@nginx.com static void 311288Smax.romanov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_conn_t *c, 311388Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap) 311488Smax.romanov@nginx.com { 3115122Smax.romanov@nginx.com nxt_int_t res; 3116167Smax.romanov@nginx.com nxt_port_t *port; 311788Smax.romanov@nginx.com nxt_event_engine_t *engine; 3118167Smax.romanov@nginx.com nxt_req_app_link_t *ra; 311988Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 312088Smax.romanov@nginx.com 312188Smax.romanov@nginx.com engine = task->thread->engine; 312288Smax.romanov@nginx.com 3123318Smax.romanov@nginx.com rc = nxt_port_rpc_register_handler_ex(task, engine->port, 3124318Smax.romanov@nginx.com nxt_router_response_ready_handler, 3125318Smax.romanov@nginx.com nxt_router_response_error_handler, 3126318Smax.romanov@nginx.com sizeof(nxt_req_conn_link_t)); 3127122Smax.romanov@nginx.com 312888Smax.romanov@nginx.com if (nxt_slow_path(rc == NULL)) { 3129141Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Failed to allocate " 3130141Smax.romanov@nginx.com "req->conn link"); 3131141Smax.romanov@nginx.com 3132141Smax.romanov@nginx.com return; 313388Smax.romanov@nginx.com } 313488Smax.romanov@nginx.com 3135318Smax.romanov@nginx.com rc->stream = nxt_port_rpc_ex_stream(rc); 3136318Smax.romanov@nginx.com rc->conn = c; 3137318Smax.romanov@nginx.com 3138318Smax.romanov@nginx.com nxt_queue_insert_tail(&c->requests, &rc->link); 3139318Smax.romanov@nginx.com 3140318Smax.romanov@nginx.com nxt_debug(task, "stream #%uD linked to conn %p at engine %p", 3141318Smax.romanov@nginx.com rc->stream, c, engine); 314253Sigor@sysoev.ru 3143167Smax.romanov@nginx.com ra = nxt_router_ra_create(task, rc); 3144167Smax.romanov@nginx.com 3145167Smax.romanov@nginx.com ra->ap = ap; 3146167Smax.romanov@nginx.com 3147167Smax.romanov@nginx.com res = nxt_router_app_port(task, ra); 3148141Smax.romanov@nginx.com 3149141Smax.romanov@nginx.com if (res != NXT_OK) { 3150141Smax.romanov@nginx.com return; 3151141Smax.romanov@nginx.com } 3152141Smax.romanov@nginx.com 3153167Smax.romanov@nginx.com port = ra->app_port; 3154141Smax.romanov@nginx.com 3155141Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 3156318Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Application port not found"); 3157141Smax.romanov@nginx.com return; 3158141Smax.romanov@nginx.com } 3159141Smax.romanov@nginx.com 3160318Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, engine->port, rc, port->pid); 3161318Smax.romanov@nginx.com 3162343Smax.romanov@nginx.com nxt_router_process_http_request_mp(task, ra); 3163167Smax.romanov@nginx.com } 3164167Smax.romanov@nginx.com 3165167Smax.romanov@nginx.com 3166167Smax.romanov@nginx.com static void 3167343Smax.romanov@nginx.com nxt_router_process_http_request_mp(nxt_task_t *task, nxt_req_app_link_t *ra) 3168167Smax.romanov@nginx.com { 3169343Smax.romanov@nginx.com uint32_t request_failed; 3170167Smax.romanov@nginx.com nxt_int_t res; 3171343Smax.romanov@nginx.com nxt_port_t *port, *c_port, *reply_port; 3172167Smax.romanov@nginx.com nxt_app_wmsg_t wmsg; 3173167Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 3174167Smax.romanov@nginx.com 3175343Smax.romanov@nginx.com nxt_assert(ra->app_port != NULL); 3176343Smax.romanov@nginx.com 3177343Smax.romanov@nginx.com port = ra->app_port; 3178167Smax.romanov@nginx.com reply_port = ra->reply_port; 3179167Smax.romanov@nginx.com ap = ra->ap; 3180141Smax.romanov@nginx.com 3181343Smax.romanov@nginx.com request_failed = 1; 3182343Smax.romanov@nginx.com 3183141Smax.romanov@nginx.com c_port = nxt_process_connected_port_find(port->process, reply_port->pid, 3184141Smax.romanov@nginx.com reply_port->id); 3185141Smax.romanov@nginx.com if (nxt_slow_path(c_port != reply_port)) { 3186141Smax.romanov@nginx.com res = nxt_port_send_port(task, port, reply_port, 0); 3187122Smax.romanov@nginx.com 3188122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3189*345Smax.romanov@nginx.com nxt_router_ra_error(task, ra, 500, 3190*345Smax.romanov@nginx.com "Failed to send reply port to application"); 3191*345Smax.romanov@nginx.com ra = NULL; 3192343Smax.romanov@nginx.com goto release_port; 3193122Smax.romanov@nginx.com } 3194122Smax.romanov@nginx.com 3195141Smax.romanov@nginx.com nxt_process_connected_port_add(port->process, reply_port); 319688Smax.romanov@nginx.com } 319788Smax.romanov@nginx.com 319888Smax.romanov@nginx.com wmsg.port = port; 319988Smax.romanov@nginx.com wmsg.write = NULL; 320088Smax.romanov@nginx.com wmsg.buf = &wmsg.write; 3201318Smax.romanov@nginx.com wmsg.stream = ra->stream; 3202167Smax.romanov@nginx.com 3203216Sigor@sysoev.ru res = port->app->prepare_msg(task, &ap->r, &wmsg); 3204122Smax.romanov@nginx.com 3205122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3206*345Smax.romanov@nginx.com nxt_router_ra_error(task, ra, 500, 3207*345Smax.romanov@nginx.com "Failed to prepare message for application"); 3208*345Smax.romanov@nginx.com ra = NULL; 3209343Smax.romanov@nginx.com goto release_port; 3210122Smax.romanov@nginx.com } 321188Smax.romanov@nginx.com 321288Smax.romanov@nginx.com nxt_debug(task, "about to send %d bytes buffer to worker port %d", 321388Smax.romanov@nginx.com nxt_buf_used_size(wmsg.write), 321488Smax.romanov@nginx.com wmsg.port->socket.fd); 321588Smax.romanov@nginx.com 3216343Smax.romanov@nginx.com request_failed = 0; 3217343Smax.romanov@nginx.com 3218122Smax.romanov@nginx.com res = nxt_port_socket_write(task, wmsg.port, NXT_PORT_MSG_DATA, 3219318Smax.romanov@nginx.com -1, ra->stream, reply_port->id, wmsg.write); 3220122Smax.romanov@nginx.com 3221122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3222*345Smax.romanov@nginx.com nxt_router_ra_error(task, ra, 500, 3223*345Smax.romanov@nginx.com "Failed to send message to application"); 3224*345Smax.romanov@nginx.com ra = NULL; 3225343Smax.romanov@nginx.com goto release_port; 3226122Smax.romanov@nginx.com } 3227343Smax.romanov@nginx.com 3228343Smax.romanov@nginx.com release_port: 3229343Smax.romanov@nginx.com 3230*345Smax.romanov@nginx.com nxt_router_app_port_release(task, port, request_failed, 0); 3231*345Smax.romanov@nginx.com 3232*345Smax.romanov@nginx.com if (ra != NULL) { 3233*345Smax.romanov@nginx.com if (request_failed != 0) { 3234*345Smax.romanov@nginx.com ra->app_port = 0; 3235*345Smax.romanov@nginx.com } 3236*345Smax.romanov@nginx.com 3237*345Smax.romanov@nginx.com nxt_router_ra_release(task, ra, ra->work.data); 3238343Smax.romanov@nginx.com } 323953Sigor@sysoev.ru } 324053Sigor@sysoev.ru 324153Sigor@sysoev.ru 3242216Sigor@sysoev.ru static nxt_int_t 3243216Sigor@sysoev.ru nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 3244216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg) 3245216Sigor@sysoev.ru { 3246216Sigor@sysoev.ru nxt_int_t rc; 3247216Sigor@sysoev.ru nxt_buf_t *b; 3248216Sigor@sysoev.ru nxt_http_field_t *field; 3249216Sigor@sysoev.ru nxt_app_request_header_t *h; 3250216Sigor@sysoev.ru 3251216Sigor@sysoev.ru static const nxt_str_t prefix = nxt_string("HTTP_"); 3252216Sigor@sysoev.ru static const nxt_str_t eof = nxt_null_string; 3253216Sigor@sysoev.ru 3254216Sigor@sysoev.ru h = &r->header; 3255216Sigor@sysoev.ru 3256216Sigor@sysoev.ru #define RC(S) \ 3257216Sigor@sysoev.ru do { \ 3258216Sigor@sysoev.ru rc = (S); \ 3259216Sigor@sysoev.ru if (nxt_slow_path(rc != NXT_OK)) { \ 3260216Sigor@sysoev.ru goto fail; \ 3261216Sigor@sysoev.ru } \ 3262216Sigor@sysoev.ru } while(0) 3263216Sigor@sysoev.ru 3264216Sigor@sysoev.ru #define NXT_WRITE(N) \ 3265216Sigor@sysoev.ru RC(nxt_app_msg_write_str(task, wmsg, N)) 3266216Sigor@sysoev.ru 3267216Sigor@sysoev.ru /* TODO error handle, async mmap buffer assignment */ 3268216Sigor@sysoev.ru 3269216Sigor@sysoev.ru NXT_WRITE(&h->method); 3270216Sigor@sysoev.ru NXT_WRITE(&h->target); 3271277Sigor@sysoev.ru 3272216Sigor@sysoev.ru if (h->path.start == h->target.start) { 3273216Sigor@sysoev.ru NXT_WRITE(&eof); 3274277Sigor@sysoev.ru 3275216Sigor@sysoev.ru } else { 3276216Sigor@sysoev.ru NXT_WRITE(&h->path); 3277216Sigor@sysoev.ru } 3278216Sigor@sysoev.ru 3279216Sigor@sysoev.ru if (h->query.start != NULL) { 3280216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 3281216Sigor@sysoev.ru h->query.start - h->target.start + 1)); 3282216Sigor@sysoev.ru } else { 3283216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 0)); 3284216Sigor@sysoev.ru } 3285216Sigor@sysoev.ru 3286216Sigor@sysoev.ru NXT_WRITE(&h->version); 3287216Sigor@sysoev.ru 3288216Sigor@sysoev.ru NXT_WRITE(&r->remote); 3289268Sigor@sysoev.ru NXT_WRITE(&r->local); 3290216Sigor@sysoev.ru 3291216Sigor@sysoev.ru NXT_WRITE(&h->host); 3292216Sigor@sysoev.ru NXT_WRITE(&h->content_type); 3293216Sigor@sysoev.ru NXT_WRITE(&h->content_length); 3294216Sigor@sysoev.ru 3295216Sigor@sysoev.ru nxt_list_each(field, h->fields) { 3296216Sigor@sysoev.ru RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, 3297216Sigor@sysoev.ru &prefix, &field->name)); 3298216Sigor@sysoev.ru NXT_WRITE(&field->value); 3299216Sigor@sysoev.ru 3300216Sigor@sysoev.ru } nxt_list_loop; 3301216Sigor@sysoev.ru 3302216Sigor@sysoev.ru /* end-of-headers mark */ 3303216Sigor@sysoev.ru NXT_WRITE(&eof); 3304216Sigor@sysoev.ru 3305216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 3306216Sigor@sysoev.ru 3307216Sigor@sysoev.ru for(b = r->body.buf; b != NULL; b = b->next) { 3308216Sigor@sysoev.ru RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3309216Sigor@sysoev.ru nxt_buf_mem_used_size(&b->mem))); 3310216Sigor@sysoev.ru } 3311216Sigor@sysoev.ru 3312216Sigor@sysoev.ru #undef NXT_WRITE 3313216Sigor@sysoev.ru #undef RC 3314216Sigor@sysoev.ru 3315216Sigor@sysoev.ru return NXT_OK; 3316216Sigor@sysoev.ru 3317216Sigor@sysoev.ru fail: 3318216Sigor@sysoev.ru 3319216Sigor@sysoev.ru return NXT_ERROR; 3320216Sigor@sysoev.ru } 3321216Sigor@sysoev.ru 3322216Sigor@sysoev.ru 3323216Sigor@sysoev.ru static nxt_int_t 3324216Sigor@sysoev.ru nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 3325216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg) 3326216Sigor@sysoev.ru { 3327216Sigor@sysoev.ru nxt_int_t rc; 3328216Sigor@sysoev.ru nxt_buf_t *b; 3329305Smax.romanov@nginx.com nxt_bool_t method_is_post; 3330216Sigor@sysoev.ru nxt_http_field_t *field; 3331216Sigor@sysoev.ru nxt_app_request_header_t *h; 3332216Sigor@sysoev.ru 3333216Sigor@sysoev.ru static const nxt_str_t prefix = nxt_string("HTTP_"); 3334216Sigor@sysoev.ru static const nxt_str_t eof = nxt_null_string; 3335216Sigor@sysoev.ru 3336216Sigor@sysoev.ru h = &r->header; 3337216Sigor@sysoev.ru 3338216Sigor@sysoev.ru #define RC(S) \ 3339216Sigor@sysoev.ru do { \ 3340216Sigor@sysoev.ru rc = (S); \ 3341216Sigor@sysoev.ru if (nxt_slow_path(rc != NXT_OK)) { \ 3342216Sigor@sysoev.ru goto fail; \ 3343216Sigor@sysoev.ru } \ 3344216Sigor@sysoev.ru } while(0) 3345216Sigor@sysoev.ru 3346216Sigor@sysoev.ru #define NXT_WRITE(N) \ 3347216Sigor@sysoev.ru RC(nxt_app_msg_write_str(task, wmsg, N)) 3348216Sigor@sysoev.ru 3349216Sigor@sysoev.ru /* TODO error handle, async mmap buffer assignment */ 3350216Sigor@sysoev.ru 3351216Sigor@sysoev.ru NXT_WRITE(&h->method); 3352216Sigor@sysoev.ru NXT_WRITE(&h->target); 3353277Sigor@sysoev.ru 3354216Sigor@sysoev.ru if (h->path.start == h->target.start) { 3355216Sigor@sysoev.ru NXT_WRITE(&eof); 3356277Sigor@sysoev.ru 3357216Sigor@sysoev.ru } else { 3358216Sigor@sysoev.ru NXT_WRITE(&h->path); 3359216Sigor@sysoev.ru } 3360216Sigor@sysoev.ru 3361216Sigor@sysoev.ru if (h->query.start != NULL) { 3362216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 3363216Sigor@sysoev.ru h->query.start - h->target.start + 1)); 3364216Sigor@sysoev.ru } else { 3365216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 0)); 3366216Sigor@sysoev.ru } 3367216Sigor@sysoev.ru 3368216Sigor@sysoev.ru NXT_WRITE(&h->version); 3369216Sigor@sysoev.ru 3370216Sigor@sysoev.ru // PHP_SELF 3371216Sigor@sysoev.ru // SCRIPT_NAME 3372216Sigor@sysoev.ru // SCRIPT_FILENAME 3373216Sigor@sysoev.ru // DOCUMENT_ROOT 3374216Sigor@sysoev.ru 3375216Sigor@sysoev.ru NXT_WRITE(&r->remote); 3376268Sigor@sysoev.ru NXT_WRITE(&r->local); 3377216Sigor@sysoev.ru 3378216Sigor@sysoev.ru NXT_WRITE(&h->host); 3379216Sigor@sysoev.ru NXT_WRITE(&h->cookie); 3380216Sigor@sysoev.ru NXT_WRITE(&h->content_type); 3381216Sigor@sysoev.ru NXT_WRITE(&h->content_length); 3382216Sigor@sysoev.ru 3383216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length)); 3384305Smax.romanov@nginx.com RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 3385305Smax.romanov@nginx.com 3386305Smax.romanov@nginx.com method_is_post = h->method.length == 4 && 3387305Smax.romanov@nginx.com h->method.start[0] == 'P' && 3388305Smax.romanov@nginx.com h->method.start[1] == 'O' && 3389305Smax.romanov@nginx.com h->method.start[2] == 'S' && 3390305Smax.romanov@nginx.com h->method.start[3] == 'T'; 3391305Smax.romanov@nginx.com 3392305Smax.romanov@nginx.com if (method_is_post) { 3393305Smax.romanov@nginx.com for(b = r->body.buf; b != NULL; b = b->next) { 3394305Smax.romanov@nginx.com RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3395305Smax.romanov@nginx.com nxt_buf_mem_used_size(&b->mem))); 3396305Smax.romanov@nginx.com } 3397305Smax.romanov@nginx.com } 3398216Sigor@sysoev.ru 3399216Sigor@sysoev.ru nxt_list_each(field, h->fields) { 3400216Sigor@sysoev.ru RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, 3401216Sigor@sysoev.ru &prefix, &field->name)); 3402216Sigor@sysoev.ru NXT_WRITE(&field->value); 3403216Sigor@sysoev.ru 3404216Sigor@sysoev.ru } nxt_list_loop; 3405216Sigor@sysoev.ru 3406216Sigor@sysoev.ru /* end-of-headers mark */ 3407216Sigor@sysoev.ru NXT_WRITE(&eof); 3408216Sigor@sysoev.ru 3409305Smax.romanov@nginx.com if (!method_is_post) { 3410305Smax.romanov@nginx.com for(b = r->body.buf; b != NULL; b = b->next) { 3411305Smax.romanov@nginx.com RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3412305Smax.romanov@nginx.com nxt_buf_mem_used_size(&b->mem))); 3413305Smax.romanov@nginx.com } 3414216Sigor@sysoev.ru } 3415216Sigor@sysoev.ru 3416216Sigor@sysoev.ru #undef NXT_WRITE 3417216Sigor@sysoev.ru #undef RC 3418216Sigor@sysoev.ru 3419216Sigor@sysoev.ru return NXT_OK; 3420216Sigor@sysoev.ru 3421216Sigor@sysoev.ru fail: 3422216Sigor@sysoev.ru 3423216Sigor@sysoev.ru return NXT_ERROR; 3424216Sigor@sysoev.ru } 3425216Sigor@sysoev.ru 3426216Sigor@sysoev.ru 3427216Sigor@sysoev.ru static nxt_int_t 3428216Sigor@sysoev.ru nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, nxt_app_wmsg_t *wmsg) 3429216Sigor@sysoev.ru { 3430216Sigor@sysoev.ru nxt_int_t rc; 3431216Sigor@sysoev.ru nxt_buf_t *b; 3432216Sigor@sysoev.ru nxt_http_field_t *field; 3433216Sigor@sysoev.ru nxt_app_request_header_t *h; 3434216Sigor@sysoev.ru 3435216Sigor@sysoev.ru static const nxt_str_t eof = nxt_null_string; 3436216Sigor@sysoev.ru 3437216Sigor@sysoev.ru h = &r->header; 3438216Sigor@sysoev.ru 3439216Sigor@sysoev.ru #define RC(S) \ 3440216Sigor@sysoev.ru do { \ 3441216Sigor@sysoev.ru rc = (S); \ 3442216Sigor@sysoev.ru if (nxt_slow_path(rc != NXT_OK)) { \ 3443216Sigor@sysoev.ru goto fail; \ 3444216Sigor@sysoev.ru } \ 3445216Sigor@sysoev.ru } while(0) 3446216Sigor@sysoev.ru 3447216Sigor@sysoev.ru #define NXT_WRITE(N) \ 3448216Sigor@sysoev.ru RC(nxt_app_msg_write_str(task, wmsg, N)) 3449216Sigor@sysoev.ru 3450216Sigor@sysoev.ru /* TODO error handle, async mmap buffer assignment */ 3451216Sigor@sysoev.ru 3452216Sigor@sysoev.ru NXT_WRITE(&h->method); 3453216Sigor@sysoev.ru NXT_WRITE(&h->target); 3454277Sigor@sysoev.ru 3455216Sigor@sysoev.ru if (h->path.start == h->target.start) { 3456216Sigor@sysoev.ru NXT_WRITE(&eof); 3457277Sigor@sysoev.ru 3458216Sigor@sysoev.ru } else { 3459216Sigor@sysoev.ru NXT_WRITE(&h->path); 3460216Sigor@sysoev.ru } 3461216Sigor@sysoev.ru 3462216Sigor@sysoev.ru if (h->query.start != NULL) { 3463216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 3464216Sigor@sysoev.ru h->query.start - h->target.start + 1)); 3465216Sigor@sysoev.ru } else { 3466216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 0)); 3467216Sigor@sysoev.ru } 3468216Sigor@sysoev.ru 3469216Sigor@sysoev.ru NXT_WRITE(&h->version); 3470253Smax.romanov@nginx.com NXT_WRITE(&r->remote); 3471216Sigor@sysoev.ru 3472216Sigor@sysoev.ru NXT_WRITE(&h->host); 3473216Sigor@sysoev.ru NXT_WRITE(&h->cookie); 3474216Sigor@sysoev.ru NXT_WRITE(&h->content_type); 3475216Sigor@sysoev.ru NXT_WRITE(&h->content_length); 3476216Sigor@sysoev.ru 3477216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length)); 3478216Sigor@sysoev.ru 3479216Sigor@sysoev.ru nxt_list_each(field, h->fields) { 3480216Sigor@sysoev.ru NXT_WRITE(&field->name); 3481216Sigor@sysoev.ru NXT_WRITE(&field->value); 3482216Sigor@sysoev.ru 3483216Sigor@sysoev.ru } nxt_list_loop; 3484216Sigor@sysoev.ru 3485216Sigor@sysoev.ru /* end-of-headers mark */ 3486216Sigor@sysoev.ru NXT_WRITE(&eof); 3487216Sigor@sysoev.ru 3488216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 3489216Sigor@sysoev.ru 3490216Sigor@sysoev.ru for(b = r->body.buf; b != NULL; b = b->next) { 3491216Sigor@sysoev.ru RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3492216Sigor@sysoev.ru nxt_buf_mem_used_size(&b->mem))); 3493216Sigor@sysoev.ru } 3494216Sigor@sysoev.ru 3495216Sigor@sysoev.ru #undef NXT_WRITE 3496216Sigor@sysoev.ru #undef RC 3497216Sigor@sysoev.ru 3498216Sigor@sysoev.ru return NXT_OK; 3499216Sigor@sysoev.ru 3500216Sigor@sysoev.ru fail: 3501216Sigor@sysoev.ru 3502216Sigor@sysoev.ru return NXT_ERROR; 3503216Sigor@sysoev.ru } 3504216Sigor@sysoev.ru 3505216Sigor@sysoev.ru 350662Sigor@sysoev.ru static const nxt_conn_state_t nxt_router_conn_close_state 350753Sigor@sysoev.ru nxt_aligned(64) = 350853Sigor@sysoev.ru { 350953Sigor@sysoev.ru .ready_handler = nxt_router_conn_free, 351053Sigor@sysoev.ru }; 351153Sigor@sysoev.ru 351253Sigor@sysoev.ru 351353Sigor@sysoev.ru static void 351488Smax.romanov@nginx.com nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data) 351588Smax.romanov@nginx.com { 351688Smax.romanov@nginx.com nxt_buf_t *b; 351788Smax.romanov@nginx.com nxt_bool_t last; 351888Smax.romanov@nginx.com nxt_conn_t *c; 351988Smax.romanov@nginx.com nxt_work_queue_t *wq; 352088Smax.romanov@nginx.com 352188Smax.romanov@nginx.com nxt_debug(task, "router conn ready %p", obj); 352288Smax.romanov@nginx.com 352388Smax.romanov@nginx.com c = obj; 352488Smax.romanov@nginx.com b = c->write; 352588Smax.romanov@nginx.com 352688Smax.romanov@nginx.com wq = &task->thread->engine->fast_work_queue; 352788Smax.romanov@nginx.com 352888Smax.romanov@nginx.com last = 0; 352988Smax.romanov@nginx.com 353088Smax.romanov@nginx.com while (b != NULL) { 353188Smax.romanov@nginx.com if (!nxt_buf_is_sync(b)) { 353288Smax.romanov@nginx.com if (nxt_buf_used_size(b) > 0) { 353388Smax.romanov@nginx.com break; 353488Smax.romanov@nginx.com } 353588Smax.romanov@nginx.com } 353688Smax.romanov@nginx.com 353788Smax.romanov@nginx.com if (nxt_buf_is_last(b)) { 353888Smax.romanov@nginx.com last = 1; 353988Smax.romanov@nginx.com } 354088Smax.romanov@nginx.com 354188Smax.romanov@nginx.com nxt_work_queue_add(wq, b->completion_handler, task, b, b->parent); 354288Smax.romanov@nginx.com 354388Smax.romanov@nginx.com b = b->next; 354488Smax.romanov@nginx.com } 354588Smax.romanov@nginx.com 354688Smax.romanov@nginx.com c->write = b; 354788Smax.romanov@nginx.com 354888Smax.romanov@nginx.com if (b != NULL) { 354988Smax.romanov@nginx.com nxt_debug(task, "router conn %p has more data to write", obj); 355088Smax.romanov@nginx.com 355188Smax.romanov@nginx.com nxt_conn_write(task->thread->engine, c); 3552277Sigor@sysoev.ru 355388Smax.romanov@nginx.com } else { 355488Smax.romanov@nginx.com nxt_debug(task, "router conn %p no more data to write, last = %d", obj, 355588Smax.romanov@nginx.com last); 355688Smax.romanov@nginx.com 355788Smax.romanov@nginx.com if (last != 0) { 355888Smax.romanov@nginx.com nxt_debug(task, "enqueue router conn close %p (ready handler)", c); 355988Smax.romanov@nginx.com 356088Smax.romanov@nginx.com nxt_work_queue_add(wq, nxt_router_conn_close, task, c, 356188Smax.romanov@nginx.com c->socket.data); 356288Smax.romanov@nginx.com } 356388Smax.romanov@nginx.com } 356488Smax.romanov@nginx.com } 356588Smax.romanov@nginx.com 356688Smax.romanov@nginx.com 356788Smax.romanov@nginx.com static void 356853Sigor@sysoev.ru nxt_router_conn_close(nxt_task_t *task, void *obj, void *data) 356953Sigor@sysoev.ru { 357062Sigor@sysoev.ru nxt_conn_t *c; 357153Sigor@sysoev.ru 357253Sigor@sysoev.ru c = obj; 357353Sigor@sysoev.ru 357453Sigor@sysoev.ru nxt_debug(task, "router conn close"); 357553Sigor@sysoev.ru 357653Sigor@sysoev.ru c->write_state = &nxt_router_conn_close_state; 357753Sigor@sysoev.ru 357862Sigor@sysoev.ru nxt_conn_close(task->thread->engine, c); 357953Sigor@sysoev.ru } 358053Sigor@sysoev.ru 358153Sigor@sysoev.ru 358253Sigor@sysoev.ru static void 3583164Smax.romanov@nginx.com nxt_router_conn_mp_cleanup(nxt_task_t *task, void *obj, void *data) 3584164Smax.romanov@nginx.com { 3585164Smax.romanov@nginx.com nxt_socket_conf_joint_t *joint; 3586164Smax.romanov@nginx.com 3587164Smax.romanov@nginx.com joint = obj; 3588164Smax.romanov@nginx.com 3589164Smax.romanov@nginx.com nxt_router_conf_release(task, joint); 3590164Smax.romanov@nginx.com } 3591164Smax.romanov@nginx.com 3592164Smax.romanov@nginx.com 3593164Smax.romanov@nginx.com static void 359453Sigor@sysoev.ru nxt_router_conn_free(nxt_task_t *task, void *obj, void *data) 359553Sigor@sysoev.ru { 359662Sigor@sysoev.ru nxt_conn_t *c; 3597337Sigor@sysoev.ru nxt_event_engine_t *engine; 359888Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 3599319Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 360053Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 360153Sigor@sysoev.ru 360253Sigor@sysoev.ru c = obj; 3603319Smax.romanov@nginx.com ap = data; 360453Sigor@sysoev.ru 360553Sigor@sysoev.ru nxt_debug(task, "router conn close done"); 360653Sigor@sysoev.ru 3607319Smax.romanov@nginx.com if (ap != NULL) { 3608319Smax.romanov@nginx.com nxt_app_http_req_done(task, ap); 3609319Smax.romanov@nginx.com 3610319Smax.romanov@nginx.com c->socket.data = NULL; 3611319Smax.romanov@nginx.com } 3612319Smax.romanov@nginx.com 361388Smax.romanov@nginx.com nxt_queue_each(rc, &c->requests, nxt_req_conn_link_t, link) { 361488Smax.romanov@nginx.com 3615318Smax.romanov@nginx.com nxt_debug(task, "conn %p close, stream #%uD", c, rc->stream); 361688Smax.romanov@nginx.com 3617343Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 3618318Smax.romanov@nginx.com 3619318Smax.romanov@nginx.com nxt_port_rpc_cancel(task, task->thread->engine->port, rc->stream); 362088Smax.romanov@nginx.com 362188Smax.romanov@nginx.com } nxt_queue_loop; 362288Smax.romanov@nginx.com 3623122Smax.romanov@nginx.com nxt_queue_remove(&c->link); 3624122Smax.romanov@nginx.com 3625337Sigor@sysoev.ru engine = task->thread->engine; 3626337Sigor@sysoev.ru 3627337Sigor@sysoev.ru nxt_sockaddr_cache_free(engine, c); 3628337Sigor@sysoev.ru 3629131Smax.romanov@nginx.com joint = c->listen->socket.data; 3630131Smax.romanov@nginx.com 3631337Sigor@sysoev.ru nxt_mp_cleanup(c->mem_pool, nxt_router_conn_mp_cleanup, 3632337Sigor@sysoev.ru &engine->task, joint, NULL); 3633164Smax.romanov@nginx.com 3634164Smax.romanov@nginx.com nxt_mp_release(c->mem_pool, c); 363553Sigor@sysoev.ru } 363653Sigor@sysoev.ru 363753Sigor@sysoev.ru 363853Sigor@sysoev.ru static void 363953Sigor@sysoev.ru nxt_router_conn_error(nxt_task_t *task, void *obj, void *data) 364053Sigor@sysoev.ru { 364162Sigor@sysoev.ru nxt_conn_t *c; 364253Sigor@sysoev.ru 364353Sigor@sysoev.ru c = obj; 364453Sigor@sysoev.ru 364553Sigor@sysoev.ru nxt_debug(task, "router conn error"); 364653Sigor@sysoev.ru 3647273Smax.romanov@nginx.com if (c->socket.fd != -1) { 3648273Smax.romanov@nginx.com c->write_state = &nxt_router_conn_close_state; 3649273Smax.romanov@nginx.com 3650273Smax.romanov@nginx.com nxt_conn_close(task->thread->engine, c); 3651273Smax.romanov@nginx.com } 365253Sigor@sysoev.ru } 365353Sigor@sysoev.ru 365453Sigor@sysoev.ru 365553Sigor@sysoev.ru static void 365653Sigor@sysoev.ru nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data) 365753Sigor@sysoev.ru { 365862Sigor@sysoev.ru nxt_conn_t *c; 365962Sigor@sysoev.ru nxt_timer_t *timer; 366053Sigor@sysoev.ru 366153Sigor@sysoev.ru timer = obj; 366253Sigor@sysoev.ru 366353Sigor@sysoev.ru nxt_debug(task, "router conn timeout"); 366453Sigor@sysoev.ru 366562Sigor@sysoev.ru c = nxt_read_timer_conn(timer); 366653Sigor@sysoev.ru 3667206Smax.romanov@nginx.com if (c->read_state == &nxt_router_conn_read_header_state) { 3668206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 408, "Read header timeout"); 3669206Smax.romanov@nginx.com 3670206Smax.romanov@nginx.com } else { 3671206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 408, "Read body timeout"); 3672206Smax.romanov@nginx.com } 367353Sigor@sysoev.ru } 367453Sigor@sysoev.ru 367553Sigor@sysoev.ru 3676318Smax.romanov@nginx.com static void 3677318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data) 3678318Smax.romanov@nginx.com { 3679318Smax.romanov@nginx.com nxt_conn_t *c; 3680318Smax.romanov@nginx.com nxt_timer_t *timer; 3681318Smax.romanov@nginx.com 3682318Smax.romanov@nginx.com timer = obj; 3683318Smax.romanov@nginx.com 3684318Smax.romanov@nginx.com nxt_debug(task, "router app timeout"); 3685318Smax.romanov@nginx.com 3686318Smax.romanov@nginx.com c = nxt_read_timer_conn(timer); 3687318Smax.romanov@nginx.com 3688318Smax.romanov@nginx.com nxt_router_gen_error(task, c, 408, "Application timeout"); 3689318Smax.romanov@nginx.com } 3690318Smax.romanov@nginx.com 3691318Smax.romanov@nginx.com 369253Sigor@sysoev.ru static nxt_msec_t 369362Sigor@sysoev.ru nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data) 369453Sigor@sysoev.ru { 369553Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 369653Sigor@sysoev.ru 369753Sigor@sysoev.ru joint = c->listen->socket.data; 369853Sigor@sysoev.ru 369953Sigor@sysoev.ru return nxt_value_at(nxt_msec_t, joint->socket_conf, data); 370053Sigor@sysoev.ru } 3701