static int uwsgi_hook_writefifo(char *arg) { char *space = strchr(arg, ' '); if (!space) { uwsgi_log("invalid hook writefifo syntax, must be: <file> <string>\n"); return -1; } *space = 0; int fd = open(arg, O_WRONLY|O_NONBLOCK); if (fd < 0) { uwsgi_error_open(arg); *space = ' '; if (errno == ENODEV) return 0; #ifdef ENXIO if (errno == ENXIO) return 0; #endif return -1; } *space = ' '; size_t l = strlen(space+1); if (write(fd, space+1, l) != (ssize_t) l) { uwsgi_error("uwsgi_hook_writefifo()/write()"); close(fd); return -1; } close(fd); return 0; }
static int uwsgi_hook_writen(char *arg) { char *space = strchr(arg, ' '); if (!space) { uwsgi_log("invalid hook writen syntax, must be: <file> <string>\n"); return -1; } *space = 0; int fd = open(arg, O_WRONLY|O_CREAT|O_TRUNC, 0666); if (fd < 0) { uwsgi_error_open(arg); *space = ' '; return -1; } *space = ' '; size_t l = strlen(space+1); char *buf = uwsgi_malloc(l + 1); memcpy(buf, space+1, l); buf[l] = '\n'; if (write(fd, buf, l+1) != (ssize_t) (l+1)) { uwsgi_error("uwsgi_hook_writen()/write()"); free(buf); close(fd); return -1; } free(buf); close(fd); return 0; }
int uwsgi_check_pidfile(char *filename) { struct stat st; pid_t ret = -1; int fd = open(filename, O_RDONLY); if (fd < 0) { uwsgi_error_open(filename); goto end; } if (fstat(fd, &st)) { uwsgi_error("fstat()"); goto end2; } char *pidstr = uwsgi_calloc(st.st_size + 1); if (read(fd, pidstr, st.st_size) != st.st_size) { uwsgi_error("read()"); goto end3; } pid_t pid = atoi(pidstr); if (pid <= 0) goto end3; if (!kill(pid, 0)) { ret = pid; } end3: free(pidstr); end2: close(fd); end: return ret; }
static int u_offload_sendfile_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) { if (!uor->name && uor->fd == -1) return -1; if (uor->name) { uor->fd = open(uor->name, O_RDONLY | O_NONBLOCK); if (uor->fd < 0) { uwsgi_error_open(uor->name); return -1; } } // make a fstat to get the file size if (!uor->len) { struct stat st; if (fstat(uor->fd, &st)) { uwsgi_error("u_offload_sendfile_prepare()/fstat()"); if (uor->name) { close(uor->fd); } return -1; } uor->len = st.st_size; } if (uor->fd2 == -1) { uor->fd2 = uor->s; } uor->s = -1; return 0; }
static int uwsgi_hook_creat(char *arg) { int fd = open(arg, O_WRONLY|O_CREAT|O_TRUNC, 0666); if (fd < 0) { uwsgi_error_open(arg); return -1; } close(fd); return 0; }
void uwsgi_python_hijack(void) { // the pyshell will be execute only in the first worker #ifndef UWSGI_PYPY FILE *pyfile; if (up.pyrun) { uwsgi.workers[uwsgi.mywid].hijacked = 1; UWSGI_GET_GIL; pyfile = fopen(up.pyrun, "r"); if (!pyfile) { uwsgi_error_open(up.pyrun); exit(1); } PyRun_SimpleFile(pyfile, up.pyrun); // could be never executed exit(0); } #endif if (up.pyshell_oneshot && uwsgi.workers[uwsgi.mywid].hijacked_count > 0) { uwsgi.workers[uwsgi.mywid].hijacked = 0; return; } if (up.pyshell && uwsgi.mywid == 1) { uwsgi.workers[uwsgi.mywid].hijacked = 1; uwsgi.workers[uwsgi.mywid].hijacked_count++; // re-map stdin to stdout and stderr if we are logging to a file if (uwsgi.logfile) { if (dup2(0, 1) < 0) { uwsgi_error("dup2()"); } if (dup2(0, 2) < 0) { uwsgi_error("dup2()"); } } UWSGI_GET_GIL; PyImport_ImportModule("readline"); #ifndef UWSGI_PYPY int ret = PyRun_InteractiveLoop(stdin, "uwsgi"); if (up.pyshell_oneshot) { exit(UWSGI_DE_HIJACKED_CODE); } if (ret == 0) { exit(UWSGI_QUIET_CODE); } #endif exit(0); } }
int event_queue_add_file_monitor(int eq, char *filename, int *id) { struct kevent kev; int fd = open(filename, O_RDONLY); if (fd < 0) { uwsgi_error_open(filename); return -1; } EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD|EV_CLEAR, NOTE_WRITE|NOTE_DELETE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_RENAME|NOTE_REVOKE, 0, 0); if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) { uwsgi_error("kevent()"); return -1; } *id = fd; uwsgi_log("added new file to monitor %s\n", filename); return fd; }
static int uwsgi_hook_append(char *arg) { char *space = strchr(arg, ' '); if (!space) { uwsgi_log("invalid hook append syntax, must be: <file> <string>\n"); return -1; } *space = 0; int fd = open(arg, O_WRONLY|O_CREAT|O_APPEND, 0666); if (fd < 0) { uwsgi_error_open(arg); *space = ' '; return -1; } *space = ' '; size_t l = strlen(space+1); if (write(fd, space+1, l) != (ssize_t) l) { uwsgi_error("uwsgi_hook_append()/write()"); close(fd); return -1; } close(fd); return 0; }
// simply read the whole content of a file char *uwsgi_simple_file_read(char *filename) { struct stat sb; char *buffer; ssize_t len; int fd = open(filename, O_RDONLY); if (fd < 0) { uwsgi_error_open(filename); goto end; } if (fstat(fd, &sb)) { uwsgi_error("fstat()"); close(fd); goto end; } buffer = uwsgi_malloc(sb.st_size + 1); len = read(fd, buffer, sb.st_size); if (len != sb.st_size) { uwsgi_error("read()"); free(buffer); close(fd); goto end; } close(fd); if (buffer[sb.st_size - 1] == '\n' || buffer[sb.st_size - 1] == '\r') { buffer[sb.st_size - 1] = 0; } buffer[sb.st_size] = 0; return buffer; end: return (char *) ""; }
void uwsgi_stats_pusher_file(struct uwsgi_stats_pusher_instance *uspi, char *json, size_t json_len) { struct uwsgi_stats_pusher_file_conf *uspic = (struct uwsgi_stats_pusher_file_conf *) uspi->data; if (!uspi->configured) { uspic = uwsgi_calloc(sizeof(struct uwsgi_stats_pusher_file_conf)); if (uspi->arg) { if (uwsgi_kvlist_parse(uspi->arg, strlen(uspi->arg), ',', '=', "path", &uspic->path, "separator", &uspic->separator, "freq", &uspic->freq, NULL)) { free(uspi); return; } } if (!uspic->path) uspic->path = "uwsgi.stats"; if (!uspic->separator) uspic->separator = "\n\n"; if (uspic->freq) uspi->freq = atoi(uspic->freq); uspi->configured = 1; uspi->data = uspic; } int fd = open(uspic->path, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP); if (fd < 0) { uwsgi_error_open(uspic->path); return; } ssize_t rlen = write(fd, json, json_len); if (rlen != (ssize_t) json_len) { uwsgi_error("uwsgi_stats_pusher_file() -> write()\n"); } rlen = write(fd, uspic->separator, strlen(uspic->separator)); if (rlen != (ssize_t) strlen(uspic->separator)) { uwsgi_error("uwsgi_stats_pusher_file() -> write()\n"); } close(fd); }
static int uwsgi_hook_appendn(char *arg) { char *space = strchr(arg, ' '); if (space) *space = 0; int fd = open(arg, O_WRONLY|O_CREAT|O_APPEND, 0666); if (fd < 0) { uwsgi_error_open(arg); if (space) *space = ' '; return -1; } if (!space) { // simple newline if (write(fd, "\n", 1) != 1) { uwsgi_error("uwsgi_hook_appendn()/write()"); close(fd); return -1; } close(fd); return 0; } *space = ' '; size_t l = strlen(space+1); char *buf = uwsgi_malloc(l + 1); memcpy(buf, space+1, l); buf[l] = '\n'; if (write(fd, buf, l+1) != (ssize_t) (l+1)) { uwsgi_error("uwsgi_hook_appendn()/write()"); free(buf); close(fd); return -1; } free(buf); close(fd); return 0; }
void uwsgi_bind_sockets() { socklen_t socket_type_len; union uwsgi_sockaddr usa; union uwsgi_sockaddr_ptr gsa; struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (!uwsgi_sock->bound && !uwsgi_socket_is_already_bound(uwsgi_sock->name)) { char *tcp_port = strrchr(uwsgi_sock->name, ':'); if (tcp_port == NULL) { uwsgi_sock->fd = bind_to_unix(uwsgi_sock->name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); uwsgi_sock->family = AF_UNIX; if (uwsgi.chown_socket) { uwsgi_chown(uwsgi_sock->name, uwsgi.chown_socket); } uwsgi_log("uwsgi socket %d bound to UNIX address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); } else { #ifdef UWSGI_IPV6 if (uwsgi_sock->name[0] == '[' && tcp_port[-1] == ']') { uwsgi_sock->fd = bind_to_tcp6(uwsgi_sock->name, uwsgi.listen_queue, tcp_port); uwsgi_log("uwsgi socket %d bound to TCP6 address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); uwsgi_sock->family = AF_INET6; } else { #endif uwsgi_sock->fd = bind_to_tcp(uwsgi_sock->name, uwsgi.listen_queue, tcp_port); uwsgi_log("uwsgi socket %d bound to TCP address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); uwsgi_sock->family = AF_INET; #ifdef UWSGI_IPV6 } #endif } if (uwsgi_sock->fd < 0 && !uwsgi_sock->per_core) { uwsgi_log("unable to create server socket on: %s\n", uwsgi_sock->name); exit(1); } } uwsgi_sock->bound = 1; uwsgi_sock = uwsgi_sock->next; } if (uwsgi.chown_socket) { if (!uwsgi.master_as_root) { uwsgi_as_root(); } } int zero_used = 0; uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->bound && uwsgi_sock->fd == 0) { zero_used = 1; break; } uwsgi_sock = uwsgi_sock->next; } if (!zero_used) { socket_type_len = sizeof(struct sockaddr_un); gsa.sa = (struct sockaddr *) &usa; if (!uwsgi.skip_zero && !getsockname(0, gsa.sa, &socket_type_len)) { if (gsa.sa->sa_family == AF_UNIX) { uwsgi_sock = uwsgi_new_socket(uwsgi_getsockname(0)); uwsgi_sock->family = AF_UNIX; uwsgi_sock->fd = 0; uwsgi_sock->bound = 1; uwsgi_log("uwsgi socket %d inherited UNIX address %s fd 0\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name); } else { uwsgi_sock = uwsgi_new_socket(uwsgi_getsockname(0)); uwsgi_sock->family = AF_INET; uwsgi_sock->fd = 0; uwsgi_sock->bound = 1; uwsgi_log("uwsgi socket %d inherited INET address %s fd 0\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name); } } else if (!uwsgi.honour_stdin) { int fd = open("/dev/null", O_RDONLY); if (fd < 0) { uwsgi_error_open("/dev/null"); exit(1); } if (fd != 0) { if (dup2(fd, 0) < 0) { uwsgi_error("dup2()"); exit(1); } close(fd); } } else if (uwsgi.honour_stdin) { if (!tcgetattr(0, &uwsgi.termios)) { uwsgi.restore_tc = 1; } } } // check for auto_port socket uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->auto_port) { #ifdef UWSGI_IPV6 if (uwsgi_sock->family == AF_INET6) { uwsgi_log("uwsgi socket %d bound to TCP6 address %s (port auto-assigned) fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); } else { #endif uwsgi_log("uwsgi socket %d bound to TCP address %s (port auto-assigned) fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); #ifdef UWSGI_IPV6 } #endif } uwsgi_sock = uwsgi_sock->next; } }
void uwsgi_map_sockets() { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { struct uwsgi_string_list *usl = uwsgi.map_socket; int enabled = 1; while (usl) { char *colon = strchr(usl->value, ':'); if (!colon) { uwsgi_log("invalid socket mapping, must be socket:worker[,worker...]\n"); exit(1); } if ((int) uwsgi_str_num(usl->value, colon - usl->value) == uwsgi_get_socket_num(uwsgi_sock)) { enabled = 0; char *p = strtok(colon + 1, ","); while (p != NULL) { int w = atoi(p); if (w < 1 || w > uwsgi.numproc) { uwsgi_log("invalid worker num: %d\n", w); exit(1); } if (w == uwsgi.mywid) { enabled = 1; uwsgi_log("mapped socket %d (%s) to worker %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi.mywid); break; } p = strtok(NULL, ","); } } usl = usl->next; } if (!enabled) { close(uwsgi_sock->fd); int fd = open("/dev/null", O_RDONLY); if (fd < 0) { uwsgi_error_open("/dev/null"); exit(1); } if (fd != uwsgi_sock->fd) { if (dup2(fd, uwsgi_sock->fd) < 0) { uwsgi_error("dup2()"); exit(1); } close(fd); } uwsgi_sock->disabled = 1; } uwsgi_sock = uwsgi_sock->next; } uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->disabled) { uwsgi_sock = uwsgi_del_socket(uwsgi_sock); } else { uwsgi_sock = uwsgi_sock->next; } } }
/* 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; } }
/* extremely complex function for reading resources (files, url...) need a lot of refactoring... */ char *uwsgi_open_and_read(char *url, size_t *size, int add_zero, char *magic_table[]) { int fd; struct stat sb; char *buffer = NULL; char byte; ssize_t len; char *uri, *colon; char *domain; char *ip; int body = 0; char *magic_buf; // stdin ? if (!strcmp(url, "-")) { buffer = uwsgi_read_fd(0, size, add_zero); } // fd ? else if (!strncmp("fd://", url, 5)) { fd = atoi(url + 5); buffer = uwsgi_read_fd(fd, size, add_zero); } // exec ? else if (!strncmp("exec://", url, 5)) { int cpipe[2]; if (pipe(cpipe)) { uwsgi_error("pipe()"); exit(1); } uwsgi_run_command(url + 7, NULL, cpipe[1]); buffer = uwsgi_read_fd(cpipe[0], size, add_zero); close(cpipe[0]); close(cpipe[1]); } // http url ? else if (!strncmp("http://", url, 7)) { domain = url + 7; uri = strchr(domain, '/'); if (!uri) { uwsgi_log("invalid http url\n"); exit(1); } uri[0] = 0; uwsgi_log("domain: %s\n", domain); colon = uwsgi_get_last_char(domain, ':'); if (colon) { colon[0] = 0; } ip = uwsgi_resolve_ip(domain); if (!ip) { uwsgi_log("unable to resolve address %s\n", domain); exit(1); } if (colon) { colon[0] = ':'; ip = uwsgi_concat2(ip, colon); } else { ip = uwsgi_concat2(ip, ":80"); } fd = uwsgi_connect(ip, 0, 0); if (fd < 0) { exit(1); } free(ip); uri[0] = '/'; len = write(fd, "GET ", 4); len = write(fd, uri, strlen(uri)); len = write(fd, " HTTP/1.0\r\n", 11); len = write(fd, "Host: ", 6); uri[0] = 0; len = write(fd, domain, strlen(domain)); uri[0] = '/'; len = write(fd, "\r\nUser-Agent: uWSGI on ", 23); len = write(fd, uwsgi.hostname, uwsgi.hostname_len); len = write(fd, "\r\n\r\n", 4); int http_status_code_ptr = 0; while (read(fd, &byte, 1) == 1) { if (byte == '\r' && body == 0) { body = 1; } else if (byte == '\n' && body == 1) { body = 2; } else if (byte == '\r' && body == 2) { body = 3; } else if (byte == '\n' && body == 3) { body = 4; } else if (body == 4) { *size = *size + 1; char *tmp = realloc(buffer, *size); if (!tmp) { uwsgi_error("uwsgi_open_and_read()/realloc()"); exit(1); } buffer = tmp; buffer[*size - 1] = byte; } else { body = 0; http_status_code_ptr++; if (http_status_code_ptr == 10) { if (byte != '2') { uwsgi_log("Not usable HTTP response: %cxx\n", byte); if (uwsgi.has_emperor) { exit(UWSGI_EXILE_CODE); } else { exit(1); } } } } } close(fd); if (add_zero) { *size = *size + 1; char *tmp = realloc(buffer, *size); if (!tmp) { uwsgi_error("uwsgi_open_and_read()/realloc()"); exit(1); } buffer = tmp; buffer[*size - 1] = 0; } } else if (!strncmp("emperor://", url, 10)) { if (uwsgi.emperor_fd_config < 0) { uwsgi_log("this is not a vassal instance\n"); exit(1); } ssize_t rlen; *size = 0; struct uwsgi_header uh; size_t remains = 4; char *ptr = (char *) &uh; while(remains) { int ret = uwsgi_waitfd(uwsgi.emperor_fd_config, 5); if (ret <= 0) { uwsgi_log("[uwsgi-vassal] error waiting for config header %s !!!\n", url); exit(1); } rlen = read(uwsgi.emperor_fd_config, ptr, remains); if (rlen <= 0) { uwsgi_log("[uwsgi-vassal] error reading config header from !!!\n", url); exit(1); } ptr+=rlen; remains-=rlen; } remains = uh.pktsize; if (!remains) { uwsgi_log("[uwsgi-vassal] invalid config from %s\n", url); exit(1); } buffer = uwsgi_calloc(remains + add_zero); ptr = buffer; while (remains) { int ret = uwsgi_waitfd(uwsgi.emperor_fd_config, 5); if (ret <= 0) { uwsgi_log("[uwsgi-vassal] error waiting for config %s !!!\n", url); exit(1); } rlen = read(uwsgi.emperor_fd_config, ptr, remains); if (rlen <= 0) { uwsgi_log("[uwsgi-vassal] error reading config from !!!\n", url); exit(1); } ptr+=rlen; remains-=rlen; } *size = uh.pktsize + add_zero; } #ifdef UWSGI_EMBED_CONFIG else if (url[0] == 0) { *size = &UWSGI_EMBED_CONFIG_END - &UWSGI_EMBED_CONFIG; if (add_zero) { *size += 1; } buffer = uwsgi_malloc(*size); memset(buffer, 0, *size); memcpy(buffer, &UWSGI_EMBED_CONFIG, &UWSGI_EMBED_CONFIG_END - &UWSGI_EMBED_CONFIG); } #endif else if (!strncmp("data://", url, 7)) { fd = open(uwsgi.binary_path, O_RDONLY); if (fd < 0) { uwsgi_error_open(uwsgi.binary_path); exit(1); } int slot = atoi(url + 7); if (slot < 0) { uwsgi_log("invalid binary data slot requested\n"); exit(1); } uwsgi_log("requesting binary data slot %d\n", slot); off_t fo = lseek(fd, 0, SEEK_END); if (fo < 0) { uwsgi_error("lseek()"); uwsgi_log("invalid binary data slot requested\n"); exit(1); } int i = 0; uint64_t datasize = 0; for (i = 0; i <= slot; i++) { fo = lseek(fd, -9, SEEK_CUR); if (fo < 0) { uwsgi_error("lseek()"); uwsgi_log("invalid binary data slot requested\n"); exit(1); } ssize_t len = read(fd, &datasize, 8); if (len != 8) { uwsgi_error("read()"); uwsgi_log("invalid binary data slot requested\n"); exit(1); } if (datasize == 0) { uwsgi_log("0 size binary data !!!\n"); exit(1); } fo = lseek(fd, -(datasize + 9), SEEK_CUR); if (fo < 0) { uwsgi_error("lseek()"); uwsgi_log("invalid binary data slot requested\n"); exit(1); } if (i == slot) { *size = datasize; if (add_zero) { *size += 1; } buffer = uwsgi_malloc(*size); memset(buffer, 0, *size); len = read(fd, buffer, datasize); if (len != (ssize_t) datasize) { uwsgi_error("read()"); uwsgi_log("invalid binary data slot requested\n"); exit(1); } } } } else if (!strncmp("sym://", url, 6)) { char *symbol = uwsgi_concat3("_binary_", url + 6, "_start"); void *sym_start_ptr = dlsym(RTLD_DEFAULT, symbol); if (!sym_start_ptr) { uwsgi_log("unable to find symbol %s\n", symbol); exit(1); } free(symbol); symbol = uwsgi_concat3("_binary_", url + 6, "_end"); void *sym_end_ptr = dlsym(RTLD_DEFAULT, symbol); if (!sym_end_ptr) { uwsgi_log("unable to find symbol %s\n", symbol); exit(1); } free(symbol); *size = sym_end_ptr - sym_start_ptr; if (add_zero) { *size += 1; } buffer = uwsgi_malloc(*size); memset(buffer, 0, *size); memcpy(buffer, sym_start_ptr, sym_end_ptr - sym_start_ptr); } #ifdef UWSGI_ELF else if (!strncmp("section://", url, 10)) { size_t s_len = 0; buffer = uwsgi_elf_section(uwsgi.binary_path, url + 10, &s_len); if (!buffer) { uwsgi_log("unable to find section %s in %s\n", url + 10, uwsgi.binary_path); exit(1); } *size = s_len; if (add_zero) *size += 1; } #endif // fallback to file else { fd = open(url, O_RDONLY); if (fd < 0) { uwsgi_error_open(url); exit(1); } if (fstat(fd, &sb)) { uwsgi_error("fstat()"); exit(1); } if (S_ISFIFO(sb.st_mode)) { buffer = uwsgi_read_fd(fd, size, add_zero); close(fd); goto end; } buffer = uwsgi_malloc(sb.st_size + add_zero); len = read(fd, buffer, sb.st_size); if (len != sb.st_size) { uwsgi_error("read()"); exit(1); } close(fd); *size = sb.st_size + add_zero; if (add_zero) buffer[sb.st_size] = 0; } end: if (magic_table) { magic_buf = magic_sub(buffer, *size, size, magic_table); free(buffer); return magic_buf; } return buffer; }
char *uwsgi_upload_progress_create(struct wsgi_request *wsgi_req, int *fd) { const char *x_progress_id = "X-Progress-ID="; char *xpi_ptr = (char *) x_progress_id; uint16_t i; char *upload_progress_filename = NULL; if (wsgi_req->uri_len <= 51) return NULL; for (i = 0; i < wsgi_req->uri_len; i++) { if (wsgi_req->uri[i] == xpi_ptr[0]) { if (xpi_ptr[0] == '=') { if (wsgi_req->uri + i + 36 <= wsgi_req->uri + wsgi_req->uri_len) { upload_progress_filename = wsgi_req->uri + i + 1; } break; } xpi_ptr++; } else { xpi_ptr = (char *) x_progress_id; } } // now check for valid uuid (from spec available at http://en.wikipedia.org/wiki/Universally_unique_identifier) if (!upload_progress_filename) return NULL; uwsgi_log("upload progress uuid = %.*s\n", 36, upload_progress_filename); if (!check_hex(upload_progress_filename, 8)) return NULL; if (upload_progress_filename[8] != '-') return NULL; if (!check_hex(upload_progress_filename + 9, 4)) return NULL; if (upload_progress_filename[13] != '-') return NULL; if (!check_hex(upload_progress_filename + 14, 4)) return NULL; if (upload_progress_filename[18] != '-') return NULL; if (!check_hex(upload_progress_filename + 19, 4)) return NULL; if (upload_progress_filename[23] != '-') return NULL; if (!check_hex(upload_progress_filename + 24, 12)) return NULL; upload_progress_filename = uwsgi_concat4n(uwsgi.upload_progress, strlen(uwsgi.upload_progress), "/", 1, upload_progress_filename, 36, ".js", 3); // here we use O_EXCL to avoid eventual application bug in uuid generation/using *fd = open(upload_progress_filename, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP); if (*fd < 0) { uwsgi_error_open(upload_progress_filename); free(upload_progress_filename); return NULL; } return upload_progress_filename; }
static int uwsgi_mongrel2_json_parse(json_t * root, struct wsgi_request *wsgi_req) { char *json_val; char *query_string = NULL; size_t query_string_len = 0; size_t script_name_len = 0; void *json_iter; char *json_key; json_t *json_value; if ((json_val = uwsgi_mongrel2_json_get_string(root, "METHOD"))) { if (!strcmp(json_val, "JSON")) { return -1; } wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_METHOD", 14, json_val, strlen(json_val)); } // pretty easy, we get the file and we map it to wsgi_req->post_file, uWSGI read api will automatically use this if ((json_val = uwsgi_mongrel2_json_get_string(root, "x-mongrel2-upload-done"))) { wsgi_req->post_file = fopen(json_val, "r"); if (!wsgi_req->post_file) { uwsgi_error_open(json_val); return -1; } } else if (uwsgi_mongrel2_json_get_string(root, "x-mongrel2-upload-start")) { return -1; } wsgi_req->uh->pktsize += uwsgi_mongrel2_json_add(wsgi_req, root, "VERSION", "SERVER_PROTOCOL", 15, NULL, NULL); wsgi_req->uh->pktsize += uwsgi_mongrel2_json_add(wsgi_req, root, "QUERY", "QUERY_STRING", 12, &query_string, &query_string_len); if (query_string == NULL) { // always set QUERY_STRING wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, "", 0); } // set SCRIPT_NAME to an empty value wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SCRIPT_NAME", 11, "", 0); if ((json_val = uwsgi_mongrel2_json_get_string(root, "PATH"))) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "PATH_INFO", 9, json_val + script_name_len, strlen(json_val + script_name_len)); if (query_string_len) { char *request_uri = uwsgi_concat3n(json_val, strlen(json_val), "?", 1, query_string, query_string_len); wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, request_uri, strlen(json_val) + 1 + query_string_len); free(request_uri); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, json_val, strlen(json_val)); } } if ((json_val = uwsgi_mongrel2_json_get_string(root, "URL_SCHEME"))) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "UWSGI_SCHEME", 12, json_val, strlen(json_val)); } if ((json_val = uwsgi_mongrel2_json_get_string(root, "host"))) { char *colon = strchr(json_val, ':'); if (colon) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, colon + 1, strlen(colon + 1)); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, "80", 2); } } if ((json_val = uwsgi_mongrel2_json_get_string(root, "x-forwarded-for"))) { char *colon = strchr(json_val, ','); if (colon) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, colon + 1, (colon + 1) - json_val); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, json_val, strlen(json_val)); } } if ((json_val = uwsgi_mongrel2_json_get_string(root, "content-length"))) { wsgi_req->post_cl = atoi(json_val); } wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len); json_iter = json_object_iter(root); while (json_iter) { json_key = (char *) json_object_iter_key(json_iter); // is it a header ? if (json_key[0] >= 97) { json_value = json_object_iter_value(json_iter); if (json_is_string(json_value)) { json_val = (char *) json_string_value(json_value); wsgi_req->uh->pktsize += proto_base_add_uwsgi_header(wsgi_req, json_key, strlen(json_key), json_val, strlen(json_val)); } } json_iter = json_object_iter_next(root, json_iter); } return 0; }
int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core_id, char *buffer, int size, char *priority, time_t at, char *body, size_t body_len) { struct timeval tv; int fd; struct uwsgi_header uh; if (!uspool) { uspool = uwsgi.spoolers; } // this lock is for threads, the pid value in filename will avoid multiprocess races uwsgi_lock(uspool->lock); gettimeofday(&tv, NULL); if (priority) { if (snprintf(filename, 1024, "%s/%s", uspool->dir, priority) <= 0) { uwsgi_unlock(uspool->lock); return 0; } // no need to check for errors... (void) mkdir(filename, 0777); if (snprintf(filename, 1024, "%s/%s/uwsgi_spoolfile_on_%s_%d_%d_%d_%llu_%llu", uspool->dir, priority, uwsgi.hostname, (int) getpid(), rn, core_id, (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec) <= 0) { uwsgi_unlock(uspool->lock); return 0; } } else { if (snprintf(filename, 1024, "%s/uwsgi_spoolfile_on_%s_%d_%d_%d_%llu_%llu", uspool->dir, uwsgi.hostname, (int) getpid(), rn, core_id, (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec) <= 0) { uwsgi_unlock(uspool->lock); return 0; } } fd = open(filename, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR); if (fd < 0) { uwsgi_error_open(filename); uwsgi_unlock(uspool->lock); return 0; } // 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); uwsgi_unlock(uspool->lock); return 0; } uh.modifier1 = 17; uh.modifier2 = 0; uh.pktsize = (uint16_t) size; #ifdef __BIG_ENDIAN__ uh.pktsize = uwsgi_swap16(uh.pktsize); #endif if (write(fd, &uh, 4) != 4) { goto clear; } if (write(fd, buffer, size) != size) { goto clear; } if (body && body_len > 0) { if ((size_t)write(fd, body, body_len) != body_len) { goto clear; } } if (at > 0) { struct timeval tv[2]; tv[0].tv_sec = at; tv[0].tv_usec = 0; tv[1].tv_sec = at; tv[1].tv_usec = 0; #ifdef __sun__ if (futimesat(fd, NULL, tv)) { #else if (futimes(fd, tv)) { #endif uwsgi_error("futimes()"); } } // here the file will be unlocked too close(fd); if (!uwsgi.spooler_quiet) uwsgi_log("[spooler] written %d bytes to file %s\n", size + 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 1; clear: uwsgi_unlock(uspool->lock); uwsgi_error("write()"); if (unlink(filename)) { uwsgi_error("unlink()"); } // unlock the file too close(fd); return 0; } 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; 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; // need to recycle ? if (uwsgi.spooler_max_tasks > 0 && uspool->tasks >= (uint64_t)uwsgi.spooler_max_tasks) { uwsgi_log("[spooler %s pid: %d] maximum number of tasks reached (%d) recycling ...\n", uspool->dir, (int) uwsgi.mypid, uwsgi.spooler_max_tasks); end_me(0); } } }
void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) { int i, ret; char spool_buf[0xffff]; struct uwsgi_header uh; char *body = NULL; size_t body_len = 0; int spool_fd; if (!dir) dir = uspool->dir; if (!strncmp("uwsgi_spoolfile_on_", task, 19) || (uwsgi.spooler_ordered && is_a_number(task))) { struct stat sf_lstat; if (lstat(task, &sf_lstat)) { return; } // a spool request for the future if (sf_lstat.st_mtime > uwsgi_now()) { return; } #ifdef __linux__ if (S_ISDIR(sf_lstat.st_mode) && uwsgi.spooler_ordered) { if (chdir(task)) { uwsgi_error("chdir()"); return; } char *prio_path = realpath(".", NULL); spooler_scandir(uspool, prio_path); free(prio_path); if (chdir(dir)) { uwsgi_error("chdir()"); } return; } #endif if (!S_ISREG(sf_lstat.st_mode)) { return; } if (!access(task, R_OK | W_OK)) { spool_fd = open(task, O_RDWR); if (spool_fd < 0) { if (errno != ENOENT) uwsgi_error_open(task); return; } // check if the file is locked by another process if (uwsgi_fcntl_is_locked(spool_fd)) { uwsgi_protected_close(spool_fd); return; } // unlink() can destroy the lock !!! if (access(task, R_OK | W_OK)) { uwsgi_protected_close(spool_fd); return; } ssize_t rlen = uwsgi_protected_read(spool_fd, &uh, 4); if (rlen != 4) { // it could be here for broken file or just opened one if (rlen < 0) uwsgi_error("read()"); uwsgi_protected_close(spool_fd); return; } #ifdef __BIG_ENDIAN__ uh.pktsize = uwsgi_swap16(uh.pktsize); #endif if (uwsgi_protected_read(spool_fd, spool_buf, uh.pktsize) != uh.pktsize) { uwsgi_error("read()"); destroy_spool(dir, task); uwsgi_protected_close(spool_fd); return; } // body available ? if (sf_lstat.st_size > (uh.pktsize+4)) { body_len = sf_lstat.st_size - (uh.pktsize+4); body = uwsgi_malloc(body_len); if ((size_t)uwsgi_protected_read(spool_fd, body, body_len) != body_len) { uwsgi_error("read()"); destroy_spool(dir, task); uwsgi_protected_close(spool_fd); free(body); return; } } // now the task is running and should not be waken up uspool->running = 1; if (!uwsgi.spooler_quiet) uwsgi_log("[spooler %s pid: %d] managing request %s ...\n", uspool->dir, (int) uwsgi.mypid, task); // chdir before running the task (if requested) if (uwsgi.spooler_chdir) { if (chdir(uwsgi.spooler_chdir)) { uwsgi_error("chdir()"); } } int callable_found = 0; for(i=0; i<256; i++) { if (uwsgi.p[i]->spooler) { time_t now = uwsgi_now(); if(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) { set_spooler_harakiri(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI]); } ret = uwsgi.p[i]->spooler(task, spool_buf, uh.pktsize, body, body_len); if(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) { set_spooler_harakiri(0); } if (ret == 0) continue; callable_found = 1; // increase task counter uspool->tasks++; if (ret == -2) { if (!uwsgi.spooler_quiet) uwsgi_log("[spooler %s pid: %d] done with task %s after %d seconds\n", uspool->dir, (int) uwsgi.mypid, task, uwsgi_now()-now); destroy_spool(dir, task); } // re-spool it break; } } if (body) free(body); // here we free and unlock the task uwsgi_protected_close(spool_fd); uspool->running = 0; if (chdir(dir)) { uwsgi_error("chdir()"); uwsgi_log("[spooler] something horrible happened to the spooler. Better to kill it.\n"); exit(1); } if (!callable_found) { uwsgi_log("unable to find the spooler function, have you loaded it into the spooler process ?\n"); } } } }
void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) { int i, ret; char spool_buf[0xffff]; struct uwsgi_header uh; char *body = NULL; size_t body_len = 0; int spool_fd; if (!dir) dir = uspool->dir; if (!strncmp("uwsgi_spoolfile_on_", task, 19) || (uwsgi.spooler_ordered && is_a_number(task))) { struct stat sf_lstat; if (lstat(task, &sf_lstat)) { return; } // a spool request for the future if (sf_lstat.st_mtime > uwsgi_now()) { return; } if (S_ISDIR(sf_lstat.st_mode) && uwsgi.spooler_ordered) { if (chdir(task)) { uwsgi_error("spooler_manage_task()/chdir()"); return; } #ifdef __UCLIBC__ char *prio_path = uwsgi_malloc(PATH_MAX); realpath(".", prio_path); #else char *prio_path = realpath(".", NULL); #endif spooler_scandir(uspool, prio_path); free(prio_path); if (chdir(dir)) { uwsgi_error("spooler_manage_task()/chdir()"); } return; } if (!S_ISREG(sf_lstat.st_mode)) { return; } if (!access(task, R_OK | W_OK)) { spool_fd = open(task, O_RDWR); if (spool_fd < 0) { if (errno != ENOENT) uwsgi_error_open(task); return; } if (uwsgi_spooler_read_header(task, spool_fd, &uh)) return; // access lstat second time after getting a lock // first-time lstat could be dirty (for example between writes in master) if (lstat(task, &sf_lstat)) { return; } if (uwsgi_spooler_read_content(spool_fd, spool_buf, &body, &body_len, &uh, &sf_lstat)) { destroy_spool(dir, task); return; } // now the task is running and should not be woken up uspool->running = 1; // this is used in cheap mode for making decision about who must die uspool->last_task_managed = uwsgi_now(); if (!uwsgi.spooler_quiet) uwsgi_log("[spooler %s pid: %d] managing request %s ...\n", uspool->dir, (int) uwsgi.mypid, task); // chdir before running the task (if requested) if (uwsgi.spooler_chdir) { if (chdir(uwsgi.spooler_chdir)) { uwsgi_error("spooler_manage_task()/chdir()"); } } int callable_found = 0; for (i = 0; i < 256; i++) { if (uwsgi.p[i]->spooler) { time_t now = uwsgi_now(); if (uwsgi.harakiri_options.spoolers > 0) { set_spooler_harakiri(uwsgi.harakiri_options.spoolers); } ret = uwsgi.p[i]->spooler(task, spool_buf, uh._pktsize, body, body_len); if (uwsgi.harakiri_options.spoolers > 0) { set_spooler_harakiri(0); } if (ret == 0) continue; callable_found = 1; // increase task counter uspool->tasks++; if (ret == -2) { if (!uwsgi.spooler_quiet) uwsgi_log("[spooler %s pid: %d] done with task %s after %lld seconds\n", uspool->dir, (int) uwsgi.mypid, task, (long long) uwsgi_now() - now); destroy_spool(dir, task); } // re-spool it break; } } if (body) free(body); // here we free and unlock the task uwsgi_protected_close(spool_fd); uspool->running = 0; // need to recycle ? if (uwsgi.spooler_max_tasks > 0 && uspool->tasks >= (uint64_t) uwsgi.spooler_max_tasks) { uwsgi_log("[spooler %s pid: %d] maximum number of tasks reached (%d) recycling ...\n", uspool->dir, (int) uwsgi.mypid, uwsgi.spooler_max_tasks); end_me(0); } if (chdir(dir)) { uwsgi_error("chdir()"); uwsgi_log("[spooler] something horrible happened to the spooler. Better to kill it.\n"); exit(1); } if (!callable_found) { uwsgi_log("unable to find the spooler function, have you loaded it into the spooler process ?\n"); } } } }
int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, PerlInterpreter **interpreters) { struct stat st; int i; SV **callables; time_t now = uwsgi_now(); char *app_name = uwsgi_concat2n(app, app_len, "", 0); // prepare for $0 uperl.embedding[1] = app_name; int fd = open(app_name, O_RDONLY); if (fd < 0) { uwsgi_error_open(app_name); goto clear2; } if (fstat(fd, &st)) { uwsgi_error("fstat()"); close(fd); goto clear2; } char *buf = uwsgi_calloc(st.st_size+1); if (read(fd, buf, st.st_size) != st.st_size) { uwsgi_error("read()"); close(fd); free(buf); goto clear2; } close(fd); // the first (default) app, should always be loaded in the main interpreter if (interpreters == NULL) { if (uwsgi_apps_cnt) { interpreters = uwsgi_calloc(sizeof(PerlInterpreter *) * uwsgi.threads); interpreters[0] = uwsgi_perl_new_interpreter(); if (!interpreters[0]) { uwsgi_log("unable to create new perl interpreter\n"); free(interpreters); goto clear2; } } else { interpreters = uperl.main; } } if (!interpreters) { goto clear2; } callables = uwsgi_calloc(sizeof(SV *) * uwsgi.threads); uperl.tmp_streaming_stash = uwsgi_calloc(sizeof(HV *) * uwsgi.threads); uperl.tmp_input_stash = uwsgi_calloc(sizeof(HV *) * uwsgi.threads); uperl.tmp_error_stash = uwsgi_calloc(sizeof(HV *) * uwsgi.threads); uperl.tmp_stream_responder = uwsgi_calloc(sizeof(CV *) * uwsgi.threads); uperl.tmp_psgix_logger = uwsgi_calloc(sizeof(CV *) * uwsgi.threads); for(i=0;i<uwsgi.threads;i++) { if (i > 0 && interpreters != uperl.main) { interpreters[i] = uwsgi_perl_new_interpreter(); if (!interpreters[i]) { uwsgi_log("unable to create new perl interpreter\n"); // what to do here ? i hope no-one will use threads with dynamic apps...but clear the whole stuff... free(callables); uwsgi_perl_free_stashes(); while(i>=0) { perl_destruct(interpreters[i]); perl_free(interpreters[i]); goto clear2; } } } PERL_SET_CONTEXT(interpreters[i]); uperl.tmp_current_i = i; if (uperl.locallib) { uwsgi_log("using %s as local::lib directory\n", uperl.locallib); uperl.embedding[1] = uwsgi_concat2("-Mlocal::lib=", uperl.locallib); uperl.embedding[2] = app_name; if (perl_parse(interpreters[i], xs_init, 3, uperl.embedding, NULL)) { // what to do here ? i hope no-one will use threads with dynamic apps... but clear the whole stuff... free(uperl.embedding[1]); uperl.embedding[1] = app_name; free(callables); uwsgi_perl_free_stashes(); goto clear; } free(uperl.embedding[1]); uperl.embedding[1] = app_name; } else { if (perl_parse(interpreters[i], xs_init, 2, uperl.embedding, NULL)) { // what to do here ? i hope no-one will use threads with dynamic apps... but clear the whole stuff... free(callables); uwsgi_perl_free_stashes(); goto clear; } } perl_eval_pv("use IO::Handle;", 0); perl_eval_pv("use IO::File;", 0); perl_eval_pv("use Scalar::Util;", 0); if (!uperl.no_die_catch) { perl_eval_pv("use Devel::StackTrace;", 0); if (!SvTRUE(ERRSV)) { uperl.stacktrace_available = 1; perl_eval_pv("$SIG{__DIE__} = \\&uwsgi::stacktrace;", 0); } } SV *dollar_zero = get_sv("0", GV_ADD); sv_setsv(dollar_zero, newSVpv(app, app_len)); callables[i] = perl_eval_pv(uwsgi_concat4("#line 1 ", app_name, "\n", buf), 0); if (!callables[i]) { uwsgi_log("unable to find PSGI function entry point.\n"); // what to do here ? i hope no-one will use threads with dynamic apps... free(callables); uwsgi_perl_free_stashes(); goto clear; } PERL_SET_CONTEXT(interpreters[0]); } free(buf); if(SvTRUE(ERRSV)) { uwsgi_log("%s\n", SvPV_nolen(ERRSV)); free(callables); uwsgi_perl_free_stashes(); goto clear; } if (uwsgi_apps_cnt >= uwsgi.max_apps) { uwsgi_log("ERROR: you cannot load more than %d apps in a worker\n", uwsgi.max_apps); goto clear; } int id = uwsgi_apps_cnt; struct uwsgi_app *wi = NULL; if (wsgi_req) { // we need a copy of app_id wi = uwsgi_add_app(id, psgi_plugin.modifier1, uwsgi_concat2n(wsgi_req->appid, wsgi_req->appid_len, "", 0), wsgi_req->appid_len, interpreters, callables); } else { wi = uwsgi_add_app(id, psgi_plugin.modifier1, "", 0, interpreters, callables); } wi->started_at = now; wi->startup_time = uwsgi_now() - now; uwsgi_log("PSGI app %d (%s) loaded in %d seconds at %p (interpreter %p)\n", id, app_name, (int) wi->startup_time, callables[0], interpreters[0]); free(app_name); // copy global data to app-specific areas wi->stream = uperl.tmp_streaming_stash; wi->input = uperl.tmp_input_stash; wi->error = uperl.tmp_error_stash; wi->responder0 = uperl.tmp_stream_responder; wi->responder1 = uperl.tmp_psgix_logger; uwsgi_emulate_cow_for_apps(id); // restore context if required if (interpreters != uperl.main) { PERL_SET_CONTEXT(uperl.main[0]); } return id; clear: if (interpreters != uperl.main) { for(i=0;i<uwsgi.threads;i++) { perl_destruct(interpreters[i]); perl_free(interpreters[i]); } free(interpreters); } PERL_SET_CONTEXT(uperl.main[0]); clear2: free(app_name); return -1; }
int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) { int i; char *colon = NULL; int counter; char **uenvs; char *uef; char **vassal_argv; pid_t pid; if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe)) { uwsgi_error("socketpair()"); return -1; } event_queue_add_fd_read(uwsgi.emperor_queue, n_ui->pipe[0]); if (n_ui->use_config) { if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe_config)) { uwsgi_error("socketpair()"); return -1; } } if (n_ui->zerg) { uwsgi.emperor_broodlord_num++; } // TODO pre-start hook // a new uWSGI instance will start pid = fork(); if (pid < 0) { uwsgi_error("fork()") } else if (pid > 0) { n_ui->pid = pid; // close the right side of the pipe close(n_ui->pipe[1]); // close the "on demand" socket if (n_ui->on_demand_fd > -1) { close(n_ui->on_demand_fd); n_ui->on_demand_fd = -1; } if (n_ui->use_config) { close(n_ui->pipe_config[1]); } if (n_ui->use_config) { struct uwsgi_header uh; uh.modifier1 = 115; uh.pktsize = n_ui->config_len; uh.modifier2 = 0; if (write(n_ui->pipe_config[0], &uh, 4) != 4) { uwsgi_error("[uwsgi-emperor] write() header config"); } else { if (write(n_ui->pipe_config[0], n_ui->config, n_ui->config_len) != (long) n_ui->config_len) { uwsgi_error("[uwsgi-emperor] write() config"); } } } return 0; } else { if (uwsgi.emperor_tyrant) { uwsgi_log("[emperor-tyrant] dropping privileges to %d %d for instance %s\n", (int) n_ui->uid, (int) n_ui->gid, n_ui->name); if (setgid(n_ui->gid)) { uwsgi_error("setgid()"); exit(1); } if (setgroups(0, NULL)) { uwsgi_error("setgroups()"); exit(1); } if (setuid(n_ui->uid)) { uwsgi_error("setuid()"); exit(1); } } unsetenv("UWSGI_RELOADS"); unsetenv("NOTIFY_SOCKET"); uef = uwsgi_num2str(n_ui->pipe[1]); if (setenv("UWSGI_EMPEROR_FD", uef, 1)) { uwsgi_error("setenv()"); exit(1); } free(uef); // add UWSGI_BROODLORD_NUM if (n_ui->zerg) { uef = uwsgi_num2str(uwsgi.emperor_broodlord_num); if (setenv("UWSGI_BROODLORD_NUM", uef, 1)) { uwsgi_error("setenv()"); exit(1); } free(uef); } if (n_ui->use_config) { uef = uwsgi_num2str(n_ui->pipe_config[1]); if (setenv("UWSGI_EMPEROR_FD_CONFIG", uef, 1)) { uwsgi_error("setenv()"); exit(1); } free(uef); } uenvs = environ; while (*uenvs) { if (!strncmp(*uenvs, "UWSGI_VASSAL_", 13)) { char *ne = uwsgi_concat2("UWSGI_", *uenvs + 13); char *oe = uwsgi_concat2n(*uenvs, strchr(*uenvs, '=') - *uenvs, "", 0); if (unsetenv(oe)) { uwsgi_error("unsetenv()"); free(oe); break; } free(oe); #ifdef UWSGI_DEBUG uwsgi_log("putenv %s\n", ne); #endif if (putenv(ne)) { uwsgi_error("putenv()"); } // do not free ne as putenv will add it to the environ uenvs = environ; continue; } uenvs++; } // close the left side of the pipe close(n_ui->pipe[0]); if (n_ui->use_config) { close(n_ui->pipe_config[0]); } counter = 4; struct uwsgi_string_list *uct = uwsgi.vassals_templates; while (uct) { counter += 2; uct = uct->next; } vassal_argv = uwsgi_malloc(sizeof(char *) * counter); // set args vassal_argv[0] = uwsgi.binary_path; if (uwsgi.emperor_broodlord) { colon = strchr(n_ui->name, ':'); if (colon) { colon[0] = 0; } } // initialize to a default value vassal_argv[1] = "--inherit"; if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".xml")) vassal_argv[1] = "--xml"; if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".ini")) vassal_argv[1] = "--ini"; if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".yml")) vassal_argv[1] = "--yaml"; if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".yaml")) vassal_argv[1] = "--yaml"; if (!strcmp(n_ui->name + (strlen(n_ui->name) - 3), ".js")) vassal_argv[1] = "--json"; if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".json")) vassal_argv[1] = "--json"; struct uwsgi_string_list *usl = uwsgi.emperor_extra_extension; while(usl) { if (uwsgi_endswith(n_ui->name, usl->value)) { vassal_argv[1] = "--config"; break; } usl = usl->next; } if (colon) { colon[0] = ':'; } vassal_argv[2] = n_ui->name; if (uwsgi.emperor_magic_exec) { if (!access(n_ui->name, R_OK | X_OK)) { vassal_argv[2] = uwsgi_concat2("exec://", n_ui->name); } } if (n_ui->use_config) { vassal_argv[2] = uwsgi_concat2("emperor://", n_ui->name); } counter = 3; uct = uwsgi.vassals_templates; while (uct) { vassal_argv[counter] = "--inherit"; vassal_argv[counter + 1] = uct->value; counter += 2; uct = uct->next; } vassal_argv[counter] = NULL; // disable stdin OR map it to the "on demand" socket if (n_ui->on_demand_fd > -1) { if (n_ui->on_demand_fd != 0) { if (dup2(n_ui->on_demand_fd, 0) < 0) { uwsgi_error("dup2()"); exit(1); } close(n_ui->on_demand_fd); } } else { int stdin_fd = open("/dev/null", O_RDONLY); if (stdin_fd < 0) { uwsgi_error_open("/dev/null"); exit(1); } if (stdin_fd != 0) { if (dup2(stdin_fd, 0) < 0) { uwsgi_error("dup2()"); exit(1); } close(stdin_fd); } } // close all of the unneded fd for (i = 3; i < (int) uwsgi.max_fd; i++) { if (n_ui->use_config) { if (i == n_ui->pipe_config[1]) continue; } if (i != n_ui->pipe[1]) { close(i); } } if (uwsgi.vassals_start_hook) { uwsgi_log("[emperor] running vassal start-hook: %s %s\n", uwsgi.vassals_start_hook, n_ui->name); if (uwsgi.emperor_absolute_dir) { if (setenv("UWSGI_VASSALS_DIR", uwsgi.emperor_absolute_dir, 1)) { uwsgi_error("setenv()"); } } int start_hook_ret = uwsgi_run_command_and_wait(uwsgi.vassals_start_hook, n_ui->name); uwsgi_log("[emperor] %s start-hook returned %d\n", n_ui->name, start_hook_ret); } // start !!! if (execvp(vassal_argv[0], vassal_argv)) { uwsgi_error("execvp()"); } uwsgi_log("[emperor] is the uwsgi binary in your system PATH ?\n"); // never here exit(UWSGI_EXILE_CODE); } return -1; }
char *uwsgi_rsa_sign(char *algo_key, char *message, size_t message_len, unsigned int *s_len) { // openssl could not be initialized if (!uwsgi.ssl_initialized) { uwsgi_ssl_init(); } *s_len = 0; EVP_PKEY *pk = NULL; char *algo = uwsgi_str(algo_key); char *colon = strchr(algo, ':'); if (!colon) { uwsgi_log("invalid RSA signature syntax, must be: <digest>:<pemfile>\n"); free(algo); return NULL; } *colon = 0; char *keyfile = colon + 1; char *signature = NULL; FILE *kf = fopen(keyfile, "r"); if (!kf) { uwsgi_error_open(keyfile); free(algo); return NULL; } if (PEM_read_PrivateKey(kf, &pk, NULL, NULL) == 0) { uwsgi_log("unable to load private key: %s\n", keyfile); free(algo); fclose(kf); return NULL; } fclose(kf); EVP_MD_CTX *ctx = EVP_MD_CTX_create(); if (!ctx) { free(algo); EVP_PKEY_free(pk); return NULL; } const EVP_MD *md = EVP_get_digestbyname(algo); if (!md) { uwsgi_log("unknown digest algo: %s\n", algo); free(algo); EVP_PKEY_free(pk); EVP_MD_CTX_destroy(ctx); return NULL; } *s_len = EVP_PKEY_size(pk); signature = uwsgi_malloc(*s_len); if (EVP_SignInit_ex(ctx, md, NULL) == 0) { ERR_print_errors_fp(stderr); free(signature); signature = NULL; *s_len = 0; goto clear; } if (EVP_SignUpdate(ctx, message, message_len) == 0) { ERR_print_errors_fp(stderr); free(signature); signature = NULL; *s_len = 0; goto clear; } if (EVP_SignFinal(ctx, (unsigned char *) signature, s_len, pk) == 0) { ERR_print_errors_fp(stderr); free(signature); signature = NULL; *s_len = 0; goto clear; } clear: free(algo); EVP_PKEY_free(pk); EVP_MD_CTX_destroy(ctx); return signature; }
void uwsgi_build_plugin(char *directory) { if (!uwsgi_file_exists(UWSGI_BUILD_DIR)) { if (mkdir(UWSGI_BUILD_DIR, S_IRWXU) < 0) { uwsgi_error("uwsgi_build_plugin()/mkdir() " UWSGI_BUILD_DIR "/"); _exit(1); } } char *dot_h = uwsgi_get_dot_h(); if (!dot_h) { uwsgi_log("unable to generate uwsgi.h"); _exit(1); } if (strlen(dot_h) == 0) { free(dot_h); uwsgi_log("invalid uwsgi.h"); _exit(1); } int dot_h_fd = open(UWSGI_BUILD_DIR "/uwsgi.h", O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR); if (dot_h_fd < 0) { uwsgi_error_open(UWSGI_BUILD_DIR "/uwsgi.h"); free(dot_h); _exit(1); } ssize_t dot_h_len = (ssize_t) strlen(dot_h); if (write(dot_h_fd, dot_h, dot_h_len) != dot_h_len) { uwsgi_error("uwsgi_build_plugin()/write()"); _exit(1); } char *config_py = uwsgi_get_config_py(); if (!config_py) { uwsgi_log("unable to generate uwsgiconfig.py"); _exit(1); } if (strlen(config_py) == 0) { uwsgi_log("invalid uwsgiconfig.py"); _exit(1); } int config_py_fd = open(UWSGI_BUILD_DIR "/uwsgiconfig.py", O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR); if (config_py_fd < 0) { uwsgi_error_open(UWSGI_BUILD_DIR "/uwsgiconfig.py"); _exit(1); } ssize_t config_py_len = (ssize_t) strlen(config_py); if (write(config_py_fd, config_py, config_py_len) != config_py_len) { uwsgi_error("uwsgi_build_plugin()/write()"); _exit(1); } char *cflags = uwsgi_get_cflags(); if (!cflags) { uwsgi_log("unable to find cflags\n"); _exit(1); } if (strlen(cflags) == 0) { uwsgi_log("invalid cflags\n"); _exit(1); } if (setenv("UWSGI_PLUGINS_BUILDER_CFLAGS", cflags, 1)) { uwsgi_error("uwsgi_build_plugin()/setenv()"); _exit(1); } // now run the python script char *argv[6]; argv[0] = getenv("PYTHON"); if (!argv[0]) argv[0] = "python"; argv[1] = UWSGI_BUILD_DIR "/uwsgiconfig.py"; argv[2] = "--extra-plugin"; char *space = strchr(directory, ' '); if (space) { *space = 0; argv[3] = directory; argv[4] = space+1; argv[5] = NULL; } else { argv[3] = directory; argv[4] = NULL; } execvp(argv[0], argv); // never here... _exit(1); }
void uwsgi_init_queue() { if (!uwsgi.queue_blocksize) uwsgi.queue_blocksize = 8192; if ((uwsgi.queue_blocksize * uwsgi.queue_size) % uwsgi.page_size != 0) { uwsgi_log("invalid queue size/blocksize %llu: must be a multiple of memory page size (%d bytes)\n", (unsigned long long) uwsgi.queue_blocksize, uwsgi.page_size); exit(1); } if (uwsgi.queue_store) { uwsgi.queue_filesize = uwsgi.queue_blocksize * uwsgi.queue_size + 16; int queue_fd; struct stat qst; if (stat(uwsgi.queue_store, &qst)) { uwsgi_log("creating a new queue store file: %s\n", uwsgi.queue_store); queue_fd = open(uwsgi.queue_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); if (queue_fd >= 0) { // fill the queue store if (ftruncate(queue_fd, uwsgi.queue_filesize)) { uwsgi_log("ftruncate()"); exit(1); } } } else { if ((size_t) qst.st_size != uwsgi.queue_filesize || !S_ISREG(qst.st_mode)) { uwsgi_log("invalid queue store file. Please remove it or fix queue blocksize/items to match its size\n"); exit(1); } queue_fd = open(uwsgi.queue_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); uwsgi_log("recovered queue from backing store file: %s\n", uwsgi.queue_store); } if (queue_fd < 0) { uwsgi_error_open(uwsgi.queue_store); exit(1); } uwsgi.queue = mmap(NULL, uwsgi.queue_filesize, PROT_READ | PROT_WRITE, MAP_SHARED, queue_fd, 0); // fix header uwsgi.queue_header = uwsgi.queue; uwsgi.queue += 16; } else { uwsgi.queue = mmap(NULL, (uwsgi.queue_blocksize * uwsgi.queue_size) + 16, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); // fix header uwsgi.queue_header = uwsgi.queue; uwsgi.queue += 16; uwsgi.queue_header->pos = 0; uwsgi.queue_header->pull_pos = 0; } if (!uwsgi.queue) { uwsgi_error("mmap()"); exit(1); } uwsgi.queue_lock = uwsgi_rwlock_init("queue"); uwsgi_log("*** Queue subsystem initialized: %dMB preallocated ***\n", (uwsgi.queue_blocksize * uwsgi.queue_size) / (1024 * 1024)); }
// dumb/fake tnetstring implementation...all is a string static int uwsgi_mongrel2_tnetstring_parse(struct wsgi_request *wsgi_req, char *buf, int len) { char *ptr = buf; char *watermark = buf + len; char *key = NULL; size_t keylen = 0; char *val = NULL; size_t vallen = 0; uint16_t script_name_len = 0; char *query_string = NULL; uint16_t query_string_len = 0; int async_upload = 0; // set an empty SCRIPT_NAME wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SCRIPT_NAME", 11, "", 0); while (ptr < watermark) { ptr = uwsgi_netstring(ptr, len - (ptr - buf), &key, &keylen); if (ptr == NULL) break; // empty keys are not allowed if (keylen == 0) break; if (ptr >= watermark) break; ptr = uwsgi_netstring(ptr, len - (ptr - buf), &val, &vallen); if (ptr == NULL) break; if (key[0] < 97) { if (!uwsgi_strncmp("METHOD", 6, key, keylen)) { if (!uwsgi_strncmp("JSON", 4, val, vallen)) { return -1; } wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_METHOD", 14, val, vallen); } else if (!uwsgi_strncmp("VERSION", 7, key, keylen)) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PROTOCOL", 15, val, vallen); } else if (!uwsgi_strncmp("QUERY", 5, key, keylen)) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, val, vallen); query_string = val; query_string_len = vallen; } else if (!uwsgi_strncmp("PATH", 4, key, keylen)) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "PATH_INFO", 9, val + script_name_len, vallen - script_name_len); if (query_string_len) { char *request_uri = uwsgi_concat3n(val, vallen, "?", 1, query_string, query_string_len); wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, request_uri, vallen + 1 + query_string_len); free(request_uri); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, val, vallen); } } } else { // add header if (!uwsgi_strncmp("host", 4, key, keylen)) { char *colon = memchr(val, ':', vallen); if (colon) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, colon + 1, vallen - ((colon + 1) - val)); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, "80", 2); } } else if (!uwsgi_strncmp("content-length", 14, key, keylen)) { wsgi_req->post_cl = uwsgi_str_num(val, vallen); } else if (!uwsgi_strncmp("x-mongrel2-upload-done", 22, key, keylen)) { char *post_filename = uwsgi_concat2n(val, vallen, "", 0); wsgi_req->post_file = fopen(post_filename, "r"); if (!wsgi_req->post_file) { uwsgi_error_open(post_filename); wsgi_req->do_not_log = 1; } async_upload += 2; free(post_filename); } else if (!uwsgi_strncmp("x-forwarded-for", 15, key, keylen)) { char *colon = memchr(val, ',', vallen); if (colon) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, colon + 1, (colon + 1) - val); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, val, vallen); } } else if (!uwsgi_strncmp("x-mongrel2-upload-start", 23, key, keylen)) { async_upload += 1; } wsgi_req->uh->pktsize += proto_base_add_uwsgi_header(wsgi_req, key, keylen, val, vallen); } } wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len); if (query_string == NULL) { // always set QUERY_STRING wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, "", 0); } // reject uncomplete upload if (async_upload == 1) { return -1; } return 0; }
void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, char *config, uint32_t config_size, uid_t uid, gid_t gid) { struct uwsgi_instance *c_ui = ui; struct uwsgi_instance *n_ui = NULL; pid_t pid; char **vassal_argv; char *uef; char **uenvs; int counter; char *colon = NULL; int i; struct timeval tv; #ifdef UWSGI_DEBUG uwsgi_log("\n\nVASSAL %s %d %.*s %d %d\n", name, born, config_size, config, uid, gid); #endif if (strlen(name) > (0xff - 1)) { uwsgi_log("[emperor] invalid vassal name\n", name); return; } gettimeofday(&tv, NULL); int now = tv.tv_sec; uint64_t micros = (tv.tv_sec * 1000 * 1000) + tv.tv_usec; // blacklist check struct uwsgi_emperor_blacklist_item *uebi = uwsgi_emperor_blacklist_check(name); if (uebi) { uint64_t i_micros = (uebi->last_attempt.tv_sec * 1000 * 1000) + uebi->last_attempt.tv_usec + uebi->throttle_level; if (i_micros > micros) { return; } } if (now - emperor_throttle < 1) { emperor_throttle_level = emperor_throttle_level * 2; } else { if (emperor_throttle_level > uwsgi.emperor_throttle) { emperor_throttle_level = emperor_throttle_level / 2; } if (emperor_throttle_level < uwsgi.emperor_throttle) { emperor_throttle_level = uwsgi.emperor_throttle; } } emperor_throttle = now; #ifdef UWSGI_DEBUG uwsgi_log("emperor throttle = %d\n", emperor_throttle_level); #endif usleep(emperor_throttle_level); if (uwsgi.emperor_tyrant) { if (uid == 0 || gid == 0) { uwsgi_log("[emperor-tyrant] invalid permissions for vassal %s\n", name); return; } } while (c_ui->ui_next) { c_ui = c_ui->ui_next; } n_ui = uwsgi_malloc(sizeof(struct uwsgi_instance)); memset(n_ui, 0, sizeof(struct uwsgi_instance)); if (config) { n_ui->use_config = 1; n_ui->config = config; n_ui->config_len = config_size; } c_ui->ui_next = n_ui; #ifdef UWSGI_DEBUG uwsgi_log("c_ui->ui_next = %p\n", c_ui->ui_next); #endif n_ui->ui_prev = c_ui; if (strchr(name, ':')) { n_ui->zerg = 1; uwsgi.emperor_broodlord_count++; } n_ui->scanner = ues; memcpy(n_ui->name, name, strlen(name)); n_ui->born = born; n_ui->uid = uid; n_ui->gid = gid; n_ui->last_mod = born; // start without loyalty n_ui->last_loyal = 0; n_ui->loyal = 0; n_ui->first_run = uwsgi_now(); n_ui->last_run = n_ui->first_run; if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe)) { uwsgi_error("socketpair()"); goto clear; } event_queue_add_fd_read(uwsgi.emperor_queue, n_ui->pipe[0]); if (n_ui->use_config) { if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe_config)) { uwsgi_error("socketpair()"); goto clear; } } // TODO pre-start hook // a new uWSGI instance will start pid = fork(); if (pid < 0) { uwsgi_error("fork()") } else if (pid > 0) { n_ui->pid = pid; // close the right side of the pipe close(n_ui->pipe[1]); if (n_ui->use_config) { close(n_ui->pipe_config[1]); } if (n_ui->use_config) { if (write(n_ui->pipe_config[0], n_ui->config, n_ui->config_len) <= 0) { uwsgi_error("write()"); } close(n_ui->pipe_config[0]); } return; } else { if (uwsgi.emperor_tyrant) { uwsgi_log("[emperor-tyrant] dropping privileges to %d %d for instance %s\n", (int) uid, (int) gid, name); if (setgid(gid)) { uwsgi_error("setgid()"); exit(1); } if (setgroups(0, NULL)) { uwsgi_error("setgroups()"); exit(1); } if (setuid(uid)) { uwsgi_error("setuid()"); exit(1); } } unsetenv("UWSGI_RELOADS"); unsetenv("NOTIFY_SOCKET"); uef = uwsgi_num2str(n_ui->pipe[1]); if (setenv("UWSGI_EMPEROR_FD", uef, 1)) { uwsgi_error("setenv()"); exit(1); } free(uef); if (n_ui->use_config) { uef = uwsgi_num2str(n_ui->pipe_config[1]); if (setenv("UWSGI_EMPEROR_FD_CONFIG", uef, 1)) { uwsgi_error("setenv()"); exit(1); } free(uef); } uenvs = environ; while (*uenvs) { if (!strncmp(*uenvs, "UWSGI_VASSAL_", 13)) { char *ne = uwsgi_concat2("UWSGI_", *uenvs + 13); char *oe = uwsgi_concat2n(*uenvs, strchr(*uenvs, '=') - *uenvs, "", 0); if (unsetenv(oe)) { uwsgi_error("unsetenv()"); break; } free(oe); #ifdef UWSGI_DEBUG uwsgi_log("putenv %s\n", ne); #endif if (putenv(ne)) { uwsgi_error("putenv()"); } // do not free ne as putenv will add it to the environ uenvs = environ; continue; } uenvs++; } // close the left side of the pipe close(n_ui->pipe[0]); if (n_ui->use_config) { close(n_ui->pipe_config[0]); } counter = 4; struct uwsgi_string_list *uct = uwsgi.vassals_templates; while (uct) { counter += 2; uct = uct->next; } vassal_argv = uwsgi_malloc(sizeof(char *) * counter); // set args vassal_argv[0] = uwsgi.binary_path; if (uwsgi.emperor_broodlord) { colon = strchr(name, ':'); if (colon) { colon[0] = 0; } } // initialize to a default value vassal_argv[1] = "--inherit"; if (!strcmp(name + (strlen(name) - 4), ".xml")) vassal_argv[1] = "--xml"; if (!strcmp(name + (strlen(name) - 4), ".ini")) vassal_argv[1] = "--ini"; if (!strcmp(name + (strlen(name) - 4), ".yml")) vassal_argv[1] = "--yaml"; if (!strcmp(name + (strlen(name) - 5), ".yaml")) vassal_argv[1] = "--yaml"; if (!strcmp(name + (strlen(name) - 3), ".js")) vassal_argv[1] = "--json"; if (!strcmp(name + (strlen(name) - 5), ".json")) vassal_argv[1] = "--json"; if (colon) { colon[0] = ':'; } vassal_argv[2] = name; if (uwsgi.emperor_magic_exec) { if (!access(name, R_OK | X_OK)) { vassal_argv[2] = uwsgi_concat2("exec://", name); } } if (n_ui->use_config) { vassal_argv[2] = uwsgi_concat2("emperor://", name); } counter = 3; uct = uwsgi.vassals_templates; while (uct) { vassal_argv[counter] = "--inherit"; vassal_argv[counter + 1] = uct->value; counter += 2; uct = uct->next; } vassal_argv[counter] = NULL; // disable stdin int stdin_fd = open("/dev/null", O_RDONLY); if (stdin_fd < 0) { uwsgi_error_open("/dev/null"); exit(1); } if (stdin_fd != 0) { if (dup2(stdin_fd, 0)) { uwsgi_error("dup2()"); exit(1); } close(stdin_fd); } // close all of the unneded fd for (i = 3; i < (int) uwsgi.max_fd; i++) { if (n_ui->use_config) { if (i == n_ui->pipe_config[1]) continue; } if (i != n_ui->pipe[1]) { close(i); } } if (uwsgi.vassals_start_hook) { uwsgi_log("[emperor] running vassal start-hook: %s %s\n", uwsgi.vassals_start_hook, n_ui->name); if (uwsgi.emperor_absolute_dir) { if (setenv("UWSGI_VASSALS_DIR", uwsgi.emperor_absolute_dir, 1)) { uwsgi_error("setenv()"); } } int start_hook_ret = uwsgi_run_command_and_wait(uwsgi.vassals_start_hook, n_ui->name); uwsgi_log("[emperor] %s start-hook returned %d\n", n_ui->name, start_hook_ret); } // start !!! if (execvp(vassal_argv[0], vassal_argv)) { uwsgi_error("execvp()"); } uwsgi_log("[emperor] is the uwsgi binary in your system PATH ?\n"); // never here exit(UWSGI_EXILE_CODE); } clear: free(n_ui); c_ui->ui_next = NULL; }
void uwsgi_check_logrotate(void) { char message[1024]; int need_rotation = 0; int need_reopen = 0; if (uwsgi.log_master) { uwsgi.shared->logsize = lseek(uwsgi.original_log_fd, 0, SEEK_CUR); } else { uwsgi.shared->logsize = lseek(2, 0, SEEK_CUR); } if (uwsgi.log_maxsize > 0 && uwsgi.shared->logsize > uwsgi.log_maxsize) { need_rotation = 1; } if (uwsgi_check_touches(uwsgi.touch_logrotate)) { need_rotation = 1; } if (uwsgi_check_touches(uwsgi.touch_logreopen)) { need_reopen = 1; } if (need_rotation) { char *rot_name = uwsgi.log_backupname; int need_free = 0; if (rot_name == NULL) { char *ts_str = uwsgi_num2str((int) uwsgi_now()); rot_name = uwsgi_concat3(uwsgi.logfile, ".", ts_str); free(ts_str); need_free = 1; } int ret = snprintf(message, 1024, "[%d] logsize: %llu, triggering rotation to %s...\n", (int) uwsgi_now(), (unsigned long long) uwsgi.shared->logsize, rot_name); if (ret > 0) { if (write(uwsgi.original_log_fd, message, ret) != ret) { // very probably this will never be printed uwsgi_error("write()"); } } if (rename(uwsgi.logfile, rot_name) == 0) { // reopen logfile dup'it and eventually gracefully reload workers; int fd = open(uwsgi.logfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP); if (fd < 0) { uwsgi_error_open(uwsgi.logfile); grace_them_all(0); } if (dup2(fd, uwsgi.original_log_fd) < 0) { uwsgi_error("dup2()"); grace_them_all(0); } close(fd); } else { uwsgi_error("unable to rotate log: rename()"); } if (need_free) free(rot_name); } else if (need_reopen) { int ret = snprintf(message, 1024, "[%d] logsize: %llu, triggering log-reopen...\n", (int) uwsgi_now(), (unsigned long long) uwsgi.shared->logsize); if (ret > 0) { if (write(uwsgi.original_log_fd, message, ret) != ret) { // very probably this will never be printed uwsgi_error("write()"); } } // reopen logfile; close(uwsgi.original_log_fd); uwsgi.original_log_fd = open(uwsgi.logfile, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP); if (uwsgi.original_log_fd < 0) { uwsgi_error_open(uwsgi.logfile); grace_them_all(0); } ret = snprintf(message, 1024, "[%d] %s reopened.\n", (int) uwsgi_now(), uwsgi.logfile); if (ret > 0) { if (write(uwsgi.original_log_fd, message, ret) != ret) { // very probably this will never be printed uwsgi_error("write()"); } } uwsgi.shared->logsize = lseek(uwsgi.original_log_fd, 0, SEEK_CUR); } }
PyObject *uwsgi_pyimport_by_filename(char *name, char *filename) { #ifdef UWSGI_PYPY uwsgi_log("import by filename is currently not supported on PyPy !!!\n"); return NULL; #else FILE *pyfile; struct _node *py_file_node = NULL; PyObject *py_compiled_node, *py_file_module; int is_a_package = 0; struct stat pystat; char *real_filename = filename; if (!uwsgi_check_scheme(filename)) { pyfile = fopen(filename, "r"); if (!pyfile) { uwsgi_log("failed to open python file %s\n", filename); return NULL; } if (fstat(fileno(pyfile), &pystat)) { uwsgi_error("fstat()"); return NULL; } if (S_ISDIR(pystat.st_mode)) { is_a_package = 1; fclose(pyfile); real_filename = uwsgi_concat2(filename, "/__init__.py"); pyfile = fopen(real_filename, "r"); if (!pyfile) { uwsgi_error_open(real_filename); free(real_filename); return NULL; } } py_file_node = PyParser_SimpleParseFile(pyfile, real_filename, Py_file_input); if (!py_file_node) { PyErr_Print(); uwsgi_log("failed to parse file %s\n", real_filename); if (is_a_package) free(real_filename); fclose(pyfile); return NULL; } fclose(pyfile); } else { int pycontent_size = 0; char *pycontent = uwsgi_open_and_read(filename, &pycontent_size, 1, NULL); if (pycontent) { py_file_node = PyParser_SimpleParseString(pycontent, Py_file_input); if (!py_file_node) { PyErr_Print(); uwsgi_log("failed to parse url %s\n", real_filename); return NULL; } } } py_compiled_node = (PyObject *) PyNode_Compile(py_file_node, real_filename); if (!py_compiled_node) { PyErr_Print(); uwsgi_log("failed to compile python file %s\n", real_filename); return NULL; } if (is_a_package) { py_file_module = PyImport_AddModule(name); if (py_file_module) { PyModule_AddObject(py_file_module, "__path__", Py_BuildValue("[O]", PyString_FromString(filename))); } free(real_filename); } py_file_module = PyImport_ExecCodeModule(name, py_compiled_node); if (!py_file_module) { PyErr_Print(); return NULL; } Py_DECREF(py_compiled_node); return py_file_module; #endif }
// create the logpipe void create_logpipe(void) { #if defined(SOCK_SEQPACKET) && defined(__linux__) if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, uwsgi.shared->worker_log_pipe)) { #else if (socketpair(AF_UNIX, SOCK_DGRAM, 0, uwsgi.shared->worker_log_pipe)) { #endif uwsgi_error("socketpair()\n"); exit(1); } uwsgi_socket_nb(uwsgi.shared->worker_log_pipe[0]); uwsgi_socket_nb(uwsgi.shared->worker_log_pipe[1]); if (uwsgi.shared->worker_log_pipe[1] != 1) { if (dup2(uwsgi.shared->worker_log_pipe[1], 1) < 0) { uwsgi_error("dup2()"); exit(1); } } if (dup2(1, 2) < 0) { uwsgi_error("dup2()"); exit(1); } } #ifdef UWSGI_ZEROMQ // the zeromq logger ssize_t uwsgi_zeromq_logger(struct uwsgi_logger *ul, char *message, size_t len) { if (!ul->configured) { if (!ul->arg) { uwsgi_log_safe("invalid zeromq syntax\n"); exit(1); } void *ctx = uwsgi_zeromq_init(); ul->data = zmq_socket(ctx, ZMQ_PUSH); if (ul->data == NULL) { uwsgi_error_safe("zmq_socket()"); exit(1); } if (zmq_connect(ul->data, ul->arg) < 0) { uwsgi_error_safe("zmq_connect()"); exit(1); } ul->configured = 1; } zmq_msg_t msg; if (zmq_msg_init_size(&msg, len) == 0) { memcpy(zmq_msg_data(&msg), message, len); #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) zmq_sendmsg(ul->data, &msg, 0); #else zmq_send(ul->data, &msg, 0); #endif zmq_msg_close(&msg); } return 0; } #endif // log to the specified file or udp address void logto(char *logfile) { int fd; #ifdef UWSGI_UDP char *udp_port; struct sockaddr_in udp_addr; udp_port = strchr(logfile, ':'); if (udp_port) { udp_port[0] = 0; if (!udp_port[1] || !logfile[0]) { uwsgi_log("invalid udp address\n"); exit(1); } fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { uwsgi_error("socket()"); exit(1); } memset(&udp_addr, 0, sizeof(struct sockaddr_in)); udp_addr.sin_family = AF_INET; udp_addr.sin_port = htons(atoi(udp_port + 1)); char *resolved = uwsgi_resolve_ip(logfile); if (resolved) { udp_addr.sin_addr.s_addr = inet_addr(resolved); } else { udp_addr.sin_addr.s_addr = inet_addr(logfile); } if (connect(fd, (const struct sockaddr *) &udp_addr, sizeof(struct sockaddr_in)) < 0) { uwsgi_error("connect()"); exit(1); } } else { #endif if (uwsgi.log_truncate) { fd = open(logfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP); } else { fd = open(logfile, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP); } if (fd < 0) { uwsgi_error_open(logfile); exit(1); } uwsgi.logfile = logfile; if (uwsgi.chmod_logfile_value) { if (chmod(uwsgi.logfile, uwsgi.chmod_logfile_value)) { uwsgi_error("chmod()"); } } #ifdef UWSGI_UDP } #endif /* stdout */ if (fd != 1) { if (dup2(fd, 1) < 0) { uwsgi_error("dup2()"); exit(1); } close(fd); } /* stderr */ if (dup2(1, 2) < 0) { uwsgi_error("dup2()"); exit(1); } }