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; 65431Sigor@sysoev.ru nxt_app_parse_ctx_t *ap; 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; 78167Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 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); 267743Smax.romanov@nginx.com static nxt_buf_t *nxt_router_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 268743Smax.romanov@nginx.com 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 285119Smax.romanov@nginx.com static nxt_router_t *nxt_router; 28620Sigor@sysoev.ru 287743Smax.romanov@nginx.com static const nxt_str_t http_prefix = nxt_string("HTTP_"); 288743Smax.romanov@nginx.com static const nxt_str_t empty_prefix = nxt_string(""); 289743Smax.romanov@nginx.com 290743Smax.romanov@nginx.com static const nxt_str_t *nxt_app_msg_prefix[] = { 291804Svbart@nginx.com &empty_prefix, 292743Smax.romanov@nginx.com &http_prefix, 293743Smax.romanov@nginx.com &http_prefix, 294743Smax.romanov@nginx.com &http_prefix, 295743Smax.romanov@nginx.com &http_prefix, 296*977Smax.romanov@gmail.com &empty_prefix, 297216Sigor@sysoev.ru }; 298216Sigor@sysoev.ru 299216Sigor@sysoev.ru 300662Smax.romanov@nginx.com nxt_port_handlers_t nxt_router_process_port_handlers = { 301662Smax.romanov@nginx.com .quit = nxt_worker_process_quit_handler, 302662Smax.romanov@nginx.com .new_port = nxt_router_new_port_handler, 303662Smax.romanov@nginx.com .change_file = nxt_port_change_log_file_handler, 304662Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 305662Smax.romanov@nginx.com .data = nxt_router_conf_data_handler, 306662Smax.romanov@nginx.com .remove_pid = nxt_router_remove_pid_handler, 307662Smax.romanov@nginx.com .access_log = nxt_router_access_log_reopen_handler, 308662Smax.romanov@nginx.com .rpc_ready = nxt_port_rpc_handler, 309662Smax.romanov@nginx.com .rpc_error = nxt_port_rpc_handler, 310662Smax.romanov@nginx.com }; 311662Smax.romanov@nginx.com 312662Smax.romanov@nginx.com 31320Sigor@sysoev.ru nxt_int_t 314141Smax.romanov@nginx.com nxt_router_start(nxt_task_t *task, void *data) 31520Sigor@sysoev.ru { 316141Smax.romanov@nginx.com nxt_int_t ret; 317662Smax.romanov@nginx.com nxt_port_t *controller_port; 318141Smax.romanov@nginx.com nxt_router_t *router; 319141Smax.romanov@nginx.com nxt_runtime_t *rt; 320141Smax.romanov@nginx.com 321141Smax.romanov@nginx.com rt = task->thread->runtime; 32253Sigor@sysoev.ru 323771Sigor@sysoev.ru #if (NXT_TLS) 324771Sigor@sysoev.ru rt->tls = nxt_service_get(rt->services, "SSL/TLS", "OpenSSL"); 325771Sigor@sysoev.ru if (nxt_slow_path(rt->tls == NULL)) { 326771Sigor@sysoev.ru return NXT_ERROR; 327771Sigor@sysoev.ru } 328771Sigor@sysoev.ru 329771Sigor@sysoev.ru ret = rt->tls->library_init(task); 330771Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 331771Sigor@sysoev.ru return ret; 332771Sigor@sysoev.ru } 333771Sigor@sysoev.ru #endif 334771Sigor@sysoev.ru 335431Sigor@sysoev.ru ret = nxt_http_init(task, rt); 33688Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 33788Smax.romanov@nginx.com return ret; 33888Smax.romanov@nginx.com } 33988Smax.romanov@nginx.com 34053Sigor@sysoev.ru router = nxt_zalloc(sizeof(nxt_router_t)); 34153Sigor@sysoev.ru if (nxt_slow_path(router == NULL)) { 34253Sigor@sysoev.ru return NXT_ERROR; 34353Sigor@sysoev.ru } 34453Sigor@sysoev.ru 34553Sigor@sysoev.ru nxt_queue_init(&router->engines); 34653Sigor@sysoev.ru nxt_queue_init(&router->sockets); 347133Sigor@sysoev.ru nxt_queue_init(&router->apps); 34853Sigor@sysoev.ru 349119Smax.romanov@nginx.com nxt_router = router; 350119Smax.romanov@nginx.com 351662Smax.romanov@nginx.com controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; 352662Smax.romanov@nginx.com if (controller_port != NULL) { 353662Smax.romanov@nginx.com nxt_router_greet_controller(task, controller_port); 354662Smax.romanov@nginx.com } 355662Smax.romanov@nginx.com 356115Sigor@sysoev.ru return NXT_OK; 357115Sigor@sysoev.ru } 358115Sigor@sysoev.ru 359115Sigor@sysoev.ru 360343Smax.romanov@nginx.com static void 361662Smax.romanov@nginx.com nxt_router_greet_controller(nxt_task_t *task, nxt_port_t *controller_port) 362662Smax.romanov@nginx.com { 363662Smax.romanov@nginx.com nxt_port_socket_write(task, controller_port, NXT_PORT_MSG_PROCESS_READY, 364662Smax.romanov@nginx.com -1, 0, 0, NULL); 365662Smax.romanov@nginx.com } 366662Smax.romanov@nginx.com 367662Smax.romanov@nginx.com 368662Smax.romanov@nginx.com static void 369507Smax.romanov@nginx.com nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port, 370507Smax.romanov@nginx.com void *data) 371167Smax.romanov@nginx.com { 372343Smax.romanov@nginx.com size_t size; 373343Smax.romanov@nginx.com uint32_t stream; 374430Sigor@sysoev.ru nxt_mp_t *mp; 375648Svbart@nginx.com nxt_int_t ret; 376343Smax.romanov@nginx.com nxt_app_t *app; 377343Smax.romanov@nginx.com nxt_buf_t *b; 378343Smax.romanov@nginx.com nxt_port_t *main_port; 379343Smax.romanov@nginx.com nxt_runtime_t *rt; 380343Smax.romanov@nginx.com 381343Smax.romanov@nginx.com app = data; 382167Smax.romanov@nginx.com 383167Smax.romanov@nginx.com rt = task->thread->runtime; 384240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 385167Smax.romanov@nginx.com 386507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start process", &app->name, app); 387343Smax.romanov@nginx.com 388343Smax.romanov@nginx.com size = app->name.length + 1 + app->conf.length; 389343Smax.romanov@nginx.com 390343Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size); 391343Smax.romanov@nginx.com 392343Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 393343Smax.romanov@nginx.com goto failed; 394167Smax.romanov@nginx.com } 395167Smax.romanov@nginx.com 396343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->name); 397343Smax.romanov@nginx.com *b->mem.free++ = '\0'; 398343Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 399343Smax.romanov@nginx.com 400753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, 1); 401753Smax.romanov@nginx.com 402343Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, port, 403343Smax.romanov@nginx.com nxt_router_app_port_ready, 404343Smax.romanov@nginx.com nxt_router_app_port_error, 405753Smax.romanov@nginx.com -1, app->joint); 406343Smax.romanov@nginx.com 407343Smax.romanov@nginx.com if (nxt_slow_path(stream == 0)) { 408753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, -1); 409753Smax.romanov@nginx.com 410343Smax.romanov@nginx.com goto failed; 411343Smax.romanov@nginx.com } 412343Smax.romanov@nginx.com 413648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1, 414648Svbart@nginx.com stream, port->id, b); 415648Svbart@nginx.com 416648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 417648Svbart@nginx.com nxt_port_rpc_cancel(task, port, stream); 418753Smax.romanov@nginx.com 419753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app->joint, -1); 420753Smax.romanov@nginx.com 421648Svbart@nginx.com goto failed; 422648Svbart@nginx.com } 423343Smax.romanov@nginx.com 424753Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 425753Smax.romanov@nginx.com 426343Smax.romanov@nginx.com return; 427343Smax.romanov@nginx.com 428343Smax.romanov@nginx.com failed: 429343Smax.romanov@nginx.com 430648Svbart@nginx.com if (b != NULL) { 431648Svbart@nginx.com mp = b->data; 432648Svbart@nginx.com nxt_mp_free(mp, b); 433648Svbart@nginx.com nxt_mp_release(mp); 434648Svbart@nginx.com } 435648Svbart@nginx.com 436343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 437343Smax.romanov@nginx.com 438507Smax.romanov@nginx.com app->pending_processes--; 439343Smax.romanov@nginx.com 440343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 441343Smax.romanov@nginx.com 442343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 443167Smax.romanov@nginx.com } 444167Smax.romanov@nginx.com 445167Smax.romanov@nginx.com 446753Smax.romanov@nginx.com static void 447753Smax.romanov@nginx.com nxt_router_app_joint_use(nxt_task_t *task, nxt_app_joint_t *app_joint, int i) 448753Smax.romanov@nginx.com { 449753Smax.romanov@nginx.com app_joint->use_count += i; 450753Smax.romanov@nginx.com 451753Smax.romanov@nginx.com if (app_joint->use_count == 0) { 452753Smax.romanov@nginx.com nxt_assert(app_joint->app == NULL); 453753Smax.romanov@nginx.com 454753Smax.romanov@nginx.com nxt_free(app_joint); 455753Smax.romanov@nginx.com } 456753Smax.romanov@nginx.com } 457753Smax.romanov@nginx.com 458753Smax.romanov@nginx.com 459343Smax.romanov@nginx.com static nxt_int_t 460507Smax.romanov@nginx.com nxt_router_start_app_process(nxt_task_t *task, nxt_app_t *app) 461141Smax.romanov@nginx.com { 462343Smax.romanov@nginx.com nxt_int_t res; 463343Smax.romanov@nginx.com nxt_port_t *router_port; 464343Smax.romanov@nginx.com nxt_runtime_t *rt; 465343Smax.romanov@nginx.com 466343Smax.romanov@nginx.com rt = task->thread->runtime; 467343Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 468343Smax.romanov@nginx.com 469343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 470343Smax.romanov@nginx.com 471507Smax.romanov@nginx.com res = nxt_port_post(task, router_port, nxt_router_start_app_process_handler, 472343Smax.romanov@nginx.com app); 473343Smax.romanov@nginx.com 474343Smax.romanov@nginx.com if (res == NXT_OK) { 475343Smax.romanov@nginx.com return res; 476318Smax.romanov@nginx.com } 477318Smax.romanov@nginx.com 478343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 479343Smax.romanov@nginx.com 480507Smax.romanov@nginx.com app->pending_processes--; 481343Smax.romanov@nginx.com 482343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 483343Smax.romanov@nginx.com 484343Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 485343Smax.romanov@nginx.com 486343Smax.romanov@nginx.com return NXT_ERROR; 487318Smax.romanov@nginx.com } 488318Smax.romanov@nginx.com 489318Smax.romanov@nginx.com 490351Smax.romanov@nginx.com nxt_inline void 491351Smax.romanov@nginx.com nxt_router_ra_init(nxt_task_t *task, nxt_req_app_link_t *ra, 492351Smax.romanov@nginx.com nxt_req_conn_link_t *rc) 493167Smax.romanov@nginx.com { 494318Smax.romanov@nginx.com nxt_event_engine_t *engine; 495351Smax.romanov@nginx.com 496318Smax.romanov@nginx.com engine = task->thread->engine; 497167Smax.romanov@nginx.com 498167Smax.romanov@nginx.com nxt_memzero(ra, sizeof(nxt_req_app_link_t)); 499167Smax.romanov@nginx.com 500318Smax.romanov@nginx.com ra->stream = rc->stream; 501425Smax.romanov@nginx.com ra->use_count = 1; 502167Smax.romanov@nginx.com ra->rc = rc; 503318Smax.romanov@nginx.com rc->ra = ra; 504318Smax.romanov@nginx.com ra->reply_port = engine->port; 505351Smax.romanov@nginx.com ra->ap = rc->ap; 506167Smax.romanov@nginx.com 507167Smax.romanov@nginx.com ra->work.handler = NULL; 508318Smax.romanov@nginx.com ra->work.task = &engine->task; 509167Smax.romanov@nginx.com ra->work.obj = ra; 510318Smax.romanov@nginx.com ra->work.data = engine; 511351Smax.romanov@nginx.com } 512351Smax.romanov@nginx.com 513351Smax.romanov@nginx.com 514351Smax.romanov@nginx.com nxt_inline nxt_req_app_link_t * 515351Smax.romanov@nginx.com nxt_router_ra_create(nxt_task_t *task, nxt_req_app_link_t *ra_src) 516351Smax.romanov@nginx.com { 517351Smax.romanov@nginx.com nxt_mp_t *mp; 518351Smax.romanov@nginx.com nxt_req_app_link_t *ra; 519351Smax.romanov@nginx.com 520425Smax.romanov@nginx.com if (ra_src->mem_pool != NULL) { 521425Smax.romanov@nginx.com return ra_src; 522425Smax.romanov@nginx.com } 523425Smax.romanov@nginx.com 524351Smax.romanov@nginx.com mp = ra_src->ap->mem_pool; 525351Smax.romanov@nginx.com 526430Sigor@sysoev.ru ra = nxt_mp_alloc(mp, sizeof(nxt_req_app_link_t)); 527351Smax.romanov@nginx.com 528351Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 529351Smax.romanov@nginx.com 530351Smax.romanov@nginx.com ra_src->rc->ra = NULL; 531351Smax.romanov@nginx.com ra_src->rc = NULL; 532351Smax.romanov@nginx.com 533351Smax.romanov@nginx.com return NULL; 534351Smax.romanov@nginx.com } 535351Smax.romanov@nginx.com 536430Sigor@sysoev.ru nxt_mp_retain(mp); 537430Sigor@sysoev.ru 538351Smax.romanov@nginx.com nxt_router_ra_init(task, ra, ra_src->rc); 539351Smax.romanov@nginx.com 540351Smax.romanov@nginx.com ra->mem_pool = mp; 541167Smax.romanov@nginx.com 542167Smax.romanov@nginx.com return ra; 543167Smax.romanov@nginx.com } 544167Smax.romanov@nginx.com 545167Smax.romanov@nginx.com 546423Smax.romanov@nginx.com nxt_inline nxt_bool_t 547423Smax.romanov@nginx.com nxt_router_msg_cancel(nxt_task_t *task, nxt_msg_info_t *msg_info, 548423Smax.romanov@nginx.com uint32_t stream) 549423Smax.romanov@nginx.com { 550423Smax.romanov@nginx.com nxt_buf_t *b, *next; 551423Smax.romanov@nginx.com nxt_bool_t cancelled; 552423Smax.romanov@nginx.com 553423Smax.romanov@nginx.com if (msg_info->buf == NULL) { 554423Smax.romanov@nginx.com return 0; 555423Smax.romanov@nginx.com } 556423Smax.romanov@nginx.com 557423Smax.romanov@nginx.com cancelled = nxt_port_mmap_tracking_cancel(task, &msg_info->tracking, 558423Smax.romanov@nginx.com stream); 559423Smax.romanov@nginx.com 560423Smax.romanov@nginx.com if (cancelled) { 561423Smax.romanov@nginx.com nxt_debug(task, "stream #%uD: cancelled by router", stream); 562423Smax.romanov@nginx.com } 563423Smax.romanov@nginx.com 564423Smax.romanov@nginx.com for (b = msg_info->buf; b != NULL; b = next) { 565423Smax.romanov@nginx.com next = b->next; 566423Smax.romanov@nginx.com 567423Smax.romanov@nginx.com b->completion_handler = msg_info->completion_handler; 568423Smax.romanov@nginx.com 569423Smax.romanov@nginx.com if (b->is_port_mmap_sent) { 570423Smax.romanov@nginx.com b->is_port_mmap_sent = cancelled == 0; 571423Smax.romanov@nginx.com b->completion_handler(task, b, b->parent); 572423Smax.romanov@nginx.com } 573423Smax.romanov@nginx.com } 574423Smax.romanov@nginx.com 575423Smax.romanov@nginx.com msg_info->buf = NULL; 576423Smax.romanov@nginx.com 577423Smax.romanov@nginx.com return cancelled; 578423Smax.romanov@nginx.com } 579423Smax.romanov@nginx.com 580423Smax.romanov@nginx.com 581167Smax.romanov@nginx.com static void 582425Smax.romanov@nginx.com nxt_router_ra_update_peer(nxt_task_t *task, nxt_req_app_link_t *ra); 583425Smax.romanov@nginx.com 584425Smax.romanov@nginx.com 585425Smax.romanov@nginx.com static void 586425Smax.romanov@nginx.com nxt_router_ra_update_peer_handler(nxt_task_t *task, void *obj, void *data) 587167Smax.romanov@nginx.com { 588425Smax.romanov@nginx.com nxt_req_app_link_t *ra; 589425Smax.romanov@nginx.com 590425Smax.romanov@nginx.com ra = obj; 591425Smax.romanov@nginx.com 592425Smax.romanov@nginx.com nxt_router_ra_update_peer(task, ra); 593425Smax.romanov@nginx.com 594425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 595425Smax.romanov@nginx.com } 596425Smax.romanov@nginx.com 597425Smax.romanov@nginx.com 598425Smax.romanov@nginx.com static void 599425Smax.romanov@nginx.com nxt_router_ra_update_peer(nxt_task_t *task, nxt_req_app_link_t *ra) 600425Smax.romanov@nginx.com { 601343Smax.romanov@nginx.com nxt_event_engine_t *engine; 602343Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 603318Smax.romanov@nginx.com 604425Smax.romanov@nginx.com engine = ra->work.data; 605318Smax.romanov@nginx.com 606343Smax.romanov@nginx.com if (task->thread->engine != engine) { 607425Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 608425Smax.romanov@nginx.com 609425Smax.romanov@nginx.com ra->work.handler = nxt_router_ra_update_peer_handler; 610318Smax.romanov@nginx.com ra->work.task = &engine->task; 611318Smax.romanov@nginx.com ra->work.next = NULL; 612318Smax.romanov@nginx.com 613425Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD post update peer to %p", 614318Smax.romanov@nginx.com ra->stream, engine); 615318Smax.romanov@nginx.com 616318Smax.romanov@nginx.com nxt_event_engine_post(engine, &ra->work); 617318Smax.romanov@nginx.com 618318Smax.romanov@nginx.com return; 619318Smax.romanov@nginx.com } 620318Smax.romanov@nginx.com 621425Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD update peer", ra->stream); 622425Smax.romanov@nginx.com 623425Smax.romanov@nginx.com rc = ra->rc; 624425Smax.romanov@nginx.com 625425Smax.romanov@nginx.com if (rc != NULL && ra->app_port != NULL) { 626425Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, engine->port, rc, ra->app_port->pid); 627425Smax.romanov@nginx.com } 628425Smax.romanov@nginx.com 629425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 630425Smax.romanov@nginx.com } 631425Smax.romanov@nginx.com 632425Smax.romanov@nginx.com 633425Smax.romanov@nginx.com static void 634425Smax.romanov@nginx.com nxt_router_ra_release(nxt_task_t *task, nxt_req_app_link_t *ra) 635425Smax.romanov@nginx.com { 636431Sigor@sysoev.ru nxt_mp_t *mp; 637431Sigor@sysoev.ru nxt_req_conn_link_t *rc; 638425Smax.romanov@nginx.com 639425Smax.romanov@nginx.com nxt_assert(task->thread->engine == ra->work.data); 640425Smax.romanov@nginx.com nxt_assert(ra->use_count == 0); 641425Smax.romanov@nginx.com 642343Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD release", ra->stream); 643343Smax.romanov@nginx.com 644343Smax.romanov@nginx.com rc = ra->rc; 645343Smax.romanov@nginx.com 646343Smax.romanov@nginx.com if (rc != NULL) { 647423Smax.romanov@nginx.com if (nxt_slow_path(ra->err_code != 0)) { 648431Sigor@sysoev.ru nxt_http_request_error(task, rc->ap->request, ra->err_code); 649423Smax.romanov@nginx.com 650423Smax.romanov@nginx.com } else { 651423Smax.romanov@nginx.com rc->app_port = ra->app_port; 652423Smax.romanov@nginx.com rc->msg_info = ra->msg_info; 653423Smax.romanov@nginx.com 654425Smax.romanov@nginx.com if (rc->app->timeout != 0) { 655431Sigor@sysoev.ru rc->ap->timer.handler = nxt_router_app_timeout; 656615Smax.romanov@nginx.com rc->ap->timer_data = rc; 657431Sigor@sysoev.ru nxt_timer_add(task->thread->engine, &rc->ap->timer, 658425Smax.romanov@nginx.com rc->app->timeout); 659425Smax.romanov@nginx.com } 660425Smax.romanov@nginx.com 661423Smax.romanov@nginx.com ra->app_port = NULL; 662423Smax.romanov@nginx.com ra->msg_info.buf = NULL; 663423Smax.romanov@nginx.com } 664343Smax.romanov@nginx.com 665343Smax.romanov@nginx.com rc->ra = NULL; 666343Smax.romanov@nginx.com ra->rc = NULL; 667343Smax.romanov@nginx.com } 668343Smax.romanov@nginx.com 669343Smax.romanov@nginx.com if (ra->app_port != NULL) { 670343Smax.romanov@nginx.com nxt_router_app_port_release(task, ra->app_port, 0, 1); 671343Smax.romanov@nginx.com 672343Smax.romanov@nginx.com ra->app_port = NULL; 673167Smax.romanov@nginx.com } 674167Smax.romanov@nginx.com 675423Smax.romanov@nginx.com nxt_router_msg_cancel(task, &ra->msg_info, ra->stream); 676423Smax.romanov@nginx.com 677430Sigor@sysoev.ru mp = ra->mem_pool; 678430Sigor@sysoev.ru 679430Sigor@sysoev.ru if (mp != NULL) { 680430Sigor@sysoev.ru nxt_mp_free(mp, ra); 681430Sigor@sysoev.ru nxt_mp_release(mp); 682351Smax.romanov@nginx.com } 683167Smax.romanov@nginx.com } 684167Smax.romanov@nginx.com 685167Smax.romanov@nginx.com 686425Smax.romanov@nginx.com static void 687425Smax.romanov@nginx.com nxt_router_ra_release_handler(nxt_task_t *task, void *obj, void *data) 688425Smax.romanov@nginx.com { 689425Smax.romanov@nginx.com nxt_req_app_link_t *ra; 690425Smax.romanov@nginx.com 691425Smax.romanov@nginx.com ra = obj; 692425Smax.romanov@nginx.com 693425Smax.romanov@nginx.com nxt_assert(ra->work.data == data); 694425Smax.romanov@nginx.com 695425Smax.romanov@nginx.com nxt_atomic_fetch_add(&ra->use_count, -1); 696425Smax.romanov@nginx.com 697425Smax.romanov@nginx.com nxt_router_ra_release(task, ra); 698425Smax.romanov@nginx.com } 699425Smax.romanov@nginx.com 700425Smax.romanov@nginx.com 701425Smax.romanov@nginx.com static void 702425Smax.romanov@nginx.com nxt_router_ra_use(nxt_task_t *task, nxt_req_app_link_t *ra, int i) 703425Smax.romanov@nginx.com { 704425Smax.romanov@nginx.com int c; 705425Smax.romanov@nginx.com nxt_event_engine_t *engine; 706425Smax.romanov@nginx.com 707425Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&ra->use_count, i); 708425Smax.romanov@nginx.com 709425Smax.romanov@nginx.com if (i < 0 && c == -i) { 710425Smax.romanov@nginx.com engine = ra->work.data; 711425Smax.romanov@nginx.com 712425Smax.romanov@nginx.com if (task->thread->engine == engine) { 713425Smax.romanov@nginx.com nxt_router_ra_release(task, ra); 714425Smax.romanov@nginx.com 715425Smax.romanov@nginx.com return; 716425Smax.romanov@nginx.com } 717425Smax.romanov@nginx.com 718425Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 719425Smax.romanov@nginx.com 720425Smax.romanov@nginx.com ra->work.handler = nxt_router_ra_release_handler; 721425Smax.romanov@nginx.com ra->work.task = &engine->task; 722425Smax.romanov@nginx.com ra->work.next = NULL; 723425Smax.romanov@nginx.com 724425Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD post release to %p", 725425Smax.romanov@nginx.com ra->stream, engine); 726425Smax.romanov@nginx.com 727425Smax.romanov@nginx.com nxt_event_engine_post(engine, &ra->work); 728425Smax.romanov@nginx.com } 729425Smax.romanov@nginx.com } 730425Smax.romanov@nginx.com 731425Smax.romanov@nginx.com 732423Smax.romanov@nginx.com nxt_inline void 733521Szelenkov@nginx.com nxt_router_ra_error(nxt_req_app_link_t *ra, int code, const char *str) 734345Smax.romanov@nginx.com { 735423Smax.romanov@nginx.com ra->app_port = NULL; 736423Smax.romanov@nginx.com ra->err_code = code; 737423Smax.romanov@nginx.com ra->err_str = str; 738345Smax.romanov@nginx.com } 739345Smax.romanov@nginx.com 740345Smax.romanov@nginx.com 741427Smax.romanov@nginx.com nxt_inline void 742427Smax.romanov@nginx.com nxt_router_ra_pending(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra) 743427Smax.romanov@nginx.com { 744427Smax.romanov@nginx.com nxt_queue_insert_tail(&ra->app_port->pending_requests, 745427Smax.romanov@nginx.com &ra->link_port_pending); 746427Smax.romanov@nginx.com nxt_queue_insert_tail(&app->pending, &ra->link_app_pending); 747427Smax.romanov@nginx.com 748427Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 749427Smax.romanov@nginx.com 750427Smax.romanov@nginx.com ra->res_time = nxt_thread_monotonic_time(task->thread) + app->res_timeout; 751427Smax.romanov@nginx.com 752427Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD enqueue to pending_requests", ra->stream); 753427Smax.romanov@nginx.com } 754427Smax.romanov@nginx.com 755427Smax.romanov@nginx.com 756425Smax.romanov@nginx.com nxt_inline nxt_bool_t 757425Smax.romanov@nginx.com nxt_queue_chk_remove(nxt_queue_link_t *lnk) 758425Smax.romanov@nginx.com { 759425Smax.romanov@nginx.com if (lnk->next != NULL) { 760425Smax.romanov@nginx.com nxt_queue_remove(lnk); 761425Smax.romanov@nginx.com 762425Smax.romanov@nginx.com lnk->next = NULL; 763425Smax.romanov@nginx.com 764425Smax.romanov@nginx.com return 1; 765425Smax.romanov@nginx.com } 766425Smax.romanov@nginx.com 767425Smax.romanov@nginx.com return 0; 768425Smax.romanov@nginx.com } 769425Smax.romanov@nginx.com 770425Smax.romanov@nginx.com 771343Smax.romanov@nginx.com nxt_inline void 772343Smax.romanov@nginx.com nxt_router_rc_unlink(nxt_task_t *task, nxt_req_conn_link_t *rc) 773343Smax.romanov@nginx.com { 774425Smax.romanov@nginx.com int ra_use_delta; 775343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 776343Smax.romanov@nginx.com 777343Smax.romanov@nginx.com if (rc->app_port != NULL) { 778343Smax.romanov@nginx.com nxt_router_app_port_release(task, rc->app_port, 0, 1); 779343Smax.romanov@nginx.com 780343Smax.romanov@nginx.com rc->app_port = NULL; 781343Smax.romanov@nginx.com } 782343Smax.romanov@nginx.com 783423Smax.romanov@nginx.com nxt_router_msg_cancel(task, &rc->msg_info, rc->stream); 784423Smax.romanov@nginx.com 785343Smax.romanov@nginx.com ra = rc->ra; 786343Smax.romanov@nginx.com 787343Smax.romanov@nginx.com if (ra != NULL) { 788343Smax.romanov@nginx.com rc->ra = NULL; 789343Smax.romanov@nginx.com ra->rc = NULL; 790343Smax.romanov@nginx.com 791425Smax.romanov@nginx.com ra_use_delta = 0; 792425Smax.romanov@nginx.com 793343Smax.romanov@nginx.com nxt_thread_mutex_lock(&rc->app->mutex); 794343Smax.romanov@nginx.com 795425Smax.romanov@nginx.com if (ra->link_app_requests.next == NULL 796427Smax.romanov@nginx.com && ra->link_port_pending.next == NULL 797427Smax.romanov@nginx.com && ra->link_app_pending.next == NULL) 798425Smax.romanov@nginx.com { 799425Smax.romanov@nginx.com ra = NULL; 800343Smax.romanov@nginx.com 801343Smax.romanov@nginx.com } else { 802425Smax.romanov@nginx.com ra_use_delta -= nxt_queue_chk_remove(&ra->link_app_requests); 803425Smax.romanov@nginx.com ra_use_delta -= nxt_queue_chk_remove(&ra->link_port_pending); 804427Smax.romanov@nginx.com nxt_queue_chk_remove(&ra->link_app_pending); 805343Smax.romanov@nginx.com } 806343Smax.romanov@nginx.com 807343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&rc->app->mutex); 808425Smax.romanov@nginx.com 809425Smax.romanov@nginx.com if (ra != NULL) { 810425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, ra_use_delta); 811425Smax.romanov@nginx.com } 812343Smax.romanov@nginx.com } 813343Smax.romanov@nginx.com 814343Smax.romanov@nginx.com if (rc->app != NULL) { 815343Smax.romanov@nginx.com nxt_router_app_use(task, rc->app, -1); 816343Smax.romanov@nginx.com 817343Smax.romanov@nginx.com rc->app = NULL; 818343Smax.romanov@nginx.com } 819343Smax.romanov@nginx.com 820346Smax.romanov@nginx.com if (rc->ap != NULL) { 821615Smax.romanov@nginx.com rc->ap->timer_data = NULL; 822615Smax.romanov@nginx.com 823346Smax.romanov@nginx.com nxt_app_http_req_done(task, rc->ap); 824346Smax.romanov@nginx.com 825346Smax.romanov@nginx.com rc->ap = NULL; 826346Smax.romanov@nginx.com } 827343Smax.romanov@nginx.com } 828343Smax.romanov@nginx.com 829343Smax.romanov@nginx.com 830141Smax.romanov@nginx.com void 831141Smax.romanov@nginx.com nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 832141Smax.romanov@nginx.com { 833141Smax.romanov@nginx.com nxt_port_new_port_handler(task, msg); 834141Smax.romanov@nginx.com 835670Smax.romanov@nginx.com if (msg->u.new_port != NULL 836670Smax.romanov@nginx.com && msg->u.new_port->type == NXT_PROCESS_CONTROLLER) 837670Smax.romanov@nginx.com { 838662Smax.romanov@nginx.com nxt_router_greet_controller(task, msg->u.new_port); 839662Smax.romanov@nginx.com } 840662Smax.romanov@nginx.com 841192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 842141Smax.romanov@nginx.com return; 843141Smax.romanov@nginx.com } 844141Smax.romanov@nginx.com 845426Smax.romanov@nginx.com if (msg->u.new_port == NULL 846426Smax.romanov@nginx.com || msg->u.new_port->type != NXT_PROCESS_WORKER) 847347Smax.romanov@nginx.com { 848192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 849141Smax.romanov@nginx.com } 850192Smax.romanov@nginx.com 851192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 852141Smax.romanov@nginx.com } 853141Smax.romanov@nginx.com 854141Smax.romanov@nginx.com 855139Sigor@sysoev.ru void 856139Sigor@sysoev.ru nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 857115Sigor@sysoev.ru { 858198Sigor@sysoev.ru nxt_int_t ret; 859139Sigor@sysoev.ru nxt_buf_t *b; 860139Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 861139Sigor@sysoev.ru 862139Sigor@sysoev.ru tmcf = nxt_router_temp_conf(task); 863139Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 864139Sigor@sysoev.ru return; 86553Sigor@sysoev.ru } 86653Sigor@sysoev.ru 867494Spluknet@nginx.com nxt_debug(task, "nxt_router_conf_data_handler(%O): %*s", 868423Smax.romanov@nginx.com nxt_buf_used_size(msg->buf), 869493Spluknet@nginx.com (size_t) nxt_buf_used_size(msg->buf), msg->buf->mem.pos); 870423Smax.romanov@nginx.com 871591Sigor@sysoev.ru tmcf->router_conf->router = nxt_router; 872139Sigor@sysoev.ru tmcf->stream = msg->port_msg.stream; 873139Sigor@sysoev.ru tmcf->port = nxt_runtime_port_find(task->thread->runtime, 874198Sigor@sysoev.ru msg->port_msg.pid, 875198Sigor@sysoev.ru msg->port_msg.reply_port); 876198Sigor@sysoev.ru 877779Smax.romanov@nginx.com if (nxt_slow_path(tmcf->port == NULL)) { 878779Smax.romanov@nginx.com nxt_alert(task, "reply port not found"); 879779Smax.romanov@nginx.com 880779Smax.romanov@nginx.com return; 881779Smax.romanov@nginx.com } 882779Smax.romanov@nginx.com 883779Smax.romanov@nginx.com nxt_port_use(task, tmcf->port, 1); 884779Smax.romanov@nginx.com 885591Sigor@sysoev.ru b = nxt_buf_chk_make_plain(tmcf->router_conf->mem_pool, 886591Sigor@sysoev.ru msg->buf, msg->size); 887551Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 888551Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 889551Smax.romanov@nginx.com 890551Smax.romanov@nginx.com return; 891551Smax.romanov@nginx.com } 892551Smax.romanov@nginx.com 893198Sigor@sysoev.ru ret = nxt_router_conf_create(task, tmcf, b->mem.pos, b->mem.free); 894198Sigor@sysoev.ru 895198Sigor@sysoev.ru if (nxt_fast_path(ret == NXT_OK)) { 896198Sigor@sysoev.ru nxt_router_conf_apply(task, tmcf, NULL); 897198Sigor@sysoev.ru 898198Sigor@sysoev.ru } else { 899198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 900139Sigor@sysoev.ru } 90153Sigor@sysoev.ru } 90253Sigor@sysoev.ru 90353Sigor@sysoev.ru 904347Smax.romanov@nginx.com static void 905507Smax.romanov@nginx.com nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port, 906507Smax.romanov@nginx.com void *data) 907347Smax.romanov@nginx.com { 908347Smax.romanov@nginx.com union { 909347Smax.romanov@nginx.com nxt_pid_t removed_pid; 910347Smax.romanov@nginx.com void *data; 911347Smax.romanov@nginx.com } u; 912347Smax.romanov@nginx.com 913347Smax.romanov@nginx.com u.data = data; 914347Smax.romanov@nginx.com 915347Smax.romanov@nginx.com nxt_port_rpc_remove_peer(task, port, u.removed_pid); 916347Smax.romanov@nginx.com } 917347Smax.romanov@nginx.com 918347Smax.romanov@nginx.com 919192Smax.romanov@nginx.com void 920192Smax.romanov@nginx.com nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 921192Smax.romanov@nginx.com { 922347Smax.romanov@nginx.com nxt_event_engine_t *engine; 923318Smax.romanov@nginx.com 924192Smax.romanov@nginx.com nxt_port_remove_pid_handler(task, msg); 925192Smax.romanov@nginx.com 926192Smax.romanov@nginx.com if (msg->port_msg.stream == 0) { 927192Smax.romanov@nginx.com return; 928192Smax.romanov@nginx.com } 929192Smax.romanov@nginx.com 930318Smax.romanov@nginx.com nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0) 931318Smax.romanov@nginx.com { 932507Smax.romanov@nginx.com nxt_port_post(task, engine->port, nxt_router_app_process_remove_pid, 933347Smax.romanov@nginx.com msg->u.data); 934318Smax.romanov@nginx.com } 935318Smax.romanov@nginx.com nxt_queue_loop; 936318Smax.romanov@nginx.com 937192Smax.romanov@nginx.com msg->port_msg.type = _NXT_PORT_MSG_RPC_ERROR; 938192Smax.romanov@nginx.com 939192Smax.romanov@nginx.com nxt_port_rpc_handler(task, msg); 940192Smax.romanov@nginx.com } 941192Smax.romanov@nginx.com 942192Smax.romanov@nginx.com 94353Sigor@sysoev.ru static nxt_router_temp_conf_t * 944139Sigor@sysoev.ru nxt_router_temp_conf(nxt_task_t *task) 94553Sigor@sysoev.ru { 94665Sigor@sysoev.ru nxt_mp_t *mp, *tmp; 94753Sigor@sysoev.ru nxt_router_conf_t *rtcf; 94853Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 94953Sigor@sysoev.ru 95065Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 95153Sigor@sysoev.ru if (nxt_slow_path(mp == NULL)) { 95253Sigor@sysoev.ru return NULL; 95353Sigor@sysoev.ru } 95453Sigor@sysoev.ru 95565Sigor@sysoev.ru rtcf = nxt_mp_zget(mp, sizeof(nxt_router_conf_t)); 95653Sigor@sysoev.ru if (nxt_slow_path(rtcf == NULL)) { 95753Sigor@sysoev.ru goto fail; 95853Sigor@sysoev.ru } 95953Sigor@sysoev.ru 96053Sigor@sysoev.ru rtcf->mem_pool = mp; 96153Sigor@sysoev.ru 96265Sigor@sysoev.ru tmp = nxt_mp_create(1024, 128, 256, 32); 96353Sigor@sysoev.ru if (nxt_slow_path(tmp == NULL)) { 96453Sigor@sysoev.ru goto fail; 96553Sigor@sysoev.ru } 96653Sigor@sysoev.ru 96765Sigor@sysoev.ru tmcf = nxt_mp_zget(tmp, sizeof(nxt_router_temp_conf_t)); 96853Sigor@sysoev.ru if (nxt_slow_path(tmcf == NULL)) { 96953Sigor@sysoev.ru goto temp_fail; 97053Sigor@sysoev.ru } 97153Sigor@sysoev.ru 97253Sigor@sysoev.ru tmcf->mem_pool = tmp; 973591Sigor@sysoev.ru tmcf->router_conf = rtcf; 974139Sigor@sysoev.ru tmcf->count = 1; 975139Sigor@sysoev.ru tmcf->engine = task->thread->engine; 97653Sigor@sysoev.ru 97753Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, 4, 97853Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 97953Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 98053Sigor@sysoev.ru goto temp_fail; 98153Sigor@sysoev.ru } 98253Sigor@sysoev.ru 98353Sigor@sysoev.ru nxt_queue_init(&tmcf->deleting); 98453Sigor@sysoev.ru nxt_queue_init(&tmcf->keeping); 98553Sigor@sysoev.ru nxt_queue_init(&tmcf->updating); 98653Sigor@sysoev.ru nxt_queue_init(&tmcf->pending); 98753Sigor@sysoev.ru nxt_queue_init(&tmcf->creating); 988416Smax.romanov@nginx.com 989774Svbart@nginx.com #if (NXT_TLS) 990774Svbart@nginx.com nxt_queue_init(&tmcf->tls); 991774Svbart@nginx.com #endif 992774Svbart@nginx.com 993133Sigor@sysoev.ru nxt_queue_init(&tmcf->apps); 994133Sigor@sysoev.ru nxt_queue_init(&tmcf->previous); 99553Sigor@sysoev.ru 99653Sigor@sysoev.ru return tmcf; 99753Sigor@sysoev.ru 99853Sigor@sysoev.ru temp_fail: 99953Sigor@sysoev.ru 100065Sigor@sysoev.ru nxt_mp_destroy(tmp); 100153Sigor@sysoev.ru 100253Sigor@sysoev.ru fail: 100353Sigor@sysoev.ru 100465Sigor@sysoev.ru nxt_mp_destroy(mp); 100553Sigor@sysoev.ru 100653Sigor@sysoev.ru return NULL; 100753Sigor@sysoev.ru } 100853Sigor@sysoev.ru 100953Sigor@sysoev.ru 1010507Smax.romanov@nginx.com nxt_inline nxt_bool_t 1011507Smax.romanov@nginx.com nxt_router_app_can_start(nxt_app_t *app) 1012507Smax.romanov@nginx.com { 1013507Smax.romanov@nginx.com return app->processes + app->pending_processes < app->max_processes 1014507Smax.romanov@nginx.com && app->pending_processes < app->max_pending_processes; 1015507Smax.romanov@nginx.com } 1016507Smax.romanov@nginx.com 1017507Smax.romanov@nginx.com 1018507Smax.romanov@nginx.com nxt_inline nxt_bool_t 1019507Smax.romanov@nginx.com nxt_router_app_need_start(nxt_app_t *app) 1020507Smax.romanov@nginx.com { 1021507Smax.romanov@nginx.com return app->idle_processes + app->pending_processes 1022507Smax.romanov@nginx.com < app->spare_processes; 1023507Smax.romanov@nginx.com } 1024507Smax.romanov@nginx.com 1025507Smax.romanov@nginx.com 1026198Sigor@sysoev.ru static void 1027198Sigor@sysoev.ru nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data) 1028139Sigor@sysoev.ru { 1029139Sigor@sysoev.ru nxt_int_t ret; 1030507Smax.romanov@nginx.com nxt_app_t *app; 1031139Sigor@sysoev.ru nxt_router_t *router; 1032139Sigor@sysoev.ru nxt_runtime_t *rt; 1033198Sigor@sysoev.ru nxt_queue_link_t *qlk; 1034198Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1035630Svbart@nginx.com nxt_router_conf_t *rtcf; 1036198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf; 1037139Sigor@sysoev.ru const nxt_event_interface_t *interface; 1038774Svbart@nginx.com #if (NXT_TLS) 1039774Svbart@nginx.com nxt_router_tlssock_t *tls; 1040774Svbart@nginx.com #endif 1041139Sigor@sysoev.ru 1042198Sigor@sysoev.ru tmcf = obj; 1043198Sigor@sysoev.ru 1044198Sigor@sysoev.ru qlk = nxt_queue_first(&tmcf->pending); 1045198Sigor@sysoev.ru 1046198Sigor@sysoev.ru if (qlk != nxt_queue_tail(&tmcf->pending)) { 1047198Sigor@sysoev.ru nxt_queue_remove(qlk); 1048198Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->creating, qlk); 1049198Sigor@sysoev.ru 1050198Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1051198Sigor@sysoev.ru 1052198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(task, tmcf, skcf); 1053198Sigor@sysoev.ru 1054198Sigor@sysoev.ru return; 1055139Sigor@sysoev.ru } 1056139Sigor@sysoev.ru 1057774Svbart@nginx.com #if (NXT_TLS) 1058774Svbart@nginx.com qlk = nxt_queue_first(&tmcf->tls); 1059774Svbart@nginx.com 1060774Svbart@nginx.com if (qlk != nxt_queue_tail(&tmcf->tls)) { 1061774Svbart@nginx.com nxt_queue_remove(qlk); 1062774Svbart@nginx.com 1063774Svbart@nginx.com tls = nxt_queue_link_data(qlk, nxt_router_tlssock_t, link); 1064774Svbart@nginx.com 1065774Svbart@nginx.com nxt_router_tls_rpc_create(task, tmcf, tls); 1066774Svbart@nginx.com return; 1067774Svbart@nginx.com } 1068774Svbart@nginx.com #endif 1069774Svbart@nginx.com 1070507Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1071507Smax.romanov@nginx.com 1072507Smax.romanov@nginx.com if (nxt_router_app_need_start(app)) { 1073507Smax.romanov@nginx.com nxt_router_app_rpc_create(task, tmcf, app); 1074507Smax.romanov@nginx.com return; 1075507Smax.romanov@nginx.com } 1076507Smax.romanov@nginx.com 1077507Smax.romanov@nginx.com } nxt_queue_loop; 1078507Smax.romanov@nginx.com 1079630Svbart@nginx.com rtcf = tmcf->router_conf; 1080630Svbart@nginx.com 1081630Svbart@nginx.com if (rtcf->access_log != NULL && rtcf->access_log->fd == -1) { 1082630Svbart@nginx.com nxt_router_access_log_open(task, tmcf); 1083630Svbart@nginx.com return; 1084630Svbart@nginx.com } 1085630Svbart@nginx.com 1086139Sigor@sysoev.ru rt = task->thread->runtime; 1087139Sigor@sysoev.ru 1088139Sigor@sysoev.ru interface = nxt_service_get(rt->services, "engine", NULL); 1089139Sigor@sysoev.ru 1090630Svbart@nginx.com router = rtcf->router; 1091198Sigor@sysoev.ru 1092139Sigor@sysoev.ru ret = nxt_router_engines_create(task, router, tmcf, interface); 1093139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1094198Sigor@sysoev.ru goto fail; 1095139Sigor@sysoev.ru } 1096139Sigor@sysoev.ru 1097139Sigor@sysoev.ru ret = nxt_router_threads_create(task, rt, tmcf); 1098139Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1099198Sigor@sysoev.ru goto fail; 1100139Sigor@sysoev.ru } 1101139Sigor@sysoev.ru 1102343Smax.romanov@nginx.com nxt_router_apps_sort(task, router, tmcf); 1103139Sigor@sysoev.ru 1104315Sigor@sysoev.ru nxt_router_engines_post(router, tmcf); 1105139Sigor@sysoev.ru 1106139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->updating); 1107139Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->creating); 1108139Sigor@sysoev.ru 1109630Svbart@nginx.com router->access_log = rtcf->access_log; 1110630Svbart@nginx.com 1111198Sigor@sysoev.ru nxt_router_conf_ready(task, tmcf); 1112198Sigor@sysoev.ru 1113198Sigor@sysoev.ru return; 1114198Sigor@sysoev.ru 1115198Sigor@sysoev.ru fail: 1116198Sigor@sysoev.ru 1117198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 1118198Sigor@sysoev.ru 1119198Sigor@sysoev.ru return; 1120139Sigor@sysoev.ru } 1121139Sigor@sysoev.ru 1122139Sigor@sysoev.ru 1123139Sigor@sysoev.ru static void 1124139Sigor@sysoev.ru nxt_router_conf_wait(nxt_task_t *task, void *obj, void *data) 1125139Sigor@sysoev.ru { 1126153Sigor@sysoev.ru nxt_joint_job_t *job; 1127153Sigor@sysoev.ru 1128153Sigor@sysoev.ru job = obj; 1129153Sigor@sysoev.ru 1130198Sigor@sysoev.ru nxt_router_conf_ready(task, job->tmcf); 1131139Sigor@sysoev.ru } 1132139Sigor@sysoev.ru 1133139Sigor@sysoev.ru 1134139Sigor@sysoev.ru static void 1135198Sigor@sysoev.ru nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 1136139Sigor@sysoev.ru { 1137139Sigor@sysoev.ru nxt_debug(task, "temp conf count:%D", tmcf->count); 1138139Sigor@sysoev.ru 1139139Sigor@sysoev.ru if (--tmcf->count == 0) { 1140193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_READY_LAST); 1141139Sigor@sysoev.ru } 1142139Sigor@sysoev.ru } 1143139Sigor@sysoev.ru 1144139Sigor@sysoev.ru 1145139Sigor@sysoev.ru static void 1146139Sigor@sysoev.ru nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 1147139Sigor@sysoev.ru { 1148507Smax.romanov@nginx.com nxt_app_t *app; 1149568Smax.romanov@nginx.com nxt_queue_t new_socket_confs; 1150148Sigor@sysoev.ru nxt_socket_t s; 1151149Sigor@sysoev.ru nxt_router_t *router; 1152148Sigor@sysoev.ru nxt_queue_link_t *qlk; 1153148Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1154630Svbart@nginx.com nxt_router_conf_t *rtcf; 1155148Sigor@sysoev.ru 1156564Svbart@nginx.com nxt_alert(task, "failed to apply new conf"); 1157198Sigor@sysoev.ru 1158148Sigor@sysoev.ru for (qlk = nxt_queue_first(&tmcf->creating); 1159148Sigor@sysoev.ru qlk != nxt_queue_tail(&tmcf->creating); 1160148Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 1161148Sigor@sysoev.ru { 1162148Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1163359Sigor@sysoev.ru s = skcf->listen->socket; 1164148Sigor@sysoev.ru 1165148Sigor@sysoev.ru if (s != -1) { 1166148Sigor@sysoev.ru nxt_socket_close(task, s); 1167148Sigor@sysoev.ru } 1168148Sigor@sysoev.ru 1169359Sigor@sysoev.ru nxt_free(skcf->listen); 1170148Sigor@sysoev.ru } 1171148Sigor@sysoev.ru 1172568Smax.romanov@nginx.com nxt_queue_init(&new_socket_confs); 1173568Smax.romanov@nginx.com nxt_queue_add(&new_socket_confs, &tmcf->updating); 1174568Smax.romanov@nginx.com nxt_queue_add(&new_socket_confs, &tmcf->pending); 1175568Smax.romanov@nginx.com nxt_queue_add(&new_socket_confs, &tmcf->creating); 1176568Smax.romanov@nginx.com 1177964Sigor@sysoev.ru rtcf = tmcf->router_conf; 1178964Sigor@sysoev.ru 1179964Sigor@sysoev.ru nxt_http_routes_cleanup(task, rtcf->routes); 1180964Sigor@sysoev.ru 1181568Smax.romanov@nginx.com nxt_queue_each(skcf, &new_socket_confs, nxt_socket_conf_t, link) { 1182568Smax.romanov@nginx.com 1183964Sigor@sysoev.ru if (skcf->pass != NULL) { 1184964Sigor@sysoev.ru nxt_http_pass_cleanup(task, skcf->pass); 1185568Smax.romanov@nginx.com } 1186568Smax.romanov@nginx.com 1187568Smax.romanov@nginx.com } nxt_queue_loop; 1188568Smax.romanov@nginx.com 1189507Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1190507Smax.romanov@nginx.com 1191753Smax.romanov@nginx.com nxt_router_app_unlink(task, app); 1192507Smax.romanov@nginx.com 1193507Smax.romanov@nginx.com } nxt_queue_loop; 1194507Smax.romanov@nginx.com 1195630Svbart@nginx.com router = rtcf->router; 1196149Sigor@sysoev.ru 1197149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->keeping); 1198149Sigor@sysoev.ru nxt_queue_add(&router->sockets, &tmcf->deleting); 1199149Sigor@sysoev.ru 1200416Smax.romanov@nginx.com nxt_queue_add(&router->apps, &tmcf->previous); 1201416Smax.romanov@nginx.com 1202148Sigor@sysoev.ru // TODO: new engines and threads 1203148Sigor@sysoev.ru 1204630Svbart@nginx.com nxt_router_access_log_release(task, &router->lock, rtcf->access_log); 1205630Svbart@nginx.com 1206630Svbart@nginx.com nxt_mp_destroy(rtcf->mem_pool); 1207139Sigor@sysoev.ru 1208193Smax.romanov@nginx.com nxt_router_conf_send(task, tmcf, NXT_PORT_MSG_RPC_ERROR); 1209139Sigor@sysoev.ru } 1210139Sigor@sysoev.ru 1211139Sigor@sysoev.ru 1212139Sigor@sysoev.ru static void 1213139Sigor@sysoev.ru nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1214193Smax.romanov@nginx.com nxt_port_msg_type_t type) 1215139Sigor@sysoev.ru { 1216193Smax.romanov@nginx.com nxt_port_socket_write(task, tmcf->port, type, -1, tmcf->stream, 0, NULL); 1217779Smax.romanov@nginx.com 1218779Smax.romanov@nginx.com nxt_port_use(task, tmcf->port, -1); 1219779Smax.romanov@nginx.com 1220779Smax.romanov@nginx.com tmcf->port = NULL; 1221139Sigor@sysoev.ru } 1222139Sigor@sysoev.ru 1223139Sigor@sysoev.ru 1224115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_conf[] = { 1225115Sigor@sysoev.ru { 1226133Sigor@sysoev.ru nxt_string("listeners_threads"), 1227115Sigor@sysoev.ru NXT_CONF_MAP_INT32, 1228115Sigor@sysoev.ru offsetof(nxt_router_conf_t, threads), 1229115Sigor@sysoev.ru }, 1230115Sigor@sysoev.ru }; 1231115Sigor@sysoev.ru 1232115Sigor@sysoev.ru 1233133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_app_conf[] = { 1234115Sigor@sysoev.ru { 1235133Sigor@sysoev.ru nxt_string("type"), 1236115Sigor@sysoev.ru NXT_CONF_MAP_STR, 1237133Sigor@sysoev.ru offsetof(nxt_router_app_conf_t, type), 1238115Sigor@sysoev.ru }, 1239115Sigor@sysoev.ru 1240115Sigor@sysoev.ru { 1241507Smax.romanov@nginx.com nxt_string("limits"), 1242507Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 1243507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, limits_value), 1244133Sigor@sysoev.ru }, 1245318Smax.romanov@nginx.com 1246318Smax.romanov@nginx.com { 1247507Smax.romanov@nginx.com nxt_string("processes"), 1248507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1249507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, processes), 1250507Smax.romanov@nginx.com }, 1251507Smax.romanov@nginx.com 1252507Smax.romanov@nginx.com { 1253507Smax.romanov@nginx.com nxt_string("processes"), 1254318Smax.romanov@nginx.com NXT_CONF_MAP_PTR, 1255507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, processes_value), 1256318Smax.romanov@nginx.com }, 1257318Smax.romanov@nginx.com }; 1258318Smax.romanov@nginx.com 1259318Smax.romanov@nginx.com 1260318Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_limits_conf[] = { 1261318Smax.romanov@nginx.com { 1262318Smax.romanov@nginx.com nxt_string("timeout"), 1263318Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1264318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, timeout), 1265318Smax.romanov@nginx.com }, 1266318Smax.romanov@nginx.com 1267318Smax.romanov@nginx.com { 1268427Smax.romanov@nginx.com nxt_string("reschedule_timeout"), 1269427Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1270427Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, res_timeout), 1271427Smax.romanov@nginx.com }, 1272427Smax.romanov@nginx.com 1273427Smax.romanov@nginx.com { 1274318Smax.romanov@nginx.com nxt_string("requests"), 1275318Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1276318Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, requests), 1277318Smax.romanov@nginx.com }, 1278133Sigor@sysoev.ru }; 1279133Sigor@sysoev.ru 1280133Sigor@sysoev.ru 1281507Smax.romanov@nginx.com static nxt_conf_map_t nxt_router_app_processes_conf[] = { 1282507Smax.romanov@nginx.com { 1283507Smax.romanov@nginx.com nxt_string("spare"), 1284507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1285507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, spare_processes), 1286507Smax.romanov@nginx.com }, 1287507Smax.romanov@nginx.com 1288507Smax.romanov@nginx.com { 1289507Smax.romanov@nginx.com nxt_string("max"), 1290507Smax.romanov@nginx.com NXT_CONF_MAP_INT32, 1291507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, max_processes), 1292507Smax.romanov@nginx.com }, 1293507Smax.romanov@nginx.com 1294507Smax.romanov@nginx.com { 1295507Smax.romanov@nginx.com nxt_string("idle_timeout"), 1296507Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1297507Smax.romanov@nginx.com offsetof(nxt_router_app_conf_t, idle_timeout), 1298507Smax.romanov@nginx.com }, 1299507Smax.romanov@nginx.com }; 1300507Smax.romanov@nginx.com 1301507Smax.romanov@nginx.com 1302133Sigor@sysoev.ru static nxt_conf_map_t nxt_router_listener_conf[] = { 1303133Sigor@sysoev.ru { 1304964Sigor@sysoev.ru nxt_string("pass"), 1305964Sigor@sysoev.ru NXT_CONF_MAP_STR_COPY, 1306964Sigor@sysoev.ru offsetof(nxt_router_listener_conf_t, pass), 1307964Sigor@sysoev.ru }, 1308964Sigor@sysoev.ru 1309964Sigor@sysoev.ru { 1310133Sigor@sysoev.ru nxt_string("application"), 1311964Sigor@sysoev.ru NXT_CONF_MAP_STR_COPY, 1312133Sigor@sysoev.ru offsetof(nxt_router_listener_conf_t, application), 1313115Sigor@sysoev.ru }, 1314115Sigor@sysoev.ru }; 1315115Sigor@sysoev.ru 1316115Sigor@sysoev.ru 1317115Sigor@sysoev.ru static nxt_conf_map_t nxt_router_http_conf[] = { 1318115Sigor@sysoev.ru { 1319115Sigor@sysoev.ru nxt_string("header_buffer_size"), 1320115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 1321115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_buffer_size), 1322115Sigor@sysoev.ru }, 1323115Sigor@sysoev.ru 1324115Sigor@sysoev.ru { 1325115Sigor@sysoev.ru nxt_string("large_header_buffer_size"), 1326115Sigor@sysoev.ru NXT_CONF_MAP_SIZE, 1327115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, large_header_buffer_size), 1328115Sigor@sysoev.ru }, 1329115Sigor@sysoev.ru 1330115Sigor@sysoev.ru { 1331206Smax.romanov@nginx.com nxt_string("large_header_buffers"), 1332206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1333206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, large_header_buffers), 1334206Smax.romanov@nginx.com }, 1335206Smax.romanov@nginx.com 1336206Smax.romanov@nginx.com { 1337206Smax.romanov@nginx.com nxt_string("body_buffer_size"), 1338206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1339206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_buffer_size), 1340206Smax.romanov@nginx.com }, 1341206Smax.romanov@nginx.com 1342206Smax.romanov@nginx.com { 1343206Smax.romanov@nginx.com nxt_string("max_body_size"), 1344206Smax.romanov@nginx.com NXT_CONF_MAP_SIZE, 1345206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, max_body_size), 1346206Smax.romanov@nginx.com }, 1347206Smax.romanov@nginx.com 1348206Smax.romanov@nginx.com { 1349431Sigor@sysoev.ru nxt_string("idle_timeout"), 1350431Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1351431Sigor@sysoev.ru offsetof(nxt_socket_conf_t, idle_timeout), 1352431Sigor@sysoev.ru }, 1353431Sigor@sysoev.ru 1354431Sigor@sysoev.ru { 1355115Sigor@sysoev.ru nxt_string("header_read_timeout"), 1356115Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1357115Sigor@sysoev.ru offsetof(nxt_socket_conf_t, header_read_timeout), 1358115Sigor@sysoev.ru }, 1359206Smax.romanov@nginx.com 1360206Smax.romanov@nginx.com { 1361206Smax.romanov@nginx.com nxt_string("body_read_timeout"), 1362206Smax.romanov@nginx.com NXT_CONF_MAP_MSEC, 1363206Smax.romanov@nginx.com offsetof(nxt_socket_conf_t, body_read_timeout), 1364206Smax.romanov@nginx.com }, 1365431Sigor@sysoev.ru 1366431Sigor@sysoev.ru { 1367431Sigor@sysoev.ru nxt_string("send_timeout"), 1368431Sigor@sysoev.ru NXT_CONF_MAP_MSEC, 1369431Sigor@sysoev.ru offsetof(nxt_socket_conf_t, send_timeout), 1370431Sigor@sysoev.ru }, 1371115Sigor@sysoev.ru }; 1372115Sigor@sysoev.ru 1373115Sigor@sysoev.ru 137453Sigor@sysoev.ru static nxt_int_t 1375115Sigor@sysoev.ru nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1376115Sigor@sysoev.ru u_char *start, u_char *end) 137753Sigor@sysoev.ru { 1378133Sigor@sysoev.ru u_char *p; 1379133Sigor@sysoev.ru size_t size; 1380115Sigor@sysoev.ru nxt_mp_t *mp; 1381115Sigor@sysoev.ru uint32_t next; 1382115Sigor@sysoev.ru nxt_int_t ret; 1383630Svbart@nginx.com nxt_str_t name, path; 1384133Sigor@sysoev.ru nxt_app_t *app, *prev; 1385359Sigor@sysoev.ru nxt_router_t *router; 1386753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 1387630Svbart@nginx.com nxt_conf_value_t *conf, *http, *value; 1388133Sigor@sysoev.ru nxt_conf_value_t *applications, *application; 1389133Sigor@sysoev.ru nxt_conf_value_t *listeners, *listener; 1390964Sigor@sysoev.ru nxt_conf_value_t *routes_conf; 1391115Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1392964Sigor@sysoev.ru nxt_http_routes_t *routes; 1393507Smax.romanov@nginx.com nxt_event_engine_t *engine; 1394216Sigor@sysoev.ru nxt_app_lang_module_t *lang; 1395133Sigor@sysoev.ru nxt_router_app_conf_t apcf; 1396630Svbart@nginx.com nxt_router_access_log_t *access_log; 1397115Sigor@sysoev.ru nxt_router_listener_conf_t lscf; 1398774Svbart@nginx.com #if (NXT_TLS) 1399774Svbart@nginx.com nxt_router_tlssock_t *tls; 1400774Svbart@nginx.com #endif 1401115Sigor@sysoev.ru 1402716Svbart@nginx.com static nxt_str_t http_path = nxt_string("/settings/http"); 1403133Sigor@sysoev.ru static nxt_str_t applications_path = nxt_string("/applications"); 1404115Sigor@sysoev.ru static nxt_str_t listeners_path = nxt_string("/listeners"); 1405964Sigor@sysoev.ru static nxt_str_t routes_path = nxt_string("/routes"); 1406630Svbart@nginx.com static nxt_str_t access_log_path = nxt_string("/access_log"); 1407774Svbart@nginx.com #if (NXT_TLS) 1408774Svbart@nginx.com static nxt_str_t certificate_path = nxt_string("/tls/certificate"); 1409774Svbart@nginx.com #endif 1410115Sigor@sysoev.ru 1411208Svbart@nginx.com conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL); 1412115Sigor@sysoev.ru if (conf == NULL) { 1413564Svbart@nginx.com nxt_alert(task, "configuration parsing error"); 1414115Sigor@sysoev.ru return NXT_ERROR; 1415115Sigor@sysoev.ru } 1416115Sigor@sysoev.ru 1417591Sigor@sysoev.ru mp = tmcf->router_conf->mem_pool; 1418213Svbart@nginx.com 1419213Svbart@nginx.com ret = nxt_conf_map_object(mp, conf, nxt_router_conf, 1420591Sigor@sysoev.ru nxt_nitems(nxt_router_conf), tmcf->router_conf); 1421115Sigor@sysoev.ru if (ret != NXT_OK) { 1422564Svbart@nginx.com nxt_alert(task, "root map error"); 1423115Sigor@sysoev.ru return NXT_ERROR; 1424115Sigor@sysoev.ru } 1425115Sigor@sysoev.ru 1426591Sigor@sysoev.ru if (tmcf->router_conf->threads == 0) { 1427591Sigor@sysoev.ru tmcf->router_conf->threads = nxt_ncpu; 1428117Sigor@sysoev.ru } 1429117Sigor@sysoev.ru 1430133Sigor@sysoev.ru applications = nxt_conf_get_path(conf, &applications_path); 1431133Sigor@sysoev.ru if (applications == NULL) { 1432564Svbart@nginx.com nxt_alert(task, "no \"applications\" block"); 1433115Sigor@sysoev.ru return NXT_ERROR; 1434115Sigor@sysoev.ru } 1435115Sigor@sysoev.ru 1436591Sigor@sysoev.ru router = tmcf->router_conf->router; 1437359Sigor@sysoev.ru 1438133Sigor@sysoev.ru next = 0; 1439133Sigor@sysoev.ru 1440133Sigor@sysoev.ru for ( ;; ) { 1441133Sigor@sysoev.ru application = nxt_conf_next_object_member(applications, &name, &next); 1442133Sigor@sysoev.ru if (application == NULL) { 1443133Sigor@sysoev.ru break; 1444133Sigor@sysoev.ru } 1445133Sigor@sysoev.ru 1446133Sigor@sysoev.ru nxt_debug(task, "application \"%V\"", &name); 1447133Sigor@sysoev.ru 1448144Smax.romanov@nginx.com size = nxt_conf_json_length(application, NULL); 1449144Smax.romanov@nginx.com 1450144Smax.romanov@nginx.com app = nxt_malloc(sizeof(nxt_app_t) + name.length + size); 1451133Sigor@sysoev.ru if (app == NULL) { 1452133Sigor@sysoev.ru goto fail; 1453133Sigor@sysoev.ru } 1454133Sigor@sysoev.ru 1455144Smax.romanov@nginx.com nxt_memzero(app, sizeof(nxt_app_t)); 1456144Smax.romanov@nginx.com 1457144Smax.romanov@nginx.com app->name.start = nxt_pointer_to(app, sizeof(nxt_app_t)); 1458144Smax.romanov@nginx.com app->conf.start = nxt_pointer_to(app, sizeof(nxt_app_t) + name.length); 1459133Sigor@sysoev.ru 1460133Sigor@sysoev.ru p = nxt_conf_json_print(app->conf.start, application, NULL); 1461133Sigor@sysoev.ru app->conf.length = p - app->conf.start; 1462133Sigor@sysoev.ru 1463144Smax.romanov@nginx.com nxt_assert(app->conf.length <= size); 1464144Smax.romanov@nginx.com 1465133Sigor@sysoev.ru nxt_debug(task, "application conf \"%V\"", &app->conf); 1466133Sigor@sysoev.ru 1467359Sigor@sysoev.ru prev = nxt_router_app_find(&router->apps, &name); 1468133Sigor@sysoev.ru 1469133Sigor@sysoev.ru if (prev != NULL && nxt_strstr_eq(&app->conf, &prev->conf)) { 1470133Sigor@sysoev.ru nxt_free(app); 1471133Sigor@sysoev.ru 1472133Sigor@sysoev.ru nxt_queue_remove(&prev->link); 1473133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->previous, &prev->link); 1474133Sigor@sysoev.ru continue; 1475133Sigor@sysoev.ru } 1476133Sigor@sysoev.ru 1477507Smax.romanov@nginx.com apcf.processes = 1; 1478507Smax.romanov@nginx.com apcf.max_processes = 1; 1479537Svbart@nginx.com apcf.spare_processes = 0; 1480318Smax.romanov@nginx.com apcf.timeout = 0; 1481427Smax.romanov@nginx.com apcf.res_timeout = 1000; 1482507Smax.romanov@nginx.com apcf.idle_timeout = 15000; 1483318Smax.romanov@nginx.com apcf.requests = 0; 1484318Smax.romanov@nginx.com apcf.limits_value = NULL; 1485507Smax.romanov@nginx.com apcf.processes_value = NULL; 1486263Smax.romanov@nginx.com 1487753Smax.romanov@nginx.com app_joint = nxt_malloc(sizeof(nxt_app_joint_t)); 1488753Smax.romanov@nginx.com if (nxt_slow_path(app_joint == NULL)) { 1489753Smax.romanov@nginx.com goto app_fail; 1490753Smax.romanov@nginx.com } 1491753Smax.romanov@nginx.com 1492753Smax.romanov@nginx.com nxt_memzero(app_joint, sizeof(nxt_app_joint_t)); 1493753Smax.romanov@nginx.com 1494213Svbart@nginx.com ret = nxt_conf_map_object(mp, application, nxt_router_app_conf, 1495136Svbart@nginx.com nxt_nitems(nxt_router_app_conf), &apcf); 1496133Sigor@sysoev.ru if (ret != NXT_OK) { 1497564Svbart@nginx.com nxt_alert(task, "application map error"); 1498133Sigor@sysoev.ru goto app_fail; 1499133Sigor@sysoev.ru } 1500115Sigor@sysoev.ru 1501318Smax.romanov@nginx.com if (apcf.limits_value != NULL) { 1502318Smax.romanov@nginx.com 1503318Smax.romanov@nginx.com if (nxt_conf_type(apcf.limits_value) != NXT_CONF_OBJECT) { 1504564Svbart@nginx.com nxt_alert(task, "application limits is not object"); 1505318Smax.romanov@nginx.com goto app_fail; 1506318Smax.romanov@nginx.com } 1507318Smax.romanov@nginx.com 1508318Smax.romanov@nginx.com ret = nxt_conf_map_object(mp, apcf.limits_value, 1509318Smax.romanov@nginx.com nxt_router_app_limits_conf, 1510318Smax.romanov@nginx.com nxt_nitems(nxt_router_app_limits_conf), 1511318Smax.romanov@nginx.com &apcf); 1512318Smax.romanov@nginx.com if (ret != NXT_OK) { 1513564Svbart@nginx.com nxt_alert(task, "application limits map error"); 1514318Smax.romanov@nginx.com goto app_fail; 1515318Smax.romanov@nginx.com } 1516318Smax.romanov@nginx.com } 1517318Smax.romanov@nginx.com 1518507Smax.romanov@nginx.com if (apcf.processes_value != NULL 1519507Smax.romanov@nginx.com && nxt_conf_type(apcf.processes_value) == NXT_CONF_OBJECT) 1520507Smax.romanov@nginx.com { 1521507Smax.romanov@nginx.com ret = nxt_conf_map_object(mp, apcf.processes_value, 1522507Smax.romanov@nginx.com nxt_router_app_processes_conf, 1523507Smax.romanov@nginx.com nxt_nitems(nxt_router_app_processes_conf), 1524507Smax.romanov@nginx.com &apcf); 1525507Smax.romanov@nginx.com if (ret != NXT_OK) { 1526564Svbart@nginx.com nxt_alert(task, "application processes map error"); 1527507Smax.romanov@nginx.com goto app_fail; 1528507Smax.romanov@nginx.com } 1529507Smax.romanov@nginx.com 1530507Smax.romanov@nginx.com } else { 1531507Smax.romanov@nginx.com apcf.max_processes = apcf.processes; 1532507Smax.romanov@nginx.com apcf.spare_processes = apcf.processes; 1533507Smax.romanov@nginx.com } 1534507Smax.romanov@nginx.com 1535133Sigor@sysoev.ru nxt_debug(task, "application type: %V", &apcf.type); 1536507Smax.romanov@nginx.com nxt_debug(task, "application processes: %D", apcf.processes); 1537507Smax.romanov@nginx.com nxt_debug(task, "application request timeout: %M", apcf.timeout); 1538507Smax.romanov@nginx.com nxt_debug(task, "application reschedule timeout: %M", apcf.res_timeout); 1539318Smax.romanov@nginx.com nxt_debug(task, "application requests: %D", apcf.requests); 1540133Sigor@sysoev.ru 1541216Sigor@sysoev.ru lang = nxt_app_lang_module(task->thread->runtime, &apcf.type); 1542216Sigor@sysoev.ru 1543216Sigor@sysoev.ru if (lang == NULL) { 1544564Svbart@nginx.com nxt_alert(task, "unknown application type: \"%V\"", &apcf.type); 1545141Smax.romanov@nginx.com goto app_fail; 1546141Smax.romanov@nginx.com } 1547141Smax.romanov@nginx.com 1548216Sigor@sysoev.ru nxt_debug(task, "application language module: \"%s\"", lang->file); 1549216Sigor@sysoev.ru 1550133Sigor@sysoev.ru ret = nxt_thread_mutex_create(&app->mutex); 1551133Sigor@sysoev.ru if (ret != NXT_OK) { 1552133Sigor@sysoev.ru goto app_fail; 1553133Sigor@sysoev.ru } 1554133Sigor@sysoev.ru 1555141Smax.romanov@nginx.com nxt_queue_init(&app->ports); 1556507Smax.romanov@nginx.com nxt_queue_init(&app->spare_ports); 1557507Smax.romanov@nginx.com nxt_queue_init(&app->idle_ports); 1558141Smax.romanov@nginx.com nxt_queue_init(&app->requests); 1559427Smax.romanov@nginx.com nxt_queue_init(&app->pending); 1560141Smax.romanov@nginx.com 1561144Smax.romanov@nginx.com app->name.length = name.length; 1562144Smax.romanov@nginx.com nxt_memcpy(app->name.start, name.start, name.length); 1563144Smax.romanov@nginx.com 1564356Svbart@nginx.com app->type = lang->type; 1565507Smax.romanov@nginx.com app->max_processes = apcf.max_processes; 1566507Smax.romanov@nginx.com app->spare_processes = apcf.spare_processes; 1567507Smax.romanov@nginx.com app->max_pending_processes = apcf.spare_processes 1568507Smax.romanov@nginx.com ? apcf.spare_processes : 1; 1569318Smax.romanov@nginx.com app->timeout = apcf.timeout; 1570427Smax.romanov@nginx.com app->res_timeout = apcf.res_timeout * 1000000; 1571507Smax.romanov@nginx.com app->idle_timeout = apcf.idle_timeout; 1572343Smax.romanov@nginx.com app->max_pending_responses = 2; 1573428Smax.romanov@nginx.com app->max_requests = apcf.requests; 1574133Sigor@sysoev.ru 1575507Smax.romanov@nginx.com engine = task->thread->engine; 1576507Smax.romanov@nginx.com 1577507Smax.romanov@nginx.com app->engine = engine; 1578507Smax.romanov@nginx.com 1579507Smax.romanov@nginx.com app->adjust_idle_work.handler = nxt_router_adjust_idle_timer; 1580507Smax.romanov@nginx.com app->adjust_idle_work.task = &engine->task; 1581507Smax.romanov@nginx.com app->adjust_idle_work.obj = app; 1582507Smax.romanov@nginx.com 1583133Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->apps, &app->link); 1584343Smax.romanov@nginx.com 1585343Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 1586753Smax.romanov@nginx.com 1587753Smax.romanov@nginx.com app->joint = app_joint; 1588753Smax.romanov@nginx.com 1589753Smax.romanov@nginx.com app_joint->use_count = 1; 1590753Smax.romanov@nginx.com app_joint->app = app; 1591753Smax.romanov@nginx.com 1592811Svbart@nginx.com app_joint->idle_timer.bias = NXT_TIMER_DEFAULT_BIAS; 1593753Smax.romanov@nginx.com app_joint->idle_timer.work_queue = &engine->fast_work_queue; 1594753Smax.romanov@nginx.com app_joint->idle_timer.handler = nxt_router_app_idle_timeout; 1595753Smax.romanov@nginx.com app_joint->idle_timer.task = &engine->task; 1596753Smax.romanov@nginx.com app_joint->idle_timer.log = app_joint->idle_timer.task->log; 1597753Smax.romanov@nginx.com 1598753Smax.romanov@nginx.com app_joint->free_app_work.handler = nxt_router_free_app; 1599753Smax.romanov@nginx.com app_joint->free_app_work.task = &engine->task; 1600753Smax.romanov@nginx.com app_joint->free_app_work.obj = app_joint; 1601133Sigor@sysoev.ru } 1602133Sigor@sysoev.ru 1603964Sigor@sysoev.ru routes_conf = nxt_conf_get_path(conf, &routes_path); 1604964Sigor@sysoev.ru if (nxt_fast_path(routes_conf != NULL)) { 1605964Sigor@sysoev.ru routes = nxt_http_routes_create(task, tmcf, routes_conf); 1606964Sigor@sysoev.ru if (nxt_slow_path(routes == NULL)) { 1607964Sigor@sysoev.ru return NXT_ERROR; 1608964Sigor@sysoev.ru } 1609964Sigor@sysoev.ru tmcf->router_conf->routes = routes; 1610964Sigor@sysoev.ru } 1611964Sigor@sysoev.ru 1612133Sigor@sysoev.ru http = nxt_conf_get_path(conf, &http_path); 1613133Sigor@sysoev.ru #if 0 1614133Sigor@sysoev.ru if (http == NULL) { 1615564Svbart@nginx.com nxt_alert(task, "no \"http\" block"); 1616133Sigor@sysoev.ru return NXT_ERROR; 1617133Sigor@sysoev.ru } 1618133Sigor@sysoev.ru #endif 1619133Sigor@sysoev.ru 1620133Sigor@sysoev.ru listeners = nxt_conf_get_path(conf, &listeners_path); 1621115Sigor@sysoev.ru if (listeners == NULL) { 1622564Svbart@nginx.com nxt_alert(task, "no \"listeners\" block"); 1623115Sigor@sysoev.ru return NXT_ERROR; 1624115Sigor@sysoev.ru } 162553Sigor@sysoev.ru 1626133Sigor@sysoev.ru next = 0; 162753Sigor@sysoev.ru 1628115Sigor@sysoev.ru for ( ;; ) { 1629115Sigor@sysoev.ru listener = nxt_conf_next_object_member(listeners, &name, &next); 1630115Sigor@sysoev.ru if (listener == NULL) { 1631115Sigor@sysoev.ru break; 1632115Sigor@sysoev.ru } 163353Sigor@sysoev.ru 1634359Sigor@sysoev.ru skcf = nxt_router_socket_conf(task, tmcf, &name); 1635115Sigor@sysoev.ru if (skcf == NULL) { 1636133Sigor@sysoev.ru goto fail; 1637115Sigor@sysoev.ru } 163853Sigor@sysoev.ru 1639770Smax.romanov@nginx.com nxt_memzero(&lscf, sizeof(lscf)); 1640770Smax.romanov@nginx.com 1641213Svbart@nginx.com ret = nxt_conf_map_object(mp, listener, nxt_router_listener_conf, 1642136Svbart@nginx.com nxt_nitems(nxt_router_listener_conf), &lscf); 1643115Sigor@sysoev.ru if (ret != NXT_OK) { 1644564Svbart@nginx.com nxt_alert(task, "listener map error"); 1645133Sigor@sysoev.ru goto fail; 1646115Sigor@sysoev.ru } 164753Sigor@sysoev.ru 1648133Sigor@sysoev.ru nxt_debug(task, "application: %V", &lscf.application); 1649133Sigor@sysoev.ru 1650133Sigor@sysoev.ru // STUB, default values if http block is not defined. 1651133Sigor@sysoev.ru skcf->header_buffer_size = 2048; 1652133Sigor@sysoev.ru skcf->large_header_buffer_size = 8192; 1653206Smax.romanov@nginx.com skcf->large_header_buffers = 4; 1654206Smax.romanov@nginx.com skcf->body_buffer_size = 16 * 1024; 1655715Svbart@nginx.com skcf->max_body_size = 8 * 1024 * 1024; 1656715Svbart@nginx.com skcf->idle_timeout = 180 * 1000; 1657715Svbart@nginx.com skcf->header_read_timeout = 30 * 1000; 1658715Svbart@nginx.com skcf->body_read_timeout = 30 * 1000; 1659715Svbart@nginx.com skcf->send_timeout = 30 * 1000; 166053Sigor@sysoev.ru 1661133Sigor@sysoev.ru if (http != NULL) { 1662213Svbart@nginx.com ret = nxt_conf_map_object(mp, http, nxt_router_http_conf, 1663136Svbart@nginx.com nxt_nitems(nxt_router_http_conf), skcf); 1664133Sigor@sysoev.ru if (ret != NXT_OK) { 1665564Svbart@nginx.com nxt_alert(task, "http map error"); 1666133Sigor@sysoev.ru goto fail; 1667133Sigor@sysoev.ru } 1668115Sigor@sysoev.ru } 1669115Sigor@sysoev.ru 1670774Svbart@nginx.com #if (NXT_TLS) 1671774Svbart@nginx.com 1672774Svbart@nginx.com value = nxt_conf_get_path(listener, &certificate_path); 1673774Svbart@nginx.com 1674774Svbart@nginx.com if (value != NULL) { 1675774Svbart@nginx.com nxt_conf_get_string(value, &name); 1676774Svbart@nginx.com 1677774Svbart@nginx.com tls = nxt_mp_get(mp, sizeof(nxt_router_tlssock_t)); 1678774Svbart@nginx.com if (nxt_slow_path(tls == NULL)) { 1679774Svbart@nginx.com goto fail; 1680774Svbart@nginx.com } 1681774Svbart@nginx.com 1682774Svbart@nginx.com tls->name = name; 1683774Svbart@nginx.com tls->conf = skcf; 1684774Svbart@nginx.com 1685774Svbart@nginx.com nxt_queue_insert_tail(&tmcf->tls, &tls->link); 1686774Svbart@nginx.com } 1687774Svbart@nginx.com 1688774Svbart@nginx.com #endif 1689774Svbart@nginx.com 1690431Sigor@sysoev.ru skcf->listen->handler = nxt_http_conn_init; 1691591Sigor@sysoev.ru skcf->router_conf = tmcf->router_conf; 1692160Sigor@sysoev.ru skcf->router_conf->count++; 1693770Smax.romanov@nginx.com 1694964Sigor@sysoev.ru if (lscf.pass.length != 0) { 1695964Sigor@sysoev.ru skcf->pass = nxt_http_pass_create(task, tmcf, &lscf.pass); 1696964Sigor@sysoev.ru 1697964Sigor@sysoev.ru /* COMPATIBILITY: listener application. */ 1698964Sigor@sysoev.ru } else if (lscf.application.length > 0) { 1699964Sigor@sysoev.ru skcf->pass = nxt_http_pass_application(task, tmcf, 1700964Sigor@sysoev.ru &lscf.application); 1701770Smax.romanov@nginx.com } 1702115Sigor@sysoev.ru } 170353Sigor@sysoev.ru 1704630Svbart@nginx.com value = nxt_conf_get_path(conf, &access_log_path); 1705630Svbart@nginx.com 1706630Svbart@nginx.com if (value != NULL) { 1707630Svbart@nginx.com nxt_conf_get_string(value, &path); 1708630Svbart@nginx.com 1709630Svbart@nginx.com access_log = router->access_log; 1710630Svbart@nginx.com 1711630Svbart@nginx.com if (access_log != NULL && nxt_strstr_eq(&path, &access_log->path)) { 1712630Svbart@nginx.com nxt_thread_spin_lock(&router->lock); 1713630Svbart@nginx.com access_log->count++; 1714630Svbart@nginx.com nxt_thread_spin_unlock(&router->lock); 1715630Svbart@nginx.com 1716630Svbart@nginx.com } else { 1717630Svbart@nginx.com access_log = nxt_malloc(sizeof(nxt_router_access_log_t) 1718630Svbart@nginx.com + path.length); 1719630Svbart@nginx.com if (access_log == NULL) { 1720630Svbart@nginx.com nxt_alert(task, "failed to allocate access log structure"); 1721630Svbart@nginx.com goto fail; 1722630Svbart@nginx.com } 1723630Svbart@nginx.com 1724630Svbart@nginx.com access_log->fd = -1; 1725630Svbart@nginx.com access_log->handler = &nxt_router_access_log_writer; 1726630Svbart@nginx.com access_log->count = 1; 1727630Svbart@nginx.com 1728630Svbart@nginx.com access_log->path.length = path.length; 1729630Svbart@nginx.com access_log->path.start = (u_char *) access_log 1730630Svbart@nginx.com + sizeof(nxt_router_access_log_t); 1731630Svbart@nginx.com 1732630Svbart@nginx.com nxt_memcpy(access_log->path.start, path.start, path.length); 1733630Svbart@nginx.com } 1734630Svbart@nginx.com 1735630Svbart@nginx.com tmcf->router_conf->access_log = access_log; 1736630Svbart@nginx.com } 1737630Svbart@nginx.com 1738964Sigor@sysoev.ru nxt_http_routes_resolve(task, tmcf); 1739964Sigor@sysoev.ru 1740359Sigor@sysoev.ru nxt_queue_add(&tmcf->deleting, &router->sockets); 1741359Sigor@sysoev.ru nxt_queue_init(&router->sockets); 1742198Sigor@sysoev.ru 174353Sigor@sysoev.ru return NXT_OK; 1744133Sigor@sysoev.ru 1745133Sigor@sysoev.ru app_fail: 1746133Sigor@sysoev.ru 1747133Sigor@sysoev.ru nxt_free(app); 1748133Sigor@sysoev.ru 1749133Sigor@sysoev.ru fail: 1750133Sigor@sysoev.ru 1751141Smax.romanov@nginx.com nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { 1752141Smax.romanov@nginx.com 1753141Smax.romanov@nginx.com nxt_queue_remove(&app->link); 1754133Sigor@sysoev.ru nxt_thread_mutex_destroy(&app->mutex); 1755133Sigor@sysoev.ru nxt_free(app); 1756141Smax.romanov@nginx.com 1757141Smax.romanov@nginx.com } nxt_queue_loop; 1758133Sigor@sysoev.ru 1759133Sigor@sysoev.ru return NXT_ERROR; 1760133Sigor@sysoev.ru } 1761133Sigor@sysoev.ru 1762133Sigor@sysoev.ru 1763133Sigor@sysoev.ru static nxt_app_t * 1764133Sigor@sysoev.ru nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name) 1765133Sigor@sysoev.ru { 1766141Smax.romanov@nginx.com nxt_app_t *app; 1767141Smax.romanov@nginx.com 1768141Smax.romanov@nginx.com nxt_queue_each(app, queue, nxt_app_t, link) { 1769133Sigor@sysoev.ru 1770133Sigor@sysoev.ru if (nxt_strstr_eq(name, &app->name)) { 1771133Sigor@sysoev.ru return app; 1772133Sigor@sysoev.ru } 1773141Smax.romanov@nginx.com 1774141Smax.romanov@nginx.com } nxt_queue_loop; 1775133Sigor@sysoev.ru 1776133Sigor@sysoev.ru return NULL; 1777133Sigor@sysoev.ru } 1778133Sigor@sysoev.ru 1779133Sigor@sysoev.ru 1780964Sigor@sysoev.ru nxt_app_t * 1781133Sigor@sysoev.ru nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, nxt_str_t *name) 1782133Sigor@sysoev.ru { 1783133Sigor@sysoev.ru nxt_app_t *app; 1784133Sigor@sysoev.ru 1785133Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->apps, name); 1786133Sigor@sysoev.ru 1787133Sigor@sysoev.ru if (app == NULL) { 1788134Sigor@sysoev.ru app = nxt_router_app_find(&tmcf->previous, name); 1789133Sigor@sysoev.ru } 1790133Sigor@sysoev.ru 1791133Sigor@sysoev.ru return app; 179253Sigor@sysoev.ru } 179353Sigor@sysoev.ru 179453Sigor@sysoev.ru 179553Sigor@sysoev.ru static nxt_socket_conf_t * 1796359Sigor@sysoev.ru nxt_router_socket_conf(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 1797359Sigor@sysoev.ru nxt_str_t *name) 179853Sigor@sysoev.ru { 1799359Sigor@sysoev.ru size_t size; 1800359Sigor@sysoev.ru nxt_int_t ret; 1801359Sigor@sysoev.ru nxt_bool_t wildcard; 1802359Sigor@sysoev.ru nxt_sockaddr_t *sa; 1803359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1804359Sigor@sysoev.ru nxt_listen_socket_t *ls; 1805359Sigor@sysoev.ru 1806359Sigor@sysoev.ru sa = nxt_sockaddr_parse(tmcf->mem_pool, name); 1807359Sigor@sysoev.ru if (nxt_slow_path(sa == NULL)) { 1808564Svbart@nginx.com nxt_alert(task, "invalid listener \"%V\"", name); 1809359Sigor@sysoev.ru return NULL; 1810359Sigor@sysoev.ru } 1811359Sigor@sysoev.ru 1812359Sigor@sysoev.ru sa->type = SOCK_STREAM; 1813359Sigor@sysoev.ru 1814359Sigor@sysoev.ru nxt_debug(task, "router listener: \"%*s\"", 1815493Spluknet@nginx.com (size_t) sa->length, nxt_sockaddr_start(sa)); 1816359Sigor@sysoev.ru 1817591Sigor@sysoev.ru skcf = nxt_mp_zget(tmcf->router_conf->mem_pool, sizeof(nxt_socket_conf_t)); 1818163Smax.romanov@nginx.com if (nxt_slow_path(skcf == NULL)) { 181953Sigor@sysoev.ru return NULL; 182053Sigor@sysoev.ru } 182153Sigor@sysoev.ru 1822359Sigor@sysoev.ru size = nxt_sockaddr_size(sa); 1823359Sigor@sysoev.ru 1824359Sigor@sysoev.ru ret = nxt_router_listen_socket_find(tmcf, skcf, sa); 1825359Sigor@sysoev.ru 1826359Sigor@sysoev.ru if (ret != NXT_OK) { 1827359Sigor@sysoev.ru 1828359Sigor@sysoev.ru ls = nxt_zalloc(sizeof(nxt_listen_socket_t) + size); 1829359Sigor@sysoev.ru if (nxt_slow_path(ls == NULL)) { 1830359Sigor@sysoev.ru return NULL; 1831359Sigor@sysoev.ru } 1832359Sigor@sysoev.ru 1833359Sigor@sysoev.ru skcf->listen = ls; 1834359Sigor@sysoev.ru 1835359Sigor@sysoev.ru ls->sockaddr = nxt_pointer_to(ls, sizeof(nxt_listen_socket_t)); 1836359Sigor@sysoev.ru nxt_memcpy(ls->sockaddr, sa, size); 1837359Sigor@sysoev.ru 1838359Sigor@sysoev.ru nxt_listen_socket_remote_size(ls); 1839359Sigor@sysoev.ru 1840359Sigor@sysoev.ru ls->socket = -1; 1841359Sigor@sysoev.ru ls->backlog = NXT_LISTEN_BACKLOG; 1842359Sigor@sysoev.ru ls->flags = NXT_NONBLOCK; 1843359Sigor@sysoev.ru ls->read_after_accept = 1; 1844359Sigor@sysoev.ru } 1845359Sigor@sysoev.ru 1846359Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) { 1847359Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN) 1848359Sigor@sysoev.ru case AF_UNIX: 1849359Sigor@sysoev.ru wildcard = 0; 1850359Sigor@sysoev.ru break; 1851359Sigor@sysoev.ru #endif 1852359Sigor@sysoev.ru #if (NXT_INET6) 1853359Sigor@sysoev.ru case AF_INET6: 1854359Sigor@sysoev.ru wildcard = IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr); 1855359Sigor@sysoev.ru break; 1856359Sigor@sysoev.ru #endif 1857359Sigor@sysoev.ru case AF_INET: 1858359Sigor@sysoev.ru default: 1859359Sigor@sysoev.ru wildcard = (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY); 1860359Sigor@sysoev.ru break; 1861359Sigor@sysoev.ru } 1862359Sigor@sysoev.ru 1863359Sigor@sysoev.ru if (!wildcard) { 1864591Sigor@sysoev.ru skcf->sockaddr = nxt_mp_zget(tmcf->router_conf->mem_pool, size); 1865359Sigor@sysoev.ru if (nxt_slow_path(skcf->sockaddr == NULL)) { 1866359Sigor@sysoev.ru return NULL; 1867359Sigor@sysoev.ru } 1868359Sigor@sysoev.ru 1869359Sigor@sysoev.ru nxt_memcpy(skcf->sockaddr, sa, size); 1870359Sigor@sysoev.ru } 1871163Smax.romanov@nginx.com 1872163Smax.romanov@nginx.com return skcf; 187353Sigor@sysoev.ru } 187453Sigor@sysoev.ru 187553Sigor@sysoev.ru 1876359Sigor@sysoev.ru static nxt_int_t 1877359Sigor@sysoev.ru nxt_router_listen_socket_find(nxt_router_temp_conf_t *tmcf, 1878359Sigor@sysoev.ru nxt_socket_conf_t *nskcf, nxt_sockaddr_t *sa) 187953Sigor@sysoev.ru { 1880359Sigor@sysoev.ru nxt_router_t *router; 1881359Sigor@sysoev.ru nxt_queue_link_t *qlk; 1882359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 1883359Sigor@sysoev.ru 1884591Sigor@sysoev.ru router = tmcf->router_conf->router; 1885359Sigor@sysoev.ru 1886359Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->sockets); 1887359Sigor@sysoev.ru qlk != nxt_queue_tail(&router->sockets); 1888359Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 188953Sigor@sysoev.ru { 1890359Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 1891359Sigor@sysoev.ru 1892359Sigor@sysoev.ru if (nxt_sockaddr_cmp(skcf->listen->sockaddr, sa)) { 1893359Sigor@sysoev.ru nskcf->listen = skcf->listen; 1894359Sigor@sysoev.ru 1895359Sigor@sysoev.ru nxt_queue_remove(qlk); 1896359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->keeping, qlk); 1897359Sigor@sysoev.ru 1898359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->updating, &nskcf->link); 1899359Sigor@sysoev.ru 1900359Sigor@sysoev.ru return NXT_OK; 190153Sigor@sysoev.ru } 190253Sigor@sysoev.ru } 190353Sigor@sysoev.ru 1904359Sigor@sysoev.ru nxt_queue_insert_tail(&tmcf->pending, &nskcf->link); 1905359Sigor@sysoev.ru 1906359Sigor@sysoev.ru return NXT_DECLINED; 190753Sigor@sysoev.ru } 190853Sigor@sysoev.ru 190953Sigor@sysoev.ru 1910198Sigor@sysoev.ru static void 1911198Sigor@sysoev.ru nxt_router_listen_socket_rpc_create(nxt_task_t *task, 1912198Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf) 1913198Sigor@sysoev.ru { 1914358Sigor@sysoev.ru size_t size; 1915198Sigor@sysoev.ru uint32_t stream; 1916648Svbart@nginx.com nxt_int_t ret; 1917198Sigor@sysoev.ru nxt_buf_t *b; 1918198Sigor@sysoev.ru nxt_port_t *main_port, *router_port; 1919198Sigor@sysoev.ru nxt_runtime_t *rt; 1920198Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 1921198Sigor@sysoev.ru 1922198Sigor@sysoev.ru rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t)); 1923198Sigor@sysoev.ru if (rpc == NULL) { 1924198Sigor@sysoev.ru goto fail; 1925198Sigor@sysoev.ru } 1926198Sigor@sysoev.ru 1927198Sigor@sysoev.ru rpc->socket_conf = skcf; 1928198Sigor@sysoev.ru rpc->temp_conf = tmcf; 1929198Sigor@sysoev.ru 1930359Sigor@sysoev.ru size = nxt_sockaddr_size(skcf->listen->sockaddr); 1931358Sigor@sysoev.ru 1932358Sigor@sysoev.ru b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 1933198Sigor@sysoev.ru if (b == NULL) { 1934198Sigor@sysoev.ru goto fail; 1935198Sigor@sysoev.ru } 1936198Sigor@sysoev.ru 1937359Sigor@sysoev.ru b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size); 1938198Sigor@sysoev.ru 1939198Sigor@sysoev.ru rt = task->thread->runtime; 1940240Sigor@sysoev.ru main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1941198Sigor@sysoev.ru router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 1942198Sigor@sysoev.ru 1943198Sigor@sysoev.ru stream = nxt_port_rpc_register_handler(task, router_port, 1944198Sigor@sysoev.ru nxt_router_listen_socket_ready, 1945198Sigor@sysoev.ru nxt_router_listen_socket_error, 1946198Sigor@sysoev.ru main_port->pid, rpc); 1947645Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 1948198Sigor@sysoev.ru goto fail; 1949198Sigor@sysoev.ru } 1950198Sigor@sysoev.ru 1951648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_SOCKET, -1, 1952648Svbart@nginx.com stream, router_port->id, b); 1953648Svbart@nginx.com 1954648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 1955648Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 1956648Svbart@nginx.com goto fail; 1957648Svbart@nginx.com } 1958198Sigor@sysoev.ru 1959198Sigor@sysoev.ru return; 1960198Sigor@sysoev.ru 1961198Sigor@sysoev.ru fail: 1962198Sigor@sysoev.ru 1963198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 1964198Sigor@sysoev.ru } 1965198Sigor@sysoev.ru 1966198Sigor@sysoev.ru 1967198Sigor@sysoev.ru static void 1968198Sigor@sysoev.ru nxt_router_listen_socket_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1969198Sigor@sysoev.ru void *data) 197053Sigor@sysoev.ru { 1971359Sigor@sysoev.ru nxt_int_t ret; 1972359Sigor@sysoev.ru nxt_socket_t s; 1973359Sigor@sysoev.ru nxt_socket_rpc_t *rpc; 197453Sigor@sysoev.ru 1975198Sigor@sysoev.ru rpc = data; 1976198Sigor@sysoev.ru 1977198Sigor@sysoev.ru s = msg->fd; 1978198Sigor@sysoev.ru 1979198Sigor@sysoev.ru ret = nxt_socket_nonblocking(task, s); 1980198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1981198Sigor@sysoev.ru goto fail; 198253Sigor@sysoev.ru } 198353Sigor@sysoev.ru 1984359Sigor@sysoev.ru nxt_socket_defer_accept(task, s, rpc->socket_conf->listen->sockaddr); 1985198Sigor@sysoev.ru 1986198Sigor@sysoev.ru ret = nxt_listen_socket(task, s, NXT_LISTEN_BACKLOG); 1987198Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 1988198Sigor@sysoev.ru goto fail; 1989198Sigor@sysoev.ru } 1990198Sigor@sysoev.ru 1991359Sigor@sysoev.ru rpc->socket_conf->listen->socket = s; 1992198Sigor@sysoev.ru 1993198Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 1994198Sigor@sysoev.ru nxt_router_conf_apply, task, rpc->temp_conf, NULL); 1995198Sigor@sysoev.ru 1996198Sigor@sysoev.ru return; 1997148Sigor@sysoev.ru 1998148Sigor@sysoev.ru fail: 1999148Sigor@sysoev.ru 2000148Sigor@sysoev.ru nxt_socket_close(task, s); 2001148Sigor@sysoev.ru 2002198Sigor@sysoev.ru nxt_router_conf_error(task, rpc->temp_conf); 2003198Sigor@sysoev.ru } 2004198Sigor@sysoev.ru 2005198Sigor@sysoev.ru 2006198Sigor@sysoev.ru static void 2007198Sigor@sysoev.ru nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2008198Sigor@sysoev.ru void *data) 2009198Sigor@sysoev.ru { 2010955Svbart@nginx.com nxt_socket_rpc_t *rpc; 2011955Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 2012955Svbart@nginx.com 2013955Svbart@nginx.com rpc = data; 2014955Svbart@nginx.com tmcf = rpc->temp_conf; 2015955Svbart@nginx.com 2016955Svbart@nginx.com #if 0 2017198Sigor@sysoev.ru u_char *p; 2018198Sigor@sysoev.ru size_t size; 2019198Sigor@sysoev.ru uint8_t error; 2020198Sigor@sysoev.ru nxt_buf_t *in, *out; 2021198Sigor@sysoev.ru nxt_sockaddr_t *sa; 2022198Sigor@sysoev.ru 2023198Sigor@sysoev.ru static nxt_str_t socket_errors[] = { 2024198Sigor@sysoev.ru nxt_string("ListenerSystem"), 2025198Sigor@sysoev.ru nxt_string("ListenerNoIPv6"), 2026198Sigor@sysoev.ru nxt_string("ListenerPort"), 2027198Sigor@sysoev.ru nxt_string("ListenerInUse"), 2028198Sigor@sysoev.ru nxt_string("ListenerNoAddress"), 2029198Sigor@sysoev.ru nxt_string("ListenerNoAccess"), 2030198Sigor@sysoev.ru nxt_string("ListenerPath"), 2031198Sigor@sysoev.ru }; 2032198Sigor@sysoev.ru 2033359Sigor@sysoev.ru sa = rpc->socket_conf->listen->sockaddr; 2034352Smax.romanov@nginx.com 2035352Smax.romanov@nginx.com in = nxt_buf_chk_make_plain(tmcf->mem_pool, msg->buf, msg->size); 2036352Smax.romanov@nginx.com 2037551Smax.romanov@nginx.com if (nxt_slow_path(in == NULL)) { 2038551Smax.romanov@nginx.com return; 2039551Smax.romanov@nginx.com } 2040352Smax.romanov@nginx.com 2041198Sigor@sysoev.ru p = in->mem.pos; 2042198Sigor@sysoev.ru 2043198Sigor@sysoev.ru error = *p++; 2044198Sigor@sysoev.ru 2045703Svbart@nginx.com size = nxt_length("listen socket error: ") 2046703Svbart@nginx.com + nxt_length("{listener: \"\", code:\"\", message: \"\"}") 2047198Sigor@sysoev.ru + sa->length + socket_errors[error].length + (in->mem.free - p); 2048198Sigor@sysoev.ru 2049198Sigor@sysoev.ru out = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 2050198Sigor@sysoev.ru if (nxt_slow_path(out == NULL)) { 2051198Sigor@sysoev.ru return; 2052198Sigor@sysoev.ru } 2053198Sigor@sysoev.ru 2054198Sigor@sysoev.ru out->mem.free = nxt_sprintf(out->mem.free, out->mem.end, 2055198Sigor@sysoev.ru "listen socket error: " 2056198Sigor@sysoev.ru "{listener: \"%*s\", code:\"%V\", message: \"%*s\"}", 2057493Spluknet@nginx.com (size_t) sa->length, nxt_sockaddr_start(sa), 2058198Sigor@sysoev.ru &socket_errors[error], in->mem.free - p, p); 2059198Sigor@sysoev.ru 2060198Sigor@sysoev.ru nxt_debug(task, "%*s", out->mem.free - out->mem.pos, out->mem.pos); 2061955Svbart@nginx.com #endif 2062198Sigor@sysoev.ru 2063198Sigor@sysoev.ru nxt_router_conf_error(task, tmcf); 206453Sigor@sysoev.ru } 206553Sigor@sysoev.ru 206653Sigor@sysoev.ru 2067774Svbart@nginx.com #if (NXT_TLS) 2068774Svbart@nginx.com 2069774Svbart@nginx.com static void 2070774Svbart@nginx.com nxt_router_tls_rpc_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 2071774Svbart@nginx.com nxt_router_tlssock_t *tls) 2072774Svbart@nginx.com { 2073774Svbart@nginx.com nxt_socket_rpc_t *rpc; 2074774Svbart@nginx.com 2075774Svbart@nginx.com rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t)); 2076774Svbart@nginx.com if (rpc == NULL) { 2077774Svbart@nginx.com nxt_router_conf_error(task, tmcf); 2078774Svbart@nginx.com return; 2079774Svbart@nginx.com } 2080774Svbart@nginx.com 2081774Svbart@nginx.com rpc->socket_conf = tls->conf; 2082774Svbart@nginx.com rpc->temp_conf = tmcf; 2083774Svbart@nginx.com 2084774Svbart@nginx.com nxt_cert_store_get(task, &tls->name, tmcf->mem_pool, 2085774Svbart@nginx.com nxt_router_tls_rpc_handler, rpc); 2086774Svbart@nginx.com } 2087774Svbart@nginx.com 2088774Svbart@nginx.com 2089774Svbart@nginx.com static void 2090774Svbart@nginx.com nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2091774Svbart@nginx.com void *data) 2092774Svbart@nginx.com { 2093774Svbart@nginx.com nxt_mp_t *mp; 2094774Svbart@nginx.com nxt_int_t ret; 2095774Svbart@nginx.com nxt_tls_conf_t *tlscf; 2096774Svbart@nginx.com nxt_socket_rpc_t *rpc; 2097774Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 2098774Svbart@nginx.com 2099774Svbart@nginx.com nxt_debug(task, "tls rpc handler"); 2100774Svbart@nginx.com 2101774Svbart@nginx.com rpc = data; 2102774Svbart@nginx.com tmcf = rpc->temp_conf; 2103774Svbart@nginx.com 2104774Svbart@nginx.com if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) { 2105774Svbart@nginx.com goto fail; 2106774Svbart@nginx.com } 2107774Svbart@nginx.com 2108774Svbart@nginx.com mp = tmcf->router_conf->mem_pool; 2109774Svbart@nginx.com 2110774Svbart@nginx.com tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t)); 2111774Svbart@nginx.com if (nxt_slow_path(tlscf == NULL)) { 2112774Svbart@nginx.com goto fail; 2113774Svbart@nginx.com } 2114774Svbart@nginx.com 2115774Svbart@nginx.com tlscf->chain_file = msg->fd; 2116774Svbart@nginx.com 2117774Svbart@nginx.com ret = task->thread->runtime->tls->server_init(task, tlscf); 2118774Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2119774Svbart@nginx.com goto fail; 2120774Svbart@nginx.com } 2121774Svbart@nginx.com 2122774Svbart@nginx.com rpc->socket_conf->tls = tlscf; 2123774Svbart@nginx.com 2124774Svbart@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 2125774Svbart@nginx.com nxt_router_conf_apply, task, tmcf, NULL); 2126774Svbart@nginx.com return; 2127774Svbart@nginx.com 2128774Svbart@nginx.com fail: 2129774Svbart@nginx.com 2130774Svbart@nginx.com nxt_router_conf_error(task, tmcf); 2131774Svbart@nginx.com } 2132774Svbart@nginx.com 2133774Svbart@nginx.com #endif 2134774Svbart@nginx.com 2135774Svbart@nginx.com 2136507Smax.romanov@nginx.com static void 2137507Smax.romanov@nginx.com nxt_router_app_rpc_create(nxt_task_t *task, 2138507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf, nxt_app_t *app) 2139507Smax.romanov@nginx.com { 2140507Smax.romanov@nginx.com size_t size; 2141507Smax.romanov@nginx.com uint32_t stream; 2142648Svbart@nginx.com nxt_int_t ret; 2143507Smax.romanov@nginx.com nxt_buf_t *b; 2144507Smax.romanov@nginx.com nxt_port_t *main_port, *router_port; 2145507Smax.romanov@nginx.com nxt_runtime_t *rt; 2146507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 2147507Smax.romanov@nginx.com 2148507Smax.romanov@nginx.com rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_app_rpc_t)); 2149507Smax.romanov@nginx.com if (rpc == NULL) { 2150507Smax.romanov@nginx.com goto fail; 2151507Smax.romanov@nginx.com } 2152507Smax.romanov@nginx.com 2153507Smax.romanov@nginx.com rpc->app = app; 2154507Smax.romanov@nginx.com rpc->temp_conf = tmcf; 2155507Smax.romanov@nginx.com 2156507Smax.romanov@nginx.com nxt_debug(task, "app '%V' prefork", &app->name); 2157507Smax.romanov@nginx.com 2158507Smax.romanov@nginx.com size = app->name.length + 1 + app->conf.length; 2159507Smax.romanov@nginx.com 2160507Smax.romanov@nginx.com b = nxt_buf_mem_alloc(tmcf->mem_pool, size, 0); 2161507Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 2162507Smax.romanov@nginx.com goto fail; 2163507Smax.romanov@nginx.com } 2164507Smax.romanov@nginx.com 2165507Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->name); 2166507Smax.romanov@nginx.com *b->mem.free++ = '\0'; 2167507Smax.romanov@nginx.com nxt_buf_cpystr(b, &app->conf); 2168507Smax.romanov@nginx.com 2169507Smax.romanov@nginx.com rt = task->thread->runtime; 2170507Smax.romanov@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 2171507Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 2172507Smax.romanov@nginx.com 2173507Smax.romanov@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 2174507Smax.romanov@nginx.com nxt_router_app_prefork_ready, 2175507Smax.romanov@nginx.com nxt_router_app_prefork_error, 2176507Smax.romanov@nginx.com -1, rpc); 2177507Smax.romanov@nginx.com if (nxt_slow_path(stream == 0)) { 2178507Smax.romanov@nginx.com goto fail; 2179507Smax.romanov@nginx.com } 2180507Smax.romanov@nginx.com 2181648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_WORKER, -1, 2182648Svbart@nginx.com stream, router_port->id, b); 2183648Svbart@nginx.com 2184648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2185648Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 2186648Svbart@nginx.com goto fail; 2187648Svbart@nginx.com } 2188648Svbart@nginx.com 2189507Smax.romanov@nginx.com app->pending_processes++; 2190507Smax.romanov@nginx.com 2191507Smax.romanov@nginx.com return; 2192507Smax.romanov@nginx.com 2193507Smax.romanov@nginx.com fail: 2194507Smax.romanov@nginx.com 2195507Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 2196507Smax.romanov@nginx.com } 2197507Smax.romanov@nginx.com 2198507Smax.romanov@nginx.com 2199507Smax.romanov@nginx.com static void 2200507Smax.romanov@nginx.com nxt_router_app_prefork_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2201507Smax.romanov@nginx.com void *data) 2202507Smax.romanov@nginx.com { 2203507Smax.romanov@nginx.com nxt_app_t *app; 2204507Smax.romanov@nginx.com nxt_port_t *port; 2205507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 2206507Smax.romanov@nginx.com nxt_event_engine_t *engine; 2207507Smax.romanov@nginx.com 2208507Smax.romanov@nginx.com rpc = data; 2209507Smax.romanov@nginx.com app = rpc->app; 2210507Smax.romanov@nginx.com 2211507Smax.romanov@nginx.com port = msg->u.new_port; 2212507Smax.romanov@nginx.com port->app = app; 2213507Smax.romanov@nginx.com 2214507Smax.romanov@nginx.com app->pending_processes--; 2215507Smax.romanov@nginx.com app->processes++; 2216507Smax.romanov@nginx.com app->idle_processes++; 2217507Smax.romanov@nginx.com 2218507Smax.romanov@nginx.com engine = task->thread->engine; 2219507Smax.romanov@nginx.com 2220507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &port->app_link); 2221507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, &port->idle_link); 2222507Smax.romanov@nginx.com 2223507Smax.romanov@nginx.com port->idle_start = 0; 2224507Smax.romanov@nginx.com 2225507Smax.romanov@nginx.com nxt_port_inc_use(port); 2226507Smax.romanov@nginx.com 2227507Smax.romanov@nginx.com nxt_work_queue_add(&engine->fast_work_queue, 2228507Smax.romanov@nginx.com nxt_router_conf_apply, task, rpc->temp_conf, NULL); 2229507Smax.romanov@nginx.com } 2230507Smax.romanov@nginx.com 2231507Smax.romanov@nginx.com 2232507Smax.romanov@nginx.com static void 2233507Smax.romanov@nginx.com nxt_router_app_prefork_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 2234507Smax.romanov@nginx.com void *data) 2235507Smax.romanov@nginx.com { 2236507Smax.romanov@nginx.com nxt_app_t *app; 2237507Smax.romanov@nginx.com nxt_app_rpc_t *rpc; 2238507Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf; 2239507Smax.romanov@nginx.com 2240507Smax.romanov@nginx.com rpc = data; 2241507Smax.romanov@nginx.com app = rpc->app; 2242507Smax.romanov@nginx.com tmcf = rpc->temp_conf; 2243507Smax.romanov@nginx.com 2244507Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, "failed to start application \"%V\"", 2245507Smax.romanov@nginx.com &app->name); 2246507Smax.romanov@nginx.com 2247507Smax.romanov@nginx.com app->pending_processes--; 2248507Smax.romanov@nginx.com 2249507Smax.romanov@nginx.com nxt_router_conf_error(task, tmcf); 2250507Smax.romanov@nginx.com } 2251507Smax.romanov@nginx.com 2252507Smax.romanov@nginx.com 225353Sigor@sysoev.ru static nxt_int_t 225453Sigor@sysoev.ru nxt_router_engines_create(nxt_task_t *task, nxt_router_t *router, 225553Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf, const nxt_event_interface_t *interface) 225653Sigor@sysoev.ru { 225753Sigor@sysoev.ru nxt_int_t ret; 225853Sigor@sysoev.ru nxt_uint_t n, threads; 225953Sigor@sysoev.ru nxt_queue_link_t *qlk; 226053Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 226153Sigor@sysoev.ru 2262591Sigor@sysoev.ru threads = tmcf->router_conf->threads; 226353Sigor@sysoev.ru 226453Sigor@sysoev.ru tmcf->engines = nxt_array_create(tmcf->mem_pool, threads, 226553Sigor@sysoev.ru sizeof(nxt_router_engine_conf_t)); 226653Sigor@sysoev.ru if (nxt_slow_path(tmcf->engines == NULL)) { 226753Sigor@sysoev.ru return NXT_ERROR; 226853Sigor@sysoev.ru } 226953Sigor@sysoev.ru 227053Sigor@sysoev.ru n = 0; 227153Sigor@sysoev.ru 227253Sigor@sysoev.ru for (qlk = nxt_queue_first(&router->engines); 227353Sigor@sysoev.ru qlk != nxt_queue_tail(&router->engines); 227453Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 227553Sigor@sysoev.ru { 227653Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 227753Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 227853Sigor@sysoev.ru return NXT_ERROR; 227953Sigor@sysoev.ru } 228053Sigor@sysoev.ru 2281115Sigor@sysoev.ru recf->engine = nxt_queue_link_data(qlk, nxt_event_engine_t, link0); 228253Sigor@sysoev.ru 228353Sigor@sysoev.ru if (n < threads) { 2284315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_KEEP; 2285115Sigor@sysoev.ru ret = nxt_router_engine_conf_update(tmcf, recf); 228653Sigor@sysoev.ru 228753Sigor@sysoev.ru } else { 2288315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_DELETE; 2289115Sigor@sysoev.ru ret = nxt_router_engine_conf_delete(tmcf, recf); 229053Sigor@sysoev.ru } 229153Sigor@sysoev.ru 229253Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 229353Sigor@sysoev.ru return ret; 229453Sigor@sysoev.ru } 229553Sigor@sysoev.ru 229653Sigor@sysoev.ru n++; 229753Sigor@sysoev.ru } 229853Sigor@sysoev.ru 229953Sigor@sysoev.ru tmcf->new_threads = n; 230053Sigor@sysoev.ru 230153Sigor@sysoev.ru while (n < threads) { 230253Sigor@sysoev.ru recf = nxt_array_zero_add(tmcf->engines); 230353Sigor@sysoev.ru if (nxt_slow_path(recf == NULL)) { 230453Sigor@sysoev.ru return NXT_ERROR; 230553Sigor@sysoev.ru } 230653Sigor@sysoev.ru 2307315Sigor@sysoev.ru recf->action = NXT_ROUTER_ENGINE_ADD; 2308315Sigor@sysoev.ru 230953Sigor@sysoev.ru recf->engine = nxt_event_engine_create(task, interface, NULL, 0, 0); 231053Sigor@sysoev.ru if (nxt_slow_path(recf->engine == NULL)) { 231153Sigor@sysoev.ru return NXT_ERROR; 231253Sigor@sysoev.ru } 231353Sigor@sysoev.ru 2314115Sigor@sysoev.ru ret = nxt_router_engine_conf_create(tmcf, recf); 231553Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 231653Sigor@sysoev.ru return ret; 231753Sigor@sysoev.ru } 231853Sigor@sysoev.ru 231953Sigor@sysoev.ru n++; 232053Sigor@sysoev.ru } 232153Sigor@sysoev.ru 232253Sigor@sysoev.ru return NXT_OK; 232353Sigor@sysoev.ru } 232453Sigor@sysoev.ru 232553Sigor@sysoev.ru 232653Sigor@sysoev.ru static nxt_int_t 2327115Sigor@sysoev.ru nxt_router_engine_conf_create(nxt_router_temp_conf_t *tmcf, 2328115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 232953Sigor@sysoev.ru { 2330359Sigor@sysoev.ru nxt_int_t ret; 233153Sigor@sysoev.ru 2332154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 2333154Sigor@sysoev.ru nxt_router_listen_socket_create); 2334115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2335115Sigor@sysoev.ru return ret; 2336115Sigor@sysoev.ru } 2337115Sigor@sysoev.ru 2338154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 2339154Sigor@sysoev.ru nxt_router_listen_socket_create); 234053Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 234153Sigor@sysoev.ru return ret; 234253Sigor@sysoev.ru } 234353Sigor@sysoev.ru 2344115Sigor@sysoev.ru return ret; 234553Sigor@sysoev.ru } 234653Sigor@sysoev.ru 234753Sigor@sysoev.ru 234853Sigor@sysoev.ru static nxt_int_t 2349115Sigor@sysoev.ru nxt_router_engine_conf_update(nxt_router_temp_conf_t *tmcf, 2350115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 235153Sigor@sysoev.ru { 2352359Sigor@sysoev.ru nxt_int_t ret; 235353Sigor@sysoev.ru 2354154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->creating, 2355154Sigor@sysoev.ru nxt_router_listen_socket_create); 235653Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 235753Sigor@sysoev.ru return ret; 235853Sigor@sysoev.ru } 235953Sigor@sysoev.ru 2360154Sigor@sysoev.ru ret = nxt_router_engine_joints_create(tmcf, recf, &tmcf->updating, 2361154Sigor@sysoev.ru nxt_router_listen_socket_update); 236253Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 236353Sigor@sysoev.ru return ret; 236453Sigor@sysoev.ru } 236553Sigor@sysoev.ru 2366139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 2367115Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2368115Sigor@sysoev.ru return ret; 2369115Sigor@sysoev.ru } 2370115Sigor@sysoev.ru 2371115Sigor@sysoev.ru return ret; 237253Sigor@sysoev.ru } 237353Sigor@sysoev.ru 237453Sigor@sysoev.ru 237553Sigor@sysoev.ru static nxt_int_t 2376115Sigor@sysoev.ru nxt_router_engine_conf_delete(nxt_router_temp_conf_t *tmcf, 2377115Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 237853Sigor@sysoev.ru { 237953Sigor@sysoev.ru nxt_int_t ret; 238053Sigor@sysoev.ru 2381313Sigor@sysoev.ru ret = nxt_router_engine_quit(tmcf, recf); 2382313Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 2383313Sigor@sysoev.ru return ret; 2384313Sigor@sysoev.ru } 2385313Sigor@sysoev.ru 2386139Sigor@sysoev.ru ret = nxt_router_engine_joints_delete(tmcf, recf, &tmcf->updating); 238753Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 238853Sigor@sysoev.ru return ret; 238953Sigor@sysoev.ru } 239053Sigor@sysoev.ru 2391139Sigor@sysoev.ru return nxt_router_engine_joints_delete(tmcf, recf, &tmcf->deleting); 239253Sigor@sysoev.ru } 239353Sigor@sysoev.ru 239453Sigor@sysoev.ru 239553Sigor@sysoev.ru static nxt_int_t 2396154Sigor@sysoev.ru nxt_router_engine_joints_create(nxt_router_temp_conf_t *tmcf, 2397154Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets, 239853Sigor@sysoev.ru nxt_work_handler_t handler) 239953Sigor@sysoev.ru { 2400153Sigor@sysoev.ru nxt_joint_job_t *job; 240153Sigor@sysoev.ru nxt_queue_link_t *qlk; 2402155Sigor@sysoev.ru nxt_socket_conf_t *skcf; 240353Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 240453Sigor@sysoev.ru 240553Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 240653Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 240753Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 240853Sigor@sysoev.ru { 2409154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2410153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2411139Sigor@sysoev.ru return NXT_ERROR; 2412139Sigor@sysoev.ru } 2413139Sigor@sysoev.ru 2414154Sigor@sysoev.ru job->work.next = recf->jobs; 2415154Sigor@sysoev.ru recf->jobs = &job->work; 2416154Sigor@sysoev.ru 2417153Sigor@sysoev.ru job->task = tmcf->engine->task; 2418153Sigor@sysoev.ru job->work.handler = handler; 2419153Sigor@sysoev.ru job->work.task = &job->task; 2420153Sigor@sysoev.ru job->work.obj = job; 2421153Sigor@sysoev.ru job->tmcf = tmcf; 242253Sigor@sysoev.ru 2423154Sigor@sysoev.ru tmcf->count++; 2424154Sigor@sysoev.ru 2425591Sigor@sysoev.ru joint = nxt_mp_alloc(tmcf->router_conf->mem_pool, 2426154Sigor@sysoev.ru sizeof(nxt_socket_conf_joint_t)); 242753Sigor@sysoev.ru if (nxt_slow_path(joint == NULL)) { 242853Sigor@sysoev.ru return NXT_ERROR; 242953Sigor@sysoev.ru } 243053Sigor@sysoev.ru 2431153Sigor@sysoev.ru job->work.data = joint; 243253Sigor@sysoev.ru 243353Sigor@sysoev.ru joint->count = 1; 2434155Sigor@sysoev.ru 2435155Sigor@sysoev.ru skcf = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 2436155Sigor@sysoev.ru skcf->count++; 2437155Sigor@sysoev.ru joint->socket_conf = skcf; 2438155Sigor@sysoev.ru 243988Smax.romanov@nginx.com joint->engine = recf->engine; 244053Sigor@sysoev.ru } 244153Sigor@sysoev.ru 244220Sigor@sysoev.ru return NXT_OK; 244320Sigor@sysoev.ru } 244420Sigor@sysoev.ru 244520Sigor@sysoev.ru 244620Sigor@sysoev.ru static nxt_int_t 2447313Sigor@sysoev.ru nxt_router_engine_quit(nxt_router_temp_conf_t *tmcf, 2448313Sigor@sysoev.ru nxt_router_engine_conf_t *recf) 2449313Sigor@sysoev.ru { 2450313Sigor@sysoev.ru nxt_joint_job_t *job; 2451313Sigor@sysoev.ru 2452313Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2453313Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2454313Sigor@sysoev.ru return NXT_ERROR; 2455313Sigor@sysoev.ru } 2456313Sigor@sysoev.ru 2457313Sigor@sysoev.ru job->work.next = recf->jobs; 2458313Sigor@sysoev.ru recf->jobs = &job->work; 2459313Sigor@sysoev.ru 2460313Sigor@sysoev.ru job->task = tmcf->engine->task; 2461313Sigor@sysoev.ru job->work.handler = nxt_router_worker_thread_quit; 2462313Sigor@sysoev.ru job->work.task = &job->task; 2463313Sigor@sysoev.ru job->work.obj = NULL; 2464313Sigor@sysoev.ru job->work.data = NULL; 2465313Sigor@sysoev.ru job->tmcf = NULL; 2466313Sigor@sysoev.ru 2467313Sigor@sysoev.ru return NXT_OK; 2468313Sigor@sysoev.ru } 2469313Sigor@sysoev.ru 2470313Sigor@sysoev.ru 2471313Sigor@sysoev.ru static nxt_int_t 2472139Sigor@sysoev.ru nxt_router_engine_joints_delete(nxt_router_temp_conf_t *tmcf, 2473139Sigor@sysoev.ru nxt_router_engine_conf_t *recf, nxt_queue_t *sockets) 247420Sigor@sysoev.ru { 2475153Sigor@sysoev.ru nxt_joint_job_t *job; 247653Sigor@sysoev.ru nxt_queue_link_t *qlk; 247720Sigor@sysoev.ru 247853Sigor@sysoev.ru for (qlk = nxt_queue_first(sockets); 247953Sigor@sysoev.ru qlk != nxt_queue_tail(sockets); 248053Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 248153Sigor@sysoev.ru { 2482154Sigor@sysoev.ru job = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_joint_job_t)); 2483153Sigor@sysoev.ru if (nxt_slow_path(job == NULL)) { 2484139Sigor@sysoev.ru return NXT_ERROR; 2485139Sigor@sysoev.ru } 2486139Sigor@sysoev.ru 2487154Sigor@sysoev.ru job->work.next = recf->jobs; 2488154Sigor@sysoev.ru recf->jobs = &job->work; 2489154Sigor@sysoev.ru 2490153Sigor@sysoev.ru job->task = tmcf->engine->task; 2491153Sigor@sysoev.ru job->work.handler = nxt_router_listen_socket_delete; 2492153Sigor@sysoev.ru job->work.task = &job->task; 2493153Sigor@sysoev.ru job->work.obj = job; 2494153Sigor@sysoev.ru job->work.data = nxt_queue_link_data(qlk, nxt_socket_conf_t, link); 2495153Sigor@sysoev.ru job->tmcf = tmcf; 2496154Sigor@sysoev.ru 2497154Sigor@sysoev.ru tmcf->count++; 249820Sigor@sysoev.ru } 249920Sigor@sysoev.ru 250053Sigor@sysoev.ru return NXT_OK; 250153Sigor@sysoev.ru } 250220Sigor@sysoev.ru 250320Sigor@sysoev.ru 250453Sigor@sysoev.ru static nxt_int_t 250553Sigor@sysoev.ru nxt_router_threads_create(nxt_task_t *task, nxt_runtime_t *rt, 250653Sigor@sysoev.ru nxt_router_temp_conf_t *tmcf) 250753Sigor@sysoev.ru { 250853Sigor@sysoev.ru nxt_int_t ret; 250953Sigor@sysoev.ru nxt_uint_t i, threads; 251053Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 251120Sigor@sysoev.ru 251253Sigor@sysoev.ru recf = tmcf->engines->elts; 2513591Sigor@sysoev.ru threads = tmcf->router_conf->threads; 251420Sigor@sysoev.ru 251553Sigor@sysoev.ru for (i = tmcf->new_threads; i < threads; i++) { 251653Sigor@sysoev.ru ret = nxt_router_thread_create(task, rt, recf[i].engine); 251753Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 251853Sigor@sysoev.ru return ret; 251953Sigor@sysoev.ru } 252020Sigor@sysoev.ru } 252120Sigor@sysoev.ru 252220Sigor@sysoev.ru return NXT_OK; 252320Sigor@sysoev.ru } 252453Sigor@sysoev.ru 252553Sigor@sysoev.ru 252653Sigor@sysoev.ru static nxt_int_t 252753Sigor@sysoev.ru nxt_router_thread_create(nxt_task_t *task, nxt_runtime_t *rt, 252853Sigor@sysoev.ru nxt_event_engine_t *engine) 252953Sigor@sysoev.ru { 253053Sigor@sysoev.ru nxt_int_t ret; 253153Sigor@sysoev.ru nxt_thread_link_t *link; 253253Sigor@sysoev.ru nxt_thread_handle_t handle; 253353Sigor@sysoev.ru 253453Sigor@sysoev.ru link = nxt_zalloc(sizeof(nxt_thread_link_t)); 253553Sigor@sysoev.ru 253653Sigor@sysoev.ru if (nxt_slow_path(link == NULL)) { 253753Sigor@sysoev.ru return NXT_ERROR; 253853Sigor@sysoev.ru } 253953Sigor@sysoev.ru 254053Sigor@sysoev.ru link->start = nxt_router_thread_start; 254153Sigor@sysoev.ru link->engine = engine; 254253Sigor@sysoev.ru link->work.handler = nxt_router_thread_exit_handler; 254353Sigor@sysoev.ru link->work.task = task; 254453Sigor@sysoev.ru link->work.data = link; 254553Sigor@sysoev.ru 254653Sigor@sysoev.ru nxt_queue_insert_tail(&rt->engines, &engine->link); 254753Sigor@sysoev.ru 254853Sigor@sysoev.ru ret = nxt_thread_create(&handle, link); 254953Sigor@sysoev.ru 255053Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 255153Sigor@sysoev.ru nxt_queue_remove(&engine->link); 255253Sigor@sysoev.ru } 255353Sigor@sysoev.ru 255453Sigor@sysoev.ru return ret; 255553Sigor@sysoev.ru } 255653Sigor@sysoev.ru 255753Sigor@sysoev.ru 255853Sigor@sysoev.ru static void 2559343Smax.romanov@nginx.com nxt_router_apps_sort(nxt_task_t *task, nxt_router_t *router, 2560343Smax.romanov@nginx.com nxt_router_temp_conf_t *tmcf) 2561133Sigor@sysoev.ru { 2562507Smax.romanov@nginx.com nxt_app_t *app; 2563141Smax.romanov@nginx.com 2564141Smax.romanov@nginx.com nxt_queue_each(app, &router->apps, nxt_app_t, link) { 2565133Sigor@sysoev.ru 2566753Smax.romanov@nginx.com nxt_router_app_unlink(task, app); 2567343Smax.romanov@nginx.com 2568141Smax.romanov@nginx.com } nxt_queue_loop; 2569133Sigor@sysoev.ru 2570133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->previous); 2571133Sigor@sysoev.ru nxt_queue_add(&router->apps, &tmcf->apps); 2572133Sigor@sysoev.ru } 2573133Sigor@sysoev.ru 2574133Sigor@sysoev.ru 2575133Sigor@sysoev.ru static void 2576315Sigor@sysoev.ru nxt_router_engines_post(nxt_router_t *router, nxt_router_temp_conf_t *tmcf) 257753Sigor@sysoev.ru { 257853Sigor@sysoev.ru nxt_uint_t n; 2579315Sigor@sysoev.ru nxt_event_engine_t *engine; 258053Sigor@sysoev.ru nxt_router_engine_conf_t *recf; 258153Sigor@sysoev.ru 258253Sigor@sysoev.ru recf = tmcf->engines->elts; 258353Sigor@sysoev.ru 258453Sigor@sysoev.ru for (n = tmcf->engines->nelts; n != 0; n--) { 2585315Sigor@sysoev.ru engine = recf->engine; 2586315Sigor@sysoev.ru 2587315Sigor@sysoev.ru switch (recf->action) { 2588315Sigor@sysoev.ru 2589315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_KEEP: 2590315Sigor@sysoev.ru break; 2591315Sigor@sysoev.ru 2592315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_ADD: 2593315Sigor@sysoev.ru nxt_queue_insert_tail(&router->engines, &engine->link0); 2594315Sigor@sysoev.ru break; 2595315Sigor@sysoev.ru 2596315Sigor@sysoev.ru case NXT_ROUTER_ENGINE_DELETE: 2597315Sigor@sysoev.ru nxt_queue_remove(&engine->link0); 2598315Sigor@sysoev.ru break; 2599315Sigor@sysoev.ru } 2600315Sigor@sysoev.ru 2601316Sigor@sysoev.ru nxt_router_engine_post(engine, recf->jobs); 2602316Sigor@sysoev.ru 260353Sigor@sysoev.ru recf++; 260453Sigor@sysoev.ru } 260553Sigor@sysoev.ru } 260653Sigor@sysoev.ru 260753Sigor@sysoev.ru 260853Sigor@sysoev.ru static void 2609315Sigor@sysoev.ru nxt_router_engine_post(nxt_event_engine_t *engine, nxt_work_t *jobs) 261053Sigor@sysoev.ru { 2611154Sigor@sysoev.ru nxt_work_t *work, *next; 2612154Sigor@sysoev.ru 2613315Sigor@sysoev.ru for (work = jobs; work != NULL; work = next) { 2614154Sigor@sysoev.ru next = work->next; 2615154Sigor@sysoev.ru work->next = NULL; 2616154Sigor@sysoev.ru 2617315Sigor@sysoev.ru nxt_event_engine_post(engine, work); 261853Sigor@sysoev.ru } 261953Sigor@sysoev.ru } 262053Sigor@sysoev.ru 262153Sigor@sysoev.ru 2622320Smax.romanov@nginx.com static nxt_port_handlers_t nxt_router_app_port_handlers = { 2623616Smax.romanov@nginx.com .rpc_error = nxt_port_rpc_handler, 2624616Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 2625616Smax.romanov@nginx.com .data = nxt_port_rpc_handler, 262688Smax.romanov@nginx.com }; 262788Smax.romanov@nginx.com 262888Smax.romanov@nginx.com 262988Smax.romanov@nginx.com static void 263053Sigor@sysoev.ru nxt_router_thread_start(void *data) 263153Sigor@sysoev.ru { 2632141Smax.romanov@nginx.com nxt_int_t ret; 2633141Smax.romanov@nginx.com nxt_port_t *port; 263488Smax.romanov@nginx.com nxt_task_t *task; 263553Sigor@sysoev.ru nxt_thread_t *thread; 263653Sigor@sysoev.ru nxt_thread_link_t *link; 263753Sigor@sysoev.ru nxt_event_engine_t *engine; 263853Sigor@sysoev.ru 263953Sigor@sysoev.ru link = data; 264053Sigor@sysoev.ru engine = link->engine; 264188Smax.romanov@nginx.com task = &engine->task; 264253Sigor@sysoev.ru 264353Sigor@sysoev.ru thread = nxt_thread(); 264453Sigor@sysoev.ru 2645165Smax.romanov@nginx.com nxt_event_engine_thread_adopt(engine); 2646165Smax.romanov@nginx.com 264753Sigor@sysoev.ru /* STUB */ 264853Sigor@sysoev.ru thread->runtime = engine->task.thread->runtime; 264953Sigor@sysoev.ru 265053Sigor@sysoev.ru engine->task.thread = thread; 265153Sigor@sysoev.ru engine->task.log = thread->log; 265253Sigor@sysoev.ru thread->engine = engine; 265363Sigor@sysoev.ru thread->task = &engine->task; 2654326Svbart@nginx.com #if 0 265553Sigor@sysoev.ru thread->fiber = &engine->fibers->fiber; 2656326Svbart@nginx.com #endif 265753Sigor@sysoev.ru 265863Sigor@sysoev.ru engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64); 2659337Sigor@sysoev.ru if (nxt_slow_path(engine->mem_pool == NULL)) { 2660337Sigor@sysoev.ru return; 2661337Sigor@sysoev.ru } 266253Sigor@sysoev.ru 2663197Smax.romanov@nginx.com port = nxt_port_new(task, nxt_port_get_next_id(), nxt_pid, 2664197Smax.romanov@nginx.com NXT_PROCESS_ROUTER); 2665141Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 2666141Smax.romanov@nginx.com return; 2667141Smax.romanov@nginx.com } 2668141Smax.romanov@nginx.com 2669141Smax.romanov@nginx.com ret = nxt_port_socket_init(task, port, 0); 2670141Smax.romanov@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 2671343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 2672141Smax.romanov@nginx.com return; 2673141Smax.romanov@nginx.com } 2674141Smax.romanov@nginx.com 2675141Smax.romanov@nginx.com engine->port = port; 2676141Smax.romanov@nginx.com 2677320Smax.romanov@nginx.com nxt_port_enable(task, port, &nxt_router_app_port_handlers); 2678141Smax.romanov@nginx.com 267953Sigor@sysoev.ru nxt_event_engine_start(engine); 268053Sigor@sysoev.ru } 268153Sigor@sysoev.ru 268253Sigor@sysoev.ru 268353Sigor@sysoev.ru static void 268453Sigor@sysoev.ru nxt_router_listen_socket_create(nxt_task_t *task, void *obj, void *data) 268553Sigor@sysoev.ru { 2686153Sigor@sysoev.ru nxt_joint_job_t *job; 2687359Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2688359Sigor@sysoev.ru nxt_listen_event_t *lev; 268953Sigor@sysoev.ru nxt_listen_socket_t *ls; 2690359Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 269153Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 269253Sigor@sysoev.ru 2693153Sigor@sysoev.ru job = obj; 269453Sigor@sysoev.ru joint = data; 269553Sigor@sysoev.ru 2696159Sigor@sysoev.ru nxt_queue_insert_tail(&task->thread->engine->joints, &joint->link); 2697159Sigor@sysoev.ru 2698359Sigor@sysoev.ru skcf = joint->socket_conf; 2699359Sigor@sysoev.ru ls = skcf->listen; 2700359Sigor@sysoev.ru 2701359Sigor@sysoev.ru lev = nxt_listen_event(task, ls); 2702359Sigor@sysoev.ru if (nxt_slow_path(lev == NULL)) { 2703359Sigor@sysoev.ru nxt_router_listen_socket_release(task, skcf); 270453Sigor@sysoev.ru return; 270553Sigor@sysoev.ru } 270653Sigor@sysoev.ru 2707359Sigor@sysoev.ru lev->socket.data = joint; 2708359Sigor@sysoev.ru 2709359Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 2710359Sigor@sysoev.ru 2711359Sigor@sysoev.ru nxt_thread_spin_lock(lock); 2712359Sigor@sysoev.ru ls->count++; 2713359Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 2714139Sigor@sysoev.ru 2715153Sigor@sysoev.ru job->work.next = NULL; 2716153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2717153Sigor@sysoev.ru 2718153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 271953Sigor@sysoev.ru } 272053Sigor@sysoev.ru 272153Sigor@sysoev.ru 272253Sigor@sysoev.ru nxt_inline nxt_listen_event_t * 272353Sigor@sysoev.ru nxt_router_listen_event(nxt_queue_t *listen_connections, 272453Sigor@sysoev.ru nxt_socket_conf_t *skcf) 272553Sigor@sysoev.ru { 2726115Sigor@sysoev.ru nxt_socket_t fd; 2727115Sigor@sysoev.ru nxt_queue_link_t *qlk; 2728359Sigor@sysoev.ru nxt_listen_event_t *lev; 2729359Sigor@sysoev.ru 2730359Sigor@sysoev.ru fd = skcf->listen->socket; 273153Sigor@sysoev.ru 2732115Sigor@sysoev.ru for (qlk = nxt_queue_first(listen_connections); 2733115Sigor@sysoev.ru qlk != nxt_queue_tail(listen_connections); 2734115Sigor@sysoev.ru qlk = nxt_queue_next(qlk)) 273553Sigor@sysoev.ru { 2736359Sigor@sysoev.ru lev = nxt_queue_link_data(qlk, nxt_listen_event_t, link); 2737359Sigor@sysoev.ru 2738359Sigor@sysoev.ru if (fd == lev->socket.fd) { 2739359Sigor@sysoev.ru return lev; 274053Sigor@sysoev.ru } 274153Sigor@sysoev.ru } 274253Sigor@sysoev.ru 274353Sigor@sysoev.ru return NULL; 274453Sigor@sysoev.ru } 274553Sigor@sysoev.ru 274653Sigor@sysoev.ru 274753Sigor@sysoev.ru static void 274853Sigor@sysoev.ru nxt_router_listen_socket_update(nxt_task_t *task, void *obj, void *data) 274953Sigor@sysoev.ru { 2750153Sigor@sysoev.ru nxt_joint_job_t *job; 275153Sigor@sysoev.ru nxt_event_engine_t *engine; 2752359Sigor@sysoev.ru nxt_listen_event_t *lev; 275353Sigor@sysoev.ru nxt_socket_conf_joint_t *joint, *old; 275453Sigor@sysoev.ru 2755153Sigor@sysoev.ru job = obj; 275653Sigor@sysoev.ru joint = data; 275753Sigor@sysoev.ru 2758139Sigor@sysoev.ru engine = task->thread->engine; 2759139Sigor@sysoev.ru 2760159Sigor@sysoev.ru nxt_queue_insert_tail(&engine->joints, &joint->link); 2761159Sigor@sysoev.ru 2762359Sigor@sysoev.ru lev = nxt_router_listen_event(&engine->listen_connections, 2763359Sigor@sysoev.ru joint->socket_conf); 2764359Sigor@sysoev.ru 2765359Sigor@sysoev.ru old = lev->socket.data; 2766359Sigor@sysoev.ru lev->socket.data = joint; 2767359Sigor@sysoev.ru lev->listen = joint->socket_conf->listen; 276853Sigor@sysoev.ru 2769153Sigor@sysoev.ru job->work.next = NULL; 2770153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2771153Sigor@sysoev.ru 2772153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 2773139Sigor@sysoev.ru 2774181Smax.romanov@nginx.com /* 2775181Smax.romanov@nginx.com * The task is allocated from configuration temporary 2776181Smax.romanov@nginx.com * memory pool so it can be freed after engine post operation. 2777181Smax.romanov@nginx.com */ 2778181Smax.romanov@nginx.com 2779181Smax.romanov@nginx.com nxt_router_conf_release(&engine->task, old); 278053Sigor@sysoev.ru } 278153Sigor@sysoev.ru 278253Sigor@sysoev.ru 278353Sigor@sysoev.ru static void 278453Sigor@sysoev.ru nxt_router_listen_socket_delete(nxt_task_t *task, void *obj, void *data) 278553Sigor@sysoev.ru { 2786153Sigor@sysoev.ru nxt_joint_job_t *job; 2787153Sigor@sysoev.ru nxt_socket_conf_t *skcf; 2788359Sigor@sysoev.ru nxt_listen_event_t *lev; 2789153Sigor@sysoev.ru nxt_event_engine_t *engine; 2790153Sigor@sysoev.ru 2791153Sigor@sysoev.ru job = obj; 279253Sigor@sysoev.ru skcf = data; 279353Sigor@sysoev.ru 2794139Sigor@sysoev.ru engine = task->thread->engine; 2795139Sigor@sysoev.ru 2796359Sigor@sysoev.ru lev = nxt_router_listen_event(&engine->listen_connections, skcf); 2797359Sigor@sysoev.ru 2798359Sigor@sysoev.ru nxt_fd_event_delete(engine, &lev->socket); 279953Sigor@sysoev.ru 2800163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket delete: %d", engine, 2801359Sigor@sysoev.ru lev->socket.fd); 2802359Sigor@sysoev.ru 2803359Sigor@sysoev.ru lev->timer.handler = nxt_router_listen_socket_close; 2804359Sigor@sysoev.ru lev->timer.work_queue = &engine->fast_work_queue; 2805359Sigor@sysoev.ru 2806359Sigor@sysoev.ru nxt_timer_add(engine, &lev->timer, 0); 2807139Sigor@sysoev.ru 2808153Sigor@sysoev.ru job->work.next = NULL; 2809153Sigor@sysoev.ru job->work.handler = nxt_router_conf_wait; 2810153Sigor@sysoev.ru 2811153Sigor@sysoev.ru nxt_event_engine_post(job->tmcf->engine, &job->work); 281253Sigor@sysoev.ru } 281353Sigor@sysoev.ru 281453Sigor@sysoev.ru 281553Sigor@sysoev.ru static void 2816313Sigor@sysoev.ru nxt_router_worker_thread_quit(nxt_task_t *task, void *obj, void *data) 2817313Sigor@sysoev.ru { 2818313Sigor@sysoev.ru nxt_event_engine_t *engine; 2819313Sigor@sysoev.ru 2820313Sigor@sysoev.ru nxt_debug(task, "router worker thread quit"); 2821313Sigor@sysoev.ru 2822313Sigor@sysoev.ru engine = task->thread->engine; 2823313Sigor@sysoev.ru 2824313Sigor@sysoev.ru engine->shutdown = 1; 2825313Sigor@sysoev.ru 2826313Sigor@sysoev.ru if (nxt_queue_is_empty(&engine->joints)) { 2827313Sigor@sysoev.ru nxt_thread_exit(task->thread); 2828313Sigor@sysoev.ru } 2829313Sigor@sysoev.ru } 2830313Sigor@sysoev.ru 2831313Sigor@sysoev.ru 2832313Sigor@sysoev.ru static void 283353Sigor@sysoev.ru nxt_router_listen_socket_close(nxt_task_t *task, void *obj, void *data) 283453Sigor@sysoev.ru { 283553Sigor@sysoev.ru nxt_timer_t *timer; 2836359Sigor@sysoev.ru nxt_listen_event_t *lev; 283753Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 283853Sigor@sysoev.ru 283953Sigor@sysoev.ru timer = obj; 2840359Sigor@sysoev.ru lev = nxt_timer_data(timer, nxt_listen_event_t, timer); 284153Sigor@sysoev.ru 2842163Smax.romanov@nginx.com nxt_debug(task, "engine %p: listen socket close: %d", task->thread->engine, 2843359Sigor@sysoev.ru lev->socket.fd); 2844359Sigor@sysoev.ru 2845359Sigor@sysoev.ru nxt_queue_remove(&lev->link); 2846359Sigor@sysoev.ru 2847683Sigor@sysoev.ru joint = lev->socket.data; 2848683Sigor@sysoev.ru lev->socket.data = NULL; 2849683Sigor@sysoev.ru 2850359Sigor@sysoev.ru /* 'task' refers to lev->task and we cannot use after nxt_free() */ 2851123Smax.romanov@nginx.com task = &task->thread->engine->task; 2852123Smax.romanov@nginx.com 2853359Sigor@sysoev.ru nxt_router_listen_socket_release(task, joint->socket_conf); 2854359Sigor@sysoev.ru 2855683Sigor@sysoev.ru nxt_router_listen_event_release(task, lev, joint); 285653Sigor@sysoev.ru } 285753Sigor@sysoev.ru 285853Sigor@sysoev.ru 285953Sigor@sysoev.ru static void 2860359Sigor@sysoev.ru nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf) 286153Sigor@sysoev.ru { 2862359Sigor@sysoev.ru nxt_listen_socket_t *ls; 286353Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 286453Sigor@sysoev.ru 2865359Sigor@sysoev.ru ls = skcf->listen; 2866118Sigor@sysoev.ru lock = &skcf->router_conf->router->lock; 286753Sigor@sysoev.ru 286853Sigor@sysoev.ru nxt_thread_spin_lock(lock); 286953Sigor@sysoev.ru 2870359Sigor@sysoev.ru nxt_debug(task, "engine %p: listen socket release: ls->count %D", 2871359Sigor@sysoev.ru task->thread->engine, ls->count); 2872359Sigor@sysoev.ru 2873359Sigor@sysoev.ru if (--ls->count != 0) { 2874359Sigor@sysoev.ru ls = NULL; 287553Sigor@sysoev.ru } 287653Sigor@sysoev.ru 287753Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 287853Sigor@sysoev.ru 2879359Sigor@sysoev.ru if (ls != NULL) { 2880359Sigor@sysoev.ru nxt_socket_close(task, ls->socket); 2881359Sigor@sysoev.ru nxt_free(ls); 288253Sigor@sysoev.ru } 288353Sigor@sysoev.ru } 288453Sigor@sysoev.ru 288553Sigor@sysoev.ru 2886683Sigor@sysoev.ru void 2887683Sigor@sysoev.ru nxt_router_listen_event_release(nxt_task_t *task, nxt_listen_event_t *lev, 2888683Sigor@sysoev.ru nxt_socket_conf_joint_t *joint) 2889683Sigor@sysoev.ru { 2890683Sigor@sysoev.ru nxt_event_engine_t *engine; 2891683Sigor@sysoev.ru 2892683Sigor@sysoev.ru nxt_debug(task, "listen event count: %D", lev->count); 2893683Sigor@sysoev.ru 2894683Sigor@sysoev.ru if (--lev->count == 0) { 2895683Sigor@sysoev.ru nxt_free(lev); 2896683Sigor@sysoev.ru } 2897683Sigor@sysoev.ru 2898683Sigor@sysoev.ru if (joint != NULL) { 2899683Sigor@sysoev.ru nxt_router_conf_release(task, joint); 2900683Sigor@sysoev.ru } 2901683Sigor@sysoev.ru 2902683Sigor@sysoev.ru engine = task->thread->engine; 2903683Sigor@sysoev.ru 2904683Sigor@sysoev.ru if (engine->shutdown && nxt_queue_is_empty(&engine->joints)) { 2905683Sigor@sysoev.ru nxt_thread_exit(task->thread); 2906683Sigor@sysoev.ru } 2907683Sigor@sysoev.ru } 2908683Sigor@sysoev.ru 2909683Sigor@sysoev.ru 2910683Sigor@sysoev.ru void 291153Sigor@sysoev.ru nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint) 291253Sigor@sysoev.ru { 291353Sigor@sysoev.ru nxt_socket_conf_t *skcf; 291453Sigor@sysoev.ru nxt_router_conf_t *rtcf; 291553Sigor@sysoev.ru nxt_thread_spinlock_t *lock; 291653Sigor@sysoev.ru 2917163Smax.romanov@nginx.com nxt_debug(task, "conf joint %p count: %D", joint, joint->count); 291853Sigor@sysoev.ru 291953Sigor@sysoev.ru if (--joint->count != 0) { 292053Sigor@sysoev.ru return; 292153Sigor@sysoev.ru } 292253Sigor@sysoev.ru 292353Sigor@sysoev.ru nxt_queue_remove(&joint->link); 292453Sigor@sysoev.ru 2925530Sigor@sysoev.ru /* 2926530Sigor@sysoev.ru * The joint content can not be safely used after the critical 2927530Sigor@sysoev.ru * section protected by the spinlock because its memory pool may 2928530Sigor@sysoev.ru * be already destroyed by another thread. 2929530Sigor@sysoev.ru */ 293053Sigor@sysoev.ru skcf = joint->socket_conf; 293153Sigor@sysoev.ru rtcf = skcf->router_conf; 293253Sigor@sysoev.ru lock = &rtcf->router->lock; 293353Sigor@sysoev.ru 293453Sigor@sysoev.ru nxt_thread_spin_lock(lock); 293553Sigor@sysoev.ru 2936163Smax.romanov@nginx.com nxt_debug(task, "conf skcf %p: %D, rtcf %p: %D", skcf, skcf->count, 2937163Smax.romanov@nginx.com rtcf, rtcf->count); 2938163Smax.romanov@nginx.com 293953Sigor@sysoev.ru if (--skcf->count != 0) { 2940952Sigor@sysoev.ru skcf = NULL; 294153Sigor@sysoev.ru rtcf = NULL; 294253Sigor@sysoev.ru 294353Sigor@sysoev.ru } else { 294453Sigor@sysoev.ru nxt_queue_remove(&skcf->link); 294553Sigor@sysoev.ru 294653Sigor@sysoev.ru if (--rtcf->count != 0) { 294753Sigor@sysoev.ru rtcf = NULL; 294853Sigor@sysoev.ru } 294953Sigor@sysoev.ru } 295053Sigor@sysoev.ru 295153Sigor@sysoev.ru nxt_thread_spin_unlock(lock); 295253Sigor@sysoev.ru 2953952Sigor@sysoev.ru if (skcf != NULL) { 2954964Sigor@sysoev.ru if (skcf->pass != NULL) { 2955964Sigor@sysoev.ru nxt_http_pass_cleanup(task, skcf->pass); 2956964Sigor@sysoev.ru } 2957964Sigor@sysoev.ru 2958952Sigor@sysoev.ru #if (NXT_TLS) 2959952Sigor@sysoev.ru if (skcf->tls != NULL) { 2960952Sigor@sysoev.ru task->thread->runtime->tls->server_free(task, skcf->tls); 2961952Sigor@sysoev.ru } 2962952Sigor@sysoev.ru #endif 2963952Sigor@sysoev.ru } 2964952Sigor@sysoev.ru 2965141Smax.romanov@nginx.com /* TODO remove engine->port */ 2966141Smax.romanov@nginx.com /* TODO excude from connected ports */ 2967141Smax.romanov@nginx.com 296853Sigor@sysoev.ru if (rtcf != NULL) { 2969115Sigor@sysoev.ru nxt_debug(task, "old router conf is destroyed"); 2970131Smax.romanov@nginx.com 2971964Sigor@sysoev.ru nxt_http_routes_cleanup(task, rtcf->routes); 2972964Sigor@sysoev.ru 2973630Svbart@nginx.com nxt_router_access_log_release(task, lock, rtcf->access_log); 2974630Svbart@nginx.com 2975131Smax.romanov@nginx.com nxt_mp_thread_adopt(rtcf->mem_pool); 2976131Smax.romanov@nginx.com 297765Sigor@sysoev.ru nxt_mp_destroy(rtcf->mem_pool); 297853Sigor@sysoev.ru } 297953Sigor@sysoev.ru } 298053Sigor@sysoev.ru 298153Sigor@sysoev.ru 298253Sigor@sysoev.ru static void 2983630Svbart@nginx.com nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r, 2984630Svbart@nginx.com nxt_router_access_log_t *access_log) 2985630Svbart@nginx.com { 2986630Svbart@nginx.com size_t size; 2987630Svbart@nginx.com u_char *buf, *p; 2988630Svbart@nginx.com nxt_off_t bytes; 2989630Svbart@nginx.com 2990630Svbart@nginx.com static nxt_time_string_t date_cache = { 2991630Svbart@nginx.com (nxt_atomic_uint_t) -1, 2992630Svbart@nginx.com nxt_router_access_log_date, 2993630Svbart@nginx.com "%02d/%s/%4d:%02d:%02d:%02d %c%02d%02d", 2994703Svbart@nginx.com nxt_length("31/Dec/1986:19:40:00 +0300"), 2995630Svbart@nginx.com NXT_THREAD_TIME_LOCAL, 2996630Svbart@nginx.com NXT_THREAD_TIME_SEC, 2997630Svbart@nginx.com }; 2998630Svbart@nginx.com 2999630Svbart@nginx.com size = r->remote->address_length 3000630Svbart@nginx.com + 6 /* ' - - [' */ 3001630Svbart@nginx.com + date_cache.size 3002630Svbart@nginx.com + 3 /* '] "' */ 3003630Svbart@nginx.com + r->method->length 3004630Svbart@nginx.com + 1 /* space */ 3005630Svbart@nginx.com + r->target.length 3006630Svbart@nginx.com + 1 /* space */ 3007630Svbart@nginx.com + r->version.length 3008630Svbart@nginx.com + 2 /* '" ' */ 3009630Svbart@nginx.com + 3 /* status */ 3010630Svbart@nginx.com + 1 /* space */ 3011630Svbart@nginx.com + NXT_OFF_T_LEN 3012630Svbart@nginx.com + 2 /* ' "' */ 3013630Svbart@nginx.com + (r->referer != NULL ? r->referer->value_length : 1) 3014630Svbart@nginx.com + 3 /* '" "' */ 3015630Svbart@nginx.com + (r->user_agent != NULL ? r->user_agent->value_length : 1) 3016630Svbart@nginx.com + 2 /* '"\n' */ 3017630Svbart@nginx.com ; 3018630Svbart@nginx.com 3019630Svbart@nginx.com buf = nxt_mp_nget(r->mem_pool, size); 3020630Svbart@nginx.com if (nxt_slow_path(buf == NULL)) { 3021630Svbart@nginx.com return; 3022630Svbart@nginx.com } 3023630Svbart@nginx.com 3024630Svbart@nginx.com p = nxt_cpymem(buf, nxt_sockaddr_address(r->remote), 3025630Svbart@nginx.com r->remote->address_length); 3026630Svbart@nginx.com 3027630Svbart@nginx.com p = nxt_cpymem(p, " - - [", 6); 3028630Svbart@nginx.com 3029630Svbart@nginx.com p = nxt_thread_time_string(task->thread, &date_cache, p); 3030630Svbart@nginx.com 3031630Svbart@nginx.com p = nxt_cpymem(p, "] \"", 3); 3032630Svbart@nginx.com 3033630Svbart@nginx.com if (r->method->length != 0) { 3034630Svbart@nginx.com p = nxt_cpymem(p, r->method->start, r->method->length); 3035630Svbart@nginx.com 3036630Svbart@nginx.com if (r->target.length != 0) { 3037630Svbart@nginx.com *p++ = ' '; 3038630Svbart@nginx.com p = nxt_cpymem(p, r->target.start, r->target.length); 3039630Svbart@nginx.com 3040630Svbart@nginx.com if (r->version.length != 0) { 3041630Svbart@nginx.com *p++ = ' '; 3042630Svbart@nginx.com p = nxt_cpymem(p, r->version.start, r->version.length); 3043630Svbart@nginx.com } 3044630Svbart@nginx.com } 3045630Svbart@nginx.com 3046630Svbart@nginx.com } else { 3047630Svbart@nginx.com *p++ = '-'; 3048630Svbart@nginx.com } 3049630Svbart@nginx.com 3050630Svbart@nginx.com p = nxt_cpymem(p, "\" ", 2); 3051630Svbart@nginx.com 3052630Svbart@nginx.com p = nxt_sprintf(p, p + 3, "%03d", r->status); 3053630Svbart@nginx.com 3054630Svbart@nginx.com *p++ = ' '; 3055630Svbart@nginx.com 3056630Svbart@nginx.com bytes = nxt_http_proto_body_bytes_sent[r->protocol](task, r->proto); 3057630Svbart@nginx.com 3058630Svbart@nginx.com p = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", bytes); 3059630Svbart@nginx.com 3060630Svbart@nginx.com p = nxt_cpymem(p, " \"", 2); 3061630Svbart@nginx.com 3062630Svbart@nginx.com if (r->referer != NULL) { 3063630Svbart@nginx.com p = nxt_cpymem(p, r->referer->value, r->referer->value_length); 3064630Svbart@nginx.com 3065630Svbart@nginx.com } else { 3066630Svbart@nginx.com *p++ = '-'; 3067630Svbart@nginx.com } 3068630Svbart@nginx.com 3069630Svbart@nginx.com p = nxt_cpymem(p, "\" \"", 3); 3070630Svbart@nginx.com 3071630Svbart@nginx.com if (r->user_agent != NULL) { 3072630Svbart@nginx.com p = nxt_cpymem(p, r->user_agent->value, r->user_agent->value_length); 3073630Svbart@nginx.com 3074630Svbart@nginx.com } else { 3075630Svbart@nginx.com *p++ = '-'; 3076630Svbart@nginx.com } 3077630Svbart@nginx.com 3078630Svbart@nginx.com p = nxt_cpymem(p, "\"\n", 2); 3079630Svbart@nginx.com 3080630Svbart@nginx.com nxt_fd_write(access_log->fd, buf, p - buf); 3081630Svbart@nginx.com } 3082630Svbart@nginx.com 3083630Svbart@nginx.com 3084630Svbart@nginx.com static u_char * 3085630Svbart@nginx.com nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, 3086630Svbart@nginx.com size_t size, const char *format) 3087630Svbart@nginx.com { 3088630Svbart@nginx.com u_char sign; 3089630Svbart@nginx.com time_t gmtoff; 3090630Svbart@nginx.com 3091630Svbart@nginx.com static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", 3092630Svbart@nginx.com "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; 3093630Svbart@nginx.com 3094630Svbart@nginx.com gmtoff = nxt_timezone(tm) / 60; 3095630Svbart@nginx.com 3096630Svbart@nginx.com if (gmtoff < 0) { 3097630Svbart@nginx.com gmtoff = -gmtoff; 3098630Svbart@nginx.com sign = '-'; 3099630Svbart@nginx.com 3100630Svbart@nginx.com } else { 3101630Svbart@nginx.com sign = '+'; 3102630Svbart@nginx.com } 3103630Svbart@nginx.com 3104630Svbart@nginx.com return nxt_sprintf(buf, buf + size, format, 3105630Svbart@nginx.com tm->tm_mday, month[tm->tm_mon], tm->tm_year + 1900, 3106630Svbart@nginx.com tm->tm_hour, tm->tm_min, tm->tm_sec, 3107630Svbart@nginx.com sign, gmtoff / 60, gmtoff % 60); 3108630Svbart@nginx.com } 3109630Svbart@nginx.com 3110630Svbart@nginx.com 3111630Svbart@nginx.com static void 3112630Svbart@nginx.com nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) 3113630Svbart@nginx.com { 3114630Svbart@nginx.com uint32_t stream; 3115648Svbart@nginx.com nxt_int_t ret; 3116630Svbart@nginx.com nxt_buf_t *b; 3117630Svbart@nginx.com nxt_port_t *main_port, *router_port; 3118630Svbart@nginx.com nxt_runtime_t *rt; 3119630Svbart@nginx.com nxt_router_access_log_t *access_log; 3120630Svbart@nginx.com 3121630Svbart@nginx.com access_log = tmcf->router_conf->access_log; 3122630Svbart@nginx.com 3123630Svbart@nginx.com b = nxt_buf_mem_alloc(tmcf->mem_pool, access_log->path.length + 1, 0); 3124630Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 3125630Svbart@nginx.com goto fail; 3126630Svbart@nginx.com } 3127630Svbart@nginx.com 3128630Svbart@nginx.com nxt_buf_cpystr(b, &access_log->path); 3129630Svbart@nginx.com *b->mem.free++ = '\0'; 3130630Svbart@nginx.com 3131630Svbart@nginx.com rt = task->thread->runtime; 3132630Svbart@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 3133630Svbart@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 3134630Svbart@nginx.com 3135630Svbart@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 3136630Svbart@nginx.com nxt_router_access_log_ready, 3137630Svbart@nginx.com nxt_router_access_log_error, 3138630Svbart@nginx.com -1, tmcf); 3139630Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 3140630Svbart@nginx.com goto fail; 3141630Svbart@nginx.com } 3142630Svbart@nginx.com 3143648Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1, 3144648Svbart@nginx.com stream, router_port->id, b); 3145648Svbart@nginx.com 3146648Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 3147648Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 3148648Svbart@nginx.com goto fail; 3149648Svbart@nginx.com } 3150630Svbart@nginx.com 3151630Svbart@nginx.com return; 3152630Svbart@nginx.com 3153630Svbart@nginx.com fail: 3154630Svbart@nginx.com 3155630Svbart@nginx.com nxt_router_conf_error(task, tmcf); 3156630Svbart@nginx.com } 3157630Svbart@nginx.com 3158630Svbart@nginx.com 3159630Svbart@nginx.com static void 3160630Svbart@nginx.com nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3161630Svbart@nginx.com void *data) 3162630Svbart@nginx.com { 3163630Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 3164630Svbart@nginx.com nxt_router_access_log_t *access_log; 3165630Svbart@nginx.com 3166630Svbart@nginx.com tmcf = data; 3167630Svbart@nginx.com 3168630Svbart@nginx.com access_log = tmcf->router_conf->access_log; 3169630Svbart@nginx.com 3170630Svbart@nginx.com access_log->fd = msg->fd; 3171630Svbart@nginx.com 3172630Svbart@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 3173630Svbart@nginx.com nxt_router_conf_apply, task, tmcf, NULL); 3174630Svbart@nginx.com } 3175630Svbart@nginx.com 3176630Svbart@nginx.com 3177630Svbart@nginx.com static void 3178630Svbart@nginx.com nxt_router_access_log_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3179630Svbart@nginx.com void *data) 3180630Svbart@nginx.com { 3181630Svbart@nginx.com nxt_router_temp_conf_t *tmcf; 3182630Svbart@nginx.com 3183630Svbart@nginx.com tmcf = data; 3184630Svbart@nginx.com 3185630Svbart@nginx.com nxt_router_conf_error(task, tmcf); 3186630Svbart@nginx.com } 3187630Svbart@nginx.com 3188630Svbart@nginx.com 3189630Svbart@nginx.com static void 3190630Svbart@nginx.com nxt_router_access_log_release(nxt_task_t *task, nxt_thread_spinlock_t *lock, 3191630Svbart@nginx.com nxt_router_access_log_t *access_log) 3192630Svbart@nginx.com { 3193630Svbart@nginx.com if (access_log == NULL) { 3194630Svbart@nginx.com return; 3195630Svbart@nginx.com } 3196630Svbart@nginx.com 3197630Svbart@nginx.com nxt_thread_spin_lock(lock); 3198630Svbart@nginx.com 3199630Svbart@nginx.com if (--access_log->count != 0) { 3200630Svbart@nginx.com access_log = NULL; 3201630Svbart@nginx.com } 3202630Svbart@nginx.com 3203630Svbart@nginx.com nxt_thread_spin_unlock(lock); 3204630Svbart@nginx.com 3205630Svbart@nginx.com if (access_log != NULL) { 3206630Svbart@nginx.com 3207630Svbart@nginx.com if (access_log->fd != -1) { 3208630Svbart@nginx.com nxt_fd_close(access_log->fd); 3209630Svbart@nginx.com } 3210630Svbart@nginx.com 3211630Svbart@nginx.com nxt_free(access_log); 3212630Svbart@nginx.com } 3213630Svbart@nginx.com } 3214630Svbart@nginx.com 3215630Svbart@nginx.com 3216631Svbart@nginx.com typedef struct { 3217631Svbart@nginx.com nxt_mp_t *mem_pool; 3218631Svbart@nginx.com nxt_router_access_log_t *access_log; 3219631Svbart@nginx.com } nxt_router_access_log_reopen_t; 3220631Svbart@nginx.com 3221631Svbart@nginx.com 3222631Svbart@nginx.com void 3223631Svbart@nginx.com nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) 3224631Svbart@nginx.com { 3225631Svbart@nginx.com nxt_mp_t *mp; 3226631Svbart@nginx.com uint32_t stream; 3227631Svbart@nginx.com nxt_int_t ret; 3228631Svbart@nginx.com nxt_buf_t *b; 3229631Svbart@nginx.com nxt_port_t *main_port, *router_port; 3230631Svbart@nginx.com nxt_runtime_t *rt; 3231631Svbart@nginx.com nxt_router_access_log_t *access_log; 3232631Svbart@nginx.com nxt_router_access_log_reopen_t *reopen; 3233631Svbart@nginx.com 3234631Svbart@nginx.com access_log = nxt_router->access_log; 3235631Svbart@nginx.com 3236631Svbart@nginx.com if (access_log == NULL) { 3237631Svbart@nginx.com return; 3238631Svbart@nginx.com } 3239631Svbart@nginx.com 3240631Svbart@nginx.com mp = nxt_mp_create(1024, 128, 256, 32); 3241631Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 3242631Svbart@nginx.com return; 3243631Svbart@nginx.com } 3244631Svbart@nginx.com 3245631Svbart@nginx.com reopen = nxt_mp_get(mp, sizeof(nxt_router_access_log_reopen_t)); 3246631Svbart@nginx.com if (nxt_slow_path(reopen == NULL)) { 3247631Svbart@nginx.com goto fail; 3248631Svbart@nginx.com } 3249631Svbart@nginx.com 3250631Svbart@nginx.com reopen->mem_pool = mp; 3251631Svbart@nginx.com reopen->access_log = access_log; 3252631Svbart@nginx.com 3253631Svbart@nginx.com b = nxt_buf_mem_alloc(mp, access_log->path.length + 1, 0); 3254631Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 3255631Svbart@nginx.com goto fail; 3256631Svbart@nginx.com } 3257631Svbart@nginx.com 3258651Svbart@nginx.com b->completion_handler = nxt_router_access_log_reopen_completion; 3259651Svbart@nginx.com 3260631Svbart@nginx.com nxt_buf_cpystr(b, &access_log->path); 3261631Svbart@nginx.com *b->mem.free++ = '\0'; 3262631Svbart@nginx.com 3263631Svbart@nginx.com rt = task->thread->runtime; 3264631Svbart@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 3265631Svbart@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 3266631Svbart@nginx.com 3267631Svbart@nginx.com stream = nxt_port_rpc_register_handler(task, router_port, 3268631Svbart@nginx.com nxt_router_access_log_reopen_ready, 3269631Svbart@nginx.com nxt_router_access_log_reopen_error, 3270631Svbart@nginx.com -1, reopen); 3271631Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 3272631Svbart@nginx.com goto fail; 3273631Svbart@nginx.com } 3274631Svbart@nginx.com 3275631Svbart@nginx.com ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1, 3276631Svbart@nginx.com stream, router_port->id, b); 3277631Svbart@nginx.com 3278631Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 3279631Svbart@nginx.com nxt_port_rpc_cancel(task, router_port, stream); 3280631Svbart@nginx.com goto fail; 3281631Svbart@nginx.com } 3282631Svbart@nginx.com 3283651Svbart@nginx.com nxt_mp_retain(mp); 3284651Svbart@nginx.com 3285631Svbart@nginx.com return; 3286631Svbart@nginx.com 3287631Svbart@nginx.com fail: 3288631Svbart@nginx.com 3289631Svbart@nginx.com nxt_mp_destroy(mp); 3290631Svbart@nginx.com } 3291631Svbart@nginx.com 3292631Svbart@nginx.com 3293631Svbart@nginx.com static void 3294651Svbart@nginx.com nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, void *data) 3295651Svbart@nginx.com { 3296651Svbart@nginx.com nxt_mp_t *mp; 3297651Svbart@nginx.com nxt_buf_t *b; 3298651Svbart@nginx.com 3299651Svbart@nginx.com b = obj; 3300651Svbart@nginx.com mp = b->data; 3301651Svbart@nginx.com 3302651Svbart@nginx.com nxt_mp_release(mp); 3303651Svbart@nginx.com } 3304651Svbart@nginx.com 3305651Svbart@nginx.com 3306651Svbart@nginx.com static void 3307631Svbart@nginx.com nxt_router_access_log_reopen_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3308631Svbart@nginx.com void *data) 3309631Svbart@nginx.com { 3310631Svbart@nginx.com nxt_router_access_log_t *access_log; 3311631Svbart@nginx.com nxt_router_access_log_reopen_t *reopen; 3312631Svbart@nginx.com 3313631Svbart@nginx.com reopen = data; 3314631Svbart@nginx.com 3315631Svbart@nginx.com access_log = reopen->access_log; 3316631Svbart@nginx.com 3317631Svbart@nginx.com if (access_log == nxt_router->access_log) { 3318631Svbart@nginx.com 3319631Svbart@nginx.com if (nxt_slow_path(dup2(msg->fd, access_log->fd) == -1)) { 3320631Svbart@nginx.com nxt_alert(task, "dup2(%FD, %FD) failed %E", 3321631Svbart@nginx.com msg->fd, access_log->fd, nxt_errno); 3322631Svbart@nginx.com } 3323631Svbart@nginx.com } 3324631Svbart@nginx.com 3325631Svbart@nginx.com nxt_fd_close(msg->fd); 3326651Svbart@nginx.com nxt_mp_release(reopen->mem_pool); 3327631Svbart@nginx.com } 3328631Svbart@nginx.com 3329631Svbart@nginx.com 3330631Svbart@nginx.com static void 3331631Svbart@nginx.com nxt_router_access_log_reopen_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3332631Svbart@nginx.com void *data) 3333631Svbart@nginx.com { 3334631Svbart@nginx.com nxt_router_access_log_reopen_t *reopen; 3335631Svbart@nginx.com 3336631Svbart@nginx.com reopen = data; 3337631Svbart@nginx.com 3338651Svbart@nginx.com nxt_mp_release(reopen->mem_pool); 3339631Svbart@nginx.com } 3340631Svbart@nginx.com 3341631Svbart@nginx.com 3342630Svbart@nginx.com static void 334353Sigor@sysoev.ru nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data) 334453Sigor@sysoev.ru { 3345141Smax.romanov@nginx.com nxt_port_t *port; 334653Sigor@sysoev.ru nxt_thread_link_t *link; 334753Sigor@sysoev.ru nxt_event_engine_t *engine; 334853Sigor@sysoev.ru nxt_thread_handle_t handle; 334953Sigor@sysoev.ru 335058Svbart@nginx.com handle = (nxt_thread_handle_t) obj; 335153Sigor@sysoev.ru link = data; 335253Sigor@sysoev.ru 335353Sigor@sysoev.ru nxt_thread_wait(handle); 335453Sigor@sysoev.ru 335553Sigor@sysoev.ru engine = link->engine; 335653Sigor@sysoev.ru 335753Sigor@sysoev.ru nxt_queue_remove(&engine->link); 335853Sigor@sysoev.ru 3359141Smax.romanov@nginx.com port = engine->port; 3360141Smax.romanov@nginx.com 3361141Smax.romanov@nginx.com // TODO notify all apps 3362141Smax.romanov@nginx.com 3363343Smax.romanov@nginx.com port->engine = task->thread->engine; 3364163Smax.romanov@nginx.com nxt_mp_thread_adopt(port->mem_pool); 3365343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 3366163Smax.romanov@nginx.com 3367163Smax.romanov@nginx.com nxt_mp_thread_adopt(engine->mem_pool); 336863Sigor@sysoev.ru nxt_mp_destroy(engine->mem_pool); 336953Sigor@sysoev.ru 337053Sigor@sysoev.ru nxt_event_engine_free(engine); 337153Sigor@sysoev.ru 337253Sigor@sysoev.ru nxt_free(link); 337353Sigor@sysoev.ru } 337453Sigor@sysoev.ru 337553Sigor@sysoev.ru 337653Sigor@sysoev.ru static void 3377318Smax.romanov@nginx.com nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3378318Smax.romanov@nginx.com void *data) 337988Smax.romanov@nginx.com { 338088Smax.romanov@nginx.com size_t dump_size; 3381431Sigor@sysoev.ru nxt_int_t ret; 3382608Sigor@sysoev.ru nxt_buf_t *b; 3383431Sigor@sysoev.ru nxt_http_request_t *r; 338488Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 3385431Sigor@sysoev.ru nxt_app_parse_ctx_t *ar; 3386743Smax.romanov@nginx.com nxt_unit_response_t *resp; 338788Smax.romanov@nginx.com 338888Smax.romanov@nginx.com b = msg->buf; 3389318Smax.romanov@nginx.com rc = data; 339088Smax.romanov@nginx.com 339188Smax.romanov@nginx.com dump_size = nxt_buf_used_size(b); 339288Smax.romanov@nginx.com 339388Smax.romanov@nginx.com if (dump_size > 300) { 339488Smax.romanov@nginx.com dump_size = 300; 339588Smax.romanov@nginx.com } 339688Smax.romanov@nginx.com 339788Smax.romanov@nginx.com if (msg->size == 0) { 339888Smax.romanov@nginx.com b = NULL; 339988Smax.romanov@nginx.com } 340088Smax.romanov@nginx.com 3401431Sigor@sysoev.ru ar = rc->ap; 3402570Smax.romanov@nginx.com if (nxt_slow_path(ar == NULL)) { 3403570Smax.romanov@nginx.com return; 3404570Smax.romanov@nginx.com } 3405425Smax.romanov@nginx.com 3406608Sigor@sysoev.ru if (ar->request->error) { 3407608Sigor@sysoev.ru nxt_router_rc_unlink(task, rc); 3408608Sigor@sysoev.ru return; 3409608Sigor@sysoev.ru } 3410608Sigor@sysoev.ru 341188Smax.romanov@nginx.com if (msg->port_msg.last != 0) { 341288Smax.romanov@nginx.com nxt_debug(task, "router data create last buf"); 341388Smax.romanov@nginx.com 3414608Sigor@sysoev.ru nxt_buf_chain_add(&b, nxt_http_buf_last(ar->request)); 3415167Smax.romanov@nginx.com 3416343Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 3417425Smax.romanov@nginx.com 3418425Smax.romanov@nginx.com } else { 3419615Smax.romanov@nginx.com if (rc->app != NULL && rc->app->timeout != 0) { 3420431Sigor@sysoev.ru ar->timer.handler = nxt_router_app_timeout; 3421615Smax.romanov@nginx.com ar->timer_data = rc; 3422431Sigor@sysoev.ru nxt_timer_add(task->thread->engine, &ar->timer, rc->app->timeout); 3423425Smax.romanov@nginx.com } 342488Smax.romanov@nginx.com } 342588Smax.romanov@nginx.com 342688Smax.romanov@nginx.com if (b == NULL) { 342788Smax.romanov@nginx.com return; 342888Smax.romanov@nginx.com } 342988Smax.romanov@nginx.com 3430206Smax.romanov@nginx.com if (msg->buf == b) { 3431206Smax.romanov@nginx.com /* Disable instant buffer completion/re-using by port. */ 3432206Smax.romanov@nginx.com msg->buf = NULL; 3433206Smax.romanov@nginx.com } 3434194Smax.romanov@nginx.com 3435431Sigor@sysoev.ru r = ar->request; 3436431Sigor@sysoev.ru 3437431Sigor@sysoev.ru if (r->header_sent) { 3438431Sigor@sysoev.ru nxt_buf_chain_add(&r->out, b); 3439431Sigor@sysoev.ru nxt_http_request_send_body(task, r, NULL); 3440277Sigor@sysoev.ru 344188Smax.romanov@nginx.com } else { 3442743Smax.romanov@nginx.com size_t b_size = nxt_buf_mem_used_size(&b->mem); 3443743Smax.romanov@nginx.com 3444743Smax.romanov@nginx.com if (nxt_slow_path(b_size < sizeof(*resp))) { 3445743Smax.romanov@nginx.com goto fail; 3446743Smax.romanov@nginx.com } 3447743Smax.romanov@nginx.com 3448743Smax.romanov@nginx.com resp = (void *) b->mem.pos; 3449743Smax.romanov@nginx.com if (nxt_slow_path(b_size < sizeof(*resp) 3450743Smax.romanov@nginx.com + resp->fields_count * sizeof(nxt_unit_field_t))) { 3451743Smax.romanov@nginx.com goto fail; 3452743Smax.romanov@nginx.com } 3453743Smax.romanov@nginx.com 3454743Smax.romanov@nginx.com nxt_unit_field_t *f; 3455743Smax.romanov@nginx.com nxt_http_field_t *field; 3456743Smax.romanov@nginx.com 3457743Smax.romanov@nginx.com for (f = resp->fields; f < resp->fields + resp->fields_count; f++) { 3458743Smax.romanov@nginx.com field = nxt_list_add(ar->resp_parser.fields); 3459743Smax.romanov@nginx.com 3460743Smax.romanov@nginx.com if (nxt_slow_path(field == NULL)) { 3461743Smax.romanov@nginx.com goto fail; 3462743Smax.romanov@nginx.com } 3463743Smax.romanov@nginx.com 3464743Smax.romanov@nginx.com field->hash = f->hash; 3465743Smax.romanov@nginx.com field->skip = f->skip; 3466743Smax.romanov@nginx.com 3467743Smax.romanov@nginx.com field->name_length = f->name_length; 3468743Smax.romanov@nginx.com field->value_length = f->value_length; 3469743Smax.romanov@nginx.com field->name = nxt_unit_sptr_get(&f->name); 3470743Smax.romanov@nginx.com field->value = nxt_unit_sptr_get(&f->value); 3471743Smax.romanov@nginx.com 3472743Smax.romanov@nginx.com nxt_debug(task, "header: %*s: %*s", 3473743Smax.romanov@nginx.com (size_t) field->name_length, field->name, 3474743Smax.romanov@nginx.com (size_t) field->value_length, field->value); 3475743Smax.romanov@nginx.com } 3476743Smax.romanov@nginx.com r->status = resp->status; 3477743Smax.romanov@nginx.com 3478743Smax.romanov@nginx.com /* 3479431Sigor@sysoev.ru ret = nxt_http_parse_fields(&ar->resp_parser, &b->mem); 3480431Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_DONE)) { 3481431Sigor@sysoev.ru goto fail; 3482431Sigor@sysoev.ru } 3483743Smax.romanov@nginx.com */ 3484431Sigor@sysoev.ru r->resp.fields = ar->resp_parser.fields; 3485431Sigor@sysoev.ru 3486431Sigor@sysoev.ru ret = nxt_http_fields_process(r->resp.fields, 3487431Sigor@sysoev.ru &nxt_response_fields_hash, r); 3488431Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 3489431Sigor@sysoev.ru goto fail; 3490431Sigor@sysoev.ru } 3491431Sigor@sysoev.ru 3492743Smax.romanov@nginx.com if (resp->piggyback_content_length != 0) { 3493743Smax.romanov@nginx.com b->mem.pos = nxt_unit_sptr_get(&resp->piggyback_content); 3494743Smax.romanov@nginx.com b->mem.free = b->mem.pos + resp->piggyback_content_length; 3495743Smax.romanov@nginx.com 3496743Smax.romanov@nginx.com } else { 3497743Smax.romanov@nginx.com b->mem.pos = b->mem.free; 3498743Smax.romanov@nginx.com } 3499743Smax.romanov@nginx.com 3500435Sigor@sysoev.ru if (nxt_buf_mem_used_size(&b->mem) == 0) { 3501435Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 3502435Sigor@sysoev.ru b->completion_handler, task, b, b->parent); 3503507Smax.romanov@nginx.com 3504520Smax.romanov@nginx.com b = b->next; 3505520Smax.romanov@nginx.com } 3506520Smax.romanov@nginx.com 3507520Smax.romanov@nginx.com if (b != NULL) { 3508431Sigor@sysoev.ru nxt_buf_chain_add(&r->out, b); 3509431Sigor@sysoev.ru } 3510431Sigor@sysoev.ru 3511431Sigor@sysoev.ru r->state = &nxt_http_request_send_state; 3512431Sigor@sysoev.ru 3513431Sigor@sysoev.ru nxt_http_request_header_send(task, r); 3514431Sigor@sysoev.ru } 3515431Sigor@sysoev.ru 3516431Sigor@sysoev.ru return; 3517431Sigor@sysoev.ru 3518431Sigor@sysoev.ru fail: 3519431Sigor@sysoev.ru 3520615Smax.romanov@nginx.com nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE); 3521615Smax.romanov@nginx.com 3522431Sigor@sysoev.ru nxt_router_rc_unlink(task, rc); 3523431Sigor@sysoev.ru } 3524431Sigor@sysoev.ru 3525431Sigor@sysoev.ru 3526431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_send_state 3527431Sigor@sysoev.ru nxt_aligned(64) = 3528431Sigor@sysoev.ru { 3529431Sigor@sysoev.ru .ready_handler = nxt_http_request_send_body, 3530943Sigor@sysoev.ru .error_handler = nxt_http_request_error_handler, 3531431Sigor@sysoev.ru }; 3532431Sigor@sysoev.ru 3533431Sigor@sysoev.ru 3534431Sigor@sysoev.ru static void 3535431Sigor@sysoev.ru nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data) 3536431Sigor@sysoev.ru { 3537431Sigor@sysoev.ru nxt_buf_t *out; 3538431Sigor@sysoev.ru nxt_http_request_t *r; 3539431Sigor@sysoev.ru 3540431Sigor@sysoev.ru r = obj; 3541431Sigor@sysoev.ru 3542431Sigor@sysoev.ru out = r->out; 3543431Sigor@sysoev.ru 3544431Sigor@sysoev.ru if (out != NULL) { 3545431Sigor@sysoev.ru r->out = NULL; 3546431Sigor@sysoev.ru nxt_http_request_send(task, r, out); 354788Smax.romanov@nginx.com } 354888Smax.romanov@nginx.com } 354988Smax.romanov@nginx.com 3550277Sigor@sysoev.ru 3551318Smax.romanov@nginx.com static void 3552318Smax.romanov@nginx.com nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3553318Smax.romanov@nginx.com void *data) 3554318Smax.romanov@nginx.com { 3555425Smax.romanov@nginx.com nxt_int_t res; 3556425Smax.romanov@nginx.com nxt_port_t *port; 3557425Smax.romanov@nginx.com nxt_bool_t cancelled; 3558425Smax.romanov@nginx.com nxt_req_app_link_t *ra; 3559318Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 3560318Smax.romanov@nginx.com 3561318Smax.romanov@nginx.com rc = data; 3562318Smax.romanov@nginx.com 3563425Smax.romanov@nginx.com ra = rc->ra; 3564425Smax.romanov@nginx.com 3565425Smax.romanov@nginx.com if (ra != NULL) { 3566425Smax.romanov@nginx.com cancelled = nxt_router_msg_cancel(task, &ra->msg_info, ra->stream); 3567425Smax.romanov@nginx.com 3568425Smax.romanov@nginx.com if (cancelled) { 3569425Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 3570425Smax.romanov@nginx.com 3571427Smax.romanov@nginx.com res = nxt_router_app_port(task, rc->app, ra); 3572425Smax.romanov@nginx.com 3573425Smax.romanov@nginx.com if (res == NXT_OK) { 3574425Smax.romanov@nginx.com port = ra->app_port; 3575425Smax.romanov@nginx.com 3576551Smax.romanov@nginx.com if (nxt_slow_path(port == NULL)) { 3577551Smax.romanov@nginx.com nxt_log(task, NXT_LOG_ERR, "port is NULL in cancelled ra"); 3578551Smax.romanov@nginx.com return; 3579551Smax.romanov@nginx.com } 3580425Smax.romanov@nginx.com 3581425Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, task->thread->engine->port, rc, 3582425Smax.romanov@nginx.com port->pid); 3583425Smax.romanov@nginx.com 3584425Smax.romanov@nginx.com nxt_router_app_prepare_request(task, ra); 3585425Smax.romanov@nginx.com } 3586425Smax.romanov@nginx.com 3587425Smax.romanov@nginx.com msg->port_msg.last = 0; 3588425Smax.romanov@nginx.com 3589425Smax.romanov@nginx.com return; 3590425Smax.romanov@nginx.com } 3591425Smax.romanov@nginx.com } 3592425Smax.romanov@nginx.com 3593616Smax.romanov@nginx.com if (rc->ap != NULL) { 3594616Smax.romanov@nginx.com nxt_http_request_error(task, rc->ap->request, 3595616Smax.romanov@nginx.com NXT_HTTP_SERVICE_UNAVAILABLE); 3596616Smax.romanov@nginx.com } 3597318Smax.romanov@nginx.com 3598343Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 3599318Smax.romanov@nginx.com } 3600318Smax.romanov@nginx.com 3601318Smax.romanov@nginx.com 3602141Smax.romanov@nginx.com static void 3603343Smax.romanov@nginx.com nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3604343Smax.romanov@nginx.com void *data) 3605192Smax.romanov@nginx.com { 3606753Smax.romanov@nginx.com nxt_app_t *app; 3607753Smax.romanov@nginx.com nxt_port_t *port; 3608753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 3609753Smax.romanov@nginx.com 3610753Smax.romanov@nginx.com app_joint = data; 3611347Smax.romanov@nginx.com port = msg->u.new_port; 3612343Smax.romanov@nginx.com 3613753Smax.romanov@nginx.com nxt_assert(app_joint != NULL); 3614343Smax.romanov@nginx.com nxt_assert(port != NULL); 3615343Smax.romanov@nginx.com 3616753Smax.romanov@nginx.com app = app_joint->app; 3617753Smax.romanov@nginx.com 3618753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 3619753Smax.romanov@nginx.com 3620753Smax.romanov@nginx.com if (nxt_slow_path(app == NULL)) { 3621753Smax.romanov@nginx.com nxt_debug(task, "new port ready for released app, send QUIT"); 3622753Smax.romanov@nginx.com 3623753Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 3624753Smax.romanov@nginx.com 3625753Smax.romanov@nginx.com return; 3626753Smax.romanov@nginx.com } 3627753Smax.romanov@nginx.com 3628343Smax.romanov@nginx.com port->app = app; 3629343Smax.romanov@nginx.com 3630343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3631343Smax.romanov@nginx.com 3632507Smax.romanov@nginx.com nxt_assert(app->pending_processes != 0); 3633507Smax.romanov@nginx.com 3634507Smax.romanov@nginx.com app->pending_processes--; 3635507Smax.romanov@nginx.com app->processes++; 3636343Smax.romanov@nginx.com 3637343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3638343Smax.romanov@nginx.com 3639507Smax.romanov@nginx.com nxt_debug(task, "app '%V' new port ready, pid %PI, %d/%d", 3640507Smax.romanov@nginx.com &app->name, port->pid, app->processes, app->pending_processes); 3641343Smax.romanov@nginx.com 3642343Smax.romanov@nginx.com nxt_router_app_port_release(task, port, 0, 0); 3643192Smax.romanov@nginx.com } 3644192Smax.romanov@nginx.com 3645192Smax.romanov@nginx.com 3646192Smax.romanov@nginx.com static void 3647343Smax.romanov@nginx.com nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 3648343Smax.romanov@nginx.com void *data) 3649192Smax.romanov@nginx.com { 3650318Smax.romanov@nginx.com nxt_app_t *app; 3651753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 3652318Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3653318Smax.romanov@nginx.com nxt_req_app_link_t *ra; 3654343Smax.romanov@nginx.com 3655753Smax.romanov@nginx.com app_joint = data; 3656753Smax.romanov@nginx.com 3657753Smax.romanov@nginx.com nxt_assert(app_joint != NULL); 3658753Smax.romanov@nginx.com 3659753Smax.romanov@nginx.com app = app_joint->app; 3660753Smax.romanov@nginx.com 3661753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 3662753Smax.romanov@nginx.com 3663753Smax.romanov@nginx.com if (nxt_slow_path(app == NULL)) { 3664753Smax.romanov@nginx.com nxt_debug(task, "start error for released app"); 3665753Smax.romanov@nginx.com 3666753Smax.romanov@nginx.com return; 3667753Smax.romanov@nginx.com } 3668343Smax.romanov@nginx.com 3669343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p start error", &app->name, app); 3670343Smax.romanov@nginx.com 3671343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3672343Smax.romanov@nginx.com 3673507Smax.romanov@nginx.com nxt_assert(app->pending_processes != 0); 3674507Smax.romanov@nginx.com 3675507Smax.romanov@nginx.com app->pending_processes--; 3676318Smax.romanov@nginx.com 3677318Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->requests)) { 3678318Smax.romanov@nginx.com lnk = nxt_queue_last(&app->requests); 3679318Smax.romanov@nginx.com nxt_queue_remove(lnk); 3680343Smax.romanov@nginx.com lnk->next = NULL; 3681318Smax.romanov@nginx.com 3682425Smax.romanov@nginx.com ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_requests); 3683318Smax.romanov@nginx.com 3684343Smax.romanov@nginx.com } else { 3685343Smax.romanov@nginx.com ra = NULL; 3686343Smax.romanov@nginx.com } 3687343Smax.romanov@nginx.com 3688343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3689343Smax.romanov@nginx.com 3690343Smax.romanov@nginx.com if (ra != NULL) { 3691318Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p abort next stream #%uD", 3692318Smax.romanov@nginx.com &app->name, app, ra->stream); 3693318Smax.romanov@nginx.com 3694507Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, "Failed to start application process"); 3695425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 3696318Smax.romanov@nginx.com } 3697192Smax.romanov@nginx.com } 3698192Smax.romanov@nginx.com 3699753Smax.romanov@nginx.com nxt_inline nxt_port_t * 3700753Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app); 3701192Smax.romanov@nginx.com 3702343Smax.romanov@nginx.com void 3703343Smax.romanov@nginx.com nxt_router_app_use(nxt_task_t *task, nxt_app_t *app, int i) 3704141Smax.romanov@nginx.com { 3705343Smax.romanov@nginx.com int c; 3706343Smax.romanov@nginx.com 3707343Smax.romanov@nginx.com c = nxt_atomic_fetch_add(&app->use_count, i); 3708343Smax.romanov@nginx.com 3709343Smax.romanov@nginx.com if (i < 0 && c == -i) { 3710343Smax.romanov@nginx.com 3711753Smax.romanov@nginx.com if (task->thread->engine != app->engine) { 3712753Smax.romanov@nginx.com nxt_event_engine_post(app->engine, &app->joint->free_app_work); 3713753Smax.romanov@nginx.com 3714753Smax.romanov@nginx.com } else { 3715753Smax.romanov@nginx.com nxt_router_free_app(task, app->joint, NULL); 3716753Smax.romanov@nginx.com } 3717163Smax.romanov@nginx.com } 3718343Smax.romanov@nginx.com } 3719343Smax.romanov@nginx.com 3720343Smax.romanov@nginx.com 3721424Smax.romanov@nginx.com nxt_inline nxt_bool_t 3722424Smax.romanov@nginx.com nxt_router_app_first_port_busy(nxt_app_t *app) 3723424Smax.romanov@nginx.com { 3724424Smax.romanov@nginx.com nxt_port_t *port; 3725424Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3726424Smax.romanov@nginx.com 3727424Smax.romanov@nginx.com lnk = nxt_queue_first(&app->ports); 3728424Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, app_link); 3729424Smax.romanov@nginx.com 3730424Smax.romanov@nginx.com return port->app_pending_responses > 0; 3731424Smax.romanov@nginx.com } 3732424Smax.romanov@nginx.com 3733424Smax.romanov@nginx.com 3734343Smax.romanov@nginx.com nxt_inline nxt_port_t * 3735427Smax.romanov@nginx.com nxt_router_pop_first_port(nxt_app_t *app) 3736343Smax.romanov@nginx.com { 3737343Smax.romanov@nginx.com nxt_port_t *port; 3738343Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3739343Smax.romanov@nginx.com 3740343Smax.romanov@nginx.com lnk = nxt_queue_first(&app->ports); 3741343Smax.romanov@nginx.com nxt_queue_remove(lnk); 3742343Smax.romanov@nginx.com 3743343Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, app_link); 3744343Smax.romanov@nginx.com 3745424Smax.romanov@nginx.com port->app_pending_responses++; 3746424Smax.romanov@nginx.com 3747507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 3748507Smax.romanov@nginx.com app->idle_processes--; 3749507Smax.romanov@nginx.com 3750507Smax.romanov@nginx.com if (port->idle_start == 0) { 3751507Smax.romanov@nginx.com nxt_assert(app->idle_processes < app->spare_processes); 3752507Smax.romanov@nginx.com 3753507Smax.romanov@nginx.com } else { 3754507Smax.romanov@nginx.com nxt_assert(app->idle_processes >= app->spare_processes); 3755507Smax.romanov@nginx.com 3756507Smax.romanov@nginx.com port->idle_start = 0; 3757507Smax.romanov@nginx.com } 3758507Smax.romanov@nginx.com } 3759507Smax.romanov@nginx.com 3760428Smax.romanov@nginx.com if ((app->max_pending_responses == 0 3761428Smax.romanov@nginx.com || port->app_pending_responses < app->max_pending_responses) 3762428Smax.romanov@nginx.com && (app->max_requests == 0 3763428Smax.romanov@nginx.com || port->app_responses + port->app_pending_responses 3764428Smax.romanov@nginx.com < app->max_requests)) 3765277Sigor@sysoev.ru { 3766343Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, lnk); 3767343Smax.romanov@nginx.com 3768425Smax.romanov@nginx.com nxt_port_inc_use(port); 3769425Smax.romanov@nginx.com 3770343Smax.romanov@nginx.com } else { 3771343Smax.romanov@nginx.com lnk->next = NULL; 3772167Smax.romanov@nginx.com } 3773167Smax.romanov@nginx.com 3774343Smax.romanov@nginx.com return port; 3775163Smax.romanov@nginx.com } 3776163Smax.romanov@nginx.com 3777163Smax.romanov@nginx.com 3778507Smax.romanov@nginx.com nxt_inline nxt_port_t * 3779507Smax.romanov@nginx.com nxt_router_app_get_port_for_quit(nxt_app_t *app) 3780141Smax.romanov@nginx.com { 3781343Smax.romanov@nginx.com nxt_port_t *port; 3782141Smax.romanov@nginx.com 3783141Smax.romanov@nginx.com port = NULL; 3784141Smax.romanov@nginx.com 3785141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3786141Smax.romanov@nginx.com 3787343Smax.romanov@nginx.com nxt_queue_each(port, &app->ports, nxt_port_t, app_link) { 3788343Smax.romanov@nginx.com 3789424Smax.romanov@nginx.com if (port->app_pending_responses > 0) { 3790343Smax.romanov@nginx.com port = NULL; 3791343Smax.romanov@nginx.com 3792343Smax.romanov@nginx.com continue; 3793343Smax.romanov@nginx.com } 3794343Smax.romanov@nginx.com 3795507Smax.romanov@nginx.com /* Caller is responsible to decrease port use count. */ 3796507Smax.romanov@nginx.com nxt_queue_chk_remove(&port->app_link); 3797507Smax.romanov@nginx.com 3798507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 3799507Smax.romanov@nginx.com app->idle_processes--; 3800507Smax.romanov@nginx.com } 3801507Smax.romanov@nginx.com 3802507Smax.romanov@nginx.com port->app = NULL; 3803507Smax.romanov@nginx.com app->processes--; 3804343Smax.romanov@nginx.com 3805343Smax.romanov@nginx.com break; 3806343Smax.romanov@nginx.com 3807343Smax.romanov@nginx.com } nxt_queue_loop; 3808141Smax.romanov@nginx.com 3809141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 3810141Smax.romanov@nginx.com 3811141Smax.romanov@nginx.com return port; 3812141Smax.romanov@nginx.com } 3813141Smax.romanov@nginx.com 3814141Smax.romanov@nginx.com 3815141Smax.romanov@nginx.com static void 3816753Smax.romanov@nginx.com nxt_router_app_unlink(nxt_task_t *task, nxt_app_t *app) 3817507Smax.romanov@nginx.com { 3818753Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p unlink", &app->name, app); 3819507Smax.romanov@nginx.com 3820507Smax.romanov@nginx.com nxt_queue_remove(&app->link); 3821507Smax.romanov@nginx.com 3822753Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 3823507Smax.romanov@nginx.com } 3824507Smax.romanov@nginx.com 3825507Smax.romanov@nginx.com 3826507Smax.romanov@nginx.com static void 3827343Smax.romanov@nginx.com nxt_router_app_process_request(nxt_task_t *task, void *obj, void *data) 3828141Smax.romanov@nginx.com { 3829343Smax.romanov@nginx.com nxt_req_app_link_t *ra; 3830343Smax.romanov@nginx.com 3831538Svbart@nginx.com ra = data; 3832538Svbart@nginx.com 3833538Svbart@nginx.com #if (NXT_DEBUG) 3834538Svbart@nginx.com { 3835538Svbart@nginx.com nxt_app_t *app; 3836538Svbart@nginx.com 3837343Smax.romanov@nginx.com app = obj; 3838141Smax.romanov@nginx.com 3839141Smax.romanov@nginx.com nxt_assert(app != NULL); 3840343Smax.romanov@nginx.com nxt_assert(ra != NULL); 3841343Smax.romanov@nginx.com nxt_assert(ra->app_port != NULL); 3842343Smax.romanov@nginx.com 3843343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p process next stream #%uD", 3844343Smax.romanov@nginx.com &app->name, app, ra->stream); 3845538Svbart@nginx.com } 3846538Svbart@nginx.com #endif 3847343Smax.romanov@nginx.com 3848425Smax.romanov@nginx.com nxt_router_app_prepare_request(task, ra); 3849343Smax.romanov@nginx.com } 3850343Smax.romanov@nginx.com 3851343Smax.romanov@nginx.com 3852343Smax.romanov@nginx.com static void 3853343Smax.romanov@nginx.com nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port, 3854343Smax.romanov@nginx.com uint32_t request_failed, uint32_t got_response) 3855343Smax.romanov@nginx.com { 3856427Smax.romanov@nginx.com nxt_app_t *app; 3857507Smax.romanov@nginx.com nxt_bool_t port_unchained; 3858507Smax.romanov@nginx.com nxt_bool_t send_quit, cancelled, adjust_idle_timer; 3859427Smax.romanov@nginx.com nxt_queue_link_t *lnk; 3860427Smax.romanov@nginx.com nxt_req_app_link_t *ra, *pending_ra, *re_ra; 3861427Smax.romanov@nginx.com nxt_port_select_state_t state; 3862343Smax.romanov@nginx.com 3863343Smax.romanov@nginx.com nxt_assert(port != NULL); 3864343Smax.romanov@nginx.com nxt_assert(port->app != NULL); 3865343Smax.romanov@nginx.com 3866427Smax.romanov@nginx.com ra = NULL; 3867427Smax.romanov@nginx.com 3868343Smax.romanov@nginx.com app = port->app; 3869343Smax.romanov@nginx.com 3870343Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 3871343Smax.romanov@nginx.com 3872424Smax.romanov@nginx.com port->app_pending_responses -= request_failed + got_response; 3873343Smax.romanov@nginx.com port->app_responses += got_response; 3874343Smax.romanov@nginx.com 3875427Smax.romanov@nginx.com if (port->pair[1] != -1 3876426Smax.romanov@nginx.com && (app->max_pending_responses == 0 3877428Smax.romanov@nginx.com || port->app_pending_responses < app->max_pending_responses) 3878428Smax.romanov@nginx.com && (app->max_requests == 0 3879428Smax.romanov@nginx.com || port->app_responses + port->app_pending_responses 3880428Smax.romanov@nginx.com < app->max_requests)) 3881343Smax.romanov@nginx.com { 3882424Smax.romanov@nginx.com if (port->app_link.next == NULL) { 3883424Smax.romanov@nginx.com if (port->app_pending_responses > 0) { 3884424Smax.romanov@nginx.com nxt_queue_insert_tail(&app->ports, &port->app_link); 3885424Smax.romanov@nginx.com 3886424Smax.romanov@nginx.com } else { 3887424Smax.romanov@nginx.com nxt_queue_insert_head(&app->ports, &port->app_link); 3888424Smax.romanov@nginx.com } 3889424Smax.romanov@nginx.com 3890425Smax.romanov@nginx.com nxt_port_inc_use(port); 3891424Smax.romanov@nginx.com 3892424Smax.romanov@nginx.com } else { 3893424Smax.romanov@nginx.com if (port->app_pending_responses == 0 3894424Smax.romanov@nginx.com && nxt_queue_first(&app->ports) != &port->app_link) 3895424Smax.romanov@nginx.com { 3896424Smax.romanov@nginx.com nxt_queue_remove(&port->app_link); 3897424Smax.romanov@nginx.com nxt_queue_insert_head(&app->ports, &port->app_link); 3898424Smax.romanov@nginx.com } 3899424Smax.romanov@nginx.com } 3900141Smax.romanov@nginx.com } 3901141Smax.romanov@nginx.com 3902427Smax.romanov@nginx.com if (!nxt_queue_is_empty(&app->ports) 3903426Smax.romanov@nginx.com && !nxt_queue_is_empty(&app->requests)) 3904343Smax.romanov@nginx.com { 3905141Smax.romanov@nginx.com lnk = nxt_queue_first(&app->requests); 3906141Smax.romanov@nginx.com nxt_queue_remove(lnk); 3907343Smax.romanov@nginx.com lnk->next = NULL; 3908141Smax.romanov@nginx.com 3909425Smax.romanov@nginx.com ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_requests); 3910425Smax.romanov@nginx.com 3911427Smax.romanov@nginx.com ra->app_port = nxt_router_pop_first_port(app); 3912425Smax.romanov@nginx.com 3913425Smax.romanov@nginx.com if (ra->app_port->app_pending_responses > 1) { 3914427Smax.romanov@nginx.com nxt_router_ra_pending(task, app, ra); 3915425Smax.romanov@nginx.com } 3916425Smax.romanov@nginx.com } 3917425Smax.romanov@nginx.com 3918427Smax.romanov@nginx.com /* Pop first pending request for this port. */ 3919425Smax.romanov@nginx.com if ((request_failed > 0 || got_response > 0) 3920425Smax.romanov@nginx.com && !nxt_queue_is_empty(&port->pending_requests)) 3921425Smax.romanov@nginx.com { 3922425Smax.romanov@nginx.com lnk = nxt_queue_first(&port->pending_requests); 3923425Smax.romanov@nginx.com nxt_queue_remove(lnk); 3924425Smax.romanov@nginx.com lnk->next = NULL; 3925425Smax.romanov@nginx.com 3926427Smax.romanov@nginx.com pending_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, 3927427Smax.romanov@nginx.com link_port_pending); 3928427Smax.romanov@nginx.com 3929427Smax.romanov@nginx.com nxt_assert(pending_ra->link_app_pending.next != NULL); 3930427Smax.romanov@nginx.com 3931427Smax.romanov@nginx.com nxt_queue_remove(&pending_ra->link_app_pending); 3932427Smax.romanov@nginx.com pending_ra->link_app_pending.next = NULL; 3933425Smax.romanov@nginx.com 3934425Smax.romanov@nginx.com } else { 3935427Smax.romanov@nginx.com pending_ra = NULL; 3936141Smax.romanov@nginx.com } 3937141Smax.romanov@nginx.com 3938427Smax.romanov@nginx.com /* Try to cancel and re-schedule first stalled request for this app. */ 3939427Smax.romanov@nginx.com if (got_response > 0 && !nxt_queue_is_empty(&app->pending)) { 3940427Smax.romanov@nginx.com lnk = nxt_queue_first(&app->pending); 3941427Smax.romanov@nginx.com 3942427Smax.romanov@nginx.com re_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, link_app_pending); 3943427Smax.romanov@nginx.com 3944427Smax.romanov@nginx.com if (re_ra->res_time <= nxt_thread_monotonic_time(task->thread)) { 3945427Smax.romanov@nginx.com 3946427Smax.romanov@nginx.com nxt_debug(task, "app '%V' stalled request #%uD detected", 3947427Smax.romanov@nginx.com &app->name, re_ra->stream); 3948427Smax.romanov@nginx.com 3949427Smax.romanov@nginx.com cancelled = nxt_router_msg_cancel(task, &re_ra->msg_info, 3950427Smax.romanov@nginx.com re_ra->stream); 3951427Smax.romanov@nginx.com 3952427Smax.romanov@nginx.com if (cancelled) { 3953427Smax.romanov@nginx.com nxt_router_ra_inc_use(re_ra); 3954427Smax.romanov@nginx.com 3955427Smax.romanov@nginx.com state.ra = re_ra; 3956427Smax.romanov@nginx.com state.app = app; 3957427Smax.romanov@nginx.com 3958427Smax.romanov@nginx.com nxt_router_port_select(task, &state); 3959427Smax.romanov@nginx.com 3960427Smax.romanov@nginx.com goto re_ra_cancelled; 3961427Smax.romanov@nginx.com } 3962427Smax.romanov@nginx.com } 3963427Smax.romanov@nginx.com } 3964427Smax.romanov@nginx.com 3965427Smax.romanov@nginx.com re_ra = NULL; 3966427Smax.romanov@nginx.com 3967427Smax.romanov@nginx.com re_ra_cancelled: 3968427Smax.romanov@nginx.com 3969753Smax.romanov@nginx.com send_quit = (app->max_requests > 0 3970753Smax.romanov@nginx.com && port->app_pending_responses == 0 3971753Smax.romanov@nginx.com && port->app_responses >= app->max_requests); 3972367Smax.romanov@nginx.com 3973507Smax.romanov@nginx.com if (send_quit) { 3974507Smax.romanov@nginx.com port_unchained = nxt_queue_chk_remove(&port->app_link); 3975507Smax.romanov@nginx.com 3976507Smax.romanov@nginx.com port->app = NULL; 3977507Smax.romanov@nginx.com app->processes--; 3978507Smax.romanov@nginx.com 3979507Smax.romanov@nginx.com } else { 3980507Smax.romanov@nginx.com port_unchained = 0; 3981507Smax.romanov@nginx.com } 3982507Smax.romanov@nginx.com 3983507Smax.romanov@nginx.com adjust_idle_timer = 0; 3984507Smax.romanov@nginx.com 3985571Smax.romanov@nginx.com if (port->pair[1] != -1 && !send_quit && port->app_pending_responses == 0) { 3986507Smax.romanov@nginx.com nxt_assert(port->idle_link.next == NULL); 3987507Smax.romanov@nginx.com 3988507Smax.romanov@nginx.com if (app->idle_processes == app->spare_processes 3989507Smax.romanov@nginx.com && app->adjust_idle_work.data == NULL) 3990507Smax.romanov@nginx.com { 3991507Smax.romanov@nginx.com adjust_idle_timer = 1; 3992507Smax.romanov@nginx.com app->adjust_idle_work.data = app; 3993507Smax.romanov@nginx.com app->adjust_idle_work.next = NULL; 3994507Smax.romanov@nginx.com } 3995507Smax.romanov@nginx.com 3996507Smax.romanov@nginx.com if (app->idle_processes < app->spare_processes) { 3997507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, &port->idle_link); 3998507Smax.romanov@nginx.com 3999507Smax.romanov@nginx.com } else { 4000507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->idle_ports, &port->idle_link); 4001507Smax.romanov@nginx.com 4002507Smax.romanov@nginx.com port->idle_start = task->thread->engine->timers.now; 4003507Smax.romanov@nginx.com } 4004507Smax.romanov@nginx.com 4005507Smax.romanov@nginx.com app->idle_processes++; 4006507Smax.romanov@nginx.com } 4007507Smax.romanov@nginx.com 4008343Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4009343Smax.romanov@nginx.com 4010507Smax.romanov@nginx.com if (adjust_idle_timer) { 4011507Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 4012507Smax.romanov@nginx.com nxt_event_engine_post(app->engine, &app->adjust_idle_work); 4013507Smax.romanov@nginx.com } 4014507Smax.romanov@nginx.com 4015427Smax.romanov@nginx.com if (pending_ra != NULL) { 4016427Smax.romanov@nginx.com nxt_router_ra_use(task, pending_ra, -1); 4017427Smax.romanov@nginx.com } 4018427Smax.romanov@nginx.com 4019427Smax.romanov@nginx.com if (re_ra != NULL) { 4020427Smax.romanov@nginx.com if (nxt_router_port_post_select(task, &state) == NXT_OK) { 4021427Smax.romanov@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 4022427Smax.romanov@nginx.com nxt_router_app_process_request, 4023427Smax.romanov@nginx.com &task->thread->engine->task, app, re_ra); 4024427Smax.romanov@nginx.com } 4025425Smax.romanov@nginx.com } 4026425Smax.romanov@nginx.com 4027343Smax.romanov@nginx.com if (ra != NULL) { 4028425Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 4029425Smax.romanov@nginx.com 4030343Smax.romanov@nginx.com nxt_work_queue_add(&task->thread->engine->fast_work_queue, 4031343Smax.romanov@nginx.com nxt_router_app_process_request, 4032343Smax.romanov@nginx.com &task->thread->engine->task, app, ra); 4033343Smax.romanov@nginx.com 4034343Smax.romanov@nginx.com goto adjust_use; 4035343Smax.romanov@nginx.com } 4036343Smax.romanov@nginx.com 4037343Smax.romanov@nginx.com /* ? */ 4038163Smax.romanov@nginx.com if (port->pair[1] == -1) { 4039343Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p port %p already closed (pid %PI dead?)", 4040343Smax.romanov@nginx.com &app->name, app, port, port->pid); 4041343Smax.romanov@nginx.com 4042343Smax.romanov@nginx.com goto adjust_use; 4043163Smax.romanov@nginx.com } 4044163Smax.romanov@nginx.com 4045367Smax.romanov@nginx.com if (send_quit) { 4046507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p send QUIT to port", 4047167Smax.romanov@nginx.com &app->name, app); 4048163Smax.romanov@nginx.com 4049163Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, 4050163Smax.romanov@nginx.com -1, 0, 0, NULL); 4051163Smax.romanov@nginx.com 4052507Smax.romanov@nginx.com if (port_unchained) { 4053507Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4054507Smax.romanov@nginx.com } 4055507Smax.romanov@nginx.com 4056343Smax.romanov@nginx.com goto adjust_use; 4057163Smax.romanov@nginx.com } 4058163Smax.romanov@nginx.com 4059167Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p requests queue is empty, keep the port", 4060167Smax.romanov@nginx.com &app->name, app); 4061141Smax.romanov@nginx.com 4062343Smax.romanov@nginx.com adjust_use: 4063343Smax.romanov@nginx.com 4064425Smax.romanov@nginx.com if (request_failed > 0 || got_response > 0) { 4065425Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4066343Smax.romanov@nginx.com } 4067141Smax.romanov@nginx.com } 4068141Smax.romanov@nginx.com 4069141Smax.romanov@nginx.com 4070343Smax.romanov@nginx.com void 4071343Smax.romanov@nginx.com nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port) 4072141Smax.romanov@nginx.com { 4073507Smax.romanov@nginx.com nxt_app_t *app; 4074507Smax.romanov@nginx.com nxt_bool_t unchain, start_process; 4075507Smax.romanov@nginx.com nxt_port_t *idle_port; 4076507Smax.romanov@nginx.com nxt_queue_link_t *idle_lnk; 4077141Smax.romanov@nginx.com 4078141Smax.romanov@nginx.com app = port->app; 4079343Smax.romanov@nginx.com 4080343Smax.romanov@nginx.com nxt_assert(app != NULL); 4081141Smax.romanov@nginx.com 4082141Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4083141Smax.romanov@nginx.com 4084507Smax.romanov@nginx.com unchain = nxt_queue_chk_remove(&port->app_link); 4085507Smax.romanov@nginx.com 4086507Smax.romanov@nginx.com if (nxt_queue_chk_remove(&port->idle_link)) { 4087507Smax.romanov@nginx.com app->idle_processes--; 4088507Smax.romanov@nginx.com 4089507Smax.romanov@nginx.com if (port->idle_start == 0 4090507Smax.romanov@nginx.com && app->idle_processes >= app->spare_processes) 4091507Smax.romanov@nginx.com { 4092507Smax.romanov@nginx.com nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); 4093507Smax.romanov@nginx.com 4094507Smax.romanov@nginx.com idle_lnk = nxt_queue_last(&app->idle_ports); 4095507Smax.romanov@nginx.com idle_port = nxt_queue_link_data(idle_lnk, nxt_port_t, idle_link); 4096507Smax.romanov@nginx.com nxt_queue_remove(idle_lnk); 4097507Smax.romanov@nginx.com 4098507Smax.romanov@nginx.com nxt_queue_insert_tail(&app->spare_ports, idle_lnk); 4099507Smax.romanov@nginx.com 4100507Smax.romanov@nginx.com idle_port->idle_start = 0; 4101507Smax.romanov@nginx.com } 4102343Smax.romanov@nginx.com } 4103343Smax.romanov@nginx.com 4104507Smax.romanov@nginx.com app->processes--; 4105507Smax.romanov@nginx.com 4106753Smax.romanov@nginx.com start_process = !task->thread->engine->shutdown 4107507Smax.romanov@nginx.com && nxt_router_app_can_start(app) 4108507Smax.romanov@nginx.com && (!nxt_queue_is_empty(&app->requests) 4109507Smax.romanov@nginx.com || nxt_router_app_need_start(app)); 4110507Smax.romanov@nginx.com 4111507Smax.romanov@nginx.com if (start_process) { 4112507Smax.romanov@nginx.com app->pending_processes++; 4113163Smax.romanov@nginx.com } 4114141Smax.romanov@nginx.com 4115141Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4116163Smax.romanov@nginx.com 4117507Smax.romanov@nginx.com nxt_debug(task, "app '%V' pid %PI closed", &app->name, port->pid); 4118343Smax.romanov@nginx.com 4119343Smax.romanov@nginx.com if (unchain) { 4120343Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4121163Smax.romanov@nginx.com } 4122163Smax.romanov@nginx.com 4123507Smax.romanov@nginx.com if (start_process) { 4124507Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 4125507Smax.romanov@nginx.com } 4126507Smax.romanov@nginx.com } 4127507Smax.romanov@nginx.com 4128507Smax.romanov@nginx.com 4129507Smax.romanov@nginx.com static void 4130507Smax.romanov@nginx.com nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, void *data) 4131507Smax.romanov@nginx.com { 4132507Smax.romanov@nginx.com nxt_app_t *app; 4133507Smax.romanov@nginx.com nxt_bool_t queued; 4134507Smax.romanov@nginx.com nxt_port_t *port; 4135507Smax.romanov@nginx.com nxt_msec_t timeout, threshold; 4136507Smax.romanov@nginx.com nxt_queue_link_t *lnk; 4137507Smax.romanov@nginx.com nxt_event_engine_t *engine; 4138507Smax.romanov@nginx.com 4139507Smax.romanov@nginx.com app = obj; 4140507Smax.romanov@nginx.com queued = (data == app); 4141507Smax.romanov@nginx.com 4142507Smax.romanov@nginx.com nxt_debug(task, "nxt_router_adjust_idle_timer: app \"%V\", queued %b", 4143507Smax.romanov@nginx.com &app->name, queued); 4144507Smax.romanov@nginx.com 4145507Smax.romanov@nginx.com engine = task->thread->engine; 4146507Smax.romanov@nginx.com 4147507Smax.romanov@nginx.com nxt_assert(app->engine == engine); 4148507Smax.romanov@nginx.com 4149811Svbart@nginx.com threshold = engine->timers.now + app->joint->idle_timer.bias; 4150507Smax.romanov@nginx.com timeout = 0; 4151507Smax.romanov@nginx.com 4152507Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4153507Smax.romanov@nginx.com 4154507Smax.romanov@nginx.com if (queued) { 4155507Smax.romanov@nginx.com app->adjust_idle_work.data = NULL; 4156343Smax.romanov@nginx.com } 4157507Smax.romanov@nginx.com 4158507Smax.romanov@nginx.com while (app->idle_processes > app->spare_processes) { 4159507Smax.romanov@nginx.com 4160551Smax.romanov@nginx.com nxt_assert(!nxt_queue_is_empty(&app->idle_ports)); 4161507Smax.romanov@nginx.com 4162507Smax.romanov@nginx.com lnk = nxt_queue_first(&app->idle_ports); 4163507Smax.romanov@nginx.com port = nxt_queue_link_data(lnk, nxt_port_t, idle_link); 4164507Smax.romanov@nginx.com 4165507Smax.romanov@nginx.com timeout = port->idle_start + app->idle_timeout; 4166507Smax.romanov@nginx.com 4167507Smax.romanov@nginx.com if (timeout > threshold) { 4168507Smax.romanov@nginx.com break; 4169507Smax.romanov@nginx.com } 4170507Smax.romanov@nginx.com 4171507Smax.romanov@nginx.com nxt_queue_remove(lnk); 4172507Smax.romanov@nginx.com lnk->next = NULL; 4173507Smax.romanov@nginx.com 4174507Smax.romanov@nginx.com nxt_queue_chk_remove(&port->app_link); 4175507Smax.romanov@nginx.com 4176507Smax.romanov@nginx.com app->idle_processes--; 4177507Smax.romanov@nginx.com app->processes--; 4178507Smax.romanov@nginx.com port->app = NULL; 4179507Smax.romanov@nginx.com 4180507Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4181507Smax.romanov@nginx.com 4182507Smax.romanov@nginx.com nxt_debug(task, "app '%V' send QUIT to idle port %PI", 4183507Smax.romanov@nginx.com &app->name, port->pid); 4184507Smax.romanov@nginx.com 4185507Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 4186507Smax.romanov@nginx.com 4187507Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4188507Smax.romanov@nginx.com 4189507Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4190507Smax.romanov@nginx.com } 4191507Smax.romanov@nginx.com 4192507Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4193507Smax.romanov@nginx.com 4194507Smax.romanov@nginx.com if (timeout > threshold) { 4195753Smax.romanov@nginx.com nxt_timer_add(engine, &app->joint->idle_timer, timeout - threshold); 4196507Smax.romanov@nginx.com 4197507Smax.romanov@nginx.com } else { 4198753Smax.romanov@nginx.com nxt_timer_disable(engine, &app->joint->idle_timer); 4199507Smax.romanov@nginx.com } 4200507Smax.romanov@nginx.com 4201507Smax.romanov@nginx.com if (queued) { 4202507Smax.romanov@nginx.com nxt_router_app_use(task, app, -1); 4203507Smax.romanov@nginx.com } 4204507Smax.romanov@nginx.com } 4205507Smax.romanov@nginx.com 4206507Smax.romanov@nginx.com 4207507Smax.romanov@nginx.com static void 4208507Smax.romanov@nginx.com nxt_router_app_idle_timeout(nxt_task_t *task, void *obj, void *data) 4209507Smax.romanov@nginx.com { 4210753Smax.romanov@nginx.com nxt_timer_t *timer; 4211753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 4212507Smax.romanov@nginx.com 4213507Smax.romanov@nginx.com timer = obj; 4214753Smax.romanov@nginx.com app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer); 4215753Smax.romanov@nginx.com 4216753Smax.romanov@nginx.com if (nxt_fast_path(app_joint->app != NULL)) { 4217753Smax.romanov@nginx.com nxt_router_adjust_idle_timer(task, app_joint->app, NULL); 4218753Smax.romanov@nginx.com } 4219753Smax.romanov@nginx.com } 4220753Smax.romanov@nginx.com 4221753Smax.romanov@nginx.com 4222753Smax.romanov@nginx.com static void 4223753Smax.romanov@nginx.com nxt_router_app_joint_release_handler(nxt_task_t *task, void *obj, void *data) 4224753Smax.romanov@nginx.com { 4225753Smax.romanov@nginx.com nxt_timer_t *timer; 4226753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 4227753Smax.romanov@nginx.com 4228753Smax.romanov@nginx.com timer = obj; 4229753Smax.romanov@nginx.com app_joint = nxt_container_of(timer, nxt_app_joint_t, idle_timer); 4230753Smax.romanov@nginx.com 4231753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 4232507Smax.romanov@nginx.com } 4233507Smax.romanov@nginx.com 4234507Smax.romanov@nginx.com 4235507Smax.romanov@nginx.com static void 4236753Smax.romanov@nginx.com nxt_router_free_app(nxt_task_t *task, void *obj, void *data) 4237507Smax.romanov@nginx.com { 4238753Smax.romanov@nginx.com nxt_app_t *app; 4239753Smax.romanov@nginx.com nxt_port_t *port; 4240753Smax.romanov@nginx.com nxt_app_joint_t *app_joint; 4241753Smax.romanov@nginx.com 4242753Smax.romanov@nginx.com app_joint = obj; 4243753Smax.romanov@nginx.com app = app_joint->app; 4244753Smax.romanov@nginx.com 4245753Smax.romanov@nginx.com for ( ;; ) { 4246753Smax.romanov@nginx.com port = nxt_router_app_get_port_for_quit(app); 4247753Smax.romanov@nginx.com if (port == NULL) { 4248753Smax.romanov@nginx.com break; 4249753Smax.romanov@nginx.com } 4250753Smax.romanov@nginx.com 4251753Smax.romanov@nginx.com nxt_debug(task, "send QUIT to app '%V' pid %PI", &app->name, port->pid); 4252753Smax.romanov@nginx.com 4253753Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 4254753Smax.romanov@nginx.com 4255753Smax.romanov@nginx.com nxt_port_use(task, port, -1); 4256753Smax.romanov@nginx.com } 4257753Smax.romanov@nginx.com 4258753Smax.romanov@nginx.com nxt_assert(app->processes == 0); 4259753Smax.romanov@nginx.com nxt_assert(app->idle_processes == 0); 4260753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->requests)); 4261753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->ports)); 4262753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->spare_ports)); 4263753Smax.romanov@nginx.com nxt_assert(nxt_queue_is_empty(&app->idle_ports)); 4264753Smax.romanov@nginx.com 4265753Smax.romanov@nginx.com nxt_thread_mutex_destroy(&app->mutex); 4266753Smax.romanov@nginx.com nxt_free(app); 4267753Smax.romanov@nginx.com 4268753Smax.romanov@nginx.com app_joint->app = NULL; 4269753Smax.romanov@nginx.com 4270753Smax.romanov@nginx.com if (nxt_timer_delete(task->thread->engine, &app_joint->idle_timer)) { 4271753Smax.romanov@nginx.com app_joint->idle_timer.handler = nxt_router_app_joint_release_handler; 4272753Smax.romanov@nginx.com nxt_timer_add(task->thread->engine, &app_joint->idle_timer, 0); 4273753Smax.romanov@nginx.com 4274753Smax.romanov@nginx.com } else { 4275753Smax.romanov@nginx.com nxt_router_app_joint_use(task, app_joint, -1); 4276753Smax.romanov@nginx.com } 4277141Smax.romanov@nginx.com } 4278141Smax.romanov@nginx.com 4279141Smax.romanov@nginx.com 4280427Smax.romanov@nginx.com static void 4281427Smax.romanov@nginx.com nxt_router_port_select(nxt_task_t *task, nxt_port_select_state_t *state) 4282141Smax.romanov@nginx.com { 4283427Smax.romanov@nginx.com nxt_app_t *app; 4284507Smax.romanov@nginx.com nxt_bool_t can_start_process; 4285427Smax.romanov@nginx.com nxt_req_app_link_t *ra; 4286427Smax.romanov@nginx.com 4287427Smax.romanov@nginx.com ra = state->ra; 4288427Smax.romanov@nginx.com app = state->app; 4289427Smax.romanov@nginx.com 4290427Smax.romanov@nginx.com state->failed_port_use_delta = 0; 4291343Smax.romanov@nginx.com 4292425Smax.romanov@nginx.com if (nxt_queue_chk_remove(&ra->link_app_requests)) 4293425Smax.romanov@nginx.com { 4294425Smax.romanov@nginx.com nxt_router_ra_dec_use(ra); 4295425Smax.romanov@nginx.com } 4296425Smax.romanov@nginx.com 4297425Smax.romanov@nginx.com if (nxt_queue_chk_remove(&ra->link_port_pending)) 4298425Smax.romanov@nginx.com { 4299427Smax.romanov@nginx.com nxt_assert(ra->link_app_pending.next != NULL); 4300427Smax.romanov@nginx.com 4301427Smax.romanov@nginx.com nxt_queue_remove(&ra->link_app_pending); 4302427Smax.romanov@nginx.com ra->link_app_pending.next = NULL; 4303427Smax.romanov@nginx.com 4304425Smax.romanov@nginx.com nxt_router_ra_dec_use(ra); 4305425Smax.romanov@nginx.com } 4306425Smax.romanov@nginx.com 4307427Smax.romanov@nginx.com state->failed_port = ra->app_port; 4308427Smax.romanov@nginx.com 4309425Smax.romanov@nginx.com if (ra->app_port != NULL) { 4310427Smax.romanov@nginx.com state->failed_port_use_delta--; 4311427Smax.romanov@nginx.com 4312427Smax.romanov@nginx.com state->failed_port->app_pending_responses--; 4313427Smax.romanov@nginx.com 4314427Smax.romanov@nginx.com if (nxt_queue_chk_remove(&state->failed_port->app_link)) { 4315427Smax.romanov@nginx.com state->failed_port_use_delta--; 4316427Smax.romanov@nginx.com } 4317427Smax.romanov@nginx.com 4318427Smax.romanov@nginx.com ra->app_port = NULL; 4319427Smax.romanov@nginx.com } 4320427Smax.romanov@nginx.com 4321507Smax.romanov@nginx.com can_start_process = nxt_router_app_can_start(app); 4322507Smax.romanov@nginx.com 4323427Smax.romanov@nginx.com state->port = NULL; 4324507Smax.romanov@nginx.com state->start_process = 0; 4325427Smax.romanov@nginx.com 4326427Smax.romanov@nginx.com if (nxt_queue_is_empty(&app->ports) 4327507Smax.romanov@nginx.com || (can_start_process && nxt_router_app_first_port_busy(app)) ) 4328427Smax.romanov@nginx.com { 4329427Smax.romanov@nginx.com ra = nxt_router_ra_create(task, ra); 4330427Smax.romanov@nginx.com 4331427Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 4332427Smax.romanov@nginx.com goto fail; 4333427Smax.romanov@nginx.com } 4334427Smax.romanov@nginx.com 4335427Smax.romanov@nginx.com if (nxt_slow_path(state->failed_port != NULL)) { 4336427Smax.romanov@nginx.com nxt_queue_insert_head(&app->requests, &ra->link_app_requests); 4337427Smax.romanov@nginx.com 4338427Smax.romanov@nginx.com } else { 4339427Smax.romanov@nginx.com nxt_queue_insert_tail(&app->requests, &ra->link_app_requests); 4340427Smax.romanov@nginx.com } 4341427Smax.romanov@nginx.com 4342427Smax.romanov@nginx.com nxt_router_ra_inc_use(ra); 4343427Smax.romanov@nginx.com 4344427Smax.romanov@nginx.com nxt_debug(task, "ra stream #%uD enqueue to app->requests", ra->stream); 4345427Smax.romanov@nginx.com 4346507Smax.romanov@nginx.com if (can_start_process) { 4347507Smax.romanov@nginx.com app->pending_processes++; 4348507Smax.romanov@nginx.com state->start_process = 1; 4349425Smax.romanov@nginx.com } 4350425Smax.romanov@nginx.com 4351425Smax.romanov@nginx.com } else { 4352427Smax.romanov@nginx.com state->port = nxt_router_pop_first_port(app); 4353427Smax.romanov@nginx.com 4354427Smax.romanov@nginx.com if (state->port->app_pending_responses > 1) { 4355427Smax.romanov@nginx.com ra = nxt_router_ra_create(task, ra); 4356427Smax.romanov@nginx.com 4357427Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 4358427Smax.romanov@nginx.com goto fail; 4359351Smax.romanov@nginx.com } 4360427Smax.romanov@nginx.com 4361427Smax.romanov@nginx.com ra->app_port = state->port; 4362427Smax.romanov@nginx.com 4363427Smax.romanov@nginx.com nxt_router_ra_pending(task, app, ra); 4364425Smax.romanov@nginx.com } 4365507Smax.romanov@nginx.com 4366507Smax.romanov@nginx.com if (can_start_process && nxt_router_app_need_start(app)) { 4367507Smax.romanov@nginx.com app->pending_processes++; 4368507Smax.romanov@nginx.com state->start_process = 1; 4369507Smax.romanov@nginx.com } 4370343Smax.romanov@nginx.com } 4371343Smax.romanov@nginx.com 4372427Smax.romanov@nginx.com fail: 4373427Smax.romanov@nginx.com 4374427Smax.romanov@nginx.com state->shared_ra = ra; 4375427Smax.romanov@nginx.com } 4376427Smax.romanov@nginx.com 4377427Smax.romanov@nginx.com 4378427Smax.romanov@nginx.com static nxt_int_t 4379427Smax.romanov@nginx.com nxt_router_port_post_select(nxt_task_t *task, nxt_port_select_state_t *state) 4380427Smax.romanov@nginx.com { 4381427Smax.romanov@nginx.com nxt_int_t res; 4382427Smax.romanov@nginx.com nxt_app_t *app; 4383427Smax.romanov@nginx.com nxt_req_app_link_t *ra; 4384427Smax.romanov@nginx.com 4385427Smax.romanov@nginx.com ra = state->shared_ra; 4386427Smax.romanov@nginx.com app = state->app; 4387427Smax.romanov@nginx.com 4388427Smax.romanov@nginx.com if (state->failed_port_use_delta != 0) { 4389427Smax.romanov@nginx.com nxt_port_use(task, state->failed_port, state->failed_port_use_delta); 4390425Smax.romanov@nginx.com } 4391425Smax.romanov@nginx.com 4392351Smax.romanov@nginx.com if (nxt_slow_path(ra == NULL)) { 4393427Smax.romanov@nginx.com if (state->port != NULL) { 4394427Smax.romanov@nginx.com nxt_port_use(task, state->port, -1); 4395425Smax.romanov@nginx.com } 4396425Smax.romanov@nginx.com 4397427Smax.romanov@nginx.com nxt_router_ra_error(state->ra, 500, 4398427Smax.romanov@nginx.com "Failed to allocate shared req<->app link"); 4399427Smax.romanov@nginx.com nxt_router_ra_use(task, state->ra, -1); 4400427Smax.romanov@nginx.com 4401351Smax.romanov@nginx.com return NXT_ERROR; 4402351Smax.romanov@nginx.com } 4403351Smax.romanov@nginx.com 4404427Smax.romanov@nginx.com if (state->port != NULL) { 4405343Smax.romanov@nginx.com nxt_debug(task, "already have port for app '%V' %p ", &app->name, app); 4406163Smax.romanov@nginx.com 4407427Smax.romanov@nginx.com ra->app_port = state->port; 4408343Smax.romanov@nginx.com 4409507Smax.romanov@nginx.com if (state->start_process) { 4410507Smax.romanov@nginx.com nxt_router_start_app_process(task, app); 4411507Smax.romanov@nginx.com } 4412507Smax.romanov@nginx.com 4413141Smax.romanov@nginx.com return NXT_OK; 4414141Smax.romanov@nginx.com } 4415141Smax.romanov@nginx.com 4416507Smax.romanov@nginx.com if (!state->start_process) { 4417507Smax.romanov@nginx.com nxt_debug(task, "app '%V' %p too many running or pending processes", 4418343Smax.romanov@nginx.com &app->name, app); 4419343Smax.romanov@nginx.com 4420343Smax.romanov@nginx.com return NXT_AGAIN; 4421343Smax.romanov@nginx.com } 4422343Smax.romanov@nginx.com 4423507Smax.romanov@nginx.com res = nxt_router_start_app_process(task, app); 4424343Smax.romanov@nginx.com 4425343Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 4426507Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, "Failed to start app process"); 4427427Smax.romanov@nginx.com nxt_router_ra_use(task, ra, -1); 4428343Smax.romanov@nginx.com 4429141Smax.romanov@nginx.com return NXT_ERROR; 4430141Smax.romanov@nginx.com } 4431141Smax.romanov@nginx.com 4432141Smax.romanov@nginx.com return NXT_AGAIN; 443388Smax.romanov@nginx.com } 443488Smax.romanov@nginx.com 443588Smax.romanov@nginx.com 4436427Smax.romanov@nginx.com static nxt_int_t 4437427Smax.romanov@nginx.com nxt_router_app_port(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra) 4438427Smax.romanov@nginx.com { 4439427Smax.romanov@nginx.com nxt_port_select_state_t state; 4440427Smax.romanov@nginx.com 4441427Smax.romanov@nginx.com state.ra = ra; 4442427Smax.romanov@nginx.com state.app = app; 4443427Smax.romanov@nginx.com 4444427Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4445427Smax.romanov@nginx.com 4446427Smax.romanov@nginx.com nxt_router_port_select(task, &state); 4447427Smax.romanov@nginx.com 4448427Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4449427Smax.romanov@nginx.com 4450427Smax.romanov@nginx.com return nxt_router_port_post_select(task, &state); 4451427Smax.romanov@nginx.com } 4452427Smax.romanov@nginx.com 4453427Smax.romanov@nginx.com 4454431Sigor@sysoev.ru void 4455964Sigor@sysoev.ru nxt_router_process_http_request(nxt_task_t *task, nxt_app_parse_ctx_t *ar, 4456964Sigor@sysoev.ru nxt_app_t *app) 445753Sigor@sysoev.ru { 4458431Sigor@sysoev.ru nxt_int_t res; 4459431Sigor@sysoev.ru nxt_port_t *port; 4460431Sigor@sysoev.ru nxt_event_engine_t *engine; 4461431Sigor@sysoev.ru nxt_http_request_t *r; 4462431Sigor@sysoev.ru nxt_req_app_link_t ra_local, *ra; 4463431Sigor@sysoev.ru nxt_req_conn_link_t *rc; 4464431Sigor@sysoev.ru 4465431Sigor@sysoev.ru r = ar->request; 446688Smax.romanov@nginx.com engine = task->thread->engine; 446788Smax.romanov@nginx.com 4468318Smax.romanov@nginx.com rc = nxt_port_rpc_register_handler_ex(task, engine->port, 4469318Smax.romanov@nginx.com nxt_router_response_ready_handler, 4470318Smax.romanov@nginx.com nxt_router_response_error_handler, 4471318Smax.romanov@nginx.com sizeof(nxt_req_conn_link_t)); 4472122Smax.romanov@nginx.com 447388Smax.romanov@nginx.com if (nxt_slow_path(rc == NULL)) { 4474431Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 4475141Smax.romanov@nginx.com return; 447688Smax.romanov@nginx.com } 447788Smax.romanov@nginx.com 4478318Smax.romanov@nginx.com rc->stream = nxt_port_rpc_ex_stream(rc); 4479425Smax.romanov@nginx.com rc->app = app; 4480425Smax.romanov@nginx.com 4481425Smax.romanov@nginx.com nxt_router_app_use(task, app, 1); 4482425Smax.romanov@nginx.com 4483431Sigor@sysoev.ru rc->ap = ar; 4484346Smax.romanov@nginx.com 4485351Smax.romanov@nginx.com ra = &ra_local; 4486351Smax.romanov@nginx.com nxt_router_ra_init(task, ra, rc); 4487167Smax.romanov@nginx.com 4488427Smax.romanov@nginx.com res = nxt_router_app_port(task, app, ra); 4489141Smax.romanov@nginx.com 4490141Smax.romanov@nginx.com if (res != NXT_OK) { 4491141Smax.romanov@nginx.com return; 4492141Smax.romanov@nginx.com } 4493141Smax.romanov@nginx.com 4494425Smax.romanov@nginx.com ra = rc->ra; 4495167Smax.romanov@nginx.com port = ra->app_port; 4496141Smax.romanov@nginx.com 4497425Smax.romanov@nginx.com nxt_assert(port != NULL); 4498141Smax.romanov@nginx.com 4499318Smax.romanov@nginx.com nxt_port_rpc_ex_set_peer(task, engine->port, rc, port->pid); 4500318Smax.romanov@nginx.com 4501425Smax.romanov@nginx.com nxt_router_app_prepare_request(task, ra); 4502167Smax.romanov@nginx.com } 4503167Smax.romanov@nginx.com 4504167Smax.romanov@nginx.com 4505167Smax.romanov@nginx.com static void 4506423Smax.romanov@nginx.com nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj, void *data) 4507423Smax.romanov@nginx.com { 4508423Smax.romanov@nginx.com } 4509423Smax.romanov@nginx.com 4510423Smax.romanov@nginx.com 4511423Smax.romanov@nginx.com static void 4512425Smax.romanov@nginx.com nxt_router_app_prepare_request(nxt_task_t *task, nxt_req_app_link_t *ra) 4513167Smax.romanov@nginx.com { 4514343Smax.romanov@nginx.com uint32_t request_failed; 4515743Smax.romanov@nginx.com nxt_buf_t *buf; 4516167Smax.romanov@nginx.com nxt_int_t res; 4517343Smax.romanov@nginx.com nxt_port_t *port, *c_port, *reply_port; 4518167Smax.romanov@nginx.com nxt_app_parse_ctx_t *ap; 4519167Smax.romanov@nginx.com 4520343Smax.romanov@nginx.com nxt_assert(ra->app_port != NULL); 4521343Smax.romanov@nginx.com 4522343Smax.romanov@nginx.com port = ra->app_port; 4523167Smax.romanov@nginx.com reply_port = ra->reply_port; 4524167Smax.romanov@nginx.com ap = ra->ap; 4525141Smax.romanov@nginx.com 4526343Smax.romanov@nginx.com request_failed = 1; 4527343Smax.romanov@nginx.com 4528141Smax.romanov@nginx.com c_port = nxt_process_connected_port_find(port->process, reply_port->pid, 4529141Smax.romanov@nginx.com reply_port->id); 4530141Smax.romanov@nginx.com if (nxt_slow_path(c_port != reply_port)) { 4531141Smax.romanov@nginx.com res = nxt_port_send_port(task, port, reply_port, 0); 4532122Smax.romanov@nginx.com 4533122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 4534423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 4535345Smax.romanov@nginx.com "Failed to send reply port to application"); 4536343Smax.romanov@nginx.com goto release_port; 4537122Smax.romanov@nginx.com } 4538122Smax.romanov@nginx.com 4539141Smax.romanov@nginx.com nxt_process_connected_port_add(port->process, reply_port); 454088Smax.romanov@nginx.com } 454188Smax.romanov@nginx.com 4542743Smax.romanov@nginx.com buf = nxt_router_prepare_msg(task, &ap->r, port, 4543743Smax.romanov@nginx.com nxt_app_msg_prefix[port->app->type]); 4544743Smax.romanov@nginx.com 4545743Smax.romanov@nginx.com if (nxt_slow_path(buf == NULL)) { 4546423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 4547345Smax.romanov@nginx.com "Failed to prepare message for application"); 4548343Smax.romanov@nginx.com goto release_port; 4549122Smax.romanov@nginx.com } 455088Smax.romanov@nginx.com 4551507Smax.romanov@nginx.com nxt_debug(task, "about to send %O bytes buffer to app process port %d", 4552743Smax.romanov@nginx.com nxt_buf_used_size(buf), 4553743Smax.romanov@nginx.com port->socket.fd); 455488Smax.romanov@nginx.com 4555343Smax.romanov@nginx.com request_failed = 0; 4556343Smax.romanov@nginx.com 4557743Smax.romanov@nginx.com ra->msg_info.buf = buf; 4558743Smax.romanov@nginx.com ra->msg_info.completion_handler = buf->completion_handler; 4559743Smax.romanov@nginx.com 4560743Smax.romanov@nginx.com for (; buf; buf = buf->next) { 4561743Smax.romanov@nginx.com buf->completion_handler = nxt_router_dummy_buf_completion; 4562423Smax.romanov@nginx.com } 4563423Smax.romanov@nginx.com 4564743Smax.romanov@nginx.com buf = ra->msg_info.buf; 4565743Smax.romanov@nginx.com 4566423Smax.romanov@nginx.com res = nxt_port_mmap_get_tracking(task, port, &ra->msg_info.tracking, 4567423Smax.romanov@nginx.com ra->stream); 4568423Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 4569423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 4570423Smax.romanov@nginx.com "Failed to get tracking area"); 4571423Smax.romanov@nginx.com goto release_port; 4572423Smax.romanov@nginx.com } 4573423Smax.romanov@nginx.com 4574743Smax.romanov@nginx.com res = nxt_port_socket_twrite(task, port, NXT_PORT_MSG_DATA, 4575743Smax.romanov@nginx.com -1, ra->stream, reply_port->id, buf, 4576423Smax.romanov@nginx.com &ra->msg_info.tracking); 4577122Smax.romanov@nginx.com 4578122Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_OK)) { 4579423Smax.romanov@nginx.com nxt_router_ra_error(ra, 500, 4580345Smax.romanov@nginx.com "Failed to send message to application"); 4581343Smax.romanov@nginx.com goto release_port; 4582122Smax.romanov@nginx.com } 4583343Smax.romanov@nginx.com 4584343Smax.romanov@nginx.com release_port: 4585343Smax.romanov@nginx.com 4586345Smax.romanov@nginx.com nxt_router_app_port_release(task, port, request_failed, 0); 4587345Smax.romanov@nginx.com 4588425Smax.romanov@nginx.com nxt_router_ra_update_peer(task, ra); 458953Sigor@sysoev.ru } 459053Sigor@sysoev.ru 459153Sigor@sysoev.ru 4592743Smax.romanov@nginx.com struct nxt_fields_iter_s { 4593743Smax.romanov@nginx.com nxt_list_part_t *part; 4594743Smax.romanov@nginx.com nxt_http_field_t *field; 4595743Smax.romanov@nginx.com }; 4596743Smax.romanov@nginx.com 4597743Smax.romanov@nginx.com typedef struct nxt_fields_iter_s nxt_fields_iter_t; 4598743Smax.romanov@nginx.com 4599743Smax.romanov@nginx.com 4600743Smax.romanov@nginx.com static nxt_http_field_t * 4601743Smax.romanov@nginx.com nxt_fields_part_first(nxt_list_part_t *part, nxt_fields_iter_t *i) 4602216Sigor@sysoev.ru { 4603743Smax.romanov@nginx.com if (part == NULL) { 4604743Smax.romanov@nginx.com return NULL; 4605216Sigor@sysoev.ru } 4606216Sigor@sysoev.ru 4607743Smax.romanov@nginx.com while (part->nelts == 0) { 4608743Smax.romanov@nginx.com part = part->next; 4609743Smax.romanov@nginx.com if (part == NULL) { 4610743Smax.romanov@nginx.com return NULL; 4611743Smax.romanov@nginx.com } 4612216Sigor@sysoev.ru } 4613216Sigor@sysoev.ru 4614743Smax.romanov@nginx.com i->part = part; 4615743Smax.romanov@nginx.com i->field = nxt_list_data(i->part); 4616743Smax.romanov@nginx.com 4617743Smax.romanov@nginx.com return i->field; 4618743Smax.romanov@nginx.com } 4619743Smax.romanov@nginx.com 4620743Smax.romanov@nginx.com 4621743Smax.romanov@nginx.com static nxt_http_field_t * 4622743Smax.romanov@nginx.com nxt_fields_first(nxt_list_t *fields, nxt_fields_iter_t *i) 4623743Smax.romanov@nginx.com { 4624743Smax.romanov@nginx.com return nxt_fields_part_first(nxt_list_part(fields), i); 4625743Smax.romanov@nginx.com } 4626743Smax.romanov@nginx.com 4627743Smax.romanov@nginx.com 4628743Smax.romanov@nginx.com static nxt_http_field_t * 4629743Smax.romanov@nginx.com nxt_fields_next(nxt_fields_iter_t *i) 4630743Smax.romanov@nginx.com { 4631743Smax.romanov@nginx.com nxt_http_field_t *end = nxt_list_data(i->part); 4632743Smax.romanov@nginx.com 4633743Smax.romanov@nginx.com end += i->part->nelts; 4634743Smax.romanov@nginx.com i->field++; 4635743Smax.romanov@nginx.com 4636743Smax.romanov@nginx.com if (i->field < end) { 4637743Smax.romanov@nginx.com return i->field; 4638216Sigor@sysoev.ru } 4639216Sigor@sysoev.ru 4640743Smax.romanov@nginx.com return nxt_fields_part_first(i->part->next, i); 4641216Sigor@sysoev.ru } 4642216Sigor@sysoev.ru 4643216Sigor@sysoev.ru 4644743Smax.romanov@nginx.com static nxt_buf_t * 4645743Smax.romanov@nginx.com nxt_router_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, 4646743Smax.romanov@nginx.com nxt_port_t *port, const nxt_str_t *prefix) 4647216Sigor@sysoev.ru { 4648743Smax.romanov@nginx.com void *target_pos, *query_pos; 4649743Smax.romanov@nginx.com u_char *pos, *end, *p, c; 4650743Smax.romanov@nginx.com size_t fields_count, req_size, size, free_size; 4651743Smax.romanov@nginx.com size_t copy_size; 4652743Smax.romanov@nginx.com nxt_buf_t *b, *buf, *out, **tail; 4653743Smax.romanov@nginx.com nxt_http_field_t *field, *dup; 4654743Smax.romanov@nginx.com nxt_unit_field_t *dst_field; 4655743Smax.romanov@nginx.com nxt_fields_iter_t iter, dup_iter; 4656743Smax.romanov@nginx.com nxt_unit_request_t *req; 4657216Sigor@sysoev.ru nxt_app_request_header_t *h; 4658216Sigor@sysoev.ru 4659216Sigor@sysoev.ru h = &r->header; 4660216Sigor@sysoev.ru 4661743Smax.romanov@nginx.com req_size = sizeof(nxt_unit_request_t) 4662967Svbart@nginx.com + h->method.length + 1 4663967Svbart@nginx.com + h->version.length + 1 4664967Svbart@nginx.com + r->remote.length + 1 4665967Svbart@nginx.com + r->local.length + 1 4666967Svbart@nginx.com + h->server_name.length + 1 4667967Svbart@nginx.com + h->target.length + 1 4668967Svbart@nginx.com + (h->path.start != h->target.start ? h->path.length + 1 : 0); 4669743Smax.romanov@nginx.com 4670743Smax.romanov@nginx.com fields_count = 0; 4671743Smax.romanov@nginx.com 4672743Smax.romanov@nginx.com nxt_list_each(field, h->fields) { 4673743Smax.romanov@nginx.com fields_count++; 4674743Smax.romanov@nginx.com 4675743Smax.romanov@nginx.com req_size += field->name_length + prefix->length + 1 4676743Smax.romanov@nginx.com + field->value_length + 1; 4677743Smax.romanov@nginx.com } nxt_list_loop; 4678743Smax.romanov@nginx.com 4679743Smax.romanov@nginx.com req_size += fields_count * sizeof(nxt_unit_field_t); 4680743Smax.romanov@nginx.com 4681743Smax.romanov@nginx.com if (nxt_slow_path(req_size > PORT_MMAP_DATA_SIZE)) { 4682743Smax.romanov@nginx.com nxt_alert(task, "headers to big to fit in shared memory (%d)", 4683743Smax.romanov@nginx.com (int) req_size); 4684743Smax.romanov@nginx.com 4685743Smax.romanov@nginx.com return NULL; 4686743Smax.romanov@nginx.com } 4687743Smax.romanov@nginx.com 4688743Smax.romanov@nginx.com out = nxt_port_mmap_get_buf(task, port, 4689743Smax.romanov@nginx.com nxt_min(req_size + r->body.preread_size, PORT_MMAP_DATA_SIZE)); 4690743Smax.romanov@nginx.com if (nxt_slow_path(out == NULL)) { 4691743Smax.romanov@nginx.com return NULL; 4692743Smax.romanov@nginx.com } 4693743Smax.romanov@nginx.com 4694743Smax.romanov@nginx.com req = (nxt_unit_request_t *) out->mem.free; 4695743Smax.romanov@nginx.com out->mem.free += req_size; 4696743Smax.romanov@nginx.com 4697743Smax.romanov@nginx.com req->content_length = h->parsed_content_length; 4698743Smax.romanov@nginx.com 4699743Smax.romanov@nginx.com p = (u_char *) (req->fields + fields_count); 4700743Smax.romanov@nginx.com 4701743Smax.romanov@nginx.com nxt_debug(task, "fields_count=%d", (int) fields_count); 4702743Smax.romanov@nginx.com 4703743Smax.romanov@nginx.com req->method_length = h->method.length; 4704743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->method, p); 4705743Smax.romanov@nginx.com p = nxt_cpymem(p, h->method.start, h->method.length); 4706743Smax.romanov@nginx.com *p++ = '\0'; 4707743Smax.romanov@nginx.com 4708743Smax.romanov@nginx.com req->version_length = h->version.length; 4709743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->version, p); 4710743Smax.romanov@nginx.com p = nxt_cpymem(p, h->version.start, h->version.length); 4711743Smax.romanov@nginx.com *p++ = '\0'; 4712743Smax.romanov@nginx.com 4713743Smax.romanov@nginx.com req->remote_length = r->remote.length; 4714743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->remote, p); 4715743Smax.romanov@nginx.com p = nxt_cpymem(p, r->remote.start, r->remote.length); 4716743Smax.romanov@nginx.com *p++ = '\0'; 4717743Smax.romanov@nginx.com 4718743Smax.romanov@nginx.com req->local_length = r->local.length; 4719743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->local, p); 4720743Smax.romanov@nginx.com p = nxt_cpymem(p, r->local.start, r->local.length); 4721743Smax.romanov@nginx.com *p++ = '\0'; 4722743Smax.romanov@nginx.com 4723967Svbart@nginx.com req->server_name_length = h->server_name.length; 4724967Svbart@nginx.com nxt_unit_sptr_set(&req->server_name, p); 4725967Svbart@nginx.com p = nxt_cpymem(p, h->server_name.start, h->server_name.length); 4726967Svbart@nginx.com *p++ = '\0'; 4727967Svbart@nginx.com 4728743Smax.romanov@nginx.com target_pos = p; 4729743Smax.romanov@nginx.com req->target_length = h->target.length; 4730743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->target, p); 4731743Smax.romanov@nginx.com p = nxt_cpymem(p, h->target.start, h->target.length); 4732743Smax.romanov@nginx.com *p++ = '\0'; 4733743Smax.romanov@nginx.com 4734743Smax.romanov@nginx.com req->path_length = h->path.length; 4735216Sigor@sysoev.ru if (h->path.start == h->target.start) { 4736743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->path, target_pos); 4737277Sigor@sysoev.ru 4738216Sigor@sysoev.ru } else { 4739743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->path, p); 4740743Smax.romanov@nginx.com p = nxt_cpymem(p, h->path.start, h->path.length); 4741743Smax.romanov@nginx.com *p++ = '\0'; 4742305Smax.romanov@nginx.com } 4743216Sigor@sysoev.ru 4744743Smax.romanov@nginx.com req->query_length = h->query.length; 4745743Smax.romanov@nginx.com if (h->query.start != NULL) { 4746743Smax.romanov@nginx.com query_pos = nxt_pointer_to(target_pos, 4747743Smax.romanov@nginx.com h->query.start - h->target.start); 4748743Smax.romanov@nginx.com 4749743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->query, query_pos); 4750277Sigor@sysoev.ru 4751216Sigor@sysoev.ru } else { 4752743Smax.romanov@nginx.com req->query.offset = 0; 4753216Sigor@sysoev.ru } 4754216Sigor@sysoev.ru 4755743Smax.romanov@nginx.com req->content_length_field = NXT_UNIT_NONE_FIELD; 4756743Smax.romanov@nginx.com req->content_type_field = NXT_UNIT_NONE_FIELD; 4757743Smax.romanov@nginx.com req->cookie_field = NXT_UNIT_NONE_FIELD; 4758743Smax.romanov@nginx.com 4759743Smax.romanov@nginx.com dst_field = req->fields; 4760743Smax.romanov@nginx.com 4761743Smax.romanov@nginx.com for (field = nxt_fields_first(h->fields, &iter); 4762743Smax.romanov@nginx.com field != NULL; 4763743Smax.romanov@nginx.com field = nxt_fields_next(&iter)) 4764743Smax.romanov@nginx.com { 4765743Smax.romanov@nginx.com if (field->skip) { 4766743Smax.romanov@nginx.com continue; 4767743Smax.romanov@nginx.com } 4768743Smax.romanov@nginx.com 4769743Smax.romanov@nginx.com dst_field->hash = field->hash; 4770743Smax.romanov@nginx.com dst_field->skip = 0; 4771743Smax.romanov@nginx.com dst_field->name_length = field->name_length + prefix->length; 4772743Smax.romanov@nginx.com dst_field->value_length = field->value_length; 4773743Smax.romanov@nginx.com 4774967Svbart@nginx.com if (field->value == h->content_length.start) { 4775743Smax.romanov@nginx.com req->content_length_field = dst_field - req->fields; 4776743Smax.romanov@nginx.com 4777743Smax.romanov@nginx.com } else if (field->value == h->content_type.start) { 4778743Smax.romanov@nginx.com req->content_type_field = dst_field - req->fields; 4779743Smax.romanov@nginx.com 4780743Smax.romanov@nginx.com } else if (field->value == h->cookie.start) { 4781743Smax.romanov@nginx.com req->cookie_field = dst_field - req->fields; 4782743Smax.romanov@nginx.com } 4783743Smax.romanov@nginx.com 4784743Smax.romanov@nginx.com nxt_debug(task, "add field 0x%04Xd, %d, %d, %p : %d %p", 4785743Smax.romanov@nginx.com (int) field->hash, (int) field->skip, 4786743Smax.romanov@nginx.com (int) field->name_length, field->name, 4787743Smax.romanov@nginx.com (int) field->value_length, field->value); 4788743Smax.romanov@nginx.com 4789743Smax.romanov@nginx.com if (prefix->length != 0) { 4790743Smax.romanov@nginx.com nxt_unit_sptr_set(&dst_field->name, p); 4791743Smax.romanov@nginx.com p = nxt_cpymem(p, prefix->start, prefix->length); 4792743Smax.romanov@nginx.com 4793743Smax.romanov@nginx.com end = field->name + field->name_length; 4794743Smax.romanov@nginx.com for (pos = field->name; pos < end; pos++) { 4795743Smax.romanov@nginx.com c = *pos; 4796743Smax.romanov@nginx.com 4797743Smax.romanov@nginx.com if (c >= 'a' && c <= 'z') { 4798743Smax.romanov@nginx.com *p++ = (c & ~0x20); 4799743Smax.romanov@nginx.com continue; 4800743Smax.romanov@nginx.com } 4801743Smax.romanov@nginx.com 4802743Smax.romanov@nginx.com if (c == '-') { 4803743Smax.romanov@nginx.com *p++ = '_'; 4804743Smax.romanov@nginx.com continue; 4805743Smax.romanov@nginx.com } 4806743Smax.romanov@nginx.com 4807743Smax.romanov@nginx.com *p++ = c; 4808743Smax.romanov@nginx.com } 4809743Smax.romanov@nginx.com 4810743Smax.romanov@nginx.com } else { 4811743Smax.romanov@nginx.com nxt_unit_sptr_set(&dst_field->name, p); 4812743Smax.romanov@nginx.com p = nxt_cpymem(p, field->name, field->name_length); 4813743Smax.romanov@nginx.com } 4814743Smax.romanov@nginx.com 4815743Smax.romanov@nginx.com *p++ = '\0'; 4816743Smax.romanov@nginx.com 4817743Smax.romanov@nginx.com nxt_unit_sptr_set(&dst_field->value, p); 4818743Smax.romanov@nginx.com p = nxt_cpymem(p, field->value, field->value_length); 4819743Smax.romanov@nginx.com 4820743Smax.romanov@nginx.com if (prefix->length != 0) { 4821743Smax.romanov@nginx.com dup_iter = iter; 4822743Smax.romanov@nginx.com 4823743Smax.romanov@nginx.com for (dup = nxt_fields_next(&dup_iter); 4824743Smax.romanov@nginx.com dup != NULL; 4825743Smax.romanov@nginx.com dup = nxt_fields_next(&dup_iter)) 4826743Smax.romanov@nginx.com { 4827743Smax.romanov@nginx.com if (dup->name_length != field->name_length 4828743Smax.romanov@nginx.com || dup->skip 4829743Smax.romanov@nginx.com || dup->hash != field->hash 4830743Smax.romanov@nginx.com || nxt_memcasecmp(dup->name, field->name, dup->name_length)) 4831743Smax.romanov@nginx.com { 4832743Smax.romanov@nginx.com continue; 4833743Smax.romanov@nginx.com } 4834743Smax.romanov@nginx.com 4835743Smax.romanov@nginx.com p = nxt_cpymem(p, ", ", 2); 4836743Smax.romanov@nginx.com p = nxt_cpymem(p, dup->value, dup->value_length); 4837743Smax.romanov@nginx.com 4838743Smax.romanov@nginx.com dst_field->value_length += 2 + dup->value_length; 4839743Smax.romanov@nginx.com 4840743Smax.romanov@nginx.com dup->skip = 1; 4841743Smax.romanov@nginx.com } 4842743Smax.romanov@nginx.com } 4843743Smax.romanov@nginx.com 4844743Smax.romanov@nginx.com *p++ = '\0'; 4845743Smax.romanov@nginx.com 4846743Smax.romanov@nginx.com dst_field++; 4847743Smax.romanov@nginx.com } 4848743Smax.romanov@nginx.com 4849743Smax.romanov@nginx.com req->fields_count = dst_field - req->fields; 4850743Smax.romanov@nginx.com 4851743Smax.romanov@nginx.com nxt_unit_sptr_set(&req->preread_content, out->mem.free); 4852743Smax.romanov@nginx.com 4853743Smax.romanov@nginx.com buf = out; 4854743Smax.romanov@nginx.com tail = &buf->next; 4855216Sigor@sysoev.ru 4856510Salexander.borisov@nginx.com for (b = r->body.buf; b != NULL; b = b->next) { 4857743Smax.romanov@nginx.com size = nxt_buf_mem_used_size(&b->mem); 4858743Smax.romanov@nginx.com pos = b->mem.pos; 4859743Smax.romanov@nginx.com 4860743Smax.romanov@nginx.com while (size > 0) { 4861743Smax.romanov@nginx.com if (buf == NULL) { 4862743Smax.romanov@nginx.com free_size = nxt_min(size, PORT_MMAP_DATA_SIZE); 4863743Smax.romanov@nginx.com 4864743Smax.romanov@nginx.com buf = nxt_port_mmap_get_buf(task, port, free_size); 4865743Smax.romanov@nginx.com if (nxt_slow_path(buf == NULL)) { 4866743Smax.romanov@nginx.com while (out != NULL) { 4867743Smax.romanov@nginx.com buf = out->next; 4868743Smax.romanov@nginx.com out->completion_handler(task, out, out->parent); 4869743Smax.romanov@nginx.com out = buf; 4870743Smax.romanov@nginx.com } 4871743Smax.romanov@nginx.com return NULL; 4872743Smax.romanov@nginx.com } 4873743Smax.romanov@nginx.com 4874743Smax.romanov@nginx.com *tail = buf; 4875743Smax.romanov@nginx.com tail = &buf->next; 4876743Smax.romanov@nginx.com 4877743Smax.romanov@nginx.com } else { 4878743Smax.romanov@nginx.com free_size = nxt_buf_mem_free_size(&buf->mem); 4879743Smax.romanov@nginx.com if (free_size < size 4880743Smax.romanov@nginx.com && nxt_port_mmap_increase_buf(task, buf, size, 1) 4881743Smax.romanov@nginx.com == NXT_OK) 4882743Smax.romanov@nginx.com { 4883743Smax.romanov@nginx.com free_size = nxt_buf_mem_free_size(&buf->mem); 4884743Smax.romanov@nginx.com } 4885743Smax.romanov@nginx.com } 4886743Smax.romanov@nginx.com 4887743Smax.romanov@nginx.com if (free_size > 0) { 4888743Smax.romanov@nginx.com copy_size = nxt_min(free_size, size); 4889743Smax.romanov@nginx.com 4890743Smax.romanov@nginx.com buf->mem.free = nxt_cpymem(buf->mem.free, pos, copy_size); 4891743Smax.romanov@nginx.com 4892743Smax.romanov@nginx.com size -= copy_size; 4893743Smax.romanov@nginx.com pos += copy_size; 4894743Smax.romanov@nginx.com 4895743Smax.romanov@nginx.com if (size == 0) { 4896743Smax.romanov@nginx.com break; 4897743Smax.romanov@nginx.com } 4898743Smax.romanov@nginx.com } 4899743Smax.romanov@nginx.com 4900743Smax.romanov@nginx.com buf = NULL; 4901743Smax.romanov@nginx.com } 4902216Sigor@sysoev.ru } 4903216Sigor@sysoev.ru 4904743Smax.romanov@nginx.com return out; 4905584Salexander.borisov@nginx.com } 4906584Salexander.borisov@nginx.com 4907584Salexander.borisov@nginx.com 490853Sigor@sysoev.ru static void 4909318Smax.romanov@nginx.com nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data) 4910318Smax.romanov@nginx.com { 4911615Smax.romanov@nginx.com nxt_app_t *app; 4912615Smax.romanov@nginx.com nxt_bool_t cancelled, unlinked; 4913615Smax.romanov@nginx.com nxt_port_t *port; 4914615Smax.romanov@nginx.com nxt_timer_t *timer; 4915615Smax.romanov@nginx.com nxt_queue_link_t *lnk; 4916615Smax.romanov@nginx.com nxt_req_app_link_t *pending_ra; 4917615Smax.romanov@nginx.com nxt_app_parse_ctx_t *ar; 4918615Smax.romanov@nginx.com nxt_req_conn_link_t *rc; 4919615Smax.romanov@nginx.com nxt_port_select_state_t state; 4920318Smax.romanov@nginx.com 4921318Smax.romanov@nginx.com timer = obj; 4922318Smax.romanov@nginx.com 4923318Smax.romanov@nginx.com nxt_debug(task, "router app timeout"); 4924318Smax.romanov@nginx.com 4925431Sigor@sysoev.ru ar = nxt_timer_data(timer, nxt_app_parse_ctx_t, timer); 4926615Smax.romanov@nginx.com rc = ar->timer_data; 4927615Smax.romanov@nginx.com app = rc->app; 4928615Smax.romanov@nginx.com 4929615Smax.romanov@nginx.com if (app == NULL) { 4930615Smax.romanov@nginx.com goto generate_error; 4931615Smax.romanov@nginx.com } 4932615Smax.romanov@nginx.com 4933615Smax.romanov@nginx.com port = NULL; 4934615Smax.romanov@nginx.com pending_ra = NULL; 4935615Smax.romanov@nginx.com 4936615Smax.romanov@nginx.com if (rc->app_port != NULL) { 4937615Smax.romanov@nginx.com port = rc->app_port; 4938615Smax.romanov@nginx.com rc->app_port = NULL; 4939615Smax.romanov@nginx.com } 4940615Smax.romanov@nginx.com 4941615Smax.romanov@nginx.com if (port == NULL && rc->ra != NULL && rc->ra->app_port != NULL) { 4942615Smax.romanov@nginx.com port = rc->ra->app_port; 4943615Smax.romanov@nginx.com rc->ra->app_port = NULL; 4944615Smax.romanov@nginx.com } 4945615Smax.romanov@nginx.com 4946615Smax.romanov@nginx.com if (port == NULL) { 4947615Smax.romanov@nginx.com goto generate_error; 4948431Sigor@sysoev.ru } 4949615Smax.romanov@nginx.com 4950615Smax.romanov@nginx.com nxt_thread_mutex_lock(&app->mutex); 4951615Smax.romanov@nginx.com 4952615Smax.romanov@nginx.com unlinked = nxt_queue_chk_remove(&port->app_link); 4953615Smax.romanov@nginx.com 4954615Smax.romanov@nginx.com if (!nxt_queue_is_empty(&port->pending_requests)) { 4955615Smax.romanov@nginx.com lnk = nxt_queue_first(&port->pending_requests); 4956615Smax.romanov@nginx.com 4957615Smax.romanov@nginx.com pending_ra = nxt_queue_link_data(lnk, nxt_req_app_link_t, 4958615Smax.romanov@nginx.com link_port_pending); 4959615Smax.romanov@nginx.com 4960615Smax.romanov@nginx.com nxt_assert(pending_ra->link_app_pending.next != NULL); 4961615Smax.romanov@nginx.com 4962615Smax.romanov@nginx.com nxt_debug(task, "app '%V' pending request #%uD found", 4963615Smax.romanov@nginx.com &app->name, pending_ra->stream); 4964615Smax.romanov@nginx.com 4965615Smax.romanov@nginx.com cancelled = nxt_router_msg_cancel(task, &pending_ra->msg_info, 4966615Smax.romanov@nginx.com pending_ra->stream); 4967615Smax.romanov@nginx.com 4968615Smax.romanov@nginx.com if (cancelled) { 4969615Smax.romanov@nginx.com nxt_router_ra_inc_use(pending_ra); 4970615Smax.romanov@nginx.com 4971615Smax.romanov@nginx.com state.ra = pending_ra; 4972615Smax.romanov@nginx.com state.app = app; 4973615Smax.romanov@nginx.com 4974615Smax.romanov@nginx.com nxt_router_port_select(task, &state); 4975615Smax.romanov@nginx.com 4976615Smax.romanov@nginx.com } else { 4977615Smax.romanov@nginx.com pending_ra = NULL; 4978615Smax.romanov@nginx.com } 4979615Smax.romanov@nginx.com } 4980615Smax.romanov@nginx.com 4981615Smax.romanov@nginx.com nxt_thread_mutex_unlock(&app->mutex); 4982615Smax.romanov@nginx.com 4983615Smax.romanov@nginx.com if (pending_ra != NULL 4984615Smax.romanov@nginx.com && nxt_router_port_post_select(task, &state) == NXT_OK) 4985615Smax.romanov@nginx.com { 4986615Smax.romanov@nginx.com nxt_router_app_prepare_request(task, pending_ra); 4987615Smax.romanov@nginx.com } 4988615Smax.romanov@nginx.com 4989615Smax.romanov@nginx.com nxt_debug(task, "send quit to app '%V' pid %PI", &app->name, port->pid); 4990615Smax.romanov@nginx.com 4991615Smax.romanov@nginx.com nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL); 4992615Smax.romanov@nginx.com 4993615Smax.romanov@nginx.com nxt_port_use(task, port, unlinked ? -2 : -1); 4994615Smax.romanov@nginx.com 4995615Smax.romanov@nginx.com generate_error: 4996615Smax.romanov@nginx.com 4997615Smax.romanov@nginx.com nxt_http_request_error(task, ar->request, NXT_HTTP_SERVICE_UNAVAILABLE); 4998615Smax.romanov@nginx.com 4999615Smax.romanov@nginx.com nxt_router_rc_unlink(task, rc); 5000318Smax.romanov@nginx.com } 5001