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 48198Sigor@sysoev.ru typedef struct { 49198Sigor@sysoev.ru nxt_socket_conf_t *socket_conf; 50198Sigor@sysoev.ru nxt_router_temp_conf_t *temp_conf; 51198Sigor@sysoev.ru } nxt_socket_rpc_t; 52198Sigor@sysoev.ru 53198Sigor@sysoev.ru 54139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task); 55198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data); 56198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task, 57139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 58139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task, 59139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 60139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task, 61193Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type); 6253Sigor@sysoev.ru static void nxt_router_listen_sockets_sort(nxt_router_t *router, 6353Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 6453Sigor@sysoev.ru 65115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task, 66115Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end); 67133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name); 68133Sigor@sysoev.ru static nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, 69133Sigor@sysoev.ru nxt_str_t *name); 70198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task, 71198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf); 72198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task, 73198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 74198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task, 75198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 7665Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, 7765Sigor@sysoev.ru nxt_sockaddr_t *sa); 7853Sigor@sysoev.ru 7953Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task, 8053Sigor@sysoev.ru nxt_router_t *router, nxt_router_temp_conf_t *tmcf, 8153Sigor@sysoev.ru const nxt_event_interface_t *interface); 82115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 83115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 84115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 85115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 86115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 87115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 88115Sigor@sysoev.ru static void nxt_router_engine_socket_count(nxt_queue_t *sockets); 89154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 90154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 91154Sigor@sysoev.ru nxt_work_handler_t handler); 92313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 93313Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 94139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 95139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets); 9653Sigor@sysoev.ru 9753Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 9853Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 9953Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 10053Sigor@sysoev.ru nxt_event_engine_t *engine); 101133Sigor@sysoev.ru static void nxt_router_apps_sort(nxt_router_t *router, 102133Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 10353Sigor@sysoev.ru 104*315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router, 105*315Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 106*315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine, 107*315Sigor@sysoev.ru nxt_work_t *jobs); 108277Sigor@sysoev.ru static void nxt_router_app_data_handler(nxt_task_t *task, 109277Sigor@sysoev.ru nxt_port_recv_msg_t *msg); 11053Sigor@sysoev.ru 11153Sigor@sysoev.ru static void nxt_router_thread_start(void *data); 11253Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj, 11353Sigor@sysoev.ru void *data); 11453Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj, 11553Sigor@sysoev.ru void *data); 11653Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, 11753Sigor@sysoev.ru void *data); 118313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, 119313Sigor@sysoev.ru void *data); 12053Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj, 12153Sigor@sysoev.ru void *data); 12253Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task, 12353Sigor@sysoev.ru nxt_socket_conf_joint_t *joint); 12453Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, 12553Sigor@sysoev.ru void *data); 12653Sigor@sysoev.ru static void nxt_router_conf_release(nxt_task_t *task, 12753Sigor@sysoev.ru nxt_socket_conf_joint_t *joint); 12853Sigor@sysoev.ru 129167Smax.romanov@nginx.com static void nxt_router_send_sw_request(nxt_task_t *task, void *obj, 130167Smax.romanov@nginx.com void *data); 131167Smax.romanov@nginx.com static nxt_bool_t nxt_router_app_free(nxt_task_t *task, nxt_app_t *app); 132167Smax.romanov@nginx.com static nxt_port_t * nxt_router_app_get_port(nxt_app_t *app, uint32_t req_id); 133141Smax.romanov@nginx.com static void nxt_router_app_release_port(nxt_task_t *task, void *obj, 134141Smax.romanov@nginx.com void *data); 135141Smax.romanov@nginx.com 13653Sigor@sysoev.ru static void nxt_router_conn_init(nxt_task_t *task, void *obj, void *data); 13753Sigor@sysoev.ru static void nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, 13853Sigor@sysoev.ru void *data); 139206Smax.romanov@nginx.com static void nxt_router_conn_http_body_read(nxt_task_t *task, void *obj, 140206Smax.romanov@nginx.com void *data); 14188Smax.romanov@nginx.com static void nxt_router_process_http_request(nxt_task_t *task, 14288Smax.romanov@nginx.com nxt_conn_t *c, nxt_app_parse_ctx_t *ap); 143141Smax.romanov@nginx.com static void nxt_router_process_http_request_mp(nxt_task_t *task, 144167Smax.romanov@nginx.com nxt_req_app_link_t *ra, nxt_port_t *port); 145216Sigor@sysoev.ru static nxt_int_t nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 146216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg); 147216Sigor@sysoev.ru static nxt_int_t nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 148216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg); 149216Sigor@sysoev.ru static nxt_int_t nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 150216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg); 15188Smax.romanov@nginx.com static void nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data); 15253Sigor@sysoev.ru static void nxt_router_conn_close(nxt_task_t *task, void *obj, void *data); 15353Sigor@sysoev.ru static void nxt_router_conn_free(nxt_task_t *task, void *obj, void *data); 15453Sigor@sysoev.ru static void nxt_router_conn_error(nxt_task_t *task, void *obj, void *data); 15553Sigor@sysoev.ru static void nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data); 15662Sigor@sysoev.ru static nxt_msec_t nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data); 15720Sigor@sysoev.ru 158141Smax.romanov@nginx.com static void nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code, 159141Smax.romanov@nginx.com const char* fmt, ...); 160141Smax.romanov@nginx.com 161119Smax.romanov@nginx.com static nxt_router_t *nxt_router; 16220Sigor@sysoev.ru 163216Sigor@sysoev.ru 164216Sigor@sysoev.ru static nxt_app_prepare_msg_t nxt_app_prepare_msg[] = { 165216Sigor@sysoev.ru nxt_python_prepare_msg, 166216Sigor@sysoev.ru nxt_php_prepare_msg, 167216Sigor@sysoev.ru nxt_go_prepare_msg, 168216Sigor@sysoev.ru }; 169216Sigor@sysoev.ru 170216Sigor@sysoev.ru 17120Sigor@sysoev.ru nxt_int_t 172141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data) 17320Sigor@sysoev.ru { 174141Smax.romanov@nginx.com nxt_int_t ret; 175141Smax.romanov@nginx.com nxt_router_t *router; 176141Smax.romanov@nginx.com nxt_runtime_t *rt; 177141Smax.romanov@nginx.com 178141Smax.romanov@nginx.com rt = task->thread->runtime; 17953Sigor@sysoev.ru 18088Smax.romanov@nginx.com ret = nxt_app_http_init(task, rt); 18188Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 18288Smax.romanov@nginx.com return ret; 18388Smax.romanov@nginx.com } 18488Smax.romanov@nginx.com 18553Sigor@sysoev.ru router = nxt_zalloc(sizeof(nxt_router_t)); 18653Sigor@sysoev.ru if (nxt_slow_path(router == NULL)) { 18753Sigor@sysoev.ru return NXT_ERROR; 18853Sigor@sysoev.ru } 18953Sigor@sysoev.ru 19053Sigor@sysoev.ru nxt_queue_init(&router->engines); 19153Sigor@sysoev.ru nxt_queue_init(&router->sockets); 192133Sigor@sysoev.ru nxt_queue_init(&router->apps); 19353Sigor@sysoev.ru 194119Smax.romanov@nginx.com nxt_router = router; 195119Smax.romanov@nginx.com 196115Sigor@sysoev.ru return NXT_OK; 197115Sigor@sysoev.ru } 198115Sigor@sysoev.ru 199115Sigor@sysoev.ru 200167Smax.romanov@nginx.com static nxt_start_worker_t * 201192Smax.romanov@nginx.com nxt_router_sw_create(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra) 202167Smax.romanov@nginx.com { 203240Sigor@sysoev.ru nxt_port_t *main_port; 204167Smax.romanov@nginx.com nxt_runtime_t *rt; 205167Smax.romanov@nginx.com nxt_start_worker_t *sw; 206167Smax.romanov@nginx.com 207192Smax.romanov@nginx.com sw = nxt_zalloc(sizeof(nxt_start_worker_t)); 208167Smax.romanov@nginx.com 209167Smax.romanov@nginx.com if (nxt_slow_path(sw == NULL)) { 210167Smax.romanov@nginx.com return NULL; 211167Smax.romanov@nginx.com } 212167Smax.romanov@nginx.com 213167Smax.romanov@nginx.com sw->app = app; 214167Smax.romanov@nginx.com sw->ra = ra; 215167Smax.romanov@nginx.com 216192Smax.romanov@nginx.com nxt_debug(task, "sw %p create, request #%uxD, app '%V' %p", sw, 217167Smax.romanov@nginx.com ra->req_id, &app->name, app); 218167Smax.romanov@nginx.com 219167Smax.romanov@nginx.com rt = task->thread->runtime; 220240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 221167Smax.romanov@nginx.com 222167Smax.romanov@nginx.com sw->work.handler = nxt_router_send_sw_request; 223240Sigor@sysoev.ru sw->work.task = &main_port->engine->task; 224167Smax.romanov@nginx.com sw->work.obj = sw; 225167Smax.romanov@nginx.com sw->work.data = task->thread->engine; 226167Smax.romanov@nginx.com sw->work.next = NULL; 227167Smax.romanov@nginx.com 228240Sigor@sysoev.ru if (task->thread->engine != main_port->engine) { 229240Sigor@sysoev.ru nxt_debug(task, "sw %p post send to main engine %p", sw, 230240Sigor@sysoev.ru main_port->engine); 231240Sigor@sysoev.ru 232240Sigor@sysoev.ru nxt_event_engine_post(main_port->engine, &sw->work); 233167Smax.romanov@nginx.com 234167Smax.romanov@nginx.com } else { 235167Smax.romanov@nginx.com nxt_router_send_sw_request(task, sw, sw->work.data); 236167Smax.romanov@nginx.com } 237167Smax.romanov@nginx.com 238167Smax.romanov@nginx.com return sw; 239167Smax.romanov@nginx.com } 240167Smax.romanov@nginx.com 241167Smax.romanov@nginx.com 242192Smax.romanov@nginx.com nxt_inline void 243192Smax.romanov@nginx.com nxt_router_sw_release(nxt_task_t *task, nxt_start_worker_t *sw) 244141Smax.romanov@nginx.com { 245192Smax.romanov@nginx.com nxt_debug(task, "sw %p release", sw); 246192Smax.romanov@nginx.com 247192Smax.romanov@nginx.com nxt_free(sw); 248141Smax.romanov@nginx.com } 249141Smax.romanov@nginx.com 250141Smax.romanov@nginx.com 251167Smax.romanov@nginx.com static nxt_req_app_link_t * 252167Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_conn_link_t *rc) 253167Smax.romanov@nginx.com { 254167Smax.romanov@nginx.com nxt_mp_t *mp; 255167Smax.romanov@nginx.com nxt_req_app_link_t *ra; 256167Smax.romanov@nginx.com 257167Smax.romanov@nginx.com mp = rc->conn->mem_pool; 258167Smax.romanov@nginx.com 259167Smax.romanov@nginx.com ra = nxt_mp_retain(mp, sizeof(nxt_req_app_link_t)); 260167Smax.romanov@nginx.com 261167Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 262167Smax.romanov@nginx.com return NULL; 263167Smax.romanov@nginx.com } 264167Smax.romanov@nginx.com 265275Smax.romanov@nginx.com nxt_debug(task, "ra #%uxD create", rc->req_id); 266167Smax.romanov@nginx.com 267167Smax.romanov@nginx.com nxt_memzero(ra, sizeof(nxt_req_app_link_t)); 268167Smax.romanov@nginx.com 269167Smax.romanov@nginx.com ra->req_id = rc->req_id; 270167Smax.romanov@nginx.com ra->app_port = NULL; 271167Smax.romanov@nginx.com ra->rc = rc; 272167Smax.romanov@nginx.com 273167Smax.romanov@nginx.com ra->mem_pool = mp; 274167Smax.romanov@nginx.com 275167Smax.romanov@nginx.com ra->work.handler = NULL; 276167Smax.romanov@nginx.com ra->work.task = &task->thread->engine->task; 277167Smax.romanov@nginx.com ra->work.obj = ra; 278167Smax.romanov@nginx.com ra->work.data = task->thread->engine; 279167Smax.romanov@nginx.com 280167Smax.romanov@nginx.com return ra; 281167Smax.romanov@nginx.com } 282167Smax.romanov@nginx.com 283167Smax.romanov@nginx.com 284167Smax.romanov@nginx.com static void 285167Smax.romanov@nginx.com nxt_router_ra_release(nxt_task_t *task, void *obj, void *data) 286167Smax.romanov@nginx.com { 287167Smax.romanov@nginx.com nxt_req_app_link_t *ra; 288167Smax.romanov@nginx.com nxt_event_engine_t *engine; 289167Smax.romanov@nginx.com 290167Smax.romanov@nginx.com ra = obj; 291167Smax.romanov@nginx.com engine = data; 292167Smax.romanov@nginx.com 293167Smax.romanov@nginx.com if (task->thread->engine != engine) { 294167Smax.romanov@nginx.com ra->work.handler = nxt_router_ra_release; 295167Smax.romanov@nginx.com ra->work.task = &engine->task; 296167Smax.romanov@nginx.com ra->work.next = NULL; 297167Smax.romanov@nginx.com 298167Smax.romanov@nginx.com nxt_debug(task, "ra #%uxD post release to %p", ra->req_id, engine); 299167Smax.romanov@nginx.com 300167Smax.romanov@nginx.com nxt_event_engine_post(engine, &ra->work); 301167Smax.romanov@nginx.com 302167Smax.romanov@nginx.com return; 303167Smax.romanov@nginx.com } 304167Smax.romanov@nginx.com 305167Smax.romanov@nginx.com nxt_debug(task, "ra #%uxD release", ra->req_id); 306167Smax.romanov@nginx.com 307167Smax.romanov@nginx.com if (ra->app_port != NULL) { 308167Smax.romanov@nginx.com 309264Smax.romanov@nginx.com nxt_router_app_release_port(task, ra->app_port, ra->app_port->app); 310264Smax.romanov@nginx.com 311264Smax.romanov@nginx.com #if 0 312264Smax.romanov@nginx.com /* Uncomment to hold app port until complete response received. */ 313167Smax.romanov@nginx.com if (ra->rc->conn != NULL) { 314167Smax.romanov@nginx.com ra->rc->app_port = ra->app_port; 315167Smax.romanov@nginx.com 316167Smax.romanov@nginx.com } else { 317167Smax.romanov@nginx.com nxt_router_app_release_port(task, ra->app_port, ra->app_port->app); 318167Smax.romanov@nginx.com } 319264Smax.romanov@nginx.com #endif 320167Smax.romanov@nginx.com } 321167Smax.romanov@nginx.com 322167Smax.romanov@nginx.com nxt_mp_release(ra->mem_pool, ra); 323167Smax.romanov@nginx.com } 324167Smax.romanov@nginx.com 325167Smax.romanov@nginx.com 326141Smax.romanov@nginx.com void 327141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 328141Smax.romanov@nginx.com { 329141Smax.romanov@nginx.com nxt_port_new_port_handler(task, msg); 330141Smax.romanov@nginx.com 331192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 332141Smax.romanov@nginx.com return; 333141Smax.romanov@nginx.com } 334141Smax.romanov@nginx.com 335192Smax.romanov@nginx.com if (msg->new_port == NULL || msg->new_port->type != NXT_PROCESS_WORKER) { 336192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 337141Smax.romanov@nginx.com } 338192Smax.romanov@nginx.com 339192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 340141Smax.romanov@nginx.com } 341141Smax.romanov@nginx.com 342141Smax.romanov@nginx.com 343139Sigor@sysoev.ru void 344139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 345115Sigor@sysoev.ru { 346139Sigor@sysoev.ru size_t dump_size; 347198Sigor@sysoev.ru nxt_int_t ret; 348139Sigor@sysoev.ru nxt_buf_t *b; 349139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 350139Sigor@sysoev.ru 351139Sigor@sysoev.ru b = msg->buf; 352139Sigor@sysoev.ru 353139Sigor@sysoev.ru dump_size = nxt_buf_used_size(b); 354139Sigor@sysoev.ru 355139Sigor@sysoev.ru if (dump_size > 300) { 356139Sigor@sysoev.ru dump_size = 300; 35753Sigor@sysoev.ru } 35853Sigor@sysoev.ru 359139Sigor@sysoev.ru nxt_debug(task, "router conf data (%z): %*s", 360139Sigor@sysoev.ru msg->size, dump_size, b->mem.pos); 361139Sigor@sysoev.ru 362139Sigor@sysoev.ru tmcf = nxt_router_temp_conf(task); 363139Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 364139Sigor@sysoev.ru return; 36553Sigor@sysoev.ru } 36653Sigor@sysoev.ru 367139Sigor@sysoev.ru tmcf->conf->router = nxt_router; 368139Sigor@sysoev.ru tmcf->stream = msg->port_msg.stream; 369139Sigor@sysoev.ru tmcf->port = nxt_runtime_port_find(task->thread->runtime, 370198Sigor@sysoev.ru msg->port_msg.pid, 371198Sigor@sysoev.ru msg->port_msg.reply_port); 372198Sigor@sysoev.ru 373198Sigor@sysoev.ru ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free); 374198Sigor@sysoev.ru 375198Sigor@sysoev.ru if (nxt_fast_path(ret == NXT_OK)) { 376198Sigor@sysoev.ru nxt_router_conf_apply(task, tmcf, NULL); 377198Sigor@sysoev.ru 378198Sigor@sysoev.ru } else { 379198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 380139Sigor@sysoev.ru } 38153Sigor@sysoev.ru } 38253Sigor@sysoev.ru 38353Sigor@sysoev.ru 384192Smax.romanov@nginx.com void 385192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 386192Smax.romanov@nginx.com { 387192Smax.romanov@nginx.com nxt_port_remove_pid_handler(task, msg); 388192Smax.romanov@nginx.com 389192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 390192Smax.romanov@nginx.com return; 391192Smax.romanov@nginx.com } 392192Smax.romanov@nginx.com 393192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 394192Smax.romanov@nginx.com 395192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 396192Smax.romanov@nginx.com } 397192Smax.romanov@nginx.com 398192Smax.romanov@nginx.com 39953Sigor@sysoev.ru static nxt_router_temp_conf_t * 400139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task) 40153Sigor@sysoev.ru { 40265Sigor@sysoev.ru nxt_mp_t *mp, *tmp; 40353Sigor@sysoev.ru nxt_router_conf_t *rtcf; 40453Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 40553Sigor@sysoev.ru 40665Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 40753Sigor@sysoev.ru if (nxt_slow_path(mp == NULL)) { 40853Sigor@sysoev.ru return NULL; 40953Sigor@sysoev.ru } 41053Sigor@sysoev.ru 41165Sigor@sysoev.ru rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t)); 41253Sigor@sysoev.ru if (nxt_slow_path(rtcf == NULL)) { 41353Sigor@sysoev.ru goto fail; 41453Sigor@sysoev.ru } 41553Sigor@sysoev.ru 41653Sigor@sysoev.ru rtcf->mem_pool = mp; 41753Sigor@sysoev.ru 41865Sigor@sysoev.ru tmp = nxt_mp_create(1024, 128, 256, 32); 41953Sigor@sysoev.ru if (nxt_slow_path(tmp == NULL)) { 42053Sigor@sysoev.ru goto fail; 42153Sigor@sysoev.ru } 42253Sigor@sysoev.ru 42365Sigor@sysoev.ru tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t)); 42453Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 42553Sigor@sysoev.ru goto temp_fail; 42653Sigor@sysoev.ru } 42753Sigor@sysoev.ru 42853Sigor@sysoev.ru tmcf->mem_pool = tmp; 42953Sigor@sysoev.ru tmcf->conf = rtcf; 430139Sigor@sysoev.ru tmcf->count = 1; 431139Sigor@sysoev.ru tmcf->engine = task->thread->engine; 43253Sigor@sysoev.ru 43353Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, 4, 43453Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 43553Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 43653Sigor@sysoev.ru goto temp_fail; 43753Sigor@sysoev.ru } 43853Sigor@sysoev.ru 43953Sigor@sysoev.ru nxt_queue_init(&tmcf->deleting); 44053Sigor@sysoev.ru nxt_queue_init(&tmcf->keeping); 44153Sigor@sysoev.ru nxt_queue_init(&tmcf->updating); 44253Sigor@sysoev.ru nxt_queue_init(&tmcf->pending); 44353Sigor@sysoev.ru nxt_queue_init(&tmcf->creating); 444133Sigor@sysoev.ru nxt_queue_init(&tmcf->apps); 445133Sigor@sysoev.ru nxt_queue_init(&tmcf->previous); 44653Sigor@sysoev.ru 44753Sigor@sysoev.ru return tmcf; 44853Sigor@sysoev.ru 44953Sigor@sysoev.ru temp_fail: 45053Sigor@sysoev.ru 45165Sigor@sysoev.ru nxt_mp_destroy(tmp); 45253Sigor@sysoev.ru 45353Sigor@sysoev.ru fail: 45453Sigor@sysoev.ru 45565Sigor@sysoev.ru nxt_mp_destroy(mp); 45653Sigor@sysoev.ru 45753Sigor@sysoev.ru return NULL; 45853Sigor@sysoev.ru } 45953Sigor@sysoev.ru 46053Sigor@sysoev.ru 461198Sigor@sysoev.ru static void 462198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data) 463139Sigor@sysoev.ru { 464139Sigor@sysoev.ru nxt_int_t ret; 465139Sigor@sysoev.ru nxt_router_t *router; 466139Sigor@sysoev.ru nxt_runtime_t *rt; 467198Sigor@sysoev.ru nxt_queue_link_t *qlk; 468198Sigor@sysoev.ru nxt_socket_conf_t *skcf; 469198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 470139Sigor@sysoev.ru const nxt_event_interface_t *interface; 471139Sigor@sysoev.ru 472198Sigor@sysoev.ru tmcf = obj; 473198Sigor@sysoev.ru 474198Sigor@sysoev.ru qlk = nxt_queue_first(&tmcf->pending); 475198Sigor@sysoev.ru 476198Sigor@sysoev.ru if (qlk != nxt_queue_tail(&tmcf->pending)) { 477198Sigor@sysoev.ru nxt_queue_remove(qlk); 478198Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->creating, qlk); 479198Sigor@sysoev.ru 480198Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 481198Sigor@sysoev.ru 482198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(task, tmcf, skcf); 483198Sigor@sysoev.ru 484198Sigor@sysoev.ru return; 485139Sigor@sysoev.ru } 486139Sigor@sysoev.ru 487139Sigor@sysoev.ru rt = task->thread->runtime; 488139Sigor@sysoev.ru 489139Sigor@sysoev.ru interface = nxt_service_get(rt->services, "engine", NULL); 490139Sigor@sysoev.ru 491198Sigor@sysoev.ru router = tmcf->conf->router; 492198Sigor@sysoev.ru 493139Sigor@sysoev.ru ret = nxt_router_engines_create(task, router, tmcf, interface); 494139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 495198Sigor@sysoev.ru goto fail; 496139Sigor@sysoev.ru } 497139Sigor@sysoev.ru 498139Sigor@sysoev.ru ret = nxt_router_threads_create(task, rt, tmcf); 499139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 500198Sigor@sysoev.ru goto fail; 501139Sigor@sysoev.ru } 502139Sigor@sysoev.ru 503139Sigor@sysoev.ru nxt_router_apps_sort(router, tmcf); 504139Sigor@sysoev.ru 505*315Sigor@sysoev.ru nxt_router_engines_post(router, tmcf); 506139Sigor@sysoev.ru 507139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->updating); 508139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->creating); 509139Sigor@sysoev.ru 510198Sigor@sysoev.ru nxt_router_conf_ready(task, tmcf); 511198Sigor@sysoev.ru 512198Sigor@sysoev.ru return; 513198Sigor@sysoev.ru 514198Sigor@sysoev.ru fail: 515198Sigor@sysoev.ru 516198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 517198Sigor@sysoev.ru 518198Sigor@sysoev.ru return; 519139Sigor@sysoev.ru } 520139Sigor@sysoev.ru 521139Sigor@sysoev.ru 522139Sigor@sysoev.ru static void 523139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data) 524139Sigor@sysoev.ru { 525153Sigor@sysoev.ru nxt_joint_job_t *job; 526153Sigor@sysoev.ru 527153Sigor@sysoev.ru job = obj; 528153Sigor@sysoev.ru 529198Sigor@sysoev.ru nxt_router_conf_ready(task, job->tmcf); 530139Sigor@sysoev.ru } 531139Sigor@sysoev.ru 532139Sigor@sysoev.ru 533139Sigor@sysoev.ru static void 534198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 535139Sigor@sysoev.ru { 536139Sigor@sysoev.ru nxt_debug(task, "temp conf count:%D", tmcf->count); 537139Sigor@sysoev.ru 538139Sigor@sysoev.ru if (--tmcf->count == 0) { 539193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST); 540139Sigor@sysoev.ru } 541139Sigor@sysoev.ru } 542139Sigor@sysoev.ru 543139Sigor@sysoev.ru 544139Sigor@sysoev.ru static void 545139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 546139Sigor@sysoev.ru { 547148Sigor@sysoev.ru nxt_socket_t s; 548149Sigor@sysoev.ru nxt_router_t *router; 549148Sigor@sysoev.ru nxt_queue_link_t *qlk; 550148Sigor@sysoev.ru nxt_socket_conf_t *skcf; 551148Sigor@sysoev.ru 552198Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "failed to apply new conf"); 553198Sigor@sysoev.ru 554148Sigor@sysoev.ru for (qlk = nxt_queue_first(&tmcf->creating); 555148Sigor@sysoev.ru qlk != nxt_queue_tail(&tmcf->creating); 556148Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 557148Sigor@sysoev.ru { 558148Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 559148Sigor@sysoev.ru s = skcf->listen.socket; 560148Sigor@sysoev.ru 561148Sigor@sysoev.ru if (s != -1) { 562148Sigor@sysoev.ru nxt_socket_close(task, s); 563148Sigor@sysoev.ru } 564148Sigor@sysoev.ru 565148Sigor@sysoev.ru nxt_free(skcf->socket); 566148Sigor@sysoev.ru } 567148Sigor@sysoev.ru 568149Sigor@sysoev.ru router = tmcf->conf->router; 569149Sigor@sysoev.ru 570149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->keeping); 571149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->deleting); 572149Sigor@sysoev.ru 573148Sigor@sysoev.ru // TODO: new engines and threads 574148Sigor@sysoev.ru 575139Sigor@sysoev.ru nxt_mp_destroy(tmcf->conf->mem_pool); 576139Sigor@sysoev.ru 577193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR); 578139Sigor@sysoev.ru } 579139Sigor@sysoev.ru 580139Sigor@sysoev.ru 581139Sigor@sysoev.ru static void 582139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 583193Smax.romanov@nginx.com nxt_port_msg_type_t type) 584139Sigor@sysoev.ru { 585193Smax.romanov@nginx.com nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL); 586139Sigor@sysoev.ru } 587139Sigor@sysoev.ru 588139Sigor@sysoev.ru 589115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_conf[] = { 590115Sigor@sysoev.ru { 591133Sigor@sysoev.ru nxt_string("listeners_threads"), 592115Sigor@sysoev.ru NXT_CONF_MAP_INT32, 593115Sigor@sysoev.ru offsetof(nxt_router_conf_t, threads), 594115Sigor@sysoev.ru }, 595115Sigor@sysoev.ru }; 596115Sigor@sysoev.ru 597115Sigor@sysoev.ru 598133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_app_conf[] = { 599115Sigor@sysoev.ru { 600133Sigor@sysoev.ru nxt_string("type"), 601115Sigor@sysoev.ru NXT_CONF_MAP_STR, 602133Sigor@sysoev.ru offsetof(nxt_router_app_conf_t, type), 603115Sigor@sysoev.ru }, 604115Sigor@sysoev.ru 605115Sigor@sysoev.ru { 606133Sigor@sysoev.ru nxt_string("workers"), 607115Sigor@sysoev.ru NXT_CONF_MAP_INT32, 608133Sigor@sysoev.ru offsetof(nxt_router_app_conf_t, workers), 609133Sigor@sysoev.ru }, 610133Sigor@sysoev.ru }; 611133Sigor@sysoev.ru 612133Sigor@sysoev.ru 613133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_listener_conf[] = { 614133Sigor@sysoev.ru { 615133Sigor@sysoev.ru nxt_string("application"), 616133Sigor@sysoev.ru NXT_CONF_MAP_STR, 617133Sigor@sysoev.ru offsetof(nxt_router_listener_conf_t, application), 618115Sigor@sysoev.ru }, 619115Sigor@sysoev.ru }; 620115Sigor@sysoev.ru 621115Sigor@sysoev.ru 622115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_http_conf[] = { 623115Sigor@sysoev.ru { 624115Sigor@sysoev.ru nxt_string("header_buffer_size"), 625115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 626115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_buffer_size), 627115Sigor@sysoev.ru }, 628115Sigor@sysoev.ru 629115Sigor@sysoev.ru { 630115Sigor@sysoev.ru nxt_string("large_header_buffer_size"), 631115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 632115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, large_header_buffer_size), 633115Sigor@sysoev.ru }, 634115Sigor@sysoev.ru 635115Sigor@sysoev.ru { 636206Smax.romanov@nginx.com nxt_string("large_header_buffers"), 637206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 638206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, large_header_buffers), 639206Smax.romanov@nginx.com }, 640206Smax.romanov@nginx.com 641206Smax.romanov@nginx.com { 642206Smax.romanov@nginx.com nxt_string("body_buffer_size"), 643206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 644206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_buffer_size), 645206Smax.romanov@nginx.com }, 646206Smax.romanov@nginx.com 647206Smax.romanov@nginx.com { 648206Smax.romanov@nginx.com nxt_string("max_body_size"), 649206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 650206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, max_body_size), 651206Smax.romanov@nginx.com }, 652206Smax.romanov@nginx.com 653206Smax.romanov@nginx.com { 654115Sigor@sysoev.ru nxt_string("header_read_timeout"), 655115Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 656115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_read_timeout), 657115Sigor@sysoev.ru }, 658206Smax.romanov@nginx.com 659206Smax.romanov@nginx.com { 660206Smax.romanov@nginx.com nxt_string("body_read_timeout"), 661206Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 662206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_read_timeout), 663206Smax.romanov@nginx.com }, 664115Sigor@sysoev.ru }; 665115Sigor@sysoev.ru 666115Sigor@sysoev.ru 66753Sigor@sysoev.ru static nxt_int_t 668115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 669115Sigor@sysoev.ru u_char *start, u_char *end) 67053Sigor@sysoev.ru { 671133Sigor@sysoev.ru u_char *p; 672133Sigor@sysoev.ru size_t size; 673115Sigor@sysoev.ru nxt_mp_t *mp; 674115Sigor@sysoev.ru uint32_t next; 675115Sigor@sysoev.ru nxt_int_t ret; 676115Sigor@sysoev.ru nxt_str_t name; 677133Sigor@sysoev.ru nxt_app_t *app, *prev; 678133Sigor@sysoev.ru nxt_app_type_t type; 679115Sigor@sysoev.ru nxt_sockaddr_t *sa; 680133Sigor@sysoev.ru nxt_conf_value_t *conf, *http; 681133Sigor@sysoev.ru nxt_conf_value_t *applications, *application; 682133Sigor@sysoev.ru nxt_conf_value_t *listeners, *listener; 683115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 684216Sigor@sysoev.ru nxt_app_lang_module_t *lang; 685133Sigor@sysoev.ru nxt_router_app_conf_t apcf; 686115Sigor@sysoev.ru nxt_router_listener_conf_t lscf; 687115Sigor@sysoev.ru 688115Sigor@sysoev.ru static nxt_str_t http_path = nxt_string("/http"); 689133Sigor@sysoev.ru static nxt_str_t applications_path = nxt_string("/applications"); 690115Sigor@sysoev.ru static nxt_str_t listeners_path = nxt_string("/listeners"); 691115Sigor@sysoev.ru 692208Svbart@nginx.com conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL); 693115Sigor@sysoev.ru if (conf == NULL) { 694115Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "configuration parsing error"); 695115Sigor@sysoev.ru return NXT_ERROR; 696115Sigor@sysoev.ru } 697115Sigor@sysoev.ru 698213Svbart@nginx.com mp = tmcf->conf->mem_pool; 699213Svbart@nginx.com 700213Svbart@nginx.com ret = nxt_conf_map_object(mp, conf, nxt_router_conf, 701136Svbart@nginx.com nxt_nitems(nxt_router_conf), tmcf->conf); 702115Sigor@sysoev.ru if (ret != NXT_OK) { 703133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "root map error"); 704115Sigor@sysoev.ru return NXT_ERROR; 705115Sigor@sysoev.ru } 706115Sigor@sysoev.ru 707117Sigor@sysoev.ru if (tmcf->conf->threads == 0) { 708117Sigor@sysoev.ru tmcf->conf->threads = nxt_ncpu; 709117Sigor@sysoev.ru } 710117Sigor@sysoev.ru 711133Sigor@sysoev.ru applications = nxt_conf_get_path(conf, &applications_path); 712133Sigor@sysoev.ru if (applications == NULL) { 713133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "no \"applications\" block"); 714115Sigor@sysoev.ru return NXT_ERROR; 715115Sigor@sysoev.ru } 716115Sigor@sysoev.ru 717133Sigor@sysoev.ru next = 0; 718133Sigor@sysoev.ru 719133Sigor@sysoev.ru for ( ;; ) { 720133Sigor@sysoev.ru application = nxt_conf_next_object_member(applications, &name, &next); 721133Sigor@sysoev.ru if (application == NULL) { 722133Sigor@sysoev.ru break; 723133Sigor@sysoev.ru } 724133Sigor@sysoev.ru 725133Sigor@sysoev.ru nxt_debug(task, "application \"%V\"", &name); 726133Sigor@sysoev.ru 727144Smax.romanov@nginx.com size = nxt_conf_json_length(application, NULL); 728144Smax.romanov@nginx.com 729144Smax.romanov@nginx.com app = nxt_malloc(sizeof(nxt_app_t) + name.length + size); 730133Sigor@sysoev.ru if (app == NULL) { 731133Sigor@sysoev.ru goto fail; 732133Sigor@sysoev.ru } 733133Sigor@sysoev.ru 734144Smax.romanov@nginx.com nxt_memzero(app, sizeof(nxt_app_t)); 735144Smax.romanov@nginx.com 736144Smax.romanov@nginx.com app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t)); 737144Smax.romanov@nginx.com app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length); 738133Sigor@sysoev.ru 739133Sigor@sysoev.ru p = nxt_conf_json_print(app->conf.start, application, NULL); 740133Sigor@sysoev.ru app->conf.length = p - app->conf.start; 741133Sigor@sysoev.ru 742144Smax.romanov@nginx.com nxt_assert(app->conf.length <= size); 743144Smax.romanov@nginx.com 744133Sigor@sysoev.ru nxt_debug(task, "application conf \"%V\"", &app->conf); 745133Sigor@sysoev.ru 746133Sigor@sysoev.ru prev = nxt_router_app_find(&tmcf->conf->router->apps, &name); 747133Sigor@sysoev.ru 748133Sigor@sysoev.ru if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) { 749133Sigor@sysoev.ru nxt_free(app); 750133Sigor@sysoev.ru 751133Sigor@sysoev.ru nxt_queue_remove(&prev->link); 752133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->previous, &prev->link); 753133Sigor@sysoev.ru continue; 754133Sigor@sysoev.ru } 755133Sigor@sysoev.ru 756263Smax.romanov@nginx.com apcf.workers = 1; 757263Smax.romanov@nginx.com 758213Svbart@nginx.com ret = nxt_conf_map_object(mp, application, nxt_router_app_conf, 759136Svbart@nginx.com nxt_nitems(nxt_router_app_conf), &apcf); 760133Sigor@sysoev.ru if (ret != NXT_OK) { 761133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "application map error"); 762133Sigor@sysoev.ru goto app_fail; 763133Sigor@sysoev.ru } 764115Sigor@sysoev.ru 765133Sigor@sysoev.ru nxt_debug(task, "application type: %V", &apcf.type); 766133Sigor@sysoev.ru nxt_debug(task, "application workers: %D", apcf.workers); 767133Sigor@sysoev.ru 768216Sigor@sysoev.ru lang = nxt_app_lang_module(task->thread->runtime, &apcf.type); 769216Sigor@sysoev.ru 770216Sigor@sysoev.ru if (lang == NULL) { 771141Smax.romanov@nginx.com nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"", 772141Smax.romanov@nginx.com &apcf.type); 773141Smax.romanov@nginx.com goto app_fail; 774141Smax.romanov@nginx.com } 775141Smax.romanov@nginx.com 776216Sigor@sysoev.ru nxt_debug(task, "application language module: \"%s\"", lang->file); 777216Sigor@sysoev.ru 778216Sigor@sysoev.ru type = nxt_app_parse_type(&lang->type); 779216Sigor@sysoev.ru 780216Sigor@sysoev.ru if (type == NXT_APP_UNKNOWN) { 781216Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "unknown application type: \"%V\"", 782216Sigor@sysoev.ru &lang->type); 783216Sigor@sysoev.ru goto app_fail; 784216Sigor@sysoev.ru } 785216Sigor@sysoev.ru 786216Sigor@sysoev.ru if (nxt_app_prepare_msg[type] == NULL) { 787133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "unsupported application type: \"%V\"", 788216Sigor@sysoev.ru &lang->type); 789133Sigor@sysoev.ru goto app_fail; 790133Sigor@sysoev.ru } 791133Sigor@sysoev.ru 792133Sigor@sysoev.ru ret = nxt_thread_mutex_create(&app->mutex); 793133Sigor@sysoev.ru if (ret != NXT_OK) { 794133Sigor@sysoev.ru goto app_fail; 795133Sigor@sysoev.ru } 796133Sigor@sysoev.ru 797141Smax.romanov@nginx.com nxt_queue_init(&app->ports); 798141Smax.romanov@nginx.com nxt_queue_init(&app->requests); 799141Smax.romanov@nginx.com 800144Smax.romanov@nginx.com app->name.length = name.length; 801144Smax.romanov@nginx.com nxt_memcpy(app->name.start, name.start, name.length); 802144Smax.romanov@nginx.com 803133Sigor@sysoev.ru app->type = type; 804133Sigor@sysoev.ru app->max_workers = apcf.workers; 805133Sigor@sysoev.ru app->live = 1; 806216Sigor@sysoev.ru app->prepare_msg = nxt_app_prepare_msg[type]; 807133Sigor@sysoev.ru 808133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->apps, &app->link); 809133Sigor@sysoev.ru } 810133Sigor@sysoev.ru 811133Sigor@sysoev.ru http = nxt_conf_get_path(conf, &http_path); 812133Sigor@sysoev.ru #if 0 813133Sigor@sysoev.ru if (http == NULL) { 814133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "no \"http\" block"); 815133Sigor@sysoev.ru return NXT_ERROR; 816133Sigor@sysoev.ru } 817133Sigor@sysoev.ru #endif 818133Sigor@sysoev.ru 819133Sigor@sysoev.ru listeners = nxt_conf_get_path(conf, &listeners_path); 820115Sigor@sysoev.ru if (listeners == NULL) { 821133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "no \"listeners\" block"); 822115Sigor@sysoev.ru return NXT_ERROR; 823115Sigor@sysoev.ru } 82453Sigor@sysoev.ru 825133Sigor@sysoev.ru next = 0; 82653Sigor@sysoev.ru 827115Sigor@sysoev.ru for ( ;; ) { 828115Sigor@sysoev.ru listener = nxt_conf_next_object_member(listeners, &name, &next); 829115Sigor@sysoev.ru if (listener == NULL) { 830115Sigor@sysoev.ru break; 831115Sigor@sysoev.ru } 83253Sigor@sysoev.ru 833115Sigor@sysoev.ru sa = nxt_sockaddr_parse(mp, &name); 834115Sigor@sysoev.ru if (sa == NULL) { 835115Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "invalid listener \"%V\"", &name); 836133Sigor@sysoev.ru goto fail; 837115Sigor@sysoev.ru } 838115Sigor@sysoev.ru 839115Sigor@sysoev.ru sa->type = SOCK_STREAM; 840115Sigor@sysoev.ru 841115Sigor@sysoev.ru nxt_debug(task, "router listener: \"%*s\"", 842115Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa)); 84353Sigor@sysoev.ru 844115Sigor@sysoev.ru skcf = nxt_router_socket_conf(task, mp, sa); 845115Sigor@sysoev.ru if (skcf == NULL) { 846133Sigor@sysoev.ru goto fail; 847115Sigor@sysoev.ru } 84853Sigor@sysoev.ru 849213Svbart@nginx.com ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf, 850136Svbart@nginx.com nxt_nitems(nxt_router_listener_conf), &lscf); 851115Sigor@sysoev.ru if (ret != NXT_OK) { 852115Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "listener map error"); 853133Sigor@sysoev.ru goto fail; 854115Sigor@sysoev.ru } 85553Sigor@sysoev.ru 856133Sigor@sysoev.ru nxt_debug(task, "application: %V", &lscf.application); 857133Sigor@sysoev.ru 858133Sigor@sysoev.ru // STUB, default values if http block is not defined. 859133Sigor@sysoev.ru skcf->header_buffer_size = 2048; 860133Sigor@sysoev.ru skcf->large_header_buffer_size = 8192; 861206Smax.romanov@nginx.com skcf->large_header_buffers = 4; 862206Smax.romanov@nginx.com skcf->body_buffer_size = 16 * 1024; 863206Smax.romanov@nginx.com skcf->max_body_size = 2 * 1024 * 1024; 864133Sigor@sysoev.ru skcf->header_read_timeout = 5000; 865206Smax.romanov@nginx.com skcf->body_read_timeout = 5000; 86653Sigor@sysoev.ru 867133Sigor@sysoev.ru if (http != NULL) { 868213Svbart@nginx.com ret = nxt_conf_map_object(mp, http, nxt_router_http_conf, 869136Svbart@nginx.com nxt_nitems(nxt_router_http_conf), skcf); 870133Sigor@sysoev.ru if (ret != NXT_OK) { 871133Sigor@sysoev.ru nxt_log(task, NXT_LOG_CRIT, "http map error"); 872133Sigor@sysoev.ru goto fail; 873133Sigor@sysoev.ru } 874115Sigor@sysoev.ru } 875115Sigor@sysoev.ru 876115Sigor@sysoev.ru skcf->listen.handler = nxt_router_conn_init; 877115Sigor@sysoev.ru skcf->router_conf = tmcf->conf; 878160Sigor@sysoev.ru skcf->router_conf->count++; 879133Sigor@sysoev.ru skcf->application = nxt_router_listener_application(tmcf, 880133Sigor@sysoev.ru &lscf.application); 881115Sigor@sysoev.ru 882115Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->pending, &skcf->link); 883115Sigor@sysoev.ru } 88453Sigor@sysoev.ru 885198Sigor@sysoev.ru nxt_router_listen_sockets_sort(tmcf->conf->router, tmcf); 886198Sigor@sysoev.ru 88753Sigor@sysoev.ru return NXT_OK; 888133Sigor@sysoev.ru 889133Sigor@sysoev.ru app_fail: 890133Sigor@sysoev.ru 891133Sigor@sysoev.ru nxt_free(app); 892133Sigor@sysoev.ru 893133Sigor@sysoev.ru fail: 894133Sigor@sysoev.ru 895141Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 896141Smax.romanov@nginx.com 897141Smax.romanov@nginx.com nxt_queue_remove(&app->link); 898133Sigor@sysoev.ru nxt_thread_mutex_destroy(&app->mutex); 899133Sigor@sysoev.ru nxt_free(app); 900141Smax.romanov@nginx.com 901141Smax.romanov@nginx.com } nxt_queue_loop; 902133Sigor@sysoev.ru 903133Sigor@sysoev.ru return NXT_ERROR; 904133Sigor@sysoev.ru } 905133Sigor@sysoev.ru 906133Sigor@sysoev.ru 907133Sigor@sysoev.ru static nxt_app_t * 908133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name) 909133Sigor@sysoev.ru { 910141Smax.romanov@nginx.com nxt_app_t *app; 911141Smax.romanov@nginx.com 912141Smax.romanov@nginx.com nxt_queue_each(app, queue, nxt_app_t, link) { 913133Sigor@sysoev.ru 914133Sigor@sysoev.ru if (nxt_strstr_eq(name, &app->name)) { 915133Sigor@sysoev.ru return app; 916133Sigor@sysoev.ru } 917141Smax.romanov@nginx.com 918141Smax.romanov@nginx.com } nxt_queue_loop; 919133Sigor@sysoev.ru 920133Sigor@sysoev.ru return NULL; 921133Sigor@sysoev.ru } 922133Sigor@sysoev.ru 923133Sigor@sysoev.ru 924133Sigor@sysoev.ru static nxt_app_t * 925133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name) 926133Sigor@sysoev.ru { 927133Sigor@sysoev.ru nxt_app_t *app; 928133Sigor@sysoev.ru 929133Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->apps, name); 930133Sigor@sysoev.ru 931133Sigor@sysoev.ru if (app == NULL) { 932134Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->previous, name); 933133Sigor@sysoev.ru } 934133Sigor@sysoev.ru 935133Sigor@sysoev.ru return app; 93653Sigor@sysoev.ru } 93753Sigor@sysoev.ru 93853Sigor@sysoev.ru 93953Sigor@sysoev.ru static nxt_socket_conf_t * 94065Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_mp_t *mp, nxt_sockaddr_t *sa) 94153Sigor@sysoev.ru { 942163Smax.romanov@nginx.com nxt_socket_conf_t *skcf; 943163Smax.romanov@nginx.com 944163Smax.romanov@nginx.com skcf = nxt_mp_zget(mp, sizeof(nxt_socket_conf_t)); 945163Smax.romanov@nginx.com if (nxt_slow_path(skcf == NULL)) { 94653Sigor@sysoev.ru return NULL; 94753Sigor@sysoev.ru } 94853Sigor@sysoev.ru 949163Smax.romanov@nginx.com skcf->sockaddr = sa; 950163Smax.romanov@nginx.com 951163Smax.romanov@nginx.com skcf->listen.sockaddr = sa; 952312Sigor@sysoev.ru 953312Sigor@sysoev.ru nxt_listen_socket_remote_size(&skcf->listen, sa); 954163Smax.romanov@nginx.com 955163Smax.romanov@nginx.com skcf->listen.socket = -1; 956163Smax.romanov@nginx.com skcf->listen.backlog = NXT_LISTEN_BACKLOG; 957163Smax.romanov@nginx.com skcf->listen.flags = NXT_NONBLOCK; 958163Smax.romanov@nginx.com skcf->listen.read_after_accept = 1; 959163Smax.romanov@nginx.com 960163Smax.romanov@nginx.com return skcf; 96153Sigor@sysoev.ru } 96253Sigor@sysoev.ru 96353Sigor@sysoev.ru 96453Sigor@sysoev.ru static void 96553Sigor@sysoev.ru nxt_router_listen_sockets_sort(nxt_router_t *router, 96653Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 96753Sigor@sysoev.ru { 96853Sigor@sysoev.ru nxt_queue_link_t *nqlk, *oqlk, *next; 96953Sigor@sysoev.ru nxt_socket_conf_t *nskcf, *oskcf; 97053Sigor@sysoev.ru 97153Sigor@sysoev.ru for (nqlk = nxt_queue_first(&tmcf->pending); 97253Sigor@sysoev.ru nqlk != nxt_queue_tail(&tmcf->pending); 97353Sigor@sysoev.ru nqlk = next) 97453Sigor@sysoev.ru { 97553Sigor@sysoev.ru next = nxt_queue_next(nqlk); 97653Sigor@sysoev.ru nskcf = nxt_queue_link_data(nqlk, nxt_socket_conf_t, link); 97753Sigor@sysoev.ru 97853Sigor@sysoev.ru for (oqlk = nxt_queue_first(&router->sockets); 97953Sigor@sysoev.ru oqlk != nxt_queue_tail(&router->sockets); 98053Sigor@sysoev.ru oqlk = nxt_queue_next(oqlk)) 98153Sigor@sysoev.ru { 98253Sigor@sysoev.ru oskcf = nxt_queue_link_data(oqlk, nxt_socket_conf_t, link); 98353Sigor@sysoev.ru 984115Sigor@sysoev.ru if (nxt_sockaddr_cmp(nskcf->sockaddr, oskcf->sockaddr)) { 985115Sigor@sysoev.ru nskcf->socket = oskcf->socket; 986115Sigor@sysoev.ru nskcf->listen.socket = oskcf->listen.socket; 987115Sigor@sysoev.ru 98853Sigor@sysoev.ru nxt_queue_remove(oqlk); 98953Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->keeping, oqlk); 99053Sigor@sysoev.ru 99153Sigor@sysoev.ru nxt_queue_remove(nqlk); 99253Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->updating, nqlk); 99353Sigor@sysoev.ru 99453Sigor@sysoev.ru break; 99553Sigor@sysoev.ru } 99653Sigor@sysoev.ru } 99753Sigor@sysoev.ru } 99853Sigor@sysoev.ru 99953Sigor@sysoev.ru nxt_queue_add(&tmcf->deleting, &router->sockets); 1000115Sigor@sysoev.ru nxt_queue_init(&router->sockets); 100153Sigor@sysoev.ru } 100253Sigor@sysoev.ru 100353Sigor@sysoev.ru 1004198Sigor@sysoev.ru static void 1005198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task, 1006198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf) 1007198Sigor@sysoev.ru { 1008198Sigor@sysoev.ru uint32_t stream; 1009198Sigor@sysoev.ru nxt_buf_t *b; 1010198Sigor@sysoev.ru nxt_port_t *main_port, *router_port; 1011198Sigor@sysoev.ru nxt_runtime_t *rt; 1012198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 1013198Sigor@sysoev.ru 1014198Sigor@sysoev.ru rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t)); 1015198Sigor@sysoev.ru if (rpc == NULL) { 1016198Sigor@sysoev.ru goto fail; 1017198Sigor@sysoev.ru } 1018198Sigor@sysoev.ru 1019198Sigor@sysoev.ru rpc->socket_conf = skcf; 1020198Sigor@sysoev.ru rpc->temp_conf = tmcf; 1021198Sigor@sysoev.ru 1022198Sigor@sysoev.ru b = nxt_buf_mem_alloc(tmcf->mem_pool, skcf->sockaddr->sockaddr_size, 0); 1023198Sigor@sysoev.ru if (b == NULL) { 1024198Sigor@sysoev.ru goto fail; 1025198Sigor@sysoev.ru } 1026198Sigor@sysoev.ru 1027198Sigor@sysoev.ru b->mem.free = nxt_cpymem(b->mem.free, skcf->sockaddr, 1028198Sigor@sysoev.ru skcf->sockaddr->sockaddr_size); 1029198Sigor@sysoev.ru 1030198Sigor@sysoev.ru rt = task->thread->runtime; 1031240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1032198Sigor@sysoev.ru router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 1033198Sigor@sysoev.ru 1034198Sigor@sysoev.ru stream = nxt_port_rpc_register_handler(task, router_port, 1035198Sigor@sysoev.ru nxt_router_listen_socket_ready, 1036198Sigor@sysoev.ru nxt_router_listen_socket_error, 1037198Sigor@sysoev.ru main_port->pid, rpc); 1038198Sigor@sysoev.ru if (stream == 0) { 1039198Sigor@sysoev.ru goto fail; 1040198Sigor@sysoev.ru } 1041198Sigor@sysoev.ru 1042198Sigor@sysoev.ru nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1, 1043198Sigor@sysoev.ru stream, router_port->id, b); 1044198Sigor@sysoev.ru 1045198Sigor@sysoev.ru return; 1046198Sigor@sysoev.ru 1047198Sigor@sysoev.ru fail: 1048198Sigor@sysoev.ru 1049198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 1050198Sigor@sysoev.ru } 1051198Sigor@sysoev.ru 1052198Sigor@sysoev.ru 1053198Sigor@sysoev.ru static void 1054198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1055198Sigor@sysoev.ru void *data) 105653Sigor@sysoev.ru { 1057115Sigor@sysoev.ru nxt_int_t ret; 1058115Sigor@sysoev.ru nxt_socket_t s; 1059198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 1060115Sigor@sysoev.ru nxt_router_socket_t *rtsk; 106153Sigor@sysoev.ru 1062198Sigor@sysoev.ru rpc = data; 1063198Sigor@sysoev.ru 1064198Sigor@sysoev.ru s = msg->fd; 1065198Sigor@sysoev.ru 1066198Sigor@sysoev.ru ret = nxt_socket_nonblocking(task, s); 1067198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1068198Sigor@sysoev.ru goto fail; 106953Sigor@sysoev.ru } 107053Sigor@sysoev.ru 1071229Sigor@sysoev.ru nxt_socket_defer_accept(task, s, rpc->socket_conf->sockaddr); 1072198Sigor@sysoev.ru 1073198Sigor@sysoev.ru ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG); 1074198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1075198Sigor@sysoev.ru goto fail; 1076198Sigor@sysoev.ru } 1077198Sigor@sysoev.ru 1078198Sigor@sysoev.ru rtsk = nxt_malloc(sizeof(nxt_router_socket_t)); 1079198Sigor@sysoev.ru if (nxt_slow_path(rtsk == NULL)) { 1080198Sigor@sysoev.ru goto fail; 1081198Sigor@sysoev.ru } 1082198Sigor@sysoev.ru 1083198Sigor@sysoev.ru rtsk->count = 0; 1084198Sigor@sysoev.ru rtsk->fd = s; 1085198Sigor@sysoev.ru 1086198Sigor@sysoev.ru rpc->socket_conf->listen.socket = s; 1087198Sigor@sysoev.ru rpc->socket_conf->socket = rtsk; 1088198Sigor@sysoev.ru 1089198Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 1090198Sigor@sysoev.ru nxt_router_conf_apply, task, rpc->temp_conf, NULL); 1091198Sigor@sysoev.ru 1092198Sigor@sysoev.ru return; 1093148Sigor@sysoev.ru 1094148Sigor@sysoev.ru fail: 1095148Sigor@sysoev.ru 1096148Sigor@sysoev.ru nxt_socket_close(task, s); 1097148Sigor@sysoev.ru 1098198Sigor@sysoev.ru nxt_router_conf_error(task, rpc->temp_conf); 1099198Sigor@sysoev.ru } 1100198Sigor@sysoev.ru 1101198Sigor@sysoev.ru 1102198Sigor@sysoev.ru static void 1103198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1104198Sigor@sysoev.ru void *data) 1105198Sigor@sysoev.ru { 1106198Sigor@sysoev.ru u_char *p; 1107198Sigor@sysoev.ru size_t size; 1108198Sigor@sysoev.ru uint8_t error; 1109198Sigor@sysoev.ru nxt_buf_t *in, *out; 1110198Sigor@sysoev.ru nxt_sockaddr_t *sa; 1111198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 1112198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 1113198Sigor@sysoev.ru 1114198Sigor@sysoev.ru static nxt_str_t socket_errors[] = { 1115198Sigor@sysoev.ru nxt_string("ListenerSystem"), 1116198Sigor@sysoev.ru nxt_string("ListenerNoIPv6"), 1117198Sigor@sysoev.ru nxt_string("ListenerPort"), 1118198Sigor@sysoev.ru nxt_string("ListenerInUse"), 1119198Sigor@sysoev.ru nxt_string("ListenerNoAddress"), 1120198Sigor@sysoev.ru nxt_string("ListenerNoAccess"), 1121198Sigor@sysoev.ru nxt_string("ListenerPath"), 1122198Sigor@sysoev.ru }; 1123198Sigor@sysoev.ru 1124198Sigor@sysoev.ru rpc = data; 1125198Sigor@sysoev.ru sa = rpc->socket_conf->sockaddr; 1126198Sigor@sysoev.ru 1127198Sigor@sysoev.ru in = msg->buf; 1128198Sigor@sysoev.ru p = in->mem.pos; 1129198Sigor@sysoev.ru 1130198Sigor@sysoev.ru error = *p++; 1131198Sigor@sysoev.ru 1132198Sigor@sysoev.ru size = sizeof("listen socket error: ") - 1 1133198Sigor@sysoev.ru + sizeof("{listener: \"\", code:\"\", message: \"\"}") - 1 1134198Sigor@sysoev.ru + sa->length + socket_errors[error].length + (in->mem.free - p); 1135198Sigor@sysoev.ru 1136198Sigor@sysoev.ru tmcf = rpc->temp_conf; 1137198Sigor@sysoev.ru 1138198Sigor@sysoev.ru out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 1139198Sigor@sysoev.ru if (nxt_slow_path(out == NULL)) { 1140198Sigor@sysoev.ru return; 1141198Sigor@sysoev.ru } 1142198Sigor@sysoev.ru 1143198Sigor@sysoev.ru out->mem.free = nxt_sprintf(out->mem.free, out->mem.end, 1144198Sigor@sysoev.ru "listen socket error: " 1145198Sigor@sysoev.ru "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}", 1146198Sigor@sysoev.ru sa->length, nxt_sockaddr_start(sa), 1147198Sigor@sysoev.ru &socket_errors[error], in->mem.free - p, p); 1148198Sigor@sysoev.ru 1149198Sigor@sysoev.ru nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos); 1150198Sigor@sysoev.ru 1151198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 115253Sigor@sysoev.ru } 115353Sigor@sysoev.ru 115453Sigor@sysoev.ru 115553Sigor@sysoev.ru static nxt_int_t 115653Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router, 115753Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface) 115853Sigor@sysoev.ru { 115953Sigor@sysoev.ru nxt_int_t ret; 116053Sigor@sysoev.ru nxt_uint_t n, threads; 116153Sigor@sysoev.ru nxt_queue_link_t *qlk; 116253Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 116353Sigor@sysoev.ru 116453Sigor@sysoev.ru threads = tmcf->conf->threads; 116553Sigor@sysoev.ru 116653Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, threads, 116753Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 116853Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 116953Sigor@sysoev.ru return NXT_ERROR; 117053Sigor@sysoev.ru } 117153Sigor@sysoev.ru 117253Sigor@sysoev.ru n = 0; 117353Sigor@sysoev.ru 117453Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->engines); 117553Sigor@sysoev.ru qlk != nxt_queue_tail(&router->engines); 117653Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 117753Sigor@sysoev.ru { 117853Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 117953Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 118053Sigor@sysoev.ru return NXT_ERROR; 118153Sigor@sysoev.ru } 118253Sigor@sysoev.ru 1183115Sigor@sysoev.ru recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0); 118453Sigor@sysoev.ru 118553Sigor@sysoev.ru if (n < threads) { 1186*315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_KEEP; 1187115Sigor@sysoev.ru ret = nxt_router_engine_conf_update(tmcf, recf); 118853Sigor@sysoev.ru 118953Sigor@sysoev.ru } else { 1190*315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_DELETE; 1191115Sigor@sysoev.ru ret = nxt_router_engine_conf_delete(tmcf, recf); 119253Sigor@sysoev.ru } 119353Sigor@sysoev.ru 119453Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 119553Sigor@sysoev.ru return ret; 119653Sigor@sysoev.ru } 119753Sigor@sysoev.ru 119853Sigor@sysoev.ru n++; 119953Sigor@sysoev.ru } 120053Sigor@sysoev.ru 120153Sigor@sysoev.ru tmcf->new_threads = n; 120253Sigor@sysoev.ru 120353Sigor@sysoev.ru while (n < threads) { 120453Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 120553Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 120653Sigor@sysoev.ru return NXT_ERROR; 120753Sigor@sysoev.ru } 120853Sigor@sysoev.ru 1209*315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_ADD; 1210*315Sigor@sysoev.ru 121153Sigor@sysoev.ru recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0); 121253Sigor@sysoev.ru if (nxt_slow_path(recf->engine == NULL)) { 121353Sigor@sysoev.ru return NXT_ERROR; 121453Sigor@sysoev.ru } 121553Sigor@sysoev.ru 1216115Sigor@sysoev.ru ret = nxt_router_engine_conf_create(tmcf, recf); 121753Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 121853Sigor@sysoev.ru return ret; 121953Sigor@sysoev.ru } 122053Sigor@sysoev.ru 122153Sigor@sysoev.ru n++; 122253Sigor@sysoev.ru } 122353Sigor@sysoev.ru 122453Sigor@sysoev.ru return NXT_OK; 122553Sigor@sysoev.ru } 122653Sigor@sysoev.ru 122753Sigor@sysoev.ru 122853Sigor@sysoev.ru static nxt_int_t 1229115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 1230115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 123153Sigor@sysoev.ru { 1232115Sigor@sysoev.ru nxt_int_t ret; 1233115Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 123453Sigor@sysoev.ru 1235154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 1236154Sigor@sysoev.ru nxt_router_listen_socket_create); 1237115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1238115Sigor@sysoev.ru return ret; 1239115Sigor@sysoev.ru } 1240115Sigor@sysoev.ru 1241154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 1242154Sigor@sysoev.ru nxt_router_listen_socket_create); 124353Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 124453Sigor@sysoev.ru return ret; 124553Sigor@sysoev.ru } 124653Sigor@sysoev.ru 1247115Sigor@sysoev.ru lock = &tmcf->conf->router->lock; 1248115Sigor@sysoev.ru 1249115Sigor@sysoev.ru nxt_thread_spin_lock(lock); 1250115Sigor@sysoev.ru 1251115Sigor@sysoev.ru nxt_router_engine_socket_count(&tmcf->creating); 1252115Sigor@sysoev.ru nxt_router_engine_socket_count(&tmcf->updating); 1253115Sigor@sysoev.ru 1254115Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 1255115Sigor@sysoev.ru 1256115Sigor@sysoev.ru return ret; 125753Sigor@sysoev.ru } 125853Sigor@sysoev.ru 125953Sigor@sysoev.ru 126053Sigor@sysoev.ru static nxt_int_t 1261115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 1262115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 126353Sigor@sysoev.ru { 1264115Sigor@sysoev.ru nxt_int_t ret; 1265115Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 126653Sigor@sysoev.ru 1267154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 1268154Sigor@sysoev.ru nxt_router_listen_socket_create); 126953Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 127053Sigor@sysoev.ru return ret; 127153Sigor@sysoev.ru } 127253Sigor@sysoev.ru 1273154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 1274154Sigor@sysoev.ru nxt_router_listen_socket_update); 127553Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 127653Sigor@sysoev.ru return ret; 127753Sigor@sysoev.ru } 127853Sigor@sysoev.ru 1279139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 1280115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1281115Sigor@sysoev.ru return ret; 1282115Sigor@sysoev.ru } 1283115Sigor@sysoev.ru 1284115Sigor@sysoev.ru lock = &tmcf->conf->router->lock; 1285115Sigor@sysoev.ru 1286115Sigor@sysoev.ru nxt_thread_spin_lock(lock); 1287115Sigor@sysoev.ru 1288115Sigor@sysoev.ru nxt_router_engine_socket_count(&tmcf->creating); 1289115Sigor@sysoev.ru 1290115Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 1291115Sigor@sysoev.ru 1292115Sigor@sysoev.ru return ret; 129353Sigor@sysoev.ru } 129453Sigor@sysoev.ru 129553Sigor@sysoev.ru 129653Sigor@sysoev.ru static nxt_int_t 1297115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 1298115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 129953Sigor@sysoev.ru { 130053Sigor@sysoev.ru nxt_int_t ret; 130153Sigor@sysoev.ru 1302313Sigor@sysoev.ru ret = nxt_router_engine_quit(tmcf, recf); 1303313Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1304313Sigor@sysoev.ru return ret; 1305313Sigor@sysoev.ru } 1306313Sigor@sysoev.ru 1307139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating); 130853Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 130953Sigor@sysoev.ru return ret; 131053Sigor@sysoev.ru } 131153Sigor@sysoev.ru 1312139Sigor@sysoev.ru return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 131353Sigor@sysoev.ru } 131453Sigor@sysoev.ru 131553Sigor@sysoev.ru 131653Sigor@sysoev.ru static nxt_int_t 1317154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 1318154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 131953Sigor@sysoev.ru nxt_work_handler_t handler) 132053Sigor@sysoev.ru { 1321153Sigor@sysoev.ru nxt_joint_job_t *job; 132253Sigor@sysoev.ru nxt_queue_link_t *qlk; 1323155Sigor@sysoev.ru nxt_socket_conf_t *skcf; 132453Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 132553Sigor@sysoev.ru 132653Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 132753Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 132853Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 132953Sigor@sysoev.ru { 1330154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 1331153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 1332139Sigor@sysoev.ru return NXT_ERROR; 1333139Sigor@sysoev.ru } 1334139Sigor@sysoev.ru 1335154Sigor@sysoev.ru job->work.next = recf->jobs; 1336154Sigor@sysoev.ru recf->jobs = &job->work; 1337154Sigor@sysoev.ru 1338153Sigor@sysoev.ru job->task = tmcf->engine->task; 1339153Sigor@sysoev.ru job->work.handler = handler; 1340153Sigor@sysoev.ru job->work.task = &job->task; 1341153Sigor@sysoev.ru job->work.obj = job; 1342153Sigor@sysoev.ru job->tmcf = tmcf; 134353Sigor@sysoev.ru 1344154Sigor@sysoev.ru tmcf->count++; 1345154Sigor@sysoev.ru 1346154Sigor@sysoev.ru joint = nxt_mp_alloc(tmcf->conf->mem_pool, 1347154Sigor@sysoev.ru sizeof(nxt_socket_conf_joint_t)); 134853Sigor@sysoev.ru if (nxt_slow_path(joint == NULL)) { 134953Sigor@sysoev.ru return NXT_ERROR; 135053Sigor@sysoev.ru } 135153Sigor@sysoev.ru 1352153Sigor@sysoev.ru job->work.data = joint; 135353Sigor@sysoev.ru 135453Sigor@sysoev.ru joint->count = 1; 1355155Sigor@sysoev.ru 1356155Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1357155Sigor@sysoev.ru skcf->count++; 1358155Sigor@sysoev.ru joint->socket_conf = skcf; 1359155Sigor@sysoev.ru 136088Smax.romanov@nginx.com joint->engine = recf->engine; 136153Sigor@sysoev.ru } 136253Sigor@sysoev.ru 136320Sigor@sysoev.ru return NXT_OK; 136420Sigor@sysoev.ru } 136520Sigor@sysoev.ru 136620Sigor@sysoev.ru 1367115Sigor@sysoev.ru static void 1368115Sigor@sysoev.ru nxt_router_engine_socket_count(nxt_queue_t *sockets) 1369115Sigor@sysoev.ru { 1370115Sigor@sysoev.ru nxt_queue_link_t *qlk; 1371115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1372115Sigor@sysoev.ru 1373115Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 1374115Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 1375115Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 1376115Sigor@sysoev.ru { 1377115Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1378115Sigor@sysoev.ru skcf->socket->count++; 1379115Sigor@sysoev.ru } 1380115Sigor@sysoev.ru } 1381115Sigor@sysoev.ru 1382115Sigor@sysoev.ru 138320Sigor@sysoev.ru static nxt_int_t 1384313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 1385313Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 1386313Sigor@sysoev.ru { 1387313Sigor@sysoev.ru nxt_joint_job_t *job; 1388313Sigor@sysoev.ru 1389313Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 1390313Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 1391313Sigor@sysoev.ru return NXT_ERROR; 1392313Sigor@sysoev.ru } 1393313Sigor@sysoev.ru 1394313Sigor@sysoev.ru job->work.next = recf->jobs; 1395313Sigor@sysoev.ru recf->jobs = &job->work; 1396313Sigor@sysoev.ru 1397313Sigor@sysoev.ru job->task = tmcf->engine->task; 1398313Sigor@sysoev.ru job->work.handler = nxt_router_worker_thread_quit; 1399313Sigor@sysoev.ru job->work.task = &job->task; 1400313Sigor@sysoev.ru job->work.obj = NULL; 1401313Sigor@sysoev.ru job->work.data = NULL; 1402313Sigor@sysoev.ru job->tmcf = NULL; 1403313Sigor@sysoev.ru 1404313Sigor@sysoev.ru return NXT_OK; 1405313Sigor@sysoev.ru } 1406313Sigor@sysoev.ru 1407313Sigor@sysoev.ru 1408313Sigor@sysoev.ru static nxt_int_t 1409139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 1410139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets) 141120Sigor@sysoev.ru { 1412153Sigor@sysoev.ru nxt_joint_job_t *job; 141353Sigor@sysoev.ru nxt_queue_link_t *qlk; 141420Sigor@sysoev.ru 141553Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 141653Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 141753Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 141853Sigor@sysoev.ru { 1419154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 1420153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 1421139Sigor@sysoev.ru return NXT_ERROR; 1422139Sigor@sysoev.ru } 1423139Sigor@sysoev.ru 1424154Sigor@sysoev.ru job->work.next = recf->jobs; 1425154Sigor@sysoev.ru recf->jobs = &job->work; 1426154Sigor@sysoev.ru 1427153Sigor@sysoev.ru job->task = tmcf->engine->task; 1428153Sigor@sysoev.ru job->work.handler = nxt_router_listen_socket_delete; 1429153Sigor@sysoev.ru job->work.task = &job->task; 1430153Sigor@sysoev.ru job->work.obj = job; 1431153Sigor@sysoev.ru job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1432153Sigor@sysoev.ru job->tmcf = tmcf; 1433154Sigor@sysoev.ru 1434154Sigor@sysoev.ru tmcf->count++; 143520Sigor@sysoev.ru } 143620Sigor@sysoev.ru 143753Sigor@sysoev.ru return NXT_OK; 143853Sigor@sysoev.ru } 143920Sigor@sysoev.ru 144020Sigor@sysoev.ru 144153Sigor@sysoev.ru static nxt_int_t 144253Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 144353Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 144453Sigor@sysoev.ru { 144553Sigor@sysoev.ru nxt_int_t ret; 144653Sigor@sysoev.ru nxt_uint_t i, threads; 144753Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 144820Sigor@sysoev.ru 144953Sigor@sysoev.ru recf = tmcf->engines->elts; 145053Sigor@sysoev.ru threads = tmcf->conf->threads; 145120Sigor@sysoev.ru 145253Sigor@sysoev.ru for (i = tmcf->new_threads; i < threads; i++) { 145353Sigor@sysoev.ru ret = nxt_router_thread_create(task, rt, recf[i].engine); 145453Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 145553Sigor@sysoev.ru return ret; 145653Sigor@sysoev.ru } 145720Sigor@sysoev.ru } 145820Sigor@sysoev.ru 145920Sigor@sysoev.ru return NXT_OK; 146020Sigor@sysoev.ru } 146153Sigor@sysoev.ru 146253Sigor@sysoev.ru 146353Sigor@sysoev.ru static nxt_int_t 146453Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 146553Sigor@sysoev.ru nxt_event_engine_t *engine) 146653Sigor@sysoev.ru { 146753Sigor@sysoev.ru nxt_int_t ret; 146853Sigor@sysoev.ru nxt_thread_link_t *link; 146953Sigor@sysoev.ru nxt_thread_handle_t handle; 147053Sigor@sysoev.ru 147153Sigor@sysoev.ru link = nxt_zalloc(sizeof(nxt_thread_link_t)); 147253Sigor@sysoev.ru 147353Sigor@sysoev.ru if (nxt_slow_path(link == NULL)) { 147453Sigor@sysoev.ru return NXT_ERROR; 147553Sigor@sysoev.ru } 147653Sigor@sysoev.ru 147753Sigor@sysoev.ru link->start = nxt_router_thread_start; 147853Sigor@sysoev.ru link->engine = engine; 147953Sigor@sysoev.ru link->work.handler = nxt_router_thread_exit_handler; 148053Sigor@sysoev.ru link->work.task = task; 148153Sigor@sysoev.ru link->work.data = link; 148253Sigor@sysoev.ru 148353Sigor@sysoev.ru nxt_queue_insert_tail(&rt->engines, &engine->link); 148453Sigor@sysoev.ru 148553Sigor@sysoev.ru ret = nxt_thread_create(&handle, link); 148653Sigor@sysoev.ru 148753Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 148853Sigor@sysoev.ru nxt_queue_remove(&engine->link); 148953Sigor@sysoev.ru } 149053Sigor@sysoev.ru 149153Sigor@sysoev.ru return ret; 149253Sigor@sysoev.ru } 149353Sigor@sysoev.ru 149453Sigor@sysoev.ru 149553Sigor@sysoev.ru static void 1496133Sigor@sysoev.ru nxt_router_apps_sort(nxt_router_t *router, nxt_router_temp_conf_t *tmcf) 1497133Sigor@sysoev.ru { 1498167Smax.romanov@nginx.com nxt_app_t *app; 1499167Smax.romanov@nginx.com nxt_port_t *port; 1500141Smax.romanov@nginx.com 1501141Smax.romanov@nginx.com nxt_queue_each(app, &router->apps, nxt_app_t, link) { 1502133Sigor@sysoev.ru 1503133Sigor@sysoev.ru nxt_queue_remove(&app->link); 1504133Sigor@sysoev.ru 1505167Smax.romanov@nginx.com nxt_thread_log_debug("about to remove app '%V' %p", &app->name, app); 1506167Smax.romanov@nginx.com 1507163Smax.romanov@nginx.com app->live = 0; 1508163Smax.romanov@nginx.com 1509167Smax.romanov@nginx.com if (nxt_router_app_free(NULL, app) != 0) { 1510163Smax.romanov@nginx.com continue; 1511163Smax.romanov@nginx.com } 1512163Smax.romanov@nginx.com 1513167Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->requests)) { 1514167Smax.romanov@nginx.com 1515167Smax.romanov@nginx.com nxt_thread_log_debug("app '%V' %p pending requests found", 1516167Smax.romanov@nginx.com &app->name, app); 1517167Smax.romanov@nginx.com continue; 1518163Smax.romanov@nginx.com } 1519163Smax.romanov@nginx.com 1520167Smax.romanov@nginx.com do { 1521167Smax.romanov@nginx.com port = nxt_router_app_get_port(app, 0); 1522167Smax.romanov@nginx.com if (port == NULL) { 1523167Smax.romanov@nginx.com break; 1524167Smax.romanov@nginx.com } 1525167Smax.romanov@nginx.com 1526167Smax.romanov@nginx.com nxt_thread_log_debug("port %p send quit", port); 1527167Smax.romanov@nginx.com 1528167Smax.romanov@nginx.com nxt_port_socket_write(&port->engine->task, port, 1529167Smax.romanov@nginx.com NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 1530167Smax.romanov@nginx.com } while (1); 1531167Smax.romanov@nginx.com 1532141Smax.romanov@nginx.com } nxt_queue_loop; 1533133Sigor@sysoev.ru 1534133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->previous); 1535133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->apps); 1536133Sigor@sysoev.ru } 1537133Sigor@sysoev.ru 1538133Sigor@sysoev.ru 1539133Sigor@sysoev.ru static void 1540*315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf) 154153Sigor@sysoev.ru { 154253Sigor@sysoev.ru nxt_uint_t n; 1543*315Sigor@sysoev.ru nxt_event_engine_t *engine; 154453Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 154553Sigor@sysoev.ru 154653Sigor@sysoev.ru recf = tmcf->engines->elts; 154753Sigor@sysoev.ru 154853Sigor@sysoev.ru for (n = tmcf->engines->nelts; n != 0; n--) { 1549*315Sigor@sysoev.ru engine = recf->engine; 1550*315Sigor@sysoev.ru 1551*315Sigor@sysoev.ru nxt_router_engine_post(engine, recf->jobs); 1552*315Sigor@sysoev.ru 1553*315Sigor@sysoev.ru switch (recf->action) { 1554*315Sigor@sysoev.ru 1555*315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_KEEP: 1556*315Sigor@sysoev.ru break; 1557*315Sigor@sysoev.ru 1558*315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_ADD: 1559*315Sigor@sysoev.ru nxt_queue_insert_tail(&router->engines, &engine->link0); 1560*315Sigor@sysoev.ru break; 1561*315Sigor@sysoev.ru 1562*315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_DELETE: 1563*315Sigor@sysoev.ru nxt_queue_remove(&engine->link0); 1564*315Sigor@sysoev.ru break; 1565*315Sigor@sysoev.ru } 1566*315Sigor@sysoev.ru 156753Sigor@sysoev.ru recf++; 156853Sigor@sysoev.ru } 156953Sigor@sysoev.ru } 157053Sigor@sysoev.ru 157153Sigor@sysoev.ru 157253Sigor@sysoev.ru static void 1573*315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs) 157453Sigor@sysoev.ru { 1575154Sigor@sysoev.ru nxt_work_t *work, *next; 1576154Sigor@sysoev.ru 1577*315Sigor@sysoev.ru for (work = jobs; work != NULL; work = next) { 1578154Sigor@sysoev.ru next = work->next; 1579154Sigor@sysoev.ru work->next = NULL; 1580154Sigor@sysoev.ru 1581*315Sigor@sysoev.ru nxt_event_engine_post(engine, work); 158253Sigor@sysoev.ru } 158353Sigor@sysoev.ru } 158453Sigor@sysoev.ru 158553Sigor@sysoev.ru 1586119Smax.romanov@nginx.com static nxt_port_handler_t nxt_router_app_port_handlers[] = { 1587192Smax.romanov@nginx.com NULL, /* NXT_PORT_MSG_QUIT */ 1588192Smax.romanov@nginx.com NULL, /* NXT_PORT_MSG_NEW_PORT */ 1589192Smax.romanov@nginx.com NULL, /* NXT_PORT_MSG_CHANGE_FILE */ 1590192Smax.romanov@nginx.com /* TODO: remove mmap_handler from app ports */ 1591192Smax.romanov@nginx.com nxt_port_mmap_handler, /* NXT_PORT_MSG_MMAP */ 1592119Smax.romanov@nginx.com nxt_router_app_data_handler, 1593192Smax.romanov@nginx.com NULL, /* NXT_PORT_MSG_REMOVE_PID */ 1594192Smax.romanov@nginx.com NULL, /* NXT_PORT_MSG_READY */ 1595192Smax.romanov@nginx.com NULL, /* NXT_PORT_MSG_START_WORKER */ 1596190Smax.romanov@nginx.com nxt_port_rpc_handler, 1597190Smax.romanov@nginx.com nxt_port_rpc_handler, 159888Smax.romanov@nginx.com }; 159988Smax.romanov@nginx.com 160088Smax.romanov@nginx.com 160188Smax.romanov@nginx.com static void 160253Sigor@sysoev.ru nxt_router_thread_start(void *data) 160353Sigor@sysoev.ru { 1604141Smax.romanov@nginx.com nxt_int_t ret; 1605141Smax.romanov@nginx.com nxt_port_t *port; 160688Smax.romanov@nginx.com nxt_task_t *task; 160753Sigor@sysoev.ru nxt_thread_t *thread; 160853Sigor@sysoev.ru nxt_thread_link_t *link; 160953Sigor@sysoev.ru nxt_event_engine_t *engine; 161053Sigor@sysoev.ru 161153Sigor@sysoev.ru link = data; 161253Sigor@sysoev.ru engine = link->engine; 161388Smax.romanov@nginx.com task = &engine->task; 161453Sigor@sysoev.ru 161553Sigor@sysoev.ru thread = nxt_thread(); 161653Sigor@sysoev.ru 1617165Smax.romanov@nginx.com nxt_event_engine_thread_adopt(engine); 1618165Smax.romanov@nginx.com 161953Sigor@sysoev.ru /* STUB */ 162053Sigor@sysoev.ru thread->runtime = engine->task.thread->runtime; 162153Sigor@sysoev.ru 162253Sigor@sysoev.ru engine->task.thread = thread; 162353Sigor@sysoev.ru engine->task.log = thread->log; 162453Sigor@sysoev.ru thread->engine = engine; 162563Sigor@sysoev.ru thread->task = &engine->task; 162653Sigor@sysoev.ru thread->fiber = &engine->fibers->fiber; 162753Sigor@sysoev.ru 162863Sigor@sysoev.ru engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64); 162953Sigor@sysoev.ru 1630197Smax.romanov@nginx.com port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid, 1631197Smax.romanov@nginx.com NXT_PROCESS_ROUTER); 1632141Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 1633141Smax.romanov@nginx.com return; 1634141Smax.romanov@nginx.com } 1635141Smax.romanov@nginx.com 1636141Smax.romanov@nginx.com ret = nxt_port_socket_init(task, port, 0); 1637141Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 1638163Smax.romanov@nginx.com nxt_mp_release(port->mem_pool, port); 1639141Smax.romanov@nginx.com return; 1640141Smax.romanov@nginx.com } 1641141Smax.romanov@nginx.com 1642141Smax.romanov@nginx.com engine->port = port; 1643141Smax.romanov@nginx.com 1644141Smax.romanov@nginx.com nxt_port_enable(task, port, nxt_router_app_port_handlers); 1645141Smax.romanov@nginx.com 164653Sigor@sysoev.ru nxt_event_engine_start(engine); 164753Sigor@sysoev.ru } 164853Sigor@sysoev.ru 164953Sigor@sysoev.ru 165053Sigor@sysoev.ru static void 165153Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data) 165253Sigor@sysoev.ru { 1653153Sigor@sysoev.ru nxt_joint_job_t *job; 165453Sigor@sysoev.ru nxt_listen_event_t *listen; 165553Sigor@sysoev.ru nxt_listen_socket_t *ls; 165653Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 165753Sigor@sysoev.ru 1658153Sigor@sysoev.ru job = obj; 165953Sigor@sysoev.ru joint = data; 166053Sigor@sysoev.ru 166153Sigor@sysoev.ru ls = &joint->socket_conf->listen; 166253Sigor@sysoev.ru 1663159Sigor@sysoev.ru nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link); 1664159Sigor@sysoev.ru 166553Sigor@sysoev.ru listen = nxt_listen_event(task, ls); 166653Sigor@sysoev.ru if (nxt_slow_path(listen == NULL)) { 166753Sigor@sysoev.ru nxt_router_listen_socket_release(task, joint); 166853Sigor@sysoev.ru return; 166953Sigor@sysoev.ru } 167053Sigor@sysoev.ru 167153Sigor@sysoev.ru listen->socket.data = joint; 1672139Sigor@sysoev.ru 1673153Sigor@sysoev.ru job->work.next = NULL; 1674153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 1675153Sigor@sysoev.ru 1676153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 167753Sigor@sysoev.ru } 167853Sigor@sysoev.ru 167953Sigor@sysoev.ru 168053Sigor@sysoev.ru nxt_inline nxt_listen_event_t * 168153Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections, 168253Sigor@sysoev.ru nxt_socket_conf_t *skcf) 168353Sigor@sysoev.ru { 1684115Sigor@sysoev.ru nxt_socket_t fd; 1685115Sigor@sysoev.ru nxt_queue_link_t *qlk; 168653Sigor@sysoev.ru nxt_listen_event_t *listen; 168753Sigor@sysoev.ru 1688115Sigor@sysoev.ru fd = skcf->socket->fd; 168953Sigor@sysoev.ru 1690115Sigor@sysoev.ru for (qlk = nxt_queue_first(listen_connections); 1691115Sigor@sysoev.ru qlk != nxt_queue_tail(listen_connections); 1692115Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 169353Sigor@sysoev.ru { 1694115Sigor@sysoev.ru listen = nxt_queue_link_data(qlk, nxt_listen_event_t, link); 169553Sigor@sysoev.ru 1696115Sigor@sysoev.ru if (fd == listen->socket.fd) { 169753Sigor@sysoev.ru return listen; 169853Sigor@sysoev.ru } 169953Sigor@sysoev.ru } 170053Sigor@sysoev.ru 170153Sigor@sysoev.ru return NULL; 170253Sigor@sysoev.ru } 170353Sigor@sysoev.ru 170453Sigor@sysoev.ru 170553Sigor@sysoev.ru static void 170653Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data) 170753Sigor@sysoev.ru { 1708153Sigor@sysoev.ru nxt_joint_job_t *job; 170953Sigor@sysoev.ru nxt_event_engine_t *engine; 171053Sigor@sysoev.ru nxt_listen_event_t *listen; 171153Sigor@sysoev.ru nxt_socket_conf_joint_t *joint, *old; 171253Sigor@sysoev.ru 1713153Sigor@sysoev.ru job = obj; 171453Sigor@sysoev.ru joint = data; 171553Sigor@sysoev.ru 1716139Sigor@sysoev.ru engine = task->thread->engine; 1717139Sigor@sysoev.ru 1718159Sigor@sysoev.ru nxt_queue_insert_tail(&engine->joints, &joint->link); 1719159Sigor@sysoev.ru 172053Sigor@sysoev.ru listen = nxt_router_listen_event(&engine->listen_connections, 172153Sigor@sysoev.ru joint->socket_conf); 172253Sigor@sysoev.ru 172353Sigor@sysoev.ru old = listen->socket.data; 172453Sigor@sysoev.ru listen->socket.data = joint; 1725177Sigor@sysoev.ru listen->listen = &joint->socket_conf->listen; 172653Sigor@sysoev.ru 1727153Sigor@sysoev.ru job->work.next = NULL; 1728153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 1729153Sigor@sysoev.ru 1730153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 1731139Sigor@sysoev.ru 1732181Smax.romanov@nginx.com /* 1733181Smax.romanov@nginx.com * The task is allocated from configuration temporary 1734181Smax.romanov@nginx.com * memory pool so it can be freed after engine post operation. 1735181Smax.romanov@nginx.com */ 1736181Smax.romanov@nginx.com 1737181Smax.romanov@nginx.com nxt_router_conf_release(&engine->task, old); 173853Sigor@sysoev.ru } 173953Sigor@sysoev.ru 174053Sigor@sysoev.ru 174153Sigor@sysoev.ru static void 174253Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data) 174353Sigor@sysoev.ru { 1744153Sigor@sysoev.ru nxt_joint_job_t *job; 1745153Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1746153Sigor@sysoev.ru nxt_listen_event_t *listen; 1747153Sigor@sysoev.ru nxt_event_engine_t *engine; 1748153Sigor@sysoev.ru 1749153Sigor@sysoev.ru job = obj; 175053Sigor@sysoev.ru skcf = data; 175153Sigor@sysoev.ru 1752139Sigor@sysoev.ru engine = task->thread->engine; 1753139Sigor@sysoev.ru 175453Sigor@sysoev.ru listen = nxt_router_listen_event(&engine->listen_connections, skcf); 175553Sigor@sysoev.ru 175653Sigor@sysoev.ru nxt_fd_event_delete(engine, &listen->socket); 175753Sigor@sysoev.ru 1758163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket delete: %d", engine, 1759163Smax.romanov@nginx.com listen->socket.fd); 1760163Smax.romanov@nginx.com 176153Sigor@sysoev.ru listen->timer.handler = nxt_router_listen_socket_close; 176253Sigor@sysoev.ru listen->timer.work_queue = &engine->fast_work_queue; 176353Sigor@sysoev.ru 176453Sigor@sysoev.ru nxt_timer_add(engine, &listen->timer, 0); 1765139Sigor@sysoev.ru 1766153Sigor@sysoev.ru job->work.next = NULL; 1767153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 1768153Sigor@sysoev.ru 1769153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 177053Sigor@sysoev.ru } 177153Sigor@sysoev.ru 177253Sigor@sysoev.ru 177353Sigor@sysoev.ru static void 1774313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data) 1775313Sigor@sysoev.ru { 1776313Sigor@sysoev.ru nxt_event_engine_t *engine; 1777313Sigor@sysoev.ru 1778313Sigor@sysoev.ru nxt_debug(task, "router worker thread quit"); 1779313Sigor@sysoev.ru 1780313Sigor@sysoev.ru engine = task->thread->engine; 1781313Sigor@sysoev.ru 1782313Sigor@sysoev.ru engine->shutdown = 1; 1783313Sigor@sysoev.ru 1784313Sigor@sysoev.ru if (nxt_queue_is_empty(&engine->joints)) { 1785313Sigor@sysoev.ru nxt_thread_exit(task->thread); 1786313Sigor@sysoev.ru } 1787313Sigor@sysoev.ru } 1788313Sigor@sysoev.ru 1789313Sigor@sysoev.ru 1790313Sigor@sysoev.ru static void 179153Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data) 179253Sigor@sysoev.ru { 179353Sigor@sysoev.ru nxt_timer_t *timer; 179453Sigor@sysoev.ru nxt_listen_event_t *listen; 179553Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 179653Sigor@sysoev.ru 179753Sigor@sysoev.ru timer = obj; 179853Sigor@sysoev.ru listen = nxt_timer_data(timer, nxt_listen_event_t, timer); 179953Sigor@sysoev.ru joint = listen->socket.data; 180053Sigor@sysoev.ru 1801163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine, 1802163Smax.romanov@nginx.com listen->socket.fd); 1803163Smax.romanov@nginx.com 180453Sigor@sysoev.ru nxt_queue_remove(&listen->link); 1805123Smax.romanov@nginx.com 1806123Smax.romanov@nginx.com /* 'task' refers to listen->task and we cannot use after nxt_free() */ 1807123Smax.romanov@nginx.com task = &task->thread->engine->task; 1808123Smax.romanov@nginx.com 180953Sigor@sysoev.ru nxt_free(listen); 181053Sigor@sysoev.ru 181153Sigor@sysoev.ru nxt_router_listen_socket_release(task, joint); 181253Sigor@sysoev.ru } 181353Sigor@sysoev.ru 181453Sigor@sysoev.ru 181553Sigor@sysoev.ru static void 181653Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, 181753Sigor@sysoev.ru nxt_socket_conf_joint_t *joint) 181853Sigor@sysoev.ru { 1819118Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1820115Sigor@sysoev.ru nxt_router_socket_t *rtsk; 182153Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 182253Sigor@sysoev.ru 1823118Sigor@sysoev.ru skcf = joint->socket_conf; 1824118Sigor@sysoev.ru rtsk = skcf->socket; 1825118Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 182653Sigor@sysoev.ru 182753Sigor@sysoev.ru nxt_thread_spin_lock(lock); 182853Sigor@sysoev.ru 1829163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket release: rtsk->count %D", 1830163Smax.romanov@nginx.com task->thread->engine, rtsk->count); 1831163Smax.romanov@nginx.com 1832115Sigor@sysoev.ru if (--rtsk->count != 0) { 1833115Sigor@sysoev.ru rtsk = NULL; 183453Sigor@sysoev.ru } 183553Sigor@sysoev.ru 183653Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 183753Sigor@sysoev.ru 1838115Sigor@sysoev.ru if (rtsk != NULL) { 1839115Sigor@sysoev.ru nxt_socket_close(task, rtsk->fd); 1840115Sigor@sysoev.ru nxt_free(rtsk); 1841118Sigor@sysoev.ru skcf->socket = NULL; 184253Sigor@sysoev.ru } 184353Sigor@sysoev.ru 184453Sigor@sysoev.ru nxt_router_conf_release(task, joint); 184553Sigor@sysoev.ru } 184653Sigor@sysoev.ru 184753Sigor@sysoev.ru 184853Sigor@sysoev.ru static void 184953Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint) 185053Sigor@sysoev.ru { 1851156Sigor@sysoev.ru nxt_bool_t exit; 185253Sigor@sysoev.ru nxt_socket_conf_t *skcf; 185353Sigor@sysoev.ru nxt_router_conf_t *rtcf; 1854313Sigor@sysoev.ru nxt_event_engine_t *engine; 185553Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 185653Sigor@sysoev.ru 1857163Smax.romanov@nginx.com nxt_debug(task, "conf joint %p count: %D", joint, joint->count); 185853Sigor@sysoev.ru 185953Sigor@sysoev.ru if (--joint->count != 0) { 186053Sigor@sysoev.ru return; 186153Sigor@sysoev.ru } 186253Sigor@sysoev.ru 186353Sigor@sysoev.ru nxt_queue_remove(&joint->link); 186453Sigor@sysoev.ru 186553Sigor@sysoev.ru skcf = joint->socket_conf; 186653Sigor@sysoev.ru rtcf = skcf->router_conf; 186753Sigor@sysoev.ru lock = &rtcf->router->lock; 186853Sigor@sysoev.ru 186953Sigor@sysoev.ru nxt_thread_spin_lock(lock); 187053Sigor@sysoev.ru 1871163Smax.romanov@nginx.com nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count, 1872163Smax.romanov@nginx.com rtcf, rtcf->count); 1873163Smax.romanov@nginx.com 187453Sigor@sysoev.ru if (--skcf->count != 0) { 187553Sigor@sysoev.ru rtcf = NULL; 187653Sigor@sysoev.ru 187753Sigor@sysoev.ru } else { 187853Sigor@sysoev.ru nxt_queue_remove(&skcf->link); 187953Sigor@sysoev.ru 188053Sigor@sysoev.ru if (--rtcf->count != 0) { 188153Sigor@sysoev.ru rtcf = NULL; 188253Sigor@sysoev.ru } 188353Sigor@sysoev.ru } 188453Sigor@sysoev.ru 188553Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 188653Sigor@sysoev.ru 1887141Smax.romanov@nginx.com /* TODO remove engine->port */ 1888141Smax.romanov@nginx.com /* TODO excude from connected ports */ 1889141Smax.romanov@nginx.com 1890156Sigor@sysoev.ru /* The joint content can be used before memory pool destruction. */ 1891313Sigor@sysoev.ru engine = joint->engine; 1892313Sigor@sysoev.ru exit = (engine->shutdown && nxt_queue_is_empty(&engine->joints)); 1893156Sigor@sysoev.ru 189453Sigor@sysoev.ru if (rtcf != NULL) { 1895115Sigor@sysoev.ru nxt_debug(task, "old router conf is destroyed"); 1896131Smax.romanov@nginx.com 1897131Smax.romanov@nginx.com nxt_mp_thread_adopt(rtcf->mem_pool); 1898131Smax.romanov@nginx.com 189965Sigor@sysoev.ru nxt_mp_destroy(rtcf->mem_pool); 190053Sigor@sysoev.ru } 190153Sigor@sysoev.ru 1902156Sigor@sysoev.ru if (exit) { 190353Sigor@sysoev.ru nxt_thread_exit(task->thread); 190453Sigor@sysoev.ru } 190553Sigor@sysoev.ru } 190653Sigor@sysoev.ru 190753Sigor@sysoev.ru 190853Sigor@sysoev.ru static void 190953Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data) 191053Sigor@sysoev.ru { 1911141Smax.romanov@nginx.com nxt_port_t *port; 191253Sigor@sysoev.ru nxt_thread_link_t *link; 191353Sigor@sysoev.ru nxt_event_engine_t *engine; 191453Sigor@sysoev.ru nxt_thread_handle_t handle; 191553Sigor@sysoev.ru 191658Svbart@nginx.com handle = (nxt_thread_handle_t) obj; 191753Sigor@sysoev.ru link = data; 191853Sigor@sysoev.ru 191953Sigor@sysoev.ru nxt_thread_wait(handle); 192053Sigor@sysoev.ru 192153Sigor@sysoev.ru engine = link->engine; 192253Sigor@sysoev.ru 192353Sigor@sysoev.ru nxt_queue_remove(&engine->link); 192453Sigor@sysoev.ru 1925141Smax.romanov@nginx.com port = engine->port; 1926141Smax.romanov@nginx.com 1927141Smax.romanov@nginx.com // TODO notify all apps 1928141Smax.romanov@nginx.com 1929163Smax.romanov@nginx.com nxt_mp_thread_adopt(port->mem_pool); 1930163Smax.romanov@nginx.com nxt_port_release(port); 1931163Smax.romanov@nginx.com 1932163Smax.romanov@nginx.com nxt_mp_thread_adopt(engine->mem_pool); 193363Sigor@sysoev.ru nxt_mp_destroy(engine->mem_pool); 193453Sigor@sysoev.ru 193553Sigor@sysoev.ru nxt_event_engine_free(engine); 193653Sigor@sysoev.ru 193753Sigor@sysoev.ru nxt_free(link); 193853Sigor@sysoev.ru } 193953Sigor@sysoev.ru 194053Sigor@sysoev.ru 1941206Smax.romanov@nginx.com static const nxt_conn_state_t nxt_router_conn_read_header_state 194253Sigor@sysoev.ru nxt_aligned(64) = 194353Sigor@sysoev.ru { 194453Sigor@sysoev.ru .ready_handler = nxt_router_conn_http_header_parse, 194553Sigor@sysoev.ru .close_handler = nxt_router_conn_close, 194653Sigor@sysoev.ru .error_handler = nxt_router_conn_error, 194753Sigor@sysoev.ru 194853Sigor@sysoev.ru .timer_handler = nxt_router_conn_timeout, 194953Sigor@sysoev.ru .timer_value = nxt_router_conn_timeout_value, 195053Sigor@sysoev.ru .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout), 195153Sigor@sysoev.ru }; 195253Sigor@sysoev.ru 195353Sigor@sysoev.ru 1954206Smax.romanov@nginx.com static const nxt_conn_state_t nxt_router_conn_read_body_state 1955206Smax.romanov@nginx.com nxt_aligned(64) = 1956206Smax.romanov@nginx.com { 1957206Smax.romanov@nginx.com .ready_handler = nxt_router_conn_http_body_read, 1958206Smax.romanov@nginx.com .close_handler = nxt_router_conn_close, 1959206Smax.romanov@nginx.com .error_handler = nxt_router_conn_error, 1960206Smax.romanov@nginx.com 1961206Smax.romanov@nginx.com .timer_handler = nxt_router_conn_timeout, 1962206Smax.romanov@nginx.com .timer_value = nxt_router_conn_timeout_value, 1963206Smax.romanov@nginx.com .timer_data = offsetof(nxt_socket_conf_t, body_read_timeout), 1964206Smax.romanov@nginx.com .timer_autoreset = 1, 1965206Smax.romanov@nginx.com }; 1966206Smax.romanov@nginx.com 1967206Smax.romanov@nginx.com 196853Sigor@sysoev.ru static void 196953Sigor@sysoev.ru nxt_router_conn_init(nxt_task_t *task, void *obj, void *data) 197053Sigor@sysoev.ru { 197153Sigor@sysoev.ru size_t size; 197262Sigor@sysoev.ru nxt_conn_t *c; 197353Sigor@sysoev.ru nxt_event_engine_t *engine; 197453Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 197553Sigor@sysoev.ru 197653Sigor@sysoev.ru c = obj; 197753Sigor@sysoev.ru joint = data; 197853Sigor@sysoev.ru 197953Sigor@sysoev.ru nxt_debug(task, "router conn init"); 198053Sigor@sysoev.ru 198153Sigor@sysoev.ru joint->count++; 198253Sigor@sysoev.ru 198353Sigor@sysoev.ru size = joint->socket_conf->header_buffer_size; 198453Sigor@sysoev.ru c->read = nxt_buf_mem_alloc(c->mem_pool, size, 0); 198553Sigor@sysoev.ru 198653Sigor@sysoev.ru c->socket.data = NULL; 198753Sigor@sysoev.ru 198853Sigor@sysoev.ru engine = task->thread->engine; 198953Sigor@sysoev.ru c->read_work_queue = &engine->fast_work_queue; 199053Sigor@sysoev.ru c->write_work_queue = &engine->fast_work_queue; 199153Sigor@sysoev.ru 1992206Smax.romanov@nginx.com c->read_state = &nxt_router_conn_read_header_state; 199353Sigor@sysoev.ru 199462Sigor@sysoev.ru nxt_conn_read(engine, c); 199553Sigor@sysoev.ru } 199653Sigor@sysoev.ru 199753Sigor@sysoev.ru 199862Sigor@sysoev.ru static const nxt_conn_state_t nxt_router_conn_write_state 199953Sigor@sysoev.ru nxt_aligned(64) = 200053Sigor@sysoev.ru { 200188Smax.romanov@nginx.com .ready_handler = nxt_router_conn_ready, 200253Sigor@sysoev.ru .close_handler = nxt_router_conn_close, 200353Sigor@sysoev.ru .error_handler = nxt_router_conn_error, 200453Sigor@sysoev.ru }; 200553Sigor@sysoev.ru 200653Sigor@sysoev.ru 200753Sigor@sysoev.ru static void 2008119Smax.romanov@nginx.com nxt_router_app_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 200988Smax.romanov@nginx.com { 201088Smax.romanov@nginx.com size_t dump_size; 2011194Smax.romanov@nginx.com nxt_buf_t *b, *last; 201288Smax.romanov@nginx.com nxt_conn_t *c; 201388Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 201488Smax.romanov@nginx.com nxt_event_engine_t *engine; 201588Smax.romanov@nginx.com 201688Smax.romanov@nginx.com b = msg->buf; 201788Smax.romanov@nginx.com engine = task->thread->engine; 201888Smax.romanov@nginx.com 201988Smax.romanov@nginx.com rc = nxt_event_engine_request_find(engine, msg->port_msg.stream); 202088Smax.romanov@nginx.com if (nxt_slow_path(rc == NULL)) { 202188Smax.romanov@nginx.com nxt_debug(task, "request id %08uxD not found", msg->port_msg.stream); 202288Smax.romanov@nginx.com 202388Smax.romanov@nginx.com return; 202488Smax.romanov@nginx.com } 202588Smax.romanov@nginx.com 202688Smax.romanov@nginx.com c = rc->conn; 202788Smax.romanov@nginx.com 202888Smax.romanov@nginx.com dump_size = nxt_buf_used_size(b); 202988Smax.romanov@nginx.com 203088Smax.romanov@nginx.com if (dump_size > 300) { 203188Smax.romanov@nginx.com dump_size = 300; 203288Smax.romanov@nginx.com } 203388Smax.romanov@nginx.com 2034119Smax.romanov@nginx.com nxt_debug(task, "%srouter app data (%z): %*s", 203588Smax.romanov@nginx.com msg->port_msg.last ? "last " : "", msg->size, dump_size, 203688Smax.romanov@nginx.com b->mem.pos); 203788Smax.romanov@nginx.com 203888Smax.romanov@nginx.com if (msg->size == 0) { 203988Smax.romanov@nginx.com b = NULL; 204088Smax.romanov@nginx.com } 204188Smax.romanov@nginx.com 204288Smax.romanov@nginx.com if (msg->port_msg.last != 0) { 204388Smax.romanov@nginx.com nxt_debug(task, "router data create last buf"); 204488Smax.romanov@nginx.com 204588Smax.romanov@nginx.com last = nxt_buf_sync_alloc(c->mem_pool, NXT_BUF_SYNC_LAST); 204688Smax.romanov@nginx.com if (nxt_slow_path(last == NULL)) { 204788Smax.romanov@nginx.com /* TODO pogorevaTb */ 204888Smax.romanov@nginx.com } 204988Smax.romanov@nginx.com 205088Smax.romanov@nginx.com nxt_buf_chain_add(&b, last); 2051167Smax.romanov@nginx.com 2052167Smax.romanov@nginx.com if (rc->app_port != NULL) { 2053167Smax.romanov@nginx.com nxt_router_app_release_port(task, rc->app_port, rc->app_port->app); 2054167Smax.romanov@nginx.com 2055167Smax.romanov@nginx.com rc->app_port = NULL; 2056167Smax.romanov@nginx.com } 2057206Smax.romanov@nginx.com 2058206Smax.romanov@nginx.com rc->conn = NULL; 205988Smax.romanov@nginx.com } 206088Smax.romanov@nginx.com 206188Smax.romanov@nginx.com if (b == NULL) { 206288Smax.romanov@nginx.com return; 206388Smax.romanov@nginx.com } 206488Smax.romanov@nginx.com 2065206Smax.romanov@nginx.com if (msg->buf == b) { 2066206Smax.romanov@nginx.com /* Disable instant buffer completion/re-using by port. */ 2067206Smax.romanov@nginx.com msg->buf = NULL; 2068206Smax.romanov@nginx.com } 2069194Smax.romanov@nginx.com 207088Smax.romanov@nginx.com if (c->write == NULL) { 207188Smax.romanov@nginx.com c->write = b; 207288Smax.romanov@nginx.com c->write_state = &nxt_router_conn_write_state; 207388Smax.romanov@nginx.com 207488Smax.romanov@nginx.com nxt_conn_write(task->thread->engine, c); 2075277Sigor@sysoev.ru 207688Smax.romanov@nginx.com } else { 207788Smax.romanov@nginx.com nxt_debug(task, "router data attach out bufs to existing chain"); 207888Smax.romanov@nginx.com 207988Smax.romanov@nginx.com nxt_buf_chain_add(&c->write, b); 208088Smax.romanov@nginx.com } 208188Smax.romanov@nginx.com } 208288Smax.romanov@nginx.com 2083277Sigor@sysoev.ru 2084141Smax.romanov@nginx.com nxt_inline const char * 2085141Smax.romanov@nginx.com nxt_router_text_by_code(int code) 2086141Smax.romanov@nginx.com { 2087141Smax.romanov@nginx.com switch (code) { 2088141Smax.romanov@nginx.com case 400: return "Bad request"; 2089141Smax.romanov@nginx.com case 404: return "Not found"; 2090141Smax.romanov@nginx.com case 403: return "Forbidden"; 2091206Smax.romanov@nginx.com case 408: return "Request Timeout"; 2092206Smax.romanov@nginx.com case 411: return "Length Required"; 2093206Smax.romanov@nginx.com case 413: return "Request Entity Too Large"; 2094141Smax.romanov@nginx.com case 500: 2095141Smax.romanov@nginx.com default: return "Internal server error"; 2096141Smax.romanov@nginx.com } 2097141Smax.romanov@nginx.com } 2098141Smax.romanov@nginx.com 2099163Smax.romanov@nginx.com 2100163Smax.romanov@nginx.com static nxt_buf_t * 2101163Smax.romanov@nginx.com nxt_router_get_error_buf(nxt_task_t *task, nxt_mp_t *mp, int code, 2102163Smax.romanov@nginx.com const char* fmt, va_list args) 210388Smax.romanov@nginx.com { 2104163Smax.romanov@nginx.com nxt_buf_t *b, *last; 2105163Smax.romanov@nginx.com const char *msg; 2106163Smax.romanov@nginx.com 2107163Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, mp, 16384); 2108141Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 2109163Smax.romanov@nginx.com return NULL; 2110141Smax.romanov@nginx.com } 2111141Smax.romanov@nginx.com 2112141Smax.romanov@nginx.com b->mem.free = nxt_sprintf(b->mem.free, b->mem.end, 2113141Smax.romanov@nginx.com "HTTP/1.0 %d %s\r\n" 2114141Smax.romanov@nginx.com "Content-Type: text/plain\r\n" 2115141Smax.romanov@nginx.com "Connection: close\r\n\r\n", 2116141Smax.romanov@nginx.com code, nxt_router_text_by_code(code)); 2117141Smax.romanov@nginx.com 2118141Smax.romanov@nginx.com msg = (const char *) b->mem.free; 2119141Smax.romanov@nginx.com 2120141Smax.romanov@nginx.com b->mem.free = nxt_vsprintf(b->mem.free, b->mem.end, fmt, args); 2121206Smax.romanov@nginx.com b->mem.free[0] = '\0'; 2122141Smax.romanov@nginx.com 2123141Smax.romanov@nginx.com nxt_log_alert(task->log, "error %d: %s", code, msg); 2124141Smax.romanov@nginx.com 2125163Smax.romanov@nginx.com last = nxt_buf_mem_ts_alloc(task, mp, 0); 2126163Smax.romanov@nginx.com 2127141Smax.romanov@nginx.com if (nxt_slow_path(last == NULL)) { 2128163Smax.romanov@nginx.com nxt_mp_release(mp, b); 2129163Smax.romanov@nginx.com return NULL; 2130141Smax.romanov@nginx.com } 2131141Smax.romanov@nginx.com 2132163Smax.romanov@nginx.com nxt_buf_set_sync(last); 2133163Smax.romanov@nginx.com nxt_buf_set_last(last); 2134163Smax.romanov@nginx.com 2135141Smax.romanov@nginx.com nxt_buf_chain_add(&b, last); 2136141Smax.romanov@nginx.com 2137163Smax.romanov@nginx.com return b; 2138163Smax.romanov@nginx.com } 2139163Smax.romanov@nginx.com 2140163Smax.romanov@nginx.com 2141163Smax.romanov@nginx.com 2142163Smax.romanov@nginx.com static void 2143163Smax.romanov@nginx.com nxt_router_gen_error(nxt_task_t *task, nxt_conn_t *c, int code, 2144163Smax.romanov@nginx.com const char* fmt, ...) 2145163Smax.romanov@nginx.com { 2146163Smax.romanov@nginx.com va_list args; 2147163Smax.romanov@nginx.com nxt_buf_t *b; 2148163Smax.romanov@nginx.com 2149163Smax.romanov@nginx.com va_start(args, fmt); 2150163Smax.romanov@nginx.com b = nxt_router_get_error_buf(task, c->mem_pool, code, fmt, args); 2151163Smax.romanov@nginx.com va_end(args); 2152163Smax.romanov@nginx.com 2153206Smax.romanov@nginx.com if (c->socket.data != NULL) { 2154206Smax.romanov@nginx.com nxt_mp_free(c->mem_pool, c->socket.data); 2155206Smax.romanov@nginx.com c->socket.data = NULL; 2156206Smax.romanov@nginx.com } 2157206Smax.romanov@nginx.com 2158273Smax.romanov@nginx.com if (c->socket.fd == -1) { 2159273Smax.romanov@nginx.com nxt_mp_release(c->mem_pool, b->next); 2160273Smax.romanov@nginx.com nxt_mp_release(c->mem_pool, b); 2161273Smax.romanov@nginx.com return; 2162273Smax.romanov@nginx.com } 2163273Smax.romanov@nginx.com 2164141Smax.romanov@nginx.com if (c->write == NULL) { 2165141Smax.romanov@nginx.com c->write = b; 2166141Smax.romanov@nginx.com c->write_state = &nxt_router_conn_write_state; 2167141Smax.romanov@nginx.com 2168141Smax.romanov@nginx.com nxt_conn_write(task->thread->engine, c); 2169277Sigor@sysoev.ru 2170141Smax.romanov@nginx.com } else { 2171141Smax.romanov@nginx.com nxt_debug(task, "router data attach out bufs to existing chain"); 2172141Smax.romanov@nginx.com 2173141Smax.romanov@nginx.com nxt_buf_chain_add(&c->write, b); 2174141Smax.romanov@nginx.com } 2175141Smax.romanov@nginx.com } 2176141Smax.romanov@nginx.com 2177141Smax.romanov@nginx.com 2178141Smax.romanov@nginx.com static void 2179192Smax.romanov@nginx.com nxt_router_sw_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data) 2180192Smax.romanov@nginx.com { 2181192Smax.romanov@nginx.com nxt_start_worker_t *sw; 2182192Smax.romanov@nginx.com 2183192Smax.romanov@nginx.com sw = data; 2184192Smax.romanov@nginx.com 2185192Smax.romanov@nginx.com nxt_assert(sw != NULL); 2186192Smax.romanov@nginx.com nxt_assert(sw->app->pending_workers != 0); 2187192Smax.romanov@nginx.com 2188192Smax.romanov@nginx.com msg->new_port->app = sw->app; 2189192Smax.romanov@nginx.com 2190192Smax.romanov@nginx.com sw->app->pending_workers--; 2191192Smax.romanov@nginx.com sw->app->workers++; 2192192Smax.romanov@nginx.com 2193192Smax.romanov@nginx.com nxt_debug(task, "sw %p got port %p", sw, msg->new_port); 2194192Smax.romanov@nginx.com 2195192Smax.romanov@nginx.com nxt_router_app_release_port(task, msg->new_port, sw->app); 2196192Smax.romanov@nginx.com 2197192Smax.romanov@nginx.com nxt_router_sw_release(task, sw); 2198192Smax.romanov@nginx.com } 2199192Smax.romanov@nginx.com 2200192Smax.romanov@nginx.com 2201192Smax.romanov@nginx.com static void 2202192Smax.romanov@nginx.com nxt_router_sw_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data) 2203192Smax.romanov@nginx.com { 2204192Smax.romanov@nginx.com nxt_start_worker_t *sw; 2205192Smax.romanov@nginx.com 2206192Smax.romanov@nginx.com sw = data; 2207192Smax.romanov@nginx.com 2208192Smax.romanov@nginx.com nxt_assert(sw != NULL); 2209192Smax.romanov@nginx.com nxt_assert(sw->app->pending_workers != 0); 2210192Smax.romanov@nginx.com 2211192Smax.romanov@nginx.com sw->app->pending_workers--; 2212192Smax.romanov@nginx.com 2213277Sigor@sysoev.ru nxt_debug(task, "sw %p error, failed to start app '%V'", 2214277Sigor@sysoev.ru sw, &sw->app->name); 2215192Smax.romanov@nginx.com 2216192Smax.romanov@nginx.com nxt_router_sw_release(task, sw); 2217192Smax.romanov@nginx.com } 2218192Smax.romanov@nginx.com 2219192Smax.romanov@nginx.com 2220192Smax.romanov@nginx.com static void 2221141Smax.romanov@nginx.com nxt_router_send_sw_request(nxt_task_t *task, void *obj, void *data) 2222141Smax.romanov@nginx.com { 2223174Sigor@sysoev.ru size_t size; 2224192Smax.romanov@nginx.com uint32_t stream; 2225141Smax.romanov@nginx.com nxt_buf_t *b; 2226141Smax.romanov@nginx.com nxt_app_t *app; 2227274Smax.romanov@nginx.com nxt_port_t *main_port, *router_port, *app_port; 2228141Smax.romanov@nginx.com nxt_runtime_t *rt; 2229141Smax.romanov@nginx.com nxt_start_worker_t *sw; 2230274Smax.romanov@nginx.com nxt_req_app_link_t *ra; 2231141Smax.romanov@nginx.com 2232141Smax.romanov@nginx.com sw = obj; 2233141Smax.romanov@nginx.com app = sw->app; 2234141Smax.romanov@nginx.com 2235274Smax.romanov@nginx.com if (nxt_queue_is_empty(&app->requests)) { 2236274Smax.romanov@nginx.com ra = sw->ra; 2237274Smax.romanov@nginx.com app_port = nxt_router_app_get_port(app, ra->req_id); 2238274Smax.romanov@nginx.com 2239274Smax.romanov@nginx.com if (app_port != NULL) { 2240274Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p process request #%uxD", 2241274Smax.romanov@nginx.com &app->name, app, ra->req_id); 2242274Smax.romanov@nginx.com 2243274Smax.romanov@nginx.com ra->app_port = app_port; 2244274Smax.romanov@nginx.com 2245274Smax.romanov@nginx.com nxt_router_process_http_request_mp(task, ra, app_port); 2246274Smax.romanov@nginx.com 2247274Smax.romanov@nginx.com nxt_router_ra_release(task, ra, ra->work.data); 2248274Smax.romanov@nginx.com nxt_router_sw_release(task, sw); 2249274Smax.romanov@nginx.com 2250274Smax.romanov@nginx.com return; 2251274Smax.romanov@nginx.com } 2252274Smax.romanov@nginx.com } 2253274Smax.romanov@nginx.com 2254167Smax.romanov@nginx.com nxt_queue_insert_tail(&app->requests, &sw->ra->link); 2255167Smax.romanov@nginx.com 2256163Smax.romanov@nginx.com if (app->workers + app->pending_workers >= app->max_workers) { 2257244Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p %uD/%uD running/pending workers, " 2258244Smax.romanov@nginx.com "max_workers (%uD) reached", &app->name, app, 2259244Smax.romanov@nginx.com app->workers, app->pending_workers, app->max_workers); 2260192Smax.romanov@nginx.com 2261192Smax.romanov@nginx.com nxt_router_sw_release(task, sw); 2262163Smax.romanov@nginx.com 2263163Smax.romanov@nginx.com return; 2264163Smax.romanov@nginx.com } 2265163Smax.romanov@nginx.com 2266163Smax.romanov@nginx.com app->pending_workers++; 2267163Smax.romanov@nginx.com 2268192Smax.romanov@nginx.com nxt_debug(task, "sw %p send", sw); 226988Smax.romanov@nginx.com 2270119Smax.romanov@nginx.com rt = task->thread->runtime; 2271240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 2272192Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 2273141Smax.romanov@nginx.com 2274174Sigor@sysoev.ru size = app->name.length + 1 + app->conf.length; 2275174Sigor@sysoev.ru 2276240Sigor@sysoev.ru b = nxt_buf_mem_alloc(main_port->mem_pool, size, 0); 2277174Sigor@sysoev.ru 2278174Sigor@sysoev.ru nxt_buf_cpystr(b, &app->name); 2279174Sigor@sysoev.ru *b->mem.free++ = '\0'; 2280141Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 2281141Smax.romanov@nginx.com 2282192Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 2283192Smax.romanov@nginx.com nxt_router_sw_ready, 2284192Smax.romanov@nginx.com nxt_router_sw_error, 2285240Sigor@sysoev.ru main_port->pid, sw); 2286240Sigor@sysoev.ru 2287240Sigor@sysoev.ru nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1, 2288192Smax.romanov@nginx.com stream, router_port->id, b); 2289141Smax.romanov@nginx.com } 2290141Smax.romanov@nginx.com 2291141Smax.romanov@nginx.com 2292163Smax.romanov@nginx.com static nxt_bool_t 2293167Smax.romanov@nginx.com nxt_router_app_free(nxt_task_t *task, nxt_app_t *app) 2294163Smax.romanov@nginx.com { 2295192Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2296192Smax.romanov@nginx.com nxt_req_app_link_t *ra; 2297167Smax.romanov@nginx.com 2298167Smax.romanov@nginx.com nxt_thread_log_debug("app '%V' %p state: %d/%uD/%uD/%d", &app->name, app, 2299167Smax.romanov@nginx.com app->live, app->workers, app->pending_workers, 2300167Smax.romanov@nginx.com nxt_queue_is_empty(&app->requests)); 2301167Smax.romanov@nginx.com 2302277Sigor@sysoev.ru if (app->live == 0 2303277Sigor@sysoev.ru && app->workers == 0 2304277Sigor@sysoev.ru && app->pending_workers == 0 2305277Sigor@sysoev.ru && nxt_queue_is_empty(&app->requests)) 2306277Sigor@sysoev.ru { 2307163Smax.romanov@nginx.com nxt_thread_mutex_destroy(&app->mutex); 2308163Smax.romanov@nginx.com nxt_free(app); 2309163Smax.romanov@nginx.com 2310163Smax.romanov@nginx.com return 1; 2311163Smax.romanov@nginx.com } 2312163Smax.romanov@nginx.com 2313277Sigor@sysoev.ru if (app->live == 1 2314277Sigor@sysoev.ru && nxt_queue_is_empty(&app->requests) == 0 2315277Sigor@sysoev.ru && app->workers + app->pending_workers < app->max_workers) 2316277Sigor@sysoev.ru { 2317167Smax.romanov@nginx.com lnk = nxt_queue_first(&app->requests); 2318167Smax.romanov@nginx.com nxt_queue_remove(lnk); 2319167Smax.romanov@nginx.com 2320167Smax.romanov@nginx.com ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link); 2321167Smax.romanov@nginx.com 2322192Smax.romanov@nginx.com nxt_router_sw_create(task, app, ra); 2323167Smax.romanov@nginx.com } 2324167Smax.romanov@nginx.com 2325163Smax.romanov@nginx.com return 0; 2326163Smax.romanov@nginx.com } 2327163Smax.romanov@nginx.com 2328163Smax.romanov@nginx.com 2329141Smax.romanov@nginx.com static nxt_port_t * 2330167Smax.romanov@nginx.com nxt_router_app_get_port(nxt_app_t *app, uint32_t req_id) 2331141Smax.romanov@nginx.com { 2332141Smax.romanov@nginx.com nxt_port_t *port; 2333141Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2334141Smax.romanov@nginx.com 2335141Smax.romanov@nginx.com port = NULL; 2336141Smax.romanov@nginx.com 2337141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2338141Smax.romanov@nginx.com 2339141Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->ports)) { 2340141Smax.romanov@nginx.com lnk = nxt_queue_first(&app->ports); 2341141Smax.romanov@nginx.com nxt_queue_remove(lnk); 2342141Smax.romanov@nginx.com 2343141Smax.romanov@nginx.com lnk->next = NULL; 2344141Smax.romanov@nginx.com 2345141Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, app_link); 2346167Smax.romanov@nginx.com 2347167Smax.romanov@nginx.com port->app_req_id = req_id; 2348141Smax.romanov@nginx.com } 2349141Smax.romanov@nginx.com 2350141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2351141Smax.romanov@nginx.com 2352141Smax.romanov@nginx.com return port; 2353141Smax.romanov@nginx.com } 2354141Smax.romanov@nginx.com 2355141Smax.romanov@nginx.com 2356141Smax.romanov@nginx.com static void 2357141Smax.romanov@nginx.com nxt_router_app_release_port(nxt_task_t *task, void *obj, void *data) 2358141Smax.romanov@nginx.com { 2359141Smax.romanov@nginx.com nxt_app_t *app; 2360141Smax.romanov@nginx.com nxt_port_t *port; 2361141Smax.romanov@nginx.com nxt_work_t *work; 2362141Smax.romanov@nginx.com nxt_queue_link_t *lnk; 2363167Smax.romanov@nginx.com nxt_req_app_link_t *ra; 2364141Smax.romanov@nginx.com 2365141Smax.romanov@nginx.com port = obj; 2366141Smax.romanov@nginx.com app = data; 2367141Smax.romanov@nginx.com 2368141Smax.romanov@nginx.com nxt_assert(app != NULL); 2369141Smax.romanov@nginx.com nxt_assert(app == port->app); 2370141Smax.romanov@nginx.com nxt_assert(port->app_link.next == NULL); 2371141Smax.romanov@nginx.com 2372141Smax.romanov@nginx.com 2373141Smax.romanov@nginx.com if (task->thread->engine != port->engine) { 2374163Smax.romanov@nginx.com work = &port->work; 2375141Smax.romanov@nginx.com 2376141Smax.romanov@nginx.com nxt_debug(task, "post release port to engine %p", port->engine); 2377141Smax.romanov@nginx.com 2378141Smax.romanov@nginx.com work->next = NULL; 2379141Smax.romanov@nginx.com work->handler = nxt_router_app_release_port; 2380166Smax.romanov@nginx.com work->task = &port->engine->task; 2381141Smax.romanov@nginx.com work->obj = port; 2382141Smax.romanov@nginx.com work->data = app; 2383141Smax.romanov@nginx.com 2384141Smax.romanov@nginx.com nxt_event_engine_post(port->engine, work); 2385141Smax.romanov@nginx.com 2386141Smax.romanov@nginx.com return; 2387141Smax.romanov@nginx.com } 2388141Smax.romanov@nginx.com 2389141Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->requests)) { 2390141Smax.romanov@nginx.com lnk = nxt_queue_first(&app->requests); 2391141Smax.romanov@nginx.com nxt_queue_remove(lnk); 2392141Smax.romanov@nginx.com 2393167Smax.romanov@nginx.com ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link); 2394167Smax.romanov@nginx.com 2395167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p process next request #%uxD", 2396167Smax.romanov@nginx.com &app->name, app, ra->req_id); 2397167Smax.romanov@nginx.com 2398167Smax.romanov@nginx.com ra->app_port = port; 2399182Smax.romanov@nginx.com port->app_req_id = ra->req_id; 2400167Smax.romanov@nginx.com 2401167Smax.romanov@nginx.com nxt_router_process_http_request_mp(task, ra, port); 2402167Smax.romanov@nginx.com 2403167Smax.romanov@nginx.com nxt_router_ra_release(task, ra, ra->work.data); 2404141Smax.romanov@nginx.com 2405141Smax.romanov@nginx.com return; 2406141Smax.romanov@nginx.com } 2407141Smax.romanov@nginx.com 2408167Smax.romanov@nginx.com port->app_req_id = 0; 2409167Smax.romanov@nginx.com 2410163Smax.romanov@nginx.com if (port->pair[1] == -1) { 2411167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p port already closed (pid %PI dead?)", 2412167Smax.romanov@nginx.com &app->name, app, port->pid); 2413163Smax.romanov@nginx.com 2414163Smax.romanov@nginx.com app->workers--; 2415167Smax.romanov@nginx.com nxt_router_app_free(task, app); 2416163Smax.romanov@nginx.com 2417163Smax.romanov@nginx.com port->app = NULL; 2418163Smax.romanov@nginx.com 2419163Smax.romanov@nginx.com nxt_port_release(port); 2420163Smax.romanov@nginx.com 2421163Smax.romanov@nginx.com return; 2422163Smax.romanov@nginx.com } 2423163Smax.romanov@nginx.com 2424163Smax.romanov@nginx.com if (!app->live) { 2425167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p is not alive, send QUIT to port", 2426167Smax.romanov@nginx.com &app->name, app); 2427163Smax.romanov@nginx.com 2428163Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, 2429163Smax.romanov@nginx.com -1, 0, 0, NULL); 2430163Smax.romanov@nginx.com 2431163Smax.romanov@nginx.com return; 2432163Smax.romanov@nginx.com } 2433163Smax.romanov@nginx.com 2434167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p requests queue is empty, keep the port", 2435167Smax.romanov@nginx.com &app->name, app); 2436141Smax.romanov@nginx.com 2437141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2438141Smax.romanov@nginx.com 2439141Smax.romanov@nginx.com nxt_queue_insert_head(&app->ports, &port->app_link); 2440141Smax.romanov@nginx.com 2441141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2442141Smax.romanov@nginx.com } 2443141Smax.romanov@nginx.com 2444141Smax.romanov@nginx.com 2445163Smax.romanov@nginx.com nxt_bool_t 2446141Smax.romanov@nginx.com nxt_router_app_remove_port(nxt_port_t *port) 2447141Smax.romanov@nginx.com { 2448163Smax.romanov@nginx.com nxt_app_t *app; 2449163Smax.romanov@nginx.com nxt_bool_t busy; 2450141Smax.romanov@nginx.com 2451141Smax.romanov@nginx.com app = port->app; 2452167Smax.romanov@nginx.com busy = port->app_req_id != 0; 2453163Smax.romanov@nginx.com 2454163Smax.romanov@nginx.com if (app == NULL) { 2455167Smax.romanov@nginx.com nxt_thread_log_debug("port %p app remove, no app", port); 2456167Smax.romanov@nginx.com 2457163Smax.romanov@nginx.com nxt_assert(port->app_link.next == NULL); 2458163Smax.romanov@nginx.com 2459163Smax.romanov@nginx.com return 1; 2460141Smax.romanov@nginx.com } 2461141Smax.romanov@nginx.com 2462141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 2463141Smax.romanov@nginx.com 2464163Smax.romanov@nginx.com if (port->app_link.next != NULL) { 2465163Smax.romanov@nginx.com 2466163Smax.romanov@nginx.com nxt_queue_remove(&port->app_link); 2467163Smax.romanov@nginx.com port->app_link.next = NULL; 2468163Smax.romanov@nginx.com 2469163Smax.romanov@nginx.com } 2470141Smax.romanov@nginx.com 2471141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 2472163Smax.romanov@nginx.com 2473163Smax.romanov@nginx.com if (busy == 0) { 2474167Smax.romanov@nginx.com nxt_thread_log_debug("port %p app remove, free, app '%V' %p", port, 2475167Smax.romanov@nginx.com &app->name, app); 2476163Smax.romanov@nginx.com 2477163Smax.romanov@nginx.com app->workers--; 2478167Smax.romanov@nginx.com nxt_router_app_free(&port->engine->task, app); 2479163Smax.romanov@nginx.com 2480163Smax.romanov@nginx.com return 1; 2481163Smax.romanov@nginx.com } 2482163Smax.romanov@nginx.com 2483167Smax.romanov@nginx.com nxt_thread_log_debug("port %p app remove, busy, app '%V' %p, req #%uxD", 2484167Smax.romanov@nginx.com port, &app->name, app, port->app_req_id); 2485167Smax.romanov@nginx.com 2486163Smax.romanov@nginx.com return 0; 2487141Smax.romanov@nginx.com } 2488141Smax.romanov@nginx.com 2489141Smax.romanov@nginx.com 2490167Smax.romanov@nginx.com static nxt_int_t 2491167Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_req_app_link_t *ra) 2492141Smax.romanov@nginx.com { 2493141Smax.romanov@nginx.com nxt_app_t *app; 2494141Smax.romanov@nginx.com nxt_conn_t *c; 2495167Smax.romanov@nginx.com nxt_port_t *port; 2496141Smax.romanov@nginx.com nxt_start_worker_t *sw; 2497141Smax.romanov@nginx.com nxt_socket_conf_joint_t *joint; 2498141Smax.romanov@nginx.com 2499141Smax.romanov@nginx.com port = NULL; 2500167Smax.romanov@nginx.com c = ra->rc->conn; 2501141Smax.romanov@nginx.com 2502141Smax.romanov@nginx.com joint = c->listen->socket.data; 2503141Smax.romanov@nginx.com app = joint->socket_conf->application; 2504141Smax.romanov@nginx.com 2505141Smax.romanov@nginx.com if (app == NULL) { 2506167Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, 2507141Smax.romanov@nginx.com "Application is NULL in socket_conf"); 2508141Smax.romanov@nginx.com return NXT_ERROR; 2509141Smax.romanov@nginx.com } 2510141Smax.romanov@nginx.com 2511141Smax.romanov@nginx.com 2512167Smax.romanov@nginx.com port = nxt_router_app_get_port(app, ra->req_id); 2513141Smax.romanov@nginx.com 2514141Smax.romanov@nginx.com if (port != NULL) { 2515163Smax.romanov@nginx.com nxt_debug(task, "already have port for app '%V'", &app->name); 2516163Smax.romanov@nginx.com 2517167Smax.romanov@nginx.com ra->app_port = port; 2518141Smax.romanov@nginx.com return NXT_OK; 2519141Smax.romanov@nginx.com } 2520141Smax.romanov@nginx.com 2521192Smax.romanov@nginx.com sw = nxt_router_sw_create(task, app, ra); 2522141Smax.romanov@nginx.com 2523141Smax.romanov@nginx.com if (nxt_slow_path(sw == NULL)) { 2524167Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, 2525141Smax.romanov@nginx.com "Failed to allocate start worker struct"); 2526141Smax.romanov@nginx.com return NXT_ERROR; 2527141Smax.romanov@nginx.com } 2528141Smax.romanov@nginx.com 2529141Smax.romanov@nginx.com return NXT_AGAIN; 253088Smax.romanov@nginx.com } 253188Smax.romanov@nginx.com 253288Smax.romanov@nginx.com 253388Smax.romanov@nginx.com static void 253453Sigor@sysoev.ru nxt_router_conn_http_header_parse(nxt_task_t *task, void *obj, void *data) 253553Sigor@sysoev.ru { 2536206Smax.romanov@nginx.com size_t size; 253753Sigor@sysoev.ru nxt_int_t ret; 2538206Smax.romanov@nginx.com nxt_buf_t *buf; 253962Sigor@sysoev.ru nxt_conn_t *c; 2540268Sigor@sysoev.ru nxt_sockaddr_t *local; 254188Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 2542206Smax.romanov@nginx.com nxt_app_request_body_t *b; 254353Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 254488Smax.romanov@nginx.com nxt_app_request_header_t *h; 254553Sigor@sysoev.ru 254653Sigor@sysoev.ru c = obj; 254788Smax.romanov@nginx.com ap = data; 2548206Smax.romanov@nginx.com buf = c->read; 2549206Smax.romanov@nginx.com joint = c->listen->socket.data; 255053Sigor@sysoev.ru 255153Sigor@sysoev.ru nxt_debug(task, "router conn http header parse"); 255253Sigor@sysoev.ru 255388Smax.romanov@nginx.com if (ap == NULL) { 2554206Smax.romanov@nginx.com ap = nxt_mp_zalloc(c->mem_pool, sizeof(nxt_app_parse_ctx_t)); 255588Smax.romanov@nginx.com if (nxt_slow_path(ap == NULL)) { 255653Sigor@sysoev.ru nxt_router_conn_close(task, c, data); 255753Sigor@sysoev.ru return; 255853Sigor@sysoev.ru } 255953Sigor@sysoev.ru 256088Smax.romanov@nginx.com ret = nxt_app_http_req_init(task, ap); 256161Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 256261Sigor@sysoev.ru nxt_router_conn_close(task, c, data); 256361Sigor@sysoev.ru return; 256461Sigor@sysoev.ru } 256588Smax.romanov@nginx.com 256688Smax.romanov@nginx.com c->socket.data = ap; 2567113Smax.romanov@nginx.com 2568113Smax.romanov@nginx.com ap->r.remote.start = nxt_sockaddr_address(c->remote); 2569113Smax.romanov@nginx.com ap->r.remote.length = c->remote->address_length; 2570206Smax.romanov@nginx.com 2571268Sigor@sysoev.ru local = joint->socket_conf->sockaddr; 2572268Sigor@sysoev.ru ap->r.local.start = nxt_sockaddr_address(local); 2573268Sigor@sysoev.ru ap->r.local.length = local->address_length; 2574268Sigor@sysoev.ru 2575206Smax.romanov@nginx.com ap->r.header.buf = buf; 257653Sigor@sysoev.ru } 257753Sigor@sysoev.ru 257888Smax.romanov@nginx.com h = &ap->r.header; 2579206Smax.romanov@nginx.com b = &ap->r.body; 2580206Smax.romanov@nginx.com 2581206Smax.romanov@nginx.com ret = nxt_app_http_req_header_parse(task, ap, buf); 2582206Smax.romanov@nginx.com 2583206Smax.romanov@nginx.com nxt_debug(task, "http parse request header: %d", ret); 258453Sigor@sysoev.ru 258553Sigor@sysoev.ru switch (nxt_expect(NXT_DONE, ret)) { 258653Sigor@sysoev.ru 258753Sigor@sysoev.ru case NXT_DONE: 258888Smax.romanov@nginx.com nxt_debug(task, "router request header parsing complete, " 258988Smax.romanov@nginx.com "content length: %O, preread: %uz", 2590206Smax.romanov@nginx.com h->parsed_content_length, nxt_buf_mem_used_size(&buf->mem)); 2591206Smax.romanov@nginx.com 2592206Smax.romanov@nginx.com if (b->done) { 2593206Smax.romanov@nginx.com nxt_router_process_http_request(task, c, ap); 2594206Smax.romanov@nginx.com 2595206Smax.romanov@nginx.com return; 2596206Smax.romanov@nginx.com } 2597206Smax.romanov@nginx.com 2598277Sigor@sysoev.ru if (joint->socket_conf->max_body_size > 0 2599277Sigor@sysoev.ru && (size_t) h->parsed_content_length 2600277Sigor@sysoev.ru > joint->socket_conf->max_body_size) 2601277Sigor@sysoev.ru { 2602206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 413, "Content-Length too big"); 2603206Smax.romanov@nginx.com return; 2604206Smax.romanov@nginx.com } 2605206Smax.romanov@nginx.com 2606206Smax.romanov@nginx.com if (nxt_buf_mem_free_size(&buf->mem) == 0) { 2607206Smax.romanov@nginx.com size = nxt_min(joint->socket_conf->body_buffer_size, 2608206Smax.romanov@nginx.com (size_t) h->parsed_content_length); 2609206Smax.romanov@nginx.com 2610206Smax.romanov@nginx.com buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0); 2611206Smax.romanov@nginx.com if (nxt_slow_path(buf->next == NULL)) { 2612206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Failed to allocate " 2613206Smax.romanov@nginx.com "buffer for request body"); 2614206Smax.romanov@nginx.com return; 2615206Smax.romanov@nginx.com } 2616206Smax.romanov@nginx.com 2617206Smax.romanov@nginx.com c->read = buf->next; 2618206Smax.romanov@nginx.com 2619206Smax.romanov@nginx.com b->preread_size += nxt_buf_mem_used_size(&buf->mem); 2620206Smax.romanov@nginx.com } 2621206Smax.romanov@nginx.com 2622206Smax.romanov@nginx.com if (b->buf == NULL) { 2623206Smax.romanov@nginx.com b->buf = c->read; 2624206Smax.romanov@nginx.com } 2625206Smax.romanov@nginx.com 2626206Smax.romanov@nginx.com c->read_state = &nxt_router_conn_read_body_state; 2627206Smax.romanov@nginx.com break; 2628206Smax.romanov@nginx.com 2629206Smax.romanov@nginx.com case NXT_ERROR: 2630206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 400, "Request header parse error"); 2631206Smax.romanov@nginx.com return; 2632206Smax.romanov@nginx.com 2633206Smax.romanov@nginx.com default: /* NXT_AGAIN */ 2634206Smax.romanov@nginx.com 2635206Smax.romanov@nginx.com if (c->read->mem.free == c->read->mem.end) { 2636206Smax.romanov@nginx.com size = joint->socket_conf->large_header_buffer_size; 2637206Smax.romanov@nginx.com 2638277Sigor@sysoev.ru if (size <= (size_t) nxt_buf_mem_used_size(&buf->mem) 2639277Sigor@sysoev.ru || ap->r.header.bufs 2640277Sigor@sysoev.ru >= joint->socket_conf->large_header_buffers) 2641277Sigor@sysoev.ru { 2642206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 413, 2643206Smax.romanov@nginx.com "Too long request headers"); 2644206Smax.romanov@nginx.com return; 2645206Smax.romanov@nginx.com } 2646206Smax.romanov@nginx.com 2647206Smax.romanov@nginx.com buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0); 2648206Smax.romanov@nginx.com if (nxt_slow_path(buf->next == NULL)) { 2649206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, 2650206Smax.romanov@nginx.com "Failed to allocate large header " 2651206Smax.romanov@nginx.com "buffer"); 2652206Smax.romanov@nginx.com return; 2653206Smax.romanov@nginx.com } 2654206Smax.romanov@nginx.com 2655206Smax.romanov@nginx.com ap->r.header.bufs++; 2656206Smax.romanov@nginx.com 2657206Smax.romanov@nginx.com size = c->read->mem.free - c->read->mem.pos; 2658206Smax.romanov@nginx.com 2659206Smax.romanov@nginx.com c->read = nxt_buf_cpy(buf->next, c->read->mem.pos, size); 2660206Smax.romanov@nginx.com } 2661206Smax.romanov@nginx.com 2662206Smax.romanov@nginx.com } 2663206Smax.romanov@nginx.com 2664206Smax.romanov@nginx.com nxt_conn_read(task->thread->engine, c); 2665206Smax.romanov@nginx.com } 2666206Smax.romanov@nginx.com 2667206Smax.romanov@nginx.com 2668206Smax.romanov@nginx.com static void 2669206Smax.romanov@nginx.com nxt_router_conn_http_body_read(nxt_task_t *task, void *obj, void *data) 2670206Smax.romanov@nginx.com { 2671206Smax.romanov@nginx.com size_t size; 2672206Smax.romanov@nginx.com nxt_int_t ret; 2673206Smax.romanov@nginx.com nxt_buf_t *buf; 2674206Smax.romanov@nginx.com nxt_conn_t *c; 2675206Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 2676206Smax.romanov@nginx.com nxt_app_request_body_t *b; 2677206Smax.romanov@nginx.com nxt_socket_conf_joint_t *joint; 2678206Smax.romanov@nginx.com nxt_app_request_header_t *h; 2679206Smax.romanov@nginx.com 2680206Smax.romanov@nginx.com c = obj; 2681206Smax.romanov@nginx.com ap = data; 2682206Smax.romanov@nginx.com buf = c->read; 2683206Smax.romanov@nginx.com 2684206Smax.romanov@nginx.com nxt_debug(task, "router conn http body read"); 2685206Smax.romanov@nginx.com 2686206Smax.romanov@nginx.com nxt_assert(ap != NULL); 2687206Smax.romanov@nginx.com 2688206Smax.romanov@nginx.com b = &ap->r.body; 2689206Smax.romanov@nginx.com h = &ap->r.header; 2690206Smax.romanov@nginx.com 2691206Smax.romanov@nginx.com ret = nxt_app_http_req_body_read(task, ap, buf); 2692206Smax.romanov@nginx.com 2693206Smax.romanov@nginx.com nxt_debug(task, "http read request body: %d", ret); 2694206Smax.romanov@nginx.com 2695206Smax.romanov@nginx.com switch (nxt_expect(NXT_DONE, ret)) { 2696206Smax.romanov@nginx.com 2697206Smax.romanov@nginx.com case NXT_DONE: 269888Smax.romanov@nginx.com nxt_router_process_http_request(task, c, ap); 269988Smax.romanov@nginx.com return; 270053Sigor@sysoev.ru 270153Sigor@sysoev.ru case NXT_ERROR: 2702206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Read body error"); 270353Sigor@sysoev.ru return; 270453Sigor@sysoev.ru 270553Sigor@sysoev.ru default: /* NXT_AGAIN */ 270653Sigor@sysoev.ru 2707206Smax.romanov@nginx.com if (nxt_buf_mem_free_size(&buf->mem) == 0) { 2708206Smax.romanov@nginx.com joint = c->listen->socket.data; 2709206Smax.romanov@nginx.com 2710206Smax.romanov@nginx.com b->preread_size += nxt_buf_mem_used_size(&buf->mem); 2711206Smax.romanov@nginx.com 2712206Smax.romanov@nginx.com size = nxt_min(joint->socket_conf->body_buffer_size, 2713206Smax.romanov@nginx.com (size_t) h->parsed_content_length - b->preread_size); 2714206Smax.romanov@nginx.com 2715206Smax.romanov@nginx.com buf->next = nxt_buf_mem_alloc(c->mem_pool, size, 0); 2716206Smax.romanov@nginx.com if (nxt_slow_path(buf->next == NULL)) { 2717206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Failed to allocate " 2718206Smax.romanov@nginx.com "buffer for request body"); 2719206Smax.romanov@nginx.com return; 272088Smax.romanov@nginx.com } 2721206Smax.romanov@nginx.com 2722206Smax.romanov@nginx.com c->read = buf->next; 272388Smax.romanov@nginx.com } 272488Smax.romanov@nginx.com 2725206Smax.romanov@nginx.com nxt_debug(task, "router request body read again, rest: %uz", 2726206Smax.romanov@nginx.com h->parsed_content_length - b->preread_size); 272788Smax.romanov@nginx.com } 272888Smax.romanov@nginx.com 272988Smax.romanov@nginx.com nxt_conn_read(task->thread->engine, c); 273088Smax.romanov@nginx.com } 273188Smax.romanov@nginx.com 273288Smax.romanov@nginx.com 273388Smax.romanov@nginx.com static void 273488Smax.romanov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_conn_t *c, 273588Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap) 273688Smax.romanov@nginx.com { 2737167Smax.romanov@nginx.com nxt_mp_t *port_mp; 2738122Smax.romanov@nginx.com nxt_int_t res; 2739167Smax.romanov@nginx.com nxt_port_t *port; 274088Smax.romanov@nginx.com nxt_req_id_t req_id; 274188Smax.romanov@nginx.com nxt_event_engine_t *engine; 2742167Smax.romanov@nginx.com nxt_req_app_link_t *ra; 274388Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 274488Smax.romanov@nginx.com 274588Smax.romanov@nginx.com engine = task->thread->engine; 274688Smax.romanov@nginx.com 274788Smax.romanov@nginx.com do { 2748138Sigor@sysoev.ru req_id = nxt_random(&task->thread->random); 274988Smax.romanov@nginx.com } while (nxt_event_engine_request_find(engine, req_id) != NULL); 275088Smax.romanov@nginx.com 275188Smax.romanov@nginx.com rc = nxt_conn_request_add(c, req_id); 2752122Smax.romanov@nginx.com 275388Smax.romanov@nginx.com if (nxt_slow_path(rc == NULL)) { 2754141Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, "Failed to allocate " 2755141Smax.romanov@nginx.com "req->conn link"); 2756141Smax.romanov@nginx.com 2757141Smax.romanov@nginx.com return; 275888Smax.romanov@nginx.com } 275988Smax.romanov@nginx.com 276088Smax.romanov@nginx.com nxt_event_engine_request_add(engine, rc); 276188Smax.romanov@nginx.com 276288Smax.romanov@nginx.com nxt_debug(task, "req_id %uxD linked to conn %p at engine %p", 276388Smax.romanov@nginx.com req_id, c, engine); 276453Sigor@sysoev.ru 2765273Smax.romanov@nginx.com c->socket.data = NULL; 2766167Smax.romanov@nginx.com 2767167Smax.romanov@nginx.com ra = nxt_router_ra_create(task, rc); 2768167Smax.romanov@nginx.com 2769167Smax.romanov@nginx.com ra->ap = ap; 2770167Smax.romanov@nginx.com ra->reply_port = engine->port; 2771167Smax.romanov@nginx.com 2772167Smax.romanov@nginx.com res = nxt_router_app_port(task, ra); 2773141Smax.romanov@nginx.com 2774141Smax.romanov@nginx.com if (res != NXT_OK) { 2775141Smax.romanov@nginx.com return; 2776141Smax.romanov@nginx.com } 2777141Smax.romanov@nginx.com 2778167Smax.romanov@nginx.com port = ra->app_port; 2779141Smax.romanov@nginx.com 2780141Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 2781141Smax.romanov@nginx.com nxt_router_gen_error(task, rc->conn, 500, "Application port not found"); 2782141Smax.romanov@nginx.com return; 2783141Smax.romanov@nginx.com } 2784141Smax.romanov@nginx.com 2785122Smax.romanov@nginx.com port_mp = port->mem_pool; 2786167Smax.romanov@nginx.com port->mem_pool = c->mem_pool; 2787167Smax.romanov@nginx.com 2788167Smax.romanov@nginx.com nxt_router_process_http_request_mp(task, ra, port); 2789167Smax.romanov@nginx.com 2790167Smax.romanov@nginx.com port->mem_pool = port_mp; 2791167Smax.romanov@nginx.com 2792167Smax.romanov@nginx.com 2793167Smax.romanov@nginx.com nxt_router_ra_release(task, ra, ra->work.data); 2794167Smax.romanov@nginx.com } 2795167Smax.romanov@nginx.com 2796167Smax.romanov@nginx.com 2797167Smax.romanov@nginx.com static void 2798167Smax.romanov@nginx.com nxt_router_process_http_request_mp(nxt_task_t *task, nxt_req_app_link_t *ra, 2799167Smax.romanov@nginx.com nxt_port_t *port) 2800167Smax.romanov@nginx.com { 2801167Smax.romanov@nginx.com nxt_int_t res; 2802167Smax.romanov@nginx.com nxt_port_t *c_port, *reply_port; 2803167Smax.romanov@nginx.com nxt_conn_t *c; 2804167Smax.romanov@nginx.com nxt_app_wmsg_t wmsg; 2805167Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 2806167Smax.romanov@nginx.com 2807167Smax.romanov@nginx.com reply_port = ra->reply_port; 2808167Smax.romanov@nginx.com ap = ra->ap; 2809167Smax.romanov@nginx.com c = ra->rc->conn; 2810141Smax.romanov@nginx.com 2811141Smax.romanov@nginx.com c_port = nxt_process_connected_port_find(port->process, reply_port->pid, 2812141Smax.romanov@nginx.com reply_port->id); 2813141Smax.romanov@nginx.com if (nxt_slow_path(c_port != reply_port)) { 2814141Smax.romanov@nginx.com res = nxt_port_send_port(task, port, reply_port, 0); 2815122Smax.romanov@nginx.com 2816122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 2817167Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, 2818141Smax.romanov@nginx.com "Failed to send reply port to application"); 2819167Smax.romanov@nginx.com return; 2820122Smax.romanov@nginx.com } 2821122Smax.romanov@nginx.com 2822141Smax.romanov@nginx.com nxt_process_connected_port_add(port->process, reply_port); 282388Smax.romanov@nginx.com } 282488Smax.romanov@nginx.com 282588Smax.romanov@nginx.com wmsg.port = port; 282688Smax.romanov@nginx.com wmsg.write = NULL; 282788Smax.romanov@nginx.com wmsg.buf = &wmsg.write; 2828167Smax.romanov@nginx.com wmsg.stream = ra->req_id; 2829167Smax.romanov@nginx.com 2830216Sigor@sysoev.ru res = port->app->prepare_msg(task, &ap->r, &wmsg); 2831122Smax.romanov@nginx.com 2832122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 2833167Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, 2834141Smax.romanov@nginx.com "Failed to prepare message for application"); 2835167Smax.romanov@nginx.com return; 2836122Smax.romanov@nginx.com } 283788Smax.romanov@nginx.com 283888Smax.romanov@nginx.com nxt_debug(task, "about to send %d bytes buffer to worker port %d", 283988Smax.romanov@nginx.com nxt_buf_used_size(wmsg.write), 284088Smax.romanov@nginx.com wmsg.port->socket.fd); 284188Smax.romanov@nginx.com 2842122Smax.romanov@nginx.com res = nxt_port_socket_write(task, wmsg.port, NXT_PORT_MSG_DATA, 2843167Smax.romanov@nginx.com -1, ra->req_id, reply_port->id, wmsg.write); 2844122Smax.romanov@nginx.com 2845122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 2846167Smax.romanov@nginx.com nxt_router_gen_error(task, c, 500, 2847141Smax.romanov@nginx.com "Failed to send message to application"); 2848167Smax.romanov@nginx.com return; 2849122Smax.romanov@nginx.com } 285053Sigor@sysoev.ru } 285153Sigor@sysoev.ru 285253Sigor@sysoev.ru 2853216Sigor@sysoev.ru static nxt_int_t 2854216Sigor@sysoev.ru nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 2855216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg) 2856216Sigor@sysoev.ru { 2857216Sigor@sysoev.ru nxt_int_t rc; 2858216Sigor@sysoev.ru nxt_buf_t *b; 2859216Sigor@sysoev.ru nxt_http_field_t *field; 2860216Sigor@sysoev.ru nxt_app_request_header_t *h; 2861216Sigor@sysoev.ru 2862216Sigor@sysoev.ru static const nxt_str_t prefix = nxt_string("HTTP_"); 2863216Sigor@sysoev.ru static const nxt_str_t eof = nxt_null_string; 2864216Sigor@sysoev.ru 2865216Sigor@sysoev.ru h = &r->header; 2866216Sigor@sysoev.ru 2867216Sigor@sysoev.ru #define RC(S) \ 2868216Sigor@sysoev.ru do { \ 2869216Sigor@sysoev.ru rc = (S); \ 2870216Sigor@sysoev.ru if (nxt_slow_path(rc != NXT_OK)) { \ 2871216Sigor@sysoev.ru goto fail; \ 2872216Sigor@sysoev.ru } \ 2873216Sigor@sysoev.ru } while(0) 2874216Sigor@sysoev.ru 2875216Sigor@sysoev.ru #define NXT_WRITE(N) \ 2876216Sigor@sysoev.ru RC(nxt_app_msg_write_str(task, wmsg, N)) 2877216Sigor@sysoev.ru 2878216Sigor@sysoev.ru /* TODO error handle, async mmap buffer assignment */ 2879216Sigor@sysoev.ru 2880216Sigor@sysoev.ru NXT_WRITE(&h->method); 2881216Sigor@sysoev.ru NXT_WRITE(&h->target); 2882277Sigor@sysoev.ru 2883216Sigor@sysoev.ru if (h->path.start == h->target.start) { 2884216Sigor@sysoev.ru NXT_WRITE(&eof); 2885277Sigor@sysoev.ru 2886216Sigor@sysoev.ru } else { 2887216Sigor@sysoev.ru NXT_WRITE(&h->path); 2888216Sigor@sysoev.ru } 2889216Sigor@sysoev.ru 2890216Sigor@sysoev.ru if (h->query.start != NULL) { 2891216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 2892216Sigor@sysoev.ru h->query.start - h->target.start + 1)); 2893216Sigor@sysoev.ru } else { 2894216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 0)); 2895216Sigor@sysoev.ru } 2896216Sigor@sysoev.ru 2897216Sigor@sysoev.ru NXT_WRITE(&h->version); 2898216Sigor@sysoev.ru 2899216Sigor@sysoev.ru NXT_WRITE(&r->remote); 2900268Sigor@sysoev.ru NXT_WRITE(&r->local); 2901216Sigor@sysoev.ru 2902216Sigor@sysoev.ru NXT_WRITE(&h->host); 2903216Sigor@sysoev.ru NXT_WRITE(&h->content_type); 2904216Sigor@sysoev.ru NXT_WRITE(&h->content_length); 2905216Sigor@sysoev.ru 2906216Sigor@sysoev.ru nxt_list_each(field, h->fields) { 2907216Sigor@sysoev.ru RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, 2908216Sigor@sysoev.ru &prefix, &field->name)); 2909216Sigor@sysoev.ru NXT_WRITE(&field->value); 2910216Sigor@sysoev.ru 2911216Sigor@sysoev.ru } nxt_list_loop; 2912216Sigor@sysoev.ru 2913216Sigor@sysoev.ru /* end-of-headers mark */ 2914216Sigor@sysoev.ru NXT_WRITE(&eof); 2915216Sigor@sysoev.ru 2916216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 2917216Sigor@sysoev.ru 2918216Sigor@sysoev.ru for(b = r->body.buf; b != NULL; b = b->next) { 2919216Sigor@sysoev.ru RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 2920216Sigor@sysoev.ru nxt_buf_mem_used_size(&b->mem))); 2921216Sigor@sysoev.ru } 2922216Sigor@sysoev.ru 2923216Sigor@sysoev.ru #undef NXT_WRITE 2924216Sigor@sysoev.ru #undef RC 2925216Sigor@sysoev.ru 2926216Sigor@sysoev.ru return NXT_OK; 2927216Sigor@sysoev.ru 2928216Sigor@sysoev.ru fail: 2929216Sigor@sysoev.ru 2930216Sigor@sysoev.ru return NXT_ERROR; 2931216Sigor@sysoev.ru } 2932216Sigor@sysoev.ru 2933216Sigor@sysoev.ru 2934216Sigor@sysoev.ru static nxt_int_t 2935216Sigor@sysoev.ru nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 2936216Sigor@sysoev.ru nxt_app_wmsg_t *wmsg) 2937216Sigor@sysoev.ru { 2938216Sigor@sysoev.ru nxt_int_t rc; 2939216Sigor@sysoev.ru nxt_buf_t *b; 2940305Smax.romanov@nginx.com nxt_bool_t method_is_post; 2941216Sigor@sysoev.ru nxt_http_field_t *field; 2942216Sigor@sysoev.ru nxt_app_request_header_t *h; 2943216Sigor@sysoev.ru 2944216Sigor@sysoev.ru static const nxt_str_t prefix = nxt_string("HTTP_"); 2945216Sigor@sysoev.ru static const nxt_str_t eof = nxt_null_string; 2946216Sigor@sysoev.ru 2947216Sigor@sysoev.ru h = &r->header; 2948216Sigor@sysoev.ru 2949216Sigor@sysoev.ru #define RC(S) \ 2950216Sigor@sysoev.ru do { \ 2951216Sigor@sysoev.ru rc = (S); \ 2952216Sigor@sysoev.ru if (nxt_slow_path(rc != NXT_OK)) { \ 2953216Sigor@sysoev.ru goto fail; \ 2954216Sigor@sysoev.ru } \ 2955216Sigor@sysoev.ru } while(0) 2956216Sigor@sysoev.ru 2957216Sigor@sysoev.ru #define NXT_WRITE(N) \ 2958216Sigor@sysoev.ru RC(nxt_app_msg_write_str(task, wmsg, N)) 2959216Sigor@sysoev.ru 2960216Sigor@sysoev.ru /* TODO error handle, async mmap buffer assignment */ 2961216Sigor@sysoev.ru 2962216Sigor@sysoev.ru NXT_WRITE(&h->method); 2963216Sigor@sysoev.ru NXT_WRITE(&h->target); 2964277Sigor@sysoev.ru 2965216Sigor@sysoev.ru if (h->path.start == h->target.start) { 2966216Sigor@sysoev.ru NXT_WRITE(&eof); 2967277Sigor@sysoev.ru 2968216Sigor@sysoev.ru } else { 2969216Sigor@sysoev.ru NXT_WRITE(&h->path); 2970216Sigor@sysoev.ru } 2971216Sigor@sysoev.ru 2972216Sigor@sysoev.ru if (h->query.start != NULL) { 2973216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 2974216Sigor@sysoev.ru h->query.start - h->target.start + 1)); 2975216Sigor@sysoev.ru } else { 2976216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 0)); 2977216Sigor@sysoev.ru } 2978216Sigor@sysoev.ru 2979216Sigor@sysoev.ru NXT_WRITE(&h->version); 2980216Sigor@sysoev.ru 2981216Sigor@sysoev.ru // PHP_SELF 2982216Sigor@sysoev.ru // SCRIPT_NAME 2983216Sigor@sysoev.ru // SCRIPT_FILENAME 2984216Sigor@sysoev.ru // DOCUMENT_ROOT 2985216Sigor@sysoev.ru 2986216Sigor@sysoev.ru NXT_WRITE(&r->remote); 2987268Sigor@sysoev.ru NXT_WRITE(&r->local); 2988216Sigor@sysoev.ru 2989216Sigor@sysoev.ru NXT_WRITE(&h->host); 2990216Sigor@sysoev.ru NXT_WRITE(&h->cookie); 2991216Sigor@sysoev.ru NXT_WRITE(&h->content_type); 2992216Sigor@sysoev.ru NXT_WRITE(&h->content_length); 2993216Sigor@sysoev.ru 2994216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length)); 2995305Smax.romanov@nginx.com RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 2996305Smax.romanov@nginx.com 2997305Smax.romanov@nginx.com method_is_post = h->method.length == 4 && 2998305Smax.romanov@nginx.com h->method.start[0] == 'P' && 2999305Smax.romanov@nginx.com h->method.start[1] == 'O' && 3000305Smax.romanov@nginx.com h->method.start[2] == 'S' && 3001305Smax.romanov@nginx.com h->method.start[3] == 'T'; 3002305Smax.romanov@nginx.com 3003305Smax.romanov@nginx.com if (method_is_post) { 3004305Smax.romanov@nginx.com for(b = r->body.buf; b != NULL; b = b->next) { 3005305Smax.romanov@nginx.com RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3006305Smax.romanov@nginx.com nxt_buf_mem_used_size(&b->mem))); 3007305Smax.romanov@nginx.com } 3008305Smax.romanov@nginx.com } 3009216Sigor@sysoev.ru 3010216Sigor@sysoev.ru nxt_list_each(field, h->fields) { 3011216Sigor@sysoev.ru RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, 3012216Sigor@sysoev.ru &prefix, &field->name)); 3013216Sigor@sysoev.ru NXT_WRITE(&field->value); 3014216Sigor@sysoev.ru 3015216Sigor@sysoev.ru } nxt_list_loop; 3016216Sigor@sysoev.ru 3017216Sigor@sysoev.ru /* end-of-headers mark */ 3018216Sigor@sysoev.ru NXT_WRITE(&eof); 3019216Sigor@sysoev.ru 3020305Smax.romanov@nginx.com if (!method_is_post) { 3021305Smax.romanov@nginx.com for(b = r->body.buf; b != NULL; b = b->next) { 3022305Smax.romanov@nginx.com RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3023305Smax.romanov@nginx.com nxt_buf_mem_used_size(&b->mem))); 3024305Smax.romanov@nginx.com } 3025216Sigor@sysoev.ru } 3026216Sigor@sysoev.ru 3027216Sigor@sysoev.ru #undef NXT_WRITE 3028216Sigor@sysoev.ru #undef RC 3029216Sigor@sysoev.ru 3030216Sigor@sysoev.ru return NXT_OK; 3031216Sigor@sysoev.ru 3032216Sigor@sysoev.ru fail: 3033216Sigor@sysoev.ru 3034216Sigor@sysoev.ru return NXT_ERROR; 3035216Sigor@sysoev.ru } 3036216Sigor@sysoev.ru 3037216Sigor@sysoev.ru 3038216Sigor@sysoev.ru static nxt_int_t 3039216Sigor@sysoev.ru nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, nxt_app_wmsg_t *wmsg) 3040216Sigor@sysoev.ru { 3041216Sigor@sysoev.ru nxt_int_t rc; 3042216Sigor@sysoev.ru nxt_buf_t *b; 3043216Sigor@sysoev.ru nxt_http_field_t *field; 3044216Sigor@sysoev.ru nxt_app_request_header_t *h; 3045216Sigor@sysoev.ru 3046216Sigor@sysoev.ru static const nxt_str_t eof = nxt_null_string; 3047216Sigor@sysoev.ru 3048216Sigor@sysoev.ru h = &r->header; 3049216Sigor@sysoev.ru 3050216Sigor@sysoev.ru #define RC(S) \ 3051216Sigor@sysoev.ru do { \ 3052216Sigor@sysoev.ru rc = (S); \ 3053216Sigor@sysoev.ru if (nxt_slow_path(rc != NXT_OK)) { \ 3054216Sigor@sysoev.ru goto fail; \ 3055216Sigor@sysoev.ru } \ 3056216Sigor@sysoev.ru } while(0) 3057216Sigor@sysoev.ru 3058216Sigor@sysoev.ru #define NXT_WRITE(N) \ 3059216Sigor@sysoev.ru RC(nxt_app_msg_write_str(task, wmsg, N)) 3060216Sigor@sysoev.ru 3061216Sigor@sysoev.ru /* TODO error handle, async mmap buffer assignment */ 3062216Sigor@sysoev.ru 3063216Sigor@sysoev.ru NXT_WRITE(&h->method); 3064216Sigor@sysoev.ru NXT_WRITE(&h->target); 3065277Sigor@sysoev.ru 3066216Sigor@sysoev.ru if (h->path.start == h->target.start) { 3067216Sigor@sysoev.ru NXT_WRITE(&eof); 3068277Sigor@sysoev.ru 3069216Sigor@sysoev.ru } else { 3070216Sigor@sysoev.ru NXT_WRITE(&h->path); 3071216Sigor@sysoev.ru } 3072216Sigor@sysoev.ru 3073216Sigor@sysoev.ru if (h->query.start != NULL) { 3074216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 3075216Sigor@sysoev.ru h->query.start - h->target.start + 1)); 3076216Sigor@sysoev.ru } else { 3077216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, 0)); 3078216Sigor@sysoev.ru } 3079216Sigor@sysoev.ru 3080216Sigor@sysoev.ru NXT_WRITE(&h->version); 3081253Smax.romanov@nginx.com NXT_WRITE(&r->remote); 3082216Sigor@sysoev.ru 3083216Sigor@sysoev.ru NXT_WRITE(&h->host); 3084216Sigor@sysoev.ru NXT_WRITE(&h->cookie); 3085216Sigor@sysoev.ru NXT_WRITE(&h->content_type); 3086216Sigor@sysoev.ru NXT_WRITE(&h->content_length); 3087216Sigor@sysoev.ru 3088216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length)); 3089216Sigor@sysoev.ru 3090216Sigor@sysoev.ru nxt_list_each(field, h->fields) { 3091216Sigor@sysoev.ru NXT_WRITE(&field->name); 3092216Sigor@sysoev.ru NXT_WRITE(&field->value); 3093216Sigor@sysoev.ru 3094216Sigor@sysoev.ru } nxt_list_loop; 3095216Sigor@sysoev.ru 3096216Sigor@sysoev.ru /* end-of-headers mark */ 3097216Sigor@sysoev.ru NXT_WRITE(&eof); 3098216Sigor@sysoev.ru 3099216Sigor@sysoev.ru RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size)); 3100216Sigor@sysoev.ru 3101216Sigor@sysoev.ru for(b = r->body.buf; b != NULL; b = b->next) { 3102216Sigor@sysoev.ru RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos, 3103216Sigor@sysoev.ru nxt_buf_mem_used_size(&b->mem))); 3104216Sigor@sysoev.ru } 3105216Sigor@sysoev.ru 3106216Sigor@sysoev.ru #undef NXT_WRITE 3107216Sigor@sysoev.ru #undef RC 3108216Sigor@sysoev.ru 3109216Sigor@sysoev.ru return NXT_OK; 3110216Sigor@sysoev.ru 3111216Sigor@sysoev.ru fail: 3112216Sigor@sysoev.ru 3113216Sigor@sysoev.ru return NXT_ERROR; 3114216Sigor@sysoev.ru } 3115216Sigor@sysoev.ru 3116216Sigor@sysoev.ru 311762Sigor@sysoev.ru static const nxt_conn_state_t nxt_router_conn_close_state 311853Sigor@sysoev.ru nxt_aligned(64) = 311953Sigor@sysoev.ru { 312053Sigor@sysoev.ru .ready_handler = nxt_router_conn_free, 312153Sigor@sysoev.ru }; 312253Sigor@sysoev.ru 312353Sigor@sysoev.ru 312453Sigor@sysoev.ru static void 312588Smax.romanov@nginx.com nxt_router_conn_ready(nxt_task_t *task, void *obj, void *data) 312688Smax.romanov@nginx.com { 312788Smax.romanov@nginx.com nxt_buf_t *b; 312888Smax.romanov@nginx.com nxt_bool_t last; 312988Smax.romanov@nginx.com nxt_conn_t *c; 313088Smax.romanov@nginx.com nxt_work_queue_t *wq; 313188Smax.romanov@nginx.com 313288Smax.romanov@nginx.com nxt_debug(task, "router conn ready %p", obj); 313388Smax.romanov@nginx.com 313488Smax.romanov@nginx.com c = obj; 313588Smax.romanov@nginx.com b = c->write; 313688Smax.romanov@nginx.com 313788Smax.romanov@nginx.com wq = &task->thread->engine->fast_work_queue; 313888Smax.romanov@nginx.com 313988Smax.romanov@nginx.com last = 0; 314088Smax.romanov@nginx.com 314188Smax.romanov@nginx.com while (b != NULL) { 314288Smax.romanov@nginx.com if (!nxt_buf_is_sync(b)) { 314388Smax.romanov@nginx.com if (nxt_buf_used_size(b) > 0) { 314488Smax.romanov@nginx.com break; 314588Smax.romanov@nginx.com } 314688Smax.romanov@nginx.com } 314788Smax.romanov@nginx.com 314888Smax.romanov@nginx.com if (nxt_buf_is_last(b)) { 314988Smax.romanov@nginx.com last = 1; 315088Smax.romanov@nginx.com } 315188Smax.romanov@nginx.com 315288Smax.romanov@nginx.com nxt_work_queue_add(wq, b->completion_handler, task, b, b->parent); 315388Smax.romanov@nginx.com 315488Smax.romanov@nginx.com b = b->next; 315588Smax.romanov@nginx.com } 315688Smax.romanov@nginx.com 315788Smax.romanov@nginx.com c->write = b; 315888Smax.romanov@nginx.com 315988Smax.romanov@nginx.com if (b != NULL) { 316088Smax.romanov@nginx.com nxt_debug(task, "router conn %p has more data to write", obj); 316188Smax.romanov@nginx.com 316288Smax.romanov@nginx.com nxt_conn_write(task->thread->engine, c); 3163277Sigor@sysoev.ru 316488Smax.romanov@nginx.com } else { 316588Smax.romanov@nginx.com nxt_debug(task, "router conn %p no more data to write, last = %d", obj, 316688Smax.romanov@nginx.com last); 316788Smax.romanov@nginx.com 316888Smax.romanov@nginx.com if (last != 0) { 316988Smax.romanov@nginx.com nxt_debug(task, "enqueue router conn close %p (ready handler)", c); 317088Smax.romanov@nginx.com 317188Smax.romanov@nginx.com nxt_work_queue_add(wq, nxt_router_conn_close, task, c, 317288Smax.romanov@nginx.com c->socket.data); 317388Smax.romanov@nginx.com } 317488Smax.romanov@nginx.com } 317588Smax.romanov@nginx.com } 317688Smax.romanov@nginx.com 317788Smax.romanov@nginx.com 317888Smax.romanov@nginx.com static void 317953Sigor@sysoev.ru nxt_router_conn_close(nxt_task_t *task, void *obj, void *data) 318053Sigor@sysoev.ru { 318162Sigor@sysoev.ru nxt_conn_t *c; 318253Sigor@sysoev.ru 318353Sigor@sysoev.ru c = obj; 318453Sigor@sysoev.ru 318553Sigor@sysoev.ru nxt_debug(task, "router conn close"); 318653Sigor@sysoev.ru 318753Sigor@sysoev.ru c->write_state = &nxt_router_conn_close_state; 318853Sigor@sysoev.ru 318962Sigor@sysoev.ru nxt_conn_close(task->thread->engine, c); 319053Sigor@sysoev.ru } 319153Sigor@sysoev.ru 319253Sigor@sysoev.ru 319353Sigor@sysoev.ru static void 3194164Smax.romanov@nginx.com nxt_router_conn_mp_cleanup(nxt_task_t *task, void *obj, void *data) 3195164Smax.romanov@nginx.com { 3196164Smax.romanov@nginx.com nxt_socket_conf_joint_t *joint; 3197164Smax.romanov@nginx.com 3198164Smax.romanov@nginx.com joint = obj; 3199164Smax.romanov@nginx.com 3200164Smax.romanov@nginx.com nxt_router_conf_release(task, joint); 3201164Smax.romanov@nginx.com } 3202164Smax.romanov@nginx.com 3203164Smax.romanov@nginx.com 3204164Smax.romanov@nginx.com static void 320553Sigor@sysoev.ru nxt_router_conn_free(nxt_task_t *task, void *obj, void *data) 320653Sigor@sysoev.ru { 320762Sigor@sysoev.ru nxt_conn_t *c; 320888Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 320953Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 321053Sigor@sysoev.ru 321153Sigor@sysoev.ru c = obj; 321253Sigor@sysoev.ru 321353Sigor@sysoev.ru nxt_debug(task, "router conn close done"); 321453Sigor@sysoev.ru 321588Smax.romanov@nginx.com nxt_queue_each(rc, &c->requests, nxt_req_conn_link_t, link) { 321688Smax.romanov@nginx.com 321788Smax.romanov@nginx.com nxt_debug(task, "conn %p close, req %uxD", c, rc->req_id); 321888Smax.romanov@nginx.com 3219141Smax.romanov@nginx.com if (rc->app_port != NULL) { 3220141Smax.romanov@nginx.com nxt_router_app_release_port(task, rc->app_port, rc->app_port->app); 3221141Smax.romanov@nginx.com 3222141Smax.romanov@nginx.com rc->app_port = NULL; 3223141Smax.romanov@nginx.com } 3224141Smax.romanov@nginx.com 3225167Smax.romanov@nginx.com rc->conn = NULL; 3226167Smax.romanov@nginx.com 322788Smax.romanov@nginx.com nxt_event_engine_request_remove(task->thread->engine, rc); 322888Smax.romanov@nginx.com 322988Smax.romanov@nginx.com } nxt_queue_loop; 323088Smax.romanov@nginx.com 3231122Smax.romanov@nginx.com nxt_queue_remove(&c->link); 3232122Smax.romanov@nginx.com 3233131Smax.romanov@nginx.com joint = c->listen->socket.data; 3234131Smax.romanov@nginx.com 3235131Smax.romanov@nginx.com task = &task->thread->engine->task; 3236131Smax.romanov@nginx.com 3237164Smax.romanov@nginx.com nxt_mp_cleanup(c->mem_pool, nxt_router_conn_mp_cleanup, task, joint, NULL); 3238164Smax.romanov@nginx.com 3239164Smax.romanov@nginx.com nxt_mp_release(c->mem_pool, c); 324053Sigor@sysoev.ru } 324153Sigor@sysoev.ru 324253Sigor@sysoev.ru 324353Sigor@sysoev.ru static void 324453Sigor@sysoev.ru nxt_router_conn_error(nxt_task_t *task, void *obj, void *data) 324553Sigor@sysoev.ru { 324662Sigor@sysoev.ru nxt_conn_t *c; 324753Sigor@sysoev.ru 324853Sigor@sysoev.ru c = obj; 324953Sigor@sysoev.ru 325053Sigor@sysoev.ru nxt_debug(task, "router conn error"); 325153Sigor@sysoev.ru 3252273Smax.romanov@nginx.com if (c->socket.fd != -1) { 3253273Smax.romanov@nginx.com c->write_state = &nxt_router_conn_close_state; 3254273Smax.romanov@nginx.com 3255273Smax.romanov@nginx.com nxt_conn_close(task->thread->engine, c); 3256273Smax.romanov@nginx.com } 325753Sigor@sysoev.ru } 325853Sigor@sysoev.ru 325953Sigor@sysoev.ru 326053Sigor@sysoev.ru static void 326153Sigor@sysoev.ru nxt_router_conn_timeout(nxt_task_t *task, void *obj, void *data) 326253Sigor@sysoev.ru { 326362Sigor@sysoev.ru nxt_conn_t *c; 326462Sigor@sysoev.ru nxt_timer_t *timer; 326553Sigor@sysoev.ru 326653Sigor@sysoev.ru timer = obj; 326753Sigor@sysoev.ru 326853Sigor@sysoev.ru nxt_debug(task, "router conn timeout"); 326953Sigor@sysoev.ru 327062Sigor@sysoev.ru c = nxt_read_timer_conn(timer); 327153Sigor@sysoev.ru 3272206Smax.romanov@nginx.com if (c->read_state == &nxt_router_conn_read_header_state) { 3273206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 408, "Read header timeout"); 3274206Smax.romanov@nginx.com 3275206Smax.romanov@nginx.com } else { 3276206Smax.romanov@nginx.com nxt_router_gen_error(task, c, 408, "Read body timeout"); 3277206Smax.romanov@nginx.com } 327853Sigor@sysoev.ru } 327953Sigor@sysoev.ru 328053Sigor@sysoev.ru 328153Sigor@sysoev.ru static nxt_msec_t 328262Sigor@sysoev.ru nxt_router_conn_timeout_value(nxt_conn_t *c, uintptr_t data) 328353Sigor@sysoev.ru { 328453Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 328553Sigor@sysoev.ru 328653Sigor@sysoev.ru joint = c->listen->socket.data; 328753Sigor@sysoev.ru 328853Sigor@sysoev.ru return nxt_value_at(nxt_msec_t, joint->socket_conf, data); 328953Sigor@sysoev.ru } 3290