static void corerouter_expire_timeouts(struct uwsgi_corerouter *ucr) { time_t current = time(NULL); struct uwsgi_rb_timer *urbt; struct corerouter_session *cr_session; for (;;) { urbt = uwsgi_min_rb_timer(ucr->timeouts); if (urbt == NULL) return; if (urbt->key <= current) { cr_session = (struct corerouter_session *) urbt->data; cr_session->timed_out = 1; if (cr_session->retry) { cr_session->retry = 0; ucr->switch_events(ucr, cr_session, -1); if (cr_session->retry) { cr_del_timeout(ucr, cr_session); cr_session->timeout = cr_add_fake_timeout(ucr, cr_session); } else { cr_session->timeout = corerouter_reset_timeout(ucr, cr_session); } } else { corerouter_close_session(ucr, cr_session); } continue; } break; } }
struct corerouter_session *corerouter_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket *ugs, int new_connection, struct sockaddr *cr_addr, socklen_t cr_addr_len) { struct corerouter_session *cs = uwsgi_calloc(ucr->session_size); struct corerouter_peer *peer = uwsgi_calloc(sizeof(struct corerouter_peer)); // main_peer has only input buffer as output buffer is taken from backend peers size_t bufsize = ucr->buffer_size; if (!bufsize) bufsize = uwsgi.page_size; peer->in = uwsgi_buffer_new(bufsize); ucr->cr_table[new_connection] = peer; cs->main_peer = peer; peer->fd = new_connection; peer->session = cs; // map corerouter and socket cs->corerouter = ucr; cs->ugs = ugs; // set initial timeout (could be overridden) peer->current_timeout = ucr->socket_timeout; ucr->active_sessions++; // build the client address memcpy(&cs->client_sockaddr, cr_addr, cr_addr_len); switch(cr_addr->sa_family) { case AF_INET: if (inet_ntop(AF_INET, &cs->client_sockaddr.sa_in.sin_addr, cs->client_address, cr_addr_len) == NULL) { uwsgi_error("corerouter_alloc_session/inet_ntop()"); memcpy(cs->client_address, "0.0.0.0", 7); cs->client_port[0] = '0'; cs->client_port[1] = 0; } uwsgi_num2str2(cs->client_sockaddr.sa_in.sin_port, cs->client_port); break; #ifdef AF_INET6 case AF_INET6: if (inet_ntop(AF_INET6, &cs->client_sockaddr.sa_in6.sin6_addr, cs->client_address, cr_addr_len) == NULL) { uwsgi_error("corerouter_alloc_session/inet_ntop()"); memcpy(cs->client_address, "0.0.0.0", 7); cs->client_port[0] = '0'; cs->client_port[1] = 0; } uwsgi_num2str2(cs->client_sockaddr.sa_in6.sin6_port, cs->client_port); break; #endif default: memcpy(cs->client_address, "0.0.0.0", 7); cs->client_port[0] = '0'; cs->client_port[1] = 0; break; } // here we prepare the real session and set the hooks if (ucr->alloc_session(ucr, ugs, cs, cr_addr, cr_addr_len)) { corerouter_close_session(ucr, cs); cs = NULL; } else { // truly set the timeout peer->timeout = cr_add_timeout(ucr, ucr->cr_table[new_connection]); } return cs; }
void corerouter_close_peer(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) { struct corerouter_session *cs = peer->session; // manage subscription reference count if (ucr->subscriptions && peer->un && peer->un->len > 0) { // decrease reference count #ifdef UWSGI_DEBUG uwsgi_log("[1] node %.*s refcnt: %llu\n", peer->un->len, peer->un->name, peer->un->reference); #endif peer->un->reference--; #ifdef UWSGI_DEBUG uwsgi_log("[2] node %.*s refcnt: %llu\n", peer->un->len, peer->un->name, peer->un->reference); #endif } if (peer->failed) { if (peer->soopt) { if (!ucr->quiet) uwsgi_log("[uwsgi-%s] unable to connect() to node \"%.*s\" (%d retries): %s\n", ucr->short_name, (int) peer->instance_address_len, peer->instance_address, peer->retries, strerror(peer->soopt)); } else if (peer->timed_out) { if (peer->instance_address_len > 0) { if (peer->connecting) { if (!ucr->quiet) uwsgi_log("[uwsgi-%s] unable to connect() to node \"%.*s\" (%d retries): timeout\n", ucr->short_name, (int) peer->instance_address_len, peer->instance_address, peer->retries); } } } // now check for dead nodes if (ucr->subscriptions && peer->un && peer->un->len > 0) { if (peer->un->death_mark == 0) uwsgi_log("[uwsgi-%s] %.*s => marking %.*s as failed\n", ucr->short_name, (int) peer->key_len, peer->key, (int) peer->instance_address_len, peer->instance_address); peer->un->failcnt++; peer->un->death_mark = 1; // check if i can remove the node if (peer->un->reference == 0) { uwsgi_remove_subscribe_node(ucr->subscriptions, peer->un); } if (ucr->cheap && !ucr->i_am_cheap && !ucr->fallback && uwsgi_no_subscriptions(ucr->subscriptions)) { uwsgi_gateway_go_cheap(ucr->name, ucr->queue, &ucr->i_am_cheap); } } else if (peer->static_node) { peer->static_node->custom = uwsgi_now(); uwsgi_log("[uwsgi-%s] %.*s => marking %.*s as failed\n", ucr->short_name, (int) peer->key_len, peer->key, (int) peer->instance_address_len, peer->instance_address); } // check if the router supports the retry hook if (!peer->can_retry) goto end; if (peer->retries >= (size_t) ucr->max_retries) goto end; peer->retries++; // reset the peer uwsgi_cr_peer_reset(peer); // set new timeout peer->timeout = cr_add_timeout(ucr, peer); if (ucr->fallback) { // ok let's try with the fallback nodes if (!cs->fallback) { cs->fallback = ucr->fallback; } else { cs->fallback = cs->fallback->next; if (!cs->fallback) goto end; } peer->instance_address = cs->fallback->value; peer->instance_address_len = cs->fallback->len; if (cs->retry(peer)) { if (!peer->failed) goto end; } return; } peer->instance_address = NULL; peer->instance_address_len = 0; if (cs->retry(peer)) { if (!peer->failed) goto end; } return; } end: uwsgi_cr_peer_del(peer); if (peer == cs->main_peer) { cs->main_peer = NULL; corerouter_close_session(ucr, cs); } else { if (cs->can_keepalive == 0 && cs->wait_full_write == 0) { corerouter_close_session(ucr, cs); } } }
void uwsgi_corerouter_loop(int id, void *data) { int i; struct uwsgi_corerouter *ucr = (struct uwsgi_corerouter *) data; ucr->cr_stats_server = -1; ucr->cr_table = uwsgi_malloc(sizeof(struct corerouter_session *) * uwsgi.max_fd); for (i = 0; i < (int) uwsgi.max_fd; i++) { ucr->cr_table[i] = NULL; } ucr->i_am_cheap = ucr->cheap; void *events = uwsgi_corerouter_setup_event_queue(ucr, id); if (ucr->has_subscription_sockets) event_queue_add_fd_read(ucr->queue, ushared->gateways[id].internal_subscription_pipe[1]); if (!ucr->socket_timeout) ucr->socket_timeout = 30; if (!ucr->static_node_gracetime) ucr->static_node_gracetime = 30; int i_am_the_first = 1; for(i=0;i<id;i++) { if (!strcmp(ushared->gateways[i].name, ucr->name)) { i_am_the_first = 0; break; } } if (ucr->stats_server && i_am_the_first) { char *tcp_port = strchr(ucr->stats_server, ':'); if (tcp_port) { // disable deferred accept for this socket int current_defer_accept = uwsgi.no_defer_accept; uwsgi.no_defer_accept = 1; ucr->cr_stats_server = bind_to_tcp(ucr->stats_server, uwsgi.listen_queue, tcp_port); uwsgi.no_defer_accept = current_defer_accept; } else { ucr->cr_stats_server = bind_to_unix(ucr->stats_server, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); } event_queue_add_fd_read(ucr->queue, ucr->cr_stats_server); uwsgi_log("*** %s stats server enabled on %s fd: %d ***\n", ucr->short_name, ucr->stats_server, ucr->cr_stats_server); } if (ucr->use_socket) { ucr->to_socket = uwsgi_get_socket_by_num(ucr->socket_num); if (ucr->to_socket) { // fix socket name_len if (ucr->to_socket->name_len == 0 && ucr->to_socket->name) { ucr->to_socket->name_len = strlen(ucr->to_socket->name); } } } if (!ucr->pb_base_dir) { ucr->pb_base_dir = getenv("TMPDIR"); if (!ucr->pb_base_dir) ucr->pb_base_dir = "/tmp"; } int nevents; time_t delta; struct uwsgi_rb_timer *min_timeout; int interesting_fd; int new_connection; if (ucr->pattern) { init_magic_table(ucr->magic_table); } union uwsgi_sockaddr cr_addr; socklen_t cr_addr_len = sizeof(struct sockaddr_un); struct corerouter_session *cr_session; ucr->mapper = uwsgi_cr_map_use_void; if (ucr->use_cache) { ucr->mapper = uwsgi_cr_map_use_cache; } else if (ucr->pattern) { ucr->mapper = uwsgi_cr_map_use_pattern; } else if (ucr->has_subscription_sockets) { ucr->mapper = uwsgi_cr_map_use_subscription; } else if (ucr->base) { ucr->mapper = uwsgi_cr_map_use_base; } else if (ucr->code_string_code && ucr->code_string_function) { ucr->mapper = uwsgi_cr_map_use_cs; } else if (ucr->to_socket) { ucr->mapper = uwsgi_cr_map_use_to; } else if (ucr->static_nodes) { ucr->mapper = uwsgi_cr_map_use_static_nodes; } else if (ucr->use_cluster) { ucr->mapper = uwsgi_cr_map_use_cluster; } ucr->timeouts = uwsgi_init_rb_timer(); for (;;) { min_timeout = uwsgi_min_rb_timer(ucr->timeouts); if (min_timeout == NULL) { delta = -1; } else { delta = min_timeout->key - time(NULL); if (delta <= 0) { corerouter_expire_timeouts(ucr); delta = 0; } } if (uwsgi.master_process && ucr->harakiri > 0) { ushared->gateways_harakiri[id] = 0; } nevents = event_queue_wait_multi(ucr->queue, delta, events, ucr->nevents); if (uwsgi.master_process && ucr->harakiri > 0) { ushared->gateways_harakiri[id] = time(NULL) + ucr->harakiri; } if (nevents == 0) { corerouter_expire_timeouts(ucr); } for (i = 0; i < nevents; i++) { interesting_fd = event_queue_interesting_fd(events, i); struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets; int taken = 0; while (ugs) { if (ugs->gateway == &ushared->gateways[id] && interesting_fd == ugs->fd) { if (!ugs->subscription) { new_connection = accept(interesting_fd, (struct sockaddr *) &cr_addr, &cr_addr_len); #ifdef UWSGI_EVENT_USE_PORT event_queue_add_fd_read(ucr->queue, interesting_fd); #endif if (new_connection < 0) { taken = 1; break; } // set socket blocking mode, on non-linux platforms, clients get the server mode #ifndef __linux__ if (!ugs->nb) { uwsgi_socket_b(new_connection); } #else if (ugs->nb) { uwsgi_socket_nb(new_connection); } #endif corerouter_alloc_session(ucr, ugs, new_connection, (struct sockaddr *) &cr_addr, cr_addr_len); } else if (ugs->subscription) { uwsgi_corerouter_manage_subscription(ucr, id, ugs); } taken = 1; break; } ugs = ugs->next; } if (taken) { continue; } if (interesting_fd == ushared->gateways[id].internal_subscription_pipe[1]) { uwsgi_corerouter_manage_internal_subscription(ucr, interesting_fd); } else if (interesting_fd == ucr->cr_stats_server) { corerouter_send_stats(ucr); } else { cr_session = ucr->cr_table[interesting_fd]; // something is going wrong... if (cr_session == NULL) continue; if (event_queue_interesting_fd_has_error(events, i)) { corerouter_close_session(ucr, cr_session); continue; } cr_session->timeout = corerouter_reset_timeout(ucr, cr_session); // mplementation specific cycle; ucr->switch_events(ucr, cr_session, interesting_fd); } } } }
void corerouter_close_session(struct uwsgi_corerouter *ucr, struct corerouter_session *cr_session) { if (cr_session->instance_fd != -1) { close(cr_session->instance_fd); ucr->cr_table[cr_session->instance_fd] = NULL; } if (ucr->subscriptions && cr_session->un && cr_session->un->len > 0) { // decrease reference count #ifdef UWSGI_DEBUG uwsgi_log("[1] node %.*s refcnt: %llu\n", cr_session->un->len, cr_session->un->name, cr_session->un->reference); #endif cr_session->un->reference--; #ifdef UWSGI_DEBUG uwsgi_log("[2] node %.*s refcnt: %llu\n", cr_session->un->len, cr_session->un->name, cr_session->un->reference); #endif } if (cr_session->instance_failed) { if (cr_session->soopt) { if (!ucr->quiet) uwsgi_log("unable to connect() to uwsgi instance \"%.*s\": %s\n", (int) cr_session->instance_address_len, cr_session->instance_address, strerror(cr_session->soopt)); } else if (cr_session->timed_out) { if (cr_session->instance_address_len > 0) { if (cr_session->status == COREROUTER_STATUS_CONNECTING) { if (!ucr->quiet) uwsgi_log("unable to connect() to uwsgi instance \"%.*s\": timeout\n", (int) cr_session->instance_address_len, cr_session->instance_address); } else if (cr_session->status == COREROUTER_STATUS_RESPONSE) { uwsgi_log("timeout waiting for instance \"%.*s\"\n", (int) cr_session->instance_address_len, cr_session->instance_address); } } } // now check for dead nodes if (ucr->subscriptions && cr_session->un && cr_session->un->len > 0) { if (cr_session->un->death_mark == 0) uwsgi_log("[uwsgi-%s] %.*s => marking %.*s as failed\n", ucr->short_name, (int) cr_session->hostname_len, cr_session->hostname, (int) cr_session->instance_address_len, cr_session->instance_address); cr_session->un->failcnt++; cr_session->un->death_mark = 1; // check if i can remove the node if (cr_session->un->reference == 0) { uwsgi_remove_subscribe_node(ucr->subscriptions, cr_session->un); } if (ucr->cheap && !ucr->i_am_cheap && !ucr->fallback && uwsgi_no_subscriptions(ucr->subscriptions)) { uwsgi_gateway_go_cheap(ucr->name, ucr->queue, &ucr->i_am_cheap); } } else if (cr_session->static_node) { cr_session->static_node->custom = uwsgi_now(); uwsgi_log("[uwsgi-%s] %.*s => marking %.*s as failed\n", ucr->short_name, (int) cr_session->hostname_len, cr_session->hostname, (int) cr_session->instance_address_len, cr_session->instance_address); } if (cr_session->tmp_socket_name) { free(cr_session->tmp_socket_name); cr_session->tmp_socket_name = NULL; } if (ucr->fallback) { // ok let's try with the fallback nodes if (!cr_session->fallback) { cr_session->fallback = ucr->fallback; } else { cr_session->fallback = cr_session->fallback->next; if (!cr_session->fallback) goto end; } cr_session->instance_address = cr_session->fallback->value; cr_session->instance_address_len = cr_session->fallback->len; // reset error and timeout cr_session->timeout = corerouter_reset_timeout(ucr, cr_session); cr_session->timed_out = 0; cr_session->soopt = 0; // reset nodes cr_session->un = NULL; cr_session->static_node = NULL; cr_session->pass_fd = is_unix(cr_session->instance_address, cr_session->instance_address_len); cr_session->instance_fd = uwsgi_connectn(cr_session->instance_address, cr_session->instance_address_len, 0, 1); if (cr_session->instance_fd < 0) { cr_session->instance_failed = 1; cr_session->soopt = errno; corerouter_close_session(ucr, cr_session); return; } ucr->cr_table[cr_session->instance_fd] = cr_session; cr_session->status = COREROUTER_STATUS_CONNECTING; ucr->cr_table[cr_session->instance_fd] = cr_session; event_queue_add_fd_write(ucr->queue, cr_session->instance_fd); return; } } end: if (cr_session->tmp_socket_name) { free(cr_session->tmp_socket_name); } if (cr_session->buf_file) fclose(cr_session->buf_file); if (cr_session->buf_file_name) { if (unlink(cr_session->buf_file_name)) { uwsgi_error("unlink()"); } free(cr_session->buf_file_name); } // could be used to free additional resources if (cr_session->close) cr_session->close(ucr, cr_session); if (cr_session->keepalive) { cr_session->keepalive = 0; return; } close(cr_session->fd); ucr->cr_table[cr_session->fd] = NULL; cr_del_timeout(ucr, cr_session); free(cr_session); }
void uwsgi_corerouter_loop(int id, void *data) { int i; struct uwsgi_corerouter *ucr = (struct uwsgi_corerouter *) data; ucr->cr_stats_server = -1; ucr->cr_table = uwsgi_malloc(sizeof(struct corerouter_session *) * uwsgi.max_fd); for (i = 0; i < (int) uwsgi.max_fd; i++) { ucr->cr_table[i] = NULL; } ucr->i_am_cheap = ucr->cheap; void *events = uwsgi_corerouter_setup_event_queue(ucr, id); if (ucr->has_subscription_sockets) event_queue_add_fd_read(ucr->queue, ushared->gateways[id].internal_subscription_pipe[1]); if (!ucr->socket_timeout) ucr->socket_timeout = 30; if (!ucr->static_node_gracetime) ucr->static_node_gracetime = 30; int i_am_the_first = 1; for(i=0;i<id;i++) { if (!strcmp(ushared->gateways[i].name, ucr->name)) { i_am_the_first = 0; break; } } if (ucr->stats_server && i_am_the_first) { char *tcp_port = strchr(ucr->stats_server, ':'); if (tcp_port) { // disable deferred accept for this socket int current_defer_accept = uwsgi.no_defer_accept; uwsgi.no_defer_accept = 1; ucr->cr_stats_server = bind_to_tcp(ucr->stats_server, uwsgi.listen_queue, tcp_port); uwsgi.no_defer_accept = current_defer_accept; } else { ucr->cr_stats_server = bind_to_unix(ucr->stats_server, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); } event_queue_add_fd_read(ucr->queue, ucr->cr_stats_server); uwsgi_log("*** %s stats server enabled on %s fd: %d ***\n", ucr->short_name, ucr->stats_server, ucr->cr_stats_server); } if (ucr->use_socket) { ucr->to_socket = uwsgi_get_socket_by_num(ucr->socket_num); if (ucr->to_socket) { // fix socket name_len if (ucr->to_socket->name_len == 0 && ucr->to_socket->name) { ucr->to_socket->name_len = strlen(ucr->to_socket->name); } } } if (!ucr->pb_base_dir) { ucr->pb_base_dir = getenv("TMPDIR"); if (!ucr->pb_base_dir) ucr->pb_base_dir = "/tmp"; } int nevents; time_t delta; struct uwsgi_rb_timer *min_timeout; int interesting_fd; int new_connection; if (ucr->pattern) { init_magic_table(ucr->magic_table); } union uwsgi_sockaddr cr_addr; socklen_t cr_addr_len = sizeof(struct sockaddr_un); struct corerouter_session *cr_session; ucr->mapper = uwsgi_cr_map_use_void; if (ucr->use_cache) { ucr->mapper = uwsgi_cr_map_use_cache; } else if (ucr->pattern) { ucr->mapper = uwsgi_cr_map_use_pattern; } else if (ucr->has_subscription_sockets) { ucr->mapper = uwsgi_cr_map_use_subscription; if (uwsgi.subscription_dotsplit) { ucr->mapper = uwsgi_cr_map_use_subscription_dotsplit; } } else if (ucr->base) { ucr->mapper = uwsgi_cr_map_use_base; } else if (ucr->code_string_code && ucr->code_string_function) { ucr->mapper = uwsgi_cr_map_use_cs; } else if (ucr->to_socket) { ucr->mapper = uwsgi_cr_map_use_to; } else if (ucr->static_nodes) { ucr->mapper = uwsgi_cr_map_use_static_nodes; } else if (ucr->use_cluster) { ucr->mapper = uwsgi_cr_map_use_cluster; } ucr->timeouts = uwsgi_init_rb_timer(); for (;;) { // set timeouts and harakiri min_timeout = uwsgi_min_rb_timer(ucr->timeouts); if (min_timeout == NULL) { delta = -1; } else { delta = min_timeout->key - uwsgi_now(); if (delta <= 0) { corerouter_expire_timeouts(ucr); delta = 0; } } if (uwsgi.master_process && ucr->harakiri > 0) { ushared->gateways_harakiri[id] = 0; } // wait for events nevents = event_queue_wait_multi(ucr->queue, delta, events, ucr->nevents); if (uwsgi.master_process && ucr->harakiri > 0) { ushared->gateways_harakiri[id] = uwsgi_now() + ucr->harakiri; } if (nevents == 0) { corerouter_expire_timeouts(ucr); } for (i = 0; i < nevents; i++) { // get the interesting fd interesting_fd = event_queue_interesting_fd(events, i); // something bad happened if (interesting_fd < 0) continue; // check if the interesting_fd matches a gateway socket struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets; int taken = 0; while (ugs) { if (ugs->gateway == &ushared->gateways[id] && interesting_fd == ugs->fd) { if (!ugs->subscription) { #if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL) new_connection = accept4(interesting_fd, (struct sockaddr *) &cr_addr, &cr_addr_len, SOCK_NONBLOCK); if (new_connection < 0) { taken = 1; break; } #else new_connection = accept(interesting_fd, (struct sockaddr *) &cr_addr, &cr_addr_len); if (new_connection < 0) { taken = 1; break; } // set socket in non-blocking mode, on non-linux platforms, clients get the server mode #ifdef __linux__ uwsgi_socket_nb(new_connection); #endif #endif corerouter_alloc_session(ucr, ugs, new_connection, (struct sockaddr *) &cr_addr, cr_addr_len); } else if (ugs->subscription) { uwsgi_corerouter_manage_subscription(ucr, id, ugs); } taken = 1; break; } ugs = ugs->next; } if (taken) { continue; } // manage internal subscription if (interesting_fd == ushared->gateways[id].internal_subscription_pipe[1]) { uwsgi_corerouter_manage_internal_subscription(ucr, interesting_fd); } // manage a stats request else if (interesting_fd == ucr->cr_stats_server) { corerouter_send_stats(ucr); } else { cr_session = ucr->cr_table[interesting_fd]; // something is going wrong... if (cr_session == NULL) continue; // on error, destroy the session if (event_queue_interesting_fd_has_error(events, i)) { if (interesting_fd == cr_session->instance_fd) { cr_session->instance_failed = 1; } corerouter_close_session(ucr, cr_session); continue; } // set timeout cr_session->timeout = corerouter_reset_timeout(ucr, cr_session); // call event hook ssize_t (*hook)(struct corerouter_session *) = NULL; if (interesting_fd == cr_session->fd) { if (event_queue_interesting_fd_is_read(events, i)) { hook = cr_session->event_hook_read; } else if (event_queue_interesting_fd_is_write(events, i)) { hook = cr_session->event_hook_write; } } else if (interesting_fd == cr_session->instance_fd) { if (event_queue_interesting_fd_is_read(events, i)) { hook = cr_session->event_hook_instance_read; } else if (event_queue_interesting_fd_is_write(events, i)) { hook = cr_session->event_hook_instance_write; } } if (!hook) { uwsgi_log("[uwsgi-corerouter] BUG, unexpected event received !!!\n"); corerouter_close_session(ucr, cr_session); continue; } ssize_t ret = hook(cr_session); // connection closed if (ret == 0) { corerouter_close_session(ucr, cr_session); continue; } else if (ret < 0) { if (errno == EINPROGRESS) continue; corerouter_close_session(ucr, cr_session); continue; } } } } }
void uwsgi_rawrouter_switch_events(struct uwsgi_corerouter *ucr, struct corerouter_session *cs, int interesting_fd) { socklen_t solen = sizeof(int); ssize_t len; char buf[8192]; switch (cs->status) { case COREROUTER_STATUS_RECV_HDR: #ifdef UWSGI_EVENT_USE_PORT event_queue_add_fd_read(ufr->queue, cs->fd); #endif // use the address as hostname cs->hostname = cs->ugs->name; cs->hostname_len = cs->ugs->name_len; // the mapper hook if (ucr->mapper(ucr, cs)) break; // no address found if (!cs->instance_address_len) { // if fallback nodes are configured, trigger them if (ucr->fallback) { cs->instance_failed = 1; } corerouter_close_session(ucr, cs); break; } cs->instance_fd = uwsgi_connectn(cs->instance_address, cs->instance_address_len, 0, 1); if (cs->instance_fd < 0) { cs->instance_failed = 1; cs->soopt = errno; corerouter_close_session(ucr, cs); break; } cs->status = COREROUTER_STATUS_CONNECTING; ucr->cr_table[cs->instance_fd] = cs; event_queue_add_fd_write(ucr->queue, cs->instance_fd); break; case COREROUTER_STATUS_CONNECTING: if (interesting_fd == cs->instance_fd) { if (getsockopt(cs->instance_fd, SOL_SOCKET, SO_ERROR, (void *) (&cs->soopt), &solen) < 0) { uwsgi_error("getsockopt()"); cs->instance_failed = 1; corerouter_close_session(ucr, cs); break; } if (cs->soopt) { cs->instance_failed = 1; corerouter_close_session(ucr, cs); break; } // increment node requests counter if (cs->un) cs->un->requests++; event_queue_fd_write_to_read(ucr->queue, cs->instance_fd); cs->status = COREROUTER_STATUS_RESPONSE; } break; case COREROUTER_STATUS_RESPONSE: // data from instance if (interesting_fd == cs->instance_fd) { len = recv(cs->instance_fd, buf, 8192, 0); #ifdef UWSGI_EVENT_USE_PORT event_queue_add_fd_read(ufr->queue, cs->instance_fd); #endif if (len <= 0) { if (len < 0) uwsgi_error("recv()"); corerouter_close_session(ucr, cs); break; } len = send(cs->fd, buf, len, 0); if (len <= 0) { if (len < 0) uwsgi_error("send()"); corerouter_close_session(ucr, cs); break; } // update transfer statistics if (cs->un) cs->un->transferred += len; } // body from client else if (interesting_fd == cs->fd) { //uwsgi_log("receiving body...\n"); len = recv(cs->fd, buf, 8192, 0); #ifdef UWSGI_EVENT_USE_PORT event_queue_add_fd_read(ufr->queue, cs->fd); #endif if (len <= 0) { if (len < 0) uwsgi_error("recv()"); corerouter_close_session(ucr, cs); break; } len = send(cs->instance_fd, buf, len, 0); if (len <= 0) { if (len < 0) uwsgi_error("send()"); corerouter_close_session(ucr, cs); break; } } break; // fallback to destroy !!! default: uwsgi_log("unknown event: closing session\n"); corerouter_close_session(ucr, cs); break; } }