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 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); }
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 uwsgi_check_logrotate(void) { char message[1024]; int need_rotation = 0; int need_reopen = 0; if (uwsgi.log_master) { uwsgi.shared->logsize = lseek(uwsgi.original_log_fd, 0, SEEK_CUR); } else { uwsgi.shared->logsize = lseek(2, 0, SEEK_CUR); } if (uwsgi.log_maxsize > 0 && uwsgi.shared->logsize > uwsgi.log_maxsize) { need_rotation = 1; } if (uwsgi_check_touches(uwsgi.touch_logrotate)) { need_rotation = 1; } if (uwsgi_check_touches(uwsgi.touch_logreopen)) { need_reopen = 1; } if (need_rotation) { char *rot_name = uwsgi.log_backupname; int need_free = 0; if (rot_name == NULL) { char *ts_str = uwsgi_num2str((int) uwsgi_now()); rot_name = uwsgi_concat3(uwsgi.logfile, ".", ts_str); free(ts_str); need_free = 1; } int ret = snprintf(message, 1024, "[%d] logsize: %llu, triggering rotation to %s...\n", (int) uwsgi_now(), (unsigned long long) uwsgi.shared->logsize, rot_name); if (ret > 0) { if (write(uwsgi.original_log_fd, message, ret) != ret) { // very probably this will never be printed uwsgi_error("write()"); } } if (rename(uwsgi.logfile, rot_name) == 0) { // reopen logfile dup'it and eventually gracefully reload workers; int fd = open(uwsgi.logfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP); if (fd < 0) { uwsgi_error_open(uwsgi.logfile); grace_them_all(0); } if (dup2(fd, uwsgi.original_log_fd) < 0) { uwsgi_error("dup2()"); grace_them_all(0); } close(fd); } else { uwsgi_error("unable to rotate log: rename()"); } if (need_free) free(rot_name); } else if (need_reopen) { int ret = snprintf(message, 1024, "[%d] logsize: %llu, triggering log-reopen...\n", (int) uwsgi_now(), (unsigned long long) uwsgi.shared->logsize); if (ret > 0) { if (write(uwsgi.original_log_fd, message, ret) != ret) { // very probably this will never be printed uwsgi_error("write()"); } } // reopen logfile; close(uwsgi.original_log_fd); uwsgi.original_log_fd = open(uwsgi.logfile, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP); if (uwsgi.original_log_fd < 0) { uwsgi_error_open(uwsgi.logfile); grace_them_all(0); } ret = snprintf(message, 1024, "[%d] %s reopened.\n", (int) uwsgi_now(), uwsgi.logfile); if (ret > 0) { if (write(uwsgi.original_log_fd, message, ret) != ret) { // very probably this will never be printed uwsgi_error("write()"); } } uwsgi.shared->logsize = lseek(uwsgi.original_log_fd, 0, SEEK_CUR); } }
ssize_t uwsgi_lf_msecs(struct wsgi_request *wsgi_req, char **buf) { int microseconds = wsgi_req->end_of_request.tv_sec * 1000000 + wsgi_req->end_of_request.tv_usec; int microseconds2 = wsgi_req->start_of_request.tv_sec * 1000000 + wsgi_req->start_of_request.tv_usec; *buf = uwsgi_num2str((microseconds - microseconds2)/1000); return strlen(*buf); }
ssize_t uwsgi_lf_time(struct wsgi_request *wsgi_req, char **buf) { *buf = uwsgi_num2str(wsgi_req->start_of_request.tv_sec); return strlen(*buf); }
void uwsgi_json_config(char *file, char *magic_table[]) { size_t len = 0; char *json_data; const char *key; json_t *root; json_error_t error; json_t *config; json_t *config_value, *config_array_item; void *config_iter; char *object_asked = "uwsgi"; char *colon; int i; if (uwsgi_check_scheme(file)) { colon = uwsgi_get_last_char(file, '/'); colon = uwsgi_get_last_char(colon, ':'); } else { colon = uwsgi_get_last_char(file, ':'); } if (colon) { colon[0] = 0; if (colon[1] != 0) { object_asked = colon + 1; } } uwsgi_log_initial("[uWSGI] getting JSON configuration from %s\n", file); json_data = uwsgi_open_and_read(file, &len, 1, magic_table); #ifdef JANSSON_MAJOR_VERSION root = json_loads(json_data, 0, &error); #else root = json_loads(json_data, &error); #endif if (!root) { uwsgi_log("error parsing JSON data: line %d %s\n", error.line, error.text); exit(1); } config = json_object_get(root, object_asked); if (!json_is_object(config)) { uwsgi_log("you must define a object named %s in your JSON data\n", object_asked); exit(1); } config_iter = json_object_iter(config); while (config_iter) { key = json_object_iter_key(config_iter); config_value = json_object_iter_value(config_iter); if (json_is_string(config_value)) { add_exported_option((char *) key, (char *) json_string_value(config_value), 0); } else if (json_is_true(config_value)) { add_exported_option((char *) key, strdup("1"), 0); } else if (json_is_false(config_value) || json_is_null(config_value)) { add_exported_option((char *) key, strdup("0"), 0); } else if (json_is_integer(config_value)) { add_exported_option((char *) key, uwsgi_num2str(json_integer_value(config_value)), 0); } else if (json_is_array(config_value)) { for (i = 0; i < (int) json_array_size(config_value); i++) { config_array_item = json_array_get(config_value, i); if (json_is_string(config_array_item)) { add_exported_option((char *) key, (char *) json_string_value(config_array_item), 0); } else if (json_is_true(config_array_item)) { add_exported_option((char *) key, strdup("1"), 0); } else if (json_is_false(config_array_item) || json_is_null(config_array_item)) { add_exported_option((char *) key, strdup("0"), 0); } else if (json_is_integer(config_array_item)) { add_exported_option((char *) key, uwsgi_num2str(json_integer_value(config_array_item)), 0); } } } config_iter = json_object_iter_next(config, config_iter); } if (colon) colon[0] = ':'; }
static int uwsgi_webdav_add_props(struct wsgi_request *wsgi_req, xmlNode *req_prop, xmlNode * multistatus, xmlNsPtr dav_ns, char *uri, char *filename, int with_values) { struct stat st; if (stat(filename, &st)) { uwsgi_error("uwsgi_webdav_add_props()/stat()"); return -1; } int is_collection = 0; xmlNode *response = xmlNewChild(multistatus, dav_ns, BAD_CAST "response", NULL); uint16_t uri_len = strlen(uri) ; char *encoded_uri = uwsgi_malloc( (uri_len * 3) + 1); http_url_encode(uri, &uri_len, encoded_uri); encoded_uri[uri_len] = 0; xmlNewChild(response, dav_ns, BAD_CAST "href", BAD_CAST encoded_uri); free(encoded_uri); xmlNode *r_propstat = xmlNewChild(response, dav_ns, BAD_CAST "propstat", NULL); char *r_status = uwsgi_concat2n(wsgi_req->protocol, wsgi_req->protocol_len, " 200 OK", 7); xmlNewChild(r_propstat, dav_ns, BAD_CAST "status", BAD_CAST r_status); free(r_status); xmlNode *r_prop = xmlNewChild(r_propstat, dav_ns, BAD_CAST "prop", NULL); if (with_values) { if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "displayname")) { char *base_uri = uwsgi_get_last_char(uri, '/'); if (base_uri) { xmlNewChild(r_prop, dav_ns, BAD_CAST "displayname", BAD_CAST base_uri+1); } else { xmlNewChild(r_prop, dav_ns, BAD_CAST "displayname", BAD_CAST uri); } } if (S_ISDIR(st.st_mode)) is_collection = 1; xmlNode *r_type = NULL; if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "resourcetype")) { r_type = xmlNewChild(r_prop, dav_ns, BAD_CAST "resourcetype", NULL); if (is_collection) { xmlNewChild(r_type, dav_ns, BAD_CAST "collection", NULL); is_collection = 1; } } if (!is_collection) { if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "getcontentlength")) { char *r_contentlength = uwsgi_num2str(st.st_size); xmlNewChild(r_prop, dav_ns, BAD_CAST "getcontentlength", BAD_CAST r_contentlength); free(r_contentlength); } if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "getcontenttype")) { size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(filename, strlen(filename), &mime_type_len); if (mime_type) { char *r_ctype = uwsgi_concat2n(mime_type, mime_type_len, "", 0); xmlNewTextChild(r_prop, dav_ns, BAD_CAST "getcontenttype", BAD_CAST r_ctype); free(r_ctype); } } } if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "creationdate")) { // there is no creation date on UNIX/POSIX, ctime is the nearest thing... char *cdate = uwsgi_webdav_new_date(st.st_ctime); if (cdate) { xmlNewTextChild(r_prop, dav_ns, BAD_CAST "creationdate", BAD_CAST cdate); free(cdate); } } if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "getlastmodified")) { char *mdate = uwsgi_webdav_new_date(st.st_mtime); if (mdate) { xmlNewTextChild(r_prop, dav_ns, BAD_CAST "getlastmodified", BAD_CAST mdate); free(mdate); } } if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "getetag")) { char *etag = uwsgi_num2str(st.st_mtime); xmlNewTextChild(r_prop, dav_ns, BAD_CAST "getetag", BAD_CAST etag); free(etag); } if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "executable")) { xmlNewChild(r_prop, dav_ns, BAD_CAST "executable", NULL); } if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "owner")) { xmlNewTextChild(r_prop, dav_ns, BAD_CAST "owner", NULL); } if (wsgi_req->remote_user_len > 0) { if (udav.principal_base) { if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "current-user-principal")) { char *current_user_principal = uwsgi_concat2n(udav.principal_base, strlen(udav.principal_base), wsgi_req->remote_user, wsgi_req->remote_user_len); xmlNode *cup = xmlNewChild(r_prop, dav_ns, BAD_CAST "current-user-principal", NULL); xmlNewTextChild(cup, dav_ns, BAD_CAST "href", BAD_CAST current_user_principal); if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "resourcetype")) { if (!strcmp(current_user_principal, uri)) { xmlNewChild(r_type, dav_ns, BAD_CAST "principal", NULL); } } free(current_user_principal); } } if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "current-user-privilege-set")) { xmlNode *cups = xmlNewChild(r_prop, dav_ns, BAD_CAST "current-user-privilege-set", NULL); xmlNode *privilege = xmlNewChild(cups, dav_ns, BAD_CAST "privilege", NULL); xmlNewChild(privilege, dav_ns, BAD_CAST "all", NULL); xmlNewChild(privilege, dav_ns, BAD_CAST "read", NULL); xmlNewChild(privilege, dav_ns, BAD_CAST "write", NULL); xmlNewChild(privilege, dav_ns, BAD_CAST "write-content", NULL); xmlNewChild(privilege, dav_ns, BAD_CAST "write-properties", NULL); } } if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "supported-report-set")) { xmlNode *report_set = xmlNewChild(r_prop, dav_ns, BAD_CAST "supported-report-set", NULL); xmlNode *supported_report = xmlNewChild(report_set, dav_ns, BAD_CAST "supported-report", NULL); xmlNewChild(supported_report, dav_ns, BAD_CAST "report", BAD_CAST "principal-property-search"); supported_report = xmlNewChild(report_set, dav_ns, BAD_CAST "supported-report", NULL); xmlNewChild(supported_report, dav_ns, BAD_CAST "report", BAD_CAST "sync-collection"); supported_report = xmlNewChild(report_set, dav_ns, BAD_CAST "supported-report", NULL); xmlNewChild(supported_report, dav_ns, BAD_CAST "report", BAD_CAST "expand-property"); supported_report = xmlNewChild(report_set, dav_ns, BAD_CAST "supported-report", NULL); xmlNewChild(supported_report, dav_ns, BAD_CAST "report", BAD_CAST "principal-search-property-set"); } uwsgi_webdav_foreach_prop(udav.add_prop, req_prop, r_prop, 0, NULL ); uwsgi_webdav_foreach_prop(udav.add_prop_href, req_prop, r_prop, 1, NULL); uwsgi_webdav_foreach_prop(udav.add_prop_comp,req_prop, r_prop, 2 , NULL); uwsgi_webdav_foreach_prop(udav.add_rtype_prop,req_prop, r_type, 0, "resourcetype"); if (is_collection) { uwsgi_webdav_foreach_prop(udav.add_rtype_collection_prop,req_prop, r_type, 0, "resourcetype"); uwsgi_webdav_foreach_prop(udav.add_collection_prop,req_prop, r_prop, 0, NULL); uwsgi_webdav_foreach_prop(udav.add_collection_prop_href,req_prop, r_prop, 1, NULL); uwsgi_webdav_foreach_prop(udav.add_collection_prop_comp,req_prop, r_prop, 2, NULL); } else { uwsgi_webdav_foreach_prop(udav.add_rtype_object_prop,req_prop, r_type, 0, "resourcetype"); uwsgi_webdav_foreach_prop(udav.add_object_prop,req_prop, r_prop, 0, NULL); uwsgi_webdav_foreach_prop(udav.add_object_prop_href,req_prop, r_prop, 1, NULL); uwsgi_webdav_foreach_prop(udav.add_object_prop_comp,req_prop, r_prop, 2, NULL); } } else { xmlNewChild(r_prop, dav_ns, BAD_CAST "displayname", NULL); xmlNewChild(r_prop, dav_ns, BAD_CAST "resourcetype", NULL); if (!S_ISDIR(st.st_mode)) { xmlNewChild(r_prop, dav_ns, BAD_CAST "getcontentlength", NULL); xmlNewChild(r_prop, dav_ns, BAD_CAST "getcontenttype", NULL); } xmlNewChild(r_prop, dav_ns, BAD_CAST "creationdate", NULL); xmlNewChild(r_prop, dav_ns, BAD_CAST "getlastmodified", NULL); xmlNewChild(r_prop, dav_ns, BAD_CAST "supported-report-set", NULL); if (wsgi_req->remote_user_len > 0) { xmlNewChild(r_prop, dav_ns, BAD_CAST "current-user-privilege-set", NULL); if (udav.principal_base) { xmlNewChild(r_prop, dav_ns, BAD_CAST "current-user-principal", NULL); } } } #if defined(__linux__) || defined(__APPLE__) // get xattr for user.uwsgi.webdav. #if defined(__linux__) ssize_t rlen = listxattr(filename, NULL, 0); #elif defined(__APPLE__) ssize_t rlen = listxattr(filename, NULL, 0, 0); #endif // do not return -1 as the previous xml is valid !!! if (rlen <= 0) return 0; // use calloc to avoid races char *xattrs = uwsgi_calloc(rlen); #if defined(__linux__) if (listxattr(filename, xattrs, rlen) <= 0) { #elif defined(__APPLE__) if (listxattr(filename, xattrs, rlen, 0) <= 0) { #endif free(xattrs); return 0; } // parse the name list ssize_t i; char *key = NULL; for(i=0;i<rlen;i++) { // check for wrong condition if (xattrs[i] == 0 && key == NULL) break; if (key && xattrs[i] == 0) { if (!uwsgi_starts_with(key, strlen(key), "user.uwsgi.webdav.", 18)) { if (uwsgi_string_list_has_item(udav.skip_prop, key + 18, strlen(key + 18))) continue; xmlNsPtr xattr_ns = NULL; // does it has a namespace ? char *separator = strchr(key + 18, '|'); char *xattr_key = key + 18; if (separator) { xattr_key = separator + 1; *separator = 0; if (!uwsgi_webdav_prop_requested(req_prop, key + 18, xattr_key)) continue; } else { if (!uwsgi_webdav_prop_requested(req_prop, NULL, xattr_key)) continue; } xmlNode *xattr_item = NULL; if (with_values) { #if defined(__linux__) ssize_t rlen2 = getxattr(filename, key, NULL, 0); #elif defined(__APPLE__) ssize_t rlen2 = getxattr(filename, key, NULL, 0, 0, 0); #endif if (rlen > 0) { // leave space for final 0 char *xvalue = uwsgi_calloc(rlen2 + 1); #if defined(__linux__) if (getxattr(filename, key, xvalue, rlen2) > 0) { #elif defined(__APPLE__) if (getxattr(filename, key, xvalue, rlen2, 0 ,0) > 0) { #endif xattr_item = xmlNewTextChild(r_prop, NULL, BAD_CAST xattr_key, BAD_CAST xvalue); } free(xvalue); } else if (rlen == 0) { xattr_item = xmlNewTextChild(r_prop, NULL, BAD_CAST xattr_key, NULL); } } else { xattr_item = xmlNewTextChild(r_prop, NULL, BAD_CAST xattr_key, NULL); } if (separator && xattr_item) { xattr_ns = xmlNewNs(xattr_item, BAD_CAST (key + 18), NULL); *separator = '|'; xmlSetNs(xattr_item, xattr_ns); } } key = NULL; } else if (key == NULL) { key = &xattrs[i]; } } free(xattrs); #endif return 0; } static size_t uwsgi_webdav_expand_path(struct wsgi_request *wsgi_req, char *item, uint16_t item_len, char *filename) { struct uwsgi_app *ua = &uwsgi_apps[wsgi_req->app_id]; char *docroot = ua->interpreter; size_t docroot_len = strlen(docroot); // merge docroot with path_info char *tmp_filename = uwsgi_concat3n(docroot, docroot_len, "/", 1, item, item_len); // try expanding the path if (!realpath(tmp_filename, filename)) { free(tmp_filename); return 0; } free(tmp_filename); return strlen(filename); } static size_t uwsgi_webdav_expand_fake_path(struct wsgi_request *wsgi_req, char *item, uint16_t item_len, char *filename) { char *last_slash = uwsgi_get_last_charn(item, item_len, '/'); if (!last_slash) return 0; size_t filename_len = uwsgi_webdav_expand_path(wsgi_req, item, last_slash - item, filename); if (!filename_len) return 0; // check for overflow if (filename_len + (item_len - (last_slash - item)) >= PATH_MAX) return 0; memcpy(filename + filename_len, last_slash, (item_len - (last_slash - item))); filename_len += (item_len - (last_slash - item)); filename[(int)filename_len] = 0; return filename_len; } static xmlDoc *uwsgi_webdav_manage_prop(struct wsgi_request *wsgi_req, xmlNode *req_prop, char *filename, size_t filename_len, int with_values) { // default 1 depth int depth = 1; 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); } xmlDoc *rdoc = xmlNewDoc(BAD_CAST "1.0"); xmlNode *multistatus = xmlNewNode(NULL, BAD_CAST "multistatus"); xmlDocSetRootElement(rdoc, multistatus); xmlNsPtr dav_ns = xmlNewNs(multistatus, BAD_CAST "DAV:", BAD_CAST "D"); xmlSetNs(multistatus, dav_ns); if (depth == 0) { char *uri = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "", 0); uwsgi_webdav_add_props(wsgi_req, req_prop, multistatus, dav_ns, uri, filename, with_values); free(uri); } else { DIR *collection = opendir(filename); struct dirent de; for (;;) { struct dirent *de_r = NULL; if (readdir_r(collection, &de, &de_r)) { uwsgi_error("uwsgi_wevdav_manage_propfind()/readdir_r()"); break; } if (de_r == NULL) { break; } char *uri = NULL; char *direntry = NULL; if (!strcmp(de.d_name, "..")) { // skip .. continue; } else if (!strcmp(de.d_name, ".")) { uri = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "", 0); direntry = uwsgi_concat2n(filename, filename_len, "", 0); } else if (wsgi_req->path_info[wsgi_req->path_info_len - 1] == '/') { uri = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, de.d_name, strlen(de.d_name)); direntry = uwsgi_concat3n(filename, filename_len, "/", 1, de.d_name, strlen(de.d_name)); } else { uri = uwsgi_concat3n(wsgi_req->path_info, wsgi_req->path_info_len, "/", 1, de.d_name, strlen(de.d_name)); direntry = uwsgi_concat3n(filename, filename_len, "/", 1, de.d_name, strlen(de.d_name)); } uwsgi_webdav_add_props(wsgi_req, req_prop, multistatus, dav_ns, uri, direntry, with_values); free(uri); free(direntry); } closedir(collection); } return rdoc; }
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; }
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; }
struct uwsgi_socket *uwsgi_new_socket(char *name) { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets, *old_uwsgi_sock; struct sockaddr_in sin; socklen_t socket_type_len; if (!uwsgi_sock) { uwsgi.sockets = uwsgi_malloc(sizeof(struct uwsgi_socket)); uwsgi_sock = uwsgi.sockets; } else { while (uwsgi_sock) { old_uwsgi_sock = uwsgi_sock; uwsgi_sock = uwsgi_sock->next; } uwsgi_sock = uwsgi_malloc(sizeof(struct uwsgi_socket)); old_uwsgi_sock->next = uwsgi_sock; } memset(uwsgi_sock, 0, sizeof(struct uwsgi_socket)); uwsgi_sock->name = name; uwsgi_sock->fd = -1; if (!name) return uwsgi_sock; if (name[0] == '=') { int shared_socket = atoi(uwsgi_sock->name + 1); if (shared_socket >= 0) { struct uwsgi_socket *uss = uwsgi_get_shared_socket_by_num(shared_socket); if (!uss) { uwsgi_log("unable to use shared socket %d\n", shared_socket); exit(1); } uwsgi_sock->bound = 1; uwsgi_sock->shared = 1; uwsgi_sock->from_shared = shared_socket; return uwsgi_sock; } } if (!uwsgi_startswith(name, "fd://", 5)) { uwsgi_add_socket_from_fd(uwsgi_sock, atoi(name + 5)); return uwsgi_sock; } char *tcp_port = strrchr(name, ':'); if (tcp_port) { // INET socket, check for 0 port if (tcp_port[1] == 0 || tcp_port[1] == '0') { uwsgi_sock->fd = bind_to_tcp(name, uwsgi.listen_queue, tcp_port); uwsgi_sock->family = AF_INET; uwsgi_sock->bound = 1; uwsgi_sock->auto_port = 1; socket_type_len = sizeof(struct sockaddr_in); if (getsockname(uwsgi_sock->fd, (struct sockaddr *) &sin, &socket_type_len)) { uwsgi_error("getsockname()"); exit(1); } char *auto_port = uwsgi_num2str(ntohs(sin.sin_port)); uwsgi_sock->name = uwsgi_concat3n(name, tcp_port - name, ":", 1, auto_port, strlen(auto_port)); } // is it fd 0 ? else if (tcp_port[1] == ':') { uwsgi_sock->fd = 0; uwsgi_sock->family = AF_INET; uwsgi_sock->bound = 1; socket_type_len = sizeof(struct sockaddr_in); if (getsockname(0, (struct sockaddr *) &sin, &socket_type_len)) { uwsgi_error("getsockname()"); exit(1); } char *auto_port = uwsgi_num2str(ntohs(sin.sin_port)); char *auto_ip = inet_ntoa(sin.sin_addr); uwsgi_sock->name = uwsgi_concat3n(auto_ip, strlen(auto_ip), ":", 1, auto_port, strlen(auto_port)); } } return uwsgi_sock; }
void *uwsgi_python_tracebacker_thread(void *foobar) { struct iovec iov[11]; 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); if (fd < 0) { uwsgi.no_defer_accept = current_defer_accept; free(str_wid); free(sock_path); return NULL; } uwsgi.no_defer_accept = current_defer_accept; PyObject *traceback_module = PyImport_ImportModule("traceback"); if (!traceback_module) { free(str_wid); free(sock_path); close(fd); 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 end2; PyObject *current_frames_items = PyObject_GetAttrString(current_frames, "items"); if (!current_frames_items) goto end; PyObject *frames_ret = PyEval_CallObject(current_frames_items, (PyObject *)NULL); if (!frames_ret) goto end3; PyObject *frames_iter = PyObject_GetIter(frames_ret); if (!frames_iter) goto end4; // we have the first frame, lets parse it if (write(client_fd, "*** uWSGI Python tracebacker output ***\n\n", 41) < 0) { uwsgi_error("write()"); } PyObject *frame = PyIter_Next(frames_iter); while(frame) { PyObject *thread_id = PyTuple_GetItem(frame, 0); if (!thread_id) goto next2; PyObject *stack = PyTuple_GetItem(frame, 1); if (!stack) goto next2; PyObject *arg_tuple = PyTuple_New(1); PyTuple_SetItem(arg_tuple, 0, stack); Py_INCREF(stack); PyObject *stacktrace = PyEval_CallObject( extract_stack, arg_tuple); Py_DECREF(arg_tuple); if (!stacktrace) goto next2; PyObject *stacktrace_iter = PyObject_GetIter(stacktrace); if (!stacktrace_iter) { Py_DECREF(stacktrace); goto next2;} PyObject *st_items = PyIter_Next(stacktrace_iter); // we have the first traceback item while(st_items) { #ifdef PYTHREE int thread_name_need_free = 0; #endif PyObject *st_filename = PyTuple_GetItem(st_items, 0); if (!st_filename) { Py_DECREF(st_items); goto next; } PyObject *st_lineno = PyTuple_GetItem(st_items, 1); if (!st_lineno) {Py_DECREF(st_items); goto next;} PyObject *st_name = PyTuple_GetItem(st_items, 2); if (!st_name) {Py_DECREF(st_items); goto next;} PyObject *st_line = PyTuple_GetItem(st_items, 3); iov[0].iov_base = "thread_id = "; iov[0].iov_len = 12; iov[1].iov_base = uwsgi_python_get_thread_name(thread_id); if (!iov[1].iov_base) { iov[1].iov_base = "<UnnamedPythonThread>"; } #ifdef PYTHREE else { thread_name_need_free = 1; } #endif iov[1].iov_len = strlen(iov[1].iov_base); iov[2].iov_base = " filename = "; iov[2].iov_len = 12; #ifdef PYTHREE PyObject *st_filename_utf8 = PyUnicode_AsUTF8String(st_filename); if (!st_filename_utf8) { if (thread_name_need_free) free(iov[1].iov_base); goto next; } iov[3].iov_base = PyString_AsString(st_filename_utf8); #else iov[3].iov_base = PyString_AsString(st_filename); #endif iov[3].iov_len = strlen(iov[3].iov_base); iov[4].iov_base = " lineno = "; iov[4].iov_len = 10 ; iov[5].iov_base = uwsgi_num2str(PyInt_AsLong(st_lineno)); iov[5].iov_len = strlen(iov[5].iov_base); iov[6].iov_base = " function = "; iov[6].iov_len = 12 ; #ifdef PYTHREE PyObject *st_name_utf8 = PyUnicode_AsUTF8String(st_name); if (!st_name_utf8) { if (thread_name_need_free) free(iov[1].iov_base); Py_DECREF(st_filename_utf8); goto next; } iov[7].iov_base = PyString_AsString(st_name_utf8); #else iov[7].iov_base = PyString_AsString(st_name); #endif iov[7].iov_len = strlen(iov[7].iov_base); iov[8].iov_base = ""; iov[8].iov_len = 0 ; iov[9].iov_base = ""; iov[9].iov_len = 0; iov[10].iov_base = "\n"; iov[10].iov_len = 1; #ifdef PYTHREE PyObject *st_line_utf8 = NULL; #endif if (st_line) { iov[8].iov_base = " line = "; iov[8].iov_len = 8; #ifdef PYTHREE PyObject *st_line_utf8 = PyUnicode_AsUTF8String(st_line); if (!st_line_utf8) { if (thread_name_need_free) free(iov[1].iov_base); Py_DECREF(st_filename_utf8); Py_DECREF(st_name_utf8); goto next; } iov[9].iov_base = PyString_AsString(st_line_utf8); #else iov[9].iov_base = PyString_AsString(st_line); #endif iov[9].iov_len = strlen(iov[9].iov_base); } if (writev(client_fd, iov, 11) < 0) { uwsgi_error("writev()"); } // free the line_no free(iov[5].iov_base); Py_DECREF(st_items); #ifdef PYTHREE Py_DECREF(st_filename_utf8); Py_DECREF(st_name_utf8); if (st_line_utf8) { Py_DECREF(st_line_utf8); } if (thread_name_need_free) free(iov[1].iov_base); #endif st_items = PyIter_Next(stacktrace_iter); } if (write(client_fd, "\n", 1) < 0) { uwsgi_error("write()"); } next: Py_DECREF(stacktrace_iter); Py_DECREF(stacktrace); next2: Py_DECREF(frame); frame = PyIter_Next(frames_iter); } Py_DECREF(frames_iter); end4: Py_DECREF(frames_ret); end3: Py_DECREF(current_frames_items); end: Py_DECREF(current_frames); end2: close(client_fd); } return NULL; }
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; } }
ssize_t uwsgi_lf_msecs(struct wsgi_request *wsgi_req, char **buf) { *buf = uwsgi_num2str((wsgi_req->end_of_request-wsgi_req->start_of_request)/1000); return strlen(*buf); }
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; }
static int uwsgi_wevdav_manage_get(struct wsgi_request *wsgi_req, int send_body) { char filename[PATH_MAX]; size_t filename_len = uwsgi_webdav_expand_path(wsgi_req, wsgi_req->path_info, wsgi_req->path_info_len, filename); if (!filename_len) { uwsgi_404(wsgi_req); return UWSGI_OK; } if (uwsgi_is_dir(filename)) { uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6); if (send_body) { uwsgi_webdav_dirlist(wsgi_req, filename); } return UWSGI_OK; } int fd = open(filename, O_RDONLY); if (fd < 0) { uwsgi_403(wsgi_req); return UWSGI_OK; } struct stat st; if (fstat(fd, &st)) { close(fd); uwsgi_403(wsgi_req); return UWSGI_OK; } if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end; // add content_length if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end; // add last-modified if (uwsgi_response_add_last_modified(wsgi_req, st.st_mtime)) goto end; // add mime_type size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(filename, filename_len, &mime_type_len); if (mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end; } // add ETag (based on file mtime, not rock-solid, but good enough) char *etag = uwsgi_num2str(st.st_mtime); if (uwsgi_response_add_header(wsgi_req, "ETag", 4, etag, strlen(etag))) { free(etag); goto end; } free(etag); // start sending the file (note: we do not use sendfile() api, for being able to use caching and transformations) if (!send_body) goto end; // use a pretty big buffer (for performance reasons) char buf[32768]; size_t remains = st.st_size; while (remains > 0) { ssize_t rlen = read(fd, buf, UMIN(32768, remains)); if (rlen <= 0) { uwsgi_error("uwsgi_wevdav_manage_get/read()"); break; } remains -= rlen; if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) { break; } } end: close(fd); return UWSGI_OK; }
ssize_t uwsgi_lf_status(struct wsgi_request *wsgi_req, char **buf) { *buf = uwsgi_num2str(wsgi_req->status); return strlen(*buf); }
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; }
ssize_t uwsgi_lf_epoch(struct wsgi_request *wsgi_req, char **buf) { *buf = uwsgi_num2str(uwsgi_now()); return strlen(*buf); }