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 { 13133Sigor@sysoev.ru nxt_str_t type; 14133Sigor@sysoev.ru uint32_t workers; 15133Sigor@sysoev.ru } nxt_router_app_conf_t; 16133Sigor@sysoev.ru 17133Sigor@sysoev.ru 18133Sigor@sysoev.ru typedef struct { 19133Sigor@sysoev.ru nxt_str_t application; 20115Sigor@sysoev.ru } nxt_router_listener_conf_t; 21115Sigor@sysoev.ru 22115Sigor@sysoev.ru 23141Smax.romanov@nginx.com typedef struct nxt_start_worker_s nxt_start_worker_t; 24141Smax.romanov@nginx.com 25141Smax.romanov@nginx.com struct nxt_start_worker_s { 26141Smax.romanov@nginx.com uint32_t stream; 27141Smax.romanov@nginx.com nxt_app_t *app; 28141Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 29141Smax.romanov@nginx.com nxt_mp_t *mem_pool; 30141Smax.romanov@nginx.com void *joint; 31141Smax.romanov@nginx.com 32141Smax.romanov@nginx.com nxt_work_t work; 33141Smax.romanov@nginx.com }; 34141Smax.romanov@nginx.com 35141Smax.romanov@nginx.com 36139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task); 37139Sigor@sysoev.ru static nxt_int_t nxt_router_conf_new(nxt_task_t *task, 38139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end); 39139Sigor@sysoev.ru static void nxt_router_conf_success(nxt_task_t *task, 40139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 41139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task, 42139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 43139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task, 44139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, u_char *start, size_t size); 45139Sigor@sysoev.ru static void nxt_router_conf_buf_completion(nxt_task_t *task, void *obj, 46139Sigor@sysoev.ru void *data); 4753Sigor@sysoev.ru static void nxt_router_listen_sockets_sort(nxt_router_t *router, 4853Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 4953Sigor@sysoev.ru 50115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task, 51115Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end); 52133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name); 53133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, 54133Sigor@sysoev.ru nxt_str_t *name); 5553Sigor@sysoev.ru static nxt_int_t nxt_router_listen_sockets_stub_create(nxt_task_t *task, 5653Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 5765Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, 5865Sigor@sysoev.ru nxt_sockaddr_t *sa); 5953Sigor@sysoev.ru 6053Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task, 6153Sigor@sysoev.ru nxt_router_t *router, nxt_router_temp_conf_t *tmcf, 6253Sigor@sysoev.ru const nxt_event_interface_t *interface); 63115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 64115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 65115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 66115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 67115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 68115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 69115Sigor@sysoev.ru static void nxt_router_engine_socket_count(nxt_queue_t *sockets); 70154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 71154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 72154Sigor@sysoev.ru nxt_work_handler_t handler); 73139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 74139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets); 7553Sigor@sysoev.ru 7653Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 7753Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 7853Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 7953Sigor@sysoev.ru nxt_event_engine_t *engine); 80133Sigor@sysoev.ru static void nxt_router_apps_sort(nxt_router_t *router, 81133Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 8253Sigor@sysoev.ru 8353Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_temp_conf_t *tmcf); 84154Sigor@sysoev.ru static void nxt_router_engine_post(nxt_router_engine_conf_t *recf); 8553Sigor@sysoev.ru 8653Sigor@sysoev.ru static void nxt_router_thread_start(void *data); 8753Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj, 8853Sigor@sysoev.ru void *data); 8953Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj, 9053Sigor@sysoev.ru void *data); 9153Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, 9253Sigor@sysoev.ru void *data); 9353Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj, 9453Sigor@sysoev.ru void *data); 9553Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task, 9653Sigor@sysoev.ru nxt_socket_conf_joint_t *joint); 9753Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, 9853Sigor@sysoev.ru void *data); 9953Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task, 10053Sigor@sysoev.ru nxt_socket_conf_joint_t *joint); 10153Sigor@sysoev.ru 102*163Smax.romanov@nginx.com static nxt_bool_t nxt_router_app_free(nxt_app_t *app); 103141Smax.romanov@nginx.com static nxt_port_t * nxt_router_app_get_port(nxt_app_t *app); 104141Smax.romanov@nginx.com static void nxt_router_app_release_port(nxt_task_t *task, void *obj, 105141Smax.romanov@nginx.com void *data); 106141Smax.romanov@nginx.com 107141Smax.romanov@nginx.com static void nxt_router_sw_add(nxt_task_t *task, nxt_router_t *router, 108141Smax.romanov@nginx.com nxt_start_worker_t *sw); 109141Smax.romanov@nginx.com static nxt_start_worker_t *nxt_router_sw_find_remove(nxt_task_t *task, 110141Smax.romanov@nginx.com nxt_router_t *router, uint32_t id); 111141Smax.romanov@nginx.com 11253Sigor@sysoev.ru static void nxt_router_conn_init(nxt_task_t *task, void *obj, void *data); 11353Sigor@sysoev.ru static void nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, 11453Sigor@sysoev.ru void *data); 11588Smax.romanov@nginx.com static void nxt_router_process_http_request(nxt_task_t *task, 11688Smax.romanov@nginx.com nxt_conn_t *c, nxt_app_parse_ctx_t *ap); 117141Smax.romanov@nginx.com static void nxt_router_process_http_request_mp(nxt_task_t *task, 118141Smax.romanov@nginx.com nxt_req_conn_link_t *rc, nxt_mp_t *mp); 11988Smax.romanov@nginx.com static void nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data); 12053Sigor@sysoev.ru static void nxt_router_conn_close(nxt_task_t *task, void *obj, void *data); 12153Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data); 12253Sigor@sysoev.ru static void nxt_router_conn_error(nxt_task_t *task, void *obj, void *data); 12353Sigor@sysoev.ru static void nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data); 12462Sigor@sysoev.ru static nxt_msec_t nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data); 12520Sigor@sysoev.ru 126141Smax.romanov@nginx.com static void nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code, 127141Smax.romanov@nginx.com const char* fmt, ...); 128141Smax.romanov@nginx.com 129119Smax.romanov@nginx.com static nxt_router_t *nxt_router; 13020Sigor@sysoev.ru 13120Sigor@sysoev.ru nxt_int_t 132141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data) 13320Sigor@sysoev.ru { 134141Smax.romanov@nginx.com nxt_int_t ret; 135141Smax.romanov@nginx.com nxt_router_t *router; 136141Smax.romanov@nginx.com nxt_runtime_t *rt; 137141Smax.romanov@nginx.com 138141Smax.romanov@nginx.com rt = task->thread->runtime; 13953Sigor@sysoev.ru 14088Smax.romanov@nginx.com ret = nxt_app_http_init(task, rt); 14188Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 14288Smax.romanov@nginx.com return ret; 14388Smax.romanov@nginx.com } 14488Smax.romanov@nginx.com 14553Sigor@sysoev.ru router = nxt_zalloc(sizeof(nxt_router_t)); 14653Sigor@sysoev.ru if (nxt_slow_path(router == NULL)) { 14753Sigor@sysoev.ru return NXT_ERROR; 14853Sigor@sysoev.ru } 14953Sigor@sysoev.ru 15053Sigor@sysoev.ru nxt_queue_init(&router->engines); 15153Sigor@sysoev.ru nxt_queue_init(&router->sockets); 152133Sigor@sysoev.ru nxt_queue_init(&router->apps); 15353Sigor@sysoev.ru 154119Smax.romanov@nginx.com nxt_router = router; 155119Smax.romanov@nginx.com 156115Sigor@sysoev.ru return NXT_OK; 157115Sigor@sysoev.ru } 158115Sigor@sysoev.ru 159115Sigor@sysoev.ru 160141Smax.romanov@nginx.com static void 161141Smax.romanov@nginx.com nxt_router_sw_release(nxt_task_t *task, void *obj, void *data) 162141Smax.romanov@nginx.com { 163141Smax.romanov@nginx.com nxt_start_worker_t *sw; 164141Smax.romanov@nginx.com nxt_socket_conf_joint_t *joint; 165141Smax.romanov@nginx.com 166141Smax.romanov@nginx.com sw = obj; 167141Smax.romanov@nginx.com joint = sw->joint; 168141Smax.romanov@nginx.com 169141Smax.romanov@nginx.com nxt_debug(task, "sw #%uxD release", sw->stream); 170141Smax.romanov@nginx.com 171141Smax.romanov@nginx.com if (nxt_mp_release(sw->mem_pool, sw) == 0) { 172141Smax.romanov@nginx.com nxt_router_conf_release(task, joint); 173141Smax.romanov@nginx.com } 174141Smax.romanov@nginx.com } 175141Smax.romanov@nginx.com 176141Smax.romanov@nginx.com 177141Smax.romanov@nginx.com void 178141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 179141Smax.romanov@nginx.com { 180141Smax.romanov@nginx.com nxt_start_worker_t *sw; 181141Smax.romanov@nginx.com 182141Smax.romanov@nginx.com nxt_port_new_port_handler(task, msg); 183141Smax.romanov@nginx.com 184141Smax.romanov@nginx.com if (msg->new_port == NULL || msg->new_port->type != NXT_PROCESS_WORKER) { 185141Smax.romanov@nginx.com return; 186141Smax.romanov@nginx.com } 187141Smax.romanov@nginx.com 188141Smax.romanov@nginx.com sw = nxt_router_sw_find_remove(task, nxt_router, msg->port_msg.stream); 189141Smax.romanov@nginx.com 190141Smax.romanov@nginx.com if (nxt_fast_path(sw != NULL)) { 191141Smax.romanov@nginx.com msg->new_port->app = sw->app; 192141Smax.romanov@nginx.com 193*163Smax.romanov@nginx.com sw->app->workers++; 194*163Smax.romanov@nginx.com 195*163Smax.romanov@nginx.com nxt_assert(sw->app->pending_workers != 0); 196*163Smax.romanov@nginx.com 197*163Smax.romanov@nginx.com sw->app->pending_workers--; 198*163Smax.romanov@nginx.com 199141Smax.romanov@nginx.com nxt_router_app_release_port(task, msg->new_port, sw->app); 200141Smax.romanov@nginx.com 201141Smax.romanov@nginx.com sw->work.handler = nxt_router_sw_release; 202141Smax.romanov@nginx.com 203141Smax.romanov@nginx.com nxt_debug(task, "post sw #%uxD release to %p", sw->stream, 204141Smax.romanov@nginx.com sw->work.data); 205141Smax.romanov@nginx.com 206141Smax.romanov@nginx.com nxt_event_engine_post(sw->work.data, &sw->work); 207141Smax.romanov@nginx.com } 208141Smax.romanov@nginx.com } 209141Smax.romanov@nginx.com 210141Smax.romanov@nginx.com 211139Sigor@sysoev.ru void 212139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 213115Sigor@sysoev.ru { 214139Sigor@sysoev.ru size_t dump_size; 215139Sigor@sysoev.ru nxt_buf_t *b; 216139Sigor@sysoev.ru nxt_int_t ret; 217139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 218139Sigor@sysoev.ru 219139Sigor@sysoev.ru b = msg->buf; 220139Sigor@sysoev.ru 221139Sigor@sysoev.ru dump_size = nxt_buf_used_size(b); 222139Sigor@sysoev.ru 223139Sigor@sysoev.ru if (dump_size > 300) { 224139Sigor@sysoev.ru dump_size = 300; 22553Sigor@sysoev.ru } 22653Sigor@sysoev.ru 227139Sigor@sysoev.ru nxt_debug(task, "router conf data (%z): %*s", 228139Sigor@sysoev.ru msg->size, dump_size, b->mem.pos); 229139Sigor@sysoev.ru 230139Sigor@sysoev.ru tmcf = nxt_router_temp_conf(task); 231139Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 232139Sigor@sysoev.ru return; 23353Sigor@sysoev.ru } 23453Sigor@sysoev.ru 235139Sigor@sysoev.ru tmcf->conf->router = nxt_router; 236139Sigor@sysoev.ru tmcf->stream = msg->port_msg.stream; 237139Sigor@sysoev.ru tmcf->port = nxt_runtime_port_find(task->thread->runtime, 238139Sigor@sysoev.ru msg->port_msg.pid, 0); 239139Sigor@sysoev.ru 240139Sigor@sysoev.ru ret = nxt_router_conf_new(task, tmcf, b->mem.pos, b->mem.free); 241139Sigor@sysoev.ru 242139Sigor@sysoev.ru b->mem.pos = b->mem.free; 243139Sigor@sysoev.ru 244139Sigor@sysoev.ru if (ret == NXT_OK) { 245139Sigor@sysoev.ru return nxt_router_conf_success(task, tmcf); 246139Sigor@sysoev.ru } 247139Sigor@sysoev.ru 248139Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "failed to apply new conf"); 249139Sigor@sysoev.ru 250139Sigor@sysoev.ru return nxt_router_conf_error(task, tmcf); 25153Sigor@sysoev.ru } 25253Sigor@sysoev.ru 25353Sigor@sysoev.ru 25453Sigor@sysoev.ru static nxt_router_temp_conf_t * 255139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task) 25653Sigor@sysoev.ru { 25765Sigor@sysoev.ru nxt_mp_t *mp, *tmp; 25853Sigor@sysoev.ru nxt_router_conf_t *rtcf; 25953Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 26053Sigor@sysoev.ru 26165Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 26253Sigor@sysoev.ru if (nxt_slow_path(mp == NULL)) { 26353Sigor@sysoev.ru return NULL; 26453Sigor@sysoev.ru } 26553Sigor@sysoev.ru 26665Sigor@sysoev.ru rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t)); 26753Sigor@sysoev.ru if (nxt_slow_path(rtcf == NULL)) { 26853Sigor@sysoev.ru goto fail; 26953Sigor@sysoev.ru } 27053Sigor@sysoev.ru 27153Sigor@sysoev.ru rtcf->mem_pool = mp; 27253Sigor@sysoev.ru 27365Sigor@sysoev.ru tmp = nxt_mp_create(1024, 128, 256, 32); 27453Sigor@sysoev.ru if (nxt_slow_path(tmp == NULL)) { 27553Sigor@sysoev.ru goto fail; 27653Sigor@sysoev.ru } 27753Sigor@sysoev.ru 27865Sigor@sysoev.ru tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t)); 27953Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 28053Sigor@sysoev.ru goto temp_fail; 28153Sigor@sysoev.ru } 28253Sigor@sysoev.ru 28353Sigor@sysoev.ru tmcf->mem_pool = tmp; 28453Sigor@sysoev.ru tmcf->conf = rtcf; 285139Sigor@sysoev.ru tmcf->count = 1; 286139Sigor@sysoev.ru tmcf->engine = task->thread->engine; 28753Sigor@sysoev.ru 28853Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, 4, 28953Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 29053Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 29153Sigor@sysoev.ru goto temp_fail; 29253Sigor@sysoev.ru } 29353Sigor@sysoev.ru 29453Sigor@sysoev.ru nxt_queue_init(&tmcf->deleting); 29553Sigor@sysoev.ru nxt_queue_init(&tmcf->keeping); 29653Sigor@sysoev.ru nxt_queue_init(&tmcf->updating); 29753Sigor@sysoev.ru nxt_queue_init(&tmcf->pending); 29853Sigor@sysoev.ru nxt_queue_init(&tmcf->creating); 299133Sigor@sysoev.ru nxt_queue_init(&tmcf->apps); 300133Sigor@sysoev.ru nxt_queue_init(&tmcf->previous); 30153Sigor@sysoev.ru 30253Sigor@sysoev.ru return tmcf; 30353Sigor@sysoev.ru 30453Sigor@sysoev.ru temp_fail: 30553Sigor@sysoev.ru 30665Sigor@sysoev.ru nxt_mp_destroy(tmp); 30753Sigor@sysoev.ru 30853Sigor@sysoev.ru fail: 30953Sigor@sysoev.ru 31065Sigor@sysoev.ru nxt_mp_destroy(mp); 31153Sigor@sysoev.ru 31253Sigor@sysoev.ru return NULL; 31353Sigor@sysoev.ru } 31453Sigor@sysoev.ru 31553Sigor@sysoev.ru 316139Sigor@sysoev.ru static nxt_int_t 317139Sigor@sysoev.ru nxt_router_conf_new(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 318139Sigor@sysoev.ru u_char *start, u_char *end) 319139Sigor@sysoev.ru { 320139Sigor@sysoev.ru nxt_int_t ret; 321139Sigor@sysoev.ru nxt_router_t *router; 322139Sigor@sysoev.ru nxt_runtime_t *rt; 323139Sigor@sysoev.ru const nxt_event_interface_t *interface; 324139Sigor@sysoev.ru 325139Sigor@sysoev.ru ret = nxt_router_conf_create(task, tmcf, start, end); 326139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 327139Sigor@sysoev.ru return ret; 328139Sigor@sysoev.ru } 329139Sigor@sysoev.ru 330139Sigor@sysoev.ru router = tmcf->conf->router; 331139Sigor@sysoev.ru 332139Sigor@sysoev.ru nxt_router_listen_sockets_sort(router, tmcf); 333139Sigor@sysoev.ru 334139Sigor@sysoev.ru ret = nxt_router_listen_sockets_stub_create(task, tmcf); 335139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 336139Sigor@sysoev.ru return ret; 337139Sigor@sysoev.ru } 338139Sigor@sysoev.ru 339139Sigor@sysoev.ru rt = task->thread->runtime; 340139Sigor@sysoev.ru 341139Sigor@sysoev.ru interface = nxt_service_get(rt->services, "engine", NULL); 342139Sigor@sysoev.ru 343139Sigor@sysoev.ru ret = nxt_router_engines_create(task, router, tmcf, interface); 344139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 345139Sigor@sysoev.ru return ret; 346139Sigor@sysoev.ru } 347139Sigor@sysoev.ru 348139Sigor@sysoev.ru ret = nxt_router_threads_create(task, rt, tmcf); 349139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 350139Sigor@sysoev.ru return ret; 351139Sigor@sysoev.ru } 352139Sigor@sysoev.ru 353139Sigor@sysoev.ru nxt_router_apps_sort(router, tmcf); 354139Sigor@sysoev.ru 355139Sigor@sysoev.ru nxt_router_engines_post(tmcf); 356139Sigor@sysoev.ru 357139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->updating); 358139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->creating); 359139Sigor@sysoev.ru 360139Sigor@sysoev.ru return NXT_OK; 361139Sigor@sysoev.ru } 362139Sigor@sysoev.ru 363139Sigor@sysoev.ru 364139Sigor@sysoev.ru static void 365139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data) 366139Sigor@sysoev.ru { 367153Sigor@sysoev.ru nxt_joint_job_t *job; 368153Sigor@sysoev.ru 369153Sigor@sysoev.ru job = obj; 370153Sigor@sysoev.ru 371153Sigor@sysoev.ru nxt_router_conf_success(task, job->tmcf); 372139Sigor@sysoev.ru } 373139Sigor@sysoev.ru 374139Sigor@sysoev.ru 375139Sigor@sysoev.ru static void 376139Sigor@sysoev.ru nxt_router_conf_success(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 377139Sigor@sysoev.ru { 378139Sigor@sysoev.ru nxt_debug(task, "temp conf count:%D", tmcf->count); 379139Sigor@sysoev.ru 380139Sigor@sysoev.ru if (--tmcf->count == 0) { 381139Sigor@sysoev.ru nxt_router_conf_send(task, tmcf, (u_char *) "OK", 2); 382139Sigor@sysoev.ru } 383139Sigor@sysoev.ru } 384139Sigor@sysoev.ru 385139Sigor@sysoev.ru 386139Sigor@sysoev.ru static void 387139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 388139Sigor@sysoev.ru { 389148Sigor@sysoev.ru nxt_socket_t s; 390149Sigor@sysoev.ru nxt_router_t *router; 391148Sigor@sysoev.ru nxt_queue_link_t *qlk; 392148Sigor@sysoev.ru nxt_socket_conf_t *skcf; 393148Sigor@sysoev.ru 394148Sigor@sysoev.ru for (qlk = nxt_queue_first(&tmcf->creating); 395148Sigor@sysoev.ru qlk != nxt_queue_tail(&tmcf->creating); 396148Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 397148Sigor@sysoev.ru { 398148Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 399148Sigor@sysoev.ru s = skcf->listen.socket; 400148Sigor@sysoev.ru 401148Sigor@sysoev.ru if (s != -1) { 402148Sigor@sysoev.ru nxt_socket_close(task, s); 403148Sigor@sysoev.ru } 404148Sigor@sysoev.ru 405148Sigor@sysoev.ru nxt_free(skcf->socket); 406148Sigor@sysoev.ru } 407148Sigor@sysoev.ru 408149Sigor@sysoev.ru router = tmcf->conf->router; 409149Sigor@sysoev.ru 410149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->keeping); 411149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->deleting); 412149Sigor@sysoev.ru 413148Sigor@sysoev.ru // TODO: new engines and threads 414148Sigor@sysoev.ru 415139Sigor@sysoev.ru nxt_mp_destroy(tmcf->conf->mem_pool); 416139Sigor@sysoev.ru 417139Sigor@sysoev.ru nxt_router_conf_send(task, tmcf, (u_char *) "ERROR", 5); 418139Sigor@sysoev.ru } 419139Sigor@sysoev.ru 420139Sigor@sysoev.ru 421139Sigor@sysoev.ru static void 422139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 423139Sigor@sysoev.ru u_char *start, size_t size) 424139Sigor@sysoev.ru { 425139Sigor@sysoev.ru nxt_buf_t *b; 426139Sigor@sysoev.ru 427139Sigor@sysoev.ru b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 428139Sigor@sysoev.ru if (nxt_slow_path(b == NULL)) { 429139Sigor@sysoev.ru return; 430139Sigor@sysoev.ru } 431139Sigor@sysoev.ru 432140Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, start, size); 433140Svbart@nginx.com 434139Sigor@sysoev.ru b->parent = tmcf->mem_pool; 435139Sigor@sysoev.ru b->completion_handler = nxt_router_conf_buf_completion; 436139Sigor@sysoev.ru 437139Sigor@sysoev.ru nxt_port_socket_write(task, tmcf->port, NXT_PORT_MSG_DATA, -1, 438139Sigor@sysoev.ru tmcf->stream, 0, b); 439139Sigor@sysoev.ru } 440139Sigor@sysoev.ru 441139Sigor@sysoev.ru 442139Sigor@sysoev.ru static void 443139Sigor@sysoev.ru nxt_router_conf_buf_completion(nxt_task_t *task, void *obj, void *data) 444139Sigor@sysoev.ru { 445139Sigor@sysoev.ru nxt_mp_t *mp; 446139Sigor@sysoev.ru 447139Sigor@sysoev.ru /* nxt_router_temp_conf_t mem pool. */ 448139Sigor@sysoev.ru mp = data; 449139Sigor@sysoev.ru 450139Sigor@sysoev.ru nxt_mp_destroy(mp); 451139Sigor@sysoev.ru } 452139Sigor@sysoev.ru 453139Sigor@sysoev.ru 454115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_conf[] = { 455115Sigor@sysoev.ru { 456133Sigor@sysoev.ru nxt_string("listeners_threads"), 457115Sigor@sysoev.ru NXT_CONF_MAP_INT32, 458115Sigor@sysoev.ru offsetof(nxt_router_conf_t, threads), 459115Sigor@sysoev.ru }, 460115Sigor@sysoev.ru }; 461115Sigor@sysoev.ru 462115Sigor@sysoev.ru 463133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_app_conf[] = { 464115Sigor@sysoev.ru { 465133Sigor@sysoev.ru nxt_string("type"), 466115Sigor@sysoev.ru NXT_CONF_MAP_STR, 467133Sigor@sysoev.ru offsetof(nxt_router_app_conf_t, type), 468115Sigor@sysoev.ru }, 469115Sigor@sysoev.ru 470115Sigor@sysoev.ru { 471133Sigor@sysoev.ru nxt_string("workers"), 472115Sigor@sysoev.ru NXT_CONF_MAP_INT32, 473133Sigor@sysoev.ru offsetof(nxt_router_app_conf_t, workers), 474133Sigor@sysoev.ru }, 475133Sigor@sysoev.ru }; 476133Sigor@sysoev.ru 477133Sigor@sysoev.ru 478133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_listener_conf[] = { 479133Sigor@sysoev.ru { 480133Sigor@sysoev.ru nxt_string("application"), 481133Sigor@sysoev.ru NXT_CONF_MAP_STR, 482133Sigor@sysoev.ru offsetof(nxt_router_listener_conf_t, application), 483115Sigor@sysoev.ru }, 484115Sigor@sysoev.ru }; 485115Sigor@sysoev.ru 486115Sigor@sysoev.ru 487115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_http_conf[] = { 488115Sigor@sysoev.ru { 489115Sigor@sysoev.ru nxt_string("header_buffer_size"), 490115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 491115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_buffer_size), 492115Sigor@sysoev.ru }, 493115Sigor@sysoev.ru 494115Sigor@sysoev.ru { 495115Sigor@sysoev.ru nxt_string("large_header_buffer_size"), 496115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 497115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, large_header_buffer_size), 498115Sigor@sysoev.ru }, 499115Sigor@sysoev.ru 500115Sigor@sysoev.ru { 501115Sigor@sysoev.ru nxt_string("header_read_timeout"), 502115Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 503115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_read_timeout), 504115Sigor@sysoev.ru }, 505115Sigor@sysoev.ru }; 506115Sigor@sysoev.ru 507115Sigor@sysoev.ru 50853Sigor@sysoev.ru static nxt_int_t 509115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 510115Sigor@sysoev.ru u_char *start, u_char *end) 51153Sigor@sysoev.ru { 512133Sigor@sysoev.ru u_char *p; 513133Sigor@sysoev.ru size_t size; 514115Sigor@sysoev.ru nxt_mp_t *mp; 515115Sigor@sysoev.ru uint32_t next; 516115Sigor@sysoev.ru nxt_int_t ret; 517115Sigor@sysoev.ru nxt_str_t name; 518133Sigor@sysoev.ru nxt_app_t *app, *prev; 519133Sigor@sysoev.ru nxt_app_type_t type; 520115Sigor@sysoev.ru nxt_sockaddr_t *sa; 521133Sigor@sysoev.ru nxt_conf_value_t *conf, *http; 522133Sigor@sysoev.ru nxt_conf_value_t *applications, *application; 523133Sigor@sysoev.ru nxt_conf_value_t *listeners, *listener; 524115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 525133Sigor@sysoev.ru nxt_router_app_conf_t apcf; 526115Sigor@sysoev.ru nxt_router_listener_conf_t lscf; 527115Sigor@sysoev.ru 528115Sigor@sysoev.ru static nxt_str_t http_path = nxt_string("/http"); 529133Sigor@sysoev.ru static nxt_str_t applications_path = nxt_string("/applications"); 530115Sigor@sysoev.ru static nxt_str_t listeners_path = nxt_string("/listeners"); 531115Sigor@sysoev.ru 532115Sigor@sysoev.ru conf = nxt_conf_json_parse(tmcf->mem_pool, start, end); 533115Sigor@sysoev.ru if (conf == NULL) { 534115Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "configuration parsing error"); 535115Sigor@sysoev.ru return NXT_ERROR; 536115Sigor@sysoev.ru } 537115Sigor@sysoev.ru 538136Svbart@nginx.com ret = nxt_conf_map_object(conf, nxt_router_conf, 539136Svbart@nginx.com nxt_nitems(nxt_router_conf), tmcf->conf); 540115Sigor@sysoev.ru if (ret != NXT_OK) { 541133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "root map error"); 542115Sigor@sysoev.ru return NXT_ERROR; 543115Sigor@sysoev.ru } 544115Sigor@sysoev.ru 545117Sigor@sysoev.ru if (tmcf->conf->threads == 0) { 546117Sigor@sysoev.ru tmcf->conf->threads = nxt_ncpu; 547117Sigor@sysoev.ru } 548117Sigor@sysoev.ru 549133Sigor@sysoev.ru applications = nxt_conf_get_path(conf, &applications_path); 550133Sigor@sysoev.ru if (applications == NULL) { 551133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block"); 552115Sigor@sysoev.ru return NXT_ERROR; 553115Sigor@sysoev.ru } 554115Sigor@sysoev.ru 555133Sigor@sysoev.ru next = 0; 556133Sigor@sysoev.ru 557133Sigor@sysoev.ru for ( ;; ) { 558133Sigor@sysoev.ru application = nxt_conf_next_object_member(applications, &name, &next); 559133Sigor@sysoev.ru if (application == NULL) { 560133Sigor@sysoev.ru break; 561133Sigor@sysoev.ru } 562133Sigor@sysoev.ru 563133Sigor@sysoev.ru nxt_debug(task, "application \"%V\"", &name); 564133Sigor@sysoev.ru 565144Smax.romanov@nginx.com size = nxt_conf_json_length(application, NULL); 566144Smax.romanov@nginx.com 567144Smax.romanov@nginx.com app = nxt_malloc(sizeof(nxt_app_t) + name.length + size); 568133Sigor@sysoev.ru if (app == NULL) { 569133Sigor@sysoev.ru goto fail; 570133Sigor@sysoev.ru } 571133Sigor@sysoev.ru 572144Smax.romanov@nginx.com nxt_memzero(app, sizeof(nxt_app_t)); 573144Smax.romanov@nginx.com 574144Smax.romanov@nginx.com app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t)); 575144Smax.romanov@nginx.com app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length); 576133Sigor@sysoev.ru 577133Sigor@sysoev.ru p = nxt_conf_json_print(app->conf.start, application, NULL); 578133Sigor@sysoev.ru app->conf.length = p - app->conf.start; 579133Sigor@sysoev.ru 580144Smax.romanov@nginx.com nxt_assert(app->conf.length <= size); 581144Smax.romanov@nginx.com 582133Sigor@sysoev.ru nxt_debug(task, "application conf \"%V\"", &app->conf); 583133Sigor@sysoev.ru 584133Sigor@sysoev.ru prev = nxt_router_app_find(&tmcf->conf->router->apps, &name); 585133Sigor@sysoev.ru 586133Sigor@sysoev.ru if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) { 587133Sigor@sysoev.ru nxt_free(app); 588133Sigor@sysoev.ru 589133Sigor@sysoev.ru nxt_queue_remove(&prev->link); 590133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->previous, &prev->link); 591133Sigor@sysoev.ru continue; 592133Sigor@sysoev.ru } 593133Sigor@sysoev.ru 594136Svbart@nginx.com ret = nxt_conf_map_object(application, nxt_router_app_conf, 595136Svbart@nginx.com nxt_nitems(nxt_router_app_conf), &apcf); 596133Sigor@sysoev.ru if (ret != NXT_OK) { 597133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "application map error"); 598133Sigor@sysoev.ru goto app_fail; 599133Sigor@sysoev.ru } 600115Sigor@sysoev.ru 601133Sigor@sysoev.ru nxt_debug(task, "application type: %V", &apcf.type); 602133Sigor@sysoev.ru nxt_debug(task, "application workers: %D", apcf.workers); 603133Sigor@sysoev.ru 604141Smax.romanov@nginx.com type = nxt_app_parse_type(&apcf.type); 605141Smax.romanov@nginx.com 606141Smax.romanov@nginx.com if (type == NXT_APP_UNKNOWN) { 607141Smax.romanov@nginx.com nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"", 608141Smax.romanov@nginx.com &apcf.type); 609141Smax.romanov@nginx.com goto app_fail; 610141Smax.romanov@nginx.com } 611141Smax.romanov@nginx.com 612141Smax.romanov@nginx.com if (nxt_app_modules[type] == NULL) { 613133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "unsupported application type: \"%V\"", 614133Sigor@sysoev.ru &apcf.type); 615133Sigor@sysoev.ru goto app_fail; 616133Sigor@sysoev.ru } 617133Sigor@sysoev.ru 618133Sigor@sysoev.ru ret = nxt_thread_mutex_create(&app->mutex); 619133Sigor@sysoev.ru if (ret != NXT_OK) { 620133Sigor@sysoev.ru goto app_fail; 621133Sigor@sysoev.ru } 622133Sigor@sysoev.ru 623141Smax.romanov@nginx.com nxt_queue_init(&app->ports); 624141Smax.romanov@nginx.com nxt_queue_init(&app->requests); 625141Smax.romanov@nginx.com 626144Smax.romanov@nginx.com app->name.length = name.length; 627144Smax.romanov@nginx.com nxt_memcpy(app->name.start, name.start, name.length); 628144Smax.romanov@nginx.com 629133Sigor@sysoev.ru app->type = type; 630133Sigor@sysoev.ru app->max_workers = apcf.workers; 631133Sigor@sysoev.ru app->live = 1; 632141Smax.romanov@nginx.com app->module = nxt_app_modules[type]; 633133Sigor@sysoev.ru 634133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->apps, &app->link); 635133Sigor@sysoev.ru } 636133Sigor@sysoev.ru 637133Sigor@sysoev.ru http = nxt_conf_get_path(conf, &http_path); 638133Sigor@sysoev.ru #if 0 639133Sigor@sysoev.ru if (http == NULL) { 640133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "no \"http\" block"); 641133Sigor@sysoev.ru return NXT_ERROR; 642133Sigor@sysoev.ru } 643133Sigor@sysoev.ru #endif 644133Sigor@sysoev.ru 645133Sigor@sysoev.ru listeners = nxt_conf_get_path(conf, &listeners_path); 646115Sigor@sysoev.ru if (listeners == NULL) { 647133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block"); 648115Sigor@sysoev.ru return NXT_ERROR; 649115Sigor@sysoev.ru } 65053Sigor@sysoev.ru 651133Sigor@sysoev.ru next = 0; 65253Sigor@sysoev.ru 653133Sigor@sysoev.ru mp = tmcf->conf->mem_pool; 654115Sigor@sysoev.ru 655115Sigor@sysoev.ru for ( ;; ) { 656115Sigor@sysoev.ru listener = nxt_conf_next_object_member(listeners, &name, &next); 657115Sigor@sysoev.ru if (listener == NULL) { 658115Sigor@sysoev.ru break; 659115Sigor@sysoev.ru } 66053Sigor@sysoev.ru 661115Sigor@sysoev.ru sa = nxt_sockaddr_parse(mp, &name); 662115Sigor@sysoev.ru if (sa == NULL) { 663115Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", &name); 664133Sigor@sysoev.ru goto fail; 665115Sigor@sysoev.ru } 666115Sigor@sysoev.ru 667115Sigor@sysoev.ru sa->type = SOCK_STREAM; 668115Sigor@sysoev.ru 669115Sigor@sysoev.ru nxt_debug(task, "router listener: \"%*s\"", 670115Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa)); 67153Sigor@sysoev.ru 672115Sigor@sysoev.ru skcf = nxt_router_socket_conf(task, mp, sa); 673115Sigor@sysoev.ru if (skcf == NULL) { 674133Sigor@sysoev.ru goto fail; 675115Sigor@sysoev.ru } 67653Sigor@sysoev.ru 677136Svbart@nginx.com ret = nxt_conf_map_object(listener, nxt_router_listener_conf, 678136Svbart@nginx.com nxt_nitems(nxt_router_listener_conf), &lscf); 679115Sigor@sysoev.ru if (ret != NXT_OK) { 680115Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "listener map error"); 681133Sigor@sysoev.ru goto fail; 682115Sigor@sysoev.ru } 68353Sigor@sysoev.ru 684133Sigor@sysoev.ru nxt_debug(task, "application: %V", &lscf.application); 685133Sigor@sysoev.ru 686133Sigor@sysoev.ru // STUB, default values if http block is not defined. 687133Sigor@sysoev.ru skcf->header_buffer_size = 2048; 688133Sigor@sysoev.ru skcf->large_header_buffer_size = 8192; 689133Sigor@sysoev.ru skcf->header_read_timeout = 5000; 69053Sigor@sysoev.ru 691133Sigor@sysoev.ru if (http != NULL) { 692136Svbart@nginx.com ret = nxt_conf_map_object(http, nxt_router_http_conf, 693136Svbart@nginx.com nxt_nitems(nxt_router_http_conf), skcf); 694133Sigor@sysoev.ru if (ret != NXT_OK) { 695133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "http map error"); 696133Sigor@sysoev.ru goto fail; 697133Sigor@sysoev.ru } 698115Sigor@sysoev.ru } 699115Sigor@sysoev.ru 700115Sigor@sysoev.ru skcf->listen.handler = nxt_router_conn_init; 701115Sigor@sysoev.ru skcf->router_conf = tmcf->conf; 702160Sigor@sysoev.ru skcf->router_conf->count++; 703133Sigor@sysoev.ru skcf->application = nxt_router_listener_application(tmcf, 704133Sigor@sysoev.ru &lscf.application); 705115Sigor@sysoev.ru 706115Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->pending, &skcf->link); 707115Sigor@sysoev.ru } 70853Sigor@sysoev.ru 70953Sigor@sysoev.ru return NXT_OK; 710133Sigor@sysoev.ru 711133Sigor@sysoev.ru app_fail: 712133Sigor@sysoev.ru 713133Sigor@sysoev.ru nxt_free(app); 714133Sigor@sysoev.ru 715133Sigor@sysoev.ru fail: 716133Sigor@sysoev.ru 717141Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 718141Smax.romanov@nginx.com 719141Smax.romanov@nginx.com nxt_queue_remove(&app->link); 720133Sigor@sysoev.ru nxt_thread_mutex_destroy(&app->mutex); 721133Sigor@sysoev.ru nxt_free(app); 722141Smax.romanov@nginx.com 723141Smax.romanov@nginx.com } nxt_queue_loop; 724133Sigor@sysoev.ru 725133Sigor@sysoev.ru return NXT_ERROR; 726133Sigor@sysoev.ru } 727133Sigor@sysoev.ru 728133Sigor@sysoev.ru 729133Sigor@sysoev.ru static nxt_app_t * 730133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name) 731133Sigor@sysoev.ru { 732141Smax.romanov@nginx.com nxt_app_t *app; 733141Smax.romanov@nginx.com 734141Smax.romanov@nginx.com nxt_queue_each(app, queue, nxt_app_t, link) { 735133Sigor@sysoev.ru 736133Sigor@sysoev.ru if (nxt_strstr_eq(name, &app->name)) { 737133Sigor@sysoev.ru return app; 738133Sigor@sysoev.ru } 739141Smax.romanov@nginx.com 740141Smax.romanov@nginx.com } nxt_queue_loop; 741133Sigor@sysoev.ru 742133Sigor@sysoev.ru return NULL; 743133Sigor@sysoev.ru } 744133Sigor@sysoev.ru 745133Sigor@sysoev.ru 746133Sigor@sysoev.ru static nxt_app_t * 747133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name) 748133Sigor@sysoev.ru { 749133Sigor@sysoev.ru nxt_app_t *app; 750133Sigor@sysoev.ru 751133Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->apps, name); 752133Sigor@sysoev.ru 753133Sigor@sysoev.ru if (app == NULL) { 754134Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->previous, name); 755133Sigor@sysoev.ru } 756133Sigor@sysoev.ru 757133Sigor@sysoev.ru return app; 75853Sigor@sysoev.ru } 75953Sigor@sysoev.ru 76053Sigor@sysoev.ru 76153Sigor@sysoev.ru static nxt_socket_conf_t * 76265Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, nxt_sockaddr_t *sa) 76353Sigor@sysoev.ru { 764*163Smax.romanov@nginx.com nxt_socket_conf_t *skcf; 765*163Smax.romanov@nginx.com 766*163Smax.romanov@nginx.com skcf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_t)); 767*163Smax.romanov@nginx.com if (nxt_slow_path(skcf == NULL)) { 76853Sigor@sysoev.ru return NULL; 76953Sigor@sysoev.ru } 77053Sigor@sysoev.ru 771*163Smax.romanov@nginx.com skcf->sockaddr = sa; 772*163Smax.romanov@nginx.com 773*163Smax.romanov@nginx.com skcf->listen.sockaddr = sa; 774*163Smax.romanov@nginx.com skcf->listen.socklen = sa->socklen; 775*163Smax.romanov@nginx.com skcf->listen.address_length = sa->length; 776*163Smax.romanov@nginx.com 777*163Smax.romanov@nginx.com skcf->listen.socket = -1; 778*163Smax.romanov@nginx.com skcf->listen.backlog = NXT_LISTEN_BACKLOG; 779*163Smax.romanov@nginx.com skcf->listen.flags = NXT_NONBLOCK; 780*163Smax.romanov@nginx.com skcf->listen.read_after_accept = 1; 781*163Smax.romanov@nginx.com 782*163Smax.romanov@nginx.com return skcf; 78353Sigor@sysoev.ru } 78453Sigor@sysoev.ru 78553Sigor@sysoev.ru 78653Sigor@sysoev.ru static void 78753Sigor@sysoev.ru nxt_router_listen_sockets_sort(nxt_router_t *router, 78853Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 78953Sigor@sysoev.ru { 79053Sigor@sysoev.ru nxt_queue_link_t *nqlk, *oqlk, *next; 79153Sigor@sysoev.ru nxt_socket_conf_t *nskcf, *oskcf; 79253Sigor@sysoev.ru 79353Sigor@sysoev.ru for (nqlk = nxt_queue_first(&tmcf->pending); 79453Sigor@sysoev.ru nqlk != nxt_queue_tail(&tmcf->pending); 79553Sigor@sysoev.ru nqlk = next) 79653Sigor@sysoev.ru { 79753Sigor@sysoev.ru next = nxt_queue_next(nqlk); 79853Sigor@sysoev.ru nskcf = nxt_queue_link_data(nqlk, nxt_socket_conf_t, link); 79953Sigor@sysoev.ru 80053Sigor@sysoev.ru for (oqlk = nxt_queue_first(&router->sockets); 80153Sigor@sysoev.ru oqlk != nxt_queue_tail(&router->sockets); 80253Sigor@sysoev.ru oqlk = nxt_queue_next(oqlk)) 80353Sigor@sysoev.ru { 80453Sigor@sysoev.ru oskcf = nxt_queue_link_data(oqlk, nxt_socket_conf_t, link); 80553Sigor@sysoev.ru 806115Sigor@sysoev.ru if (nxt_sockaddr_cmp(nskcf->sockaddr, oskcf->sockaddr)) { 807115Sigor@sysoev.ru nskcf->socket = oskcf->socket; 808115Sigor@sysoev.ru nskcf->listen.socket = oskcf->listen.socket; 809115Sigor@sysoev.ru 81053Sigor@sysoev.ru nxt_queue_remove(oqlk); 81153Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->keeping, oqlk); 81253Sigor@sysoev.ru 81353Sigor@sysoev.ru nxt_queue_remove(nqlk); 81453Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->updating, nqlk); 81553Sigor@sysoev.ru 81653Sigor@sysoev.ru break; 81753Sigor@sysoev.ru } 81853Sigor@sysoev.ru } 81953Sigor@sysoev.ru } 82053Sigor@sysoev.ru 82153Sigor@sysoev.ru nxt_queue_add(&tmcf->deleting, &router->sockets); 822115Sigor@sysoev.ru nxt_queue_init(&router->sockets); 82353Sigor@sysoev.ru } 82453Sigor@sysoev.ru 82553Sigor@sysoev.ru 82653Sigor@sysoev.ru static nxt_int_t 82753Sigor@sysoev.ru nxt_router_listen_sockets_stub_create(nxt_task_t *task, 82853Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 82953Sigor@sysoev.ru { 830115Sigor@sysoev.ru nxt_int_t ret; 831115Sigor@sysoev.ru nxt_socket_t s; 832115Sigor@sysoev.ru nxt_queue_link_t *qlk, *nqlk; 833115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 834115Sigor@sysoev.ru nxt_router_socket_t *rtsk; 83553Sigor@sysoev.ru 83653Sigor@sysoev.ru for (qlk = nxt_queue_first(&tmcf->pending); 83753Sigor@sysoev.ru qlk != nxt_queue_tail(&tmcf->pending); 83853Sigor@sysoev.ru qlk = nqlk) 83953Sigor@sysoev.ru { 840115Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 841115Sigor@sysoev.ru 842115Sigor@sysoev.ru s = nxt_listen_socket_create0(task, skcf->sockaddr, NXT_NONBLOCK); 843115Sigor@sysoev.ru if (nxt_slow_path(s == -1)) { 844115Sigor@sysoev.ru return NXT_ERROR; 845115Sigor@sysoev.ru } 846115Sigor@sysoev.ru 847115Sigor@sysoev.ru ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG); 848115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 849148Sigor@sysoev.ru goto fail; 850115Sigor@sysoev.ru } 851115Sigor@sysoev.ru 852115Sigor@sysoev.ru skcf->listen.socket = s; 853115Sigor@sysoev.ru 854148Sigor@sysoev.ru rtsk = nxt_malloc(sizeof(nxt_router_socket_t)); 855148Sigor@sysoev.ru if (nxt_slow_path(rtsk == NULL)) { 856148Sigor@sysoev.ru goto fail; 857148Sigor@sysoev.ru } 858148Sigor@sysoev.ru 859148Sigor@sysoev.ru rtsk->count = 0; 860148Sigor@sysoev.ru rtsk->fd = skcf->listen.socket; 861148Sigor@sysoev.ru skcf->socket = rtsk; 862115Sigor@sysoev.ru 86353Sigor@sysoev.ru nqlk = nxt_queue_next(qlk); 86453Sigor@sysoev.ru nxt_queue_remove(qlk); 86553Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->creating, qlk); 86653Sigor@sysoev.ru } 86753Sigor@sysoev.ru 86853Sigor@sysoev.ru return NXT_OK; 869148Sigor@sysoev.ru 870148Sigor@sysoev.ru fail: 871148Sigor@sysoev.ru 872148Sigor@sysoev.ru nxt_socket_close(task, s); 873148Sigor@sysoev.ru 874148Sigor@sysoev.ru return NXT_ERROR; 87553Sigor@sysoev.ru } 87653Sigor@sysoev.ru 87753Sigor@sysoev.ru 87853Sigor@sysoev.ru static nxt_int_t 87953Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router, 88053Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface) 88153Sigor@sysoev.ru { 88253Sigor@sysoev.ru nxt_int_t ret; 88353Sigor@sysoev.ru nxt_uint_t n, threads; 88453Sigor@sysoev.ru nxt_queue_link_t *qlk; 88553Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 88653Sigor@sysoev.ru 88753Sigor@sysoev.ru threads = tmcf->conf->threads; 88853Sigor@sysoev.ru 88953Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, threads, 89053Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 89153Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 89253Sigor@sysoev.ru return NXT_ERROR; 89353Sigor@sysoev.ru } 89453Sigor@sysoev.ru 89553Sigor@sysoev.ru n = 0; 89653Sigor@sysoev.ru 89753Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->engines); 89853Sigor@sysoev.ru qlk != nxt_queue_tail(&router->engines); 89953Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 90053Sigor@sysoev.ru { 90153Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 90253Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 90353Sigor@sysoev.ru return NXT_ERROR; 90453Sigor@sysoev.ru } 90553Sigor@sysoev.ru 906115Sigor@sysoev.ru recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0); 90753Sigor@sysoev.ru 90853Sigor@sysoev.ru if (n < threads) { 909115Sigor@sysoev.ru ret = nxt_router_engine_conf_update(tmcf, recf); 91053Sigor@sysoev.ru 91153Sigor@sysoev.ru } else { 912115Sigor@sysoev.ru ret = nxt_router_engine_conf_delete(tmcf, recf); 91353Sigor@sysoev.ru } 91453Sigor@sysoev.ru 91553Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 91653Sigor@sysoev.ru return ret; 91753Sigor@sysoev.ru } 91853Sigor@sysoev.ru 91953Sigor@sysoev.ru n++; 92053Sigor@sysoev.ru } 92153Sigor@sysoev.ru 92253Sigor@sysoev.ru tmcf->new_threads = n; 92353Sigor@sysoev.ru 92453Sigor@sysoev.ru while (n < threads) { 92553Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 92653Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 92753Sigor@sysoev.ru return NXT_ERROR; 92853Sigor@sysoev.ru } 92953Sigor@sysoev.ru 93053Sigor@sysoev.ru recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0); 93153Sigor@sysoev.ru if (nxt_slow_path(recf->engine == NULL)) { 93253Sigor@sysoev.ru return NXT_ERROR; 93353Sigor@sysoev.ru } 93453Sigor@sysoev.ru 935115Sigor@sysoev.ru ret = nxt_router_engine_conf_create(tmcf, recf); 93653Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 93753Sigor@sysoev.ru return ret; 93853Sigor@sysoev.ru } 93953Sigor@sysoev.ru 940115Sigor@sysoev.ru nxt_queue_insert_tail(&router->engines, &recf->engine->link0); 941115Sigor@sysoev.ru 94253Sigor@sysoev.ru n++; 94353Sigor@sysoev.ru } 94453Sigor@sysoev.ru 94553Sigor@sysoev.ru return NXT_OK; 94653Sigor@sysoev.ru } 94753Sigor@sysoev.ru 94853Sigor@sysoev.ru 94953Sigor@sysoev.ru static nxt_int_t 950115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 951115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 95253Sigor@sysoev.ru { 953115Sigor@sysoev.ru nxt_int_t ret; 954115Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 95553Sigor@sysoev.ru 956154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 957154Sigor@sysoev.ru nxt_router_listen_socket_create); 958115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 959115Sigor@sysoev.ru return ret; 960115Sigor@sysoev.ru } 961115Sigor@sysoev.ru 962154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 963154Sigor@sysoev.ru nxt_router_listen_socket_create); 96453Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 96553Sigor@sysoev.ru return ret; 96653Sigor@sysoev.ru } 96753Sigor@sysoev.ru 968115Sigor@sysoev.ru lock = &tmcf->conf->router->lock; 969115Sigor@sysoev.ru 970115Sigor@sysoev.ru nxt_thread_spin_lock(lock); 971115Sigor@sysoev.ru 972115Sigor@sysoev.ru nxt_router_engine_socket_count(&tmcf->creating); 973115Sigor@sysoev.ru nxt_router_engine_socket_count(&tmcf->updating); 974115Sigor@sysoev.ru 975115Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 976115Sigor@sysoev.ru 977115Sigor@sysoev.ru return ret; 97853Sigor@sysoev.ru } 97953Sigor@sysoev.ru 98053Sigor@sysoev.ru 98153Sigor@sysoev.ru static nxt_int_t 982115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 983115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 98453Sigor@sysoev.ru { 985115Sigor@sysoev.ru nxt_int_t ret; 986115Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 98753Sigor@sysoev.ru 988154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 989154Sigor@sysoev.ru nxt_router_listen_socket_create); 99053Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 99153Sigor@sysoev.ru return ret; 99253Sigor@sysoev.ru } 99353Sigor@sysoev.ru 994154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 995154Sigor@sysoev.ru nxt_router_listen_socket_update); 99653Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 99753Sigor@sysoev.ru return ret; 99853Sigor@sysoev.ru } 99953Sigor@sysoev.ru 1000139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 1001115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1002115Sigor@sysoev.ru return ret; 1003115Sigor@sysoev.ru } 1004115Sigor@sysoev.ru 1005115Sigor@sysoev.ru lock = &tmcf->conf->router->lock; 1006115Sigor@sysoev.ru 1007115Sigor@sysoev.ru nxt_thread_spin_lock(lock); 1008115Sigor@sysoev.ru 1009115Sigor@sysoev.ru nxt_router_engine_socket_count(&tmcf->creating); 1010115Sigor@sysoev.ru 1011115Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 1012115Sigor@sysoev.ru 1013115Sigor@sysoev.ru return ret; 101453Sigor@sysoev.ru } 101553Sigor@sysoev.ru 101653Sigor@sysoev.ru 101753Sigor@sysoev.ru static nxt_int_t 1018115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 1019115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 102053Sigor@sysoev.ru { 102153Sigor@sysoev.ru nxt_int_t ret; 102253Sigor@sysoev.ru 1023139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating); 102453Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 102553Sigor@sysoev.ru return ret; 102653Sigor@sysoev.ru } 102753Sigor@sysoev.ru 1028139Sigor@sysoev.ru return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 102953Sigor@sysoev.ru } 103053Sigor@sysoev.ru 103153Sigor@sysoev.ru 103253Sigor@sysoev.ru static nxt_int_t 1033154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 1034154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 103553Sigor@sysoev.ru nxt_work_handler_t handler) 103653Sigor@sysoev.ru { 1037153Sigor@sysoev.ru nxt_joint_job_t *job; 103853Sigor@sysoev.ru nxt_queue_link_t *qlk; 1039155Sigor@sysoev.ru nxt_socket_conf_t *skcf; 104053Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 104153Sigor@sysoev.ru 104253Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 104353Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 104453Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 104553Sigor@sysoev.ru { 1046154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 1047153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 1048139Sigor@sysoev.ru return NXT_ERROR; 1049139Sigor@sysoev.ru } 1050139Sigor@sysoev.ru 1051154Sigor@sysoev.ru job->work.next = recf->jobs; 1052154Sigor@sysoev.ru recf->jobs = &job->work; 1053154Sigor@sysoev.ru 1054153Sigor@sysoev.ru job->task = tmcf->engine->task; 1055153Sigor@sysoev.ru job->work.handler = handler; 1056153Sigor@sysoev.ru job->work.task = &job->task; 1057153Sigor@sysoev.ru job->work.obj = job; 1058153Sigor@sysoev.ru job->tmcf = tmcf; 105953Sigor@sysoev.ru 1060154Sigor@sysoev.ru tmcf->count++; 1061154Sigor@sysoev.ru 1062154Sigor@sysoev.ru joint = nxt_mp_alloc(tmcf->conf->mem_pool, 1063154Sigor@sysoev.ru sizeof(nxt_socket_conf_joint_t)); 106453Sigor@sysoev.ru if (nxt_slow_path(joint == NULL)) { 106553Sigor@sysoev.ru return NXT_ERROR; 106653Sigor@sysoev.ru } 106753Sigor@sysoev.ru 1068153Sigor@sysoev.ru job->work.data = joint; 106953Sigor@sysoev.ru 107053Sigor@sysoev.ru joint->count = 1; 1071155Sigor@sysoev.ru 1072155Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1073155Sigor@sysoev.ru skcf->count++; 1074155Sigor@sysoev.ru joint->socket_conf = skcf; 1075155Sigor@sysoev.ru 107688Smax.romanov@nginx.com joint->engine = recf->engine; 107753Sigor@sysoev.ru } 107853Sigor@sysoev.ru 107920Sigor@sysoev.ru return NXT_OK; 108020Sigor@sysoev.ru } 108120Sigor@sysoev.ru 108220Sigor@sysoev.ru 1083115Sigor@sysoev.ru static void 1084115Sigor@sysoev.ru nxt_router_engine_socket_count(nxt_queue_t *sockets) 1085115Sigor@sysoev.ru { 1086115Sigor@sysoev.ru nxt_queue_link_t *qlk; 1087115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1088115Sigor@sysoev.ru 1089115Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 1090115Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 1091115Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 1092115Sigor@sysoev.ru { 1093115Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1094115Sigor@sysoev.ru skcf->socket->count++; 1095115Sigor@sysoev.ru } 1096115Sigor@sysoev.ru } 1097115Sigor@sysoev.ru 1098115Sigor@sysoev.ru 109920Sigor@sysoev.ru static nxt_int_t 1100139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 1101139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets) 110220Sigor@sysoev.ru { 1103153Sigor@sysoev.ru nxt_joint_job_t *job; 110453Sigor@sysoev.ru nxt_queue_link_t *qlk; 110520Sigor@sysoev.ru 110653Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 110753Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 110853Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 110953Sigor@sysoev.ru { 1110154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 1111153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 1112139Sigor@sysoev.ru return NXT_ERROR; 1113139Sigor@sysoev.ru } 1114139Sigor@sysoev.ru 1115154Sigor@sysoev.ru job->work.next = recf->jobs; 1116154Sigor@sysoev.ru recf->jobs = &job->work; 1117154Sigor@sysoev.ru 1118153Sigor@sysoev.ru job->task = tmcf->engine->task; 1119153Sigor@sysoev.ru job->work.handler = nxt_router_listen_socket_delete; 1120153Sigor@sysoev.ru job->work.task = &job->task; 1121153Sigor@sysoev.ru job->work.obj = job; 1122153Sigor@sysoev.ru job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1123153Sigor@sysoev.ru job->tmcf = tmcf; 1124154Sigor@sysoev.ru 1125154Sigor@sysoev.ru tmcf->count++; 112620Sigor@sysoev.ru } 112720Sigor@sysoev.ru 112853Sigor@sysoev.ru return NXT_OK; 112953Sigor@sysoev.ru } 113020Sigor@sysoev.ru 113120Sigor@sysoev.ru 113253Sigor@sysoev.ru static nxt_int_t 113353Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 113453Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 113553Sigor@sysoev.ru { 113653Sigor@sysoev.ru nxt_int_t ret; 113753Sigor@sysoev.ru nxt_uint_t i, threads; 113853Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 113920Sigor@sysoev.ru 114053Sigor@sysoev.ru recf = tmcf->engines->elts; 114153Sigor@sysoev.ru threads = tmcf->conf->threads; 114220Sigor@sysoev.ru 114353Sigor@sysoev.ru for (i = tmcf->new_threads; i < threads; i++) { 114453Sigor@sysoev.ru ret = nxt_router_thread_create(task, rt, recf[i].engine); 114553Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 114653Sigor@sysoev.ru return ret; 114753Sigor@sysoev.ru } 114820Sigor@sysoev.ru } 114920Sigor@sysoev.ru 115020Sigor@sysoev.ru return NXT_OK; 115120Sigor@sysoev.ru } 115253Sigor@sysoev.ru 115353Sigor@sysoev.ru 115453Sigor@sysoev.ru static nxt_int_t 115553Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 115653Sigor@sysoev.ru nxt_event_engine_t *engine) 115753Sigor@sysoev.ru { 115853Sigor@sysoev.ru nxt_int_t ret; 115953Sigor@sysoev.ru nxt_thread_link_t *link; 116053Sigor@sysoev.ru nxt_thread_handle_t handle; 116153Sigor@sysoev.ru 116253Sigor@sysoev.ru link = nxt_zalloc(sizeof(nxt_thread_link_t)); 116353Sigor@sysoev.ru 116453Sigor@sysoev.ru if (nxt_slow_path(link == NULL)) { 116553Sigor@sysoev.ru return NXT_ERROR; 116653Sigor@sysoev.ru } 116753Sigor@sysoev.ru 116853Sigor@sysoev.ru link->start = nxt_router_thread_start; 116953Sigor@sysoev.ru link->engine = engine; 117053Sigor@sysoev.ru link->work.handler = nxt_router_thread_exit_handler; 117153Sigor@sysoev.ru link->work.task = task; 117253Sigor@sysoev.ru link->work.data = link; 117353Sigor@sysoev.ru 117453Sigor@sysoev.ru nxt_queue_insert_tail(&rt->engines, &engine->link); 117553Sigor@sysoev.ru 117653Sigor@sysoev.ru ret = nxt_thread_create(&handle, link); 117753Sigor@sysoev.ru 117853Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 117953Sigor@sysoev.ru nxt_queue_remove(&engine->link); 118053Sigor@sysoev.ru } 118153Sigor@sysoev.ru 118253Sigor@sysoev.ru return ret; 118353Sigor@sysoev.ru } 118453Sigor@sysoev.ru 118553Sigor@sysoev.ru 118653Sigor@sysoev.ru static void 1187133Sigor@sysoev.ru nxt_router_apps_sort(nxt_router_t *router, nxt_router_temp_conf_t *tmcf) 1188133Sigor@sysoev.ru { 1189*163Smax.romanov@nginx.com nxt_app_t *app; 1190*163Smax.romanov@nginx.com nxt_port_t *port; 1191141Smax.romanov@nginx.com 1192141Smax.romanov@nginx.com nxt_queue_each(app, &router->apps, nxt_app_t, link) { 1193133Sigor@sysoev.ru 1194133Sigor@sysoev.ru nxt_queue_remove(&app->link); 1195133Sigor@sysoev.ru 1196*163Smax.romanov@nginx.com app->live = 0; 1197*163Smax.romanov@nginx.com 1198*163Smax.romanov@nginx.com if (nxt_router_app_free(app) != 0) { 1199*163Smax.romanov@nginx.com continue; 1200*163Smax.romanov@nginx.com } 1201*163Smax.romanov@nginx.com 1202*163Smax.romanov@nginx.com if (nxt_queue_is_empty(&app->requests)) { 1203*163Smax.romanov@nginx.com 1204*163Smax.romanov@nginx.com do { 1205*163Smax.romanov@nginx.com port = nxt_router_app_get_port(app); 1206*163Smax.romanov@nginx.com if (port == NULL) { 1207*163Smax.romanov@nginx.com break; 1208*163Smax.romanov@nginx.com } 1209*163Smax.romanov@nginx.com 1210*163Smax.romanov@nginx.com nxt_port_socket_write(&port->engine->task, port, 1211*163Smax.romanov@nginx.com NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 1212*163Smax.romanov@nginx.com } while (1); 1213*163Smax.romanov@nginx.com 1214*163Smax.romanov@nginx.com } 1215*163Smax.romanov@nginx.com 1216141Smax.romanov@nginx.com } nxt_queue_loop; 1217133Sigor@sysoev.ru 1218133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->previous); 1219133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->apps); 1220133Sigor@sysoev.ru } 1221133Sigor@sysoev.ru 1222133Sigor@sysoev.ru 1223133Sigor@sysoev.ru static void 122453Sigor@sysoev.ru nxt_router_engines_post(nxt_router_temp_conf_t *tmcf) 122553Sigor@sysoev.ru { 122653Sigor@sysoev.ru nxt_uint_t n; 122753Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 122853Sigor@sysoev.ru 122953Sigor@sysoev.ru recf = tmcf->engines->elts; 123053Sigor@sysoev.ru 123153Sigor@sysoev.ru for (n = tmcf->engines->nelts; n != 0; n--) { 1232154Sigor@sysoev.ru nxt_router_engine_post(recf); 123353Sigor@sysoev.ru recf++; 123453Sigor@sysoev.ru } 123553Sigor@sysoev.ru } 123653Sigor@sysoev.ru 123753Sigor@sysoev.ru 123853Sigor@sysoev.ru static void 1239154Sigor@sysoev.ru nxt_router_engine_post(nxt_router_engine_conf_t *recf) 124053Sigor@sysoev.ru { 1241154Sigor@sysoev.ru nxt_work_t *work, *next; 1242154Sigor@sysoev.ru 1243154Sigor@sysoev.ru for (work = recf->jobs; work != NULL; work = next) { 1244154Sigor@sysoev.ru next = work->next; 1245154Sigor@sysoev.ru work->next = NULL; 1246154Sigor@sysoev.ru 1247154Sigor@sysoev.ru nxt_event_engine_post(recf->engine, work); 124853Sigor@sysoev.ru } 124953Sigor@sysoev.ru } 125053Sigor@sysoev.ru 125153Sigor@sysoev.ru 125253Sigor@sysoev.ru static void 1253119Smax.romanov@nginx.com nxt_router_app_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); 125488Smax.romanov@nginx.com 1255119Smax.romanov@nginx.com static nxt_port_handler_t nxt_router_app_port_handlers[] = { 125688Smax.romanov@nginx.com NULL, 125788Smax.romanov@nginx.com nxt_port_new_port_handler, 125888Smax.romanov@nginx.com nxt_port_change_log_file_handler, 125988Smax.romanov@nginx.com nxt_port_mmap_handler, 1260119Smax.romanov@nginx.com nxt_router_app_data_handler, 1261125Smax.romanov@nginx.com nxt_port_remove_pid_handler, 126288Smax.romanov@nginx.com }; 126388Smax.romanov@nginx.com 126488Smax.romanov@nginx.com 126588Smax.romanov@nginx.com static void 126653Sigor@sysoev.ru nxt_router_thread_start(void *data) 126753Sigor@sysoev.ru { 1268141Smax.romanov@nginx.com nxt_int_t ret; 1269141Smax.romanov@nginx.com nxt_port_t *port; 127088Smax.romanov@nginx.com nxt_task_t *task; 127153Sigor@sysoev.ru nxt_thread_t *thread; 127253Sigor@sysoev.ru nxt_thread_link_t *link; 127353Sigor@sysoev.ru nxt_event_engine_t *engine; 127453Sigor@sysoev.ru 127553Sigor@sysoev.ru link = data; 127653Sigor@sysoev.ru engine = link->engine; 127788Smax.romanov@nginx.com task = &engine->task; 127853Sigor@sysoev.ru 127953Sigor@sysoev.ru thread = nxt_thread(); 128053Sigor@sysoev.ru 128153Sigor@sysoev.ru /* STUB */ 128253Sigor@sysoev.ru thread->runtime = engine->task.thread->runtime; 128353Sigor@sysoev.ru 128453Sigor@sysoev.ru engine->task.thread = thread; 128553Sigor@sysoev.ru engine->task.log = thread->log; 128653Sigor@sysoev.ru thread->engine = engine; 128763Sigor@sysoev.ru thread->task = &engine->task; 128853Sigor@sysoev.ru thread->fiber = &engine->fibers->fiber; 128953Sigor@sysoev.ru 129063Sigor@sysoev.ru engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64); 129153Sigor@sysoev.ru 1292*163Smax.romanov@nginx.com port = nxt_port_new(nxt_port_get_next_id(), nxt_pid, NXT_PROCESS_ROUTER); 1293141Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 1294141Smax.romanov@nginx.com return; 1295141Smax.romanov@nginx.com } 1296141Smax.romanov@nginx.com 1297141Smax.romanov@nginx.com ret = nxt_port_socket_init(task, port, 0); 1298141Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 1299*163Smax.romanov@nginx.com nxt_mp_release(port->mem_pool, port); 1300141Smax.romanov@nginx.com return; 1301141Smax.romanov@nginx.com } 1302141Smax.romanov@nginx.com 1303141Smax.romanov@nginx.com engine->port = port; 1304141Smax.romanov@nginx.com 1305141Smax.romanov@nginx.com nxt_port_enable(task, port, nxt_router_app_port_handlers); 1306141Smax.romanov@nginx.com 130753Sigor@sysoev.ru nxt_event_engine_start(engine); 130853Sigor@sysoev.ru } 130953Sigor@sysoev.ru 131053Sigor@sysoev.ru 131153Sigor@sysoev.ru static void 131253Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data) 131353Sigor@sysoev.ru { 1314153Sigor@sysoev.ru nxt_joint_job_t *job; 131553Sigor@sysoev.ru nxt_listen_event_t *listen; 131653Sigor@sysoev.ru nxt_listen_socket_t *ls; 131753Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 131853Sigor@sysoev.ru 1319153Sigor@sysoev.ru job = obj; 132053Sigor@sysoev.ru joint = data; 132153Sigor@sysoev.ru 132253Sigor@sysoev.ru ls = &joint->socket_conf->listen; 132353Sigor@sysoev.ru 1324159Sigor@sysoev.ru nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link); 1325159Sigor@sysoev.ru 132653Sigor@sysoev.ru listen = nxt_listen_event(task, ls); 132753Sigor@sysoev.ru if (nxt_slow_path(listen == NULL)) { 132853Sigor@sysoev.ru nxt_router_listen_socket_release(task, joint); 132953Sigor@sysoev.ru return; 133053Sigor@sysoev.ru } 133153Sigor@sysoev.ru 133253Sigor@sysoev.ru listen->socket.data = joint; 1333139Sigor@sysoev.ru 1334153Sigor@sysoev.ru job->work.next = NULL; 1335153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 1336153Sigor@sysoev.ru 1337153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 133853Sigor@sysoev.ru } 133953Sigor@sysoev.ru 134053Sigor@sysoev.ru 134153Sigor@sysoev.ru nxt_inline nxt_listen_event_t * 134253Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections, 134353Sigor@sysoev.ru nxt_socket_conf_t *skcf) 134453Sigor@sysoev.ru { 1345115Sigor@sysoev.ru nxt_socket_t fd; 1346115Sigor@sysoev.ru nxt_queue_link_t *qlk; 134753Sigor@sysoev.ru nxt_listen_event_t *listen; 134853Sigor@sysoev.ru 1349115Sigor@sysoev.ru fd = skcf->socket->fd; 135053Sigor@sysoev.ru 1351115Sigor@sysoev.ru for (qlk = nxt_queue_first(listen_connections); 1352115Sigor@sysoev.ru qlk != nxt_queue_tail(listen_connections); 1353115Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 135453Sigor@sysoev.ru { 1355115Sigor@sysoev.ru listen = nxt_queue_link_data(qlk, nxt_listen_event_t, link); 135653Sigor@sysoev.ru 1357115Sigor@sysoev.ru if (fd == listen->socket.fd) { 135853Sigor@sysoev.ru return listen; 135953Sigor@sysoev.ru } 136053Sigor@sysoev.ru } 136153Sigor@sysoev.ru 136253Sigor@sysoev.ru return NULL; 136353Sigor@sysoev.ru } 136453Sigor@sysoev.ru 136553Sigor@sysoev.ru 136653Sigor@sysoev.ru static void 136753Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data) 136853Sigor@sysoev.ru { 1369153Sigor@sysoev.ru nxt_joint_job_t *job; 137053Sigor@sysoev.ru nxt_event_engine_t *engine; 137153Sigor@sysoev.ru nxt_listen_event_t *listen; 137253Sigor@sysoev.ru nxt_socket_conf_joint_t *joint, *old; 137353Sigor@sysoev.ru 1374153Sigor@sysoev.ru job = obj; 137553Sigor@sysoev.ru joint = data; 137653Sigor@sysoev.ru 1377139Sigor@sysoev.ru engine = task->thread->engine; 1378139Sigor@sysoev.ru 1379159Sigor@sysoev.ru nxt_queue_insert_tail(&engine->joints, &joint->link); 1380159Sigor@sysoev.ru 138153Sigor@sysoev.ru listen = nxt_router_listen_event(&engine->listen_connections, 138253Sigor@sysoev.ru joint->socket_conf); 138353Sigor@sysoev.ru 138453Sigor@sysoev.ru old = listen->socket.data; 138553Sigor@sysoev.ru listen->socket.data = joint; 138653Sigor@sysoev.ru 1387153Sigor@sysoev.ru job->work.next = NULL; 1388153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 1389153Sigor@sysoev.ru 1390153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 1391139Sigor@sysoev.ru 139253Sigor@sysoev.ru nxt_router_conf_release(task, old); 139353Sigor@sysoev.ru } 139453Sigor@sysoev.ru 139553Sigor@sysoev.ru 139653Sigor@sysoev.ru static void 139753Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data) 139853Sigor@sysoev.ru { 1399153Sigor@sysoev.ru nxt_joint_job_t *job; 1400153Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1401153Sigor@sysoev.ru nxt_listen_event_t *listen; 1402153Sigor@sysoev.ru nxt_event_engine_t *engine; 1403153Sigor@sysoev.ru 1404153Sigor@sysoev.ru job = obj; 140553Sigor@sysoev.ru skcf = data; 140653Sigor@sysoev.ru 1407139Sigor@sysoev.ru engine = task->thread->engine; 1408139Sigor@sysoev.ru 140953Sigor@sysoev.ru listen = nxt_router_listen_event(&engine->listen_connections, skcf); 141053Sigor@sysoev.ru 141153Sigor@sysoev.ru nxt_fd_event_delete(engine, &listen->socket); 141253Sigor@sysoev.ru 1413*163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket delete: %d", engine, 1414*163Smax.romanov@nginx.com listen->socket.fd); 1415*163Smax.romanov@nginx.com 141653Sigor@sysoev.ru listen->timer.handler = nxt_router_listen_socket_close; 141753Sigor@sysoev.ru listen->timer.work_queue = &engine->fast_work_queue; 141853Sigor@sysoev.ru 141953Sigor@sysoev.ru nxt_timer_add(engine, &listen->timer, 0); 1420139Sigor@sysoev.ru 1421153Sigor@sysoev.ru job->work.next = NULL; 1422153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 1423153Sigor@sysoev.ru 1424153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 142553Sigor@sysoev.ru } 142653Sigor@sysoev.ru 142753Sigor@sysoev.ru 142853Sigor@sysoev.ru static void 142953Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data) 143053Sigor@sysoev.ru { 143153Sigor@sysoev.ru nxt_timer_t *timer; 143253Sigor@sysoev.ru nxt_listen_event_t *listen; 143353Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 143453Sigor@sysoev.ru 143553Sigor@sysoev.ru timer = obj; 143653Sigor@sysoev.ru listen = nxt_timer_data(timer, nxt_listen_event_t, timer); 143753Sigor@sysoev.ru joint = listen->socket.data; 143853Sigor@sysoev.ru 1439*163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine, 1440*163Smax.romanov@nginx.com listen->socket.fd); 1441*163Smax.romanov@nginx.com 144253Sigor@sysoev.ru nxt_queue_remove(&listen->link); 1443123Smax.romanov@nginx.com 1444123Smax.romanov@nginx.com /* 'task' refers to listen->task and we cannot use after nxt_free() */ 1445123Smax.romanov@nginx.com task = &task->thread->engine->task; 1446123Smax.romanov@nginx.com 144753Sigor@sysoev.ru nxt_free(listen); 144853Sigor@sysoev.ru 144953Sigor@sysoev.ru nxt_router_listen_socket_release(task, joint); 145053Sigor@sysoev.ru } 145153Sigor@sysoev.ru 145253Sigor@sysoev.ru 145353Sigor@sysoev.ru static void 145453Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, 145553Sigor@sysoev.ru nxt_socket_conf_joint_t *joint) 145653Sigor@sysoev.ru { 1457118Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1458115Sigor@sysoev.ru nxt_router_socket_t *rtsk; 145953Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 146053Sigor@sysoev.ru 1461118Sigor@sysoev.ru skcf = joint->socket_conf; 1462118Sigor@sysoev.ru rtsk = skcf->socket; 1463118Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 146453Sigor@sysoev.ru 146553Sigor@sysoev.ru nxt_thread_spin_lock(lock); 146653Sigor@sysoev.ru 1467*163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket release: rtsk->count %D", 1468*163Smax.romanov@nginx.com task->thread->engine, rtsk->count); 1469*163Smax.romanov@nginx.com 1470115Sigor@sysoev.ru if (--rtsk->count != 0) { 1471115Sigor@sysoev.ru rtsk = NULL; 147253Sigor@sysoev.ru } 147353Sigor@sysoev.ru 147453Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 147553Sigor@sysoev.ru 1476115Sigor@sysoev.ru if (rtsk != NULL) { 1477115Sigor@sysoev.ru nxt_socket_close(task, rtsk->fd); 1478115Sigor@sysoev.ru nxt_free(rtsk); 1479118Sigor@sysoev.ru skcf->socket = NULL; 148053Sigor@sysoev.ru } 148153Sigor@sysoev.ru 148253Sigor@sysoev.ru nxt_router_conf_release(task, joint); 148353Sigor@sysoev.ru } 148453Sigor@sysoev.ru 148553Sigor@sysoev.ru 148653Sigor@sysoev.ru static void 148753Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint) 148853Sigor@sysoev.ru { 1489156Sigor@sysoev.ru nxt_bool_t exit; 149053Sigor@sysoev.ru nxt_socket_conf_t *skcf; 149153Sigor@sysoev.ru nxt_router_conf_t *rtcf; 149253Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 149353Sigor@sysoev.ru 1494*163Smax.romanov@nginx.com nxt_debug(task, "conf joint %p count: %D", joint, joint->count); 149553Sigor@sysoev.ru 149653Sigor@sysoev.ru if (--joint->count != 0) { 149753Sigor@sysoev.ru return; 149853Sigor@sysoev.ru } 149953Sigor@sysoev.ru 150053Sigor@sysoev.ru nxt_queue_remove(&joint->link); 150153Sigor@sysoev.ru 150253Sigor@sysoev.ru skcf = joint->socket_conf; 150353Sigor@sysoev.ru rtcf = skcf->router_conf; 150453Sigor@sysoev.ru lock = &rtcf->router->lock; 150553Sigor@sysoev.ru 150653Sigor@sysoev.ru nxt_thread_spin_lock(lock); 150753Sigor@sysoev.ru 1508*163Smax.romanov@nginx.com nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count, 1509*163Smax.romanov@nginx.com rtcf, rtcf->count); 1510*163Smax.romanov@nginx.com 151153Sigor@sysoev.ru if (--skcf->count != 0) { 151253Sigor@sysoev.ru rtcf = NULL; 151353Sigor@sysoev.ru 151453Sigor@sysoev.ru } else { 151553Sigor@sysoev.ru nxt_queue_remove(&skcf->link); 151653Sigor@sysoev.ru 151753Sigor@sysoev.ru if (--rtcf->count != 0) { 151853Sigor@sysoev.ru rtcf = NULL; 151953Sigor@sysoev.ru } 152053Sigor@sysoev.ru } 152153Sigor@sysoev.ru 152253Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 152353Sigor@sysoev.ru 1524141Smax.romanov@nginx.com /* TODO remove engine->port */ 1525141Smax.romanov@nginx.com /* TODO excude from connected ports */ 1526141Smax.romanov@nginx.com 1527156Sigor@sysoev.ru /* The joint content can be used before memory pool destruction. */ 1528156Sigor@sysoev.ru exit = nxt_queue_is_empty(&joint->engine->joints); 1529156Sigor@sysoev.ru 153053Sigor@sysoev.ru if (rtcf != NULL) { 1531115Sigor@sysoev.ru nxt_debug(task, "old router conf is destroyed"); 1532131Smax.romanov@nginx.com 1533131Smax.romanov@nginx.com nxt_mp_thread_adopt(rtcf->mem_pool); 1534131Smax.romanov@nginx.com 153565Sigor@sysoev.ru nxt_mp_destroy(rtcf->mem_pool); 153653Sigor@sysoev.ru } 153753Sigor@sysoev.ru 1538156Sigor@sysoev.ru if (exit) { 153953Sigor@sysoev.ru nxt_thread_exit(task->thread); 154053Sigor@sysoev.ru } 154153Sigor@sysoev.ru } 154253Sigor@sysoev.ru 154353Sigor@sysoev.ru 154453Sigor@sysoev.ru static void 154553Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data) 154653Sigor@sysoev.ru { 1547141Smax.romanov@nginx.com nxt_port_t *port; 154853Sigor@sysoev.ru nxt_thread_link_t *link; 154953Sigor@sysoev.ru nxt_event_engine_t *engine; 155053Sigor@sysoev.ru nxt_thread_handle_t handle; 155153Sigor@sysoev.ru 155258Svbart@nginx.com handle = (nxt_thread_handle_t) obj; 155353Sigor@sysoev.ru link = data; 155453Sigor@sysoev.ru 155553Sigor@sysoev.ru nxt_thread_wait(handle); 155653Sigor@sysoev.ru 155753Sigor@sysoev.ru engine = link->engine; 155853Sigor@sysoev.ru 155953Sigor@sysoev.ru nxt_queue_remove(&engine->link); 156053Sigor@sysoev.ru 1561141Smax.romanov@nginx.com port = engine->port; 1562141Smax.romanov@nginx.com 1563141Smax.romanov@nginx.com // TODO notify all apps 1564141Smax.romanov@nginx.com 1565*163Smax.romanov@nginx.com nxt_mp_thread_adopt(port->mem_pool); 1566*163Smax.romanov@nginx.com nxt_port_release(port); 1567*163Smax.romanov@nginx.com 1568*163Smax.romanov@nginx.com nxt_mp_thread_adopt(engine->mem_pool); 156963Sigor@sysoev.ru nxt_mp_destroy(engine->mem_pool); 157053Sigor@sysoev.ru 157153Sigor@sysoev.ru nxt_event_engine_free(engine); 157253Sigor@sysoev.ru 157353Sigor@sysoev.ru nxt_free(link); 157453Sigor@sysoev.ru } 157553Sigor@sysoev.ru 157653Sigor@sysoev.ru 157762Sigor@sysoev.ru static const nxt_conn_state_t nxt_router_conn_read_state 157853Sigor@sysoev.ru nxt_aligned(64) = 157953Sigor@sysoev.ru { 158053Sigor@sysoev.ru .ready_handler = nxt_router_conn_http_header_parse, 158153Sigor@sysoev.ru .close_handler = nxt_router_conn_close, 158253Sigor@sysoev.ru .error_handler = nxt_router_conn_error, 158353Sigor@sysoev.ru 158453Sigor@sysoev.ru .timer_handler = nxt_router_conn_timeout, 158553Sigor@sysoev.ru .timer_value = nxt_router_conn_timeout_value, 158653Sigor@sysoev.ru .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout), 158753Sigor@sysoev.ru }; 158853Sigor@sysoev.ru 158953Sigor@sysoev.ru 159053Sigor@sysoev.ru static void 159153Sigor@sysoev.ru nxt_router_conn_init(nxt_task_t *task, void *obj, void *data) 159253Sigor@sysoev.ru { 159353Sigor@sysoev.ru size_t size; 159462Sigor@sysoev.ru nxt_conn_t *c; 159553Sigor@sysoev.ru nxt_event_engine_t *engine; 159653Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 159753Sigor@sysoev.ru 159853Sigor@sysoev.ru c = obj; 159953Sigor@sysoev.ru joint = data; 160053Sigor@sysoev.ru 160153Sigor@sysoev.ru nxt_debug(task, "router conn init"); 160253Sigor@sysoev.ru 160353Sigor@sysoev.ru joint->count++; 160453Sigor@sysoev.ru 160553Sigor@sysoev.ru size = joint->socket_conf->header_buffer_size; 160653Sigor@sysoev.ru c->read = nxt_buf_mem_alloc(c->mem_pool, size, 0); 160753Sigor@sysoev.ru 160853Sigor@sysoev.ru c->socket.data = NULL; 160953Sigor@sysoev.ru 161053Sigor@sysoev.ru engine = task->thread->engine; 161153Sigor@sysoev.ru c->read_work_queue = &engine->fast_work_queue; 161253Sigor@sysoev.ru c->write_work_queue = &engine->fast_work_queue; 161353Sigor@sysoev.ru 161453Sigor@sysoev.ru c->read_state = &nxt_router_conn_read_state; 161553Sigor@sysoev.ru 161662Sigor@sysoev.ru nxt_conn_read(engine, c); 161753Sigor@sysoev.ru } 161853Sigor@sysoev.ru 161953Sigor@sysoev.ru 162062Sigor@sysoev.ru static const nxt_conn_state_t nxt_router_conn_write_state 162153Sigor@sysoev.ru nxt_aligned(64) = 162253Sigor@sysoev.ru { 162388Smax.romanov@nginx.com .ready_handler = nxt_router_conn_ready, 162453Sigor@sysoev.ru .close_handler = nxt_router_conn_close, 162553Sigor@sysoev.ru .error_handler = nxt_router_conn_error, 162653Sigor@sysoev.ru }; 162753Sigor@sysoev.ru 162853Sigor@sysoev.ru 162953Sigor@sysoev.ru static void 1630119Smax.romanov@nginx.com nxt_router_app_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 163188Smax.romanov@nginx.com { 163288Smax.romanov@nginx.com size_t dump_size; 163388Smax.romanov@nginx.com nxt_buf_t *b, *i, *last; 163488Smax.romanov@nginx.com nxt_conn_t *c; 163588Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 163688Smax.romanov@nginx.com nxt_event_engine_t *engine; 163788Smax.romanov@nginx.com 163888Smax.romanov@nginx.com b = msg->buf; 163988Smax.romanov@nginx.com engine = task->thread->engine; 164088Smax.romanov@nginx.com 164188Smax.romanov@nginx.com rc = nxt_event_engine_request_find(engine, msg->port_msg.stream); 164288Smax.romanov@nginx.com if (nxt_slow_path(rc == NULL)) { 164388Smax.romanov@nginx.com 164488Smax.romanov@nginx.com nxt_debug(task, "request id %08uxD not found", msg->port_msg.stream); 164588Smax.romanov@nginx.com 164695Smax.romanov@nginx.com /* Mark buffers as read. */ 164788Smax.romanov@nginx.com for (i = b; i != NULL; i = i->next) { 164888Smax.romanov@nginx.com i->mem.pos = i->mem.free; 164988Smax.romanov@nginx.com } 165088Smax.romanov@nginx.com 165188Smax.romanov@nginx.com return; 165288Smax.romanov@nginx.com } 165388Smax.romanov@nginx.com 165488Smax.romanov@nginx.com c = rc->conn; 165588Smax.romanov@nginx.com 165688Smax.romanov@nginx.com dump_size = nxt_buf_used_size(b); 165788Smax.romanov@nginx.com 165888Smax.romanov@nginx.com if (dump_size > 300) { 165988Smax.romanov@nginx.com dump_size = 300; 166088Smax.romanov@nginx.com } 166188Smax.romanov@nginx.com 1662119Smax.romanov@nginx.com nxt_debug(task, "%srouter app data (%z): %*s", 166388Smax.romanov@nginx.com msg->port_msg.last ? "last " : "", msg->size, dump_size, 166488Smax.romanov@nginx.com b->mem.pos); 166588Smax.romanov@nginx.com 166688Smax.romanov@nginx.com if (msg->size == 0) { 166788Smax.romanov@nginx.com b = NULL; 166888Smax.romanov@nginx.com } 166988Smax.romanov@nginx.com 167088Smax.romanov@nginx.com if (msg->port_msg.last != 0) { 167188Smax.romanov@nginx.com nxt_debug(task, "router data create last buf"); 167288Smax.romanov@nginx.com 167388Smax.romanov@nginx.com last = nxt_buf_sync_alloc(c->mem_pool, NXT_BUF_SYNC_LAST); 167488Smax.romanov@nginx.com if (nxt_slow_path(last == NULL)) { 167588Smax.romanov@nginx.com /* TODO pogorevaTb */ 167688Smax.romanov@nginx.com } 167788Smax.romanov@nginx.com 167888Smax.romanov@nginx.com nxt_buf_chain_add(&b, last); 167988Smax.romanov@nginx.com } 168088Smax.romanov@nginx.com 168188Smax.romanov@nginx.com if (b == NULL) { 168288Smax.romanov@nginx.com return; 168388Smax.romanov@nginx.com } 168488Smax.romanov@nginx.com 168588Smax.romanov@nginx.com if (c->write == NULL) { 168688Smax.romanov@nginx.com c->write = b; 168788Smax.romanov@nginx.com c->write_state = &nxt_router_conn_write_state; 168888Smax.romanov@nginx.com 168988Smax.romanov@nginx.com nxt_conn_write(task->thread->engine, c); 169088Smax.romanov@nginx.com } else { 169188Smax.romanov@nginx.com nxt_debug(task, "router data attach out bufs to existing chain"); 169288Smax.romanov@nginx.com 169388Smax.romanov@nginx.com nxt_buf_chain_add(&c->write, b); 169488Smax.romanov@nginx.com } 169588Smax.romanov@nginx.com } 169688Smax.romanov@nginx.com 1697141Smax.romanov@nginx.com nxt_inline const char * 1698141Smax.romanov@nginx.com nxt_router_text_by_code(int code) 1699141Smax.romanov@nginx.com { 1700141Smax.romanov@nginx.com switch (code) { 1701141Smax.romanov@nginx.com case 400: return "Bad request"; 1702141Smax.romanov@nginx.com case 404: return "Not found"; 1703141Smax.romanov@nginx.com case 403: return "Forbidden"; 1704141Smax.romanov@nginx.com case 500: 1705141Smax.romanov@nginx.com default: return "Internal server error"; 1706141Smax.romanov@nginx.com } 1707141Smax.romanov@nginx.com } 1708141Smax.romanov@nginx.com 1709*163Smax.romanov@nginx.com 1710*163Smax.romanov@nginx.com static nxt_buf_t * 1711*163Smax.romanov@nginx.com nxt_router_get_error_buf(nxt_task_t *task, nxt_mp_t *mp, int code, 1712*163Smax.romanov@nginx.com const char* fmt, va_list args) 171388Smax.romanov@nginx.com { 1714*163Smax.romanov@nginx.com nxt_buf_t *b, *last; 1715*163Smax.romanov@nginx.com const char *msg; 1716*163Smax.romanov@nginx.com 1717*163Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, mp, 16384); 1718141Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 1719*163Smax.romanov@nginx.com return NULL; 1720141Smax.romanov@nginx.com } 1721141Smax.romanov@nginx.com 1722141Smax.romanov@nginx.com b->mem.free = nxt_sprintf(b->mem.free, b->mem.end, 1723141Smax.romanov@nginx.com "HTTP/1.0 %d %s\r\n" 1724141Smax.romanov@nginx.com "Content-Type: text/plain\r\n" 1725141Smax.romanov@nginx.com "Connection: close\r\n\r\n", 1726141Smax.romanov@nginx.com code, nxt_router_text_by_code(code)); 1727141Smax.romanov@nginx.com 1728141Smax.romanov@nginx.com msg = (const char *) b->mem.free; 1729141Smax.romanov@nginx.com 1730141Smax.romanov@nginx.com b->mem.free = nxt_vsprintf(b->mem.free, b->mem.end, fmt, args); 1731141Smax.romanov@nginx.com 1732141Smax.romanov@nginx.com nxt_log_alert(task->log, "error %d: %s", code, msg); 1733141Smax.romanov@nginx.com 1734*163Smax.romanov@nginx.com last = nxt_buf_mem_ts_alloc(task, mp, 0); 1735*163Smax.romanov@nginx.com 1736141Smax.romanov@nginx.com if (nxt_slow_path(last == NULL)) { 1737*163Smax.romanov@nginx.com nxt_mp_release(mp, b); 1738*163Smax.romanov@nginx.com return NULL; 1739141Smax.romanov@nginx.com } 1740141Smax.romanov@nginx.com 1741*163Smax.romanov@nginx.com nxt_buf_set_sync(last); 1742*163Smax.romanov@nginx.com nxt_buf_set_last(last); 1743*163Smax.romanov@nginx.com 1744141Smax.romanov@nginx.com nxt_buf_chain_add(&b, last); 1745141Smax.romanov@nginx.com 1746*163Smax.romanov@nginx.com return b; 1747*163Smax.romanov@nginx.com } 1748*163Smax.romanov@nginx.com 1749*163Smax.romanov@nginx.com 1750*163Smax.romanov@nginx.com 1751*163Smax.romanov@nginx.com static void 1752*163Smax.romanov@nginx.com nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code, 1753*163Smax.romanov@nginx.com const char* fmt, ...) 1754*163Smax.romanov@nginx.com { 1755*163Smax.romanov@nginx.com va_list args; 1756*163Smax.romanov@nginx.com nxt_buf_t *b; 1757*163Smax.romanov@nginx.com 1758*163Smax.romanov@nginx.com va_start(args, fmt); 1759*163Smax.romanov@nginx.com b = nxt_router_get_error_buf(task, c->mem_pool, code, fmt, args); 1760*163Smax.romanov@nginx.com va_end(args); 1761*163Smax.romanov@nginx.com 1762141Smax.romanov@nginx.com if (c->write == NULL) { 1763141Smax.romanov@nginx.com c->write = b; 1764141Smax.romanov@nginx.com c->write_state = &nxt_router_conn_write_state; 1765141Smax.romanov@nginx.com 1766141Smax.romanov@nginx.com nxt_conn_write(task->thread->engine, c); 1767141Smax.romanov@nginx.com } else { 1768141Smax.romanov@nginx.com nxt_debug(task, "router data attach out bufs to existing chain"); 1769141Smax.romanov@nginx.com 1770141Smax.romanov@nginx.com nxt_buf_chain_add(&c->write, b); 1771141Smax.romanov@nginx.com } 1772141Smax.romanov@nginx.com } 1773141Smax.romanov@nginx.com 1774141Smax.romanov@nginx.com 1775141Smax.romanov@nginx.com static void 1776141Smax.romanov@nginx.com nxt_router_send_sw_request(nxt_task_t *task, void *obj, void *data) 1777141Smax.romanov@nginx.com { 1778141Smax.romanov@nginx.com nxt_buf_t *b; 1779141Smax.romanov@nginx.com nxt_app_t *app; 1780141Smax.romanov@nginx.com nxt_port_t *port; 1781141Smax.romanov@nginx.com nxt_runtime_t *rt; 1782141Smax.romanov@nginx.com nxt_start_worker_t *sw; 1783141Smax.romanov@nginx.com 1784141Smax.romanov@nginx.com sw = obj; 1785141Smax.romanov@nginx.com app = sw->app; 1786141Smax.romanov@nginx.com 1787*163Smax.romanov@nginx.com if (app->workers + app->pending_workers >= app->max_workers) { 1788*163Smax.romanov@nginx.com sw->work.handler = nxt_router_sw_release; 1789*163Smax.romanov@nginx.com 1790*163Smax.romanov@nginx.com nxt_debug(task, "%uD/%uD running/penging workers, post sw #%uxD " 1791*163Smax.romanov@nginx.com "release to %p", sw->stream, sw->work.data); 1792*163Smax.romanov@nginx.com 1793*163Smax.romanov@nginx.com nxt_event_engine_post(sw->work.data, &sw->work); 1794*163Smax.romanov@nginx.com 1795*163Smax.romanov@nginx.com return; 1796*163Smax.romanov@nginx.com } 1797*163Smax.romanov@nginx.com 1798*163Smax.romanov@nginx.com app->pending_workers++; 1799*163Smax.romanov@nginx.com 1800141Smax.romanov@nginx.com nxt_debug(task, "send sw #%uD", sw->stream); 1801141Smax.romanov@nginx.com 1802141Smax.romanov@nginx.com nxt_router_sw_add(task, nxt_router, sw); 1803141Smax.romanov@nginx.com nxt_queue_insert_tail(&app->requests, &sw->rc->app_link); 180488Smax.romanov@nginx.com 1805119Smax.romanov@nginx.com rt = task->thread->runtime; 1806141Smax.romanov@nginx.com port = rt->port_by_type[NXT_PROCESS_MASTER]; 1807141Smax.romanov@nginx.com 1808141Smax.romanov@nginx.com b = nxt_buf_mem_alloc(port->mem_pool, app->conf.length, 0); 1809141Smax.romanov@nginx.com 1810141Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 1811141Smax.romanov@nginx.com 1812141Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_DATA, -1, sw->stream, 0, b); 1813141Smax.romanov@nginx.com } 1814141Smax.romanov@nginx.com 1815141Smax.romanov@nginx.com 1816*163Smax.romanov@nginx.com static nxt_bool_t 1817*163Smax.romanov@nginx.com nxt_router_app_free(nxt_app_t *app) 1818*163Smax.romanov@nginx.com { 1819*163Smax.romanov@nginx.com if (app->live == 0 && app->workers == 0 && 1820*163Smax.romanov@nginx.com app->pending_workers == 0 && 1821*163Smax.romanov@nginx.com nxt_queue_is_empty(&app->requests)) { 1822*163Smax.romanov@nginx.com 1823*163Smax.romanov@nginx.com nxt_thread_mutex_destroy(&app->mutex); 1824*163Smax.romanov@nginx.com nxt_free(app); 1825*163Smax.romanov@nginx.com 1826*163Smax.romanov@nginx.com return 1; 1827*163Smax.romanov@nginx.com } 1828*163Smax.romanov@nginx.com 1829*163Smax.romanov@nginx.com return 0; 1830*163Smax.romanov@nginx.com } 1831*163Smax.romanov@nginx.com 1832*163Smax.romanov@nginx.com 1833141Smax.romanov@nginx.com static nxt_port_t * 1834141Smax.romanov@nginx.com nxt_router_app_get_port(nxt_app_t *app) 1835141Smax.romanov@nginx.com { 1836141Smax.romanov@nginx.com nxt_port_t *port; 1837141Smax.romanov@nginx.com nxt_queue_link_t *lnk; 1838141Smax.romanov@nginx.com 1839141Smax.romanov@nginx.com port = NULL; 1840141Smax.romanov@nginx.com 1841141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 1842141Smax.romanov@nginx.com 1843141Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->ports)) { 1844141Smax.romanov@nginx.com lnk = nxt_queue_first(&app->ports); 1845141Smax.romanov@nginx.com nxt_queue_remove(lnk); 1846141Smax.romanov@nginx.com 1847141Smax.romanov@nginx.com lnk->next = NULL; 1848141Smax.romanov@nginx.com 1849141Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, app_link); 1850141Smax.romanov@nginx.com } 1851141Smax.romanov@nginx.com 1852141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 1853141Smax.romanov@nginx.com 1854141Smax.romanov@nginx.com return port; 1855141Smax.romanov@nginx.com } 1856141Smax.romanov@nginx.com 1857141Smax.romanov@nginx.com 1858141Smax.romanov@nginx.com static void 1859141Smax.romanov@nginx.com nxt_router_app_release_port(nxt_task_t *task, void *obj, void *data) 1860141Smax.romanov@nginx.com { 1861141Smax.romanov@nginx.com nxt_app_t *app; 1862141Smax.romanov@nginx.com nxt_port_t *port; 1863141Smax.romanov@nginx.com nxt_work_t *work; 1864*163Smax.romanov@nginx.com nxt_process_t *process; 1865141Smax.romanov@nginx.com nxt_queue_link_t *lnk; 1866141Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 1867141Smax.romanov@nginx.com 1868141Smax.romanov@nginx.com port = obj; 1869141Smax.romanov@nginx.com app = data; 1870141Smax.romanov@nginx.com 1871141Smax.romanov@nginx.com nxt_assert(app != NULL); 1872141Smax.romanov@nginx.com nxt_assert(app == port->app); 1873141Smax.romanov@nginx.com nxt_assert(port->app_link.next == NULL); 1874141Smax.romanov@nginx.com 1875141Smax.romanov@nginx.com 1876141Smax.romanov@nginx.com if (task->thread->engine != port->engine) { 1877*163Smax.romanov@nginx.com work = &port->work; 1878141Smax.romanov@nginx.com 1879141Smax.romanov@nginx.com nxt_debug(task, "post release port to engine %p", port->engine); 1880141Smax.romanov@nginx.com 1881141Smax.romanov@nginx.com work->next = NULL; 1882141Smax.romanov@nginx.com work->handler = nxt_router_app_release_port; 1883141Smax.romanov@nginx.com work->task = port->socket.task; 1884141Smax.romanov@nginx.com work->obj = port; 1885141Smax.romanov@nginx.com work->data = app; 1886141Smax.romanov@nginx.com 1887141Smax.romanov@nginx.com nxt_event_engine_post(port->engine, work); 1888141Smax.romanov@nginx.com 1889141Smax.romanov@nginx.com return; 1890141Smax.romanov@nginx.com } 1891141Smax.romanov@nginx.com 1892141Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->requests)) { 1893141Smax.romanov@nginx.com lnk = nxt_queue_first(&app->requests); 1894141Smax.romanov@nginx.com nxt_queue_remove(lnk); 1895141Smax.romanov@nginx.com 1896141Smax.romanov@nginx.com rc = nxt_queue_link_data(lnk, nxt_req_conn_link_t, app_link); 1897141Smax.romanov@nginx.com 1898*163Smax.romanov@nginx.com nxt_debug(task, "app '%V' process next request #%uxD", 1899*163Smax.romanov@nginx.com &app->name, rc->req_id); 1900141Smax.romanov@nginx.com 1901141Smax.romanov@nginx.com rc->app_port = port; 1902141Smax.romanov@nginx.com 1903141Smax.romanov@nginx.com nxt_router_process_http_request_mp(task, rc, rc->app_port->mem_pool); 1904141Smax.romanov@nginx.com 1905141Smax.romanov@nginx.com return; 1906141Smax.romanov@nginx.com } 1907141Smax.romanov@nginx.com 1908*163Smax.romanov@nginx.com if (port->pair[1] == -1) { 1909*163Smax.romanov@nginx.com nxt_debug(task, "app '%V' port already closed (pid %PI dead?)", 1910*163Smax.romanov@nginx.com &app->name, port->pid); 1911*163Smax.romanov@nginx.com 1912*163Smax.romanov@nginx.com app->workers--; 1913*163Smax.romanov@nginx.com nxt_router_app_free(app); 1914*163Smax.romanov@nginx.com 1915*163Smax.romanov@nginx.com port->app = NULL; 1916*163Smax.romanov@nginx.com process = port->process; 1917*163Smax.romanov@nginx.com 1918*163Smax.romanov@nginx.com nxt_port_release(port); 1919*163Smax.romanov@nginx.com 1920*163Smax.romanov@nginx.com if (nxt_queue_is_empty(&process->ports)) { 1921*163Smax.romanov@nginx.com nxt_runtime_process_destroy(task->thread->runtime, process); 1922*163Smax.romanov@nginx.com } 1923*163Smax.romanov@nginx.com 1924*163Smax.romanov@nginx.com return; 1925*163Smax.romanov@nginx.com } 1926*163Smax.romanov@nginx.com 1927*163Smax.romanov@nginx.com if (!app->live) { 1928*163Smax.romanov@nginx.com nxt_debug(task, "app '%V' is not alive, send QUIT to port", 1929*163Smax.romanov@nginx.com &app->name); 1930*163Smax.romanov@nginx.com 1931*163Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, 1932*163Smax.romanov@nginx.com -1, 0, 0, NULL); 1933*163Smax.romanov@nginx.com 1934*163Smax.romanov@nginx.com return; 1935*163Smax.romanov@nginx.com } 1936*163Smax.romanov@nginx.com 1937*163Smax.romanov@nginx.com nxt_debug(task, "app '%V' requests queue is empty, keep the port", 1938*163Smax.romanov@nginx.com &app->name); 1939141Smax.romanov@nginx.com 1940141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 1941141Smax.romanov@nginx.com 1942141Smax.romanov@nginx.com nxt_queue_insert_head(&app->ports, &port->app_link); 1943141Smax.romanov@nginx.com 1944141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 1945141Smax.romanov@nginx.com } 1946141Smax.romanov@nginx.com 1947141Smax.romanov@nginx.com 1948*163Smax.romanov@nginx.com nxt_bool_t 1949141Smax.romanov@nginx.com nxt_router_app_remove_port(nxt_port_t *port) 1950141Smax.romanov@nginx.com { 1951*163Smax.romanov@nginx.com nxt_app_t *app; 1952*163Smax.romanov@nginx.com nxt_bool_t busy; 1953141Smax.romanov@nginx.com 1954141Smax.romanov@nginx.com app = port->app; 1955*163Smax.romanov@nginx.com busy = 1; 1956*163Smax.romanov@nginx.com 1957*163Smax.romanov@nginx.com if (app == NULL) { 1958*163Smax.romanov@nginx.com nxt_assert(port->app_link.next == NULL); 1959*163Smax.romanov@nginx.com 1960*163Smax.romanov@nginx.com return 1; 1961141Smax.romanov@nginx.com } 1962141Smax.romanov@nginx.com 1963141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 1964141Smax.romanov@nginx.com 1965*163Smax.romanov@nginx.com if (port->app_link.next != NULL) { 1966*163Smax.romanov@nginx.com 1967*163Smax.romanov@nginx.com nxt_queue_remove(&port->app_link); 1968*163Smax.romanov@nginx.com port->app_link.next = NULL; 1969*163Smax.romanov@nginx.com 1970*163Smax.romanov@nginx.com busy = 0; 1971*163Smax.romanov@nginx.com } 1972141Smax.romanov@nginx.com 1973141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 1974*163Smax.romanov@nginx.com 1975*163Smax.romanov@nginx.com if (busy == 0) { 1976*163Smax.romanov@nginx.com 1977*163Smax.romanov@nginx.com app->workers--; 1978*163Smax.romanov@nginx.com nxt_router_app_free(app); 1979*163Smax.romanov@nginx.com 1980*163Smax.romanov@nginx.com return 1; 1981*163Smax.romanov@nginx.com } 1982*163Smax.romanov@nginx.com 1983*163Smax.romanov@nginx.com return 0; 1984141Smax.romanov@nginx.com } 1985141Smax.romanov@nginx.com 1986141Smax.romanov@nginx.com 1987141Smax.romanov@nginx.com nxt_inline nxt_int_t 1988141Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_req_conn_link_t *rc) 1989141Smax.romanov@nginx.com { 1990141Smax.romanov@nginx.com nxt_app_t *app; 1991141Smax.romanov@nginx.com nxt_conn_t *c; 1992141Smax.romanov@nginx.com nxt_port_t *port, *master_port; 1993141Smax.romanov@nginx.com nxt_runtime_t *rt; 1994141Smax.romanov@nginx.com nxt_start_worker_t *sw; 1995141Smax.romanov@nginx.com nxt_socket_conf_joint_t *joint; 1996141Smax.romanov@nginx.com 1997141Smax.romanov@nginx.com port = NULL; 1998141Smax.romanov@nginx.com c = rc->conn; 1999141Smax.romanov@nginx.com 2000141Smax.romanov@nginx.com joint = c->listen->socket.data; 2001141Smax.romanov@nginx.com app = joint->socket_conf->application; 2002141Smax.romanov@nginx.com 2003141Smax.romanov@nginx.com 2004141Smax.romanov@nginx.com if (app == NULL) { 2005141Smax.romanov@nginx.com nxt_router_gen_error(task, rc->conn, 500, 2006141Smax.romanov@nginx.com "Application is NULL in socket_conf"); 2007141Smax.romanov@nginx.com return NXT_ERROR; 2008141Smax.romanov@nginx.com } 2009141Smax.romanov@nginx.com 2010141Smax.romanov@nginx.com 2011141Smax.romanov@nginx.com port = nxt_router_app_get_port(app); 2012141Smax.romanov@nginx.com 2013141Smax.romanov@nginx.com if (port != NULL) { 2014*163Smax.romanov@nginx.com nxt_debug(task, "already have port for app '%V'", &app->name); 2015*163Smax.romanov@nginx.com 2016141Smax.romanov@nginx.com rc->app_port = port; 2017141Smax.romanov@nginx.com return NXT_OK; 2018141Smax.romanov@nginx.com } 2019141Smax.romanov@nginx.com 2020141Smax.romanov@nginx.com sw = nxt_mp_retain(c->mem_pool, sizeof(nxt_start_worker_t)); 2021141Smax.romanov@nginx.com 2022141Smax.romanov@nginx.com if (nxt_slow_path(sw == NULL)) { 2023141Smax.romanov@nginx.com nxt_router_gen_error(task, rc->conn, 500, 2024141Smax.romanov@nginx.com "Failed to allocate start worker struct"); 2025141Smax.romanov@nginx.com return NXT_ERROR; 2026141Smax.romanov@nginx.com } 2027141Smax.romanov@nginx.com 2028141Smax.romanov@nginx.com nxt_memzero(sw, sizeof(nxt_start_worker_t)); 2029141Smax.romanov@nginx.com 2030141Smax.romanov@nginx.com sw->stream = nxt_random(&task->thread->random); 2031141Smax.romanov@nginx.com sw->app = app; 2032141Smax.romanov@nginx.com sw->rc = rc; 2033141Smax.romanov@nginx.com sw->mem_pool = c->mem_pool; 2034141Smax.romanov@nginx.com sw->joint = c->listen->socket.data; 2035141Smax.romanov@nginx.com 2036141Smax.romanov@nginx.com sw->work.handler = nxt_router_send_sw_request; 2037141Smax.romanov@nginx.com sw->work.task = task; 2038141Smax.romanov@nginx.com sw->work.obj = sw; 2039141Smax.romanov@nginx.com sw->work.data = task->thread->engine; 2040141Smax.romanov@nginx.com 2041141Smax.romanov@nginx.com rt = task->thread->runtime; 2042141Smax.romanov@nginx.com 2043141Smax.romanov@nginx.com master_port = rt->port_by_type[NXT_PROCESS_MASTER]; 2044141Smax.romanov@nginx.com 2045141Smax.romanov@nginx.com nxt_debug(task, "post send sw %uxD to master engine %p", sw->stream, 2046141Smax.romanov@nginx.com master_port->engine); 2047141Smax.romanov@nginx.com 2048141Smax.romanov@nginx.com nxt_event_engine_post(master_port->engine, &sw->work); 2049141Smax.romanov@nginx.com 2050141Smax.romanov@nginx.com return NXT_AGAIN; 205188Smax.romanov@nginx.com } 205288Smax.romanov@nginx.com 205388Smax.romanov@nginx.com 205488Smax.romanov@nginx.com static void 205553Sigor@sysoev.ru nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, void *data) 205653Sigor@sysoev.ru { 205788Smax.romanov@nginx.com size_t size, preread; 205853Sigor@sysoev.ru nxt_int_t ret; 205953Sigor@sysoev.ru nxt_buf_t *b; 206062Sigor@sysoev.ru nxt_conn_t *c; 206188Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 206253Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 206388Smax.romanov@nginx.com nxt_app_request_header_t *h; 206453Sigor@sysoev.ru 206553Sigor@sysoev.ru c = obj; 206688Smax.romanov@nginx.com ap = data; 206788Smax.romanov@nginx.com b = c->read; 206853Sigor@sysoev.ru 206953Sigor@sysoev.ru nxt_debug(task, "router conn http header parse"); 207053Sigor@sysoev.ru 207188Smax.romanov@nginx.com if (ap == NULL) { 207288Smax.romanov@nginx.com ap = nxt_mp_zget(c->mem_pool, sizeof(nxt_app_parse_ctx_t)); 207388Smax.romanov@nginx.com if (nxt_slow_path(ap == NULL)) { 207453Sigor@sysoev.ru nxt_router_conn_close(task, c, data); 207553Sigor@sysoev.ru return; 207653Sigor@sysoev.ru } 207753Sigor@sysoev.ru 207888Smax.romanov@nginx.com ret = nxt_app_http_req_init(task, ap); 207961Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 208061Sigor@sysoev.ru nxt_router_conn_close(task, c, data); 208161Sigor@sysoev.ru return; 208261Sigor@sysoev.ru } 208388Smax.romanov@nginx.com 208488Smax.romanov@nginx.com c->socket.data = ap; 2085113Smax.romanov@nginx.com 2086113Smax.romanov@nginx.com ap->r.remote.start = nxt_sockaddr_address(c->remote); 2087113Smax.romanov@nginx.com ap->r.remote.length = c->remote->address_length; 208853Sigor@sysoev.ru } 208953Sigor@sysoev.ru 209088Smax.romanov@nginx.com h = &ap->r.header; 209188Smax.romanov@nginx.com 209288Smax.romanov@nginx.com ret = nxt_app_http_req_parse(task, ap, b); 209353Sigor@sysoev.ru 209453Sigor@sysoev.ru nxt_debug(task, "http parse request: %d", ret); 209553Sigor@sysoev.ru 209653Sigor@sysoev.ru switch (nxt_expect(NXT_DONE, ret)) { 209753Sigor@sysoev.ru 209853Sigor@sysoev.ru case NXT_DONE: 209988Smax.romanov@nginx.com preread = nxt_buf_mem_used_size(&b->mem); 210088Smax.romanov@nginx.com 210188Smax.romanov@nginx.com nxt_debug(task, "router request header parsing complete, " 210288Smax.romanov@nginx.com "content length: %O, preread: %uz", 210388Smax.romanov@nginx.com h->parsed_content_length, preread); 210488Smax.romanov@nginx.com 210588Smax.romanov@nginx.com nxt_router_process_http_request(task, c, ap); 210688Smax.romanov@nginx.com return; 210753Sigor@sysoev.ru 210853Sigor@sysoev.ru case NXT_ERROR: 210953Sigor@sysoev.ru nxt_router_conn_close(task, c, data); 211053Sigor@sysoev.ru return; 211153Sigor@sysoev.ru 211253Sigor@sysoev.ru default: /* NXT_AGAIN */ 211353Sigor@sysoev.ru 211488Smax.romanov@nginx.com if (h->done == 0) { 211588Smax.romanov@nginx.com 211688Smax.romanov@nginx.com if (c->read->mem.free == c->read->mem.end) { 211788Smax.romanov@nginx.com joint = c->listen->socket.data; 211888Smax.romanov@nginx.com size = joint->socket_conf->large_header_buffer_size; 211988Smax.romanov@nginx.com 212088Smax.romanov@nginx.com if (size > (size_t) nxt_buf_mem_size(&b->mem)) { 212188Smax.romanov@nginx.com b = nxt_buf_mem_alloc(c->mem_pool, size, 0); 212288Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 212388Smax.romanov@nginx.com nxt_router_conn_close(task, c, data); 212488Smax.romanov@nginx.com return; 212588Smax.romanov@nginx.com } 212688Smax.romanov@nginx.com 212788Smax.romanov@nginx.com size = c->read->mem.free - c->read->mem.pos; 2128141Smax.romanov@nginx.com 2129141Smax.romanov@nginx.com c->read = nxt_buf_cpy(b, c->read->mem.pos, size); 213088Smax.romanov@nginx.com } else { 2131141Smax.romanov@nginx.com nxt_router_gen_error(task, c, 400, 2132141Smax.romanov@nginx.com "Too long request headers"); 2133141Smax.romanov@nginx.com return; 213488Smax.romanov@nginx.com } 213588Smax.romanov@nginx.com } 213688Smax.romanov@nginx.com } 213788Smax.romanov@nginx.com 213888Smax.romanov@nginx.com if (ap->r.body.done == 0) { 213988Smax.romanov@nginx.com 214088Smax.romanov@nginx.com preread = nxt_buf_mem_used_size(&b->mem); 214188Smax.romanov@nginx.com 214288Smax.romanov@nginx.com if (h->parsed_content_length - preread > 214388Smax.romanov@nginx.com (size_t) nxt_buf_mem_free_size(&b->mem)) { 214488Smax.romanov@nginx.com 214588Smax.romanov@nginx.com b = nxt_buf_mem_alloc(c->mem_pool, h->parsed_content_length, 0); 214688Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 2147141Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Failed to allocate " 2148141Smax.romanov@nginx.com "buffer for request body"); 2149141Smax.romanov@nginx.com return; 215088Smax.romanov@nginx.com } 215188Smax.romanov@nginx.com 2152141Smax.romanov@nginx.com c->read = nxt_buf_cpy(b, c->read->mem.pos, preread); 215353Sigor@sysoev.ru } 215453Sigor@sysoev.ru 215588Smax.romanov@nginx.com nxt_debug(task, "router request body read again, rest: %uz", 215688Smax.romanov@nginx.com h->parsed_content_length - preread); 215753Sigor@sysoev.ru 215853Sigor@sysoev.ru } 215953Sigor@sysoev.ru 216088Smax.romanov@nginx.com } 216188Smax.romanov@nginx.com 216288Smax.romanov@nginx.com nxt_conn_read(task->thread->engine, c); 216388Smax.romanov@nginx.com } 216488Smax.romanov@nginx.com 216588Smax.romanov@nginx.com 216688Smax.romanov@nginx.com static void 216788Smax.romanov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_conn_t *c, 216888Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap) 216988Smax.romanov@nginx.com { 2170122Smax.romanov@nginx.com nxt_int_t res; 217188Smax.romanov@nginx.com nxt_req_id_t req_id; 217288Smax.romanov@nginx.com nxt_event_engine_t *engine; 217388Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 217488Smax.romanov@nginx.com 217588Smax.romanov@nginx.com engine = task->thread->engine; 217688Smax.romanov@nginx.com 217788Smax.romanov@nginx.com do { 2178138Sigor@sysoev.ru req_id = nxt_random(&task->thread->random); 217988Smax.romanov@nginx.com } while (nxt_event_engine_request_find(engine, req_id) != NULL); 218088Smax.romanov@nginx.com 218188Smax.romanov@nginx.com rc = nxt_conn_request_add(c, req_id); 2182122Smax.romanov@nginx.com 218388Smax.romanov@nginx.com if (nxt_slow_path(rc == NULL)) { 2184141Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Failed to allocate " 2185141Smax.romanov@nginx.com "req->conn link"); 2186141Smax.romanov@nginx.com 2187141Smax.romanov@nginx.com return; 218888Smax.romanov@nginx.com } 218988Smax.romanov@nginx.com 2190*163Smax.romanov@nginx.com rc->ap = ap; 2191*163Smax.romanov@nginx.com 219288Smax.romanov@nginx.com nxt_event_engine_request_add(engine, rc); 219388Smax.romanov@nginx.com 219488Smax.romanov@nginx.com nxt_debug(task, "req_id %uxD linked to conn %p at engine %p", 219588Smax.romanov@nginx.com req_id, c, engine); 219653Sigor@sysoev.ru 2197141Smax.romanov@nginx.com rc->reply_port = engine->port; 2198141Smax.romanov@nginx.com 2199141Smax.romanov@nginx.com res = nxt_router_app_port(task, rc); 2200141Smax.romanov@nginx.com 2201141Smax.romanov@nginx.com if (res != NXT_OK) { 2202141Smax.romanov@nginx.com return; 2203141Smax.romanov@nginx.com } 2204141Smax.romanov@nginx.com 2205141Smax.romanov@nginx.com nxt_router_process_http_request_mp(task, rc, c->mem_pool); 2206141Smax.romanov@nginx.com } 2207141Smax.romanov@nginx.com 2208141Smax.romanov@nginx.com 2209141Smax.romanov@nginx.com static void 2210141Smax.romanov@nginx.com nxt_router_process_http_request_mp(nxt_task_t *task, nxt_req_conn_link_t *rc, 2211141Smax.romanov@nginx.com nxt_mp_t *mp) 2212141Smax.romanov@nginx.com { 2213141Smax.romanov@nginx.com nxt_mp_t *port_mp; 2214141Smax.romanov@nginx.com nxt_int_t res; 2215141Smax.romanov@nginx.com nxt_port_t *port, *c_port, *reply_port; 2216141Smax.romanov@nginx.com nxt_app_wmsg_t wmsg; 2217141Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 2218141Smax.romanov@nginx.com 2219141Smax.romanov@nginx.com port = rc->app_port; 2220141Smax.romanov@nginx.com 2221141Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 2222141Smax.romanov@nginx.com nxt_router_gen_error(task, rc->conn, 500, "Application port not found"); 2223141Smax.romanov@nginx.com return; 2224141Smax.romanov@nginx.com } 2225141Smax.romanov@nginx.com 2226141Smax.romanov@nginx.com reply_port = rc->reply_port; 2227*163Smax.romanov@nginx.com ap = rc->ap; 2228141Smax.romanov@nginx.com 2229122Smax.romanov@nginx.com port_mp = port->mem_pool; 2230141Smax.romanov@nginx.com port->mem_pool = mp; 2231141Smax.romanov@nginx.com 2232141Smax.romanov@nginx.com c_port = nxt_process_connected_port_find(port->process, reply_port->pid, 2233141Smax.romanov@nginx.com reply_port->id); 2234141Smax.romanov@nginx.com if (nxt_slow_path(c_port != reply_port)) { 2235141Smax.romanov@nginx.com res = nxt_port_send_port(task, port, reply_port, 0); 2236122Smax.romanov@nginx.com 2237122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 2238141Smax.romanov@nginx.com nxt_router_gen_error(task, rc->conn, 500, 2239141Smax.romanov@nginx.com "Failed to send reply port to application"); 2240141Smax.romanov@nginx.com goto fail; 2241122Smax.romanov@nginx.com } 2242122Smax.romanov@nginx.com 2243141Smax.romanov@nginx.com nxt_process_connected_port_add(port->process, reply_port); 224488Smax.romanov@nginx.com } 224588Smax.romanov@nginx.com 224688Smax.romanov@nginx.com wmsg.port = port; 224788Smax.romanov@nginx.com wmsg.write = NULL; 224888Smax.romanov@nginx.com wmsg.buf = &wmsg.write; 2249141Smax.romanov@nginx.com wmsg.stream = rc->req_id; 2250141Smax.romanov@nginx.com 2251141Smax.romanov@nginx.com res = rc->app_port->app->module->prepare_msg(task, &ap->r, &wmsg); 2252122Smax.romanov@nginx.com 2253122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 2254141Smax.romanov@nginx.com nxt_router_gen_error(task, rc->conn, 500, 2255141Smax.romanov@nginx.com "Failed to prepare message for application"); 2256141Smax.romanov@nginx.com goto fail; 2257122Smax.romanov@nginx.com } 225888Smax.romanov@nginx.com 225988Smax.romanov@nginx.com nxt_debug(task, "about to send %d bytes buffer to worker port %d", 226088Smax.romanov@nginx.com nxt_buf_used_size(wmsg.write), 226188Smax.romanov@nginx.com wmsg.port->socket.fd); 226288Smax.romanov@nginx.com 2263122Smax.romanov@nginx.com res = nxt_port_socket_write(task, wmsg.port, NXT_PORT_MSG_DATA, 2264141Smax.romanov@nginx.com -1, rc->req_id, reply_port->id, wmsg.write); 2265122Smax.romanov@nginx.com 2266122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 2267141Smax.romanov@nginx.com nxt_router_gen_error(task, rc->conn, 500, 2268141Smax.romanov@nginx.com "Failed to send message to application"); 2269141Smax.romanov@nginx.com goto fail; 2270122Smax.romanov@nginx.com } 2271122Smax.romanov@nginx.com 2272141Smax.romanov@nginx.com fail: 2273122Smax.romanov@nginx.com port->mem_pool = port_mp; 227453Sigor@sysoev.ru } 227553Sigor@sysoev.ru 227653Sigor@sysoev.ru 227762Sigor@sysoev.ru static const nxt_conn_state_t nxt_router_conn_close_state 227853Sigor@sysoev.ru nxt_aligned(64) = 227953Sigor@sysoev.ru { 228053Sigor@sysoev.ru .ready_handler = nxt_router_conn_free, 228153Sigor@sysoev.ru }; 228253Sigor@sysoev.ru 228353Sigor@sysoev.ru 228453Sigor@sysoev.ru static void 228588Smax.romanov@nginx.com nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data) 228688Smax.romanov@nginx.com { 228788Smax.romanov@nginx.com nxt_buf_t *b; 228888Smax.romanov@nginx.com nxt_bool_t last; 228988Smax.romanov@nginx.com nxt_conn_t *c; 229088Smax.romanov@nginx.com nxt_work_queue_t *wq; 229188Smax.romanov@nginx.com 229288Smax.romanov@nginx.com nxt_debug(task, "router conn ready %p", obj); 229388Smax.romanov@nginx.com 229488Smax.romanov@nginx.com c = obj; 229588Smax.romanov@nginx.com b = c->write; 229688Smax.romanov@nginx.com 229788Smax.romanov@nginx.com wq = &task->thread->engine->fast_work_queue; 229888Smax.romanov@nginx.com 229988Smax.romanov@nginx.com last = 0; 230088Smax.romanov@nginx.com 230188Smax.romanov@nginx.com while (b != NULL) { 230288Smax.romanov@nginx.com if (!nxt_buf_is_sync(b)) { 230388Smax.romanov@nginx.com if (nxt_buf_used_size(b) > 0) { 230488Smax.romanov@nginx.com break; 230588Smax.romanov@nginx.com } 230688Smax.romanov@nginx.com } 230788Smax.romanov@nginx.com 230888Smax.romanov@nginx.com if (nxt_buf_is_last(b)) { 230988Smax.romanov@nginx.com last = 1; 231088Smax.romanov@nginx.com } 231188Smax.romanov@nginx.com 231288Smax.romanov@nginx.com nxt_work_queue_add(wq, b->completion_handler, task, b, b->parent); 231388Smax.romanov@nginx.com 231488Smax.romanov@nginx.com b = b->next; 231588Smax.romanov@nginx.com } 231688Smax.romanov@nginx.com 231788Smax.romanov@nginx.com c->write = b; 231888Smax.romanov@nginx.com 231988Smax.romanov@nginx.com if (b != NULL) { 232088Smax.romanov@nginx.com nxt_debug(task, "router conn %p has more data to write", obj); 232188Smax.romanov@nginx.com 232288Smax.romanov@nginx.com nxt_conn_write(task->thread->engine, c); 232388Smax.romanov@nginx.com } else { 232488Smax.romanov@nginx.com nxt_debug(task, "router conn %p no more data to write, last = %d", obj, 232588Smax.romanov@nginx.com last); 232688Smax.romanov@nginx.com 232788Smax.romanov@nginx.com if (last != 0) { 232888Smax.romanov@nginx.com nxt_debug(task, "enqueue router conn close %p (ready handler)", c); 232988Smax.romanov@nginx.com 233088Smax.romanov@nginx.com nxt_work_queue_add(wq, nxt_router_conn_close, task, c, 233188Smax.romanov@nginx.com c->socket.data); 233288Smax.romanov@nginx.com } 233388Smax.romanov@nginx.com } 233488Smax.romanov@nginx.com } 233588Smax.romanov@nginx.com 233688Smax.romanov@nginx.com 233788Smax.romanov@nginx.com static void 233853Sigor@sysoev.ru nxt_router_conn_close(nxt_task_t *task, void *obj, void *data) 233953Sigor@sysoev.ru { 234062Sigor@sysoev.ru nxt_conn_t *c; 234153Sigor@sysoev.ru 234253Sigor@sysoev.ru c = obj; 234353Sigor@sysoev.ru 234453Sigor@sysoev.ru nxt_debug(task, "router conn close"); 234553Sigor@sysoev.ru 234653Sigor@sysoev.ru c->write_state = &nxt_router_conn_close_state; 234753Sigor@sysoev.ru 234862Sigor@sysoev.ru nxt_conn_close(task->thread->engine, c); 234953Sigor@sysoev.ru } 235053Sigor@sysoev.ru 235153Sigor@sysoev.ru 235253Sigor@sysoev.ru static void 235353Sigor@sysoev.ru nxt_router_conn_free(nxt_task_t *task, void *obj, void *data) 235453Sigor@sysoev.ru { 235562Sigor@sysoev.ru nxt_conn_t *c; 235688Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 235753Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 235853Sigor@sysoev.ru 235953Sigor@sysoev.ru c = obj; 236053Sigor@sysoev.ru 236153Sigor@sysoev.ru nxt_debug(task, "router conn close done"); 236253Sigor@sysoev.ru 236388Smax.romanov@nginx.com nxt_queue_each(rc, &c->requests, nxt_req_conn_link_t, link) { 236488Smax.romanov@nginx.com 236588Smax.romanov@nginx.com nxt_debug(task, "conn %p close, req %uxD", c, rc->req_id); 236688Smax.romanov@nginx.com 2367141Smax.romanov@nginx.com if (rc->app_port != NULL) { 2368141Smax.romanov@nginx.com nxt_router_app_release_port(task, rc->app_port, rc->app_port->app); 2369141Smax.romanov@nginx.com 2370141Smax.romanov@nginx.com rc->app_port = NULL; 2371141Smax.romanov@nginx.com } 2372141Smax.romanov@nginx.com 237388Smax.romanov@nginx.com nxt_event_engine_request_remove(task->thread->engine, rc); 237488Smax.romanov@nginx.com 237588Smax.romanov@nginx.com } nxt_queue_loop; 237688Smax.romanov@nginx.com 2377122Smax.romanov@nginx.com nxt_queue_remove(&c->link); 2378122Smax.romanov@nginx.com 2379131Smax.romanov@nginx.com joint = c->listen->socket.data; 2380131Smax.romanov@nginx.com 2381131Smax.romanov@nginx.com task = &task->thread->engine->task; 2382131Smax.romanov@nginx.com 2383141Smax.romanov@nginx.com if (nxt_mp_release(c->mem_pool, c) == 0) { 2384141Smax.romanov@nginx.com nxt_router_conf_release(task, joint); 2385141Smax.romanov@nginx.com } 238653Sigor@sysoev.ru } 238753Sigor@sysoev.ru 238853Sigor@sysoev.ru 238953Sigor@sysoev.ru static void 239053Sigor@sysoev.ru nxt_router_conn_error(nxt_task_t *task, void *obj, void *data) 239153Sigor@sysoev.ru { 239262Sigor@sysoev.ru nxt_conn_t *c; 239353Sigor@sysoev.ru 239453Sigor@sysoev.ru c = obj; 239553Sigor@sysoev.ru 239653Sigor@sysoev.ru nxt_debug(task, "router conn error"); 239753Sigor@sysoev.ru 239853Sigor@sysoev.ru c->write_state = &nxt_router_conn_close_state; 239953Sigor@sysoev.ru 240062Sigor@sysoev.ru nxt_conn_close(task->thread->engine, c); 240153Sigor@sysoev.ru } 240253Sigor@sysoev.ru 240353Sigor@sysoev.ru 240453Sigor@sysoev.ru static void 240553Sigor@sysoev.ru nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data) 240653Sigor@sysoev.ru { 240762Sigor@sysoev.ru nxt_conn_t *c; 240862Sigor@sysoev.ru nxt_timer_t *timer; 240953Sigor@sysoev.ru 241053Sigor@sysoev.ru timer = obj; 241153Sigor@sysoev.ru 241253Sigor@sysoev.ru nxt_debug(task, "router conn timeout"); 241353Sigor@sysoev.ru 241462Sigor@sysoev.ru c = nxt_read_timer_conn(timer); 241553Sigor@sysoev.ru 241653Sigor@sysoev.ru c->write_state = &nxt_router_conn_close_state; 241753Sigor@sysoev.ru 241862Sigor@sysoev.ru nxt_conn_close(task->thread->engine, c); 241953Sigor@sysoev.ru } 242053Sigor@sysoev.ru 242153Sigor@sysoev.ru 242253Sigor@sysoev.ru static nxt_msec_t 242362Sigor@sysoev.ru nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data) 242453Sigor@sysoev.ru { 242553Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 242653Sigor@sysoev.ru 242753Sigor@sysoev.ru joint = c->listen->socket.data; 242853Sigor@sysoev.ru 242953Sigor@sysoev.ru return nxt_value_at(nxt_msec_t, joint->socket_conf, data); 243053Sigor@sysoev.ru } 2431141Smax.romanov@nginx.com 2432141Smax.romanov@nginx.com 2433141Smax.romanov@nginx.com static nxt_int_t 2434141Smax.romanov@nginx.com nxt_sw_test(nxt_lvlhsh_query_t *lhq, void *data) 2435141Smax.romanov@nginx.com { 2436141Smax.romanov@nginx.com return NXT_OK; 2437141Smax.romanov@nginx.com } 2438141Smax.romanov@nginx.com 2439141Smax.romanov@nginx.com 2440141Smax.romanov@nginx.com static const nxt_lvlhsh_proto_t lvlhsh_sw_proto nxt_aligned(64) = { 2441141Smax.romanov@nginx.com NXT_LVLHSH_DEFAULT, 2442141Smax.romanov@nginx.com nxt_sw_test, 2443141Smax.romanov@nginx.com nxt_lvlhsh_alloc, 2444141Smax.romanov@nginx.com nxt_lvlhsh_free, 2445141Smax.romanov@nginx.com }; 2446141Smax.romanov@nginx.com 2447141Smax.romanov@nginx.com 2448141Smax.romanov@nginx.com static void 2449141Smax.romanov@nginx.com nxt_router_sw_add(nxt_task_t *task, nxt_router_t *router, 2450141Smax.romanov@nginx.com nxt_start_worker_t *sw) 2451141Smax.romanov@nginx.com { 2452141Smax.romanov@nginx.com nxt_lvlhsh_query_t lhq; 2453141Smax.romanov@nginx.com 2454141Smax.romanov@nginx.com lhq.key_hash = nxt_murmur_hash2(&sw->stream, sizeof(sw->stream)); 2455141Smax.romanov@nginx.com lhq.key.length = sizeof(sw->stream); 2456141Smax.romanov@nginx.com lhq.key.start = (u_char *) &sw->stream; 2457141Smax.romanov@nginx.com lhq.proto = &lvlhsh_sw_proto; 2458141Smax.romanov@nginx.com lhq.replace = 0; 2459141Smax.romanov@nginx.com lhq.value = sw; 2460141Smax.romanov@nginx.com lhq.pool = task->thread->runtime->mem_pool; 2461141Smax.romanov@nginx.com 2462141Smax.romanov@nginx.com switch (nxt_lvlhsh_insert(&router->start_workers, &lhq)) { 2463141Smax.romanov@nginx.com 2464141Smax.romanov@nginx.com case NXT_OK: 2465141Smax.romanov@nginx.com break; 2466141Smax.romanov@nginx.com 2467141Smax.romanov@nginx.com default: 2468141Smax.romanov@nginx.com nxt_log_error(NXT_LOG_WARN, task->log, "stream %08uxD sw add failed", 2469141Smax.romanov@nginx.com sw->stream); 2470141Smax.romanov@nginx.com break; 2471141Smax.romanov@nginx.com } 2472141Smax.romanov@nginx.com } 2473141Smax.romanov@nginx.com 2474141Smax.romanov@nginx.com 2475141Smax.romanov@nginx.com static nxt_start_worker_t * 2476141Smax.romanov@nginx.com nxt_router_sw_find_remove(nxt_task_t *task, nxt_router_t *router, uint32_t id) 2477141Smax.romanov@nginx.com { 2478141Smax.romanov@nginx.com nxt_lvlhsh_query_t lhq; 2479141Smax.romanov@nginx.com 2480141Smax.romanov@nginx.com lhq.key_hash = nxt_murmur_hash2(&id, sizeof(id)); 2481141Smax.romanov@nginx.com lhq.key.length = sizeof(id); 2482141Smax.romanov@nginx.com lhq.key.start = (u_char *) &id; 2483141Smax.romanov@nginx.com lhq.proto = &lvlhsh_sw_proto; 2484141Smax.romanov@nginx.com lhq.pool = task->thread->runtime->mem_pool; 2485141Smax.romanov@nginx.com 2486141Smax.romanov@nginx.com switch (nxt_lvlhsh_delete(&router->start_workers, &lhq)) { 2487141Smax.romanov@nginx.com 2488141Smax.romanov@nginx.com case NXT_OK: 2489141Smax.romanov@nginx.com return lhq.value; 2490141Smax.romanov@nginx.com 2491141Smax.romanov@nginx.com default: 2492141Smax.romanov@nginx.com nxt_log_error(NXT_LOG_WARN, task->log, "stream %08uxD sw remove failed", 2493141Smax.romanov@nginx.com id); 2494141Smax.romanov@nginx.com break; 2495141Smax.romanov@nginx.com } 2496141Smax.romanov@nginx.com 2497141Smax.romanov@nginx.com return NULL; 2498141Smax.romanov@nginx.com } 2499