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> 10774Svbart@nginx.com #if (NXT_TLS) 11774Svbart@nginx.com #include <nxt_cert.h> 12774Svbart@nginx.com #endif 13431Sigor@sysoev.ru #include <nxt_http.h> 14743Smax.romanov@nginx.com #include <nxt_port_memory_int.h> 15743Smax.romanov@nginx.com #include <nxt_unit_request.h> 16743Smax.romanov@nginx.com #include <nxt_unit_response.h> 1720Sigor@sysoev.ru 1820Sigor@sysoev.ru 19115Sigor@sysoev.ru typedef struct { 20318Smax.romanov@nginx.com nxt_str_t type; 21507Smax.romanov@nginx.com uint32_t processes; 22507Smax.romanov@nginx.com uint32_t max_processes; 23507Smax.romanov@nginx.com uint32_t spare_processes; 24318Smax.romanov@nginx.com nxt_msec_t timeout; 25427Smax.romanov@nginx.com nxt_msec_t res_timeout; 26507Smax.romanov@nginx.com nxt_msec_t idle_timeout; 27318Smax.romanov@nginx.com uint32_t requests; 28318Smax.romanov@nginx.com nxt_conf_value_t *limits_value; 29507Smax.romanov@nginx.com nxt_conf_value_t *processes_value; 30133Sigor@sysoev.ru } nxt_router_app_conf_t; 31133Sigor@sysoev.ru 32133Sigor@sysoev.ru 33133Sigor@sysoev.ru typedef struct { 34964Sigor@sysoev.ru nxt_str_t pass; 35964Sigor@sysoev.ru nxt_str_t application; 36115Sigor@sysoev.ru } nxt_router_listener_conf_t; 37115Sigor@sysoev.ru 38115Sigor@sysoev.ru 39774Svbart@nginx.com #if (NXT_TLS) 40774Svbart@nginx.com 41774Svbart@nginx.com typedef struct { 42774Svbart@nginx.com nxt_str_t name; 43774Svbart@nginx.com nxt_socket_conf_t *conf; 44774Svbart@nginx.com 45774Svbart@nginx.com nxt_queue_link_t link; /* for nxt_socket_conf_t.tls */ 46774Svbart@nginx.com } nxt_router_tlssock_t; 47774Svbart@nginx.com 48774Svbart@nginx.com #endif 49774Svbart@nginx.com 50774Svbart@nginx.com 51423Smax.romanov@nginx.com typedef struct nxt_msg_info_s { 52423Smax.romanov@nginx.com nxt_buf_t *buf; 53423Smax.romanov@nginx.com nxt_port_mmap_tracking_t tracking; 54423Smax.romanov@nginx.com nxt_work_handler_t completion_handler; 55423Smax.romanov@nginx.com } nxt_msg_info_t; 56423Smax.romanov@nginx.com 57423Smax.romanov@nginx.com 58167Smax.romanov@nginx.com typedef struct nxt_req_app_link_s nxt_req_app_link_t; 59141Smax.romanov@nginx.com 60141Smax.romanov@nginx.com 61318Smax.romanov@nginx.com typedef struct { 62431Sigor@sysoev.ru uint32_t stream; 63431Sigor@sysoev.ru nxt_app_t *app; 64431Sigor@sysoev.ru nxt_port_t *app_port; 65*1007Salexander.borisov@nginx.com nxt_http_request_t *request; 66431Sigor@sysoev.ru nxt_msg_info_t msg_info; 67431Sigor@sysoev.ru nxt_req_app_link_t *ra; 68431Sigor@sysoev.ru 69431Sigor@sysoev.ru nxt_queue_link_t link; /* for nxt_conn_t.requests */ 70318Smax.romanov@nginx.com } nxt_req_conn_link_t; 71318Smax.romanov@nginx.com 72318Smax.romanov@nginx.com 73167Smax.romanov@nginx.com struct nxt_req_app_link_s { 74318Smax.romanov@nginx.com uint32_t stream; 75425Smax.romanov@nginx.com nxt_atomic_t use_count; 76167Smax.romanov@nginx.com nxt_port_t *app_port; 77167Smax.romanov@nginx.com nxt_port_t *reply_port; 78*1007Salexander.borisov@nginx.com nxt_http_request_t *request; 79423Smax.romanov@nginx.com nxt_msg_info_t msg_info; 80167Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 81167Smax.romanov@nginx.com 82427Smax.romanov@nginx.com nxt_nsec_t res_time; 83427Smax.romanov@nginx.com 84425Smax.romanov@nginx.com nxt_queue_link_t link_app_requests; /* for nxt_app_t.requests */ 85425Smax.romanov@nginx.com nxt_queue_link_t link_port_pending; /* for nxt_port_t.pending_requests */ 86427Smax.romanov@nginx.com nxt_queue_link_t link_app_pending; /* for nxt_app_t.pending */ 87167Smax.romanov@nginx.com 88167Smax.romanov@nginx.com nxt_mp_t *mem_pool; 89167Smax.romanov@nginx.com nxt_work_t work; 90345Smax.romanov@nginx.com 91345Smax.romanov@nginx.com int err_code; 92345Smax.romanov@nginx.com const char *err_str; 93167Smax.romanov@nginx.com }; 94167Smax.romanov@nginx.com 95167Smax.romanov@nginx.com 96198Sigor@sysoev.ru typedef struct { 97198Sigor@sysoev.ru nxt_socket_conf_t *socket_conf; 98198Sigor@sysoev.ru nxt_router_temp_conf_t *temp_conf; 99198Sigor@sysoev.ru } nxt_socket_rpc_t; 100198Sigor@sysoev.ru 101198Sigor@sysoev.ru 102507Smax.romanov@nginx.com typedef struct { 103507Smax.romanov@nginx.com nxt_app_t *app; 104507Smax.romanov@nginx.com nxt_router_temp_conf_t *temp_conf; 105507Smax.romanov@nginx.com } nxt_app_rpc_t; 106507Smax.romanov@nginx.com 107507Smax.romanov@nginx.com 108427Smax.romanov@nginx.com struct nxt_port_select_state_s { 109427Smax.romanov@nginx.com nxt_app_t *app; 110427Smax.romanov@nginx.com nxt_req_app_link_t *ra; 111427Smax.romanov@nginx.com 112427Smax.romanov@nginx.com nxt_port_t *failed_port; 113427Smax.romanov@nginx.com int failed_port_use_delta; 114427Smax.romanov@nginx.com 115507Smax.romanov@nginx.com uint8_t start_process; /* 1 bit */ 116427Smax.romanov@nginx.com nxt_req_app_link_t *shared_ra; 117427Smax.romanov@nginx.com nxt_port_t *port; 118427Smax.romanov@nginx.com }; 119427Smax.romanov@nginx.com 120427Smax.romanov@nginx.com typedef struct nxt_port_select_state_s nxt_port_select_state_t; 121427Smax.romanov@nginx.com 122662Smax.romanov@nginx.com static void nxt_router_greet_controller(nxt_task_t *task, 123662Smax.romanov@nginx.com nxt_port_t *controller_port); 124662Smax.romanov@nginx.com 125427Smax.romanov@nginx.com static void nxt_router_port_select(nxt_task_t *task, 126427Smax.romanov@nginx.com nxt_port_select_state_t *state); 127427Smax.romanov@nginx.com 128427Smax.romanov@nginx.com static nxt_int_t nxt_router_port_post_select(nxt_task_t *task, 129427Smax.romanov@nginx.com nxt_port_select_state_t *state); 130427Smax.romanov@nginx.com 131507Smax.romanov@nginx.com static nxt_int_t nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app); 132343Smax.romanov@nginx.com 133425Smax.romanov@nginx.com nxt_inline void 134425Smax.romanov@nginx.com nxt_router_ra_inc_use(nxt_req_app_link_t *ra) 135425Smax.romanov@nginx.com { 136425Smax.romanov@nginx.com nxt_atomic_fetch_add(&ra->use_count, 1); 137425Smax.romanov@nginx.com } 138425Smax.romanov@nginx.com 139425Smax.romanov@nginx.com nxt_inline void 140425Smax.romanov@nginx.com nxt_router_ra_dec_use(nxt_req_app_link_t *ra) 141425Smax.romanov@nginx.com { 142538Svbart@nginx.com #if (NXT_DEBUG) 143425Smax.romanov@nginx.com int c; 144425Smax.romanov@nginx.com 145425Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&ra->use_count, -1); 146425Smax.romanov@nginx.com 147425Smax.romanov@nginx.com nxt_assert(c > 1); 148538Svbart@nginx.com #else 149538Svbart@nginx.com (void) nxt_atomic_fetch_add(&ra->use_count, -1); 150538Svbart@nginx.com #endif 151425Smax.romanov@nginx.com } 152425Smax.romanov@nginx.com 153425Smax.romanov@nginx.com static void nxt_router_ra_use(nxt_task_t *task, nxt_req_app_link_t *ra, int i); 154425Smax.romanov@nginx.com 155139Sigor@sysoev.ru static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task); 156198Sigor@sysoev.ru static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data); 157198Sigor@sysoev.ru static void nxt_router_conf_ready(nxt_task_t *task, 158139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 159139Sigor@sysoev.ru static void nxt_router_conf_error(nxt_task_t *task, 160139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 161139Sigor@sysoev.ru static void nxt_router_conf_send(nxt_task_t *task, 162193Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type); 16353Sigor@sysoev.ru 164115Sigor@sysoev.ru static nxt_int_t nxt_router_conf_create(nxt_task_t *task, 165115Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end); 166133Sigor@sysoev.ru static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name); 167198Sigor@sysoev.ru static void nxt_router_listen_socket_rpc_create(nxt_task_t *task, 168198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf); 169198Sigor@sysoev.ru static void nxt_router_listen_socket_ready(nxt_task_t *task, 170198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 171198Sigor@sysoev.ru static void nxt_router_listen_socket_error(nxt_task_t *task, 172198Sigor@sysoev.ru nxt_port_recv_msg_t *msg, void *data); 173774Svbart@nginx.com #if (NXT_TLS) 174774Svbart@nginx.com static void nxt_router_tls_rpc_create(nxt_task_t *task, 175774Svbart@nginx.com nxt_router_temp_conf_t *tmcf, nxt_router_tlssock_t *tls); 176774Svbart@nginx.com static void nxt_router_tls_rpc_handler(nxt_task_t *task, 177774Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 178774Svbart@nginx.com #endif 179507Smax.romanov@nginx.com static void nxt_router_app_rpc_create(nxt_task_t *task, 180507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_app_t *app); 181507Smax.romanov@nginx.com static void nxt_router_app_prefork_ready(nxt_task_t *task, 182507Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 183507Smax.romanov@nginx.com static void nxt_router_app_prefork_error(nxt_task_t *task, 184507Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 185359Sigor@sysoev.ru static nxt_socket_conf_t *nxt_router_socket_conf(nxt_task_t *task, 186359Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_str_t *name); 187359Sigor@sysoev.ru static nxt_int_t nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, 188359Sigor@sysoev.ru nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa); 18953Sigor@sysoev.ru 19053Sigor@sysoev.ru static nxt_int_t nxt_router_engines_create(nxt_task_t *task, 19153Sigor@sysoev.ru nxt_router_t *router, nxt_router_temp_conf_t *tmcf, 19253Sigor@sysoev.ru const nxt_event_interface_t *interface); 193115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 194115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 195115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 196115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 197115Sigor@sysoev.ru static nxt_int_t nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 198115Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 199154Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 200154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 201154Sigor@sysoev.ru nxt_work_handler_t handler); 202313Sigor@sysoev.ru static nxt_int_t nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 203313Sigor@sysoev.ru nxt_router_engine_conf_t *recf); 204139Sigor@sysoev.ru static nxt_int_t nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 205139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets); 20653Sigor@sysoev.ru 20753Sigor@sysoev.ru static nxt_int_t nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 20853Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 20953Sigor@sysoev.ru static nxt_int_t nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 21053Sigor@sysoev.ru nxt_event_engine_t *engine); 211343Smax.romanov@nginx.com static void nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 212133Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 21353Sigor@sysoev.ru 214315Sigor@sysoev.ru static void nxt_router_engines_post(nxt_router_t *router, 215315Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf); 216315Sigor@sysoev.ru static void nxt_router_engine_post(nxt_event_engine_t *engine, 217315Sigor@sysoev.ru nxt_work_t *jobs); 21853Sigor@sysoev.ru 21953Sigor@sysoev.ru static void nxt_router_thread_start(void *data); 22053Sigor@sysoev.ru static void nxt_router_listen_socket_create(nxt_task_t *task, void *obj, 22153Sigor@sysoev.ru void *data); 22253Sigor@sysoev.ru static void nxt_router_listen_socket_update(nxt_task_t *task, void *obj, 22353Sigor@sysoev.ru void *data); 22453Sigor@sysoev.ru static void nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, 22553Sigor@sysoev.ru void *data); 226313Sigor@sysoev.ru static void nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, 227313Sigor@sysoev.ru void *data); 22853Sigor@sysoev.ru static void nxt_router_listen_socket_close(nxt_task_t *task, void *obj, 22953Sigor@sysoev.ru void *data); 23053Sigor@sysoev.ru static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, 23153Sigor@sysoev.ru void *data); 232359Sigor@sysoev.ru static void nxt_router_listen_socket_release(nxt_task_t *task, 233359Sigor@sysoev.ru nxt_socket_conf_t *skcf); 23453Sigor@sysoev.ru 235630Svbart@nginx.com static void nxt_router_access_log_writer(nxt_task_t *task, 236630Svbart@nginx.com nxt_http_request_t *r, nxt_router_access_log_t *access_log); 237630Svbart@nginx.com static u_char *nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, 238630Svbart@nginx.com struct tm *tm, size_t size, const char *format); 239630Svbart@nginx.com static void nxt_router_access_log_open(nxt_task_t *task, 240630Svbart@nginx.com nxt_router_temp_conf_t *tmcf); 241630Svbart@nginx.com static void nxt_router_access_log_ready(nxt_task_t *task, 242630Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 243630Svbart@nginx.com static void nxt_router_access_log_error(nxt_task_t *task, 244630Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 245630Svbart@nginx.com static void nxt_router_access_log_release(nxt_task_t *task, 246630Svbart@nginx.com nxt_thread_spinlock_t *lock, nxt_router_access_log_t *access_log); 247651Svbart@nginx.com static void nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, 248651Svbart@nginx.com void *data); 249631Svbart@nginx.com static void nxt_router_access_log_reopen_ready(nxt_task_t *task, 250631Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 251631Svbart@nginx.com static void nxt_router_access_log_reopen_error(nxt_task_t *task, 252631Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 253630Svbart@nginx.com 254343Smax.romanov@nginx.com static void nxt_router_app_port_ready(nxt_task_t *task, 255343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 256343Smax.romanov@nginx.com static void nxt_router_app_port_error(nxt_task_t *task, 257343Smax.romanov@nginx.com nxt_port_recv_msg_t *msg, void *data); 258343Smax.romanov@nginx.com 259753Smax.romanov@nginx.com static void nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app); 260343Smax.romanov@nginx.com static void nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port, 261343Smax.romanov@nginx.com uint32_t request_failed, uint32_t got_response); 262427Smax.romanov@nginx.com static nxt_int_t nxt_router_app_port(nxt_task_t *task, nxt_app_t *app, 263427Smax.romanov@nginx.com nxt_req_app_link_t *ra); 264141Smax.romanov@nginx.com 265425Smax.romanov@nginx.com static void nxt_router_app_prepare_request(nxt_task_t *task, 266343Smax.romanov@nginx.com nxt_req_app_link_t *ra); 267*1007Salexander.borisov@nginx.com static nxt_buf_t *nxt_router_prepare_msg(nxt_task_t *task, 268*1007Salexander.borisov@nginx.com nxt_http_request_t *r, nxt_port_t *port, const nxt_str_t *prefix); 269510Salexander.borisov@nginx.com 270318Smax.romanov@nginx.com static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data); 271507Smax.romanov@nginx.com static void nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, 272507Smax.romanov@nginx.com void *data); 273507Smax.romanov@nginx.com static void nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, 274507Smax.romanov@nginx.com void *data); 275753Smax.romanov@nginx.com static void nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, 276507Smax.romanov@nginx.com void *data); 277753Smax.romanov@nginx.com static void nxt_router_free_app(nxt_task_t *task, void *obj, void *data); 278431Sigor@sysoev.ru 279431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_send_state; 280431Sigor@sysoev.ru static void nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data); 281141Smax.romanov@nginx.com 282753Smax.romanov@nginx.com static void nxt_router_app_joint_use(nxt_task_t *task, 283753Smax.romanov@nginx.com nxt_app_joint_t *app_joint, int i); 284753Smax.romanov@nginx.com 285*1007Salexander.borisov@nginx.com static nxt_int_t nxt_router_http_request_done(nxt_task_t *task, 286*1007Salexander.borisov@nginx.com nxt_http_request_t *r); 287*1007Salexander.borisov@nginx.com static void nxt_router_http_request_release(nxt_task_t *task, void *obj, 288*1007Salexander.borisov@nginx.com void *data); 289*1007Salexander.borisov@nginx.com 290119Smax.romanov@nginx.com static nxt_router_t *nxt_router; 29120Sigor@sysoev.ru 292743Smax.romanov@nginx.com static const nxt_str_t http_prefix = nxt_string("HTTP_"); 293743Smax.romanov@nginx.com static const nxt_str_t empty_prefix = nxt_string(""); 294743Smax.romanov@nginx.com 295743Smax.romanov@nginx.com static const nxt_str_t *nxt_app_msg_prefix[] = { 296804Svbart@nginx.com &empty_prefix, 297743Smax.romanov@nginx.com &http_prefix, 298743Smax.romanov@nginx.com &http_prefix, 299743Smax.romanov@nginx.com &http_prefix, 300743Smax.romanov@nginx.com &http_prefix, 301977Smax.romanov@gmail.com &empty_prefix, 302216Sigor@sysoev.ru }; 303216Sigor@sysoev.ru 304216Sigor@sysoev.ru 305662Smax.romanov@nginx.com nxt_port_handlers_t nxt_router_process_port_handlers = { 306662Smax.romanov@nginx.com .quit = nxt_worker_process_quit_handler, 307662Smax.romanov@nginx.com .new_port = nxt_router_new_port_handler, 308662Smax.romanov@nginx.com .change_file = nxt_port_change_log_file_handler, 309662Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 310662Smax.romanov@nginx.com .data = nxt_router_conf_data_handler, 311662Smax.romanov@nginx.com .remove_pid = nxt_router_remove_pid_handler, 312662Smax.romanov@nginx.com .access_log = nxt_router_access_log_reopen_handler, 313662Smax.romanov@nginx.com .rpc_ready = nxt_port_rpc_handler, 314662Smax.romanov@nginx.com .rpc_error = nxt_port_rpc_handler, 315662Smax.romanov@nginx.com }; 316662Smax.romanov@nginx.com 317662Smax.romanov@nginx.com 31820Sigor@sysoev.ru nxt_int_t 319141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data) 32020Sigor@sysoev.ru { 321141Smax.romanov@nginx.com nxt_int_t ret; 322662Smax.romanov@nginx.com nxt_port_t *controller_port; 323141Smax.romanov@nginx.com nxt_router_t *router; 324141Smax.romanov@nginx.com nxt_runtime_t *rt; 325141Smax.romanov@nginx.com 326141Smax.romanov@nginx.com rt = task->thread->runtime; 32753Sigor@sysoev.ru 328771Sigor@sysoev.ru #if (NXT_TLS) 329771Sigor@sysoev.ru rt->tls = nxt_service_get(rt->services, "SSL/TLS", "OpenSSL"); 330771Sigor@sysoev.ru if (nxt_slow_path(rt->tls == NULL)) { 331771Sigor@sysoev.ru return NXT_ERROR; 332771Sigor@sysoev.ru } 333771Sigor@sysoev.ru 334771Sigor@sysoev.ru ret = rt->tls->library_init(task); 335771Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 336771Sigor@sysoev.ru return ret; 337771Sigor@sysoev.ru } 338771Sigor@sysoev.ru #endif 339771Sigor@sysoev.ru 340431Sigor@sysoev.ru ret = nxt_http_init(task, rt); 34188Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 34288Smax.romanov@nginx.com return ret; 34388Smax.romanov@nginx.com } 34488Smax.romanov@nginx.com 34553Sigor@sysoev.ru router = nxt_zalloc(sizeof(nxt_router_t)); 34653Sigor@sysoev.ru if (nxt_slow_path(router == NULL)) { 34753Sigor@sysoev.ru return NXT_ERROR; 34853Sigor@sysoev.ru } 34953Sigor@sysoev.ru 35053Sigor@sysoev.ru nxt_queue_init(&router->engines); 35153Sigor@sysoev.ru nxt_queue_init(&router->sockets); 352133Sigor@sysoev.ru nxt_queue_init(&router->apps); 35353Sigor@sysoev.ru 354119Smax.romanov@nginx.com nxt_router = router; 355119Smax.romanov@nginx.com 356662Smax.romanov@nginx.com controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; 357662Smax.romanov@nginx.com if (controller_port != NULL) { 358662Smax.romanov@nginx.com nxt_router_greet_controller(task, controller_port); 359662Smax.romanov@nginx.com } 360662Smax.romanov@nginx.com 361115Sigor@sysoev.ru return NXT_OK; 362115Sigor@sysoev.ru } 363115Sigor@sysoev.ru 364115Sigor@sysoev.ru 365343Smax.romanov@nginx.com static void 366662Smax.romanov@nginx.com nxt_router_greet_controller(nxt_task_t *task, nxt_port_t *controller_port) 367662Smax.romanov@nginx.com { 368662Smax.romanov@nginx.com nxt_port_socket_write(task, controller_port, NXT_PORT_MSG_PROCESS_READY, 369662Smax.romanov@nginx.com -1, 0, 0, NULL); 370662Smax.romanov@nginx.com } 371662Smax.romanov@nginx.com 372662Smax.romanov@nginx.com 373662Smax.romanov@nginx.com static void 374507Smax.romanov@nginx.com nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port, 375507Smax.romanov@nginx.com void *data) 376167Smax.romanov@nginx.com { 377343Smax.romanov@nginx.com size_t size; 378343Smax.romanov@nginx.com uint32_t stream; 379430Sigor@sysoev.ru nxt_mp_t *mp; 380648Svbart@nginx.com nxt_int_t ret; 381343Smax.romanov@nginx.com nxt_app_t *app; 382343Smax.romanov@nginx.com nxt_buf_t *b; 383343Smax.romanov@nginx.com nxt_port_t *main_port; 384343Smax.romanov@nginx.com nxt_runtime_t *rt; 385343Smax.romanov@nginx.com 386343Smax.romanov@nginx.com app = data; 387167Smax.romanov@nginx.com 388167Smax.romanov@nginx.com rt = task->thread->runtime; 389240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 390167Smax.romanov@nginx.com 391507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start process", &app->name, app); 392343Smax.romanov@nginx.com 393343Smax.romanov@nginx.com size = app->name.length + 1 + app->conf.length; 394343Smax.romanov@nginx.com 395343Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size); 396343Smax.romanov@nginx.com 397343Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 398343Smax.romanov@nginx.com goto failed; 399167Smax.romanov@nginx.com } 400167Smax.romanov@nginx.com 401343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->name); 402343Smax.romanov@nginx.com *b->mem.free++ = '\0'; 403343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 404343Smax.romanov@nginx.com 405753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, 1); 406753Smax.romanov@nginx.com 407343Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, port, 408343Smax.romanov@nginx.com nxt_router_app_port_ready, 409343Smax.romanov@nginx.com nxt_router_app_port_error, 410753Smax.romanov@nginx.com -1, app->joint); 411343Smax.romanov@nginx.com 412343Smax.romanov@nginx.com if (nxt_slow_path(stream == 0)) { 413753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, -1); 414753Smax.romanov@nginx.com 415343Smax.romanov@nginx.com goto failed; 416343Smax.romanov@nginx.com } 417343Smax.romanov@nginx.com 418648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1, 419648Svbart@nginx.com stream, port->id, b); 420648Svbart@nginx.com 421648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 422648Svbart@nginx.com nxt_port_rpc_cancel(task, port, stream); 423753Smax.romanov@nginx.com 424753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, -1); 425753Smax.romanov@nginx.com 426648Svbart@nginx.com goto failed; 427648Svbart@nginx.com } 428343Smax.romanov@nginx.com 429753Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 430753Smax.romanov@nginx.com 431343Smax.romanov@nginx.com return; 432343Smax.romanov@nginx.com 433343Smax.romanov@nginx.com failed: 434343Smax.romanov@nginx.com 435648Svbart@nginx.com if (b != NULL) { 436648Svbart@nginx.com mp = b->data; 437648Svbart@nginx.com nxt_mp_free(mp, b); 438648Svbart@nginx.com nxt_mp_release(mp); 439648Svbart@nginx.com } 440648Svbart@nginx.com 441343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 442343Smax.romanov@nginx.com 443507Smax.romanov@nginx.com app->pending_processes--; 444343Smax.romanov@nginx.com 445343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 446343Smax.romanov@nginx.com 447343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 448167Smax.romanov@nginx.com } 449167Smax.romanov@nginx.com 450167Smax.romanov@nginx.com 451753Smax.romanov@nginx.com static void 452753Smax.romanov@nginx.com nxt_router_app_joint_use(nxt_task_t *task, nxt_app_joint_t *app_joint, int i) 453753Smax.romanov@nginx.com { 454753Smax.romanov@nginx.com app_joint->use_count += i; 455753Smax.romanov@nginx.com 456753Smax.romanov@nginx.com if (app_joint->use_count == 0) { 457753Smax.romanov@nginx.com nxt_assert(app_joint->app == NULL); 458753Smax.romanov@nginx.com 459753Smax.romanov@nginx.com nxt_free(app_joint); 460753Smax.romanov@nginx.com } 461753Smax.romanov@nginx.com } 462753Smax.romanov@nginx.com 463753Smax.romanov@nginx.com 464343Smax.romanov@nginx.com static nxt_int_t 465507Smax.romanov@nginx.com nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app) 466141Smax.romanov@nginx.com { 467343Smax.romanov@nginx.com nxt_int_t res; 468343Smax.romanov@nginx.com nxt_port_t *router_port; 469343Smax.romanov@nginx.com nxt_runtime_t *rt; 470343Smax.romanov@nginx.com 471343Smax.romanov@nginx.com rt = task->thread->runtime; 472343Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 473343Smax.romanov@nginx.com 474343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 475343Smax.romanov@nginx.com 476507Smax.romanov@nginx.com res = nxt_port_post(task, router_port, nxt_router_start_app_process_handler, 477343Smax.romanov@nginx.com app); 478343Smax.romanov@nginx.com 479343Smax.romanov@nginx.com if (res == NXT_OK) { 480343Smax.romanov@nginx.com return res; 481318Smax.romanov@nginx.com } 482318Smax.romanov@nginx.com 483343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 484343Smax.romanov@nginx.com 485507Smax.romanov@nginx.com app->pending_processes--; 486343Smax.romanov@nginx.com 487343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 488343Smax.romanov@nginx.com 489343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 490343Smax.romanov@nginx.com 491343Smax.romanov@nginx.com return NXT_ERROR; 492318Smax.romanov@nginx.com } 493318Smax.romanov@nginx.com 494318Smax.romanov@nginx.com 495351Smax.romanov@nginx.com nxt_inline void 496351Smax.romanov@nginx.com nxt_router_ra_init(nxt_task_t *task, nxt_req_app_link_t *ra, 497351Smax.romanov@nginx.com nxt_req_conn_link_t *rc) 498167Smax.romanov@nginx.com { 499318Smax.romanov@nginx.com nxt_event_engine_t *engine; 500351Smax.romanov@nginx.com 501318Smax.romanov@nginx.com engine = task->thread->engine; 502167Smax.romanov@nginx.com 503167Smax.romanov@nginx.com nxt_memzero(ra, sizeof(nxt_req_app_link_t)); 504167Smax.romanov@nginx.com 505318Smax.romanov@nginx.com ra->stream = rc->stream; 506425Smax.romanov@nginx.com ra->use_count = 1; 507167Smax.romanov@nginx.com ra->rc = rc; 508318Smax.romanov@nginx.com rc->ra = ra; 509318Smax.romanov@nginx.com ra->reply_port = engine->port; 510*1007Salexander.borisov@nginx.com ra->request = rc->request; 511167Smax.romanov@nginx.com 512167Smax.romanov@nginx.com ra->work.handler = NULL; 513318Smax.romanov@nginx.com ra->work.task = &engine->task; 514167Smax.romanov@nginx.com ra->work.obj = ra; 515318Smax.romanov@nginx.com ra->work.data = engine; 516351Smax.romanov@nginx.com } 517351Smax.romanov@nginx.com 518351Smax.romanov@nginx.com 519351Smax.romanov@nginx.com nxt_inline nxt_req_app_link_t * 520351Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_app_link_t *ra_src) 521351Smax.romanov@nginx.com { 522351Smax.romanov@nginx.com nxt_mp_t *mp; 523351Smax.romanov@nginx.com nxt_req_app_link_t *ra; 524351Smax.romanov@nginx.com 525425Smax.romanov@nginx.com if (ra_src->mem_pool != NULL) { 526425Smax.romanov@nginx.com return ra_src; 527425Smax.romanov@nginx.com } 528425Smax.romanov@nginx.com 529*1007Salexander.borisov@nginx.com mp = ra_src->request->mem_pool; 530351Smax.romanov@nginx.com 531430Sigor@sysoev.ru ra = nxt_mp_alloc(mp, sizeof(nxt_req_app_link_t)); 532351Smax.romanov@nginx.com 533351Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 534351Smax.romanov@nginx.com 535351Smax.romanov@nginx.com ra_src->rc->ra = NULL; 536351Smax.romanov@nginx.com ra_src->rc = NULL; 537351Smax.romanov@nginx.com 538351Smax.romanov@nginx.com return NULL; 539351Smax.romanov@nginx.com } 540351Smax.romanov@nginx.com 541430Sigor@sysoev.ru nxt_mp_retain(mp); 542430Sigor@sysoev.ru 543351Smax.romanov@nginx.com nxt_router_ra_init(task, ra, ra_src->rc); 544351Smax.romanov@nginx.com 545351Smax.romanov@nginx.com ra->mem_pool = mp; 546167Smax.romanov@nginx.com 547167Smax.romanov@nginx.com return ra; 548167Smax.romanov@nginx.com } 549167Smax.romanov@nginx.com 550167Smax.romanov@nginx.com 551423Smax.romanov@nginx.com nxt_inline nxt_bool_t 552423Smax.romanov@nginx.com nxt_router_msg_cancel(nxt_task_t *task, nxt_msg_info_t *msg_info, 553423Smax.romanov@nginx.com uint32_t stream) 554423Smax.romanov@nginx.com { 555423Smax.romanov@nginx.com nxt_buf_t *b, *next; 556423Smax.romanov@nginx.com nxt_bool_t cancelled; 557423Smax.romanov@nginx.com 558423Smax.romanov@nginx.com if (msg_info->buf == NULL) { 559423Smax.romanov@nginx.com return 0; 560423Smax.romanov@nginx.com } 561423Smax.romanov@nginx.com 562423Smax.romanov@nginx.com cancelled = nxt_port_mmap_tracking_cancel(task, &msg_info->tracking, 563423Smax.romanov@nginx.com stream); 564423Smax.romanov@nginx.com 565423Smax.romanov@nginx.com if (cancelled) { 566423Smax.romanov@nginx.com nxt_debug(task, "stream #%uD: cancelled by router", stream); 567423Smax.romanov@nginx.com } 568423Smax.romanov@nginx.com 569423Smax.romanov@nginx.com for (b = msg_info->buf; b != NULL; b = next) { 570423Smax.romanov@nginx.com next = b->next; 571423Smax.romanov@nginx.com 572423Smax.romanov@nginx.com b->completion_handler = msg_info->completion_handler; 573423Smax.romanov@nginx.com 574423Smax.romanov@nginx.com if (b->is_port_mmap_sent) { 575423Smax.romanov@nginx.com b->is_port_mmap_sent = cancelled == 0; 576423Smax.romanov@nginx.com b->completion_handler(task, b, b->parent); 577423Smax.romanov@nginx.com } 578423Smax.romanov@nginx.com } 579423Smax.romanov@nginx.com 580423Smax.romanov@nginx.com msg_info->buf = NULL; 581423Smax.romanov@nginx.com 582423Smax.romanov@nginx.com return cancelled; 583423Smax.romanov@nginx.com } 584423Smax.romanov@nginx.com 585423Smax.romanov@nginx.com 586167Smax.romanov@nginx.com static void 587425Smax.romanov@nginx.com nxt_router_ra_update_peer(nxt_task_t *task, nxt_req_app_link_t *ra); 588425Smax.romanov@nginx.com 589425Smax.romanov@nginx.com 590425Smax.romanov@nginx.com static void 591425Smax.romanov@nginx.com nxt_router_ra_update_peer_handler(nxt_task_t *task, void *obj, void *data) 592167Smax.romanov@nginx.com { 593425Smax.romanov@nginx.com nxt_req_app_link_t *ra; 594425Smax.romanov@nginx.com 595425Smax.romanov@nginx.com ra = obj; 596425Smax.romanov@nginx.com 597425Smax.romanov@nginx.com nxt_router_ra_update_peer(task, ra); 598425Smax.romanov@nginx.com 599425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 600425Smax.romanov@nginx.com } 601425Smax.romanov@nginx.com 602425Smax.romanov@nginx.com 603425Smax.romanov@nginx.com static void 604425Smax.romanov@nginx.com nxt_router_ra_update_peer(nxt_task_t *task, nxt_req_app_link_t *ra) 605425Smax.romanov@nginx.com { 606343Smax.romanov@nginx.com nxt_event_engine_t *engine; 607343Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 608318Smax.romanov@nginx.com 609425Smax.romanov@nginx.com engine = ra->work.data; 610318Smax.romanov@nginx.com 611343Smax.romanov@nginx.com if (task->thread->engine != engine) { 612425Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 613425Smax.romanov@nginx.com 614425Smax.romanov@nginx.com ra->work.handler = nxt_router_ra_update_peer_handler; 615318Smax.romanov@nginx.com ra->work.task = &engine->task; 616318Smax.romanov@nginx.com ra->work.next = NULL; 617318Smax.romanov@nginx.com 618425Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD post update peer to %p", 619318Smax.romanov@nginx.com ra->stream, engine); 620318Smax.romanov@nginx.com 621318Smax.romanov@nginx.com nxt_event_engine_post(engine, &ra->work); 622318Smax.romanov@nginx.com 623318Smax.romanov@nginx.com return; 624318Smax.romanov@nginx.com } 625318Smax.romanov@nginx.com 626425Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD update peer", ra->stream); 627425Smax.romanov@nginx.com 628425Smax.romanov@nginx.com rc = ra->rc; 629425Smax.romanov@nginx.com 630425Smax.romanov@nginx.com if (rc != NULL && ra->app_port != NULL) { 631425Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, engine->port, rc, ra->app_port->pid); 632425Smax.romanov@nginx.com } 633425Smax.romanov@nginx.com 634425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 635425Smax.romanov@nginx.com } 636425Smax.romanov@nginx.com 637425Smax.romanov@nginx.com 638425Smax.romanov@nginx.com static void 639425Smax.romanov@nginx.com nxt_router_ra_release(nxt_task_t *task, nxt_req_app_link_t *ra) 640425Smax.romanov@nginx.com { 641431Sigor@sysoev.ru nxt_mp_t *mp; 642431Sigor@sysoev.ru nxt_req_conn_link_t *rc; 643425Smax.romanov@nginx.com 644425Smax.romanov@nginx.com nxt_assert(task->thread->engine == ra->work.data); 645425Smax.romanov@nginx.com nxt_assert(ra->use_count == 0); 646425Smax.romanov@nginx.com 647343Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD release", ra->stream); 648343Smax.romanov@nginx.com 649343Smax.romanov@nginx.com rc = ra->rc; 650343Smax.romanov@nginx.com 651343Smax.romanov@nginx.com if (rc != NULL) { 652423Smax.romanov@nginx.com if (nxt_slow_path(ra->err_code != 0)) { 653*1007Salexander.borisov@nginx.com nxt_http_request_error(task, rc->request, ra->err_code); 654423Smax.romanov@nginx.com 655423Smax.romanov@nginx.com } else { 656423Smax.romanov@nginx.com rc->app_port = ra->app_port; 657423Smax.romanov@nginx.com rc->msg_info = ra->msg_info; 658423Smax.romanov@nginx.com 659425Smax.romanov@nginx.com if (rc->app->timeout != 0) { 660*1007Salexander.borisov@nginx.com rc->request->timer.handler = nxt_router_app_timeout; 661*1007Salexander.borisov@nginx.com rc->request->timer_data = rc; 662*1007Salexander.borisov@nginx.com nxt_timer_add(task->thread->engine, &rc->request->timer, 663425Smax.romanov@nginx.com rc->app->timeout); 664425Smax.romanov@nginx.com } 665425Smax.romanov@nginx.com 666423Smax.romanov@nginx.com ra->app_port = NULL; 667423Smax.romanov@nginx.com ra->msg_info.buf = NULL; 668423Smax.romanov@nginx.com } 669343Smax.romanov@nginx.com 670343Smax.romanov@nginx.com rc->ra = NULL; 671343Smax.romanov@nginx.com ra->rc = NULL; 672343Smax.romanov@nginx.com } 673343Smax.romanov@nginx.com 674343Smax.romanov@nginx.com if (ra->app_port != NULL) { 675343Smax.romanov@nginx.com nxt_router_app_port_release(task, ra->app_port, 0, 1); 676343Smax.romanov@nginx.com 677343Smax.romanov@nginx.com ra->app_port = NULL; 678167Smax.romanov@nginx.com } 679167Smax.romanov@nginx.com 680423Smax.romanov@nginx.com nxt_router_msg_cancel(task, &ra->msg_info, ra->stream); 681423Smax.romanov@nginx.com 682430Sigor@sysoev.ru mp = ra->mem_pool; 683430Sigor@sysoev.ru 684430Sigor@sysoev.ru if (mp != NULL) { 685430Sigor@sysoev.ru nxt_mp_free(mp, ra); 686430Sigor@sysoev.ru nxt_mp_release(mp); 687351Smax.romanov@nginx.com } 688167Smax.romanov@nginx.com } 689167Smax.romanov@nginx.com 690167Smax.romanov@nginx.com 691425Smax.romanov@nginx.com static void 692425Smax.romanov@nginx.com nxt_router_ra_release_handler(nxt_task_t *task, void *obj, void *data) 693425Smax.romanov@nginx.com { 694425Smax.romanov@nginx.com nxt_req_app_link_t *ra; 695425Smax.romanov@nginx.com 696425Smax.romanov@nginx.com ra = obj; 697425Smax.romanov@nginx.com 698425Smax.romanov@nginx.com nxt_assert(ra->work.data == data); 699425Smax.romanov@nginx.com 700425Smax.romanov@nginx.com nxt_atomic_fetch_add(&ra->use_count, -1); 701425Smax.romanov@nginx.com 702425Smax.romanov@nginx.com nxt_router_ra_release(task, ra); 703425Smax.romanov@nginx.com } 704425Smax.romanov@nginx.com 705425Smax.romanov@nginx.com 706425Smax.romanov@nginx.com static void 707425Smax.romanov@nginx.com nxt_router_ra_use(nxt_task_t *task, nxt_req_app_link_t *ra, int i) 708425Smax.romanov@nginx.com { 709425Smax.romanov@nginx.com int c; 710425Smax.romanov@nginx.com nxt_event_engine_t *engine; 711425Smax.romanov@nginx.com 712425Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&ra->use_count, i); 713425Smax.romanov@nginx.com 714425Smax.romanov@nginx.com if (i < 0 && c == -i) { 715425Smax.romanov@nginx.com engine = ra->work.data; 716425Smax.romanov@nginx.com 717425Smax.romanov@nginx.com if (task->thread->engine == engine) { 718425Smax.romanov@nginx.com nxt_router_ra_release(task, ra); 719425Smax.romanov@nginx.com 720425Smax.romanov@nginx.com return; 721425Smax.romanov@nginx.com } 722425Smax.romanov@nginx.com 723425Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 724425Smax.romanov@nginx.com 725425Smax.romanov@nginx.com ra->work.handler = nxt_router_ra_release_handler; 726425Smax.romanov@nginx.com ra->work.task = &engine->task; 727425Smax.romanov@nginx.com ra->work.next = NULL; 728425Smax.romanov@nginx.com 729425Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD post release to %p", 730425Smax.romanov@nginx.com ra->stream, engine); 731425Smax.romanov@nginx.com 732425Smax.romanov@nginx.com nxt_event_engine_post(engine, &ra->work); 733425Smax.romanov@nginx.com } 734425Smax.romanov@nginx.com } 735425Smax.romanov@nginx.com 736425Smax.romanov@nginx.com 737423Smax.romanov@nginx.com nxt_inline void 738521Szelenkov@nginx.com nxt_router_ra_error(nxt_req_app_link_t *ra, int code, const char *str) 739345Smax.romanov@nginx.com { 740423Smax.romanov@nginx.com ra->app_port = NULL; 741423Smax.romanov@nginx.com ra->err_code = code; 742423Smax.romanov@nginx.com ra->err_str = str; 743345Smax.romanov@nginx.com } 744345Smax.romanov@nginx.com 745345Smax.romanov@nginx.com 746427Smax.romanov@nginx.com nxt_inline void 747427Smax.romanov@nginx.com nxt_router_ra_pending(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra) 748427Smax.romanov@nginx.com { 749427Smax.romanov@nginx.com nxt_queue_insert_tail(&ra->app_port->pending_requests, 750427Smax.romanov@nginx.com &ra->link_port_pending); 751427Smax.romanov@nginx.com nxt_queue_insert_tail(&app->pending, &ra->link_app_pending); 752427Smax.romanov@nginx.com 753427Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 754427Smax.romanov@nginx.com 755427Smax.romanov@nginx.com ra->res_time = nxt_thread_monotonic_time(task->thread) + app->res_timeout; 756427Smax.romanov@nginx.com 757427Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD enqueue to pending_requests", ra->stream); 758427Smax.romanov@nginx.com } 759427Smax.romanov@nginx.com 760427Smax.romanov@nginx.com 761425Smax.romanov@nginx.com nxt_inline nxt_bool_t 762425Smax.romanov@nginx.com nxt_queue_chk_remove(nxt_queue_link_t *lnk) 763425Smax.romanov@nginx.com { 764425Smax.romanov@nginx.com if (lnk->next != NULL) { 765425Smax.romanov@nginx.com nxt_queue_remove(lnk); 766425Smax.romanov@nginx.com 767425Smax.romanov@nginx.com lnk->next = NULL; 768425Smax.romanov@nginx.com 769425Smax.romanov@nginx.com return 1; 770425Smax.romanov@nginx.com } 771425Smax.romanov@nginx.com 772425Smax.romanov@nginx.com return 0; 773425Smax.romanov@nginx.com } 774425Smax.romanov@nginx.com 775425Smax.romanov@nginx.com 776343Smax.romanov@nginx.com nxt_inline void 777343Smax.romanov@nginx.com nxt_router_rc_unlink(nxt_task_t *task, nxt_req_conn_link_t *rc) 778343Smax.romanov@nginx.com { 779425Smax.romanov@nginx.com int ra_use_delta; 780343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 781343Smax.romanov@nginx.com 782343Smax.romanov@nginx.com if (rc->app_port != NULL) { 783343Smax.romanov@nginx.com nxt_router_app_port_release(task, rc->app_port, 0, 1); 784343Smax.romanov@nginx.com 785343Smax.romanov@nginx.com rc->app_port = NULL; 786343Smax.romanov@nginx.com } 787343Smax.romanov@nginx.com 788423Smax.romanov@nginx.com nxt_router_msg_cancel(task, &rc->msg_info, rc->stream); 789423Smax.romanov@nginx.com 790343Smax.romanov@nginx.com ra = rc->ra; 791343Smax.romanov@nginx.com 792343Smax.romanov@nginx.com if (ra != NULL) { 793343Smax.romanov@nginx.com rc->ra = NULL; 794343Smax.romanov@nginx.com ra->rc = NULL; 795343Smax.romanov@nginx.com 796425Smax.romanov@nginx.com ra_use_delta = 0; 797425Smax.romanov@nginx.com 798343Smax.romanov@nginx.com nxt_thread_mutex_lock(&rc->app->mutex); 799343Smax.romanov@nginx.com 800425Smax.romanov@nginx.com if (ra->link_app_requests.next == NULL 801427Smax.romanov@nginx.com && ra->link_port_pending.next == NULL 802427Smax.romanov@nginx.com && ra->link_app_pending.next == NULL) 803425Smax.romanov@nginx.com { 804425Smax.romanov@nginx.com ra = NULL; 805343Smax.romanov@nginx.com 806343Smax.romanov@nginx.com } else { 807425Smax.romanov@nginx.com ra_use_delta -= nxt_queue_chk_remove(&ra->link_app_requests); 808425Smax.romanov@nginx.com ra_use_delta -= nxt_queue_chk_remove(&ra->link_port_pending); 809427Smax.romanov@nginx.com nxt_queue_chk_remove(&ra->link_app_pending); 810343Smax.romanov@nginx.com } 811343Smax.romanov@nginx.com 812343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&rc->app->mutex); 813425Smax.romanov@nginx.com 814425Smax.romanov@nginx.com if (ra != NULL) { 815425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, ra_use_delta); 816425Smax.romanov@nginx.com } 817343Smax.romanov@nginx.com } 818343Smax.romanov@nginx.com 819343Smax.romanov@nginx.com if (rc->app != NULL) { 820343Smax.romanov@nginx.com nxt_router_app_use(task, rc->app, -1); 821343Smax.romanov@nginx.com 822343Smax.romanov@nginx.com rc->app = NULL; 823343Smax.romanov@nginx.com } 824343Smax.romanov@nginx.com 825*1007Salexander.borisov@nginx.com if (rc->request != NULL) { 826*1007Salexander.borisov@nginx.com rc->request->timer_data = NULL; 827*1007Salexander.borisov@nginx.com 828*1007Salexander.borisov@nginx.com nxt_router_http_request_done(task, rc->request); 829*1007Salexander.borisov@nginx.com 830*1007Salexander.borisov@nginx.com rc->request = NULL; 831346Smax.romanov@nginx.com } 832343Smax.romanov@nginx.com } 833343Smax.romanov@nginx.com 834343Smax.romanov@nginx.com 835141Smax.romanov@nginx.com void 836141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 837141Smax.romanov@nginx.com { 838141Smax.romanov@nginx.com nxt_port_new_port_handler(task, msg); 839141Smax.romanov@nginx.com 840670Smax.romanov@nginx.com if (msg->u.new_port != NULL 841670Smax.romanov@nginx.com && msg->u.new_port->type == NXT_PROCESS_CONTROLLER) 842670Smax.romanov@nginx.com { 843662Smax.romanov@nginx.com nxt_router_greet_controller(task, msg->u.new_port); 844662Smax.romanov@nginx.com } 845662Smax.romanov@nginx.com 846192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 847141Smax.romanov@nginx.com return; 848141Smax.romanov@nginx.com } 849141Smax.romanov@nginx.com 850426Smax.romanov@nginx.com if (msg->u.new_port == NULL 851426Smax.romanov@nginx.com || msg->u.new_port->type != NXT_PROCESS_WORKER) 852347Smax.romanov@nginx.com { 853192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 854141Smax.romanov@nginx.com } 855192Smax.romanov@nginx.com 856192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 857141Smax.romanov@nginx.com } 858141Smax.romanov@nginx.com 859141Smax.romanov@nginx.com 860139Sigor@sysoev.ru void 861139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 862115Sigor@sysoev.ru { 863198Sigor@sysoev.ru nxt_int_t ret; 864139Sigor@sysoev.ru nxt_buf_t *b; 865139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 866139Sigor@sysoev.ru 867139Sigor@sysoev.ru tmcf = nxt_router_temp_conf(task); 868139Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 869139Sigor@sysoev.ru return; 87053Sigor@sysoev.ru } 87153Sigor@sysoev.ru 872494Spluknet@nginx.com nxt_debug(task, "nxt_router_conf_data_handler(%O): %*s", 873423Smax.romanov@nginx.com nxt_buf_used_size(msg->buf), 874493Spluknet@nginx.com (size_t) nxt_buf_used_size(msg->buf), msg->buf->mem.pos); 875423Smax.romanov@nginx.com 876591Sigor@sysoev.ru tmcf->router_conf->router = nxt_router; 877139Sigor@sysoev.ru tmcf->stream = msg->port_msg.stream; 878139Sigor@sysoev.ru tmcf->port = nxt_runtime_port_find(task->thread->runtime, 879198Sigor@sysoev.ru msg->port_msg.pid, 880198Sigor@sysoev.ru msg->port_msg.reply_port); 881198Sigor@sysoev.ru 882779Smax.romanov@nginx.com if (nxt_slow_path(tmcf->port == NULL)) { 883779Smax.romanov@nginx.com nxt_alert(task, "reply port not found"); 884779Smax.romanov@nginx.com 885779Smax.romanov@nginx.com return; 886779Smax.romanov@nginx.com } 887779Smax.romanov@nginx.com 888779Smax.romanov@nginx.com nxt_port_use(task, tmcf->port, 1); 889779Smax.romanov@nginx.com 890591Sigor@sysoev.ru b = nxt_buf_chk_make_plain(tmcf->router_conf->mem_pool, 891591Sigor@sysoev.ru msg->buf, msg->size); 892551Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 893551Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 894551Smax.romanov@nginx.com 895551Smax.romanov@nginx.com return; 896551Smax.romanov@nginx.com } 897551Smax.romanov@nginx.com 898198Sigor@sysoev.ru ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free); 899198Sigor@sysoev.ru 900198Sigor@sysoev.ru if (nxt_fast_path(ret == NXT_OK)) { 901198Sigor@sysoev.ru nxt_router_conf_apply(task, tmcf, NULL); 902198Sigor@sysoev.ru 903198Sigor@sysoev.ru } else { 904198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 905139Sigor@sysoev.ru } 90653Sigor@sysoev.ru } 90753Sigor@sysoev.ru 90853Sigor@sysoev.ru 909347Smax.romanov@nginx.com static void 910507Smax.romanov@nginx.com nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port, 911507Smax.romanov@nginx.com void *data) 912347Smax.romanov@nginx.com { 913347Smax.romanov@nginx.com union { 914347Smax.romanov@nginx.com nxt_pid_t removed_pid; 915347Smax.romanov@nginx.com void *data; 916347Smax.romanov@nginx.com } u; 917347Smax.romanov@nginx.com 918347Smax.romanov@nginx.com u.data = data; 919347Smax.romanov@nginx.com 920347Smax.romanov@nginx.com nxt_port_rpc_remove_peer(task, port, u.removed_pid); 921347Smax.romanov@nginx.com } 922347Smax.romanov@nginx.com 923347Smax.romanov@nginx.com 924192Smax.romanov@nginx.com void 925192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 926192Smax.romanov@nginx.com { 927347Smax.romanov@nginx.com nxt_event_engine_t *engine; 928318Smax.romanov@nginx.com 929192Smax.romanov@nginx.com nxt_port_remove_pid_handler(task, msg); 930192Smax.romanov@nginx.com 931192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 932192Smax.romanov@nginx.com return; 933192Smax.romanov@nginx.com } 934192Smax.romanov@nginx.com 935318Smax.romanov@nginx.com nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0) 936318Smax.romanov@nginx.com { 937507Smax.romanov@nginx.com nxt_port_post(task, engine->port, nxt_router_app_process_remove_pid, 938347Smax.romanov@nginx.com msg->u.data); 939318Smax.romanov@nginx.com } 940318Smax.romanov@nginx.com nxt_queue_loop; 941318Smax.romanov@nginx.com 942192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 943192Smax.romanov@nginx.com 944192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 945192Smax.romanov@nginx.com } 946192Smax.romanov@nginx.com 947192Smax.romanov@nginx.com 94853Sigor@sysoev.ru static nxt_router_temp_conf_t * 949139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task) 95053Sigor@sysoev.ru { 95165Sigor@sysoev.ru nxt_mp_t *mp, *tmp; 95253Sigor@sysoev.ru nxt_router_conf_t *rtcf; 95353Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 95453Sigor@sysoev.ru 95565Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 95653Sigor@sysoev.ru if (nxt_slow_path(mp == NULL)) { 95753Sigor@sysoev.ru return NULL; 95853Sigor@sysoev.ru } 95953Sigor@sysoev.ru 96065Sigor@sysoev.ru rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t)); 96153Sigor@sysoev.ru if (nxt_slow_path(rtcf == NULL)) { 96253Sigor@sysoev.ru goto fail; 96353Sigor@sysoev.ru } 96453Sigor@sysoev.ru 96553Sigor@sysoev.ru rtcf->mem_pool = mp; 96653Sigor@sysoev.ru 96765Sigor@sysoev.ru tmp = nxt_mp_create(1024, 128, 256, 32); 96853Sigor@sysoev.ru if (nxt_slow_path(tmp == NULL)) { 96953Sigor@sysoev.ru goto fail; 97053Sigor@sysoev.ru } 97153Sigor@sysoev.ru 97265Sigor@sysoev.ru tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t)); 97353Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 97453Sigor@sysoev.ru goto temp_fail; 97553Sigor@sysoev.ru } 97653Sigor@sysoev.ru 97753Sigor@sysoev.ru tmcf->mem_pool = tmp; 978591Sigor@sysoev.ru tmcf->router_conf = rtcf; 979139Sigor@sysoev.ru tmcf->count = 1; 980139Sigor@sysoev.ru tmcf->engine = task->thread->engine; 98153Sigor@sysoev.ru 98253Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, 4, 98353Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 98453Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 98553Sigor@sysoev.ru goto temp_fail; 98653Sigor@sysoev.ru } 98753Sigor@sysoev.ru 98853Sigor@sysoev.ru nxt_queue_init(&tmcf->deleting); 98953Sigor@sysoev.ru nxt_queue_init(&tmcf->keeping); 99053Sigor@sysoev.ru nxt_queue_init(&tmcf->updating); 99153Sigor@sysoev.ru nxt_queue_init(&tmcf->pending); 99253Sigor@sysoev.ru nxt_queue_init(&tmcf->creating); 993416Smax.romanov@nginx.com 994774Svbart@nginx.com #if (NXT_TLS) 995774Svbart@nginx.com nxt_queue_init(&tmcf->tls); 996774Svbart@nginx.com #endif 997774Svbart@nginx.com 998133Sigor@sysoev.ru nxt_queue_init(&tmcf->apps); 999133Sigor@sysoev.ru nxt_queue_init(&tmcf->previous); 100053Sigor@sysoev.ru 100153Sigor@sysoev.ru return tmcf; 100253Sigor@sysoev.ru 100353Sigor@sysoev.ru temp_fail: 100453Sigor@sysoev.ru 100565Sigor@sysoev.ru nxt_mp_destroy(tmp); 100653Sigor@sysoev.ru 100753Sigor@sysoev.ru fail: 100853Sigor@sysoev.ru 100965Sigor@sysoev.ru nxt_mp_destroy(mp); 101053Sigor@sysoev.ru 101153Sigor@sysoev.ru return NULL; 101253Sigor@sysoev.ru } 101353Sigor@sysoev.ru 101453Sigor@sysoev.ru 1015507Smax.romanov@nginx.com nxt_inline nxt_bool_t 1016507Smax.romanov@nginx.com nxt_router_app_can_start(nxt_app_t *app) 1017507Smax.romanov@nginx.com { 1018507Smax.romanov@nginx.com return app->processes + app->pending_processes < app->max_processes 1019507Smax.romanov@nginx.com && app->pending_processes < app->max_pending_processes; 1020507Smax.romanov@nginx.com } 1021507Smax.romanov@nginx.com 1022507Smax.romanov@nginx.com 1023507Smax.romanov@nginx.com nxt_inline nxt_bool_t 1024507Smax.romanov@nginx.com nxt_router_app_need_start(nxt_app_t *app) 1025507Smax.romanov@nginx.com { 1026507Smax.romanov@nginx.com return app->idle_processes + app->pending_processes 1027507Smax.romanov@nginx.com < app->spare_processes; 1028507Smax.romanov@nginx.com } 1029507Smax.romanov@nginx.com 1030507Smax.romanov@nginx.com 1031198Sigor@sysoev.ru static void 1032198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data) 1033139Sigor@sysoev.ru { 1034139Sigor@sysoev.ru nxt_int_t ret; 1035507Smax.romanov@nginx.com nxt_app_t *app; 1036139Sigor@sysoev.ru nxt_router_t *router; 1037139Sigor@sysoev.ru nxt_runtime_t *rt; 1038198Sigor@sysoev.ru nxt_queue_link_t *qlk; 1039198Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1040630Svbart@nginx.com nxt_router_conf_t *rtcf; 1041198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 1042139Sigor@sysoev.ru const nxt_event_interface_t *interface; 1043774Svbart@nginx.com #if (NXT_TLS) 1044774Svbart@nginx.com nxt_router_tlssock_t *tls; 1045774Svbart@nginx.com #endif 1046139Sigor@sysoev.ru 1047198Sigor@sysoev.ru tmcf = obj; 1048198Sigor@sysoev.ru 1049198Sigor@sysoev.ru qlk = nxt_queue_first(&tmcf->pending); 1050198Sigor@sysoev.ru 1051198Sigor@sysoev.ru if (qlk != nxt_queue_tail(&tmcf->pending)) { 1052198Sigor@sysoev.ru nxt_queue_remove(qlk); 1053198Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->creating, qlk); 1054198Sigor@sysoev.ru 1055198Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1056198Sigor@sysoev.ru 1057198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(task, tmcf, skcf); 1058198Sigor@sysoev.ru 1059198Sigor@sysoev.ru return; 1060139Sigor@sysoev.ru } 1061139Sigor@sysoev.ru 1062774Svbart@nginx.com #if (NXT_TLS) 1063774Svbart@nginx.com qlk = nxt_queue_first(&tmcf->tls); 1064774Svbart@nginx.com 1065774Svbart@nginx.com if (qlk != nxt_queue_tail(&tmcf->tls)) { 1066774Svbart@nginx.com nxt_queue_remove(qlk); 1067774Svbart@nginx.com 1068774Svbart@nginx.com tls = nxt_queue_link_data(qlk, nxt_router_tlssock_t, link); 1069774Svbart@nginx.com 1070774Svbart@nginx.com nxt_router_tls_rpc_create(task, tmcf, tls); 1071774Svbart@nginx.com return; 1072774Svbart@nginx.com } 1073774Svbart@nginx.com #endif 1074774Svbart@nginx.com 1075507Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1076507Smax.romanov@nginx.com 1077507Smax.romanov@nginx.com if (nxt_router_app_need_start(app)) { 1078507Smax.romanov@nginx.com nxt_router_app_rpc_create(task, tmcf, app); 1079507Smax.romanov@nginx.com return; 1080507Smax.romanov@nginx.com } 1081507Smax.romanov@nginx.com 1082507Smax.romanov@nginx.com } nxt_queue_loop; 1083507Smax.romanov@nginx.com 1084630Svbart@nginx.com rtcf = tmcf->router_conf; 1085630Svbart@nginx.com 1086630Svbart@nginx.com if (rtcf->access_log != NULL && rtcf->access_log->fd == -1) { 1087630Svbart@nginx.com nxt_router_access_log_open(task, tmcf); 1088630Svbart@nginx.com return; 1089630Svbart@nginx.com } 1090630Svbart@nginx.com 1091139Sigor@sysoev.ru rt = task->thread->runtime; 1092139Sigor@sysoev.ru 1093139Sigor@sysoev.ru interface = nxt_service_get(rt->services, "engine", NULL); 1094139Sigor@sysoev.ru 1095630Svbart@nginx.com router = rtcf->router; 1096198Sigor@sysoev.ru 1097139Sigor@sysoev.ru ret = nxt_router_engines_create(task, router, tmcf, interface); 1098139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1099198Sigor@sysoev.ru goto fail; 1100139Sigor@sysoev.ru } 1101139Sigor@sysoev.ru 1102139Sigor@sysoev.ru ret = nxt_router_threads_create(task, rt, tmcf); 1103139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1104198Sigor@sysoev.ru goto fail; 1105139Sigor@sysoev.ru } 1106139Sigor@sysoev.ru 1107343Smax.romanov@nginx.com nxt_router_apps_sort(task, router, tmcf); 1108139Sigor@sysoev.ru 1109315Sigor@sysoev.ru nxt_router_engines_post(router, tmcf); 1110139Sigor@sysoev.ru 1111139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->updating); 1112139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->creating); 1113139Sigor@sysoev.ru 1114630Svbart@nginx.com router->access_log = rtcf->access_log; 1115630Svbart@nginx.com 1116198Sigor@sysoev.ru nxt_router_conf_ready(task, tmcf); 1117198Sigor@sysoev.ru 1118198Sigor@sysoev.ru return; 1119198Sigor@sysoev.ru 1120198Sigor@sysoev.ru fail: 1121198Sigor@sysoev.ru 1122198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 1123198Sigor@sysoev.ru 1124198Sigor@sysoev.ru return; 1125139Sigor@sysoev.ru } 1126139Sigor@sysoev.ru 1127139Sigor@sysoev.ru 1128139Sigor@sysoev.ru static void 1129139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data) 1130139Sigor@sysoev.ru { 1131153Sigor@sysoev.ru nxt_joint_job_t *job; 1132153Sigor@sysoev.ru 1133153Sigor@sysoev.ru job = obj; 1134153Sigor@sysoev.ru 1135198Sigor@sysoev.ru nxt_router_conf_ready(task, job->tmcf); 1136139Sigor@sysoev.ru } 1137139Sigor@sysoev.ru 1138139Sigor@sysoev.ru 1139139Sigor@sysoev.ru static void 1140198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 1141139Sigor@sysoev.ru { 1142139Sigor@sysoev.ru nxt_debug(task, "temp conf count:%D", tmcf->count); 1143139Sigor@sysoev.ru 1144139Sigor@sysoev.ru if (--tmcf->count == 0) { 1145193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST); 1146139Sigor@sysoev.ru } 1147139Sigor@sysoev.ru } 1148139Sigor@sysoev.ru 1149139Sigor@sysoev.ru 1150139Sigor@sysoev.ru static void 1151139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 1152139Sigor@sysoev.ru { 1153507Smax.romanov@nginx.com nxt_app_t *app; 1154568Smax.romanov@nginx.com nxt_queue_t new_socket_confs; 1155148Sigor@sysoev.ru nxt_socket_t s; 1156149Sigor@sysoev.ru nxt_router_t *router; 1157148Sigor@sysoev.ru nxt_queue_link_t *qlk; 1158148Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1159630Svbart@nginx.com nxt_router_conf_t *rtcf; 1160148Sigor@sysoev.ru 1161564Svbart@nginx.com nxt_alert(task, "failed to apply new conf"); 1162198Sigor@sysoev.ru 1163148Sigor@sysoev.ru for (qlk = nxt_queue_first(&tmcf->creating); 1164148Sigor@sysoev.ru qlk != nxt_queue_tail(&tmcf->creating); 1165148Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 1166148Sigor@sysoev.ru { 1167148Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1168359Sigor@sysoev.ru s = skcf->listen->socket; 1169148Sigor@sysoev.ru 1170148Sigor@sysoev.ru if (s != -1) { 1171148Sigor@sysoev.ru nxt_socket_close(task, s); 1172148Sigor@sysoev.ru } 1173148Sigor@sysoev.ru 1174359Sigor@sysoev.ru nxt_free(skcf->listen); 1175148Sigor@sysoev.ru } 1176148Sigor@sysoev.ru 1177568Smax.romanov@nginx.com nxt_queue_init(&new_socket_confs); 1178568Smax.romanov@nginx.com nxt_queue_add(&new_socket_confs, &tmcf->updating); 1179568Smax.romanov@nginx.com nxt_queue_add(&new_socket_confs, &tmcf->pending); 1180568Smax.romanov@nginx.com nxt_queue_add(&new_socket_confs, &tmcf->creating); 1181568Smax.romanov@nginx.com 1182964Sigor@sysoev.ru rtcf = tmcf->router_conf; 1183964Sigor@sysoev.ru 1184964Sigor@sysoev.ru nxt_http_routes_cleanup(task, rtcf->routes); 1185964Sigor@sysoev.ru 1186568Smax.romanov@nginx.com nxt_queue_each(skcf, &new_socket_confs, nxt_socket_conf_t, link) { 1187568Smax.romanov@nginx.com 1188964Sigor@sysoev.ru if (skcf->pass != NULL) { 1189964Sigor@sysoev.ru nxt_http_pass_cleanup(task, skcf->pass); 1190568Smax.romanov@nginx.com } 1191568Smax.romanov@nginx.com 1192568Smax.romanov@nginx.com } nxt_queue_loop; 1193568Smax.romanov@nginx.com 1194507Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1195507Smax.romanov@nginx.com 1196753Smax.romanov@nginx.com nxt_router_app_unlink(task, app); 1197507Smax.romanov@nginx.com 1198507Smax.romanov@nginx.com } nxt_queue_loop; 1199507Smax.romanov@nginx.com 1200630Svbart@nginx.com router = rtcf->router; 1201149Sigor@sysoev.ru 1202149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->keeping); 1203149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->deleting); 1204149Sigor@sysoev.ru 1205416Smax.romanov@nginx.com nxt_queue_add(&router->apps, &tmcf->previous); 1206416Smax.romanov@nginx.com 1207148Sigor@sysoev.ru // TODO: new engines and threads 1208148Sigor@sysoev.ru 1209630Svbart@nginx.com nxt_router_access_log_release(task, &router->lock, rtcf->access_log); 1210630Svbart@nginx.com 1211630Svbart@nginx.com nxt_mp_destroy(rtcf->mem_pool); 1212139Sigor@sysoev.ru 1213193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR); 1214139Sigor@sysoev.ru } 1215139Sigor@sysoev.ru 1216139Sigor@sysoev.ru 1217139Sigor@sysoev.ru static void 1218139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1219193Smax.romanov@nginx.com nxt_port_msg_type_t type) 1220139Sigor@sysoev.ru { 1221193Smax.romanov@nginx.com nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL); 1222779Smax.romanov@nginx.com 1223779Smax.romanov@nginx.com nxt_port_use(task, tmcf->port, -1); 1224779Smax.romanov@nginx.com 1225779Smax.romanov@nginx.com tmcf->port = NULL; 1226139Sigor@sysoev.ru } 1227139Sigor@sysoev.ru 1228139Sigor@sysoev.ru 1229115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_conf[] = { 1230115Sigor@sysoev.ru { 1231133Sigor@sysoev.ru nxt_string("listeners_threads"), 1232115Sigor@sysoev.ru NXT_CONF_MAP_INT32, 1233115Sigor@sysoev.ru offsetof(nxt_router_conf_t, threads), 1234115Sigor@sysoev.ru }, 1235115Sigor@sysoev.ru }; 1236115Sigor@sysoev.ru 1237115Sigor@sysoev.ru 1238133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_app_conf[] = { 1239115Sigor@sysoev.ru { 1240133Sigor@sysoev.ru nxt_string("type"), 1241115Sigor@sysoev.ru NXT_CONF_MAP_STR, 1242133Sigor@sysoev.ru offsetof(nxt_router_app_conf_t, type), 1243115Sigor@sysoev.ru }, 1244115Sigor@sysoev.ru 1245115Sigor@sysoev.ru { 1246507Smax.romanov@nginx.com nxt_string("limits"), 1247507Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 1248507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, limits_value), 1249133Sigor@sysoev.ru }, 1250318Smax.romanov@nginx.com 1251318Smax.romanov@nginx.com { 1252507Smax.romanov@nginx.com nxt_string("processes"), 1253507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1254507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, processes), 1255507Smax.romanov@nginx.com }, 1256507Smax.romanov@nginx.com 1257507Smax.romanov@nginx.com { 1258507Smax.romanov@nginx.com nxt_string("processes"), 1259318Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 1260507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, processes_value), 1261318Smax.romanov@nginx.com }, 1262318Smax.romanov@nginx.com }; 1263318Smax.romanov@nginx.com 1264318Smax.romanov@nginx.com 1265318Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_limits_conf[] = { 1266318Smax.romanov@nginx.com { 1267318Smax.romanov@nginx.com nxt_string("timeout"), 1268318Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1269318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, timeout), 1270318Smax.romanov@nginx.com }, 1271318Smax.romanov@nginx.com 1272318Smax.romanov@nginx.com { 1273427Smax.romanov@nginx.com nxt_string("reschedule_timeout"), 1274427Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1275427Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, res_timeout), 1276427Smax.romanov@nginx.com }, 1277427Smax.romanov@nginx.com 1278427Smax.romanov@nginx.com { 1279318Smax.romanov@nginx.com nxt_string("requests"), 1280318Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1281318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, requests), 1282318Smax.romanov@nginx.com }, 1283133Sigor@sysoev.ru }; 1284133Sigor@sysoev.ru 1285133Sigor@sysoev.ru 1286507Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_processes_conf[] = { 1287507Smax.romanov@nginx.com { 1288507Smax.romanov@nginx.com nxt_string("spare"), 1289507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1290507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, spare_processes), 1291507Smax.romanov@nginx.com }, 1292507Smax.romanov@nginx.com 1293507Smax.romanov@nginx.com { 1294507Smax.romanov@nginx.com nxt_string("max"), 1295507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1296507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, max_processes), 1297507Smax.romanov@nginx.com }, 1298507Smax.romanov@nginx.com 1299507Smax.romanov@nginx.com { 1300507Smax.romanov@nginx.com nxt_string("idle_timeout"), 1301507Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1302507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, idle_timeout), 1303507Smax.romanov@nginx.com }, 1304507Smax.romanov@nginx.com }; 1305507Smax.romanov@nginx.com 1306507Smax.romanov@nginx.com 1307133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_listener_conf[] = { 1308133Sigor@sysoev.ru { 1309964Sigor@sysoev.ru nxt_string("pass"), 1310964Sigor@sysoev.ru NXT_CONF_MAP_STR_COPY, 1311964Sigor@sysoev.ru offsetof(nxt_router_listener_conf_t, pass), 1312964Sigor@sysoev.ru }, 1313964Sigor@sysoev.ru 1314964Sigor@sysoev.ru { 1315133Sigor@sysoev.ru nxt_string("application"), 1316964Sigor@sysoev.ru NXT_CONF_MAP_STR_COPY, 1317133Sigor@sysoev.ru offsetof(nxt_router_listener_conf_t, application), 1318115Sigor@sysoev.ru }, 1319115Sigor@sysoev.ru }; 1320115Sigor@sysoev.ru 1321115Sigor@sysoev.ru 1322115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_http_conf[] = { 1323115Sigor@sysoev.ru { 1324115Sigor@sysoev.ru nxt_string("header_buffer_size"), 1325115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 1326115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_buffer_size), 1327115Sigor@sysoev.ru }, 1328115Sigor@sysoev.ru 1329115Sigor@sysoev.ru { 1330115Sigor@sysoev.ru nxt_string("large_header_buffer_size"), 1331115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 1332115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, large_header_buffer_size), 1333115Sigor@sysoev.ru }, 1334115Sigor@sysoev.ru 1335115Sigor@sysoev.ru { 1336206Smax.romanov@nginx.com nxt_string("large_header_buffers"), 1337206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1338206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, large_header_buffers), 1339206Smax.romanov@nginx.com }, 1340206Smax.romanov@nginx.com 1341206Smax.romanov@nginx.com { 1342206Smax.romanov@nginx.com nxt_string("body_buffer_size"), 1343206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1344206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_buffer_size), 1345206Smax.romanov@nginx.com }, 1346206Smax.romanov@nginx.com 1347206Smax.romanov@nginx.com { 1348206Smax.romanov@nginx.com nxt_string("max_body_size"), 1349206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1350206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, max_body_size), 1351206Smax.romanov@nginx.com }, 1352206Smax.romanov@nginx.com 1353206Smax.romanov@nginx.com { 1354431Sigor@sysoev.ru nxt_string("idle_timeout"), 1355431Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1356431Sigor@sysoev.ru offsetof(nxt_socket_conf_t, idle_timeout), 1357431Sigor@sysoev.ru }, 1358431Sigor@sysoev.ru 1359431Sigor@sysoev.ru { 1360115Sigor@sysoev.ru nxt_string("header_read_timeout"), 1361115Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1362115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_read_timeout), 1363115Sigor@sysoev.ru }, 1364206Smax.romanov@nginx.com 1365206Smax.romanov@nginx.com { 1366206Smax.romanov@nginx.com nxt_string("body_read_timeout"), 1367206Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1368206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_read_timeout), 1369206Smax.romanov@nginx.com }, 1370431Sigor@sysoev.ru 1371431Sigor@sysoev.ru { 1372431Sigor@sysoev.ru nxt_string("send_timeout"), 1373431Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1374431Sigor@sysoev.ru offsetof(nxt_socket_conf_t, send_timeout), 1375431Sigor@sysoev.ru }, 1376115Sigor@sysoev.ru }; 1377115Sigor@sysoev.ru 1378115Sigor@sysoev.ru 137953Sigor@sysoev.ru static nxt_int_t 1380115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1381115Sigor@sysoev.ru u_char *start, u_char *end) 138253Sigor@sysoev.ru { 1383133Sigor@sysoev.ru u_char *p; 1384133Sigor@sysoev.ru size_t size; 1385115Sigor@sysoev.ru nxt_mp_t *mp; 1386115Sigor@sysoev.ru uint32_t next; 1387115Sigor@sysoev.ru nxt_int_t ret; 1388630Svbart@nginx.com nxt_str_t name, path; 1389133Sigor@sysoev.ru nxt_app_t *app, *prev; 1390359Sigor@sysoev.ru nxt_router_t *router; 1391753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 1392630Svbart@nginx.com nxt_conf_value_t *conf, *http, *value; 1393133Sigor@sysoev.ru nxt_conf_value_t *applications, *application; 1394133Sigor@sysoev.ru nxt_conf_value_t *listeners, *listener; 1395964Sigor@sysoev.ru nxt_conf_value_t *routes_conf; 1396115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1397964Sigor@sysoev.ru nxt_http_routes_t *routes; 1398507Smax.romanov@nginx.com nxt_event_engine_t *engine; 1399216Sigor@sysoev.ru nxt_app_lang_module_t *lang; 1400133Sigor@sysoev.ru nxt_router_app_conf_t apcf; 1401630Svbart@nginx.com nxt_router_access_log_t *access_log; 1402115Sigor@sysoev.ru nxt_router_listener_conf_t lscf; 1403774Svbart@nginx.com #if (NXT_TLS) 1404774Svbart@nginx.com nxt_router_tlssock_t *tls; 1405774Svbart@nginx.com #endif 1406115Sigor@sysoev.ru 1407716Svbart@nginx.com static nxt_str_t http_path = nxt_string("/settings/http"); 1408133Sigor@sysoev.ru static nxt_str_t applications_path = nxt_string("/applications"); 1409115Sigor@sysoev.ru static nxt_str_t listeners_path = nxt_string("/listeners"); 1410964Sigor@sysoev.ru static nxt_str_t routes_path = nxt_string("/routes"); 1411630Svbart@nginx.com static nxt_str_t access_log_path = nxt_string("/access_log"); 1412774Svbart@nginx.com #if (NXT_TLS) 1413774Svbart@nginx.com static nxt_str_t certificate_path = nxt_string("/tls/certificate"); 1414774Svbart@nginx.com #endif 1415115Sigor@sysoev.ru 1416208Svbart@nginx.com conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL); 1417115Sigor@sysoev.ru if (conf == NULL) { 1418564Svbart@nginx.com nxt_alert(task, "configuration parsing error"); 1419115Sigor@sysoev.ru return NXT_ERROR; 1420115Sigor@sysoev.ru } 1421115Sigor@sysoev.ru 1422591Sigor@sysoev.ru mp = tmcf->router_conf->mem_pool; 1423213Svbart@nginx.com 1424213Svbart@nginx.com ret = nxt_conf_map_object(mp, conf, nxt_router_conf, 1425591Sigor@sysoev.ru nxt_nitems(nxt_router_conf), tmcf->router_conf); 1426115Sigor@sysoev.ru if (ret != NXT_OK) { 1427564Svbart@nginx.com nxt_alert(task, "root map error"); 1428115Sigor@sysoev.ru return NXT_ERROR; 1429115Sigor@sysoev.ru } 1430115Sigor@sysoev.ru 1431591Sigor@sysoev.ru if (tmcf->router_conf->threads == 0) { 1432591Sigor@sysoev.ru tmcf->router_conf->threads = nxt_ncpu; 1433117Sigor@sysoev.ru } 1434117Sigor@sysoev.ru 1435133Sigor@sysoev.ru applications = nxt_conf_get_path(conf, &applications_path); 1436133Sigor@sysoev.ru if (applications == NULL) { 1437564Svbart@nginx.com nxt_alert(task, "no \"applications\" block"); 1438115Sigor@sysoev.ru return NXT_ERROR; 1439115Sigor@sysoev.ru } 1440115Sigor@sysoev.ru 1441591Sigor@sysoev.ru router = tmcf->router_conf->router; 1442359Sigor@sysoev.ru 1443133Sigor@sysoev.ru next = 0; 1444133Sigor@sysoev.ru 1445133Sigor@sysoev.ru for ( ;; ) { 1446133Sigor@sysoev.ru application = nxt_conf_next_object_member(applications, &name, &next); 1447133Sigor@sysoev.ru if (application == NULL) { 1448133Sigor@sysoev.ru break; 1449133Sigor@sysoev.ru } 1450133Sigor@sysoev.ru 1451133Sigor@sysoev.ru nxt_debug(task, "application \"%V\"", &name); 1452133Sigor@sysoev.ru 1453144Smax.romanov@nginx.com size = nxt_conf_json_length(application, NULL); 1454144Smax.romanov@nginx.com 1455144Smax.romanov@nginx.com app = nxt_malloc(sizeof(nxt_app_t) + name.length + size); 1456133Sigor@sysoev.ru if (app == NULL) { 1457133Sigor@sysoev.ru goto fail; 1458133Sigor@sysoev.ru } 1459133Sigor@sysoev.ru 1460144Smax.romanov@nginx.com nxt_memzero(app, sizeof(nxt_app_t)); 1461144Smax.romanov@nginx.com 1462144Smax.romanov@nginx.com app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t)); 1463144Smax.romanov@nginx.com app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length); 1464133Sigor@sysoev.ru 1465133Sigor@sysoev.ru p = nxt_conf_json_print(app->conf.start, application, NULL); 1466133Sigor@sysoev.ru app->conf.length = p - app->conf.start; 1467133Sigor@sysoev.ru 1468144Smax.romanov@nginx.com nxt_assert(app->conf.length <= size); 1469144Smax.romanov@nginx.com 1470133Sigor@sysoev.ru nxt_debug(task, "application conf \"%V\"", &app->conf); 1471133Sigor@sysoev.ru 1472359Sigor@sysoev.ru prev = nxt_router_app_find(&router->apps, &name); 1473133Sigor@sysoev.ru 1474133Sigor@sysoev.ru if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) { 1475133Sigor@sysoev.ru nxt_free(app); 1476133Sigor@sysoev.ru 1477133Sigor@sysoev.ru nxt_queue_remove(&prev->link); 1478133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->previous, &prev->link); 1479133Sigor@sysoev.ru continue; 1480133Sigor@sysoev.ru } 1481133Sigor@sysoev.ru 1482507Smax.romanov@nginx.com apcf.processes = 1; 1483507Smax.romanov@nginx.com apcf.max_processes = 1; 1484537Svbart@nginx.com apcf.spare_processes = 0; 1485318Smax.romanov@nginx.com apcf.timeout = 0; 1486427Smax.romanov@nginx.com apcf.res_timeout = 1000; 1487507Smax.romanov@nginx.com apcf.idle_timeout = 15000; 1488318Smax.romanov@nginx.com apcf.requests = 0; 1489318Smax.romanov@nginx.com apcf.limits_value = NULL; 1490507Smax.romanov@nginx.com apcf.processes_value = NULL; 1491263Smax.romanov@nginx.com 1492753Smax.romanov@nginx.com app_joint = nxt_malloc(sizeof(nxt_app_joint_t)); 1493753Smax.romanov@nginx.com if (nxt_slow_path(app_joint == NULL)) { 1494753Smax.romanov@nginx.com goto app_fail; 1495753Smax.romanov@nginx.com } 1496753Smax.romanov@nginx.com 1497753Smax.romanov@nginx.com nxt_memzero(app_joint, sizeof(nxt_app_joint_t)); 1498753Smax.romanov@nginx.com 1499213Svbart@nginx.com ret = nxt_conf_map_object(mp, application, nxt_router_app_conf, 1500136Svbart@nginx.com nxt_nitems(nxt_router_app_conf), &apcf); 1501133Sigor@sysoev.ru if (ret != NXT_OK) { 1502564Svbart@nginx.com nxt_alert(task, "application map error"); 1503133Sigor@sysoev.ru goto app_fail; 1504133Sigor@sysoev.ru } 1505115Sigor@sysoev.ru 1506318Smax.romanov@nginx.com if (apcf.limits_value != NULL) { 1507318Smax.romanov@nginx.com 1508318Smax.romanov@nginx.com if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) { 1509564Svbart@nginx.com nxt_alert(task, "application limits is not object"); 1510318Smax.romanov@nginx.com goto app_fail; 1511318Smax.romanov@nginx.com } 1512318Smax.romanov@nginx.com 1513318Smax.romanov@nginx.com ret = nxt_conf_map_object(mp, apcf.limits_value, 1514318Smax.romanov@nginx.com nxt_router_app_limits_conf, 1515318Smax.romanov@nginx.com nxt_nitems(nxt_router_app_limits_conf), 1516318Smax.romanov@nginx.com &apcf); 1517318Smax.romanov@nginx.com if (ret != NXT_OK) { 1518564Svbart@nginx.com nxt_alert(task, "application limits map error"); 1519318Smax.romanov@nginx.com goto app_fail; 1520318Smax.romanov@nginx.com } 1521318Smax.romanov@nginx.com } 1522318Smax.romanov@nginx.com 1523507Smax.romanov@nginx.com if (apcf.processes_value != NULL 1524507Smax.romanov@nginx.com && nxt_conf_type(apcf.processes_value) == NXT_CONF_OBJECT) 1525507Smax.romanov@nginx.com { 1526507Smax.romanov@nginx.com ret = nxt_conf_map_object(mp, apcf.processes_value, 1527507Smax.romanov@nginx.com nxt_router_app_processes_conf, 1528507Smax.romanov@nginx.com nxt_nitems(nxt_router_app_processes_conf), 1529507Smax.romanov@nginx.com &apcf); 1530507Smax.romanov@nginx.com if (ret != NXT_OK) { 1531564Svbart@nginx.com nxt_alert(task, "application processes map error"); 1532507Smax.romanov@nginx.com goto app_fail; 1533507Smax.romanov@nginx.com } 1534507Smax.romanov@nginx.com 1535507Smax.romanov@nginx.com } else { 1536507Smax.romanov@nginx.com apcf.max_processes = apcf.processes; 1537507Smax.romanov@nginx.com apcf.spare_processes = apcf.processes; 1538507Smax.romanov@nginx.com } 1539507Smax.romanov@nginx.com 1540133Sigor@sysoev.ru nxt_debug(task, "application type: %V", &apcf.type); 1541507Smax.romanov@nginx.com nxt_debug(task, "application processes: %D", apcf.processes); 1542507Smax.romanov@nginx.com nxt_debug(task, "application request timeout: %M", apcf.timeout); 1543507Smax.romanov@nginx.com nxt_debug(task, "application reschedule timeout: %M", apcf.res_timeout); 1544318Smax.romanov@nginx.com nxt_debug(task, "application requests: %D", apcf.requests); 1545133Sigor@sysoev.ru 1546216Sigor@sysoev.ru lang = nxt_app_lang_module(task->thread->runtime, &apcf.type); 1547216Sigor@sysoev.ru 1548216Sigor@sysoev.ru if (lang == NULL) { 1549564Svbart@nginx.com nxt_alert(task, "unknown application type: \"%V\"", &apcf.type); 1550141Smax.romanov@nginx.com goto app_fail; 1551141Smax.romanov@nginx.com } 1552141Smax.romanov@nginx.com 1553216Sigor@sysoev.ru nxt_debug(task, "application language module: \"%s\"", lang->file); 1554216Sigor@sysoev.ru 1555133Sigor@sysoev.ru ret = nxt_thread_mutex_create(&app->mutex); 1556133Sigor@sysoev.ru if (ret != NXT_OK) { 1557133Sigor@sysoev.ru goto app_fail; 1558133Sigor@sysoev.ru } 1559133Sigor@sysoev.ru 1560141Smax.romanov@nginx.com nxt_queue_init(&app->ports); 1561507Smax.romanov@nginx.com nxt_queue_init(&app->spare_ports); 1562507Smax.romanov@nginx.com nxt_queue_init(&app->idle_ports); 1563141Smax.romanov@nginx.com nxt_queue_init(&app->requests); 1564427Smax.romanov@nginx.com nxt_queue_init(&app->pending); 1565141Smax.romanov@nginx.com 1566144Smax.romanov@nginx.com app->name.length = name.length; 1567144Smax.romanov@nginx.com nxt_memcpy(app->name.start, name.start, name.length); 1568144Smax.romanov@nginx.com 1569356Svbart@nginx.com app->type = lang->type; 1570507Smax.romanov@nginx.com app->max_processes = apcf.max_processes; 1571507Smax.romanov@nginx.com app->spare_processes = apcf.spare_processes; 1572507Smax.romanov@nginx.com app->max_pending_processes = apcf.spare_processes 1573507Smax.romanov@nginx.com ? apcf.spare_processes : 1; 1574318Smax.romanov@nginx.com app->timeout = apcf.timeout; 1575427Smax.romanov@nginx.com app->res_timeout = apcf.res_timeout * 1000000; 1576507Smax.romanov@nginx.com app->idle_timeout = apcf.idle_timeout; 1577343Smax.romanov@nginx.com app->max_pending_responses = 2; 1578428Smax.romanov@nginx.com app->max_requests = apcf.requests; 1579133Sigor@sysoev.ru 1580507Smax.romanov@nginx.com engine = task->thread->engine; 1581507Smax.romanov@nginx.com 1582507Smax.romanov@nginx.com app->engine = engine; 1583507Smax.romanov@nginx.com 1584507Smax.romanov@nginx.com app->adjust_idle_work.handler = nxt_router_adjust_idle_timer; 1585507Smax.romanov@nginx.com app->adjust_idle_work.task = &engine->task; 1586507Smax.romanov@nginx.com app->adjust_idle_work.obj = app; 1587507Smax.romanov@nginx.com 1588133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->apps, &app->link); 1589343Smax.romanov@nginx.com 1590343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 1591753Smax.romanov@nginx.com 1592753Smax.romanov@nginx.com app->joint = app_joint; 1593753Smax.romanov@nginx.com 1594753Smax.romanov@nginx.com app_joint->use_count = 1; 1595753Smax.romanov@nginx.com app_joint->app = app; 1596753Smax.romanov@nginx.com 1597811Svbart@nginx.com app_joint->idle_timer.bias = NXT_TIMER_DEFAULT_BIAS; 1598753Smax.romanov@nginx.com app_joint->idle_timer.work_queue = &engine->fast_work_queue; 1599753Smax.romanov@nginx.com app_joint->idle_timer.handler = nxt_router_app_idle_timeout; 1600753Smax.romanov@nginx.com app_joint->idle_timer.task = &engine->task; 1601753Smax.romanov@nginx.com app_joint->idle_timer.log = app_joint->idle_timer.task->log; 1602753Smax.romanov@nginx.com 1603753Smax.romanov@nginx.com app_joint->free_app_work.handler = nxt_router_free_app; 1604753Smax.romanov@nginx.com app_joint->free_app_work.task = &engine->task; 1605753Smax.romanov@nginx.com app_joint->free_app_work.obj = app_joint; 1606133Sigor@sysoev.ru } 1607133Sigor@sysoev.ru 1608964Sigor@sysoev.ru routes_conf = nxt_conf_get_path(conf, &routes_path); 1609964Sigor@sysoev.ru if (nxt_fast_path(routes_conf != NULL)) { 1610964Sigor@sysoev.ru routes = nxt_http_routes_create(task, tmcf, routes_conf); 1611964Sigor@sysoev.ru if (nxt_slow_path(routes == NULL)) { 1612964Sigor@sysoev.ru return NXT_ERROR; 1613964Sigor@sysoev.ru } 1614964Sigor@sysoev.ru tmcf->router_conf->routes = routes; 1615964Sigor@sysoev.ru } 1616964Sigor@sysoev.ru 1617133Sigor@sysoev.ru http = nxt_conf_get_path(conf, &http_path); 1618133Sigor@sysoev.ru #if 0 1619133Sigor@sysoev.ru if (http == NULL) { 1620564Svbart@nginx.com nxt_alert(task, "no \"http\" block"); 1621133Sigor@sysoev.ru return NXT_ERROR; 1622133Sigor@sysoev.ru } 1623133Sigor@sysoev.ru #endif 1624133Sigor@sysoev.ru 1625133Sigor@sysoev.ru listeners = nxt_conf_get_path(conf, &listeners_path); 1626115Sigor@sysoev.ru if (listeners == NULL) { 1627564Svbart@nginx.com nxt_alert(task, "no \"listeners\" block"); 1628115Sigor@sysoev.ru return NXT_ERROR; 1629115Sigor@sysoev.ru } 163053Sigor@sysoev.ru 1631133Sigor@sysoev.ru next = 0; 163253Sigor@sysoev.ru 1633115Sigor@sysoev.ru for ( ;; ) { 1634115Sigor@sysoev.ru listener = nxt_conf_next_object_member(listeners, &name, &next); 1635115Sigor@sysoev.ru if (listener == NULL) { 1636115Sigor@sysoev.ru break; 1637115Sigor@sysoev.ru } 163853Sigor@sysoev.ru 1639359Sigor@sysoev.ru skcf = nxt_router_socket_conf(task, tmcf, &name); 1640115Sigor@sysoev.ru if (skcf == NULL) { 1641133Sigor@sysoev.ru goto fail; 1642115Sigor@sysoev.ru } 164353Sigor@sysoev.ru 1644770Smax.romanov@nginx.com nxt_memzero(&lscf, sizeof(lscf)); 1645770Smax.romanov@nginx.com 1646213Svbart@nginx.com ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf, 1647136Svbart@nginx.com nxt_nitems(nxt_router_listener_conf), &lscf); 1648115Sigor@sysoev.ru if (ret != NXT_OK) { 1649564Svbart@nginx.com nxt_alert(task, "listener map error"); 1650133Sigor@sysoev.ru goto fail; 1651115Sigor@sysoev.ru } 165253Sigor@sysoev.ru 1653133Sigor@sysoev.ru nxt_debug(task, "application: %V", &lscf.application); 1654133Sigor@sysoev.ru 1655133Sigor@sysoev.ru // STUB, default values if http block is not defined. 1656133Sigor@sysoev.ru skcf->header_buffer_size = 2048; 1657133Sigor@sysoev.ru skcf->large_header_buffer_size = 8192; 1658206Smax.romanov@nginx.com skcf->large_header_buffers = 4; 1659206Smax.romanov@nginx.com skcf->body_buffer_size = 16 * 1024; 1660715Svbart@nginx.com skcf->max_body_size = 8 * 1024 * 1024; 1661715Svbart@nginx.com skcf->idle_timeout = 180 * 1000; 1662715Svbart@nginx.com skcf->header_read_timeout = 30 * 1000; 1663715Svbart@nginx.com skcf->body_read_timeout = 30 * 1000; 1664715Svbart@nginx.com skcf->send_timeout = 30 * 1000; 166553Sigor@sysoev.ru 1666133Sigor@sysoev.ru if (http != NULL) { 1667213Svbart@nginx.com ret = nxt_conf_map_object(mp, http, nxt_router_http_conf, 1668136Svbart@nginx.com nxt_nitems(nxt_router_http_conf), skcf); 1669133Sigor@sysoev.ru if (ret != NXT_OK) { 1670564Svbart@nginx.com nxt_alert(task, "http map error"); 1671133Sigor@sysoev.ru goto fail; 1672133Sigor@sysoev.ru } 1673115Sigor@sysoev.ru } 1674115Sigor@sysoev.ru 1675774Svbart@nginx.com #if (NXT_TLS) 1676774Svbart@nginx.com 1677774Svbart@nginx.com value = nxt_conf_get_path(listener, &certificate_path); 1678774Svbart@nginx.com 1679774Svbart@nginx.com if (value != NULL) { 1680774Svbart@nginx.com nxt_conf_get_string(value, &name); 1681774Svbart@nginx.com 1682774Svbart@nginx.com tls = nxt_mp_get(mp, sizeof(nxt_router_tlssock_t)); 1683774Svbart@nginx.com if (nxt_slow_path(tls == NULL)) { 1684774Svbart@nginx.com goto fail; 1685774Svbart@nginx.com } 1686774Svbart@nginx.com 1687774Svbart@nginx.com tls->name = name; 1688774Svbart@nginx.com tls->conf = skcf; 1689774Svbart@nginx.com 1690774Svbart@nginx.com nxt_queue_insert_tail(&tmcf->tls, &tls->link); 1691774Svbart@nginx.com } 1692774Svbart@nginx.com 1693774Svbart@nginx.com #endif 1694774Svbart@nginx.com 1695431Sigor@sysoev.ru skcf->listen->handler = nxt_http_conn_init; 1696591Sigor@sysoev.ru skcf->router_conf = tmcf->router_conf; 1697160Sigor@sysoev.ru skcf->router_conf->count++; 1698770Smax.romanov@nginx.com 1699964Sigor@sysoev.ru if (lscf.pass.length != 0) { 1700964Sigor@sysoev.ru skcf->pass = nxt_http_pass_create(task, tmcf, &lscf.pass); 1701964Sigor@sysoev.ru 1702964Sigor@sysoev.ru /* COMPATIBILITY: listener application. */ 1703964Sigor@sysoev.ru } else if (lscf.application.length > 0) { 1704964Sigor@sysoev.ru skcf->pass = nxt_http_pass_application(task, tmcf, 1705964Sigor@sysoev.ru &lscf.application); 1706770Smax.romanov@nginx.com } 1707115Sigor@sysoev.ru } 170853Sigor@sysoev.ru 1709630Svbart@nginx.com value = nxt_conf_get_path(conf, &access_log_path); 1710630Svbart@nginx.com 1711630Svbart@nginx.com if (value != NULL) { 1712630Svbart@nginx.com nxt_conf_get_string(value, &path); 1713630Svbart@nginx.com 1714630Svbart@nginx.com access_log = router->access_log; 1715630Svbart@nginx.com 1716630Svbart@nginx.com if (access_log != NULL && nxt_strstr_eq(&path, &access_log->path)) { 1717630Svbart@nginx.com nxt_thread_spin_lock(&router->lock); 1718630Svbart@nginx.com access_log->count++; 1719630Svbart@nginx.com nxt_thread_spin_unlock(&router->lock); 1720630Svbart@nginx.com 1721630Svbart@nginx.com } else { 1722630Svbart@nginx.com access_log = nxt_malloc(sizeof(nxt_router_access_log_t) 1723630Svbart@nginx.com + path.length); 1724630Svbart@nginx.com if (access_log == NULL) { 1725630Svbart@nginx.com nxt_alert(task, "failed to allocate access log structure"); 1726630Svbart@nginx.com goto fail; 1727630Svbart@nginx.com } 1728630Svbart@nginx.com 1729630Svbart@nginx.com access_log->fd = -1; 1730630Svbart@nginx.com access_log->handler = &nxt_router_access_log_writer; 1731630Svbart@nginx.com access_log->count = 1; 1732630Svbart@nginx.com 1733630Svbart@nginx.com access_log->path.length = path.length; 1734630Svbart@nginx.com access_log->path.start = (u_char *) access_log 1735630Svbart@nginx.com + sizeof(nxt_router_access_log_t); 1736630Svbart@nginx.com 1737630Svbart@nginx.com nxt_memcpy(access_log->path.start, path.start, path.length); 1738630Svbart@nginx.com } 1739630Svbart@nginx.com 1740630Svbart@nginx.com tmcf->router_conf->access_log = access_log; 1741630Svbart@nginx.com } 1742630Svbart@nginx.com 1743964Sigor@sysoev.ru nxt_http_routes_resolve(task, tmcf); 1744964Sigor@sysoev.ru 1745359Sigor@sysoev.ru nxt_queue_add(&tmcf->deleting, &router->sockets); 1746359Sigor@sysoev.ru nxt_queue_init(&router->sockets); 1747198Sigor@sysoev.ru 174853Sigor@sysoev.ru return NXT_OK; 1749133Sigor@sysoev.ru 1750133Sigor@sysoev.ru app_fail: 1751133Sigor@sysoev.ru 1752133Sigor@sysoev.ru nxt_free(app); 1753133Sigor@sysoev.ru 1754133Sigor@sysoev.ru fail: 1755133Sigor@sysoev.ru 1756141Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1757141Smax.romanov@nginx.com 1758141Smax.romanov@nginx.com nxt_queue_remove(&app->link); 1759133Sigor@sysoev.ru nxt_thread_mutex_destroy(&app->mutex); 1760133Sigor@sysoev.ru nxt_free(app); 1761141Smax.romanov@nginx.com 1762141Smax.romanov@nginx.com } nxt_queue_loop; 1763133Sigor@sysoev.ru 1764133Sigor@sysoev.ru return NXT_ERROR; 1765133Sigor@sysoev.ru } 1766133Sigor@sysoev.ru 1767133Sigor@sysoev.ru 1768133Sigor@sysoev.ru static nxt_app_t * 1769133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name) 1770133Sigor@sysoev.ru { 1771141Smax.romanov@nginx.com nxt_app_t *app; 1772141Smax.romanov@nginx.com 1773141Smax.romanov@nginx.com nxt_queue_each(app, queue, nxt_app_t, link) { 1774133Sigor@sysoev.ru 1775133Sigor@sysoev.ru if (nxt_strstr_eq(name, &app->name)) { 1776133Sigor@sysoev.ru return app; 1777133Sigor@sysoev.ru } 1778141Smax.romanov@nginx.com 1779141Smax.romanov@nginx.com } nxt_queue_loop; 1780133Sigor@sysoev.ru 1781133Sigor@sysoev.ru return NULL; 1782133Sigor@sysoev.ru } 1783133Sigor@sysoev.ru 1784133Sigor@sysoev.ru 1785964Sigor@sysoev.ru nxt_app_t * 1786133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name) 1787133Sigor@sysoev.ru { 1788133Sigor@sysoev.ru nxt_app_t *app; 1789133Sigor@sysoev.ru 1790133Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->apps, name); 1791133Sigor@sysoev.ru 1792133Sigor@sysoev.ru if (app == NULL) { 1793134Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->previous, name); 1794133Sigor@sysoev.ru } 1795133Sigor@sysoev.ru 1796133Sigor@sysoev.ru return app; 179753Sigor@sysoev.ru } 179853Sigor@sysoev.ru 179953Sigor@sysoev.ru 180053Sigor@sysoev.ru static nxt_socket_conf_t * 1801359Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1802359Sigor@sysoev.ru nxt_str_t *name) 180353Sigor@sysoev.ru { 1804359Sigor@sysoev.ru size_t size; 1805359Sigor@sysoev.ru nxt_int_t ret; 1806359Sigor@sysoev.ru nxt_bool_t wildcard; 1807359Sigor@sysoev.ru nxt_sockaddr_t *sa; 1808359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1809359Sigor@sysoev.ru nxt_listen_socket_t *ls; 1810359Sigor@sysoev.ru 1811359Sigor@sysoev.ru sa = nxt_sockaddr_parse(tmcf->mem_pool, name); 1812359Sigor@sysoev.ru if (nxt_slow_path(sa == NULL)) { 1813564Svbart@nginx.com nxt_alert(task, "invalid listener \"%V\"", name); 1814359Sigor@sysoev.ru return NULL; 1815359Sigor@sysoev.ru } 1816359Sigor@sysoev.ru 1817359Sigor@sysoev.ru sa->type = SOCK_STREAM; 1818359Sigor@sysoev.ru 1819359Sigor@sysoev.ru nxt_debug(task, "router listener: \"%*s\"", 1820493Spluknet@nginx.com (size_t) sa->length, nxt_sockaddr_start(sa)); 1821359Sigor@sysoev.ru 1822591Sigor@sysoev.ru skcf = nxt_mp_zget(tmcf->router_conf->mem_pool, sizeof(nxt_socket_conf_t)); 1823163Smax.romanov@nginx.com if (nxt_slow_path(skcf == NULL)) { 182453Sigor@sysoev.ru return NULL; 182553Sigor@sysoev.ru } 182653Sigor@sysoev.ru 1827359Sigor@sysoev.ru size = nxt_sockaddr_size(sa); 1828359Sigor@sysoev.ru 1829359Sigor@sysoev.ru ret = nxt_router_listen_socket_find(tmcf, skcf, sa); 1830359Sigor@sysoev.ru 1831359Sigor@sysoev.ru if (ret != NXT_OK) { 1832359Sigor@sysoev.ru 1833359Sigor@sysoev.ru ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size); 1834359Sigor@sysoev.ru if (nxt_slow_path(ls == NULL)) { 1835359Sigor@sysoev.ru return NULL; 1836359Sigor@sysoev.ru } 1837359Sigor@sysoev.ru 1838359Sigor@sysoev.ru skcf->listen = ls; 1839359Sigor@sysoev.ru 1840359Sigor@sysoev.ru ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t)); 1841359Sigor@sysoev.ru nxt_memcpy(ls->sockaddr, sa, size); 1842359Sigor@sysoev.ru 1843359Sigor@sysoev.ru nxt_listen_socket_remote_size(ls); 1844359Sigor@sysoev.ru 1845359Sigor@sysoev.ru ls->socket = -1; 1846359Sigor@sysoev.ru ls->backlog = NXT_LISTEN_BACKLOG; 1847359Sigor@sysoev.ru ls->flags = NXT_NONBLOCK; 1848359Sigor@sysoev.ru ls->read_after_accept = 1; 1849359Sigor@sysoev.ru } 1850359Sigor@sysoev.ru 1851359Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) { 1852359Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 1853359Sigor@sysoev.ru case AF_UNIX: 1854359Sigor@sysoev.ru wildcard = 0; 1855359Sigor@sysoev.ru break; 1856359Sigor@sysoev.ru #endif 1857359Sigor@sysoev.ru #if (NXT_INET6) 1858359Sigor@sysoev.ru case AF_INET6: 1859359Sigor@sysoev.ru wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr); 1860359Sigor@sysoev.ru break; 1861359Sigor@sysoev.ru #endif 1862359Sigor@sysoev.ru case AF_INET: 1863359Sigor@sysoev.ru default: 1864359Sigor@sysoev.ru wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY); 1865359Sigor@sysoev.ru break; 1866359Sigor@sysoev.ru } 1867359Sigor@sysoev.ru 1868359Sigor@sysoev.ru if (!wildcard) { 1869591Sigor@sysoev.ru skcf->sockaddr = nxt_mp_zget(tmcf->router_conf->mem_pool, size); 1870359Sigor@sysoev.ru if (nxt_slow_path(skcf->sockaddr == NULL)) { 1871359Sigor@sysoev.ru return NULL; 1872359Sigor@sysoev.ru } 1873359Sigor@sysoev.ru 1874359Sigor@sysoev.ru nxt_memcpy(skcf->sockaddr, sa, size); 1875359Sigor@sysoev.ru } 1876163Smax.romanov@nginx.com 1877163Smax.romanov@nginx.com return skcf; 187853Sigor@sysoev.ru } 187953Sigor@sysoev.ru 188053Sigor@sysoev.ru 1881359Sigor@sysoev.ru static nxt_int_t 1882359Sigor@sysoev.ru nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, 1883359Sigor@sysoev.ru nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa) 188453Sigor@sysoev.ru { 1885359Sigor@sysoev.ru nxt_router_t *router; 1886359Sigor@sysoev.ru nxt_queue_link_t *qlk; 1887359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1888359Sigor@sysoev.ru 1889591Sigor@sysoev.ru router = tmcf->router_conf->router; 1890359Sigor@sysoev.ru 1891359Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->sockets); 1892359Sigor@sysoev.ru qlk != nxt_queue_tail(&router->sockets); 1893359Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 189453Sigor@sysoev.ru { 1895359Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1896359Sigor@sysoev.ru 1897359Sigor@sysoev.ru if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) { 1898359Sigor@sysoev.ru nskcf->listen = skcf->listen; 1899359Sigor@sysoev.ru 1900359Sigor@sysoev.ru nxt_queue_remove(qlk); 1901359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->keeping, qlk); 1902359Sigor@sysoev.ru 1903359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->updating, &nskcf->link); 1904359Sigor@sysoev.ru 1905359Sigor@sysoev.ru return NXT_OK; 190653Sigor@sysoev.ru } 190753Sigor@sysoev.ru } 190853Sigor@sysoev.ru 1909359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->pending, &nskcf->link); 1910359Sigor@sysoev.ru 1911359Sigor@sysoev.ru return NXT_DECLINED; 191253Sigor@sysoev.ru } 191353Sigor@sysoev.ru 191453Sigor@sysoev.ru 1915198Sigor@sysoev.ru static void 1916198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task, 1917198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf) 1918198Sigor@sysoev.ru { 1919358Sigor@sysoev.ru size_t size; 1920198Sigor@sysoev.ru uint32_t stream; 1921648Svbart@nginx.com nxt_int_t ret; 1922198Sigor@sysoev.ru nxt_buf_t *b; 1923198Sigor@sysoev.ru nxt_port_t *main_port, *router_port; 1924198Sigor@sysoev.ru nxt_runtime_t *rt; 1925198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 1926198Sigor@sysoev.ru 1927198Sigor@sysoev.ru rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t)); 1928198Sigor@sysoev.ru if (rpc == NULL) { 1929198Sigor@sysoev.ru goto fail; 1930198Sigor@sysoev.ru } 1931198Sigor@sysoev.ru 1932198Sigor@sysoev.ru rpc->socket_conf = skcf; 1933198Sigor@sysoev.ru rpc->temp_conf = tmcf; 1934198Sigor@sysoev.ru 1935359Sigor@sysoev.ru size = nxt_sockaddr_size(skcf->listen->sockaddr); 1936358Sigor@sysoev.ru 1937358Sigor@sysoev.ru b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 1938198Sigor@sysoev.ru if (b == NULL) { 1939198Sigor@sysoev.ru goto fail; 1940198Sigor@sysoev.ru } 1941198Sigor@sysoev.ru 1942359Sigor@sysoev.ru b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size); 1943198Sigor@sysoev.ru 1944198Sigor@sysoev.ru rt = task->thread->runtime; 1945240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1946198Sigor@sysoev.ru router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 1947198Sigor@sysoev.ru 1948198Sigor@sysoev.ru stream = nxt_port_rpc_register_handler(task, router_port, 1949198Sigor@sysoev.ru nxt_router_listen_socket_ready, 1950198Sigor@sysoev.ru nxt_router_listen_socket_error, 1951198Sigor@sysoev.ru main_port->pid, rpc); 1952645Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 1953198Sigor@sysoev.ru goto fail; 1954198Sigor@sysoev.ru } 1955198Sigor@sysoev.ru 1956648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1, 1957648Svbart@nginx.com stream, router_port->id, b); 1958648Svbart@nginx.com 1959648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 1960648Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 1961648Svbart@nginx.com goto fail; 1962648Svbart@nginx.com } 1963198Sigor@sysoev.ru 1964198Sigor@sysoev.ru return; 1965198Sigor@sysoev.ru 1966198Sigor@sysoev.ru fail: 1967198Sigor@sysoev.ru 1968198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 1969198Sigor@sysoev.ru } 1970198Sigor@sysoev.ru 1971198Sigor@sysoev.ru 1972198Sigor@sysoev.ru static void 1973198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1974198Sigor@sysoev.ru void *data) 197553Sigor@sysoev.ru { 1976359Sigor@sysoev.ru nxt_int_t ret; 1977359Sigor@sysoev.ru nxt_socket_t s; 1978359Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 197953Sigor@sysoev.ru 1980198Sigor@sysoev.ru rpc = data; 1981198Sigor@sysoev.ru 1982198Sigor@sysoev.ru s = msg->fd; 1983198Sigor@sysoev.ru 1984198Sigor@sysoev.ru ret = nxt_socket_nonblocking(task, s); 1985198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1986198Sigor@sysoev.ru goto fail; 198753Sigor@sysoev.ru } 198853Sigor@sysoev.ru 1989359Sigor@sysoev.ru nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr); 1990198Sigor@sysoev.ru 1991198Sigor@sysoev.ru ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG); 1992198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1993198Sigor@sysoev.ru goto fail; 1994198Sigor@sysoev.ru } 1995198Sigor@sysoev.ru 1996359Sigor@sysoev.ru rpc->socket_conf->listen->socket = s; 1997198Sigor@sysoev.ru 1998198Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 1999198Sigor@sysoev.ru nxt_router_conf_apply, task, rpc->temp_conf, NULL); 2000198Sigor@sysoev.ru 2001198Sigor@sysoev.ru return; 2002148Sigor@sysoev.ru 2003148Sigor@sysoev.ru fail: 2004148Sigor@sysoev.ru 2005148Sigor@sysoev.ru nxt_socket_close(task, s); 2006148Sigor@sysoev.ru 2007198Sigor@sysoev.ru nxt_router_conf_error(task, rpc->temp_conf); 2008198Sigor@sysoev.ru } 2009198Sigor@sysoev.ru 2010198Sigor@sysoev.ru 2011198Sigor@sysoev.ru static void 2012198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2013198Sigor@sysoev.ru void *data) 2014198Sigor@sysoev.ru { 2015955Svbart@nginx.com nxt_socket_rpc_t *rpc; 2016955Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 2017955Svbart@nginx.com 2018955Svbart@nginx.com rpc = data; 2019955Svbart@nginx.com tmcf = rpc->temp_conf; 2020955Svbart@nginx.com 2021955Svbart@nginx.com #if 0 2022198Sigor@sysoev.ru u_char *p; 2023198Sigor@sysoev.ru size_t size; 2024198Sigor@sysoev.ru uint8_t error; 2025198Sigor@sysoev.ru nxt_buf_t *in, *out; 2026198Sigor@sysoev.ru nxt_sockaddr_t *sa; 2027198Sigor@sysoev.ru 2028198Sigor@sysoev.ru static nxt_str_t socket_errors[] = { 2029198Sigor@sysoev.ru nxt_string("ListenerSystem"), 2030198Sigor@sysoev.ru nxt_string("ListenerNoIPv6"), 2031198Sigor@sysoev.ru nxt_string("ListenerPort"), 2032198Sigor@sysoev.ru nxt_string("ListenerInUse"), 2033198Sigor@sysoev.ru nxt_string("ListenerNoAddress"), 2034198Sigor@sysoev.ru nxt_string("ListenerNoAccess"), 2035198Sigor@sysoev.ru nxt_string("ListenerPath"), 2036198Sigor@sysoev.ru }; 2037198Sigor@sysoev.ru 2038359Sigor@sysoev.ru sa = rpc->socket_conf->listen->sockaddr; 2039352Smax.romanov@nginx.com 2040352Smax.romanov@nginx.com in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size); 2041352Smax.romanov@nginx.com 2042551Smax.romanov@nginx.com if (nxt_slow_path(in == NULL)) { 2043551Smax.romanov@nginx.com return; 2044551Smax.romanov@nginx.com } 2045352Smax.romanov@nginx.com 2046198Sigor@sysoev.ru p = in->mem.pos; 2047198Sigor@sysoev.ru 2048198Sigor@sysoev.ru error = *p++; 2049198Sigor@sysoev.ru 2050703Svbart@nginx.com size = nxt_length("listen socket error: ") 2051703Svbart@nginx.com + nxt_length("{listener: \"\", code:\"\", message: \"\"}") 2052198Sigor@sysoev.ru + sa->length + socket_errors[error].length + (in->mem.free - p); 2053198Sigor@sysoev.ru 2054198Sigor@sysoev.ru out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 2055198Sigor@sysoev.ru if (nxt_slow_path(out == NULL)) { 2056198Sigor@sysoev.ru return; 2057198Sigor@sysoev.ru } 2058198Sigor@sysoev.ru 2059198Sigor@sysoev.ru out->mem.free = nxt_sprintf(out->mem.free, out->mem.end, 2060198Sigor@sysoev.ru "listen socket error: " 2061198Sigor@sysoev.ru "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}", 2062493Spluknet@nginx.com (size_t) sa->length, nxt_sockaddr_start(sa), 2063198Sigor@sysoev.ru &socket_errors[error], in->mem.free - p, p); 2064198Sigor@sysoev.ru 2065198Sigor@sysoev.ru nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos); 2066955Svbart@nginx.com #endif 2067198Sigor@sysoev.ru 2068198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 206953Sigor@sysoev.ru } 207053Sigor@sysoev.ru 207153Sigor@sysoev.ru 2072774Svbart@nginx.com #if (NXT_TLS) 2073774Svbart@nginx.com 2074774Svbart@nginx.com static void 2075774Svbart@nginx.com nxt_router_tls_rpc_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 2076774Svbart@nginx.com nxt_router_tlssock_t *tls) 2077774Svbart@nginx.com { 2078774Svbart@nginx.com nxt_socket_rpc_t *rpc; 2079774Svbart@nginx.com 2080774Svbart@nginx.com rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t)); 2081774Svbart@nginx.com if (rpc == NULL) { 2082774Svbart@nginx.com nxt_router_conf_error(task, tmcf); 2083774Svbart@nginx.com return; 2084774Svbart@nginx.com } 2085774Svbart@nginx.com 2086774Svbart@nginx.com rpc->socket_conf = tls->conf; 2087774Svbart@nginx.com rpc->temp_conf = tmcf; 2088774Svbart@nginx.com 2089774Svbart@nginx.com nxt_cert_store_get(task, &tls->name, tmcf->mem_pool, 2090774Svbart@nginx.com nxt_router_tls_rpc_handler, rpc); 2091774Svbart@nginx.com } 2092774Svbart@nginx.com 2093774Svbart@nginx.com 2094774Svbart@nginx.com static void 2095774Svbart@nginx.com nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2096774Svbart@nginx.com void *data) 2097774Svbart@nginx.com { 2098774Svbart@nginx.com nxt_mp_t *mp; 2099774Svbart@nginx.com nxt_int_t ret; 2100774Svbart@nginx.com nxt_tls_conf_t *tlscf; 2101774Svbart@nginx.com nxt_socket_rpc_t *rpc; 2102774Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 2103774Svbart@nginx.com 2104774Svbart@nginx.com nxt_debug(task, "tls rpc handler"); 2105774Svbart@nginx.com 2106774Svbart@nginx.com rpc = data; 2107774Svbart@nginx.com tmcf = rpc->temp_conf; 2108774Svbart@nginx.com 2109774Svbart@nginx.com if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) { 2110774Svbart@nginx.com goto fail; 2111774Svbart@nginx.com } 2112774Svbart@nginx.com 2113774Svbart@nginx.com mp = tmcf->router_conf->mem_pool; 2114774Svbart@nginx.com 2115774Svbart@nginx.com tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t)); 2116774Svbart@nginx.com if (nxt_slow_path(tlscf == NULL)) { 2117774Svbart@nginx.com goto fail; 2118774Svbart@nginx.com } 2119774Svbart@nginx.com 2120774Svbart@nginx.com tlscf->chain_file = msg->fd; 2121774Svbart@nginx.com 2122774Svbart@nginx.com ret = task->thread->runtime->tls->server_init(task, tlscf); 2123774Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2124774Svbart@nginx.com goto fail; 2125774Svbart@nginx.com } 2126774Svbart@nginx.com 2127774Svbart@nginx.com rpc->socket_conf->tls = tlscf; 2128774Svbart@nginx.com 2129774Svbart@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 2130774Svbart@nginx.com nxt_router_conf_apply, task, tmcf, NULL); 2131774Svbart@nginx.com return; 2132774Svbart@nginx.com 2133774Svbart@nginx.com fail: 2134774Svbart@nginx.com 2135774Svbart@nginx.com nxt_router_conf_error(task, tmcf); 2136774Svbart@nginx.com } 2137774Svbart@nginx.com 2138774Svbart@nginx.com #endif 2139774Svbart@nginx.com 2140774Svbart@nginx.com 2141507Smax.romanov@nginx.com static void 2142507Smax.romanov@nginx.com nxt_router_app_rpc_create(nxt_task_t *task, 2143507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_app_t *app) 2144507Smax.romanov@nginx.com { 2145507Smax.romanov@nginx.com size_t size; 2146507Smax.romanov@nginx.com uint32_t stream; 2147648Svbart@nginx.com nxt_int_t ret; 2148507Smax.romanov@nginx.com nxt_buf_t *b; 2149507Smax.romanov@nginx.com nxt_port_t *main_port, *router_port; 2150507Smax.romanov@nginx.com nxt_runtime_t *rt; 2151507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 2152507Smax.romanov@nginx.com 2153507Smax.romanov@nginx.com rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_app_rpc_t)); 2154507Smax.romanov@nginx.com if (rpc == NULL) { 2155507Smax.romanov@nginx.com goto fail; 2156507Smax.romanov@nginx.com } 2157507Smax.romanov@nginx.com 2158507Smax.romanov@nginx.com rpc->app = app; 2159507Smax.romanov@nginx.com rpc->temp_conf = tmcf; 2160507Smax.romanov@nginx.com 2161507Smax.romanov@nginx.com nxt_debug(task, "app '%V' prefork", &app->name); 2162507Smax.romanov@nginx.com 2163507Smax.romanov@nginx.com size = app->name.length + 1 + app->conf.length; 2164507Smax.romanov@nginx.com 2165507Smax.romanov@nginx.com b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 2166507Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 2167507Smax.romanov@nginx.com goto fail; 2168507Smax.romanov@nginx.com } 2169507Smax.romanov@nginx.com 2170507Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->name); 2171507Smax.romanov@nginx.com *b->mem.free++ = '\0'; 2172507Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 2173507Smax.romanov@nginx.com 2174507Smax.romanov@nginx.com rt = task->thread->runtime; 2175507Smax.romanov@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 2176507Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 2177507Smax.romanov@nginx.com 2178507Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 2179507Smax.romanov@nginx.com nxt_router_app_prefork_ready, 2180507Smax.romanov@nginx.com nxt_router_app_prefork_error, 2181507Smax.romanov@nginx.com -1, rpc); 2182507Smax.romanov@nginx.com if (nxt_slow_path(stream == 0)) { 2183507Smax.romanov@nginx.com goto fail; 2184507Smax.romanov@nginx.com } 2185507Smax.romanov@nginx.com 2186648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1, 2187648Svbart@nginx.com stream, router_port->id, b); 2188648Svbart@nginx.com 2189648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2190648Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 2191648Svbart@nginx.com goto fail; 2192648Svbart@nginx.com } 2193648Svbart@nginx.com 2194507Smax.romanov@nginx.com app->pending_processes++; 2195507Smax.romanov@nginx.com 2196507Smax.romanov@nginx.com return; 2197507Smax.romanov@nginx.com 2198507Smax.romanov@nginx.com fail: 2199507Smax.romanov@nginx.com 2200507Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 2201507Smax.romanov@nginx.com } 2202507Smax.romanov@nginx.com 2203507Smax.romanov@nginx.com 2204507Smax.romanov@nginx.com static void 2205507Smax.romanov@nginx.com nxt_router_app_prefork_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2206507Smax.romanov@nginx.com void *data) 2207507Smax.romanov@nginx.com { 2208507Smax.romanov@nginx.com nxt_app_t *app; 2209507Smax.romanov@nginx.com nxt_port_t *port; 2210507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 2211507Smax.romanov@nginx.com nxt_event_engine_t *engine; 2212507Smax.romanov@nginx.com 2213507Smax.romanov@nginx.com rpc = data; 2214507Smax.romanov@nginx.com app = rpc->app; 2215507Smax.romanov@nginx.com 2216507Smax.romanov@nginx.com port = msg->u.new_port; 2217507Smax.romanov@nginx.com port->app = app; 2218507Smax.romanov@nginx.com 2219507Smax.romanov@nginx.com app->pending_processes--; 2220507Smax.romanov@nginx.com app->processes++; 2221507Smax.romanov@nginx.com app->idle_processes++; 2222507Smax.romanov@nginx.com 2223507Smax.romanov@nginx.com engine = task->thread->engine; 2224507Smax.romanov@nginx.com 2225507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &port->app_link); 2226507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, &port->idle_link); 2227507Smax.romanov@nginx.com 2228507Smax.romanov@nginx.com port->idle_start = 0; 2229507Smax.romanov@nginx.com 2230507Smax.romanov@nginx.com nxt_port_inc_use(port); 2231507Smax.romanov@nginx.com 2232507Smax.romanov@nginx.com nxt_work_queue_add(&engine->fast_work_queue, 2233507Smax.romanov@nginx.com nxt_router_conf_apply, task, rpc->temp_conf, NULL); 2234507Smax.romanov@nginx.com } 2235507Smax.romanov@nginx.com 2236507Smax.romanov@nginx.com 2237507Smax.romanov@nginx.com static void 2238507Smax.romanov@nginx.com nxt_router_app_prefork_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2239507Smax.romanov@nginx.com void *data) 2240507Smax.romanov@nginx.com { 2241507Smax.romanov@nginx.com nxt_app_t *app; 2242507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 2243507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf; 2244507Smax.romanov@nginx.com 2245507Smax.romanov@nginx.com rpc = data; 2246507Smax.romanov@nginx.com app = rpc->app; 2247507Smax.romanov@nginx.com tmcf = rpc->temp_conf; 2248507Smax.romanov@nginx.com 2249507Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, "failed to start application \"%V\"", 2250507Smax.romanov@nginx.com &app->name); 2251507Smax.romanov@nginx.com 2252507Smax.romanov@nginx.com app->pending_processes--; 2253507Smax.romanov@nginx.com 2254507Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 2255507Smax.romanov@nginx.com } 2256507Smax.romanov@nginx.com 2257507Smax.romanov@nginx.com 225853Sigor@sysoev.ru static nxt_int_t 225953Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router, 226053Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface) 226153Sigor@sysoev.ru { 226253Sigor@sysoev.ru nxt_int_t ret; 226353Sigor@sysoev.ru nxt_uint_t n, threads; 226453Sigor@sysoev.ru nxt_queue_link_t *qlk; 226553Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 226653Sigor@sysoev.ru 2267591Sigor@sysoev.ru threads = tmcf->router_conf->threads; 226853Sigor@sysoev.ru 226953Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, threads, 227053Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 227153Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 227253Sigor@sysoev.ru return NXT_ERROR; 227353Sigor@sysoev.ru } 227453Sigor@sysoev.ru 227553Sigor@sysoev.ru n = 0; 227653Sigor@sysoev.ru 227753Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->engines); 227853Sigor@sysoev.ru qlk != nxt_queue_tail(&router->engines); 227953Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 228053Sigor@sysoev.ru { 228153Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 228253Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 228353Sigor@sysoev.ru return NXT_ERROR; 228453Sigor@sysoev.ru } 228553Sigor@sysoev.ru 2286115Sigor@sysoev.ru recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0); 228753Sigor@sysoev.ru 228853Sigor@sysoev.ru if (n < threads) { 2289315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_KEEP; 2290115Sigor@sysoev.ru ret = nxt_router_engine_conf_update(tmcf, recf); 229153Sigor@sysoev.ru 229253Sigor@sysoev.ru } else { 2293315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_DELETE; 2294115Sigor@sysoev.ru ret = nxt_router_engine_conf_delete(tmcf, recf); 229553Sigor@sysoev.ru } 229653Sigor@sysoev.ru 229753Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 229853Sigor@sysoev.ru return ret; 229953Sigor@sysoev.ru } 230053Sigor@sysoev.ru 230153Sigor@sysoev.ru n++; 230253Sigor@sysoev.ru } 230353Sigor@sysoev.ru 230453Sigor@sysoev.ru tmcf->new_threads = n; 230553Sigor@sysoev.ru 230653Sigor@sysoev.ru while (n < threads) { 230753Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 230853Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 230953Sigor@sysoev.ru return NXT_ERROR; 231053Sigor@sysoev.ru } 231153Sigor@sysoev.ru 2312315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_ADD; 2313315Sigor@sysoev.ru 231453Sigor@sysoev.ru recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0); 231553Sigor@sysoev.ru if (nxt_slow_path(recf->engine == NULL)) { 231653Sigor@sysoev.ru return NXT_ERROR; 231753Sigor@sysoev.ru } 231853Sigor@sysoev.ru 2319115Sigor@sysoev.ru ret = nxt_router_engine_conf_create(tmcf, recf); 232053Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 232153Sigor@sysoev.ru return ret; 232253Sigor@sysoev.ru } 232353Sigor@sysoev.ru 232453Sigor@sysoev.ru n++; 232553Sigor@sysoev.ru } 232653Sigor@sysoev.ru 232753Sigor@sysoev.ru return NXT_OK; 232853Sigor@sysoev.ru } 232953Sigor@sysoev.ru 233053Sigor@sysoev.ru 233153Sigor@sysoev.ru static nxt_int_t 2332115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 2333115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 233453Sigor@sysoev.ru { 2335359Sigor@sysoev.ru nxt_int_t ret; 233653Sigor@sysoev.ru 2337154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 2338154Sigor@sysoev.ru nxt_router_listen_socket_create); 2339115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2340115Sigor@sysoev.ru return ret; 2341115Sigor@sysoev.ru } 2342115Sigor@sysoev.ru 2343154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 2344154Sigor@sysoev.ru nxt_router_listen_socket_create); 234553Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 234653Sigor@sysoev.ru return ret; 234753Sigor@sysoev.ru } 234853Sigor@sysoev.ru 2349115Sigor@sysoev.ru return ret; 235053Sigor@sysoev.ru } 235153Sigor@sysoev.ru 235253Sigor@sysoev.ru 235353Sigor@sysoev.ru static nxt_int_t 2354115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 2355115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 235653Sigor@sysoev.ru { 2357359Sigor@sysoev.ru nxt_int_t ret; 235853Sigor@sysoev.ru 2359154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 2360154Sigor@sysoev.ru nxt_router_listen_socket_create); 236153Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 236253Sigor@sysoev.ru return ret; 236353Sigor@sysoev.ru } 236453Sigor@sysoev.ru 2365154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 2366154Sigor@sysoev.ru nxt_router_listen_socket_update); 236753Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 236853Sigor@sysoev.ru return ret; 236953Sigor@sysoev.ru } 237053Sigor@sysoev.ru 2371139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 2372115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2373115Sigor@sysoev.ru return ret; 2374115Sigor@sysoev.ru } 2375115Sigor@sysoev.ru 2376115Sigor@sysoev.ru return ret; 237753Sigor@sysoev.ru } 237853Sigor@sysoev.ru 237953Sigor@sysoev.ru 238053Sigor@sysoev.ru static nxt_int_t 2381115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 2382115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 238353Sigor@sysoev.ru { 238453Sigor@sysoev.ru nxt_int_t ret; 238553Sigor@sysoev.ru 2386313Sigor@sysoev.ru ret = nxt_router_engine_quit(tmcf, recf); 2387313Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2388313Sigor@sysoev.ru return ret; 2389313Sigor@sysoev.ru } 2390313Sigor@sysoev.ru 2391139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating); 239253Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 239353Sigor@sysoev.ru return ret; 239453Sigor@sysoev.ru } 239553Sigor@sysoev.ru 2396139Sigor@sysoev.ru return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 239753Sigor@sysoev.ru } 239853Sigor@sysoev.ru 239953Sigor@sysoev.ru 240053Sigor@sysoev.ru static nxt_int_t 2401154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 2402154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 240353Sigor@sysoev.ru nxt_work_handler_t handler) 240453Sigor@sysoev.ru { 2405153Sigor@sysoev.ru nxt_joint_job_t *job; 240653Sigor@sysoev.ru nxt_queue_link_t *qlk; 2407155Sigor@sysoev.ru nxt_socket_conf_t *skcf; 240853Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 240953Sigor@sysoev.ru 241053Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 241153Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 241253Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 241353Sigor@sysoev.ru { 2414154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2415153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2416139Sigor@sysoev.ru return NXT_ERROR; 2417139Sigor@sysoev.ru } 2418139Sigor@sysoev.ru 2419154Sigor@sysoev.ru job->work.next = recf->jobs; 2420154Sigor@sysoev.ru recf->jobs = &job->work; 2421154Sigor@sysoev.ru 2422153Sigor@sysoev.ru job->task = tmcf->engine->task; 2423153Sigor@sysoev.ru job->work.handler = handler; 2424153Sigor@sysoev.ru job->work.task = &job->task; 2425153Sigor@sysoev.ru job->work.obj = job; 2426153Sigor@sysoev.ru job->tmcf = tmcf; 242753Sigor@sysoev.ru 2428154Sigor@sysoev.ru tmcf->count++; 2429154Sigor@sysoev.ru 2430591Sigor@sysoev.ru joint = nxt_mp_alloc(tmcf->router_conf->mem_pool, 2431154Sigor@sysoev.ru sizeof(nxt_socket_conf_joint_t)); 243253Sigor@sysoev.ru if (nxt_slow_path(joint == NULL)) { 243353Sigor@sysoev.ru return NXT_ERROR; 243453Sigor@sysoev.ru } 243553Sigor@sysoev.ru 2436153Sigor@sysoev.ru job->work.data = joint; 243753Sigor@sysoev.ru 243853Sigor@sysoev.ru joint->count = 1; 2439155Sigor@sysoev.ru 2440155Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 2441155Sigor@sysoev.ru skcf->count++; 2442155Sigor@sysoev.ru joint->socket_conf = skcf; 2443155Sigor@sysoev.ru 244488Smax.romanov@nginx.com joint->engine = recf->engine; 244553Sigor@sysoev.ru } 244653Sigor@sysoev.ru 244720Sigor@sysoev.ru return NXT_OK; 244820Sigor@sysoev.ru } 244920Sigor@sysoev.ru 245020Sigor@sysoev.ru 245120Sigor@sysoev.ru static nxt_int_t 2452313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 2453313Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 2454313Sigor@sysoev.ru { 2455313Sigor@sysoev.ru nxt_joint_job_t *job; 2456313Sigor@sysoev.ru 2457313Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2458313Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2459313Sigor@sysoev.ru return NXT_ERROR; 2460313Sigor@sysoev.ru } 2461313Sigor@sysoev.ru 2462313Sigor@sysoev.ru job->work.next = recf->jobs; 2463313Sigor@sysoev.ru recf->jobs = &job->work; 2464313Sigor@sysoev.ru 2465313Sigor@sysoev.ru job->task = tmcf->engine->task; 2466313Sigor@sysoev.ru job->work.handler = nxt_router_worker_thread_quit; 2467313Sigor@sysoev.ru job->work.task = &job->task; 2468313Sigor@sysoev.ru job->work.obj = NULL; 2469313Sigor@sysoev.ru job->work.data = NULL; 2470313Sigor@sysoev.ru job->tmcf = NULL; 2471313Sigor@sysoev.ru 2472313Sigor@sysoev.ru return NXT_OK; 2473313Sigor@sysoev.ru } 2474313Sigor@sysoev.ru 2475313Sigor@sysoev.ru 2476313Sigor@sysoev.ru static nxt_int_t 2477139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 2478139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets) 247920Sigor@sysoev.ru { 2480153Sigor@sysoev.ru nxt_joint_job_t *job; 248153Sigor@sysoev.ru nxt_queue_link_t *qlk; 248220Sigor@sysoev.ru 248353Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 248453Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 248553Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 248653Sigor@sysoev.ru { 2487154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2488153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2489139Sigor@sysoev.ru return NXT_ERROR; 2490139Sigor@sysoev.ru } 2491139Sigor@sysoev.ru 2492154Sigor@sysoev.ru job->work.next = recf->jobs; 2493154Sigor@sysoev.ru recf->jobs = &job->work; 2494154Sigor@sysoev.ru 2495153Sigor@sysoev.ru job->task = tmcf->engine->task; 2496153Sigor@sysoev.ru job->work.handler = nxt_router_listen_socket_delete; 2497153Sigor@sysoev.ru job->work.task = &job->task; 2498153Sigor@sysoev.ru job->work.obj = job; 2499153Sigor@sysoev.ru job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 2500153Sigor@sysoev.ru job->tmcf = tmcf; 2501154Sigor@sysoev.ru 2502154Sigor@sysoev.ru tmcf->count++; 250320Sigor@sysoev.ru } 250420Sigor@sysoev.ru 250553Sigor@sysoev.ru return NXT_OK; 250653Sigor@sysoev.ru } 250720Sigor@sysoev.ru 250820Sigor@sysoev.ru 250953Sigor@sysoev.ru static nxt_int_t 251053Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 251153Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 251253Sigor@sysoev.ru { 251353Sigor@sysoev.ru nxt_int_t ret; 251453Sigor@sysoev.ru nxt_uint_t i, threads; 251553Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 251620Sigor@sysoev.ru 251753Sigor@sysoev.ru recf = tmcf->engines->elts; 2518591Sigor@sysoev.ru threads = tmcf->router_conf->threads; 251920Sigor@sysoev.ru 252053Sigor@sysoev.ru for (i = tmcf->new_threads; i < threads; i++) { 252153Sigor@sysoev.ru ret = nxt_router_thread_create(task, rt, recf[i].engine); 252253Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 252353Sigor@sysoev.ru return ret; 252453Sigor@sysoev.ru } 252520Sigor@sysoev.ru } 252620Sigor@sysoev.ru 252720Sigor@sysoev.ru return NXT_OK; 252820Sigor@sysoev.ru } 252953Sigor@sysoev.ru 253053Sigor@sysoev.ru 253153Sigor@sysoev.ru static nxt_int_t 253253Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 253353Sigor@sysoev.ru nxt_event_engine_t *engine) 253453Sigor@sysoev.ru { 253553Sigor@sysoev.ru nxt_int_t ret; 253653Sigor@sysoev.ru nxt_thread_link_t *link; 253753Sigor@sysoev.ru nxt_thread_handle_t handle; 253853Sigor@sysoev.ru 253953Sigor@sysoev.ru link = nxt_zalloc(sizeof(nxt_thread_link_t)); 254053Sigor@sysoev.ru 254153Sigor@sysoev.ru if (nxt_slow_path(link == NULL)) { 254253Sigor@sysoev.ru return NXT_ERROR; 254353Sigor@sysoev.ru } 254453Sigor@sysoev.ru 254553Sigor@sysoev.ru link->start = nxt_router_thread_start; 254653Sigor@sysoev.ru link->engine = engine; 254753Sigor@sysoev.ru link->work.handler = nxt_router_thread_exit_handler; 254853Sigor@sysoev.ru link->work.task = task; 254953Sigor@sysoev.ru link->work.data = link; 255053Sigor@sysoev.ru 255153Sigor@sysoev.ru nxt_queue_insert_tail(&rt->engines, &engine->link); 255253Sigor@sysoev.ru 255353Sigor@sysoev.ru ret = nxt_thread_create(&handle, link); 255453Sigor@sysoev.ru 255553Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 255653Sigor@sysoev.ru nxt_queue_remove(&engine->link); 255753Sigor@sysoev.ru } 255853Sigor@sysoev.ru 255953Sigor@sysoev.ru return ret; 256053Sigor@sysoev.ru } 256153Sigor@sysoev.ru 256253Sigor@sysoev.ru 256353Sigor@sysoev.ru static void 2564343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 2565343Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf) 2566133Sigor@sysoev.ru { 2567507Smax.romanov@nginx.com nxt_app_t *app; 2568141Smax.romanov@nginx.com 2569141Smax.romanov@nginx.com nxt_queue_each(app, &router->apps, nxt_app_t, link) { 2570133Sigor@sysoev.ru 2571753Smax.romanov@nginx.com nxt_router_app_unlink(task, app); 2572343Smax.romanov@nginx.com 2573141Smax.romanov@nginx.com } nxt_queue_loop; 2574133Sigor@sysoev.ru 2575133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->previous); 2576133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->apps); 2577133Sigor@sysoev.ru } 2578133Sigor@sysoev.ru 2579133Sigor@sysoev.ru 2580133Sigor@sysoev.ru static void 2581315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf) 258253Sigor@sysoev.ru { 258353Sigor@sysoev.ru nxt_uint_t n; 2584315Sigor@sysoev.ru nxt_event_engine_t *engine; 258553Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 258653Sigor@sysoev.ru 258753Sigor@sysoev.ru recf = tmcf->engines->elts; 258853Sigor@sysoev.ru 258953Sigor@sysoev.ru for (n = tmcf->engines->nelts; n != 0; n--) { 2590315Sigor@sysoev.ru engine = recf->engine; 2591315Sigor@sysoev.ru 2592315Sigor@sysoev.ru switch (recf->action) { 2593315Sigor@sysoev.ru 2594315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_KEEP: 2595315Sigor@sysoev.ru break; 2596315Sigor@sysoev.ru 2597315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_ADD: 2598315Sigor@sysoev.ru nxt_queue_insert_tail(&router->engines, &engine->link0); 2599315Sigor@sysoev.ru break; 2600315Sigor@sysoev.ru 2601315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_DELETE: 2602315Sigor@sysoev.ru nxt_queue_remove(&engine->link0); 2603315Sigor@sysoev.ru break; 2604315Sigor@sysoev.ru } 2605315Sigor@sysoev.ru 2606316Sigor@sysoev.ru nxt_router_engine_post(engine, recf->jobs); 2607316Sigor@sysoev.ru 260853Sigor@sysoev.ru recf++; 260953Sigor@sysoev.ru } 261053Sigor@sysoev.ru } 261153Sigor@sysoev.ru 261253Sigor@sysoev.ru 261353Sigor@sysoev.ru static void 2614315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs) 261553Sigor@sysoev.ru { 2616154Sigor@sysoev.ru nxt_work_t *work, *next; 2617154Sigor@sysoev.ru 2618315Sigor@sysoev.ru for (work = jobs; work != NULL; work = next) { 2619154Sigor@sysoev.ru next = work->next; 2620154Sigor@sysoev.ru work->next = NULL; 2621154Sigor@sysoev.ru 2622315Sigor@sysoev.ru nxt_event_engine_post(engine, work); 262353Sigor@sysoev.ru } 262453Sigor@sysoev.ru } 262553Sigor@sysoev.ru 262653Sigor@sysoev.ru 2627320Smax.romanov@nginx.com static nxt_port_handlers_t nxt_router_app_port_handlers = { 2628616Smax.romanov@nginx.com .rpc_error = nxt_port_rpc_handler, 2629616Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 2630616Smax.romanov@nginx.com .data = nxt_port_rpc_handler, 263188Smax.romanov@nginx.com }; 263288Smax.romanov@nginx.com 263388Smax.romanov@nginx.com 263488Smax.romanov@nginx.com static void 263553Sigor@sysoev.ru nxt_router_thread_start(void *data) 263653Sigor@sysoev.ru { 2637141Smax.romanov@nginx.com nxt_int_t ret; 2638141Smax.romanov@nginx.com nxt_port_t *port; 263988Smax.romanov@nginx.com nxt_task_t *task; 264053Sigor@sysoev.ru nxt_thread_t *thread; 264153Sigor@sysoev.ru nxt_thread_link_t *link; 264253Sigor@sysoev.ru nxt_event_engine_t *engine; 264353Sigor@sysoev.ru 264453Sigor@sysoev.ru link = data; 264553Sigor@sysoev.ru engine = link->engine; 264688Smax.romanov@nginx.com task = &engine->task; 264753Sigor@sysoev.ru 264853Sigor@sysoev.ru thread = nxt_thread(); 264953Sigor@sysoev.ru 2650165Smax.romanov@nginx.com nxt_event_engine_thread_adopt(engine); 2651165Smax.romanov@nginx.com 265253Sigor@sysoev.ru /* STUB */ 265353Sigor@sysoev.ru thread->runtime = engine->task.thread->runtime; 265453Sigor@sysoev.ru 265553Sigor@sysoev.ru engine->task.thread = thread; 265653Sigor@sysoev.ru engine->task.log = thread->log; 265753Sigor@sysoev.ru thread->engine = engine; 265863Sigor@sysoev.ru thread->task = &engine->task; 2659326Svbart@nginx.com #if 0 266053Sigor@sysoev.ru thread->fiber = &engine->fibers->fiber; 2661326Svbart@nginx.com #endif 266253Sigor@sysoev.ru 266363Sigor@sysoev.ru engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64); 2664337Sigor@sysoev.ru if (nxt_slow_path(engine->mem_pool == NULL)) { 2665337Sigor@sysoev.ru return; 2666337Sigor@sysoev.ru } 266753Sigor@sysoev.ru 2668197Smax.romanov@nginx.com port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid, 2669197Smax.romanov@nginx.com NXT_PROCESS_ROUTER); 2670141Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 2671141Smax.romanov@nginx.com return; 2672141Smax.romanov@nginx.com } 2673141Smax.romanov@nginx.com 2674141Smax.romanov@nginx.com ret = nxt_port_socket_init(task, port, 0); 2675141Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2676343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 2677141Smax.romanov@nginx.com return; 2678141Smax.romanov@nginx.com } 2679141Smax.romanov@nginx.com 2680141Smax.romanov@nginx.com engine->port = port; 2681141Smax.romanov@nginx.com 2682320Smax.romanov@nginx.com nxt_port_enable(task, port, &nxt_router_app_port_handlers); 2683141Smax.romanov@nginx.com 268453Sigor@sysoev.ru nxt_event_engine_start(engine); 268553Sigor@sysoev.ru } 268653Sigor@sysoev.ru 268753Sigor@sysoev.ru 268853Sigor@sysoev.ru static void 268953Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data) 269053Sigor@sysoev.ru { 2691153Sigor@sysoev.ru nxt_joint_job_t *job; 2692359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2693359Sigor@sysoev.ru nxt_listen_event_t *lev; 269453Sigor@sysoev.ru nxt_listen_socket_t *ls; 2695359Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 269653Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 269753Sigor@sysoev.ru 2698153Sigor@sysoev.ru job = obj; 269953Sigor@sysoev.ru joint = data; 270053Sigor@sysoev.ru 2701159Sigor@sysoev.ru nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link); 2702159Sigor@sysoev.ru 2703359Sigor@sysoev.ru skcf = joint->socket_conf; 2704359Sigor@sysoev.ru ls = skcf->listen; 2705359Sigor@sysoev.ru 2706359Sigor@sysoev.ru lev = nxt_listen_event(task, ls); 2707359Sigor@sysoev.ru if (nxt_slow_path(lev == NULL)) { 2708359Sigor@sysoev.ru nxt_router_listen_socket_release(task, skcf); 270953Sigor@sysoev.ru return; 271053Sigor@sysoev.ru } 271153Sigor@sysoev.ru 2712359Sigor@sysoev.ru lev->socket.data = joint; 2713359Sigor@sysoev.ru 2714359Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 2715359Sigor@sysoev.ru 2716359Sigor@sysoev.ru nxt_thread_spin_lock(lock); 2717359Sigor@sysoev.ru ls->count++; 2718359Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 2719139Sigor@sysoev.ru 2720153Sigor@sysoev.ru job->work.next = NULL; 2721153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2722153Sigor@sysoev.ru 2723153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 272453Sigor@sysoev.ru } 272553Sigor@sysoev.ru 272653Sigor@sysoev.ru 272753Sigor@sysoev.ru nxt_inline nxt_listen_event_t * 272853Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections, 272953Sigor@sysoev.ru nxt_socket_conf_t *skcf) 273053Sigor@sysoev.ru { 2731115Sigor@sysoev.ru nxt_socket_t fd; 2732115Sigor@sysoev.ru nxt_queue_link_t *qlk; 2733359Sigor@sysoev.ru nxt_listen_event_t *lev; 2734359Sigor@sysoev.ru 2735359Sigor@sysoev.ru fd = skcf->listen->socket; 273653Sigor@sysoev.ru 2737115Sigor@sysoev.ru for (qlk = nxt_queue_first(listen_connections); 2738115Sigor@sysoev.ru qlk != nxt_queue_tail(listen_connections); 2739115Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 274053Sigor@sysoev.ru { 2741359Sigor@sysoev.ru lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link); 2742359Sigor@sysoev.ru 2743359Sigor@sysoev.ru if (fd == lev->socket.fd) { 2744359Sigor@sysoev.ru return lev; 274553Sigor@sysoev.ru } 274653Sigor@sysoev.ru } 274753Sigor@sysoev.ru 274853Sigor@sysoev.ru return NULL; 274953Sigor@sysoev.ru } 275053Sigor@sysoev.ru 275153Sigor@sysoev.ru 275253Sigor@sysoev.ru static void 275353Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data) 275453Sigor@sysoev.ru { 2755153Sigor@sysoev.ru nxt_joint_job_t *job; 275653Sigor@sysoev.ru nxt_event_engine_t *engine; 2757359Sigor@sysoev.ru nxt_listen_event_t *lev; 275853Sigor@sysoev.ru nxt_socket_conf_joint_t *joint, *old; 275953Sigor@sysoev.ru 2760153Sigor@sysoev.ru job = obj; 276153Sigor@sysoev.ru joint = data; 276253Sigor@sysoev.ru 2763139Sigor@sysoev.ru engine = task->thread->engine; 2764139Sigor@sysoev.ru 2765159Sigor@sysoev.ru nxt_queue_insert_tail(&engine->joints, &joint->link); 2766159Sigor@sysoev.ru 2767359Sigor@sysoev.ru lev = nxt_router_listen_event(&engine->listen_connections, 2768359Sigor@sysoev.ru joint->socket_conf); 2769359Sigor@sysoev.ru 2770359Sigor@sysoev.ru old = lev->socket.data; 2771359Sigor@sysoev.ru lev->socket.data = joint; 2772359Sigor@sysoev.ru lev->listen = joint->socket_conf->listen; 277353Sigor@sysoev.ru 2774153Sigor@sysoev.ru job->work.next = NULL; 2775153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2776153Sigor@sysoev.ru 2777153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 2778139Sigor@sysoev.ru 2779181Smax.romanov@nginx.com /* 2780181Smax.romanov@nginx.com * The task is allocated from configuration temporary 2781181Smax.romanov@nginx.com * memory pool so it can be freed after engine post operation. 2782181Smax.romanov@nginx.com */ 2783181Smax.romanov@nginx.com 2784181Smax.romanov@nginx.com nxt_router_conf_release(&engine->task, old); 278553Sigor@sysoev.ru } 278653Sigor@sysoev.ru 278753Sigor@sysoev.ru 278853Sigor@sysoev.ru static void 278953Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data) 279053Sigor@sysoev.ru { 2791153Sigor@sysoev.ru nxt_joint_job_t *job; 2792153Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2793359Sigor@sysoev.ru nxt_listen_event_t *lev; 2794153Sigor@sysoev.ru nxt_event_engine_t *engine; 2795153Sigor@sysoev.ru 2796153Sigor@sysoev.ru job = obj; 279753Sigor@sysoev.ru skcf = data; 279853Sigor@sysoev.ru 2799139Sigor@sysoev.ru engine = task->thread->engine; 2800139Sigor@sysoev.ru 2801359Sigor@sysoev.ru lev = nxt_router_listen_event(&engine->listen_connections, skcf); 2802359Sigor@sysoev.ru 2803359Sigor@sysoev.ru nxt_fd_event_delete(engine, &lev->socket); 280453Sigor@sysoev.ru 2805163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket delete: %d", engine, 2806359Sigor@sysoev.ru lev->socket.fd); 2807359Sigor@sysoev.ru 2808359Sigor@sysoev.ru lev->timer.handler = nxt_router_listen_socket_close; 2809359Sigor@sysoev.ru lev->timer.work_queue = &engine->fast_work_queue; 2810359Sigor@sysoev.ru 2811359Sigor@sysoev.ru nxt_timer_add(engine, &lev->timer, 0); 2812139Sigor@sysoev.ru 2813153Sigor@sysoev.ru job->work.next = NULL; 2814153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2815153Sigor@sysoev.ru 2816153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 281753Sigor@sysoev.ru } 281853Sigor@sysoev.ru 281953Sigor@sysoev.ru 282053Sigor@sysoev.ru static void 2821313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data) 2822313Sigor@sysoev.ru { 2823313Sigor@sysoev.ru nxt_event_engine_t *engine; 2824313Sigor@sysoev.ru 2825313Sigor@sysoev.ru nxt_debug(task, "router worker thread quit"); 2826313Sigor@sysoev.ru 2827313Sigor@sysoev.ru engine = task->thread->engine; 2828313Sigor@sysoev.ru 2829313Sigor@sysoev.ru engine->shutdown = 1; 2830313Sigor@sysoev.ru 2831313Sigor@sysoev.ru if (nxt_queue_is_empty(&engine->joints)) { 2832313Sigor@sysoev.ru nxt_thread_exit(task->thread); 2833313Sigor@sysoev.ru } 2834313Sigor@sysoev.ru } 2835313Sigor@sysoev.ru 2836313Sigor@sysoev.ru 2837313Sigor@sysoev.ru static void 283853Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data) 283953Sigor@sysoev.ru { 284053Sigor@sysoev.ru nxt_timer_t *timer; 2841359Sigor@sysoev.ru nxt_listen_event_t *lev; 284253Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 284353Sigor@sysoev.ru 284453Sigor@sysoev.ru timer = obj; 2845359Sigor@sysoev.ru lev = nxt_timer_data(timer, nxt_listen_event_t, timer); 284653Sigor@sysoev.ru 2847163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine, 2848359Sigor@sysoev.ru lev->socket.fd); 2849359Sigor@sysoev.ru 2850359Sigor@sysoev.ru nxt_queue_remove(&lev->link); 2851359Sigor@sysoev.ru 2852683Sigor@sysoev.ru joint = lev->socket.data; 2853683Sigor@sysoev.ru lev->socket.data = NULL; 2854683Sigor@sysoev.ru 2855359Sigor@sysoev.ru /* 'task' refers to lev->task and we cannot use after nxt_free() */ 2856123Smax.romanov@nginx.com task = &task->thread->engine->task; 2857123Smax.romanov@nginx.com 2858359Sigor@sysoev.ru nxt_router_listen_socket_release(task, joint->socket_conf); 2859359Sigor@sysoev.ru 2860683Sigor@sysoev.ru nxt_router_listen_event_release(task, lev, joint); 286153Sigor@sysoev.ru } 286253Sigor@sysoev.ru 286353Sigor@sysoev.ru 286453Sigor@sysoev.ru static void 2865359Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf) 286653Sigor@sysoev.ru { 2867359Sigor@sysoev.ru nxt_listen_socket_t *ls; 286853Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 286953Sigor@sysoev.ru 2870359Sigor@sysoev.ru ls = skcf->listen; 2871118Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 287253Sigor@sysoev.ru 287353Sigor@sysoev.ru nxt_thread_spin_lock(lock); 287453Sigor@sysoev.ru 2875359Sigor@sysoev.ru nxt_debug(task, "engine %p: listen socket release: ls->count %D", 2876359Sigor@sysoev.ru task->thread->engine, ls->count); 2877359Sigor@sysoev.ru 2878359Sigor@sysoev.ru if (--ls->count != 0) { 2879359Sigor@sysoev.ru ls = NULL; 288053Sigor@sysoev.ru } 288153Sigor@sysoev.ru 288253Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 288353Sigor@sysoev.ru 2884359Sigor@sysoev.ru if (ls != NULL) { 2885359Sigor@sysoev.ru nxt_socket_close(task, ls->socket); 2886359Sigor@sysoev.ru nxt_free(ls); 288753Sigor@sysoev.ru } 288853Sigor@sysoev.ru } 288953Sigor@sysoev.ru 289053Sigor@sysoev.ru 2891683Sigor@sysoev.ru void 2892683Sigor@sysoev.ru nxt_router_listen_event_release(nxt_task_t *task, nxt_listen_event_t *lev, 2893683Sigor@sysoev.ru nxt_socket_conf_joint_t *joint) 2894683Sigor@sysoev.ru { 2895683Sigor@sysoev.ru nxt_event_engine_t *engine; 2896683Sigor@sysoev.ru 2897683Sigor@sysoev.ru nxt_debug(task, "listen event count: %D", lev->count); 2898683Sigor@sysoev.ru 2899683Sigor@sysoev.ru if (--lev->count == 0) { 2900683Sigor@sysoev.ru nxt_free(lev); 2901683Sigor@sysoev.ru } 2902683Sigor@sysoev.ru 2903683Sigor@sysoev.ru if (joint != NULL) { 2904683Sigor@sysoev.ru nxt_router_conf_release(task, joint); 2905683Sigor@sysoev.ru } 2906683Sigor@sysoev.ru 2907683Sigor@sysoev.ru engine = task->thread->engine; 2908683Sigor@sysoev.ru 2909683Sigor@sysoev.ru if (engine->shutdown && nxt_queue_is_empty(&engine->joints)) { 2910683Sigor@sysoev.ru nxt_thread_exit(task->thread); 2911683Sigor@sysoev.ru } 2912683Sigor@sysoev.ru } 2913683Sigor@sysoev.ru 2914683Sigor@sysoev.ru 2915683Sigor@sysoev.ru void 291653Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint) 291753Sigor@sysoev.ru { 291853Sigor@sysoev.ru nxt_socket_conf_t *skcf; 291953Sigor@sysoev.ru nxt_router_conf_t *rtcf; 292053Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 292153Sigor@sysoev.ru 2922163Smax.romanov@nginx.com nxt_debug(task, "conf joint %p count: %D", joint, joint->count); 292353Sigor@sysoev.ru 292453Sigor@sysoev.ru if (--joint->count != 0) { 292553Sigor@sysoev.ru return; 292653Sigor@sysoev.ru } 292753Sigor@sysoev.ru 292853Sigor@sysoev.ru nxt_queue_remove(&joint->link); 292953Sigor@sysoev.ru 2930530Sigor@sysoev.ru /* 2931530Sigor@sysoev.ru * The joint content can not be safely used after the critical 2932530Sigor@sysoev.ru * section protected by the spinlock because its memory pool may 2933530Sigor@sysoev.ru * be already destroyed by another thread. 2934530Sigor@sysoev.ru */ 293553Sigor@sysoev.ru skcf = joint->socket_conf; 293653Sigor@sysoev.ru rtcf = skcf->router_conf; 293753Sigor@sysoev.ru lock = &rtcf->router->lock; 293853Sigor@sysoev.ru 293953Sigor@sysoev.ru nxt_thread_spin_lock(lock); 294053Sigor@sysoev.ru 2941163Smax.romanov@nginx.com nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count, 2942163Smax.romanov@nginx.com rtcf, rtcf->count); 2943163Smax.romanov@nginx.com 294453Sigor@sysoev.ru if (--skcf->count != 0) { 2945952Sigor@sysoev.ru skcf = NULL; 294653Sigor@sysoev.ru rtcf = NULL; 294753Sigor@sysoev.ru 294853Sigor@sysoev.ru } else { 294953Sigor@sysoev.ru nxt_queue_remove(&skcf->link); 295053Sigor@sysoev.ru 295153Sigor@sysoev.ru if (--rtcf->count != 0) { 295253Sigor@sysoev.ru rtcf = NULL; 295353Sigor@sysoev.ru } 295453Sigor@sysoev.ru } 295553Sigor@sysoev.ru 295653Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 295753Sigor@sysoev.ru 2958952Sigor@sysoev.ru if (skcf != NULL) { 2959964Sigor@sysoev.ru if (skcf->pass != NULL) { 2960964Sigor@sysoev.ru nxt_http_pass_cleanup(task, skcf->pass); 2961964Sigor@sysoev.ru } 2962964Sigor@sysoev.ru 2963952Sigor@sysoev.ru #if (NXT_TLS) 2964952Sigor@sysoev.ru if (skcf->tls != NULL) { 2965952Sigor@sysoev.ru task->thread->runtime->tls->server_free(task, skcf->tls); 2966952Sigor@sysoev.ru } 2967952Sigor@sysoev.ru #endif 2968952Sigor@sysoev.ru } 2969952Sigor@sysoev.ru 2970141Smax.romanov@nginx.com /* TODO remove engine->port */ 2971141Smax.romanov@nginx.com /* TODO excude from connected ports */ 2972141Smax.romanov@nginx.com 297353Sigor@sysoev.ru if (rtcf != NULL) { 2974115Sigor@sysoev.ru nxt_debug(task, "old router conf is destroyed"); 2975131Smax.romanov@nginx.com 2976964Sigor@sysoev.ru nxt_http_routes_cleanup(task, rtcf->routes); 2977964Sigor@sysoev.ru 2978630Svbart@nginx.com nxt_router_access_log_release(task, lock, rtcf->access_log); 2979630Svbart@nginx.com 2980131Smax.romanov@nginx.com nxt_mp_thread_adopt(rtcf->mem_pool); 2981131Smax.romanov@nginx.com 298265Sigor@sysoev.ru nxt_mp_destroy(rtcf->mem_pool); 298353Sigor@sysoev.ru } 298453Sigor@sysoev.ru } 298553Sigor@sysoev.ru 298653Sigor@sysoev.ru 298753Sigor@sysoev.ru static void 2988630Svbart@nginx.com nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r, 2989630Svbart@nginx.com nxt_router_access_log_t *access_log) 2990630Svbart@nginx.com { 2991630Svbart@nginx.com size_t size; 2992630Svbart@nginx.com u_char *buf, *p; 2993630Svbart@nginx.com nxt_off_t bytes; 2994630Svbart@nginx.com 2995630Svbart@nginx.com static nxt_time_string_t date_cache = { 2996630Svbart@nginx.com (nxt_atomic_uint_t) -1, 2997630Svbart@nginx.com nxt_router_access_log_date, 2998630Svbart@nginx.com "%02d/%s/%4d:%02d:%02d:%02d %c%02d%02d", 2999703Svbart@nginx.com nxt_length("31/Dec/1986:19:40:00 +0300"), 3000630Svbart@nginx.com NXT_THREAD_TIME_LOCAL, 3001630Svbart@nginx.com NXT_THREAD_TIME_SEC, 3002630Svbart@nginx.com }; 3003630Svbart@nginx.com 3004630Svbart@nginx.com size = r->remote->address_length 3005630Svbart@nginx.com + 6 /* ' - - [' */ 3006630Svbart@nginx.com + date_cache.size 3007630Svbart@nginx.com + 3 /* '] "' */ 3008630Svbart@nginx.com + r->method->length 3009630Svbart@nginx.com + 1 /* space */ 3010630Svbart@nginx.com + r->target.length 3011630Svbart@nginx.com + 1 /* space */ 3012630Svbart@nginx.com + r->version.length 3013630Svbart@nginx.com + 2 /* '" ' */ 3014630Svbart@nginx.com + 3 /* status */ 3015630Svbart@nginx.com + 1 /* space */ 3016630Svbart@nginx.com + NXT_OFF_T_LEN 3017630Svbart@nginx.com + 2 /* ' "' */ 3018630Svbart@nginx.com + (r->referer != NULL ? r->referer->value_length : 1) 3019630Svbart@nginx.com + 3 /* '" "' */ 3020630Svbart@nginx.com + (r->user_agent != NULL ? r->user_agent->value_length : 1) 3021630Svbart@nginx.com + 2 /* '"\n' */ 3022630Svbart@nginx.com ; 3023630Svbart@nginx.com 3024630Svbart@nginx.com buf = nxt_mp_nget(r->mem_pool, size); 3025630Svbart@nginx.com if (nxt_slow_path(buf == NULL)) { 3026630Svbart@nginx.com return; 3027630Svbart@nginx.com } 3028630Svbart@nginx.com 3029630Svbart@nginx.com p = nxt_cpymem(buf, nxt_sockaddr_address(r->remote), 3030630Svbart@nginx.com r->remote->address_length); 3031630Svbart@nginx.com 3032630Svbart@nginx.com p = nxt_cpymem(p, " - - [", 6); 3033630Svbart@nginx.com 3034630Svbart@nginx.com p = nxt_thread_time_string(task->thread, &date_cache, p); 3035630Svbart@nginx.com 3036630Svbart@nginx.com p = nxt_cpymem(p, "] \"", 3); 3037630Svbart@nginx.com 3038630Svbart@nginx.com if (r->method->length != 0) { 3039630Svbart@nginx.com p = nxt_cpymem(p, r->method->start, r->method->length); 3040630Svbart@nginx.com 3041630Svbart@nginx.com if (r->target.length != 0) { 3042630Svbart@nginx.com *p++ = ' '; 3043630Svbart@nginx.com p = nxt_cpymem(p, r->target.start, r->target.length); 3044630Svbart@nginx.com 3045630Svbart@nginx.com if (r->version.length != 0) { 3046630Svbart@nginx.com *p++ = ' '; 3047630Svbart@nginx.com p = nxt_cpymem(p, r->version.start, r->version.length); 3048630Svbart@nginx.com } 3049630Svbart@nginx.com } 3050630Svbart@nginx.com 3051630Svbart@nginx.com } else { 3052630Svbart@nginx.com *p++ = '-'; 3053630Svbart@nginx.com } 3054630Svbart@nginx.com 3055630Svbart@nginx.com p = nxt_cpymem(p, "\" ", 2); 3056630Svbart@nginx.com 3057630Svbart@nginx.com p = nxt_sprintf(p, p + 3, "%03d", r->status); 3058630Svbart@nginx.com 3059630Svbart@nginx.com *p++ = ' '; 3060630Svbart@nginx.com 3061630Svbart@nginx.com bytes = nxt_http_proto_body_bytes_sent[r->protocol](task, r->proto); 3062630Svbart@nginx.com 3063630Svbart@nginx.com p = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", bytes); 3064630Svbart@nginx.com 3065630Svbart@nginx.com p = nxt_cpymem(p, " \"", 2); 3066630Svbart@nginx.com 3067630Svbart@nginx.com if (r->referer != NULL) { 3068630Svbart@nginx.com p = nxt_cpymem(p, r->referer->value, r->referer->value_length); 3069630Svbart@nginx.com 3070630Svbart@nginx.com } else { 3071630Svbart@nginx.com *p++ = '-'; 3072630Svbart@nginx.com } 3073630Svbart@nginx.com 3074630Svbart@nginx.com p = nxt_cpymem(p, "\" \"", 3); 3075630Svbart@nginx.com 3076630Svbart@nginx.com if (r->user_agent != NULL) { 3077630Svbart@nginx.com p = nxt_cpymem(p, r->user_agent->value, r->user_agent->value_length); 3078630Svbart@nginx.com 3079630Svbart@nginx.com } else { 3080630Svbart@nginx.com *p++ = '-'; 3081630Svbart@nginx.com } 3082630Svbart@nginx.com 3083630Svbart@nginx.com p = nxt_cpymem(p, "\"\n", 2); 3084630Svbart@nginx.com 3085630Svbart@nginx.com nxt_fd_write(access_log->fd, buf, p - buf); 3086630Svbart@nginx.com } 3087630Svbart@nginx.com 3088630Svbart@nginx.com 3089630Svbart@nginx.com static u_char * 3090630Svbart@nginx.com nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, 3091630Svbart@nginx.com size_t size, const char *format) 3092630Svbart@nginx.com { 3093630Svbart@nginx.com u_char sign; 3094630Svbart@nginx.com time_t gmtoff; 3095630Svbart@nginx.com 3096630Svbart@nginx.com static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", 3097630Svbart@nginx.com "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; 3098630Svbart@nginx.com 3099630Svbart@nginx.com gmtoff = nxt_timezone(tm) / 60; 3100630Svbart@nginx.com 3101630Svbart@nginx.com if (gmtoff < 0) { 3102630Svbart@nginx.com gmtoff = -gmtoff; 3103630Svbart@nginx.com sign = '-'; 3104630Svbart@nginx.com 3105630Svbart@nginx.com } else { 3106630Svbart@nginx.com sign = '+'; 3107630Svbart@nginx.com } 3108630Svbart@nginx.com 3109630Svbart@nginx.com return nxt_sprintf(buf, buf + size, format, 3110630Svbart@nginx.com tm->tm_mday, month[tm->tm_mon], tm->tm_year + 1900, 3111630Svbart@nginx.com tm->tm_hour, tm->tm_min, tm->tm_sec, 3112630Svbart@nginx.com sign, gmtoff / 60, gmtoff % 60); 3113630Svbart@nginx.com } 3114630Svbart@nginx.com 3115630Svbart@nginx.com 3116630Svbart@nginx.com static void 3117630Svbart@nginx.com nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 3118630Svbart@nginx.com { 3119630Svbart@nginx.com uint32_t stream; 3120648Svbart@nginx.com nxt_int_t ret; 3121630Svbart@nginx.com nxt_buf_t *b; 3122630Svbart@nginx.com nxt_port_t *main_port, *router_port; 3123630Svbart@nginx.com nxt_runtime_t *rt; 3124630Svbart@nginx.com nxt_router_access_log_t *access_log; 3125630Svbart@nginx.com 3126630Svbart@nginx.com access_log = tmcf->router_conf->access_log; 3127630Svbart@nginx.com 3128630Svbart@nginx.com b = nxt_buf_mem_alloc(tmcf->mem_pool, access_log->path.length + 1, 0); 3129630Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 3130630Svbart@nginx.com goto fail; 3131630Svbart@nginx.com } 3132630Svbart@nginx.com 3133630Svbart@nginx.com nxt_buf_cpystr(b, &access_log->path); 3134630Svbart@nginx.com *b->mem.free++ = '\0'; 3135630Svbart@nginx.com 3136630Svbart@nginx.com rt = task->thread->runtime; 3137630Svbart@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 3138630Svbart@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 3139630Svbart@nginx.com 3140630Svbart@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 3141630Svbart@nginx.com nxt_router_access_log_ready, 3142630Svbart@nginx.com nxt_router_access_log_error, 3143630Svbart@nginx.com -1, tmcf); 3144630Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 3145630Svbart@nginx.com goto fail; 3146630Svbart@nginx.com } 3147630Svbart@nginx.com 3148648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1, 3149648Svbart@nginx.com stream, router_port->id, b); 3150648Svbart@nginx.com 3151648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 3152648Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 3153648Svbart@nginx.com goto fail; 3154648Svbart@nginx.com } 3155630Svbart@nginx.com 3156630Svbart@nginx.com return; 3157630Svbart@nginx.com 3158630Svbart@nginx.com fail: 3159630Svbart@nginx.com 3160630Svbart@nginx.com nxt_router_conf_error(task, tmcf); 3161630Svbart@nginx.com } 3162630Svbart@nginx.com 3163630Svbart@nginx.com 3164630Svbart@nginx.com static void 3165630Svbart@nginx.com nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3166630Svbart@nginx.com void *data) 3167630Svbart@nginx.com { 3168630Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 3169630Svbart@nginx.com nxt_router_access_log_t *access_log; 3170630Svbart@nginx.com 3171630Svbart@nginx.com tmcf = data; 3172630Svbart@nginx.com 3173630Svbart@nginx.com access_log = tmcf->router_conf->access_log; 3174630Svbart@nginx.com 3175630Svbart@nginx.com access_log->fd = msg->fd; 3176630Svbart@nginx.com 3177630Svbart@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 3178630Svbart@nginx.com nxt_router_conf_apply, task, tmcf, NULL); 3179630Svbart@nginx.com } 3180630Svbart@nginx.com 3181630Svbart@nginx.com 3182630Svbart@nginx.com static void 3183630Svbart@nginx.com nxt_router_access_log_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3184630Svbart@nginx.com void *data) 3185630Svbart@nginx.com { 3186630Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 3187630Svbart@nginx.com 3188630Svbart@nginx.com tmcf = data; 3189630Svbart@nginx.com 3190630Svbart@nginx.com nxt_router_conf_error(task, tmcf); 3191630Svbart@nginx.com } 3192630Svbart@nginx.com 3193630Svbart@nginx.com 3194630Svbart@nginx.com static void 3195630Svbart@nginx.com nxt_router_access_log_release(nxt_task_t *task, nxt_thread_spinlock_t *lock, 3196630Svbart@nginx.com nxt_router_access_log_t *access_log) 3197630Svbart@nginx.com { 3198630Svbart@nginx.com if (access_log == NULL) { 3199630Svbart@nginx.com return; 3200630Svbart@nginx.com } 3201630Svbart@nginx.com 3202630Svbart@nginx.com nxt_thread_spin_lock(lock); 3203630Svbart@nginx.com 3204630Svbart@nginx.com if (--access_log->count != 0) { 3205630Svbart@nginx.com access_log = NULL; 3206630Svbart@nginx.com } 3207630Svbart@nginx.com 3208630Svbart@nginx.com nxt_thread_spin_unlock(lock); 3209630Svbart@nginx.com 3210630Svbart@nginx.com if (access_log != NULL) { 3211630Svbart@nginx.com 3212630Svbart@nginx.com if (access_log->fd != -1) { 3213630Svbart@nginx.com nxt_fd_close(access_log->fd); 3214630Svbart@nginx.com } 3215630Svbart@nginx.com 3216630Svbart@nginx.com nxt_free(access_log); 3217630Svbart@nginx.com } 3218630Svbart@nginx.com } 3219630Svbart@nginx.com 3220630Svbart@nginx.com 3221631Svbart@nginx.com typedef struct { 3222631Svbart@nginx.com nxt_mp_t *mem_pool; 3223631Svbart@nginx.com nxt_router_access_log_t *access_log; 3224631Svbart@nginx.com } nxt_router_access_log_reopen_t; 3225631Svbart@nginx.com 3226631Svbart@nginx.com 3227631Svbart@nginx.com void 3228631Svbart@nginx.com nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 3229631Svbart@nginx.com { 3230631Svbart@nginx.com nxt_mp_t *mp; 3231631Svbart@nginx.com uint32_t stream; 3232631Svbart@nginx.com nxt_int_t ret; 3233631Svbart@nginx.com nxt_buf_t *b; 3234631Svbart@nginx.com nxt_port_t *main_port, *router_port; 3235631Svbart@nginx.com nxt_runtime_t *rt; 3236631Svbart@nginx.com nxt_router_access_log_t *access_log; 3237631Svbart@nginx.com nxt_router_access_log_reopen_t *reopen; 3238631Svbart@nginx.com 3239631Svbart@nginx.com access_log = nxt_router->access_log; 3240631Svbart@nginx.com 3241631Svbart@nginx.com if (access_log == NULL) { 3242631Svbart@nginx.com return; 3243631Svbart@nginx.com } 3244631Svbart@nginx.com 3245631Svbart@nginx.com mp = nxt_mp_create(1024, 128, 256, 32); 3246631Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 3247631Svbart@nginx.com return; 3248631Svbart@nginx.com } 3249631Svbart@nginx.com 3250631Svbart@nginx.com reopen = nxt_mp_get(mp, sizeof(nxt_router_access_log_reopen_t)); 3251631Svbart@nginx.com if (nxt_slow_path(reopen == NULL)) { 3252631Svbart@nginx.com goto fail; 3253631Svbart@nginx.com } 3254631Svbart@nginx.com 3255631Svbart@nginx.com reopen->mem_pool = mp; 3256631Svbart@nginx.com reopen->access_log = access_log; 3257631Svbart@nginx.com 3258631Svbart@nginx.com b = nxt_buf_mem_alloc(mp, access_log->path.length + 1, 0); 3259631Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 3260631Svbart@nginx.com goto fail; 3261631Svbart@nginx.com } 3262631Svbart@nginx.com 3263651Svbart@nginx.com b->completion_handler = nxt_router_access_log_reopen_completion; 3264651Svbart@nginx.com 3265631Svbart@nginx.com nxt_buf_cpystr(b, &access_log->path); 3266631Svbart@nginx.com *b->mem.free++ = '\0'; 3267631Svbart@nginx.com 3268631Svbart@nginx.com rt = task->thread->runtime; 3269631Svbart@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 3270631Svbart@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 3271631Svbart@nginx.com 3272631Svbart@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 3273631Svbart@nginx.com nxt_router_access_log_reopen_ready, 3274631Svbart@nginx.com nxt_router_access_log_reopen_error, 3275631Svbart@nginx.com -1, reopen); 3276631Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 3277631Svbart@nginx.com goto fail; 3278631Svbart@nginx.com } 3279631Svbart@nginx.com 3280631Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1, 3281631Svbart@nginx.com stream, router_port->id, b); 3282631Svbart@nginx.com 3283631Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 3284631Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 3285631Svbart@nginx.com goto fail; 3286631Svbart@nginx.com } 3287631Svbart@nginx.com 3288651Svbart@nginx.com nxt_mp_retain(mp); 3289651Svbart@nginx.com 3290631Svbart@nginx.com return; 3291631Svbart@nginx.com 3292631Svbart@nginx.com fail: 3293631Svbart@nginx.com 3294631Svbart@nginx.com nxt_mp_destroy(mp); 3295631Svbart@nginx.com } 3296631Svbart@nginx.com 3297631Svbart@nginx.com 3298631Svbart@nginx.com static void 3299651Svbart@nginx.com nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, void *data) 3300651Svbart@nginx.com { 3301651Svbart@nginx.com nxt_mp_t *mp; 3302651Svbart@nginx.com nxt_buf_t *b; 3303651Svbart@nginx.com 3304651Svbart@nginx.com b = obj; 3305651Svbart@nginx.com mp = b->data; 3306651Svbart@nginx.com 3307651Svbart@nginx.com nxt_mp_release(mp); 3308651Svbart@nginx.com } 3309651Svbart@nginx.com 3310651Svbart@nginx.com 3311651Svbart@nginx.com static void 3312631Svbart@nginx.com nxt_router_access_log_reopen_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3313631Svbart@nginx.com void *data) 3314631Svbart@nginx.com { 3315631Svbart@nginx.com nxt_router_access_log_t *access_log; 3316631Svbart@nginx.com nxt_router_access_log_reopen_t *reopen; 3317631Svbart@nginx.com 3318631Svbart@nginx.com reopen = data; 3319631Svbart@nginx.com 3320631Svbart@nginx.com access_log = reopen->access_log; 3321631Svbart@nginx.com 3322631Svbart@nginx.com if (access_log == nxt_router->access_log) { 3323631Svbart@nginx.com 3324631Svbart@nginx.com if (nxt_slow_path(dup2(msg->fd, access_log->fd) == -1)) { 3325631Svbart@nginx.com nxt_alert(task, "dup2(%FD, %FD) failed %E", 3326631Svbart@nginx.com msg->fd, access_log->fd, nxt_errno); 3327631Svbart@nginx.com } 3328631Svbart@nginx.com } 3329631Svbart@nginx.com 3330631Svbart@nginx.com nxt_fd_close(msg->fd); 3331651Svbart@nginx.com nxt_mp_release(reopen->mem_pool); 3332631Svbart@nginx.com } 3333631Svbart@nginx.com 3334631Svbart@nginx.com 3335631Svbart@nginx.com static void 3336631Svbart@nginx.com nxt_router_access_log_reopen_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3337631Svbart@nginx.com void *data) 3338631Svbart@nginx.com { 3339631Svbart@nginx.com nxt_router_access_log_reopen_t *reopen; 3340631Svbart@nginx.com 3341631Svbart@nginx.com reopen = data; 3342631Svbart@nginx.com 3343651Svbart@nginx.com nxt_mp_release(reopen->mem_pool); 3344631Svbart@nginx.com } 3345631Svbart@nginx.com 3346631Svbart@nginx.com 3347630Svbart@nginx.com static void 334853Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data) 334953Sigor@sysoev.ru { 3350141Smax.romanov@nginx.com nxt_port_t *port; 335153Sigor@sysoev.ru nxt_thread_link_t *link; 335253Sigor@sysoev.ru nxt_event_engine_t *engine; 335353Sigor@sysoev.ru nxt_thread_handle_t handle; 335453Sigor@sysoev.ru 335558Svbart@nginx.com handle = (nxt_thread_handle_t) obj; 335653Sigor@sysoev.ru link = data; 335753Sigor@sysoev.ru 335853Sigor@sysoev.ru nxt_thread_wait(handle); 335953Sigor@sysoev.ru 336053Sigor@sysoev.ru engine = link->engine; 336153Sigor@sysoev.ru 336253Sigor@sysoev.ru nxt_queue_remove(&engine->link); 336353Sigor@sysoev.ru 3364141Smax.romanov@nginx.com port = engine->port; 3365141Smax.romanov@nginx.com 3366141Smax.romanov@nginx.com // TODO notify all apps 3367141Smax.romanov@nginx.com 3368343Smax.romanov@nginx.com port->engine = task->thread->engine; 3369163Smax.romanov@nginx.com nxt_mp_thread_adopt(port->mem_pool); 3370343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3371163Smax.romanov@nginx.com 3372163Smax.romanov@nginx.com nxt_mp_thread_adopt(engine->mem_pool); 337363Sigor@sysoev.ru nxt_mp_destroy(engine->mem_pool); 337453Sigor@sysoev.ru 337553Sigor@sysoev.ru nxt_event_engine_free(engine); 337653Sigor@sysoev.ru 337753Sigor@sysoev.ru nxt_free(link); 337853Sigor@sysoev.ru } 337953Sigor@sysoev.ru 338053Sigor@sysoev.ru 338153Sigor@sysoev.ru static void 3382318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3383318Smax.romanov@nginx.com void *data) 338488Smax.romanov@nginx.com { 338588Smax.romanov@nginx.com size_t dump_size; 3386431Sigor@sysoev.ru nxt_int_t ret; 3387608Sigor@sysoev.ru nxt_buf_t *b; 3388*1007Salexander.borisov@nginx.com nxt_unit_field_t *f; 3389*1007Salexander.borisov@nginx.com nxt_http_field_t *field; 3390431Sigor@sysoev.ru nxt_http_request_t *r; 339188Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 3392743Smax.romanov@nginx.com nxt_unit_response_t *resp; 339388Smax.romanov@nginx.com 339488Smax.romanov@nginx.com b = msg->buf; 3395318Smax.romanov@nginx.com rc = data; 339688Smax.romanov@nginx.com 339788Smax.romanov@nginx.com dump_size = nxt_buf_used_size(b); 339888Smax.romanov@nginx.com 339988Smax.romanov@nginx.com if (dump_size > 300) { 340088Smax.romanov@nginx.com dump_size = 300; 340188Smax.romanov@nginx.com } 340288Smax.romanov@nginx.com 340388Smax.romanov@nginx.com if (msg->size == 0) { 340488Smax.romanov@nginx.com b = NULL; 340588Smax.romanov@nginx.com } 340688Smax.romanov@nginx.com 3407*1007Salexander.borisov@nginx.com r = rc->request; 3408*1007Salexander.borisov@nginx.com if (nxt_slow_path(r == NULL)) { 3409570Smax.romanov@nginx.com return; 3410570Smax.romanov@nginx.com } 3411425Smax.romanov@nginx.com 3412*1007Salexander.borisov@nginx.com if (r->error) { 3413608Sigor@sysoev.ru nxt_router_rc_unlink(task, rc); 3414608Sigor@sysoev.ru return; 3415608Sigor@sysoev.ru } 3416608Sigor@sysoev.ru 341788Smax.romanov@nginx.com if (msg->port_msg.last != 0) { 341888Smax.romanov@nginx.com nxt_debug(task, "router data create last buf"); 341988Smax.romanov@nginx.com 3420*1007Salexander.borisov@nginx.com nxt_buf_chain_add(&b, nxt_http_buf_last(r)); 3421167Smax.romanov@nginx.com 3422343Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 3423425Smax.romanov@nginx.com 3424425Smax.romanov@nginx.com } else { 3425615Smax.romanov@nginx.com if (rc->app != NULL && rc->app->timeout != 0) { 3426*1007Salexander.borisov@nginx.com r->timer.handler = nxt_router_app_timeout; 3427*1007Salexander.borisov@nginx.com r->timer_data = rc; 3428*1007Salexander.borisov@nginx.com nxt_timer_add(task->thread->engine, &r->timer, rc->app->timeout); 3429425Smax.romanov@nginx.com } 343088Smax.romanov@nginx.com } 343188Smax.romanov@nginx.com 343288Smax.romanov@nginx.com if (b == NULL) { 343388Smax.romanov@nginx.com return; 343488Smax.romanov@nginx.com } 343588Smax.romanov@nginx.com 3436206Smax.romanov@nginx.com if (msg->buf == b) { 3437206Smax.romanov@nginx.com /* Disable instant buffer completion/re-using by port. */ 3438206Smax.romanov@nginx.com msg->buf = NULL; 3439206Smax.romanov@nginx.com } 3440194Smax.romanov@nginx.com 3441431Sigor@sysoev.ru if (r->header_sent) { 3442431Sigor@sysoev.ru nxt_buf_chain_add(&r->out, b); 3443431Sigor@sysoev.ru nxt_http_request_send_body(task, r, NULL); 3444277Sigor@sysoev.ru 344588Smax.romanov@nginx.com } else { 3446743Smax.romanov@nginx.com size_t b_size = nxt_buf_mem_used_size(&b->mem); 3447743Smax.romanov@nginx.com 3448743Smax.romanov@nginx.com if (nxt_slow_path(b_size < sizeof(*resp))) { 3449743Smax.romanov@nginx.com goto fail; 3450743Smax.romanov@nginx.com } 3451743Smax.romanov@nginx.com 3452743Smax.romanov@nginx.com resp = (void *) b->mem.pos; 3453743Smax.romanov@nginx.com if (nxt_slow_path(b_size < sizeof(*resp) 3454743Smax.romanov@nginx.com + resp->fields_count * sizeof(nxt_unit_field_t))) { 3455743Smax.romanov@nginx.com goto fail; 3456743Smax.romanov@nginx.com } 3457743Smax.romanov@nginx.com 3458743Smax.romanov@nginx.com for (f = resp->fields; f < resp->fields + resp->fields_count; f++) { 3459*1007Salexander.borisov@nginx.com field = nxt_list_add(r->resp.fields); 3460743Smax.romanov@nginx.com 3461743Smax.romanov@nginx.com if (nxt_slow_path(field == NULL)) { 3462743Smax.romanov@nginx.com goto fail; 3463743Smax.romanov@nginx.com } 3464743Smax.romanov@nginx.com 3465743Smax.romanov@nginx.com field->hash = f->hash; 3466743Smax.romanov@nginx.com field->skip = f->skip; 3467743Smax.romanov@nginx.com 3468743Smax.romanov@nginx.com field->name_length = f->name_length; 3469743Smax.romanov@nginx.com field->value_length = f->value_length; 3470743Smax.romanov@nginx.com field->name = nxt_unit_sptr_get(&f->name); 3471743Smax.romanov@nginx.com field->value = nxt_unit_sptr_get(&f->value); 3472743Smax.romanov@nginx.com 3473743Smax.romanov@nginx.com nxt_debug(task, "header: %*s: %*s", 3474743Smax.romanov@nginx.com (size_t) field->name_length, field->name, 3475743Smax.romanov@nginx.com (size_t) field->value_length, field->value); 3476743Smax.romanov@nginx.com } 3477*1007Salexander.borisov@nginx.com 3478743Smax.romanov@nginx.com r->status = resp->status; 3479743Smax.romanov@nginx.com 3480431Sigor@sysoev.ru ret = nxt_http_fields_process(r->resp.fields, 3481431Sigor@sysoev.ru &nxt_response_fields_hash, r); 3482431Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 3483431Sigor@sysoev.ru goto fail; 3484431Sigor@sysoev.ru } 3485431Sigor@sysoev.ru 3486743Smax.romanov@nginx.com if (resp->piggyback_content_length != 0) { 3487743Smax.romanov@nginx.com b->mem.pos = nxt_unit_sptr_get(&resp->piggyback_content); 3488743Smax.romanov@nginx.com b->mem.free = b->mem.pos + resp->piggyback_content_length; 3489743Smax.romanov@nginx.com 3490743Smax.romanov@nginx.com } else { 3491743Smax.romanov@nginx.com b->mem.pos = b->mem.free; 3492743Smax.romanov@nginx.com } 3493743Smax.romanov@nginx.com 3494435Sigor@sysoev.ru if (nxt_buf_mem_used_size(&b->mem) == 0) { 3495435Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 3496435Sigor@sysoev.ru b->completion_handler, task, b, b->parent); 3497507Smax.romanov@nginx.com 3498520Smax.romanov@nginx.com b = b->next; 3499520Smax.romanov@nginx.com } 3500520Smax.romanov@nginx.com 3501520Smax.romanov@nginx.com if (b != NULL) { 3502431Sigor@sysoev.ru nxt_buf_chain_add(&r->out, b); 3503431Sigor@sysoev.ru } 3504431Sigor@sysoev.ru 3505431Sigor@sysoev.ru r->state = &nxt_http_request_send_state; 3506431Sigor@sysoev.ru 3507431Sigor@sysoev.ru nxt_http_request_header_send(task, r); 3508431Sigor@sysoev.ru } 3509431Sigor@sysoev.ru 3510431Sigor@sysoev.ru return; 3511431Sigor@sysoev.ru 3512431Sigor@sysoev.ru fail: 3513431Sigor@sysoev.ru 3514615Smax.romanov@nginx.com nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE); 3515615Smax.romanov@nginx.com 3516431Sigor@sysoev.ru nxt_router_rc_unlink(task, rc); 3517431Sigor@sysoev.ru } 3518431Sigor@sysoev.ru 3519431Sigor@sysoev.ru 3520431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_send_state 3521431Sigor@sysoev.ru nxt_aligned(64) = 3522431Sigor@sysoev.ru { 3523431Sigor@sysoev.ru .ready_handler = nxt_http_request_send_body, 3524943Sigor@sysoev.ru .error_handler = nxt_http_request_error_handler, 3525431Sigor@sysoev.ru }; 3526431Sigor@sysoev.ru 3527431Sigor@sysoev.ru 3528431Sigor@sysoev.ru static void 3529431Sigor@sysoev.ru nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data) 3530431Sigor@sysoev.ru { 3531431Sigor@sysoev.ru nxt_buf_t *out; 3532431Sigor@sysoev.ru nxt_http_request_t *r; 3533431Sigor@sysoev.ru 3534431Sigor@sysoev.ru r = obj; 3535431Sigor@sysoev.ru 3536431Sigor@sysoev.ru out = r->out; 3537431Sigor@sysoev.ru 3538431Sigor@sysoev.ru if (out != NULL) { 3539431Sigor@sysoev.ru r->out = NULL; 3540431Sigor@sysoev.ru nxt_http_request_send(task, r, out); 354188Smax.romanov@nginx.com } 354288Smax.romanov@nginx.com } 354388Smax.romanov@nginx.com 3544277Sigor@sysoev.ru 3545318Smax.romanov@nginx.com static void 3546318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3547318Smax.romanov@nginx.com void *data) 3548318Smax.romanov@nginx.com { 3549425Smax.romanov@nginx.com nxt_int_t res; 3550425Smax.romanov@nginx.com nxt_port_t *port; 3551425Smax.romanov@nginx.com nxt_bool_t cancelled; 3552425Smax.romanov@nginx.com nxt_req_app_link_t *ra; 3553318Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 3554318Smax.romanov@nginx.com 3555318Smax.romanov@nginx.com rc = data; 3556318Smax.romanov@nginx.com 3557425Smax.romanov@nginx.com ra = rc->ra; 3558425Smax.romanov@nginx.com 3559425Smax.romanov@nginx.com if (ra != NULL) { 3560425Smax.romanov@nginx.com cancelled = nxt_router_msg_cancel(task, &ra->msg_info, ra->stream); 3561425Smax.romanov@nginx.com 3562425Smax.romanov@nginx.com if (cancelled) { 3563425Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 3564425Smax.romanov@nginx.com 3565427Smax.romanov@nginx.com res = nxt_router_app_port(task, rc->app, ra); 3566425Smax.romanov@nginx.com 3567425Smax.romanov@nginx.com if (res == NXT_OK) { 3568425Smax.romanov@nginx.com port = ra->app_port; 3569425Smax.romanov@nginx.com 3570551Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 3571551Smax.romanov@nginx.com nxt_log(task, NXT_LOG_ERR, "port is NULL in cancelled ra"); 3572551Smax.romanov@nginx.com return; 3573551Smax.romanov@nginx.com } 3574425Smax.romanov@nginx.com 3575425Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, task->thread->engine->port, rc, 3576425Smax.romanov@nginx.com port->pid); 3577425Smax.romanov@nginx.com 3578425Smax.romanov@nginx.com nxt_router_app_prepare_request(task, ra); 3579425Smax.romanov@nginx.com } 3580425Smax.romanov@nginx.com 3581425Smax.romanov@nginx.com msg->port_msg.last = 0; 3582425Smax.romanov@nginx.com 3583425Smax.romanov@nginx.com return; 3584425Smax.romanov@nginx.com } 3585425Smax.romanov@nginx.com } 3586425Smax.romanov@nginx.com 3587*1007Salexander.borisov@nginx.com if (rc->request != NULL) { 3588*1007Salexander.borisov@nginx.com nxt_http_request_error(task, rc->request, 3589616Smax.romanov@nginx.com NXT_HTTP_SERVICE_UNAVAILABLE); 3590616Smax.romanov@nginx.com } 3591318Smax.romanov@nginx.com 3592343Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 3593318Smax.romanov@nginx.com } 3594318Smax.romanov@nginx.com 3595318Smax.romanov@nginx.com 3596141Smax.romanov@nginx.com static void 3597343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3598343Smax.romanov@nginx.com void *data) 3599192Smax.romanov@nginx.com { 3600753Smax.romanov@nginx.com nxt_app_t *app; 3601753Smax.romanov@nginx.com nxt_port_t *port; 3602753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 3603753Smax.romanov@nginx.com 3604753Smax.romanov@nginx.com app_joint = data; 3605347Smax.romanov@nginx.com port = msg->u.new_port; 3606343Smax.romanov@nginx.com 3607753Smax.romanov@nginx.com nxt_assert(app_joint != NULL); 3608343Smax.romanov@nginx.com nxt_assert(port != NULL); 3609343Smax.romanov@nginx.com 3610753Smax.romanov@nginx.com app = app_joint->app; 3611753Smax.romanov@nginx.com 3612753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 3613753Smax.romanov@nginx.com 3614753Smax.romanov@nginx.com if (nxt_slow_path(app == NULL)) { 3615753Smax.romanov@nginx.com nxt_debug(task, "new port ready for released app, send QUIT"); 3616753Smax.romanov@nginx.com 3617753Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 3618753Smax.romanov@nginx.com 3619753Smax.romanov@nginx.com return; 3620753Smax.romanov@nginx.com } 3621753Smax.romanov@nginx.com 3622343Smax.romanov@nginx.com port->app = app; 3623343Smax.romanov@nginx.com 3624343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3625343Smax.romanov@nginx.com 3626507Smax.romanov@nginx.com nxt_assert(app->pending_processes != 0); 3627507Smax.romanov@nginx.com 3628507Smax.romanov@nginx.com app->pending_processes--; 3629507Smax.romanov@nginx.com app->processes++; 3630343Smax.romanov@nginx.com 3631343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3632343Smax.romanov@nginx.com 3633507Smax.romanov@nginx.com nxt_debug(task, "app '%V' new port ready, pid %PI, %d/%d", 3634507Smax.romanov@nginx.com &app->name, port->pid, app->processes, app->pending_processes); 3635343Smax.romanov@nginx.com 3636343Smax.romanov@nginx.com nxt_router_app_port_release(task, port, 0, 0); 3637192Smax.romanov@nginx.com } 3638192Smax.romanov@nginx.com 3639192Smax.romanov@nginx.com 3640192Smax.romanov@nginx.com static void 3641343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3642343Smax.romanov@nginx.com void *data) 3643192Smax.romanov@nginx.com { 3644318Smax.romanov@nginx.com nxt_app_t *app; 3645753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 3646318Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3647318Smax.romanov@nginx.com nxt_req_app_link_t *ra; 3648343Smax.romanov@nginx.com 3649753Smax.romanov@nginx.com app_joint = data; 3650753Smax.romanov@nginx.com 3651753Smax.romanov@nginx.com nxt_assert(app_joint != NULL); 3652753Smax.romanov@nginx.com 3653753Smax.romanov@nginx.com app = app_joint->app; 3654753Smax.romanov@nginx.com 3655753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 3656753Smax.romanov@nginx.com 3657753Smax.romanov@nginx.com if (nxt_slow_path(app == NULL)) { 3658753Smax.romanov@nginx.com nxt_debug(task, "start error for released app"); 3659753Smax.romanov@nginx.com 3660753Smax.romanov@nginx.com return; 3661753Smax.romanov@nginx.com } 3662343Smax.romanov@nginx.com 3663343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start error", &app->name, app); 3664343Smax.romanov@nginx.com 3665343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3666343Smax.romanov@nginx.com 3667507Smax.romanov@nginx.com nxt_assert(app->pending_processes != 0); 3668507Smax.romanov@nginx.com 3669507Smax.romanov@nginx.com app->pending_processes--; 3670318Smax.romanov@nginx.com 3671318Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->requests)) { 3672318Smax.romanov@nginx.com lnk = nxt_queue_last(&app->requests); 3673318Smax.romanov@nginx.com nxt_queue_remove(lnk); 3674343Smax.romanov@nginx.com lnk->next = NULL; 3675318Smax.romanov@nginx.com 3676425Smax.romanov@nginx.com ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_requests); 3677318Smax.romanov@nginx.com 3678343Smax.romanov@nginx.com } else { 3679343Smax.romanov@nginx.com ra = NULL; 3680343Smax.romanov@nginx.com } 3681343Smax.romanov@nginx.com 3682343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3683343Smax.romanov@nginx.com 3684343Smax.romanov@nginx.com if (ra != NULL) { 3685318Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p abort next stream #%uD", 3686318Smax.romanov@nginx.com &app->name, app, ra->stream); 3687318Smax.romanov@nginx.com 3688507Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, "Failed to start application process"); 3689425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 3690318Smax.romanov@nginx.com } 3691192Smax.romanov@nginx.com } 3692192Smax.romanov@nginx.com 3693753Smax.romanov@nginx.com nxt_inline nxt_port_t * 3694753Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app); 3695192Smax.romanov@nginx.com 3696343Smax.romanov@nginx.com void 3697343Smax.romanov@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i) 3698141Smax.romanov@nginx.com { 3699343Smax.romanov@nginx.com int c; 3700343Smax.romanov@nginx.com 3701343Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&app->use_count, i); 3702343Smax.romanov@nginx.com 3703343Smax.romanov@nginx.com if (i < 0 && c == -i) { 3704343Smax.romanov@nginx.com 3705753Smax.romanov@nginx.com if (task->thread->engine != app->engine) { 3706753Smax.romanov@nginx.com nxt_event_engine_post(app->engine, &app->joint->free_app_work); 3707753Smax.romanov@nginx.com 3708753Smax.romanov@nginx.com } else { 3709753Smax.romanov@nginx.com nxt_router_free_app(task, app->joint, NULL); 3710753Smax.romanov@nginx.com } 3711163Smax.romanov@nginx.com } 3712343Smax.romanov@nginx.com } 3713343Smax.romanov@nginx.com 3714343Smax.romanov@nginx.com 3715424Smax.romanov@nginx.com nxt_inline nxt_bool_t 3716424Smax.romanov@nginx.com nxt_router_app_first_port_busy(nxt_app_t *app) 3717424Smax.romanov@nginx.com { 3718424Smax.romanov@nginx.com nxt_port_t *port; 3719424Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3720424Smax.romanov@nginx.com 3721424Smax.romanov@nginx.com lnk = nxt_queue_first(&app->ports); 3722424Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, app_link); 3723424Smax.romanov@nginx.com 3724424Smax.romanov@nginx.com return port->app_pending_responses > 0; 3725424Smax.romanov@nginx.com } 3726424Smax.romanov@nginx.com 3727424Smax.romanov@nginx.com 3728343Smax.romanov@nginx.com nxt_inline nxt_port_t * 3729427Smax.romanov@nginx.com nxt_router_pop_first_port(nxt_app_t *app) 3730343Smax.romanov@nginx.com { 3731343Smax.romanov@nginx.com nxt_port_t *port; 3732343Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3733343Smax.romanov@nginx.com 3734343Smax.romanov@nginx.com lnk = nxt_queue_first(&app->ports); 3735343Smax.romanov@nginx.com nxt_queue_remove(lnk); 3736343Smax.romanov@nginx.com 3737343Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, app_link); 3738343Smax.romanov@nginx.com 3739424Smax.romanov@nginx.com port->app_pending_responses++; 3740424Smax.romanov@nginx.com 3741507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 3742507Smax.romanov@nginx.com app->idle_processes--; 3743507Smax.romanov@nginx.com 3744507Smax.romanov@nginx.com if (port->idle_start == 0) { 3745507Smax.romanov@nginx.com nxt_assert(app->idle_processes < app->spare_processes); 3746507Smax.romanov@nginx.com 3747507Smax.romanov@nginx.com } else { 3748507Smax.romanov@nginx.com nxt_assert(app->idle_processes >= app->spare_processes); 3749507Smax.romanov@nginx.com 3750507Smax.romanov@nginx.com port->idle_start = 0; 3751507Smax.romanov@nginx.com } 3752507Smax.romanov@nginx.com } 3753507Smax.romanov@nginx.com 3754428Smax.romanov@nginx.com if ((app->max_pending_responses == 0 3755428Smax.romanov@nginx.com || port->app_pending_responses < app->max_pending_responses) 3756428Smax.romanov@nginx.com && (app->max_requests == 0 3757428Smax.romanov@nginx.com || port->app_responses + port->app_pending_responses 3758428Smax.romanov@nginx.com < app->max_requests)) 3759277Sigor@sysoev.ru { 3760343Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, lnk); 3761343Smax.romanov@nginx.com 3762425Smax.romanov@nginx.com nxt_port_inc_use(port); 3763425Smax.romanov@nginx.com 3764343Smax.romanov@nginx.com } else { 3765343Smax.romanov@nginx.com lnk->next = NULL; 3766167Smax.romanov@nginx.com } 3767167Smax.romanov@nginx.com 3768343Smax.romanov@nginx.com return port; 3769163Smax.romanov@nginx.com } 3770163Smax.romanov@nginx.com 3771163Smax.romanov@nginx.com 3772507Smax.romanov@nginx.com nxt_inline nxt_port_t * 3773507Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app) 3774141Smax.romanov@nginx.com { 3775343Smax.romanov@nginx.com nxt_port_t *port; 3776141Smax.romanov@nginx.com 3777141Smax.romanov@nginx.com port = NULL; 3778141Smax.romanov@nginx.com 3779141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3780141Smax.romanov@nginx.com 3781343Smax.romanov@nginx.com nxt_queue_each(port, &app->ports, nxt_port_t, app_link) { 3782343Smax.romanov@nginx.com 3783424Smax.romanov@nginx.com if (port->app_pending_responses > 0) { 3784343Smax.romanov@nginx.com port = NULL; 3785343Smax.romanov@nginx.com 3786343Smax.romanov@nginx.com continue; 3787343Smax.romanov@nginx.com } 3788343Smax.romanov@nginx.com 3789507Smax.romanov@nginx.com /* Caller is responsible to decrease port use count. */ 3790507Smax.romanov@nginx.com nxt_queue_chk_remove(&port->app_link); 3791507Smax.romanov@nginx.com 3792507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 3793507Smax.romanov@nginx.com app->idle_processes--; 3794507Smax.romanov@nginx.com } 3795507Smax.romanov@nginx.com 3796507Smax.romanov@nginx.com port->app = NULL; 3797507Smax.romanov@nginx.com app->processes--; 3798343Smax.romanov@nginx.com 3799343Smax.romanov@nginx.com break; 3800343Smax.romanov@nginx.com 3801343Smax.romanov@nginx.com } nxt_queue_loop; 3802141Smax.romanov@nginx.com 3803141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3804141Smax.romanov@nginx.com 3805141Smax.romanov@nginx.com return port; 3806141Smax.romanov@nginx.com } 3807141Smax.romanov@nginx.com 3808141Smax.romanov@nginx.com 3809141Smax.romanov@nginx.com static void 3810753Smax.romanov@nginx.com nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app) 3811507Smax.romanov@nginx.com { 3812753Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p unlink", &app->name, app); 3813507Smax.romanov@nginx.com 3814507Smax.romanov@nginx.com nxt_queue_remove(&app->link); 3815507Smax.romanov@nginx.com 3816753Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 3817507Smax.romanov@nginx.com } 3818507Smax.romanov@nginx.com 3819507Smax.romanov@nginx.com 3820507Smax.romanov@nginx.com static void 3821343Smax.romanov@nginx.com nxt_router_app_process_request(nxt_task_t *task, void *obj, void *data) 3822141Smax.romanov@nginx.com { 3823343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 3824343Smax.romanov@nginx.com 3825538Svbart@nginx.com ra = data; 3826538Svbart@nginx.com 3827538Svbart@nginx.com #if (NXT_DEBUG) 3828538Svbart@nginx.com { 3829538Svbart@nginx.com nxt_app_t *app; 3830538Svbart@nginx.com 3831343Smax.romanov@nginx.com app = obj; 3832141Smax.romanov@nginx.com 3833141Smax.romanov@nginx.com nxt_assert(app != NULL); 3834343Smax.romanov@nginx.com nxt_assert(ra != NULL); 3835343Smax.romanov@nginx.com nxt_assert(ra->app_port != NULL); 3836343Smax.romanov@nginx.com 3837343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p process next stream #%uD", 3838343Smax.romanov@nginx.com &app->name, app, ra->stream); 3839538Svbart@nginx.com } 3840538Svbart@nginx.com #endif 3841343Smax.romanov@nginx.com 3842425Smax.romanov@nginx.com nxt_router_app_prepare_request(task, ra); 3843343Smax.romanov@nginx.com } 3844343Smax.romanov@nginx.com 3845343Smax.romanov@nginx.com 3846343Smax.romanov@nginx.com static void 3847343Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port, 3848343Smax.romanov@nginx.com uint32_t request_failed, uint32_t got_response) 3849343Smax.romanov@nginx.com { 3850427Smax.romanov@nginx.com nxt_app_t *app; 3851507Smax.romanov@nginx.com nxt_bool_t port_unchained; 3852507Smax.romanov@nginx.com nxt_bool_t send_quit, cancelled, adjust_idle_timer; 3853427Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3854427Smax.romanov@nginx.com nxt_req_app_link_t *ra, *pending_ra, *re_ra; 3855427Smax.romanov@nginx.com nxt_port_select_state_t state; 3856343Smax.romanov@nginx.com 3857343Smax.romanov@nginx.com nxt_assert(port != NULL); 3858343Smax.romanov@nginx.com nxt_assert(port->app != NULL); 3859343Smax.romanov@nginx.com 3860427Smax.romanov@nginx.com ra = NULL; 3861427Smax.romanov@nginx.com 3862343Smax.romanov@nginx.com app = port->app; 3863343Smax.romanov@nginx.com 3864343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3865343Smax.romanov@nginx.com 3866424Smax.romanov@nginx.com port->app_pending_responses -= request_failed + got_response; 3867343Smax.romanov@nginx.com port->app_responses += got_response; 3868343Smax.romanov@nginx.com 3869427Smax.romanov@nginx.com if (port->pair[1] != -1 3870426Smax.romanov@nginx.com && (app->max_pending_responses == 0 3871428Smax.romanov@nginx.com || port->app_pending_responses < app->max_pending_responses) 3872428Smax.romanov@nginx.com && (app->max_requests == 0 3873428Smax.romanov@nginx.com || port->app_responses + port->app_pending_responses 3874428Smax.romanov@nginx.com < app->max_requests)) 3875343Smax.romanov@nginx.com { 3876424Smax.romanov@nginx.com if (port->app_link.next == NULL) { 3877424Smax.romanov@nginx.com if (port->app_pending_responses > 0) { 3878424Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &port->app_link); 3879424Smax.romanov@nginx.com 3880424Smax.romanov@nginx.com } else { 3881424Smax.romanov@nginx.com nxt_queue_insert_head(&app->ports, &port->app_link); 3882424Smax.romanov@nginx.com } 3883424Smax.romanov@nginx.com 3884425Smax.romanov@nginx.com nxt_port_inc_use(port); 3885424Smax.romanov@nginx.com 3886424Smax.romanov@nginx.com } else { 3887424Smax.romanov@nginx.com if (port->app_pending_responses == 0 3888424Smax.romanov@nginx.com && nxt_queue_first(&app->ports) != &port->app_link) 3889424Smax.romanov@nginx.com { 3890424Smax.romanov@nginx.com nxt_queue_remove(&port->app_link); 3891424Smax.romanov@nginx.com nxt_queue_insert_head(&app->ports, &port->app_link); 3892424Smax.romanov@nginx.com } 3893424Smax.romanov@nginx.com } 3894141Smax.romanov@nginx.com } 3895141Smax.romanov@nginx.com 3896427Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->ports) 3897426Smax.romanov@nginx.com && !nxt_queue_is_empty(&app->requests)) 3898343Smax.romanov@nginx.com { 3899141Smax.romanov@nginx.com lnk = nxt_queue_first(&app->requests); 3900141Smax.romanov@nginx.com nxt_queue_remove(lnk); 3901343Smax.romanov@nginx.com lnk->next = NULL; 3902141Smax.romanov@nginx.com 3903425Smax.romanov@nginx.com ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_requests); 3904425Smax.romanov@nginx.com 3905427Smax.romanov@nginx.com ra->app_port = nxt_router_pop_first_port(app); 3906425Smax.romanov@nginx.com 3907425Smax.romanov@nginx.com if (ra->app_port->app_pending_responses > 1) { 3908427Smax.romanov@nginx.com nxt_router_ra_pending(task, app, ra); 3909425Smax.romanov@nginx.com } 3910425Smax.romanov@nginx.com } 3911425Smax.romanov@nginx.com 3912427Smax.romanov@nginx.com /* Pop first pending request for this port. */ 3913425Smax.romanov@nginx.com if ((request_failed > 0 || got_response > 0) 3914425Smax.romanov@nginx.com && !nxt_queue_is_empty(&port->pending_requests)) 3915425Smax.romanov@nginx.com { 3916425Smax.romanov@nginx.com lnk = nxt_queue_first(&port->pending_requests); 3917425Smax.romanov@nginx.com nxt_queue_remove(lnk); 3918425Smax.romanov@nginx.com lnk->next = NULL; 3919425Smax.romanov@nginx.com 3920427Smax.romanov@nginx.com pending_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, 3921427Smax.romanov@nginx.com link_port_pending); 3922427Smax.romanov@nginx.com 3923427Smax.romanov@nginx.com nxt_assert(pending_ra->link_app_pending.next != NULL); 3924427Smax.romanov@nginx.com 3925427Smax.romanov@nginx.com nxt_queue_remove(&pending_ra->link_app_pending); 3926427Smax.romanov@nginx.com pending_ra->link_app_pending.next = NULL; 3927425Smax.romanov@nginx.com 3928425Smax.romanov@nginx.com } else { 3929427Smax.romanov@nginx.com pending_ra = NULL; 3930141Smax.romanov@nginx.com } 3931141Smax.romanov@nginx.com 3932427Smax.romanov@nginx.com /* Try to cancel and re-schedule first stalled request for this app. */ 3933427Smax.romanov@nginx.com if (got_response > 0 && !nxt_queue_is_empty(&app->pending)) { 3934427Smax.romanov@nginx.com lnk = nxt_queue_first(&app->pending); 3935427Smax.romanov@nginx.com 3936427Smax.romanov@nginx.com re_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_pending); 3937427Smax.romanov@nginx.com 3938427Smax.romanov@nginx.com if (re_ra->res_time <= nxt_thread_monotonic_time(task->thread)) { 3939427Smax.romanov@nginx.com 3940427Smax.romanov@nginx.com nxt_debug(task, "app '%V' stalled request #%uD detected", 3941427Smax.romanov@nginx.com &app->name, re_ra->stream); 3942427Smax.romanov@nginx.com 3943427Smax.romanov@nginx.com cancelled = nxt_router_msg_cancel(task, &re_ra->msg_info, 3944427Smax.romanov@nginx.com re_ra->stream); 3945427Smax.romanov@nginx.com 3946427Smax.romanov@nginx.com if (cancelled) { 3947427Smax.romanov@nginx.com nxt_router_ra_inc_use(re_ra); 3948427Smax.romanov@nginx.com 3949427Smax.romanov@nginx.com state.ra = re_ra; 3950427Smax.romanov@nginx.com state.app = app; 3951427Smax.romanov@nginx.com 3952427Smax.romanov@nginx.com nxt_router_port_select(task, &state); 3953427Smax.romanov@nginx.com 3954427Smax.romanov@nginx.com goto re_ra_cancelled; 3955427Smax.romanov@nginx.com } 3956427Smax.romanov@nginx.com } 3957427Smax.romanov@nginx.com } 3958427Smax.romanov@nginx.com 3959427Smax.romanov@nginx.com re_ra = NULL; 3960427Smax.romanov@nginx.com 3961427Smax.romanov@nginx.com re_ra_cancelled: 3962427Smax.romanov@nginx.com 3963753Smax.romanov@nginx.com send_quit = (app->max_requests > 0 3964753Smax.romanov@nginx.com && port->app_pending_responses == 0 3965753Smax.romanov@nginx.com && port->app_responses >= app->max_requests); 3966367Smax.romanov@nginx.com 3967507Smax.romanov@nginx.com if (send_quit) { 3968507Smax.romanov@nginx.com port_unchained = nxt_queue_chk_remove(&port->app_link); 3969507Smax.romanov@nginx.com 3970507Smax.romanov@nginx.com port->app = NULL; 3971507Smax.romanov@nginx.com app->processes--; 3972507Smax.romanov@nginx.com 3973507Smax.romanov@nginx.com } else { 3974507Smax.romanov@nginx.com port_unchained = 0; 3975507Smax.romanov@nginx.com } 3976507Smax.romanov@nginx.com 3977507Smax.romanov@nginx.com adjust_idle_timer = 0; 3978507Smax.romanov@nginx.com 3979571Smax.romanov@nginx.com if (port->pair[1] != -1 && !send_quit && port->app_pending_responses == 0) { 3980507Smax.romanov@nginx.com nxt_assert(port->idle_link.next == NULL); 3981507Smax.romanov@nginx.com 3982507Smax.romanov@nginx.com if (app->idle_processes == app->spare_processes 3983507Smax.romanov@nginx.com && app->adjust_idle_work.data == NULL) 3984507Smax.romanov@nginx.com { 3985507Smax.romanov@nginx.com adjust_idle_timer = 1; 3986507Smax.romanov@nginx.com app->adjust_idle_work.data = app; 3987507Smax.romanov@nginx.com app->adjust_idle_work.next = NULL; 3988507Smax.romanov@nginx.com } 3989507Smax.romanov@nginx.com 3990507Smax.romanov@nginx.com if (app->idle_processes < app->spare_processes) { 3991507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, &port->idle_link); 3992507Smax.romanov@nginx.com 3993507Smax.romanov@nginx.com } else { 3994507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->idle_ports, &port->idle_link); 3995507Smax.romanov@nginx.com 3996507Smax.romanov@nginx.com port->idle_start = task->thread->engine->timers.now; 3997507Smax.romanov@nginx.com } 3998507Smax.romanov@nginx.com 3999507Smax.romanov@nginx.com app->idle_processes++; 4000507Smax.romanov@nginx.com } 4001507Smax.romanov@nginx.com 4002343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4003343Smax.romanov@nginx.com 4004507Smax.romanov@nginx.com if (adjust_idle_timer) { 4005507Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 4006507Smax.romanov@nginx.com nxt_event_engine_post(app->engine, &app->adjust_idle_work); 4007507Smax.romanov@nginx.com } 4008507Smax.romanov@nginx.com 4009427Smax.romanov@nginx.com if (pending_ra != NULL) { 4010427Smax.romanov@nginx.com nxt_router_ra_use(task, pending_ra, -1); 4011427Smax.romanov@nginx.com } 4012427Smax.romanov@nginx.com 4013427Smax.romanov@nginx.com if (re_ra != NULL) { 4014427Smax.romanov@nginx.com if (nxt_router_port_post_select(task, &state) == NXT_OK) { 4015427Smax.romanov@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 4016427Smax.romanov@nginx.com nxt_router_app_process_request, 4017427Smax.romanov@nginx.com &task->thread->engine->task, app, re_ra); 4018427Smax.romanov@nginx.com } 4019425Smax.romanov@nginx.com } 4020425Smax.romanov@nginx.com 4021343Smax.romanov@nginx.com if (ra != NULL) { 4022425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 4023425Smax.romanov@nginx.com 4024343Smax.romanov@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 4025343Smax.romanov@nginx.com nxt_router_app_process_request, 4026343Smax.romanov@nginx.com &task->thread->engine->task, app, ra); 4027343Smax.romanov@nginx.com 4028343Smax.romanov@nginx.com goto adjust_use; 4029343Smax.romanov@nginx.com } 4030343Smax.romanov@nginx.com 4031343Smax.romanov@nginx.com /* ? */ 4032163Smax.romanov@nginx.com if (port->pair[1] == -1) { 4033343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)", 4034343Smax.romanov@nginx.com &app->name, app, port, port->pid); 4035343Smax.romanov@nginx.com 4036343Smax.romanov@nginx.com goto adjust_use; 4037163Smax.romanov@nginx.com } 4038163Smax.romanov@nginx.com 4039367Smax.romanov@nginx.com if (send_quit) { 4040507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p send QUIT to port", 4041167Smax.romanov@nginx.com &app->name, app); 4042163Smax.romanov@nginx.com 4043163Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, 4044163Smax.romanov@nginx.com -1, 0, 0, NULL); 4045163Smax.romanov@nginx.com 4046507Smax.romanov@nginx.com if (port_unchained) { 4047507Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4048507Smax.romanov@nginx.com } 4049507Smax.romanov@nginx.com 4050343Smax.romanov@nginx.com goto adjust_use; 4051163Smax.romanov@nginx.com } 4052163Smax.romanov@nginx.com 4053167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p requests queue is empty, keep the port", 4054167Smax.romanov@nginx.com &app->name, app); 4055141Smax.romanov@nginx.com 4056343Smax.romanov@nginx.com adjust_use: 4057343Smax.romanov@nginx.com 4058425Smax.romanov@nginx.com if (request_failed > 0 || got_response > 0) { 4059425Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4060343Smax.romanov@nginx.com } 4061141Smax.romanov@nginx.com } 4062141Smax.romanov@nginx.com 4063141Smax.romanov@nginx.com 4064343Smax.romanov@nginx.com void 4065343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port) 4066141Smax.romanov@nginx.com { 4067507Smax.romanov@nginx.com nxt_app_t *app; 4068507Smax.romanov@nginx.com nxt_bool_t unchain, start_process; 4069507Smax.romanov@nginx.com nxt_port_t *idle_port; 4070507Smax.romanov@nginx.com nxt_queue_link_t *idle_lnk; 4071141Smax.romanov@nginx.com 4072141Smax.romanov@nginx.com app = port->app; 4073343Smax.romanov@nginx.com 4074343Smax.romanov@nginx.com nxt_assert(app != NULL); 4075141Smax.romanov@nginx.com 4076141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4077141Smax.romanov@nginx.com 4078507Smax.romanov@nginx.com unchain = nxt_queue_chk_remove(&port->app_link); 4079507Smax.romanov@nginx.com 4080507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 4081507Smax.romanov@nginx.com app->idle_processes--; 4082507Smax.romanov@nginx.com 4083507Smax.romanov@nginx.com if (port->idle_start == 0 4084507Smax.romanov@nginx.com && app->idle_processes >= app->spare_processes) 4085507Smax.romanov@nginx.com { 4086507Smax.romanov@nginx.com nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); 4087507Smax.romanov@nginx.com 4088507Smax.romanov@nginx.com idle_lnk = nxt_queue_last(&app->idle_ports); 4089507Smax.romanov@nginx.com idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link); 4090507Smax.romanov@nginx.com nxt_queue_remove(idle_lnk); 4091507Smax.romanov@nginx.com 4092507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, idle_lnk); 4093507Smax.romanov@nginx.com 4094507Smax.romanov@nginx.com idle_port->idle_start = 0; 4095507Smax.romanov@nginx.com } 4096343Smax.romanov@nginx.com } 4097343Smax.romanov@nginx.com 4098507Smax.romanov@nginx.com app->processes--; 4099507Smax.romanov@nginx.com 4100753Smax.romanov@nginx.com start_process = !task->thread->engine->shutdown 4101507Smax.romanov@nginx.com && nxt_router_app_can_start(app) 4102507Smax.romanov@nginx.com && (!nxt_queue_is_empty(&app->requests) 4103507Smax.romanov@nginx.com || nxt_router_app_need_start(app)); 4104507Smax.romanov@nginx.com 4105507Smax.romanov@nginx.com if (start_process) { 4106507Smax.romanov@nginx.com app->pending_processes++; 4107163Smax.romanov@nginx.com } 4108141Smax.romanov@nginx.com 4109141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4110163Smax.romanov@nginx.com 4111507Smax.romanov@nginx.com nxt_debug(task, "app '%V' pid %PI closed", &app->name, port->pid); 4112343Smax.romanov@nginx.com 4113343Smax.romanov@nginx.com if (unchain) { 4114343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4115163Smax.romanov@nginx.com } 4116163Smax.romanov@nginx.com 4117507Smax.romanov@nginx.com if (start_process) { 4118507Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 4119507Smax.romanov@nginx.com } 4120507Smax.romanov@nginx.com } 4121507Smax.romanov@nginx.com 4122507Smax.romanov@nginx.com 4123507Smax.romanov@nginx.com static void 4124507Smax.romanov@nginx.com nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, void *data) 4125507Smax.romanov@nginx.com { 4126507Smax.romanov@nginx.com nxt_app_t *app; 4127507Smax.romanov@nginx.com nxt_bool_t queued; 4128507Smax.romanov@nginx.com nxt_port_t *port; 4129507Smax.romanov@nginx.com nxt_msec_t timeout, threshold; 4130507Smax.romanov@nginx.com nxt_queue_link_t *lnk; 4131507Smax.romanov@nginx.com nxt_event_engine_t *engine; 4132507Smax.romanov@nginx.com 4133507Smax.romanov@nginx.com app = obj; 4134507Smax.romanov@nginx.com queued = (data == app); 4135507Smax.romanov@nginx.com 4136507Smax.romanov@nginx.com nxt_debug(task, "nxt_router_adjust_idle_timer: app \"%V\", queued %b", 4137507Smax.romanov@nginx.com &app->name, queued); 4138507Smax.romanov@nginx.com 4139507Smax.romanov@nginx.com engine = task->thread->engine; 4140507Smax.romanov@nginx.com 4141507Smax.romanov@nginx.com nxt_assert(app->engine == engine); 4142507Smax.romanov@nginx.com 4143811Svbart@nginx.com threshold = engine->timers.now + app->joint->idle_timer.bias; 4144507Smax.romanov@nginx.com timeout = 0; 4145507Smax.romanov@nginx.com 4146507Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4147507Smax.romanov@nginx.com 4148507Smax.romanov@nginx.com if (queued) { 4149507Smax.romanov@nginx.com app->adjust_idle_work.data = NULL; 4150343Smax.romanov@nginx.com } 4151507Smax.romanov@nginx.com 4152507Smax.romanov@nginx.com while (app->idle_processes > app->spare_processes) { 4153507Smax.romanov@nginx.com 4154551Smax.romanov@nginx.com nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); 4155507Smax.romanov@nginx.com 4156507Smax.romanov@nginx.com lnk = nxt_queue_first(&app->idle_ports); 4157507Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, idle_link); 4158507Smax.romanov@nginx.com 4159507Smax.romanov@nginx.com timeout = port->idle_start + app->idle_timeout; 4160507Smax.romanov@nginx.com 4161507Smax.romanov@nginx.com if (timeout > threshold) { 4162507Smax.romanov@nginx.com break; 4163507Smax.romanov@nginx.com } 4164507Smax.romanov@nginx.com 4165507Smax.romanov@nginx.com nxt_queue_remove(lnk); 4166507Smax.romanov@nginx.com lnk->next = NULL; 4167507Smax.romanov@nginx.com 4168507Smax.romanov@nginx.com nxt_queue_chk_remove(&port->app_link); 4169507Smax.romanov@nginx.com 4170507Smax.romanov@nginx.com app->idle_processes--; 4171507Smax.romanov@nginx.com app->processes--; 4172507Smax.romanov@nginx.com port->app = NULL; 4173507Smax.romanov@nginx.com 4174507Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4175507Smax.romanov@nginx.com 4176507Smax.romanov@nginx.com nxt_debug(task, "app '%V' send QUIT to idle port %PI", 4177507Smax.romanov@nginx.com &app->name, port->pid); 4178507Smax.romanov@nginx.com 4179507Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 4180507Smax.romanov@nginx.com 4181507Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4182507Smax.romanov@nginx.com 4183507Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4184507Smax.romanov@nginx.com } 4185507Smax.romanov@nginx.com 4186507Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4187507Smax.romanov@nginx.com 4188507Smax.romanov@nginx.com if (timeout > threshold) { 4189753Smax.romanov@nginx.com nxt_timer_add(engine, &app->joint->idle_timer, timeout - threshold); 4190507Smax.romanov@nginx.com 4191507Smax.romanov@nginx.com } else { 4192753Smax.romanov@nginx.com nxt_timer_disable(engine, &app->joint->idle_timer); 4193507Smax.romanov@nginx.com } 4194507Smax.romanov@nginx.com 4195507Smax.romanov@nginx.com if (queued) { 4196507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 4197507Smax.romanov@nginx.com } 4198507Smax.romanov@nginx.com } 4199507Smax.romanov@nginx.com 4200507Smax.romanov@nginx.com 4201507Smax.romanov@nginx.com static void 4202507Smax.romanov@nginx.com nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, void *data) 4203507Smax.romanov@nginx.com { 4204753Smax.romanov@nginx.com nxt_timer_t *timer; 4205753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 4206507Smax.romanov@nginx.com 4207507Smax.romanov@nginx.com timer = obj; 4208753Smax.romanov@nginx.com app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer); 4209753Smax.romanov@nginx.com 4210753Smax.romanov@nginx.com if (nxt_fast_path(app_joint->app != NULL)) { 4211753Smax.romanov@nginx.com nxt_router_adjust_idle_timer(task, app_joint->app, NULL); 4212753Smax.romanov@nginx.com } 4213753Smax.romanov@nginx.com } 4214753Smax.romanov@nginx.com 4215753Smax.romanov@nginx.com 4216753Smax.romanov@nginx.com static void 4217753Smax.romanov@nginx.com nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, void *data) 4218753Smax.romanov@nginx.com { 4219753Smax.romanov@nginx.com nxt_timer_t *timer; 4220753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 4221753Smax.romanov@nginx.com 4222753Smax.romanov@nginx.com timer = obj; 4223753Smax.romanov@nginx.com app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer); 4224753Smax.romanov@nginx.com 4225753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 4226507Smax.romanov@nginx.com } 4227507Smax.romanov@nginx.com 4228507Smax.romanov@nginx.com 4229507Smax.romanov@nginx.com static void 4230753Smax.romanov@nginx.com nxt_router_free_app(nxt_task_t *task, void *obj, void *data) 4231507Smax.romanov@nginx.com { 4232753Smax.romanov@nginx.com nxt_app_t *app; 4233753Smax.romanov@nginx.com nxt_port_t *port; 4234753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 4235753Smax.romanov@nginx.com 4236753Smax.romanov@nginx.com app_joint = obj; 4237753Smax.romanov@nginx.com app = app_joint->app; 4238753Smax.romanov@nginx.com 4239753Smax.romanov@nginx.com for ( ;; ) { 4240753Smax.romanov@nginx.com port = nxt_router_app_get_port_for_quit(app); 4241753Smax.romanov@nginx.com if (port == NULL) { 4242753Smax.romanov@nginx.com break; 4243753Smax.romanov@nginx.com } 4244753Smax.romanov@nginx.com 4245753Smax.romanov@nginx.com nxt_debug(task, "send QUIT to app '%V' pid %PI", &app->name, port->pid); 4246753Smax.romanov@nginx.com 4247753Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 4248753Smax.romanov@nginx.com 4249753Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4250753Smax.romanov@nginx.com } 4251753Smax.romanov@nginx.com 4252753Smax.romanov@nginx.com nxt_assert(app->processes == 0); 4253753Smax.romanov@nginx.com nxt_assert(app->idle_processes == 0); 4254753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->requests)); 4255753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->ports)); 4256753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->spare_ports)); 4257753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->idle_ports)); 4258753Smax.romanov@nginx.com 4259753Smax.romanov@nginx.com nxt_thread_mutex_destroy(&app->mutex); 4260753Smax.romanov@nginx.com nxt_free(app); 4261753Smax.romanov@nginx.com 4262753Smax.romanov@nginx.com app_joint->app = NULL; 4263753Smax.romanov@nginx.com 4264753Smax.romanov@nginx.com if (nxt_timer_delete(task->thread->engine, &app_joint->idle_timer)) { 4265753Smax.romanov@nginx.com app_joint->idle_timer.handler = nxt_router_app_joint_release_handler; 4266753Smax.romanov@nginx.com nxt_timer_add(task->thread->engine, &app_joint->idle_timer, 0); 4267753Smax.romanov@nginx.com 4268753Smax.romanov@nginx.com } else { 4269753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 4270753Smax.romanov@nginx.com } 4271141Smax.romanov@nginx.com } 4272141Smax.romanov@nginx.com 4273141Smax.romanov@nginx.com 4274427Smax.romanov@nginx.com static void 4275427Smax.romanov@nginx.com nxt_router_port_select(nxt_task_t *task, nxt_port_select_state_t *state) 4276141Smax.romanov@nginx.com { 4277427Smax.romanov@nginx.com nxt_app_t *app; 4278507Smax.romanov@nginx.com nxt_bool_t can_start_process; 4279427Smax.romanov@nginx.com nxt_req_app_link_t *ra; 4280427Smax.romanov@nginx.com 4281427Smax.romanov@nginx.com ra = state->ra; 4282427Smax.romanov@nginx.com app = state->app; 4283427Smax.romanov@nginx.com 4284427Smax.romanov@nginx.com state->failed_port_use_delta = 0; 4285343Smax.romanov@nginx.com 4286425Smax.romanov@nginx.com if (nxt_queue_chk_remove(&ra->link_app_requests)) 4287425Smax.romanov@nginx.com { 4288425Smax.romanov@nginx.com nxt_router_ra_dec_use(ra); 4289425Smax.romanov@nginx.com } 4290425Smax.romanov@nginx.com 4291425Smax.romanov@nginx.com if (nxt_queue_chk_remove(&ra->link_port_pending)) 4292425Smax.romanov@nginx.com { 4293427Smax.romanov@nginx.com nxt_assert(ra->link_app_pending.next != NULL); 4294427Smax.romanov@nginx.com 4295427Smax.romanov@nginx.com nxt_queue_remove(&ra->link_app_pending); 4296427Smax.romanov@nginx.com ra->link_app_pending.next = NULL; 4297427Smax.romanov@nginx.com 4298425Smax.romanov@nginx.com nxt_router_ra_dec_use(ra); 4299425Smax.romanov@nginx.com } 4300425Smax.romanov@nginx.com 4301427Smax.romanov@nginx.com state->failed_port = ra->app_port; 4302427Smax.romanov@nginx.com 4303425Smax.romanov@nginx.com if (ra->app_port != NULL) { 4304427Smax.romanov@nginx.com state->failed_port_use_delta--; 4305427Smax.romanov@nginx.com 4306427Smax.romanov@nginx.com state->failed_port->app_pending_responses--; 4307427Smax.romanov@nginx.com 4308427Smax.romanov@nginx.com if (nxt_queue_chk_remove(&state->failed_port->app_link)) { 4309427Smax.romanov@nginx.com state->failed_port_use_delta--; 4310427Smax.romanov@nginx.com } 4311427Smax.romanov@nginx.com 4312427Smax.romanov@nginx.com ra->app_port = NULL; 4313427Smax.romanov@nginx.com } 4314427Smax.romanov@nginx.com 4315507Smax.romanov@nginx.com can_start_process = nxt_router_app_can_start(app); 4316507Smax.romanov@nginx.com 4317427Smax.romanov@nginx.com state->port = NULL; 4318507Smax.romanov@nginx.com state->start_process = 0; 4319427Smax.romanov@nginx.com 4320427Smax.romanov@nginx.com if (nxt_queue_is_empty(&app->ports) 4321507Smax.romanov@nginx.com || (can_start_process && nxt_router_app_first_port_busy(app)) ) 4322427Smax.romanov@nginx.com { 4323427Smax.romanov@nginx.com ra = nxt_router_ra_create(task, ra); 4324427Smax.romanov@nginx.com 4325427Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 4326427Smax.romanov@nginx.com goto fail; 4327427Smax.romanov@nginx.com } 4328427Smax.romanov@nginx.com 4329427Smax.romanov@nginx.com if (nxt_slow_path(state->failed_port != NULL)) { 4330427Smax.romanov@nginx.com nxt_queue_insert_head(&app->requests, &ra->link_app_requests); 4331427Smax.romanov@nginx.com 4332427Smax.romanov@nginx.com } else { 4333427Smax.romanov@nginx.com nxt_queue_insert_tail(&app->requests, &ra->link_app_requests); 4334427Smax.romanov@nginx.com } 4335427Smax.romanov@nginx.com 4336427Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 4337427Smax.romanov@nginx.com 4338427Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD enqueue to app->requests", ra->stream); 4339427Smax.romanov@nginx.com 4340507Smax.romanov@nginx.com if (can_start_process) { 4341507Smax.romanov@nginx.com app->pending_processes++; 4342507Smax.romanov@nginx.com state->start_process = 1; 4343425Smax.romanov@nginx.com } 4344425Smax.romanov@nginx.com 4345425Smax.romanov@nginx.com } else { 4346427Smax.romanov@nginx.com state->port = nxt_router_pop_first_port(app); 4347427Smax.romanov@nginx.com 4348427Smax.romanov@nginx.com if (state->port->app_pending_responses > 1) { 4349427Smax.romanov@nginx.com ra = nxt_router_ra_create(task, ra); 4350427Smax.romanov@nginx.com 4351427Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 4352427Smax.romanov@nginx.com goto fail; 4353351Smax.romanov@nginx.com } 4354427Smax.romanov@nginx.com 4355427Smax.romanov@nginx.com ra->app_port = state->port; 4356427Smax.romanov@nginx.com 4357427Smax.romanov@nginx.com nxt_router_ra_pending(task, app, ra); 4358425Smax.romanov@nginx.com } 4359507Smax.romanov@nginx.com 4360507Smax.romanov@nginx.com if (can_start_process && nxt_router_app_need_start(app)) { 4361507Smax.romanov@nginx.com app->pending_processes++; 4362507Smax.romanov@nginx.com state->start_process = 1; 4363507Smax.romanov@nginx.com } 4364343Smax.romanov@nginx.com } 4365343Smax.romanov@nginx.com 4366427Smax.romanov@nginx.com fail: 4367427Smax.romanov@nginx.com 4368427Smax.romanov@nginx.com state->shared_ra = ra; 4369427Smax.romanov@nginx.com } 4370427Smax.romanov@nginx.com 4371427Smax.romanov@nginx.com 4372427Smax.romanov@nginx.com static nxt_int_t 4373427Smax.romanov@nginx.com nxt_router_port_post_select(nxt_task_t *task, nxt_port_select_state_t *state) 4374427Smax.romanov@nginx.com { 4375427Smax.romanov@nginx.com nxt_int_t res; 4376427Smax.romanov@nginx.com nxt_app_t *app; 4377427Smax.romanov@nginx.com nxt_req_app_link_t *ra; 4378427Smax.romanov@nginx.com 4379427Smax.romanov@nginx.com ra = state->shared_ra; 4380427Smax.romanov@nginx.com app = state->app; 4381427Smax.romanov@nginx.com 4382427Smax.romanov@nginx.com if (state->failed_port_use_delta != 0) { 4383427Smax.romanov@nginx.com nxt_port_use(task, state->failed_port, state->failed_port_use_delta); 4384425Smax.romanov@nginx.com } 4385425Smax.romanov@nginx.com 4386351Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 4387427Smax.romanov@nginx.com if (state->port != NULL) { 4388427Smax.romanov@nginx.com nxt_port_use(task, state->port, -1); 4389425Smax.romanov@nginx.com } 4390425Smax.romanov@nginx.com 4391427Smax.romanov@nginx.com nxt_router_ra_error(state->ra, 500, 4392427Smax.romanov@nginx.com "Failed to allocate shared req<->app link"); 4393427Smax.romanov@nginx.com nxt_router_ra_use(task, state->ra, -1); 4394427Smax.romanov@nginx.com 4395351Smax.romanov@nginx.com return NXT_ERROR; 4396351Smax.romanov@nginx.com } 4397351Smax.romanov@nginx.com 4398427Smax.romanov@nginx.com if (state->port != NULL) { 4399343Smax.romanov@nginx.com nxt_debug(task, "already have port for app '%V' %p ", &app->name, app); 4400163Smax.romanov@nginx.com 4401427Smax.romanov@nginx.com ra->app_port = state->port; 4402343Smax.romanov@nginx.com 4403507Smax.romanov@nginx.com if (state->start_process) { 4404507Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 4405507Smax.romanov@nginx.com } 4406507Smax.romanov@nginx.com 4407141Smax.romanov@nginx.com return NXT_OK; 4408141Smax.romanov@nginx.com } 4409141Smax.romanov@nginx.com 4410507Smax.romanov@nginx.com if (!state->start_process) { 4411507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p too many running or pending processes", 4412343Smax.romanov@nginx.com &app->name, app); 4413343Smax.romanov@nginx.com 4414343Smax.romanov@nginx.com return NXT_AGAIN; 4415343Smax.romanov@nginx.com } 4416343Smax.romanov@nginx.com 4417507Smax.romanov@nginx.com res = nxt_router_start_app_process(task, app); 4418343Smax.romanov@nginx.com 4419343Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 4420507Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, "Failed to start app process"); 4421427Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 4422343Smax.romanov@nginx.com 4423141Smax.romanov@nginx.com return NXT_ERROR; 4424141Smax.romanov@nginx.com } 4425141Smax.romanov@nginx.com 4426141Smax.romanov@nginx.com return NXT_AGAIN; 442788Smax.romanov@nginx.com } 442888Smax.romanov@nginx.com 442988Smax.romanov@nginx.com 4430427Smax.romanov@nginx.com static nxt_int_t 4431427Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra) 4432427Smax.romanov@nginx.com { 4433427Smax.romanov@nginx.com nxt_port_select_state_t state; 4434427Smax.romanov@nginx.com 4435427Smax.romanov@nginx.com state.ra = ra; 4436427Smax.romanov@nginx.com state.app = app; 4437427Smax.romanov@nginx.com 4438427Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4439427Smax.romanov@nginx.com 4440427Smax.romanov@nginx.com nxt_router_port_select(task, &state); 4441427Smax.romanov@nginx.com 4442427Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4443427Smax.romanov@nginx.com 4444427Smax.romanov@nginx.com return nxt_router_port_post_select(task, &state); 4445427Smax.romanov@nginx.com } 4446427Smax.romanov@nginx.com 4447427Smax.romanov@nginx.com 4448431Sigor@sysoev.ru void 4449*1007Salexander.borisov@nginx.com nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r, 4450964Sigor@sysoev.ru nxt_app_t *app) 445153Sigor@sysoev.ru { 4452431Sigor@sysoev.ru nxt_int_t res; 4453431Sigor@sysoev.ru nxt_port_t *port; 4454431Sigor@sysoev.ru nxt_event_engine_t *engine; 4455431Sigor@sysoev.ru nxt_req_app_link_t ra_local, *ra; 4456431Sigor@sysoev.ru nxt_req_conn_link_t *rc; 4457431Sigor@sysoev.ru 445888Smax.romanov@nginx.com engine = task->thread->engine; 445988Smax.romanov@nginx.com 4460318Smax.romanov@nginx.com rc = nxt_port_rpc_register_handler_ex(task, engine->port, 4461318Smax.romanov@nginx.com nxt_router_response_ready_handler, 4462318Smax.romanov@nginx.com nxt_router_response_error_handler, 4463318Smax.romanov@nginx.com sizeof(nxt_req_conn_link_t)); 4464122Smax.romanov@nginx.com 446588Smax.romanov@nginx.com if (nxt_slow_path(rc == NULL)) { 4466431Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 4467141Smax.romanov@nginx.com return; 446888Smax.romanov@nginx.com } 446988Smax.romanov@nginx.com 4470318Smax.romanov@nginx.com rc->stream = nxt_port_rpc_ex_stream(rc); 4471425Smax.romanov@nginx.com rc->app = app; 4472425Smax.romanov@nginx.com 4473425Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 4474425Smax.romanov@nginx.com 4475*1007Salexander.borisov@nginx.com rc->request = r; 4476346Smax.romanov@nginx.com 4477351Smax.romanov@nginx.com ra = &ra_local; 4478351Smax.romanov@nginx.com nxt_router_ra_init(task, ra, rc); 4479167Smax.romanov@nginx.com 4480427Smax.romanov@nginx.com res = nxt_router_app_port(task, app, ra); 4481141Smax.romanov@nginx.com 4482141Smax.romanov@nginx.com if (res != NXT_OK) { 4483141Smax.romanov@nginx.com return; 4484141Smax.romanov@nginx.com } 4485141Smax.romanov@nginx.com 4486425Smax.romanov@nginx.com ra = rc->ra; 4487167Smax.romanov@nginx.com port = ra->app_port; 4488141Smax.romanov@nginx.com 4489425Smax.romanov@nginx.com nxt_assert(port != NULL); 4490141Smax.romanov@nginx.com 4491318Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, engine->port, rc, port->pid); 4492318Smax.romanov@nginx.com 4493425Smax.romanov@nginx.com nxt_router_app_prepare_request(task, ra); 4494167Smax.romanov@nginx.com } 4495167Smax.romanov@nginx.com 4496167Smax.romanov@nginx.com 4497167Smax.romanov@nginx.com static void 4498423Smax.romanov@nginx.com nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj, void *data) 4499423Smax.romanov@nginx.com { 4500423Smax.romanov@nginx.com } 4501423Smax.romanov@nginx.com 4502423Smax.romanov@nginx.com 4503423Smax.romanov@nginx.com static void 4504425Smax.romanov@nginx.com nxt_router_app_prepare_request(nxt_task_t *task, nxt_req_app_link_t *ra) 4505167Smax.romanov@nginx.com { 4506*1007Salexander.borisov@nginx.com uint32_t request_failed; 4507*1007Salexander.borisov@nginx.com nxt_buf_t *buf; 4508*1007Salexander.borisov@nginx.com nxt_int_t res; 4509*1007Salexander.borisov@nginx.com nxt_port_t *port, *c_port, *reply_port; 4510167Smax.romanov@nginx.com 4511343Smax.romanov@nginx.com nxt_assert(ra->app_port != NULL); 4512343Smax.romanov@nginx.com 4513343Smax.romanov@nginx.com port = ra->app_port; 4514167Smax.romanov@nginx.com reply_port = ra->reply_port; 4515141Smax.romanov@nginx.com 4516343Smax.romanov@nginx.com request_failed = 1; 4517343Smax.romanov@nginx.com 4518141Smax.romanov@nginx.com c_port = nxt_process_connected_port_find(port->process, reply_port->pid, 4519141Smax.romanov@nginx.com reply_port->id); 4520141Smax.romanov@nginx.com if (nxt_slow_path(c_port != reply_port)) { 4521141Smax.romanov@nginx.com res = nxt_port_send_port(task, port, reply_port, 0); 4522122Smax.romanov@nginx.com 4523122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 4524423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 4525345Smax.romanov@nginx.com "Failed to send reply port to application"); 4526343Smax.romanov@nginx.com goto release_port; 4527122Smax.romanov@nginx.com } 4528122Smax.romanov@nginx.com 4529141Smax.romanov@nginx.com nxt_process_connected_port_add(port->process, reply_port); 453088Smax.romanov@nginx.com } 453188Smax.romanov@nginx.com 4532*1007Salexander.borisov@nginx.com buf = nxt_router_prepare_msg(task, ra->request, port, 4533743Smax.romanov@nginx.com nxt_app_msg_prefix[port->app->type]); 4534743Smax.romanov@nginx.com 4535743Smax.romanov@nginx.com if (nxt_slow_path(buf == NULL)) { 4536423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 4537345Smax.romanov@nginx.com "Failed to prepare message for application"); 4538343Smax.romanov@nginx.com goto release_port; 4539122Smax.romanov@nginx.com } 454088Smax.romanov@nginx.com 4541507Smax.romanov@nginx.com nxt_debug(task, "about to send %O bytes buffer to app process port %d", 4542743Smax.romanov@nginx.com nxt_buf_used_size(buf), 4543743Smax.romanov@nginx.com port->socket.fd); 454488Smax.romanov@nginx.com 4545343Smax.romanov@nginx.com request_failed = 0; 4546343Smax.romanov@nginx.com 4547743Smax.romanov@nginx.com ra->msg_info.buf = buf; 4548743Smax.romanov@nginx.com ra->msg_info.completion_handler = buf->completion_handler; 4549743Smax.romanov@nginx.com 4550743Smax.romanov@nginx.com for (; buf; buf = buf->next) { 4551743Smax.romanov@nginx.com buf->completion_handler = nxt_router_dummy_buf_completion; 4552423Smax.romanov@nginx.com } 4553423Smax.romanov@nginx.com 4554743Smax.romanov@nginx.com buf = ra->msg_info.buf; 4555743Smax.romanov@nginx.com 4556423Smax.romanov@nginx.com res = nxt_port_mmap_get_tracking(task, port, &ra->msg_info.tracking, 4557423Smax.romanov@nginx.com ra->stream); 4558423Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 4559423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 4560423Smax.romanov@nginx.com "Failed to get tracking area"); 4561423Smax.romanov@nginx.com goto release_port; 4562423Smax.romanov@nginx.com } 4563423Smax.romanov@nginx.com 4564743Smax.romanov@nginx.com res = nxt_port_socket_twrite(task, port, NXT_PORT_MSG_DATA, 4565743Smax.romanov@nginx.com -1, ra->stream, reply_port->id, buf, 4566423Smax.romanov@nginx.com &ra->msg_info.tracking); 4567122Smax.romanov@nginx.com 4568122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 4569423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 4570345Smax.romanov@nginx.com "Failed to send message to application"); 4571343Smax.romanov@nginx.com goto release_port; 4572122Smax.romanov@nginx.com } 4573343Smax.romanov@nginx.com 4574343Smax.romanov@nginx.com release_port: 4575343Smax.romanov@nginx.com 4576345Smax.romanov@nginx.com nxt_router_app_port_release(task, port, request_failed, 0); 4577345Smax.romanov@nginx.com 4578425Smax.romanov@nginx.com nxt_router_ra_update_peer(task, ra); 457953Sigor@sysoev.ru } 458053Sigor@sysoev.ru 458153Sigor@sysoev.ru 4582743Smax.romanov@nginx.com struct nxt_fields_iter_s { 4583743Smax.romanov@nginx.com nxt_list_part_t *part; 4584743Smax.romanov@nginx.com nxt_http_field_t *field; 4585743Smax.romanov@nginx.com }; 4586743Smax.romanov@nginx.com 4587743Smax.romanov@nginx.com typedef struct nxt_fields_iter_s nxt_fields_iter_t; 4588743Smax.romanov@nginx.com 4589743Smax.romanov@nginx.com 4590743Smax.romanov@nginx.com static nxt_http_field_t * 4591743Smax.romanov@nginx.com nxt_fields_part_first(nxt_list_part_t *part, nxt_fields_iter_t *i) 4592216Sigor@sysoev.ru { 4593743Smax.romanov@nginx.com if (part == NULL) { 4594743Smax.romanov@nginx.com return NULL; 4595216Sigor@sysoev.ru } 4596216Sigor@sysoev.ru 4597743Smax.romanov@nginx.com while (part->nelts == 0) { 4598743Smax.romanov@nginx.com part = part->next; 4599743Smax.romanov@nginx.com if (part == NULL) { 4600743Smax.romanov@nginx.com return NULL; 4601743Smax.romanov@nginx.com } 4602216Sigor@sysoev.ru } 4603216Sigor@sysoev.ru 4604743Smax.romanov@nginx.com i->part = part; 4605743Smax.romanov@nginx.com i->field = nxt_list_data(i->part); 4606743Smax.romanov@nginx.com 4607743Smax.romanov@nginx.com return i->field; 4608743Smax.romanov@nginx.com } 4609743Smax.romanov@nginx.com 4610743Smax.romanov@nginx.com 4611743Smax.romanov@nginx.com static nxt_http_field_t * 4612743Smax.romanov@nginx.com nxt_fields_first(nxt_list_t *fields, nxt_fields_iter_t *i) 4613743Smax.romanov@nginx.com { 4614743Smax.romanov@nginx.com return nxt_fields_part_first(nxt_list_part(fields), i); 4615743Smax.romanov@nginx.com } 4616743Smax.romanov@nginx.com 4617743Smax.romanov@nginx.com 4618743Smax.romanov@nginx.com static nxt_http_field_t * 4619743Smax.romanov@nginx.com nxt_fields_next(nxt_fields_iter_t *i) 4620743Smax.romanov@nginx.com { 4621743Smax.romanov@nginx.com nxt_http_field_t *end = nxt_list_data(i->part); 4622743Smax.romanov@nginx.com 4623743Smax.romanov@nginx.com end += i->part->nelts; 4624743Smax.romanov@nginx.com i->field++; 4625743Smax.romanov@nginx.com 4626743Smax.romanov@nginx.com if (i->field < end) { 4627743Smax.romanov@nginx.com return i->field; 4628216Sigor@sysoev.ru } 4629216Sigor@sysoev.ru 4630743Smax.romanov@nginx.com return nxt_fields_part_first(i->part->next, i); 4631216Sigor@sysoev.ru } 4632216Sigor@sysoev.ru 4633216Sigor@sysoev.ru 4634743Smax.romanov@nginx.com static nxt_buf_t * 4635*1007Salexander.borisov@nginx.com nxt_router_prepare_msg(nxt_task_t *task, nxt_http_request_t *r, 4636743Smax.romanov@nginx.com nxt_port_t *port, const nxt_str_t *prefix) 4637216Sigor@sysoev.ru { 4638*1007Salexander.borisov@nginx.com void *target_pos, *query_pos; 4639*1007Salexander.borisov@nginx.com u_char *pos, *end, *p, c; 4640*1007Salexander.borisov@nginx.com size_t fields_count, req_size, size, free_size; 4641*1007Salexander.borisov@nginx.com size_t copy_size; 4642*1007Salexander.borisov@nginx.com nxt_off_t content_length; 4643*1007Salexander.borisov@nginx.com nxt_buf_t *b, *buf, *out, **tail; 4644*1007Salexander.borisov@nginx.com nxt_http_field_t *field, *dup; 4645*1007Salexander.borisov@nginx.com nxt_unit_field_t *dst_field; 4646*1007Salexander.borisov@nginx.com nxt_fields_iter_t iter, dup_iter; 4647*1007Salexander.borisov@nginx.com nxt_unit_request_t *req; 4648216Sigor@sysoev.ru 4649743Smax.romanov@nginx.com req_size = sizeof(nxt_unit_request_t) 4650*1007Salexander.borisov@nginx.com + r->method->length + 1 4651*1007Salexander.borisov@nginx.com + r->version.length + 1 4652*1007Salexander.borisov@nginx.com + r->remote->length + 1 4653*1007Salexander.borisov@nginx.com + r->local->length + 1 4654*1007Salexander.borisov@nginx.com + r->server_name.length + 1 4655*1007Salexander.borisov@nginx.com + r->target.length + 1 4656*1007Salexander.borisov@nginx.com + (r->path->start != r->target.start ? r->path->length + 1 : 0); 4657*1007Salexander.borisov@nginx.com 4658*1007Salexander.borisov@nginx.com content_length = r->content_length_n < 0 ? 0 : r->content_length_n; 4659743Smax.romanov@nginx.com fields_count = 0; 4660743Smax.romanov@nginx.com 4661*1007Salexander.borisov@nginx.com nxt_list_each(field, r->fields) { 4662743Smax.romanov@nginx.com fields_count++; 4663743Smax.romanov@nginx.com 4664743Smax.romanov@nginx.com req_size += field->name_length + prefix->length + 1 4665743Smax.romanov@nginx.com + field->value_length + 1; 4666743Smax.romanov@nginx.com } nxt_list_loop; 4667743Smax.romanov@nginx.com 4668743Smax.romanov@nginx.com req_size += fields_count * sizeof(nxt_unit_field_t); 4669743Smax.romanov@nginx.com 4670743Smax.romanov@nginx.com if (nxt_slow_path(req_size > PORT_MMAP_DATA_SIZE)) { 4671743Smax.romanov@nginx.com nxt_alert(task, "headers to big to fit in shared memory (%d)", 4672743Smax.romanov@nginx.com (int) req_size); 4673743Smax.romanov@nginx.com 4674743Smax.romanov@nginx.com return NULL; 4675743Smax.romanov@nginx.com } 4676743Smax.romanov@nginx.com 4677743Smax.romanov@nginx.com out = nxt_port_mmap_get_buf(task, port, 4678*1007Salexander.borisov@nginx.com nxt_min(req_size + content_length, PORT_MMAP_DATA_SIZE)); 4679743Smax.romanov@nginx.com if (nxt_slow_path(out == NULL)) { 4680743Smax.romanov@nginx.com return NULL; 4681743Smax.romanov@nginx.com } 4682743Smax.romanov@nginx.com 4683743Smax.romanov@nginx.com req = (nxt_unit_request_t *) out->mem.free; 4684743Smax.romanov@nginx.com out->mem.free += req_size; 4685743Smax.romanov@nginx.com 4686*1007Salexander.borisov@nginx.com req->content_length = content_length; 4687743Smax.romanov@nginx.com 4688743Smax.romanov@nginx.com p = (u_char *) (req->fields + fields_count); 4689743Smax.romanov@nginx.com 4690743Smax.romanov@nginx.com nxt_debug(task, "fields_count=%d", (int) fields_count); 4691743Smax.romanov@nginx.com 4692*1007Salexander.borisov@nginx.com req->method_length = r->method->length; 4693743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->method, p); 4694*1007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->method->start, r->method->length); 4695743Smax.romanov@nginx.com *p++ = '\0'; 4696743Smax.romanov@nginx.com 4697*1007Salexander.borisov@nginx.com req->version_length = r->version.length; 4698743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->version, p); 4699*1007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->version.start, r->version.length); 4700743Smax.romanov@nginx.com *p++ = '\0'; 4701743Smax.romanov@nginx.com 4702*1007Salexander.borisov@nginx.com req->remote_length = r->remote->address_length; 4703743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->remote, p); 4704*1007Salexander.borisov@nginx.com p = nxt_cpymem(p, nxt_sockaddr_address(r->remote), 4705*1007Salexander.borisov@nginx.com r->remote->address_length); 4706743Smax.romanov@nginx.com *p++ = '\0'; 4707743Smax.romanov@nginx.com 4708*1007Salexander.borisov@nginx.com req->local_length = r->local->address_length; 4709743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->local, p); 4710*1007Salexander.borisov@nginx.com p = nxt_cpymem(p, nxt_sockaddr_address(r->local), r->local->address_length); 4711743Smax.romanov@nginx.com *p++ = '\0'; 4712743Smax.romanov@nginx.com 4713*1007Salexander.borisov@nginx.com req->server_name_length = r->server_name.length; 4714967Svbart@nginx.com nxt_unit_sptr_set(&req->server_name, p); 4715*1007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->server_name.start, r->server_name.length); 4716967Svbart@nginx.com *p++ = '\0'; 4717967Svbart@nginx.com 4718743Smax.romanov@nginx.com target_pos = p; 4719*1007Salexander.borisov@nginx.com req->target_length = (uint32_t) r->target.length; 4720743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->target, p); 4721*1007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->target.start, r->target.length); 4722743Smax.romanov@nginx.com *p++ = '\0'; 4723743Smax.romanov@nginx.com 4724*1007Salexander.borisov@nginx.com req->path_length = (uint32_t) r->path->length; 4725*1007Salexander.borisov@nginx.com if (r->path->start == r->target.start) { 4726743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->path, target_pos); 4727277Sigor@sysoev.ru 4728216Sigor@sysoev.ru } else { 4729743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->path, p); 4730*1007Salexander.borisov@nginx.com p = nxt_cpymem(p, r->path->start, r->path->length); 4731743Smax.romanov@nginx.com *p++ = '\0'; 4732305Smax.romanov@nginx.com } 4733216Sigor@sysoev.ru 4734*1007Salexander.borisov@nginx.com req->query_length = r->args != NULL ? (uint32_t) r->args->length : 0; 4735*1007Salexander.borisov@nginx.com if (r->args != NULL && r->args->start != NULL) { 4736743Smax.romanov@nginx.com query_pos = nxt_pointer_to(target_pos, 4737*1007Salexander.borisov@nginx.com r->args->start - r->target.start); 4738743Smax.romanov@nginx.com 4739743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->query, query_pos); 4740277Sigor@sysoev.ru 4741216Sigor@sysoev.ru } else { 4742743Smax.romanov@nginx.com req->query.offset = 0; 4743216Sigor@sysoev.ru } 4744216Sigor@sysoev.ru 4745743Smax.romanov@nginx.com req->content_length_field = NXT_UNIT_NONE_FIELD; 4746743Smax.romanov@nginx.com req->content_type_field = NXT_UNIT_NONE_FIELD; 4747743Smax.romanov@nginx.com req->cookie_field = NXT_UNIT_NONE_FIELD; 4748743Smax.romanov@nginx.com 4749743Smax.romanov@nginx.com dst_field = req->fields; 4750743Smax.romanov@nginx.com 4751*1007Salexander.borisov@nginx.com for (field = nxt_fields_first(r->fields, &iter); 4752743Smax.romanov@nginx.com field != NULL; 4753743Smax.romanov@nginx.com field = nxt_fields_next(&iter)) 4754743Smax.romanov@nginx.com { 4755743Smax.romanov@nginx.com if (field->skip) { 4756743Smax.romanov@nginx.com continue; 4757743Smax.romanov@nginx.com } 4758743Smax.romanov@nginx.com 4759743Smax.romanov@nginx.com dst_field->hash = field->hash; 4760743Smax.romanov@nginx.com dst_field->skip = 0; 4761743Smax.romanov@nginx.com dst_field->name_length = field->name_length + prefix->length; 4762743Smax.romanov@nginx.com dst_field->value_length = field->value_length; 4763743Smax.romanov@nginx.com 4764*1007Salexander.borisov@nginx.com if (field == r->content_length) { 4765743Smax.romanov@nginx.com req->content_length_field = dst_field - req->fields; 4766743Smax.romanov@nginx.com 4767*1007Salexander.borisov@nginx.com } else if (field == r->content_type) { 4768743Smax.romanov@nginx.com req->content_type_field = dst_field - req->fields; 4769743Smax.romanov@nginx.com 4770*1007Salexander.borisov@nginx.com } else if (field == r->cookie) { 4771743Smax.romanov@nginx.com req->cookie_field = dst_field - req->fields; 4772743Smax.romanov@nginx.com } 4773743Smax.romanov@nginx.com 4774743Smax.romanov@nginx.com nxt_debug(task, "add field 0x%04Xd, %d, %d, %p : %d %p", 4775743Smax.romanov@nginx.com (int) field->hash, (int) field->skip, 4776743Smax.romanov@nginx.com (int) field->name_length, field->name, 4777743Smax.romanov@nginx.com (int) field->value_length, field->value); 4778743Smax.romanov@nginx.com 4779743Smax.romanov@nginx.com if (prefix->length != 0) { 4780743Smax.romanov@nginx.com nxt_unit_sptr_set(&dst_field->name, p); 4781743Smax.romanov@nginx.com p = nxt_cpymem(p, prefix->start, prefix->length); 4782743Smax.romanov@nginx.com 4783743Smax.romanov@nginx.com end = field->name + field->name_length; 4784743Smax.romanov@nginx.com for (pos = field->name; pos < end; pos++) { 4785743Smax.romanov@nginx.com c = *pos; 4786743Smax.romanov@nginx.com 4787743Smax.romanov@nginx.com if (c >= 'a' && c <= 'z') { 4788743Smax.romanov@nginx.com *p++ = (c & ~0x20); 4789743Smax.romanov@nginx.com continue; 4790743Smax.romanov@nginx.com } 4791743Smax.romanov@nginx.com 4792743Smax.romanov@nginx.com if (c == '-') { 4793743Smax.romanov@nginx.com *p++ = '_'; 4794743Smax.romanov@nginx.com continue; 4795743Smax.romanov@nginx.com } 4796743Smax.romanov@nginx.com 4797743Smax.romanov@nginx.com *p++ = c; 4798743Smax.romanov@nginx.com } 4799743Smax.romanov@nginx.com 4800743Smax.romanov@nginx.com } else { 4801743Smax.romanov@nginx.com nxt_unit_sptr_set(&dst_field->name, p); 4802743Smax.romanov@nginx.com p = nxt_cpymem(p, field->name, field->name_length); 4803743Smax.romanov@nginx.com } 4804743Smax.romanov@nginx.com 4805743Smax.romanov@nginx.com *p++ = '\0'; 4806743Smax.romanov@nginx.com 4807743Smax.romanov@nginx.com nxt_unit_sptr_set(&dst_field->value, p); 4808743Smax.romanov@nginx.com p = nxt_cpymem(p, field->value, field->value_length); 4809743Smax.romanov@nginx.com 4810743Smax.romanov@nginx.com if (prefix->length != 0) { 4811743Smax.romanov@nginx.com dup_iter = iter; 4812743Smax.romanov@nginx.com 4813743Smax.romanov@nginx.com for (dup = nxt_fields_next(&dup_iter); 4814743Smax.romanov@nginx.com dup != NULL; 4815743Smax.romanov@nginx.com dup = nxt_fields_next(&dup_iter)) 4816743Smax.romanov@nginx.com { 4817743Smax.romanov@nginx.com if (dup->name_length != field->name_length 4818743Smax.romanov@nginx.com || dup->skip 4819743Smax.romanov@nginx.com || dup->hash != field->hash 4820743Smax.romanov@nginx.com || nxt_memcasecmp(dup->name, field->name, dup->name_length)) 4821743Smax.romanov@nginx.com { 4822743Smax.romanov@nginx.com continue; 4823743Smax.romanov@nginx.com } 4824743Smax.romanov@nginx.com 4825743Smax.romanov@nginx.com p = nxt_cpymem(p, ", ", 2); 4826743Smax.romanov@nginx.com p = nxt_cpymem(p, dup->value, dup->value_length); 4827743Smax.romanov@nginx.com 4828743Smax.romanov@nginx.com dst_field->value_length += 2 + dup->value_length; 4829743Smax.romanov@nginx.com 4830743Smax.romanov@nginx.com dup->skip = 1; 4831743Smax.romanov@nginx.com } 4832743Smax.romanov@nginx.com } 4833743Smax.romanov@nginx.com 4834743Smax.romanov@nginx.com *p++ = '\0'; 4835743Smax.romanov@nginx.com 4836743Smax.romanov@nginx.com dst_field++; 4837743Smax.romanov@nginx.com } 4838743Smax.romanov@nginx.com 4839*1007Salexander.borisov@nginx.com req->fields_count = (uint32_t) (dst_field - req->fields); 4840743Smax.romanov@nginx.com 4841743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->preread_content, out->mem.free); 4842743Smax.romanov@nginx.com 4843743Smax.romanov@nginx.com buf = out; 4844743Smax.romanov@nginx.com tail = &buf->next; 4845216Sigor@sysoev.ru 4846*1007Salexander.borisov@nginx.com for (b = r->body; b != NULL; b = b->next) { 4847743Smax.romanov@nginx.com size = nxt_buf_mem_used_size(&b->mem); 4848743Smax.romanov@nginx.com pos = b->mem.pos; 4849743Smax.romanov@nginx.com 4850743Smax.romanov@nginx.com while (size > 0) { 4851743Smax.romanov@nginx.com if (buf == NULL) { 4852743Smax.romanov@nginx.com free_size = nxt_min(size, PORT_MMAP_DATA_SIZE); 4853743Smax.romanov@nginx.com 4854743Smax.romanov@nginx.com buf = nxt_port_mmap_get_buf(task, port, free_size); 4855743Smax.romanov@nginx.com if (nxt_slow_path(buf == NULL)) { 4856743Smax.romanov@nginx.com while (out != NULL) { 4857743Smax.romanov@nginx.com buf = out->next; 4858743Smax.romanov@nginx.com out->completion_handler(task, out, out->parent); 4859743Smax.romanov@nginx.com out = buf; 4860743Smax.romanov@nginx.com } 4861743Smax.romanov@nginx.com return NULL; 4862743Smax.romanov@nginx.com } 4863743Smax.romanov@nginx.com 4864743Smax.romanov@nginx.com *tail = buf; 4865743Smax.romanov@nginx.com tail = &buf->next; 4866743Smax.romanov@nginx.com 4867743Smax.romanov@nginx.com } else { 4868743Smax.romanov@nginx.com free_size = nxt_buf_mem_free_size(&buf->mem); 4869743Smax.romanov@nginx.com if (free_size < size 4870743Smax.romanov@nginx.com && nxt_port_mmap_increase_buf(task, buf, size, 1) 4871743Smax.romanov@nginx.com == NXT_OK) 4872743Smax.romanov@nginx.com { 4873743Smax.romanov@nginx.com free_size = nxt_buf_mem_free_size(&buf->mem); 4874743Smax.romanov@nginx.com } 4875743Smax.romanov@nginx.com } 4876743Smax.romanov@nginx.com 4877743Smax.romanov@nginx.com if (free_size > 0) { 4878743Smax.romanov@nginx.com copy_size = nxt_min(free_size, size); 4879743Smax.romanov@nginx.com 4880743Smax.romanov@nginx.com buf->mem.free = nxt_cpymem(buf->mem.free, pos, copy_size); 4881743Smax.romanov@nginx.com 4882743Smax.romanov@nginx.com size -= copy_size; 4883743Smax.romanov@nginx.com pos += copy_size; 4884743Smax.romanov@nginx.com 4885743Smax.romanov@nginx.com if (size == 0) { 4886743Smax.romanov@nginx.com break; 4887743Smax.romanov@nginx.com } 4888743Smax.romanov@nginx.com } 4889743Smax.romanov@nginx.com 4890743Smax.romanov@nginx.com buf = NULL; 4891743Smax.romanov@nginx.com } 4892216Sigor@sysoev.ru } 4893216Sigor@sysoev.ru 4894743Smax.romanov@nginx.com return out; 4895584Salexander.borisov@nginx.com } 4896584Salexander.borisov@nginx.com 4897584Salexander.borisov@nginx.com 489853Sigor@sysoev.ru static void 4899318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data) 4900318Smax.romanov@nginx.com { 4901615Smax.romanov@nginx.com nxt_app_t *app; 4902615Smax.romanov@nginx.com nxt_bool_t cancelled, unlinked; 4903615Smax.romanov@nginx.com nxt_port_t *port; 4904615Smax.romanov@nginx.com nxt_timer_t *timer; 4905615Smax.romanov@nginx.com nxt_queue_link_t *lnk; 4906*1007Salexander.borisov@nginx.com nxt_http_request_t *r; 4907615Smax.romanov@nginx.com nxt_req_app_link_t *pending_ra; 4908615Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 4909615Smax.romanov@nginx.com nxt_port_select_state_t state; 4910318Smax.romanov@nginx.com 4911318Smax.romanov@nginx.com timer = obj; 4912318Smax.romanov@nginx.com 4913318Smax.romanov@nginx.com nxt_debug(task, "router app timeout"); 4914318Smax.romanov@nginx.com 4915*1007Salexander.borisov@nginx.com r = nxt_timer_data(timer, nxt_http_request_t, timer); 4916*1007Salexander.borisov@nginx.com rc = r->timer_data; 4917615Smax.romanov@nginx.com app = rc->app; 4918615Smax.romanov@nginx.com 4919615Smax.romanov@nginx.com if (app == NULL) { 4920615Smax.romanov@nginx.com goto generate_error; 4921615Smax.romanov@nginx.com } 4922615Smax.romanov@nginx.com 4923615Smax.romanov@nginx.com port = NULL; 4924615Smax.romanov@nginx.com pending_ra = NULL; 4925615Smax.romanov@nginx.com 4926615Smax.romanov@nginx.com if (rc->app_port != NULL) { 4927615Smax.romanov@nginx.com port = rc->app_port; 4928615Smax.romanov@nginx.com rc->app_port = NULL; 4929615Smax.romanov@nginx.com } 4930615Smax.romanov@nginx.com 4931615Smax.romanov@nginx.com if (port == NULL && rc->ra != NULL && rc->ra->app_port != NULL) { 4932615Smax.romanov@nginx.com port = rc->ra->app_port; 4933615Smax.romanov@nginx.com rc->ra->app_port = NULL; 4934615Smax.romanov@nginx.com } 4935615Smax.romanov@nginx.com 4936615Smax.romanov@nginx.com if (port == NULL) { 4937615Smax.romanov@nginx.com goto generate_error; 4938431Sigor@sysoev.ru } 4939615Smax.romanov@nginx.com 4940615Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4941615Smax.romanov@nginx.com 4942615Smax.romanov@nginx.com unlinked = nxt_queue_chk_remove(&port->app_link); 4943615Smax.romanov@nginx.com 4944615Smax.romanov@nginx.com if (!nxt_queue_is_empty(&port->pending_requests)) { 4945615Smax.romanov@nginx.com lnk = nxt_queue_first(&port->pending_requests); 4946615Smax.romanov@nginx.com 4947615Smax.romanov@nginx.com pending_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, 4948615Smax.romanov@nginx.com link_port_pending); 4949615Smax.romanov@nginx.com 4950615Smax.romanov@nginx.com nxt_assert(pending_ra->link_app_pending.next != NULL); 4951615Smax.romanov@nginx.com 4952615Smax.romanov@nginx.com nxt_debug(task, "app '%V' pending request #%uD found", 4953615Smax.romanov@nginx.com &app->name, pending_ra->stream); 4954615Smax.romanov@nginx.com 4955615Smax.romanov@nginx.com cancelled = nxt_router_msg_cancel(task, &pending_ra->msg_info, 4956615Smax.romanov@nginx.com pending_ra->stream); 4957615Smax.romanov@nginx.com 4958615Smax.romanov@nginx.com if (cancelled) { 4959615Smax.romanov@nginx.com nxt_router_ra_inc_use(pending_ra); 4960615Smax.romanov@nginx.com 4961615Smax.romanov@nginx.com state.ra = pending_ra; 4962615Smax.romanov@nginx.com state.app = app; 4963615Smax.romanov@nginx.com 4964615Smax.romanov@nginx.com nxt_router_port_select(task, &state); 4965615Smax.romanov@nginx.com 4966615Smax.romanov@nginx.com } else { 4967615Smax.romanov@nginx.com pending_ra = NULL; 4968615Smax.romanov@nginx.com } 4969615Smax.romanov@nginx.com } 4970615Smax.romanov@nginx.com 4971615Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4972615Smax.romanov@nginx.com 4973615Smax.romanov@nginx.com if (pending_ra != NULL 4974615Smax.romanov@nginx.com && nxt_router_port_post_select(task, &state) == NXT_OK) 4975615Smax.romanov@nginx.com { 4976615Smax.romanov@nginx.com nxt_router_app_prepare_request(task, pending_ra); 4977615Smax.romanov@nginx.com } 4978615Smax.romanov@nginx.com 4979615Smax.romanov@nginx.com nxt_debug(task, "send quit to app '%V' pid %PI", &app->name, port->pid); 4980615Smax.romanov@nginx.com 4981615Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 4982615Smax.romanov@nginx.com 4983615Smax.romanov@nginx.com nxt_port_use(task, port, unlinked ? -2 : -1); 4984615Smax.romanov@nginx.com 4985615Smax.romanov@nginx.com generate_error: 4986615Smax.romanov@nginx.com 4987*1007Salexander.borisov@nginx.com nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE); 4988615Smax.romanov@nginx.com 4989615Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 4990318Smax.romanov@nginx.com } 4991*1007Salexander.borisov@nginx.com 4992*1007Salexander.borisov@nginx.com 4993*1007Salexander.borisov@nginx.com static nxt_int_t 4994*1007Salexander.borisov@nginx.com nxt_router_http_request_done(nxt_task_t *task, nxt_http_request_t *r) 4995*1007Salexander.borisov@nginx.com { 4996*1007Salexander.borisov@nginx.com r->timer.handler = nxt_router_http_request_release; 4997*1007Salexander.borisov@nginx.com nxt_timer_add(task->thread->engine, &r->timer, 0); 4998*1007Salexander.borisov@nginx.com 4999*1007Salexander.borisov@nginx.com return NXT_OK; 5000*1007Salexander.borisov@nginx.com } 5001*1007Salexander.borisov@nginx.com 5002*1007Salexander.borisov@nginx.com 5003*1007Salexander.borisov@nginx.com static void 5004*1007Salexander.borisov@nginx.com nxt_router_http_request_release(nxt_task_t *task, void *obj, void *data) 5005*1007Salexander.borisov@nginx.com { 5006*1007Salexander.borisov@nginx.com nxt_http_request_t *r; 5007*1007Salexander.borisov@nginx.com 5008*1007Salexander.borisov@nginx.com nxt_debug(task, "http app release"); 5009*1007Salexander.borisov@nginx.com 5010*1007Salexander.borisov@nginx.com r = nxt_timer_data(obj, nxt_http_request_t, timer); 5011*1007Salexander.borisov@nginx.com 5012*1007Salexander.borisov@nginx.com nxt_mp_release(r->mem_pool); 5013*1007Salexander.borisov@nginx.com } 5014