int uwsgi_cr_map_use_subscription_dotsplit(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) { char *name = peer->key; uint16_t name_len = peer->key_len; // max 5 split, reduce DOS attempts int count = 5; split: if (!count) return 0; #ifdef UWSGI_DEBUG uwsgi_log("trying with %.*s\n", name_len, name); #endif peer->un = uwsgi_get_subscribe_node(ucr->subscriptions, name, name_len); if (!peer->un) { char *next = memchr(name+1, '.', name_len-1); if (next) { name_len -= next - name; name = next; count--; goto split; } } if (peer->un && peer->un->len) { peer->instance_address = peer->un->name; peer->instance_address_len = peer->un->len; peer->modifier1 = peer->un->modifier1; } else if (ucr->cheap && !ucr->i_am_cheap && uwsgi_no_subscriptions(ucr->subscriptions)) { uwsgi_gateway_go_cheap(ucr->name, ucr->queue, &ucr->i_am_cheap); } return 0; }
int uwsgi_cr_map_use_subscription_dotsplit(struct uwsgi_corerouter *ucr, struct corerouter_session *cr_session) { char *name = cr_session->hostname; uint16_t name_len = cr_session->hostname_len; split: #ifdef UWSGI_DEBUG uwsgi_log("trying with %.*s\n", name_len, name); #endif cr_session->un = uwsgi_get_subscribe_node(ucr->subscriptions, name, name_len); if (!cr_session->un) { char *next = memchr(name+1, '.', name_len-1); if (next) { name_len -= next - name; name = next; goto split; } } if (cr_session->un && cr_session->un->len) { cr_session->instance_address = cr_session->un->name; cr_session->instance_address_len = cr_session->un->len; cr_session->modifier1 = cr_session->un->modifier1; } else if (ucr->cheap && !ucr->i_am_cheap && uwsgi_no_subscriptions(ucr->subscriptions)) { uwsgi_gateway_go_cheap(ucr->name, ucr->queue, &ucr->i_am_cheap); } return 0; }
void uwsgi_corerouter_manage_subscription(struct uwsgi_corerouter *ucr, int id, struct uwsgi_gateway_socket *ugs) { int i; struct uwsgi_subscribe_req usr; char bbuf[4096]; ssize_t len = recv(ugs->fd, bbuf, 4096, 0); #ifdef UWSGI_EVENT_USE_PORT event_queue_add_fd_read(ucr->queue, ugs->fd); #endif if (len > 0) { memset(&usr, 0, sizeof(struct uwsgi_subscribe_req)); uwsgi_hooked_parse(bbuf + 4, len - 4, corerouter_manage_subscription, &usr); // subscribe request ? if (bbuf[3] == 0) { if (uwsgi_add_subscribe_node(&ucr->subscriptions, &usr, ucr->subscription_regexp) && ucr->i_am_cheap) { struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets; while (ugs) { if (!strcmp(ugs->owner, ucr->name) && !ugs->subscription) { event_queue_add_fd_read(ucr->queue, ugs->fd); } ugs = ugs->next; } ucr->i_am_cheap = 0; uwsgi_log("[%s pid %d] leaving cheap mode...\n", ucr->name, (int) uwsgi.mypid); } } //unsubscribe else { struct uwsgi_subscribe_node *node = uwsgi_get_subscribe_node_by_name(&ucr->subscriptions, usr.key, usr.keylen, usr.address, usr.address_len, ucr->subscription_regexp); if (node && node->len) { if (node->death_mark == 0) uwsgi_log("[%s pid %d] %.*s => marking %.*s as failed\n", ucr->name, (int) uwsgi.mypid, (int) usr.keylen, usr.key, (int) usr.address_len, usr.address); node->failcnt++; node->death_mark = 1; // check if i can remove the node if (node->reference == 0) { uwsgi_remove_subscribe_node(&ucr->subscriptions, node); } if (ucr->subscriptions == NULL && ucr->cheap && !ucr->i_am_cheap) { uwsgi_gateway_go_cheap(ucr->name, ucr->queue, &ucr->i_am_cheap); } } } // propagate the subscription to other nodes for (i = 0; i < ushared->gateways_cnt; i++) { if (i == id) continue; if (!strcmp(ushared->gateways[i].name, ucr->name)) { if (send(ushared->gateways[i].internal_subscription_pipe[0], bbuf, len, 0) != len) { uwsgi_error("send()"); } } } } }
int uwsgi_fr_map_use_subscription(struct fastrouter_session *fr_session, char **magic_table) { fr_session->un = uwsgi_get_subscribe_node(&ufr.subscriptions, fr_session->hostname, fr_session->hostname_len, ufr.subscription_regexp); if (fr_session->un && fr_session->un->len) { fr_session->instance_address = fr_session->un->name; fr_session->instance_address_len = fr_session->un->len; fr_session->modifier1 = fr_session->un->modifier1; } else if (ufr.subscriptions == NULL && ufr.cheap && !ufr.i_am_cheap) { uwsgi_gateway_go_cheap("uWSGI fastrouter", ufr.queue, &ufr.i_am_cheap); } return 0; }
int uwsgi_cr_map_use_subscription(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) { peer->un = uwsgi_get_subscribe_node(ucr->subscriptions, peer->key, peer->key_len); if (peer->un && peer->un->len) { peer->instance_address = peer->un->name; peer->instance_address_len = peer->un->len; peer->modifier1 = peer->un->modifier1; } else if (ucr->cheap && !ucr->i_am_cheap && uwsgi_no_subscriptions(ucr->subscriptions)) { uwsgi_gateway_go_cheap(ucr->name, ucr->queue, &ucr->i_am_cheap); } return 0; }
int uwsgi_cr_map_use_subscription(struct uwsgi_corerouter *ucr, struct corerouter_session *cr_session) { cr_session->un = uwsgi_get_subscribe_node(ucr->subscriptions, cr_session->hostname, cr_session->hostname_len); if (cr_session->un && cr_session->un->len) { cr_session->instance_address = cr_session->un->name; cr_session->instance_address_len = cr_session->un->len; cr_session->modifier1 = cr_session->un->modifier1; } else if (ucr->cheap && !ucr->i_am_cheap && uwsgi_no_subscriptions(ucr->subscriptions)) { uwsgi_gateway_go_cheap(ucr->name, ucr->queue, &ucr->i_am_cheap); } return 0; }
void uwsgi_corerouter_manage_internal_subscription(struct uwsgi_corerouter *ucr, int fd) { struct uwsgi_subscribe_req usr; char bbuf[4096]; ssize_t len = recv(fd, bbuf, 4096, 0); if (len > 0) { memset(&usr, 0, sizeof(struct uwsgi_subscribe_req)); uwsgi_hooked_parse(bbuf + 4, len - 4, corerouter_manage_subscription, &usr); // subscribe request ? if (bbuf[3] == 0) { if (uwsgi_add_subscribe_node(ucr->subscriptions, &usr) && ucr->i_am_cheap) { struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets; while (ugs) { if (!strcmp(ugs->owner, ucr->name) && !ugs->subscription) { event_queue_add_fd_read(ucr->queue, ugs->fd); } ugs = ugs->next; } ucr->i_am_cheap = 0; uwsgi_log("[%s pid %d] leaving cheap mode...\n", ucr->name, (int) uwsgi.mypid); } } //unsubscribe else { struct uwsgi_subscribe_node *node = uwsgi_get_subscribe_node_by_name(ucr->subscriptions, usr.key, usr.keylen, usr.address, usr.address_len); if (node && node->len) { if (node->death_mark == 0) uwsgi_log("[%s pid %d] %.*s => marking %.*s as failed\n", ucr->name, (int) uwsgi.mypid, (int) usr.keylen, usr.key, (int) usr.address_len, usr.address); node->failcnt++; node->death_mark = 1; // check if i can remove the node if (node->reference == 0) { uwsgi_remove_subscribe_node(ucr->subscriptions, node); } if (ucr->cheap && !ucr->i_am_cheap && uwsgi_no_subscriptions(ucr->subscriptions)) { uwsgi_gateway_go_cheap(ucr->name, ucr->queue, &ucr->i_am_cheap); } } } } }
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 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); }