// this is the monitor for glob patterns void uwsgi_imperial_monitor_glob(struct uwsgi_emperor_scanner *ues) { glob_t g; int i; struct stat st; struct uwsgi_instance *ui_current; if (glob(ues->arg, GLOB_MARK | GLOB_NOCHECK, NULL, &g)) { uwsgi_error("glob()"); return; } for (i = 0; i < (int) g.gl_pathc; i++) { if (!uwsgi_emperor_is_valid(g.gl_pathv[i])) continue; if (stat(g.gl_pathv[i], &st)) continue; if (!S_ISREG(st.st_mode)) continue; ui_current = emperor_get(g.gl_pathv[i]); uid_t t_uid = st.st_uid; gid_t t_gid = st.st_gid; if (uwsgi.emperor_tyrant && uwsgi.emperor_tyrant_nofollow) { struct stat lst; if (lstat(g.gl_pathv[i], &lst)) { uwsgi_error("[emperor-tyrant]/lstat()"); if (ui_current) { uwsgi_log("!!! availability of file %s changed. stopping the instance... !!!\n", g.gl_pathv[i]); emperor_stop(ui_current); } continue; } t_uid = lst.st_uid; t_gid = lst.st_gid; } if (ui_current) { // check if uid or gid are changed, in such case, stop the instance if (uwsgi.emperor_tyrant) { if (t_uid != ui_current->uid || t_gid != ui_current->gid) { uwsgi_log("!!! permissions of file %s changed. stopping the instance... !!!\n", g.gl_pathv[i]); emperor_stop(ui_current); continue; } } // check if mtime is changed and the uWSGI instance must be reloaded if (st.st_mtime > ui_current->last_mod) { emperor_respawn(ui_current, st.st_mtime); } } else { char *socket_name = emperor_check_on_demand_socket(g.gl_pathv[i]); emperor_add(ues, g.gl_pathv[i], st.st_mtime, NULL, 0, t_uid, t_gid, socket_name); if (socket_name) free(socket_name); } } globfree(&g); // now check for removed instances struct uwsgi_instance *c_ui = ui->ui_next; while (c_ui) { if (c_ui->scanner == ues) { if (c_ui->zerg) { char *colon = strrchr(c_ui->name, ':'); if (!colon) { emperor_stop(c_ui); } else { char *filename = uwsgi_calloc(0xff); memcpy(filename, c_ui->name, colon - c_ui->name); if (stat(filename, &st)) { emperor_stop(c_ui); } free(filename); } } else { if (stat(c_ui->name, &st)) { emperor_stop(c_ui); } } } c_ui = c_ui->ui_next; } }
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, char *socket_name) { struct uwsgi_instance *c_ui = ui; struct uwsgi_instance *n_ui = NULL; 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: %s\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_calloc(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; n_ui->on_demand_fd = -1; if (socket_name) { n_ui->socket_name = uwsgi_str(socket_name); } n_ui->pid = -1; // ok here we check if we need to bind to the specified socket or continue with the activation if (socket_name) { char *tcp_port = strchr(socket_name, ':'); if (tcp_port) { // disable deferred accept for this socket int current_defer_accept = uwsgi.no_defer_accept; uwsgi.no_defer_accept = 1; n_ui->on_demand_fd = bind_to_tcp(socket_name, uwsgi.listen_queue, tcp_port); uwsgi.no_defer_accept = current_defer_accept; } else { n_ui->on_demand_fd = bind_to_unix(socket_name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); } if (n_ui->on_demand_fd < 0) { uwsgi_error("emperor_add()/bind()"); free(n_ui); c_ui->ui_next = NULL; return; } event_queue_add_fd_read(uwsgi.emperor_queue, n_ui->on_demand_fd); uwsgi_log("[uwsgi-emperor] %s -> \"on demand\" instance detected, waiting for connections on socket \"%s\" ...\n", name, socket_name); return; } if (uwsgi_emperor_vassal_start(n_ui)) { // clear the vassal free(n_ui); c_ui->ui_next = NULL; } }
struct corerouter_session *corerouter_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket *ugs, int new_connection, struct sockaddr *cr_addr, socklen_t cr_addr_len) { struct corerouter_session *cs = uwsgi_calloc(ucr->session_size); struct corerouter_peer *peer = uwsgi_calloc(sizeof(struct corerouter_peer)); // main_peer has only input buffer as output buffer is taken from backend peers size_t bufsize = ucr->buffer_size; if (!bufsize) bufsize = uwsgi.page_size; peer->in = uwsgi_buffer_new(bufsize); ucr->cr_table[new_connection] = peer; cs->main_peer = peer; peer->fd = new_connection; peer->session = cs; // map corerouter and socket cs->corerouter = ucr; cs->ugs = ugs; // set initial timeout (could be overridden) peer->current_timeout = ucr->socket_timeout; ucr->active_sessions++; // build the client address memcpy(&cs->client_sockaddr, cr_addr, cr_addr_len); switch(cr_addr->sa_family) { case AF_INET: if (inet_ntop(AF_INET, &cs->client_sockaddr.sa_in.sin_addr, cs->client_address, cr_addr_len) == NULL) { uwsgi_error("corerouter_alloc_session/inet_ntop()"); memcpy(cs->client_address, "0.0.0.0", 7); cs->client_port[0] = '0'; cs->client_port[1] = 0; } uwsgi_num2str2(cs->client_sockaddr.sa_in.sin_port, cs->client_port); break; #ifdef AF_INET6 case AF_INET6: if (inet_ntop(AF_INET6, &cs->client_sockaddr.sa_in6.sin6_addr, cs->client_address, cr_addr_len) == NULL) { uwsgi_error("corerouter_alloc_session/inet_ntop()"); memcpy(cs->client_address, "0.0.0.0", 7); cs->client_port[0] = '0'; cs->client_port[1] = 0; } uwsgi_num2str2(cs->client_sockaddr.sa_in6.sin6_port, cs->client_port); break; #endif default: memcpy(cs->client_address, "0.0.0.0", 7); cs->client_port[0] = '0'; cs->client_port[1] = 0; break; } // here we prepare the real session and set the hooks if (ucr->alloc_session(ucr, ugs, cs, cr_addr, cr_addr_len)) { corerouter_close_session(ucr, cs); cs = NULL; } else { // truly set the timeout peer->timeout = cr_add_timeout(ucr, ucr->cr_table[new_connection]); } return cs; }
// this is the monitor for non-glob directories void uwsgi_imperial_monitor_directory(struct uwsgi_emperor_scanner *ues) { struct uwsgi_instance *ui_current; struct dirent *de; struct stat st; if (chdir(ues->arg)) { uwsgi_error("chdir()"); return; } DIR *dir = opendir("."); while ((de = readdir(dir)) != NULL) { if (!uwsgi_emperor_is_valid(de->d_name)) continue; if (stat(de->d_name, &st)) continue; if (!S_ISREG(st.st_mode)) continue; ui_current = emperor_get(de->d_name); uid_t t_uid = st.st_uid; gid_t t_gid = st.st_gid; if (uwsgi.emperor_tyrant && uwsgi.emperor_tyrant_nofollow) { struct stat lst; if (lstat(de->d_name, &lst)) { uwsgi_error("[emperor-tyrant]/lstat()"); if (ui_current) { uwsgi_log("!!! availability of file %s changed. stopping the instance... !!!\n", de->d_name); emperor_stop(ui_current); } continue; } t_uid = lst.st_uid; t_gid = lst.st_gid; } if (ui_current) { // check if uid or gid are changed, in such case, stop the instance if (uwsgi.emperor_tyrant) { if (t_uid != ui_current->uid || t_gid != ui_current->gid) { uwsgi_log("!!! permissions of file %s changed. stopping the instance... !!!\n", de->d_name); emperor_stop(ui_current); continue; } } // check if mtime is changed and the uWSGI instance must be reloaded if (st.st_mtime > ui_current->last_mod) { emperor_respawn(ui_current, st.st_mtime); } } else { char *socket_name = emperor_check_on_demand_socket(de->d_name); emperor_add(ues, de->d_name, st.st_mtime, NULL, 0, t_uid, t_gid, socket_name); if (socket_name) free(socket_name); } } closedir(dir); // now check for removed instances struct uwsgi_instance *c_ui = ui->ui_next; while (c_ui) { if (c_ui->scanner == ues) { if (c_ui->zerg) { char *colon = strrchr(c_ui->name, ':'); if (!colon) { emperor_stop(c_ui); } else { char *filename = uwsgi_calloc(0xff); memcpy(filename, c_ui->name, colon - c_ui->name); if (stat(filename, &st)) { emperor_stop(c_ui); } free(filename); } } else { if (stat(c_ui->name, &st)) { emperor_stop(c_ui); } } } c_ui = c_ui->ui_next; } }
/* 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; }
ssize_t uwsgi_redis_logger(struct uwsgi_logger *ul, char *message, size_t len) { ssize_t ret,ret2; struct uwsgi_redislog_state *uredislog = NULL; if (!ul->configured) { if (!ul->data) { ul->data = uwsgi_calloc(sizeof(struct uwsgi_redislog_state)); uredislog = (struct uwsgi_redislog_state *) ul->data; } if (ul->arg != NULL) { char *logarg = uwsgi_str(ul->arg); char *comma1 = strchr(logarg, ','); if (!comma1) { uredislog->address = logarg; goto done; } *comma1 = 0; uredislog->address = logarg; comma1++; if (*comma1 == 0) goto done; char *comma2 = strchr(comma1,','); if (!comma2) { uredislog->command = uwsgi_redis_logger_build_command(comma1); goto done; } *comma2 = 0; uredislog->command = uwsgi_redis_logger_build_command(comma1); comma2++; if (*comma2 == 0) goto done; uredislog->prefix = comma2; } done: if (!uredislog->address) uredislog->address = uwsgi_str("127.0.0.1:6379"); if (!uredislog->command) uredislog->command = "*3\r\n$7\r\npublish\r\n$5\r\nuwsgi\r\n"; if (!uredislog->prefix) uredislog->prefix = ""; uredislog->fd = -1; uredislog->iovec[0].iov_base = uredislog->command; uredislog->iovec[0].iov_len = strlen(uredislog->command); uredislog->iovec[1].iov_base = "$"; uredislog->iovec[1].iov_len = 1; uredislog->iovec[2].iov_base = uredislog->msgsize; uredislog->iovec[3].iov_base = "\r\n"; uredislog->iovec[3].iov_len = 2; uredislog->iovec[4].iov_base = uredislog->prefix; uredislog->iovec[4].iov_len = strlen(uredislog->prefix); uredislog->iovec[6].iov_base = "\r\n"; uredislog->iovec[6].iov_len = 2; ul->configured = 1; } uredislog = (struct uwsgi_redislog_state *) ul->data; if (uredislog->fd == -1) { uredislog->fd = uwsgi_connect(uredislog->address, uwsgi.socket_timeout, 0); } if (uredislog->fd == -1) return -1; // drop newline if (message[len-1] == '\n') len--; uwsgi_num2str2(len + uredislog->iovec[4].iov_len, uredislog->msgsize); uredislog->iovec[2].iov_len = strlen(uredislog->msgsize); uredislog->iovec[5].iov_base = message; uredislog->iovec[5].iov_len = len; ret = writev(uredislog->fd, uredislog->iovec, 7); if (ret <= 0) { close(uredislog->fd); uredislog->fd = -1; return -1; } again: // read til a \n is found (ugly but fast) ret2 = read(uredislog->fd, uredislog->response, 8); if (ret2 <= 0) { close(uredislog->fd); uredislog->fd = -1; return -1; } if (!memchr(uredislog->response, '\n', ret2)) { goto again; } return ret; }
static void asyncio_loop() { if (!uwsgi.has_threads && uwsgi.mywid == 1) { uwsgi_log("!!! Running asyncio without threads IS NOT recommended, enable them with --enable-threads !!!\n"); } if (uwsgi.socket_timeout < 30) { uwsgi_log("!!! Running asyncio with a socket-timeout lower than 30 seconds is not recommended, tune it with --socket-timeout !!!\n"); } if (!uwsgi.async_waiting_fd_table) uwsgi.async_waiting_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd); if (!uwsgi.async_proto_fd_table) uwsgi.async_proto_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd); // get the GIL UWSGI_GET_GIL up.gil_get = gil_asyncio_get; up.gil_release = gil_asyncio_release; uwsgi.wait_write_hook = uwsgi_asyncio_wait_write_hook; uwsgi.wait_read_hook = uwsgi_asyncio_wait_read_hook; if (uwsgi.async < 1) { uwsgi_log("the asyncio loop engine requires async mode (--async <n>)\n"); exit(1); } if (!uwsgi.schedule_to_main) { uwsgi_log("*** DANGER *** asyncio mode without coroutine/greenthread engine loaded !!!\n"); } if (!uwsgi.schedule_to_req) { uwsgi.schedule_to_req = async_schedule_to_req_green; } else { uwsgi.schedule_fix = uwsgi_asyncio_schedule_fix; } #ifndef PYTHREE PyObject *asyncio = PyImport_ImportModule("trollius"); #else PyObject *asyncio = PyImport_ImportModule("asyncio"); #endif if (!asyncio) uwsgi_pyexit; uasyncio.mod = asyncio; uasyncio.loop = PyObject_CallMethod(asyncio, "get_event_loop", NULL); if (!uasyncio.loop) uwsgi_pyexit; // main greenlet waiting for connection (one greenlet per-socket) PyObject *asyncio_accept = PyCFunction_New(uwsgi_asyncio_accept_def, NULL); Py_INCREF(asyncio_accept); uasyncio.request = PyCFunction_New(uwsgi_asyncio_request_def, NULL); if (!uasyncio.request) uwsgi_pyexit; uasyncio.hook_fd = PyCFunction_New(uwsgi_asyncio_hook_fd_def, NULL); if (!uasyncio.hook_fd) uwsgi_pyexit; uasyncio.hook_timeout = PyCFunction_New(uwsgi_asyncio_hook_timeout_def, NULL); if (!uasyncio.hook_timeout) uwsgi_pyexit; uasyncio.hook_fix = PyCFunction_New(uwsgi_asyncio_hook_fix_def, NULL); if (!uasyncio.hook_fix) uwsgi_pyexit; Py_INCREF(uasyncio.request); Py_INCREF(uasyncio.hook_fd); Py_INCREF(uasyncio.hook_timeout); Py_INCREF(uasyncio.hook_fix); // call add_handler on each socket struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while(uwsgi_sock) { if (PyObject_CallMethod(uasyncio.loop, "add_reader", "iOl", uwsgi_sock->fd, asyncio_accept, (long) uwsgi_sock) == NULL) { uwsgi_pyexit; } uwsgi_sock = uwsgi_sock->next; } if (PyObject_CallMethod(uasyncio.loop, "run_forever", NULL) == NULL) { uwsgi_pyexit; } // never here ? }
int uwsgi_python_init() { #ifndef UWSGI_PYPY char *pyversion = strchr(Py_GetVersion(), '\n'); if (!pyversion) { uwsgi_log_initial("Python version: %s\n", Py_GetVersion()); } else { uwsgi_log_initial("Python version: %.*s %s\n", pyversion-Py_GetVersion(), Py_GetVersion(), Py_GetCompiler()+1); } #else uwsgi_log_initial("PyPy version: %s\n", PYPY_VERSION); #endif if (up.home != NULL) { #ifdef PYTHREE wchar_t *wpyhome; size_t len = strlen(up.home) + 1; wpyhome = uwsgi_calloc(sizeof(wchar_t) * len ); if (!wpyhome) { uwsgi_error("malloc()"); exit(1); } mbstowcs(wpyhome, up.home, len); Py_SetPythonHome(wpyhome); // do not free this memory !!! //free(wpyhome); #else Py_SetPythonHome(up.home); #endif uwsgi_log("Set PythonHome to %s\n", up.home); } #ifdef PYTHREE wchar_t pname[6]; mbstowcs(pname, "uWSGI", 6); Py_SetProgramName(pname); #else Py_SetProgramName("uWSGI"); #endif #ifndef UWSGI_PYPY Py_OptimizeFlag = up.optimize; #endif Py_Initialize(); if (!uwsgi.has_threads) { uwsgi_log("*** Python threads support is disabled. You can enable it with --enable-threads ***\n"); } up.wsgi_spitout = PyCFunction_New(uwsgi_spit_method, NULL); up.wsgi_writeout = PyCFunction_New(uwsgi_write_method, NULL); up.main_thread = PyThreadState_Get(); // by default set a fake GIL (little impact on performance) up.gil_get = gil_fake_get; up.gil_release = gil_fake_release; up.swap_ts = simple_swap_ts; up.reset_ts = simple_reset_ts; uwsgi_log_initial("Python main interpreter initialized at %p\n", up.main_thread); return 1; }
static char *uwsgi_xslt_apply(char *xmlfile, char *xsltfile, char *params, int *rlen) { char **vparams = NULL; char *tmp_params = NULL; uint16_t count = 0; if (params) { // first count the number of items size_t i; size_t params_len = strlen(params); for(i=0;i<params_len;i++) { if (params[i] == '=') { count++; } } vparams = uwsgi_calloc( sizeof(char *) * ((count * 2) + 1)); tmp_params = uwsgi_str(params); char *p = strtok(tmp_params, "&"); int pos = 0; while(p) { char *equal = strchr(p, '='); if (equal) { *equal = 0; vparams[pos] = p; pos++; vparams[pos] = uwsgi_concat3("\"", equal+1, "\""); pos++; } p = strtok(NULL, "&"); } } // we reset them every time to avoid collision with other xml engines xmlSubstituteEntitiesDefault(1); xmlLoadExtDtdDefaultValue = 1; xmlDocPtr doc = xmlParseFile(xmlfile); if (!doc) { if (vparams) { int i; for(i=1;i<(count*2);i+=2) free(vparams[i]); free(tmp_params); free(vparams); } return NULL; } xsltStylesheetPtr ss = xsltParseStylesheetFile((const xmlChar *) xsltfile); if (!ss) { xmlFreeDoc(doc); if (vparams) { int i; for(i=1;i<(count*2);i+=2) free(vparams[i]); free(tmp_params); free(vparams); } return NULL; } xmlDocPtr res = xsltApplyStylesheet(ss, doc, (const char **) vparams); if (!res) { xsltFreeStylesheet(ss); xmlFreeDoc(doc); if (vparams) { int i; for(i=1;i<(count*2);i+=2) free(vparams[i]); free(tmp_params); free(vparams); } return NULL; } xmlChar *output; int ret = xsltSaveResultToString(&output, rlen, res, ss); xsltFreeStylesheet(ss); xmlFreeDoc(res); xmlFreeDoc(doc); if (vparams) { int i; for(i=1;i<(count*2);i+=2) free(vparams[i]); free(tmp_params); free(vparams); } if (ret < 0) return NULL; return (char *) output; }
void uwsgi_fork_server(char *socket) { // map fd 0 to /dev/null to avoid mess uwsgi_remap_fd(0, "/dev/null"); int fd = bind_to_unix(socket, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); if (fd < 0) exit(1); // automatically receive credentials (TODO make something useful with them, like checking the pid is from the Emperor) if (uwsgi_socket_passcred(fd)) exit(1); // initialize the event queue int eq = event_queue_init(); if (uwsgi.has_emperor) { event_queue_add_fd_read(eq, uwsgi.emperor_fd); } event_queue_add_fd_read(eq, fd); // now start waiting for connections for(;;) { int interesting_fd = -1; int rlen = event_queue_wait(eq, -1, &interesting_fd); if (rlen <= 0) continue; if (uwsgi.has_emperor && interesting_fd == uwsgi.emperor_fd) { char byte; ssize_t rlen = read(uwsgi.emperor_fd, &byte, 1); if (rlen > 0) { uwsgi_log_verbose("received message %d from emperor\n", byte); } exit(0); } if (interesting_fd != fd) continue; struct sockaddr_un client_src; socklen_t client_src_len = 0; int client_fd = accept(fd, (struct sockaddr *) &client_src, &client_src_len); if (client_fd < 0) { uwsgi_error("uwsgi_fork_server()/accept()"); continue; } char hbuf[4]; pid_t ppid = -1; uid_t uid = -1; gid_t gid = -1; int fds_count = 8; size_t remains = 4; // we can receive up to 8 fds (generally from 1 to 3) int fds[8]; // we only read 4 bytes header ssize_t len = uwsgi_recv_cred_and_fds(client_fd, hbuf, remains, &ppid, &uid, &gid, fds, &fds_count); uwsgi_log_verbose("[uwsgi-fork-server] connection from pid: %d uid: %d gid:%d fds:%d\n", ppid, uid, gid, fds_count); if (len <= 0 || fds_count < 1) { uwsgi_error("uwsgi_fork_server()/recvmsg()"); goto end; } remains -= len; if (uwsgi_read_nb(client_fd, hbuf + (4-remains), remains, uwsgi.socket_timeout)) { uwsgi_error("uwsgi_fork_server()/uwsgi_read_nb()"); goto end; } struct uwsgi_header *uh = (struct uwsgi_header *) hbuf; // this memory area must be freed in the right place !!! char *body_argv = uwsgi_malloc(uh->_pktsize); if (uwsgi_read_nb(client_fd, body_argv, uh->_pktsize, uwsgi.socket_timeout)) { free(body_argv); uwsgi_error("uwsgi_fork_server()/uwsgi_read_nb()"); goto end; } pid_t pid = fork(); if (pid < 0) { free(body_argv); int i; for(i=0;i<fds_count;i++) close(fds[i]); // error on fork() uwsgi_error("uwsgi_fork_server()/fork()"); goto end; } else if (pid > 0) { free(body_argv); // close inherited decriptors int i; for(i=0;i<fds_count;i++) close(fds[i]); // wait for child death... waitpid(pid, NULL, 0); goto end; } else { // close Emperor channels // we do not close others file desctiptor as lot // of funny tricks could be accomplished with them if (uwsgi.has_emperor) { close(uwsgi.emperor_fd); if (uwsgi.emperor_fd_config > -1) close(uwsgi.emperor_fd_config); } // set EMPEROR_FD and FD_CONFIG env vars char *uef = uwsgi_num2str(fds[0]); if (setenv("UWSGI_EMPEROR_FD", uef, 1)) { uwsgi_error("uwsgi_fork_server()/setenv()"); exit(1); } free(uef); int pipe_config = -1; int on_demand = -1; if (uh->modifier2 & VASSAL_HAS_CONFIG && fds_count > 1) { pipe_config = fds[1]; char *uef = uwsgi_num2str(pipe_config); if (setenv("UWSGI_EMPEROR_FD_CONFIG", uef, 1)) { uwsgi_error("uwsgi_fork_server()/setenv()"); exit(1); } free(uef); } if (uh->modifier2 & VASSAL_HAS_ON_DEMAND && fds_count > 1) { if (pipe_config > -1) { if (fds_count > 2) { on_demand = fds[2]; } } else { on_demand = fds[1]; } } // dup the on_demand socket to 0 and close it if (on_demand > -1) { if (dup2(on_demand, 0) < 0) { uwsgi_error("uwsgi_fork_server()/dup2()"); exit(1); } close(on_demand); } // now fork again and die pid_t new_pid = fork(); if (new_pid < 0) { uwsgi_error("uwsgi_fork_server()/fork()"); exit(1); } else if (new_pid > 0) { exit(0); } else { // send the pid to the client_fd and close it struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); // leave space for header ub->pos = 4; if (uwsgi_buffer_append_keynum(ub, "pid", 3, getpid())) exit(1); // fix uwsgi header if (uwsgi_buffer_set_uh(ub, 35, 0)) goto end; // send_pid() if (uwsgi_write_nb(client_fd, ub->buf, ub->pos, uwsgi.socket_timeout)) exit(1); close(client_fd); uwsgi_log("double fork() and reparenting successful (new pid: %d)\n", getpid()); uwsgi_buffer_destroy(ub); // now parse the uwsgi packet array and build the argv struct uwsgi_string_list *usl = NULL, *usl_argv = NULL; uwsgi_hooked_parse_array(body_argv, uh->_pktsize, parse_argv_hook, &usl_argv); free(body_argv); // build new argc/argv uwsgi.new_argc = 0; size_t procname_len = 1; uwsgi_foreach(usl, usl_argv) { uwsgi.new_argc++; procname_len += usl->len + 1; } char *new_procname = uwsgi_calloc(procname_len); uwsgi.new_argv = uwsgi_calloc(sizeof(char *) * (uwsgi.new_argc + 1)); int counter = 0; uwsgi_foreach(usl, usl_argv) { uwsgi.new_argv[counter] = usl->value; strcat(new_procname, usl->value); strcat(new_procname, " "); counter++; } // fix process name uwsgi_set_processname(new_procname); free(new_procname); // this is the only step required to have a consistent environment uwsgi.fork_socket = NULL; // this avoids the process to re-exec itself uwsgi.exit_on_reload = 1; // fixup the Emperor communication uwsgi_check_emperor(); // continue with uWSGI startup return; } }
static void tornado_loop() { if (!uwsgi.has_threads && uwsgi.mywid == 1) { uwsgi_log("!!! Running tornado without threads IS NOT recommended, enable them with --enable-threads !!!\n"); } if (uwsgi.socket_timeout < 30) { uwsgi_log("!!! Running tornado with a socket-timeout lower than 30 seconds is not recommended, tune it with --socket-timeout !!!\n"); } if (!uwsgi.async_waiting_fd_table) uwsgi.async_waiting_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd); if (!uwsgi.async_proto_fd_table) uwsgi.async_proto_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd); // get the GIL UWSGI_GET_GIL up.gil_get = gil_tornado_get; up.gil_release = gil_tornado_release; uwsgi.wait_write_hook = uwsgi_tornado_wait_write_hook; uwsgi.wait_read_hook = uwsgi_tornado_wait_read_hook; uwsgi.schedule_fix = uwsgi_tornado_schedule_fix; if (uwsgi.async < 2) { uwsgi_log("the tornado loop engine requires async mode (--async <n>)\n"); exit(1); } if (!uwsgi.schedule_to_main) { uwsgi_log("*** DANGER *** tornado mode without coroutine/greenthread engine loaded !!!\n"); } PyObject *tornado_dict = get_uwsgi_pydict("tornado.ioloop"); if (!tornado_dict) uwsgi_pyexit; PyObject *tornado_IOLoop = PyDict_GetItemString(tornado_dict, "IOLoop"); if (!tornado_IOLoop) uwsgi_pyexit; utornado.ioloop = PyObject_CallMethod(tornado_IOLoop, "instance", NULL); if (!utornado.ioloop) uwsgi_pyexit; // main greenlet waiting for connection (one greenlet per-socket) PyObject *uwsgi_tornado_accept = PyCFunction_New(uwsgi_tornado_accept_def, NULL); Py_INCREF(uwsgi_tornado_accept); utornado.request = PyCFunction_New(uwsgi_tornado_request_def, NULL); if (!utornado.request) uwsgi_pyexit; utornado.hook_fd = PyCFunction_New(uwsgi_tornado_hook_fd_def, NULL); if (!utornado.hook_fd) uwsgi_pyexit; utornado.hook_timeout = PyCFunction_New(uwsgi_tornado_hook_timeout_def, NULL); if (!utornado.hook_timeout) uwsgi_pyexit; utornado.hook_fix = PyCFunction_New(uwsgi_tornado_hook_fix_def, NULL); if (!utornado.hook_fix) uwsgi_pyexit; utornado.read = PyObject_GetAttrString(utornado.ioloop, "READ"); if (!utornado.read) uwsgi_pyexit; utornado.write = PyObject_GetAttrString(utornado.ioloop, "WRITE"); if (!utornado.write) uwsgi_pyexit; utornado.functools = PyImport_ImportModule("functools"); if (!utornado.functools) uwsgi_pyexit; Py_INCREF(utornado.request); Py_INCREF(utornado.hook_fd); Py_INCREF(utornado.hook_timeout); Py_INCREF(utornado.hook_fix); Py_INCREF(utornado.read); Py_INCREF(utornado.write); // call add_handler on each socket struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while(uwsgi_sock) { if (PyObject_CallMethod(utornado.ioloop, "add_handler", "iOO", uwsgi_sock->fd, uwsgi_tornado_accept, utornado.read) == NULL) { uwsgi_pyexit; } uwsgi_sock = uwsgi_sock->next; } if (PyObject_CallMethod(utornado.ioloop, "start", NULL) == NULL) { uwsgi_pyexit; } // never here ? }
static void stats_pusher_statsd(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) { if (!uspi->configured) { struct statsd_node *sn = uwsgi_calloc(sizeof(struct statsd_node)); char *comma = strchr(uspi->arg, ','); if (comma) { sn->prefix = comma+1; sn->prefix_len = strlen(sn->prefix); *comma = 0; } else { sn->prefix = "uwsgi"; sn->prefix_len = 5; } char *colon = strchr(uspi->arg, ':'); if (!colon) { uwsgi_log("invalid statsd address %s\n", uspi->arg); if (comma) *comma = ','; free(sn); return; } sn->addr_len = socket_to_in_addr(uspi->arg, colon, 0, &sn->addr.sa_in); sn->fd = socket(AF_INET, SOCK_DGRAM, 0); if (sn->fd < 0) { uwsgi_error("stats_pusher_statsd()/socket()"); if (comma) *comma = ','; free(sn); return; } uwsgi_socket_nb(sn->fd); if (comma) *comma = ','; uspi->data = sn; uspi->configured = 1; } // we use the same buffer for all of the packets struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); struct uwsgi_metric *um = uwsgi.metrics; while(um) { if (u_stats_pusher_statsd.no_workers && !uwsgi_starts_with(um->name, um->name_len, "worker.", 7)) { goto next; } uwsgi_rlock(uwsgi.metrics_lock); // ignore return value if (um->type == UWSGI_METRIC_GAUGE) { statsd_send_metric(ub, uspi, um->name, um->name_len, *um->value, "|g"); } else { statsd_send_metric(ub, uspi, um->name, um->name_len, *um->value, "|c"); } uwsgi_rwunlock(uwsgi.metrics_lock); if (um->reset_after_push){ uwsgi_wlock(uwsgi.metrics_lock); *um->value = um->initial_value; uwsgi_rwunlock(uwsgi.metrics_lock); } next: um = um->next; } uwsgi_buffer_destroy(ub); }
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); } } if (uperl.argv_items || uperl.argv_item) { AV *uperl_argv = GvAV(PL_argvgv); if (uperl.argv_items) { char *argv_list = uwsgi_str(uperl.argv_items); char *p = strtok(argv_list, " "); while(p) { av_push(uperl_argv, newSVpv(p, 0)); p = strtok(NULL, " "); } } struct uwsgi_string_list *usl = uperl.argv_item; while(usl) { av_push(uperl_argv, newSVpv(usl->value, usl->len)); usl = usl->next; } } 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]); } uperl.loaded = 1; 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; }
void uwsgi_detach_daemons() { struct uwsgi_daemon *ud = uwsgi.daemons; while (ud) { #ifdef UWSGI_SSL // stop any legion daemon, doesn't matter if dumb or smart if (ud->pid > 0 && (ud->legion || !ud->pidfile)) { #else // stop only dumb daemons if (ud->pid > 0 && !ud->pidfile) { #endif uwsgi_log("[uwsgi-daemons] stopping daemon (pid: %d): %s\n", (int) ud->pid, ud->command); // try to stop daemon gracefully, kill it if it won't die // if mercy is not set then wait up to 3 seconds time_t timeout = uwsgi_now() + (uwsgi.reload_mercy ? uwsgi.reload_mercy : 3); int waitpid_status; while (!kill(ud->pid, 0)) { kill(-ud->pid, ud->stop_signal); sleep(1); waitpid(-ud->pid, &waitpid_status, WNOHANG); if (uwsgi_now() >= timeout) { uwsgi_log("[uwsgi-daemons] daemon did not die in time, killing (pid: %d): %s\n", (int) ud->pid, ud->command); kill(-ud->pid, SIGKILL); break; } } // unregister daemon to prevent it from being respawned ud->registered = 0; } ud = ud->next; } } void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) { // skip unregistered daemons if (!ud->registered) return; int throttle = 0; if (uwsgi.current_time - ud->last_spawn <= 3) { throttle = ud->respawns - (uwsgi.current_time - ud->last_spawn); // if ud->respawns == 0 then we can end up with throttle < 0 if (throttle <= 0) throttle = 1; } pid_t pid = uwsgi_fork("uWSGI external daemon"); if (pid < 0) { uwsgi_error("fork()"); return; } if (pid > 0) { ud->has_daemonized = 0; ud->pid = pid; ud->status = 1; ud->pidfile_checks = 0; if (ud->respawns == 0) { ud->born = uwsgi_now(); } ud->respawns++; ud->last_spawn = uwsgi_now(); } else { // close uwsgi sockets uwsgi_close_all_sockets(); uwsgi_close_all_fds(); if (ud->gid) { if (setgid(ud->gid)) { uwsgi_error("uwsgi_spawn_daemon()/setgid()"); exit(1); } } if (ud->uid) { if (setuid(ud->uid)) { uwsgi_error("uwsgi_spawn_daemon()/setuid()"); exit(1); } } if (ud->daemonize) { /* refork... */ pid = fork(); if (pid < 0) { uwsgi_error("fork()"); exit(1); } if (pid != 0) { _exit(0); } uwsgi_write_pidfile(ud->pidfile); } if (!uwsgi.daemons_honour_stdin && !ud->honour_stdin) { // /dev/null will became stdin uwsgi_remap_fd(0, "/dev/null"); } if (setsid() < 0) { uwsgi_error("setsid()"); exit(1); } if (!ud->pidfile) { #ifdef __linux__ if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) { uwsgi_error("prctl()"); } #endif } if (throttle) { uwsgi_log("[uwsgi-daemons] throttling \"%s\" for %d seconds\n", ud->command, throttle); sleep((unsigned int) throttle); } uwsgi_log("[uwsgi-daemons] %sspawning \"%s\" (uid: %d gid: %d)\n", ud->respawns > 0 ? "re" : "", ud->command, (int) getuid(), (int) getgid()); uwsgi_exec_command_with_args(ud->command); uwsgi_log("[uwsgi-daemons] unable to spawn \"%s\"\n", ud->command); // never here; exit(1); } return; } void uwsgi_opt_add_daemon(char *opt, char *value, void *none) { struct uwsgi_daemon *uwsgi_ud = uwsgi.daemons, *old_ud; char *pidfile = NULL; int daemonize = 0; int freq = 10; char *space = NULL; int stop_signal = SIGTERM; int reload_signal = 0; char *command = uwsgi_str(value); #ifdef UWSGI_SSL char *legion = NULL; if (!uwsgi_starts_with(opt, strlen(command), "legion-", 7)) { space = strchr(command, ' '); if (!space) { uwsgi_log("invalid legion daemon syntax: %s\n", command); exit(1); } *space = 0; legion = command; command = space+1; } #endif if (!strcmp(opt, "smart-attach-daemon") || !strcmp(opt, "smart-attach-daemon2") || !strcmp(opt, "legion-smart-attach-daemon") || !strcmp(opt, "legion-smart-attach-daemon2")) { space = strchr(command, ' '); if (!space) { uwsgi_log("invalid smart-attach-daemon syntax: %s\n", command); exit(1); } *space = 0; pidfile = command; // check for freq char *comma = strchr(pidfile, ','); if (comma) { *comma = 0; freq = atoi(comma + 1); } command = space + 1; if (!strcmp(opt, "smart-attach-daemon2") || !strcmp(opt, "legion-smart-attach-daemon2")) { daemonize = 1; } } if (!uwsgi_ud) { uwsgi.daemons = uwsgi_calloc(sizeof(struct uwsgi_daemon)); uwsgi_ud = uwsgi.daemons; } else { while (uwsgi_ud) { old_ud = uwsgi_ud; uwsgi_ud = uwsgi_ud->next; } uwsgi_ud = uwsgi_calloc(sizeof(struct uwsgi_daemon)); old_ud->next = uwsgi_ud; } uwsgi_ud->command = command; uwsgi_ud->pid = 0; uwsgi_ud->status = 0; uwsgi_ud->freq = freq; uwsgi_ud->registered = 0; uwsgi_ud->next = NULL; uwsgi_ud->respawns = 0; uwsgi_ud->last_spawn = 0; uwsgi_ud->daemonize = daemonize; uwsgi_ud->pidfile = pidfile; uwsgi_ud->control = 0; uwsgi_ud->stop_signal = stop_signal; uwsgi_ud->reload_signal = reload_signal; if (!strcmp(opt, "attach-control-daemon")) { uwsgi_ud->control = 1; } #ifdef UWSGI_SSL uwsgi_ud->legion = legion; #endif uwsgi.daemons_cnt++; } void uwsgi_opt_add_daemon2(char *opt, char *value, void *none) { struct uwsgi_daemon *uwsgi_ud = uwsgi.daemons, *old_ud; char *d_command = NULL; char *d_freq = NULL; char *d_pidfile = NULL; char *d_control = NULL; char *d_legion = NULL; char *d_daemonize = NULL; char *d_touch = NULL; char *d_stopsignal = NULL; char *d_reloadsignal = NULL; char *d_stdin = NULL; char *d_uid = NULL; char *d_gid = NULL; char *arg = uwsgi_str(value); if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=', "command", &d_command, "cmd", &d_command, "exec", &d_command, "freq", &d_freq, "pidfile", &d_pidfile, "control", &d_control, "daemonize", &d_daemonize, "daemon", &d_daemonize, "touch", &d_touch, "stopsignal", &d_stopsignal, "stop_signal", &d_stopsignal, "reloadsignal", &d_reloadsignal, "reload_signal", &d_reloadsignal, "stdin", &d_stdin, "uid", &d_uid, "gid", &d_gid, NULL)) { uwsgi_log("invalid --%s keyval syntax\n", opt); exit(1); } if (!d_command) { uwsgi_log("--%s: you need to specify a 'command' key\n", opt); exit(1); } #ifndef UWSGI_SSL if (d_legion) { uwsgi_log("legion subsystem is not supported on this uWSGI version, rebuild with ssl support\n"); exit(1); } #endif if (!uwsgi_ud) { uwsgi.daemons = uwsgi_calloc(sizeof(struct uwsgi_daemon)); uwsgi_ud = uwsgi.daemons; } else { while (uwsgi_ud) { old_ud = uwsgi_ud; uwsgi_ud = uwsgi_ud->next; } uwsgi_ud = uwsgi_calloc(sizeof(struct uwsgi_daemon)); old_ud->next = uwsgi_ud; } uwsgi_ud->command = d_command; uwsgi_ud->freq = d_freq ? atoi(d_freq) : 10; uwsgi_ud->daemonize = d_daemonize ? 1 : 0; uwsgi_ud->pidfile = d_pidfile; uwsgi_ud->stop_signal = d_stopsignal ? atoi(d_stopsignal) : SIGTERM; uwsgi_ud->reload_signal = d_reloadsignal ? atoi(d_reloadsignal) : 0; uwsgi_ud->control = d_control ? 1 : 0; uwsgi_ud->uid = d_uid ? atoi(d_uid) : 0; uwsgi_ud->gid = d_gid ? atoi(d_gid) : 0; uwsgi_ud->honour_stdin = d_stdin ? 1 : 0; #ifdef UWSGI_SSL uwsgi_ud->legion = d_legion; #endif if (d_touch) { size_t i,rlen = 0; char **argv = uwsgi_split_quoted(d_touch, strlen(d_touch), ";", &rlen); for(i=0;i<rlen;i++) { uwsgi_string_new_list(&uwsgi_ud->touch, argv[i]); } if (argv) free(argv); } uwsgi.daemons_cnt++; free(arg); }
int bind_to_unix_dgram(char *socket_name) { int serverfd; struct sockaddr_un *uws_addr; socklen_t len; serverfd = socket(AF_UNIX, SOCK_DGRAM, 0); if (serverfd < 0) { uwsgi_error("socket()"); uwsgi_nuclear_blast(); } if (unlink(socket_name) != 0 && errno != ENOENT) { uwsgi_error("unlink()"); } uws_addr = uwsgi_calloc(sizeof(struct sockaddr_un)); uws_addr->sun_family = AF_UNIX; memcpy(uws_addr->sun_path, socket_name, UMIN(strlen(socket_name), 102)); len = strlen(socket_name); #ifdef __HAIKU__ if (bind(serverfd, (struct sockaddr *) uws_addr, sizeof(struct sockaddr_un))) { #else if (bind(serverfd, (struct sockaddr *) uws_addr, len + ((void *) uws_addr->sun_path - (void *) uws_addr)) != 0) { #endif uwsgi_error("bind()"); uwsgi_nuclear_blast(); } return serverfd; } int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abstract_socket) { int serverfd; struct sockaddr_un *uws_addr; socklen_t len; // leave 1 byte for abstract namespace (108 linux -> 104 bsd/mac) if (strlen(socket_name) > 102) { uwsgi_log("invalid socket name\n"); uwsgi_nuclear_blast(); } if (socket_name[0] == '@') { abstract_socket = 1; } else if (strlen(socket_name) > 1 && socket_name[0] == '\\' && socket_name[1] == '0') { abstract_socket = 1; } uws_addr = malloc(sizeof(struct sockaddr_un)); if (uws_addr == NULL) { uwsgi_error("malloc()"); uwsgi_nuclear_blast(); } memset(uws_addr, 0, sizeof(struct sockaddr_un)); serverfd = socket(AF_UNIX, SOCK_STREAM, 0); if (serverfd < 0) { uwsgi_error("socket()"); uwsgi_nuclear_blast(); } if (abstract_socket == 0) { if (unlink(socket_name) != 0 && errno != ENOENT) { uwsgi_error("unlink()"); } } if (abstract_socket == 1) { uwsgi_log("setting abstract socket mode (warning: only Linux supports this)\n"); } uws_addr->sun_family = AF_UNIX; if (socket_name[0] == '@') { memcpy(uws_addr->sun_path + abstract_socket, socket_name + 1, UMIN(strlen(socket_name + 1), 101)); len = strlen(socket_name) + 1; } else if (strlen(socket_name) > 1 && socket_name[0] == '\\' && socket_name[1] == '0') { memcpy(uws_addr->sun_path + abstract_socket, socket_name + 2, UMIN(strlen(socket_name + 2), 101)); len = strlen(socket_name + 1) + 1; } else if (abstract_socket) { memcpy(uws_addr->sun_path + 1, socket_name, UMIN(strlen(socket_name), 101)); len = strlen(socket_name) + 1; } else { memcpy(uws_addr->sun_path + abstract_socket, socket_name, UMIN(strlen(socket_name), 102)); len = strlen(socket_name); } #ifdef __HAIKU__ if (bind(serverfd, (struct sockaddr *) uws_addr, sizeof(struct sockaddr_un))) { #else if (bind(serverfd, (struct sockaddr *) uws_addr, len + ((void *) uws_addr->sun_path - (void *) uws_addr)) != 0) { #endif uwsgi_error("bind()"); uwsgi_nuclear_blast(); } if (listen(serverfd, listen_queue) != 0) { uwsgi_error("listen()"); uwsgi_nuclear_blast(); } // chmod unix socket for lazy users if (chmod_socket == 1 && abstract_socket == 0) { if (uwsgi.chmod_socket_value) { if (chmod(socket_name, uwsgi.chmod_socket_value) != 0) { uwsgi_error("chmod()"); } } else { uwsgi_log("chmod() socket to 666 for lazy and brave users\n"); if (chmod(socket_name, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) != 0) { uwsgi_error("chmod()"); } } } free(uws_addr); return serverfd; } #ifdef UWSGI_UDP int bind_to_udp(char *socket_name, int multicast, int broadcast) { int serverfd; struct sockaddr_in uws_addr; char *udp_port; int bcast = 1; int reuse = 1; #ifdef UWSGI_MULTICAST struct ip_mreq mc; uint8_t loop = 1; #endif udp_port = strchr(socket_name, ':'); if (udp_port == NULL) { return -1; } udp_port[0] = 0; if (socket_name[0] == 0 && multicast) { uwsgi_log("invalid multicast address\n"); return -1; } memset(&uws_addr, 0, sizeof(struct sockaddr_in)); uws_addr.sin_family = AF_INET; uws_addr.sin_port = htons(atoi(udp_port + 1)); #ifdef UWSGI_MULTICAST if (!broadcast && !multicast) { char quad[4]; char *first_part = strchr(socket_name, '.'); if (first_part && first_part - socket_name < 4) { memset(quad, 0, 4); memcpy(quad, socket_name, first_part - socket_name); if (atoi(quad) >= 224 && atoi(quad) <= 239) { multicast = 1; } } #else if (!broadcast) { #endif if (!strcmp(socket_name, "255.255.255.255")) { broadcast = 1; } } if (broadcast) { uws_addr.sin_addr.s_addr = INADDR_BROADCAST; } else if (socket_name[0] != 0) { uws_addr.sin_addr.s_addr = inet_addr(socket_name); } else { uws_addr.sin_addr.s_addr = INADDR_ANY; } serverfd = socket(AF_INET, SOCK_DGRAM, 0); if (serverfd < 0) { uwsgi_error("socket()"); return -1; } if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) { uwsgi_error("setsockopt()"); } #ifdef UWSGI_MULTICAST if (multicast) { // if multicast is enabled remember to bind to INADDR_ANY uws_addr.sin_addr.s_addr = INADDR_ANY; mc.imr_multiaddr.s_addr = inet_addr(socket_name); mc.imr_interface.s_addr = INADDR_ANY; } #endif if (broadcast) { if (setsockopt(serverfd, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast))) { perror("setsockopt"); close(serverfd); return -1; } } if (bind(serverfd, (struct sockaddr *) &uws_addr, sizeof(uws_addr)) != 0) { uwsgi_error("bind()"); close(serverfd); return -1; } #ifdef UWSGI_MULTICAST if (multicast) { uwsgi_log("[uWSGI] joining multicast group: %s:%d\n", socket_name, ntohs(uws_addr.sin_port)); if (setsockopt(serverfd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop))) { uwsgi_error("setsockopt()"); } if (setsockopt(serverfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mc, sizeof(mc))) { uwsgi_error("setsockopt()"); } if (setsockopt(serverfd, IPPROTO_IP, IP_MULTICAST_TTL, &uwsgi.multicast_ttl, sizeof(uwsgi.multicast_ttl))) { uwsgi_error("setsockopt()"); } } #endif udp_port[0] = ':'; return serverfd; } #endif int uwsgi_connectn(char *socket_name, uint16_t len, int timeout, int async) { int fd; char *zeroed_socket_name = uwsgi_concat2n(socket_name, len, "", 0); fd = uwsgi_connect(zeroed_socket_name, timeout, async); free(zeroed_socket_name); return fd; }
static void uwsgi_rados_add_mountpoint(char *arg, size_t arg_len) { struct uwsgi_rados_mountpoint *urmp = uwsgi_calloc(sizeof(struct uwsgi_rados_mountpoint)); if (uwsgi_kvlist_parse(arg, arg_len, ',', '=', "mountpoint", &urmp->mountpoint, "config", &urmp->config, "pool", &urmp->pool, "timeout", &urmp->str_timeout, "allow_put", &urmp->allow_put, "allow_delete", &urmp->allow_delete, "allow_mkcol", &urmp->allow_mkcol, "allow_propfind", &urmp->allow_propfind, "username", &urmp->username, "buffer_size", &urmp->str_buffer_size, "put_buffer_size", &urmp->str_put_buffer_size, NULL)) { uwsgi_log("unable to parse rados mountpoint definition\n"); exit(1); } if (!urmp->mountpoint|| !urmp->pool) { uwsgi_log("[rados] mount requires a mountpoint, and a pool name.\n"); exit(1); } if (urmp->str_timeout) { urmp->timeout = atoi(urmp->str_timeout); } if (urmp->str_buffer_size) { urmp->buffer_size = atoi(urmp->str_buffer_size); if (urmp->buffer_size > MAX_BUF_SIZE) { urmp->buffer_size = MAX_BUF_SIZE; } else if (urmp->buffer_size < MIN_BUF_SIZE) { urmp->buffer_size = MIN_BUF_SIZE; } } else { urmp->buffer_size = DEF_BUF_SIZE; } if (urmp->str_put_buffer_size) { urmp->put_buffer_size = atoi(urmp->str_put_buffer_size); if (urmp->put_buffer_size > MAX_BUF_SIZE) { urmp->put_buffer_size = MAX_BUF_SIZE; } else if (urmp->put_buffer_size < MIN_BUF_SIZE) { urmp->put_buffer_size = MIN_BUF_SIZE; } } else { urmp->put_buffer_size = urmp->buffer_size; } time_t now = uwsgi_now(); uwsgi_log("[rados] mounting %s ...\n", urmp->mountpoint); rados_t cluster; if (rados_create(&cluster, urmp->username) < 0) { uwsgi_error("can't create Ceph cluster handle"); exit(1); } urmp->cluster = cluster; if (urmp->config) uwsgi_log("using Ceph conf:%s\n", urmp->config); else uwsgi_log("using default Ceph conf.\n"); if (rados_conf_read_file(cluster, urmp->config) < 0) { uwsgi_error("can't configure Ceph cluster handle"); exit(1); } int timeout = urmp->timeout ? urmp->timeout : urados.timeout; char *timeout_str = uwsgi_num2str(timeout); rados_conf_set(cluster, "client_mount_timeout", timeout_str); rados_conf_set(cluster, "rados_mon_op_timeout", timeout_str); rados_conf_set(cluster, "rados_osd_op_timeout", timeout_str); free(timeout_str); if (rados_connect(cluster) < 0) { uwsgi_error("can't connect with Ceph cluster"); exit(1); } void *ctx_ptr; if (uwsgi.threads > 1) { int i; rados_ioctx_t *ctxes = uwsgi_calloc(sizeof(rados_ioctx_t) * uwsgi.threads); for(i=0;i<uwsgi.threads;i++) { if (rados_ioctx_create(cluster, urmp->pool, &ctxes[i]) < 0) { uwsgi_error("can't open rados pool") rados_shutdown(cluster); exit(1); } } ctx_ptr = ctxes; } else { rados_ioctx_t ctx; if (rados_ioctx_create(cluster, urmp->pool, &ctx) < 0) { uwsgi_error("can't open rados pool") rados_shutdown(cluster); exit(1); } ctx_ptr = ctx; } char fsid[37]; rados_cluster_fsid(cluster, fsid, 37); uwsgi_log("connected to Ceph pool: %s on cluster %.*s\n", urmp->pool, 37, fsid); int id = uwsgi_apps_cnt; struct uwsgi_app *ua = uwsgi_add_app(id, rados_plugin.modifier1, urmp->mountpoint, strlen(urmp->mountpoint), NULL, (void*)1); if (!ua) { uwsgi_log("[rados] unable to mount %s\n", urmp->mountpoint); rados_shutdown(cluster); exit(1); } ua->responder0 = ctx_ptr; ua->responder1 = urmp; ua->started_at = now; ua->startup_time = uwsgi_now() - now; uwsgi_log("Rados app/mountpoint %d (%s) loaded in %d seconds at %p\n", id, urmp->mountpoint, (int) ua->startup_time, ctx_ptr); }
static void carbon_post_init() { int i; struct uwsgi_string_list *usl = u_carbon.servers; if (!uwsgi.sockets) return; if (!u_carbon.servers) return; while(usl) { struct carbon_server_list *u_server = uwsgi_calloc(sizeof(struct carbon_server_list)); u_server->value = usl->value; u_server->healthy = 1; u_server->errors = 0; if (u_carbon.servers_data) { u_server->next = u_carbon.servers_data; } u_carbon.servers_data = u_server; uwsgi_log("[carbon] added server %s\n", usl->value); usl = usl->next; } if (!u_carbon.root_node) u_carbon.root_node = "uwsgi."; if (strlen(u_carbon.root_node) && !uwsgi_endswith(u_carbon.root_node, ".")) { u_carbon.root_node = uwsgi_concat2(u_carbon.root_node, "."); } if (u_carbon.freq < 1) u_carbon.freq = 60; if (u_carbon.timeout < 1) u_carbon.timeout = 3; if (u_carbon.max_retries <= 0) u_carbon.max_retries = 1; if (u_carbon.retry_delay <= 0) u_carbon.retry_delay = 7; if (!u_carbon.id) { u_carbon.id = uwsgi_str(uwsgi.sockets->name); for(i=0;i<(int)strlen(u_carbon.id);i++) { if (u_carbon.id[i] == '.') u_carbon.id[i] = '_'; } } u_carbon.hostname = uwsgi_str(uwsgi.hostname); if (u_carbon.hostname_dot_replacement) { for(i=0;i<(int)strlen(u_carbon.hostname);i++) { if (u_carbon.hostname[i] == '.') u_carbon.hostname[i] = u_carbon.hostname_dot_replacement[0]; } } if (!u_carbon.last_busyness_values) { u_carbon.last_busyness_values = uwsgi_calloc(sizeof(unsigned long long) * uwsgi.numproc); } if (!u_carbon.current_busyness_values) { u_carbon.current_busyness_values = uwsgi_calloc(sizeof(unsigned long long) * uwsgi.numproc); } if (!u_carbon.was_busy) { u_carbon.was_busy = uwsgi_calloc(sizeof(int) * uwsgi.numproc); } // set next update to now()+retry_delay, this way we will have first flush just after start u_carbon.last_update = uwsgi_now() - u_carbon.freq + u_carbon.retry_delay; uwsgi_log("[carbon] carbon plugin started, %is frequency, %is timeout, max retries %i, retry delay %is\n", u_carbon.freq, u_carbon.timeout, u_carbon.max_retries, u_carbon.retry_delay); struct uwsgi_stats_pusher_instance *uspi = uwsgi_stats_pusher_add(u_carbon.pusher, NULL); uspi->freq = u_carbon.freq; // no need to generate the json uspi->raw=1; }