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; 34346Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 35318Smax.romanov@nginx.com nxt_req_app_link_t *ra; 36318Smax.romanov@nginx.com 37318Smax.romanov@nginx.com nxt_queue_link_t link; /* for nxt_conn_t.requests */ 38318Smax.romanov@nginx.com } nxt_req_conn_link_t; 39318Smax.romanov@nginx.com 40318Smax.romanov@nginx.com 41167Smax.romanov@nginx.com struct nxt_req_app_link_s { 42318Smax.romanov@nginx.com uint32_t stream; 43167Smax.romanov@nginx.com nxt_port_t *app_port; 44318Smax.romanov@nginx.com nxt_pid_t app_pid; 45167Smax.romanov@nginx.com nxt_port_t *reply_port; 46167Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 47167Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 48167Smax.romanov@nginx.com 49167Smax.romanov@nginx.com nxt_queue_link_t link; /* for nxt_app_t.requests */ 50167Smax.romanov@nginx.com 51167Smax.romanov@nginx.com nxt_mp_t *mem_pool; 52167Smax.romanov@nginx.com nxt_work_t work; 53345Smax.romanov@nginx.com 54345Smax.romanov@nginx.com int err_code; 55345Smax.romanov@nginx.com const char *err_str; 56167Smax.romanov@nginx.com }; 57167Smax.romanov@nginx.com 58167Smax.romanov@nginx.com 59198Sigor@sysoev.ru typedef struct { 60198Sigor@sysoev.ru nxt_socket_conf_t *socket_conf; 61198Sigor@sysoev.ru nxt_router_temp_conf_t *temp_conf; 62198Sigor@sysoev.ru } nxt_socket_rpc_t; 63198Sigor@sysoev.ru 64198Sigor@sysoev.ru 65343Smax.romanov@nginx.com static nxt_int_t nxt_router_start_worker(nxt_task_t *task, nxt_app_t *app); 66343Smax.romanov@nginx.com 67345Smax.romanov@nginx.com static void nxt_router_ra_error(nxt_task_t *task, nxt_req_app_link_t *ra, 68345Smax.romanov@nginx.com int code, const char* str); 69345Smax.romanov@nginx.com 70139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task); 71198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data); 72198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task, 73139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 74139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task, 75139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 76139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task, 77193Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type); 7853Sigor@sysoev.ru static void nxt_router_listen_sockets_sort(nxt_router_t *router, 7953Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 8053Sigor@sysoev.ru 81115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task, 82115Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end); 83133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name); 84133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, 85133Sigor@sysoev.ru nxt_str_t *name); 86198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task, 87198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf); 88198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task, 89198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 90198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task, 91198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 9265Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, 9365Sigor@sysoev.ru nxt_sockaddr_t *sa); 9453Sigor@sysoev.ru 9553Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task, 9653Sigor@sysoev.ru nxt_router_t *router, nxt_router_temp_conf_t *tmcf, 9753Sigor@sysoev.ru const nxt_event_interface_t *interface); 98115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 99115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 100115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 101115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 102115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 103115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 104115Sigor@sysoev.ru static void nxt_router_engine_socket_count(nxt_queue_t *sockets); 105154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 106154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 107154Sigor@sysoev.ru nxt_work_handler_t handler); 108313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 109313Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 110139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 111139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets); 11253Sigor@sysoev.ru 11353Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 11453Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 11553Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 11653Sigor@sysoev.ru nxt_event_engine_t *engine); 117343Smax.romanov@nginx.com static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 118133Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 11953Sigor@sysoev.ru 120315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router, 121315Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 122315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine, 123315Sigor@sysoev.ru nxt_work_t *jobs); 12453Sigor@sysoev.ru 12553Sigor@sysoev.ru static void nxt_router_thread_start(void *data); 12653Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj, 12753Sigor@sysoev.ru void *data); 12853Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj, 12953Sigor@sysoev.ru void *data); 13053Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, 13153Sigor@sysoev.ru void *data); 132313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, 133313Sigor@sysoev.ru void *data); 13453Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj, 13553Sigor@sysoev.ru void *data); 13653Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task, 13753Sigor@sysoev.ru nxt_socket_conf_joint_t *joint); 13853Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, 13953Sigor@sysoev.ru void *data); 14053Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task, 14153Sigor@sysoev.ru nxt_socket_conf_joint_t *joint); 14253Sigor@sysoev.ru 143343Smax.romanov@nginx.com static void nxt_router_app_port_ready(nxt_task_t *task, 144343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 145343Smax.romanov@nginx.com static void nxt_router_app_port_error(nxt_task_t *task, 146343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 147343Smax.romanov@nginx.com 148343Smax.romanov@nginx.com static nxt_port_t * nxt_router_app_get_idle_port(nxt_app_t *app); 149343Smax.romanov@nginx.com static void nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port, 150343Smax.romanov@nginx.com uint32_t request_failed, uint32_t got_response); 151141Smax.romanov@nginx.com 15253Sigor@sysoev.ru static void nxt_router_conn_init(nxt_task_t *task, void *obj, void *data); 15353Sigor@sysoev.ru static void nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, 15453Sigor@sysoev.ru void *data); 155206Smax.romanov@nginx.com static void nxt_router_conn_http_body_read(nxt_task_t *task, void *obj, 156206Smax.romanov@nginx.com void *data); 15788Smax.romanov@nginx.com static void nxt_router_process_http_request(nxt_task_t *task, 15888Smax.romanov@nginx.com nxt_conn_t *c, nxt_app_parse_ctx_t *ap); 159141Smax.romanov@nginx.com static void nxt_router_process_http_request_mp(nxt_task_t *task, 160343Smax.romanov@nginx.com nxt_req_app_link_t *ra); 161216Sigor@sysoev.ru static nxt_int_t nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 162216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg); 163216Sigor@sysoev.ru static nxt_int_t nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 164216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg); 165216Sigor@sysoev.ru static nxt_int_t nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 166216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg); 16788Smax.romanov@nginx.com static void nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data); 16853Sigor@sysoev.ru static void nxt_router_conn_close(nxt_task_t *task, void *obj, void *data); 16953Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data); 17053Sigor@sysoev.ru static void nxt_router_conn_error(nxt_task_t *task, void *obj, void *data); 17153Sigor@sysoev.ru static void nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data); 172318Smax.romanov@nginx.com static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data); 17362Sigor@sysoev.ru static nxt_msec_t nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data); 17420Sigor@sysoev.ru 175141Smax.romanov@nginx.com static void nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code, 176345Smax.romanov@nginx.com const char* str); 177141Smax.romanov@nginx.com 178119Smax.romanov@nginx.com static nxt_router_t *nxt_router; 17920Sigor@sysoev.ru 180216Sigor@sysoev.ru 181216Sigor@sysoev.ru static nxt_app_prepare_msg_t nxt_app_prepare_msg[] = { 182216Sigor@sysoev.ru nxt_python_prepare_msg, 183216Sigor@sysoev.ru nxt_php_prepare_msg, 184216Sigor@sysoev.ru nxt_go_prepare_msg, 185216Sigor@sysoev.ru }; 186216Sigor@sysoev.ru 187216Sigor@sysoev.ru 18820Sigor@sysoev.ru nxt_int_t 189141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data) 19020Sigor@sysoev.ru { 191141Smax.romanov@nginx.com nxt_int_t ret; 192141Smax.romanov@nginx.com nxt_router_t *router; 193141Smax.romanov@nginx.com nxt_runtime_t *rt; 194141Smax.romanov@nginx.com 195141Smax.romanov@nginx.com rt = task->thread->runtime; 19653Sigor@sysoev.ru 19788Smax.romanov@nginx.com ret = nxt_app_http_init(task, rt); 19888Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 19988Smax.romanov@nginx.com return ret; 20088Smax.romanov@nginx.com } 20188Smax.romanov@nginx.com 20253Sigor@sysoev.ru router = nxt_zalloc(sizeof(nxt_router_t)); 20353Sigor@sysoev.ru if (nxt_slow_path(router == NULL)) { 20453Sigor@sysoev.ru return NXT_ERROR; 20553Sigor@sysoev.ru } 20653Sigor@sysoev.ru 20753Sigor@sysoev.ru nxt_queue_init(&router->engines); 20853Sigor@sysoev.ru nxt_queue_init(&router->sockets); 209133Sigor@sysoev.ru nxt_queue_init(&router->apps); 21053Sigor@sysoev.ru 211119Smax.romanov@nginx.com nxt_router = router; 212119Smax.romanov@nginx.com 213115Sigor@sysoev.ru return NXT_OK; 214115Sigor@sysoev.ru } 215115Sigor@sysoev.ru 216115Sigor@sysoev.ru 217343Smax.romanov@nginx.com static void 218343Smax.romanov@nginx.com nxt_router_start_worker_handler(nxt_task_t *task, nxt_port_t *port, void *data) 219167Smax.romanov@nginx.com { 220343Smax.romanov@nginx.com size_t size; 221343Smax.romanov@nginx.com uint32_t stream; 222343Smax.romanov@nginx.com nxt_app_t *app; 223343Smax.romanov@nginx.com nxt_buf_t *b; 224343Smax.romanov@nginx.com nxt_port_t *main_port; 225343Smax.romanov@nginx.com nxt_runtime_t *rt; 226343Smax.romanov@nginx.com 227343Smax.romanov@nginx.com app = data; 228167Smax.romanov@nginx.com 229167Smax.romanov@nginx.com rt = task->thread->runtime; 230240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 231167Smax.romanov@nginx.com 232343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start worker", &app->name, app); 233343Smax.romanov@nginx.com 234343Smax.romanov@nginx.com size = app->name.length + 1 + app->conf.length; 235343Smax.romanov@nginx.com 236343Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size); 237343Smax.romanov@nginx.com 238343Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 239343Smax.romanov@nginx.com goto failed; 240167Smax.romanov@nginx.com } 241167Smax.romanov@nginx.com 242343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->name); 243343Smax.romanov@nginx.com *b->mem.free++ = '\0'; 244343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 245343Smax.romanov@nginx.com 246343Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, port, 247343Smax.romanov@nginx.com nxt_router_app_port_ready, 248343Smax.romanov@nginx.com nxt_router_app_port_error, 249343Smax.romanov@nginx.com -1, app); 250343Smax.romanov@nginx.com 251343Smax.romanov@nginx.com if (nxt_slow_path(stream == 0)) { 252343Smax.romanov@nginx.com nxt_mp_release(b->data, b); 253343Smax.romanov@nginx.com 254343Smax.romanov@nginx.com goto failed; 255343Smax.romanov@nginx.com } 256343Smax.romanov@nginx.com 257343Smax.romanov@nginx.com nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1, 258343Smax.romanov@nginx.com stream, port->id, b); 259343Smax.romanov@nginx.com 260343Smax.romanov@nginx.com return; 261343Smax.romanov@nginx.com 262343Smax.romanov@nginx.com failed: 263343Smax.romanov@nginx.com 264343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 265343Smax.romanov@nginx.com 266343Smax.romanov@nginx.com app->pending_workers--; 267343Smax.romanov@nginx.com 268343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 269343Smax.romanov@nginx.com 270343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 271167Smax.romanov@nginx.com } 272167Smax.romanov@nginx.com 273167Smax.romanov@nginx.com 274343Smax.romanov@nginx.com static nxt_int_t 275343Smax.romanov@nginx.com nxt_router_start_worker(nxt_task_t *task, nxt_app_t *app) 276141Smax.romanov@nginx.com { 277343Smax.romanov@nginx.com nxt_int_t res; 278343Smax.romanov@nginx.com nxt_port_t *router_port; 279343Smax.romanov@nginx.com nxt_runtime_t *rt; 280343Smax.romanov@nginx.com 281343Smax.romanov@nginx.com rt = task->thread->runtime; 282343Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 283343Smax.romanov@nginx.com 284343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 285343Smax.romanov@nginx.com 286343Smax.romanov@nginx.com res = nxt_port_post(task, router_port, nxt_router_start_worker_handler, 287343Smax.romanov@nginx.com app); 288343Smax.romanov@nginx.com 289343Smax.romanov@nginx.com if (res == NXT_OK) { 290343Smax.romanov@nginx.com return res; 291318Smax.romanov@nginx.com } 292318Smax.romanov@nginx.com 293343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 294343Smax.romanov@nginx.com 295343Smax.romanov@nginx.com app->pending_workers--; 296343Smax.romanov@nginx.com 297343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 298343Smax.romanov@nginx.com 299343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 300343Smax.romanov@nginx.com 301343Smax.romanov@nginx.com return NXT_ERROR; 302318Smax.romanov@nginx.com } 303318Smax.romanov@nginx.com 304318Smax.romanov@nginx.com 305*351Smax.romanov@nginx.com nxt_inline void 306*351Smax.romanov@nginx.com nxt_router_ra_init(nxt_task_t *task, nxt_req_app_link_t *ra, 307*351Smax.romanov@nginx.com nxt_req_conn_link_t *rc) 308167Smax.romanov@nginx.com { 309318Smax.romanov@nginx.com nxt_event_engine_t *engine; 310*351Smax.romanov@nginx.com 311318Smax.romanov@nginx.com engine = task->thread->engine; 312167Smax.romanov@nginx.com 313167Smax.romanov@nginx.com nxt_memzero(ra, sizeof(nxt_req_app_link_t)); 314167Smax.romanov@nginx.com 315318Smax.romanov@nginx.com ra->stream = rc->stream; 316318Smax.romanov@nginx.com ra->app_pid = -1; 317167Smax.romanov@nginx.com ra->rc = rc; 318318Smax.romanov@nginx.com rc->ra = ra; 319318Smax.romanov@nginx.com ra->reply_port = engine->port; 320*351Smax.romanov@nginx.com ra->ap = rc->ap; 321167Smax.romanov@nginx.com 322167Smax.romanov@nginx.com ra->work.handler = NULL; 323318Smax.romanov@nginx.com ra->work.task = &engine->task; 324167Smax.romanov@nginx.com ra->work.obj = ra; 325318Smax.romanov@nginx.com ra->work.data = engine; 326*351Smax.romanov@nginx.com } 327*351Smax.romanov@nginx.com 328*351Smax.romanov@nginx.com 329*351Smax.romanov@nginx.com nxt_inline nxt_req_app_link_t * 330*351Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_app_link_t *ra_src) 331*351Smax.romanov@nginx.com { 332*351Smax.romanov@nginx.com nxt_mp_t *mp; 333*351Smax.romanov@nginx.com nxt_req_app_link_t *ra; 334*351Smax.romanov@nginx.com 335*351Smax.romanov@nginx.com mp = ra_src->ap->mem_pool; 336*351Smax.romanov@nginx.com 337*351Smax.romanov@nginx.com ra = nxt_mp_retain(mp, sizeof(nxt_req_app_link_t)); 338*351Smax.romanov@nginx.com 339*351Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 340*351Smax.romanov@nginx.com 341*351Smax.romanov@nginx.com ra_src->rc->ra = NULL; 342*351Smax.romanov@nginx.com ra_src->rc = NULL; 343*351Smax.romanov@nginx.com 344*351Smax.romanov@nginx.com return NULL; 345*351Smax.romanov@nginx.com } 346*351Smax.romanov@nginx.com 347*351Smax.romanov@nginx.com nxt_router_ra_init(task, ra, ra_src->rc); 348*351Smax.romanov@nginx.com 349*351Smax.romanov@nginx.com ra->mem_pool = mp; 350167Smax.romanov@nginx.com 351167Smax.romanov@nginx.com return ra; 352167Smax.romanov@nginx.com } 353167Smax.romanov@nginx.com 354167Smax.romanov@nginx.com 355167Smax.romanov@nginx.com static void 356167Smax.romanov@nginx.com nxt_router_ra_release(nxt_task_t *task, void *obj, void *data) 357167Smax.romanov@nginx.com { 358343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 359343Smax.romanov@nginx.com nxt_event_engine_t *engine; 360343Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 361318Smax.romanov@nginx.com 362318Smax.romanov@nginx.com ra = obj; 363318Smax.romanov@nginx.com engine = data; 364318Smax.romanov@nginx.com 365343Smax.romanov@nginx.com if (task->thread->engine != engine) { 366343Smax.romanov@nginx.com if (ra->app_port != NULL) { 367343Smax.romanov@nginx.com ra->app_pid = ra->app_port->pid; 368318Smax.romanov@nginx.com } 369318Smax.romanov@nginx.com 370318Smax.romanov@nginx.com ra->work.handler = nxt_router_ra_release; 371318Smax.romanov@nginx.com ra->work.task = &engine->task; 372318Smax.romanov@nginx.com ra->work.next = NULL; 373318Smax.romanov@nginx.com 374318Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD post release to %p", 375318Smax.romanov@nginx.com ra->stream, engine); 376318Smax.romanov@nginx.com 377318Smax.romanov@nginx.com nxt_event_engine_post(engine, &ra->work); 378318Smax.romanov@nginx.com 379318Smax.romanov@nginx.com return; 380318Smax.romanov@nginx.com } 381318Smax.romanov@nginx.com 382343Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD release", ra->stream); 383343Smax.romanov@nginx.com 384343Smax.romanov@nginx.com rc = ra->rc; 385343Smax.romanov@nginx.com 386343Smax.romanov@nginx.com if (rc != NULL) { 387343Smax.romanov@nginx.com if (ra->app_pid != -1) { 388343Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, engine->port, rc, ra->app_pid); 389343Smax.romanov@nginx.com } 390343Smax.romanov@nginx.com 391343Smax.romanov@nginx.com rc->app_port = ra->app_port; 392343Smax.romanov@nginx.com 393343Smax.romanov@nginx.com ra->app_port = NULL; 394343Smax.romanov@nginx.com rc->ra = NULL; 395343Smax.romanov@nginx.com ra->rc = NULL; 396318Smax.romanov@nginx.com } 397318Smax.romanov@nginx.com 398343Smax.romanov@nginx.com if (ra->app_port != NULL) { 399343Smax.romanov@nginx.com nxt_router_app_port_release(task, ra->app_port, 0, 1); 400343Smax.romanov@nginx.com 401343Smax.romanov@nginx.com ra->app_port = NULL; 402343Smax.romanov@nginx.com } 403318Smax.romanov@nginx.com 404*351Smax.romanov@nginx.com if (ra->mem_pool != NULL) { 405*351Smax.romanov@nginx.com nxt_mp_release(ra->mem_pool, ra); 406*351Smax.romanov@nginx.com } 407318Smax.romanov@nginx.com } 408318Smax.romanov@nginx.com 409318Smax.romanov@nginx.com 410318Smax.romanov@nginx.com static void 411318Smax.romanov@nginx.com nxt_router_ra_abort(nxt_task_t *task, void *obj, void *data) 412318Smax.romanov@nginx.com { 413343Smax.romanov@nginx.com nxt_conn_t *c; 414343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 415343Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 416343Smax.romanov@nginx.com nxt_event_engine_t *engine; 417167Smax.romanov@nginx.com 418167Smax.romanov@nginx.com ra = obj; 419167Smax.romanov@nginx.com engine = data; 420167Smax.romanov@nginx.com 421167Smax.romanov@nginx.com if (task->thread->engine != engine) { 422318Smax.romanov@nginx.com ra->work.handler = nxt_router_ra_abort; 423167Smax.romanov@nginx.com ra->work.task = &engine->task; 424167Smax.romanov@nginx.com ra->work.next = NULL; 425167Smax.romanov@nginx.com 426318Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD post abort to %p", ra->stream, engine); 427167Smax.romanov@nginx.com 428167Smax.romanov@nginx.com nxt_event_engine_post(engine, &ra->work); 429167Smax.romanov@nginx.com 430167Smax.romanov@nginx.com return; 431167Smax.romanov@nginx.com } 432167Smax.romanov@nginx.com 433318Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD abort", ra->stream); 434318Smax.romanov@nginx.com 435343Smax.romanov@nginx.com rc = ra->rc; 436343Smax.romanov@nginx.com 437343Smax.romanov@nginx.com if (rc != NULL) { 438343Smax.romanov@nginx.com c = rc->conn; 439318Smax.romanov@nginx.com 440318Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, 441318Smax.romanov@nginx.com "Failed to start application worker"); 442343Smax.romanov@nginx.com 443343Smax.romanov@nginx.com rc->ra = NULL; 444343Smax.romanov@nginx.com ra->rc = NULL; 445343Smax.romanov@nginx.com } 446343Smax.romanov@nginx.com 447343Smax.romanov@nginx.com if (ra->app_port != NULL) { 448343Smax.romanov@nginx.com nxt_router_app_port_release(task, ra->app_port, 0, 1); 449343Smax.romanov@nginx.com 450343Smax.romanov@nginx.com ra->app_port = NULL; 451167Smax.romanov@nginx.com } 452167Smax.romanov@nginx.com 453*351Smax.romanov@nginx.com if (ra->mem_pool != NULL) { 454*351Smax.romanov@nginx.com nxt_mp_release(ra->mem_pool, ra); 455*351Smax.romanov@nginx.com } 456167Smax.romanov@nginx.com } 457167Smax.romanov@nginx.com 458167Smax.romanov@nginx.com 459345Smax.romanov@nginx.com static void 460345Smax.romanov@nginx.com nxt_router_ra_error_handler(nxt_task_t *task, void *obj, void *data) 461345Smax.romanov@nginx.com { 462345Smax.romanov@nginx.com nxt_req_app_link_t *ra; 463345Smax.romanov@nginx.com 464345Smax.romanov@nginx.com ra = obj; 465345Smax.romanov@nginx.com 466345Smax.romanov@nginx.com nxt_router_ra_error(task, ra, ra->err_code, ra->err_str); 467345Smax.romanov@nginx.com } 468345Smax.romanov@nginx.com 469345Smax.romanov@nginx.com 470345Smax.romanov@nginx.com static void 471345Smax.romanov@nginx.com nxt_router_ra_error(nxt_task_t *task, nxt_req_app_link_t *ra, int code, 472345Smax.romanov@nginx.com const char* str) 473345Smax.romanov@nginx.com { 474345Smax.romanov@nginx.com nxt_conn_t *c; 475345Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 476345Smax.romanov@nginx.com nxt_event_engine_t *engine; 477345Smax.romanov@nginx.com 478345Smax.romanov@nginx.com engine = ra->work.data; 479345Smax.romanov@nginx.com 480345Smax.romanov@nginx.com if (task->thread->engine != engine) { 481345Smax.romanov@nginx.com ra->err_code = code; 482345Smax.romanov@nginx.com ra->err_str = str; 483345Smax.romanov@nginx.com 484345Smax.romanov@nginx.com ra->work.handler = nxt_router_ra_error_handler; 485345Smax.romanov@nginx.com ra->work.task = &engine->task; 486345Smax.romanov@nginx.com ra->work.next = NULL; 487345Smax.romanov@nginx.com 488345Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD post error to %p", ra->stream, engine); 489345Smax.romanov@nginx.com 490345Smax.romanov@nginx.com nxt_event_engine_post(engine, &ra->work); 491345Smax.romanov@nginx.com 492345Smax.romanov@nginx.com return; 493345Smax.romanov@nginx.com } 494345Smax.romanov@nginx.com 495345Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD error", ra->stream); 496345Smax.romanov@nginx.com 497345Smax.romanov@nginx.com rc = ra->rc; 498345Smax.romanov@nginx.com 499345Smax.romanov@nginx.com if (rc != NULL) { 500345Smax.romanov@nginx.com c = rc->conn; 501345Smax.romanov@nginx.com 502345Smax.romanov@nginx.com nxt_router_gen_error(task, c, code, str); 503345Smax.romanov@nginx.com 504345Smax.romanov@nginx.com rc->ra = NULL; 505345Smax.romanov@nginx.com ra->rc = NULL; 506345Smax.romanov@nginx.com } 507345Smax.romanov@nginx.com 508345Smax.romanov@nginx.com if (ra->app_port != NULL) { 509345Smax.romanov@nginx.com nxt_router_app_port_release(task, ra->app_port, 0, 1); 510345Smax.romanov@nginx.com 511345Smax.romanov@nginx.com ra->app_port = NULL; 512345Smax.romanov@nginx.com } 513345Smax.romanov@nginx.com 514*351Smax.romanov@nginx.com if (ra->mem_pool != NULL) { 515*351Smax.romanov@nginx.com nxt_mp_release(ra->mem_pool, ra); 516*351Smax.romanov@nginx.com } 517345Smax.romanov@nginx.com } 518345Smax.romanov@nginx.com 519345Smax.romanov@nginx.com 520343Smax.romanov@nginx.com nxt_inline void 521343Smax.romanov@nginx.com nxt_router_rc_unlink(nxt_task_t *task, nxt_req_conn_link_t *rc) 522343Smax.romanov@nginx.com { 523343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 524343Smax.romanov@nginx.com 525343Smax.romanov@nginx.com if (rc->app_port != NULL) { 526343Smax.romanov@nginx.com nxt_router_app_port_release(task, rc->app_port, 0, 1); 527343Smax.romanov@nginx.com 528343Smax.romanov@nginx.com rc->app_port = NULL; 529343Smax.romanov@nginx.com } 530343Smax.romanov@nginx.com 531343Smax.romanov@nginx.com ra = rc->ra; 532343Smax.romanov@nginx.com 533343Smax.romanov@nginx.com if (ra != NULL) { 534343Smax.romanov@nginx.com rc->ra = NULL; 535343Smax.romanov@nginx.com ra->rc = NULL; 536343Smax.romanov@nginx.com 537343Smax.romanov@nginx.com nxt_thread_mutex_lock(&rc->app->mutex); 538343Smax.romanov@nginx.com 539343Smax.romanov@nginx.com if (ra->link.next != NULL) { 540343Smax.romanov@nginx.com nxt_queue_remove(&ra->link); 541343Smax.romanov@nginx.com 542343Smax.romanov@nginx.com ra->link.next = NULL; 543343Smax.romanov@nginx.com 544343Smax.romanov@nginx.com } else { 545343Smax.romanov@nginx.com ra = NULL; 546343Smax.romanov@nginx.com } 547343Smax.romanov@nginx.com 548343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&rc->app->mutex); 549343Smax.romanov@nginx.com } 550343Smax.romanov@nginx.com 551343Smax.romanov@nginx.com if (ra != NULL) { 552343Smax.romanov@nginx.com nxt_router_ra_release(task, ra, ra->work.data); 553343Smax.romanov@nginx.com } 554343Smax.romanov@nginx.com 555343Smax.romanov@nginx.com if (rc->app != NULL) { 556343Smax.romanov@nginx.com nxt_router_app_use(task, rc->app, -1); 557343Smax.romanov@nginx.com 558343Smax.romanov@nginx.com rc->app = NULL; 559343Smax.romanov@nginx.com } 560343Smax.romanov@nginx.com 561346Smax.romanov@nginx.com if (rc->ap != NULL) { 562346Smax.romanov@nginx.com nxt_app_http_req_done(task, rc->ap); 563346Smax.romanov@nginx.com 564346Smax.romanov@nginx.com rc->ap = NULL; 565346Smax.romanov@nginx.com } 566346Smax.romanov@nginx.com 567343Smax.romanov@nginx.com nxt_queue_remove(&rc->link); 568343Smax.romanov@nginx.com 569343Smax.romanov@nginx.com rc->conn = NULL; 570343Smax.romanov@nginx.com } 571343Smax.romanov@nginx.com 572343Smax.romanov@nginx.com 573141Smax.romanov@nginx.com void 574141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 575141Smax.romanov@nginx.com { 576141Smax.romanov@nginx.com nxt_port_new_port_handler(task, msg); 577141Smax.romanov@nginx.com 578192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 579141Smax.romanov@nginx.com return; 580141Smax.romanov@nginx.com } 581141Smax.romanov@nginx.com 582347Smax.romanov@nginx.com if (msg->u.new_port == NULL || 583347Smax.romanov@nginx.com msg->u.new_port->type != NXT_PROCESS_WORKER) 584347Smax.romanov@nginx.com { 585192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 586141Smax.romanov@nginx.com } 587192Smax.romanov@nginx.com 588192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 589141Smax.romanov@nginx.com } 590141Smax.romanov@nginx.com 591141Smax.romanov@nginx.com 592139Sigor@sysoev.ru void 593139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 594115Sigor@sysoev.ru { 595139Sigor@sysoev.ru size_t dump_size; 596198Sigor@sysoev.ru nxt_int_t ret; 597139Sigor@sysoev.ru nxt_buf_t *b; 598139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 599139Sigor@sysoev.ru 600139Sigor@sysoev.ru b = msg->buf; 601139Sigor@sysoev.ru 602139Sigor@sysoev.ru dump_size = nxt_buf_used_size(b); 603139Sigor@sysoev.ru 604139Sigor@sysoev.ru if (dump_size > 300) { 605139Sigor@sysoev.ru dump_size = 300; 60653Sigor@sysoev.ru } 60753Sigor@sysoev.ru 608139Sigor@sysoev.ru nxt_debug(task, "router conf data (%z): %*s", 609139Sigor@sysoev.ru msg->size, dump_size, b->mem.pos); 610139Sigor@sysoev.ru 611139Sigor@sysoev.ru tmcf = nxt_router_temp_conf(task); 612139Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 613139Sigor@sysoev.ru return; 61453Sigor@sysoev.ru } 61553Sigor@sysoev.ru 616139Sigor@sysoev.ru tmcf->conf->router = nxt_router; 617139Sigor@sysoev.ru tmcf->stream = msg->port_msg.stream; 618139Sigor@sysoev.ru tmcf->port = nxt_runtime_port_find(task->thread->runtime, 619198Sigor@sysoev.ru msg->port_msg.pid, 620198Sigor@sysoev.ru msg->port_msg.reply_port); 621198Sigor@sysoev.ru 622198Sigor@sysoev.ru ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free); 623198Sigor@sysoev.ru 624198Sigor@sysoev.ru if (nxt_fast_path(ret == NXT_OK)) { 625198Sigor@sysoev.ru nxt_router_conf_apply(task, tmcf, NULL); 626198Sigor@sysoev.ru 627198Sigor@sysoev.ru } else { 628198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 629139Sigor@sysoev.ru } 63053Sigor@sysoev.ru } 63153Sigor@sysoev.ru 63253Sigor@sysoev.ru 633347Smax.romanov@nginx.com static void 634347Smax.romanov@nginx.com nxt_router_worker_remove_pid(nxt_task_t *task, nxt_port_t *port, void *data) 635347Smax.romanov@nginx.com { 636347Smax.romanov@nginx.com union { 637347Smax.romanov@nginx.com nxt_pid_t removed_pid; 638347Smax.romanov@nginx.com void *data; 639347Smax.romanov@nginx.com } u; 640347Smax.romanov@nginx.com 641347Smax.romanov@nginx.com u.data = data; 642347Smax.romanov@nginx.com 643347Smax.romanov@nginx.com nxt_port_rpc_remove_peer(task, port, u.removed_pid); 644347Smax.romanov@nginx.com } 645347Smax.romanov@nginx.com 646347Smax.romanov@nginx.com 647192Smax.romanov@nginx.com void 648192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 649192Smax.romanov@nginx.com { 650347Smax.romanov@nginx.com nxt_event_engine_t *engine; 651318Smax.romanov@nginx.com 652192Smax.romanov@nginx.com nxt_port_remove_pid_handler(task, msg); 653192Smax.romanov@nginx.com 654192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 655192Smax.romanov@nginx.com return; 656192Smax.romanov@nginx.com } 657192Smax.romanov@nginx.com 658318Smax.romanov@nginx.com nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0) 659318Smax.romanov@nginx.com { 660347Smax.romanov@nginx.com nxt_port_post(task, engine->port, nxt_router_worker_remove_pid, 661347Smax.romanov@nginx.com msg->u.data); 662318Smax.romanov@nginx.com } 663318Smax.romanov@nginx.com nxt_queue_loop; 664318Smax.romanov@nginx.com 665192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 666192Smax.romanov@nginx.com 667192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 668192Smax.romanov@nginx.com } 669192Smax.romanov@nginx.com 670192Smax.romanov@nginx.com 67153Sigor@sysoev.ru static nxt_router_temp_conf_t * 672139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task) 67353Sigor@sysoev.ru { 67465Sigor@sysoev.ru nxt_mp_t *mp, *tmp; 67553Sigor@sysoev.ru nxt_router_conf_t *rtcf; 67653Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 67753Sigor@sysoev.ru 67865Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 67953Sigor@sysoev.ru if (nxt_slow_path(mp == NULL)) { 68053Sigor@sysoev.ru return NULL; 68153Sigor@sysoev.ru } 68253Sigor@sysoev.ru 68365Sigor@sysoev.ru rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t)); 68453Sigor@sysoev.ru if (nxt_slow_path(rtcf == NULL)) { 68553Sigor@sysoev.ru goto fail; 68653Sigor@sysoev.ru } 68753Sigor@sysoev.ru 68853Sigor@sysoev.ru rtcf->mem_pool = mp; 68953Sigor@sysoev.ru 69065Sigor@sysoev.ru tmp = nxt_mp_create(1024, 128, 256, 32); 69153Sigor@sysoev.ru if (nxt_slow_path(tmp == NULL)) { 69253Sigor@sysoev.ru goto fail; 69353Sigor@sysoev.ru } 69453Sigor@sysoev.ru 69565Sigor@sysoev.ru tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t)); 69653Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 69753Sigor@sysoev.ru goto temp_fail; 69853Sigor@sysoev.ru } 69953Sigor@sysoev.ru 70053Sigor@sysoev.ru tmcf->mem_pool = tmp; 70153Sigor@sysoev.ru tmcf->conf = rtcf; 702139Sigor@sysoev.ru tmcf->count = 1; 703139Sigor@sysoev.ru tmcf->engine = task->thread->engine; 70453Sigor@sysoev.ru 70553Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, 4, 70653Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 70753Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 70853Sigor@sysoev.ru goto temp_fail; 70953Sigor@sysoev.ru } 71053Sigor@sysoev.ru 71153Sigor@sysoev.ru nxt_queue_init(&tmcf->deleting); 71253Sigor@sysoev.ru nxt_queue_init(&tmcf->keeping); 71353Sigor@sysoev.ru nxt_queue_init(&tmcf->updating); 71453Sigor@sysoev.ru nxt_queue_init(&tmcf->pending); 71553Sigor@sysoev.ru nxt_queue_init(&tmcf->creating); 716133Sigor@sysoev.ru nxt_queue_init(&tmcf->apps); 717133Sigor@sysoev.ru nxt_queue_init(&tmcf->previous); 71853Sigor@sysoev.ru 71953Sigor@sysoev.ru return tmcf; 72053Sigor@sysoev.ru 72153Sigor@sysoev.ru temp_fail: 72253Sigor@sysoev.ru 72365Sigor@sysoev.ru nxt_mp_destroy(tmp); 72453Sigor@sysoev.ru 72553Sigor@sysoev.ru fail: 72653Sigor@sysoev.ru 72765Sigor@sysoev.ru nxt_mp_destroy(mp); 72853Sigor@sysoev.ru 72953Sigor@sysoev.ru return NULL; 73053Sigor@sysoev.ru } 73153Sigor@sysoev.ru 73253Sigor@sysoev.ru 733198Sigor@sysoev.ru static void 734198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data) 735139Sigor@sysoev.ru { 736139Sigor@sysoev.ru nxt_int_t ret; 737139Sigor@sysoev.ru nxt_router_t *router; 738139Sigor@sysoev.ru nxt_runtime_t *rt; 739198Sigor@sysoev.ru nxt_queue_link_t *qlk; 740198Sigor@sysoev.ru nxt_socket_conf_t *skcf; 741198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 742139Sigor@sysoev.ru const nxt_event_interface_t *interface; 743139Sigor@sysoev.ru 744198Sigor@sysoev.ru tmcf = obj; 745198Sigor@sysoev.ru 746198Sigor@sysoev.ru qlk = nxt_queue_first(&tmcf->pending); 747198Sigor@sysoev.ru 748198Sigor@sysoev.ru if (qlk != nxt_queue_tail(&tmcf->pending)) { 749198Sigor@sysoev.ru nxt_queue_remove(qlk); 750198Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->creating, qlk); 751198Sigor@sysoev.ru 752198Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 753198Sigor@sysoev.ru 754198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(task, tmcf, skcf); 755198Sigor@sysoev.ru 756198Sigor@sysoev.ru return; 757139Sigor@sysoev.ru } 758139Sigor@sysoev.ru 759139Sigor@sysoev.ru rt = task->thread->runtime; 760139Sigor@sysoev.ru 761139Sigor@sysoev.ru interface = nxt_service_get(rt->services, "engine", NULL); 762139Sigor@sysoev.ru 763198Sigor@sysoev.ru router = tmcf->conf->router; 764198Sigor@sysoev.ru 765139Sigor@sysoev.ru ret = nxt_router_engines_create(task, router, tmcf, interface); 766139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 767198Sigor@sysoev.ru goto fail; 768139Sigor@sysoev.ru } 769139Sigor@sysoev.ru 770139Sigor@sysoev.ru ret = nxt_router_threads_create(task, rt, tmcf); 771139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 772198Sigor@sysoev.ru goto fail; 773139Sigor@sysoev.ru } 774139Sigor@sysoev.ru 775343Smax.romanov@nginx.com nxt_router_apps_sort(task, router, tmcf); 776139Sigor@sysoev.ru 777315Sigor@sysoev.ru nxt_router_engines_post(router, tmcf); 778139Sigor@sysoev.ru 779139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->updating); 780139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->creating); 781139Sigor@sysoev.ru 782198Sigor@sysoev.ru nxt_router_conf_ready(task, tmcf); 783198Sigor@sysoev.ru 784198Sigor@sysoev.ru return; 785198Sigor@sysoev.ru 786198Sigor@sysoev.ru fail: 787198Sigor@sysoev.ru 788198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 789198Sigor@sysoev.ru 790198Sigor@sysoev.ru return; 791139Sigor@sysoev.ru } 792139Sigor@sysoev.ru 793139Sigor@sysoev.ru 794139Sigor@sysoev.ru static void 795139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data) 796139Sigor@sysoev.ru { 797153Sigor@sysoev.ru nxt_joint_job_t *job; 798153Sigor@sysoev.ru 799153Sigor@sysoev.ru job = obj; 800153Sigor@sysoev.ru 801198Sigor@sysoev.ru nxt_router_conf_ready(task, job->tmcf); 802139Sigor@sysoev.ru } 803139Sigor@sysoev.ru 804139Sigor@sysoev.ru 805139Sigor@sysoev.ru static void 806198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 807139Sigor@sysoev.ru { 808139Sigor@sysoev.ru nxt_debug(task, "temp conf count:%D", tmcf->count); 809139Sigor@sysoev.ru 810139Sigor@sysoev.ru if (--tmcf->count == 0) { 811193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST); 812139Sigor@sysoev.ru } 813139Sigor@sysoev.ru } 814139Sigor@sysoev.ru 815139Sigor@sysoev.ru 816139Sigor@sysoev.ru static void 817139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 818139Sigor@sysoev.ru { 819148Sigor@sysoev.ru nxt_socket_t s; 820149Sigor@sysoev.ru nxt_router_t *router; 821148Sigor@sysoev.ru nxt_queue_link_t *qlk; 822148Sigor@sysoev.ru nxt_socket_conf_t *skcf; 823148Sigor@sysoev.ru 824198Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "failed to apply new conf"); 825198Sigor@sysoev.ru 826148Sigor@sysoev.ru for (qlk = nxt_queue_first(&tmcf->creating); 827148Sigor@sysoev.ru qlk != nxt_queue_tail(&tmcf->creating); 828148Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 829148Sigor@sysoev.ru { 830148Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 831148Sigor@sysoev.ru s = skcf->listen.socket; 832148Sigor@sysoev.ru 833148Sigor@sysoev.ru if (s != -1) { 834148Sigor@sysoev.ru nxt_socket_close(task, s); 835148Sigor@sysoev.ru } 836148Sigor@sysoev.ru 837148Sigor@sysoev.ru nxt_free(skcf->socket); 838148Sigor@sysoev.ru } 839148Sigor@sysoev.ru 840149Sigor@sysoev.ru router = tmcf->conf->router; 841149Sigor@sysoev.ru 842149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->keeping); 843149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->deleting); 844149Sigor@sysoev.ru 845148Sigor@sysoev.ru // TODO: new engines and threads 846148Sigor@sysoev.ru 847139Sigor@sysoev.ru nxt_mp_destroy(tmcf->conf->mem_pool); 848139Sigor@sysoev.ru 849193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR); 850139Sigor@sysoev.ru } 851139Sigor@sysoev.ru 852139Sigor@sysoev.ru 853139Sigor@sysoev.ru static void 854139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 855193Smax.romanov@nginx.com nxt_port_msg_type_t type) 856139Sigor@sysoev.ru { 857193Smax.romanov@nginx.com nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL); 858139Sigor@sysoev.ru } 859139Sigor@sysoev.ru 860139Sigor@sysoev.ru 861115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_conf[] = { 862115Sigor@sysoev.ru { 863133Sigor@sysoev.ru nxt_string("listeners_threads"), 864115Sigor@sysoev.ru NXT_CONF_MAP_INT32, 865115Sigor@sysoev.ru offsetof(nxt_router_conf_t, threads), 866115Sigor@sysoev.ru }, 867115Sigor@sysoev.ru }; 868115Sigor@sysoev.ru 869115Sigor@sysoev.ru 870133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_app_conf[] = { 871115Sigor@sysoev.ru { 872133Sigor@sysoev.ru nxt_string("type"), 873115Sigor@sysoev.ru NXT_CONF_MAP_STR, 874133Sigor@sysoev.ru offsetof(nxt_router_app_conf_t, type), 875115Sigor@sysoev.ru }, 876115Sigor@sysoev.ru 877115Sigor@sysoev.ru { 878133Sigor@sysoev.ru nxt_string("workers"), 879115Sigor@sysoev.ru NXT_CONF_MAP_INT32, 880133Sigor@sysoev.ru offsetof(nxt_router_app_conf_t, workers), 881133Sigor@sysoev.ru }, 882318Smax.romanov@nginx.com 883318Smax.romanov@nginx.com { 884318Smax.romanov@nginx.com nxt_string("limits"), 885318Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 886318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, limits_value), 887318Smax.romanov@nginx.com }, 888318Smax.romanov@nginx.com }; 889318Smax.romanov@nginx.com 890318Smax.romanov@nginx.com 891318Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_limits_conf[] = { 892318Smax.romanov@nginx.com { 893318Smax.romanov@nginx.com nxt_string("timeout"), 894318Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 895318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, timeout), 896318Smax.romanov@nginx.com }, 897318Smax.romanov@nginx.com 898318Smax.romanov@nginx.com { 899318Smax.romanov@nginx.com nxt_string("requests"), 900318Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 901318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, requests), 902318Smax.romanov@nginx.com }, 903133Sigor@sysoev.ru }; 904133Sigor@sysoev.ru 905133Sigor@sysoev.ru 906133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_listener_conf[] = { 907133Sigor@sysoev.ru { 908133Sigor@sysoev.ru nxt_string("application"), 909133Sigor@sysoev.ru NXT_CONF_MAP_STR, 910133Sigor@sysoev.ru offsetof(nxt_router_listener_conf_t, application), 911115Sigor@sysoev.ru }, 912115Sigor@sysoev.ru }; 913115Sigor@sysoev.ru 914115Sigor@sysoev.ru 915115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_http_conf[] = { 916115Sigor@sysoev.ru { 917115Sigor@sysoev.ru nxt_string("header_buffer_size"), 918115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 919115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_buffer_size), 920115Sigor@sysoev.ru }, 921115Sigor@sysoev.ru 922115Sigor@sysoev.ru { 923115Sigor@sysoev.ru nxt_string("large_header_buffer_size"), 924115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 925115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, large_header_buffer_size), 926115Sigor@sysoev.ru }, 927115Sigor@sysoev.ru 928115Sigor@sysoev.ru { 929206Smax.romanov@nginx.com nxt_string("large_header_buffers"), 930206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 931206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, large_header_buffers), 932206Smax.romanov@nginx.com }, 933206Smax.romanov@nginx.com 934206Smax.romanov@nginx.com { 935206Smax.romanov@nginx.com nxt_string("body_buffer_size"), 936206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 937206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_buffer_size), 938206Smax.romanov@nginx.com }, 939206Smax.romanov@nginx.com 940206Smax.romanov@nginx.com { 941206Smax.romanov@nginx.com nxt_string("max_body_size"), 942206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 943206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, max_body_size), 944206Smax.romanov@nginx.com }, 945206Smax.romanov@nginx.com 946206Smax.romanov@nginx.com { 947115Sigor@sysoev.ru nxt_string("header_read_timeout"), 948115Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 949115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_read_timeout), 950115Sigor@sysoev.ru }, 951206Smax.romanov@nginx.com 952206Smax.romanov@nginx.com { 953206Smax.romanov@nginx.com nxt_string("body_read_timeout"), 954206Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 955206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_read_timeout), 956206Smax.romanov@nginx.com }, 957115Sigor@sysoev.ru }; 958115Sigor@sysoev.ru 959115Sigor@sysoev.ru 96053Sigor@sysoev.ru static nxt_int_t 961115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 962115Sigor@sysoev.ru u_char *start, u_char *end) 96353Sigor@sysoev.ru { 964133Sigor@sysoev.ru u_char *p; 965133Sigor@sysoev.ru size_t size; 966115Sigor@sysoev.ru nxt_mp_t *mp; 967115Sigor@sysoev.ru uint32_t next; 968115Sigor@sysoev.ru nxt_int_t ret; 969115Sigor@sysoev.ru nxt_str_t name; 970133Sigor@sysoev.ru nxt_app_t *app, *prev; 971133Sigor@sysoev.ru nxt_app_type_t type; 972115Sigor@sysoev.ru nxt_sockaddr_t *sa; 973133Sigor@sysoev.ru nxt_conf_value_t *conf, *http; 974133Sigor@sysoev.ru nxt_conf_value_t *applications, *application; 975133Sigor@sysoev.ru nxt_conf_value_t *listeners, *listener; 976115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 977216Sigor@sysoev.ru nxt_app_lang_module_t *lang; 978133Sigor@sysoev.ru nxt_router_app_conf_t apcf; 979115Sigor@sysoev.ru nxt_router_listener_conf_t lscf; 980115Sigor@sysoev.ru 981115Sigor@sysoev.ru static nxt_str_t http_path = nxt_string("/http"); 982133Sigor@sysoev.ru static nxt_str_t applications_path = nxt_string("/applications"); 983115Sigor@sysoev.ru static nxt_str_t listeners_path = nxt_string("/listeners"); 984115Sigor@sysoev.ru 985208Svbart@nginx.com conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL); 986115Sigor@sysoev.ru if (conf == NULL) { 987115Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "configuration parsing error"); 988115Sigor@sysoev.ru return NXT_ERROR; 989115Sigor@sysoev.ru } 990115Sigor@sysoev.ru 991213Svbart@nginx.com mp = tmcf->conf->mem_pool; 992213Svbart@nginx.com 993213Svbart@nginx.com ret = nxt_conf_map_object(mp, conf, nxt_router_conf, 994136Svbart@nginx.com nxt_nitems(nxt_router_conf), tmcf->conf); 995115Sigor@sysoev.ru if (ret != NXT_OK) { 996133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "root map error"); 997115Sigor@sysoev.ru return NXT_ERROR; 998115Sigor@sysoev.ru } 999115Sigor@sysoev.ru 1000117Sigor@sysoev.ru if (tmcf->conf->threads == 0) { 1001117Sigor@sysoev.ru tmcf->conf->threads = nxt_ncpu; 1002117Sigor@sysoev.ru } 1003117Sigor@sysoev.ru 1004133Sigor@sysoev.ru applications = nxt_conf_get_path(conf, &applications_path); 1005133Sigor@sysoev.ru if (applications == NULL) { 1006133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block"); 1007115Sigor@sysoev.ru return NXT_ERROR; 1008115Sigor@sysoev.ru } 1009115Sigor@sysoev.ru 1010133Sigor@sysoev.ru next = 0; 1011133Sigor@sysoev.ru 1012133Sigor@sysoev.ru for ( ;; ) { 1013133Sigor@sysoev.ru application = nxt_conf_next_object_member(applications, &name, &next); 1014133Sigor@sysoev.ru if (application == NULL) { 1015133Sigor@sysoev.ru break; 1016133Sigor@sysoev.ru } 1017133Sigor@sysoev.ru 1018133Sigor@sysoev.ru nxt_debug(task, "application \"%V\"", &name); 1019133Sigor@sysoev.ru 1020144Smax.romanov@nginx.com size = nxt_conf_json_length(application, NULL); 1021144Smax.romanov@nginx.com 1022144Smax.romanov@nginx.com app = nxt_malloc(sizeof(nxt_app_t) + name.length + size); 1023133Sigor@sysoev.ru if (app == NULL) { 1024133Sigor@sysoev.ru goto fail; 1025133Sigor@sysoev.ru } 1026133Sigor@sysoev.ru 1027144Smax.romanov@nginx.com nxt_memzero(app, sizeof(nxt_app_t)); 1028144Smax.romanov@nginx.com 1029144Smax.romanov@nginx.com app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t)); 1030144Smax.romanov@nginx.com app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length); 1031133Sigor@sysoev.ru 1032133Sigor@sysoev.ru p = nxt_conf_json_print(app->conf.start, application, NULL); 1033133Sigor@sysoev.ru app->conf.length = p - app->conf.start; 1034133Sigor@sysoev.ru 1035144Smax.romanov@nginx.com nxt_assert(app->conf.length <= size); 1036144Smax.romanov@nginx.com 1037133Sigor@sysoev.ru nxt_debug(task, "application conf \"%V\"", &app->conf); 1038133Sigor@sysoev.ru 1039133Sigor@sysoev.ru prev = nxt_router_app_find(&tmcf->conf->router->apps, &name); 1040133Sigor@sysoev.ru 1041133Sigor@sysoev.ru if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) { 1042133Sigor@sysoev.ru nxt_free(app); 1043133Sigor@sysoev.ru 1044133Sigor@sysoev.ru nxt_queue_remove(&prev->link); 1045133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->previous, &prev->link); 1046133Sigor@sysoev.ru continue; 1047133Sigor@sysoev.ru } 1048133Sigor@sysoev.ru 1049263Smax.romanov@nginx.com apcf.workers = 1; 1050318Smax.romanov@nginx.com apcf.timeout = 0; 1051318Smax.romanov@nginx.com apcf.requests = 0; 1052318Smax.romanov@nginx.com apcf.limits_value = NULL; 1053263Smax.romanov@nginx.com 1054213Svbart@nginx.com ret = nxt_conf_map_object(mp, application, nxt_router_app_conf, 1055136Svbart@nginx.com nxt_nitems(nxt_router_app_conf), &apcf); 1056133Sigor@sysoev.ru if (ret != NXT_OK) { 1057133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "application map error"); 1058133Sigor@sysoev.ru goto app_fail; 1059133Sigor@sysoev.ru } 1060115Sigor@sysoev.ru 1061318Smax.romanov@nginx.com if (apcf.limits_value != NULL) { 1062318Smax.romanov@nginx.com 1063318Smax.romanov@nginx.com if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) { 1064318Smax.romanov@nginx.com nxt_log(task, NXT_LOG_CRIT, "application limits is not object"); 1065318Smax.romanov@nginx.com goto app_fail; 1066318Smax.romanov@nginx.com } 1067318Smax.romanov@nginx.com 1068318Smax.romanov@nginx.com ret = nxt_conf_map_object(mp, apcf.limits_value, 1069318Smax.romanov@nginx.com nxt_router_app_limits_conf, 1070318Smax.romanov@nginx.com nxt_nitems(nxt_router_app_limits_conf), 1071318Smax.romanov@nginx.com &apcf); 1072318Smax.romanov@nginx.com if (ret != NXT_OK) { 1073318Smax.romanov@nginx.com nxt_log(task, NXT_LOG_CRIT, "application limits map error"); 1074318Smax.romanov@nginx.com goto app_fail; 1075318Smax.romanov@nginx.com } 1076318Smax.romanov@nginx.com } 1077318Smax.romanov@nginx.com 1078133Sigor@sysoev.ru nxt_debug(task, "application type: %V", &apcf.type); 1079133Sigor@sysoev.ru nxt_debug(task, "application workers: %D", apcf.workers); 1080318Smax.romanov@nginx.com nxt_debug(task, "application timeout: %D", apcf.timeout); 1081318Smax.romanov@nginx.com nxt_debug(task, "application requests: %D", apcf.requests); 1082133Sigor@sysoev.ru 1083216Sigor@sysoev.ru lang = nxt_app_lang_module(task->thread->runtime, &apcf.type); 1084216Sigor@sysoev.ru 1085216Sigor@sysoev.ru if (lang == NULL) { 1086141Smax.romanov@nginx.com nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"", 1087141Smax.romanov@nginx.com &apcf.type); 1088141Smax.romanov@nginx.com goto app_fail; 1089141Smax.romanov@nginx.com } 1090141Smax.romanov@nginx.com 1091216Sigor@sysoev.ru nxt_debug(task, "application language module: \"%s\"", lang->file); 1092216Sigor@sysoev.ru 1093216Sigor@sysoev.ru type = nxt_app_parse_type(&lang->type); 1094216Sigor@sysoev.ru 1095216Sigor@sysoev.ru if (type == NXT_APP_UNKNOWN) { 1096216Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"", 1097216Sigor@sysoev.ru &lang->type); 1098216Sigor@sysoev.ru goto app_fail; 1099216Sigor@sysoev.ru } 1100216Sigor@sysoev.ru 1101216Sigor@sysoev.ru if (nxt_app_prepare_msg[type] == NULL) { 1102133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "unsupported application type: \"%V\"", 1103216Sigor@sysoev.ru &lang->type); 1104133Sigor@sysoev.ru goto app_fail; 1105133Sigor@sysoev.ru } 1106133Sigor@sysoev.ru 1107133Sigor@sysoev.ru ret = nxt_thread_mutex_create(&app->mutex); 1108133Sigor@sysoev.ru if (ret != NXT_OK) { 1109133Sigor@sysoev.ru goto app_fail; 1110133Sigor@sysoev.ru } 1111133Sigor@sysoev.ru 1112141Smax.romanov@nginx.com nxt_queue_init(&app->ports); 1113141Smax.romanov@nginx.com nxt_queue_init(&app->requests); 1114141Smax.romanov@nginx.com 1115144Smax.romanov@nginx.com app->name.length = name.length; 1116144Smax.romanov@nginx.com nxt_memcpy(app->name.start, name.start, name.length); 1117144Smax.romanov@nginx.com 1118133Sigor@sysoev.ru app->type = type; 1119133Sigor@sysoev.ru app->max_workers = apcf.workers; 1120318Smax.romanov@nginx.com app->timeout = apcf.timeout; 1121133Sigor@sysoev.ru app->live = 1; 1122343Smax.romanov@nginx.com app->max_pending_responses = 2; 1123216Sigor@sysoev.ru app->prepare_msg = nxt_app_prepare_msg[type]; 1124133Sigor@sysoev.ru 1125133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->apps, &app->link); 1126343Smax.romanov@nginx.com 1127343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 1128133Sigor@sysoev.ru } 1129133Sigor@sysoev.ru 1130133Sigor@sysoev.ru http = nxt_conf_get_path(conf, &http_path); 1131133Sigor@sysoev.ru #if 0 1132133Sigor@sysoev.ru if (http == NULL) { 1133133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "no \"http\" block"); 1134133Sigor@sysoev.ru return NXT_ERROR; 1135133Sigor@sysoev.ru } 1136133Sigor@sysoev.ru #endif 1137133Sigor@sysoev.ru 1138133Sigor@sysoev.ru listeners = nxt_conf_get_path(conf, &listeners_path); 1139115Sigor@sysoev.ru if (listeners == NULL) { 1140133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block"); 1141115Sigor@sysoev.ru return NXT_ERROR; 1142115Sigor@sysoev.ru } 114353Sigor@sysoev.ru 1144133Sigor@sysoev.ru next = 0; 114553Sigor@sysoev.ru 1146115Sigor@sysoev.ru for ( ;; ) { 1147115Sigor@sysoev.ru listener = nxt_conf_next_object_member(listeners, &name, &next); 1148115Sigor@sysoev.ru if (listener == NULL) { 1149115Sigor@sysoev.ru break; 1150115Sigor@sysoev.ru } 115153Sigor@sysoev.ru 1152115Sigor@sysoev.ru sa = nxt_sockaddr_parse(mp, &name); 1153115Sigor@sysoev.ru if (sa == NULL) { 1154115Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", &name); 1155133Sigor@sysoev.ru goto fail; 1156115Sigor@sysoev.ru } 1157115Sigor@sysoev.ru 1158115Sigor@sysoev.ru sa->type = SOCK_STREAM; 1159115Sigor@sysoev.ru 1160115Sigor@sysoev.ru nxt_debug(task, "router listener: \"%*s\"", 1161115Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa)); 116253Sigor@sysoev.ru 1163115Sigor@sysoev.ru skcf = nxt_router_socket_conf(task, mp, sa); 1164115Sigor@sysoev.ru if (skcf == NULL) { 1165133Sigor@sysoev.ru goto fail; 1166115Sigor@sysoev.ru } 116753Sigor@sysoev.ru 1168213Svbart@nginx.com ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf, 1169136Svbart@nginx.com nxt_nitems(nxt_router_listener_conf), &lscf); 1170115Sigor@sysoev.ru if (ret != NXT_OK) { 1171115Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "listener map error"); 1172133Sigor@sysoev.ru goto fail; 1173115Sigor@sysoev.ru } 117453Sigor@sysoev.ru 1175133Sigor@sysoev.ru nxt_debug(task, "application: %V", &lscf.application); 1176133Sigor@sysoev.ru 1177133Sigor@sysoev.ru // STUB, default values if http block is not defined. 1178133Sigor@sysoev.ru skcf->header_buffer_size = 2048; 1179133Sigor@sysoev.ru skcf->large_header_buffer_size = 8192; 1180206Smax.romanov@nginx.com skcf->large_header_buffers = 4; 1181206Smax.romanov@nginx.com skcf->body_buffer_size = 16 * 1024; 1182206Smax.romanov@nginx.com skcf->max_body_size = 2 * 1024 * 1024; 1183133Sigor@sysoev.ru skcf->header_read_timeout = 5000; 1184206Smax.romanov@nginx.com skcf->body_read_timeout = 5000; 118553Sigor@sysoev.ru 1186133Sigor@sysoev.ru if (http != NULL) { 1187213Svbart@nginx.com ret = nxt_conf_map_object(mp, http, nxt_router_http_conf, 1188136Svbart@nginx.com nxt_nitems(nxt_router_http_conf), skcf); 1189133Sigor@sysoev.ru if (ret != NXT_OK) { 1190133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "http map error"); 1191133Sigor@sysoev.ru goto fail; 1192133Sigor@sysoev.ru } 1193115Sigor@sysoev.ru } 1194115Sigor@sysoev.ru 1195115Sigor@sysoev.ru skcf->listen.handler = nxt_router_conn_init; 1196115Sigor@sysoev.ru skcf->router_conf = tmcf->conf; 1197160Sigor@sysoev.ru skcf->router_conf->count++; 1198133Sigor@sysoev.ru skcf->application = nxt_router_listener_application(tmcf, 1199133Sigor@sysoev.ru &lscf.application); 1200115Sigor@sysoev.ru 1201115Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->pending, &skcf->link); 1202115Sigor@sysoev.ru } 120353Sigor@sysoev.ru 1204198Sigor@sysoev.ru nxt_router_listen_sockets_sort(tmcf->conf->router, tmcf); 1205198Sigor@sysoev.ru 120653Sigor@sysoev.ru return NXT_OK; 1207133Sigor@sysoev.ru 1208133Sigor@sysoev.ru app_fail: 1209133Sigor@sysoev.ru 1210133Sigor@sysoev.ru nxt_free(app); 1211133Sigor@sysoev.ru 1212133Sigor@sysoev.ru fail: 1213133Sigor@sysoev.ru 1214141Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1215141Smax.romanov@nginx.com 1216141Smax.romanov@nginx.com nxt_queue_remove(&app->link); 1217133Sigor@sysoev.ru nxt_thread_mutex_destroy(&app->mutex); 1218133Sigor@sysoev.ru nxt_free(app); 1219141Smax.romanov@nginx.com 1220141Smax.romanov@nginx.com } nxt_queue_loop; 1221133Sigor@sysoev.ru 1222133Sigor@sysoev.ru return NXT_ERROR; 1223133Sigor@sysoev.ru } 1224133Sigor@sysoev.ru 1225133Sigor@sysoev.ru 1226133Sigor@sysoev.ru static nxt_app_t * 1227133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name) 1228133Sigor@sysoev.ru { 1229141Smax.romanov@nginx.com nxt_app_t *app; 1230141Smax.romanov@nginx.com 1231141Smax.romanov@nginx.com nxt_queue_each(app, queue, nxt_app_t, link) { 1232133Sigor@sysoev.ru 1233133Sigor@sysoev.ru if (nxt_strstr_eq(name, &app->name)) { 1234133Sigor@sysoev.ru return app; 1235133Sigor@sysoev.ru } 1236141Smax.romanov@nginx.com 1237141Smax.romanov@nginx.com } nxt_queue_loop; 1238133Sigor@sysoev.ru 1239133Sigor@sysoev.ru return NULL; 1240133Sigor@sysoev.ru } 1241133Sigor@sysoev.ru 1242133Sigor@sysoev.ru 1243133Sigor@sysoev.ru static nxt_app_t * 1244133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name) 1245133Sigor@sysoev.ru { 1246133Sigor@sysoev.ru nxt_app_t *app; 1247133Sigor@sysoev.ru 1248133Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->apps, name); 1249133Sigor@sysoev.ru 1250133Sigor@sysoev.ru if (app == NULL) { 1251134Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->previous, name); 1252133Sigor@sysoev.ru } 1253133Sigor@sysoev.ru 1254133Sigor@sysoev.ru return app; 125553Sigor@sysoev.ru } 125653Sigor@sysoev.ru 125753Sigor@sysoev.ru 125853Sigor@sysoev.ru static nxt_socket_conf_t * 125965Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, nxt_sockaddr_t *sa) 126053Sigor@sysoev.ru { 1261163Smax.romanov@nginx.com nxt_socket_conf_t *skcf; 1262163Smax.romanov@nginx.com 1263163Smax.romanov@nginx.com skcf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_t)); 1264163Smax.romanov@nginx.com if (nxt_slow_path(skcf == NULL)) { 126553Sigor@sysoev.ru return NULL; 126653Sigor@sysoev.ru } 126753Sigor@sysoev.ru 1268163Smax.romanov@nginx.com skcf->sockaddr = sa; 1269163Smax.romanov@nginx.com 1270163Smax.romanov@nginx.com skcf->listen.sockaddr = sa; 1271312Sigor@sysoev.ru 1272312Sigor@sysoev.ru nxt_listen_socket_remote_size(&skcf->listen, sa); 1273163Smax.romanov@nginx.com 1274163Smax.romanov@nginx.com skcf->listen.socket = -1; 1275163Smax.romanov@nginx.com skcf->listen.backlog = NXT_LISTEN_BACKLOG; 1276163Smax.romanov@nginx.com skcf->listen.flags = NXT_NONBLOCK; 1277163Smax.romanov@nginx.com skcf->listen.read_after_accept = 1; 1278163Smax.romanov@nginx.com 1279163Smax.romanov@nginx.com return skcf; 128053Sigor@sysoev.ru } 128153Sigor@sysoev.ru 128253Sigor@sysoev.ru 128353Sigor@sysoev.ru static void 128453Sigor@sysoev.ru nxt_router_listen_sockets_sort(nxt_router_t *router, 128553Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 128653Sigor@sysoev.ru { 128753Sigor@sysoev.ru nxt_queue_link_t *nqlk, *oqlk, *next; 128853Sigor@sysoev.ru nxt_socket_conf_t *nskcf, *oskcf; 128953Sigor@sysoev.ru 129053Sigor@sysoev.ru for (nqlk = nxt_queue_first(&tmcf->pending); 129153Sigor@sysoev.ru nqlk != nxt_queue_tail(&tmcf->pending); 129253Sigor@sysoev.ru nqlk = next) 129353Sigor@sysoev.ru { 129453Sigor@sysoev.ru next = nxt_queue_next(nqlk); 129553Sigor@sysoev.ru nskcf = nxt_queue_link_data(nqlk, nxt_socket_conf_t, link); 129653Sigor@sysoev.ru 129753Sigor@sysoev.ru for (oqlk = nxt_queue_first(&router->sockets); 129853Sigor@sysoev.ru oqlk != nxt_queue_tail(&router->sockets); 129953Sigor@sysoev.ru oqlk = nxt_queue_next(oqlk)) 130053Sigor@sysoev.ru { 130153Sigor@sysoev.ru oskcf = nxt_queue_link_data(oqlk, nxt_socket_conf_t, link); 130253Sigor@sysoev.ru 1303115Sigor@sysoev.ru if (nxt_sockaddr_cmp(nskcf->sockaddr, oskcf->sockaddr)) { 1304115Sigor@sysoev.ru nskcf->socket = oskcf->socket; 1305115Sigor@sysoev.ru nskcf->listen.socket = oskcf->listen.socket; 1306115Sigor@sysoev.ru 130753Sigor@sysoev.ru nxt_queue_remove(oqlk); 130853Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->keeping, oqlk); 130953Sigor@sysoev.ru 131053Sigor@sysoev.ru nxt_queue_remove(nqlk); 131153Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->updating, nqlk); 131253Sigor@sysoev.ru 131353Sigor@sysoev.ru break; 131453Sigor@sysoev.ru } 131553Sigor@sysoev.ru } 131653Sigor@sysoev.ru } 131753Sigor@sysoev.ru 131853Sigor@sysoev.ru nxt_queue_add(&tmcf->deleting, &router->sockets); 1319115Sigor@sysoev.ru nxt_queue_init(&router->sockets); 132053Sigor@sysoev.ru } 132153Sigor@sysoev.ru 132253Sigor@sysoev.ru 1323198Sigor@sysoev.ru static void 1324198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task, 1325198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf) 1326198Sigor@sysoev.ru { 1327198Sigor@sysoev.ru uint32_t stream; 1328198Sigor@sysoev.ru nxt_buf_t *b; 1329198Sigor@sysoev.ru nxt_port_t *main_port, *router_port; 1330198Sigor@sysoev.ru nxt_runtime_t *rt; 1331198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 1332198Sigor@sysoev.ru 1333198Sigor@sysoev.ru rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t)); 1334198Sigor@sysoev.ru if (rpc == NULL) { 1335198Sigor@sysoev.ru goto fail; 1336198Sigor@sysoev.ru } 1337198Sigor@sysoev.ru 1338198Sigor@sysoev.ru rpc->socket_conf = skcf; 1339198Sigor@sysoev.ru rpc->temp_conf = tmcf; 1340198Sigor@sysoev.ru 1341198Sigor@sysoev.ru b = nxt_buf_mem_alloc(tmcf->mem_pool, skcf->sockaddr->sockaddr_size, 0); 1342198Sigor@sysoev.ru if (b == NULL) { 1343198Sigor@sysoev.ru goto fail; 1344198Sigor@sysoev.ru } 1345198Sigor@sysoev.ru 1346198Sigor@sysoev.ru b->mem.free = nxt_cpymem(b->mem.free, skcf->sockaddr, 1347198Sigor@sysoev.ru skcf->sockaddr->sockaddr_size); 1348198Sigor@sysoev.ru 1349198Sigor@sysoev.ru rt = task->thread->runtime; 1350240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1351198Sigor@sysoev.ru router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 1352198Sigor@sysoev.ru 1353198Sigor@sysoev.ru stream = nxt_port_rpc_register_handler(task, router_port, 1354198Sigor@sysoev.ru nxt_router_listen_socket_ready, 1355198Sigor@sysoev.ru nxt_router_listen_socket_error, 1356198Sigor@sysoev.ru main_port->pid, rpc); 1357198Sigor@sysoev.ru if (stream == 0) { 1358198Sigor@sysoev.ru goto fail; 1359198Sigor@sysoev.ru } 1360198Sigor@sysoev.ru 1361198Sigor@sysoev.ru nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1, 1362198Sigor@sysoev.ru stream, router_port->id, b); 1363198Sigor@sysoev.ru 1364198Sigor@sysoev.ru return; 1365198Sigor@sysoev.ru 1366198Sigor@sysoev.ru fail: 1367198Sigor@sysoev.ru 1368198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 1369198Sigor@sysoev.ru } 1370198Sigor@sysoev.ru 1371198Sigor@sysoev.ru 1372198Sigor@sysoev.ru static void 1373198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1374198Sigor@sysoev.ru void *data) 137553Sigor@sysoev.ru { 1376115Sigor@sysoev.ru nxt_int_t ret; 1377115Sigor@sysoev.ru nxt_socket_t s; 1378198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 1379115Sigor@sysoev.ru nxt_router_socket_t *rtsk; 138053Sigor@sysoev.ru 1381198Sigor@sysoev.ru rpc = data; 1382198Sigor@sysoev.ru 1383198Sigor@sysoev.ru s = msg->fd; 1384198Sigor@sysoev.ru 1385198Sigor@sysoev.ru ret = nxt_socket_nonblocking(task, s); 1386198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1387198Sigor@sysoev.ru goto fail; 138853Sigor@sysoev.ru } 138953Sigor@sysoev.ru 1390229Sigor@sysoev.ru nxt_socket_defer_accept(task, s, rpc->socket_conf->sockaddr); 1391198Sigor@sysoev.ru 1392198Sigor@sysoev.ru ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG); 1393198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1394198Sigor@sysoev.ru goto fail; 1395198Sigor@sysoev.ru } 1396198Sigor@sysoev.ru 1397198Sigor@sysoev.ru rtsk = nxt_malloc(sizeof(nxt_router_socket_t)); 1398198Sigor@sysoev.ru if (nxt_slow_path(rtsk == NULL)) { 1399198Sigor@sysoev.ru goto fail; 1400198Sigor@sysoev.ru } 1401198Sigor@sysoev.ru 1402198Sigor@sysoev.ru rtsk->count = 0; 1403198Sigor@sysoev.ru rtsk->fd = s; 1404198Sigor@sysoev.ru 1405198Sigor@sysoev.ru rpc->socket_conf->listen.socket = s; 1406198Sigor@sysoev.ru rpc->socket_conf->socket = rtsk; 1407198Sigor@sysoev.ru 1408198Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 1409198Sigor@sysoev.ru nxt_router_conf_apply, task, rpc->temp_conf, NULL); 1410198Sigor@sysoev.ru 1411198Sigor@sysoev.ru return; 1412148Sigor@sysoev.ru 1413148Sigor@sysoev.ru fail: 1414148Sigor@sysoev.ru 1415148Sigor@sysoev.ru nxt_socket_close(task, s); 1416148Sigor@sysoev.ru 1417198Sigor@sysoev.ru nxt_router_conf_error(task, rpc->temp_conf); 1418198Sigor@sysoev.ru } 1419198Sigor@sysoev.ru 1420198Sigor@sysoev.ru 1421198Sigor@sysoev.ru static void 1422198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1423198Sigor@sysoev.ru void *data) 1424198Sigor@sysoev.ru { 1425198Sigor@sysoev.ru u_char *p; 1426198Sigor@sysoev.ru size_t size; 1427198Sigor@sysoev.ru uint8_t error; 1428198Sigor@sysoev.ru nxt_buf_t *in, *out; 1429198Sigor@sysoev.ru nxt_sockaddr_t *sa; 1430198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 1431198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 1432198Sigor@sysoev.ru 1433198Sigor@sysoev.ru static nxt_str_t socket_errors[] = { 1434198Sigor@sysoev.ru nxt_string("ListenerSystem"), 1435198Sigor@sysoev.ru nxt_string("ListenerNoIPv6"), 1436198Sigor@sysoev.ru nxt_string("ListenerPort"), 1437198Sigor@sysoev.ru nxt_string("ListenerInUse"), 1438198Sigor@sysoev.ru nxt_string("ListenerNoAddress"), 1439198Sigor@sysoev.ru nxt_string("ListenerNoAccess"), 1440198Sigor@sysoev.ru nxt_string("ListenerPath"), 1441198Sigor@sysoev.ru }; 1442198Sigor@sysoev.ru 1443198Sigor@sysoev.ru rpc = data; 1444198Sigor@sysoev.ru sa = rpc->socket_conf->sockaddr; 1445198Sigor@sysoev.ru 1446198Sigor@sysoev.ru in = msg->buf; 1447198Sigor@sysoev.ru p = in->mem.pos; 1448198Sigor@sysoev.ru 1449198Sigor@sysoev.ru error = *p++; 1450198Sigor@sysoev.ru 1451198Sigor@sysoev.ru size = sizeof("listen socket error: ") - 1 1452198Sigor@sysoev.ru + sizeof("{listener: \"\", code:\"\", message: \"\"}") - 1 1453198Sigor@sysoev.ru + sa->length + socket_errors[error].length + (in->mem.free - p); 1454198Sigor@sysoev.ru 1455198Sigor@sysoev.ru tmcf = rpc->temp_conf; 1456198Sigor@sysoev.ru 1457198Sigor@sysoev.ru out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 1458198Sigor@sysoev.ru if (nxt_slow_path(out == NULL)) { 1459198Sigor@sysoev.ru return; 1460198Sigor@sysoev.ru } 1461198Sigor@sysoev.ru 1462198Sigor@sysoev.ru out->mem.free = nxt_sprintf(out->mem.free, out->mem.end, 1463198Sigor@sysoev.ru "listen socket error: " 1464198Sigor@sysoev.ru "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}", 1465198Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa), 1466198Sigor@sysoev.ru &socket_errors[error], in->mem.free - p, p); 1467198Sigor@sysoev.ru 1468198Sigor@sysoev.ru nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos); 1469198Sigor@sysoev.ru 1470198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 147153Sigor@sysoev.ru } 147253Sigor@sysoev.ru 147353Sigor@sysoev.ru 147453Sigor@sysoev.ru static nxt_int_t 147553Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router, 147653Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface) 147753Sigor@sysoev.ru { 147853Sigor@sysoev.ru nxt_int_t ret; 147953Sigor@sysoev.ru nxt_uint_t n, threads; 148053Sigor@sysoev.ru nxt_queue_link_t *qlk; 148153Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 148253Sigor@sysoev.ru 148353Sigor@sysoev.ru threads = tmcf->conf->threads; 148453Sigor@sysoev.ru 148553Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, threads, 148653Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 148753Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 148853Sigor@sysoev.ru return NXT_ERROR; 148953Sigor@sysoev.ru } 149053Sigor@sysoev.ru 149153Sigor@sysoev.ru n = 0; 149253Sigor@sysoev.ru 149353Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->engines); 149453Sigor@sysoev.ru qlk != nxt_queue_tail(&router->engines); 149553Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 149653Sigor@sysoev.ru { 149753Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 149853Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 149953Sigor@sysoev.ru return NXT_ERROR; 150053Sigor@sysoev.ru } 150153Sigor@sysoev.ru 1502115Sigor@sysoev.ru recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0); 150353Sigor@sysoev.ru 150453Sigor@sysoev.ru if (n < threads) { 1505315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_KEEP; 1506115Sigor@sysoev.ru ret = nxt_router_engine_conf_update(tmcf, recf); 150753Sigor@sysoev.ru 150853Sigor@sysoev.ru } else { 1509315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_DELETE; 1510115Sigor@sysoev.ru ret = nxt_router_engine_conf_delete(tmcf, recf); 151153Sigor@sysoev.ru } 151253Sigor@sysoev.ru 151353Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 151453Sigor@sysoev.ru return ret; 151553Sigor@sysoev.ru } 151653Sigor@sysoev.ru 151753Sigor@sysoev.ru n++; 151853Sigor@sysoev.ru } 151953Sigor@sysoev.ru 152053Sigor@sysoev.ru tmcf->new_threads = n; 152153Sigor@sysoev.ru 152253Sigor@sysoev.ru while (n < threads) { 152353Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 152453Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 152553Sigor@sysoev.ru return NXT_ERROR; 152653Sigor@sysoev.ru } 152753Sigor@sysoev.ru 1528315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_ADD; 1529315Sigor@sysoev.ru 153053Sigor@sysoev.ru recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0); 153153Sigor@sysoev.ru if (nxt_slow_path(recf->engine == NULL)) { 153253Sigor@sysoev.ru return NXT_ERROR; 153353Sigor@sysoev.ru } 153453Sigor@sysoev.ru 1535115Sigor@sysoev.ru ret = nxt_router_engine_conf_create(tmcf, recf); 153653Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 153753Sigor@sysoev.ru return ret; 153853Sigor@sysoev.ru } 153953Sigor@sysoev.ru 154053Sigor@sysoev.ru n++; 154153Sigor@sysoev.ru } 154253Sigor@sysoev.ru 154353Sigor@sysoev.ru return NXT_OK; 154453Sigor@sysoev.ru } 154553Sigor@sysoev.ru 154653Sigor@sysoev.ru 154753Sigor@sysoev.ru static nxt_int_t 1548115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 1549115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 155053Sigor@sysoev.ru { 1551115Sigor@sysoev.ru nxt_int_t ret; 1552115Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 155353Sigor@sysoev.ru 1554154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 1555154Sigor@sysoev.ru nxt_router_listen_socket_create); 1556115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1557115Sigor@sysoev.ru return ret; 1558115Sigor@sysoev.ru } 1559115Sigor@sysoev.ru 1560154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 1561154Sigor@sysoev.ru nxt_router_listen_socket_create); 156253Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 156353Sigor@sysoev.ru return ret; 156453Sigor@sysoev.ru } 156553Sigor@sysoev.ru 1566115Sigor@sysoev.ru lock = &tmcf->conf->router->lock; 1567115Sigor@sysoev.ru 1568115Sigor@sysoev.ru nxt_thread_spin_lock(lock); 1569115Sigor@sysoev.ru 1570115Sigor@sysoev.ru nxt_router_engine_socket_count(&tmcf->creating); 1571115Sigor@sysoev.ru nxt_router_engine_socket_count(&tmcf->updating); 1572115Sigor@sysoev.ru 1573115Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 1574115Sigor@sysoev.ru 1575115Sigor@sysoev.ru return ret; 157653Sigor@sysoev.ru } 157753Sigor@sysoev.ru 157853Sigor@sysoev.ru 157953Sigor@sysoev.ru static nxt_int_t 1580115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 1581115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 158253Sigor@sysoev.ru { 1583115Sigor@sysoev.ru nxt_int_t ret; 1584115Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 158553Sigor@sysoev.ru 1586154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 1587154Sigor@sysoev.ru nxt_router_listen_socket_create); 158853Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 158953Sigor@sysoev.ru return ret; 159053Sigor@sysoev.ru } 159153Sigor@sysoev.ru 1592154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 1593154Sigor@sysoev.ru nxt_router_listen_socket_update); 159453Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 159553Sigor@sysoev.ru return ret; 159653Sigor@sysoev.ru } 159753Sigor@sysoev.ru 1598139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 1599115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1600115Sigor@sysoev.ru return ret; 1601115Sigor@sysoev.ru } 1602115Sigor@sysoev.ru 1603115Sigor@sysoev.ru lock = &tmcf->conf->router->lock; 1604115Sigor@sysoev.ru 1605115Sigor@sysoev.ru nxt_thread_spin_lock(lock); 1606115Sigor@sysoev.ru 1607115Sigor@sysoev.ru nxt_router_engine_socket_count(&tmcf->creating); 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_delete(nxt_router_temp_conf_t *tmcf, 1617115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 161853Sigor@sysoev.ru { 161953Sigor@sysoev.ru nxt_int_t ret; 162053Sigor@sysoev.ru 1621313Sigor@sysoev.ru ret = nxt_router_engine_quit(tmcf, recf); 1622313Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1623313Sigor@sysoev.ru return ret; 1624313Sigor@sysoev.ru } 1625313Sigor@sysoev.ru 1626139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating); 162753Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 162853Sigor@sysoev.ru return ret; 162953Sigor@sysoev.ru } 163053Sigor@sysoev.ru 1631139Sigor@sysoev.ru return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 163253Sigor@sysoev.ru } 163353Sigor@sysoev.ru 163453Sigor@sysoev.ru 163553Sigor@sysoev.ru static nxt_int_t 1636154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 1637154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 163853Sigor@sysoev.ru nxt_work_handler_t handler) 163953Sigor@sysoev.ru { 1640153Sigor@sysoev.ru nxt_joint_job_t *job; 164153Sigor@sysoev.ru nxt_queue_link_t *qlk; 1642155Sigor@sysoev.ru nxt_socket_conf_t *skcf; 164353Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 164453Sigor@sysoev.ru 164553Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 164653Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 164753Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 164853Sigor@sysoev.ru { 1649154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 1650153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 1651139Sigor@sysoev.ru return NXT_ERROR; 1652139Sigor@sysoev.ru } 1653139Sigor@sysoev.ru 1654154Sigor@sysoev.ru job->work.next = recf->jobs; 1655154Sigor@sysoev.ru recf->jobs = &job->work; 1656154Sigor@sysoev.ru 1657153Sigor@sysoev.ru job->task = tmcf->engine->task; 1658153Sigor@sysoev.ru job->work.handler = handler; 1659153Sigor@sysoev.ru job->work.task = &job->task; 1660153Sigor@sysoev.ru job->work.obj = job; 1661153Sigor@sysoev.ru job->tmcf = tmcf; 166253Sigor@sysoev.ru 1663154Sigor@sysoev.ru tmcf->count++; 1664154Sigor@sysoev.ru 1665154Sigor@sysoev.ru joint = nxt_mp_alloc(tmcf->conf->mem_pool, 1666154Sigor@sysoev.ru sizeof(nxt_socket_conf_joint_t)); 166753Sigor@sysoev.ru if (nxt_slow_path(joint == NULL)) { 166853Sigor@sysoev.ru return NXT_ERROR; 166953Sigor@sysoev.ru } 167053Sigor@sysoev.ru 1671153Sigor@sysoev.ru job->work.data = joint; 167253Sigor@sysoev.ru 167353Sigor@sysoev.ru joint->count = 1; 1674155Sigor@sysoev.ru 1675155Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1676155Sigor@sysoev.ru skcf->count++; 1677155Sigor@sysoev.ru joint->socket_conf = skcf; 1678155Sigor@sysoev.ru 167988Smax.romanov@nginx.com joint->engine = recf->engine; 168053Sigor@sysoev.ru } 168153Sigor@sysoev.ru 168220Sigor@sysoev.ru return NXT_OK; 168320Sigor@sysoev.ru } 168420Sigor@sysoev.ru 168520Sigor@sysoev.ru 1686115Sigor@sysoev.ru static void 1687115Sigor@sysoev.ru nxt_router_engine_socket_count(nxt_queue_t *sockets) 1688115Sigor@sysoev.ru { 1689115Sigor@sysoev.ru nxt_queue_link_t *qlk; 1690115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1691115Sigor@sysoev.ru 1692115Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 1693115Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 1694115Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 1695115Sigor@sysoev.ru { 1696115Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1697115Sigor@sysoev.ru skcf->socket->count++; 1698115Sigor@sysoev.ru } 1699115Sigor@sysoev.ru } 1700115Sigor@sysoev.ru 1701115Sigor@sysoev.ru 170220Sigor@sysoev.ru static nxt_int_t 1703313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 1704313Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 1705313Sigor@sysoev.ru { 1706313Sigor@sysoev.ru nxt_joint_job_t *job; 1707313Sigor@sysoev.ru 1708313Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 1709313Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 1710313Sigor@sysoev.ru return NXT_ERROR; 1711313Sigor@sysoev.ru } 1712313Sigor@sysoev.ru 1713313Sigor@sysoev.ru job->work.next = recf->jobs; 1714313Sigor@sysoev.ru recf->jobs = &job->work; 1715313Sigor@sysoev.ru 1716313Sigor@sysoev.ru job->task = tmcf->engine->task; 1717313Sigor@sysoev.ru job->work.handler = nxt_router_worker_thread_quit; 1718313Sigor@sysoev.ru job->work.task = &job->task; 1719313Sigor@sysoev.ru job->work.obj = NULL; 1720313Sigor@sysoev.ru job->work.data = NULL; 1721313Sigor@sysoev.ru job->tmcf = NULL; 1722313Sigor@sysoev.ru 1723313Sigor@sysoev.ru return NXT_OK; 1724313Sigor@sysoev.ru } 1725313Sigor@sysoev.ru 1726313Sigor@sysoev.ru 1727313Sigor@sysoev.ru static nxt_int_t 1728139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 1729139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets) 173020Sigor@sysoev.ru { 1731153Sigor@sysoev.ru nxt_joint_job_t *job; 173253Sigor@sysoev.ru nxt_queue_link_t *qlk; 173320Sigor@sysoev.ru 173453Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 173553Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 173653Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 173753Sigor@sysoev.ru { 1738154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 1739153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 1740139Sigor@sysoev.ru return NXT_ERROR; 1741139Sigor@sysoev.ru } 1742139Sigor@sysoev.ru 1743154Sigor@sysoev.ru job->work.next = recf->jobs; 1744154Sigor@sysoev.ru recf->jobs = &job->work; 1745154Sigor@sysoev.ru 1746153Sigor@sysoev.ru job->task = tmcf->engine->task; 1747153Sigor@sysoev.ru job->work.handler = nxt_router_listen_socket_delete; 1748153Sigor@sysoev.ru job->work.task = &job->task; 1749153Sigor@sysoev.ru job->work.obj = job; 1750153Sigor@sysoev.ru job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1751153Sigor@sysoev.ru job->tmcf = tmcf; 1752154Sigor@sysoev.ru 1753154Sigor@sysoev.ru tmcf->count++; 175420Sigor@sysoev.ru } 175520Sigor@sysoev.ru 175653Sigor@sysoev.ru return NXT_OK; 175753Sigor@sysoev.ru } 175820Sigor@sysoev.ru 175920Sigor@sysoev.ru 176053Sigor@sysoev.ru static nxt_int_t 176153Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 176253Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 176353Sigor@sysoev.ru { 176453Sigor@sysoev.ru nxt_int_t ret; 176553Sigor@sysoev.ru nxt_uint_t i, threads; 176653Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 176720Sigor@sysoev.ru 176853Sigor@sysoev.ru recf = tmcf->engines->elts; 176953Sigor@sysoev.ru threads = tmcf->conf->threads; 177020Sigor@sysoev.ru 177153Sigor@sysoev.ru for (i = tmcf->new_threads; i < threads; i++) { 177253Sigor@sysoev.ru ret = nxt_router_thread_create(task, rt, recf[i].engine); 177353Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 177453Sigor@sysoev.ru return ret; 177553Sigor@sysoev.ru } 177620Sigor@sysoev.ru } 177720Sigor@sysoev.ru 177820Sigor@sysoev.ru return NXT_OK; 177920Sigor@sysoev.ru } 178053Sigor@sysoev.ru 178153Sigor@sysoev.ru 178253Sigor@sysoev.ru static nxt_int_t 178353Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 178453Sigor@sysoev.ru nxt_event_engine_t *engine) 178553Sigor@sysoev.ru { 178653Sigor@sysoev.ru nxt_int_t ret; 178753Sigor@sysoev.ru nxt_thread_link_t *link; 178853Sigor@sysoev.ru nxt_thread_handle_t handle; 178953Sigor@sysoev.ru 179053Sigor@sysoev.ru link = nxt_zalloc(sizeof(nxt_thread_link_t)); 179153Sigor@sysoev.ru 179253Sigor@sysoev.ru if (nxt_slow_path(link == NULL)) { 179353Sigor@sysoev.ru return NXT_ERROR; 179453Sigor@sysoev.ru } 179553Sigor@sysoev.ru 179653Sigor@sysoev.ru link->start = nxt_router_thread_start; 179753Sigor@sysoev.ru link->engine = engine; 179853Sigor@sysoev.ru link->work.handler = nxt_router_thread_exit_handler; 179953Sigor@sysoev.ru link->work.task = task; 180053Sigor@sysoev.ru link->work.data = link; 180153Sigor@sysoev.ru 180253Sigor@sysoev.ru nxt_queue_insert_tail(&rt->engines, &engine->link); 180353Sigor@sysoev.ru 180453Sigor@sysoev.ru ret = nxt_thread_create(&handle, link); 180553Sigor@sysoev.ru 180653Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 180753Sigor@sysoev.ru nxt_queue_remove(&engine->link); 180853Sigor@sysoev.ru } 180953Sigor@sysoev.ru 181053Sigor@sysoev.ru return ret; 181153Sigor@sysoev.ru } 181253Sigor@sysoev.ru 181353Sigor@sysoev.ru 181453Sigor@sysoev.ru static void 1815343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 1816343Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf) 1817133Sigor@sysoev.ru { 1818343Smax.romanov@nginx.com nxt_app_t *app; 1819343Smax.romanov@nginx.com nxt_port_t *port; 1820141Smax.romanov@nginx.com 1821141Smax.romanov@nginx.com nxt_queue_each(app, &router->apps, nxt_app_t, link) { 1822133Sigor@sysoev.ru 1823133Sigor@sysoev.ru nxt_queue_remove(&app->link); 1824133Sigor@sysoev.ru 1825343Smax.romanov@nginx.com nxt_debug(task, "about to free app '%V' %p", &app->name, app); 1826167Smax.romanov@nginx.com 1827163Smax.romanov@nginx.com app->live = 0; 1828163Smax.romanov@nginx.com 1829167Smax.romanov@nginx.com do { 1830343Smax.romanov@nginx.com port = nxt_router_app_get_idle_port(app); 1831167Smax.romanov@nginx.com if (port == NULL) { 1832167Smax.romanov@nginx.com break; 1833167Smax.romanov@nginx.com } 1834167Smax.romanov@nginx.com 1835343Smax.romanov@nginx.com nxt_debug(task, "port %p send quit", port); 1836343Smax.romanov@nginx.com 1837343Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, 1838343Smax.romanov@nginx.com NULL); 1839343Smax.romanov@nginx.com 1840343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 1841167Smax.romanov@nginx.com } while (1); 1842167Smax.romanov@nginx.com 1843343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 1844343Smax.romanov@nginx.com 1845141Smax.romanov@nginx.com } nxt_queue_loop; 1846133Sigor@sysoev.ru 1847133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->previous); 1848133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->apps); 1849133Sigor@sysoev.ru } 1850133Sigor@sysoev.ru 1851133Sigor@sysoev.ru 1852133Sigor@sysoev.ru static void 1853315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf) 185453Sigor@sysoev.ru { 185553Sigor@sysoev.ru nxt_uint_t n; 1856315Sigor@sysoev.ru nxt_event_engine_t *engine; 185753Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 185853Sigor@sysoev.ru 185953Sigor@sysoev.ru recf = tmcf->engines->elts; 186053Sigor@sysoev.ru 186153Sigor@sysoev.ru for (n = tmcf->engines->nelts; n != 0; n--) { 1862315Sigor@sysoev.ru engine = recf->engine; 1863315Sigor@sysoev.ru 1864315Sigor@sysoev.ru switch (recf->action) { 1865315Sigor@sysoev.ru 1866315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_KEEP: 1867315Sigor@sysoev.ru break; 1868315Sigor@sysoev.ru 1869315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_ADD: 1870315Sigor@sysoev.ru nxt_queue_insert_tail(&router->engines, &engine->link0); 1871315Sigor@sysoev.ru break; 1872315Sigor@sysoev.ru 1873315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_DELETE: 1874315Sigor@sysoev.ru nxt_queue_remove(&engine->link0); 1875315Sigor@sysoev.ru break; 1876315Sigor@sysoev.ru } 1877315Sigor@sysoev.ru 1878316Sigor@sysoev.ru nxt_router_engine_post(engine, recf->jobs); 1879316Sigor@sysoev.ru 188053Sigor@sysoev.ru recf++; 188153Sigor@sysoev.ru } 188253Sigor@sysoev.ru } 188353Sigor@sysoev.ru 188453Sigor@sysoev.ru 188553Sigor@sysoev.ru static void 1886315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs) 188753Sigor@sysoev.ru { 1888154Sigor@sysoev.ru nxt_work_t *work, *next; 1889154Sigor@sysoev.ru 1890315Sigor@sysoev.ru for (work = jobs; work != NULL; work = next) { 1891154Sigor@sysoev.ru next = work->next; 1892154Sigor@sysoev.ru work->next = NULL; 1893154Sigor@sysoev.ru 1894315Sigor@sysoev.ru nxt_event_engine_post(engine, work); 189553Sigor@sysoev.ru } 189653Sigor@sysoev.ru } 189753Sigor@sysoev.ru 189853Sigor@sysoev.ru 1899320Smax.romanov@nginx.com static nxt_port_handlers_t nxt_router_app_port_handlers = { 1900320Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 1901320Smax.romanov@nginx.com .data = nxt_port_rpc_handler, 190288Smax.romanov@nginx.com }; 190388Smax.romanov@nginx.com 190488Smax.romanov@nginx.com 190588Smax.romanov@nginx.com static void 190653Sigor@sysoev.ru nxt_router_thread_start(void *data) 190753Sigor@sysoev.ru { 1908141Smax.romanov@nginx.com nxt_int_t ret; 1909141Smax.romanov@nginx.com nxt_port_t *port; 191088Smax.romanov@nginx.com nxt_task_t *task; 191153Sigor@sysoev.ru nxt_thread_t *thread; 191253Sigor@sysoev.ru nxt_thread_link_t *link; 191353Sigor@sysoev.ru nxt_event_engine_t *engine; 191453Sigor@sysoev.ru 191553Sigor@sysoev.ru link = data; 191653Sigor@sysoev.ru engine = link->engine; 191788Smax.romanov@nginx.com task = &engine->task; 191853Sigor@sysoev.ru 191953Sigor@sysoev.ru thread = nxt_thread(); 192053Sigor@sysoev.ru 1921165Smax.romanov@nginx.com nxt_event_engine_thread_adopt(engine); 1922165Smax.romanov@nginx.com 192353Sigor@sysoev.ru /* STUB */ 192453Sigor@sysoev.ru thread->runtime = engine->task.thread->runtime; 192553Sigor@sysoev.ru 192653Sigor@sysoev.ru engine->task.thread = thread; 192753Sigor@sysoev.ru engine->task.log = thread->log; 192853Sigor@sysoev.ru thread->engine = engine; 192963Sigor@sysoev.ru thread->task = &engine->task; 1930326Svbart@nginx.com #if 0 193153Sigor@sysoev.ru thread->fiber = &engine->fibers->fiber; 1932326Svbart@nginx.com #endif 193353Sigor@sysoev.ru 193463Sigor@sysoev.ru engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64); 1935337Sigor@sysoev.ru if (nxt_slow_path(engine->mem_pool == NULL)) { 1936337Sigor@sysoev.ru return; 1937337Sigor@sysoev.ru } 193853Sigor@sysoev.ru 1939197Smax.romanov@nginx.com port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid, 1940197Smax.romanov@nginx.com NXT_PROCESS_ROUTER); 1941141Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 1942141Smax.romanov@nginx.com return; 1943141Smax.romanov@nginx.com } 1944141Smax.romanov@nginx.com 1945141Smax.romanov@nginx.com ret = nxt_port_socket_init(task, port, 0); 1946141Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 1947343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 1948141Smax.romanov@nginx.com return; 1949141Smax.romanov@nginx.com } 1950141Smax.romanov@nginx.com 1951141Smax.romanov@nginx.com engine->port = port; 1952141Smax.romanov@nginx.com 1953320Smax.romanov@nginx.com nxt_port_enable(task, port, &nxt_router_app_port_handlers); 1954141Smax.romanov@nginx.com 195553Sigor@sysoev.ru nxt_event_engine_start(engine); 195653Sigor@sysoev.ru } 195753Sigor@sysoev.ru 195853Sigor@sysoev.ru 195953Sigor@sysoev.ru static void 196053Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data) 196153Sigor@sysoev.ru { 1962153Sigor@sysoev.ru nxt_joint_job_t *job; 196353Sigor@sysoev.ru nxt_listen_event_t *listen; 196453Sigor@sysoev.ru nxt_listen_socket_t *ls; 196553Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 196653Sigor@sysoev.ru 1967153Sigor@sysoev.ru job = obj; 196853Sigor@sysoev.ru joint = data; 196953Sigor@sysoev.ru 197053Sigor@sysoev.ru ls = &joint->socket_conf->listen; 197153Sigor@sysoev.ru 1972159Sigor@sysoev.ru nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link); 1973159Sigor@sysoev.ru 197453Sigor@sysoev.ru listen = nxt_listen_event(task, ls); 197553Sigor@sysoev.ru if (nxt_slow_path(listen == NULL)) { 197653Sigor@sysoev.ru nxt_router_listen_socket_release(task, joint); 197753Sigor@sysoev.ru return; 197853Sigor@sysoev.ru } 197953Sigor@sysoev.ru 198053Sigor@sysoev.ru listen->socket.data = joint; 1981139Sigor@sysoev.ru 1982153Sigor@sysoev.ru job->work.next = NULL; 1983153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 1984153Sigor@sysoev.ru 1985153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 198653Sigor@sysoev.ru } 198753Sigor@sysoev.ru 198853Sigor@sysoev.ru 198953Sigor@sysoev.ru nxt_inline nxt_listen_event_t * 199053Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections, 199153Sigor@sysoev.ru nxt_socket_conf_t *skcf) 199253Sigor@sysoev.ru { 1993115Sigor@sysoev.ru nxt_socket_t fd; 1994115Sigor@sysoev.ru nxt_queue_link_t *qlk; 199553Sigor@sysoev.ru nxt_listen_event_t *listen; 199653Sigor@sysoev.ru 1997115Sigor@sysoev.ru fd = skcf->socket->fd; 199853Sigor@sysoev.ru 1999115Sigor@sysoev.ru for (qlk = nxt_queue_first(listen_connections); 2000115Sigor@sysoev.ru qlk != nxt_queue_tail(listen_connections); 2001115Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 200253Sigor@sysoev.ru { 2003115Sigor@sysoev.ru listen = nxt_queue_link_data(qlk, nxt_listen_event_t, link); 200453Sigor@sysoev.ru 2005115Sigor@sysoev.ru if (fd == listen->socket.fd) { 200653Sigor@sysoev.ru return listen; 200753Sigor@sysoev.ru } 200853Sigor@sysoev.ru } 200953Sigor@sysoev.ru 201053Sigor@sysoev.ru return NULL; 201153Sigor@sysoev.ru } 201253Sigor@sysoev.ru 201353Sigor@sysoev.ru 201453Sigor@sysoev.ru static void 201553Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data) 201653Sigor@sysoev.ru { 2017153Sigor@sysoev.ru nxt_joint_job_t *job; 201853Sigor@sysoev.ru nxt_event_engine_t *engine; 201953Sigor@sysoev.ru nxt_listen_event_t *listen; 202053Sigor@sysoev.ru nxt_socket_conf_joint_t *joint, *old; 202153Sigor@sysoev.ru 2022153Sigor@sysoev.ru job = obj; 202353Sigor@sysoev.ru joint = data; 202453Sigor@sysoev.ru 2025139Sigor@sysoev.ru engine = task->thread->engine; 2026139Sigor@sysoev.ru 2027159Sigor@sysoev.ru nxt_queue_insert_tail(&engine->joints, &joint->link); 2028159Sigor@sysoev.ru 202953Sigor@sysoev.ru listen = nxt_router_listen_event(&engine->listen_connections, 203053Sigor@sysoev.ru joint->socket_conf); 203153Sigor@sysoev.ru 203253Sigor@sysoev.ru old = listen->socket.data; 203353Sigor@sysoev.ru listen->socket.data = joint; 2034177Sigor@sysoev.ru listen->listen = &joint->socket_conf->listen; 203553Sigor@sysoev.ru 2036153Sigor@sysoev.ru job->work.next = NULL; 2037153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2038153Sigor@sysoev.ru 2039153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 2040139Sigor@sysoev.ru 2041181Smax.romanov@nginx.com /* 2042181Smax.romanov@nginx.com * The task is allocated from configuration temporary 2043181Smax.romanov@nginx.com * memory pool so it can be freed after engine post operation. 2044181Smax.romanov@nginx.com */ 2045181Smax.romanov@nginx.com 2046181Smax.romanov@nginx.com nxt_router_conf_release(&engine->task, old); 204753Sigor@sysoev.ru } 204853Sigor@sysoev.ru 204953Sigor@sysoev.ru 205053Sigor@sysoev.ru static void 205153Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data) 205253Sigor@sysoev.ru { 2053153Sigor@sysoev.ru nxt_joint_job_t *job; 2054153Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2055153Sigor@sysoev.ru nxt_listen_event_t *listen; 2056153Sigor@sysoev.ru nxt_event_engine_t *engine; 2057153Sigor@sysoev.ru 2058153Sigor@sysoev.ru job = obj; 205953Sigor@sysoev.ru skcf = data; 206053Sigor@sysoev.ru 2061139Sigor@sysoev.ru engine = task->thread->engine; 2062139Sigor@sysoev.ru 206353Sigor@sysoev.ru listen = nxt_router_listen_event(&engine->listen_connections, skcf); 206453Sigor@sysoev.ru 206553Sigor@sysoev.ru nxt_fd_event_delete(engine, &listen->socket); 206653Sigor@sysoev.ru 2067163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket delete: %d", engine, 2068163Smax.romanov@nginx.com listen->socket.fd); 2069163Smax.romanov@nginx.com 207053Sigor@sysoev.ru listen->timer.handler = nxt_router_listen_socket_close; 207153Sigor@sysoev.ru listen->timer.work_queue = &engine->fast_work_queue; 207253Sigor@sysoev.ru 207353Sigor@sysoev.ru nxt_timer_add(engine, &listen->timer, 0); 2074139Sigor@sysoev.ru 2075153Sigor@sysoev.ru job->work.next = NULL; 2076153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2077153Sigor@sysoev.ru 2078153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 207953Sigor@sysoev.ru } 208053Sigor@sysoev.ru 208153Sigor@sysoev.ru 208253Sigor@sysoev.ru static void 2083313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data) 2084313Sigor@sysoev.ru { 2085313Sigor@sysoev.ru nxt_event_engine_t *engine; 2086313Sigor@sysoev.ru 2087313Sigor@sysoev.ru nxt_debug(task, "router worker thread quit"); 2088313Sigor@sysoev.ru 2089313Sigor@sysoev.ru engine = task->thread->engine; 2090313Sigor@sysoev.ru 2091313Sigor@sysoev.ru engine->shutdown = 1; 2092313Sigor@sysoev.ru 2093313Sigor@sysoev.ru if (nxt_queue_is_empty(&engine->joints)) { 2094313Sigor@sysoev.ru nxt_thread_exit(task->thread); 2095313Sigor@sysoev.ru } 2096313Sigor@sysoev.ru } 2097313Sigor@sysoev.ru 2098313Sigor@sysoev.ru 2099313Sigor@sysoev.ru static void 210053Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data) 210153Sigor@sysoev.ru { 210253Sigor@sysoev.ru nxt_timer_t *timer; 210353Sigor@sysoev.ru nxt_listen_event_t *listen; 210453Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 210553Sigor@sysoev.ru 210653Sigor@sysoev.ru timer = obj; 210753Sigor@sysoev.ru listen = nxt_timer_data(timer, nxt_listen_event_t, timer); 210853Sigor@sysoev.ru joint = listen->socket.data; 210953Sigor@sysoev.ru 2110163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine, 2111163Smax.romanov@nginx.com listen->socket.fd); 2112163Smax.romanov@nginx.com 211353Sigor@sysoev.ru nxt_queue_remove(&listen->link); 2114123Smax.romanov@nginx.com 2115123Smax.romanov@nginx.com /* 'task' refers to listen->task and we cannot use after nxt_free() */ 2116123Smax.romanov@nginx.com task = &task->thread->engine->task; 2117123Smax.romanov@nginx.com 211853Sigor@sysoev.ru nxt_free(listen); 211953Sigor@sysoev.ru 212053Sigor@sysoev.ru nxt_router_listen_socket_release(task, joint); 212153Sigor@sysoev.ru } 212253Sigor@sysoev.ru 212353Sigor@sysoev.ru 212453Sigor@sysoev.ru static void 212553Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, 212653Sigor@sysoev.ru nxt_socket_conf_joint_t *joint) 212753Sigor@sysoev.ru { 2128118Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2129115Sigor@sysoev.ru nxt_router_socket_t *rtsk; 213053Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 213153Sigor@sysoev.ru 2132118Sigor@sysoev.ru skcf = joint->socket_conf; 2133118Sigor@sysoev.ru rtsk = skcf->socket; 2134118Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 213553Sigor@sysoev.ru 213653Sigor@sysoev.ru nxt_thread_spin_lock(lock); 213753Sigor@sysoev.ru 2138163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket release: rtsk->count %D", 2139163Smax.romanov@nginx.com task->thread->engine, rtsk->count); 2140163Smax.romanov@nginx.com 2141115Sigor@sysoev.ru if (--rtsk->count != 0) { 2142115Sigor@sysoev.ru rtsk = NULL; 214353Sigor@sysoev.ru } 214453Sigor@sysoev.ru 214553Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 214653Sigor@sysoev.ru 2147115Sigor@sysoev.ru if (rtsk != NULL) { 2148115Sigor@sysoev.ru nxt_socket_close(task, rtsk->fd); 2149115Sigor@sysoev.ru nxt_free(rtsk); 2150118Sigor@sysoev.ru skcf->socket = NULL; 215153Sigor@sysoev.ru } 215253Sigor@sysoev.ru 215353Sigor@sysoev.ru nxt_router_conf_release(task, joint); 215453Sigor@sysoev.ru } 215553Sigor@sysoev.ru 215653Sigor@sysoev.ru 215753Sigor@sysoev.ru static void 215853Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint) 215953Sigor@sysoev.ru { 2160156Sigor@sysoev.ru nxt_bool_t exit; 216153Sigor@sysoev.ru nxt_socket_conf_t *skcf; 216253Sigor@sysoev.ru nxt_router_conf_t *rtcf; 2163313Sigor@sysoev.ru nxt_event_engine_t *engine; 216453Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 216553Sigor@sysoev.ru 2166163Smax.romanov@nginx.com nxt_debug(task, "conf joint %p count: %D", joint, joint->count); 216753Sigor@sysoev.ru 216853Sigor@sysoev.ru if (--joint->count != 0) { 216953Sigor@sysoev.ru return; 217053Sigor@sysoev.ru } 217153Sigor@sysoev.ru 217253Sigor@sysoev.ru nxt_queue_remove(&joint->link); 217353Sigor@sysoev.ru 217453Sigor@sysoev.ru skcf = joint->socket_conf; 217553Sigor@sysoev.ru rtcf = skcf->router_conf; 217653Sigor@sysoev.ru lock = &rtcf->router->lock; 217753Sigor@sysoev.ru 217853Sigor@sysoev.ru nxt_thread_spin_lock(lock); 217953Sigor@sysoev.ru 2180163Smax.romanov@nginx.com nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count, 2181163Smax.romanov@nginx.com rtcf, rtcf->count); 2182163Smax.romanov@nginx.com 218353Sigor@sysoev.ru if (--skcf->count != 0) { 218453Sigor@sysoev.ru rtcf = NULL; 218553Sigor@sysoev.ru 218653Sigor@sysoev.ru } else { 218753Sigor@sysoev.ru nxt_queue_remove(&skcf->link); 218853Sigor@sysoev.ru 218953Sigor@sysoev.ru if (--rtcf->count != 0) { 219053Sigor@sysoev.ru rtcf = NULL; 219153Sigor@sysoev.ru } 219253Sigor@sysoev.ru } 219353Sigor@sysoev.ru 219453Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 219553Sigor@sysoev.ru 2196141Smax.romanov@nginx.com /* TODO remove engine->port */ 2197141Smax.romanov@nginx.com /* TODO excude from connected ports */ 2198141Smax.romanov@nginx.com 2199156Sigor@sysoev.ru /* The joint content can be used before memory pool destruction. */ 2200313Sigor@sysoev.ru engine = joint->engine; 2201313Sigor@sysoev.ru exit = (engine->shutdown && nxt_queue_is_empty(&engine->joints)); 2202156Sigor@sysoev.ru 220353Sigor@sysoev.ru if (rtcf != NULL) { 2204115Sigor@sysoev.ru nxt_debug(task, "old router conf is destroyed"); 2205131Smax.romanov@nginx.com 2206131Smax.romanov@nginx.com nxt_mp_thread_adopt(rtcf->mem_pool); 2207131Smax.romanov@nginx.com 220865Sigor@sysoev.ru nxt_mp_destroy(rtcf->mem_pool); 220953Sigor@sysoev.ru } 221053Sigor@sysoev.ru 2211156Sigor@sysoev.ru if (exit) { 221253Sigor@sysoev.ru nxt_thread_exit(task->thread); 221353Sigor@sysoev.ru } 221453Sigor@sysoev.ru } 221553Sigor@sysoev.ru 221653Sigor@sysoev.ru 221753Sigor@sysoev.ru static void 221853Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data) 221953Sigor@sysoev.ru { 2220141Smax.romanov@nginx.com nxt_port_t *port; 222153Sigor@sysoev.ru nxt_thread_link_t *link; 222253Sigor@sysoev.ru nxt_event_engine_t *engine; 222353Sigor@sysoev.ru nxt_thread_handle_t handle; 222453Sigor@sysoev.ru 222558Svbart@nginx.com handle = (nxt_thread_handle_t) obj; 222653Sigor@sysoev.ru link = data; 222753Sigor@sysoev.ru 222853Sigor@sysoev.ru nxt_thread_wait(handle); 222953Sigor@sysoev.ru 223053Sigor@sysoev.ru engine = link->engine; 223153Sigor@sysoev.ru 223253Sigor@sysoev.ru nxt_queue_remove(&engine->link); 223353Sigor@sysoev.ru 2234141Smax.romanov@nginx.com port = engine->port; 2235141Smax.romanov@nginx.com 2236141Smax.romanov@nginx.com // TODO notify all apps 2237141Smax.romanov@nginx.com 2238343Smax.romanov@nginx.com port->engine = task->thread->engine; 2239163Smax.romanov@nginx.com nxt_mp_thread_adopt(port->mem_pool); 2240343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 2241163Smax.romanov@nginx.com 2242163Smax.romanov@nginx.com nxt_mp_thread_adopt(engine->mem_pool); 224363Sigor@sysoev.ru nxt_mp_destroy(engine->mem_pool); 224453Sigor@sysoev.ru 224553Sigor@sysoev.ru nxt_event_engine_free(engine); 224653Sigor@sysoev.ru 224753Sigor@sysoev.ru nxt_free(link); 224853Sigor@sysoev.ru } 224953Sigor@sysoev.ru 225053Sigor@sysoev.ru 2251206Smax.romanov@nginx.com static const nxt_conn_state_t nxt_router_conn_read_header_state 225253Sigor@sysoev.ru nxt_aligned(64) = 225353Sigor@sysoev.ru { 225453Sigor@sysoev.ru .ready_handler = nxt_router_conn_http_header_parse, 225553Sigor@sysoev.ru .close_handler = nxt_router_conn_close, 225653Sigor@sysoev.ru .error_handler = nxt_router_conn_error, 225753Sigor@sysoev.ru 225853Sigor@sysoev.ru .timer_handler = nxt_router_conn_timeout, 225953Sigor@sysoev.ru .timer_value = nxt_router_conn_timeout_value, 226053Sigor@sysoev.ru .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout), 226153Sigor@sysoev.ru }; 226253Sigor@sysoev.ru 226353Sigor@sysoev.ru 2264206Smax.romanov@nginx.com static const nxt_conn_state_t nxt_router_conn_read_body_state 2265206Smax.romanov@nginx.com nxt_aligned(64) = 2266206Smax.romanov@nginx.com { 2267206Smax.romanov@nginx.com .ready_handler = nxt_router_conn_http_body_read, 2268206Smax.romanov@nginx.com .close_handler = nxt_router_conn_close, 2269206Smax.romanov@nginx.com .error_handler = nxt_router_conn_error, 2270206Smax.romanov@nginx.com 2271206Smax.romanov@nginx.com .timer_handler = nxt_router_conn_timeout, 2272206Smax.romanov@nginx.com .timer_value = nxt_router_conn_timeout_value, 2273206Smax.romanov@nginx.com .timer_data = offsetof(nxt_socket_conf_t, body_read_timeout), 2274206Smax.romanov@nginx.com .timer_autoreset = 1, 2275206Smax.romanov@nginx.com }; 2276206Smax.romanov@nginx.com 2277206Smax.romanov@nginx.com 227853Sigor@sysoev.ru static void 227953Sigor@sysoev.ru nxt_router_conn_init(nxt_task_t *task, void *obj, void *data) 228053Sigor@sysoev.ru { 228153Sigor@sysoev.ru size_t size; 228262Sigor@sysoev.ru nxt_conn_t *c; 228353Sigor@sysoev.ru nxt_event_engine_t *engine; 228453Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 228553Sigor@sysoev.ru 228653Sigor@sysoev.ru c = obj; 228753Sigor@sysoev.ru joint = data; 228853Sigor@sysoev.ru 228953Sigor@sysoev.ru nxt_debug(task, "router conn init"); 229053Sigor@sysoev.ru 229153Sigor@sysoev.ru joint->count++; 229253Sigor@sysoev.ru 229353Sigor@sysoev.ru size = joint->socket_conf->header_buffer_size; 229453Sigor@sysoev.ru c->read = nxt_buf_mem_alloc(c->mem_pool, size, 0); 229553Sigor@sysoev.ru 229653Sigor@sysoev.ru c->socket.data = NULL; 229753Sigor@sysoev.ru 229853Sigor@sysoev.ru engine = task->thread->engine; 229953Sigor@sysoev.ru c->read_work_queue = &engine->fast_work_queue; 230053Sigor@sysoev.ru c->write_work_queue = &engine->fast_work_queue; 230153Sigor@sysoev.ru 2302206Smax.romanov@nginx.com c->read_state = &nxt_router_conn_read_header_state; 230353Sigor@sysoev.ru 230462Sigor@sysoev.ru nxt_conn_read(engine, c); 230553Sigor@sysoev.ru } 230653Sigor@sysoev.ru 230753Sigor@sysoev.ru 230862Sigor@sysoev.ru static const nxt_conn_state_t nxt_router_conn_write_state 230953Sigor@sysoev.ru nxt_aligned(64) = 231053Sigor@sysoev.ru { 231188Smax.romanov@nginx.com .ready_handler = nxt_router_conn_ready, 231253Sigor@sysoev.ru .close_handler = nxt_router_conn_close, 231353Sigor@sysoev.ru .error_handler = nxt_router_conn_error, 231453Sigor@sysoev.ru }; 231553Sigor@sysoev.ru 231653Sigor@sysoev.ru 231753Sigor@sysoev.ru static void 2318318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2319318Smax.romanov@nginx.com void *data) 232088Smax.romanov@nginx.com { 232188Smax.romanov@nginx.com size_t dump_size; 2322194Smax.romanov@nginx.com nxt_buf_t *b, *last; 232388Smax.romanov@nginx.com nxt_conn_t *c; 232488Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 232588Smax.romanov@nginx.com 232688Smax.romanov@nginx.com b = msg->buf; 2327318Smax.romanov@nginx.com rc = data; 232888Smax.romanov@nginx.com 232988Smax.romanov@nginx.com c = rc->conn; 233088Smax.romanov@nginx.com 233188Smax.romanov@nginx.com dump_size = nxt_buf_used_size(b); 233288Smax.romanov@nginx.com 233388Smax.romanov@nginx.com if (dump_size > 300) { 233488Smax.romanov@nginx.com dump_size = 300; 233588Smax.romanov@nginx.com } 233688Smax.romanov@nginx.com 2337119Smax.romanov@nginx.com nxt_debug(task, "%srouter app data (%z): %*s", 233888Smax.romanov@nginx.com msg->port_msg.last ? "last " : "", msg->size, dump_size, 233988Smax.romanov@nginx.com b->mem.pos); 234088Smax.romanov@nginx.com 234188Smax.romanov@nginx.com if (msg->size == 0) { 234288Smax.romanov@nginx.com b = NULL; 234388Smax.romanov@nginx.com } 234488Smax.romanov@nginx.com 234588Smax.romanov@nginx.com if (msg->port_msg.last != 0) { 234688Smax.romanov@nginx.com nxt_debug(task, "router data create last buf"); 234788Smax.romanov@nginx.com 234888Smax.romanov@nginx.com last = nxt_buf_sync_alloc(c->mem_pool, NXT_BUF_SYNC_LAST); 234988Smax.romanov@nginx.com if (nxt_slow_path(last == NULL)) { 235088Smax.romanov@nginx.com /* TODO pogorevaTb */ 235188Smax.romanov@nginx.com } 235288Smax.romanov@nginx.com 235388Smax.romanov@nginx.com nxt_buf_chain_add(&b, last); 2354167Smax.romanov@nginx.com 2355343Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 235688Smax.romanov@nginx.com } 235788Smax.romanov@nginx.com 235888Smax.romanov@nginx.com if (b == NULL) { 235988Smax.romanov@nginx.com return; 236088Smax.romanov@nginx.com } 236188Smax.romanov@nginx.com 2362206Smax.romanov@nginx.com if (msg->buf == b) { 2363206Smax.romanov@nginx.com /* Disable instant buffer completion/re-using by port. */ 2364206Smax.romanov@nginx.com msg->buf = NULL; 2365206Smax.romanov@nginx.com } 2366194Smax.romanov@nginx.com 236788Smax.romanov@nginx.com if (c->write == NULL) { 236888Smax.romanov@nginx.com c->write = b; 236988Smax.romanov@nginx.com c->write_state = &nxt_router_conn_write_state; 237088Smax.romanov@nginx.com 237188Smax.romanov@nginx.com nxt_conn_write(task->thread->engine, c); 2372277Sigor@sysoev.ru 237388Smax.romanov@nginx.com } else { 237488Smax.romanov@nginx.com nxt_debug(task, "router data attach out bufs to existing chain"); 237588Smax.romanov@nginx.com 237688Smax.romanov@nginx.com nxt_buf_chain_add(&c->write, b); 237788Smax.romanov@nginx.com } 237888Smax.romanov@nginx.com } 237988Smax.romanov@nginx.com 2380277Sigor@sysoev.ru 2381318Smax.romanov@nginx.com static void 2382318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2383318Smax.romanov@nginx.com void *data) 2384318Smax.romanov@nginx.com { 2385318Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 2386318Smax.romanov@nginx.com 2387318Smax.romanov@nginx.com rc = data; 2388318Smax.romanov@nginx.com 2389318Smax.romanov@nginx.com nxt_router_gen_error(task, rc->conn, 500, 2390318Smax.romanov@nginx.com "Application terminated unexpectedly"); 2391318Smax.romanov@nginx.com 2392343Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 2393318Smax.romanov@nginx.com } 2394318Smax.romanov@nginx.com 2395318Smax.romanov@nginx.com 2396141Smax.romanov@nginx.com nxt_inline const char * 2397141Smax.romanov@nginx.com nxt_router_text_by_code(int code) 2398141Smax.romanov@nginx.com { 2399141Smax.romanov@nginx.com switch (code) { 2400141Smax.romanov@nginx.com case 400: return "Bad request"; 2401141Smax.romanov@nginx.com case 404: return "Not found"; 2402141Smax.romanov@nginx.com case 403: return "Forbidden"; 2403206Smax.romanov@nginx.com case 408: return "Request Timeout"; 2404206Smax.romanov@nginx.com case 411: return "Length Required"; 2405206Smax.romanov@nginx.com case 413: return "Request Entity Too Large"; 2406141Smax.romanov@nginx.com case 500: 2407141Smax.romanov@nginx.com default: return "Internal server error"; 2408141Smax.romanov@nginx.com } 2409141Smax.romanov@nginx.com } 2410141Smax.romanov@nginx.com 2411163Smax.romanov@nginx.com 2412163Smax.romanov@nginx.com static nxt_buf_t * 2413163Smax.romanov@nginx.com nxt_router_get_error_buf(nxt_task_t *task, nxt_mp_t *mp, int code, 2414345Smax.romanov@nginx.com const char* str) 241588Smax.romanov@nginx.com { 2416345Smax.romanov@nginx.com nxt_buf_t *b, *last; 2417345Smax.romanov@nginx.com 2418345Smax.romanov@nginx.com b = nxt_buf_mem_alloc(mp, 16384, 0); 2419141Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 2420163Smax.romanov@nginx.com return NULL; 2421141Smax.romanov@nginx.com } 2422141Smax.romanov@nginx.com 2423141Smax.romanov@nginx.com b->mem.free = nxt_sprintf(b->mem.free, b->mem.end, 2424141Smax.romanov@nginx.com "HTTP/1.0 %d %s\r\n" 2425141Smax.romanov@nginx.com "Content-Type: text/plain\r\n" 2426141Smax.romanov@nginx.com "Connection: close\r\n\r\n", 2427141Smax.romanov@nginx.com code, nxt_router_text_by_code(code)); 2428141Smax.romanov@nginx.com 2429345Smax.romanov@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str, nxt_strlen(str)); 2430345Smax.romanov@nginx.com 2431345Smax.romanov@nginx.com nxt_log_alert(task->log, "error %d: %s", code, str); 2432345Smax.romanov@nginx.com 2433345Smax.romanov@nginx.com last = nxt_buf_sync_alloc(mp, NXT_BUF_SYNC_LAST); 2434163Smax.romanov@nginx.com 2435141Smax.romanov@nginx.com if (nxt_slow_path(last == NULL)) { 2436345Smax.romanov@nginx.com nxt_mp_free(mp, b); 2437163Smax.romanov@nginx.com return NULL; 2438141Smax.romanov@nginx.com } 2439141Smax.romanov@nginx.com 2440141Smax.romanov@nginx.com nxt_buf_chain_add(&b, last); 2441141Smax.romanov@nginx.com 2442163Smax.romanov@nginx.com return b; 2443163Smax.romanov@nginx.com } 2444163Smax.romanov@nginx.com 2445163Smax.romanov@nginx.com 2446163Smax.romanov@nginx.com 2447163Smax.romanov@nginx.com static void 2448163Smax.romanov@nginx.com nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code, 2449345Smax.romanov@nginx.com const char* str) 2450163Smax.romanov@nginx.com { 2451318Smax.romanov@nginx.com nxt_mp_t *mp; 2452163Smax.romanov@nginx.com nxt_buf_t *b; 2453163Smax.romanov@nginx.com 2454318Smax.romanov@nginx.com /* TODO: fix when called in the middle of response */ 2455318Smax.romanov@nginx.com 2456345Smax.romanov@nginx.com mp = c->mem_pool; 2457345Smax.romanov@nginx.com 2458345Smax.romanov@nginx.com b = nxt_router_get_error_buf(task, mp, code, str); 2459163Smax.romanov@nginx.com 2460273Smax.romanov@nginx.com if (c->socket.fd == -1) { 2461345Smax.romanov@nginx.com nxt_mp_free(mp, b->next); 2462345Smax.romanov@nginx.com nxt_mp_free(mp, b); 2463273Smax.romanov@nginx.com return; 2464273Smax.romanov@nginx.com } 2465273Smax.romanov@nginx.com 2466141Smax.romanov@nginx.com if (c->write == NULL) { 2467141Smax.romanov@nginx.com c->write = b; 2468141Smax.romanov@nginx.com c->write_state = &nxt_router_conn_write_state; 2469141Smax.romanov@nginx.com 2470141Smax.romanov@nginx.com nxt_conn_write(task->thread->engine, c); 2471277Sigor@sysoev.ru 2472141Smax.romanov@nginx.com } else { 2473141Smax.romanov@nginx.com nxt_debug(task, "router data attach out bufs to existing chain"); 2474141Smax.romanov@nginx.com 2475141Smax.romanov@nginx.com nxt_buf_chain_add(&c->write, b); 2476141Smax.romanov@nginx.com } 2477141Smax.romanov@nginx.com } 2478141Smax.romanov@nginx.com 2479141Smax.romanov@nginx.com 2480141Smax.romanov@nginx.com static void 2481343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2482343Smax.romanov@nginx.com void *data) 2483192Smax.romanov@nginx.com { 2484343Smax.romanov@nginx.com nxt_app_t *app; 2485343Smax.romanov@nginx.com nxt_port_t *port; 2486343Smax.romanov@nginx.com 2487343Smax.romanov@nginx.com app = data; 2488347Smax.romanov@nginx.com port = msg->u.new_port; 2489343Smax.romanov@nginx.com 2490343Smax.romanov@nginx.com nxt_assert(app != NULL); 2491343Smax.romanov@nginx.com nxt_assert(port != NULL); 2492343Smax.romanov@nginx.com 2493343Smax.romanov@nginx.com port->app = app; 2494343Smax.romanov@nginx.com 2495343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2496343Smax.romanov@nginx.com 2497343Smax.romanov@nginx.com nxt_assert(app->pending_workers != 0); 2498343Smax.romanov@nginx.com 2499343Smax.romanov@nginx.com app->pending_workers--; 2500343Smax.romanov@nginx.com app->workers++; 2501343Smax.romanov@nginx.com 2502343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2503343Smax.romanov@nginx.com 2504343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p new port ready", &app->name, app); 2505343Smax.romanov@nginx.com 2506343Smax.romanov@nginx.com nxt_router_app_port_release(task, port, 0, 0); 2507192Smax.romanov@nginx.com } 2508192Smax.romanov@nginx.com 2509192Smax.romanov@nginx.com 2510192Smax.romanov@nginx.com static void 2511343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2512343Smax.romanov@nginx.com void *data) 2513192Smax.romanov@nginx.com { 2514318Smax.romanov@nginx.com nxt_app_t *app; 2515318Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2516318Smax.romanov@nginx.com nxt_req_app_link_t *ra; 2517343Smax.romanov@nginx.com 2518343Smax.romanov@nginx.com app = data; 2519343Smax.romanov@nginx.com 2520343Smax.romanov@nginx.com nxt_assert(app != NULL); 2521343Smax.romanov@nginx.com 2522343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start error", &app->name, app); 2523343Smax.romanov@nginx.com 2524343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2525343Smax.romanov@nginx.com 2526343Smax.romanov@nginx.com nxt_assert(app->pending_workers != 0); 2527343Smax.romanov@nginx.com 2528343Smax.romanov@nginx.com app->pending_workers--; 2529318Smax.romanov@nginx.com 2530318Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->requests)) { 2531318Smax.romanov@nginx.com lnk = nxt_queue_last(&app->requests); 2532318Smax.romanov@nginx.com nxt_queue_remove(lnk); 2533343Smax.romanov@nginx.com lnk->next = NULL; 2534318Smax.romanov@nginx.com 2535318Smax.romanov@nginx.com ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link); 2536318Smax.romanov@nginx.com 2537343Smax.romanov@nginx.com } else { 2538343Smax.romanov@nginx.com ra = NULL; 2539343Smax.romanov@nginx.com } 2540343Smax.romanov@nginx.com 2541343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2542343Smax.romanov@nginx.com 2543343Smax.romanov@nginx.com if (ra != NULL) { 2544318Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p abort next stream #%uD", 2545318Smax.romanov@nginx.com &app->name, app, ra->stream); 2546318Smax.romanov@nginx.com 2547318Smax.romanov@nginx.com nxt_router_ra_abort(task, ra, ra->work.data); 2548318Smax.romanov@nginx.com } 2549192Smax.romanov@nginx.com 2550343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 2551192Smax.romanov@nginx.com } 2552192Smax.romanov@nginx.com 2553192Smax.romanov@nginx.com 2554343Smax.romanov@nginx.com void 2555343Smax.romanov@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i) 2556141Smax.romanov@nginx.com { 2557343Smax.romanov@nginx.com int c; 2558343Smax.romanov@nginx.com 2559343Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&app->use_count, i); 2560343Smax.romanov@nginx.com 2561343Smax.romanov@nginx.com if (i < 0 && c == -i) { 2562343Smax.romanov@nginx.com 2563343Smax.romanov@nginx.com nxt_assert(app->live == 0); 2564343Smax.romanov@nginx.com nxt_assert(app->workers == 0); 2565343Smax.romanov@nginx.com nxt_assert(app->pending_workers == 0); 2566343Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->requests) != 0); 2567343Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->ports) != 0); 2568343Smax.romanov@nginx.com 2569163Smax.romanov@nginx.com nxt_thread_mutex_destroy(&app->mutex); 2570163Smax.romanov@nginx.com nxt_free(app); 2571163Smax.romanov@nginx.com } 2572343Smax.romanov@nginx.com } 2573343Smax.romanov@nginx.com 2574343Smax.romanov@nginx.com 2575343Smax.romanov@nginx.com nxt_inline nxt_port_t * 2576343Smax.romanov@nginx.com nxt_router_app_get_port_unsafe(nxt_app_t *app, int *use_delta) 2577343Smax.romanov@nginx.com { 2578343Smax.romanov@nginx.com nxt_port_t *port; 2579343Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2580343Smax.romanov@nginx.com 2581343Smax.romanov@nginx.com lnk = nxt_queue_first(&app->ports); 2582343Smax.romanov@nginx.com nxt_queue_remove(lnk); 2583343Smax.romanov@nginx.com 2584343Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, app_link); 2585343Smax.romanov@nginx.com 2586343Smax.romanov@nginx.com port->app_requests++; 2587343Smax.romanov@nginx.com 2588343Smax.romanov@nginx.com if (app->live && 2589343Smax.romanov@nginx.com (app->max_pending_responses == 0 || 2590343Smax.romanov@nginx.com (port->app_requests - port->app_responses) < 2591343Smax.romanov@nginx.com app->max_pending_responses) ) 2592277Sigor@sysoev.ru { 2593343Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, lnk); 2594343Smax.romanov@nginx.com 2595343Smax.romanov@nginx.com } else { 2596343Smax.romanov@nginx.com lnk->next = NULL; 2597343Smax.romanov@nginx.com 2598343Smax.romanov@nginx.com (*use_delta)--; 2599167Smax.romanov@nginx.com } 2600167Smax.romanov@nginx.com 2601343Smax.romanov@nginx.com return port; 2602163Smax.romanov@nginx.com } 2603163Smax.romanov@nginx.com 2604163Smax.romanov@nginx.com 2605141Smax.romanov@nginx.com static nxt_port_t * 2606343Smax.romanov@nginx.com nxt_router_app_get_idle_port(nxt_app_t *app) 2607141Smax.romanov@nginx.com { 2608343Smax.romanov@nginx.com nxt_port_t *port; 2609141Smax.romanov@nginx.com 2610141Smax.romanov@nginx.com port = NULL; 2611141Smax.romanov@nginx.com 2612141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2613141Smax.romanov@nginx.com 2614343Smax.romanov@nginx.com nxt_queue_each(port, &app->ports, nxt_port_t, app_link) { 2615343Smax.romanov@nginx.com 2616343Smax.romanov@nginx.com if (port->app_requests > port->app_responses) { 2617343Smax.romanov@nginx.com port = NULL; 2618343Smax.romanov@nginx.com 2619343Smax.romanov@nginx.com continue; 2620343Smax.romanov@nginx.com } 2621343Smax.romanov@nginx.com 2622343Smax.romanov@nginx.com nxt_queue_remove(&port->app_link); 2623343Smax.romanov@nginx.com port->app_link.next = NULL; 2624343Smax.romanov@nginx.com 2625343Smax.romanov@nginx.com break; 2626343Smax.romanov@nginx.com 2627343Smax.romanov@nginx.com } nxt_queue_loop; 2628141Smax.romanov@nginx.com 2629141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2630141Smax.romanov@nginx.com 2631141Smax.romanov@nginx.com return port; 2632141Smax.romanov@nginx.com } 2633141Smax.romanov@nginx.com 2634141Smax.romanov@nginx.com 2635141Smax.romanov@nginx.com static void 2636343Smax.romanov@nginx.com nxt_router_app_process_request(nxt_task_t *task, void *obj, void *data) 2637141Smax.romanov@nginx.com { 2638343Smax.romanov@nginx.com nxt_app_t *app; 2639343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 2640343Smax.romanov@nginx.com 2641343Smax.romanov@nginx.com app = obj; 2642343Smax.romanov@nginx.com ra = data; 2643141Smax.romanov@nginx.com 2644141Smax.romanov@nginx.com nxt_assert(app != NULL); 2645343Smax.romanov@nginx.com nxt_assert(ra != NULL); 2646343Smax.romanov@nginx.com nxt_assert(ra->app_port != NULL); 2647343Smax.romanov@nginx.com 2648343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p process next stream #%uD", 2649343Smax.romanov@nginx.com &app->name, app, ra->stream); 2650343Smax.romanov@nginx.com 2651343Smax.romanov@nginx.com nxt_router_process_http_request_mp(task, ra); 2652343Smax.romanov@nginx.com } 2653343Smax.romanov@nginx.com 2654343Smax.romanov@nginx.com 2655343Smax.romanov@nginx.com static void 2656343Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port, 2657343Smax.romanov@nginx.com uint32_t request_failed, uint32_t got_response) 2658343Smax.romanov@nginx.com { 2659343Smax.romanov@nginx.com int use_delta, ra_use_delta; 2660343Smax.romanov@nginx.com nxt_app_t *app; 2661343Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2662343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 2663343Smax.romanov@nginx.com 2664343Smax.romanov@nginx.com nxt_assert(port != NULL); 2665343Smax.romanov@nginx.com nxt_assert(port->app != NULL); 2666343Smax.romanov@nginx.com 2667343Smax.romanov@nginx.com app = port->app; 2668343Smax.romanov@nginx.com 2669343Smax.romanov@nginx.com use_delta = (request_failed == 0 && got_response == 0) ? 0 : -1; 2670343Smax.romanov@nginx.com 2671343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2672343Smax.romanov@nginx.com 2673343Smax.romanov@nginx.com port->app_requests -= request_failed; 2674343Smax.romanov@nginx.com port->app_responses += got_response; 2675343Smax.romanov@nginx.com 2676343Smax.romanov@nginx.com if (app->live != 0 && 2677343Smax.romanov@nginx.com port->pair[1] != -1 && 2678343Smax.romanov@nginx.com port->app_link.next == NULL && 2679343Smax.romanov@nginx.com (app->max_pending_responses == 0 || 2680343Smax.romanov@nginx.com (port->app_requests - port->app_responses) < 2681343Smax.romanov@nginx.com app->max_pending_responses) ) 2682343Smax.romanov@nginx.com { 2683343Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &port->app_link); 2684343Smax.romanov@nginx.com use_delta++; 2685141Smax.romanov@nginx.com } 2686141Smax.romanov@nginx.com 2687343Smax.romanov@nginx.com if (app->live != 0 && 2688343Smax.romanov@nginx.com !nxt_queue_is_empty(&app->ports) && 2689343Smax.romanov@nginx.com !nxt_queue_is_empty(&app->requests)) 2690343Smax.romanov@nginx.com { 2691141Smax.romanov@nginx.com lnk = nxt_queue_first(&app->requests); 2692141Smax.romanov@nginx.com nxt_queue_remove(lnk); 2693343Smax.romanov@nginx.com lnk->next = NULL; 2694141Smax.romanov@nginx.com 2695167Smax.romanov@nginx.com ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link); 2696167Smax.romanov@nginx.com 2697343Smax.romanov@nginx.com ra_use_delta = 1; 2698343Smax.romanov@nginx.com ra->app_port = nxt_router_app_get_port_unsafe(app, &ra_use_delta); 2699343Smax.romanov@nginx.com 2700343Smax.romanov@nginx.com } else { 2701343Smax.romanov@nginx.com ra = NULL; 2702343Smax.romanov@nginx.com ra_use_delta = 0; 2703141Smax.romanov@nginx.com } 2704141Smax.romanov@nginx.com 2705343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2706343Smax.romanov@nginx.com 2707343Smax.romanov@nginx.com if (ra != NULL) { 2708343Smax.romanov@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 2709343Smax.romanov@nginx.com nxt_router_app_process_request, 2710343Smax.romanov@nginx.com &task->thread->engine->task, app, ra); 2711343Smax.romanov@nginx.com 2712343Smax.romanov@nginx.com goto adjust_use; 2713343Smax.romanov@nginx.com } 2714343Smax.romanov@nginx.com 2715343Smax.romanov@nginx.com /* ? */ 2716163Smax.romanov@nginx.com if (port->pair[1] == -1) { 2717343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)", 2718343Smax.romanov@nginx.com &app->name, app, port, port->pid); 2719343Smax.romanov@nginx.com 2720343Smax.romanov@nginx.com goto adjust_use; 2721163Smax.romanov@nginx.com } 2722163Smax.romanov@nginx.com 2723343Smax.romanov@nginx.com if (app->live == 0) { 2724167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p is not alive, send QUIT to port", 2725167Smax.romanov@nginx.com &app->name, app); 2726163Smax.romanov@nginx.com 2727163Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, 2728163Smax.romanov@nginx.com -1, 0, 0, NULL); 2729163Smax.romanov@nginx.com 2730343Smax.romanov@nginx.com goto adjust_use; 2731163Smax.romanov@nginx.com } 2732163Smax.romanov@nginx.com 2733167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p requests queue is empty, keep the port", 2734167Smax.romanov@nginx.com &app->name, app); 2735141Smax.romanov@nginx.com 2736343Smax.romanov@nginx.com adjust_use: 2737343Smax.romanov@nginx.com 2738343Smax.romanov@nginx.com if (use_delta != 0) { 2739343Smax.romanov@nginx.com nxt_port_use(task, port, use_delta); 2740343Smax.romanov@nginx.com } 2741343Smax.romanov@nginx.com 2742343Smax.romanov@nginx.com if (ra_use_delta != 0) { 2743343Smax.romanov@nginx.com nxt_port_use(task, ra->app_port, ra_use_delta); 2744343Smax.romanov@nginx.com } 2745141Smax.romanov@nginx.com } 2746141Smax.romanov@nginx.com 2747141Smax.romanov@nginx.com 2748343Smax.romanov@nginx.com void 2749343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port) 2750141Smax.romanov@nginx.com { 2751163Smax.romanov@nginx.com nxt_app_t *app; 2752343Smax.romanov@nginx.com nxt_bool_t unchain, start_worker; 2753141Smax.romanov@nginx.com 2754141Smax.romanov@nginx.com app = port->app; 2755343Smax.romanov@nginx.com 2756343Smax.romanov@nginx.com nxt_assert(app != NULL); 2757141Smax.romanov@nginx.com 2758141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2759141Smax.romanov@nginx.com 2760343Smax.romanov@nginx.com unchain = port->app_link.next != NULL; 2761343Smax.romanov@nginx.com 2762343Smax.romanov@nginx.com if (unchain) { 2763163Smax.romanov@nginx.com nxt_queue_remove(&port->app_link); 2764163Smax.romanov@nginx.com port->app_link.next = NULL; 2765343Smax.romanov@nginx.com } 2766343Smax.romanov@nginx.com 2767343Smax.romanov@nginx.com app->workers--; 2768343Smax.romanov@nginx.com 2769343Smax.romanov@nginx.com start_worker = app->live != 0 && 2770343Smax.romanov@nginx.com nxt_queue_is_empty(&app->requests) == 0 && 2771343Smax.romanov@nginx.com app->workers + app->pending_workers < app->max_workers; 2772343Smax.romanov@nginx.com 2773343Smax.romanov@nginx.com if (start_worker) { 2774343Smax.romanov@nginx.com app->pending_workers++; 2775163Smax.romanov@nginx.com } 2776141Smax.romanov@nginx.com 2777141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2778163Smax.romanov@nginx.com 2779343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p port %p close", &app->name, app, port); 2780343Smax.romanov@nginx.com 2781343Smax.romanov@nginx.com if (unchain) { 2782343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 2783163Smax.romanov@nginx.com } 2784163Smax.romanov@nginx.com 2785343Smax.romanov@nginx.com if (start_worker) { 2786343Smax.romanov@nginx.com nxt_router_start_worker(task, app); 2787343Smax.romanov@nginx.com } 2788141Smax.romanov@nginx.com } 2789141Smax.romanov@nginx.com 2790141Smax.romanov@nginx.com 2791167Smax.romanov@nginx.com static nxt_int_t 2792167Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_req_app_link_t *ra) 2793141Smax.romanov@nginx.com { 2794343Smax.romanov@nginx.com int use_delta; 2795343Smax.romanov@nginx.com nxt_int_t res; 2796141Smax.romanov@nginx.com nxt_app_t *app; 2797343Smax.romanov@nginx.com nxt_bool_t can_start_worker; 2798141Smax.romanov@nginx.com nxt_conn_t *c; 2799167Smax.romanov@nginx.com nxt_port_t *port; 2800318Smax.romanov@nginx.com nxt_event_engine_t *engine; 2801141Smax.romanov@nginx.com nxt_socket_conf_joint_t *joint; 2802141Smax.romanov@nginx.com 2803141Smax.romanov@nginx.com port = NULL; 2804343Smax.romanov@nginx.com use_delta = 1; 2805167Smax.romanov@nginx.com c = ra->rc->conn; 2806141Smax.romanov@nginx.com 2807141Smax.romanov@nginx.com joint = c->listen->socket.data; 2808141Smax.romanov@nginx.com app = joint->socket_conf->application; 2809141Smax.romanov@nginx.com 2810141Smax.romanov@nginx.com if (app == NULL) { 2811167Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, 2812141Smax.romanov@nginx.com "Application is NULL in socket_conf"); 2813141Smax.romanov@nginx.com return NXT_ERROR; 2814141Smax.romanov@nginx.com } 2815141Smax.romanov@nginx.com 2816343Smax.romanov@nginx.com ra->rc->app = app; 2817343Smax.romanov@nginx.com 2818343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 2819343Smax.romanov@nginx.com 2820318Smax.romanov@nginx.com engine = task->thread->engine; 2821318Smax.romanov@nginx.com 2822318Smax.romanov@nginx.com nxt_timer_disable(engine, &c->read_timer); 2823318Smax.romanov@nginx.com 2824318Smax.romanov@nginx.com if (app->timeout != 0) { 2825318Smax.romanov@nginx.com c->read_timer.handler = nxt_router_app_timeout; 2826318Smax.romanov@nginx.com nxt_timer_add(engine, &c->read_timer, app->timeout); 2827318Smax.romanov@nginx.com } 2828318Smax.romanov@nginx.com 2829*351Smax.romanov@nginx.com can_start_worker = 0; 2830*351Smax.romanov@nginx.com 2831343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2832343Smax.romanov@nginx.com 2833343Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->ports)) { 2834343Smax.romanov@nginx.com port = nxt_router_app_get_port_unsafe(app, &use_delta); 2835343Smax.romanov@nginx.com 2836343Smax.romanov@nginx.com } else { 2837*351Smax.romanov@nginx.com ra = nxt_router_ra_create(task, ra); 2838*351Smax.romanov@nginx.com 2839*351Smax.romanov@nginx.com if (nxt_fast_path(ra != NULL)) { 2840*351Smax.romanov@nginx.com nxt_queue_insert_tail(&app->requests, &ra->link); 2841*351Smax.romanov@nginx.com 2842*351Smax.romanov@nginx.com can_start_worker = (app->workers + app->pending_workers) < 2843*351Smax.romanov@nginx.com app->max_workers; 2844*351Smax.romanov@nginx.com if (can_start_worker) { 2845*351Smax.romanov@nginx.com app->pending_workers++; 2846*351Smax.romanov@nginx.com } 2847343Smax.romanov@nginx.com } 2848343Smax.romanov@nginx.com 2849343Smax.romanov@nginx.com port = NULL; 2850343Smax.romanov@nginx.com } 2851343Smax.romanov@nginx.com 2852343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2853141Smax.romanov@nginx.com 2854*351Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 2855*351Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Failed to allocate " 2856*351Smax.romanov@nginx.com "req<->app link"); 2857*351Smax.romanov@nginx.com return NXT_ERROR; 2858*351Smax.romanov@nginx.com } 2859*351Smax.romanov@nginx.com 2860141Smax.romanov@nginx.com if (port != NULL) { 2861343Smax.romanov@nginx.com nxt_debug(task, "already have port for app '%V' %p ", &app->name, app); 2862163Smax.romanov@nginx.com 2863167Smax.romanov@nginx.com ra->app_port = port; 2864343Smax.romanov@nginx.com 2865343Smax.romanov@nginx.com if (use_delta != 0) { 2866343Smax.romanov@nginx.com nxt_port_use(task, port, use_delta); 2867343Smax.romanov@nginx.com } 2868141Smax.romanov@nginx.com return NXT_OK; 2869141Smax.romanov@nginx.com } 2870141Smax.romanov@nginx.com 2871*351Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD allocated", ra->stream); 2872*351Smax.romanov@nginx.com 2873343Smax.romanov@nginx.com if (!can_start_worker) { 2874343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p too many running or pending workers", 2875343Smax.romanov@nginx.com &app->name, app); 2876343Smax.romanov@nginx.com 2877343Smax.romanov@nginx.com return NXT_AGAIN; 2878343Smax.romanov@nginx.com } 2879343Smax.romanov@nginx.com 2880343Smax.romanov@nginx.com res = nxt_router_start_worker(task, app); 2881343Smax.romanov@nginx.com 2882343Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 2883343Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Failed to start worker"); 2884343Smax.romanov@nginx.com 2885141Smax.romanov@nginx.com return NXT_ERROR; 2886141Smax.romanov@nginx.com } 2887141Smax.romanov@nginx.com 2888141Smax.romanov@nginx.com return NXT_AGAIN; 288988Smax.romanov@nginx.com } 289088Smax.romanov@nginx.com 289188Smax.romanov@nginx.com 289288Smax.romanov@nginx.com static void 289353Sigor@sysoev.ru nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, void *data) 289453Sigor@sysoev.ru { 2895206Smax.romanov@nginx.com size_t size; 289653Sigor@sysoev.ru nxt_int_t ret; 2897206Smax.romanov@nginx.com nxt_buf_t *buf; 289862Sigor@sysoev.ru nxt_conn_t *c; 2899268Sigor@sysoev.ru nxt_sockaddr_t *local; 290088Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 2901206Smax.romanov@nginx.com nxt_app_request_body_t *b; 290253Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 290388Smax.romanov@nginx.com nxt_app_request_header_t *h; 290453Sigor@sysoev.ru 290553Sigor@sysoev.ru c = obj; 290688Smax.romanov@nginx.com ap = data; 2907206Smax.romanov@nginx.com buf = c->read; 2908206Smax.romanov@nginx.com joint = c->listen->socket.data; 290953Sigor@sysoev.ru 291053Sigor@sysoev.ru nxt_debug(task, "router conn http header parse"); 291153Sigor@sysoev.ru 291288Smax.romanov@nginx.com if (ap == NULL) { 2913319Smax.romanov@nginx.com ap = nxt_app_http_req_init(task); 291488Smax.romanov@nginx.com if (nxt_slow_path(ap == NULL)) { 2915319Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, 2916319Smax.romanov@nginx.com "Failed to allocate parse context"); 291761Sigor@sysoev.ru return; 291861Sigor@sysoev.ru } 291988Smax.romanov@nginx.com 292088Smax.romanov@nginx.com c->socket.data = ap; 2921113Smax.romanov@nginx.com 2922113Smax.romanov@nginx.com ap->r.remote.start = nxt_sockaddr_address(c->remote); 2923113Smax.romanov@nginx.com ap->r.remote.length = c->remote->address_length; 2924206Smax.romanov@nginx.com 2925268Sigor@sysoev.ru local = joint->socket_conf->sockaddr; 2926268Sigor@sysoev.ru ap->r.local.start = nxt_sockaddr_address(local); 2927268Sigor@sysoev.ru ap->r.local.length = local->address_length; 2928268Sigor@sysoev.ru 2929206Smax.romanov@nginx.com ap->r.header.buf = buf; 293053Sigor@sysoev.ru } 293153Sigor@sysoev.ru 293288Smax.romanov@nginx.com h = &ap->r.header; 2933206Smax.romanov@nginx.com b = &ap->r.body; 2934206Smax.romanov@nginx.com 2935206Smax.romanov@nginx.com ret = nxt_app_http_req_header_parse(task, ap, buf); 2936206Smax.romanov@nginx.com 2937206Smax.romanov@nginx.com nxt_debug(task, "http parse request header: %d", ret); 293853Sigor@sysoev.ru 293953Sigor@sysoev.ru switch (nxt_expect(NXT_DONE, ret)) { 294053Sigor@sysoev.ru 294153Sigor@sysoev.ru case NXT_DONE: 294288Smax.romanov@nginx.com nxt_debug(task, "router request header parsing complete, " 294388Smax.romanov@nginx.com "content length: %O, preread: %uz", 2944206Smax.romanov@nginx.com h->parsed_content_length, nxt_buf_mem_used_size(&buf->mem)); 2945206Smax.romanov@nginx.com 2946206Smax.romanov@nginx.com if (b->done) { 2947206Smax.romanov@nginx.com nxt_router_process_http_request(task, c, ap); 2948206Smax.romanov@nginx.com 2949206Smax.romanov@nginx.com return; 2950206Smax.romanov@nginx.com } 2951206Smax.romanov@nginx.com 2952277Sigor@sysoev.ru if (joint->socket_conf->max_body_size > 0 2953277Sigor@sysoev.ru && (size_t) h->parsed_content_length 2954277Sigor@sysoev.ru > joint->socket_conf->max_body_size) 2955277Sigor@sysoev.ru { 2956206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 413, "Content-Length too big"); 2957206Smax.romanov@nginx.com return; 2958206Smax.romanov@nginx.com } 2959206Smax.romanov@nginx.com 2960206Smax.romanov@nginx.com if (nxt_buf_mem_free_size(&buf->mem) == 0) { 2961206Smax.romanov@nginx.com size = nxt_min(joint->socket_conf->body_buffer_size, 2962206Smax.romanov@nginx.com (size_t) h->parsed_content_length); 2963206Smax.romanov@nginx.com 2964206Smax.romanov@nginx.com buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0); 2965206Smax.romanov@nginx.com if (nxt_slow_path(buf->next == NULL)) { 2966206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Failed to allocate " 2967206Smax.romanov@nginx.com "buffer for request body"); 2968206Smax.romanov@nginx.com return; 2969206Smax.romanov@nginx.com } 2970206Smax.romanov@nginx.com 2971206Smax.romanov@nginx.com c->read = buf->next; 2972206Smax.romanov@nginx.com 2973206Smax.romanov@nginx.com b->preread_size += nxt_buf_mem_used_size(&buf->mem); 2974206Smax.romanov@nginx.com } 2975206Smax.romanov@nginx.com 2976206Smax.romanov@nginx.com if (b->buf == NULL) { 2977206Smax.romanov@nginx.com b->buf = c->read; 2978206Smax.romanov@nginx.com } 2979206Smax.romanov@nginx.com 2980206Smax.romanov@nginx.com c->read_state = &nxt_router_conn_read_body_state; 2981206Smax.romanov@nginx.com break; 2982206Smax.romanov@nginx.com 2983206Smax.romanov@nginx.com case NXT_ERROR: 2984206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 400, "Request header parse error"); 2985206Smax.romanov@nginx.com return; 2986206Smax.romanov@nginx.com 2987206Smax.romanov@nginx.com default: /* NXT_AGAIN */ 2988206Smax.romanov@nginx.com 2989206Smax.romanov@nginx.com if (c->read->mem.free == c->read->mem.end) { 2990206Smax.romanov@nginx.com size = joint->socket_conf->large_header_buffer_size; 2991206Smax.romanov@nginx.com 2992277Sigor@sysoev.ru if (size <= (size_t) nxt_buf_mem_used_size(&buf->mem) 2993277Sigor@sysoev.ru || ap->r.header.bufs 2994277Sigor@sysoev.ru >= joint->socket_conf->large_header_buffers) 2995277Sigor@sysoev.ru { 2996206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 413, 2997206Smax.romanov@nginx.com "Too long request headers"); 2998206Smax.romanov@nginx.com return; 2999206Smax.romanov@nginx.com } 3000206Smax.romanov@nginx.com 3001206Smax.romanov@nginx.com buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0); 3002206Smax.romanov@nginx.com if (nxt_slow_path(buf->next == NULL)) { 3003206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, 3004206Smax.romanov@nginx.com "Failed to allocate large header " 3005206Smax.romanov@nginx.com "buffer"); 3006206Smax.romanov@nginx.com return; 3007206Smax.romanov@nginx.com } 3008206Smax.romanov@nginx.com 3009206Smax.romanov@nginx.com ap->r.header.bufs++; 3010206Smax.romanov@nginx.com 3011206Smax.romanov@nginx.com size = c->read->mem.free - c->read->mem.pos; 3012206Smax.romanov@nginx.com 3013206Smax.romanov@nginx.com c->read = nxt_buf_cpy(buf->next, c->read->mem.pos, size); 3014206Smax.romanov@nginx.com } 3015206Smax.romanov@nginx.com 3016206Smax.romanov@nginx.com } 3017206Smax.romanov@nginx.com 3018206Smax.romanov@nginx.com nxt_conn_read(task->thread->engine, c); 3019206Smax.romanov@nginx.com } 3020206Smax.romanov@nginx.com 3021206Smax.romanov@nginx.com 3022206Smax.romanov@nginx.com static void 3023206Smax.romanov@nginx.com nxt_router_conn_http_body_read(nxt_task_t *task, void *obj, void *data) 3024206Smax.romanov@nginx.com { 3025206Smax.romanov@nginx.com size_t size; 3026206Smax.romanov@nginx.com nxt_int_t ret; 3027206Smax.romanov@nginx.com nxt_buf_t *buf; 3028206Smax.romanov@nginx.com nxt_conn_t *c; 3029206Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 3030206Smax.romanov@nginx.com nxt_app_request_body_t *b; 3031206Smax.romanov@nginx.com nxt_socket_conf_joint_t *joint; 3032206Smax.romanov@nginx.com nxt_app_request_header_t *h; 3033206Smax.romanov@nginx.com 3034206Smax.romanov@nginx.com c = obj; 3035206Smax.romanov@nginx.com ap = data; 3036206Smax.romanov@nginx.com buf = c->read; 3037206Smax.romanov@nginx.com 3038206Smax.romanov@nginx.com nxt_debug(task, "router conn http body read"); 3039206Smax.romanov@nginx.com 3040206Smax.romanov@nginx.com nxt_assert(ap != NULL); 3041206Smax.romanov@nginx.com 3042206Smax.romanov@nginx.com b = &ap->r.body; 3043206Smax.romanov@nginx.com h = &ap->r.header; 3044206Smax.romanov@nginx.com 3045206Smax.romanov@nginx.com ret = nxt_app_http_req_body_read(task, ap, buf); 3046206Smax.romanov@nginx.com 3047206Smax.romanov@nginx.com nxt_debug(task, "http read request body: %d", ret); 3048206Smax.romanov@nginx.com 3049206Smax.romanov@nginx.com switch (nxt_expect(NXT_DONE, ret)) { 3050206Smax.romanov@nginx.com 3051206Smax.romanov@nginx.com case NXT_DONE: 305288Smax.romanov@nginx.com nxt_router_process_http_request(task, c, ap); 305388Smax.romanov@nginx.com return; 305453Sigor@sysoev.ru 305553Sigor@sysoev.ru case NXT_ERROR: 3056206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Read body error"); 305753Sigor@sysoev.ru return; 305853Sigor@sysoev.ru 305953Sigor@sysoev.ru default: /* NXT_AGAIN */ 306053Sigor@sysoev.ru 3061206Smax.romanov@nginx.com if (nxt_buf_mem_free_size(&buf->mem) == 0) { 3062206Smax.romanov@nginx.com joint = c->listen->socket.data; 3063206Smax.romanov@nginx.com 3064206Smax.romanov@nginx.com b->preread_size += nxt_buf_mem_used_size(&buf->mem); 3065206Smax.romanov@nginx.com 3066206Smax.romanov@nginx.com size = nxt_min(joint->socket_conf->body_buffer_size, 3067206Smax.romanov@nginx.com (size_t) h->parsed_content_length - b->preread_size); 3068206Smax.romanov@nginx.com 3069206Smax.romanov@nginx.com buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0); 3070206Smax.romanov@nginx.com if (nxt_slow_path(buf->next == NULL)) { 3071206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Failed to allocate " 3072206Smax.romanov@nginx.com "buffer for request body"); 3073206Smax.romanov@nginx.com return; 307488Smax.romanov@nginx.com } 3075206Smax.romanov@nginx.com 3076206Smax.romanov@nginx.com c->read = buf->next; 307788Smax.romanov@nginx.com } 307888Smax.romanov@nginx.com 3079206Smax.romanov@nginx.com nxt_debug(task, "router request body read again, rest: %uz", 3080206Smax.romanov@nginx.com h->parsed_content_length - b->preread_size); 308188Smax.romanov@nginx.com } 308288Smax.romanov@nginx.com 308388Smax.romanov@nginx.com nxt_conn_read(task->thread->engine, c); 308488Smax.romanov@nginx.com } 308588Smax.romanov@nginx.com 308688Smax.romanov@nginx.com 308788Smax.romanov@nginx.com static void 308888Smax.romanov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_conn_t *c, 308988Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap) 309088Smax.romanov@nginx.com { 3091122Smax.romanov@nginx.com nxt_int_t res; 3092167Smax.romanov@nginx.com nxt_port_t *port; 309388Smax.romanov@nginx.com nxt_event_engine_t *engine; 3094*351Smax.romanov@nginx.com nxt_req_app_link_t ra_local, *ra; 309588Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 309688Smax.romanov@nginx.com 309788Smax.romanov@nginx.com engine = task->thread->engine; 309888Smax.romanov@nginx.com 3099318Smax.romanov@nginx.com rc = nxt_port_rpc_register_handler_ex(task, engine->port, 3100318Smax.romanov@nginx.com nxt_router_response_ready_handler, 3101318Smax.romanov@nginx.com nxt_router_response_error_handler, 3102318Smax.romanov@nginx.com sizeof(nxt_req_conn_link_t)); 3103122Smax.romanov@nginx.com 310488Smax.romanov@nginx.com if (nxt_slow_path(rc == NULL)) { 3105141Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Failed to allocate " 3106346Smax.romanov@nginx.com "req<->conn link"); 3107141Smax.romanov@nginx.com 3108141Smax.romanov@nginx.com return; 310988Smax.romanov@nginx.com } 311088Smax.romanov@nginx.com 3111318Smax.romanov@nginx.com rc->stream = nxt_port_rpc_ex_stream(rc); 3112318Smax.romanov@nginx.com rc->conn = c; 3113318Smax.romanov@nginx.com 3114318Smax.romanov@nginx.com nxt_queue_insert_tail(&c->requests, &rc->link); 3115318Smax.romanov@nginx.com 3116318Smax.romanov@nginx.com nxt_debug(task, "stream #%uD linked to conn %p at engine %p", 3117318Smax.romanov@nginx.com rc->stream, c, engine); 311853Sigor@sysoev.ru 3119346Smax.romanov@nginx.com rc->ap = ap; 3120346Smax.romanov@nginx.com c->socket.data = NULL; 3121346Smax.romanov@nginx.com 3122*351Smax.romanov@nginx.com ra = &ra_local; 3123*351Smax.romanov@nginx.com nxt_router_ra_init(task, ra, rc); 3124167Smax.romanov@nginx.com 3125167Smax.romanov@nginx.com res = nxt_router_app_port(task, ra); 3126141Smax.romanov@nginx.com 3127141Smax.romanov@nginx.com if (res != NXT_OK) { 3128141Smax.romanov@nginx.com return; 3129141Smax.romanov@nginx.com } 3130141Smax.romanov@nginx.com 3131167Smax.romanov@nginx.com port = ra->app_port; 3132141Smax.romanov@nginx.com 3133141Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 3134318Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Application port not found"); 3135141Smax.romanov@nginx.com return; 3136141Smax.romanov@nginx.com } 3137141Smax.romanov@nginx.com 3138318Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, engine->port, rc, port->pid); 3139318Smax.romanov@nginx.com 3140343Smax.romanov@nginx.com nxt_router_process_http_request_mp(task, ra); 3141167Smax.romanov@nginx.com } 3142167Smax.romanov@nginx.com 3143167Smax.romanov@nginx.com 3144167Smax.romanov@nginx.com static void 3145343Smax.romanov@nginx.com nxt_router_process_http_request_mp(nxt_task_t *task, nxt_req_app_link_t *ra) 3146167Smax.romanov@nginx.com { 3147343Smax.romanov@nginx.com uint32_t request_failed; 3148167Smax.romanov@nginx.com nxt_int_t res; 3149343Smax.romanov@nginx.com nxt_port_t *port, *c_port, *reply_port; 3150167Smax.romanov@nginx.com nxt_app_wmsg_t wmsg; 3151167Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 3152167Smax.romanov@nginx.com 3153343Smax.romanov@nginx.com nxt_assert(ra->app_port != NULL); 3154343Smax.romanov@nginx.com 3155343Smax.romanov@nginx.com port = ra->app_port; 3156167Smax.romanov@nginx.com reply_port = ra->reply_port; 3157167Smax.romanov@nginx.com ap = ra->ap; 3158141Smax.romanov@nginx.com 3159343Smax.romanov@nginx.com request_failed = 1; 3160343Smax.romanov@nginx.com 3161141Smax.romanov@nginx.com c_port = nxt_process_connected_port_find(port->process, reply_port->pid, 3162141Smax.romanov@nginx.com reply_port->id); 3163141Smax.romanov@nginx.com if (nxt_slow_path(c_port != reply_port)) { 3164141Smax.romanov@nginx.com res = nxt_port_send_port(task, port, reply_port, 0); 3165122Smax.romanov@nginx.com 3166122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3167345Smax.romanov@nginx.com nxt_router_ra_error(task, ra, 500, 3168345Smax.romanov@nginx.com "Failed to send reply port to application"); 3169345Smax.romanov@nginx.com ra = NULL; 3170343Smax.romanov@nginx.com goto release_port; 3171122Smax.romanov@nginx.com } 3172122Smax.romanov@nginx.com 3173141Smax.romanov@nginx.com nxt_process_connected_port_add(port->process, reply_port); 317488Smax.romanov@nginx.com } 317588Smax.romanov@nginx.com 317688Smax.romanov@nginx.com wmsg.port = port; 317788Smax.romanov@nginx.com wmsg.write = NULL; 317888Smax.romanov@nginx.com wmsg.buf = &wmsg.write; 3179318Smax.romanov@nginx.com wmsg.stream = ra->stream; 3180167Smax.romanov@nginx.com 3181216Sigor@sysoev.ru res = port->app->prepare_msg(task, &ap->r, &wmsg); 3182122Smax.romanov@nginx.com 3183122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3184345Smax.romanov@nginx.com nxt_router_ra_error(task, ra, 500, 3185345Smax.romanov@nginx.com "Failed to prepare message for application"); 3186345Smax.romanov@nginx.com ra = NULL; 3187343Smax.romanov@nginx.com goto release_port; 3188122Smax.romanov@nginx.com } 318988Smax.romanov@nginx.com 319088Smax.romanov@nginx.com nxt_debug(task, "about to send %d bytes buffer to worker port %d", 319188Smax.romanov@nginx.com nxt_buf_used_size(wmsg.write), 319288Smax.romanov@nginx.com wmsg.port->socket.fd); 319388Smax.romanov@nginx.com 3194343Smax.romanov@nginx.com request_failed = 0; 3195343Smax.romanov@nginx.com 3196122Smax.romanov@nginx.com res = nxt_port_socket_write(task, wmsg.port, NXT_PORT_MSG_DATA, 3197318Smax.romanov@nginx.com -1, ra->stream, reply_port->id, wmsg.write); 3198122Smax.romanov@nginx.com 3199122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3200345Smax.romanov@nginx.com nxt_router_ra_error(task, ra, 500, 3201345Smax.romanov@nginx.com "Failed to send message to application"); 3202345Smax.romanov@nginx.com ra = NULL; 3203343Smax.romanov@nginx.com goto release_port; 3204122Smax.romanov@nginx.com } 3205343Smax.romanov@nginx.com 3206343Smax.romanov@nginx.com release_port: 3207343Smax.romanov@nginx.com 3208345Smax.romanov@nginx.com nxt_router_app_port_release(task, port, request_failed, 0); 3209345Smax.romanov@nginx.com 3210345Smax.romanov@nginx.com if (ra != NULL) { 3211345Smax.romanov@nginx.com if (request_failed != 0) { 3212345Smax.romanov@nginx.com ra->app_port = 0; 3213345Smax.romanov@nginx.com } 3214345Smax.romanov@nginx.com 3215345Smax.romanov@nginx.com nxt_router_ra_release(task, ra, ra->work.data); 3216343Smax.romanov@nginx.com } 321753Sigor@sysoev.ru } 321853Sigor@sysoev.ru 321953Sigor@sysoev.ru 3220216Sigor@sysoev.ru static nxt_int_t 3221216Sigor@sysoev.ru nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 3222216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg) 3223216Sigor@sysoev.ru { 3224216Sigor@sysoev.ru nxt_int_t rc; 3225216Sigor@sysoev.ru nxt_buf_t *b; 3226216Sigor@sysoev.ru nxt_http_field_t *field; 3227216Sigor@sysoev.ru nxt_app_request_header_t *h; 3228216Sigor@sysoev.ru 3229216Sigor@sysoev.ru static const nxt_str_t prefix = nxt_string("HTTP_"); 3230216Sigor@sysoev.ru static const nxt_str_t eof = nxt_null_string; 3231216Sigor@sysoev.ru 3232216Sigor@sysoev.ru h = &r->header; 3233216Sigor@sysoev.ru 3234216Sigor@sysoev.ru #define RC(S) \ 3235216Sigor@sysoev.ru do { \ 3236216Sigor@sysoev.ru rc = (S); \ 3237216Sigor@sysoev.ru if (nxt_slow_path(rc != NXT_OK)) { \ 3238216Sigor@sysoev.ru goto fail; \ 3239216Sigor@sysoev.ru } \ 3240216Sigor@sysoev.ru } while(0) 3241216Sigor@sysoev.ru 3242216Sigor@sysoev.ru #define NXT_WRITE(N) \ 3243216Sigor@sysoev.ru RC(nxt_app_msg_write_str(task, wmsg, N)) 3244216Sigor@sysoev.ru 3245216Sigor@sysoev.ru /* TODO error handle, async mmap buffer assignment */ 3246216Sigor@sysoev.ru 3247216Sigor@sysoev.ru NXT_WRITE(&h->method); 3248216Sigor@sysoev.ru NXT_WRITE(&h->target); 3249277Sigor@sysoev.ru 3250216Sigor@sysoev.ru if (h->path.start == h->target.start) { 3251216Sigor@sysoev.ru NXT_WRITE(&eof); 3252277Sigor@sysoev.ru 3253216Sigor@sysoev.ru } else { 3254216Sigor@sysoev.ru NXT_WRITE(&h->path); 3255216Sigor@sysoev.ru } 3256216Sigor@sysoev.ru 3257216Sigor@sysoev.ru if (h->query.start != NULL) { 3258216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 3259216Sigor@sysoev.ru h->query.start - h->target.start + 1)); 3260216Sigor@sysoev.ru } else { 3261216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 0)); 3262216Sigor@sysoev.ru } 3263216Sigor@sysoev.ru 3264216Sigor@sysoev.ru NXT_WRITE(&h->version); 3265216Sigor@sysoev.ru 3266216Sigor@sysoev.ru NXT_WRITE(&r->remote); 3267268Sigor@sysoev.ru NXT_WRITE(&r->local); 3268216Sigor@sysoev.ru 3269216Sigor@sysoev.ru NXT_WRITE(&h->host); 3270216Sigor@sysoev.ru NXT_WRITE(&h->content_type); 3271216Sigor@sysoev.ru NXT_WRITE(&h->content_length); 3272216Sigor@sysoev.ru 3273216Sigor@sysoev.ru nxt_list_each(field, h->fields) { 3274216Sigor@sysoev.ru RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, 3275216Sigor@sysoev.ru &prefix, &field->name)); 3276216Sigor@sysoev.ru NXT_WRITE(&field->value); 3277216Sigor@sysoev.ru 3278216Sigor@sysoev.ru } nxt_list_loop; 3279216Sigor@sysoev.ru 3280216Sigor@sysoev.ru /* end-of-headers mark */ 3281216Sigor@sysoev.ru NXT_WRITE(&eof); 3282216Sigor@sysoev.ru 3283216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 3284216Sigor@sysoev.ru 3285216Sigor@sysoev.ru for(b = r->body.buf; b != NULL; b = b->next) { 3286216Sigor@sysoev.ru RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3287216Sigor@sysoev.ru nxt_buf_mem_used_size(&b->mem))); 3288216Sigor@sysoev.ru } 3289216Sigor@sysoev.ru 3290216Sigor@sysoev.ru #undef NXT_WRITE 3291216Sigor@sysoev.ru #undef RC 3292216Sigor@sysoev.ru 3293216Sigor@sysoev.ru return NXT_OK; 3294216Sigor@sysoev.ru 3295216Sigor@sysoev.ru fail: 3296216Sigor@sysoev.ru 3297216Sigor@sysoev.ru return NXT_ERROR; 3298216Sigor@sysoev.ru } 3299216Sigor@sysoev.ru 3300216Sigor@sysoev.ru 3301216Sigor@sysoev.ru static nxt_int_t 3302216Sigor@sysoev.ru nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 3303216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg) 3304216Sigor@sysoev.ru { 3305216Sigor@sysoev.ru nxt_int_t rc; 3306216Sigor@sysoev.ru nxt_buf_t *b; 3307305Smax.romanov@nginx.com nxt_bool_t method_is_post; 3308216Sigor@sysoev.ru nxt_http_field_t *field; 3309216Sigor@sysoev.ru nxt_app_request_header_t *h; 3310216Sigor@sysoev.ru 3311216Sigor@sysoev.ru static const nxt_str_t prefix = nxt_string("HTTP_"); 3312216Sigor@sysoev.ru static const nxt_str_t eof = nxt_null_string; 3313216Sigor@sysoev.ru 3314216Sigor@sysoev.ru h = &r->header; 3315216Sigor@sysoev.ru 3316216Sigor@sysoev.ru #define RC(S) \ 3317216Sigor@sysoev.ru do { \ 3318216Sigor@sysoev.ru rc = (S); \ 3319216Sigor@sysoev.ru if (nxt_slow_path(rc != NXT_OK)) { \ 3320216Sigor@sysoev.ru goto fail; \ 3321216Sigor@sysoev.ru } \ 3322216Sigor@sysoev.ru } while(0) 3323216Sigor@sysoev.ru 3324216Sigor@sysoev.ru #define NXT_WRITE(N) \ 3325216Sigor@sysoev.ru RC(nxt_app_msg_write_str(task, wmsg, N)) 3326216Sigor@sysoev.ru 3327216Sigor@sysoev.ru /* TODO error handle, async mmap buffer assignment */ 3328216Sigor@sysoev.ru 3329216Sigor@sysoev.ru NXT_WRITE(&h->method); 3330216Sigor@sysoev.ru NXT_WRITE(&h->target); 3331277Sigor@sysoev.ru 3332216Sigor@sysoev.ru if (h->path.start == h->target.start) { 3333216Sigor@sysoev.ru NXT_WRITE(&eof); 3334277Sigor@sysoev.ru 3335216Sigor@sysoev.ru } else { 3336216Sigor@sysoev.ru NXT_WRITE(&h->path); 3337216Sigor@sysoev.ru } 3338216Sigor@sysoev.ru 3339216Sigor@sysoev.ru if (h->query.start != NULL) { 3340216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 3341216Sigor@sysoev.ru h->query.start - h->target.start + 1)); 3342216Sigor@sysoev.ru } else { 3343216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 0)); 3344216Sigor@sysoev.ru } 3345216Sigor@sysoev.ru 3346216Sigor@sysoev.ru NXT_WRITE(&h->version); 3347216Sigor@sysoev.ru 3348216Sigor@sysoev.ru // PHP_SELF 3349216Sigor@sysoev.ru // SCRIPT_NAME 3350216Sigor@sysoev.ru // SCRIPT_FILENAME 3351216Sigor@sysoev.ru // DOCUMENT_ROOT 3352216Sigor@sysoev.ru 3353216Sigor@sysoev.ru NXT_WRITE(&r->remote); 3354268Sigor@sysoev.ru NXT_WRITE(&r->local); 3355216Sigor@sysoev.ru 3356216Sigor@sysoev.ru NXT_WRITE(&h->host); 3357216Sigor@sysoev.ru NXT_WRITE(&h->cookie); 3358216Sigor@sysoev.ru NXT_WRITE(&h->content_type); 3359216Sigor@sysoev.ru NXT_WRITE(&h->content_length); 3360216Sigor@sysoev.ru 3361216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length)); 3362305Smax.romanov@nginx.com RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 3363305Smax.romanov@nginx.com 3364305Smax.romanov@nginx.com method_is_post = h->method.length == 4 && 3365305Smax.romanov@nginx.com h->method.start[0] == 'P' && 3366305Smax.romanov@nginx.com h->method.start[1] == 'O' && 3367305Smax.romanov@nginx.com h->method.start[2] == 'S' && 3368305Smax.romanov@nginx.com h->method.start[3] == 'T'; 3369305Smax.romanov@nginx.com 3370305Smax.romanov@nginx.com if (method_is_post) { 3371305Smax.romanov@nginx.com for(b = r->body.buf; b != NULL; b = b->next) { 3372305Smax.romanov@nginx.com RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3373305Smax.romanov@nginx.com nxt_buf_mem_used_size(&b->mem))); 3374305Smax.romanov@nginx.com } 3375305Smax.romanov@nginx.com } 3376216Sigor@sysoev.ru 3377216Sigor@sysoev.ru nxt_list_each(field, h->fields) { 3378216Sigor@sysoev.ru RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, 3379216Sigor@sysoev.ru &prefix, &field->name)); 3380216Sigor@sysoev.ru NXT_WRITE(&field->value); 3381216Sigor@sysoev.ru 3382216Sigor@sysoev.ru } nxt_list_loop; 3383216Sigor@sysoev.ru 3384216Sigor@sysoev.ru /* end-of-headers mark */ 3385216Sigor@sysoev.ru NXT_WRITE(&eof); 3386216Sigor@sysoev.ru 3387305Smax.romanov@nginx.com if (!method_is_post) { 3388305Smax.romanov@nginx.com for(b = r->body.buf; b != NULL; b = b->next) { 3389305Smax.romanov@nginx.com RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3390305Smax.romanov@nginx.com nxt_buf_mem_used_size(&b->mem))); 3391305Smax.romanov@nginx.com } 3392216Sigor@sysoev.ru } 3393216Sigor@sysoev.ru 3394216Sigor@sysoev.ru #undef NXT_WRITE 3395216Sigor@sysoev.ru #undef RC 3396216Sigor@sysoev.ru 3397216Sigor@sysoev.ru return NXT_OK; 3398216Sigor@sysoev.ru 3399216Sigor@sysoev.ru fail: 3400216Sigor@sysoev.ru 3401216Sigor@sysoev.ru return NXT_ERROR; 3402216Sigor@sysoev.ru } 3403216Sigor@sysoev.ru 3404216Sigor@sysoev.ru 3405216Sigor@sysoev.ru static nxt_int_t 3406216Sigor@sysoev.ru nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, nxt_app_wmsg_t *wmsg) 3407216Sigor@sysoev.ru { 3408216Sigor@sysoev.ru nxt_int_t rc; 3409216Sigor@sysoev.ru nxt_buf_t *b; 3410216Sigor@sysoev.ru nxt_http_field_t *field; 3411216Sigor@sysoev.ru nxt_app_request_header_t *h; 3412216Sigor@sysoev.ru 3413216Sigor@sysoev.ru static const nxt_str_t eof = nxt_null_string; 3414216Sigor@sysoev.ru 3415216Sigor@sysoev.ru h = &r->header; 3416216Sigor@sysoev.ru 3417216Sigor@sysoev.ru #define RC(S) \ 3418216Sigor@sysoev.ru do { \ 3419216Sigor@sysoev.ru rc = (S); \ 3420216Sigor@sysoev.ru if (nxt_slow_path(rc != NXT_OK)) { \ 3421216Sigor@sysoev.ru goto fail; \ 3422216Sigor@sysoev.ru } \ 3423216Sigor@sysoev.ru } while(0) 3424216Sigor@sysoev.ru 3425216Sigor@sysoev.ru #define NXT_WRITE(N) \ 3426216Sigor@sysoev.ru RC(nxt_app_msg_write_str(task, wmsg, N)) 3427216Sigor@sysoev.ru 3428216Sigor@sysoev.ru /* TODO error handle, async mmap buffer assignment */ 3429216Sigor@sysoev.ru 3430216Sigor@sysoev.ru NXT_WRITE(&h->method); 3431216Sigor@sysoev.ru NXT_WRITE(&h->target); 3432277Sigor@sysoev.ru 3433216Sigor@sysoev.ru if (h->path.start == h->target.start) { 3434216Sigor@sysoev.ru NXT_WRITE(&eof); 3435277Sigor@sysoev.ru 3436216Sigor@sysoev.ru } else { 3437216Sigor@sysoev.ru NXT_WRITE(&h->path); 3438216Sigor@sysoev.ru } 3439216Sigor@sysoev.ru 3440216Sigor@sysoev.ru if (h->query.start != NULL) { 3441216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 3442216Sigor@sysoev.ru h->query.start - h->target.start + 1)); 3443216Sigor@sysoev.ru } else { 3444216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 0)); 3445216Sigor@sysoev.ru } 3446216Sigor@sysoev.ru 3447216Sigor@sysoev.ru NXT_WRITE(&h->version); 3448253Smax.romanov@nginx.com NXT_WRITE(&r->remote); 3449216Sigor@sysoev.ru 3450216Sigor@sysoev.ru NXT_WRITE(&h->host); 3451216Sigor@sysoev.ru NXT_WRITE(&h->cookie); 3452216Sigor@sysoev.ru NXT_WRITE(&h->content_type); 3453216Sigor@sysoev.ru NXT_WRITE(&h->content_length); 3454216Sigor@sysoev.ru 3455216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length)); 3456216Sigor@sysoev.ru 3457216Sigor@sysoev.ru nxt_list_each(field, h->fields) { 3458216Sigor@sysoev.ru NXT_WRITE(&field->name); 3459216Sigor@sysoev.ru NXT_WRITE(&field->value); 3460216Sigor@sysoev.ru 3461216Sigor@sysoev.ru } nxt_list_loop; 3462216Sigor@sysoev.ru 3463216Sigor@sysoev.ru /* end-of-headers mark */ 3464216Sigor@sysoev.ru NXT_WRITE(&eof); 3465216Sigor@sysoev.ru 3466216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 3467216Sigor@sysoev.ru 3468216Sigor@sysoev.ru for(b = r->body.buf; b != NULL; b = b->next) { 3469216Sigor@sysoev.ru RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3470216Sigor@sysoev.ru nxt_buf_mem_used_size(&b->mem))); 3471216Sigor@sysoev.ru } 3472216Sigor@sysoev.ru 3473216Sigor@sysoev.ru #undef NXT_WRITE 3474216Sigor@sysoev.ru #undef RC 3475216Sigor@sysoev.ru 3476216Sigor@sysoev.ru return NXT_OK; 3477216Sigor@sysoev.ru 3478216Sigor@sysoev.ru fail: 3479216Sigor@sysoev.ru 3480216Sigor@sysoev.ru return NXT_ERROR; 3481216Sigor@sysoev.ru } 3482216Sigor@sysoev.ru 3483216Sigor@sysoev.ru 348462Sigor@sysoev.ru static const nxt_conn_state_t nxt_router_conn_close_state 348553Sigor@sysoev.ru nxt_aligned(64) = 348653Sigor@sysoev.ru { 348753Sigor@sysoev.ru .ready_handler = nxt_router_conn_free, 348853Sigor@sysoev.ru }; 348953Sigor@sysoev.ru 349053Sigor@sysoev.ru 349153Sigor@sysoev.ru static void 349288Smax.romanov@nginx.com nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data) 349388Smax.romanov@nginx.com { 349488Smax.romanov@nginx.com nxt_buf_t *b; 349588Smax.romanov@nginx.com nxt_bool_t last; 349688Smax.romanov@nginx.com nxt_conn_t *c; 349788Smax.romanov@nginx.com nxt_work_queue_t *wq; 349888Smax.romanov@nginx.com 349988Smax.romanov@nginx.com nxt_debug(task, "router conn ready %p", obj); 350088Smax.romanov@nginx.com 350188Smax.romanov@nginx.com c = obj; 350288Smax.romanov@nginx.com b = c->write; 350388Smax.romanov@nginx.com 350488Smax.romanov@nginx.com wq = &task->thread->engine->fast_work_queue; 350588Smax.romanov@nginx.com 350688Smax.romanov@nginx.com last = 0; 350788Smax.romanov@nginx.com 350888Smax.romanov@nginx.com while (b != NULL) { 350988Smax.romanov@nginx.com if (!nxt_buf_is_sync(b)) { 351088Smax.romanov@nginx.com if (nxt_buf_used_size(b) > 0) { 351188Smax.romanov@nginx.com break; 351288Smax.romanov@nginx.com } 351388Smax.romanov@nginx.com } 351488Smax.romanov@nginx.com 351588Smax.romanov@nginx.com if (nxt_buf_is_last(b)) { 351688Smax.romanov@nginx.com last = 1; 351788Smax.romanov@nginx.com } 351888Smax.romanov@nginx.com 351988Smax.romanov@nginx.com nxt_work_queue_add(wq, b->completion_handler, task, b, b->parent); 352088Smax.romanov@nginx.com 352188Smax.romanov@nginx.com b = b->next; 352288Smax.romanov@nginx.com } 352388Smax.romanov@nginx.com 352488Smax.romanov@nginx.com c->write = b; 352588Smax.romanov@nginx.com 352688Smax.romanov@nginx.com if (b != NULL) { 352788Smax.romanov@nginx.com nxt_debug(task, "router conn %p has more data to write", obj); 352888Smax.romanov@nginx.com 352988Smax.romanov@nginx.com nxt_conn_write(task->thread->engine, c); 3530277Sigor@sysoev.ru 353188Smax.romanov@nginx.com } else { 353288Smax.romanov@nginx.com nxt_debug(task, "router conn %p no more data to write, last = %d", obj, 353388Smax.romanov@nginx.com last); 353488Smax.romanov@nginx.com 353588Smax.romanov@nginx.com if (last != 0) { 353688Smax.romanov@nginx.com nxt_debug(task, "enqueue router conn close %p (ready handler)", c); 353788Smax.romanov@nginx.com 353888Smax.romanov@nginx.com nxt_work_queue_add(wq, nxt_router_conn_close, task, c, 353988Smax.romanov@nginx.com c->socket.data); 354088Smax.romanov@nginx.com } 354188Smax.romanov@nginx.com } 354288Smax.romanov@nginx.com } 354388Smax.romanov@nginx.com 354488Smax.romanov@nginx.com 354588Smax.romanov@nginx.com static void 354653Sigor@sysoev.ru nxt_router_conn_close(nxt_task_t *task, void *obj, void *data) 354753Sigor@sysoev.ru { 354862Sigor@sysoev.ru nxt_conn_t *c; 354953Sigor@sysoev.ru 355053Sigor@sysoev.ru c = obj; 355153Sigor@sysoev.ru 355253Sigor@sysoev.ru nxt_debug(task, "router conn close"); 355353Sigor@sysoev.ru 355453Sigor@sysoev.ru c->write_state = &nxt_router_conn_close_state; 355553Sigor@sysoev.ru 355662Sigor@sysoev.ru nxt_conn_close(task->thread->engine, c); 355753Sigor@sysoev.ru } 355853Sigor@sysoev.ru 355953Sigor@sysoev.ru 356053Sigor@sysoev.ru static void 3561164Smax.romanov@nginx.com nxt_router_conn_mp_cleanup(nxt_task_t *task, void *obj, void *data) 3562164Smax.romanov@nginx.com { 3563164Smax.romanov@nginx.com nxt_socket_conf_joint_t *joint; 3564164Smax.romanov@nginx.com 3565164Smax.romanov@nginx.com joint = obj; 3566164Smax.romanov@nginx.com 3567164Smax.romanov@nginx.com nxt_router_conf_release(task, joint); 3568164Smax.romanov@nginx.com } 3569164Smax.romanov@nginx.com 3570164Smax.romanov@nginx.com 3571164Smax.romanov@nginx.com static void 357253Sigor@sysoev.ru nxt_router_conn_free(nxt_task_t *task, void *obj, void *data) 357353Sigor@sysoev.ru { 357462Sigor@sysoev.ru nxt_conn_t *c; 3575337Sigor@sysoev.ru nxt_event_engine_t *engine; 357688Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 3577319Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 357853Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 357953Sigor@sysoev.ru 358053Sigor@sysoev.ru c = obj; 3581319Smax.romanov@nginx.com ap = data; 358253Sigor@sysoev.ru 358353Sigor@sysoev.ru nxt_debug(task, "router conn close done"); 358453Sigor@sysoev.ru 3585319Smax.romanov@nginx.com if (ap != NULL) { 3586319Smax.romanov@nginx.com nxt_app_http_req_done(task, ap); 3587319Smax.romanov@nginx.com 3588319Smax.romanov@nginx.com c->socket.data = NULL; 3589319Smax.romanov@nginx.com } 3590319Smax.romanov@nginx.com 359188Smax.romanov@nginx.com nxt_queue_each(rc, &c->requests, nxt_req_conn_link_t, link) { 359288Smax.romanov@nginx.com 3593318Smax.romanov@nginx.com nxt_debug(task, "conn %p close, stream #%uD", c, rc->stream); 359488Smax.romanov@nginx.com 3595343Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 3596318Smax.romanov@nginx.com 3597318Smax.romanov@nginx.com nxt_port_rpc_cancel(task, task->thread->engine->port, rc->stream); 359888Smax.romanov@nginx.com 359988Smax.romanov@nginx.com } nxt_queue_loop; 360088Smax.romanov@nginx.com 3601122Smax.romanov@nginx.com nxt_queue_remove(&c->link); 3602122Smax.romanov@nginx.com 3603337Sigor@sysoev.ru engine = task->thread->engine; 3604337Sigor@sysoev.ru 3605337Sigor@sysoev.ru nxt_sockaddr_cache_free(engine, c); 3606337Sigor@sysoev.ru 3607131Smax.romanov@nginx.com joint = c->listen->socket.data; 3608131Smax.romanov@nginx.com 3609337Sigor@sysoev.ru nxt_mp_cleanup(c->mem_pool, nxt_router_conn_mp_cleanup, 3610337Sigor@sysoev.ru &engine->task, joint, NULL); 3611164Smax.romanov@nginx.com 3612164Smax.romanov@nginx.com nxt_mp_release(c->mem_pool, c); 361353Sigor@sysoev.ru } 361453Sigor@sysoev.ru 361553Sigor@sysoev.ru 361653Sigor@sysoev.ru static void 361753Sigor@sysoev.ru nxt_router_conn_error(nxt_task_t *task, void *obj, void *data) 361853Sigor@sysoev.ru { 361962Sigor@sysoev.ru nxt_conn_t *c; 362053Sigor@sysoev.ru 362153Sigor@sysoev.ru c = obj; 362253Sigor@sysoev.ru 362353Sigor@sysoev.ru nxt_debug(task, "router conn error"); 362453Sigor@sysoev.ru 3625273Smax.romanov@nginx.com if (c->socket.fd != -1) { 3626273Smax.romanov@nginx.com c->write_state = &nxt_router_conn_close_state; 3627273Smax.romanov@nginx.com 3628273Smax.romanov@nginx.com nxt_conn_close(task->thread->engine, c); 3629273Smax.romanov@nginx.com } 363053Sigor@sysoev.ru } 363153Sigor@sysoev.ru 363253Sigor@sysoev.ru 363353Sigor@sysoev.ru static void 363453Sigor@sysoev.ru nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data) 363553Sigor@sysoev.ru { 363662Sigor@sysoev.ru nxt_conn_t *c; 363762Sigor@sysoev.ru nxt_timer_t *timer; 363853Sigor@sysoev.ru 363953Sigor@sysoev.ru timer = obj; 364053Sigor@sysoev.ru 364153Sigor@sysoev.ru nxt_debug(task, "router conn timeout"); 364253Sigor@sysoev.ru 364362Sigor@sysoev.ru c = nxt_read_timer_conn(timer); 364453Sigor@sysoev.ru 3645206Smax.romanov@nginx.com if (c->read_state == &nxt_router_conn_read_header_state) { 3646206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 408, "Read header timeout"); 3647206Smax.romanov@nginx.com 3648206Smax.romanov@nginx.com } else { 3649206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 408, "Read body timeout"); 3650206Smax.romanov@nginx.com } 365153Sigor@sysoev.ru } 365253Sigor@sysoev.ru 365353Sigor@sysoev.ru 3654318Smax.romanov@nginx.com static void 3655318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data) 3656318Smax.romanov@nginx.com { 3657318Smax.romanov@nginx.com nxt_conn_t *c; 3658318Smax.romanov@nginx.com nxt_timer_t *timer; 3659318Smax.romanov@nginx.com 3660318Smax.romanov@nginx.com timer = obj; 3661318Smax.romanov@nginx.com 3662318Smax.romanov@nginx.com nxt_debug(task, "router app timeout"); 3663318Smax.romanov@nginx.com 3664318Smax.romanov@nginx.com c = nxt_read_timer_conn(timer); 3665318Smax.romanov@nginx.com 3666318Smax.romanov@nginx.com nxt_router_gen_error(task, c, 408, "Application timeout"); 3667318Smax.romanov@nginx.com } 3668318Smax.romanov@nginx.com 3669318Smax.romanov@nginx.com 367053Sigor@sysoev.ru static nxt_msec_t 367162Sigor@sysoev.ru nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data) 367253Sigor@sysoev.ru { 367353Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 367453Sigor@sysoev.ru 367553Sigor@sysoev.ru joint = c->listen->socket.data; 367653Sigor@sysoev.ru 367753Sigor@sysoev.ru return nxt_value_at(nxt_msec_t, joint->socket_conf, data); 367853Sigor@sysoev.ru } 3679