int uwsgi_cr_map_use_cache(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) { uint64_t hits = 0; uwsgi_rlock(ucr->cache->lock); char *value = uwsgi_cache_get4(ucr->cache, peer->key, peer->key_len, &peer->instance_address_len, &hits); if (!value) goto end; peer->tmp_socket_name = uwsgi_concat2n(value, peer->instance_address_len, "", 0); size_t nodes = uwsgi_str_occurence(peer->tmp_socket_name, peer->instance_address_len, '|'); if (nodes > 0) { size_t choosen_node = hits % (nodes+1); size_t choosen_node_len = 0; peer->instance_address = uwsgi_str_split_nget(peer->tmp_socket_name, peer->instance_address_len, '|', choosen_node, &choosen_node_len); if (!peer->instance_address) goto end; peer->instance_address_len = choosen_node_len; } else { peer->instance_address = peer->tmp_socket_name; } char *cs_mod = uwsgi_str_contains(peer->instance_address, peer->instance_address_len, ','); if (cs_mod) { peer->modifier1 = uwsgi_str_num(cs_mod + 1, (peer->instance_address_len - (cs_mod - peer->instance_address)) - 1); peer->instance_address_len = (cs_mod - peer->instance_address); } end: uwsgi_rwunlock(ucr->cache->lock); return 0; }
int uwsgi_fr_map_use_cache(struct fastrouter_session *fr_session, char **magic_table) { fr_session->instance_address = uwsgi_cache_get(fr_session->hostname, fr_session->hostname_len, &fr_session->instance_address_len); char *cs_mod = uwsgi_str_contains(fr_session->instance_address, fr_session->instance_address_len, ','); if (cs_mod) { fr_session->modifier1 = uwsgi_str_num(cs_mod + 1, (fr_session->instance_address_len - (cs_mod - fr_session->instance_address)) - 1); fr_session->instance_address_len = (cs_mod - fr_session->instance_address); } return 0; }
int uwsgi_cr_map_use_cache(struct uwsgi_corerouter *ucr, struct corerouter_session *cr_session) { cr_session->instance_address = uwsgi_cache_get(cr_session->hostname, cr_session->hostname_len, &cr_session->instance_address_len); char *cs_mod = uwsgi_str_contains(cr_session->instance_address, cr_session->instance_address_len, ','); if (cs_mod) { cr_session->modifier1 = uwsgi_str_num(cs_mod + 1, (cr_session->instance_address_len - (cs_mod - cr_session->instance_address)) - 1); cr_session->instance_address_len = (cs_mod - cr_session->instance_address); } return 0; }
int uwsgi_fr_map_use_cs(struct fastrouter_session *fr_session, char **magic_table) { if (uwsgi.p[ufr.code_string_modifier1]->code_string) { fr_session->instance_address = uwsgi.p[ufr.code_string_modifier1]->code_string("uwsgi_fastrouter", ufr.code_string_code, ufr.code_string_function, fr_session->hostname, fr_session->hostname_len); if (fr_session->instance_address) { fr_session->instance_address_len = strlen(fr_session->instance_address); char *cs_mod = uwsgi_str_contains(fr_session->instance_address, fr_session->instance_address_len, ','); if (cs_mod) { fr_session->modifier1 = uwsgi_str_num(cs_mod + 1, (fr_session->instance_address_len - (cs_mod - fr_session->instance_address)) - 1); fr_session->instance_address_len = (cs_mod - fr_session->instance_address); } } } return 0; }
int uwsgi_cr_map_use_cs(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) { if (uwsgi.p[ucr->code_string_modifier1]->code_string) { char *name = uwsgi_concat2("uwsgi_", ucr->short_name); peer->instance_address = uwsgi.p[ucr->code_string_modifier1]->code_string(name, ucr->code_string_code, ucr->code_string_function, peer->key, peer->key_len); free(name); if (peer->instance_address) { peer->instance_address_len = strlen(peer->instance_address); char *cs_mod = uwsgi_str_contains(peer->instance_address, peer->instance_address_len, ','); if (cs_mod) { peer->modifier1 = uwsgi_str_num(cs_mod + 1, (peer->instance_address_len - (cs_mod - peer->instance_address)) - 1); peer->instance_address_len = (cs_mod - peer->instance_address); } } } return 0; }
int uwsgi_cr_map_use_cs(struct uwsgi_corerouter *ucr, struct corerouter_session *cr_session) { if (uwsgi.p[ucr->code_string_modifier1]->code_string) { char *name = uwsgi_concat2("uwsgi_", ucr->short_name); cr_session->instance_address = uwsgi.p[ucr->code_string_modifier1]->code_string(name, ucr->code_string_code, ucr->code_string_function, cr_session->hostname, cr_session->hostname_len); free(name); if (cr_session->instance_address) { cr_session->instance_address_len = strlen(cr_session->instance_address); char *cs_mod = uwsgi_str_contains(cr_session->instance_address, cr_session->instance_address_len, ','); if (cs_mod) { cr_session->modifier1 = uwsgi_str_num(cs_mod + 1, (cr_session->instance_address_len - (cs_mod - cr_session->instance_address)) - 1); cr_session->instance_address_len = (cs_mod - cr_session->instance_address); } } } return 0; }
void fastrouter_loop() { int nevents; int interesting_fd; int new_connection; ssize_t len; int i; time_t delta; char bbuf[UMAX16]; char *tcp_port; char *tmp_socket_name; int tmp_socket_name_len; struct uwsgi_subscribe_req usr; char *magic_table[0xff]; struct uwsgi_rb_timer *min_timeout; void *events; struct msghdr msg; union { struct cmsghdr cmsg; char control [CMSG_SPACE (sizeof (int))]; } msg_control; struct cmsghdr *cmsg; struct sockaddr_un fr_addr; socklen_t fr_addr_len = sizeof(struct sockaddr_un); struct fastrouter_session *fr_session; struct fastrouter_session *fr_table[2048]; struct iovec iov[2]; int soopt; socklen_t solen = sizeof(int); int ufr_subserver = -1; for(i=0;i<2048;i++) { fr_table[i] = NULL; } ufr.queue = event_queue_init(); struct uwsgi_fastrouter_socket *ufr_sock = ufr.sockets; while(ufr_sock) { if (ufr_sock->name[0] == '=') { int shared_socket = atoi(ufr_sock->name+1); if (shared_socket >= 0) { ufr_sock->fd = uwsgi_get_shared_socket_fd_by_num(shared_socket); if (ufr_sock->fd == -1) { uwsgi_log("unable to use shared socket %d\n", shared_socket); } } } else { tcp_port = strchr(ufr_sock->name, ':'); if (tcp_port) { ufr_sock->fd = bind_to_tcp(ufr_sock->name, uwsgi.listen_queue, tcp_port); } else { ufr_sock->fd = bind_to_unix(ufr_sock->name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); } } uwsgi_log("uwsgi fastrouter/proxy bound on %s\n", ufr_sock->name); if (!ufr.cheap) { event_queue_add_fd_read(ufr.queue, ufr_sock->fd); } else { uwsgi_log("[uwsgi-fastrouter] cheap mode requested. Waiting for subscriptions...\n"); ufr.i_am_cheap = 1; } ufr_sock = ufr_sock->next; } events = event_queue_alloc(ufr.nevents); ufr.timeouts = uwsgi_init_rb_timer(); if (!ufr.socket_timeout) ufr.socket_timeout = 30; if (ufr.subscription_server) { ufr_subserver = bind_to_udp(ufr.subscription_server, 0, 0); event_queue_add_fd_read(ufr.queue, ufr_subserver); if (!ufr.subscription_slot) ufr.subscription_slot = 30; // check for node status every 10 seconds //ufr.subscriptions_check = add_check_timeout(10); } if (ufr.pattern) { init_magic_table(magic_table); } for (;;) { min_timeout = uwsgi_min_rb_timer(ufr.timeouts); if (min_timeout == NULL ) { delta = -1; } else { delta = min_timeout->key - time(NULL); if (delta <= 0) { expire_timeouts(fr_table); delta = 0; } } nevents = event_queue_wait_multi(ufr.queue, delta, events, ufr.nevents); if (nevents == 0) { expire_timeouts(fr_table); } for (i=0;i<nevents;i++) { tmp_socket_name = NULL; interesting_fd = event_queue_interesting_fd(events, i); int taken = 0; struct uwsgi_fastrouter_socket *uwsgi_sock = ufr.sockets; while(uwsgi_sock) { if (interesting_fd == uwsgi_sock->fd) { new_connection = accept(interesting_fd, (struct sockaddr *) &fr_addr, &fr_addr_len); if (new_connection < 0) { continue; } fr_table[new_connection] = alloc_fr_session(); fr_table[new_connection]->fd = new_connection; fr_table[new_connection]->instance_fd = -1; fr_table[new_connection]->status = FASTROUTER_STATUS_RECV_HDR; fr_table[new_connection]->h_pos = 0; fr_table[new_connection]->pos = 0; fr_table[new_connection]->un = NULL; fr_table[new_connection]->instance_failed = 0; fr_table[new_connection]->instance_address_len = 0; fr_table[new_connection]->hostname_len = 0; fr_table[new_connection]->hostname = NULL; fr_table[new_connection]->timeout = add_timeout(fr_table[new_connection]); event_queue_add_fd_read(ufr.queue, new_connection); taken = 1; break; } uwsgi_sock = uwsgi_sock->next; } if (taken) { continue; } if (interesting_fd == ufr_subserver) { len = recv(ufr_subserver, bbuf, 4096, 0); #ifdef UWSGI_EVENT_USE_PORT event_queue_add_fd_read(ufr.queue, ufr_subserver); #endif if (len > 0) { memset(&usr, 0, sizeof(struct uwsgi_subscribe_req)); uwsgi_hooked_parse(bbuf+4, len-4, fastrouter_manage_subscription, &usr); if (uwsgi_add_subscribe_node(&ufr.subscriptions, &usr, ufr.subscription_regexp) && ufr.i_am_cheap) { struct uwsgi_fastrouter_socket *ufr_sock = ufr.sockets; while(ufr_sock) { event_queue_add_fd_read(ufr.queue, ufr_sock->fd); ufr_sock = ufr_sock->next; } ufr.i_am_cheap = 0; uwsgi_log("[uwsgi-fastrouter] leaving cheap mode...\n"); } } } else { fr_session = fr_table[interesting_fd]; // something is going wrong... if (fr_session == NULL) continue; if (event_queue_interesting_fd_has_error(events, i)) { close_session(fr_table, fr_session); continue; } fr_session->timeout = reset_timeout(fr_session); switch(fr_session->status) { case FASTROUTER_STATUS_RECV_HDR: len = recv(fr_session->fd, (char *)(&fr_session->uh) + fr_session->h_pos, 4-fr_session->h_pos, 0); if (len <= 0) { uwsgi_error("recv()"); close_session(fr_table, fr_session); break; } fr_session->h_pos += len; if (fr_session->h_pos == 4) { #ifdef UWSGI_DEBUG uwsgi_log("modifier1: %d pktsize: %d modifier2: %d\n", fr_session->uh.modifier1, fr_session->uh.pktsize, fr_session->uh.modifier2); #endif fr_session->status = FASTROUTER_STATUS_RECV_VARS; } break; case FASTROUTER_STATUS_RECV_VARS: len = recv(fr_session->fd, fr_session->buffer + fr_session->pos, fr_session->uh.pktsize - fr_session->pos, 0); if (len <= 0) { uwsgi_error("recv()"); close_session(fr_table, fr_session); break; } fr_session->pos += len; if (fr_session->pos == fr_session->uh.pktsize) { if (uwsgi_hooked_parse(fr_session->buffer, fr_session->uh.pktsize, fr_get_hostname, (void *) fr_session)) { close_session(fr_table, fr_session); break; } if (fr_session->hostname_len == 0) { close_session(fr_table, fr_session); break; } #ifdef UWSGI_DEBUG //uwsgi_log("requested domain %.*s\n", fr_session->hostname_len, fr_session->hostname); #endif if (ufr.use_cache) { fr_session->instance_address = uwsgi_cache_get(fr_session->hostname, fr_session->hostname_len, &fr_session->instance_address_len); char *cs_mod = uwsgi_str_contains(fr_session->instance_address, fr_session->instance_address_len, ','); if (cs_mod) { fr_session->modifier1 = uwsgi_str_num(cs_mod+1, (fr_session->instance_address_len - (cs_mod - fr_session->instance_address))-1); fr_session->instance_address_len = (cs_mod - fr_session->instance_address); } } else if (ufr.pattern) { magic_table['s'] = uwsgi_concat2n(fr_session->hostname, fr_session->hostname_len, "", 0); tmp_socket_name = magic_sub(ufr.pattern, ufr.pattern_len, &tmp_socket_name_len, magic_table); free(magic_table['s']); fr_session->instance_address_len = tmp_socket_name_len; fr_session->instance_address = tmp_socket_name; } else if (ufr.subscription_server) { 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.base) { tmp_socket_name = uwsgi_concat2nn(ufr.base, ufr.base_len, fr_session->hostname, fr_session->hostname_len, &tmp_socket_name_len); fr_session->instance_address_len = tmp_socket_name_len; fr_session->instance_address = tmp_socket_name; } else if (ufr.code_string_code && ufr.code_string_function) { if (uwsgi.p[ufr.code_string_modifier1]->code_string) { fr_session->instance_address = uwsgi.p[ufr.code_string_modifier1]->code_string("uwsgi_fastrouter", ufr.code_string_code, ufr.code_string_function, fr_session->hostname, fr_session->hostname_len); if (fr_session->instance_address) { fr_session->instance_address_len = strlen(fr_session->instance_address); char *cs_mod = uwsgi_str_contains(fr_session->instance_address, fr_session->instance_address_len, ','); if (cs_mod) { fr_session->modifier1 = uwsgi_str_num(cs_mod+1, (fr_session->instance_address_len - (cs_mod - fr_session->instance_address))-1); fr_session->instance_address_len = (cs_mod - fr_session->instance_address); } } } } // no address found if (!fr_session->instance_address_len) { close_session(fr_table, fr_session); break; } fr_session->pass_fd = is_unix(fr_session->instance_address, fr_session->instance_address_len); fr_session->instance_fd = uwsgi_connectn(fr_session->instance_address, fr_session->instance_address_len, 0, 1); if (tmp_socket_name) free(tmp_socket_name); if (fr_session->instance_fd < 0) { /* if (ufr.subscription_server) { if (fr_session->un && fr_session->un->len > 0) { uwsgi_log("[uwsgi-fastrouter] %.*s => marking %.*s as failed\n", (int) fr_session->hostname_len, fr_session->hostname, (int) fr_session->instance_address_len,fr_session->instance_address); uwsgi_remove_subscribe_node(&ufr.subscriptions, fr_session->un); if (ufr.subscriptions == NULL && ufr.cheap && !ufr.i_am_cheap) { uwsgi_log("[uwsgi-fastrouter] no more nodes available. Going cheap...\n"); struct uwsgi_fastrouter_socket *ufr_sock = ufr.sockets; while(ufr_sock) { event_queue_del_fd(ufr.queue, ufr_sock->fd, event_queue_read()); ufr_sock = ufr_sock->next; } ufr.i_am_cheap = 1; } } } */ fr_session->instance_failed = 1; close_session(fr_table, fr_session); break; } fr_session->status = FASTROUTER_STATUS_CONNECTING; fr_table[fr_session->instance_fd] = fr_session; event_queue_add_fd_write(ufr.queue, fr_session->instance_fd); } break; case FASTROUTER_STATUS_CONNECTING: if (interesting_fd == fr_session->instance_fd) { if (getsockopt(fr_session->instance_fd, SOL_SOCKET, SO_ERROR, (void *) (&soopt), &solen) < 0) { uwsgi_error("getsockopt()"); fr_session->instance_failed = 1; close_session(fr_table, fr_session); break; } if (soopt) { uwsgi_log("unable to connect() to uwsgi instance: %s\n", strerror(soopt)); fr_session->instance_failed = 1; close_session(fr_table, fr_session); break; } fr_session->uh.modifier1 = fr_session->modifier1; iov[0].iov_base = &fr_session->uh; iov[0].iov_len = 4; iov[1].iov_base = fr_session->buffer; iov[1].iov_len = fr_session->uh.pktsize; // increment node requests counter if (fr_session->un) fr_session->un->requests++; // fd passing: PERFORMANCE EXTREME BOOST !!! if (fr_session->pass_fd && !uwsgi.no_fd_passing) { msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = 2; msg.msg_flags = 0; msg.msg_control = &msg_control; msg.msg_controllen = sizeof (msg_control); cmsg = CMSG_FIRSTHDR (&msg); cmsg->cmsg_len = CMSG_LEN (sizeof (int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; memcpy(CMSG_DATA(cmsg), &fr_session->fd, sizeof(int)); if (sendmsg(fr_session->instance_fd, &msg, 0) < 0) { uwsgi_error("sendmsg()"); } close_session(fr_table, fr_session); break; } if (writev(fr_session->instance_fd, iov, 2) < 0) { uwsgi_error("writev()"); close_session(fr_table, fr_session); break; } event_queue_fd_write_to_read(ufr.queue, fr_session->instance_fd); fr_session->status = FASTROUTER_STATUS_RESPONSE; } break; case FASTROUTER_STATUS_RESPONSE: // data from instance if (interesting_fd == fr_session->instance_fd) { len = recv(fr_session->instance_fd, fr_session->buffer, 0xffff, 0); if (len <= 0) { if (len < 0) uwsgi_error("recv()"); close_session(fr_table, fr_session); break; } len = send(fr_session->fd, fr_session->buffer, len, 0); if (len <= 0) { if (len < 0) uwsgi_error("send()"); close_session(fr_table, fr_session); break; } // update transfer statistics if (fr_session->un) fr_session->un->transferred += len; } // body from client else if (interesting_fd == fr_session->fd) { //uwsgi_log("receiving body...\n"); len = recv(fr_session->fd, fr_session->buffer, 0xffff, 0); if (len <= 0) { if (len < 0) uwsgi_error("recv()"); close_session(fr_table, fr_session); break; } len = send(fr_session->instance_fd, fr_session->buffer, len, 0); if (len <= 0) { if (len < 0) uwsgi_error("send()"); close_session(fr_table, fr_session); break; } } break; // fallback to destroy !!! default: uwsgi_log("unknown event: closing session\n"); close_session(fr_table, fr_session); break; } } } } }
void uwsgi_opt_add_cron2(char *opt, char *value, void *foobar) { char *c_minute = NULL; char *c_hour = NULL; char *c_day = NULL; char *c_month = NULL; char *c_week = NULL; char *c_unique = NULL; char *c_harakiri = NULL; char *c_legion = NULL; char *c_command = value; char *space = strchr(value, ' '); if (space) { if (uwsgi_str_contains(value, space - value, '=')) { // --cron2 key=val command *space = 0; c_command = space + 1; } // no point in parsing key=val list if there is none if (uwsgi_kvlist_parse(value, strlen(value), ',', '=', "minute", &c_minute, "hour", &c_hour, "day", &c_day, "month", &c_month, "week", &c_week, "unique", &c_unique, "harakiri", &c_harakiri, "legion", &c_legion, NULL)) { uwsgi_log("unable to parse cron definition: %s\n", value); exit(1); } } else { if (uwsgi_str_contains(value, strlen(value), '=')) { // --cron2 key=val uwsgi_log("unable to parse cron definition: %s\n", value); exit(1); } } struct uwsgi_cron *old_uc, *uc = uwsgi.crons; if (!uc) { uc = uwsgi_malloc(sizeof(struct uwsgi_cron)); uwsgi.crons = uc; } else { old_uc = uc; while (uc->next) { uc = uc->next; old_uc = uc; } old_uc->next = uwsgi_malloc(sizeof(struct uwsgi_cron)); uc = old_uc->next; } memset(uc, 0, sizeof(struct uwsgi_cron)); uc->command = c_command; if (!uc->command) { uwsgi_log("[uwsgi-cron] invalid command in cron definition: %s\n", value); exit(1); } // defaults uc->minute = -1; uc->hour = -1; uc->day = -1; uc->month = -1; uc->week = -1; uc->unique = 0; uc->mercy = 0; uc->harakiri = 0; uc->pid = -1; #ifdef UWSGI_SSL uc->legion = c_legion; #endif if (c_minute) uc->minute = atoi(c_minute); if (c_hour) uc->hour = atoi(c_hour); if (c_day) uc->day = atoi(c_day); if (c_month) uc->month = atoi(c_month); if (c_week) uc->week = atoi(c_week); if (c_unique) uc->unique = atoi(c_unique); if (c_harakiri) { if (atoi(c_harakiri)) { // harakiri > 0 uc->mercy = atoi(c_harakiri); } else { // harakiri == 0 uc->mercy = -1; } } else if (uwsgi.cron_harakiri) { uc->harakiri = uwsgi.cron_harakiri; } }