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()"); } } } } }
// called after receaving the uwsgi header (read vars) static ssize_t fr_recv_uwsgi_vars(struct corerouter_peer *main_peer) { struct uwsgi_header *uh = (struct uwsgi_header *) main_peer->in->buf; // better to store it as the original buf address could change uint16_t pktsize = uh->_pktsize; // increase buffer if needed if (uwsgi_buffer_fix(main_peer->in, pktsize+4)) return -1; ssize_t len = cr_read_exact(main_peer, pktsize+4, "fr_recv_uwsgi_vars()"); if (!len) return 0; // headers received, ready to choose the instance if (main_peer->in->pos == (size_t)(pktsize+4)) { struct uwsgi_corerouter *ucr = main_peer->session->corerouter; struct corerouter_peer *new_peer = uwsgi_cr_peer_add(main_peer->session); new_peer->last_hook_read = fr_instance_read; if (!ufr.force_key) { // find the hostname if (uwsgi_hooked_parse(main_peer->in->buf+4, pktsize, fr_get_hostname, (void *) new_peer)) { return -1; } } else { new_peer->key_len = strlen(ufr.force_key); memcpy(new_peer->key, ufr.force_key, new_peer->key_len); } // check the hostname; if (new_peer->key_len == 0) return -1; // find an instance using the key if (ucr->mapper(ucr, new_peer)) return -1; // check instance if (new_peer->instance_address_len == 0) { if (ufr.cr.fallback_on_no_key) { new_peer->failed = 1; new_peer->can_retry = 1; corerouter_close_peer(&ufr.cr, new_peer); return len; } return -1; } new_peer->can_retry = 1; cr_connect(new_peer, fr_instance_connected); } return len; }
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); } } } } }
// called after receaving the uwsgi header (read vars) ssize_t fr_recv_uwsgi_vars(struct corerouter_peer *main_peer) { struct uwsgi_header *uh = (struct uwsgi_header *) main_peer->in->buf; // increase buffer if needed if (uwsgi_buffer_fix(main_peer->in, uh->pktsize+4)) return -1; ssize_t len = cr_read_exact(main_peer, uh->pktsize+4, "fr_recv_uwsgi_vars()"); if (!len) return 0; // headers received, ready to choose the instance if (main_peer->in->pos == (size_t)(uh->pktsize+4)) { struct uwsgi_corerouter *ucr = main_peer->session->corerouter; struct corerouter_peer *new_peer = uwsgi_cr_peer_add(main_peer->session); new_peer->last_hook_read = fr_instance_read; // find the hostname if (uwsgi_hooked_parse(main_peer->in->buf+4, uh->pktsize, fr_get_hostname, (void *) new_peer)) { return -1; } // check the hostname; if (new_peer->key_len == 0) return -1; // find an instance using the key if (ucr->mapper(ucr, new_peer)) return -1; // check instance if (new_peer->instance_address_len == 0) return -1; cr_connect(new_peer, fr_instance_connected); } return len; }
int uwsgi_python_spooler(char *filename, char *buf, uint16_t len, char *body, size_t body_len) { static int random_seed_reset = 0; UWSGI_GET_GIL; PyObject *spool_dict = PyDict_New(); PyObject *spool_func, *pyargs, *ret; if (!random_seed_reset) { uwsgi_python_reset_random_seed(); random_seed_reset = 1; } if (!up.embedded_dict) { // ignore UWSGI_RELEASE_GIL; return 0; } spool_func = PyDict_GetItemString(up.embedded_dict, "spooler"); if (!spool_func) { // ignore UWSGI_RELEASE_GIL; return 0; } if (uwsgi_hooked_parse(buf, len, uwsgi_python_add_item, spool_dict)) { // malformed packet, destroy it UWSGI_RELEASE_GIL; return -2; } pyargs = PyTuple_New(1); PyDict_SetItemString(spool_dict, "spooler_task_name", PyString_FromString(filename)); if (body && body_len > 0) { PyDict_SetItemString(spool_dict, "body", PyString_FromStringAndSize(body, body_len)); } PyTuple_SetItem(pyargs, 0, spool_dict); ret = python_call(spool_func, pyargs, 0, NULL); if (ret) { if (!PyInt_Check(ret)) { // error, retry UWSGI_RELEASE_GIL; return -1; } int retval = (int) PyInt_AsLong(ret); UWSGI_RELEASE_GIL; return retval; } if (PyErr_Occurred()) PyErr_Print(); // error, retry UWSGI_RELEASE_GIL; return -1; }
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; } } } } }
static int uwsgi_cache_request(struct wsgi_request *wsgi_req) { uint64_t vallen = 0; char *value; char *argv[3]; uint16_t argvs[3]; uint8_t argc = 0; // used for modifier2 17 struct uwsgi_cache_magic_context ucmc; struct uwsgi_cache *uc = NULL; switch(wsgi_req->uh->modifier2) { case 0: // get if (wsgi_req->uh->_pktsize > 0) { value = uwsgi_cache_magic_get(wsgi_req->buffer, wsgi_req->uh->_pktsize, &vallen, NULL, NULL); if (value) { wsgi_req->uh->_pktsize = vallen; if (uwsgi_response_write_body_do(wsgi_req, (char *)&wsgi_req->uh, 4)) { free(value) ; return -1;} uwsgi_response_write_body_do(wsgi_req, value, vallen); free(value); } } break; case 1: // set if (wsgi_req->uh->_pktsize > 0) { // max 3 items argc = 3; if (!uwsgi_parse_array(wsgi_req->buffer, wsgi_req->uh->_pktsize, argv, argvs, &argc)) { if (argc > 1) { uwsgi_cache_magic_set(argv[0], argvs[0], argv[1], argvs[1], 0, 0, NULL); } } } break; case 2: // del if (wsgi_req->uh->_pktsize > 0) { uwsgi_cache_magic_del(wsgi_req->buffer, wsgi_req->uh->_pktsize, NULL); } break; case 3: case 4: // dict if (wsgi_req->uh->_pktsize > 0) { uwsgi_hooked_parse(wsgi_req->buffer, wsgi_req->uh->_pktsize, cache_simple_command, (void *) wsgi_req); } break; case 5: // get (uwsgi + stream) if (wsgi_req->uh->_pktsize > 0) { value = uwsgi_cache_magic_get(wsgi_req->buffer, wsgi_req->uh->_pktsize, &vallen, NULL, NULL); if (value) { wsgi_req->uh->_pktsize = 0; wsgi_req->uh->modifier2 = 1; if (uwsgi_response_write_body_do(wsgi_req, (char *)&wsgi_req->uh, 4)) { free(value) ;return -1;} uwsgi_response_write_body_do(wsgi_req, value, vallen); free(value); } else { wsgi_req->uh->_pktsize = 0; wsgi_req->uh->modifier2 = 0; uwsgi_response_write_body_do(wsgi_req, (char *)&wsgi_req->uh, 4); free(value); } } break; case 6: // dump uc = uwsgi.caches; if (wsgi_req->uh->_pktsize > 0) { uc = uwsgi_cache_by_namelen(wsgi_req->buffer, wsgi_req->uh->_pktsize); } if (!uc) break; uwsgi_wlock(uc->lock); struct uwsgi_buffer *cache_dump = uwsgi_buffer_new(uwsgi.page_size + uc->filesize); cache_dump->pos = 4; if (uwsgi_buffer_append_keynum(cache_dump, "items", 5, uc->max_items)) { uwsgi_buffer_destroy(cache_dump); break; } if (uwsgi_buffer_append_keynum(cache_dump, "blocksize", 9, uc->blocksize)) { uwsgi_buffer_destroy(cache_dump); break; } if (uwsgi_buffer_set_uh(cache_dump, 111, 7)) { uwsgi_buffer_destroy(cache_dump); break; } if (uwsgi_buffer_append(cache_dump, (char *)uc->items, uc->filesize)) { uwsgi_buffer_destroy(cache_dump); break; } uwsgi_rwunlock(uc->lock); uwsgi_response_write_body_do(wsgi_req, cache_dump->buf, cache_dump->pos); uwsgi_buffer_destroy(cache_dump); break; case 17: if (wsgi_req->uh->_pktsize == 0) break; memset(&ucmc, 0, sizeof(struct uwsgi_cache_magic_context)); if (uwsgi_hooked_parse(wsgi_req->buffer, wsgi_req->uh->_pktsize, uwsgi_cache_magic_context_hook, &ucmc)) { break; } manage_magic_context(wsgi_req, &ucmc); break; default: break; } return UWSGI_OK; }
/* CHANGED in 2.0.7: wsgi_req is useless ! */ char *uwsgi_spool_request(struct wsgi_request *wsgi_req, char *buf, size_t len, char *body, size_t body_len) { struct timeval tv; static uint64_t internal_counter = 0; int fd = -1; struct spooler_req sr; if (len > 0xffff) { uwsgi_log("[uwsgi-spooler] args buffer is limited to 64k, use the 'body' for bigger values\n"); return NULL; } // parse the request buffer memset(&sr, 0, sizeof(struct spooler_req)); uwsgi_hooked_parse(buf, len, spooler_req_parser_hook, &sr); struct uwsgi_spooler *uspool = uwsgi.spoolers; if (!uspool) { uwsgi_log("[uwsgi-spooler] no spooler available\n"); return NULL; } // if it is a number, get the spooler by id instead of by name if (sr.spooler && sr.spooler_len) { uspool = uwsgi_get_spooler_by_name(sr.spooler, sr.spooler_len); if (!uspool) { uwsgi_log("[uwsgi-spooler] unable to find spooler \"%.*s\"\n", sr.spooler_len, sr.spooler); return NULL; } } // this lock is for threads, the pid value in filename will avoid multiprocess races uwsgi_lock(uspool->lock); // we increase it even if the request fails internal_counter++; gettimeofday(&tv, NULL); char *filename = NULL; size_t filename_len = 0; if (sr.priority && sr.priority_len) { filename_len = strlen(uspool->dir) + sr.priority_len + strlen(uwsgi.hostname) + 256; filename = uwsgi_malloc(filename_len); int ret = snprintf(filename, filename_len, "%s/%.*s", uspool->dir, (int) sr.priority_len, sr.priority); if (ret <= 0 || ret >= (int) filename_len) { uwsgi_log("[uwsgi-spooler] error generating spooler filename\n"); free(filename); uwsgi_unlock(uspool->lock); return NULL; } // no need to check for errors... (void) mkdir(filename, 0777); ret = snprintf(filename, filename_len, "%s/%.*s/uwsgi_spoolfile_on_%s_%d_%llu_%d_%llu_%llu", uspool->dir, (int)sr.priority_len, sr.priority, uwsgi.hostname, (int) getpid(), (unsigned long long) internal_counter, rand(), (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec); if (ret <= 0 || ret >=(int) filename_len) { uwsgi_log("[uwsgi-spooler] error generating spooler filename\n"); free(filename); uwsgi_unlock(uspool->lock); return NULL; } } else { filename_len = strlen(uspool->dir) + strlen(uwsgi.hostname) + 256; filename = uwsgi_malloc(filename_len); int ret = snprintf(filename, filename_len, "%s/uwsgi_spoolfile_on_%s_%d_%llu_%d_%llu_%llu", uspool->dir, uwsgi.hostname, (int) getpid(), (unsigned long long) internal_counter, rand(), (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec); if (ret <= 0 || ret >= (int) filename_len) { uwsgi_log("[uwsgi-spooler] error generating spooler filename\n"); free(filename); uwsgi_unlock(uspool->lock); return NULL; } } fd = open(filename, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR); if (fd < 0) { uwsgi_error_open(filename); free(filename); uwsgi_unlock(uspool->lock); return NULL; } // now lock the file, it will no be runnable, until the lock is not removed // a race could come if the spooler take the file before fcntl is called // in such case the spooler will detect a zeroed file and will retry later if (uwsgi_fcntl_lock(fd)) { close(fd); free(filename); uwsgi_unlock(uspool->lock); return NULL; } struct uwsgi_header uh; uh.modifier1 = 17; uh.modifier2 = 0; uh.pktsize = (uint16_t) len; #ifdef __BIG_ENDIAN__ uh.pktsize = uwsgi_swap16(uh.pktsize); #endif if (write(fd, &uh, 4) != 4) { uwsgi_log("[spooler] unable to write header for %s\n", filename); goto clear; } if (write(fd, buf, len) != (ssize_t) len) { uwsgi_log("[spooler] unable to write args for %s\n", filename); goto clear; } if (body && body_len > 0) { if ((size_t) write(fd, body, body_len) != body_len) { uwsgi_log("[spooler] unable to write body for %s\n", filename); goto clear; } } if (sr.at > 0) { #ifdef __UCLIBC__ struct timespec ts[2]; ts[0].tv_sec = sr.at; ts[0].tv_nsec = 0; ts[1].tv_sec = sr.at; ts[1].tv_nsec = 0; if (futimens(fd, ts)) { uwsgi_error("uwsgi_spooler_request()/futimens()"); } #else struct timeval tv[2]; tv[0].tv_sec = sr.at; tv[0].tv_usec = 0; tv[1].tv_sec = sr.at; tv[1].tv_usec = 0; #ifdef __sun__ if (futimesat(fd, NULL, tv)) { #else if (futimes(fd, tv)) { #endif uwsgi_error("uwsgi_spooler_request()/futimes()"); } #endif } // here the file will be unlocked too close(fd); if (!uwsgi.spooler_quiet) uwsgi_log("[spooler] written %lu bytes to file %s\n", (unsigned long) len + body_len + 4, filename); // and here waiting threads can continue uwsgi_unlock(uspool->lock); /* wake up the spoolers attached to the specified dir ... (HACKY) no need to fear races, as USR1 is harmless an all of the uWSGI processes... it could be a problem if a new process takes the old pid, but modern systems should avoid that */ struct uwsgi_spooler *spoolers = uwsgi.spoolers; while (spoolers) { if (!strcmp(spoolers->dir, uspool->dir)) { if (spoolers->pid > 0 && spoolers->running == 0) { (void) kill(spoolers->pid, SIGUSR1); } } spoolers = spoolers->next; } return filename; clear: uwsgi_unlock(uspool->lock); uwsgi_error("uwsgi_spool_request()/write()"); if (unlink(filename)) { uwsgi_error("uwsgi_spool_request()/unlink()"); } free(filename); // unlock the file too close(fd); return NULL; } void spooler(struct uwsgi_spooler *uspool) { // prevent process blindly reading stdin to make mess int nullfd; // asked by Marco Beri #ifdef __HAIKU__ #ifdef UWSGI_DEBUG uwsgi_log("lowering spooler priority to %d\n", B_LOW_PRIORITY); #endif set_thread_priority(find_thread(NULL), B_LOW_PRIORITY); #else #ifdef UWSGI_DEBUG uwsgi_log("lowering spooler priority to %d\n", PRIO_MAX); #endif setpriority(PRIO_PROCESS, getpid(), PRIO_MAX); #endif nullfd = open("/dev/null", O_RDONLY); if (nullfd < 0) { uwsgi_error_open("/dev/null"); exit(1); } if (nullfd != 0) { dup2(nullfd, 0); close(nullfd); } int spooler_event_queue = event_queue_init(); int interesting_fd = -1; if (uwsgi.master_process) { event_queue_add_fd_read(spooler_event_queue, uwsgi.shared->spooler_signal_pipe[1]); } // reset the tasks counter uspool->tasks = 0; for (;;) { if (chdir(uspool->dir)) { uwsgi_error("chdir()"); exit(1); } if (uwsgi.spooler_ordered) { #ifdef __linux__ spooler_scandir(uspool, NULL); #else spooler_readdir(uspool, NULL); #endif } else { spooler_readdir(uspool, NULL); } int timeout = uwsgi.shared->spooler_frequency ? uwsgi.shared->spooler_frequency : uwsgi.spooler_frequency; if (wakeup > 0) { timeout = 0; } if (event_queue_wait(spooler_event_queue, timeout, &interesting_fd) > 0) { if (uwsgi.master_process) { if (interesting_fd == uwsgi.shared->spooler_signal_pipe[1]) { uwsgi_receive_signal(interesting_fd, "spooler", (int) getpid()); } } } // avoid races uint64_t tmp_wakeup = wakeup; if (tmp_wakeup > 0) { tmp_wakeup--; } wakeup = tmp_wakeup; } }
int uwsgi_cache_request(struct wsgi_request *wsgi_req) { uint64_t vallen = 0; char *value; char *argv[3]; uint16_t argvs[3]; uint8_t argc = 0; switch(wsgi_req->uh.modifier2) { case 0: // get if (wsgi_req->uh.pktsize > 0) { value = uwsgi_cache_get(wsgi_req->buffer, wsgi_req->uh.pktsize, &vallen); if (value && vallen > 0) { wsgi_req->uh.pktsize = vallen; wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, (char *)&wsgi_req->uh, 4); wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, value, vallen); } } break; case 1: // set if (wsgi_req->uh.pktsize > 0) { argc = 3; if (!uwsgi_parse_array(wsgi_req->buffer, wsgi_req->uh.pktsize, argv, argvs, &argc)) { if (argc > 1) { uwsgi_cache_set(argv[0], argvs[0], argv[1], argvs[1], 0, 0); } } } break; case 2: // del if (wsgi_req->uh.pktsize > 0) { uwsgi_cache_del(wsgi_req->buffer, wsgi_req->uh.pktsize, 0); } break; case 3: case 4: // dict if (wsgi_req->uh.pktsize > 0) { uwsgi_hooked_parse(wsgi_req->buffer, wsgi_req->uh.pktsize, cache_command, (void *) wsgi_req); } break; case 5: // get (uwsgi + stream) if (wsgi_req->uh.pktsize > 0) { value = uwsgi_cache_get(wsgi_req->buffer, wsgi_req->uh.pktsize, &vallen); if (value && vallen > 0) { wsgi_req->uh.pktsize = 0; wsgi_req->uh.modifier2 = 1; wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, (char *)&wsgi_req->uh, 4); wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, value, vallen); } else { wsgi_req->uh.pktsize = 0; wsgi_req->uh.modifier2 = 0; wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, (char *)&wsgi_req->uh, 4); } } break; } return 0; }
int uwsgi_exceptions_catch(struct wsgi_request *wsgi_req) { if (uwsgi_response_prepare_headers(wsgi_req, "500 Internal Server Error", 25)) { return -1; } if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) { return -1; } struct uwsgi_buffer *ub = uwsgi_buffer_new(4096); if (uwsgi_buffer_append(ub, "uWSGI exceptions catcher for \"", 30)) goto error; if (uwsgi_buffer_append(ub, wsgi_req->method, wsgi_req->method_len)) goto error; if (uwsgi_buffer_append(ub, " ", 1)) goto error; if (uwsgi_buffer_append(ub, wsgi_req->uri, wsgi_req->uri_len)) goto error; if (uwsgi_buffer_append(ub, "\" (request plugin: \"", 20)) goto error; if (uwsgi_buffer_append(ub, (char *) uwsgi.p[wsgi_req->uh->modifier1]->name, strlen(uwsgi.p[wsgi_req->uh->modifier1]->name))) goto error; if (uwsgi_buffer_append(ub, "\", modifier1: ", 14 )) goto error; if (uwsgi_buffer_num64(ub, wsgi_req->uh->modifier1)) goto error; if (uwsgi_buffer_append(ub, ")\n\n", 3)) goto error; if (uwsgi_buffer_append(ub, "Exception: ", 11)) goto error; if (uwsgi.p[wsgi_req->uh->modifier1]->exception_repr) { struct uwsgi_buffer *ub_exc_repr = uwsgi.p[wsgi_req->uh->modifier1]->exception_repr(wsgi_req); if (ub_exc_repr) { if (uwsgi_buffer_append(ub, ub_exc_repr->buf, ub_exc_repr->pos)) { uwsgi_buffer_destroy(ub_exc_repr); goto error; } uwsgi_buffer_destroy(ub_exc_repr); } else { goto notavail3; } } else { notavail3: if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error; } if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error; if (uwsgi_buffer_append(ub, "Exception class: ", 17)) goto error; if (uwsgi.p[wsgi_req->uh->modifier1]->exception_class) { struct uwsgi_buffer *ub_exc_class = uwsgi.p[wsgi_req->uh->modifier1]->exception_class(wsgi_req); if (ub_exc_class) { if (uwsgi_buffer_append(ub, ub_exc_class->buf, ub_exc_class->pos)) { uwsgi_buffer_destroy(ub_exc_class); goto error; } uwsgi_buffer_destroy(ub_exc_class); } else { goto notavail; } } else { notavail: if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error; } if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error; if (uwsgi_buffer_append(ub, "Exception message: ", 19)) goto error; if (uwsgi.p[wsgi_req->uh->modifier1]->exception_msg) { struct uwsgi_buffer *ub_exc_msg = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req); if (ub_exc_msg) { if (uwsgi_buffer_append(ub, ub_exc_msg->buf, ub_exc_msg->pos)) { uwsgi_buffer_destroy(ub_exc_msg); goto error; } uwsgi_buffer_destroy(ub_exc_msg); } else { goto notavail2; } } else { notavail2: if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error; } if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error; if (uwsgi_buffer_append(ub, "Backtrace:\n", 11)) goto error; if (uwsgi.p[wsgi_req->uh->modifier1]->backtrace) { struct uwsgi_buffer *ub_exc_bt = uwsgi.p[wsgi_req->uh->modifier1]->backtrace(wsgi_req); if (ub_exc_bt) { struct uwsgi_buffer *parsed_bt = uwsgi_buffer_new(4096); if (uwsgi_hooked_parse_array(ub_exc_bt->buf, ub_exc_bt->pos, append_backtrace_to_ubuf, parsed_bt)) { uwsgi_buffer_destroy(ub_exc_bt); uwsgi_buffer_destroy(parsed_bt); goto error; } uwsgi_buffer_destroy(ub_exc_bt); if (uwsgi_buffer_append(ub, parsed_bt->buf, parsed_bt->pos)) { uwsgi_buffer_destroy(parsed_bt); goto error; } uwsgi_buffer_destroy(parsed_bt); } else { goto notavail4; } } else { notavail4: if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error; } if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error; if (uwsgi_hooked_parse(wsgi_req->buffer, wsgi_req->uh->pktsize, append_vars_to_ubuf, ub)) { goto error; } if (uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos)) { goto error; } uwsgi_buffer_destroy(ub); return 0; error: uwsgi_buffer_destroy(ub); return -1; }