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 79115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task, 80115Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end); 81133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name); 82133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, 83133Sigor@sysoev.ru nxt_str_t *name); 84198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task, 85198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf); 86198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task, 87198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 88198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task, 89198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 90*359Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, 91*359Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_str_t *name); 92*359Sigor@sysoev.ru static nxt_int_t nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, 93*359Sigor@sysoev.ru nxt_socket_conf_t *nskcf, 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); 104154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 105154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 106154Sigor@sysoev.ru nxt_work_handler_t handler); 107313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 108313Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 109139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 110139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets); 11153Sigor@sysoev.ru 11253Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 11353Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 11453Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 11553Sigor@sysoev.ru nxt_event_engine_t *engine); 116343Smax.romanov@nginx.com static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 117133Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 11853Sigor@sysoev.ru 119315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router, 120315Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 121315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine, 122315Sigor@sysoev.ru nxt_work_t *jobs); 12353Sigor@sysoev.ru 12453Sigor@sysoev.ru static void nxt_router_thread_start(void *data); 12553Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj, 12653Sigor@sysoev.ru void *data); 12753Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj, 12853Sigor@sysoev.ru void *data); 12953Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, 13053Sigor@sysoev.ru void *data); 131313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, 132313Sigor@sysoev.ru void *data); 13353Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj, 13453Sigor@sysoev.ru void *data); 13553Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, 13653Sigor@sysoev.ru void *data); 137*359Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task, 138*359Sigor@sysoev.ru nxt_socket_conf_t *skcf); 13953Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task, 14053Sigor@sysoev.ru nxt_socket_conf_joint_t *joint); 14153Sigor@sysoev.ru 142343Smax.romanov@nginx.com static void nxt_router_app_port_ready(nxt_task_t *task, 143343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 144343Smax.romanov@nginx.com static void nxt_router_app_port_error(nxt_task_t *task, 145343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 146343Smax.romanov@nginx.com 147343Smax.romanov@nginx.com static nxt_port_t * nxt_router_app_get_idle_port(nxt_app_t *app); 148343Smax.romanov@nginx.com static void nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port, 149343Smax.romanov@nginx.com uint32_t request_failed, uint32_t got_response); 150141Smax.romanov@nginx.com 15153Sigor@sysoev.ru static void nxt_router_conn_init(nxt_task_t *task, void *obj, void *data); 15253Sigor@sysoev.ru static void nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, 15353Sigor@sysoev.ru void *data); 154*359Sigor@sysoev.ru static nxt_sockaddr_t *nxt_router_local_addr(nxt_task_t *task, nxt_conn_t *c); 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 305351Smax.romanov@nginx.com nxt_inline void 306351Smax.romanov@nginx.com nxt_router_ra_init(nxt_task_t *task, nxt_req_app_link_t *ra, 307351Smax.romanov@nginx.com nxt_req_conn_link_t *rc) 308167Smax.romanov@nginx.com { 309318Smax.romanov@nginx.com nxt_event_engine_t *engine; 310351Smax.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; 320351Smax.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; 326351Smax.romanov@nginx.com } 327351Smax.romanov@nginx.com 328351Smax.romanov@nginx.com 329351Smax.romanov@nginx.com nxt_inline nxt_req_app_link_t * 330351Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_app_link_t *ra_src) 331351Smax.romanov@nginx.com { 332351Smax.romanov@nginx.com nxt_mp_t *mp; 333351Smax.romanov@nginx.com nxt_req_app_link_t *ra; 334351Smax.romanov@nginx.com 335351Smax.romanov@nginx.com mp = ra_src->ap->mem_pool; 336351Smax.romanov@nginx.com 337351Smax.romanov@nginx.com ra = nxt_mp_retain(mp, sizeof(nxt_req_app_link_t)); 338351Smax.romanov@nginx.com 339351Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 340351Smax.romanov@nginx.com 341351Smax.romanov@nginx.com ra_src->rc->ra = NULL; 342351Smax.romanov@nginx.com ra_src->rc = NULL; 343351Smax.romanov@nginx.com 344351Smax.romanov@nginx.com return NULL; 345351Smax.romanov@nginx.com } 346351Smax.romanov@nginx.com 347351Smax.romanov@nginx.com nxt_router_ra_init(task, ra, ra_src->rc); 348351Smax.romanov@nginx.com 349351Smax.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 404351Smax.romanov@nginx.com if (ra->mem_pool != NULL) { 405351Smax.romanov@nginx.com nxt_mp_release(ra->mem_pool, ra); 406351Smax.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 453351Smax.romanov@nginx.com if (ra->mem_pool != NULL) { 454351Smax.romanov@nginx.com nxt_mp_release(ra->mem_pool, ra); 455351Smax.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 514351Smax.romanov@nginx.com if (ra->mem_pool != NULL) { 515351Smax.romanov@nginx.com nxt_mp_release(ra->mem_pool, ra); 516351Smax.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 { 595198Sigor@sysoev.ru nxt_int_t ret; 596139Sigor@sysoev.ru nxt_buf_t *b; 597139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 598139Sigor@sysoev.ru 599139Sigor@sysoev.ru tmcf = nxt_router_temp_conf(task); 600139Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 601139Sigor@sysoev.ru return; 60253Sigor@sysoev.ru } 60353Sigor@sysoev.ru 604352Smax.romanov@nginx.com b = nxt_buf_chk_make_plain(tmcf->conf->mem_pool, msg->buf, msg->size); 605352Smax.romanov@nginx.com 606352Smax.romanov@nginx.com nxt_assert(b != NULL); 607352Smax.romanov@nginx.com 608139Sigor@sysoev.ru tmcf->conf->router = nxt_router; 609139Sigor@sysoev.ru tmcf->stream = msg->port_msg.stream; 610139Sigor@sysoev.ru tmcf->port = nxt_runtime_port_find(task->thread->runtime, 611198Sigor@sysoev.ru msg->port_msg.pid, 612198Sigor@sysoev.ru msg->port_msg.reply_port); 613198Sigor@sysoev.ru 614198Sigor@sysoev.ru ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free); 615198Sigor@sysoev.ru 616198Sigor@sysoev.ru if (nxt_fast_path(ret == NXT_OK)) { 617198Sigor@sysoev.ru nxt_router_conf_apply(task, tmcf, NULL); 618198Sigor@sysoev.ru 619198Sigor@sysoev.ru } else { 620198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 621139Sigor@sysoev.ru } 62253Sigor@sysoev.ru } 62353Sigor@sysoev.ru 62453Sigor@sysoev.ru 625347Smax.romanov@nginx.com static void 626347Smax.romanov@nginx.com nxt_router_worker_remove_pid(nxt_task_t *task, nxt_port_t *port, void *data) 627347Smax.romanov@nginx.com { 628347Smax.romanov@nginx.com union { 629347Smax.romanov@nginx.com nxt_pid_t removed_pid; 630347Smax.romanov@nginx.com void *data; 631347Smax.romanov@nginx.com } u; 632347Smax.romanov@nginx.com 633347Smax.romanov@nginx.com u.data = data; 634347Smax.romanov@nginx.com 635347Smax.romanov@nginx.com nxt_port_rpc_remove_peer(task, port, u.removed_pid); 636347Smax.romanov@nginx.com } 637347Smax.romanov@nginx.com 638347Smax.romanov@nginx.com 639192Smax.romanov@nginx.com void 640192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 641192Smax.romanov@nginx.com { 642347Smax.romanov@nginx.com nxt_event_engine_t *engine; 643318Smax.romanov@nginx.com 644192Smax.romanov@nginx.com nxt_port_remove_pid_handler(task, msg); 645192Smax.romanov@nginx.com 646192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 647192Smax.romanov@nginx.com return; 648192Smax.romanov@nginx.com } 649192Smax.romanov@nginx.com 650318Smax.romanov@nginx.com nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0) 651318Smax.romanov@nginx.com { 652347Smax.romanov@nginx.com nxt_port_post(task, engine->port, nxt_router_worker_remove_pid, 653347Smax.romanov@nginx.com msg->u.data); 654318Smax.romanov@nginx.com } 655318Smax.romanov@nginx.com nxt_queue_loop; 656318Smax.romanov@nginx.com 657192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 658192Smax.romanov@nginx.com 659192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 660192Smax.romanov@nginx.com } 661192Smax.romanov@nginx.com 662192Smax.romanov@nginx.com 66353Sigor@sysoev.ru static nxt_router_temp_conf_t * 664139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task) 66553Sigor@sysoev.ru { 66665Sigor@sysoev.ru nxt_mp_t *mp, *tmp; 66753Sigor@sysoev.ru nxt_router_conf_t *rtcf; 66853Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 66953Sigor@sysoev.ru 67065Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 67153Sigor@sysoev.ru if (nxt_slow_path(mp == NULL)) { 67253Sigor@sysoev.ru return NULL; 67353Sigor@sysoev.ru } 67453Sigor@sysoev.ru 67565Sigor@sysoev.ru rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t)); 67653Sigor@sysoev.ru if (nxt_slow_path(rtcf == NULL)) { 67753Sigor@sysoev.ru goto fail; 67853Sigor@sysoev.ru } 67953Sigor@sysoev.ru 68053Sigor@sysoev.ru rtcf->mem_pool = mp; 68153Sigor@sysoev.ru 68265Sigor@sysoev.ru tmp = nxt_mp_create(1024, 128, 256, 32); 68353Sigor@sysoev.ru if (nxt_slow_path(tmp == NULL)) { 68453Sigor@sysoev.ru goto fail; 68553Sigor@sysoev.ru } 68653Sigor@sysoev.ru 68765Sigor@sysoev.ru tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t)); 68853Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 68953Sigor@sysoev.ru goto temp_fail; 69053Sigor@sysoev.ru } 69153Sigor@sysoev.ru 69253Sigor@sysoev.ru tmcf->mem_pool = tmp; 69353Sigor@sysoev.ru tmcf->conf = rtcf; 694139Sigor@sysoev.ru tmcf->count = 1; 695139Sigor@sysoev.ru tmcf->engine = task->thread->engine; 69653Sigor@sysoev.ru 69753Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, 4, 69853Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 69953Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 70053Sigor@sysoev.ru goto temp_fail; 70153Sigor@sysoev.ru } 70253Sigor@sysoev.ru 70353Sigor@sysoev.ru nxt_queue_init(&tmcf->deleting); 70453Sigor@sysoev.ru nxt_queue_init(&tmcf->keeping); 70553Sigor@sysoev.ru nxt_queue_init(&tmcf->updating); 70653Sigor@sysoev.ru nxt_queue_init(&tmcf->pending); 70753Sigor@sysoev.ru nxt_queue_init(&tmcf->creating); 708133Sigor@sysoev.ru nxt_queue_init(&tmcf->apps); 709133Sigor@sysoev.ru nxt_queue_init(&tmcf->previous); 71053Sigor@sysoev.ru 71153Sigor@sysoev.ru return tmcf; 71253Sigor@sysoev.ru 71353Sigor@sysoev.ru temp_fail: 71453Sigor@sysoev.ru 71565Sigor@sysoev.ru nxt_mp_destroy(tmp); 71653Sigor@sysoev.ru 71753Sigor@sysoev.ru fail: 71853Sigor@sysoev.ru 71965Sigor@sysoev.ru nxt_mp_destroy(mp); 72053Sigor@sysoev.ru 72153Sigor@sysoev.ru return NULL; 72253Sigor@sysoev.ru } 72353Sigor@sysoev.ru 72453Sigor@sysoev.ru 725198Sigor@sysoev.ru static void 726198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data) 727139Sigor@sysoev.ru { 728139Sigor@sysoev.ru nxt_int_t ret; 729139Sigor@sysoev.ru nxt_router_t *router; 730139Sigor@sysoev.ru nxt_runtime_t *rt; 731198Sigor@sysoev.ru nxt_queue_link_t *qlk; 732198Sigor@sysoev.ru nxt_socket_conf_t *skcf; 733198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 734139Sigor@sysoev.ru const nxt_event_interface_t *interface; 735139Sigor@sysoev.ru 736198Sigor@sysoev.ru tmcf = obj; 737198Sigor@sysoev.ru 738198Sigor@sysoev.ru qlk = nxt_queue_first(&tmcf->pending); 739198Sigor@sysoev.ru 740198Sigor@sysoev.ru if (qlk != nxt_queue_tail(&tmcf->pending)) { 741198Sigor@sysoev.ru nxt_queue_remove(qlk); 742198Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->creating, qlk); 743198Sigor@sysoev.ru 744198Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 745198Sigor@sysoev.ru 746198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(task, tmcf, skcf); 747198Sigor@sysoev.ru 748198Sigor@sysoev.ru return; 749139Sigor@sysoev.ru } 750139Sigor@sysoev.ru 751139Sigor@sysoev.ru rt = task->thread->runtime; 752139Sigor@sysoev.ru 753139Sigor@sysoev.ru interface = nxt_service_get(rt->services, "engine", NULL); 754139Sigor@sysoev.ru 755198Sigor@sysoev.ru router = tmcf->conf->router; 756198Sigor@sysoev.ru 757139Sigor@sysoev.ru ret = nxt_router_engines_create(task, router, tmcf, interface); 758139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 759198Sigor@sysoev.ru goto fail; 760139Sigor@sysoev.ru } 761139Sigor@sysoev.ru 762139Sigor@sysoev.ru ret = nxt_router_threads_create(task, rt, tmcf); 763139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 764198Sigor@sysoev.ru goto fail; 765139Sigor@sysoev.ru } 766139Sigor@sysoev.ru 767343Smax.romanov@nginx.com nxt_router_apps_sort(task, router, tmcf); 768139Sigor@sysoev.ru 769315Sigor@sysoev.ru nxt_router_engines_post(router, tmcf); 770139Sigor@sysoev.ru 771139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->updating); 772139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->creating); 773139Sigor@sysoev.ru 774198Sigor@sysoev.ru nxt_router_conf_ready(task, tmcf); 775198Sigor@sysoev.ru 776198Sigor@sysoev.ru return; 777198Sigor@sysoev.ru 778198Sigor@sysoev.ru fail: 779198Sigor@sysoev.ru 780198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 781198Sigor@sysoev.ru 782198Sigor@sysoev.ru return; 783139Sigor@sysoev.ru } 784139Sigor@sysoev.ru 785139Sigor@sysoev.ru 786139Sigor@sysoev.ru static void 787139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data) 788139Sigor@sysoev.ru { 789153Sigor@sysoev.ru nxt_joint_job_t *job; 790153Sigor@sysoev.ru 791153Sigor@sysoev.ru job = obj; 792153Sigor@sysoev.ru 793198Sigor@sysoev.ru nxt_router_conf_ready(task, job->tmcf); 794139Sigor@sysoev.ru } 795139Sigor@sysoev.ru 796139Sigor@sysoev.ru 797139Sigor@sysoev.ru static void 798198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 799139Sigor@sysoev.ru { 800139Sigor@sysoev.ru nxt_debug(task, "temp conf count:%D", tmcf->count); 801139Sigor@sysoev.ru 802139Sigor@sysoev.ru if (--tmcf->count == 0) { 803193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST); 804139Sigor@sysoev.ru } 805139Sigor@sysoev.ru } 806139Sigor@sysoev.ru 807139Sigor@sysoev.ru 808139Sigor@sysoev.ru static void 809139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 810139Sigor@sysoev.ru { 811148Sigor@sysoev.ru nxt_socket_t s; 812149Sigor@sysoev.ru nxt_router_t *router; 813148Sigor@sysoev.ru nxt_queue_link_t *qlk; 814148Sigor@sysoev.ru nxt_socket_conf_t *skcf; 815148Sigor@sysoev.ru 816198Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "failed to apply new conf"); 817198Sigor@sysoev.ru 818148Sigor@sysoev.ru for (qlk = nxt_queue_first(&tmcf->creating); 819148Sigor@sysoev.ru qlk != nxt_queue_tail(&tmcf->creating); 820148Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 821148Sigor@sysoev.ru { 822148Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 823*359Sigor@sysoev.ru s = skcf->listen->socket; 824148Sigor@sysoev.ru 825148Sigor@sysoev.ru if (s != -1) { 826148Sigor@sysoev.ru nxt_socket_close(task, s); 827148Sigor@sysoev.ru } 828148Sigor@sysoev.ru 829*359Sigor@sysoev.ru nxt_free(skcf->listen); 830148Sigor@sysoev.ru } 831148Sigor@sysoev.ru 832149Sigor@sysoev.ru router = tmcf->conf->router; 833149Sigor@sysoev.ru 834149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->keeping); 835149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->deleting); 836149Sigor@sysoev.ru 837148Sigor@sysoev.ru // TODO: new engines and threads 838148Sigor@sysoev.ru 839139Sigor@sysoev.ru nxt_mp_destroy(tmcf->conf->mem_pool); 840139Sigor@sysoev.ru 841193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR); 842139Sigor@sysoev.ru } 843139Sigor@sysoev.ru 844139Sigor@sysoev.ru 845139Sigor@sysoev.ru static void 846139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 847193Smax.romanov@nginx.com nxt_port_msg_type_t type) 848139Sigor@sysoev.ru { 849193Smax.romanov@nginx.com nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL); 850139Sigor@sysoev.ru } 851139Sigor@sysoev.ru 852139Sigor@sysoev.ru 853115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_conf[] = { 854115Sigor@sysoev.ru { 855133Sigor@sysoev.ru nxt_string("listeners_threads"), 856115Sigor@sysoev.ru NXT_CONF_MAP_INT32, 857115Sigor@sysoev.ru offsetof(nxt_router_conf_t, threads), 858115Sigor@sysoev.ru }, 859115Sigor@sysoev.ru }; 860115Sigor@sysoev.ru 861115Sigor@sysoev.ru 862133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_app_conf[] = { 863115Sigor@sysoev.ru { 864133Sigor@sysoev.ru nxt_string("type"), 865115Sigor@sysoev.ru NXT_CONF_MAP_STR, 866133Sigor@sysoev.ru offsetof(nxt_router_app_conf_t, type), 867115Sigor@sysoev.ru }, 868115Sigor@sysoev.ru 869115Sigor@sysoev.ru { 870133Sigor@sysoev.ru nxt_string("workers"), 871115Sigor@sysoev.ru NXT_CONF_MAP_INT32, 872133Sigor@sysoev.ru offsetof(nxt_router_app_conf_t, workers), 873133Sigor@sysoev.ru }, 874318Smax.romanov@nginx.com 875318Smax.romanov@nginx.com { 876318Smax.romanov@nginx.com nxt_string("limits"), 877318Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 878318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, limits_value), 879318Smax.romanov@nginx.com }, 880318Smax.romanov@nginx.com }; 881318Smax.romanov@nginx.com 882318Smax.romanov@nginx.com 883318Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_limits_conf[] = { 884318Smax.romanov@nginx.com { 885318Smax.romanov@nginx.com nxt_string("timeout"), 886318Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 887318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, timeout), 888318Smax.romanov@nginx.com }, 889318Smax.romanov@nginx.com 890318Smax.romanov@nginx.com { 891318Smax.romanov@nginx.com nxt_string("requests"), 892318Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 893318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, requests), 894318Smax.romanov@nginx.com }, 895133Sigor@sysoev.ru }; 896133Sigor@sysoev.ru 897133Sigor@sysoev.ru 898133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_listener_conf[] = { 899133Sigor@sysoev.ru { 900133Sigor@sysoev.ru nxt_string("application"), 901133Sigor@sysoev.ru NXT_CONF_MAP_STR, 902133Sigor@sysoev.ru offsetof(nxt_router_listener_conf_t, application), 903115Sigor@sysoev.ru }, 904115Sigor@sysoev.ru }; 905115Sigor@sysoev.ru 906115Sigor@sysoev.ru 907115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_http_conf[] = { 908115Sigor@sysoev.ru { 909115Sigor@sysoev.ru nxt_string("header_buffer_size"), 910115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 911115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_buffer_size), 912115Sigor@sysoev.ru }, 913115Sigor@sysoev.ru 914115Sigor@sysoev.ru { 915115Sigor@sysoev.ru nxt_string("large_header_buffer_size"), 916115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 917115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, large_header_buffer_size), 918115Sigor@sysoev.ru }, 919115Sigor@sysoev.ru 920115Sigor@sysoev.ru { 921206Smax.romanov@nginx.com nxt_string("large_header_buffers"), 922206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 923206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, large_header_buffers), 924206Smax.romanov@nginx.com }, 925206Smax.romanov@nginx.com 926206Smax.romanov@nginx.com { 927206Smax.romanov@nginx.com nxt_string("body_buffer_size"), 928206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 929206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_buffer_size), 930206Smax.romanov@nginx.com }, 931206Smax.romanov@nginx.com 932206Smax.romanov@nginx.com { 933206Smax.romanov@nginx.com nxt_string("max_body_size"), 934206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 935206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, max_body_size), 936206Smax.romanov@nginx.com }, 937206Smax.romanov@nginx.com 938206Smax.romanov@nginx.com { 939115Sigor@sysoev.ru nxt_string("header_read_timeout"), 940115Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 941115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_read_timeout), 942115Sigor@sysoev.ru }, 943206Smax.romanov@nginx.com 944206Smax.romanov@nginx.com { 945206Smax.romanov@nginx.com nxt_string("body_read_timeout"), 946206Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 947206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_read_timeout), 948206Smax.romanov@nginx.com }, 949115Sigor@sysoev.ru }; 950115Sigor@sysoev.ru 951115Sigor@sysoev.ru 95253Sigor@sysoev.ru static nxt_int_t 953115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 954115Sigor@sysoev.ru u_char *start, u_char *end) 95553Sigor@sysoev.ru { 956133Sigor@sysoev.ru u_char *p; 957133Sigor@sysoev.ru size_t size; 958115Sigor@sysoev.ru nxt_mp_t *mp; 959115Sigor@sysoev.ru uint32_t next; 960115Sigor@sysoev.ru nxt_int_t ret; 961115Sigor@sysoev.ru nxt_str_t name; 962133Sigor@sysoev.ru nxt_app_t *app, *prev; 963*359Sigor@sysoev.ru nxt_router_t *router; 964133Sigor@sysoev.ru nxt_conf_value_t *conf, *http; 965133Sigor@sysoev.ru nxt_conf_value_t *applications, *application; 966133Sigor@sysoev.ru nxt_conf_value_t *listeners, *listener; 967115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 968216Sigor@sysoev.ru nxt_app_lang_module_t *lang; 969133Sigor@sysoev.ru nxt_router_app_conf_t apcf; 970115Sigor@sysoev.ru nxt_router_listener_conf_t lscf; 971115Sigor@sysoev.ru 972115Sigor@sysoev.ru static nxt_str_t http_path = nxt_string("/http"); 973133Sigor@sysoev.ru static nxt_str_t applications_path = nxt_string("/applications"); 974115Sigor@sysoev.ru static nxt_str_t listeners_path = nxt_string("/listeners"); 975115Sigor@sysoev.ru 976208Svbart@nginx.com conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL); 977115Sigor@sysoev.ru if (conf == NULL) { 978115Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "configuration parsing error"); 979115Sigor@sysoev.ru return NXT_ERROR; 980115Sigor@sysoev.ru } 981115Sigor@sysoev.ru 982213Svbart@nginx.com mp = tmcf->conf->mem_pool; 983213Svbart@nginx.com 984213Svbart@nginx.com ret = nxt_conf_map_object(mp, conf, nxt_router_conf, 985136Svbart@nginx.com nxt_nitems(nxt_router_conf), tmcf->conf); 986115Sigor@sysoev.ru if (ret != NXT_OK) { 987133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "root map error"); 988115Sigor@sysoev.ru return NXT_ERROR; 989115Sigor@sysoev.ru } 990115Sigor@sysoev.ru 991117Sigor@sysoev.ru if (tmcf->conf->threads == 0) { 992117Sigor@sysoev.ru tmcf->conf->threads = nxt_ncpu; 993117Sigor@sysoev.ru } 994117Sigor@sysoev.ru 995133Sigor@sysoev.ru applications = nxt_conf_get_path(conf, &applications_path); 996133Sigor@sysoev.ru if (applications == NULL) { 997133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block"); 998115Sigor@sysoev.ru return NXT_ERROR; 999115Sigor@sysoev.ru } 1000115Sigor@sysoev.ru 1001*359Sigor@sysoev.ru router = tmcf->conf->router; 1002*359Sigor@sysoev.ru 1003133Sigor@sysoev.ru next = 0; 1004133Sigor@sysoev.ru 1005133Sigor@sysoev.ru for ( ;; ) { 1006133Sigor@sysoev.ru application = nxt_conf_next_object_member(applications, &name, &next); 1007133Sigor@sysoev.ru if (application == NULL) { 1008133Sigor@sysoev.ru break; 1009133Sigor@sysoev.ru } 1010133Sigor@sysoev.ru 1011133Sigor@sysoev.ru nxt_debug(task, "application \"%V\"", &name); 1012133Sigor@sysoev.ru 1013144Smax.romanov@nginx.com size = nxt_conf_json_length(application, NULL); 1014144Smax.romanov@nginx.com 1015144Smax.romanov@nginx.com app = nxt_malloc(sizeof(nxt_app_t) + name.length + size); 1016133Sigor@sysoev.ru if (app == NULL) { 1017133Sigor@sysoev.ru goto fail; 1018133Sigor@sysoev.ru } 1019133Sigor@sysoev.ru 1020144Smax.romanov@nginx.com nxt_memzero(app, sizeof(nxt_app_t)); 1021144Smax.romanov@nginx.com 1022144Smax.romanov@nginx.com app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t)); 1023144Smax.romanov@nginx.com app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length); 1024133Sigor@sysoev.ru 1025133Sigor@sysoev.ru p = nxt_conf_json_print(app->conf.start, application, NULL); 1026133Sigor@sysoev.ru app->conf.length = p - app->conf.start; 1027133Sigor@sysoev.ru 1028144Smax.romanov@nginx.com nxt_assert(app->conf.length <= size); 1029144Smax.romanov@nginx.com 1030133Sigor@sysoev.ru nxt_debug(task, "application conf \"%V\"", &app->conf); 1031133Sigor@sysoev.ru 1032*359Sigor@sysoev.ru prev = nxt_router_app_find(&router->apps, &name); 1033133Sigor@sysoev.ru 1034133Sigor@sysoev.ru if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) { 1035133Sigor@sysoev.ru nxt_free(app); 1036133Sigor@sysoev.ru 1037133Sigor@sysoev.ru nxt_queue_remove(&prev->link); 1038133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->previous, &prev->link); 1039133Sigor@sysoev.ru continue; 1040133Sigor@sysoev.ru } 1041133Sigor@sysoev.ru 1042263Smax.romanov@nginx.com apcf.workers = 1; 1043318Smax.romanov@nginx.com apcf.timeout = 0; 1044318Smax.romanov@nginx.com apcf.requests = 0; 1045318Smax.romanov@nginx.com apcf.limits_value = NULL; 1046263Smax.romanov@nginx.com 1047213Svbart@nginx.com ret = nxt_conf_map_object(mp, application, nxt_router_app_conf, 1048136Svbart@nginx.com nxt_nitems(nxt_router_app_conf), &apcf); 1049133Sigor@sysoev.ru if (ret != NXT_OK) { 1050133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "application map error"); 1051133Sigor@sysoev.ru goto app_fail; 1052133Sigor@sysoev.ru } 1053115Sigor@sysoev.ru 1054318Smax.romanov@nginx.com if (apcf.limits_value != NULL) { 1055318Smax.romanov@nginx.com 1056318Smax.romanov@nginx.com if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) { 1057318Smax.romanov@nginx.com nxt_log(task, NXT_LOG_CRIT, "application limits is not object"); 1058318Smax.romanov@nginx.com goto app_fail; 1059318Smax.romanov@nginx.com } 1060318Smax.romanov@nginx.com 1061318Smax.romanov@nginx.com ret = nxt_conf_map_object(mp, apcf.limits_value, 1062318Smax.romanov@nginx.com nxt_router_app_limits_conf, 1063318Smax.romanov@nginx.com nxt_nitems(nxt_router_app_limits_conf), 1064318Smax.romanov@nginx.com &apcf); 1065318Smax.romanov@nginx.com if (ret != NXT_OK) { 1066318Smax.romanov@nginx.com nxt_log(task, NXT_LOG_CRIT, "application limits map error"); 1067318Smax.romanov@nginx.com goto app_fail; 1068318Smax.romanov@nginx.com } 1069318Smax.romanov@nginx.com } 1070318Smax.romanov@nginx.com 1071133Sigor@sysoev.ru nxt_debug(task, "application type: %V", &apcf.type); 1072133Sigor@sysoev.ru nxt_debug(task, "application workers: %D", apcf.workers); 1073318Smax.romanov@nginx.com nxt_debug(task, "application timeout: %D", apcf.timeout); 1074318Smax.romanov@nginx.com nxt_debug(task, "application requests: %D", apcf.requests); 1075133Sigor@sysoev.ru 1076216Sigor@sysoev.ru lang = nxt_app_lang_module(task->thread->runtime, &apcf.type); 1077216Sigor@sysoev.ru 1078216Sigor@sysoev.ru if (lang == NULL) { 1079141Smax.romanov@nginx.com nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"", 1080141Smax.romanov@nginx.com &apcf.type); 1081141Smax.romanov@nginx.com goto app_fail; 1082141Smax.romanov@nginx.com } 1083141Smax.romanov@nginx.com 1084216Sigor@sysoev.ru nxt_debug(task, "application language module: \"%s\"", lang->file); 1085216Sigor@sysoev.ru 1086133Sigor@sysoev.ru ret = nxt_thread_mutex_create(&app->mutex); 1087133Sigor@sysoev.ru if (ret != NXT_OK) { 1088133Sigor@sysoev.ru goto app_fail; 1089133Sigor@sysoev.ru } 1090133Sigor@sysoev.ru 1091141Smax.romanov@nginx.com nxt_queue_init(&app->ports); 1092141Smax.romanov@nginx.com nxt_queue_init(&app->requests); 1093141Smax.romanov@nginx.com 1094144Smax.romanov@nginx.com app->name.length = name.length; 1095144Smax.romanov@nginx.com nxt_memcpy(app->name.start, name.start, name.length); 1096144Smax.romanov@nginx.com 1097356Svbart@nginx.com app->type = lang->type; 1098133Sigor@sysoev.ru app->max_workers = apcf.workers; 1099318Smax.romanov@nginx.com app->timeout = apcf.timeout; 1100133Sigor@sysoev.ru app->live = 1; 1101343Smax.romanov@nginx.com app->max_pending_responses = 2; 1102356Svbart@nginx.com app->prepare_msg = nxt_app_prepare_msg[lang->type]; 1103133Sigor@sysoev.ru 1104133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->apps, &app->link); 1105343Smax.romanov@nginx.com 1106343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 1107133Sigor@sysoev.ru } 1108133Sigor@sysoev.ru 1109133Sigor@sysoev.ru http = nxt_conf_get_path(conf, &http_path); 1110133Sigor@sysoev.ru #if 0 1111133Sigor@sysoev.ru if (http == NULL) { 1112133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "no \"http\" block"); 1113133Sigor@sysoev.ru return NXT_ERROR; 1114133Sigor@sysoev.ru } 1115133Sigor@sysoev.ru #endif 1116133Sigor@sysoev.ru 1117133Sigor@sysoev.ru listeners = nxt_conf_get_path(conf, &listeners_path); 1118115Sigor@sysoev.ru if (listeners == NULL) { 1119133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block"); 1120115Sigor@sysoev.ru return NXT_ERROR; 1121115Sigor@sysoev.ru } 112253Sigor@sysoev.ru 1123133Sigor@sysoev.ru next = 0; 112453Sigor@sysoev.ru 1125115Sigor@sysoev.ru for ( ;; ) { 1126115Sigor@sysoev.ru listener = nxt_conf_next_object_member(listeners, &name, &next); 1127115Sigor@sysoev.ru if (listener == NULL) { 1128115Sigor@sysoev.ru break; 1129115Sigor@sysoev.ru } 113053Sigor@sysoev.ru 1131*359Sigor@sysoev.ru skcf = nxt_router_socket_conf(task, tmcf, &name); 1132115Sigor@sysoev.ru if (skcf == NULL) { 1133133Sigor@sysoev.ru goto fail; 1134115Sigor@sysoev.ru } 113553Sigor@sysoev.ru 1136213Svbart@nginx.com ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf, 1137136Svbart@nginx.com nxt_nitems(nxt_router_listener_conf), &lscf); 1138115Sigor@sysoev.ru if (ret != NXT_OK) { 1139115Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "listener map error"); 1140133Sigor@sysoev.ru goto fail; 1141115Sigor@sysoev.ru } 114253Sigor@sysoev.ru 1143133Sigor@sysoev.ru nxt_debug(task, "application: %V", &lscf.application); 1144133Sigor@sysoev.ru 1145133Sigor@sysoev.ru // STUB, default values if http block is not defined. 1146133Sigor@sysoev.ru skcf->header_buffer_size = 2048; 1147133Sigor@sysoev.ru skcf->large_header_buffer_size = 8192; 1148206Smax.romanov@nginx.com skcf->large_header_buffers = 4; 1149206Smax.romanov@nginx.com skcf->body_buffer_size = 16 * 1024; 1150206Smax.romanov@nginx.com skcf->max_body_size = 2 * 1024 * 1024; 1151133Sigor@sysoev.ru skcf->header_read_timeout = 5000; 1152206Smax.romanov@nginx.com skcf->body_read_timeout = 5000; 115353Sigor@sysoev.ru 1154133Sigor@sysoev.ru if (http != NULL) { 1155213Svbart@nginx.com ret = nxt_conf_map_object(mp, http, nxt_router_http_conf, 1156136Svbart@nginx.com nxt_nitems(nxt_router_http_conf), skcf); 1157133Sigor@sysoev.ru if (ret != NXT_OK) { 1158133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "http map error"); 1159133Sigor@sysoev.ru goto fail; 1160133Sigor@sysoev.ru } 1161115Sigor@sysoev.ru } 1162115Sigor@sysoev.ru 1163*359Sigor@sysoev.ru skcf->listen->handler = nxt_router_conn_init; 1164115Sigor@sysoev.ru skcf->router_conf = tmcf->conf; 1165160Sigor@sysoev.ru skcf->router_conf->count++; 1166133Sigor@sysoev.ru skcf->application = nxt_router_listener_application(tmcf, 1167133Sigor@sysoev.ru &lscf.application); 1168115Sigor@sysoev.ru } 116953Sigor@sysoev.ru 1170*359Sigor@sysoev.ru nxt_queue_add(&tmcf->deleting, &router->sockets); 1171*359Sigor@sysoev.ru nxt_queue_init(&router->sockets); 1172198Sigor@sysoev.ru 117353Sigor@sysoev.ru return NXT_OK; 1174133Sigor@sysoev.ru 1175133Sigor@sysoev.ru app_fail: 1176133Sigor@sysoev.ru 1177133Sigor@sysoev.ru nxt_free(app); 1178133Sigor@sysoev.ru 1179133Sigor@sysoev.ru fail: 1180133Sigor@sysoev.ru 1181141Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1182141Smax.romanov@nginx.com 1183141Smax.romanov@nginx.com nxt_queue_remove(&app->link); 1184133Sigor@sysoev.ru nxt_thread_mutex_destroy(&app->mutex); 1185133Sigor@sysoev.ru nxt_free(app); 1186141Smax.romanov@nginx.com 1187141Smax.romanov@nginx.com } nxt_queue_loop; 1188133Sigor@sysoev.ru 1189133Sigor@sysoev.ru return NXT_ERROR; 1190133Sigor@sysoev.ru } 1191133Sigor@sysoev.ru 1192133Sigor@sysoev.ru 1193133Sigor@sysoev.ru static nxt_app_t * 1194133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name) 1195133Sigor@sysoev.ru { 1196141Smax.romanov@nginx.com nxt_app_t *app; 1197141Smax.romanov@nginx.com 1198141Smax.romanov@nginx.com nxt_queue_each(app, queue, nxt_app_t, link) { 1199133Sigor@sysoev.ru 1200133Sigor@sysoev.ru if (nxt_strstr_eq(name, &app->name)) { 1201133Sigor@sysoev.ru return app; 1202133Sigor@sysoev.ru } 1203141Smax.romanov@nginx.com 1204141Smax.romanov@nginx.com } nxt_queue_loop; 1205133Sigor@sysoev.ru 1206133Sigor@sysoev.ru return NULL; 1207133Sigor@sysoev.ru } 1208133Sigor@sysoev.ru 1209133Sigor@sysoev.ru 1210133Sigor@sysoev.ru static nxt_app_t * 1211133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name) 1212133Sigor@sysoev.ru { 1213133Sigor@sysoev.ru nxt_app_t *app; 1214133Sigor@sysoev.ru 1215133Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->apps, name); 1216133Sigor@sysoev.ru 1217133Sigor@sysoev.ru if (app == NULL) { 1218134Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->previous, name); 1219133Sigor@sysoev.ru } 1220133Sigor@sysoev.ru 1221133Sigor@sysoev.ru return app; 122253Sigor@sysoev.ru } 122353Sigor@sysoev.ru 122453Sigor@sysoev.ru 122553Sigor@sysoev.ru static nxt_socket_conf_t * 1226*359Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1227*359Sigor@sysoev.ru nxt_str_t *name) 122853Sigor@sysoev.ru { 1229*359Sigor@sysoev.ru size_t size; 1230*359Sigor@sysoev.ru nxt_int_t ret; 1231*359Sigor@sysoev.ru nxt_bool_t wildcard; 1232*359Sigor@sysoev.ru nxt_sockaddr_t *sa; 1233*359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1234*359Sigor@sysoev.ru nxt_listen_socket_t *ls; 1235*359Sigor@sysoev.ru 1236*359Sigor@sysoev.ru sa = nxt_sockaddr_parse(tmcf->mem_pool, name); 1237*359Sigor@sysoev.ru if (nxt_slow_path(sa == NULL)) { 1238*359Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", name); 1239*359Sigor@sysoev.ru return NULL; 1240*359Sigor@sysoev.ru } 1241*359Sigor@sysoev.ru 1242*359Sigor@sysoev.ru sa->type = SOCK_STREAM; 1243*359Sigor@sysoev.ru 1244*359Sigor@sysoev.ru nxt_debug(task, "router listener: \"%*s\"", 1245*359Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa)); 1246*359Sigor@sysoev.ru 1247*359Sigor@sysoev.ru skcf = nxt_mp_zget(tmcf->conf->mem_pool, sizeof(nxt_socket_conf_t)); 1248163Smax.romanov@nginx.com if (nxt_slow_path(skcf == NULL)) { 124953Sigor@sysoev.ru return NULL; 125053Sigor@sysoev.ru } 125153Sigor@sysoev.ru 1252*359Sigor@sysoev.ru size = nxt_sockaddr_size(sa); 1253*359Sigor@sysoev.ru 1254*359Sigor@sysoev.ru ret = nxt_router_listen_socket_find(tmcf, skcf, sa); 1255*359Sigor@sysoev.ru 1256*359Sigor@sysoev.ru if (ret != NXT_OK) { 1257*359Sigor@sysoev.ru 1258*359Sigor@sysoev.ru ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size); 1259*359Sigor@sysoev.ru if (nxt_slow_path(ls == NULL)) { 1260*359Sigor@sysoev.ru return NULL; 1261*359Sigor@sysoev.ru } 1262*359Sigor@sysoev.ru 1263*359Sigor@sysoev.ru skcf->listen = ls; 1264*359Sigor@sysoev.ru 1265*359Sigor@sysoev.ru ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t)); 1266*359Sigor@sysoev.ru nxt_memcpy(ls->sockaddr, sa, size); 1267*359Sigor@sysoev.ru 1268*359Sigor@sysoev.ru nxt_listen_socket_remote_size(ls); 1269*359Sigor@sysoev.ru 1270*359Sigor@sysoev.ru ls->socket = -1; 1271*359Sigor@sysoev.ru ls->backlog = NXT_LISTEN_BACKLOG; 1272*359Sigor@sysoev.ru ls->flags = NXT_NONBLOCK; 1273*359Sigor@sysoev.ru ls->read_after_accept = 1; 1274*359Sigor@sysoev.ru } 1275*359Sigor@sysoev.ru 1276*359Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) { 1277*359Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 1278*359Sigor@sysoev.ru case AF_UNIX: 1279*359Sigor@sysoev.ru wildcard = 0; 1280*359Sigor@sysoev.ru break; 1281*359Sigor@sysoev.ru #endif 1282*359Sigor@sysoev.ru #if (NXT_INET6) 1283*359Sigor@sysoev.ru case AF_INET6: 1284*359Sigor@sysoev.ru wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr); 1285*359Sigor@sysoev.ru break; 1286*359Sigor@sysoev.ru #endif 1287*359Sigor@sysoev.ru case AF_INET: 1288*359Sigor@sysoev.ru default: 1289*359Sigor@sysoev.ru wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY); 1290*359Sigor@sysoev.ru break; 1291*359Sigor@sysoev.ru } 1292*359Sigor@sysoev.ru 1293*359Sigor@sysoev.ru if (!wildcard) { 1294*359Sigor@sysoev.ru skcf->sockaddr = nxt_mp_zget(tmcf->conf->mem_pool, size); 1295*359Sigor@sysoev.ru if (nxt_slow_path(skcf->sockaddr == NULL)) { 1296*359Sigor@sysoev.ru return NULL; 1297*359Sigor@sysoev.ru } 1298*359Sigor@sysoev.ru 1299*359Sigor@sysoev.ru nxt_memcpy(skcf->sockaddr, sa, size); 1300*359Sigor@sysoev.ru } 1301163Smax.romanov@nginx.com 1302163Smax.romanov@nginx.com return skcf; 130353Sigor@sysoev.ru } 130453Sigor@sysoev.ru 130553Sigor@sysoev.ru 1306*359Sigor@sysoev.ru static nxt_int_t 1307*359Sigor@sysoev.ru nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, 1308*359Sigor@sysoev.ru nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa) 130953Sigor@sysoev.ru { 1310*359Sigor@sysoev.ru nxt_router_t *router; 1311*359Sigor@sysoev.ru nxt_queue_link_t *qlk; 1312*359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1313*359Sigor@sysoev.ru 1314*359Sigor@sysoev.ru router = tmcf->conf->router; 1315*359Sigor@sysoev.ru 1316*359Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->sockets); 1317*359Sigor@sysoev.ru qlk != nxt_queue_tail(&router->sockets); 1318*359Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 131953Sigor@sysoev.ru { 1320*359Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1321*359Sigor@sysoev.ru 1322*359Sigor@sysoev.ru if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) { 1323*359Sigor@sysoev.ru nskcf->listen = skcf->listen; 1324*359Sigor@sysoev.ru 1325*359Sigor@sysoev.ru nxt_queue_remove(qlk); 1326*359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->keeping, qlk); 1327*359Sigor@sysoev.ru 1328*359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->updating, &nskcf->link); 1329*359Sigor@sysoev.ru 1330*359Sigor@sysoev.ru return NXT_OK; 133153Sigor@sysoev.ru } 133253Sigor@sysoev.ru } 133353Sigor@sysoev.ru 1334*359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->pending, &nskcf->link); 1335*359Sigor@sysoev.ru 1336*359Sigor@sysoev.ru return NXT_DECLINED; 133753Sigor@sysoev.ru } 133853Sigor@sysoev.ru 133953Sigor@sysoev.ru 1340198Sigor@sysoev.ru static void 1341198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task, 1342198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf) 1343198Sigor@sysoev.ru { 1344358Sigor@sysoev.ru size_t size; 1345198Sigor@sysoev.ru uint32_t stream; 1346198Sigor@sysoev.ru nxt_buf_t *b; 1347198Sigor@sysoev.ru nxt_port_t *main_port, *router_port; 1348198Sigor@sysoev.ru nxt_runtime_t *rt; 1349198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 1350198Sigor@sysoev.ru 1351198Sigor@sysoev.ru rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t)); 1352198Sigor@sysoev.ru if (rpc == NULL) { 1353198Sigor@sysoev.ru goto fail; 1354198Sigor@sysoev.ru } 1355198Sigor@sysoev.ru 1356198Sigor@sysoev.ru rpc->socket_conf = skcf; 1357198Sigor@sysoev.ru rpc->temp_conf = tmcf; 1358198Sigor@sysoev.ru 1359*359Sigor@sysoev.ru size = nxt_sockaddr_size(skcf->listen->sockaddr); 1360358Sigor@sysoev.ru 1361358Sigor@sysoev.ru b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 1362198Sigor@sysoev.ru if (b == NULL) { 1363198Sigor@sysoev.ru goto fail; 1364198Sigor@sysoev.ru } 1365198Sigor@sysoev.ru 1366*359Sigor@sysoev.ru b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size); 1367198Sigor@sysoev.ru 1368198Sigor@sysoev.ru rt = task->thread->runtime; 1369240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1370198Sigor@sysoev.ru router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 1371198Sigor@sysoev.ru 1372198Sigor@sysoev.ru stream = nxt_port_rpc_register_handler(task, router_port, 1373198Sigor@sysoev.ru nxt_router_listen_socket_ready, 1374198Sigor@sysoev.ru nxt_router_listen_socket_error, 1375198Sigor@sysoev.ru main_port->pid, rpc); 1376198Sigor@sysoev.ru if (stream == 0) { 1377198Sigor@sysoev.ru goto fail; 1378198Sigor@sysoev.ru } 1379198Sigor@sysoev.ru 1380198Sigor@sysoev.ru nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1, 1381198Sigor@sysoev.ru stream, router_port->id, b); 1382198Sigor@sysoev.ru 1383198Sigor@sysoev.ru return; 1384198Sigor@sysoev.ru 1385198Sigor@sysoev.ru fail: 1386198Sigor@sysoev.ru 1387198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 1388198Sigor@sysoev.ru } 1389198Sigor@sysoev.ru 1390198Sigor@sysoev.ru 1391198Sigor@sysoev.ru static void 1392198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1393198Sigor@sysoev.ru void *data) 139453Sigor@sysoev.ru { 1395*359Sigor@sysoev.ru nxt_int_t ret; 1396*359Sigor@sysoev.ru nxt_socket_t s; 1397*359Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 139853Sigor@sysoev.ru 1399198Sigor@sysoev.ru rpc = data; 1400198Sigor@sysoev.ru 1401198Sigor@sysoev.ru s = msg->fd; 1402198Sigor@sysoev.ru 1403198Sigor@sysoev.ru ret = nxt_socket_nonblocking(task, s); 1404198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1405198Sigor@sysoev.ru goto fail; 140653Sigor@sysoev.ru } 140753Sigor@sysoev.ru 1408*359Sigor@sysoev.ru nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr); 1409198Sigor@sysoev.ru 1410198Sigor@sysoev.ru ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG); 1411198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1412198Sigor@sysoev.ru goto fail; 1413198Sigor@sysoev.ru } 1414198Sigor@sysoev.ru 1415*359Sigor@sysoev.ru rpc->socket_conf->listen->socket = s; 1416198Sigor@sysoev.ru 1417198Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 1418198Sigor@sysoev.ru nxt_router_conf_apply, task, rpc->temp_conf, NULL); 1419198Sigor@sysoev.ru 1420198Sigor@sysoev.ru return; 1421148Sigor@sysoev.ru 1422148Sigor@sysoev.ru fail: 1423148Sigor@sysoev.ru 1424148Sigor@sysoev.ru nxt_socket_close(task, s); 1425148Sigor@sysoev.ru 1426198Sigor@sysoev.ru nxt_router_conf_error(task, rpc->temp_conf); 1427198Sigor@sysoev.ru } 1428198Sigor@sysoev.ru 1429198Sigor@sysoev.ru 1430198Sigor@sysoev.ru static void 1431198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1432198Sigor@sysoev.ru void *data) 1433198Sigor@sysoev.ru { 1434198Sigor@sysoev.ru u_char *p; 1435198Sigor@sysoev.ru size_t size; 1436198Sigor@sysoev.ru uint8_t error; 1437198Sigor@sysoev.ru nxt_buf_t *in, *out; 1438198Sigor@sysoev.ru nxt_sockaddr_t *sa; 1439198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 1440198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 1441198Sigor@sysoev.ru 1442198Sigor@sysoev.ru static nxt_str_t socket_errors[] = { 1443198Sigor@sysoev.ru nxt_string("ListenerSystem"), 1444198Sigor@sysoev.ru nxt_string("ListenerNoIPv6"), 1445198Sigor@sysoev.ru nxt_string("ListenerPort"), 1446198Sigor@sysoev.ru nxt_string("ListenerInUse"), 1447198Sigor@sysoev.ru nxt_string("ListenerNoAddress"), 1448198Sigor@sysoev.ru nxt_string("ListenerNoAccess"), 1449198Sigor@sysoev.ru nxt_string("ListenerPath"), 1450198Sigor@sysoev.ru }; 1451198Sigor@sysoev.ru 1452198Sigor@sysoev.ru rpc = data; 1453*359Sigor@sysoev.ru sa = rpc->socket_conf->listen->sockaddr; 1454352Smax.romanov@nginx.com tmcf = rpc->temp_conf; 1455352Smax.romanov@nginx.com 1456352Smax.romanov@nginx.com in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size); 1457352Smax.romanov@nginx.com 1458352Smax.romanov@nginx.com nxt_assert(in != NULL); 1459352Smax.romanov@nginx.com 1460198Sigor@sysoev.ru p = in->mem.pos; 1461198Sigor@sysoev.ru 1462198Sigor@sysoev.ru error = *p++; 1463198Sigor@sysoev.ru 1464198Sigor@sysoev.ru size = sizeof("listen socket error: ") - 1 1465198Sigor@sysoev.ru + sizeof("{listener: \"\", code:\"\", message: \"\"}") - 1 1466198Sigor@sysoev.ru + sa->length + socket_errors[error].length + (in->mem.free - p); 1467198Sigor@sysoev.ru 1468198Sigor@sysoev.ru out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 1469198Sigor@sysoev.ru if (nxt_slow_path(out == NULL)) { 1470198Sigor@sysoev.ru return; 1471198Sigor@sysoev.ru } 1472198Sigor@sysoev.ru 1473198Sigor@sysoev.ru out->mem.free = nxt_sprintf(out->mem.free, out->mem.end, 1474198Sigor@sysoev.ru "listen socket error: " 1475198Sigor@sysoev.ru "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}", 1476198Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa), 1477198Sigor@sysoev.ru &socket_errors[error], in->mem.free - p, p); 1478198Sigor@sysoev.ru 1479198Sigor@sysoev.ru nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos); 1480198Sigor@sysoev.ru 1481198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 148253Sigor@sysoev.ru } 148353Sigor@sysoev.ru 148453Sigor@sysoev.ru 148553Sigor@sysoev.ru static nxt_int_t 148653Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router, 148753Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface) 148853Sigor@sysoev.ru { 148953Sigor@sysoev.ru nxt_int_t ret; 149053Sigor@sysoev.ru nxt_uint_t n, threads; 149153Sigor@sysoev.ru nxt_queue_link_t *qlk; 149253Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 149353Sigor@sysoev.ru 149453Sigor@sysoev.ru threads = tmcf->conf->threads; 149553Sigor@sysoev.ru 149653Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, threads, 149753Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 149853Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 149953Sigor@sysoev.ru return NXT_ERROR; 150053Sigor@sysoev.ru } 150153Sigor@sysoev.ru 150253Sigor@sysoev.ru n = 0; 150353Sigor@sysoev.ru 150453Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->engines); 150553Sigor@sysoev.ru qlk != nxt_queue_tail(&router->engines); 150653Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 150753Sigor@sysoev.ru { 150853Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 150953Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 151053Sigor@sysoev.ru return NXT_ERROR; 151153Sigor@sysoev.ru } 151253Sigor@sysoev.ru 1513115Sigor@sysoev.ru recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0); 151453Sigor@sysoev.ru 151553Sigor@sysoev.ru if (n < threads) { 1516315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_KEEP; 1517115Sigor@sysoev.ru ret = nxt_router_engine_conf_update(tmcf, recf); 151853Sigor@sysoev.ru 151953Sigor@sysoev.ru } else { 1520315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_DELETE; 1521115Sigor@sysoev.ru ret = nxt_router_engine_conf_delete(tmcf, recf); 152253Sigor@sysoev.ru } 152353Sigor@sysoev.ru 152453Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 152553Sigor@sysoev.ru return ret; 152653Sigor@sysoev.ru } 152753Sigor@sysoev.ru 152853Sigor@sysoev.ru n++; 152953Sigor@sysoev.ru } 153053Sigor@sysoev.ru 153153Sigor@sysoev.ru tmcf->new_threads = n; 153253Sigor@sysoev.ru 153353Sigor@sysoev.ru while (n < threads) { 153453Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 153553Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 153653Sigor@sysoev.ru return NXT_ERROR; 153753Sigor@sysoev.ru } 153853Sigor@sysoev.ru 1539315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_ADD; 1540315Sigor@sysoev.ru 154153Sigor@sysoev.ru recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0); 154253Sigor@sysoev.ru if (nxt_slow_path(recf->engine == NULL)) { 154353Sigor@sysoev.ru return NXT_ERROR; 154453Sigor@sysoev.ru } 154553Sigor@sysoev.ru 1546115Sigor@sysoev.ru ret = nxt_router_engine_conf_create(tmcf, recf); 154753Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 154853Sigor@sysoev.ru return ret; 154953Sigor@sysoev.ru } 155053Sigor@sysoev.ru 155153Sigor@sysoev.ru n++; 155253Sigor@sysoev.ru } 155353Sigor@sysoev.ru 155453Sigor@sysoev.ru return NXT_OK; 155553Sigor@sysoev.ru } 155653Sigor@sysoev.ru 155753Sigor@sysoev.ru 155853Sigor@sysoev.ru static nxt_int_t 1559115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 1560115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 156153Sigor@sysoev.ru { 1562*359Sigor@sysoev.ru nxt_int_t ret; 156353Sigor@sysoev.ru 1564154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 1565154Sigor@sysoev.ru nxt_router_listen_socket_create); 1566115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1567115Sigor@sysoev.ru return ret; 1568115Sigor@sysoev.ru } 1569115Sigor@sysoev.ru 1570154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 1571154Sigor@sysoev.ru nxt_router_listen_socket_create); 157253Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 157353Sigor@sysoev.ru return ret; 157453Sigor@sysoev.ru } 157553Sigor@sysoev.ru 1576115Sigor@sysoev.ru return ret; 157753Sigor@sysoev.ru } 157853Sigor@sysoev.ru 157953Sigor@sysoev.ru 158053Sigor@sysoev.ru static nxt_int_t 1581115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 1582115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 158353Sigor@sysoev.ru { 1584*359Sigor@sysoev.ru nxt_int_t ret; 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 return ret; 160453Sigor@sysoev.ru } 160553Sigor@sysoev.ru 160653Sigor@sysoev.ru 160753Sigor@sysoev.ru static nxt_int_t 1608115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 1609115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 161053Sigor@sysoev.ru { 161153Sigor@sysoev.ru nxt_int_t ret; 161253Sigor@sysoev.ru 1613313Sigor@sysoev.ru ret = nxt_router_engine_quit(tmcf, recf); 1614313Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1615313Sigor@sysoev.ru return ret; 1616313Sigor@sysoev.ru } 1617313Sigor@sysoev.ru 1618139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating); 161953Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 162053Sigor@sysoev.ru return ret; 162153Sigor@sysoev.ru } 162253Sigor@sysoev.ru 1623139Sigor@sysoev.ru return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 162453Sigor@sysoev.ru } 162553Sigor@sysoev.ru 162653Sigor@sysoev.ru 162753Sigor@sysoev.ru static nxt_int_t 1628154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 1629154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 163053Sigor@sysoev.ru nxt_work_handler_t handler) 163153Sigor@sysoev.ru { 1632153Sigor@sysoev.ru nxt_joint_job_t *job; 163353Sigor@sysoev.ru nxt_queue_link_t *qlk; 1634155Sigor@sysoev.ru nxt_socket_conf_t *skcf; 163553Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 163653Sigor@sysoev.ru 163753Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 163853Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 163953Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 164053Sigor@sysoev.ru { 1641154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 1642153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 1643139Sigor@sysoev.ru return NXT_ERROR; 1644139Sigor@sysoev.ru } 1645139Sigor@sysoev.ru 1646154Sigor@sysoev.ru job->work.next = recf->jobs; 1647154Sigor@sysoev.ru recf->jobs = &job->work; 1648154Sigor@sysoev.ru 1649153Sigor@sysoev.ru job->task = tmcf->engine->task; 1650153Sigor@sysoev.ru job->work.handler = handler; 1651153Sigor@sysoev.ru job->work.task = &job->task; 1652153Sigor@sysoev.ru job->work.obj = job; 1653153Sigor@sysoev.ru job->tmcf = tmcf; 165453Sigor@sysoev.ru 1655154Sigor@sysoev.ru tmcf->count++; 1656154Sigor@sysoev.ru 1657154Sigor@sysoev.ru joint = nxt_mp_alloc(tmcf->conf->mem_pool, 1658154Sigor@sysoev.ru sizeof(nxt_socket_conf_joint_t)); 165953Sigor@sysoev.ru if (nxt_slow_path(joint == NULL)) { 166053Sigor@sysoev.ru return NXT_ERROR; 166153Sigor@sysoev.ru } 166253Sigor@sysoev.ru 1663153Sigor@sysoev.ru job->work.data = joint; 166453Sigor@sysoev.ru 166553Sigor@sysoev.ru joint->count = 1; 1666155Sigor@sysoev.ru 1667155Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1668155Sigor@sysoev.ru skcf->count++; 1669155Sigor@sysoev.ru joint->socket_conf = skcf; 1670155Sigor@sysoev.ru 167188Smax.romanov@nginx.com joint->engine = recf->engine; 167253Sigor@sysoev.ru } 167353Sigor@sysoev.ru 167420Sigor@sysoev.ru return NXT_OK; 167520Sigor@sysoev.ru } 167620Sigor@sysoev.ru 167720Sigor@sysoev.ru 167820Sigor@sysoev.ru static nxt_int_t 1679313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 1680313Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 1681313Sigor@sysoev.ru { 1682313Sigor@sysoev.ru nxt_joint_job_t *job; 1683313Sigor@sysoev.ru 1684313Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 1685313Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 1686313Sigor@sysoev.ru return NXT_ERROR; 1687313Sigor@sysoev.ru } 1688313Sigor@sysoev.ru 1689313Sigor@sysoev.ru job->work.next = recf->jobs; 1690313Sigor@sysoev.ru recf->jobs = &job->work; 1691313Sigor@sysoev.ru 1692313Sigor@sysoev.ru job->task = tmcf->engine->task; 1693313Sigor@sysoev.ru job->work.handler = nxt_router_worker_thread_quit; 1694313Sigor@sysoev.ru job->work.task = &job->task; 1695313Sigor@sysoev.ru job->work.obj = NULL; 1696313Sigor@sysoev.ru job->work.data = NULL; 1697313Sigor@sysoev.ru job->tmcf = NULL; 1698313Sigor@sysoev.ru 1699313Sigor@sysoev.ru return NXT_OK; 1700313Sigor@sysoev.ru } 1701313Sigor@sysoev.ru 1702313Sigor@sysoev.ru 1703313Sigor@sysoev.ru static nxt_int_t 1704139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 1705139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets) 170620Sigor@sysoev.ru { 1707153Sigor@sysoev.ru nxt_joint_job_t *job; 170853Sigor@sysoev.ru nxt_queue_link_t *qlk; 170920Sigor@sysoev.ru 171053Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 171153Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 171253Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 171353Sigor@sysoev.ru { 1714154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 1715153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 1716139Sigor@sysoev.ru return NXT_ERROR; 1717139Sigor@sysoev.ru } 1718139Sigor@sysoev.ru 1719154Sigor@sysoev.ru job->work.next = recf->jobs; 1720154Sigor@sysoev.ru recf->jobs = &job->work; 1721154Sigor@sysoev.ru 1722153Sigor@sysoev.ru job->task = tmcf->engine->task; 1723153Sigor@sysoev.ru job->work.handler = nxt_router_listen_socket_delete; 1724153Sigor@sysoev.ru job->work.task = &job->task; 1725153Sigor@sysoev.ru job->work.obj = job; 1726153Sigor@sysoev.ru job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1727153Sigor@sysoev.ru job->tmcf = tmcf; 1728154Sigor@sysoev.ru 1729154Sigor@sysoev.ru tmcf->count++; 173020Sigor@sysoev.ru } 173120Sigor@sysoev.ru 173253Sigor@sysoev.ru return NXT_OK; 173353Sigor@sysoev.ru } 173420Sigor@sysoev.ru 173520Sigor@sysoev.ru 173653Sigor@sysoev.ru static nxt_int_t 173753Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 173853Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 173953Sigor@sysoev.ru { 174053Sigor@sysoev.ru nxt_int_t ret; 174153Sigor@sysoev.ru nxt_uint_t i, threads; 174253Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 174320Sigor@sysoev.ru 174453Sigor@sysoev.ru recf = tmcf->engines->elts; 174553Sigor@sysoev.ru threads = tmcf->conf->threads; 174620Sigor@sysoev.ru 174753Sigor@sysoev.ru for (i = tmcf->new_threads; i < threads; i++) { 174853Sigor@sysoev.ru ret = nxt_router_thread_create(task, rt, recf[i].engine); 174953Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 175053Sigor@sysoev.ru return ret; 175153Sigor@sysoev.ru } 175220Sigor@sysoev.ru } 175320Sigor@sysoev.ru 175420Sigor@sysoev.ru return NXT_OK; 175520Sigor@sysoev.ru } 175653Sigor@sysoev.ru 175753Sigor@sysoev.ru 175853Sigor@sysoev.ru static nxt_int_t 175953Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 176053Sigor@sysoev.ru nxt_event_engine_t *engine) 176153Sigor@sysoev.ru { 176253Sigor@sysoev.ru nxt_int_t ret; 176353Sigor@sysoev.ru nxt_thread_link_t *link; 176453Sigor@sysoev.ru nxt_thread_handle_t handle; 176553Sigor@sysoev.ru 176653Sigor@sysoev.ru link = nxt_zalloc(sizeof(nxt_thread_link_t)); 176753Sigor@sysoev.ru 176853Sigor@sysoev.ru if (nxt_slow_path(link == NULL)) { 176953Sigor@sysoev.ru return NXT_ERROR; 177053Sigor@sysoev.ru } 177153Sigor@sysoev.ru 177253Sigor@sysoev.ru link->start = nxt_router_thread_start; 177353Sigor@sysoev.ru link->engine = engine; 177453Sigor@sysoev.ru link->work.handler = nxt_router_thread_exit_handler; 177553Sigor@sysoev.ru link->work.task = task; 177653Sigor@sysoev.ru link->work.data = link; 177753Sigor@sysoev.ru 177853Sigor@sysoev.ru nxt_queue_insert_tail(&rt->engines, &engine->link); 177953Sigor@sysoev.ru 178053Sigor@sysoev.ru ret = nxt_thread_create(&handle, link); 178153Sigor@sysoev.ru 178253Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 178353Sigor@sysoev.ru nxt_queue_remove(&engine->link); 178453Sigor@sysoev.ru } 178553Sigor@sysoev.ru 178653Sigor@sysoev.ru return ret; 178753Sigor@sysoev.ru } 178853Sigor@sysoev.ru 178953Sigor@sysoev.ru 179053Sigor@sysoev.ru static void 1791343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 1792343Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf) 1793133Sigor@sysoev.ru { 1794343Smax.romanov@nginx.com nxt_app_t *app; 1795343Smax.romanov@nginx.com nxt_port_t *port; 1796141Smax.romanov@nginx.com 1797141Smax.romanov@nginx.com nxt_queue_each(app, &router->apps, nxt_app_t, link) { 1798133Sigor@sysoev.ru 1799133Sigor@sysoev.ru nxt_queue_remove(&app->link); 1800133Sigor@sysoev.ru 1801343Smax.romanov@nginx.com nxt_debug(task, "about to free app '%V' %p", &app->name, app); 1802167Smax.romanov@nginx.com 1803163Smax.romanov@nginx.com app->live = 0; 1804163Smax.romanov@nginx.com 1805167Smax.romanov@nginx.com do { 1806343Smax.romanov@nginx.com port = nxt_router_app_get_idle_port(app); 1807167Smax.romanov@nginx.com if (port == NULL) { 1808167Smax.romanov@nginx.com break; 1809167Smax.romanov@nginx.com } 1810167Smax.romanov@nginx.com 1811343Smax.romanov@nginx.com nxt_debug(task, "port %p send quit", port); 1812343Smax.romanov@nginx.com 1813343Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, 1814343Smax.romanov@nginx.com NULL); 1815343Smax.romanov@nginx.com 1816343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 1817167Smax.romanov@nginx.com } while (1); 1818167Smax.romanov@nginx.com 1819343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 1820343Smax.romanov@nginx.com 1821141Smax.romanov@nginx.com } nxt_queue_loop; 1822133Sigor@sysoev.ru 1823133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->previous); 1824133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->apps); 1825133Sigor@sysoev.ru } 1826133Sigor@sysoev.ru 1827133Sigor@sysoev.ru 1828133Sigor@sysoev.ru static void 1829315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf) 183053Sigor@sysoev.ru { 183153Sigor@sysoev.ru nxt_uint_t n; 1832315Sigor@sysoev.ru nxt_event_engine_t *engine; 183353Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 183453Sigor@sysoev.ru 183553Sigor@sysoev.ru recf = tmcf->engines->elts; 183653Sigor@sysoev.ru 183753Sigor@sysoev.ru for (n = tmcf->engines->nelts; n != 0; n--) { 1838315Sigor@sysoev.ru engine = recf->engine; 1839315Sigor@sysoev.ru 1840315Sigor@sysoev.ru switch (recf->action) { 1841315Sigor@sysoev.ru 1842315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_KEEP: 1843315Sigor@sysoev.ru break; 1844315Sigor@sysoev.ru 1845315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_ADD: 1846315Sigor@sysoev.ru nxt_queue_insert_tail(&router->engines, &engine->link0); 1847315Sigor@sysoev.ru break; 1848315Sigor@sysoev.ru 1849315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_DELETE: 1850315Sigor@sysoev.ru nxt_queue_remove(&engine->link0); 1851315Sigor@sysoev.ru break; 1852315Sigor@sysoev.ru } 1853315Sigor@sysoev.ru 1854316Sigor@sysoev.ru nxt_router_engine_post(engine, recf->jobs); 1855316Sigor@sysoev.ru 185653Sigor@sysoev.ru recf++; 185753Sigor@sysoev.ru } 185853Sigor@sysoev.ru } 185953Sigor@sysoev.ru 186053Sigor@sysoev.ru 186153Sigor@sysoev.ru static void 1862315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs) 186353Sigor@sysoev.ru { 1864154Sigor@sysoev.ru nxt_work_t *work, *next; 1865154Sigor@sysoev.ru 1866315Sigor@sysoev.ru for (work = jobs; work != NULL; work = next) { 1867154Sigor@sysoev.ru next = work->next; 1868154Sigor@sysoev.ru work->next = NULL; 1869154Sigor@sysoev.ru 1870315Sigor@sysoev.ru nxt_event_engine_post(engine, work); 187153Sigor@sysoev.ru } 187253Sigor@sysoev.ru } 187353Sigor@sysoev.ru 187453Sigor@sysoev.ru 1875320Smax.romanov@nginx.com static nxt_port_handlers_t nxt_router_app_port_handlers = { 1876320Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 1877320Smax.romanov@nginx.com .data = nxt_port_rpc_handler, 187888Smax.romanov@nginx.com }; 187988Smax.romanov@nginx.com 188088Smax.romanov@nginx.com 188188Smax.romanov@nginx.com static void 188253Sigor@sysoev.ru nxt_router_thread_start(void *data) 188353Sigor@sysoev.ru { 1884141Smax.romanov@nginx.com nxt_int_t ret; 1885141Smax.romanov@nginx.com nxt_port_t *port; 188688Smax.romanov@nginx.com nxt_task_t *task; 188753Sigor@sysoev.ru nxt_thread_t *thread; 188853Sigor@sysoev.ru nxt_thread_link_t *link; 188953Sigor@sysoev.ru nxt_event_engine_t *engine; 189053Sigor@sysoev.ru 189153Sigor@sysoev.ru link = data; 189253Sigor@sysoev.ru engine = link->engine; 189388Smax.romanov@nginx.com task = &engine->task; 189453Sigor@sysoev.ru 189553Sigor@sysoev.ru thread = nxt_thread(); 189653Sigor@sysoev.ru 1897165Smax.romanov@nginx.com nxt_event_engine_thread_adopt(engine); 1898165Smax.romanov@nginx.com 189953Sigor@sysoev.ru /* STUB */ 190053Sigor@sysoev.ru thread->runtime = engine->task.thread->runtime; 190153Sigor@sysoev.ru 190253Sigor@sysoev.ru engine->task.thread = thread; 190353Sigor@sysoev.ru engine->task.log = thread->log; 190453Sigor@sysoev.ru thread->engine = engine; 190563Sigor@sysoev.ru thread->task = &engine->task; 1906326Svbart@nginx.com #if 0 190753Sigor@sysoev.ru thread->fiber = &engine->fibers->fiber; 1908326Svbart@nginx.com #endif 190953Sigor@sysoev.ru 191063Sigor@sysoev.ru engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64); 1911337Sigor@sysoev.ru if (nxt_slow_path(engine->mem_pool == NULL)) { 1912337Sigor@sysoev.ru return; 1913337Sigor@sysoev.ru } 191453Sigor@sysoev.ru 1915197Smax.romanov@nginx.com port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid, 1916197Smax.romanov@nginx.com NXT_PROCESS_ROUTER); 1917141Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 1918141Smax.romanov@nginx.com return; 1919141Smax.romanov@nginx.com } 1920141Smax.romanov@nginx.com 1921141Smax.romanov@nginx.com ret = nxt_port_socket_init(task, port, 0); 1922141Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 1923343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 1924141Smax.romanov@nginx.com return; 1925141Smax.romanov@nginx.com } 1926141Smax.romanov@nginx.com 1927141Smax.romanov@nginx.com engine->port = port; 1928141Smax.romanov@nginx.com 1929320Smax.romanov@nginx.com nxt_port_enable(task, port, &nxt_router_app_port_handlers); 1930141Smax.romanov@nginx.com 193153Sigor@sysoev.ru nxt_event_engine_start(engine); 193253Sigor@sysoev.ru } 193353Sigor@sysoev.ru 193453Sigor@sysoev.ru 193553Sigor@sysoev.ru static void 193653Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data) 193753Sigor@sysoev.ru { 1938153Sigor@sysoev.ru nxt_joint_job_t *job; 1939*359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1940*359Sigor@sysoev.ru nxt_listen_event_t *lev; 194153Sigor@sysoev.ru nxt_listen_socket_t *ls; 1942*359Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 194353Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 194453Sigor@sysoev.ru 1945153Sigor@sysoev.ru job = obj; 194653Sigor@sysoev.ru joint = data; 194753Sigor@sysoev.ru 1948159Sigor@sysoev.ru nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link); 1949159Sigor@sysoev.ru 1950*359Sigor@sysoev.ru skcf = joint->socket_conf; 1951*359Sigor@sysoev.ru ls = skcf->listen; 1952*359Sigor@sysoev.ru 1953*359Sigor@sysoev.ru lev = nxt_listen_event(task, ls); 1954*359Sigor@sysoev.ru if (nxt_slow_path(lev == NULL)) { 1955*359Sigor@sysoev.ru nxt_router_listen_socket_release(task, skcf); 195653Sigor@sysoev.ru return; 195753Sigor@sysoev.ru } 195853Sigor@sysoev.ru 1959*359Sigor@sysoev.ru lev->socket.data = joint; 1960*359Sigor@sysoev.ru 1961*359Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 1962*359Sigor@sysoev.ru 1963*359Sigor@sysoev.ru nxt_thread_spin_lock(lock); 1964*359Sigor@sysoev.ru ls->count++; 1965*359Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 1966139Sigor@sysoev.ru 1967153Sigor@sysoev.ru job->work.next = NULL; 1968153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 1969153Sigor@sysoev.ru 1970153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 197153Sigor@sysoev.ru } 197253Sigor@sysoev.ru 197353Sigor@sysoev.ru 197453Sigor@sysoev.ru nxt_inline nxt_listen_event_t * 197553Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections, 197653Sigor@sysoev.ru nxt_socket_conf_t *skcf) 197753Sigor@sysoev.ru { 1978115Sigor@sysoev.ru nxt_socket_t fd; 1979115Sigor@sysoev.ru nxt_queue_link_t *qlk; 1980*359Sigor@sysoev.ru nxt_listen_event_t *lev; 1981*359Sigor@sysoev.ru 1982*359Sigor@sysoev.ru fd = skcf->listen->socket; 198353Sigor@sysoev.ru 1984115Sigor@sysoev.ru for (qlk = nxt_queue_first(listen_connections); 1985115Sigor@sysoev.ru qlk != nxt_queue_tail(listen_connections); 1986115Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 198753Sigor@sysoev.ru { 1988*359Sigor@sysoev.ru lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link); 1989*359Sigor@sysoev.ru 1990*359Sigor@sysoev.ru if (fd == lev->socket.fd) { 1991*359Sigor@sysoev.ru return lev; 199253Sigor@sysoev.ru } 199353Sigor@sysoev.ru } 199453Sigor@sysoev.ru 199553Sigor@sysoev.ru return NULL; 199653Sigor@sysoev.ru } 199753Sigor@sysoev.ru 199853Sigor@sysoev.ru 199953Sigor@sysoev.ru static void 200053Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data) 200153Sigor@sysoev.ru { 2002153Sigor@sysoev.ru nxt_joint_job_t *job; 200353Sigor@sysoev.ru nxt_event_engine_t *engine; 2004*359Sigor@sysoev.ru nxt_listen_event_t *lev; 200553Sigor@sysoev.ru nxt_socket_conf_joint_t *joint, *old; 200653Sigor@sysoev.ru 2007153Sigor@sysoev.ru job = obj; 200853Sigor@sysoev.ru joint = data; 200953Sigor@sysoev.ru 2010139Sigor@sysoev.ru engine = task->thread->engine; 2011139Sigor@sysoev.ru 2012159Sigor@sysoev.ru nxt_queue_insert_tail(&engine->joints, &joint->link); 2013159Sigor@sysoev.ru 2014*359Sigor@sysoev.ru lev = nxt_router_listen_event(&engine->listen_connections, 2015*359Sigor@sysoev.ru joint->socket_conf); 2016*359Sigor@sysoev.ru 2017*359Sigor@sysoev.ru old = lev->socket.data; 2018*359Sigor@sysoev.ru lev->socket.data = joint; 2019*359Sigor@sysoev.ru lev->listen = joint->socket_conf->listen; 202053Sigor@sysoev.ru 2021153Sigor@sysoev.ru job->work.next = NULL; 2022153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2023153Sigor@sysoev.ru 2024153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 2025139Sigor@sysoev.ru 2026181Smax.romanov@nginx.com /* 2027181Smax.romanov@nginx.com * The task is allocated from configuration temporary 2028181Smax.romanov@nginx.com * memory pool so it can be freed after engine post operation. 2029181Smax.romanov@nginx.com */ 2030181Smax.romanov@nginx.com 2031181Smax.romanov@nginx.com nxt_router_conf_release(&engine->task, old); 203253Sigor@sysoev.ru } 203353Sigor@sysoev.ru 203453Sigor@sysoev.ru 203553Sigor@sysoev.ru static void 203653Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data) 203753Sigor@sysoev.ru { 2038153Sigor@sysoev.ru nxt_joint_job_t *job; 2039153Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2040*359Sigor@sysoev.ru nxt_listen_event_t *lev; 2041153Sigor@sysoev.ru nxt_event_engine_t *engine; 2042153Sigor@sysoev.ru 2043153Sigor@sysoev.ru job = obj; 204453Sigor@sysoev.ru skcf = data; 204553Sigor@sysoev.ru 2046139Sigor@sysoev.ru engine = task->thread->engine; 2047139Sigor@sysoev.ru 2048*359Sigor@sysoev.ru lev = nxt_router_listen_event(&engine->listen_connections, skcf); 2049*359Sigor@sysoev.ru 2050*359Sigor@sysoev.ru nxt_fd_event_delete(engine, &lev->socket); 205153Sigor@sysoev.ru 2052163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket delete: %d", engine, 2053*359Sigor@sysoev.ru lev->socket.fd); 2054*359Sigor@sysoev.ru 2055*359Sigor@sysoev.ru lev->timer.handler = nxt_router_listen_socket_close; 2056*359Sigor@sysoev.ru lev->timer.work_queue = &engine->fast_work_queue; 2057*359Sigor@sysoev.ru 2058*359Sigor@sysoev.ru nxt_timer_add(engine, &lev->timer, 0); 2059139Sigor@sysoev.ru 2060153Sigor@sysoev.ru job->work.next = NULL; 2061153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2062153Sigor@sysoev.ru 2063153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 206453Sigor@sysoev.ru } 206553Sigor@sysoev.ru 206653Sigor@sysoev.ru 206753Sigor@sysoev.ru static void 2068313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data) 2069313Sigor@sysoev.ru { 2070313Sigor@sysoev.ru nxt_event_engine_t *engine; 2071313Sigor@sysoev.ru 2072313Sigor@sysoev.ru nxt_debug(task, "router worker thread quit"); 2073313Sigor@sysoev.ru 2074313Sigor@sysoev.ru engine = task->thread->engine; 2075313Sigor@sysoev.ru 2076313Sigor@sysoev.ru engine->shutdown = 1; 2077313Sigor@sysoev.ru 2078313Sigor@sysoev.ru if (nxt_queue_is_empty(&engine->joints)) { 2079313Sigor@sysoev.ru nxt_thread_exit(task->thread); 2080313Sigor@sysoev.ru } 2081313Sigor@sysoev.ru } 2082313Sigor@sysoev.ru 2083313Sigor@sysoev.ru 2084313Sigor@sysoev.ru static void 208553Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data) 208653Sigor@sysoev.ru { 208753Sigor@sysoev.ru nxt_timer_t *timer; 2088*359Sigor@sysoev.ru nxt_listen_event_t *lev; 208953Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 209053Sigor@sysoev.ru 209153Sigor@sysoev.ru timer = obj; 2092*359Sigor@sysoev.ru lev = nxt_timer_data(timer, nxt_listen_event_t, timer); 2093*359Sigor@sysoev.ru joint = lev->socket.data; 209453Sigor@sysoev.ru 2095163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine, 2096*359Sigor@sysoev.ru lev->socket.fd); 2097*359Sigor@sysoev.ru 2098*359Sigor@sysoev.ru nxt_queue_remove(&lev->link); 2099*359Sigor@sysoev.ru 2100*359Sigor@sysoev.ru /* 'task' refers to lev->task and we cannot use after nxt_free() */ 2101123Smax.romanov@nginx.com task = &task->thread->engine->task; 2102123Smax.romanov@nginx.com 2103*359Sigor@sysoev.ru nxt_router_listen_socket_release(task, joint->socket_conf); 2104*359Sigor@sysoev.ru 2105*359Sigor@sysoev.ru nxt_free(lev); 2106*359Sigor@sysoev.ru 2107*359Sigor@sysoev.ru nxt_router_conf_release(task, joint); 210853Sigor@sysoev.ru } 210953Sigor@sysoev.ru 211053Sigor@sysoev.ru 211153Sigor@sysoev.ru static void 2112*359Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf) 211353Sigor@sysoev.ru { 2114*359Sigor@sysoev.ru nxt_listen_socket_t *ls; 211553Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 211653Sigor@sysoev.ru 2117*359Sigor@sysoev.ru ls = skcf->listen; 2118118Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 211953Sigor@sysoev.ru 212053Sigor@sysoev.ru nxt_thread_spin_lock(lock); 212153Sigor@sysoev.ru 2122*359Sigor@sysoev.ru nxt_debug(task, "engine %p: listen socket release: ls->count %D", 2123*359Sigor@sysoev.ru task->thread->engine, ls->count); 2124*359Sigor@sysoev.ru 2125*359Sigor@sysoev.ru if (--ls->count != 0) { 2126*359Sigor@sysoev.ru ls = NULL; 212753Sigor@sysoev.ru } 212853Sigor@sysoev.ru 212953Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 213053Sigor@sysoev.ru 2131*359Sigor@sysoev.ru if (ls != NULL) { 2132*359Sigor@sysoev.ru nxt_socket_close(task, ls->socket); 2133*359Sigor@sysoev.ru nxt_free(ls); 213453Sigor@sysoev.ru } 213553Sigor@sysoev.ru } 213653Sigor@sysoev.ru 213753Sigor@sysoev.ru 213853Sigor@sysoev.ru static void 213953Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint) 214053Sigor@sysoev.ru { 2141156Sigor@sysoev.ru nxt_bool_t exit; 214253Sigor@sysoev.ru nxt_socket_conf_t *skcf; 214353Sigor@sysoev.ru nxt_router_conf_t *rtcf; 2144313Sigor@sysoev.ru nxt_event_engine_t *engine; 214553Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 214653Sigor@sysoev.ru 2147163Smax.romanov@nginx.com nxt_debug(task, "conf joint %p count: %D", joint, joint->count); 214853Sigor@sysoev.ru 214953Sigor@sysoev.ru if (--joint->count != 0) { 215053Sigor@sysoev.ru return; 215153Sigor@sysoev.ru } 215253Sigor@sysoev.ru 215353Sigor@sysoev.ru nxt_queue_remove(&joint->link); 215453Sigor@sysoev.ru 215553Sigor@sysoev.ru skcf = joint->socket_conf; 215653Sigor@sysoev.ru rtcf = skcf->router_conf; 215753Sigor@sysoev.ru lock = &rtcf->router->lock; 215853Sigor@sysoev.ru 215953Sigor@sysoev.ru nxt_thread_spin_lock(lock); 216053Sigor@sysoev.ru 2161163Smax.romanov@nginx.com nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count, 2162163Smax.romanov@nginx.com rtcf, rtcf->count); 2163163Smax.romanov@nginx.com 216453Sigor@sysoev.ru if (--skcf->count != 0) { 216553Sigor@sysoev.ru rtcf = NULL; 216653Sigor@sysoev.ru 216753Sigor@sysoev.ru } else { 216853Sigor@sysoev.ru nxt_queue_remove(&skcf->link); 216953Sigor@sysoev.ru 217053Sigor@sysoev.ru if (--rtcf->count != 0) { 217153Sigor@sysoev.ru rtcf = NULL; 217253Sigor@sysoev.ru } 217353Sigor@sysoev.ru } 217453Sigor@sysoev.ru 217553Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 217653Sigor@sysoev.ru 2177141Smax.romanov@nginx.com /* TODO remove engine->port */ 2178141Smax.romanov@nginx.com /* TODO excude from connected ports */ 2179141Smax.romanov@nginx.com 2180156Sigor@sysoev.ru /* The joint content can be used before memory pool destruction. */ 2181313Sigor@sysoev.ru engine = joint->engine; 2182313Sigor@sysoev.ru exit = (engine->shutdown && nxt_queue_is_empty(&engine->joints)); 2183156Sigor@sysoev.ru 218453Sigor@sysoev.ru if (rtcf != NULL) { 2185115Sigor@sysoev.ru nxt_debug(task, "old router conf is destroyed"); 2186131Smax.romanov@nginx.com 2187131Smax.romanov@nginx.com nxt_mp_thread_adopt(rtcf->mem_pool); 2188131Smax.romanov@nginx.com 218965Sigor@sysoev.ru nxt_mp_destroy(rtcf->mem_pool); 219053Sigor@sysoev.ru } 219153Sigor@sysoev.ru 2192156Sigor@sysoev.ru if (exit) { 219353Sigor@sysoev.ru nxt_thread_exit(task->thread); 219453Sigor@sysoev.ru } 219553Sigor@sysoev.ru } 219653Sigor@sysoev.ru 219753Sigor@sysoev.ru 219853Sigor@sysoev.ru static void 219953Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data) 220053Sigor@sysoev.ru { 2201141Smax.romanov@nginx.com nxt_port_t *port; 220253Sigor@sysoev.ru nxt_thread_link_t *link; 220353Sigor@sysoev.ru nxt_event_engine_t *engine; 220453Sigor@sysoev.ru nxt_thread_handle_t handle; 220553Sigor@sysoev.ru 220658Svbart@nginx.com handle = (nxt_thread_handle_t) obj; 220753Sigor@sysoev.ru link = data; 220853Sigor@sysoev.ru 220953Sigor@sysoev.ru nxt_thread_wait(handle); 221053Sigor@sysoev.ru 221153Sigor@sysoev.ru engine = link->engine; 221253Sigor@sysoev.ru 221353Sigor@sysoev.ru nxt_queue_remove(&engine->link); 221453Sigor@sysoev.ru 2215141Smax.romanov@nginx.com port = engine->port; 2216141Smax.romanov@nginx.com 2217141Smax.romanov@nginx.com // TODO notify all apps 2218141Smax.romanov@nginx.com 2219343Smax.romanov@nginx.com port->engine = task->thread->engine; 2220163Smax.romanov@nginx.com nxt_mp_thread_adopt(port->mem_pool); 2221343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 2222163Smax.romanov@nginx.com 2223163Smax.romanov@nginx.com nxt_mp_thread_adopt(engine->mem_pool); 222463Sigor@sysoev.ru nxt_mp_destroy(engine->mem_pool); 222553Sigor@sysoev.ru 222653Sigor@sysoev.ru nxt_event_engine_free(engine); 222753Sigor@sysoev.ru 222853Sigor@sysoev.ru nxt_free(link); 222953Sigor@sysoev.ru } 223053Sigor@sysoev.ru 223153Sigor@sysoev.ru 2232206Smax.romanov@nginx.com static const nxt_conn_state_t nxt_router_conn_read_header_state 223353Sigor@sysoev.ru nxt_aligned(64) = 223453Sigor@sysoev.ru { 223553Sigor@sysoev.ru .ready_handler = nxt_router_conn_http_header_parse, 223653Sigor@sysoev.ru .close_handler = nxt_router_conn_close, 223753Sigor@sysoev.ru .error_handler = nxt_router_conn_error, 223853Sigor@sysoev.ru 223953Sigor@sysoev.ru .timer_handler = nxt_router_conn_timeout, 224053Sigor@sysoev.ru .timer_value = nxt_router_conn_timeout_value, 224153Sigor@sysoev.ru .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout), 224253Sigor@sysoev.ru }; 224353Sigor@sysoev.ru 224453Sigor@sysoev.ru 2245206Smax.romanov@nginx.com static const nxt_conn_state_t nxt_router_conn_read_body_state 2246206Smax.romanov@nginx.com nxt_aligned(64) = 2247206Smax.romanov@nginx.com { 2248206Smax.romanov@nginx.com .ready_handler = nxt_router_conn_http_body_read, 2249206Smax.romanov@nginx.com .close_handler = nxt_router_conn_close, 2250206Smax.romanov@nginx.com .error_handler = nxt_router_conn_error, 2251206Smax.romanov@nginx.com 2252206Smax.romanov@nginx.com .timer_handler = nxt_router_conn_timeout, 2253206Smax.romanov@nginx.com .timer_value = nxt_router_conn_timeout_value, 2254206Smax.romanov@nginx.com .timer_data = offsetof(nxt_socket_conf_t, body_read_timeout), 2255206Smax.romanov@nginx.com .timer_autoreset = 1, 2256206Smax.romanov@nginx.com }; 2257206Smax.romanov@nginx.com 2258206Smax.romanov@nginx.com 225953Sigor@sysoev.ru static void 226053Sigor@sysoev.ru nxt_router_conn_init(nxt_task_t *task, void *obj, void *data) 226153Sigor@sysoev.ru { 226253Sigor@sysoev.ru size_t size; 226362Sigor@sysoev.ru nxt_conn_t *c; 2264*359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 226553Sigor@sysoev.ru nxt_event_engine_t *engine; 226653Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 226753Sigor@sysoev.ru 226853Sigor@sysoev.ru c = obj; 226953Sigor@sysoev.ru joint = data; 227053Sigor@sysoev.ru 227153Sigor@sysoev.ru nxt_debug(task, "router conn init"); 227253Sigor@sysoev.ru 2273*359Sigor@sysoev.ru c->joint = joint; 227453Sigor@sysoev.ru joint->count++; 227553Sigor@sysoev.ru 2276*359Sigor@sysoev.ru skcf = joint->socket_conf; 2277*359Sigor@sysoev.ru c->local = skcf->sockaddr; 2278*359Sigor@sysoev.ru 2279*359Sigor@sysoev.ru size = skcf->header_buffer_size; 228053Sigor@sysoev.ru c->read = nxt_buf_mem_alloc(c->mem_pool, size, 0); 228153Sigor@sysoev.ru 228253Sigor@sysoev.ru c->socket.data = NULL; 228353Sigor@sysoev.ru 228453Sigor@sysoev.ru engine = task->thread->engine; 228553Sigor@sysoev.ru c->read_work_queue = &engine->fast_work_queue; 228653Sigor@sysoev.ru c->write_work_queue = &engine->fast_work_queue; 228753Sigor@sysoev.ru 2288206Smax.romanov@nginx.com c->read_state = &nxt_router_conn_read_header_state; 228953Sigor@sysoev.ru 229062Sigor@sysoev.ru nxt_conn_read(engine, c); 229153Sigor@sysoev.ru } 229253Sigor@sysoev.ru 229353Sigor@sysoev.ru 229462Sigor@sysoev.ru static const nxt_conn_state_t nxt_router_conn_write_state 229553Sigor@sysoev.ru nxt_aligned(64) = 229653Sigor@sysoev.ru { 229788Smax.romanov@nginx.com .ready_handler = nxt_router_conn_ready, 229853Sigor@sysoev.ru .close_handler = nxt_router_conn_close, 229953Sigor@sysoev.ru .error_handler = nxt_router_conn_error, 230053Sigor@sysoev.ru }; 230153Sigor@sysoev.ru 230253Sigor@sysoev.ru 230353Sigor@sysoev.ru static void 2304318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2305318Smax.romanov@nginx.com void *data) 230688Smax.romanov@nginx.com { 230788Smax.romanov@nginx.com size_t dump_size; 2308194Smax.romanov@nginx.com nxt_buf_t *b, *last; 230988Smax.romanov@nginx.com nxt_conn_t *c; 231088Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 231188Smax.romanov@nginx.com 231288Smax.romanov@nginx.com b = msg->buf; 2313318Smax.romanov@nginx.com rc = data; 231488Smax.romanov@nginx.com 231588Smax.romanov@nginx.com c = rc->conn; 231688Smax.romanov@nginx.com 231788Smax.romanov@nginx.com dump_size = nxt_buf_used_size(b); 231888Smax.romanov@nginx.com 231988Smax.romanov@nginx.com if (dump_size > 300) { 232088Smax.romanov@nginx.com dump_size = 300; 232188Smax.romanov@nginx.com } 232288Smax.romanov@nginx.com 2323119Smax.romanov@nginx.com nxt_debug(task, "%srouter app data (%z): %*s", 232488Smax.romanov@nginx.com msg->port_msg.last ? "last " : "", msg->size, dump_size, 232588Smax.romanov@nginx.com b->mem.pos); 232688Smax.romanov@nginx.com 232788Smax.romanov@nginx.com if (msg->size == 0) { 232888Smax.romanov@nginx.com b = NULL; 232988Smax.romanov@nginx.com } 233088Smax.romanov@nginx.com 233188Smax.romanov@nginx.com if (msg->port_msg.last != 0) { 233288Smax.romanov@nginx.com nxt_debug(task, "router data create last buf"); 233388Smax.romanov@nginx.com 233488Smax.romanov@nginx.com last = nxt_buf_sync_alloc(c->mem_pool, NXT_BUF_SYNC_LAST); 233588Smax.romanov@nginx.com if (nxt_slow_path(last == NULL)) { 233688Smax.romanov@nginx.com /* TODO pogorevaTb */ 233788Smax.romanov@nginx.com } 233888Smax.romanov@nginx.com 233988Smax.romanov@nginx.com nxt_buf_chain_add(&b, last); 2340167Smax.romanov@nginx.com 2341343Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 234288Smax.romanov@nginx.com } 234388Smax.romanov@nginx.com 234488Smax.romanov@nginx.com if (b == NULL) { 234588Smax.romanov@nginx.com return; 234688Smax.romanov@nginx.com } 234788Smax.romanov@nginx.com 2348206Smax.romanov@nginx.com if (msg->buf == b) { 2349206Smax.romanov@nginx.com /* Disable instant buffer completion/re-using by port. */ 2350206Smax.romanov@nginx.com msg->buf = NULL; 2351206Smax.romanov@nginx.com } 2352194Smax.romanov@nginx.com 235388Smax.romanov@nginx.com if (c->write == NULL) { 235488Smax.romanov@nginx.com c->write = b; 235588Smax.romanov@nginx.com c->write_state = &nxt_router_conn_write_state; 235688Smax.romanov@nginx.com 235788Smax.romanov@nginx.com nxt_conn_write(task->thread->engine, c); 2358277Sigor@sysoev.ru 235988Smax.romanov@nginx.com } else { 236088Smax.romanov@nginx.com nxt_debug(task, "router data attach out bufs to existing chain"); 236188Smax.romanov@nginx.com 236288Smax.romanov@nginx.com nxt_buf_chain_add(&c->write, b); 236388Smax.romanov@nginx.com } 236488Smax.romanov@nginx.com } 236588Smax.romanov@nginx.com 2366277Sigor@sysoev.ru 2367318Smax.romanov@nginx.com static void 2368318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2369318Smax.romanov@nginx.com void *data) 2370318Smax.romanov@nginx.com { 2371318Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 2372318Smax.romanov@nginx.com 2373318Smax.romanov@nginx.com rc = data; 2374318Smax.romanov@nginx.com 2375318Smax.romanov@nginx.com nxt_router_gen_error(task, rc->conn, 500, 2376318Smax.romanov@nginx.com "Application terminated unexpectedly"); 2377318Smax.romanov@nginx.com 2378343Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 2379318Smax.romanov@nginx.com } 2380318Smax.romanov@nginx.com 2381318Smax.romanov@nginx.com 2382141Smax.romanov@nginx.com nxt_inline const char * 2383141Smax.romanov@nginx.com nxt_router_text_by_code(int code) 2384141Smax.romanov@nginx.com { 2385141Smax.romanov@nginx.com switch (code) { 2386141Smax.romanov@nginx.com case 400: return "Bad request"; 2387141Smax.romanov@nginx.com case 404: return "Not found"; 2388141Smax.romanov@nginx.com case 403: return "Forbidden"; 2389206Smax.romanov@nginx.com case 408: return "Request Timeout"; 2390206Smax.romanov@nginx.com case 411: return "Length Required"; 2391206Smax.romanov@nginx.com case 413: return "Request Entity Too Large"; 2392141Smax.romanov@nginx.com case 500: 2393141Smax.romanov@nginx.com default: return "Internal server error"; 2394141Smax.romanov@nginx.com } 2395141Smax.romanov@nginx.com } 2396141Smax.romanov@nginx.com 2397163Smax.romanov@nginx.com 2398163Smax.romanov@nginx.com static nxt_buf_t * 2399163Smax.romanov@nginx.com nxt_router_get_error_buf(nxt_task_t *task, nxt_mp_t *mp, int code, 2400345Smax.romanov@nginx.com const char* str) 240188Smax.romanov@nginx.com { 2402345Smax.romanov@nginx.com nxt_buf_t *b, *last; 2403345Smax.romanov@nginx.com 2404345Smax.romanov@nginx.com b = nxt_buf_mem_alloc(mp, 16384, 0); 2405141Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 2406163Smax.romanov@nginx.com return NULL; 2407141Smax.romanov@nginx.com } 2408141Smax.romanov@nginx.com 2409141Smax.romanov@nginx.com b->mem.free = nxt_sprintf(b->mem.free, b->mem.end, 2410141Smax.romanov@nginx.com "HTTP/1.0 %d %s\r\n" 2411141Smax.romanov@nginx.com "Content-Type: text/plain\r\n" 2412141Smax.romanov@nginx.com "Connection: close\r\n\r\n", 2413141Smax.romanov@nginx.com code, nxt_router_text_by_code(code)); 2414141Smax.romanov@nginx.com 2415345Smax.romanov@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str, nxt_strlen(str)); 2416345Smax.romanov@nginx.com 2417345Smax.romanov@nginx.com nxt_log_alert(task->log, "error %d: %s", code, str); 2418345Smax.romanov@nginx.com 2419345Smax.romanov@nginx.com last = nxt_buf_sync_alloc(mp, NXT_BUF_SYNC_LAST); 2420163Smax.romanov@nginx.com 2421141Smax.romanov@nginx.com if (nxt_slow_path(last == NULL)) { 2422345Smax.romanov@nginx.com nxt_mp_free(mp, b); 2423163Smax.romanov@nginx.com return NULL; 2424141Smax.romanov@nginx.com } 2425141Smax.romanov@nginx.com 2426141Smax.romanov@nginx.com nxt_buf_chain_add(&b, last); 2427141Smax.romanov@nginx.com 2428163Smax.romanov@nginx.com return b; 2429163Smax.romanov@nginx.com } 2430163Smax.romanov@nginx.com 2431163Smax.romanov@nginx.com 2432163Smax.romanov@nginx.com 2433163Smax.romanov@nginx.com static void 2434163Smax.romanov@nginx.com nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code, 2435345Smax.romanov@nginx.com const char* str) 2436163Smax.romanov@nginx.com { 2437318Smax.romanov@nginx.com nxt_mp_t *mp; 2438163Smax.romanov@nginx.com nxt_buf_t *b; 2439163Smax.romanov@nginx.com 2440318Smax.romanov@nginx.com /* TODO: fix when called in the middle of response */ 2441318Smax.romanov@nginx.com 2442345Smax.romanov@nginx.com mp = c->mem_pool; 2443345Smax.romanov@nginx.com 2444345Smax.romanov@nginx.com b = nxt_router_get_error_buf(task, mp, code, str); 2445163Smax.romanov@nginx.com 2446273Smax.romanov@nginx.com if (c->socket.fd == -1) { 2447345Smax.romanov@nginx.com nxt_mp_free(mp, b->next); 2448345Smax.romanov@nginx.com nxt_mp_free(mp, b); 2449273Smax.romanov@nginx.com return; 2450273Smax.romanov@nginx.com } 2451273Smax.romanov@nginx.com 2452141Smax.romanov@nginx.com if (c->write == NULL) { 2453141Smax.romanov@nginx.com c->write = b; 2454141Smax.romanov@nginx.com c->write_state = &nxt_router_conn_write_state; 2455141Smax.romanov@nginx.com 2456141Smax.romanov@nginx.com nxt_conn_write(task->thread->engine, c); 2457277Sigor@sysoev.ru 2458141Smax.romanov@nginx.com } else { 2459141Smax.romanov@nginx.com nxt_debug(task, "router data attach out bufs to existing chain"); 2460141Smax.romanov@nginx.com 2461141Smax.romanov@nginx.com nxt_buf_chain_add(&c->write, b); 2462141Smax.romanov@nginx.com } 2463141Smax.romanov@nginx.com } 2464141Smax.romanov@nginx.com 2465141Smax.romanov@nginx.com 2466141Smax.romanov@nginx.com static void 2467343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2468343Smax.romanov@nginx.com void *data) 2469192Smax.romanov@nginx.com { 2470343Smax.romanov@nginx.com nxt_app_t *app; 2471343Smax.romanov@nginx.com nxt_port_t *port; 2472343Smax.romanov@nginx.com 2473343Smax.romanov@nginx.com app = data; 2474347Smax.romanov@nginx.com port = msg->u.new_port; 2475343Smax.romanov@nginx.com 2476343Smax.romanov@nginx.com nxt_assert(app != NULL); 2477343Smax.romanov@nginx.com nxt_assert(port != NULL); 2478343Smax.romanov@nginx.com 2479343Smax.romanov@nginx.com port->app = app; 2480343Smax.romanov@nginx.com 2481343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2482343Smax.romanov@nginx.com 2483343Smax.romanov@nginx.com nxt_assert(app->pending_workers != 0); 2484343Smax.romanov@nginx.com 2485343Smax.romanov@nginx.com app->pending_workers--; 2486343Smax.romanov@nginx.com app->workers++; 2487343Smax.romanov@nginx.com 2488343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2489343Smax.romanov@nginx.com 2490343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p new port ready", &app->name, app); 2491343Smax.romanov@nginx.com 2492343Smax.romanov@nginx.com nxt_router_app_port_release(task, port, 0, 0); 2493192Smax.romanov@nginx.com } 2494192Smax.romanov@nginx.com 2495192Smax.romanov@nginx.com 2496192Smax.romanov@nginx.com static void 2497343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2498343Smax.romanov@nginx.com void *data) 2499192Smax.romanov@nginx.com { 2500318Smax.romanov@nginx.com nxt_app_t *app; 2501318Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2502318Smax.romanov@nginx.com nxt_req_app_link_t *ra; 2503343Smax.romanov@nginx.com 2504343Smax.romanov@nginx.com app = data; 2505343Smax.romanov@nginx.com 2506343Smax.romanov@nginx.com nxt_assert(app != NULL); 2507343Smax.romanov@nginx.com 2508343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start error", &app->name, app); 2509343Smax.romanov@nginx.com 2510343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2511343Smax.romanov@nginx.com 2512343Smax.romanov@nginx.com nxt_assert(app->pending_workers != 0); 2513343Smax.romanov@nginx.com 2514343Smax.romanov@nginx.com app->pending_workers--; 2515318Smax.romanov@nginx.com 2516318Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->requests)) { 2517318Smax.romanov@nginx.com lnk = nxt_queue_last(&app->requests); 2518318Smax.romanov@nginx.com nxt_queue_remove(lnk); 2519343Smax.romanov@nginx.com lnk->next = NULL; 2520318Smax.romanov@nginx.com 2521318Smax.romanov@nginx.com ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link); 2522318Smax.romanov@nginx.com 2523343Smax.romanov@nginx.com } else { 2524343Smax.romanov@nginx.com ra = NULL; 2525343Smax.romanov@nginx.com } 2526343Smax.romanov@nginx.com 2527343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2528343Smax.romanov@nginx.com 2529343Smax.romanov@nginx.com if (ra != NULL) { 2530318Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p abort next stream #%uD", 2531318Smax.romanov@nginx.com &app->name, app, ra->stream); 2532318Smax.romanov@nginx.com 2533318Smax.romanov@nginx.com nxt_router_ra_abort(task, ra, ra->work.data); 2534318Smax.romanov@nginx.com } 2535192Smax.romanov@nginx.com 2536343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 2537192Smax.romanov@nginx.com } 2538192Smax.romanov@nginx.com 2539192Smax.romanov@nginx.com 2540343Smax.romanov@nginx.com void 2541343Smax.romanov@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i) 2542141Smax.romanov@nginx.com { 2543343Smax.romanov@nginx.com int c; 2544343Smax.romanov@nginx.com 2545343Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&app->use_count, i); 2546343Smax.romanov@nginx.com 2547343Smax.romanov@nginx.com if (i < 0 && c == -i) { 2548343Smax.romanov@nginx.com 2549343Smax.romanov@nginx.com nxt_assert(app->live == 0); 2550343Smax.romanov@nginx.com nxt_assert(app->workers == 0); 2551343Smax.romanov@nginx.com nxt_assert(app->pending_workers == 0); 2552343Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->requests) != 0); 2553343Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->ports) != 0); 2554343Smax.romanov@nginx.com 2555163Smax.romanov@nginx.com nxt_thread_mutex_destroy(&app->mutex); 2556163Smax.romanov@nginx.com nxt_free(app); 2557163Smax.romanov@nginx.com } 2558343Smax.romanov@nginx.com } 2559343Smax.romanov@nginx.com 2560343Smax.romanov@nginx.com 2561343Smax.romanov@nginx.com nxt_inline nxt_port_t * 2562343Smax.romanov@nginx.com nxt_router_app_get_port_unsafe(nxt_app_t *app, int *use_delta) 2563343Smax.romanov@nginx.com { 2564343Smax.romanov@nginx.com nxt_port_t *port; 2565343Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2566343Smax.romanov@nginx.com 2567343Smax.romanov@nginx.com lnk = nxt_queue_first(&app->ports); 2568343Smax.romanov@nginx.com nxt_queue_remove(lnk); 2569343Smax.romanov@nginx.com 2570343Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, app_link); 2571343Smax.romanov@nginx.com 2572343Smax.romanov@nginx.com port->app_requests++; 2573343Smax.romanov@nginx.com 2574343Smax.romanov@nginx.com if (app->live && 2575343Smax.romanov@nginx.com (app->max_pending_responses == 0 || 2576343Smax.romanov@nginx.com (port->app_requests - port->app_responses) < 2577343Smax.romanov@nginx.com app->max_pending_responses) ) 2578277Sigor@sysoev.ru { 2579343Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, lnk); 2580343Smax.romanov@nginx.com 2581343Smax.romanov@nginx.com } else { 2582343Smax.romanov@nginx.com lnk->next = NULL; 2583343Smax.romanov@nginx.com 2584343Smax.romanov@nginx.com (*use_delta)--; 2585167Smax.romanov@nginx.com } 2586167Smax.romanov@nginx.com 2587343Smax.romanov@nginx.com return port; 2588163Smax.romanov@nginx.com } 2589163Smax.romanov@nginx.com 2590163Smax.romanov@nginx.com 2591141Smax.romanov@nginx.com static nxt_port_t * 2592343Smax.romanov@nginx.com nxt_router_app_get_idle_port(nxt_app_t *app) 2593141Smax.romanov@nginx.com { 2594343Smax.romanov@nginx.com nxt_port_t *port; 2595141Smax.romanov@nginx.com 2596141Smax.romanov@nginx.com port = NULL; 2597141Smax.romanov@nginx.com 2598141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2599141Smax.romanov@nginx.com 2600343Smax.romanov@nginx.com nxt_queue_each(port, &app->ports, nxt_port_t, app_link) { 2601343Smax.romanov@nginx.com 2602343Smax.romanov@nginx.com if (port->app_requests > port->app_responses) { 2603343Smax.romanov@nginx.com port = NULL; 2604343Smax.romanov@nginx.com 2605343Smax.romanov@nginx.com continue; 2606343Smax.romanov@nginx.com } 2607343Smax.romanov@nginx.com 2608343Smax.romanov@nginx.com nxt_queue_remove(&port->app_link); 2609343Smax.romanov@nginx.com port->app_link.next = NULL; 2610343Smax.romanov@nginx.com 2611343Smax.romanov@nginx.com break; 2612343Smax.romanov@nginx.com 2613343Smax.romanov@nginx.com } nxt_queue_loop; 2614141Smax.romanov@nginx.com 2615141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2616141Smax.romanov@nginx.com 2617141Smax.romanov@nginx.com return port; 2618141Smax.romanov@nginx.com } 2619141Smax.romanov@nginx.com 2620141Smax.romanov@nginx.com 2621141Smax.romanov@nginx.com static void 2622343Smax.romanov@nginx.com nxt_router_app_process_request(nxt_task_t *task, void *obj, void *data) 2623141Smax.romanov@nginx.com { 2624343Smax.romanov@nginx.com nxt_app_t *app; 2625343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 2626343Smax.romanov@nginx.com 2627343Smax.romanov@nginx.com app = obj; 2628343Smax.romanov@nginx.com ra = data; 2629141Smax.romanov@nginx.com 2630141Smax.romanov@nginx.com nxt_assert(app != NULL); 2631343Smax.romanov@nginx.com nxt_assert(ra != NULL); 2632343Smax.romanov@nginx.com nxt_assert(ra->app_port != NULL); 2633343Smax.romanov@nginx.com 2634343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p process next stream #%uD", 2635343Smax.romanov@nginx.com &app->name, app, ra->stream); 2636343Smax.romanov@nginx.com 2637343Smax.romanov@nginx.com nxt_router_process_http_request_mp(task, ra); 2638343Smax.romanov@nginx.com } 2639343Smax.romanov@nginx.com 2640343Smax.romanov@nginx.com 2641343Smax.romanov@nginx.com static void 2642343Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port, 2643343Smax.romanov@nginx.com uint32_t request_failed, uint32_t got_response) 2644343Smax.romanov@nginx.com { 2645343Smax.romanov@nginx.com int use_delta, ra_use_delta; 2646343Smax.romanov@nginx.com nxt_app_t *app; 2647343Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2648343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 2649343Smax.romanov@nginx.com 2650343Smax.romanov@nginx.com nxt_assert(port != NULL); 2651343Smax.romanov@nginx.com nxt_assert(port->app != NULL); 2652343Smax.romanov@nginx.com 2653343Smax.romanov@nginx.com app = port->app; 2654343Smax.romanov@nginx.com 2655343Smax.romanov@nginx.com use_delta = (request_failed == 0 && got_response == 0) ? 0 : -1; 2656343Smax.romanov@nginx.com 2657343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2658343Smax.romanov@nginx.com 2659343Smax.romanov@nginx.com port->app_requests -= request_failed; 2660343Smax.romanov@nginx.com port->app_responses += got_response; 2661343Smax.romanov@nginx.com 2662343Smax.romanov@nginx.com if (app->live != 0 && 2663343Smax.romanov@nginx.com port->pair[1] != -1 && 2664343Smax.romanov@nginx.com port->app_link.next == NULL && 2665343Smax.romanov@nginx.com (app->max_pending_responses == 0 || 2666343Smax.romanov@nginx.com (port->app_requests - port->app_responses) < 2667343Smax.romanov@nginx.com app->max_pending_responses) ) 2668343Smax.romanov@nginx.com { 2669343Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &port->app_link); 2670343Smax.romanov@nginx.com use_delta++; 2671141Smax.romanov@nginx.com } 2672141Smax.romanov@nginx.com 2673343Smax.romanov@nginx.com if (app->live != 0 && 2674343Smax.romanov@nginx.com !nxt_queue_is_empty(&app->ports) && 2675343Smax.romanov@nginx.com !nxt_queue_is_empty(&app->requests)) 2676343Smax.romanov@nginx.com { 2677141Smax.romanov@nginx.com lnk = nxt_queue_first(&app->requests); 2678141Smax.romanov@nginx.com nxt_queue_remove(lnk); 2679343Smax.romanov@nginx.com lnk->next = NULL; 2680141Smax.romanov@nginx.com 2681167Smax.romanov@nginx.com ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link); 2682167Smax.romanov@nginx.com 2683343Smax.romanov@nginx.com ra_use_delta = 1; 2684343Smax.romanov@nginx.com ra->app_port = nxt_router_app_get_port_unsafe(app, &ra_use_delta); 2685343Smax.romanov@nginx.com 2686343Smax.romanov@nginx.com } else { 2687343Smax.romanov@nginx.com ra = NULL; 2688343Smax.romanov@nginx.com ra_use_delta = 0; 2689141Smax.romanov@nginx.com } 2690141Smax.romanov@nginx.com 2691343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2692343Smax.romanov@nginx.com 2693343Smax.romanov@nginx.com if (ra != NULL) { 2694343Smax.romanov@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 2695343Smax.romanov@nginx.com nxt_router_app_process_request, 2696343Smax.romanov@nginx.com &task->thread->engine->task, app, ra); 2697343Smax.romanov@nginx.com 2698343Smax.romanov@nginx.com goto adjust_use; 2699343Smax.romanov@nginx.com } 2700343Smax.romanov@nginx.com 2701343Smax.romanov@nginx.com /* ? */ 2702163Smax.romanov@nginx.com if (port->pair[1] == -1) { 2703343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)", 2704343Smax.romanov@nginx.com &app->name, app, port, port->pid); 2705343Smax.romanov@nginx.com 2706343Smax.romanov@nginx.com goto adjust_use; 2707163Smax.romanov@nginx.com } 2708163Smax.romanov@nginx.com 2709343Smax.romanov@nginx.com if (app->live == 0) { 2710167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p is not alive, send QUIT to port", 2711167Smax.romanov@nginx.com &app->name, app); 2712163Smax.romanov@nginx.com 2713163Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, 2714163Smax.romanov@nginx.com -1, 0, 0, NULL); 2715163Smax.romanov@nginx.com 2716343Smax.romanov@nginx.com goto adjust_use; 2717163Smax.romanov@nginx.com } 2718163Smax.romanov@nginx.com 2719167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p requests queue is empty, keep the port", 2720167Smax.romanov@nginx.com &app->name, app); 2721141Smax.romanov@nginx.com 2722343Smax.romanov@nginx.com adjust_use: 2723343Smax.romanov@nginx.com 2724343Smax.romanov@nginx.com if (use_delta != 0) { 2725343Smax.romanov@nginx.com nxt_port_use(task, port, use_delta); 2726343Smax.romanov@nginx.com } 2727343Smax.romanov@nginx.com 2728343Smax.romanov@nginx.com if (ra_use_delta != 0) { 2729343Smax.romanov@nginx.com nxt_port_use(task, ra->app_port, ra_use_delta); 2730343Smax.romanov@nginx.com } 2731141Smax.romanov@nginx.com } 2732141Smax.romanov@nginx.com 2733141Smax.romanov@nginx.com 2734343Smax.romanov@nginx.com void 2735343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port) 2736141Smax.romanov@nginx.com { 2737163Smax.romanov@nginx.com nxt_app_t *app; 2738343Smax.romanov@nginx.com nxt_bool_t unchain, start_worker; 2739141Smax.romanov@nginx.com 2740141Smax.romanov@nginx.com app = port->app; 2741343Smax.romanov@nginx.com 2742343Smax.romanov@nginx.com nxt_assert(app != NULL); 2743141Smax.romanov@nginx.com 2744141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2745141Smax.romanov@nginx.com 2746343Smax.romanov@nginx.com unchain = port->app_link.next != NULL; 2747343Smax.romanov@nginx.com 2748343Smax.romanov@nginx.com if (unchain) { 2749163Smax.romanov@nginx.com nxt_queue_remove(&port->app_link); 2750163Smax.romanov@nginx.com port->app_link.next = NULL; 2751343Smax.romanov@nginx.com } 2752343Smax.romanov@nginx.com 2753343Smax.romanov@nginx.com app->workers--; 2754343Smax.romanov@nginx.com 2755343Smax.romanov@nginx.com start_worker = app->live != 0 && 2756343Smax.romanov@nginx.com nxt_queue_is_empty(&app->requests) == 0 && 2757343Smax.romanov@nginx.com app->workers + app->pending_workers < app->max_workers; 2758343Smax.romanov@nginx.com 2759343Smax.romanov@nginx.com if (start_worker) { 2760343Smax.romanov@nginx.com app->pending_workers++; 2761163Smax.romanov@nginx.com } 2762141Smax.romanov@nginx.com 2763141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2764163Smax.romanov@nginx.com 2765343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p port %p close", &app->name, app, port); 2766343Smax.romanov@nginx.com 2767343Smax.romanov@nginx.com if (unchain) { 2768343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 2769163Smax.romanov@nginx.com } 2770163Smax.romanov@nginx.com 2771343Smax.romanov@nginx.com if (start_worker) { 2772343Smax.romanov@nginx.com nxt_router_start_worker(task, app); 2773343Smax.romanov@nginx.com } 2774141Smax.romanov@nginx.com } 2775141Smax.romanov@nginx.com 2776141Smax.romanov@nginx.com 2777167Smax.romanov@nginx.com static nxt_int_t 2778167Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_req_app_link_t *ra) 2779141Smax.romanov@nginx.com { 2780343Smax.romanov@nginx.com int use_delta; 2781343Smax.romanov@nginx.com nxt_int_t res; 2782141Smax.romanov@nginx.com nxt_app_t *app; 2783343Smax.romanov@nginx.com nxt_bool_t can_start_worker; 2784141Smax.romanov@nginx.com nxt_conn_t *c; 2785167Smax.romanov@nginx.com nxt_port_t *port; 2786318Smax.romanov@nginx.com nxt_event_engine_t *engine; 2787141Smax.romanov@nginx.com nxt_socket_conf_joint_t *joint; 2788141Smax.romanov@nginx.com 2789141Smax.romanov@nginx.com port = NULL; 2790343Smax.romanov@nginx.com use_delta = 1; 2791167Smax.romanov@nginx.com c = ra->rc->conn; 2792141Smax.romanov@nginx.com 2793*359Sigor@sysoev.ru joint = c->joint; 2794141Smax.romanov@nginx.com app = joint->socket_conf->application; 2795141Smax.romanov@nginx.com 2796141Smax.romanov@nginx.com if (app == NULL) { 2797167Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, 2798141Smax.romanov@nginx.com "Application is NULL in socket_conf"); 2799141Smax.romanov@nginx.com return NXT_ERROR; 2800141Smax.romanov@nginx.com } 2801141Smax.romanov@nginx.com 2802343Smax.romanov@nginx.com ra->rc->app = app; 2803343Smax.romanov@nginx.com 2804343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 2805343Smax.romanov@nginx.com 2806318Smax.romanov@nginx.com engine = task->thread->engine; 2807318Smax.romanov@nginx.com 2808318Smax.romanov@nginx.com nxt_timer_disable(engine, &c->read_timer); 2809318Smax.romanov@nginx.com 2810318Smax.romanov@nginx.com if (app->timeout != 0) { 2811318Smax.romanov@nginx.com c->read_timer.handler = nxt_router_app_timeout; 2812318Smax.romanov@nginx.com nxt_timer_add(engine, &c->read_timer, app->timeout); 2813318Smax.romanov@nginx.com } 2814318Smax.romanov@nginx.com 2815351Smax.romanov@nginx.com can_start_worker = 0; 2816351Smax.romanov@nginx.com 2817343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2818343Smax.romanov@nginx.com 2819343Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->ports)) { 2820343Smax.romanov@nginx.com port = nxt_router_app_get_port_unsafe(app, &use_delta); 2821343Smax.romanov@nginx.com 2822343Smax.romanov@nginx.com } else { 2823351Smax.romanov@nginx.com ra = nxt_router_ra_create(task, ra); 2824351Smax.romanov@nginx.com 2825351Smax.romanov@nginx.com if (nxt_fast_path(ra != NULL)) { 2826351Smax.romanov@nginx.com nxt_queue_insert_tail(&app->requests, &ra->link); 2827351Smax.romanov@nginx.com 2828351Smax.romanov@nginx.com can_start_worker = (app->workers + app->pending_workers) < 2829351Smax.romanov@nginx.com app->max_workers; 2830351Smax.romanov@nginx.com if (can_start_worker) { 2831351Smax.romanov@nginx.com app->pending_workers++; 2832351Smax.romanov@nginx.com } 2833343Smax.romanov@nginx.com } 2834343Smax.romanov@nginx.com 2835343Smax.romanov@nginx.com port = NULL; 2836343Smax.romanov@nginx.com } 2837343Smax.romanov@nginx.com 2838343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2839141Smax.romanov@nginx.com 2840351Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 2841351Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Failed to allocate " 2842351Smax.romanov@nginx.com "req<->app link"); 2843351Smax.romanov@nginx.com return NXT_ERROR; 2844351Smax.romanov@nginx.com } 2845351Smax.romanov@nginx.com 2846141Smax.romanov@nginx.com if (port != NULL) { 2847343Smax.romanov@nginx.com nxt_debug(task, "already have port for app '%V' %p ", &app->name, app); 2848163Smax.romanov@nginx.com 2849167Smax.romanov@nginx.com ra->app_port = port; 2850343Smax.romanov@nginx.com 2851343Smax.romanov@nginx.com if (use_delta != 0) { 2852343Smax.romanov@nginx.com nxt_port_use(task, port, use_delta); 2853343Smax.romanov@nginx.com } 2854141Smax.romanov@nginx.com return NXT_OK; 2855141Smax.romanov@nginx.com } 2856141Smax.romanov@nginx.com 2857351Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD allocated", ra->stream); 2858351Smax.romanov@nginx.com 2859343Smax.romanov@nginx.com if (!can_start_worker) { 2860343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p too many running or pending workers", 2861343Smax.romanov@nginx.com &app->name, app); 2862343Smax.romanov@nginx.com 2863343Smax.romanov@nginx.com return NXT_AGAIN; 2864343Smax.romanov@nginx.com } 2865343Smax.romanov@nginx.com 2866343Smax.romanov@nginx.com res = nxt_router_start_worker(task, app); 2867343Smax.romanov@nginx.com 2868343Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 2869343Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Failed to start worker"); 2870343Smax.romanov@nginx.com 2871141Smax.romanov@nginx.com return NXT_ERROR; 2872141Smax.romanov@nginx.com } 2873141Smax.romanov@nginx.com 2874141Smax.romanov@nginx.com return NXT_AGAIN; 287588Smax.romanov@nginx.com } 287688Smax.romanov@nginx.com 287788Smax.romanov@nginx.com 287888Smax.romanov@nginx.com static void 287953Sigor@sysoev.ru nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, void *data) 288053Sigor@sysoev.ru { 2881206Smax.romanov@nginx.com size_t size; 288253Sigor@sysoev.ru nxt_int_t ret; 2883206Smax.romanov@nginx.com nxt_buf_t *buf; 288462Sigor@sysoev.ru nxt_conn_t *c; 2885268Sigor@sysoev.ru nxt_sockaddr_t *local; 288688Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 2887206Smax.romanov@nginx.com nxt_app_request_body_t *b; 288853Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 288988Smax.romanov@nginx.com nxt_app_request_header_t *h; 289053Sigor@sysoev.ru 289153Sigor@sysoev.ru c = obj; 289288Smax.romanov@nginx.com ap = data; 2893206Smax.romanov@nginx.com buf = c->read; 2894*359Sigor@sysoev.ru joint = c->joint; 289553Sigor@sysoev.ru 289653Sigor@sysoev.ru nxt_debug(task, "router conn http header parse"); 289753Sigor@sysoev.ru 289888Smax.romanov@nginx.com if (ap == NULL) { 2899319Smax.romanov@nginx.com ap = nxt_app_http_req_init(task); 290088Smax.romanov@nginx.com if (nxt_slow_path(ap == NULL)) { 2901319Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, 2902319Smax.romanov@nginx.com "Failed to allocate parse context"); 290361Sigor@sysoev.ru return; 290461Sigor@sysoev.ru } 290588Smax.romanov@nginx.com 290688Smax.romanov@nginx.com c->socket.data = ap; 2907113Smax.romanov@nginx.com 2908113Smax.romanov@nginx.com ap->r.remote.start = nxt_sockaddr_address(c->remote); 2909113Smax.romanov@nginx.com ap->r.remote.length = c->remote->address_length; 2910206Smax.romanov@nginx.com 2911*359Sigor@sysoev.ru /* 2912*359Sigor@sysoev.ru * TODO: need an application flag to get local address 2913*359Sigor@sysoev.ru * required by "SERVER_ADDR" in Pyhton and PHP. Not used in Go. 2914*359Sigor@sysoev.ru */ 2915*359Sigor@sysoev.ru local = nxt_router_local_addr(task, c); 2916*359Sigor@sysoev.ru 2917*359Sigor@sysoev.ru if (nxt_fast_path(local != NULL)) { 2918*359Sigor@sysoev.ru ap->r.local.start = nxt_sockaddr_address(local); 2919*359Sigor@sysoev.ru ap->r.local.length = local->address_length; 2920*359Sigor@sysoev.ru } 2921268Sigor@sysoev.ru 2922206Smax.romanov@nginx.com ap->r.header.buf = buf; 292353Sigor@sysoev.ru } 292453Sigor@sysoev.ru 292588Smax.romanov@nginx.com h = &ap->r.header; 2926206Smax.romanov@nginx.com b = &ap->r.body; 2927206Smax.romanov@nginx.com 2928206Smax.romanov@nginx.com ret = nxt_app_http_req_header_parse(task, ap, buf); 2929206Smax.romanov@nginx.com 2930206Smax.romanov@nginx.com nxt_debug(task, "http parse request header: %d", ret); 293153Sigor@sysoev.ru 293253Sigor@sysoev.ru switch (nxt_expect(NXT_DONE, ret)) { 293353Sigor@sysoev.ru 293453Sigor@sysoev.ru case NXT_DONE: 293588Smax.romanov@nginx.com nxt_debug(task, "router request header parsing complete, " 293688Smax.romanov@nginx.com "content length: %O, preread: %uz", 2937206Smax.romanov@nginx.com h->parsed_content_length, nxt_buf_mem_used_size(&buf->mem)); 2938206Smax.romanov@nginx.com 2939206Smax.romanov@nginx.com if (b->done) { 2940206Smax.romanov@nginx.com nxt_router_process_http_request(task, c, ap); 2941206Smax.romanov@nginx.com 2942206Smax.romanov@nginx.com return; 2943206Smax.romanov@nginx.com } 2944206Smax.romanov@nginx.com 2945277Sigor@sysoev.ru if (joint->socket_conf->max_body_size > 0 2946277Sigor@sysoev.ru && (size_t) h->parsed_content_length 2947277Sigor@sysoev.ru > joint->socket_conf->max_body_size) 2948277Sigor@sysoev.ru { 2949206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 413, "Content-Length too big"); 2950206Smax.romanov@nginx.com return; 2951206Smax.romanov@nginx.com } 2952206Smax.romanov@nginx.com 2953206Smax.romanov@nginx.com if (nxt_buf_mem_free_size(&buf->mem) == 0) { 2954206Smax.romanov@nginx.com size = nxt_min(joint->socket_conf->body_buffer_size, 2955206Smax.romanov@nginx.com (size_t) h->parsed_content_length); 2956206Smax.romanov@nginx.com 2957206Smax.romanov@nginx.com buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0); 2958206Smax.romanov@nginx.com if (nxt_slow_path(buf->next == NULL)) { 2959206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Failed to allocate " 2960206Smax.romanov@nginx.com "buffer for request body"); 2961206Smax.romanov@nginx.com return; 2962206Smax.romanov@nginx.com } 2963206Smax.romanov@nginx.com 2964206Smax.romanov@nginx.com c->read = buf->next; 2965206Smax.romanov@nginx.com 2966206Smax.romanov@nginx.com b->preread_size += nxt_buf_mem_used_size(&buf->mem); 2967206Smax.romanov@nginx.com } 2968206Smax.romanov@nginx.com 2969206Smax.romanov@nginx.com if (b->buf == NULL) { 2970206Smax.romanov@nginx.com b->buf = c->read; 2971206Smax.romanov@nginx.com } 2972206Smax.romanov@nginx.com 2973206Smax.romanov@nginx.com c->read_state = &nxt_router_conn_read_body_state; 2974206Smax.romanov@nginx.com break; 2975206Smax.romanov@nginx.com 2976206Smax.romanov@nginx.com case NXT_ERROR: 2977206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 400, "Request header parse error"); 2978206Smax.romanov@nginx.com return; 2979206Smax.romanov@nginx.com 2980206Smax.romanov@nginx.com default: /* NXT_AGAIN */ 2981206Smax.romanov@nginx.com 2982206Smax.romanov@nginx.com if (c->read->mem.free == c->read->mem.end) { 2983206Smax.romanov@nginx.com size = joint->socket_conf->large_header_buffer_size; 2984206Smax.romanov@nginx.com 2985277Sigor@sysoev.ru if (size <= (size_t) nxt_buf_mem_used_size(&buf->mem) 2986277Sigor@sysoev.ru || ap->r.header.bufs 2987277Sigor@sysoev.ru >= joint->socket_conf->large_header_buffers) 2988277Sigor@sysoev.ru { 2989206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 413, 2990206Smax.romanov@nginx.com "Too long request headers"); 2991206Smax.romanov@nginx.com return; 2992206Smax.romanov@nginx.com } 2993206Smax.romanov@nginx.com 2994206Smax.romanov@nginx.com buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0); 2995206Smax.romanov@nginx.com if (nxt_slow_path(buf->next == NULL)) { 2996206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, 2997206Smax.romanov@nginx.com "Failed to allocate large header " 2998206Smax.romanov@nginx.com "buffer"); 2999206Smax.romanov@nginx.com return; 3000206Smax.romanov@nginx.com } 3001206Smax.romanov@nginx.com 3002206Smax.romanov@nginx.com ap->r.header.bufs++; 3003206Smax.romanov@nginx.com 3004206Smax.romanov@nginx.com size = c->read->mem.free - c->read->mem.pos; 3005206Smax.romanov@nginx.com 3006206Smax.romanov@nginx.com c->read = nxt_buf_cpy(buf->next, c->read->mem.pos, size); 3007206Smax.romanov@nginx.com } 3008206Smax.romanov@nginx.com 3009206Smax.romanov@nginx.com } 3010206Smax.romanov@nginx.com 3011206Smax.romanov@nginx.com nxt_conn_read(task->thread->engine, c); 3012206Smax.romanov@nginx.com } 3013206Smax.romanov@nginx.com 3014206Smax.romanov@nginx.com 3015*359Sigor@sysoev.ru static nxt_sockaddr_t * 3016*359Sigor@sysoev.ru nxt_router_local_addr(nxt_task_t *task, nxt_conn_t *c) 3017*359Sigor@sysoev.ru { 3018*359Sigor@sysoev.ru int ret; 3019*359Sigor@sysoev.ru size_t size; 3020*359Sigor@sysoev.ru socklen_t socklen; 3021*359Sigor@sysoev.ru nxt_sockaddr_t *sa; 3022*359Sigor@sysoev.ru 3023*359Sigor@sysoev.ru if (c->local != NULL) { 3024*359Sigor@sysoev.ru return c->local; 3025*359Sigor@sysoev.ru } 3026*359Sigor@sysoev.ru 3027*359Sigor@sysoev.ru /* AF_UNIX should not get in here. */ 3028*359Sigor@sysoev.ru 3029*359Sigor@sysoev.ru switch (c->remote->u.sockaddr.sa_family) { 3030*359Sigor@sysoev.ru #if (NXT_INET6) 3031*359Sigor@sysoev.ru case AF_INET6: 3032*359Sigor@sysoev.ru socklen = sizeof(struct sockaddr_in6); 3033*359Sigor@sysoev.ru size = offsetof(nxt_sockaddr_t, u) + socklen + NXT_INET6_ADDR_STR_LEN; 3034*359Sigor@sysoev.ru break; 3035*359Sigor@sysoev.ru #endif 3036*359Sigor@sysoev.ru case AF_INET: 3037*359Sigor@sysoev.ru default: 3038*359Sigor@sysoev.ru socklen = sizeof(struct sockaddr_in6); 3039*359Sigor@sysoev.ru size = offsetof(nxt_sockaddr_t, u) + socklen + NXT_INET_ADDR_STR_LEN; 3040*359Sigor@sysoev.ru break; 3041*359Sigor@sysoev.ru } 3042*359Sigor@sysoev.ru 3043*359Sigor@sysoev.ru sa = nxt_mp_get(c->mem_pool, size); 3044*359Sigor@sysoev.ru if (nxt_slow_path(sa == NULL)) { 3045*359Sigor@sysoev.ru return NULL; 3046*359Sigor@sysoev.ru } 3047*359Sigor@sysoev.ru 3048*359Sigor@sysoev.ru ret = getsockname(c->socket.fd, &sa->u.sockaddr, &socklen); 3049*359Sigor@sysoev.ru if (nxt_slow_path(ret != 0)) { 3050*359Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "getsockname(%d) failed", c->socket.fd); 3051*359Sigor@sysoev.ru return NULL; 3052*359Sigor@sysoev.ru } 3053*359Sigor@sysoev.ru 3054*359Sigor@sysoev.ru c->local = sa; 3055*359Sigor@sysoev.ru 3056*359Sigor@sysoev.ru nxt_sockaddr_text(sa); 3057*359Sigor@sysoev.ru 3058*359Sigor@sysoev.ru /* 3059*359Sigor@sysoev.ru * TODO: here we can adjust the end of non-freeable block 3060*359Sigor@sysoev.ru * in c->mem_pool to the end of actual sockaddr length. 3061*359Sigor@sysoev.ru */ 3062*359Sigor@sysoev.ru 3063*359Sigor@sysoev.ru return sa; 3064*359Sigor@sysoev.ru } 3065*359Sigor@sysoev.ru 3066*359Sigor@sysoev.ru 3067206Smax.romanov@nginx.com static void 3068206Smax.romanov@nginx.com nxt_router_conn_http_body_read(nxt_task_t *task, void *obj, void *data) 3069206Smax.romanov@nginx.com { 3070206Smax.romanov@nginx.com size_t size; 3071206Smax.romanov@nginx.com nxt_int_t ret; 3072206Smax.romanov@nginx.com nxt_buf_t *buf; 3073206Smax.romanov@nginx.com nxt_conn_t *c; 3074206Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 3075206Smax.romanov@nginx.com nxt_app_request_body_t *b; 3076206Smax.romanov@nginx.com nxt_socket_conf_joint_t *joint; 3077206Smax.romanov@nginx.com nxt_app_request_header_t *h; 3078206Smax.romanov@nginx.com 3079206Smax.romanov@nginx.com c = obj; 3080206Smax.romanov@nginx.com ap = data; 3081206Smax.romanov@nginx.com buf = c->read; 3082206Smax.romanov@nginx.com 3083206Smax.romanov@nginx.com nxt_debug(task, "router conn http body read"); 3084206Smax.romanov@nginx.com 3085206Smax.romanov@nginx.com nxt_assert(ap != NULL); 3086206Smax.romanov@nginx.com 3087206Smax.romanov@nginx.com b = &ap->r.body; 3088206Smax.romanov@nginx.com h = &ap->r.header; 3089206Smax.romanov@nginx.com 3090206Smax.romanov@nginx.com ret = nxt_app_http_req_body_read(task, ap, buf); 3091206Smax.romanov@nginx.com 3092206Smax.romanov@nginx.com nxt_debug(task, "http read request body: %d", ret); 3093206Smax.romanov@nginx.com 3094206Smax.romanov@nginx.com switch (nxt_expect(NXT_DONE, ret)) { 3095206Smax.romanov@nginx.com 3096206Smax.romanov@nginx.com case NXT_DONE: 309788Smax.romanov@nginx.com nxt_router_process_http_request(task, c, ap); 309888Smax.romanov@nginx.com return; 309953Sigor@sysoev.ru 310053Sigor@sysoev.ru case NXT_ERROR: 3101206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Read body error"); 310253Sigor@sysoev.ru return; 310353Sigor@sysoev.ru 310453Sigor@sysoev.ru default: /* NXT_AGAIN */ 310553Sigor@sysoev.ru 3106206Smax.romanov@nginx.com if (nxt_buf_mem_free_size(&buf->mem) == 0) { 3107*359Sigor@sysoev.ru joint = c->joint; 3108206Smax.romanov@nginx.com 3109206Smax.romanov@nginx.com b->preread_size += nxt_buf_mem_used_size(&buf->mem); 3110206Smax.romanov@nginx.com 3111206Smax.romanov@nginx.com size = nxt_min(joint->socket_conf->body_buffer_size, 3112206Smax.romanov@nginx.com (size_t) h->parsed_content_length - b->preread_size); 3113206Smax.romanov@nginx.com 3114206Smax.romanov@nginx.com buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0); 3115206Smax.romanov@nginx.com if (nxt_slow_path(buf->next == NULL)) { 3116206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Failed to allocate " 3117206Smax.romanov@nginx.com "buffer for request body"); 3118206Smax.romanov@nginx.com return; 311988Smax.romanov@nginx.com } 3120206Smax.romanov@nginx.com 3121206Smax.romanov@nginx.com c->read = buf->next; 312288Smax.romanov@nginx.com } 312388Smax.romanov@nginx.com 3124206Smax.romanov@nginx.com nxt_debug(task, "router request body read again, rest: %uz", 3125206Smax.romanov@nginx.com h->parsed_content_length - b->preread_size); 312688Smax.romanov@nginx.com } 312788Smax.romanov@nginx.com 312888Smax.romanov@nginx.com nxt_conn_read(task->thread->engine, c); 312988Smax.romanov@nginx.com } 313088Smax.romanov@nginx.com 313188Smax.romanov@nginx.com 313288Smax.romanov@nginx.com static void 313388Smax.romanov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_conn_t *c, 313488Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap) 313588Smax.romanov@nginx.com { 3136122Smax.romanov@nginx.com nxt_int_t res; 3137167Smax.romanov@nginx.com nxt_port_t *port; 313888Smax.romanov@nginx.com nxt_event_engine_t *engine; 3139351Smax.romanov@nginx.com nxt_req_app_link_t ra_local, *ra; 314088Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 314188Smax.romanov@nginx.com 314288Smax.romanov@nginx.com engine = task->thread->engine; 314388Smax.romanov@nginx.com 3144318Smax.romanov@nginx.com rc = nxt_port_rpc_register_handler_ex(task, engine->port, 3145318Smax.romanov@nginx.com nxt_router_response_ready_handler, 3146318Smax.romanov@nginx.com nxt_router_response_error_handler, 3147318Smax.romanov@nginx.com sizeof(nxt_req_conn_link_t)); 3148122Smax.romanov@nginx.com 314988Smax.romanov@nginx.com if (nxt_slow_path(rc == NULL)) { 3150141Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Failed to allocate " 3151346Smax.romanov@nginx.com "req<->conn link"); 3152141Smax.romanov@nginx.com 3153141Smax.romanov@nginx.com return; 315488Smax.romanov@nginx.com } 315588Smax.romanov@nginx.com 3156318Smax.romanov@nginx.com rc->stream = nxt_port_rpc_ex_stream(rc); 3157318Smax.romanov@nginx.com rc->conn = c; 3158318Smax.romanov@nginx.com 3159318Smax.romanov@nginx.com nxt_queue_insert_tail(&c->requests, &rc->link); 3160318Smax.romanov@nginx.com 3161318Smax.romanov@nginx.com nxt_debug(task, "stream #%uD linked to conn %p at engine %p", 3162318Smax.romanov@nginx.com rc->stream, c, engine); 316353Sigor@sysoev.ru 3164346Smax.romanov@nginx.com rc->ap = ap; 3165346Smax.romanov@nginx.com c->socket.data = NULL; 3166346Smax.romanov@nginx.com 3167351Smax.romanov@nginx.com ra = &ra_local; 3168351Smax.romanov@nginx.com nxt_router_ra_init(task, ra, rc); 3169167Smax.romanov@nginx.com 3170167Smax.romanov@nginx.com res = nxt_router_app_port(task, ra); 3171141Smax.romanov@nginx.com 3172141Smax.romanov@nginx.com if (res != NXT_OK) { 3173141Smax.romanov@nginx.com return; 3174141Smax.romanov@nginx.com } 3175141Smax.romanov@nginx.com 3176167Smax.romanov@nginx.com port = ra->app_port; 3177141Smax.romanov@nginx.com 3178141Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 3179318Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Application port not found"); 3180141Smax.romanov@nginx.com return; 3181141Smax.romanov@nginx.com } 3182141Smax.romanov@nginx.com 3183318Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, engine->port, rc, port->pid); 3184318Smax.romanov@nginx.com 3185343Smax.romanov@nginx.com nxt_router_process_http_request_mp(task, ra); 3186167Smax.romanov@nginx.com } 3187167Smax.romanov@nginx.com 3188167Smax.romanov@nginx.com 3189167Smax.romanov@nginx.com static void 3190343Smax.romanov@nginx.com nxt_router_process_http_request_mp(nxt_task_t *task, nxt_req_app_link_t *ra) 3191167Smax.romanov@nginx.com { 3192343Smax.romanov@nginx.com uint32_t request_failed; 3193167Smax.romanov@nginx.com nxt_int_t res; 3194343Smax.romanov@nginx.com nxt_port_t *port, *c_port, *reply_port; 3195167Smax.romanov@nginx.com nxt_app_wmsg_t wmsg; 3196167Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 3197167Smax.romanov@nginx.com 3198343Smax.romanov@nginx.com nxt_assert(ra->app_port != NULL); 3199343Smax.romanov@nginx.com 3200343Smax.romanov@nginx.com port = ra->app_port; 3201167Smax.romanov@nginx.com reply_port = ra->reply_port; 3202167Smax.romanov@nginx.com ap = ra->ap; 3203141Smax.romanov@nginx.com 3204343Smax.romanov@nginx.com request_failed = 1; 3205343Smax.romanov@nginx.com 3206141Smax.romanov@nginx.com c_port = nxt_process_connected_port_find(port->process, reply_port->pid, 3207141Smax.romanov@nginx.com reply_port->id); 3208141Smax.romanov@nginx.com if (nxt_slow_path(c_port != reply_port)) { 3209141Smax.romanov@nginx.com res = nxt_port_send_port(task, port, reply_port, 0); 3210122Smax.romanov@nginx.com 3211122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3212345Smax.romanov@nginx.com nxt_router_ra_error(task, ra, 500, 3213345Smax.romanov@nginx.com "Failed to send reply port to application"); 3214345Smax.romanov@nginx.com ra = NULL; 3215343Smax.romanov@nginx.com goto release_port; 3216122Smax.romanov@nginx.com } 3217122Smax.romanov@nginx.com 3218141Smax.romanov@nginx.com nxt_process_connected_port_add(port->process, reply_port); 321988Smax.romanov@nginx.com } 322088Smax.romanov@nginx.com 322188Smax.romanov@nginx.com wmsg.port = port; 322288Smax.romanov@nginx.com wmsg.write = NULL; 322388Smax.romanov@nginx.com wmsg.buf = &wmsg.write; 3224318Smax.romanov@nginx.com wmsg.stream = ra->stream; 3225167Smax.romanov@nginx.com 3226216Sigor@sysoev.ru res = port->app->prepare_msg(task, &ap->r, &wmsg); 3227122Smax.romanov@nginx.com 3228122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3229345Smax.romanov@nginx.com nxt_router_ra_error(task, ra, 500, 3230345Smax.romanov@nginx.com "Failed to prepare message for application"); 3231345Smax.romanov@nginx.com ra = NULL; 3232343Smax.romanov@nginx.com goto release_port; 3233122Smax.romanov@nginx.com } 323488Smax.romanov@nginx.com 323588Smax.romanov@nginx.com nxt_debug(task, "about to send %d bytes buffer to worker port %d", 323688Smax.romanov@nginx.com nxt_buf_used_size(wmsg.write), 323788Smax.romanov@nginx.com wmsg.port->socket.fd); 323888Smax.romanov@nginx.com 3239343Smax.romanov@nginx.com request_failed = 0; 3240343Smax.romanov@nginx.com 3241122Smax.romanov@nginx.com res = nxt_port_socket_write(task, wmsg.port, NXT_PORT_MSG_DATA, 3242318Smax.romanov@nginx.com -1, ra->stream, reply_port->id, wmsg.write); 3243122Smax.romanov@nginx.com 3244122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 3245345Smax.romanov@nginx.com nxt_router_ra_error(task, ra, 500, 3246345Smax.romanov@nginx.com "Failed to send message to application"); 3247345Smax.romanov@nginx.com ra = NULL; 3248343Smax.romanov@nginx.com goto release_port; 3249122Smax.romanov@nginx.com } 3250343Smax.romanov@nginx.com 3251343Smax.romanov@nginx.com release_port: 3252343Smax.romanov@nginx.com 3253345Smax.romanov@nginx.com nxt_router_app_port_release(task, port, request_failed, 0); 3254345Smax.romanov@nginx.com 3255345Smax.romanov@nginx.com if (ra != NULL) { 3256345Smax.romanov@nginx.com if (request_failed != 0) { 3257345Smax.romanov@nginx.com ra->app_port = 0; 3258345Smax.romanov@nginx.com } 3259345Smax.romanov@nginx.com 3260345Smax.romanov@nginx.com nxt_router_ra_release(task, ra, ra->work.data); 3261343Smax.romanov@nginx.com } 326253Sigor@sysoev.ru } 326353Sigor@sysoev.ru 326453Sigor@sysoev.ru 3265216Sigor@sysoev.ru static nxt_int_t 3266216Sigor@sysoev.ru nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 3267216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg) 3268216Sigor@sysoev.ru { 3269216Sigor@sysoev.ru nxt_int_t rc; 3270216Sigor@sysoev.ru nxt_buf_t *b; 3271216Sigor@sysoev.ru nxt_http_field_t *field; 3272216Sigor@sysoev.ru nxt_app_request_header_t *h; 3273216Sigor@sysoev.ru 3274216Sigor@sysoev.ru static const nxt_str_t prefix = nxt_string("HTTP_"); 3275216Sigor@sysoev.ru static const nxt_str_t eof = nxt_null_string; 3276216Sigor@sysoev.ru 3277216Sigor@sysoev.ru h = &r->header; 3278216Sigor@sysoev.ru 3279216Sigor@sysoev.ru #define RC(S) \ 3280216Sigor@sysoev.ru do { \ 3281216Sigor@sysoev.ru rc = (S); \ 3282216Sigor@sysoev.ru if (nxt_slow_path(rc != NXT_OK)) { \ 3283216Sigor@sysoev.ru goto fail; \ 3284216Sigor@sysoev.ru } \ 3285216Sigor@sysoev.ru } while(0) 3286216Sigor@sysoev.ru 3287216Sigor@sysoev.ru #define NXT_WRITE(N) \ 3288216Sigor@sysoev.ru RC(nxt_app_msg_write_str(task, wmsg, N)) 3289216Sigor@sysoev.ru 3290216Sigor@sysoev.ru /* TODO error handle, async mmap buffer assignment */ 3291216Sigor@sysoev.ru 3292216Sigor@sysoev.ru NXT_WRITE(&h->method); 3293216Sigor@sysoev.ru NXT_WRITE(&h->target); 3294277Sigor@sysoev.ru 3295216Sigor@sysoev.ru if (h->path.start == h->target.start) { 3296216Sigor@sysoev.ru NXT_WRITE(&eof); 3297277Sigor@sysoev.ru 3298216Sigor@sysoev.ru } else { 3299216Sigor@sysoev.ru NXT_WRITE(&h->path); 3300216Sigor@sysoev.ru } 3301216Sigor@sysoev.ru 3302216Sigor@sysoev.ru if (h->query.start != NULL) { 3303216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 3304216Sigor@sysoev.ru h->query.start - h->target.start + 1)); 3305216Sigor@sysoev.ru } else { 3306216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 0)); 3307216Sigor@sysoev.ru } 3308216Sigor@sysoev.ru 3309216Sigor@sysoev.ru NXT_WRITE(&h->version); 3310216Sigor@sysoev.ru 3311216Sigor@sysoev.ru NXT_WRITE(&r->remote); 3312268Sigor@sysoev.ru NXT_WRITE(&r->local); 3313216Sigor@sysoev.ru 3314216Sigor@sysoev.ru NXT_WRITE(&h->host); 3315216Sigor@sysoev.ru NXT_WRITE(&h->content_type); 3316216Sigor@sysoev.ru NXT_WRITE(&h->content_length); 3317216Sigor@sysoev.ru 3318216Sigor@sysoev.ru nxt_list_each(field, h->fields) { 3319216Sigor@sysoev.ru RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, 3320216Sigor@sysoev.ru &prefix, &field->name)); 3321216Sigor@sysoev.ru NXT_WRITE(&field->value); 3322216Sigor@sysoev.ru 3323216Sigor@sysoev.ru } nxt_list_loop; 3324216Sigor@sysoev.ru 3325216Sigor@sysoev.ru /* end-of-headers mark */ 3326216Sigor@sysoev.ru NXT_WRITE(&eof); 3327216Sigor@sysoev.ru 3328216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 3329216Sigor@sysoev.ru 3330216Sigor@sysoev.ru for(b = r->body.buf; b != NULL; b = b->next) { 3331216Sigor@sysoev.ru RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3332216Sigor@sysoev.ru nxt_buf_mem_used_size(&b->mem))); 3333216Sigor@sysoev.ru } 3334216Sigor@sysoev.ru 3335216Sigor@sysoev.ru #undef NXT_WRITE 3336216Sigor@sysoev.ru #undef RC 3337216Sigor@sysoev.ru 3338216Sigor@sysoev.ru return NXT_OK; 3339216Sigor@sysoev.ru 3340216Sigor@sysoev.ru fail: 3341216Sigor@sysoev.ru 3342216Sigor@sysoev.ru return NXT_ERROR; 3343216Sigor@sysoev.ru } 3344216Sigor@sysoev.ru 3345216Sigor@sysoev.ru 3346216Sigor@sysoev.ru static nxt_int_t 3347216Sigor@sysoev.ru nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 3348216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg) 3349216Sigor@sysoev.ru { 3350216Sigor@sysoev.ru nxt_int_t rc; 3351216Sigor@sysoev.ru nxt_buf_t *b; 3352305Smax.romanov@nginx.com nxt_bool_t method_is_post; 3353216Sigor@sysoev.ru nxt_http_field_t *field; 3354216Sigor@sysoev.ru nxt_app_request_header_t *h; 3355216Sigor@sysoev.ru 3356216Sigor@sysoev.ru static const nxt_str_t prefix = nxt_string("HTTP_"); 3357216Sigor@sysoev.ru static const nxt_str_t eof = nxt_null_string; 3358216Sigor@sysoev.ru 3359216Sigor@sysoev.ru h = &r->header; 3360216Sigor@sysoev.ru 3361216Sigor@sysoev.ru #define RC(S) \ 3362216Sigor@sysoev.ru do { \ 3363216Sigor@sysoev.ru rc = (S); \ 3364216Sigor@sysoev.ru if (nxt_slow_path(rc != NXT_OK)) { \ 3365216Sigor@sysoev.ru goto fail; \ 3366216Sigor@sysoev.ru } \ 3367216Sigor@sysoev.ru } while(0) 3368216Sigor@sysoev.ru 3369216Sigor@sysoev.ru #define NXT_WRITE(N) \ 3370216Sigor@sysoev.ru RC(nxt_app_msg_write_str(task, wmsg, N)) 3371216Sigor@sysoev.ru 3372216Sigor@sysoev.ru /* TODO error handle, async mmap buffer assignment */ 3373216Sigor@sysoev.ru 3374216Sigor@sysoev.ru NXT_WRITE(&h->method); 3375216Sigor@sysoev.ru NXT_WRITE(&h->target); 3376277Sigor@sysoev.ru 3377216Sigor@sysoev.ru if (h->path.start == h->target.start) { 3378216Sigor@sysoev.ru NXT_WRITE(&eof); 3379277Sigor@sysoev.ru 3380216Sigor@sysoev.ru } else { 3381216Sigor@sysoev.ru NXT_WRITE(&h->path); 3382216Sigor@sysoev.ru } 3383216Sigor@sysoev.ru 3384216Sigor@sysoev.ru if (h->query.start != NULL) { 3385216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 3386216Sigor@sysoev.ru h->query.start - h->target.start + 1)); 3387216Sigor@sysoev.ru } else { 3388216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 0)); 3389216Sigor@sysoev.ru } 3390216Sigor@sysoev.ru 3391216Sigor@sysoev.ru NXT_WRITE(&h->version); 3392216Sigor@sysoev.ru 3393216Sigor@sysoev.ru // PHP_SELF 3394216Sigor@sysoev.ru // SCRIPT_NAME 3395216Sigor@sysoev.ru // SCRIPT_FILENAME 3396216Sigor@sysoev.ru // DOCUMENT_ROOT 3397216Sigor@sysoev.ru 3398216Sigor@sysoev.ru NXT_WRITE(&r->remote); 3399268Sigor@sysoev.ru NXT_WRITE(&r->local); 3400216Sigor@sysoev.ru 3401216Sigor@sysoev.ru NXT_WRITE(&h->host); 3402216Sigor@sysoev.ru NXT_WRITE(&h->cookie); 3403216Sigor@sysoev.ru NXT_WRITE(&h->content_type); 3404216Sigor@sysoev.ru NXT_WRITE(&h->content_length); 3405216Sigor@sysoev.ru 3406216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length)); 3407305Smax.romanov@nginx.com RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 3408305Smax.romanov@nginx.com 3409305Smax.romanov@nginx.com method_is_post = h->method.length == 4 && 3410305Smax.romanov@nginx.com h->method.start[0] == 'P' && 3411305Smax.romanov@nginx.com h->method.start[1] == 'O' && 3412305Smax.romanov@nginx.com h->method.start[2] == 'S' && 3413305Smax.romanov@nginx.com h->method.start[3] == 'T'; 3414305Smax.romanov@nginx.com 3415305Smax.romanov@nginx.com if (method_is_post) { 3416305Smax.romanov@nginx.com for(b = r->body.buf; b != NULL; b = b->next) { 3417305Smax.romanov@nginx.com RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3418305Smax.romanov@nginx.com nxt_buf_mem_used_size(&b->mem))); 3419305Smax.romanov@nginx.com } 3420305Smax.romanov@nginx.com } 3421216Sigor@sysoev.ru 3422216Sigor@sysoev.ru nxt_list_each(field, h->fields) { 3423216Sigor@sysoev.ru RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, 3424216Sigor@sysoev.ru &prefix, &field->name)); 3425216Sigor@sysoev.ru NXT_WRITE(&field->value); 3426216Sigor@sysoev.ru 3427216Sigor@sysoev.ru } nxt_list_loop; 3428216Sigor@sysoev.ru 3429216Sigor@sysoev.ru /* end-of-headers mark */ 3430216Sigor@sysoev.ru NXT_WRITE(&eof); 3431216Sigor@sysoev.ru 3432305Smax.romanov@nginx.com if (!method_is_post) { 3433305Smax.romanov@nginx.com for(b = r->body.buf; b != NULL; b = b->next) { 3434305Smax.romanov@nginx.com RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3435305Smax.romanov@nginx.com nxt_buf_mem_used_size(&b->mem))); 3436305Smax.romanov@nginx.com } 3437216Sigor@sysoev.ru } 3438216Sigor@sysoev.ru 3439216Sigor@sysoev.ru #undef NXT_WRITE 3440216Sigor@sysoev.ru #undef RC 3441216Sigor@sysoev.ru 3442216Sigor@sysoev.ru return NXT_OK; 3443216Sigor@sysoev.ru 3444216Sigor@sysoev.ru fail: 3445216Sigor@sysoev.ru 3446216Sigor@sysoev.ru return NXT_ERROR; 3447216Sigor@sysoev.ru } 3448216Sigor@sysoev.ru 3449216Sigor@sysoev.ru 3450216Sigor@sysoev.ru static nxt_int_t 3451216Sigor@sysoev.ru nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, nxt_app_wmsg_t *wmsg) 3452216Sigor@sysoev.ru { 3453216Sigor@sysoev.ru nxt_int_t rc; 3454216Sigor@sysoev.ru nxt_buf_t *b; 3455216Sigor@sysoev.ru nxt_http_field_t *field; 3456216Sigor@sysoev.ru nxt_app_request_header_t *h; 3457216Sigor@sysoev.ru 3458216Sigor@sysoev.ru static const nxt_str_t eof = nxt_null_string; 3459216Sigor@sysoev.ru 3460216Sigor@sysoev.ru h = &r->header; 3461216Sigor@sysoev.ru 3462216Sigor@sysoev.ru #define RC(S) \ 3463216Sigor@sysoev.ru do { \ 3464216Sigor@sysoev.ru rc = (S); \ 3465216Sigor@sysoev.ru if (nxt_slow_path(rc != NXT_OK)) { \ 3466216Sigor@sysoev.ru goto fail; \ 3467216Sigor@sysoev.ru } \ 3468216Sigor@sysoev.ru } while(0) 3469216Sigor@sysoev.ru 3470216Sigor@sysoev.ru #define NXT_WRITE(N) \ 3471216Sigor@sysoev.ru RC(nxt_app_msg_write_str(task, wmsg, N)) 3472216Sigor@sysoev.ru 3473216Sigor@sysoev.ru /* TODO error handle, async mmap buffer assignment */ 3474216Sigor@sysoev.ru 3475216Sigor@sysoev.ru NXT_WRITE(&h->method); 3476216Sigor@sysoev.ru NXT_WRITE(&h->target); 3477277Sigor@sysoev.ru 3478216Sigor@sysoev.ru if (h->path.start == h->target.start) { 3479216Sigor@sysoev.ru NXT_WRITE(&eof); 3480277Sigor@sysoev.ru 3481216Sigor@sysoev.ru } else { 3482216Sigor@sysoev.ru NXT_WRITE(&h->path); 3483216Sigor@sysoev.ru } 3484216Sigor@sysoev.ru 3485216Sigor@sysoev.ru if (h->query.start != NULL) { 3486216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 3487216Sigor@sysoev.ru h->query.start - h->target.start + 1)); 3488216Sigor@sysoev.ru } else { 3489216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 0)); 3490216Sigor@sysoev.ru } 3491216Sigor@sysoev.ru 3492216Sigor@sysoev.ru NXT_WRITE(&h->version); 3493253Smax.romanov@nginx.com NXT_WRITE(&r->remote); 3494216Sigor@sysoev.ru 3495216Sigor@sysoev.ru NXT_WRITE(&h->host); 3496216Sigor@sysoev.ru NXT_WRITE(&h->cookie); 3497216Sigor@sysoev.ru NXT_WRITE(&h->content_type); 3498216Sigor@sysoev.ru NXT_WRITE(&h->content_length); 3499216Sigor@sysoev.ru 3500216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length)); 3501216Sigor@sysoev.ru 3502216Sigor@sysoev.ru nxt_list_each(field, h->fields) { 3503216Sigor@sysoev.ru NXT_WRITE(&field->name); 3504216Sigor@sysoev.ru NXT_WRITE(&field->value); 3505216Sigor@sysoev.ru 3506216Sigor@sysoev.ru } nxt_list_loop; 3507216Sigor@sysoev.ru 3508216Sigor@sysoev.ru /* end-of-headers mark */ 3509216Sigor@sysoev.ru NXT_WRITE(&eof); 3510216Sigor@sysoev.ru 3511216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 3512216Sigor@sysoev.ru 3513216Sigor@sysoev.ru for(b = r->body.buf; b != NULL; b = b->next) { 3514216Sigor@sysoev.ru RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3515216Sigor@sysoev.ru nxt_buf_mem_used_size(&b->mem))); 3516216Sigor@sysoev.ru } 3517216Sigor@sysoev.ru 3518216Sigor@sysoev.ru #undef NXT_WRITE 3519216Sigor@sysoev.ru #undef RC 3520216Sigor@sysoev.ru 3521216Sigor@sysoev.ru return NXT_OK; 3522216Sigor@sysoev.ru 3523216Sigor@sysoev.ru fail: 3524216Sigor@sysoev.ru 3525216Sigor@sysoev.ru return NXT_ERROR; 3526216Sigor@sysoev.ru } 3527216Sigor@sysoev.ru 3528216Sigor@sysoev.ru 352962Sigor@sysoev.ru static const nxt_conn_state_t nxt_router_conn_close_state 353053Sigor@sysoev.ru nxt_aligned(64) = 353153Sigor@sysoev.ru { 353253Sigor@sysoev.ru .ready_handler = nxt_router_conn_free, 353353Sigor@sysoev.ru }; 353453Sigor@sysoev.ru 353553Sigor@sysoev.ru 353653Sigor@sysoev.ru static void 353788Smax.romanov@nginx.com nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data) 353888Smax.romanov@nginx.com { 353988Smax.romanov@nginx.com nxt_buf_t *b; 354088Smax.romanov@nginx.com nxt_bool_t last; 354188Smax.romanov@nginx.com nxt_conn_t *c; 354288Smax.romanov@nginx.com nxt_work_queue_t *wq; 354388Smax.romanov@nginx.com 354488Smax.romanov@nginx.com nxt_debug(task, "router conn ready %p", obj); 354588Smax.romanov@nginx.com 354688Smax.romanov@nginx.com c = obj; 354788Smax.romanov@nginx.com b = c->write; 354888Smax.romanov@nginx.com 354988Smax.romanov@nginx.com wq = &task->thread->engine->fast_work_queue; 355088Smax.romanov@nginx.com 355188Smax.romanov@nginx.com last = 0; 355288Smax.romanov@nginx.com 355388Smax.romanov@nginx.com while (b != NULL) { 355488Smax.romanov@nginx.com if (!nxt_buf_is_sync(b)) { 355588Smax.romanov@nginx.com if (nxt_buf_used_size(b) > 0) { 355688Smax.romanov@nginx.com break; 355788Smax.romanov@nginx.com } 355888Smax.romanov@nginx.com } 355988Smax.romanov@nginx.com 356088Smax.romanov@nginx.com if (nxt_buf_is_last(b)) { 356188Smax.romanov@nginx.com last = 1; 356288Smax.romanov@nginx.com } 356388Smax.romanov@nginx.com 356488Smax.romanov@nginx.com nxt_work_queue_add(wq, b->completion_handler, task, b, b->parent); 356588Smax.romanov@nginx.com 356688Smax.romanov@nginx.com b = b->next; 356788Smax.romanov@nginx.com } 356888Smax.romanov@nginx.com 356988Smax.romanov@nginx.com c->write = b; 357088Smax.romanov@nginx.com 357188Smax.romanov@nginx.com if (b != NULL) { 357288Smax.romanov@nginx.com nxt_debug(task, "router conn %p has more data to write", obj); 357388Smax.romanov@nginx.com 357488Smax.romanov@nginx.com nxt_conn_write(task->thread->engine, c); 3575277Sigor@sysoev.ru 357688Smax.romanov@nginx.com } else { 357788Smax.romanov@nginx.com nxt_debug(task, "router conn %p no more data to write, last = %d", obj, 357888Smax.romanov@nginx.com last); 357988Smax.romanov@nginx.com 358088Smax.romanov@nginx.com if (last != 0) { 358188Smax.romanov@nginx.com nxt_debug(task, "enqueue router conn close %p (ready handler)", c); 358288Smax.romanov@nginx.com 358388Smax.romanov@nginx.com nxt_work_queue_add(wq, nxt_router_conn_close, task, c, 358488Smax.romanov@nginx.com c->socket.data); 358588Smax.romanov@nginx.com } 358688Smax.romanov@nginx.com } 358788Smax.romanov@nginx.com } 358888Smax.romanov@nginx.com 358988Smax.romanov@nginx.com 359088Smax.romanov@nginx.com static void 359153Sigor@sysoev.ru nxt_router_conn_close(nxt_task_t *task, void *obj, void *data) 359253Sigor@sysoev.ru { 359362Sigor@sysoev.ru nxt_conn_t *c; 359453Sigor@sysoev.ru 359553Sigor@sysoev.ru c = obj; 359653Sigor@sysoev.ru 359753Sigor@sysoev.ru nxt_debug(task, "router conn close"); 359853Sigor@sysoev.ru 359953Sigor@sysoev.ru c->write_state = &nxt_router_conn_close_state; 360053Sigor@sysoev.ru 360162Sigor@sysoev.ru nxt_conn_close(task->thread->engine, c); 360253Sigor@sysoev.ru } 360353Sigor@sysoev.ru 360453Sigor@sysoev.ru 360553Sigor@sysoev.ru static void 3606164Smax.romanov@nginx.com nxt_router_conn_mp_cleanup(nxt_task_t *task, void *obj, void *data) 3607164Smax.romanov@nginx.com { 3608164Smax.romanov@nginx.com nxt_socket_conf_joint_t *joint; 3609164Smax.romanov@nginx.com 3610164Smax.romanov@nginx.com joint = obj; 3611164Smax.romanov@nginx.com 3612164Smax.romanov@nginx.com nxt_router_conf_release(task, joint); 3613164Smax.romanov@nginx.com } 3614164Smax.romanov@nginx.com 3615164Smax.romanov@nginx.com 3616164Smax.romanov@nginx.com static void 361753Sigor@sysoev.ru nxt_router_conn_free(nxt_task_t *task, void *obj, void *data) 361853Sigor@sysoev.ru { 361962Sigor@sysoev.ru nxt_conn_t *c; 3620337Sigor@sysoev.ru nxt_event_engine_t *engine; 362188Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 3622319Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 362353Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 362453Sigor@sysoev.ru 362553Sigor@sysoev.ru c = obj; 3626319Smax.romanov@nginx.com ap = data; 362753Sigor@sysoev.ru 362853Sigor@sysoev.ru nxt_debug(task, "router conn close done"); 362953Sigor@sysoev.ru 3630319Smax.romanov@nginx.com if (ap != NULL) { 3631319Smax.romanov@nginx.com nxt_app_http_req_done(task, ap); 3632319Smax.romanov@nginx.com 3633319Smax.romanov@nginx.com c->socket.data = NULL; 3634319Smax.romanov@nginx.com } 3635319Smax.romanov@nginx.com 363688Smax.romanov@nginx.com nxt_queue_each(rc, &c->requests, nxt_req_conn_link_t, link) { 363788Smax.romanov@nginx.com 3638318Smax.romanov@nginx.com nxt_debug(task, "conn %p close, stream #%uD", c, rc->stream); 363988Smax.romanov@nginx.com 3640343Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 3641318Smax.romanov@nginx.com 3642318Smax.romanov@nginx.com nxt_port_rpc_cancel(task, task->thread->engine->port, rc->stream); 364388Smax.romanov@nginx.com 364488Smax.romanov@nginx.com } nxt_queue_loop; 364588Smax.romanov@nginx.com 3646122Smax.romanov@nginx.com nxt_queue_remove(&c->link); 3647122Smax.romanov@nginx.com 3648337Sigor@sysoev.ru engine = task->thread->engine; 3649337Sigor@sysoev.ru 3650337Sigor@sysoev.ru nxt_sockaddr_cache_free(engine, c); 3651337Sigor@sysoev.ru 3652*359Sigor@sysoev.ru joint = c->joint; 3653131Smax.romanov@nginx.com 3654337Sigor@sysoev.ru nxt_mp_cleanup(c->mem_pool, nxt_router_conn_mp_cleanup, 3655337Sigor@sysoev.ru &engine->task, joint, NULL); 3656164Smax.romanov@nginx.com 3657164Smax.romanov@nginx.com nxt_mp_release(c->mem_pool, c); 365853Sigor@sysoev.ru } 365953Sigor@sysoev.ru 366053Sigor@sysoev.ru 366153Sigor@sysoev.ru static void 366253Sigor@sysoev.ru nxt_router_conn_error(nxt_task_t *task, void *obj, void *data) 366353Sigor@sysoev.ru { 366462Sigor@sysoev.ru nxt_conn_t *c; 366553Sigor@sysoev.ru 366653Sigor@sysoev.ru c = obj; 366753Sigor@sysoev.ru 366853Sigor@sysoev.ru nxt_debug(task, "router conn error"); 366953Sigor@sysoev.ru 3670273Smax.romanov@nginx.com if (c->socket.fd != -1) { 3671273Smax.romanov@nginx.com c->write_state = &nxt_router_conn_close_state; 3672273Smax.romanov@nginx.com 3673273Smax.romanov@nginx.com nxt_conn_close(task->thread->engine, c); 3674273Smax.romanov@nginx.com } 367553Sigor@sysoev.ru } 367653Sigor@sysoev.ru 367753Sigor@sysoev.ru 367853Sigor@sysoev.ru static void 367953Sigor@sysoev.ru nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data) 368053Sigor@sysoev.ru { 368162Sigor@sysoev.ru nxt_conn_t *c; 368262Sigor@sysoev.ru nxt_timer_t *timer; 368353Sigor@sysoev.ru 368453Sigor@sysoev.ru timer = obj; 368553Sigor@sysoev.ru 368653Sigor@sysoev.ru nxt_debug(task, "router conn timeout"); 368753Sigor@sysoev.ru 368862Sigor@sysoev.ru c = nxt_read_timer_conn(timer); 368953Sigor@sysoev.ru 3690206Smax.romanov@nginx.com if (c->read_state == &nxt_router_conn_read_header_state) { 3691206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 408, "Read header timeout"); 3692206Smax.romanov@nginx.com 3693206Smax.romanov@nginx.com } else { 3694206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 408, "Read body timeout"); 3695206Smax.romanov@nginx.com } 369653Sigor@sysoev.ru } 369753Sigor@sysoev.ru 369853Sigor@sysoev.ru 3699318Smax.romanov@nginx.com static void 3700318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data) 3701318Smax.romanov@nginx.com { 3702318Smax.romanov@nginx.com nxt_conn_t *c; 3703318Smax.romanov@nginx.com nxt_timer_t *timer; 3704318Smax.romanov@nginx.com 3705318Smax.romanov@nginx.com timer = obj; 3706318Smax.romanov@nginx.com 3707318Smax.romanov@nginx.com nxt_debug(task, "router app timeout"); 3708318Smax.romanov@nginx.com 3709318Smax.romanov@nginx.com c = nxt_read_timer_conn(timer); 3710318Smax.romanov@nginx.com 3711318Smax.romanov@nginx.com nxt_router_gen_error(task, c, 408, "Application timeout"); 3712318Smax.romanov@nginx.com } 3713318Smax.romanov@nginx.com 3714318Smax.romanov@nginx.com 371553Sigor@sysoev.ru static nxt_msec_t 371662Sigor@sysoev.ru nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data) 371753Sigor@sysoev.ru { 371853Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 371953Sigor@sysoev.ru 3720*359Sigor@sysoev.ru joint = c->joint; 372153Sigor@sysoev.ru 372253Sigor@sysoev.ru return nxt_value_at(nxt_msec_t, joint->socket_conf, data); 372353Sigor@sysoev.ru } 3724