static int uwsgi_libssh2_init() { char *home = getenv("HOME"); if (!home) { uwsgi_error("uwsgi_libssh2_init()/getenv()"); } if (!ulibssh2.mountpoints && !ulibssh2.username) { uwsgi_log("[SSH] you need to specify at least a mountpoint or a username!"); } if (ulibssh2.auth_pw && !ulibssh2.password) { uwsgi_log("[SSH] password authentication needs a password!"); exit(1); } if (!ulibssh2.private_key_path) { ulibssh2.private_key_path = uwsgi_concat2(home, "/.ssh/id_rsa"); } if (!ulibssh2.private_key_passphrase) { ulibssh2.private_key_passphrase = ""; } if (!ulibssh2.known_hosts_path) { ulibssh2.known_hosts_path = uwsgi_concat2(home, "/.ssh/known_hosts"); } if (!ulibssh2.ssh_timeout) { ulibssh2.ssh_timeout = uwsgi.socket_timeout; } return 0; }
static int uwsgi_ssh_routing(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { // ssh://username[:password]@127.0.0.1:2222/tmp/foo.txt,username[:password]@127.0.0.1:2222/tmp/foobis.txt char *remote_url = NULL; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) { uwsgi_error("uwsgi_ssh_routing()/uwsgi_routing_translate()"); remote_url = ur->data; } else { remote_url = ub->buf; } remote_url = uwsgi_concat2(remote_url, ","); char *remote_pointer = remote_url; char *comma = NULL; struct uwsgi_ssh_mountpoint *usm = uwsgi_calloc(sizeof(struct uwsgi_ssh_mountpoint)); int return_status = -1; while ((comma = strchr(remote_url, ',')) != NULL) { *comma = 0; if (uwsgi_ssh_url_parser(remote_url, &usm)) { uwsgi_log("[SSH] skipping malformed route %s\n", remote_url); return_status = 500; continue; } if (!(return_status = uwsgi_ssh_request_file( wsgi_req, usm->path, usm ))) { goto end; } else { uwsgi_log("[SSH] route %s to %s returned %d. Engaging fail-over mechanism (if any)...\n", usm->remote, usm->path, return_status); } remote_url = comma + 1; } switch (return_status) { case 404: uwsgi_404(wsgi_req); break; case 500: default: uwsgi_500(wsgi_req); } end: free(remote_pointer); uwsgi_buffer_destroy(ub); return UWSGI_OK; }
char *uwsgi_pythonize(char *orig) { char *name = uwsgi_concat2(orig, ""); size_t i; size_t len = 0; if (!strncmp(name, "sym://", 6)) { name+=6; } else if (!strncmp(name, "http://", 7)) { name+=7; } else if (!strncmp(name, "data://", 7)) { name+=7; } len = strlen(name); for(i=0;i<len;i++) { if (name[i] == '.') { name[i] = '_'; } else if (name[i] == '/') { name[i] = '_'; } } if ((name[len-3] == '.' || name[len-3] == '_') && name[len-2] == 'p' && name[len-1] == 'y') { name[len-3] = 0; } return name; }
void uwsgi_autoload_plugins_by_name(char *argv_zero) { char *plugins_requested = NULL; char *original_proc_name = getenv("UWSGI_ORIGINAL_PROC_NAME"); if (!original_proc_name) { // here we use argv[0]; original_proc_name = argv_zero; setenv("UWSGI_ORIGINAL_PROC_NAME", original_proc_name, 1); } char *p = strrchr(original_proc_name, '/'); if (p == NULL) p = original_proc_name; p = strstr(p, "uwsgi_"); if (p != NULL) { plugins_requested = strtok(uwsgi_str(p + 6), "_"); while (plugins_requested) { uwsgi_log("[uwsgi] implicit plugin requested %s\n", plugins_requested); uwsgi_load_plugin(-1, plugins_requested, NULL); plugins_requested = strtok(NULL, "_"); } } plugins_requested = getenv("UWSGI_PLUGINS"); if (plugins_requested) { plugins_requested = uwsgi_concat2(plugins_requested, ""); char *p = strtok(plugins_requested, ","); while (p != NULL) { uwsgi_load_plugin(-1, p, NULL); p = strtok(NULL, ","); } } }
void uwsgi_opt_ldap_dump_ldif(char *opt, char *foo, void *bar) { int i; int items; uwsgi_log("\n"); uwsgi_log("dn: cn=uwsgi,cn=schema,cn=config\n"); uwsgi_log("objectClass: olcSchemaConfig\n"); uwsgi_log("cn: uwsgi\n"); struct uwsgi_ldap_entry *entry, *ule = get_ldap_names(&items); for (i = 0; i < items; i++) { entry = &ule[i]; uwsgi_log("olcAttributeTypes: ( 1.3.6.1.4.1.35156.17.4.%d NAME (%s", entry->num, entry->names); if (entry->has_arg) { uwsgi_log(" ) SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )\n"); } else { uwsgi_log(" ) SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )\n"); } } uwsgi_log("olcAttributeTypes: ( 1.3.6.1.4.1.35156.17.4.50000 NAME 'uWSGInull' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )\n"); uwsgi_log("olcObjectClasses: ( 1.3.6.1.4.1.35156.17.3.1 NAME 'uWSGIConfig' SUP top AUXILIARY DESC 'uWSGI configuration' MAY ( "); for (i = 0; i < items; i++) { entry = &ule[i]; char *list2 = uwsgi_concat2(entry->names + 1, ""); char *p = strtok(list2, " "); while (p != NULL) { uwsgi_log("%.*s $ ", strlen(p) - 2, p + 1); p = strtok(NULL, " "); } free(list2); } uwsgi_log("uWSGInull ))\n"); uwsgi_log("\n"); exit(0); }
/* trying to emulate Graham's mod_wsgi, this will allows easy and fast migrations */ PyObject *uwsgi_file_loader(void *arg1) { char *filename = (char *) arg1; PyObject *wsgi_file_module, *wsgi_file_dict; PyObject *wsgi_file_callable; char *callable = up.callable; if (!callable) callable = "application"; char *pythonized_filename = uwsgi_pythonize(filename); char *py_filename = uwsgi_concat2("uwsgi_file_", pythonized_filename); free(pythonized_filename); wsgi_file_module = uwsgi_pyimport_by_filename(py_filename, filename); if (!wsgi_file_module) { PyErr_Print(); free(py_filename); return NULL; } wsgi_file_dict = PyModule_GetDict(wsgi_file_module); if (!wsgi_file_dict) { PyErr_Print(); Py_DECREF(wsgi_file_module); free(py_filename); return NULL; } wsgi_file_callable = PyDict_GetItemString(wsgi_file_dict, callable); if (!wsgi_file_callable) { PyErr_Print(); Py_DECREF(wsgi_file_dict); Py_DECREF(wsgi_file_module); free(py_filename); uwsgi_log( "unable to find \"application\" callable in file %s\n", filename); return NULL; } if (!PyFunction_Check(wsgi_file_callable) && !PyCallable_Check(wsgi_file_callable)) { uwsgi_log( "\"application\" must be a callable object in file %s\n", filename); Py_DECREF(wsgi_file_callable); Py_DECREF(wsgi_file_dict); Py_DECREF(wsgi_file_module); free(py_filename); return NULL; } free(py_filename); return wsgi_file_callable; }
struct uwsgi_imperial_monitor *imperial_monitor_get_by_scheme(char *arg) { struct uwsgi_imperial_monitor *uim = uwsgi.emperor_monitors; while (uim) { char *scheme = uwsgi_concat2(uim->scheme, "://"); if (!uwsgi_starts_with(arg, strlen(arg), scheme, strlen(scheme))) { free(scheme); return uim; } free(scheme); uim = uim->next; } return NULL; }
char *uwsgi_getsockname(int fd) { socklen_t socket_type_len = sizeof(struct sockaddr_un); union uwsgi_sockaddr usa; union uwsgi_sockaddr_ptr gsa; char computed_port[6]; char ipv4a[INET_ADDRSTRLEN + 1]; gsa.sa = (struct sockaddr *) &usa; if (!getsockname(fd, gsa.sa, &socket_type_len)) { if (gsa.sa->sa_family == AF_UNIX) { if (usa.sa_un.sun_path[0] == 0) { return uwsgi_concat2("@", usa.sa_un.sun_path + 1); } else { return uwsgi_str(usa.sa_un.sun_path); } } else { memset(ipv4a, 0, INET_ADDRSTRLEN + 1); memset(computed_port, 0, 6); if (snprintf(computed_port, 6, "%d", ntohs(gsa.sa_in->sin_port)) > 0) { if (inet_ntop(AF_INET, (const void *) &gsa.sa_in->sin_addr.s_addr, ipv4a, INET_ADDRSTRLEN)) { if (!strcmp("0.0.0.0", ipv4a)) { return uwsgi_concat2(":", computed_port); } else { return uwsgi_concat3(ipv4a, ":", computed_port); } } } } } return NULL; }
int uwsgi_cr_map_use_cs(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) { if (uwsgi.p[ucr->code_string_modifier1]->code_string) { char *name = uwsgi_concat2("uwsgi_", ucr->short_name); peer->instance_address = uwsgi.p[ucr->code_string_modifier1]->code_string(name, ucr->code_string_code, ucr->code_string_function, peer->key, peer->key_len); free(name); if (peer->instance_address) { peer->instance_address_len = strlen(peer->instance_address); char *cs_mod = uwsgi_str_contains(peer->instance_address, peer->instance_address_len, ','); if (cs_mod) { peer->modifier1 = uwsgi_str_num(cs_mod + 1, (peer->instance_address_len - (cs_mod - peer->instance_address)) - 1); peer->instance_address_len = (cs_mod - peer->instance_address); } } } return 0; }
void uwsgi_opt_ini_paste(char *opt, char *value, void *foobar) { uwsgi_opt_load_ini(opt, value, NULL); if (value[0] != '/') { up.paste = uwsgi_concat4("config:", uwsgi.cwd, "/", value); } else { up.paste = uwsgi_concat2("config:", value); } if (!strcmp("ini-paste-logged", opt)) { up.paste_logger = 1; } }
int uwsgi_cr_map_use_cs(struct uwsgi_corerouter *ucr, struct corerouter_session *cr_session) { if (uwsgi.p[ucr->code_string_modifier1]->code_string) { char *name = uwsgi_concat2("uwsgi_", ucr->short_name); cr_session->instance_address = uwsgi.p[ucr->code_string_modifier1]->code_string(name, ucr->code_string_code, ucr->code_string_function, cr_session->hostname, cr_session->hostname_len); free(name); if (cr_session->instance_address) { cr_session->instance_address_len = strlen(cr_session->instance_address); char *cs_mod = uwsgi_str_contains(cr_session->instance_address, cr_session->instance_address_len, ','); if (cs_mod) { cr_session->modifier1 = uwsgi_str_num(cs_mod + 1, (cr_session->instance_address_len - (cs_mod - cr_session->instance_address)) - 1); cr_session->instance_address_len = (cs_mod - cr_session->instance_address); } } } return 0; }
int uwsgi_ssh_url_parser(char *url, struct uwsgi_ssh_mountpoint **usm) { // [ssh://]username[:password]@host:port/path if (!url || !(*usm)) { return -1; } if (!memcmp(url, "ssh://", 6)) { url += 6; } // first of all, the remote path char *slash = strchr(url, '/'); if (slash) { *slash = 0; (*usm)->path = uwsgi_concat2("/", slash + 1); } else { uwsgi_log("[SSH] malformed ssh url (path)\n"); return -1; } // then, the user:password char *at = strchr(url, '@'); if (at) { *at = 0; char *colon = strchr(url, ':'); if (colon) { *colon = 0; (*usm)->password = uwsgi_str(colon + 1); } else { (*usm)->password = NULL; // there is no password! } (*usm)->username = uwsgi_str(url); // and eventually, the remote host (ip:port) (*usm)->remote = uwsgi_str(at + 1); } else { (*usm)->remote = uwsgi_str(url); } return 0; }
static int uwsgi_webdav_prop_del(char *filename, char *attr, char *ns) { int ret = 0; #if defined(__linux__) || defined(__APPLE__) char *xattr_name = NULL; if (ns) { xattr_name = uwsgi_concat4("user.uwsgi.webdav.", ns, "|", attr); } else { xattr_name = uwsgi_concat2("user.uwsgi.webdav.", attr); } #if defined(__linux__) ret = removexattr(filename, xattr_name); #elif defined(__APPLE__) ret = removexattr(filename, xattr_name, 0); #endif free(xattr_name); #endif return ret; }
void uwsgi_python_harakiri(int wid) { if (up.tracebacker) { char buf[8192]; char *address = uwsgi_concat2(up.tracebacker, uwsgi_num2str(wid)); int fd = uwsgi_connect(address, -1, 0); for (;;) { int ret = uwsgi_waitfd(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]); if (ret <= 0) { break; } ssize_t len = read(fd, buf, 8192); if (len <= 0) { break; } uwsgi_log("%.*s", (int) len, buf); } free(address); } }
static int uwsgi_ssh_request(struct wsgi_request *wsgi_req) { #if !defined(UWSGI_PLUGIN_API) || UWSGI_PLUGIN_API == 1 if (!wsgi_req->uh->pktsize) #else if (!wsgi_req->len) #endif { uwsgi_log("[SSH] skipping empty request.\n"); return -1; } if (uwsgi_parse_vars(wsgi_req)) { uwsgi_error("uwsgi_ssh_request()/uwsgi_parse_vars()"); return -1; } if (wsgi_req->path_info_len == 0 || wsgi_req->path_info_len > PATH_MAX || wsgi_req->path_info[wsgi_req->path_info_len - 1] == '/') { uwsgi_403(wsgi_req); return UWSGI_OK; } wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, libssh2_plugin.modifier1); if (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) { if (uwsgi_apps[uwsgi.default_app].modifier1 == libssh2_plugin.modifier1) { wsgi_req->app_id = uwsgi.default_app; } } if (wsgi_req->app_id == -1) { uwsgi_404(wsgi_req); return UWSGI_OK; } struct uwsgi_app *ua = &uwsgi_apps[wsgi_req->app_id]; struct uwsgi_ssh_mountpoint *usm_list = (struct uwsgi_ssh_mountpoint *) ua->callable; char *complete_filepath = NULL; char *filepath = NULL; if (wsgi_req->path_info_len > ua->mountpoint_len && memcmp(wsgi_req->path_info, ua->mountpoint, ua->mountpoint_len) == 0) { filepath = uwsgi_strncopy( wsgi_req->path_info + ua->mountpoint_len, wsgi_req->path_info_len - ua->mountpoint_len ); } else { filepath = uwsgi_strncopy(wsgi_req->path_info, wsgi_req->path_info_len); } complete_filepath = uwsgi_concat2(usm_list->path, filepath); free(filepath); int return_status = 500; struct uwsgi_ssh_mountpoint *usm = usm_list; do { return_status = uwsgi_ssh_request_file( wsgi_req, complete_filepath, usm ); } while (return_status == 500 && ((usm = usm->next) != NULL)); free(complete_filepath); switch (return_status) { case 404: uwsgi_404(wsgi_req); break; case 500: default: uwsgi_500(wsgi_req); } return 0; }
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 }
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; }
void uwsgi_setup_locking() { int i; if (uwsgi.locking_setup) return; // use the fastest available locking if (uwsgi.lock_engine) { if (!strcmp(uwsgi.lock_engine, "ipcsem")) { uwsgi_log_initial("lock engine: ipcsem\n"); atexit(uwsgi_ipcsem_clear); uwsgi.lock_ops.lock_init = uwsgi_lock_ipcsem_init; uwsgi.lock_ops.lock_check = uwsgi_lock_ipcsem_check; uwsgi.lock_ops.lock = uwsgi_lock_ipcsem; uwsgi.lock_ops.unlock = uwsgi_unlock_ipcsem; uwsgi.lock_ops.rwlock_init = uwsgi_rwlock_ipcsem_init; uwsgi.lock_ops.rwlock_check = uwsgi_rwlock_ipcsem_check; uwsgi.lock_ops.rlock = uwsgi_rlock_ipcsem; uwsgi.lock_ops.wlock = uwsgi_wlock_ipcsem; uwsgi.lock_ops.rwunlock = uwsgi_rwunlock_ipcsem; uwsgi.lock_size = 8; uwsgi.rwlock_size = 8; goto ready; } uwsgi_log("unable to find lock engine \"%s\"\n", uwsgi.lock_engine); exit(1); } uwsgi_log_initial("lock engine: %s\n", UWSGI_LOCK_ENGINE_NAME); #ifdef UWSGI_IPCSEM_ATEXIT atexit(uwsgi_ipcsem_clear); #endif uwsgi.lock_ops.lock_init = uwsgi_lock_fast_init; uwsgi.lock_ops.lock_check = uwsgi_lock_fast_check; uwsgi.lock_ops.lock = uwsgi_lock_fast; uwsgi.lock_ops.unlock = uwsgi_unlock_fast; uwsgi.lock_ops.rwlock_init = uwsgi_rwlock_fast_init; uwsgi.lock_ops.rwlock_check = uwsgi_rwlock_fast_check; uwsgi.lock_ops.rlock = uwsgi_rlock_fast; uwsgi.lock_ops.wlock = uwsgi_wlock_fast; uwsgi.lock_ops.rwunlock = uwsgi_rwunlock_fast; uwsgi.lock_size = UWSGI_LOCK_SIZE; uwsgi.rwlock_size = UWSGI_RWLOCK_SIZE; ready: // application generic lock uwsgi.user_lock = uwsgi_malloc(sizeof(void *) * (uwsgi.locks + 1)); for (i = 0; i < uwsgi.locks + 1; i++) { char *num = uwsgi_num2str(i); uwsgi.user_lock[i] = uwsgi_lock_init(uwsgi_concat2("user ", num)); free(num); } // event queue lock (mitigate same event on multiple queues) if (uwsgi.threads > 1) { pthread_mutex_init(&uwsgi.thunder_mutex, NULL); } if (uwsgi.master_process) { // signal table lock uwsgi.signal_table_lock = uwsgi_lock_init("signal"); // fmon table lock uwsgi.fmon_table_lock = uwsgi_lock_init("filemon"); // timer table lock uwsgi.timer_table_lock = uwsgi_lock_init("timer"); // rb_timer table lock uwsgi.rb_timer_table_lock = uwsgi_lock_init("rbtimer"); // cron table lock uwsgi.cron_table_lock = uwsgi_lock_init("cron"); } if (uwsgi.use_thunder_lock) { // process shared thunder lock uwsgi.the_thunder_lock = uwsgi_lock_init("thunder"); #ifdef UNBIT // we have a serious bug on Unbit (and very probably on older libc) // when all of the workers die in the same moment the pthread robust mutes is left // in inconsistent state and we have no way to recover // we span a thread in the master constantly ensuring the lock is ok // for now we apply it only for Unbit (where thunder-lock is automatically enabled) uwsgi_robust_mutexes_watchdog(); #endif } uwsgi.rpc_table_lock = uwsgi_lock_init("rpc"); #ifdef UWSGI_SSL // register locking for legions struct uwsgi_legion *ul = uwsgi.legions; while(ul) { ul->lock = uwsgi_lock_init(uwsgi_concat2("legion_", ul->legion)); ul = ul->next; } #endif uwsgi.locking_setup = 1; }
void *uwsgi_python_autoreloader_thread(void *foobar) { PyObject *modules; // block signals on this thread sigset_t smask; sigfillset(&smask); #ifndef UWSGI_DEBUG sigdelset(&smask, SIGSEGV); #endif pthread_sigmask(SIG_BLOCK, &smask, NULL); PyThreadState *pts = PyThreadState_New(up.main_thread->interp); pthread_setspecific(up.upt_save_key, (void *) pts); pthread_setspecific(up.upt_gil_key, (void *) pts); UWSGI_GET_GIL; PyObject *threading_module = PyImport_ImportModule("threading"); if (threading_module) { PyObject *threading_module_dict = PyModule_GetDict(threading_module); if (threading_module_dict) { #ifdef PYTHREE PyObject *threading_current = PyDict_GetItemString(threading_module_dict, "current_thread"); #else PyObject *threading_current = PyDict_GetItemString(threading_module_dict, "currentThread"); #endif if (threading_current) { PyObject *current_thread = PyEval_CallObject(threading_current, (PyObject *)NULL); if (!current_thread) { // ignore the error PyErr_Clear(); } else { PyObject_SetAttrString(current_thread, "name", PyString_FromString("uWSGIAutoReloader")); Py_INCREF(current_thread); modules = PyImport_GetModuleDict(); goto cycle; } } } } return NULL; cycle: if (uwsgi.mywid == 1) { uwsgi_log("Python auto-reloader enabled\n"); } PyObject *times_dict = PyDict_New(); char *filename; for(;;) { UWSGI_RELEASE_GIL; sleep(up.auto_reload); UWSGI_GET_GIL; // do not start monitoring til the first app is loaded (required for lazy mode) if (uwsgi_apps_cnt == 0) continue; #ifdef UWSGI_PYTHON_OLD int pos = 0; #else Py_ssize_t pos = 0; #endif PyObject *mod_name, *mod; while (PyDict_Next(modules, &pos, &mod_name, &mod)) { int found = 0; struct uwsgi_string_list *usl = up.auto_reload_ignore; while(usl) { if (!strcmp(usl->value, PyString_AsString(mod_name))) { found = 1; break; } usl = usl->next; } if (found) continue; if (!PyObject_HasAttrString(mod, "__file__")) continue; PyObject *mod_file = PyObject_GetAttrString(mod, "__file__"); if (!mod_file) continue; #ifdef PYTHREE PyObject *zero = PyUnicode_AsUTF8String(mod_file); char *mod_filename = PyString_AsString(zero); #else char *mod_filename = PyString_AsString(mod_file); #endif if (!mod_filename) { #ifdef PYTHREE Py_DECREF(zero); #endif continue; } char *ext = strrchr(mod_filename, '.'); if (ext && (!strcmp(ext+1, "pyc") || !strcmp(ext+1, "pyd") || !strcmp(ext+1, "pyo"))) { filename = uwsgi_concat2n(mod_filename, strlen(mod_filename)-1, "", 0); } else { filename = uwsgi_concat2(mod_filename, ""); } if (uwsgi_check_python_mtime(times_dict, filename)) { UWSGI_RELEASE_GIL; return NULL; } free(filename); #ifdef PYTHREE Py_DECREF(zero); #endif } } return NULL; }
void *uwsgi_python_tracebacker_thread(void *foobar) { struct iovec iov[9]; PyObject *new_thread = uwsgi_python_setup_thread("uWSGITraceBacker"); if (!new_thread) return NULL; struct sockaddr_un so_sun; socklen_t so_sun_len = 0; char *str_wid = uwsgi_num2str(uwsgi.mywid); char *sock_path = uwsgi_concat2(up.tracebacker, str_wid); int current_defer_accept = uwsgi.no_defer_accept; uwsgi.no_defer_accept = 1; int fd = bind_to_unix(sock_path, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); uwsgi.no_defer_accept = current_defer_accept; PyObject *threading_module = PyImport_ImportModule("threading"); if (!threading_module) return NULL; //PyObject *threading_dict = PyModule_GetDict(threading_module); PyObject *traceback_module = PyImport_ImportModule("traceback"); if (!traceback_module) return NULL; PyObject *traceback_dict = PyModule_GetDict(traceback_module); PyObject *extract_stack = PyDict_GetItemString(traceback_dict, "extract_stack"); PyObject *sys_module = PyImport_ImportModule("sys"); PyObject *sys_dict = PyModule_GetDict(sys_module); PyObject *_current_frames = PyDict_GetItemString(sys_dict, "_current_frames"); uwsgi_log("python tracebacker for worker %d available on %s\n", uwsgi.mywid, sock_path); for(;;) { UWSGI_RELEASE_GIL; int client_fd = accept(fd, (struct sockaddr *) &so_sun, &so_sun_len); if (client_fd < 0) { uwsgi_error("accept()"); UWSGI_GET_GIL; continue; } UWSGI_GET_GIL; // here is the core of the tracebacker PyObject *current_frames = PyEval_CallObject(_current_frames, (PyObject *)NULL); if (!current_frames) goto end; uwsgi_log("current_frames = %p\n", current_frames); PyObject *current_frames_items = PyObject_GetAttrString(current_frames, "items"); if (!current_frames_items) goto end; uwsgi_log("current_frames_items = %p\n", current_frames_items); PyObject *frames_ret = PyEval_CallObject(current_frames_items, (PyObject *)NULL); if (!frames_ret) goto end; uwsgi_log("frames_ret = %p\n", frames_ret); PyObject *frames_iter = PyObject_GetIter(frames_ret); uwsgi_log("frames_iter = %p\n", frames_iter); PyObject *frame = PyIter_Next(frames_iter); while(frame) { uwsgi_log("frame = %p\n", frame); PyObject *stack = PyTuple_GetItem(frame, 1); uwsgi_log("stack = %p\n", stack); PyObject *arg_tuple = PyTuple_New(1); PyTuple_SetItem(arg_tuple, 0, stack); PyObject *stacktrace = PyEval_CallObject( extract_stack, arg_tuple); uwsgi_log("stacktrace = %p\n", stacktrace); PyObject *stacktrace_iter = PyObject_GetIter(stacktrace); PyObject *st_items = PyIter_Next(stacktrace_iter); while(st_items) { uwsgi_log("st_items = %p\n", st_items); PyObject *st_filename = PyTuple_GetItem(st_items, 0); PyObject *st_lineno = PyTuple_GetItem(st_items, 1); PyObject *st_name = PyTuple_GetItem(st_items, 2); PyObject *st_line = PyTuple_GetItem(st_items, 3); iov[0].iov_base = "filename = "; iov[0].iov_len = 11; iov[1].iov_base = PyString_AsString(st_filename); iov[1].iov_len = strlen(iov[1].iov_base); iov[2].iov_base = " lineno = "; iov[2].iov_len = 10 ; iov[3].iov_base = uwsgi_num2str(PyInt_AsLong(st_lineno)); iov[3].iov_len = strlen(iov[3].iov_base); iov[4].iov_base = " function = "; iov[4].iov_len = 12 ; iov[5].iov_base = PyString_AsString(st_name); iov[5].iov_len = strlen(iov[5].iov_base); iov[6].iov_base = "\n"; iov[6].iov_len = 1 ; if (st_line) { } if (writev(client_fd, iov, 7) < 0) { uwsgi_error("writev()"); } st_items = PyIter_Next(stacktrace_iter); } frame = PyIter_Next(frames_iter); } end: close(client_fd); } return NULL; }
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; }
static void uwsgi_rados_propfind(struct wsgi_request *wsgi_req, rados_ioctx_t ctx, char *key, uint64_t size, time_t mtime, int timeout) { // consume the body size_t remains = wsgi_req->post_cl; while(remains > 0) { ssize_t body_len = 0; char *body = uwsgi_request_body_read(wsgi_req, UMIN(remains, 32768), &body_len); if (!body || body == uwsgi.empty) break; remains -= body_len; } if (uwsgi_response_prepare_headers(wsgi_req, "207 Multi-Status", 16)) return; if (uwsgi_response_add_content_type(wsgi_req, "text/xml; charset=\"utf-8\"", 25)) return; struct uwsgi_buffer *ub = uwsgi_webdav_multistatus_new(); if (!ub) return; if (key) { size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(key, strlen(key), &mime_type_len); char *slashed = uwsgi_concat2("/", key); if (uwsgi_webdav_propfind_item_add(ub, slashed, strlen(key)+1, size, mtime, mime_type, mime_type_len, NULL, 0, NULL, 0)) { free(slashed); goto end; } free(slashed); if (uwsgi_webdav_multistatus_close(ub)) goto end; uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); goto end; } // request for / size_t depth = 0; uint16_t http_depth_len = 0; char *http_depth = uwsgi_get_var(wsgi_req, "HTTP_DEPTH", 10, &http_depth_len); if (http_depth) { depth = uwsgi_str_num(http_depth, http_depth_len); } if (depth == 0) { if (uwsgi_webdav_propfind_item_add(ub, "/", 1, 0, 0, NULL, 0, NULL, 0, NULL, 0)) { goto end; } if (uwsgi_webdav_multistatus_close(ub)) goto end; uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); goto end; } struct uwsgi_rados_io *urio = &urados.urio[wsgi_req->async_id]; rados_list_ctx_t ctx_list; if (rados_objects_list_open(ctx, &ctx_list) < 0) { goto end; } char *entry = NULL; while(rados_objects_list_next(ctx_list, (const char **)&entry, NULL) == 0) { uint64_t stat_size = 0; time_t stat_mtime = 0; if (uwsgi.async > 0) { if (uwsgi_rados_async_stat(urio, ctx, entry, &stat_size, &stat_mtime, timeout) < 0) goto end; } else { if (rados_stat(ctx, entry, &stat_size, &stat_mtime) < 0) goto end; } size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(entry, strlen(entry), &mime_type_len); char *slashed = uwsgi_concat2("/", entry); if (uwsgi_webdav_propfind_item_add(ub, slashed, strlen(entry)+1, stat_size, stat_mtime, mime_type, mime_type_len, NULL, 0, NULL, 0)) { free(slashed); goto end; } free(slashed); if (uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos)) goto end; // reset buffer; ub->pos = 0; } rados_objects_list_close(ctx_list); if (uwsgi_webdav_multistatus_close(ub)) goto end; uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); end: uwsgi_buffer_destroy(ub); }
static int uwsgi_hook_print(char *arg) { char *line = uwsgi_concat2(arg, "\n"); uwsgi_log(line); free(line); return 0; }
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; }
static int uwsgi_pypy_init() { size_t rlen = 0; char *buffer = NULL; void *is_cpython_loaded = dlsym(RTLD_DEFAULT, "Py_Initialize"); if (is_cpython_loaded) { uwsgi_log("!!! Loading both PyPy and CPython in the same process IS PURE EVIL AND IT IS NOT SUPPORTED !!!\n"); exit(1); } if (dlsym(RTLD_DEFAULT, "rpython_startup_code")) { uwsgi_log("PyPy runtime detected, skipping libpypy-c loading\n"); goto ready; } else if (upypy.lib) { upypy.handler = dlopen(upypy.lib, RTLD_NOW | RTLD_GLOBAL); } else { if (upypy.home) { #ifdef __CYGWIN__ char *libpath = uwsgi_concat2(upypy.home, "/libpypy-c.dll"); #elif defined(__APPLE__) char *libpath = uwsgi_concat2(upypy.home, "/libpypy-c.dylib"); #else char *libpath = uwsgi_concat2(upypy.home, "/libpypy-c.so"); #endif if (uwsgi_file_exists(libpath)) { upypy.handler = dlopen(libpath, RTLD_NOW | RTLD_GLOBAL); } free(libpath); } // fallback to standard library search path if (!upypy.handler) { #ifdef __CYGWIN__ upypy.handler = dlopen("libpypy-c.dll", RTLD_NOW | RTLD_GLOBAL); #elif defined(__APPLE__) upypy.handler = dlopen("libpypy-c.dylib", RTLD_NOW | RTLD_GLOBAL); #else upypy.handler = dlopen("libpypy-c.so", RTLD_NOW | RTLD_GLOBAL); #endif } } if (!upypy.handler) { uwsgi_log("unable to load pypy library: %s\n", dlerror()); exit(1); } u_rpython_startup_code = dlsym(upypy.handler, "rpython_startup_code"); if (!u_rpython_startup_code) { uwsgi_log("unable to find rpython_startup_code() symbol\n"); exit(1); } u_pypy_setup_home = dlsym(upypy.handler, "pypy_setup_home"); if (!u_pypy_setup_home) { uwsgi_log("unable to find pypy_setup_home() symbol\n"); exit(1); } u_pypy_init_threads = dlsym(upypy.handler, "pypy_init_threads"); if (!u_pypy_init_threads) { uwsgi_log("!!! WARNING your libpypy-c does not export pypy_init_threads, multithreading will not work !!!\n"); } u_rpython_startup_code(); if (!upypy.home) { upypy.home = getenv("PYPY_HOME"); if (!upypy.home) { uwsgi_log("you have to specify a pypy home with --pypy-home\n"); exit(1); } } if (u_pypy_setup_home(upypy.home, 0)) { char *retry = uwsgi_concat2(upypy.home, "/lib_pypy"); if (uwsgi_is_dir(retry)) { // this time we use debug if (!u_pypy_setup_home(retry, 1)) { free(retry); goto ready; } } uwsgi_log("unable to set pypy home to \"%s\"\n", upypy.home); exit(1); } ready: u_pypy_execute_source = dlsym(upypy.handler, "pypy_execute_source"); if (!u_pypy_execute_source) { uwsgi_log("unable to find pypy_execute_source() symbol\n"); exit(1); } u_pypy_thread_attach = dlsym(upypy.handler, "pypy_thread_attach"); if (!u_pypy_thread_attach) { uwsgi_log("!!! WARNING your libpypy-c does not export pypy_thread_attach, multithreading will not work !!!\n"); } if (upypy.setup) { buffer = uwsgi_open_and_read(upypy.setup, &rlen, 1, NULL); } else { char *start = dlsym(RTLD_DEFAULT, "uwsgi_pypy_setup_start"); if (!start) { start = dlsym(RTLD_DEFAULT, "_uwsgi_pypy_setup_start"); } char *end = dlsym(RTLD_DEFAULT, "uwsgi_pypy_setup_end"); if (!end) { end = dlsym(RTLD_DEFAULT, "_uwsgi_pypy_setup_end"); } if (start && end) { buffer = uwsgi_concat2n(start, end-start, "", 0); } } if (!buffer) { uwsgi_log("you have to load a pypy setup file with --pypy-setup\n"); exit(1); } if (u_pypy_execute_source(buffer)) { exit(1); } free(buffer); // add items to the pythonpath struct uwsgi_string_list *usl = upypy.pp; while(usl) { if (uwsgi_pypy_hook_pythonpath) { uwsgi_pypy_hook_pythonpath(usl->value); } usl = usl->next; } return 0; }
void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) { void *plugin_handle = NULL; char *plugin_abs_path = NULL; char *plugin_filename = NULL; int need_free = 0; char *plugin_name = uwsgi_strip(uwsgi_str(plugin)); char *plugin_symbol_name_start = plugin_name; struct uwsgi_plugin *up; char linkpath_buf[1024], linkpath[1024]; int linkpath_size; char *colon = strchr(plugin_name, ':'); if (colon) { colon[0] = 0; modifier = atoi(plugin_name); plugin_name = colon + 1; colon[0] = ':'; } if (!uwsgi_endswith(plugin_name, "_plugin.so")) { plugin_name = uwsgi_concat2(plugin_name, "_plugin.so"); need_free = 1; } plugin_symbol_name_start = plugin_name; // step 1: check for absolute plugin (stop if it fails) if (strchr(plugin_name, '/')) { #ifdef UWSGI_ELF uwsgi_plugin_parse_section(plugin_name); #endif plugin_handle = dlopen(plugin_name, RTLD_NOW | RTLD_GLOBAL); if (!plugin_handle) { if (!has_option) uwsgi_log("%s\n", dlerror()); goto end; } plugin_symbol_name_start = uwsgi_get_last_char(plugin_name, '/'); plugin_symbol_name_start++; plugin_abs_path = plugin_name; goto success; } // step dir, check for user-supplied plugins directory struct uwsgi_string_list *pdir = uwsgi.plugins_dir; while (pdir) { plugin_filename = uwsgi_concat3(pdir->value, "/", plugin_name); #ifdef UWSGI_ELF uwsgi_plugin_parse_section(plugin_filename); #endif plugin_handle = dlopen(plugin_filename, RTLD_NOW | RTLD_GLOBAL); if (plugin_handle) { plugin_abs_path = plugin_filename; //free(plugin_filename); goto success; } free(plugin_filename); plugin_filename = NULL; pdir = pdir->next; } // last step: search in compile-time plugin_dir if (!plugin_handle) { plugin_filename = uwsgi_concat3(UWSGI_PLUGIN_DIR, "/", plugin_name); #ifdef UWSGI_ELF uwsgi_plugin_parse_section(plugin_filename); #endif plugin_handle = dlopen(plugin_filename, RTLD_NOW | RTLD_GLOBAL); plugin_abs_path = plugin_filename; //free(plugin_filename); } success: if (!plugin_handle) { if (!has_option) uwsgi_log("!!! UNABLE to load uWSGI plugin: %s !!!\n", dlerror()); } else { char *plugin_entry_symbol = uwsgi_concat2n(plugin_symbol_name_start, strlen(plugin_symbol_name_start) - 3, "", 0); up = dlsym(plugin_handle, plugin_entry_symbol); if (!up) { // is it a link ? memset(linkpath_buf, 0, 1024); memset(linkpath, 0, 1024); if ((linkpath_size = readlink(plugin_abs_path, linkpath_buf, 1023)) > 0) { do { linkpath_buf[linkpath_size] = '\0'; strncpy(linkpath, linkpath_buf, linkpath_size + 1); } while ((linkpath_size = readlink(linkpath, linkpath_buf, 1023)) > 0); #ifdef UWSGI_DEBUG uwsgi_log("%s\n", linkpath); #endif free(plugin_entry_symbol); char *slash = uwsgi_get_last_char(linkpath, '/'); if (!slash) { slash = linkpath; } else { slash++; } plugin_entry_symbol = uwsgi_concat2n(slash, strlen(slash) - 3, "", 0); up = dlsym(plugin_handle, plugin_entry_symbol); } } if (up) { if (!up->name) { uwsgi_log("the loaded plugin (%s) has no .name attribute\n", plugin_name); if (dlclose(plugin_handle)) { uwsgi_error("dlclose()"); } if (need_free) free(plugin_name); if (plugin_filename) free(plugin_filename); free(plugin_entry_symbol); return NULL; } if (plugin_already_loaded(up->name)) { if (dlclose(plugin_handle)) { uwsgi_error("dlclose()"); } if (need_free) free(plugin_name); if (plugin_filename) free(plugin_filename); free(plugin_entry_symbol); return NULL; } if (has_option) { struct uwsgi_option *op = up->options; int found = 0; while (op && op->name) { if (!strcmp(has_option, op->name)) { found = 1; break; } op++; } if (!found) { if (dlclose(plugin_handle)) { uwsgi_error("dlclose()"); } if (need_free) free(plugin_name); if (plugin_filename) free(plugin_filename); free(plugin_entry_symbol); return NULL; } } if (modifier != -1) { fill_plugin_table(modifier, up); up->modifier1 = modifier; } else { fill_plugin_table(up->modifier1, up); } if (need_free) free(plugin_name); if (plugin_filename) free(plugin_filename); free(plugin_entry_symbol); if (up->on_load) up->on_load(); return plugin_handle; } if (!has_option) uwsgi_log("%s\n", dlerror()); } end: if (need_free) free(plugin_name); if (plugin_filename) free(plugin_filename); return NULL; }
void *uwsgi_python_autoreloader_thread(void *foobar) { PyObject *new_thread = uwsgi_python_setup_thread("uWSGIAutoReloader"); if (!new_thread) return NULL; PyObject *modules = PyImport_GetModuleDict(); if (uwsgi.mywid == 1) { uwsgi_log("Python auto-reloader enabled\n"); } PyObject *times_dict = PyDict_New(); char *filename; for(;;) { UWSGI_RELEASE_GIL; sleep(up.auto_reload); UWSGI_GET_GIL; // do not start monitoring til the first app is loaded (required for lazy mode) if (uwsgi_apps_cnt == 0) continue; #ifdef UWSGI_PYTHON_OLD int pos = 0; #else Py_ssize_t pos = 0; #endif PyObject *mod_name, *mod; while (PyDict_Next(modules, &pos, &mod_name, &mod)) { int found = 0; struct uwsgi_string_list *usl = up.auto_reload_ignore; while(usl) { if (!strcmp(usl->value, PyString_AsString(mod_name))) { found = 1; break; } usl = usl->next; } if (found) continue; if (!PyObject_HasAttrString(mod, "__file__")) continue; PyObject *mod_file = PyObject_GetAttrString(mod, "__file__"); if (!mod_file) continue; #ifdef PYTHREE PyObject *zero = PyUnicode_AsUTF8String(mod_file); char *mod_filename = PyString_AsString(zero); #else char *mod_filename = PyString_AsString(mod_file); #endif if (!mod_filename) { #ifdef PYTHREE Py_DECREF(zero); #endif continue; } char *ext = strrchr(mod_filename, '.'); if (ext && (!strcmp(ext+1, "pyc") || !strcmp(ext+1, "pyd") || !strcmp(ext+1, "pyo"))) { filename = uwsgi_concat2n(mod_filename, strlen(mod_filename)-1, "", 0); } else { filename = uwsgi_concat2(mod_filename, ""); } if (uwsgi_check_python_mtime(times_dict, filename)) { UWSGI_RELEASE_GIL; return NULL; } free(filename); #ifdef PYTHREE Py_DECREF(zero); #endif } } return NULL; }
static char *emperor_check_on_demand_socket(char *filename) { size_t len = 0; if (uwsgi.emperor_on_demand_extension) { char *tmp = uwsgi_concat2(filename, uwsgi.emperor_on_demand_extension); int fd = open(tmp, O_RDONLY); free(tmp); if (fd < 0) return NULL; char *ret = uwsgi_read_fd(fd, &len, 1); close(fd); // change the first non prinabel character to 0 size_t i; for(i=0;i<len;i++) { if (ret[i] < 32) { ret[i] = 0; break; } } if (ret[0] == 0) { free(ret); return NULL; } return ret; } else if (uwsgi.emperor_on_demand_directory) { // we need to build the socket path automagically char *start_of_vassal_name = uwsgi_get_last_char(filename, '/'); if (!start_of_vassal_name) { start_of_vassal_name = filename; } else { start_of_vassal_name++; } char *last_dot = uwsgi_get_last_char(filename, '.'); if (!last_dot) return NULL; return uwsgi_concat4n(uwsgi.emperor_on_demand_directory, strlen(uwsgi.emperor_on_demand_directory), "/", 1, start_of_vassal_name, last_dot - start_of_vassal_name, ".socket", 7); } else if (uwsgi.emperor_on_demand_exec) { int cpipe[2]; if (pipe(cpipe)) { uwsgi_error("emperor_check_on_demand_socket()pipe()"); return NULL; } char *cmd = uwsgi_concat4(uwsgi.emperor_on_demand_exec, " \"", filename, "\""); int r = uwsgi_run_command(cmd, NULL, cpipe[1]); free(cmd); if (r < 0) { close(cpipe[0]); close(cpipe[1]); return NULL; } char *ret = uwsgi_read_fd(cpipe[0], &len, 1); close(cpipe[0]); close(cpipe[1]); // change the first non prinabel character to 0 size_t i; for(i=0;i<len;i++) { if (ret[i] < 32) { ret[i] = 0; break; } } if (ret[0] == 0) { free(ret); return NULL; } return ret; } return NULL; }
void uwsgi_setup_locking() { int i; if (uwsgi.locking_setup) return; // use the fastest available locking if (uwsgi.lock_engine) { if (!strcmp(uwsgi.lock_engine, "ipcsem")) { uwsgi_log_initial("lock engine: ipcsem\n"); atexit(uwsgi_ipcsem_clear); uwsgi.lock_ops.lock_init = uwsgi_lock_ipcsem_init; uwsgi.lock_ops.lock_check = uwsgi_lock_ipcsem_check; uwsgi.lock_ops.lock = uwsgi_lock_ipcsem; uwsgi.lock_ops.unlock = uwsgi_unlock_ipcsem; uwsgi.lock_ops.rwlock_init = uwsgi_rwlock_ipcsem_init; uwsgi.lock_ops.rwlock_check = uwsgi_rwlock_ipcsem_check; uwsgi.lock_ops.rlock = uwsgi_rlock_ipcsem; uwsgi.lock_ops.wlock = uwsgi_wlock_ipcsem; uwsgi.lock_ops.rwunlock = uwsgi_rwunlock_ipcsem; uwsgi.lock_size = 8; uwsgi.rwlock_size = 8; goto ready; } uwsgi_log("unable to find lock engine \"%s\"\n", uwsgi.lock_engine); exit(1); } uwsgi_log_initial("lock engine: %s\n", UWSGI_LOCK_ENGINE_NAME); #ifdef UWSGI_IPCSEM_ATEXIT atexit(uwsgi_ipcsem_clear); #endif uwsgi.lock_ops.lock_init = uwsgi_lock_fast_init; uwsgi.lock_ops.lock_check = uwsgi_lock_fast_check; uwsgi.lock_ops.lock = uwsgi_lock_fast; uwsgi.lock_ops.unlock = uwsgi_unlock_fast; uwsgi.lock_ops.rwlock_init = uwsgi_rwlock_fast_init; uwsgi.lock_ops.rwlock_check = uwsgi_rwlock_fast_check; uwsgi.lock_ops.rlock = uwsgi_rlock_fast; uwsgi.lock_ops.wlock = uwsgi_wlock_fast; uwsgi.lock_ops.rwunlock = uwsgi_rwunlock_fast; uwsgi.lock_size = UWSGI_LOCK_SIZE; uwsgi.rwlock_size = UWSGI_RWLOCK_SIZE; ready: // application generic lock uwsgi.user_lock = uwsgi_malloc(sizeof(void *) * (uwsgi.locks + 1)); for (i = 0; i < uwsgi.locks + 1; i++) { uwsgi.user_lock[i] = uwsgi_lock_init(uwsgi_concat2("user ", uwsgi_num2str(i))); } // event queue lock (mitigate same event on multiple queues) if (uwsgi.threads > 1) { pthread_mutex_init(&uwsgi.thunder_mutex, NULL); } if (uwsgi.master_process) { // signal table lock uwsgi.signal_table_lock = uwsgi_lock_init("signal"); // fmon table lock uwsgi.fmon_table_lock = uwsgi_lock_init("filemon"); // timer table lock uwsgi.timer_table_lock = uwsgi_lock_init("timer"); // rb_timer table lock uwsgi.rb_timer_table_lock = uwsgi_lock_init("rbtimer"); // cron table lock uwsgi.cron_table_lock = uwsgi_lock_init("cron"); } if (uwsgi.use_thunder_lock) { // process shared thunder lock uwsgi.the_thunder_lock = uwsgi_lock_init("thunder"); } uwsgi.rpc_table_lock = uwsgi_lock_init("rpc"); #ifdef UWSGI_SSL // register locking for legions struct uwsgi_legion *ul = uwsgi.legions; while(ul) { ul->lock = uwsgi_lock_init(uwsgi_concat2("legion_", ul->legion)); ul = ul->next; } #endif uwsgi.locking_setup = 1; }
char *uwsgi_format_airbrake_backtrace(struct uwsgi_thread *ut) { struct uwsgi_airbrake_config *uacc = (struct uwsgi_airbrake_config *) ut->data; xmlChar *xmlbuff; int buffersize; xmlDocPtr doc = NULL; xmlNodePtr notice_node = NULL, node = NULL, line_node = NULL, errnode = NULL; char *msg = NULL; doc = xmlNewDoc(BAD_CAST "1.0"); notice_node = xmlNewNode(NULL, BAD_CAST "notice"); xmlNewProp(notice_node, BAD_CAST "version", BAD_CAST "2.3"); xmlDocSetRootElement(doc, notice_node); xmlNewChild(notice_node, NULL, BAD_CAST "api-key", BAD_CAST uacc->apikey); node = xmlNewChild(notice_node, NULL, BAD_CAST "notifier", NULL); xmlNewChild(node, NULL, BAD_CAST "name", BAD_CAST "uWSGI"); xmlNewChild(node, NULL, BAD_CAST "version", BAD_CAST UWSGI_VERSION); xmlNewChild(node, NULL, BAD_CAST "url", BAD_CAST "https://github.com/unbit/uwsgi"); // request env node = xmlNewChild(notice_node, NULL, BAD_CAST "request", NULL); node = xmlNewChild(node, NULL, BAD_CAST "cgi-data", NULL); line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST UWSGI_VERSION); xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "uwsgi_version"); line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST __VERSION__); xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "compiled_with_version"); struct utsname uuts; #ifdef __sun__ if (uname(&uuts) < 0) { #else if (uname(&uuts)) { #endif uwsgi_error("uname()"); } else { line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST uuts.sysname); xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "os_sysname"); char *os_version = uwsgi_concat3(uuts.release, "-", uuts.version); line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST os_version); xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "os_version"); free(os_version); line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST uuts.machine); xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "machine"); line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST uuts.nodename); xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "nodename"); } // end request env node = xmlNewChild(notice_node, NULL, BAD_CAST "server-environment", NULL); xmlNewChild(node, NULL, BAD_CAST "app-version", BAD_CAST UWSGI_VERSION); if (uacc->env) { xmlNewChild(node, NULL, BAD_CAST "environment-name", BAD_CAST uacc->env); } else { xmlNewChild(node, NULL, BAD_CAST "environment-name", BAD_CAST UWSGI_VERSION); } errnode = xmlNewChild(notice_node, NULL, BAD_CAST "error", NULL); xmlNewChild(errnode, NULL, BAD_CAST "class", BAD_CAST "RuntimeError"); node = xmlNewChild(errnode, NULL, BAD_CAST "backtrace", NULL); char *ctx = NULL; char *text = uwsgi_str(ut->buf); char *p = strtok_r(text, "\n", &ctx); while (p) { // skip log messages if (!uwsgi_startswith(p, "***", 3)) goto next; // backtrace line looks like this: uwsgi(simple_loop_run+0xc5) [0x451555] // we take binary/lib as filename // and extract method name from remaining string char *n = strchr(p, '('); if (n) { *n = 0; char *pls = strchr(n+1, '+'); if (pls) { *pls = 0; } if (!strcmp("uwsgi_backtrace", n+1) || !strcmp("what_i_am_doing", n+1)) { goto next; } else if (!strcmp("uwsgi_fpe", n+1)) { msg = uwsgi_concat4("uWSGI FPE at ", n+1, " in ", p); goto next; } if (!msg) { if (strlen(n+1)) { msg = uwsgi_concat4("uWSGI segfault at ", n+1, " in ", p); } else { // method name might be missing msg = uwsgi_concat2("uWSGI segfault in ", p); } } // skip empty lines if (!p) goto next; line_node = xmlNewChild(node, NULL, BAD_CAST "line", NULL); if ((n+1)[0] == ')') { xmlNewProp(line_node, BAD_CAST "method", BAD_CAST "()"); } else { xmlNewProp(line_node, BAD_CAST "method", BAD_CAST n+1); } xmlNewProp(line_node, BAD_CAST "file", BAD_CAST p); //xmlNewProp(line_node, BAD_CAST "number", BAD_CAST "0"); } next: p = strtok_r(NULL, "\n", &ctx); } xmlNewChild(errnode, NULL, BAD_CAST "message", BAD_CAST msg); xmlDocDumpFormatMemory(doc, &xmlbuff, &buffersize, 1); xmlFreeDoc(doc); xmlCleanupParser(); xmlMemoryDump(); free(msg); free(text); return (char *) xmlbuff; } static void uwsgi_airbrake_loop(struct uwsgi_thread *ut) { int interesting_fd; ut->buf = uwsgi_malloc(uwsgi.log_master_bufsize); CURL *curl = curl_easy_init(); // ARGH !!! if (!curl) return; curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]); curl_easy_setopt(curl, CURLOPT_TIMEOUT, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]); curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); curl_easy_setopt(curl, CURLOPT_READDATA, ut); curl_easy_setopt(curl, CURLOPT_POST, 1L); struct curl_slist *expect = NULL; expect = curl_slist_append(expect, "Expect:"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, expect); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); struct uwsgi_airbrake_config *uacc = (struct uwsgi_airbrake_config *) ut->data; char *opts = uwsgi_str(uacc->arg); // fill curl options char *ctx = NULL; char *p = strtok_r(opts, ";", &ctx); while(p) { uwsgi_airbrake_setopt(curl, uwsgi_str(p), uacc); p = strtok_r(NULL, ";", &ctx); } for(;;) { int ret = event_queue_wait(ut->queue, -1, &interesting_fd); if (ret < 0) return; if (ret == 0) continue; if (interesting_fd != ut->pipe[1]) continue; ssize_t rlen = read(ut->pipe[1], ut->buf, uwsgi.log_master_bufsize); if (rlen <= 0) continue; ut->pos = 0; ut->len = (size_t) rlen; ut->custom0 = 0; char *notice = uwsgi_format_airbrake_backtrace(ut); curl_slist_append(expect, "Accept: */*"); curl_slist_append(expect, "Content-Type: text/xml; charset=utf-8"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, expect); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, notice); curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(notice)); curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t) ut->len); CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) { uwsgi_log_alarm("-curl] curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } free(notice); } }