static char *uwsgi_route_var_xattr2(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) { char *colon = memchr(key, ':', keylen); if (!colon) return NULL; uint16_t var_vallen = 0; char *var_value = uwsgi_get_var(wsgi_req, key, colon-key, &var_vallen); if (var_value) { uint16_t var2_vallen = 0; char *var2_value = uwsgi_get_var(wsgi_req, colon+1, (keylen-1) - (colon-key), &var2_vallen); if (var2_value) { char *filename = uwsgi_concat2n(var_value, var_vallen, "", 0); char *name = uwsgi_concat2n(var2_value, var2_vallen, "", 0); ssize_t rlen = getxattr(filename, name, NULL, 0); if (rlen > 0) { char *value = uwsgi_calloc(rlen); getxattr(filename, name, value, rlen); *vallen = rlen; free(filename); free(name); return value; } free(filename); free(name); } } return NULL; }
// cache command (uWSGI specific) static struct uwsgi_buffer *ssi_cmd_cache(struct wsgi_request *wsgi_req, struct uwsgi_ssi_arg *argv, int argc) { size_t var_len = 0; char *var = uwsgi_ssi_get_arg(argv, argc, "key", 3, &var_len); if (!var || var_len == 0) return NULL; size_t cache_len = 0; char *cache = uwsgi_ssi_get_arg(argv, argc, "name", 4, &cache_len); char *cache_name = NULL; if (cache && cache_len) { cache_name = uwsgi_concat2n(cache, cache_len, "", 0); } uint64_t rlen = 0; char *value = uwsgi_cache_magic_get(var, var_len, &rlen, NULL, cache_name); if (cache_name) free(cache_name); struct uwsgi_buffer *ub = NULL; if (value) { ub = uwsgi_buffer_new(rlen); if (uwsgi_buffer_append(ub, value, rlen)) { free(value); uwsgi_buffer_destroy(ub); return NULL; } free(value); } return ub; }
ssize_t uwsgi_proto_zeromq_write(struct wsgi_request * wsgi_req, char *buf, size_t len) { zmq_msg_t reply; char *zmq_body; if (len == 0) return 0; zmq_body = uwsgi_concat2n(wsgi_req->proto_parser_buf, (int) wsgi_req->proto_parser_pos, buf, (int) len); //uwsgi_log("|%.*s|\n", (int)wsgi_req->proto_parser_pos+len, zmq_body); zmq_msg_init_data(&reply, zmq_body, wsgi_req->proto_parser_pos + len, uwsgi_proto_zeromq_free, NULL); if (uwsgi.threads > 1) pthread_mutex_lock(&uwsgi.zmq_lock); if (zmq_send(uwsgi.zmq_pub, &reply, 0)) { if (!uwsgi.ignore_write_errors) { uwsgi_error("zmq_send()"); } wsgi_req->write_errors++; if (uwsgi.threads > 1) pthread_mutex_unlock(&uwsgi.zmq_lock); zmq_msg_close(&reply); return 0; } if (uwsgi.threads > 1) pthread_mutex_unlock(&uwsgi.zmq_lock); zmq_msg_close(&reply); return len; }
int uwsgi_cr_map_use_cache(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) { uint64_t hits = 0; uwsgi_rlock(ucr->cache->lock); char *value = uwsgi_cache_get4(ucr->cache, peer->key, peer->key_len, &peer->instance_address_len, &hits); if (!value) goto end; peer->tmp_socket_name = uwsgi_concat2n(value, peer->instance_address_len, "", 0); size_t nodes = uwsgi_str_occurence(peer->tmp_socket_name, peer->instance_address_len, '|'); if (nodes > 0) { size_t choosen_node = hits % (nodes+1); size_t choosen_node_len = 0; peer->instance_address = uwsgi_str_split_nget(peer->tmp_socket_name, peer->instance_address_len, '|', choosen_node, &choosen_node_len); if (!peer->instance_address) goto end; peer->instance_address_len = choosen_node_len; } else { peer->instance_address = peer->tmp_socket_name; } 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); } end: uwsgi_rwunlock(ucr->cache->lock); return 0; }
socklen_t socket_to_in_addr6(char *socket_name, char *port, int portn, struct sockaddr_in6 * sin_addr) { memset(sin_addr, 0, sizeof(struct sockaddr_in6)); sin_addr->sin6_family = AF_INET6; if (port) { *port = 0; sin_addr->sin6_port = htons(atoi(port + 1)); } else { sin_addr->sin6_port = htons(portn); } if (!strcmp(socket_name, "[::]")) { sin_addr->sin6_addr = in6addr_any; } else { char *sanitized_sn = uwsgi_concat2n(socket_name + 1, strlen(socket_name + 1) - 1, "", 0); char *resolved = uwsgi_resolve_ip(sanitized_sn); if (resolved) { inet_pton(AF_INET6, resolved, sin_addr->sin6_addr.s6_addr); } else { inet_pton(AF_INET6, sanitized_sn, sin_addr->sin6_addr.s6_addr); } free(sanitized_sn); } if (port) { *port = ':'; } return sizeof(struct sockaddr_in6); }
int uwsgi_cr_map_use_pattern(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) { size_t tmp_socket_name_len = 0; ucr->magic_table['s'] = uwsgi_concat2n(peer->key, peer->key_len, "", 0); peer->tmp_socket_name = magic_sub(ucr->pattern, ucr->pattern_len, &tmp_socket_name_len, ucr->magic_table); free(ucr->magic_table['s']); peer->instance_address_len = tmp_socket_name_len; peer->instance_address = peer->tmp_socket_name; return 0; }
int uwsgi_cr_map_use_pattern(struct uwsgi_corerouter *ucr, struct corerouter_session *cr_session) { int tmp_socket_name_len = 0; ucr->magic_table['s'] = uwsgi_concat2n(cr_session->hostname, cr_session->hostname_len, "", 0); cr_session->tmp_socket_name = magic_sub(ucr->pattern, ucr->pattern_len, &tmp_socket_name_len, ucr->magic_table); free(ucr->magic_table['s']); cr_session->instance_address_len = tmp_socket_name_len; cr_session->instance_address = cr_session->tmp_socket_name; return 0; }
static char *uwsgi_webdav_new_date(uint64_t t) { // 30+1 char d[31]; int len = uwsgi_http_date((time_t) t, d); if (!len) { return NULL; } return uwsgi_concat2n(d, len, "", 0); }
int uwsgi_fr_map_use_pattern(struct fastrouter_session *fr_session, char **magic_table) { int tmp_socket_name_len = 0; magic_table['s'] = uwsgi_concat2n(fr_session->hostname, fr_session->hostname_len, "", 0); fr_session->tmp_socket_name = magic_sub(ufr.pattern, ufr.pattern_len, &tmp_socket_name_len, magic_table); free(magic_table['s']); fr_session->instance_address_len = tmp_socket_name_len; fr_session->instance_address = fr_session->tmp_socket_name; return 0; }
void uwsgi_opt_add_legion_cron(char *opt, char *value, void *foobar) { char *space = strchr(value, ' '); if (!space) { uwsgi_log("invalid %s syntax, must be prefixed with a legion name\n", opt); exit(1); } char *legion = uwsgi_concat2n(value, space-value, "", 0); struct uwsgi_cron *uc = uwsgi_cron_add(space+1); uc->legion = legion; }
// status could be NNN or NNN message int uwsgi_response_prepare_headers(struct wsgi_request *wsgi_req, char *status, uint16_t status_len) { if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || status_len < 3 || wsgi_req->write_errors) return -1; if (!wsgi_req->headers) { wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size); wsgi_req->headers->limit = UMAX16; } // reset the buffer (could be useful for rollbacks...) wsgi_req->headers->pos = 0; // reset headers count wsgi_req->header_cnt = 0; struct uwsgi_buffer *hh = NULL; wsgi_req->status = uwsgi_str3_num(status); #ifdef UWSGI_ROUTING // apply error routes if (uwsgi_apply_error_routes(wsgi_req) == UWSGI_ROUTE_BREAK) { // from now on ignore write body requests... wsgi_req->ignore_body = 1; return -1; } wsgi_req->is_error_routing = 0; #endif if (status_len <= 4) { char *new_sc = NULL; size_t new_sc_len = 0; uint16_t sc_len = 0; const char *sc = uwsgi_http_status_msg(status, &sc_len); if (sc) { new_sc = uwsgi_concat3n(status, 3, " ", 1, (char *)sc, sc_len); new_sc_len = 4+sc_len; } else { new_sc = uwsgi_concat2n(status, 3, " Unknown", 8); new_sc_len = 11; } hh = wsgi_req->socket->proto_prepare_headers(wsgi_req, new_sc, new_sc_len); free(new_sc); } else { hh = wsgi_req->socket->proto_prepare_headers(wsgi_req, status, status_len); } if (!hh) {wsgi_req->write_errors++; return -1;} if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error; uwsgi_buffer_destroy(hh); return 0; error: uwsgi_buffer_destroy(hh); wsgi_req->write_errors++; return -1; }
jobject uwsgi_jvm_str(char *str, size_t len) { jobject new_str; if (len > 0) { char *tmp = uwsgi_concat2n(str, len, "", 0); new_str = (*ujvm_env)->NewStringUTF(ujvm_env, tmp); free(tmp); } else { new_str = (*ujvm_env)->NewStringUTF(ujvm_env, str); } return new_str; }
static void uwsgi_webdav_do_prop_update(struct wsgi_request *wsgi_req, xmlNode *prop, xmlNode *response, char *filename, uint8_t action) { xmlNode *node; // search for "prop" for (node = prop->children; node; node = node->next) { if (node->type == XML_ELEMENT_NODE) { xmlNode *propstat = xmlNewChild(response, NULL, BAD_CAST "propstat", NULL); xmlNode *r_prop = xmlNewChild(propstat, NULL, BAD_CAST "prop" , NULL); xmlNode *new_prop = xmlNewChild(r_prop, NULL, node->name, NULL); if (node->ns) { xmlNsPtr xattr_ns = xmlNewNs(new_prop, node->ns->href, NULL); xmlSetNs(new_prop, xattr_ns); } if (action == 0) { if (uwsgi_webdav_prop_set(filename, (char *) node->name, node->ns ? (char *) node->ns->href : NULL, node->children ? (char *) node->children->content : "")) { char *r_status = uwsgi_concat2n(wsgi_req->protocol, wsgi_req->protocol_len, " 403 Forbidden", 14); xmlNewChild(r_prop, NULL, BAD_CAST "status", BAD_CAST r_status); free(r_status); } else { char *r_status = uwsgi_concat2n(wsgi_req->protocol, wsgi_req->protocol_len, " 200 OK", 7); xmlNewChild(r_prop, NULL, BAD_CAST "status", BAD_CAST r_status); free(r_status); } } else if (action == 1) { if (uwsgi_webdav_prop_del(filename, (char *) node->name, node->ns ? (char *) node->ns->href : NULL)) { char *r_status = uwsgi_concat2n(wsgi_req->protocol, wsgi_req->protocol_len, " 403 Forbidden", 14); xmlNewChild(r_prop, NULL, BAD_CAST "status", BAD_CAST r_status); free(r_status); } else { char *r_status = uwsgi_concat2n(wsgi_req->protocol, wsgi_req->protocol_len, " 200 OK", 7); xmlNewChild(r_prop, NULL, BAD_CAST "status", BAD_CAST r_status); free(r_status); } } } } }
// include command static struct uwsgi_buffer *ssi_cmd_include(struct wsgi_request *wsgi_req, struct uwsgi_ssi_arg *argv, int argc) { size_t var_len = 0; char *var = uwsgi_ssi_get_arg(argv, argc, "file", 4, &var_len); if (!var || var_len == 0) return NULL; char *filename = uwsgi_concat2n(var, var_len, "", 0); struct uwsgi_buffer *ub = uwsgi_buffer_from_file(filename); free(filename); return ub; }
// status could be NNN or NNN message int uwsgi_response_prepare_headers(struct wsgi_request *wsgi_req, char *status, uint16_t status_len) { if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || status_len < 3 || wsgi_req->write_errors) return -1; if (!wsgi_req->headers) { wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size); wsgi_req->headers->limit = UMAX16; } // reset the buffer (could be useful for rollbacks...) wsgi_req->headers->pos = 0; struct uwsgi_buffer *hh = NULL; if (status_len <= 4) { char *new_sc = NULL; size_t new_sc_len = 0; uint16_t sc_len = 0; const char *sc = uwsgi_http_status_msg(status, &sc_len); if (sc) { new_sc = uwsgi_concat3n(status, 3, " ", 1, (char *)sc, sc_len); new_sc_len = 4+sc_len; } else { new_sc = uwsgi_concat2n(status, 3, " Unknown", 8); new_sc_len = 11; } hh = wsgi_req->socket->proto_prepare_headers(wsgi_req, new_sc, new_sc_len); free(new_sc); } else { hh = wsgi_req->socket->proto_prepare_headers(wsgi_req, status, status_len); } if (!hh) {wsgi_req->write_errors++; return -1;} if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error; uwsgi_buffer_destroy(hh); wsgi_req->status = uwsgi_str3_num(status); return 0; error: uwsgi_buffer_destroy(hh); wsgi_req->write_errors++; return -1; }
static char *amqp_wait_queue_declare_ok(int fd) { uint32_t size; char *frame = amqp_get_method(fd, 50, 11, &size); char *queue = NULL; char *ptr; char *watermark; if (frame) { ptr = frame+4; watermark = frame+size; ptr = amqp_get_str(ptr, watermark); if (!ptr) { free(frame); return NULL; } queue = uwsgi_concat2n(frame+5, *(frame+4), "", 0); free(frame); return queue; } return NULL; }
static struct uwsgi_buffer *uwsgi_ruby_backtrace(struct wsgi_request *wsgi_req) { VALUE err = rb_errinfo(); VALUE ary = rb_funcall(err, rb_intern("backtrace"), 0); int i; struct uwsgi_buffer *ub = uwsgi_buffer_new(4096); char *filename = NULL; char *function = NULL; for (i=0; i<RARRAY_LEN(ary); i++) { char *bt = RSTRING_PTR(RARRAY_PTR(ary)[i]); // ok let's start the C dance to parse the backtrace char *colon = strchr(bt, ':'); if (!colon) continue; filename = uwsgi_concat2n(bt, (int) (colon-bt), "", 0); uint16_t filename_len = colon-bt; colon++; if (*colon == 0) goto error; char *lineno_ptr = colon; colon = strchr(lineno_ptr, ':'); if (!colon) goto error; int64_t lineno = uwsgi_str_num(lineno_ptr, (int) (colon-lineno_ptr)); colon++; if (*colon == 0) goto error; colon = strchr(lineno_ptr, '`'); if (!colon) goto error; colon++; if (*colon == 0) goto error; char *function_ptr = colon; char *function_end = strchr(function_ptr, '\''); if (!function_end) goto error; function = uwsgi_concat2n(function_ptr, (int) (function_end-function_ptr), "", 0); uint16_t function_len = function_end-function_ptr; if (uwsgi_buffer_u16le(ub, filename_len)) goto error; if (uwsgi_buffer_append(ub, filename, filename_len)) goto error; if (uwsgi_buffer_append_valnum(ub, lineno)) goto error; if (uwsgi_buffer_u16le(ub, function_len)) goto error; if (uwsgi_buffer_append(ub, function, function_len)) goto error; // in ruby we do not have text/code nor custom if (uwsgi_buffer_u16le(ub, 0)) goto error; if (uwsgi_buffer_append(ub, "", 0)) goto error; if (uwsgi_buffer_u16le(ub, 0)) goto error; if (uwsgi_buffer_append(ub, "", 0)) goto error; free(filename); filename = NULL; free(function); function = NULL; } return ub; error: uwsgi_buffer_destroy(ub); if (filename) { free(filename); } if (function) { free(function); } return NULL; }
static int uwsgi_wevdav_manage_proppatch(struct wsgi_request *wsgi_req, xmlDoc * doc) { 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 == 0) { uwsgi_404(wsgi_req); return UWSGI_OK; } xmlNode *element = xmlDocGetRootElement(doc); if (!element) return -1; if (!element || (strcmp((char *) element->name, "propertyupdate"))) return -1; if (uwsgi_response_prepare_headers(wsgi_req, "207 Multi-Status", 16)) return -1; if (uwsgi_response_add_content_type(wsgi_req, "application/xml; charset=\"utf-8\"", 32)) return -1; 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); xmlNode *response = xmlNewChild(multistatus, dav_ns, BAD_CAST "response", NULL); char *uri = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "", 0); 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); // propfind can be "set" or "remove" xmlNode *node; for (node = element->children; node; node = node->next) { if (node->type == XML_ELEMENT_NODE) { if (node->ns && !strcmp((char *) node->ns->href, "DAV:")) { if (!strcmp((char *) node->name, "set")) { uwsgi_webdav_manage_prop_update(wsgi_req, node, response, filename, 0); } else if (!strcmp((char *) node->name, "remove")) { uwsgi_webdav_manage_prop_update(wsgi_req, node, response, filename, 1); } } } } if (!rdoc) return UWSGI_OK; xmlChar *xmlbuf; int xlen = 0; xmlDocDumpFormatMemory(rdoc, &xmlbuf, &xlen, 1); uwsgi_response_add_content_length(wsgi_req, xlen); uwsgi_response_write_body_do(wsgi_req, (char *) xmlbuf, xlen); #ifdef UWSGI_DEBUG uwsgi_log("\n%.*s\n", xlen, xmlbuf); #endif xmlFreeDoc(rdoc); xmlFree(xmlbuf); return UWSGI_OK; }
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_imperial_monitor_amqp_event(struct uwsgi_emperor_scanner *ues) { uint64_t msgsize; char *amqp_routing_key = NULL; struct uwsgi_instance *ui_current; struct stat st; char *config = uwsgi_amqp_consume(ues->fd, &msgsize, &amqp_routing_key); if (!config) { uwsgi_log("problem with RabbitMQ server, trying reconnection...\n"); close(ues->fd); ues->fd = -1; return; } // having a routing key means the body will be mapped to a config chunk if (amqp_routing_key) { uwsgi_log("AMQP routing_key = %s\n", amqp_routing_key); ui_current = emperor_get(amqp_routing_key); if (ui_current) { // make a new config free(ui_current->config); ui_current->config = config; ui_current->config_len = msgsize; if (!msgsize) { emperor_stop(ui_current); } else { emperor_respawn(ui_current, uwsgi_now()); } goto end0; } if (msgsize > 0) { emperor_add(ues, amqp_routing_key, uwsgi_now(), config, msgsize, 0, 0); } end0: free(config); free(amqp_routing_key); return; } // no routing key means the body contains a path to a config file if (msgsize >= 0xff || !msgsize) goto end; char *config_file = uwsgi_concat2n(config, msgsize, "", 0); ui_current = emperor_get(config_file); // if non-http check for file existance if (strncmp(config_file, "http://", 7)) { if (stat(config_file, &st)) { free(config_file); if (ui_current) emperor_stop(ui_current); goto end; } if (!S_ISREG(st.st_mode)) { free(config_file); if (ui_current) emperor_stop(ui_current); goto end; } } if (ui_current) { emperor_respawn(ui_current, uwsgi_now()); } else { emperor_add(ues, config_file, uwsgi_now(), NULL, 0, 0, 0); } free(config_file); end: free(config); }
static void mongrel2_connect() { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while(uwsgi_sock) { if (uwsgi_sock->proto != uwsgi_proto_zeromq_parser) goto next; uwsgi_sock->ctx = zmq_init(1); if (!uwsgi_sock->ctx) { uwsgi_error("mongrel2_connect()/zmq_init()"); exit(1); } char *responder = strchr(uwsgi_sock->name, ','); if (!responder) { uwsgi_log("invalid zeromq address: %s\n", uwsgi_sock->name); exit(1); } uwsgi_sock->receiver = uwsgi_concat2n(uwsgi_sock->name, responder - uwsgi_sock->name, "", 0); responder++; uwsgi_sock->pub = zmq_socket(uwsgi_sock->ctx, ZMQ_PUB); if (uwsgi_sock->pub == NULL) { uwsgi_error("mongrel2_connect()/zmq_socket()"); exit(1); } // generate uuid uwsgi_uuid(uwsgi_sock->uuid); if (zmq_setsockopt(uwsgi_sock->pub, ZMQ_IDENTITY, uwsgi_sock->uuid, 36) < 0) { uwsgi_error("mongrel2_connect()/zmq_setsockopt()"); exit(1); } if (zmq_connect(uwsgi_sock->pub, responder) < 0) { uwsgi_error("mongrel2_connect()/zmq_connect()"); exit(1); } uwsgi_log("zeromq UUID for responder %s on worker %d: %.*s\n", responder, uwsgi.mywid, 36, uwsgi_sock->uuid); // inform loop engine about edge trigger status uwsgi.is_et = 1; // initialize a lock for multithread usage if (uwsgi.threads > 1) { pthread_mutex_init(&uwsgi_sock->lock, NULL); } // one pull per-thread if (pthread_key_create(&uwsgi_sock->key, NULL)) { uwsgi_error("mongrel2_connect()/pthread_key_create()"); exit(1); } void *tmp_zmq_pull = zmq_socket(uwsgi_sock->ctx, ZMQ_PULL); if (tmp_zmq_pull == NULL) { uwsgi_error("mongrel2_connect()/zmq_socket()"); exit(1); } if (zmq_connect(tmp_zmq_pull, uwsgi_sock->receiver) < 0) { uwsgi_error("mongrel2_connect()/zmq_connect()"); exit(1); } pthread_setspecific(uwsgi_sock->key, tmp_zmq_pull); #ifdef ZMQ_FD size_t zmq_socket_len = sizeof(int); if (zmq_getsockopt(pthread_getspecific(uwsgi_sock->key), ZMQ_FD, &uwsgi_sock->fd, &zmq_socket_len) < 0) { uwsgi_error("mongrel2_connect()/zmq_getsockopt()"); exit(1); } if (uwsgi.threads > 1) { uwsgi_sock->fd_threads = uwsgi_malloc(sizeof(int) * uwsgi.threads); uwsgi_sock->fd_threads[0] = uwsgi_sock->fd; } #endif uwsgi_sock->bound = 1; #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) uwsgi_sock->recv_flag = ZMQ_DONTWAIT; #else uwsgi_sock->recv_flag = ZMQ_NOBLOCK; #endif next: uwsgi_sock = uwsgi_sock->next; } }
void uwsgi_subscribe(char *subscription, uint8_t cmd) { int subfile_size; int i; char *key = NULL; int keysize = 0; char *modifier1 = NULL; int modifier1_len = 0; char *socket_name = NULL; char *udp_address = subscription; char *udp_port = NULL; char *subscription_key = NULL; char *sign = NULL; // check for explicit socket_name char *equal = strchr(subscription, '='); if (equal) { socket_name = subscription; if (socket_name[0] == '=') { equal = strchr(socket_name + 1, '='); if (!equal) return; *equal = '\0'; struct uwsgi_socket *us = uwsgi_get_shared_socket_by_num(atoi(socket_name + 1)); if (!us) return; socket_name = us->name; } *equal = '\0'; udp_address = equal + 1; } // check for unix socket if (udp_address[0] != '/') { udp_port = strchr(udp_address, ':'); if (!udp_port) { if (equal) *equal = '='; return; } subscription_key = strchr(udp_port + 1, ':'); } else { subscription_key = strchr(udp_address + 1, ':'); } if (!subscription_key) { if (equal) *equal = '='; return; } udp_address = uwsgi_concat2n(udp_address, subscription_key - udp_address, "", 0); if (subscription_key[1] == '@') { if (!uwsgi_file_exists(subscription_key + 2)) goto clear; char *lines = uwsgi_open_and_read(subscription_key + 2, &subfile_size, 1, NULL); if (subfile_size > 0) { key = lines; for (i = 0; i < subfile_size; i++) { if (lines[i] == 0) { if (keysize > 0) { if (key[0] != '#' && key[0] != '\n') { modifier1 = strchr(key, ','); if (modifier1) { modifier1[0] = 0; modifier1++; modifier1_len = strlen(modifier1); keysize = strlen(key); } uwsgi_send_subscription(udp_address, key, keysize, uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign); modifier1 = NULL; modifier1_len = 0; } } break; } else if (lines[i] == '\n') { if (keysize > 0) { if (key[0] != '#' && key[0] != '\n') { lines[i] = 0; modifier1 = strchr(key, ','); if (modifier1) { modifier1[0] = 0; modifier1++; modifier1_len = strlen(modifier1); keysize = strlen(key); } uwsgi_send_subscription(udp_address, key, keysize, uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign); modifier1 = NULL; modifier1_len = 0; lines[i] = '\n'; } } key = lines + i + 1; keysize = 0; continue; } keysize++; } free(lines); } } else { modifier1 = strchr(subscription_key + 1, ','); if (modifier1) { modifier1[0] = 0; modifier1++; sign = strchr(modifier1 + 1, ','); if (sign) { *sign = 0; sign++; } modifier1_len = strlen(modifier1); } uwsgi_send_subscription(udp_address, subscription_key + 1, strlen(subscription_key + 1), uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign); if (modifier1) modifier1[-1] = ','; if (sign) sign[-1] = ','; } clear: if (equal) *equal = '='; free(udp_address); }
// dumb/fake tnetstring implementation...all is a string static int uwsgi_mongrel2_tnetstring_parse(struct wsgi_request *wsgi_req, char *buf, int len) { char *ptr = buf; char *watermark = buf + len; char *key = NULL; size_t keylen = 0; char *val = NULL; size_t vallen = 0; uint16_t script_name_len = 0; char *query_string = NULL; uint16_t query_string_len = 0; int async_upload = 0; // set an empty SCRIPT_NAME wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SCRIPT_NAME", 11, "", 0); while (ptr < watermark) { ptr = uwsgi_netstring(ptr, len - (ptr - buf), &key, &keylen); if (ptr == NULL) break; // empty keys are not allowed if (keylen == 0) break; if (ptr >= watermark) break; ptr = uwsgi_netstring(ptr, len - (ptr - buf), &val, &vallen); if (ptr == NULL) break; if (key[0] < 97) { if (!uwsgi_strncmp("METHOD", 6, key, keylen)) { if (!uwsgi_strncmp("JSON", 4, val, vallen)) { return -1; } wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_METHOD", 14, val, vallen); } else if (!uwsgi_strncmp("VERSION", 7, key, keylen)) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PROTOCOL", 15, val, vallen); } else if (!uwsgi_strncmp("QUERY", 5, key, keylen)) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, val, vallen); query_string = val; query_string_len = vallen; } else if (!uwsgi_strncmp("PATH", 4, key, keylen)) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "PATH_INFO", 9, val + script_name_len, vallen - script_name_len); if (query_string_len) { char *request_uri = uwsgi_concat3n(val, vallen, "?", 1, query_string, query_string_len); wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, request_uri, vallen + 1 + query_string_len); free(request_uri); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, val, vallen); } } } else { // add header if (!uwsgi_strncmp("host", 4, key, keylen)) { char *colon = memchr(val, ':', vallen); if (colon) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, colon + 1, vallen - ((colon + 1) - val)); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, "80", 2); } } else if (!uwsgi_strncmp("content-length", 14, key, keylen)) { wsgi_req->post_cl = uwsgi_str_num(val, vallen); } else if (!uwsgi_strncmp("x-mongrel2-upload-done", 22, key, keylen)) { char *post_filename = uwsgi_concat2n(val, vallen, "", 0); wsgi_req->post_file = fopen(post_filename, "r"); if (!wsgi_req->post_file) { uwsgi_error_open(post_filename); wsgi_req->do_not_log = 1; } async_upload += 2; free(post_filename); } else if (!uwsgi_strncmp("x-forwarded-for", 15, key, keylen)) { char *colon = memchr(val, ',', vallen); if (colon) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, colon + 1, (colon + 1) - val); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, val, vallen); } } else if (!uwsgi_strncmp("x-mongrel2-upload-start", 23, key, keylen)) { async_upload += 1; } wsgi_req->uh->pktsize += proto_base_add_uwsgi_header(wsgi_req, key, keylen, val, vallen); } } wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len); if (query_string == NULL) { // always set QUERY_STRING wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, "", 0); } // reject uncomplete upload if (async_upload == 1) { return -1; } return 0; }
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; }
void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, char *config, uint32_t config_size, uid_t uid, gid_t gid) { struct uwsgi_instance *c_ui = ui; struct uwsgi_instance *n_ui = NULL; pid_t pid; char **vassal_argv; char *uef; char **uenvs; int counter; char *colon = NULL; int i; struct timeval tv; #ifdef UWSGI_DEBUG uwsgi_log("\n\nVASSAL %s %d %.*s %d %d\n", name, born, config_size, config, uid, gid); #endif if (strlen(name) > (0xff - 1)) { uwsgi_log("[emperor] invalid vassal name\n", name); return; } gettimeofday(&tv, NULL); int now = tv.tv_sec; uint64_t micros = (tv.tv_sec * 1000 * 1000) + tv.tv_usec; // blacklist check struct uwsgi_emperor_blacklist_item *uebi = uwsgi_emperor_blacklist_check(name); if (uebi) { uint64_t i_micros = (uebi->last_attempt.tv_sec * 1000 * 1000) + uebi->last_attempt.tv_usec + uebi->throttle_level; if (i_micros > micros) { return; } } if (now - emperor_throttle < 1) { emperor_throttle_level = emperor_throttle_level * 2; } else { if (emperor_throttle_level > uwsgi.emperor_throttle) { emperor_throttle_level = emperor_throttle_level / 2; } if (emperor_throttle_level < uwsgi.emperor_throttle) { emperor_throttle_level = uwsgi.emperor_throttle; } } emperor_throttle = now; #ifdef UWSGI_DEBUG uwsgi_log("emperor throttle = %d\n", emperor_throttle_level); #endif usleep(emperor_throttle_level); if (uwsgi.emperor_tyrant) { if (uid == 0 || gid == 0) { uwsgi_log("[emperor-tyrant] invalid permissions for vassal %s\n", name); return; } } while (c_ui->ui_next) { c_ui = c_ui->ui_next; } n_ui = uwsgi_malloc(sizeof(struct uwsgi_instance)); memset(n_ui, 0, sizeof(struct uwsgi_instance)); if (config) { n_ui->use_config = 1; n_ui->config = config; n_ui->config_len = config_size; } c_ui->ui_next = n_ui; #ifdef UWSGI_DEBUG uwsgi_log("c_ui->ui_next = %p\n", c_ui->ui_next); #endif n_ui->ui_prev = c_ui; if (strchr(name, ':')) { n_ui->zerg = 1; uwsgi.emperor_broodlord_count++; } n_ui->scanner = ues; memcpy(n_ui->name, name, strlen(name)); n_ui->born = born; n_ui->uid = uid; n_ui->gid = gid; n_ui->last_mod = born; // start without loyalty n_ui->last_loyal = 0; n_ui->loyal = 0; n_ui->first_run = uwsgi_now(); n_ui->last_run = n_ui->first_run; if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe)) { uwsgi_error("socketpair()"); goto clear; } event_queue_add_fd_read(uwsgi.emperor_queue, n_ui->pipe[0]); if (n_ui->use_config) { if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe_config)) { uwsgi_error("socketpair()"); goto clear; } } // TODO pre-start hook // a new uWSGI instance will start pid = fork(); if (pid < 0) { uwsgi_error("fork()") } else if (pid > 0) { n_ui->pid = pid; // close the right side of the pipe close(n_ui->pipe[1]); if (n_ui->use_config) { close(n_ui->pipe_config[1]); } if (n_ui->use_config) { if (write(n_ui->pipe_config[0], n_ui->config, n_ui->config_len) <= 0) { uwsgi_error("write()"); } close(n_ui->pipe_config[0]); } return; } else { if (uwsgi.emperor_tyrant) { uwsgi_log("[emperor-tyrant] dropping privileges to %d %d for instance %s\n", (int) uid, (int) gid, name); if (setgid(gid)) { uwsgi_error("setgid()"); exit(1); } if (setgroups(0, NULL)) { uwsgi_error("setgroups()"); exit(1); } if (setuid(uid)) { uwsgi_error("setuid()"); exit(1); } } unsetenv("UWSGI_RELOADS"); unsetenv("NOTIFY_SOCKET"); uef = uwsgi_num2str(n_ui->pipe[1]); if (setenv("UWSGI_EMPEROR_FD", uef, 1)) { uwsgi_error("setenv()"); exit(1); } free(uef); if (n_ui->use_config) { uef = uwsgi_num2str(n_ui->pipe_config[1]); if (setenv("UWSGI_EMPEROR_FD_CONFIG", uef, 1)) { uwsgi_error("setenv()"); exit(1); } free(uef); } uenvs = environ; while (*uenvs) { if (!strncmp(*uenvs, "UWSGI_VASSAL_", 13)) { char *ne = uwsgi_concat2("UWSGI_", *uenvs + 13); char *oe = uwsgi_concat2n(*uenvs, strchr(*uenvs, '=') - *uenvs, "", 0); if (unsetenv(oe)) { uwsgi_error("unsetenv()"); break; } free(oe); #ifdef UWSGI_DEBUG uwsgi_log("putenv %s\n", ne); #endif if (putenv(ne)) { uwsgi_error("putenv()"); } // do not free ne as putenv will add it to the environ uenvs = environ; continue; } uenvs++; } // close the left side of the pipe close(n_ui->pipe[0]); if (n_ui->use_config) { close(n_ui->pipe_config[0]); } counter = 4; struct uwsgi_string_list *uct = uwsgi.vassals_templates; while (uct) { counter += 2; uct = uct->next; } vassal_argv = uwsgi_malloc(sizeof(char *) * counter); // set args vassal_argv[0] = uwsgi.binary_path; if (uwsgi.emperor_broodlord) { colon = strchr(name, ':'); if (colon) { colon[0] = 0; } } // initialize to a default value vassal_argv[1] = "--inherit"; if (!strcmp(name + (strlen(name) - 4), ".xml")) vassal_argv[1] = "--xml"; if (!strcmp(name + (strlen(name) - 4), ".ini")) vassal_argv[1] = "--ini"; if (!strcmp(name + (strlen(name) - 4), ".yml")) vassal_argv[1] = "--yaml"; if (!strcmp(name + (strlen(name) - 5), ".yaml")) vassal_argv[1] = "--yaml"; if (!strcmp(name + (strlen(name) - 3), ".js")) vassal_argv[1] = "--json"; if (!strcmp(name + (strlen(name) - 5), ".json")) vassal_argv[1] = "--json"; if (colon) { colon[0] = ':'; } vassal_argv[2] = name; if (uwsgi.emperor_magic_exec) { if (!access(name, R_OK | X_OK)) { vassal_argv[2] = uwsgi_concat2("exec://", name); } } if (n_ui->use_config) { vassal_argv[2] = uwsgi_concat2("emperor://", name); } counter = 3; uct = uwsgi.vassals_templates; while (uct) { vassal_argv[counter] = "--inherit"; vassal_argv[counter + 1] = uct->value; counter += 2; uct = uct->next; } vassal_argv[counter] = NULL; // disable stdin int stdin_fd = open("/dev/null", O_RDONLY); if (stdin_fd < 0) { uwsgi_error_open("/dev/null"); exit(1); } if (stdin_fd != 0) { if (dup2(stdin_fd, 0)) { uwsgi_error("dup2()"); exit(1); } close(stdin_fd); } // close all of the unneded fd for (i = 3; i < (int) uwsgi.max_fd; i++) { if (n_ui->use_config) { if (i == n_ui->pipe_config[1]) continue; } if (i != n_ui->pipe[1]) { close(i); } } if (uwsgi.vassals_start_hook) { uwsgi_log("[emperor] running vassal start-hook: %s %s\n", uwsgi.vassals_start_hook, n_ui->name); if (uwsgi.emperor_absolute_dir) { if (setenv("UWSGI_VASSALS_DIR", uwsgi.emperor_absolute_dir, 1)) { uwsgi_error("setenv()"); } } int start_hook_ret = uwsgi_run_command_and_wait(uwsgi.vassals_start_hook, n_ui->name); uwsgi_log("[emperor] %s start-hook returned %d\n", n_ui->name, start_hook_ret); } // start !!! if (execvp(vassal_argv[0], vassal_argv)) { uwsgi_error("execvp()"); } uwsgi_log("[emperor] is the uwsgi binary in your system PATH ?\n"); // never here exit(UWSGI_EXILE_CODE); } clear: free(n_ui); c_ui->ui_next = NULL; }
void fastrouter_loop() { int nevents; int interesting_fd; int new_connection; ssize_t len; int i; time_t delta; char bbuf[UMAX16]; char *tcp_port; char *tmp_socket_name; int tmp_socket_name_len; struct uwsgi_subscribe_req usr; char *magic_table[0xff]; struct uwsgi_rb_timer *min_timeout; void *events; struct msghdr msg; union { struct cmsghdr cmsg; char control [CMSG_SPACE (sizeof (int))]; } msg_control; struct cmsghdr *cmsg; struct sockaddr_un fr_addr; socklen_t fr_addr_len = sizeof(struct sockaddr_un); struct fastrouter_session *fr_session; struct fastrouter_session *fr_table[2048]; struct iovec iov[2]; int soopt; socklen_t solen = sizeof(int); int ufr_subserver = -1; for(i=0;i<2048;i++) { fr_table[i] = NULL; } ufr.queue = event_queue_init(); struct uwsgi_fastrouter_socket *ufr_sock = ufr.sockets; while(ufr_sock) { if (ufr_sock->name[0] == '=') { int shared_socket = atoi(ufr_sock->name+1); if (shared_socket >= 0) { ufr_sock->fd = uwsgi_get_shared_socket_fd_by_num(shared_socket); if (ufr_sock->fd == -1) { uwsgi_log("unable to use shared socket %d\n", shared_socket); } } } else { tcp_port = strchr(ufr_sock->name, ':'); if (tcp_port) { ufr_sock->fd = bind_to_tcp(ufr_sock->name, uwsgi.listen_queue, tcp_port); } else { ufr_sock->fd = bind_to_unix(ufr_sock->name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); } } uwsgi_log("uwsgi fastrouter/proxy bound on %s\n", ufr_sock->name); if (!ufr.cheap) { event_queue_add_fd_read(ufr.queue, ufr_sock->fd); } else { uwsgi_log("[uwsgi-fastrouter] cheap mode requested. Waiting for subscriptions...\n"); ufr.i_am_cheap = 1; } ufr_sock = ufr_sock->next; } events = event_queue_alloc(ufr.nevents); ufr.timeouts = uwsgi_init_rb_timer(); if (!ufr.socket_timeout) ufr.socket_timeout = 30; if (ufr.subscription_server) { ufr_subserver = bind_to_udp(ufr.subscription_server, 0, 0); event_queue_add_fd_read(ufr.queue, ufr_subserver); if (!ufr.subscription_slot) ufr.subscription_slot = 30; // check for node status every 10 seconds //ufr.subscriptions_check = add_check_timeout(10); } if (ufr.pattern) { init_magic_table(magic_table); } for (;;) { min_timeout = uwsgi_min_rb_timer(ufr.timeouts); if (min_timeout == NULL ) { delta = -1; } else { delta = min_timeout->key - time(NULL); if (delta <= 0) { expire_timeouts(fr_table); delta = 0; } } nevents = event_queue_wait_multi(ufr.queue, delta, events, ufr.nevents); if (nevents == 0) { expire_timeouts(fr_table); } for (i=0;i<nevents;i++) { tmp_socket_name = NULL; interesting_fd = event_queue_interesting_fd(events, i); int taken = 0; struct uwsgi_fastrouter_socket *uwsgi_sock = ufr.sockets; while(uwsgi_sock) { if (interesting_fd == uwsgi_sock->fd) { new_connection = accept(interesting_fd, (struct sockaddr *) &fr_addr, &fr_addr_len); if (new_connection < 0) { continue; } fr_table[new_connection] = alloc_fr_session(); fr_table[new_connection]->fd = new_connection; fr_table[new_connection]->instance_fd = -1; fr_table[new_connection]->status = FASTROUTER_STATUS_RECV_HDR; fr_table[new_connection]->h_pos = 0; fr_table[new_connection]->pos = 0; fr_table[new_connection]->un = NULL; fr_table[new_connection]->instance_failed = 0; fr_table[new_connection]->instance_address_len = 0; fr_table[new_connection]->hostname_len = 0; fr_table[new_connection]->hostname = NULL; fr_table[new_connection]->timeout = add_timeout(fr_table[new_connection]); event_queue_add_fd_read(ufr.queue, new_connection); taken = 1; break; } uwsgi_sock = uwsgi_sock->next; } if (taken) { continue; } if (interesting_fd == ufr_subserver) { len = recv(ufr_subserver, bbuf, 4096, 0); #ifdef UWSGI_EVENT_USE_PORT event_queue_add_fd_read(ufr.queue, ufr_subserver); #endif if (len > 0) { memset(&usr, 0, sizeof(struct uwsgi_subscribe_req)); uwsgi_hooked_parse(bbuf+4, len-4, fastrouter_manage_subscription, &usr); if (uwsgi_add_subscribe_node(&ufr.subscriptions, &usr, ufr.subscription_regexp) && ufr.i_am_cheap) { struct uwsgi_fastrouter_socket *ufr_sock = ufr.sockets; while(ufr_sock) { event_queue_add_fd_read(ufr.queue, ufr_sock->fd); ufr_sock = ufr_sock->next; } ufr.i_am_cheap = 0; uwsgi_log("[uwsgi-fastrouter] leaving cheap mode...\n"); } } } else { fr_session = fr_table[interesting_fd]; // something is going wrong... if (fr_session == NULL) continue; if (event_queue_interesting_fd_has_error(events, i)) { close_session(fr_table, fr_session); continue; } fr_session->timeout = reset_timeout(fr_session); switch(fr_session->status) { case FASTROUTER_STATUS_RECV_HDR: len = recv(fr_session->fd, (char *)(&fr_session->uh) + fr_session->h_pos, 4-fr_session->h_pos, 0); if (len <= 0) { uwsgi_error("recv()"); close_session(fr_table, fr_session); break; } fr_session->h_pos += len; if (fr_session->h_pos == 4) { #ifdef UWSGI_DEBUG uwsgi_log("modifier1: %d pktsize: %d modifier2: %d\n", fr_session->uh.modifier1, fr_session->uh.pktsize, fr_session->uh.modifier2); #endif fr_session->status = FASTROUTER_STATUS_RECV_VARS; } break; case FASTROUTER_STATUS_RECV_VARS: len = recv(fr_session->fd, fr_session->buffer + fr_session->pos, fr_session->uh.pktsize - fr_session->pos, 0); if (len <= 0) { uwsgi_error("recv()"); close_session(fr_table, fr_session); break; } fr_session->pos += len; if (fr_session->pos == fr_session->uh.pktsize) { if (uwsgi_hooked_parse(fr_session->buffer, fr_session->uh.pktsize, fr_get_hostname, (void *) fr_session)) { close_session(fr_table, fr_session); break; } if (fr_session->hostname_len == 0) { close_session(fr_table, fr_session); break; } #ifdef UWSGI_DEBUG //uwsgi_log("requested domain %.*s\n", fr_session->hostname_len, fr_session->hostname); #endif if (ufr.use_cache) { fr_session->instance_address = uwsgi_cache_get(fr_session->hostname, fr_session->hostname_len, &fr_session->instance_address_len); char *cs_mod = uwsgi_str_contains(fr_session->instance_address, fr_session->instance_address_len, ','); if (cs_mod) { fr_session->modifier1 = uwsgi_str_num(cs_mod+1, (fr_session->instance_address_len - (cs_mod - fr_session->instance_address))-1); fr_session->instance_address_len = (cs_mod - fr_session->instance_address); } } else if (ufr.pattern) { magic_table['s'] = uwsgi_concat2n(fr_session->hostname, fr_session->hostname_len, "", 0); tmp_socket_name = magic_sub(ufr.pattern, ufr.pattern_len, &tmp_socket_name_len, magic_table); free(magic_table['s']); fr_session->instance_address_len = tmp_socket_name_len; fr_session->instance_address = tmp_socket_name; } else if (ufr.subscription_server) { fr_session->un = uwsgi_get_subscribe_node(&ufr.subscriptions, fr_session->hostname, fr_session->hostname_len, ufr.subscription_regexp); if (fr_session->un && fr_session->un->len) { fr_session->instance_address = fr_session->un->name; fr_session->instance_address_len = fr_session->un->len; fr_session->modifier1 = fr_session->un->modifier1; } } else if (ufr.base) { tmp_socket_name = uwsgi_concat2nn(ufr.base, ufr.base_len, fr_session->hostname, fr_session->hostname_len, &tmp_socket_name_len); fr_session->instance_address_len = tmp_socket_name_len; fr_session->instance_address = tmp_socket_name; } else if (ufr.code_string_code && ufr.code_string_function) { if (uwsgi.p[ufr.code_string_modifier1]->code_string) { fr_session->instance_address = uwsgi.p[ufr.code_string_modifier1]->code_string("uwsgi_fastrouter", ufr.code_string_code, ufr.code_string_function, fr_session->hostname, fr_session->hostname_len); if (fr_session->instance_address) { fr_session->instance_address_len = strlen(fr_session->instance_address); char *cs_mod = uwsgi_str_contains(fr_session->instance_address, fr_session->instance_address_len, ','); if (cs_mod) { fr_session->modifier1 = uwsgi_str_num(cs_mod+1, (fr_session->instance_address_len - (cs_mod - fr_session->instance_address))-1); fr_session->instance_address_len = (cs_mod - fr_session->instance_address); } } } } // no address found if (!fr_session->instance_address_len) { close_session(fr_table, fr_session); break; } fr_session->pass_fd = is_unix(fr_session->instance_address, fr_session->instance_address_len); fr_session->instance_fd = uwsgi_connectn(fr_session->instance_address, fr_session->instance_address_len, 0, 1); if (tmp_socket_name) free(tmp_socket_name); if (fr_session->instance_fd < 0) { /* if (ufr.subscription_server) { if (fr_session->un && fr_session->un->len > 0) { uwsgi_log("[uwsgi-fastrouter] %.*s => marking %.*s as failed\n", (int) fr_session->hostname_len, fr_session->hostname, (int) fr_session->instance_address_len,fr_session->instance_address); uwsgi_remove_subscribe_node(&ufr.subscriptions, fr_session->un); if (ufr.subscriptions == NULL && ufr.cheap && !ufr.i_am_cheap) { uwsgi_log("[uwsgi-fastrouter] no more nodes available. Going cheap...\n"); struct uwsgi_fastrouter_socket *ufr_sock = ufr.sockets; while(ufr_sock) { event_queue_del_fd(ufr.queue, ufr_sock->fd, event_queue_read()); ufr_sock = ufr_sock->next; } ufr.i_am_cheap = 1; } } } */ fr_session->instance_failed = 1; close_session(fr_table, fr_session); break; } fr_session->status = FASTROUTER_STATUS_CONNECTING; fr_table[fr_session->instance_fd] = fr_session; event_queue_add_fd_write(ufr.queue, fr_session->instance_fd); } break; case FASTROUTER_STATUS_CONNECTING: if (interesting_fd == fr_session->instance_fd) { if (getsockopt(fr_session->instance_fd, SOL_SOCKET, SO_ERROR, (void *) (&soopt), &solen) < 0) { uwsgi_error("getsockopt()"); fr_session->instance_failed = 1; close_session(fr_table, fr_session); break; } if (soopt) { uwsgi_log("unable to connect() to uwsgi instance: %s\n", strerror(soopt)); fr_session->instance_failed = 1; close_session(fr_table, fr_session); break; } fr_session->uh.modifier1 = fr_session->modifier1; iov[0].iov_base = &fr_session->uh; iov[0].iov_len = 4; iov[1].iov_base = fr_session->buffer; iov[1].iov_len = fr_session->uh.pktsize; // increment node requests counter if (fr_session->un) fr_session->un->requests++; // fd passing: PERFORMANCE EXTREME BOOST !!! if (fr_session->pass_fd && !uwsgi.no_fd_passing) { msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = 2; msg.msg_flags = 0; msg.msg_control = &msg_control; msg.msg_controllen = sizeof (msg_control); cmsg = CMSG_FIRSTHDR (&msg); cmsg->cmsg_len = CMSG_LEN (sizeof (int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; memcpy(CMSG_DATA(cmsg), &fr_session->fd, sizeof(int)); if (sendmsg(fr_session->instance_fd, &msg, 0) < 0) { uwsgi_error("sendmsg()"); } close_session(fr_table, fr_session); break; } if (writev(fr_session->instance_fd, iov, 2) < 0) { uwsgi_error("writev()"); close_session(fr_table, fr_session); break; } event_queue_fd_write_to_read(ufr.queue, fr_session->instance_fd); fr_session->status = FASTROUTER_STATUS_RESPONSE; } break; case FASTROUTER_STATUS_RESPONSE: // data from instance if (interesting_fd == fr_session->instance_fd) { len = recv(fr_session->instance_fd, fr_session->buffer, 0xffff, 0); if (len <= 0) { if (len < 0) uwsgi_error("recv()"); close_session(fr_table, fr_session); break; } len = send(fr_session->fd, fr_session->buffer, len, 0); if (len <= 0) { if (len < 0) uwsgi_error("send()"); close_session(fr_table, fr_session); break; } // update transfer statistics if (fr_session->un) fr_session->un->transferred += len; } // body from client else if (interesting_fd == fr_session->fd) { //uwsgi_log("receiving body...\n"); len = recv(fr_session->fd, fr_session->buffer, 0xffff, 0); if (len <= 0) { if (len < 0) uwsgi_error("recv()"); close_session(fr_table, fr_session); break; } len = send(fr_session->instance_fd, fr_session->buffer, len, 0); if (len <= 0) { if (len < 0) uwsgi_error("send()"); close_session(fr_table, fr_session); break; } } break; // fallback to destroy !!! default: uwsgi_log("unknown event: closing session\n"); close_session(fr_table, fr_session); break; } } } } }
// this is the command manager static void uwsgi_imperial_monitor_zeromq_cmd(struct uwsgi_emperor_scanner *ues) { int64_t more = 0; size_t more_size = sizeof(more); int i; zmq_msg_t msg[6]; zmq_msg_init(&msg[0]); zmq_msg_init(&msg[1]); zmq_msg_init(&msg[2]); zmq_msg_init(&msg[3]); zmq_msg_init(&msg[4]); zmq_msg_init(&msg[5]); for(i=0;i<6;i++) { #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) zmq_recvmsg(ues->data, &msg[i], ZMQ_DONTWAIT); #else zmq_recv(ues->data, &msg[i], ZMQ_NOBLOCK); #endif if (zmq_getsockopt(ues->data, ZMQ_RCVMORE, &more, &more_size)) { uwsgi_error("zmq_getsockopt()"); break; } if (!more && i < 4) break; } if (i < 1) { uwsgi_log("[emperor-zeromq] bad message received (command and instance name required)\n"); return; } char *ez_cmd = zmq_msg_data(&msg[0]); size_t ez_cmd_len = zmq_msg_size(&msg[0]); char *ez_name = zmq_msg_data(&msg[1]); size_t ez_name_len = zmq_msg_size(&msg[1]); char *ez_config = NULL; size_t ez_config_len = 0; char *ez_uid = NULL; size_t ez_uid_len = 0; char *ez_gid = NULL; size_t ez_gid_len = 0; char *ez_socket_name = NULL; size_t ez_socket_name_len = 0; char *socket_name = NULL; // config if (i > 1) { ez_config = zmq_msg_data(&msg[2]); ez_config_len = zmq_msg_size(&msg[2]); } // uid if (i > 2) { ez_uid = zmq_msg_data(&msg[3]); ez_uid_len = zmq_msg_size(&msg[3]); } // gid if (i > 3) { ez_gid = zmq_msg_data(&msg[4]); ez_gid_len = zmq_msg_size(&msg[4]); } // gid if (i > 4) { ez_socket_name = zmq_msg_data(&msg[5]); ez_socket_name_len = zmq_msg_size(&msg[5]); } char *name = uwsgi_concat2n(ez_name, ez_name_len, "", 0); // ok let's start checking commands if (!uwsgi_strncmp(ez_cmd, ez_cmd_len, "touch", 5)) { char *config = NULL; if (ez_config_len > 0) { config = uwsgi_concat2n(ez_config, ez_config_len, "", 0); } uid_t vassal_uid = 0; gid_t vassal_gid = 0; if (ez_uid_len > 0) { vassal_uid = uwsgi_str_num(ez_uid, ez_uid_len); } if (ez_gid_len > 0) { vassal_gid = uwsgi_str_num(ez_gid, ez_gid_len); } if (ez_socket_name) { socket_name = uwsgi_concat2n(ez_socket_name, ez_socket_name_len, "", 0); } uwsgi_emperor_simple_do(ues, name, config, uwsgi_now(), vassal_uid, vassal_gid, socket_name); if (config) { free(config); } if (socket_name) { free(socket_name); } } // destroy an instance else if (!uwsgi_strncmp(ez_cmd, ez_cmd_len, "destroy", 7)) { struct uwsgi_instance *ui = emperor_get(name); if (!ui) { uwsgi_log("[emperor-zeromq] unknown instance \"%s\"\n", name); } else { emperor_stop(ui); } } else { uwsgi_log("[emperor-zeromq] unknown command \"%.*s\"\n", (int)ez_cmd_len, ez_cmd); } free(name); zmq_msg_close(&msg[0]); zmq_msg_close(&msg[1]); zmq_msg_close(&msg[2]); zmq_msg_close(&msg[3]); zmq_msg_close(&msg[4]); zmq_msg_close(&msg[5]); }
static int uwsgi_rpc_request(struct wsgi_request *wsgi_req) { // this is the list of args char *argv[UMAX8]; // this is the size of each argument uint16_t argvs[UMAX8]; // maximum number of supported arguments uint8_t argc = 0xff; // response output char response_buf[UMAX16]; /* Standard RPC request */ if (!wsgi_req->uh->pktsize) { uwsgi_log("Empty RPC request. skip.\n"); return -1; } if (wsgi_req->uh->modifier2 == 2) { if (uwsgi_parse_vars(wsgi_req)) { uwsgi_log("Invalid RPC request. skip.\n"); return -1; } if (wsgi_req->path_info_len == 0) { uwsgi_500(wsgi_req); return UWSGI_OK; } char *args = NULL; if (wsgi_req->path_info[0] == '/') { args = uwsgi_concat2n(wsgi_req->path_info+1, wsgi_req->path_info_len-1, "", 0); } else { args = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "", 0); } argc = 0; argv[0] = strtok(args, "/"); if (!argv[0]) { free(args); uwsgi_500(wsgi_req); return UWSGI_OK; } char *p = strtok(NULL, "/"); while(p) { argc++; argv[argc] = p; argvs[argc] = strlen(p); p = strtok(NULL, "/"); } wsgi_req->uh->pktsize = uwsgi_rpc(argv[0], argc, argv+1, argvs+1, response_buf); free(args); if (!wsgi_req->uh->pktsize) { uwsgi_404(wsgi_req); return UWSGI_OK; } if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return 1; if (uwsgi_response_add_content_length(wsgi_req, wsgi_req->uh->pktsize)) return -1; uint16_t ctype_len = 0; char *ctype = uwsgi_get_var(wsgi_req, "HTTP_ACCEPT", 11, &ctype_len); if (ctype && strcmp(ctype, "*/*") && strcmp(ctype, "*")) { if (uwsgi_response_add_content_type(wsgi_req, ctype, ctype_len)) return -1; } else { if (uwsgi_response_add_content_type(wsgi_req, "application/binary", 18)) return -1; } goto sendbody; } #ifdef UWSGI_XML_LIBXML2 if (wsgi_req->uh->modifier2 == 3) { if (wsgi_req->post_cl == 0) { uwsgi_500(wsgi_req); return UWSGI_OK; } ssize_t body_len = 0; char *body = uwsgi_request_body_read(wsgi_req, wsgi_req->post_cl, &body_len); xmlDoc *doc = xmlReadMemory(body, body_len, NULL, NULL, 0); if (!doc) { uwsgi_500(wsgi_req); return UWSGI_OK; } int ret = uwsgi_rpc_xmlrpc(wsgi_req, doc, argv, argvs, &argc, response_buf); xmlFreeDoc(doc); if (ret) { uwsgi_500(wsgi_req); } return UWSGI_OK; } #endif if (uwsgi_parse_array(wsgi_req->buffer, wsgi_req->uh->pktsize, argv, argvs, &argc)) { uwsgi_log("Invalid RPC request. skip.\n"); return -1; } // call the function (output will be in wsgi_req->buffer) wsgi_req->uh->pktsize = uwsgi_rpc(argv[0], argc-1, argv+1, argvs+1, response_buf); // using modifier2 we may want a raw output if (wsgi_req->uh->modifier2 == 0) { if (uwsgi_response_write_body_do(wsgi_req, (char *) wsgi_req->uh, 4)) { return -1; } } sendbody: // write the response uwsgi_response_write_body_do(wsgi_req, response_buf, wsgi_req->uh->pktsize); return UWSGI_OK; }
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; }
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; }