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 23167Smax.romanov@nginx.com typedef struct nxt_req_app_link_s nxt_req_app_link_t; 24141Smax.romanov@nginx.com typedef struct nxt_start_worker_s nxt_start_worker_t; 25141Smax.romanov@nginx.com 26141Smax.romanov@nginx.com struct nxt_start_worker_s { 27141Smax.romanov@nginx.com nxt_app_t *app; 28167Smax.romanov@nginx.com nxt_req_app_link_t *ra; 29141Smax.romanov@nginx.com 30141Smax.romanov@nginx.com nxt_work_t work; 31141Smax.romanov@nginx.com }; 32141Smax.romanov@nginx.com 33141Smax.romanov@nginx.com 34167Smax.romanov@nginx.com struct nxt_req_app_link_s { 35167Smax.romanov@nginx.com nxt_req_id_t req_id; 36167Smax.romanov@nginx.com nxt_port_t *app_port; 37167Smax.romanov@nginx.com nxt_port_t *reply_port; 38167Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 39167Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 40167Smax.romanov@nginx.com 41167Smax.romanov@nginx.com nxt_queue_link_t link; /* for nxt_app_t.requests */ 42167Smax.romanov@nginx.com 43167Smax.romanov@nginx.com nxt_mp_t *mem_pool; 44167Smax.romanov@nginx.com nxt_work_t work; 45167Smax.romanov@nginx.com }; 46167Smax.romanov@nginx.com 47167Smax.romanov@nginx.com 48139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task); 49139Sigor@sysoev.ru static nxt_int_t nxt_router_conf_new(nxt_task_t *task, 50139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end); 51139Sigor@sysoev.ru static void nxt_router_conf_success(nxt_task_t *task, 52139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 53139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task, 54139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 55139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task, 56*193Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type); 5753Sigor@sysoev.ru static void nxt_router_listen_sockets_sort(nxt_router_t *router, 5853Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 5953Sigor@sysoev.ru 60115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task, 61115Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end); 62133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name); 63133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, 64133Sigor@sysoev.ru nxt_str_t *name); 6553Sigor@sysoev.ru static nxt_int_t nxt_router_listen_sockets_stub_create(nxt_task_t *task, 6653Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 6765Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, 6865Sigor@sysoev.ru nxt_sockaddr_t *sa); 6953Sigor@sysoev.ru 7053Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task, 7153Sigor@sysoev.ru nxt_router_t *router, nxt_router_temp_conf_t *tmcf, 7253Sigor@sysoev.ru const nxt_event_interface_t *interface); 73115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 74115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 75115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 76115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 77115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 78115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 79115Sigor@sysoev.ru static void nxt_router_engine_socket_count(nxt_queue_t *sockets); 80154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 81154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 82154Sigor@sysoev.ru nxt_work_handler_t handler); 83139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 84139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets); 8553Sigor@sysoev.ru 8653Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 8753Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 8853Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 8953Sigor@sysoev.ru nxt_event_engine_t *engine); 90133Sigor@sysoev.ru static void nxt_router_apps_sort(nxt_router_t *router, 91133Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 9253Sigor@sysoev.ru 9353Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_temp_conf_t *tmcf); 94154Sigor@sysoev.ru static void nxt_router_engine_post(nxt_router_engine_conf_t *recf); 9553Sigor@sysoev.ru 9653Sigor@sysoev.ru static void nxt_router_thread_start(void *data); 9753Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj, 9853Sigor@sysoev.ru void *data); 9953Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj, 10053Sigor@sysoev.ru void *data); 10153Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, 10253Sigor@sysoev.ru void *data); 10353Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj, 10453Sigor@sysoev.ru void *data); 10553Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task, 10653Sigor@sysoev.ru nxt_socket_conf_joint_t *joint); 10753Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, 10853Sigor@sysoev.ru void *data); 10953Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task, 11053Sigor@sysoev.ru nxt_socket_conf_joint_t *joint); 11153Sigor@sysoev.ru 112167Smax.romanov@nginx.com static void nxt_router_send_sw_request(nxt_task_t *task, void *obj, 113167Smax.romanov@nginx.com void *data); 114167Smax.romanov@nginx.com static nxt_bool_t nxt_router_app_free(nxt_task_t *task, nxt_app_t *app); 115167Smax.romanov@nginx.com static nxt_port_t * nxt_router_app_get_port(nxt_app_t *app, uint32_t req_id); 116141Smax.romanov@nginx.com static void nxt_router_app_release_port(nxt_task_t *task, void *obj, 117141Smax.romanov@nginx.com void *data); 118141Smax.romanov@nginx.com 11953Sigor@sysoev.ru static void nxt_router_conn_init(nxt_task_t *task, void *obj, void *data); 12053Sigor@sysoev.ru static void nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, 12153Sigor@sysoev.ru void *data); 12288Smax.romanov@nginx.com static void nxt_router_process_http_request(nxt_task_t *task, 12388Smax.romanov@nginx.com nxt_conn_t *c, nxt_app_parse_ctx_t *ap); 124141Smax.romanov@nginx.com static void nxt_router_process_http_request_mp(nxt_task_t *task, 125167Smax.romanov@nginx.com nxt_req_app_link_t *ra, nxt_port_t *port); 12688Smax.romanov@nginx.com static void nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data); 12753Sigor@sysoev.ru static void nxt_router_conn_close(nxt_task_t *task, void *obj, void *data); 12853Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data); 12953Sigor@sysoev.ru static void nxt_router_conn_error(nxt_task_t *task, void *obj, void *data); 13053Sigor@sysoev.ru static void nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data); 13162Sigor@sysoev.ru static nxt_msec_t nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data); 13220Sigor@sysoev.ru 133141Smax.romanov@nginx.com static void nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code, 134141Smax.romanov@nginx.com const char* fmt, ...); 135141Smax.romanov@nginx.com 136119Smax.romanov@nginx.com static nxt_router_t *nxt_router; 13720Sigor@sysoev.ru 13820Sigor@sysoev.ru nxt_int_t 139141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data) 14020Sigor@sysoev.ru { 141141Smax.romanov@nginx.com nxt_int_t ret; 142141Smax.romanov@nginx.com nxt_router_t *router; 143141Smax.romanov@nginx.com nxt_runtime_t *rt; 144141Smax.romanov@nginx.com 145141Smax.romanov@nginx.com rt = task->thread->runtime; 14653Sigor@sysoev.ru 14788Smax.romanov@nginx.com ret = nxt_app_http_init(task, rt); 14888Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 14988Smax.romanov@nginx.com return ret; 15088Smax.romanov@nginx.com } 15188Smax.romanov@nginx.com 15253Sigor@sysoev.ru router = nxt_zalloc(sizeof(nxt_router_t)); 15353Sigor@sysoev.ru if (nxt_slow_path(router == NULL)) { 15453Sigor@sysoev.ru return NXT_ERROR; 15553Sigor@sysoev.ru } 15653Sigor@sysoev.ru 15753Sigor@sysoev.ru nxt_queue_init(&router->engines); 15853Sigor@sysoev.ru nxt_queue_init(&router->sockets); 159133Sigor@sysoev.ru nxt_queue_init(&router->apps); 16053Sigor@sysoev.ru 161119Smax.romanov@nginx.com nxt_router = router; 162119Smax.romanov@nginx.com 163115Sigor@sysoev.ru return NXT_OK; 164115Sigor@sysoev.ru } 165115Sigor@sysoev.ru 166115Sigor@sysoev.ru 167167Smax.romanov@nginx.com static nxt_start_worker_t * 168192Smax.romanov@nginx.com nxt_router_sw_create(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra) 169167Smax.romanov@nginx.com { 170167Smax.romanov@nginx.com nxt_port_t *master_port; 171167Smax.romanov@nginx.com nxt_runtime_t *rt; 172167Smax.romanov@nginx.com nxt_start_worker_t *sw; 173167Smax.romanov@nginx.com 174192Smax.romanov@nginx.com sw = nxt_zalloc(sizeof(nxt_start_worker_t)); 175167Smax.romanov@nginx.com 176167Smax.romanov@nginx.com if (nxt_slow_path(sw == NULL)) { 177167Smax.romanov@nginx.com return NULL; 178167Smax.romanov@nginx.com } 179167Smax.romanov@nginx.com 180167Smax.romanov@nginx.com sw->app = app; 181167Smax.romanov@nginx.com sw->ra = ra; 182167Smax.romanov@nginx.com 183192Smax.romanov@nginx.com nxt_debug(task, "sw %p create, request #%uxD, app '%V' %p", sw, 184167Smax.romanov@nginx.com ra->req_id, &app->name, app); 185167Smax.romanov@nginx.com 186167Smax.romanov@nginx.com rt = task->thread->runtime; 187167Smax.romanov@nginx.com master_port = rt->port_by_type[NXT_PROCESS_MASTER]; 188167Smax.romanov@nginx.com 189167Smax.romanov@nginx.com sw->work.handler = nxt_router_send_sw_request; 190167Smax.romanov@nginx.com sw->work.task = &master_port->engine->task; 191167Smax.romanov@nginx.com sw->work.obj = sw; 192167Smax.romanov@nginx.com sw->work.data = task->thread->engine; 193167Smax.romanov@nginx.com sw->work.next = NULL; 194167Smax.romanov@nginx.com 195167Smax.romanov@nginx.com if (task->thread->engine != master_port->engine) { 196192Smax.romanov@nginx.com nxt_debug(task, "sw %p post send to master engine %p", sw, 197167Smax.romanov@nginx.com master_port->engine); 198167Smax.romanov@nginx.com 199167Smax.romanov@nginx.com nxt_event_engine_post(master_port->engine, &sw->work); 200167Smax.romanov@nginx.com 201167Smax.romanov@nginx.com } else { 202167Smax.romanov@nginx.com nxt_router_send_sw_request(task, sw, sw->work.data); 203167Smax.romanov@nginx.com } 204167Smax.romanov@nginx.com 205167Smax.romanov@nginx.com return sw; 206167Smax.romanov@nginx.com } 207167Smax.romanov@nginx.com 208167Smax.romanov@nginx.com 209192Smax.romanov@nginx.com nxt_inline void 210192Smax.romanov@nginx.com nxt_router_sw_release(nxt_task_t *task, nxt_start_worker_t *sw) 211141Smax.romanov@nginx.com { 212192Smax.romanov@nginx.com nxt_debug(task, "sw %p release", sw); 213192Smax.romanov@nginx.com 214192Smax.romanov@nginx.com nxt_free(sw); 215141Smax.romanov@nginx.com } 216141Smax.romanov@nginx.com 217141Smax.romanov@nginx.com 218167Smax.romanov@nginx.com static nxt_req_app_link_t * 219167Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_conn_link_t *rc) 220167Smax.romanov@nginx.com { 221167Smax.romanov@nginx.com nxt_mp_t *mp; 222167Smax.romanov@nginx.com nxt_req_app_link_t *ra; 223167Smax.romanov@nginx.com 224167Smax.romanov@nginx.com mp = rc->conn->mem_pool; 225167Smax.romanov@nginx.com 226167Smax.romanov@nginx.com ra = nxt_mp_retain(mp, sizeof(nxt_req_app_link_t)); 227167Smax.romanov@nginx.com 228167Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 229167Smax.romanov@nginx.com return NULL; 230167Smax.romanov@nginx.com } 231167Smax.romanov@nginx.com 232167Smax.romanov@nginx.com nxt_debug(task, "ra #%uxD create", ra->req_id); 233167Smax.romanov@nginx.com 234167Smax.romanov@nginx.com nxt_memzero(ra, sizeof(nxt_req_app_link_t)); 235167Smax.romanov@nginx.com 236167Smax.romanov@nginx.com ra->req_id = rc->req_id; 237167Smax.romanov@nginx.com ra->app_port = NULL; 238167Smax.romanov@nginx.com ra->rc = rc; 239167Smax.romanov@nginx.com 240167Smax.romanov@nginx.com ra->mem_pool = mp; 241167Smax.romanov@nginx.com 242167Smax.romanov@nginx.com ra->work.handler = NULL; 243167Smax.romanov@nginx.com ra->work.task = &task->thread->engine->task; 244167Smax.romanov@nginx.com ra->work.obj = ra; 245167Smax.romanov@nginx.com ra->work.data = task->thread->engine; 246167Smax.romanov@nginx.com 247167Smax.romanov@nginx.com return ra; 248167Smax.romanov@nginx.com } 249167Smax.romanov@nginx.com 250167Smax.romanov@nginx.com 251167Smax.romanov@nginx.com static void 252167Smax.romanov@nginx.com nxt_router_ra_release(nxt_task_t *task, void *obj, void *data) 253167Smax.romanov@nginx.com { 254167Smax.romanov@nginx.com nxt_req_app_link_t *ra; 255167Smax.romanov@nginx.com nxt_event_engine_t *engine; 256167Smax.romanov@nginx.com 257167Smax.romanov@nginx.com ra = obj; 258167Smax.romanov@nginx.com engine = data; 259167Smax.romanov@nginx.com 260167Smax.romanov@nginx.com if (task->thread->engine != engine) { 261167Smax.romanov@nginx.com ra->work.handler = nxt_router_ra_release; 262167Smax.romanov@nginx.com ra->work.task = &engine->task; 263167Smax.romanov@nginx.com ra->work.next = NULL; 264167Smax.romanov@nginx.com 265167Smax.romanov@nginx.com nxt_debug(task, "ra #%uxD post release to %p", ra->req_id, engine); 266167Smax.romanov@nginx.com 267167Smax.romanov@nginx.com nxt_event_engine_post(engine, &ra->work); 268167Smax.romanov@nginx.com 269167Smax.romanov@nginx.com return; 270167Smax.romanov@nginx.com } 271167Smax.romanov@nginx.com 272167Smax.romanov@nginx.com nxt_debug(task, "ra #%uxD release", ra->req_id); 273167Smax.romanov@nginx.com 274167Smax.romanov@nginx.com if (ra->app_port != NULL) { 275167Smax.romanov@nginx.com 276167Smax.romanov@nginx.com if (ra->rc->conn != NULL) { 277167Smax.romanov@nginx.com ra->rc->app_port = ra->app_port; 278167Smax.romanov@nginx.com 279167Smax.romanov@nginx.com } else { 280167Smax.romanov@nginx.com nxt_router_app_release_port(task, ra->app_port, ra->app_port->app); 281167Smax.romanov@nginx.com } 282167Smax.romanov@nginx.com } 283167Smax.romanov@nginx.com 284167Smax.romanov@nginx.com nxt_mp_release(ra->mem_pool, ra); 285167Smax.romanov@nginx.com } 286167Smax.romanov@nginx.com 287167Smax.romanov@nginx.com 288141Smax.romanov@nginx.com void 289141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 290141Smax.romanov@nginx.com { 291141Smax.romanov@nginx.com nxt_port_new_port_handler(task, msg); 292141Smax.romanov@nginx.com 293192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 294141Smax.romanov@nginx.com return; 295141Smax.romanov@nginx.com } 296141Smax.romanov@nginx.com 297192Smax.romanov@nginx.com if (msg->new_port == NULL || msg->new_port->type != NXT_PROCESS_WORKER) { 298192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 299141Smax.romanov@nginx.com } 300192Smax.romanov@nginx.com 301192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 302141Smax.romanov@nginx.com } 303141Smax.romanov@nginx.com 304141Smax.romanov@nginx.com 305139Sigor@sysoev.ru void 306139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 307115Sigor@sysoev.ru { 308139Sigor@sysoev.ru size_t dump_size; 309139Sigor@sysoev.ru nxt_buf_t *b; 310139Sigor@sysoev.ru nxt_int_t ret; 311139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 312139Sigor@sysoev.ru 313139Sigor@sysoev.ru b = msg->buf; 314139Sigor@sysoev.ru 315139Sigor@sysoev.ru dump_size = nxt_buf_used_size(b); 316139Sigor@sysoev.ru 317139Sigor@sysoev.ru if (dump_size > 300) { 318139Sigor@sysoev.ru dump_size = 300; 31953Sigor@sysoev.ru } 32053Sigor@sysoev.ru 321139Sigor@sysoev.ru nxt_debug(task, "router conf data (%z): %*s", 322139Sigor@sysoev.ru msg->size, dump_size, b->mem.pos); 323139Sigor@sysoev.ru 324139Sigor@sysoev.ru tmcf = nxt_router_temp_conf(task); 325139Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 326139Sigor@sysoev.ru return; 32753Sigor@sysoev.ru } 32853Sigor@sysoev.ru 329139Sigor@sysoev.ru tmcf->conf->router = nxt_router; 330139Sigor@sysoev.ru tmcf->stream = msg->port_msg.stream; 331139Sigor@sysoev.ru tmcf->port = nxt_runtime_port_find(task->thread->runtime, 332139Sigor@sysoev.ru msg->port_msg.pid, 0); 333139Sigor@sysoev.ru 334139Sigor@sysoev.ru ret = nxt_router_conf_new(task, tmcf, b->mem.pos, b->mem.free); 335139Sigor@sysoev.ru 336139Sigor@sysoev.ru b->mem.pos = b->mem.free; 337139Sigor@sysoev.ru 338139Sigor@sysoev.ru if (ret == NXT_OK) { 339180Smax.romanov@nginx.com nxt_router_conf_success(task, tmcf); 340180Smax.romanov@nginx.com return; 341139Sigor@sysoev.ru } 342139Sigor@sysoev.ru 343139Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "failed to apply new conf"); 344139Sigor@sysoev.ru 345180Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 34653Sigor@sysoev.ru } 34753Sigor@sysoev.ru 34853Sigor@sysoev.ru 349192Smax.romanov@nginx.com void 350192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 351192Smax.romanov@nginx.com { 352192Smax.romanov@nginx.com nxt_port_remove_pid_handler(task, msg); 353192Smax.romanov@nginx.com 354192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 355192Smax.romanov@nginx.com return; 356192Smax.romanov@nginx.com } 357192Smax.romanov@nginx.com 358192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 359192Smax.romanov@nginx.com 360192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 361192Smax.romanov@nginx.com } 362192Smax.romanov@nginx.com 363192Smax.romanov@nginx.com 36453Sigor@sysoev.ru static nxt_router_temp_conf_t * 365139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task) 36653Sigor@sysoev.ru { 36765Sigor@sysoev.ru nxt_mp_t *mp, *tmp; 36853Sigor@sysoev.ru nxt_router_conf_t *rtcf; 36953Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 37053Sigor@sysoev.ru 37165Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 37253Sigor@sysoev.ru if (nxt_slow_path(mp == NULL)) { 37353Sigor@sysoev.ru return NULL; 37453Sigor@sysoev.ru } 37553Sigor@sysoev.ru 37665Sigor@sysoev.ru rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t)); 37753Sigor@sysoev.ru if (nxt_slow_path(rtcf == NULL)) { 37853Sigor@sysoev.ru goto fail; 37953Sigor@sysoev.ru } 38053Sigor@sysoev.ru 38153Sigor@sysoev.ru rtcf->mem_pool = mp; 38253Sigor@sysoev.ru 38365Sigor@sysoev.ru tmp = nxt_mp_create(1024, 128, 256, 32); 38453Sigor@sysoev.ru if (nxt_slow_path(tmp == NULL)) { 38553Sigor@sysoev.ru goto fail; 38653Sigor@sysoev.ru } 38753Sigor@sysoev.ru 38865Sigor@sysoev.ru tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t)); 38953Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 39053Sigor@sysoev.ru goto temp_fail; 39153Sigor@sysoev.ru } 39253Sigor@sysoev.ru 39353Sigor@sysoev.ru tmcf->mem_pool = tmp; 39453Sigor@sysoev.ru tmcf->conf = rtcf; 395139Sigor@sysoev.ru tmcf->count = 1; 396139Sigor@sysoev.ru tmcf->engine = task->thread->engine; 39753Sigor@sysoev.ru 39853Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, 4, 39953Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 40053Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 40153Sigor@sysoev.ru goto temp_fail; 40253Sigor@sysoev.ru } 40353Sigor@sysoev.ru 40453Sigor@sysoev.ru nxt_queue_init(&tmcf->deleting); 40553Sigor@sysoev.ru nxt_queue_init(&tmcf->keeping); 40653Sigor@sysoev.ru nxt_queue_init(&tmcf->updating); 40753Sigor@sysoev.ru nxt_queue_init(&tmcf->pending); 40853Sigor@sysoev.ru nxt_queue_init(&tmcf->creating); 409133Sigor@sysoev.ru nxt_queue_init(&tmcf->apps); 410133Sigor@sysoev.ru nxt_queue_init(&tmcf->previous); 41153Sigor@sysoev.ru 41253Sigor@sysoev.ru return tmcf; 41353Sigor@sysoev.ru 41453Sigor@sysoev.ru temp_fail: 41553Sigor@sysoev.ru 41665Sigor@sysoev.ru nxt_mp_destroy(tmp); 41753Sigor@sysoev.ru 41853Sigor@sysoev.ru fail: 41953Sigor@sysoev.ru 42065Sigor@sysoev.ru nxt_mp_destroy(mp); 42153Sigor@sysoev.ru 42253Sigor@sysoev.ru return NULL; 42353Sigor@sysoev.ru } 42453Sigor@sysoev.ru 42553Sigor@sysoev.ru 426139Sigor@sysoev.ru static nxt_int_t 427139Sigor@sysoev.ru nxt_router_conf_new(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 428139Sigor@sysoev.ru u_char *start, u_char *end) 429139Sigor@sysoev.ru { 430139Sigor@sysoev.ru nxt_int_t ret; 431139Sigor@sysoev.ru nxt_router_t *router; 432139Sigor@sysoev.ru nxt_runtime_t *rt; 433139Sigor@sysoev.ru const nxt_event_interface_t *interface; 434139Sigor@sysoev.ru 435139Sigor@sysoev.ru ret = nxt_router_conf_create(task, tmcf, start, end); 436139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 437139Sigor@sysoev.ru return ret; 438139Sigor@sysoev.ru } 439139Sigor@sysoev.ru 440139Sigor@sysoev.ru router = tmcf->conf->router; 441139Sigor@sysoev.ru 442139Sigor@sysoev.ru nxt_router_listen_sockets_sort(router, tmcf); 443139Sigor@sysoev.ru 444139Sigor@sysoev.ru ret = nxt_router_listen_sockets_stub_create(task, tmcf); 445139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 446139Sigor@sysoev.ru return ret; 447139Sigor@sysoev.ru } 448139Sigor@sysoev.ru 449139Sigor@sysoev.ru rt = task->thread->runtime; 450139Sigor@sysoev.ru 451139Sigor@sysoev.ru interface = nxt_service_get(rt->services, "engine", NULL); 452139Sigor@sysoev.ru 453139Sigor@sysoev.ru ret = nxt_router_engines_create(task, router, tmcf, interface); 454139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 455139Sigor@sysoev.ru return ret; 456139Sigor@sysoev.ru } 457139Sigor@sysoev.ru 458139Sigor@sysoev.ru ret = nxt_router_threads_create(task, rt, tmcf); 459139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 460139Sigor@sysoev.ru return ret; 461139Sigor@sysoev.ru } 462139Sigor@sysoev.ru 463139Sigor@sysoev.ru nxt_router_apps_sort(router, tmcf); 464139Sigor@sysoev.ru 465139Sigor@sysoev.ru nxt_router_engines_post(tmcf); 466139Sigor@sysoev.ru 467139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->updating); 468139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->creating); 469139Sigor@sysoev.ru 470139Sigor@sysoev.ru return NXT_OK; 471139Sigor@sysoev.ru } 472139Sigor@sysoev.ru 473139Sigor@sysoev.ru 474139Sigor@sysoev.ru static void 475139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data) 476139Sigor@sysoev.ru { 477153Sigor@sysoev.ru nxt_joint_job_t *job; 478153Sigor@sysoev.ru 479153Sigor@sysoev.ru job = obj; 480153Sigor@sysoev.ru 481153Sigor@sysoev.ru nxt_router_conf_success(task, job->tmcf); 482139Sigor@sysoev.ru } 483139Sigor@sysoev.ru 484139Sigor@sysoev.ru 485139Sigor@sysoev.ru static void 486139Sigor@sysoev.ru nxt_router_conf_success(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 487139Sigor@sysoev.ru { 488139Sigor@sysoev.ru nxt_debug(task, "temp conf count:%D", tmcf->count); 489139Sigor@sysoev.ru 490139Sigor@sysoev.ru if (--tmcf->count == 0) { 491*193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST); 492139Sigor@sysoev.ru } 493139Sigor@sysoev.ru } 494139Sigor@sysoev.ru 495139Sigor@sysoev.ru 496139Sigor@sysoev.ru static void 497139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 498139Sigor@sysoev.ru { 499148Sigor@sysoev.ru nxt_socket_t s; 500149Sigor@sysoev.ru nxt_router_t *router; 501148Sigor@sysoev.ru nxt_queue_link_t *qlk; 502148Sigor@sysoev.ru nxt_socket_conf_t *skcf; 503148Sigor@sysoev.ru 504148Sigor@sysoev.ru for (qlk = nxt_queue_first(&tmcf->creating); 505148Sigor@sysoev.ru qlk != nxt_queue_tail(&tmcf->creating); 506148Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 507148Sigor@sysoev.ru { 508148Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 509148Sigor@sysoev.ru s = skcf->listen.socket; 510148Sigor@sysoev.ru 511148Sigor@sysoev.ru if (s != -1) { 512148Sigor@sysoev.ru nxt_socket_close(task, s); 513148Sigor@sysoev.ru } 514148Sigor@sysoev.ru 515148Sigor@sysoev.ru nxt_free(skcf->socket); 516148Sigor@sysoev.ru } 517148Sigor@sysoev.ru 518149Sigor@sysoev.ru router = tmcf->conf->router; 519149Sigor@sysoev.ru 520149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->keeping); 521149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->deleting); 522149Sigor@sysoev.ru 523148Sigor@sysoev.ru // TODO: new engines and threads 524148Sigor@sysoev.ru 525139Sigor@sysoev.ru nxt_mp_destroy(tmcf->conf->mem_pool); 526139Sigor@sysoev.ru 527*193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR); 528139Sigor@sysoev.ru } 529139Sigor@sysoev.ru 530139Sigor@sysoev.ru 531139Sigor@sysoev.ru static void 532139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 533*193Smax.romanov@nginx.com nxt_port_msg_type_t type) 534139Sigor@sysoev.ru { 535*193Smax.romanov@nginx.com nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL); 536139Sigor@sysoev.ru } 537139Sigor@sysoev.ru 538139Sigor@sysoev.ru 539115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_conf[] = { 540115Sigor@sysoev.ru { 541133Sigor@sysoev.ru nxt_string("listeners_threads"), 542115Sigor@sysoev.ru NXT_CONF_MAP_INT32, 543115Sigor@sysoev.ru offsetof(nxt_router_conf_t, threads), 544115Sigor@sysoev.ru }, 545115Sigor@sysoev.ru }; 546115Sigor@sysoev.ru 547115Sigor@sysoev.ru 548133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_app_conf[] = { 549115Sigor@sysoev.ru { 550133Sigor@sysoev.ru nxt_string("type"), 551115Sigor@sysoev.ru NXT_CONF_MAP_STR, 552133Sigor@sysoev.ru offsetof(nxt_router_app_conf_t, type), 553115Sigor@sysoev.ru }, 554115Sigor@sysoev.ru 555115Sigor@sysoev.ru { 556133Sigor@sysoev.ru nxt_string("workers"), 557115Sigor@sysoev.ru NXT_CONF_MAP_INT32, 558133Sigor@sysoev.ru offsetof(nxt_router_app_conf_t, workers), 559133Sigor@sysoev.ru }, 560133Sigor@sysoev.ru }; 561133Sigor@sysoev.ru 562133Sigor@sysoev.ru 563133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_listener_conf[] = { 564133Sigor@sysoev.ru { 565133Sigor@sysoev.ru nxt_string("application"), 566133Sigor@sysoev.ru NXT_CONF_MAP_STR, 567133Sigor@sysoev.ru offsetof(nxt_router_listener_conf_t, application), 568115Sigor@sysoev.ru }, 569115Sigor@sysoev.ru }; 570115Sigor@sysoev.ru 571115Sigor@sysoev.ru 572115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_http_conf[] = { 573115Sigor@sysoev.ru { 574115Sigor@sysoev.ru nxt_string("header_buffer_size"), 575115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 576115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_buffer_size), 577115Sigor@sysoev.ru }, 578115Sigor@sysoev.ru 579115Sigor@sysoev.ru { 580115Sigor@sysoev.ru nxt_string("large_header_buffer_size"), 581115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 582115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, large_header_buffer_size), 583115Sigor@sysoev.ru }, 584115Sigor@sysoev.ru 585115Sigor@sysoev.ru { 586115Sigor@sysoev.ru nxt_string("header_read_timeout"), 587115Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 588115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_read_timeout), 589115Sigor@sysoev.ru }, 590115Sigor@sysoev.ru }; 591115Sigor@sysoev.ru 592115Sigor@sysoev.ru 59353Sigor@sysoev.ru static nxt_int_t 594115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 595115Sigor@sysoev.ru u_char *start, u_char *end) 59653Sigor@sysoev.ru { 597133Sigor@sysoev.ru u_char *p; 598133Sigor@sysoev.ru size_t size; 599115Sigor@sysoev.ru nxt_mp_t *mp; 600115Sigor@sysoev.ru uint32_t next; 601115Sigor@sysoev.ru nxt_int_t ret; 602115Sigor@sysoev.ru nxt_str_t name; 603133Sigor@sysoev.ru nxt_app_t *app, *prev; 604133Sigor@sysoev.ru nxt_app_type_t type; 605115Sigor@sysoev.ru nxt_sockaddr_t *sa; 606133Sigor@sysoev.ru nxt_conf_value_t *conf, *http; 607133Sigor@sysoev.ru nxt_conf_value_t *applications, *application; 608133Sigor@sysoev.ru nxt_conf_value_t *listeners, *listener; 609115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 610133Sigor@sysoev.ru nxt_router_app_conf_t apcf; 611115Sigor@sysoev.ru nxt_router_listener_conf_t lscf; 612115Sigor@sysoev.ru 613115Sigor@sysoev.ru static nxt_str_t http_path = nxt_string("/http"); 614133Sigor@sysoev.ru static nxt_str_t applications_path = nxt_string("/applications"); 615115Sigor@sysoev.ru static nxt_str_t listeners_path = nxt_string("/listeners"); 616115Sigor@sysoev.ru 617115Sigor@sysoev.ru conf = nxt_conf_json_parse(tmcf->mem_pool, start, end); 618115Sigor@sysoev.ru if (conf == NULL) { 619115Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "configuration parsing error"); 620115Sigor@sysoev.ru return NXT_ERROR; 621115Sigor@sysoev.ru } 622115Sigor@sysoev.ru 623136Svbart@nginx.com ret = nxt_conf_map_object(conf, nxt_router_conf, 624136Svbart@nginx.com nxt_nitems(nxt_router_conf), tmcf->conf); 625115Sigor@sysoev.ru if (ret != NXT_OK) { 626133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "root map error"); 627115Sigor@sysoev.ru return NXT_ERROR; 628115Sigor@sysoev.ru } 629115Sigor@sysoev.ru 630117Sigor@sysoev.ru if (tmcf->conf->threads == 0) { 631117Sigor@sysoev.ru tmcf->conf->threads = nxt_ncpu; 632117Sigor@sysoev.ru } 633117Sigor@sysoev.ru 634133Sigor@sysoev.ru applications = nxt_conf_get_path(conf, &applications_path); 635133Sigor@sysoev.ru if (applications == NULL) { 636133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block"); 637115Sigor@sysoev.ru return NXT_ERROR; 638115Sigor@sysoev.ru } 639115Sigor@sysoev.ru 640133Sigor@sysoev.ru next = 0; 641133Sigor@sysoev.ru 642133Sigor@sysoev.ru for ( ;; ) { 643133Sigor@sysoev.ru application = nxt_conf_next_object_member(applications, &name, &next); 644133Sigor@sysoev.ru if (application == NULL) { 645133Sigor@sysoev.ru break; 646133Sigor@sysoev.ru } 647133Sigor@sysoev.ru 648133Sigor@sysoev.ru nxt_debug(task, "application \"%V\"", &name); 649133Sigor@sysoev.ru 650144Smax.romanov@nginx.com size = nxt_conf_json_length(application, NULL); 651144Smax.romanov@nginx.com 652144Smax.romanov@nginx.com app = nxt_malloc(sizeof(nxt_app_t) + name.length + size); 653133Sigor@sysoev.ru if (app == NULL) { 654133Sigor@sysoev.ru goto fail; 655133Sigor@sysoev.ru } 656133Sigor@sysoev.ru 657144Smax.romanov@nginx.com nxt_memzero(app, sizeof(nxt_app_t)); 658144Smax.romanov@nginx.com 659144Smax.romanov@nginx.com app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t)); 660144Smax.romanov@nginx.com app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length); 661133Sigor@sysoev.ru 662133Sigor@sysoev.ru p = nxt_conf_json_print(app->conf.start, application, NULL); 663133Sigor@sysoev.ru app->conf.length = p - app->conf.start; 664133Sigor@sysoev.ru 665144Smax.romanov@nginx.com nxt_assert(app->conf.length <= size); 666144Smax.romanov@nginx.com 667133Sigor@sysoev.ru nxt_debug(task, "application conf \"%V\"", &app->conf); 668133Sigor@sysoev.ru 669133Sigor@sysoev.ru prev = nxt_router_app_find(&tmcf->conf->router->apps, &name); 670133Sigor@sysoev.ru 671133Sigor@sysoev.ru if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) { 672133Sigor@sysoev.ru nxt_free(app); 673133Sigor@sysoev.ru 674133Sigor@sysoev.ru nxt_queue_remove(&prev->link); 675133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->previous, &prev->link); 676133Sigor@sysoev.ru continue; 677133Sigor@sysoev.ru } 678133Sigor@sysoev.ru 679136Svbart@nginx.com ret = nxt_conf_map_object(application, nxt_router_app_conf, 680136Svbart@nginx.com nxt_nitems(nxt_router_app_conf), &apcf); 681133Sigor@sysoev.ru if (ret != NXT_OK) { 682133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "application map error"); 683133Sigor@sysoev.ru goto app_fail; 684133Sigor@sysoev.ru } 685115Sigor@sysoev.ru 686133Sigor@sysoev.ru nxt_debug(task, "application type: %V", &apcf.type); 687133Sigor@sysoev.ru nxt_debug(task, "application workers: %D", apcf.workers); 688133Sigor@sysoev.ru 689141Smax.romanov@nginx.com type = nxt_app_parse_type(&apcf.type); 690141Smax.romanov@nginx.com 691141Smax.romanov@nginx.com if (type == NXT_APP_UNKNOWN) { 692141Smax.romanov@nginx.com nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"", 693141Smax.romanov@nginx.com &apcf.type); 694141Smax.romanov@nginx.com goto app_fail; 695141Smax.romanov@nginx.com } 696141Smax.romanov@nginx.com 697141Smax.romanov@nginx.com if (nxt_app_modules[type] == NULL) { 698133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "unsupported application type: \"%V\"", 699133Sigor@sysoev.ru &apcf.type); 700133Sigor@sysoev.ru goto app_fail; 701133Sigor@sysoev.ru } 702133Sigor@sysoev.ru 703133Sigor@sysoev.ru ret = nxt_thread_mutex_create(&app->mutex); 704133Sigor@sysoev.ru if (ret != NXT_OK) { 705133Sigor@sysoev.ru goto app_fail; 706133Sigor@sysoev.ru } 707133Sigor@sysoev.ru 708141Smax.romanov@nginx.com nxt_queue_init(&app->ports); 709141Smax.romanov@nginx.com nxt_queue_init(&app->requests); 710141Smax.romanov@nginx.com 711144Smax.romanov@nginx.com app->name.length = name.length; 712144Smax.romanov@nginx.com nxt_memcpy(app->name.start, name.start, name.length); 713144Smax.romanov@nginx.com 714133Sigor@sysoev.ru app->type = type; 715133Sigor@sysoev.ru app->max_workers = apcf.workers; 716133Sigor@sysoev.ru app->live = 1; 717141Smax.romanov@nginx.com app->module = nxt_app_modules[type]; 718133Sigor@sysoev.ru 719133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->apps, &app->link); 720133Sigor@sysoev.ru } 721133Sigor@sysoev.ru 722133Sigor@sysoev.ru http = nxt_conf_get_path(conf, &http_path); 723133Sigor@sysoev.ru #if 0 724133Sigor@sysoev.ru if (http == NULL) { 725133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "no \"http\" block"); 726133Sigor@sysoev.ru return NXT_ERROR; 727133Sigor@sysoev.ru } 728133Sigor@sysoev.ru #endif 729133Sigor@sysoev.ru 730133Sigor@sysoev.ru listeners = nxt_conf_get_path(conf, &listeners_path); 731115Sigor@sysoev.ru if (listeners == NULL) { 732133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block"); 733115Sigor@sysoev.ru return NXT_ERROR; 734115Sigor@sysoev.ru } 73553Sigor@sysoev.ru 736133Sigor@sysoev.ru next = 0; 73753Sigor@sysoev.ru 738133Sigor@sysoev.ru mp = tmcf->conf->mem_pool; 739115Sigor@sysoev.ru 740115Sigor@sysoev.ru for ( ;; ) { 741115Sigor@sysoev.ru listener = nxt_conf_next_object_member(listeners, &name, &next); 742115Sigor@sysoev.ru if (listener == NULL) { 743115Sigor@sysoev.ru break; 744115Sigor@sysoev.ru } 74553Sigor@sysoev.ru 746115Sigor@sysoev.ru sa = nxt_sockaddr_parse(mp, &name); 747115Sigor@sysoev.ru if (sa == NULL) { 748115Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", &name); 749133Sigor@sysoev.ru goto fail; 750115Sigor@sysoev.ru } 751115Sigor@sysoev.ru 752115Sigor@sysoev.ru sa->type = SOCK_STREAM; 753115Sigor@sysoev.ru 754115Sigor@sysoev.ru nxt_debug(task, "router listener: \"%*s\"", 755115Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa)); 75653Sigor@sysoev.ru 757115Sigor@sysoev.ru skcf = nxt_router_socket_conf(task, mp, sa); 758115Sigor@sysoev.ru if (skcf == NULL) { 759133Sigor@sysoev.ru goto fail; 760115Sigor@sysoev.ru } 76153Sigor@sysoev.ru 762136Svbart@nginx.com ret = nxt_conf_map_object(listener, nxt_router_listener_conf, 763136Svbart@nginx.com nxt_nitems(nxt_router_listener_conf), &lscf); 764115Sigor@sysoev.ru if (ret != NXT_OK) { 765115Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "listener map error"); 766133Sigor@sysoev.ru goto fail; 767115Sigor@sysoev.ru } 76853Sigor@sysoev.ru 769133Sigor@sysoev.ru nxt_debug(task, "application: %V", &lscf.application); 770133Sigor@sysoev.ru 771133Sigor@sysoev.ru // STUB, default values if http block is not defined. 772133Sigor@sysoev.ru skcf->header_buffer_size = 2048; 773133Sigor@sysoev.ru skcf->large_header_buffer_size = 8192; 774133Sigor@sysoev.ru skcf->header_read_timeout = 5000; 77553Sigor@sysoev.ru 776133Sigor@sysoev.ru if (http != NULL) { 777136Svbart@nginx.com ret = nxt_conf_map_object(http, nxt_router_http_conf, 778136Svbart@nginx.com nxt_nitems(nxt_router_http_conf), skcf); 779133Sigor@sysoev.ru if (ret != NXT_OK) { 780133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "http map error"); 781133Sigor@sysoev.ru goto fail; 782133Sigor@sysoev.ru } 783115Sigor@sysoev.ru } 784115Sigor@sysoev.ru 785115Sigor@sysoev.ru skcf->listen.handler = nxt_router_conn_init; 786115Sigor@sysoev.ru skcf->router_conf = tmcf->conf; 787160Sigor@sysoev.ru skcf->router_conf->count++; 788133Sigor@sysoev.ru skcf->application = nxt_router_listener_application(tmcf, 789133Sigor@sysoev.ru &lscf.application); 790115Sigor@sysoev.ru 791115Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->pending, &skcf->link); 792115Sigor@sysoev.ru } 79353Sigor@sysoev.ru 79453Sigor@sysoev.ru return NXT_OK; 795133Sigor@sysoev.ru 796133Sigor@sysoev.ru app_fail: 797133Sigor@sysoev.ru 798133Sigor@sysoev.ru nxt_free(app); 799133Sigor@sysoev.ru 800133Sigor@sysoev.ru fail: 801133Sigor@sysoev.ru 802141Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 803141Smax.romanov@nginx.com 804141Smax.romanov@nginx.com nxt_queue_remove(&app->link); 805133Sigor@sysoev.ru nxt_thread_mutex_destroy(&app->mutex); 806133Sigor@sysoev.ru nxt_free(app); 807141Smax.romanov@nginx.com 808141Smax.romanov@nginx.com } nxt_queue_loop; 809133Sigor@sysoev.ru 810133Sigor@sysoev.ru return NXT_ERROR; 811133Sigor@sysoev.ru } 812133Sigor@sysoev.ru 813133Sigor@sysoev.ru 814133Sigor@sysoev.ru static nxt_app_t * 815133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name) 816133Sigor@sysoev.ru { 817141Smax.romanov@nginx.com nxt_app_t *app; 818141Smax.romanov@nginx.com 819141Smax.romanov@nginx.com nxt_queue_each(app, queue, nxt_app_t, link) { 820133Sigor@sysoev.ru 821133Sigor@sysoev.ru if (nxt_strstr_eq(name, &app->name)) { 822133Sigor@sysoev.ru return app; 823133Sigor@sysoev.ru } 824141Smax.romanov@nginx.com 825141Smax.romanov@nginx.com } nxt_queue_loop; 826133Sigor@sysoev.ru 827133Sigor@sysoev.ru return NULL; 828133Sigor@sysoev.ru } 829133Sigor@sysoev.ru 830133Sigor@sysoev.ru 831133Sigor@sysoev.ru static nxt_app_t * 832133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name) 833133Sigor@sysoev.ru { 834133Sigor@sysoev.ru nxt_app_t *app; 835133Sigor@sysoev.ru 836133Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->apps, name); 837133Sigor@sysoev.ru 838133Sigor@sysoev.ru if (app == NULL) { 839134Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->previous, name); 840133Sigor@sysoev.ru } 841133Sigor@sysoev.ru 842133Sigor@sysoev.ru return app; 84353Sigor@sysoev.ru } 84453Sigor@sysoev.ru 84553Sigor@sysoev.ru 84653Sigor@sysoev.ru static nxt_socket_conf_t * 84765Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, nxt_sockaddr_t *sa) 84853Sigor@sysoev.ru { 849163Smax.romanov@nginx.com nxt_socket_conf_t *skcf; 850163Smax.romanov@nginx.com 851163Smax.romanov@nginx.com skcf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_t)); 852163Smax.romanov@nginx.com if (nxt_slow_path(skcf == NULL)) { 85353Sigor@sysoev.ru return NULL; 85453Sigor@sysoev.ru } 85553Sigor@sysoev.ru 856163Smax.romanov@nginx.com skcf->sockaddr = sa; 857163Smax.romanov@nginx.com 858163Smax.romanov@nginx.com skcf->listen.sockaddr = sa; 859163Smax.romanov@nginx.com skcf->listen.socklen = sa->socklen; 860163Smax.romanov@nginx.com skcf->listen.address_length = sa->length; 861163Smax.romanov@nginx.com 862163Smax.romanov@nginx.com skcf->listen.socket = -1; 863163Smax.romanov@nginx.com skcf->listen.backlog = NXT_LISTEN_BACKLOG; 864163Smax.romanov@nginx.com skcf->listen.flags = NXT_NONBLOCK; 865163Smax.romanov@nginx.com skcf->listen.read_after_accept = 1; 866163Smax.romanov@nginx.com 867163Smax.romanov@nginx.com return skcf; 86853Sigor@sysoev.ru } 86953Sigor@sysoev.ru 87053Sigor@sysoev.ru 87153Sigor@sysoev.ru static void 87253Sigor@sysoev.ru nxt_router_listen_sockets_sort(nxt_router_t *router, 87353Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 87453Sigor@sysoev.ru { 87553Sigor@sysoev.ru nxt_queue_link_t *nqlk, *oqlk, *next; 87653Sigor@sysoev.ru nxt_socket_conf_t *nskcf, *oskcf; 87753Sigor@sysoev.ru 87853Sigor@sysoev.ru for (nqlk = nxt_queue_first(&tmcf->pending); 87953Sigor@sysoev.ru nqlk != nxt_queue_tail(&tmcf->pending); 88053Sigor@sysoev.ru nqlk = next) 88153Sigor@sysoev.ru { 88253Sigor@sysoev.ru next = nxt_queue_next(nqlk); 88353Sigor@sysoev.ru nskcf = nxt_queue_link_data(nqlk, nxt_socket_conf_t, link); 88453Sigor@sysoev.ru 88553Sigor@sysoev.ru for (oqlk = nxt_queue_first(&router->sockets); 88653Sigor@sysoev.ru oqlk != nxt_queue_tail(&router->sockets); 88753Sigor@sysoev.ru oqlk = nxt_queue_next(oqlk)) 88853Sigor@sysoev.ru { 88953Sigor@sysoev.ru oskcf = nxt_queue_link_data(oqlk, nxt_socket_conf_t, link); 89053Sigor@sysoev.ru 891115Sigor@sysoev.ru if (nxt_sockaddr_cmp(nskcf->sockaddr, oskcf->sockaddr)) { 892115Sigor@sysoev.ru nskcf->socket = oskcf->socket; 893115Sigor@sysoev.ru nskcf->listen.socket = oskcf->listen.socket; 894115Sigor@sysoev.ru 89553Sigor@sysoev.ru nxt_queue_remove(oqlk); 89653Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->keeping, oqlk); 89753Sigor@sysoev.ru 89853Sigor@sysoev.ru nxt_queue_remove(nqlk); 89953Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->updating, nqlk); 90053Sigor@sysoev.ru 90153Sigor@sysoev.ru break; 90253Sigor@sysoev.ru } 90353Sigor@sysoev.ru } 90453Sigor@sysoev.ru } 90553Sigor@sysoev.ru 90653Sigor@sysoev.ru nxt_queue_add(&tmcf->deleting, &router->sockets); 907115Sigor@sysoev.ru nxt_queue_init(&router->sockets); 90853Sigor@sysoev.ru } 90953Sigor@sysoev.ru 91053Sigor@sysoev.ru 91153Sigor@sysoev.ru static nxt_int_t 91253Sigor@sysoev.ru nxt_router_listen_sockets_stub_create(nxt_task_t *task, 91353Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 91453Sigor@sysoev.ru { 915115Sigor@sysoev.ru nxt_int_t ret; 916115Sigor@sysoev.ru nxt_socket_t s; 917115Sigor@sysoev.ru nxt_queue_link_t *qlk, *nqlk; 918115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 919115Sigor@sysoev.ru nxt_router_socket_t *rtsk; 92053Sigor@sysoev.ru 92153Sigor@sysoev.ru for (qlk = nxt_queue_first(&tmcf->pending); 92253Sigor@sysoev.ru qlk != nxt_queue_tail(&tmcf->pending); 92353Sigor@sysoev.ru qlk = nqlk) 92453Sigor@sysoev.ru { 925115Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 926115Sigor@sysoev.ru 927115Sigor@sysoev.ru s = nxt_listen_socket_create0(task, skcf->sockaddr, NXT_NONBLOCK); 928115Sigor@sysoev.ru if (nxt_slow_path(s == -1)) { 929115Sigor@sysoev.ru return NXT_ERROR; 930115Sigor@sysoev.ru } 931115Sigor@sysoev.ru 932115Sigor@sysoev.ru ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG); 933115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 934148Sigor@sysoev.ru goto fail; 935115Sigor@sysoev.ru } 936115Sigor@sysoev.ru 937115Sigor@sysoev.ru skcf->listen.socket = s; 938115Sigor@sysoev.ru 939148Sigor@sysoev.ru rtsk = nxt_malloc(sizeof(nxt_router_socket_t)); 940148Sigor@sysoev.ru if (nxt_slow_path(rtsk == NULL)) { 941148Sigor@sysoev.ru goto fail; 942148Sigor@sysoev.ru } 943148Sigor@sysoev.ru 944148Sigor@sysoev.ru rtsk->count = 0; 945148Sigor@sysoev.ru rtsk->fd = skcf->listen.socket; 946148Sigor@sysoev.ru skcf->socket = rtsk; 947115Sigor@sysoev.ru 94853Sigor@sysoev.ru nqlk = nxt_queue_next(qlk); 94953Sigor@sysoev.ru nxt_queue_remove(qlk); 95053Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->creating, qlk); 95153Sigor@sysoev.ru } 95253Sigor@sysoev.ru 95353Sigor@sysoev.ru return NXT_OK; 954148Sigor@sysoev.ru 955148Sigor@sysoev.ru fail: 956148Sigor@sysoev.ru 957148Sigor@sysoev.ru nxt_socket_close(task, s); 958148Sigor@sysoev.ru 959148Sigor@sysoev.ru return NXT_ERROR; 96053Sigor@sysoev.ru } 96153Sigor@sysoev.ru 96253Sigor@sysoev.ru 96353Sigor@sysoev.ru static nxt_int_t 96453Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router, 96553Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface) 96653Sigor@sysoev.ru { 96753Sigor@sysoev.ru nxt_int_t ret; 96853Sigor@sysoev.ru nxt_uint_t n, threads; 96953Sigor@sysoev.ru nxt_queue_link_t *qlk; 97053Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 97153Sigor@sysoev.ru 97253Sigor@sysoev.ru threads = tmcf->conf->threads; 97353Sigor@sysoev.ru 97453Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, threads, 97553Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 97653Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 97753Sigor@sysoev.ru return NXT_ERROR; 97853Sigor@sysoev.ru } 97953Sigor@sysoev.ru 98053Sigor@sysoev.ru n = 0; 98153Sigor@sysoev.ru 98253Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->engines); 98353Sigor@sysoev.ru qlk != nxt_queue_tail(&router->engines); 98453Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 98553Sigor@sysoev.ru { 98653Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 98753Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 98853Sigor@sysoev.ru return NXT_ERROR; 98953Sigor@sysoev.ru } 99053Sigor@sysoev.ru 991115Sigor@sysoev.ru recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0); 99253Sigor@sysoev.ru 99353Sigor@sysoev.ru if (n < threads) { 994115Sigor@sysoev.ru ret = nxt_router_engine_conf_update(tmcf, recf); 99553Sigor@sysoev.ru 99653Sigor@sysoev.ru } else { 997115Sigor@sysoev.ru ret = nxt_router_engine_conf_delete(tmcf, recf); 99853Sigor@sysoev.ru } 99953Sigor@sysoev.ru 100053Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 100153Sigor@sysoev.ru return ret; 100253Sigor@sysoev.ru } 100353Sigor@sysoev.ru 100453Sigor@sysoev.ru n++; 100553Sigor@sysoev.ru } 100653Sigor@sysoev.ru 100753Sigor@sysoev.ru tmcf->new_threads = n; 100853Sigor@sysoev.ru 100953Sigor@sysoev.ru while (n < threads) { 101053Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 101153Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 101253Sigor@sysoev.ru return NXT_ERROR; 101353Sigor@sysoev.ru } 101453Sigor@sysoev.ru 101553Sigor@sysoev.ru recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0); 101653Sigor@sysoev.ru if (nxt_slow_path(recf->engine == NULL)) { 101753Sigor@sysoev.ru return NXT_ERROR; 101853Sigor@sysoev.ru } 101953Sigor@sysoev.ru 1020115Sigor@sysoev.ru ret = nxt_router_engine_conf_create(tmcf, recf); 102153Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 102253Sigor@sysoev.ru return ret; 102353Sigor@sysoev.ru } 102453Sigor@sysoev.ru 1025115Sigor@sysoev.ru nxt_queue_insert_tail(&router->engines, &recf->engine->link0); 1026115Sigor@sysoev.ru 102753Sigor@sysoev.ru n++; 102853Sigor@sysoev.ru } 102953Sigor@sysoev.ru 103053Sigor@sysoev.ru return NXT_OK; 103153Sigor@sysoev.ru } 103253Sigor@sysoev.ru 103353Sigor@sysoev.ru 103453Sigor@sysoev.ru static nxt_int_t 1035115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 1036115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 103753Sigor@sysoev.ru { 1038115Sigor@sysoev.ru nxt_int_t ret; 1039115Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 104053Sigor@sysoev.ru 1041154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 1042154Sigor@sysoev.ru nxt_router_listen_socket_create); 1043115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1044115Sigor@sysoev.ru return ret; 1045115Sigor@sysoev.ru } 1046115Sigor@sysoev.ru 1047154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 1048154Sigor@sysoev.ru nxt_router_listen_socket_create); 104953Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 105053Sigor@sysoev.ru return ret; 105153Sigor@sysoev.ru } 105253Sigor@sysoev.ru 1053115Sigor@sysoev.ru lock = &tmcf->conf->router->lock; 1054115Sigor@sysoev.ru 1055115Sigor@sysoev.ru nxt_thread_spin_lock(lock); 1056115Sigor@sysoev.ru 1057115Sigor@sysoev.ru nxt_router_engine_socket_count(&tmcf->creating); 1058115Sigor@sysoev.ru nxt_router_engine_socket_count(&tmcf->updating); 1059115Sigor@sysoev.ru 1060115Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 1061115Sigor@sysoev.ru 1062115Sigor@sysoev.ru return ret; 106353Sigor@sysoev.ru } 106453Sigor@sysoev.ru 106553Sigor@sysoev.ru 106653Sigor@sysoev.ru static nxt_int_t 1067115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 1068115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 106953Sigor@sysoev.ru { 1070115Sigor@sysoev.ru nxt_int_t ret; 1071115Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 107253Sigor@sysoev.ru 1073154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 1074154Sigor@sysoev.ru nxt_router_listen_socket_create); 107553Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 107653Sigor@sysoev.ru return ret; 107753Sigor@sysoev.ru } 107853Sigor@sysoev.ru 1079154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 1080154Sigor@sysoev.ru nxt_router_listen_socket_update); 108153Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 108253Sigor@sysoev.ru return ret; 108353Sigor@sysoev.ru } 108453Sigor@sysoev.ru 1085139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 1086115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1087115Sigor@sysoev.ru return ret; 1088115Sigor@sysoev.ru } 1089115Sigor@sysoev.ru 1090115Sigor@sysoev.ru lock = &tmcf->conf->router->lock; 1091115Sigor@sysoev.ru 1092115Sigor@sysoev.ru nxt_thread_spin_lock(lock); 1093115Sigor@sysoev.ru 1094115Sigor@sysoev.ru nxt_router_engine_socket_count(&tmcf->creating); 1095115Sigor@sysoev.ru 1096115Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 1097115Sigor@sysoev.ru 1098115Sigor@sysoev.ru return ret; 109953Sigor@sysoev.ru } 110053Sigor@sysoev.ru 110153Sigor@sysoev.ru 110253Sigor@sysoev.ru static nxt_int_t 1103115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 1104115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 110553Sigor@sysoev.ru { 110653Sigor@sysoev.ru nxt_int_t ret; 110753Sigor@sysoev.ru 1108139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating); 110953Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 111053Sigor@sysoev.ru return ret; 111153Sigor@sysoev.ru } 111253Sigor@sysoev.ru 1113139Sigor@sysoev.ru return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 111453Sigor@sysoev.ru } 111553Sigor@sysoev.ru 111653Sigor@sysoev.ru 111753Sigor@sysoev.ru static nxt_int_t 1118154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 1119154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 112053Sigor@sysoev.ru nxt_work_handler_t handler) 112153Sigor@sysoev.ru { 1122153Sigor@sysoev.ru nxt_joint_job_t *job; 112353Sigor@sysoev.ru nxt_queue_link_t *qlk; 1124155Sigor@sysoev.ru nxt_socket_conf_t *skcf; 112553Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 112653Sigor@sysoev.ru 112753Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 112853Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 112953Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 113053Sigor@sysoev.ru { 1131154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 1132153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 1133139Sigor@sysoev.ru return NXT_ERROR; 1134139Sigor@sysoev.ru } 1135139Sigor@sysoev.ru 1136154Sigor@sysoev.ru job->work.next = recf->jobs; 1137154Sigor@sysoev.ru recf->jobs = &job->work; 1138154Sigor@sysoev.ru 1139153Sigor@sysoev.ru job->task = tmcf->engine->task; 1140153Sigor@sysoev.ru job->work.handler = handler; 1141153Sigor@sysoev.ru job->work.task = &job->task; 1142153Sigor@sysoev.ru job->work.obj = job; 1143153Sigor@sysoev.ru job->tmcf = tmcf; 114453Sigor@sysoev.ru 1145154Sigor@sysoev.ru tmcf->count++; 1146154Sigor@sysoev.ru 1147154Sigor@sysoev.ru joint = nxt_mp_alloc(tmcf->conf->mem_pool, 1148154Sigor@sysoev.ru sizeof(nxt_socket_conf_joint_t)); 114953Sigor@sysoev.ru if (nxt_slow_path(joint == NULL)) { 115053Sigor@sysoev.ru return NXT_ERROR; 115153Sigor@sysoev.ru } 115253Sigor@sysoev.ru 1153153Sigor@sysoev.ru job->work.data = joint; 115453Sigor@sysoev.ru 115553Sigor@sysoev.ru joint->count = 1; 1156155Sigor@sysoev.ru 1157155Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1158155Sigor@sysoev.ru skcf->count++; 1159155Sigor@sysoev.ru joint->socket_conf = skcf; 1160155Sigor@sysoev.ru 116188Smax.romanov@nginx.com joint->engine = recf->engine; 116253Sigor@sysoev.ru } 116353Sigor@sysoev.ru 116420Sigor@sysoev.ru return NXT_OK; 116520Sigor@sysoev.ru } 116620Sigor@sysoev.ru 116720Sigor@sysoev.ru 1168115Sigor@sysoev.ru static void 1169115Sigor@sysoev.ru nxt_router_engine_socket_count(nxt_queue_t *sockets) 1170115Sigor@sysoev.ru { 1171115Sigor@sysoev.ru nxt_queue_link_t *qlk; 1172115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1173115Sigor@sysoev.ru 1174115Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 1175115Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 1176115Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 1177115Sigor@sysoev.ru { 1178115Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1179115Sigor@sysoev.ru skcf->socket->count++; 1180115Sigor@sysoev.ru } 1181115Sigor@sysoev.ru } 1182115Sigor@sysoev.ru 1183115Sigor@sysoev.ru 118420Sigor@sysoev.ru static nxt_int_t 1185139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 1186139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets) 118720Sigor@sysoev.ru { 1188153Sigor@sysoev.ru nxt_joint_job_t *job; 118953Sigor@sysoev.ru nxt_queue_link_t *qlk; 119020Sigor@sysoev.ru 119153Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 119253Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 119353Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 119453Sigor@sysoev.ru { 1195154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 1196153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 1197139Sigor@sysoev.ru return NXT_ERROR; 1198139Sigor@sysoev.ru } 1199139Sigor@sysoev.ru 1200154Sigor@sysoev.ru job->work.next = recf->jobs; 1201154Sigor@sysoev.ru recf->jobs = &job->work; 1202154Sigor@sysoev.ru 1203153Sigor@sysoev.ru job->task = tmcf->engine->task; 1204153Sigor@sysoev.ru job->work.handler = nxt_router_listen_socket_delete; 1205153Sigor@sysoev.ru job->work.task = &job->task; 1206153Sigor@sysoev.ru job->work.obj = job; 1207153Sigor@sysoev.ru job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1208153Sigor@sysoev.ru job->tmcf = tmcf; 1209154Sigor@sysoev.ru 1210154Sigor@sysoev.ru tmcf->count++; 121120Sigor@sysoev.ru } 121220Sigor@sysoev.ru 121353Sigor@sysoev.ru return NXT_OK; 121453Sigor@sysoev.ru } 121520Sigor@sysoev.ru 121620Sigor@sysoev.ru 121753Sigor@sysoev.ru static nxt_int_t 121853Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 121953Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 122053Sigor@sysoev.ru { 122153Sigor@sysoev.ru nxt_int_t ret; 122253Sigor@sysoev.ru nxt_uint_t i, threads; 122353Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 122420Sigor@sysoev.ru 122553Sigor@sysoev.ru recf = tmcf->engines->elts; 122653Sigor@sysoev.ru threads = tmcf->conf->threads; 122720Sigor@sysoev.ru 122853Sigor@sysoev.ru for (i = tmcf->new_threads; i < threads; i++) { 122953Sigor@sysoev.ru ret = nxt_router_thread_create(task, rt, recf[i].engine); 123053Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 123153Sigor@sysoev.ru return ret; 123253Sigor@sysoev.ru } 123320Sigor@sysoev.ru } 123420Sigor@sysoev.ru 123520Sigor@sysoev.ru return NXT_OK; 123620Sigor@sysoev.ru } 123753Sigor@sysoev.ru 123853Sigor@sysoev.ru 123953Sigor@sysoev.ru static nxt_int_t 124053Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 124153Sigor@sysoev.ru nxt_event_engine_t *engine) 124253Sigor@sysoev.ru { 124353Sigor@sysoev.ru nxt_int_t ret; 124453Sigor@sysoev.ru nxt_thread_link_t *link; 124553Sigor@sysoev.ru nxt_thread_handle_t handle; 124653Sigor@sysoev.ru 124753Sigor@sysoev.ru link = nxt_zalloc(sizeof(nxt_thread_link_t)); 124853Sigor@sysoev.ru 124953Sigor@sysoev.ru if (nxt_slow_path(link == NULL)) { 125053Sigor@sysoev.ru return NXT_ERROR; 125153Sigor@sysoev.ru } 125253Sigor@sysoev.ru 125353Sigor@sysoev.ru link->start = nxt_router_thread_start; 125453Sigor@sysoev.ru link->engine = engine; 125553Sigor@sysoev.ru link->work.handler = nxt_router_thread_exit_handler; 125653Sigor@sysoev.ru link->work.task = task; 125753Sigor@sysoev.ru link->work.data = link; 125853Sigor@sysoev.ru 125953Sigor@sysoev.ru nxt_queue_insert_tail(&rt->engines, &engine->link); 126053Sigor@sysoev.ru 126153Sigor@sysoev.ru ret = nxt_thread_create(&handle, link); 126253Sigor@sysoev.ru 126353Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 126453Sigor@sysoev.ru nxt_queue_remove(&engine->link); 126553Sigor@sysoev.ru } 126653Sigor@sysoev.ru 126753Sigor@sysoev.ru return ret; 126853Sigor@sysoev.ru } 126953Sigor@sysoev.ru 127053Sigor@sysoev.ru 127153Sigor@sysoev.ru static void 1272133Sigor@sysoev.ru nxt_router_apps_sort(nxt_router_t *router, nxt_router_temp_conf_t *tmcf) 1273133Sigor@sysoev.ru { 1274167Smax.romanov@nginx.com nxt_app_t *app; 1275167Smax.romanov@nginx.com nxt_port_t *port; 1276141Smax.romanov@nginx.com 1277141Smax.romanov@nginx.com nxt_queue_each(app, &router->apps, nxt_app_t, link) { 1278133Sigor@sysoev.ru 1279133Sigor@sysoev.ru nxt_queue_remove(&app->link); 1280133Sigor@sysoev.ru 1281167Smax.romanov@nginx.com nxt_thread_log_debug("about to remove app '%V' %p", &app->name, app); 1282167Smax.romanov@nginx.com 1283163Smax.romanov@nginx.com app->live = 0; 1284163Smax.romanov@nginx.com 1285167Smax.romanov@nginx.com if (nxt_router_app_free(NULL, app) != 0) { 1286163Smax.romanov@nginx.com continue; 1287163Smax.romanov@nginx.com } 1288163Smax.romanov@nginx.com 1289167Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->requests)) { 1290167Smax.romanov@nginx.com 1291167Smax.romanov@nginx.com nxt_thread_log_debug("app '%V' %p pending requests found", 1292167Smax.romanov@nginx.com &app->name, app); 1293167Smax.romanov@nginx.com continue; 1294163Smax.romanov@nginx.com } 1295163Smax.romanov@nginx.com 1296167Smax.romanov@nginx.com do { 1297167Smax.romanov@nginx.com port = nxt_router_app_get_port(app, 0); 1298167Smax.romanov@nginx.com if (port == NULL) { 1299167Smax.romanov@nginx.com break; 1300167Smax.romanov@nginx.com } 1301167Smax.romanov@nginx.com 1302167Smax.romanov@nginx.com nxt_thread_log_debug("port %p send quit", port); 1303167Smax.romanov@nginx.com 1304167Smax.romanov@nginx.com nxt_port_socket_write(&port->engine->task, port, 1305167Smax.romanov@nginx.com NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 1306167Smax.romanov@nginx.com } while (1); 1307167Smax.romanov@nginx.com 1308141Smax.romanov@nginx.com } nxt_queue_loop; 1309133Sigor@sysoev.ru 1310133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->previous); 1311133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->apps); 1312133Sigor@sysoev.ru } 1313133Sigor@sysoev.ru 1314133Sigor@sysoev.ru 1315133Sigor@sysoev.ru static void 131653Sigor@sysoev.ru nxt_router_engines_post(nxt_router_temp_conf_t *tmcf) 131753Sigor@sysoev.ru { 131853Sigor@sysoev.ru nxt_uint_t n; 131953Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 132053Sigor@sysoev.ru 132153Sigor@sysoev.ru recf = tmcf->engines->elts; 132253Sigor@sysoev.ru 132353Sigor@sysoev.ru for (n = tmcf->engines->nelts; n != 0; n--) { 1324154Sigor@sysoev.ru nxt_router_engine_post(recf); 132553Sigor@sysoev.ru recf++; 132653Sigor@sysoev.ru } 132753Sigor@sysoev.ru } 132853Sigor@sysoev.ru 132953Sigor@sysoev.ru 133053Sigor@sysoev.ru static void 1331154Sigor@sysoev.ru nxt_router_engine_post(nxt_router_engine_conf_t *recf) 133253Sigor@sysoev.ru { 1333154Sigor@sysoev.ru nxt_work_t *work, *next; 1334154Sigor@sysoev.ru 1335154Sigor@sysoev.ru for (work = recf->jobs; work != NULL; work = next) { 1336154Sigor@sysoev.ru next = work->next; 1337154Sigor@sysoev.ru work->next = NULL; 1338154Sigor@sysoev.ru 1339154Sigor@sysoev.ru nxt_event_engine_post(recf->engine, work); 134053Sigor@sysoev.ru } 134153Sigor@sysoev.ru } 134253Sigor@sysoev.ru 134353Sigor@sysoev.ru 134453Sigor@sysoev.ru static void 1345119Smax.romanov@nginx.com nxt_router_app_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); 134688Smax.romanov@nginx.com 1347119Smax.romanov@nginx.com static nxt_port_handler_t nxt_router_app_port_handlers[] = { 1348192Smax.romanov@nginx.com NULL, /* NXT_PORT_MSG_QUIT */ 1349192Smax.romanov@nginx.com NULL, /* NXT_PORT_MSG_NEW_PORT */ 1350192Smax.romanov@nginx.com NULL, /* NXT_PORT_MSG_CHANGE_FILE */ 1351192Smax.romanov@nginx.com /* TODO: remove mmap_handler from app ports */ 1352192Smax.romanov@nginx.com nxt_port_mmap_handler, /* NXT_PORT_MSG_MMAP */ 1353119Smax.romanov@nginx.com nxt_router_app_data_handler, 1354192Smax.romanov@nginx.com NULL, /* NXT_PORT_MSG_REMOVE_PID */ 1355192Smax.romanov@nginx.com NULL, /* NXT_PORT_MSG_READY */ 1356192Smax.romanov@nginx.com NULL, /* NXT_PORT_MSG_START_WORKER */ 1357190Smax.romanov@nginx.com nxt_port_rpc_handler, 1358190Smax.romanov@nginx.com nxt_port_rpc_handler, 135988Smax.romanov@nginx.com }; 136088Smax.romanov@nginx.com 136188Smax.romanov@nginx.com 136288Smax.romanov@nginx.com static void 136353Sigor@sysoev.ru nxt_router_thread_start(void *data) 136453Sigor@sysoev.ru { 1365141Smax.romanov@nginx.com nxt_int_t ret; 1366141Smax.romanov@nginx.com nxt_port_t *port; 136788Smax.romanov@nginx.com nxt_task_t *task; 136853Sigor@sysoev.ru nxt_thread_t *thread; 136953Sigor@sysoev.ru nxt_thread_link_t *link; 137053Sigor@sysoev.ru nxt_event_engine_t *engine; 137153Sigor@sysoev.ru 137253Sigor@sysoev.ru link = data; 137353Sigor@sysoev.ru engine = link->engine; 137488Smax.romanov@nginx.com task = &engine->task; 137553Sigor@sysoev.ru 137653Sigor@sysoev.ru thread = nxt_thread(); 137753Sigor@sysoev.ru 1378165Smax.romanov@nginx.com nxt_event_engine_thread_adopt(engine); 1379165Smax.romanov@nginx.com 138053Sigor@sysoev.ru /* STUB */ 138153Sigor@sysoev.ru thread->runtime = engine->task.thread->runtime; 138253Sigor@sysoev.ru 138353Sigor@sysoev.ru engine->task.thread = thread; 138453Sigor@sysoev.ru engine->task.log = thread->log; 138553Sigor@sysoev.ru thread->engine = engine; 138663Sigor@sysoev.ru thread->task = &engine->task; 138753Sigor@sysoev.ru thread->fiber = &engine->fibers->fiber; 138853Sigor@sysoev.ru 138963Sigor@sysoev.ru engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64); 139053Sigor@sysoev.ru 1391163Smax.romanov@nginx.com port = nxt_port_new(nxt_port_get_next_id(), nxt_pid, NXT_PROCESS_ROUTER); 1392141Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 1393141Smax.romanov@nginx.com return; 1394141Smax.romanov@nginx.com } 1395141Smax.romanov@nginx.com 1396141Smax.romanov@nginx.com ret = nxt_port_socket_init(task, port, 0); 1397141Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 1398163Smax.romanov@nginx.com nxt_mp_release(port->mem_pool, port); 1399141Smax.romanov@nginx.com return; 1400141Smax.romanov@nginx.com } 1401141Smax.romanov@nginx.com 1402141Smax.romanov@nginx.com engine->port = port; 1403141Smax.romanov@nginx.com 1404141Smax.romanov@nginx.com nxt_port_enable(task, port, nxt_router_app_port_handlers); 1405141Smax.romanov@nginx.com 140653Sigor@sysoev.ru nxt_event_engine_start(engine); 140753Sigor@sysoev.ru } 140853Sigor@sysoev.ru 140953Sigor@sysoev.ru 141053Sigor@sysoev.ru static void 141153Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data) 141253Sigor@sysoev.ru { 1413153Sigor@sysoev.ru nxt_joint_job_t *job; 141453Sigor@sysoev.ru nxt_listen_event_t *listen; 141553Sigor@sysoev.ru nxt_listen_socket_t *ls; 141653Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 141753Sigor@sysoev.ru 1418153Sigor@sysoev.ru job = obj; 141953Sigor@sysoev.ru joint = data; 142053Sigor@sysoev.ru 142153Sigor@sysoev.ru ls = &joint->socket_conf->listen; 142253Sigor@sysoev.ru 1423159Sigor@sysoev.ru nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link); 1424159Sigor@sysoev.ru 142553Sigor@sysoev.ru listen = nxt_listen_event(task, ls); 142653Sigor@sysoev.ru if (nxt_slow_path(listen == NULL)) { 142753Sigor@sysoev.ru nxt_router_listen_socket_release(task, joint); 142853Sigor@sysoev.ru return; 142953Sigor@sysoev.ru } 143053Sigor@sysoev.ru 143153Sigor@sysoev.ru listen->socket.data = joint; 1432139Sigor@sysoev.ru 1433153Sigor@sysoev.ru job->work.next = NULL; 1434153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 1435153Sigor@sysoev.ru 1436153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 143753Sigor@sysoev.ru } 143853Sigor@sysoev.ru 143953Sigor@sysoev.ru 144053Sigor@sysoev.ru nxt_inline nxt_listen_event_t * 144153Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections, 144253Sigor@sysoev.ru nxt_socket_conf_t *skcf) 144353Sigor@sysoev.ru { 1444115Sigor@sysoev.ru nxt_socket_t fd; 1445115Sigor@sysoev.ru nxt_queue_link_t *qlk; 144653Sigor@sysoev.ru nxt_listen_event_t *listen; 144753Sigor@sysoev.ru 1448115Sigor@sysoev.ru fd = skcf->socket->fd; 144953Sigor@sysoev.ru 1450115Sigor@sysoev.ru for (qlk = nxt_queue_first(listen_connections); 1451115Sigor@sysoev.ru qlk != nxt_queue_tail(listen_connections); 1452115Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 145353Sigor@sysoev.ru { 1454115Sigor@sysoev.ru listen = nxt_queue_link_data(qlk, nxt_listen_event_t, link); 145553Sigor@sysoev.ru 1456115Sigor@sysoev.ru if (fd == listen->socket.fd) { 145753Sigor@sysoev.ru return listen; 145853Sigor@sysoev.ru } 145953Sigor@sysoev.ru } 146053Sigor@sysoev.ru 146153Sigor@sysoev.ru return NULL; 146253Sigor@sysoev.ru } 146353Sigor@sysoev.ru 146453Sigor@sysoev.ru 146553Sigor@sysoev.ru static void 146653Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data) 146753Sigor@sysoev.ru { 1468153Sigor@sysoev.ru nxt_joint_job_t *job; 146953Sigor@sysoev.ru nxt_event_engine_t *engine; 147053Sigor@sysoev.ru nxt_listen_event_t *listen; 147153Sigor@sysoev.ru nxt_socket_conf_joint_t *joint, *old; 147253Sigor@sysoev.ru 1473153Sigor@sysoev.ru job = obj; 147453Sigor@sysoev.ru joint = data; 147553Sigor@sysoev.ru 1476139Sigor@sysoev.ru engine = task->thread->engine; 1477139Sigor@sysoev.ru 1478159Sigor@sysoev.ru nxt_queue_insert_tail(&engine->joints, &joint->link); 1479159Sigor@sysoev.ru 148053Sigor@sysoev.ru listen = nxt_router_listen_event(&engine->listen_connections, 148153Sigor@sysoev.ru joint->socket_conf); 148253Sigor@sysoev.ru 148353Sigor@sysoev.ru old = listen->socket.data; 148453Sigor@sysoev.ru listen->socket.data = joint; 1485177Sigor@sysoev.ru listen->listen = &joint->socket_conf->listen; 148653Sigor@sysoev.ru 1487153Sigor@sysoev.ru job->work.next = NULL; 1488153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 1489153Sigor@sysoev.ru 1490153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 1491139Sigor@sysoev.ru 1492181Smax.romanov@nginx.com /* 1493181Smax.romanov@nginx.com * The task is allocated from configuration temporary 1494181Smax.romanov@nginx.com * memory pool so it can be freed after engine post operation. 1495181Smax.romanov@nginx.com */ 1496181Smax.romanov@nginx.com 1497181Smax.romanov@nginx.com nxt_router_conf_release(&engine->task, old); 149853Sigor@sysoev.ru } 149953Sigor@sysoev.ru 150053Sigor@sysoev.ru 150153Sigor@sysoev.ru static void 150253Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data) 150353Sigor@sysoev.ru { 1504153Sigor@sysoev.ru nxt_joint_job_t *job; 1505153Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1506153Sigor@sysoev.ru nxt_listen_event_t *listen; 1507153Sigor@sysoev.ru nxt_event_engine_t *engine; 1508153Sigor@sysoev.ru 1509153Sigor@sysoev.ru job = obj; 151053Sigor@sysoev.ru skcf = data; 151153Sigor@sysoev.ru 1512139Sigor@sysoev.ru engine = task->thread->engine; 1513139Sigor@sysoev.ru 151453Sigor@sysoev.ru listen = nxt_router_listen_event(&engine->listen_connections, skcf); 151553Sigor@sysoev.ru 151653Sigor@sysoev.ru nxt_fd_event_delete(engine, &listen->socket); 151753Sigor@sysoev.ru 1518163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket delete: %d", engine, 1519163Smax.romanov@nginx.com listen->socket.fd); 1520163Smax.romanov@nginx.com 152153Sigor@sysoev.ru listen->timer.handler = nxt_router_listen_socket_close; 152253Sigor@sysoev.ru listen->timer.work_queue = &engine->fast_work_queue; 152353Sigor@sysoev.ru 152453Sigor@sysoev.ru nxt_timer_add(engine, &listen->timer, 0); 1525139Sigor@sysoev.ru 1526153Sigor@sysoev.ru job->work.next = NULL; 1527153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 1528153Sigor@sysoev.ru 1529153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 153053Sigor@sysoev.ru } 153153Sigor@sysoev.ru 153253Sigor@sysoev.ru 153353Sigor@sysoev.ru static void 153453Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data) 153553Sigor@sysoev.ru { 153653Sigor@sysoev.ru nxt_timer_t *timer; 153753Sigor@sysoev.ru nxt_listen_event_t *listen; 153853Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 153953Sigor@sysoev.ru 154053Sigor@sysoev.ru timer = obj; 154153Sigor@sysoev.ru listen = nxt_timer_data(timer, nxt_listen_event_t, timer); 154253Sigor@sysoev.ru joint = listen->socket.data; 154353Sigor@sysoev.ru 1544163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine, 1545163Smax.romanov@nginx.com listen->socket.fd); 1546163Smax.romanov@nginx.com 154753Sigor@sysoev.ru nxt_queue_remove(&listen->link); 1548123Smax.romanov@nginx.com 1549123Smax.romanov@nginx.com /* 'task' refers to listen->task and we cannot use after nxt_free() */ 1550123Smax.romanov@nginx.com task = &task->thread->engine->task; 1551123Smax.romanov@nginx.com 155253Sigor@sysoev.ru nxt_free(listen); 155353Sigor@sysoev.ru 155453Sigor@sysoev.ru nxt_router_listen_socket_release(task, joint); 155553Sigor@sysoev.ru } 155653Sigor@sysoev.ru 155753Sigor@sysoev.ru 155853Sigor@sysoev.ru static void 155953Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, 156053Sigor@sysoev.ru nxt_socket_conf_joint_t *joint) 156153Sigor@sysoev.ru { 1562118Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1563115Sigor@sysoev.ru nxt_router_socket_t *rtsk; 156453Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 156553Sigor@sysoev.ru 1566118Sigor@sysoev.ru skcf = joint->socket_conf; 1567118Sigor@sysoev.ru rtsk = skcf->socket; 1568118Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 156953Sigor@sysoev.ru 157053Sigor@sysoev.ru nxt_thread_spin_lock(lock); 157153Sigor@sysoev.ru 1572163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket release: rtsk->count %D", 1573163Smax.romanov@nginx.com task->thread->engine, rtsk->count); 1574163Smax.romanov@nginx.com 1575115Sigor@sysoev.ru if (--rtsk->count != 0) { 1576115Sigor@sysoev.ru rtsk = NULL; 157753Sigor@sysoev.ru } 157853Sigor@sysoev.ru 157953Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 158053Sigor@sysoev.ru 1581115Sigor@sysoev.ru if (rtsk != NULL) { 1582115Sigor@sysoev.ru nxt_socket_close(task, rtsk->fd); 1583115Sigor@sysoev.ru nxt_free(rtsk); 1584118Sigor@sysoev.ru skcf->socket = NULL; 158553Sigor@sysoev.ru } 158653Sigor@sysoev.ru 158753Sigor@sysoev.ru nxt_router_conf_release(task, joint); 158853Sigor@sysoev.ru } 158953Sigor@sysoev.ru 159053Sigor@sysoev.ru 159153Sigor@sysoev.ru static void 159253Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint) 159353Sigor@sysoev.ru { 1594156Sigor@sysoev.ru nxt_bool_t exit; 159553Sigor@sysoev.ru nxt_socket_conf_t *skcf; 159653Sigor@sysoev.ru nxt_router_conf_t *rtcf; 159753Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 159853Sigor@sysoev.ru 1599163Smax.romanov@nginx.com nxt_debug(task, "conf joint %p count: %D", joint, joint->count); 160053Sigor@sysoev.ru 160153Sigor@sysoev.ru if (--joint->count != 0) { 160253Sigor@sysoev.ru return; 160353Sigor@sysoev.ru } 160453Sigor@sysoev.ru 160553Sigor@sysoev.ru nxt_queue_remove(&joint->link); 160653Sigor@sysoev.ru 160753Sigor@sysoev.ru skcf = joint->socket_conf; 160853Sigor@sysoev.ru rtcf = skcf->router_conf; 160953Sigor@sysoev.ru lock = &rtcf->router->lock; 161053Sigor@sysoev.ru 161153Sigor@sysoev.ru nxt_thread_spin_lock(lock); 161253Sigor@sysoev.ru 1613163Smax.romanov@nginx.com nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count, 1614163Smax.romanov@nginx.com rtcf, rtcf->count); 1615163Smax.romanov@nginx.com 161653Sigor@sysoev.ru if (--skcf->count != 0) { 161753Sigor@sysoev.ru rtcf = NULL; 161853Sigor@sysoev.ru 161953Sigor@sysoev.ru } else { 162053Sigor@sysoev.ru nxt_queue_remove(&skcf->link); 162153Sigor@sysoev.ru 162253Sigor@sysoev.ru if (--rtcf->count != 0) { 162353Sigor@sysoev.ru rtcf = NULL; 162453Sigor@sysoev.ru } 162553Sigor@sysoev.ru } 162653Sigor@sysoev.ru 162753Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 162853Sigor@sysoev.ru 1629141Smax.romanov@nginx.com /* TODO remove engine->port */ 1630141Smax.romanov@nginx.com /* TODO excude from connected ports */ 1631141Smax.romanov@nginx.com 1632156Sigor@sysoev.ru /* The joint content can be used before memory pool destruction. */ 1633156Sigor@sysoev.ru exit = nxt_queue_is_empty(&joint->engine->joints); 1634156Sigor@sysoev.ru 163553Sigor@sysoev.ru if (rtcf != NULL) { 1636115Sigor@sysoev.ru nxt_debug(task, "old router conf is destroyed"); 1637131Smax.romanov@nginx.com 1638131Smax.romanov@nginx.com nxt_mp_thread_adopt(rtcf->mem_pool); 1639131Smax.romanov@nginx.com 164065Sigor@sysoev.ru nxt_mp_destroy(rtcf->mem_pool); 164153Sigor@sysoev.ru } 164253Sigor@sysoev.ru 1643156Sigor@sysoev.ru if (exit) { 164453Sigor@sysoev.ru nxt_thread_exit(task->thread); 164553Sigor@sysoev.ru } 164653Sigor@sysoev.ru } 164753Sigor@sysoev.ru 164853Sigor@sysoev.ru 164953Sigor@sysoev.ru static void 165053Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data) 165153Sigor@sysoev.ru { 1652141Smax.romanov@nginx.com nxt_port_t *port; 165353Sigor@sysoev.ru nxt_thread_link_t *link; 165453Sigor@sysoev.ru nxt_event_engine_t *engine; 165553Sigor@sysoev.ru nxt_thread_handle_t handle; 165653Sigor@sysoev.ru 165758Svbart@nginx.com handle = (nxt_thread_handle_t) obj; 165853Sigor@sysoev.ru link = data; 165953Sigor@sysoev.ru 166053Sigor@sysoev.ru nxt_thread_wait(handle); 166153Sigor@sysoev.ru 166253Sigor@sysoev.ru engine = link->engine; 166353Sigor@sysoev.ru 166453Sigor@sysoev.ru nxt_queue_remove(&engine->link); 166553Sigor@sysoev.ru 1666141Smax.romanov@nginx.com port = engine->port; 1667141Smax.romanov@nginx.com 1668141Smax.romanov@nginx.com // TODO notify all apps 1669141Smax.romanov@nginx.com 1670163Smax.romanov@nginx.com nxt_mp_thread_adopt(port->mem_pool); 1671163Smax.romanov@nginx.com nxt_port_release(port); 1672163Smax.romanov@nginx.com 1673163Smax.romanov@nginx.com nxt_mp_thread_adopt(engine->mem_pool); 167463Sigor@sysoev.ru nxt_mp_destroy(engine->mem_pool); 167553Sigor@sysoev.ru 167653Sigor@sysoev.ru nxt_event_engine_free(engine); 167753Sigor@sysoev.ru 167853Sigor@sysoev.ru nxt_free(link); 167953Sigor@sysoev.ru } 168053Sigor@sysoev.ru 168153Sigor@sysoev.ru 168262Sigor@sysoev.ru static const nxt_conn_state_t nxt_router_conn_read_state 168353Sigor@sysoev.ru nxt_aligned(64) = 168453Sigor@sysoev.ru { 168553Sigor@sysoev.ru .ready_handler = nxt_router_conn_http_header_parse, 168653Sigor@sysoev.ru .close_handler = nxt_router_conn_close, 168753Sigor@sysoev.ru .error_handler = nxt_router_conn_error, 168853Sigor@sysoev.ru 168953Sigor@sysoev.ru .timer_handler = nxt_router_conn_timeout, 169053Sigor@sysoev.ru .timer_value = nxt_router_conn_timeout_value, 169153Sigor@sysoev.ru .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout), 169253Sigor@sysoev.ru }; 169353Sigor@sysoev.ru 169453Sigor@sysoev.ru 169553Sigor@sysoev.ru static void 169653Sigor@sysoev.ru nxt_router_conn_init(nxt_task_t *task, void *obj, void *data) 169753Sigor@sysoev.ru { 169853Sigor@sysoev.ru size_t size; 169962Sigor@sysoev.ru nxt_conn_t *c; 170053Sigor@sysoev.ru nxt_event_engine_t *engine; 170153Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 170253Sigor@sysoev.ru 170353Sigor@sysoev.ru c = obj; 170453Sigor@sysoev.ru joint = data; 170553Sigor@sysoev.ru 170653Sigor@sysoev.ru nxt_debug(task, "router conn init"); 170753Sigor@sysoev.ru 170853Sigor@sysoev.ru joint->count++; 170953Sigor@sysoev.ru 171053Sigor@sysoev.ru size = joint->socket_conf->header_buffer_size; 171153Sigor@sysoev.ru c->read = nxt_buf_mem_alloc(c->mem_pool, size, 0); 171253Sigor@sysoev.ru 171353Sigor@sysoev.ru c->socket.data = NULL; 171453Sigor@sysoev.ru 171553Sigor@sysoev.ru engine = task->thread->engine; 171653Sigor@sysoev.ru c->read_work_queue = &engine->fast_work_queue; 171753Sigor@sysoev.ru c->write_work_queue = &engine->fast_work_queue; 171853Sigor@sysoev.ru 171953Sigor@sysoev.ru c->read_state = &nxt_router_conn_read_state; 172053Sigor@sysoev.ru 172162Sigor@sysoev.ru nxt_conn_read(engine, c); 172253Sigor@sysoev.ru } 172353Sigor@sysoev.ru 172453Sigor@sysoev.ru 172562Sigor@sysoev.ru static const nxt_conn_state_t nxt_router_conn_write_state 172653Sigor@sysoev.ru nxt_aligned(64) = 172753Sigor@sysoev.ru { 172888Smax.romanov@nginx.com .ready_handler = nxt_router_conn_ready, 172953Sigor@sysoev.ru .close_handler = nxt_router_conn_close, 173053Sigor@sysoev.ru .error_handler = nxt_router_conn_error, 173153Sigor@sysoev.ru }; 173253Sigor@sysoev.ru 173353Sigor@sysoev.ru 173453Sigor@sysoev.ru static void 1735119Smax.romanov@nginx.com nxt_router_app_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 173688Smax.romanov@nginx.com { 173788Smax.romanov@nginx.com size_t dump_size; 173888Smax.romanov@nginx.com nxt_buf_t *b, *i, *last; 173988Smax.romanov@nginx.com nxt_conn_t *c; 174088Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 174188Smax.romanov@nginx.com nxt_event_engine_t *engine; 174288Smax.romanov@nginx.com 174388Smax.romanov@nginx.com b = msg->buf; 174488Smax.romanov@nginx.com engine = task->thread->engine; 174588Smax.romanov@nginx.com 174688Smax.romanov@nginx.com rc = nxt_event_engine_request_find(engine, msg->port_msg.stream); 174788Smax.romanov@nginx.com if (nxt_slow_path(rc == NULL)) { 174888Smax.romanov@nginx.com 174988Smax.romanov@nginx.com nxt_debug(task, "request id %08uxD not found", msg->port_msg.stream); 175088Smax.romanov@nginx.com 175195Smax.romanov@nginx.com /* Mark buffers as read. */ 175288Smax.romanov@nginx.com for (i = b; i != NULL; i = i->next) { 175388Smax.romanov@nginx.com i->mem.pos = i->mem.free; 175488Smax.romanov@nginx.com } 175588Smax.romanov@nginx.com 175688Smax.romanov@nginx.com return; 175788Smax.romanov@nginx.com } 175888Smax.romanov@nginx.com 175988Smax.romanov@nginx.com c = rc->conn; 176088Smax.romanov@nginx.com 176188Smax.romanov@nginx.com dump_size = nxt_buf_used_size(b); 176288Smax.romanov@nginx.com 176388Smax.romanov@nginx.com if (dump_size > 300) { 176488Smax.romanov@nginx.com dump_size = 300; 176588Smax.romanov@nginx.com } 176688Smax.romanov@nginx.com 1767119Smax.romanov@nginx.com nxt_debug(task, "%srouter app data (%z): %*s", 176888Smax.romanov@nginx.com msg->port_msg.last ? "last " : "", msg->size, dump_size, 176988Smax.romanov@nginx.com b->mem.pos); 177088Smax.romanov@nginx.com 177188Smax.romanov@nginx.com if (msg->size == 0) { 177288Smax.romanov@nginx.com b = NULL; 177388Smax.romanov@nginx.com } 177488Smax.romanov@nginx.com 177588Smax.romanov@nginx.com if (msg->port_msg.last != 0) { 177688Smax.romanov@nginx.com nxt_debug(task, "router data create last buf"); 177788Smax.romanov@nginx.com 177888Smax.romanov@nginx.com last = nxt_buf_sync_alloc(c->mem_pool, NXT_BUF_SYNC_LAST); 177988Smax.romanov@nginx.com if (nxt_slow_path(last == NULL)) { 178088Smax.romanov@nginx.com /* TODO pogorevaTb */ 178188Smax.romanov@nginx.com } 178288Smax.romanov@nginx.com 178388Smax.romanov@nginx.com nxt_buf_chain_add(&b, last); 1784167Smax.romanov@nginx.com 1785167Smax.romanov@nginx.com if (rc->app_port != NULL) { 1786167Smax.romanov@nginx.com nxt_router_app_release_port(task, rc->app_port, rc->app_port->app); 1787167Smax.romanov@nginx.com 1788167Smax.romanov@nginx.com rc->app_port = NULL; 1789167Smax.romanov@nginx.com } 179088Smax.romanov@nginx.com } 179188Smax.romanov@nginx.com 179288Smax.romanov@nginx.com if (b == NULL) { 179388Smax.romanov@nginx.com return; 179488Smax.romanov@nginx.com } 179588Smax.romanov@nginx.com 179688Smax.romanov@nginx.com if (c->write == NULL) { 179788Smax.romanov@nginx.com c->write = b; 179888Smax.romanov@nginx.com c->write_state = &nxt_router_conn_write_state; 179988Smax.romanov@nginx.com 180088Smax.romanov@nginx.com nxt_conn_write(task->thread->engine, c); 180188Smax.romanov@nginx.com } else { 180288Smax.romanov@nginx.com nxt_debug(task, "router data attach out bufs to existing chain"); 180388Smax.romanov@nginx.com 180488Smax.romanov@nginx.com nxt_buf_chain_add(&c->write, b); 180588Smax.romanov@nginx.com } 180688Smax.romanov@nginx.com } 180788Smax.romanov@nginx.com 1808141Smax.romanov@nginx.com nxt_inline const char * 1809141Smax.romanov@nginx.com nxt_router_text_by_code(int code) 1810141Smax.romanov@nginx.com { 1811141Smax.romanov@nginx.com switch (code) { 1812141Smax.romanov@nginx.com case 400: return "Bad request"; 1813141Smax.romanov@nginx.com case 404: return "Not found"; 1814141Smax.romanov@nginx.com case 403: return "Forbidden"; 1815141Smax.romanov@nginx.com case 500: 1816141Smax.romanov@nginx.com default: return "Internal server error"; 1817141Smax.romanov@nginx.com } 1818141Smax.romanov@nginx.com } 1819141Smax.romanov@nginx.com 1820163Smax.romanov@nginx.com 1821163Smax.romanov@nginx.com static nxt_buf_t * 1822163Smax.romanov@nginx.com nxt_router_get_error_buf(nxt_task_t *task, nxt_mp_t *mp, int code, 1823163Smax.romanov@nginx.com const char* fmt, va_list args) 182488Smax.romanov@nginx.com { 1825163Smax.romanov@nginx.com nxt_buf_t *b, *last; 1826163Smax.romanov@nginx.com const char *msg; 1827163Smax.romanov@nginx.com 1828163Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, mp, 16384); 1829141Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 1830163Smax.romanov@nginx.com return NULL; 1831141Smax.romanov@nginx.com } 1832141Smax.romanov@nginx.com 1833141Smax.romanov@nginx.com b->mem.free = nxt_sprintf(b->mem.free, b->mem.end, 1834141Smax.romanov@nginx.com "HTTP/1.0 %d %s\r\n" 1835141Smax.romanov@nginx.com "Content-Type: text/plain\r\n" 1836141Smax.romanov@nginx.com "Connection: close\r\n\r\n", 1837141Smax.romanov@nginx.com code, nxt_router_text_by_code(code)); 1838141Smax.romanov@nginx.com 1839141Smax.romanov@nginx.com msg = (const char *) b->mem.free; 1840141Smax.romanov@nginx.com 1841141Smax.romanov@nginx.com b->mem.free = nxt_vsprintf(b->mem.free, b->mem.end, fmt, args); 1842141Smax.romanov@nginx.com 1843141Smax.romanov@nginx.com nxt_log_alert(task->log, "error %d: %s", code, msg); 1844141Smax.romanov@nginx.com 1845163Smax.romanov@nginx.com last = nxt_buf_mem_ts_alloc(task, mp, 0); 1846163Smax.romanov@nginx.com 1847141Smax.romanov@nginx.com if (nxt_slow_path(last == NULL)) { 1848163Smax.romanov@nginx.com nxt_mp_release(mp, b); 1849163Smax.romanov@nginx.com return NULL; 1850141Smax.romanov@nginx.com } 1851141Smax.romanov@nginx.com 1852163Smax.romanov@nginx.com nxt_buf_set_sync(last); 1853163Smax.romanov@nginx.com nxt_buf_set_last(last); 1854163Smax.romanov@nginx.com 1855141Smax.romanov@nginx.com nxt_buf_chain_add(&b, last); 1856141Smax.romanov@nginx.com 1857163Smax.romanov@nginx.com return b; 1858163Smax.romanov@nginx.com } 1859163Smax.romanov@nginx.com 1860163Smax.romanov@nginx.com 1861163Smax.romanov@nginx.com 1862163Smax.romanov@nginx.com static void 1863163Smax.romanov@nginx.com nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code, 1864163Smax.romanov@nginx.com const char* fmt, ...) 1865163Smax.romanov@nginx.com { 1866163Smax.romanov@nginx.com va_list args; 1867163Smax.romanov@nginx.com nxt_buf_t *b; 1868163Smax.romanov@nginx.com 1869163Smax.romanov@nginx.com va_start(args, fmt); 1870163Smax.romanov@nginx.com b = nxt_router_get_error_buf(task, c->mem_pool, code, fmt, args); 1871163Smax.romanov@nginx.com va_end(args); 1872163Smax.romanov@nginx.com 1873141Smax.romanov@nginx.com if (c->write == NULL) { 1874141Smax.romanov@nginx.com c->write = b; 1875141Smax.romanov@nginx.com c->write_state = &nxt_router_conn_write_state; 1876141Smax.romanov@nginx.com 1877141Smax.romanov@nginx.com nxt_conn_write(task->thread->engine, c); 1878141Smax.romanov@nginx.com } else { 1879141Smax.romanov@nginx.com nxt_debug(task, "router data attach out bufs to existing chain"); 1880141Smax.romanov@nginx.com 1881141Smax.romanov@nginx.com nxt_buf_chain_add(&c->write, b); 1882141Smax.romanov@nginx.com } 1883141Smax.romanov@nginx.com } 1884141Smax.romanov@nginx.com 1885141Smax.romanov@nginx.com 1886141Smax.romanov@nginx.com static void 1887192Smax.romanov@nginx.com nxt_router_sw_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data) 1888192Smax.romanov@nginx.com { 1889192Smax.romanov@nginx.com nxt_start_worker_t *sw; 1890192Smax.romanov@nginx.com 1891192Smax.romanov@nginx.com sw = data; 1892192Smax.romanov@nginx.com 1893192Smax.romanov@nginx.com nxt_assert(sw != NULL); 1894192Smax.romanov@nginx.com nxt_assert(sw->app->pending_workers != 0); 1895192Smax.romanov@nginx.com 1896192Smax.romanov@nginx.com msg->new_port->app = sw->app; 1897192Smax.romanov@nginx.com 1898192Smax.romanov@nginx.com sw->app->pending_workers--; 1899192Smax.romanov@nginx.com sw->app->workers++; 1900192Smax.romanov@nginx.com 1901192Smax.romanov@nginx.com nxt_debug(task, "sw %p got port %p", sw, msg->new_port); 1902192Smax.romanov@nginx.com 1903192Smax.romanov@nginx.com nxt_router_app_release_port(task, msg->new_port, sw->app); 1904192Smax.romanov@nginx.com 1905192Smax.romanov@nginx.com nxt_router_sw_release(task, sw); 1906192Smax.romanov@nginx.com } 1907192Smax.romanov@nginx.com 1908192Smax.romanov@nginx.com 1909192Smax.romanov@nginx.com static void 1910192Smax.romanov@nginx.com nxt_router_sw_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data) 1911192Smax.romanov@nginx.com { 1912192Smax.romanov@nginx.com nxt_start_worker_t *sw; 1913192Smax.romanov@nginx.com 1914192Smax.romanov@nginx.com sw = data; 1915192Smax.romanov@nginx.com 1916192Smax.romanov@nginx.com nxt_assert(sw != NULL); 1917192Smax.romanov@nginx.com nxt_assert(sw->app->pending_workers != 0); 1918192Smax.romanov@nginx.com 1919192Smax.romanov@nginx.com sw->app->pending_workers--; 1920192Smax.romanov@nginx.com 1921192Smax.romanov@nginx.com nxt_debug(task, "sw %p error, failed to start app '%V'", sw, &sw->app->name); 1922192Smax.romanov@nginx.com 1923192Smax.romanov@nginx.com nxt_router_sw_release(task, sw); 1924192Smax.romanov@nginx.com } 1925192Smax.romanov@nginx.com 1926192Smax.romanov@nginx.com 1927192Smax.romanov@nginx.com static void 1928141Smax.romanov@nginx.com nxt_router_send_sw_request(nxt_task_t *task, void *obj, void *data) 1929141Smax.romanov@nginx.com { 1930174Sigor@sysoev.ru size_t size; 1931192Smax.romanov@nginx.com uint32_t stream; 1932141Smax.romanov@nginx.com nxt_buf_t *b; 1933141Smax.romanov@nginx.com nxt_app_t *app; 1934192Smax.romanov@nginx.com nxt_port_t *master_port, *router_port; 1935141Smax.romanov@nginx.com nxt_runtime_t *rt; 1936141Smax.romanov@nginx.com nxt_start_worker_t *sw; 1937141Smax.romanov@nginx.com 1938141Smax.romanov@nginx.com sw = obj; 1939141Smax.romanov@nginx.com app = sw->app; 1940141Smax.romanov@nginx.com 1941167Smax.romanov@nginx.com nxt_queue_insert_tail(&app->requests, &sw->ra->link); 1942167Smax.romanov@nginx.com 1943163Smax.romanov@nginx.com if (app->workers + app->pending_workers >= app->max_workers) { 1944167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p %uD/%uD running/penging workers, " 1945167Smax.romanov@nginx.com "post sw #%uxD release to %p", &app->name, app, 1946192Smax.romanov@nginx.com "sw %p release", &app->name, app, 1947192Smax.romanov@nginx.com app->workers, app->pending_workers, sw); 1948192Smax.romanov@nginx.com 1949192Smax.romanov@nginx.com nxt_router_sw_release(task, sw); 1950163Smax.romanov@nginx.com 1951163Smax.romanov@nginx.com return; 1952163Smax.romanov@nginx.com } 1953163Smax.romanov@nginx.com 1954163Smax.romanov@nginx.com app->pending_workers++; 1955163Smax.romanov@nginx.com 1956192Smax.romanov@nginx.com nxt_debug(task, "sw %p send", sw); 195788Smax.romanov@nginx.com 1958119Smax.romanov@nginx.com rt = task->thread->runtime; 1959192Smax.romanov@nginx.com master_port = rt->port_by_type[NXT_PROCESS_MASTER]; 1960192Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 1961141Smax.romanov@nginx.com 1962174Sigor@sysoev.ru size = app->name.length + 1 + app->conf.length; 1963174Sigor@sysoev.ru 1964192Smax.romanov@nginx.com b = nxt_buf_mem_alloc(master_port->mem_pool, size, 0); 1965174Sigor@sysoev.ru 1966174Sigor@sysoev.ru nxt_buf_cpystr(b, &app->name); 1967174Sigor@sysoev.ru *b->mem.free++ = '\0'; 1968141Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 1969141Smax.romanov@nginx.com 1970192Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 1971192Smax.romanov@nginx.com nxt_router_sw_ready, 1972192Smax.romanov@nginx.com nxt_router_sw_error, 1973192Smax.romanov@nginx.com master_port->pid, sw); 1974192Smax.romanov@nginx.com 1975192Smax.romanov@nginx.com nxt_port_socket_write(task, master_port, NXT_PORT_MSG_START_WORKER, -1, 1976192Smax.romanov@nginx.com stream, router_port->id, b); 1977141Smax.romanov@nginx.com } 1978141Smax.romanov@nginx.com 1979141Smax.romanov@nginx.com 1980163Smax.romanov@nginx.com static nxt_bool_t 1981167Smax.romanov@nginx.com nxt_router_app_free(nxt_task_t *task, nxt_app_t *app) 1982163Smax.romanov@nginx.com { 1983192Smax.romanov@nginx.com nxt_queue_link_t *lnk; 1984192Smax.romanov@nginx.com nxt_req_app_link_t *ra; 1985167Smax.romanov@nginx.com 1986167Smax.romanov@nginx.com nxt_thread_log_debug("app '%V' %p state: %d/%uD/%uD/%d", &app->name, app, 1987167Smax.romanov@nginx.com app->live, app->workers, app->pending_workers, 1988167Smax.romanov@nginx.com nxt_queue_is_empty(&app->requests)); 1989167Smax.romanov@nginx.com 1990163Smax.romanov@nginx.com if (app->live == 0 && app->workers == 0 && 1991163Smax.romanov@nginx.com app->pending_workers == 0 && 1992163Smax.romanov@nginx.com nxt_queue_is_empty(&app->requests)) { 1993163Smax.romanov@nginx.com 1994163Smax.romanov@nginx.com nxt_thread_mutex_destroy(&app->mutex); 1995163Smax.romanov@nginx.com nxt_free(app); 1996163Smax.romanov@nginx.com 1997163Smax.romanov@nginx.com return 1; 1998163Smax.romanov@nginx.com } 1999163Smax.romanov@nginx.com 2000167Smax.romanov@nginx.com if (app->live == 1 && nxt_queue_is_empty(&app->requests) == 0 && 2001167Smax.romanov@nginx.com (app->workers + app->pending_workers < app->max_workers)) { 2002167Smax.romanov@nginx.com 2003167Smax.romanov@nginx.com lnk = nxt_queue_first(&app->requests); 2004167Smax.romanov@nginx.com nxt_queue_remove(lnk); 2005167Smax.romanov@nginx.com 2006167Smax.romanov@nginx.com ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link); 2007167Smax.romanov@nginx.com 2008192Smax.romanov@nginx.com nxt_router_sw_create(task, app, ra); 2009167Smax.romanov@nginx.com } 2010167Smax.romanov@nginx.com 2011163Smax.romanov@nginx.com return 0; 2012163Smax.romanov@nginx.com } 2013163Smax.romanov@nginx.com 2014163Smax.romanov@nginx.com 2015141Smax.romanov@nginx.com static nxt_port_t * 2016167Smax.romanov@nginx.com nxt_router_app_get_port(nxt_app_t *app, uint32_t req_id) 2017141Smax.romanov@nginx.com { 2018141Smax.romanov@nginx.com nxt_port_t *port; 2019141Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2020141Smax.romanov@nginx.com 2021141Smax.romanov@nginx.com port = NULL; 2022141Smax.romanov@nginx.com 2023141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2024141Smax.romanov@nginx.com 2025141Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->ports)) { 2026141Smax.romanov@nginx.com lnk = nxt_queue_first(&app->ports); 2027141Smax.romanov@nginx.com nxt_queue_remove(lnk); 2028141Smax.romanov@nginx.com 2029141Smax.romanov@nginx.com lnk->next = NULL; 2030141Smax.romanov@nginx.com 2031141Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, app_link); 2032167Smax.romanov@nginx.com 2033167Smax.romanov@nginx.com port->app_req_id = req_id; 2034141Smax.romanov@nginx.com } 2035141Smax.romanov@nginx.com 2036141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2037141Smax.romanov@nginx.com 2038141Smax.romanov@nginx.com return port; 2039141Smax.romanov@nginx.com } 2040141Smax.romanov@nginx.com 2041141Smax.romanov@nginx.com 2042141Smax.romanov@nginx.com static void 2043141Smax.romanov@nginx.com nxt_router_app_release_port(nxt_task_t *task, void *obj, void *data) 2044141Smax.romanov@nginx.com { 2045141Smax.romanov@nginx.com nxt_app_t *app; 2046141Smax.romanov@nginx.com nxt_port_t *port; 2047141Smax.romanov@nginx.com nxt_work_t *work; 2048141Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2049167Smax.romanov@nginx.com nxt_req_app_link_t *ra; 2050141Smax.romanov@nginx.com 2051141Smax.romanov@nginx.com port = obj; 2052141Smax.romanov@nginx.com app = data; 2053141Smax.romanov@nginx.com 2054141Smax.romanov@nginx.com nxt_assert(app != NULL); 2055141Smax.romanov@nginx.com nxt_assert(app == port->app); 2056141Smax.romanov@nginx.com nxt_assert(port->app_link.next == NULL); 2057141Smax.romanov@nginx.com 2058141Smax.romanov@nginx.com 2059141Smax.romanov@nginx.com if (task->thread->engine != port->engine) { 2060163Smax.romanov@nginx.com work = &port->work; 2061141Smax.romanov@nginx.com 2062141Smax.romanov@nginx.com nxt_debug(task, "post release port to engine %p", port->engine); 2063141Smax.romanov@nginx.com 2064141Smax.romanov@nginx.com work->next = NULL; 2065141Smax.romanov@nginx.com work->handler = nxt_router_app_release_port; 2066166Smax.romanov@nginx.com work->task = &port->engine->task; 2067141Smax.romanov@nginx.com work->obj = port; 2068141Smax.romanov@nginx.com work->data = app; 2069141Smax.romanov@nginx.com 2070141Smax.romanov@nginx.com nxt_event_engine_post(port->engine, work); 2071141Smax.romanov@nginx.com 2072141Smax.romanov@nginx.com return; 2073141Smax.romanov@nginx.com } 2074141Smax.romanov@nginx.com 2075141Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->requests)) { 2076141Smax.romanov@nginx.com lnk = nxt_queue_first(&app->requests); 2077141Smax.romanov@nginx.com nxt_queue_remove(lnk); 2078141Smax.romanov@nginx.com 2079167Smax.romanov@nginx.com ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link); 2080167Smax.romanov@nginx.com 2081167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p process next request #%uxD", 2082167Smax.romanov@nginx.com &app->name, app, ra->req_id); 2083167Smax.romanov@nginx.com 2084167Smax.romanov@nginx.com ra->app_port = port; 2085182Smax.romanov@nginx.com port->app_req_id = ra->req_id; 2086167Smax.romanov@nginx.com 2087167Smax.romanov@nginx.com nxt_router_process_http_request_mp(task, ra, port); 2088167Smax.romanov@nginx.com 2089167Smax.romanov@nginx.com nxt_router_ra_release(task, ra, ra->work.data); 2090141Smax.romanov@nginx.com 2091141Smax.romanov@nginx.com return; 2092141Smax.romanov@nginx.com } 2093141Smax.romanov@nginx.com 2094167Smax.romanov@nginx.com port->app_req_id = 0; 2095167Smax.romanov@nginx.com 2096163Smax.romanov@nginx.com if (port->pair[1] == -1) { 2097167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p port already closed (pid %PI dead?)", 2098167Smax.romanov@nginx.com &app->name, app, port->pid); 2099163Smax.romanov@nginx.com 2100163Smax.romanov@nginx.com app->workers--; 2101167Smax.romanov@nginx.com nxt_router_app_free(task, app); 2102163Smax.romanov@nginx.com 2103163Smax.romanov@nginx.com port->app = NULL; 2104163Smax.romanov@nginx.com 2105163Smax.romanov@nginx.com nxt_port_release(port); 2106163Smax.romanov@nginx.com 2107163Smax.romanov@nginx.com return; 2108163Smax.romanov@nginx.com } 2109163Smax.romanov@nginx.com 2110163Smax.romanov@nginx.com if (!app->live) { 2111167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p is not alive, send QUIT to port", 2112167Smax.romanov@nginx.com &app->name, app); 2113163Smax.romanov@nginx.com 2114163Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, 2115163Smax.romanov@nginx.com -1, 0, 0, NULL); 2116163Smax.romanov@nginx.com 2117163Smax.romanov@nginx.com return; 2118163Smax.romanov@nginx.com } 2119163Smax.romanov@nginx.com 2120167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p requests queue is empty, keep the port", 2121167Smax.romanov@nginx.com &app->name, app); 2122141Smax.romanov@nginx.com 2123141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2124141Smax.romanov@nginx.com 2125141Smax.romanov@nginx.com nxt_queue_insert_head(&app->ports, &port->app_link); 2126141Smax.romanov@nginx.com 2127141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2128141Smax.romanov@nginx.com } 2129141Smax.romanov@nginx.com 2130141Smax.romanov@nginx.com 2131163Smax.romanov@nginx.com nxt_bool_t 2132141Smax.romanov@nginx.com nxt_router_app_remove_port(nxt_port_t *port) 2133141Smax.romanov@nginx.com { 2134163Smax.romanov@nginx.com nxt_app_t *app; 2135163Smax.romanov@nginx.com nxt_bool_t busy; 2136141Smax.romanov@nginx.com 2137141Smax.romanov@nginx.com app = port->app; 2138167Smax.romanov@nginx.com busy = port->app_req_id != 0; 2139163Smax.romanov@nginx.com 2140163Smax.romanov@nginx.com if (app == NULL) { 2141167Smax.romanov@nginx.com nxt_thread_log_debug("port %p app remove, no app", port); 2142167Smax.romanov@nginx.com 2143163Smax.romanov@nginx.com nxt_assert(port->app_link.next == NULL); 2144163Smax.romanov@nginx.com 2145163Smax.romanov@nginx.com return 1; 2146141Smax.romanov@nginx.com } 2147141Smax.romanov@nginx.com 2148141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2149141Smax.romanov@nginx.com 2150163Smax.romanov@nginx.com if (port->app_link.next != NULL) { 2151163Smax.romanov@nginx.com 2152163Smax.romanov@nginx.com nxt_queue_remove(&port->app_link); 2153163Smax.romanov@nginx.com port->app_link.next = NULL; 2154163Smax.romanov@nginx.com 2155163Smax.romanov@nginx.com } 2156141Smax.romanov@nginx.com 2157141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2158163Smax.romanov@nginx.com 2159163Smax.romanov@nginx.com if (busy == 0) { 2160167Smax.romanov@nginx.com nxt_thread_log_debug("port %p app remove, free, app '%V' %p", port, 2161167Smax.romanov@nginx.com &app->name, app); 2162163Smax.romanov@nginx.com 2163163Smax.romanov@nginx.com app->workers--; 2164167Smax.romanov@nginx.com nxt_router_app_free(&port->engine->task, app); 2165163Smax.romanov@nginx.com 2166163Smax.romanov@nginx.com return 1; 2167163Smax.romanov@nginx.com } 2168163Smax.romanov@nginx.com 2169167Smax.romanov@nginx.com nxt_thread_log_debug("port %p app remove, busy, app '%V' %p, req #%uxD", 2170167Smax.romanov@nginx.com port, &app->name, app, port->app_req_id); 2171167Smax.romanov@nginx.com 2172163Smax.romanov@nginx.com return 0; 2173141Smax.romanov@nginx.com } 2174141Smax.romanov@nginx.com 2175141Smax.romanov@nginx.com 2176167Smax.romanov@nginx.com static nxt_int_t 2177167Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_req_app_link_t *ra) 2178141Smax.romanov@nginx.com { 2179141Smax.romanov@nginx.com nxt_app_t *app; 2180141Smax.romanov@nginx.com nxt_conn_t *c; 2181167Smax.romanov@nginx.com nxt_port_t *port; 2182141Smax.romanov@nginx.com nxt_start_worker_t *sw; 2183141Smax.romanov@nginx.com nxt_socket_conf_joint_t *joint; 2184141Smax.romanov@nginx.com 2185141Smax.romanov@nginx.com port = NULL; 2186167Smax.romanov@nginx.com c = ra->rc->conn; 2187141Smax.romanov@nginx.com 2188141Smax.romanov@nginx.com joint = c->listen->socket.data; 2189141Smax.romanov@nginx.com app = joint->socket_conf->application; 2190141Smax.romanov@nginx.com 2191141Smax.romanov@nginx.com if (app == NULL) { 2192167Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, 2193141Smax.romanov@nginx.com "Application is NULL in socket_conf"); 2194141Smax.romanov@nginx.com return NXT_ERROR; 2195141Smax.romanov@nginx.com } 2196141Smax.romanov@nginx.com 2197141Smax.romanov@nginx.com 2198167Smax.romanov@nginx.com port = nxt_router_app_get_port(app, ra->req_id); 2199141Smax.romanov@nginx.com 2200141Smax.romanov@nginx.com if (port != NULL) { 2201163Smax.romanov@nginx.com nxt_debug(task, "already have port for app '%V'", &app->name); 2202163Smax.romanov@nginx.com 2203167Smax.romanov@nginx.com ra->app_port = port; 2204141Smax.romanov@nginx.com return NXT_OK; 2205141Smax.romanov@nginx.com } 2206141Smax.romanov@nginx.com 2207192Smax.romanov@nginx.com sw = nxt_router_sw_create(task, app, ra); 2208141Smax.romanov@nginx.com 2209141Smax.romanov@nginx.com if (nxt_slow_path(sw == NULL)) { 2210167Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, 2211141Smax.romanov@nginx.com "Failed to allocate start worker struct"); 2212141Smax.romanov@nginx.com return NXT_ERROR; 2213141Smax.romanov@nginx.com } 2214141Smax.romanov@nginx.com 2215141Smax.romanov@nginx.com return NXT_AGAIN; 221688Smax.romanov@nginx.com } 221788Smax.romanov@nginx.com 221888Smax.romanov@nginx.com 221988Smax.romanov@nginx.com static void 222053Sigor@sysoev.ru nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, void *data) 222153Sigor@sysoev.ru { 222288Smax.romanov@nginx.com size_t size, preread; 222353Sigor@sysoev.ru nxt_int_t ret; 222453Sigor@sysoev.ru nxt_buf_t *b; 222562Sigor@sysoev.ru nxt_conn_t *c; 222688Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 222753Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 222888Smax.romanov@nginx.com nxt_app_request_header_t *h; 222953Sigor@sysoev.ru 223053Sigor@sysoev.ru c = obj; 223188Smax.romanov@nginx.com ap = data; 223288Smax.romanov@nginx.com b = c->read; 223353Sigor@sysoev.ru 223453Sigor@sysoev.ru nxt_debug(task, "router conn http header parse"); 223553Sigor@sysoev.ru 223688Smax.romanov@nginx.com if (ap == NULL) { 223788Smax.romanov@nginx.com ap = nxt_mp_zget(c->mem_pool, sizeof(nxt_app_parse_ctx_t)); 223888Smax.romanov@nginx.com if (nxt_slow_path(ap == NULL)) { 223953Sigor@sysoev.ru nxt_router_conn_close(task, c, data); 224053Sigor@sysoev.ru return; 224153Sigor@sysoev.ru } 224253Sigor@sysoev.ru 224388Smax.romanov@nginx.com ret = nxt_app_http_req_init(task, ap); 224461Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 224561Sigor@sysoev.ru nxt_router_conn_close(task, c, data); 224661Sigor@sysoev.ru return; 224761Sigor@sysoev.ru } 224888Smax.romanov@nginx.com 224988Smax.romanov@nginx.com c->socket.data = ap; 2250113Smax.romanov@nginx.com 2251113Smax.romanov@nginx.com ap->r.remote.start = nxt_sockaddr_address(c->remote); 2252113Smax.romanov@nginx.com ap->r.remote.length = c->remote->address_length; 225353Sigor@sysoev.ru } 225453Sigor@sysoev.ru 225588Smax.romanov@nginx.com h = &ap->r.header; 225688Smax.romanov@nginx.com 225788Smax.romanov@nginx.com ret = nxt_app_http_req_parse(task, ap, b); 225853Sigor@sysoev.ru 225953Sigor@sysoev.ru nxt_debug(task, "http parse request: %d", ret); 226053Sigor@sysoev.ru 226153Sigor@sysoev.ru switch (nxt_expect(NXT_DONE, ret)) { 226253Sigor@sysoev.ru 226353Sigor@sysoev.ru case NXT_DONE: 226488Smax.romanov@nginx.com preread = nxt_buf_mem_used_size(&b->mem); 226588Smax.romanov@nginx.com 226688Smax.romanov@nginx.com nxt_debug(task, "router request header parsing complete, " 226788Smax.romanov@nginx.com "content length: %O, preread: %uz", 226888Smax.romanov@nginx.com h->parsed_content_length, preread); 226988Smax.romanov@nginx.com 227088Smax.romanov@nginx.com nxt_router_process_http_request(task, c, ap); 227188Smax.romanov@nginx.com return; 227253Sigor@sysoev.ru 227353Sigor@sysoev.ru case NXT_ERROR: 227453Sigor@sysoev.ru nxt_router_conn_close(task, c, data); 227553Sigor@sysoev.ru return; 227653Sigor@sysoev.ru 227753Sigor@sysoev.ru default: /* NXT_AGAIN */ 227853Sigor@sysoev.ru 227988Smax.romanov@nginx.com if (h->done == 0) { 228088Smax.romanov@nginx.com 228188Smax.romanov@nginx.com if (c->read->mem.free == c->read->mem.end) { 228288Smax.romanov@nginx.com joint = c->listen->socket.data; 228388Smax.romanov@nginx.com size = joint->socket_conf->large_header_buffer_size; 228488Smax.romanov@nginx.com 228588Smax.romanov@nginx.com if (size > (size_t) nxt_buf_mem_size(&b->mem)) { 228688Smax.romanov@nginx.com b = nxt_buf_mem_alloc(c->mem_pool, size, 0); 228788Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 228888Smax.romanov@nginx.com nxt_router_conn_close(task, c, data); 228988Smax.romanov@nginx.com return; 229088Smax.romanov@nginx.com } 229188Smax.romanov@nginx.com 229288Smax.romanov@nginx.com size = c->read->mem.free - c->read->mem.pos; 2293141Smax.romanov@nginx.com 2294141Smax.romanov@nginx.com c->read = nxt_buf_cpy(b, c->read->mem.pos, size); 229588Smax.romanov@nginx.com } else { 2296141Smax.romanov@nginx.com nxt_router_gen_error(task, c, 400, 2297141Smax.romanov@nginx.com "Too long request headers"); 2298141Smax.romanov@nginx.com return; 229988Smax.romanov@nginx.com } 230088Smax.romanov@nginx.com } 230188Smax.romanov@nginx.com } 230288Smax.romanov@nginx.com 230388Smax.romanov@nginx.com if (ap->r.body.done == 0) { 230488Smax.romanov@nginx.com 230588Smax.romanov@nginx.com preread = nxt_buf_mem_used_size(&b->mem); 230688Smax.romanov@nginx.com 230788Smax.romanov@nginx.com if (h->parsed_content_length - preread > 230888Smax.romanov@nginx.com (size_t) nxt_buf_mem_free_size(&b->mem)) { 230988Smax.romanov@nginx.com 231088Smax.romanov@nginx.com b = nxt_buf_mem_alloc(c->mem_pool, h->parsed_content_length, 0); 231188Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 2312141Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Failed to allocate " 2313141Smax.romanov@nginx.com "buffer for request body"); 2314141Smax.romanov@nginx.com return; 231588Smax.romanov@nginx.com } 231688Smax.romanov@nginx.com 2317141Smax.romanov@nginx.com c->read = nxt_buf_cpy(b, c->read->mem.pos, preread); 231853Sigor@sysoev.ru } 231953Sigor@sysoev.ru 232088Smax.romanov@nginx.com nxt_debug(task, "router request body read again, rest: %uz", 232188Smax.romanov@nginx.com h->parsed_content_length - preread); 232253Sigor@sysoev.ru 232353Sigor@sysoev.ru } 232453Sigor@sysoev.ru 232588Smax.romanov@nginx.com } 232688Smax.romanov@nginx.com 232788Smax.romanov@nginx.com nxt_conn_read(task->thread->engine, c); 232888Smax.romanov@nginx.com } 232988Smax.romanov@nginx.com 233088Smax.romanov@nginx.com 233188Smax.romanov@nginx.com static void 233288Smax.romanov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_conn_t *c, 233388Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap) 233488Smax.romanov@nginx.com { 2335167Smax.romanov@nginx.com nxt_mp_t *port_mp; 2336122Smax.romanov@nginx.com nxt_int_t res; 2337167Smax.romanov@nginx.com nxt_port_t *port; 233888Smax.romanov@nginx.com nxt_req_id_t req_id; 233988Smax.romanov@nginx.com nxt_event_engine_t *engine; 2340167Smax.romanov@nginx.com nxt_req_app_link_t *ra; 234188Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 234288Smax.romanov@nginx.com 234388Smax.romanov@nginx.com engine = task->thread->engine; 234488Smax.romanov@nginx.com 234588Smax.romanov@nginx.com do { 2346138Sigor@sysoev.ru req_id = nxt_random(&task->thread->random); 234788Smax.romanov@nginx.com } while (nxt_event_engine_request_find(engine, req_id) != NULL); 234888Smax.romanov@nginx.com 234988Smax.romanov@nginx.com rc = nxt_conn_request_add(c, req_id); 2350122Smax.romanov@nginx.com 235188Smax.romanov@nginx.com if (nxt_slow_path(rc == NULL)) { 2352141Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Failed to allocate " 2353141Smax.romanov@nginx.com "req->conn link"); 2354141Smax.romanov@nginx.com 2355141Smax.romanov@nginx.com return; 235688Smax.romanov@nginx.com } 235788Smax.romanov@nginx.com 235888Smax.romanov@nginx.com nxt_event_engine_request_add(engine, rc); 235988Smax.romanov@nginx.com 236088Smax.romanov@nginx.com nxt_debug(task, "req_id %uxD linked to conn %p at engine %p", 236188Smax.romanov@nginx.com req_id, c, engine); 236253Sigor@sysoev.ru 2363167Smax.romanov@nginx.com 2364167Smax.romanov@nginx.com ra = nxt_router_ra_create(task, rc); 2365167Smax.romanov@nginx.com 2366167Smax.romanov@nginx.com ra->ap = ap; 2367167Smax.romanov@nginx.com ra->reply_port = engine->port; 2368167Smax.romanov@nginx.com 2369167Smax.romanov@nginx.com res = nxt_router_app_port(task, ra); 2370141Smax.romanov@nginx.com 2371141Smax.romanov@nginx.com if (res != NXT_OK) { 2372141Smax.romanov@nginx.com return; 2373141Smax.romanov@nginx.com } 2374141Smax.romanov@nginx.com 2375167Smax.romanov@nginx.com port = ra->app_port; 2376141Smax.romanov@nginx.com 2377141Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 2378141Smax.romanov@nginx.com nxt_router_gen_error(task, rc->conn, 500, "Application port not found"); 2379141Smax.romanov@nginx.com return; 2380141Smax.romanov@nginx.com } 2381141Smax.romanov@nginx.com 2382122Smax.romanov@nginx.com port_mp = port->mem_pool; 2383167Smax.romanov@nginx.com port->mem_pool = c->mem_pool; 2384167Smax.romanov@nginx.com 2385167Smax.romanov@nginx.com nxt_router_process_http_request_mp(task, ra, port); 2386167Smax.romanov@nginx.com 2387167Smax.romanov@nginx.com port->mem_pool = port_mp; 2388167Smax.romanov@nginx.com 2389167Smax.romanov@nginx.com 2390167Smax.romanov@nginx.com nxt_router_ra_release(task, ra, ra->work.data); 2391167Smax.romanov@nginx.com } 2392167Smax.romanov@nginx.com 2393167Smax.romanov@nginx.com 2394167Smax.romanov@nginx.com static void 2395167Smax.romanov@nginx.com nxt_router_process_http_request_mp(nxt_task_t *task, nxt_req_app_link_t *ra, 2396167Smax.romanov@nginx.com nxt_port_t *port) 2397167Smax.romanov@nginx.com { 2398167Smax.romanov@nginx.com nxt_int_t res; 2399167Smax.romanov@nginx.com nxt_port_t *c_port, *reply_port; 2400167Smax.romanov@nginx.com nxt_conn_t *c; 2401167Smax.romanov@nginx.com nxt_app_wmsg_t wmsg; 2402167Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 2403167Smax.romanov@nginx.com 2404167Smax.romanov@nginx.com reply_port = ra->reply_port; 2405167Smax.romanov@nginx.com ap = ra->ap; 2406167Smax.romanov@nginx.com c = ra->rc->conn; 2407141Smax.romanov@nginx.com 2408141Smax.romanov@nginx.com c_port = nxt_process_connected_port_find(port->process, reply_port->pid, 2409141Smax.romanov@nginx.com reply_port->id); 2410141Smax.romanov@nginx.com if (nxt_slow_path(c_port != reply_port)) { 2411141Smax.romanov@nginx.com res = nxt_port_send_port(task, port, reply_port, 0); 2412122Smax.romanov@nginx.com 2413122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 2414167Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, 2415141Smax.romanov@nginx.com "Failed to send reply port to application"); 2416167Smax.romanov@nginx.com return; 2417122Smax.romanov@nginx.com } 2418122Smax.romanov@nginx.com 2419141Smax.romanov@nginx.com nxt_process_connected_port_add(port->process, reply_port); 242088Smax.romanov@nginx.com } 242188Smax.romanov@nginx.com 242288Smax.romanov@nginx.com wmsg.port = port; 242388Smax.romanov@nginx.com wmsg.write = NULL; 242488Smax.romanov@nginx.com wmsg.buf = &wmsg.write; 2425167Smax.romanov@nginx.com wmsg.stream = ra->req_id; 2426167Smax.romanov@nginx.com 2427167Smax.romanov@nginx.com res = port->app->module->prepare_msg(task, &ap->r, &wmsg); 2428122Smax.romanov@nginx.com 2429122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 2430167Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, 2431141Smax.romanov@nginx.com "Failed to prepare message for application"); 2432167Smax.romanov@nginx.com return; 2433122Smax.romanov@nginx.com } 243488Smax.romanov@nginx.com 243588Smax.romanov@nginx.com nxt_debug(task, "about to send %d bytes buffer to worker port %d", 243688Smax.romanov@nginx.com nxt_buf_used_size(wmsg.write), 243788Smax.romanov@nginx.com wmsg.port->socket.fd); 243888Smax.romanov@nginx.com 2439122Smax.romanov@nginx.com res = nxt_port_socket_write(task, wmsg.port, NXT_PORT_MSG_DATA, 2440167Smax.romanov@nginx.com -1, ra->req_id, reply_port->id, wmsg.write); 2441122Smax.romanov@nginx.com 2442122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 2443167Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, 2444141Smax.romanov@nginx.com "Failed to send message to application"); 2445167Smax.romanov@nginx.com return; 2446122Smax.romanov@nginx.com } 244753Sigor@sysoev.ru } 244853Sigor@sysoev.ru 244953Sigor@sysoev.ru 245062Sigor@sysoev.ru static const nxt_conn_state_t nxt_router_conn_close_state 245153Sigor@sysoev.ru nxt_aligned(64) = 245253Sigor@sysoev.ru { 245353Sigor@sysoev.ru .ready_handler = nxt_router_conn_free, 245453Sigor@sysoev.ru }; 245553Sigor@sysoev.ru 245653Sigor@sysoev.ru 245753Sigor@sysoev.ru static void 245888Smax.romanov@nginx.com nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data) 245988Smax.romanov@nginx.com { 246088Smax.romanov@nginx.com nxt_buf_t *b; 246188Smax.romanov@nginx.com nxt_bool_t last; 246288Smax.romanov@nginx.com nxt_conn_t *c; 246388Smax.romanov@nginx.com nxt_work_queue_t *wq; 246488Smax.romanov@nginx.com 246588Smax.romanov@nginx.com nxt_debug(task, "router conn ready %p", obj); 246688Smax.romanov@nginx.com 246788Smax.romanov@nginx.com c = obj; 246888Smax.romanov@nginx.com b = c->write; 246988Smax.romanov@nginx.com 247088Smax.romanov@nginx.com wq = &task->thread->engine->fast_work_queue; 247188Smax.romanov@nginx.com 247288Smax.romanov@nginx.com last = 0; 247388Smax.romanov@nginx.com 247488Smax.romanov@nginx.com while (b != NULL) { 247588Smax.romanov@nginx.com if (!nxt_buf_is_sync(b)) { 247688Smax.romanov@nginx.com if (nxt_buf_used_size(b) > 0) { 247788Smax.romanov@nginx.com break; 247888Smax.romanov@nginx.com } 247988Smax.romanov@nginx.com } 248088Smax.romanov@nginx.com 248188Smax.romanov@nginx.com if (nxt_buf_is_last(b)) { 248288Smax.romanov@nginx.com last = 1; 248388Smax.romanov@nginx.com } 248488Smax.romanov@nginx.com 248588Smax.romanov@nginx.com nxt_work_queue_add(wq, b->completion_handler, task, b, b->parent); 248688Smax.romanov@nginx.com 248788Smax.romanov@nginx.com b = b->next; 248888Smax.romanov@nginx.com } 248988Smax.romanov@nginx.com 249088Smax.romanov@nginx.com c->write = b; 249188Smax.romanov@nginx.com 249288Smax.romanov@nginx.com if (b != NULL) { 249388Smax.romanov@nginx.com nxt_debug(task, "router conn %p has more data to write", obj); 249488Smax.romanov@nginx.com 249588Smax.romanov@nginx.com nxt_conn_write(task->thread->engine, c); 249688Smax.romanov@nginx.com } else { 249788Smax.romanov@nginx.com nxt_debug(task, "router conn %p no more data to write, last = %d", obj, 249888Smax.romanov@nginx.com last); 249988Smax.romanov@nginx.com 250088Smax.romanov@nginx.com if (last != 0) { 250188Smax.romanov@nginx.com nxt_debug(task, "enqueue router conn close %p (ready handler)", c); 250288Smax.romanov@nginx.com 250388Smax.romanov@nginx.com nxt_work_queue_add(wq, nxt_router_conn_close, task, c, 250488Smax.romanov@nginx.com c->socket.data); 250588Smax.romanov@nginx.com } 250688Smax.romanov@nginx.com } 250788Smax.romanov@nginx.com } 250888Smax.romanov@nginx.com 250988Smax.romanov@nginx.com 251088Smax.romanov@nginx.com static void 251153Sigor@sysoev.ru nxt_router_conn_close(nxt_task_t *task, void *obj, void *data) 251253Sigor@sysoev.ru { 251362Sigor@sysoev.ru nxt_conn_t *c; 251453Sigor@sysoev.ru 251553Sigor@sysoev.ru c = obj; 251653Sigor@sysoev.ru 251753Sigor@sysoev.ru nxt_debug(task, "router conn close"); 251853Sigor@sysoev.ru 251953Sigor@sysoev.ru c->write_state = &nxt_router_conn_close_state; 252053Sigor@sysoev.ru 252162Sigor@sysoev.ru nxt_conn_close(task->thread->engine, c); 252253Sigor@sysoev.ru } 252353Sigor@sysoev.ru 252453Sigor@sysoev.ru 252553Sigor@sysoev.ru static void 2526164Smax.romanov@nginx.com nxt_router_conn_mp_cleanup(nxt_task_t *task, void *obj, void *data) 2527164Smax.romanov@nginx.com { 2528164Smax.romanov@nginx.com nxt_socket_conf_joint_t *joint; 2529164Smax.romanov@nginx.com 2530164Smax.romanov@nginx.com joint = obj; 2531164Smax.romanov@nginx.com 2532164Smax.romanov@nginx.com nxt_router_conf_release(task, joint); 2533164Smax.romanov@nginx.com } 2534164Smax.romanov@nginx.com 2535164Smax.romanov@nginx.com 2536164Smax.romanov@nginx.com static void 253753Sigor@sysoev.ru nxt_router_conn_free(nxt_task_t *task, void *obj, void *data) 253853Sigor@sysoev.ru { 253962Sigor@sysoev.ru nxt_conn_t *c; 254088Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 254153Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 254253Sigor@sysoev.ru 254353Sigor@sysoev.ru c = obj; 254453Sigor@sysoev.ru 254553Sigor@sysoev.ru nxt_debug(task, "router conn close done"); 254653Sigor@sysoev.ru 254788Smax.romanov@nginx.com nxt_queue_each(rc, &c->requests, nxt_req_conn_link_t, link) { 254888Smax.romanov@nginx.com 254988Smax.romanov@nginx.com nxt_debug(task, "conn %p close, req %uxD", c, rc->req_id); 255088Smax.romanov@nginx.com 2551141Smax.romanov@nginx.com if (rc->app_port != NULL) { 2552141Smax.romanov@nginx.com nxt_router_app_release_port(task, rc->app_port, rc->app_port->app); 2553141Smax.romanov@nginx.com 2554141Smax.romanov@nginx.com rc->app_port = NULL; 2555141Smax.romanov@nginx.com } 2556141Smax.romanov@nginx.com 2557167Smax.romanov@nginx.com rc->conn = NULL; 2558167Smax.romanov@nginx.com 255988Smax.romanov@nginx.com nxt_event_engine_request_remove(task->thread->engine, rc); 256088Smax.romanov@nginx.com 256188Smax.romanov@nginx.com } nxt_queue_loop; 256288Smax.romanov@nginx.com 2563122Smax.romanov@nginx.com nxt_queue_remove(&c->link); 2564122Smax.romanov@nginx.com 2565131Smax.romanov@nginx.com joint = c->listen->socket.data; 2566131Smax.romanov@nginx.com 2567131Smax.romanov@nginx.com task = &task->thread->engine->task; 2568131Smax.romanov@nginx.com 2569164Smax.romanov@nginx.com nxt_mp_cleanup(c->mem_pool, nxt_router_conn_mp_cleanup, task, joint, NULL); 2570164Smax.romanov@nginx.com 2571164Smax.romanov@nginx.com nxt_mp_release(c->mem_pool, c); 257253Sigor@sysoev.ru } 257353Sigor@sysoev.ru 257453Sigor@sysoev.ru 257553Sigor@sysoev.ru static void 257653Sigor@sysoev.ru nxt_router_conn_error(nxt_task_t *task, void *obj, void *data) 257753Sigor@sysoev.ru { 257862Sigor@sysoev.ru nxt_conn_t *c; 257953Sigor@sysoev.ru 258053Sigor@sysoev.ru c = obj; 258153Sigor@sysoev.ru 258253Sigor@sysoev.ru nxt_debug(task, "router conn error"); 258353Sigor@sysoev.ru 258453Sigor@sysoev.ru c->write_state = &nxt_router_conn_close_state; 258553Sigor@sysoev.ru 258662Sigor@sysoev.ru nxt_conn_close(task->thread->engine, c); 258753Sigor@sysoev.ru } 258853Sigor@sysoev.ru 258953Sigor@sysoev.ru 259053Sigor@sysoev.ru static void 259153Sigor@sysoev.ru nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data) 259253Sigor@sysoev.ru { 259362Sigor@sysoev.ru nxt_conn_t *c; 259462Sigor@sysoev.ru nxt_timer_t *timer; 259553Sigor@sysoev.ru 259653Sigor@sysoev.ru timer = obj; 259753Sigor@sysoev.ru 259853Sigor@sysoev.ru nxt_debug(task, "router conn timeout"); 259953Sigor@sysoev.ru 260062Sigor@sysoev.ru c = nxt_read_timer_conn(timer); 260153Sigor@sysoev.ru 260253Sigor@sysoev.ru c->write_state = &nxt_router_conn_close_state; 260353Sigor@sysoev.ru 260462Sigor@sysoev.ru nxt_conn_close(task->thread->engine, c); 260553Sigor@sysoev.ru } 260653Sigor@sysoev.ru 260753Sigor@sysoev.ru 260853Sigor@sysoev.ru static nxt_msec_t 260962Sigor@sysoev.ru nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data) 261053Sigor@sysoev.ru { 261153Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 261253Sigor@sysoev.ru 261353Sigor@sysoev.ru joint = c->listen->socket.data; 261453Sigor@sysoev.ru 261553Sigor@sysoev.ru return nxt_value_at(nxt_msec_t, joint->socket_conf, data); 261653Sigor@sysoev.ru } 2617