uwsgi-2.1 merged to master

This commit is contained in:
Roberto De Ioris
2014-09-12 06:47:41 +02:00
70 changed files with 3140 additions and 748 deletions

4
.gitignore vendored
View File

@@ -22,3 +22,7 @@ core/dot_h.c
+# coverity
+/cov-int/
+uwsgi.tar.xz
/build/
/dist/
/uWSGI.egg-info/

View File

@@ -29,3 +29,4 @@ Danila Shtan <danila@shtan.ru>
Ævar Arnfjörð Bjarmason
Yu Zhao (getcwd)
Mathieu Dupuy
Mike Kaplinskiy

View File

@@ -54,7 +54,7 @@ def uwsgi_pypy_greenlet_switch(wsgi_req):
# update current running greenlet
lib.uwsgi.wsgi_req = wsgi_req
if lib.uwsgi.async <= 1:
if lib.uwsgi.async < 1:
raise Exception("pypy greenlets require async mode !!!")
lib.uwsgi.schedule_to_main = uwsgi_pypy_greenlet_switch
lib.uwsgi.schedule_to_req = uwsgi_pypy_greenlet_schedule

View File

@@ -165,7 +165,7 @@ static void async_expire_timeouts(uint64_t now) {
int async_add_fd_read(struct wsgi_request *wsgi_req, int fd, int timeout) {
if (uwsgi.async < 2 || !uwsgi.async_waiting_fd_table){
if (uwsgi.async < 1 || !uwsgi.async_waiting_fd_table){
uwsgi_log_verbose("ASYNC call without async mode !!!\n");
return -1;
}
@@ -257,7 +257,7 @@ static int async_wait_fd_read2(int fd0, int fd1, int timeout, int *fd) {
void async_add_timeout(struct wsgi_request *wsgi_req, int timeout) {
if (uwsgi.async < 2 || !uwsgi.rb_async_timeouts) {
if (uwsgi.async < 1 || !uwsgi.rb_async_timeouts) {
uwsgi_log_verbose("ASYNC call without async mode !!!\n");
return;
}
@@ -272,7 +272,7 @@ void async_add_timeout(struct wsgi_request *wsgi_req, int timeout) {
int async_add_fd_write(struct wsgi_request *wsgi_req, int fd, int timeout) {
if (uwsgi.async < 2 || !uwsgi.async_waiting_fd_table) {
if (uwsgi.async < 1 || !uwsgi.async_waiting_fd_table) {
uwsgi_log_verbose("ASYNC call without async mode !!!\n");
return -1;
}
@@ -406,7 +406,7 @@ static int uwsgi_async_wait_milliseconds_hook(int timeout) {
void async_loop() {
if (uwsgi.async < 2) {
if (uwsgi.async < 1) {
uwsgi_log("the async loop engine requires async mode (--async <n>)\n");
exit(1);
}
@@ -481,7 +481,12 @@ void async_loop() {
// signals are executed in the main stack... in the future we could have dedicated stacks for them
if (uwsgi.signal_socket > -1 && (interesting_fd == uwsgi.signal_socket || interesting_fd == uwsgi.my_signal_socket)) {
uwsgi_receive_signal(interesting_fd, "worker", uwsgi.mywid);
uwsgi.wsgi_req = find_first_available_wsgi_req();
if (uwsgi.wsgi_req == NULL) {
uwsgi_async_queue_is_full((time_t)now);
continue;
}
uwsgi_receive_signal(uwsgi.wsgi_req, interesting_fd, "worker", uwsgi.mywid);
continue;
}

View File

@@ -150,6 +150,32 @@ int uwsgi_buffer_append_json(struct uwsgi_buffer *ub, char *buf, size_t len) {
return 0;
}
int uwsgi_buffer_append_xml(struct uwsgi_buffer *ub, char *buf, size_t len) {
// need to escape \ and "
size_t i;
for(i=0;i<len;i++) {
if (buf[i] == '"') {
if (uwsgi_buffer_append(ub, "&quot;", 6)) return -1;
}
else if (buf[i] == '\'') {
if (uwsgi_buffer_append(ub, "&apos;", 6)) return -1;
}
else if (buf[i] == '<') {
if (uwsgi_buffer_append(ub, "&lt;", 4)) return -1;
}
else if (buf[i] == '>') {
if (uwsgi_buffer_append(ub, "&gt;", 4)) return -1;
}
else if (buf[i] == '&') {
if (uwsgi_buffer_append(ub, "&amp;", 5)) return -1;
}
else {
if (uwsgi_buffer_append(ub, buf+i, 1)) return -1;
}
}
return 0;
}
int uwsgi_buffer_u16le(struct uwsgi_buffer *ub, uint16_t num) {
uint8_t buf[2];
buf[0] = (uint8_t) (num & 0xff);
@@ -418,3 +444,10 @@ void uwsgi_buffer_map(struct uwsgi_buffer *ub, char *buf, size_t len) {
ub->pos = len;
ub->len = len;
}
int uwsgi_buffer_httpdate(struct uwsgi_buffer *ub, time_t t) {
char http_last_modified[49];
int size = uwsgi_http_date(t, http_last_modified);
if (size <= 0) return -1;
return uwsgi_buffer_append(ub, http_last_modified, size);
}

View File

@@ -5,7 +5,6 @@ The uWSGI Emperor
*/
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
extern char **environ;
@@ -37,6 +36,128 @@ struct uwsgi_emperor_blacklist_item {
struct uwsgi_emperor_blacklist_item *emperor_blacklist;
char *vassal_attr_get(struct uwsgi_instance *c_ui, char *attr) {
if (!attr) return NULL;
struct uwsgi_dyn_dict *attrs = c_ui->attrs;
while(attrs) {
if (!strcmp(attrs->key, attr)) {
return attrs->value;
}
attrs = attrs->next;
}
return NULL;
}
// this generates the argv for the new vassal
static char **vassal_new_argv(struct uwsgi_instance *n_ui, int *slot_to_free) {
int counter = 4;
struct uwsgi_string_list *uct;
uwsgi_foreach(uct, uwsgi.vassals_templates_before) counter += 2;
uwsgi_foreach(uct, uwsgi.vassals_includes_before) counter += 2;
uwsgi_foreach(uct, uwsgi.vassals_set) counter += 2;
uwsgi_foreach(uct, uwsgi.vassals_templates) counter += 2;
uwsgi_foreach(uct, uwsgi.vassals_includes) counter += 2;
char **vassal_argv = uwsgi_malloc(sizeof(char *) * counter);
// set args
vassal_argv[0] = uwsgi.emperor_wrapper ? uwsgi.emperor_wrapper : uwsgi.binary_path;
char *wrapper_attr = vassal_attr_get(n_ui, uwsgi.emperor_wrapper_attr);
if (wrapper_attr) vassal_argv[0] = wrapper_attr;
// reset counter
counter = 1;
uwsgi_foreach(uct, uwsgi.vassals_templates_before) {
vassal_argv[counter] = "--inherit";
vassal_argv[counter + 1] = uct->value;
counter += 2;
}
uwsgi_foreach(uct, uwsgi.vassals_includes_before) {
vassal_argv[counter] = "--include";
vassal_argv[counter + 1] = uct->value;
counter += 2;
}
uwsgi_foreach(uct, uwsgi.vassals_set) {
vassal_argv[counter] = "--set";
vassal_argv[counter + 1] = uct->value;
counter += 2;
}
char *colon = NULL;
if (uwsgi.emperor_broodlord) {
colon = strchr(n_ui->name, ':');
if (colon) {
colon[0] = 0;
}
}
// initialize to a default value
vassal_argv[counter] = "--inherit";
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".xml"))
vassal_argv[counter] = "--xml";
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".ini"))
vassal_argv[counter] = "--ini";
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".yml"))
vassal_argv[counter] = "--yaml";
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".yaml"))
vassal_argv[counter] = "--yaml";
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 3), ".js"))
vassal_argv[counter] = "--json";
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".json"))
vassal_argv[counter] = "--json";
struct uwsgi_string_list *usl = uwsgi.emperor_extra_extension;
while (usl) {
if (uwsgi_endswith(n_ui->name, usl->value)) {
vassal_argv[counter] = "--config";
break;
}
usl = usl->next;
}
if (colon)
colon[0] = ':';
// start config filename...
counter++;
vassal_argv[counter] = n_ui->name;
if (uwsgi.emperor_magic_exec) {
if (!access(n_ui->name, R_OK | X_OK)) {
vassal_argv[counter] = uwsgi_concat2("exec://", n_ui->name);
if (slot_to_free)
*slot_to_free = counter;
}
}
else if (n_ui->use_config) {
vassal_argv[counter] = uwsgi_concat2("emperor://", n_ui->name);
if (slot_to_free)
*slot_to_free = counter;
}
// start templates,includes,inherit...
counter++;
uwsgi_foreach(uct, uwsgi.vassals_templates) {
vassal_argv[counter] = "--inherit";
vassal_argv[counter + 1] = uct->value;
counter += 2;
}
uwsgi_foreach(uct, uwsgi.vassals_includes) {
vassal_argv[counter] = "--include";
vassal_argv[counter + 1] = uct->value;
counter += 2;
}
vassal_argv[counter] = NULL;
return vassal_argv;
}
/*
this should be placed in core/socket.c but we realized it was needed
only after 2.0 so we cannot change uwsgi.h
@@ -211,7 +332,7 @@ int uwsgi_emperor_is_valid(char *name) {
return 0;
}
static char *emperor_check_on_demand_socket(char *filename) {
static char *emperor_check_on_demand_socket(char *filename, struct uwsgi_dyn_dict *attrs) {
size_t len = 0;
if (uwsgi.emperor_on_demand_extension) {
char *tmp = uwsgi_concat2(filename, uwsgi.emperor_on_demand_extension);
@@ -348,8 +469,14 @@ void uwsgi_imperial_monitor_directory(struct uwsgi_emperor_scanner *ues) {
}
}
else {
char *socket_name = emperor_check_on_demand_socket(de->d_name);
emperor_add(ues, de->d_name, st.st_mtime, NULL, 0, t_uid, t_gid, socket_name);
struct uwsgi_dyn_dict *attrs = NULL;
if (uwsgi.emperor_collect_attributes) {
if (uwsgi_endswith(de->d_name, ".ini")) {
uwsgi_emperor_ini_attrs(de->d_name, NULL, &attrs);
}
}
char *socket_name = emperor_check_on_demand_socket(de->d_name, attrs);
emperor_add_with_attrs(ues, de->d_name, st.st_mtime, NULL, 0, t_uid, t_gid, socket_name, attrs);
if (socket_name)
free(socket_name);
}
@@ -469,10 +596,16 @@ void uwsgi_imperial_monitor_glob(struct uwsgi_emperor_scanner *ues) {
}
}
else {
char *socket_name = emperor_check_on_demand_socket(g.gl_pathv[i]);
emperor_add(ues, g.gl_pathv[i], st.st_mtime, NULL, 0, t_uid, t_gid, socket_name);
if (socket_name)
free(socket_name);
struct uwsgi_dyn_dict *attrs = NULL;
if (uwsgi.emperor_collect_attributes) {
if (uwsgi_endswith(g.gl_pathv[i], ".ini")) {
uwsgi_emperor_ini_attrs(g.gl_pathv[i], NULL, &attrs);
}
}
char *socket_name = emperor_check_on_demand_socket(g.gl_pathv[i], attrs);
emperor_add_with_attrs(ues, g.gl_pathv[i], st.st_mtime, NULL, 0, t_uid, t_gid, socket_name, attrs);
if (socket_name)
free(socket_name);
}
}
@@ -666,16 +799,12 @@ void emperor_del(struct uwsgi_instance *c_ui) {
}
// this will destroy the whole uWSGI instance (and workers)
if (c_ui->pipe[0] != -1)
close(c_ui->pipe[0]);
if (c_ui->pipe[1] != -1)
close(c_ui->pipe[1]);
if (c_ui->pipe[0] != -1) close(c_ui->pipe[0]);
if (c_ui->pipe[1] != -1) close(c_ui->pipe[1]);
if (c_ui->use_config) {
if (c_ui->pipe_config[0] != -1)
close(c_ui->pipe_config[0]);
if (c_ui->pipe_config[1] != -1)
close(c_ui->pipe_config[1]);
if (c_ui->pipe_config[0] != -1) close(c_ui->pipe_config[0]);
if (c_ui->pipe_config[1] != -1) close(c_ui->pipe_config[1]);
}
if (uwsgi.vassals_stop_hook) {
@@ -703,15 +832,20 @@ void emperor_del(struct uwsgi_instance *c_ui) {
free(c_ui->socket_name);
}
if (c_ui->config)
free(c_ui->config);
if (c_ui->on_demand_fd > -1) {
close(c_ui->on_demand_fd);
}
if (c_ui->config) free(c_ui->config);
struct uwsgi_dyn_dict *attr = c_ui->attrs;
while(attr) {
struct uwsgi_dyn_dict *tmp = attr;
attr = attr->next;
if (tmp->value) free(tmp->value);
free(tmp);
}
free(c_ui);
}
void emperor_back_to_ondemand(struct uwsgi_instance *c_ui) {
@@ -822,6 +956,10 @@ void emperor_respawn(struct uwsgi_instance *c_ui, time_t mod) {
}
void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, char *config, uint32_t config_size, uid_t uid, gid_t gid, char *socket_name) {
emperor_add_with_attrs(ues, name, born, config, config_size, uid, gid, socket_name, NULL);
}
void emperor_add_with_attrs(struct uwsgi_emperor_scanner *ues, char *name, time_t born, char *config, uint32_t config_size, uid_t uid, gid_t gid, char *socket_name, struct uwsgi_dyn_dict *attrs) {
struct uwsgi_instance *c_ui = ui;
struct uwsgi_instance *n_ui = NULL;
@@ -912,6 +1050,8 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
n_ui->last_loyal = 0;
n_ui->loyal = 0;
n_ui->attrs = attrs;
n_ui->first_run = uwsgi_now();
n_ui->last_run = n_ui->first_run;
n_ui->on_demand_fd = -1;
@@ -937,6 +1077,9 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
event_queue_add_fd_read(uwsgi.emperor_queue, n_ui->on_demand_fd);
uwsgi_log("[uwsgi-emperor] %s -> \"on demand\" instance detected, waiting for connections on socket \"%s\" ...\n", name, socket_name);
if (uwsgi_hooks_run_and_return(uwsgi.hook_as_on_demand_vassal, "as-on-demand-vassal", name, 0)) {
emperor_del(n_ui);
}
return;
}
@@ -948,6 +1091,117 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *);
static void vassal_fork_server_parser_hook(char *key, uint16_t key_len, char *value, uint16_t value_len, void *data) {
pid_t *pid = (pid_t *) data;
if (!uwsgi_strncmp(key, key_len, "pid", 3)) {
// ignore negative values
if (value_len > 0 && value[0] == '-') return;
*pid = uwsgi_str_num(value, value_len);
}
}
/*
there are max 3 file descriptors we need to pass to the fork server:
n_ui->pipe[1]
n_ui->pipe_config[1]
n_ui->on_demand_fd
*/
static pid_t emperor_connect_to_fork_server(char *socket, struct uwsgi_instance *n_ui) {
int fd = uwsgi_connect(socket, uwsgi.socket_timeout, 0);
if (fd < 0) {
uwsgi_error("emperor_connect_to_fork_server()/uwsgi_connect()");
return -1;
}
int slot_to_free = -1;
char **vassal_argv = vassal_new_argv(n_ui, &slot_to_free);
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
// leave space for uwsgi header
ub->pos = 4;
int error = 0, counter = 0;
while (vassal_argv[counter]) {
if (!error && uwsgi_buffer_u16le(ub, strlen(vassal_argv[counter])))
error = 1;
if (!error && uwsgi_buffer_append(ub, vassal_argv[counter], strlen(vassal_argv[counter])))
error = 1;
if (counter == slot_to_free)
free(vassal_argv[counter]);
counter++;
}
free(vassal_argv);
if (error) {
uwsgi_log_verbose("[uwsgi-emperor] %s: unable to complete fork-server session\n", n_ui->name);
goto end;
}
// bit 0 -> pipe (0x01)
// bit 1 -> config_pipe (0x02)
// bit 2 -> on_demand (0x04)
uint8_t modifier2_mask = 0x01;
int fds[8];
int fds_count = 1;
fds[0] = n_ui->pipe[1];
// add pipe config ?
if (n_ui->use_config) {
modifier2_mask |= 0x02;
fds[fds_count] = n_ui->pipe_config[1];
fds_count++;
}
// add ondemand ?
if (n_ui->on_demand_fd > -1) {
modifier2_mask |= 0x04;
fds[fds_count] = n_ui->on_demand_fd;
fds_count++;
}
// fix uwsgi header
if (uwsgi_buffer_set_uh(ub, 35, modifier2_mask)) goto end;
if (uwsgi_send_fds_and_body(fd, fds, fds_count, ub->buf, ub->pos)) {
uwsgi_log_verbose("[uwsgi-emperor] %s: unable to complete fork-server session\n", n_ui->name);
goto end;
}
uwsgi_buffer_destroy(ub);
// now wait for the response (the pid number)
// the response could contain various info, currently we only need the "pid" attribute
size_t buf_len = uwsgi.page_size;
char *buf = uwsgi_malloc(buf_len);
uint8_t modifier1 = 0;
uint8_t modifier2 = 0;
int ret = uwsgi_read_with_realloc(fd, &buf, &buf_len, uwsgi.socket_timeout, &modifier1, &modifier2);
if (ret) {
free(buf);
uwsgi_log_verbose("[uwsgi-emperor] %s: unable to complete fork-server session\n", n_ui->name);
goto end2;
}
pid_t pid = -1;
uwsgi_hooked_parse(buf, buf_len, vassal_fork_server_parser_hook, &pid);
free(buf);
// close the connection
close(fd);
// return the pid to the Emperor
return pid;
end:
uwsgi_buffer_destroy(ub);
end2:
close(fd);
return -1;
}
int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
pid_t pid;
@@ -972,20 +1226,31 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
uwsgi.emperor_broodlord_num++;
}
// TODO pre-start hook
if (uwsgi_hooks_run_and_return(uwsgi.hook_as_emperor_before_vassal, "as-emperor-before-vassal", NULL, 0)) {
emperor_del(n_ui);
}
// check for fork server
char *fork_server = uwsgi.emperor_use_fork_server;
char *fork_server_attr = vassal_attr_get(n_ui, uwsgi.emperor_fork_server_attr);
if (fork_server_attr) fork_server = fork_server_attr;
// a new uWSGI instance will start
if (fork_server && !uwsgi_string_list_has_item(uwsgi.vassal_fork_base, n_ui->name, strlen(n_ui->name))) {
// pid can only be > 0 or -1
n_ui->adopted = 1;
pid = emperor_connect_to_fork_server(fork_server, n_ui);
}
#if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL) && !defined(__ia64__)
if (uwsgi.emperor_clone) {
else if (uwsgi.emperor_clone) {
char stack[PTHREAD_STACK_MIN];
pid = clone((int (*)(void *)) uwsgi_emperor_spawn_vassal, stack + PTHREAD_STACK_MIN, SIGCHLD | uwsgi.emperor_clone, (void *) n_ui);
}
#endif
else {
#endif
pid = fork();
#if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL) && !defined(__ia64__)
}
#endif
if (pid < 0) {
uwsgi_error("uwsgi_emperor_spawn_vassal()/fork()")
}
@@ -1084,6 +1349,10 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
func(n_ui->name, n_ui->pid, n_ui->uid, n_ui->gid);
}
}
#if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL)
uwsgi_hooks_setns_run(uwsgi.hook_as_emperor_setns, n_ui->pid, n_ui->uid, n_ui->gid);
#endif
return 0;
}
else {
@@ -1121,6 +1390,8 @@ static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) {
}
#endif
uwsgi_hooks_run(uwsgi.hook_as_vassal_before_drop, "as-vassal-before-drop", 1);
#ifdef UWSGI_CAP
#if defined(CAP_LAST_CAP) && defined(PR_CAPBSET_READ) && defined(PR_CAPBSET_DROP)
if (uwsgi.emperor_cap && uwsgi.emperor_cap_count > 0) {
@@ -1250,103 +1521,8 @@ static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) {
close(n_ui->pipe_config[0]);
}
int counter = 4;
struct uwsgi_string_list *uct;
uwsgi_foreach(uct, uwsgi.vassals_templates_before) counter += 2;
uwsgi_foreach(uct, uwsgi.vassals_includes_before) counter += 2;
uwsgi_foreach(uct, uwsgi.vassals_set) counter += 2;
uwsgi_foreach(uct, uwsgi.vassals_templates) counter += 2;
uwsgi_foreach(uct, uwsgi.vassals_includes) counter += 2;
char **vassal_argv = vassal_new_argv(n_ui, NULL);
char **vassal_argv = uwsgi_malloc(sizeof(char *) * counter);
// set args
vassal_argv[0] = uwsgi.emperor_wrapper ? uwsgi.emperor_wrapper : uwsgi.binary_path;
// reset counter
counter = 1;
uwsgi_foreach(uct, uwsgi.vassals_templates_before) {
vassal_argv[counter] = "--inherit";
vassal_argv[counter + 1] = uct->value;
counter += 2;
}
uwsgi_foreach(uct, uwsgi.vassals_includes_before) {
vassal_argv[counter] = "--include";
vassal_argv[counter + 1] = uct->value;
counter += 2;
}
uwsgi_foreach(uct, uwsgi.vassals_set) {
vassal_argv[counter] = "--set";
vassal_argv[counter + 1] = uct->value;
counter += 2;
}
char *colon = NULL;
if (uwsgi.emperor_broodlord) {
colon = strchr(n_ui->name, ':');
if (colon) {
colon[0] = 0;
}
}
// initialize to a default value
vassal_argv[counter] = "--inherit";
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".xml"))
vassal_argv[counter] = "--xml";
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".ini"))
vassal_argv[counter] = "--ini";
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".yml"))
vassal_argv[counter] = "--yaml";
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".yaml"))
vassal_argv[counter] = "--yaml";
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 3), ".js"))
vassal_argv[counter] = "--json";
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".json"))
vassal_argv[counter] = "--json";
struct uwsgi_string_list *usl = uwsgi.emperor_extra_extension;
while (usl) {
if (uwsgi_endswith(n_ui->name, usl->value)) {
vassal_argv[counter] = "--config";
break;
}
usl = usl->next;
}
if (colon)
colon[0] = ':';
// start config filename...
counter++;
vassal_argv[counter] = n_ui->name;
if (uwsgi.emperor_magic_exec) {
if (!access(n_ui->name, R_OK | X_OK)) {
vassal_argv[counter] = uwsgi_concat2("exec://", n_ui->name);
}
}
if (n_ui->use_config) {
vassal_argv[counter] = uwsgi_concat2("emperor://", n_ui->name);
}
// start templates,includes,inherit...
counter++;
uwsgi_foreach(uct, uwsgi.vassals_templates) {
vassal_argv[counter] = "--inherit";
vassal_argv[counter + 1] = uct->value;
counter += 2;
}
uwsgi_foreach(uct, uwsgi.vassals_includes) {
vassal_argv[counter] = "--include";
vassal_argv[counter + 1] = uct->value;
counter += 2;
}
vassal_argv[counter] = NULL;
// disable stdin OR map it to the "on demand" socket
if (n_ui->on_demand_fd > -1) {
@@ -1389,6 +1565,7 @@ static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) {
uwsgi_hooks_run(uwsgi.hook_as_vassal, "as-vassal", 1);
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.mount_as_vassal) {
uwsgi_log("mounting \"%s\" (as-vassal)...\n", usl->value);
if (uwsgi_mount_hook(usl->value)) {
@@ -1441,6 +1618,14 @@ static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) {
func(n_ui->name, n_ui->uid, n_ui->gid);
}
char *force_chdir = vassal_attr_get(n_ui, uwsgi.emperor_chdir_attr);
if (force_chdir) {
if (chdir(force_chdir)) {
uwsgi_error("--emperor-chdir-attr/chdir()");
exit(UWSGI_EXILE_CODE);
}
}
// ->vassal_before_exec
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->vassal_before_exec) {
@@ -1449,7 +1634,7 @@ static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) {
}
for (i = 0; i < uwsgi.gp_cnt; i++) {
if (uwsgi.gp[i]->vassal) {
if (uwsgi.gp[i]->vassal_before_exec) {
uwsgi.gp[i]->vassal_before_exec(n_ui);
}
}
@@ -1614,6 +1799,20 @@ static void emperor_cleanup() {
void emperor_loop() {
#if defined(__linux__) && defined(PR_SET_CHILD_SUBREAPER)
if (uwsgi.emperor_use_fork_server || uwsgi.emperor_subreaper || uwsgi.emperor_fork_server_attr) {
if (prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0)) {
uwsgi_error("uwsgi_fork_server()/fork()");
exit(1);
}
}
#else
if (uwsgi.emperor_use_fork_server || uwsgi.emperor_subreaper || uwsgi.emperor_fork_server_attr) {
uwsgi_log("*** DANGER: your kernel misses PR_SET_CHILD_SUBREAPER feature, required by the fork server ***\n");
uwsgi_log("*** your Emperor will not be able to correctly wait() on vassals ***\n");
}
#endif
// monitor a directory
struct uwsgi_instance ui_base;
@@ -1902,6 +2101,7 @@ recheck:
uwsgi_error("waitpid()");
}
}
ui_current = ui;
while (ui_current->ui_next) {
ui_current = ui_current->ui_next;
@@ -1924,17 +2124,17 @@ recheck:
socket_name = uwsgi_str(ui_current->socket_name);
}
emperor_add(ui_current->scanner, ui_current->name, ui_current->last_mod, config, ui_current->config_len, ui_current->uid, ui_current->gid, socket_name);
// temporarily set frequency to 0, so we can eventually fast-restart the instance
emperor_del(ui_current);
freq = 0;
// temporarily set frequency to 1, so we can eventually fast-restart the instance
freq = 1;
}
break;
}
else if (ui_current->status == 1) {
// remove 'marked for dead' instance
emperor_del(ui_current);
// temporarily set frequency to 0, so we can eventually fast-restart the instance
freq = 0;
// temporarily set frequency to 1, so we can eventually fast-restart the instance
freq = 1;
break;
}
// back to on_demand mode ...
@@ -1952,14 +2152,18 @@ recheck:
ui_current->ready = 0;
ui_current->accepting = 0;
uwsgi_log("[uwsgi-emperor] %s -> back to \"on demand\" mode, waiting for connections on socket \"%s\" ...\n", ui_current->name, ui_current->socket_name);
if (uwsgi_hooks_run_and_return(uwsgi.hook_as_on_demand_vassal, "as-on-demand-vassal", ui_current->name, 0)) {
emperor_del(ui_current);
freq = 1;
}
break;
}
}
else if (ui_current->cursed_at > 0) {
if (ui_current->pid == -1) {
emperor_del(ui_current);
// temporarily set frequency to 0, so we can eventually fast-restart the instance
freq = 0;
// temporarily set frequency to 1, so we can eventually fast-restart the instance
freq = 1;
break;
}
else if (now - ui_current->cursed_at >= uwsgi.emperor_curse_tolerance) {
@@ -2093,6 +2297,9 @@ void emperor_send_stats(int fd) {
if (uwsgi_stats_keyval_comma(us, "on_demand", c_ui->socket_name ? c_ui->socket_name : ""))
goto end0;
if (uwsgi_stats_keylong_comma(us, "adopted", (unsigned long long) c_ui->adopted))
goto end0;
if (uwsgi_stats_keylong_comma(us, "uid", (unsigned long long) c_ui->uid))
goto end0;
if (uwsgi_stats_keylong_comma(us, "gid", (unsigned long long) c_ui->gid))
@@ -2101,6 +2308,31 @@ void emperor_send_stats(int fd) {
if (uwsgi_stats_keyval_comma(us, "monitor", c_ui->scanner->arg))
goto end0;
if (uwsgi_stats_key(us, "attrs"))
goto end0;
if (uwsgi_stats_list_open(us))
goto end0;
struct uwsgi_dyn_dict *attrs = c_ui->attrs;
while(attrs) {
if (attrs->next) {
if (uwsgi_stats_keyval_comma(us, attrs->key, attrs->value))
goto end0;
}
else {
if (uwsgi_stats_keyval(us, attrs->key, attrs->value))
goto end0;
}
attrs = attrs->next;
}
if (uwsgi_stats_list_close(us))
goto end0;
if (uwsgi_stats_comma(us))
goto end0;
if (uwsgi_stats_keylong(us, "respawns", (unsigned long long) c_ui->respawns))
goto end0;
@@ -2289,6 +2521,34 @@ next:
}
void uwsgi_emperor_simple_do_with_attrs(struct uwsgi_emperor_scanner *ues, char *name, char *config, time_t ts, uid_t uid, gid_t gid, char *socket_name, struct uwsgi_dyn_dict *attrs) {
uwsgi_emperor_simple_do(ues, name, config, ts, uid, gid, socket_name);
struct uwsgi_instance *ui_current = emperor_get(name);
// free attrs ?
if (!ui_current) {
struct uwsgi_dyn_dict *attr = attrs;
while(attr) {
struct uwsgi_dyn_dict *tmp = attr;
attr = attr->next;
if (tmp->value) free(tmp->value);
free(tmp);
}
return;
}
// if the instance has attrs mapped, let's free them
if (ui_current->attrs) {
struct uwsgi_dyn_dict *attr = ui_current->attrs;
while(attr) {
struct uwsgi_dyn_dict *tmp = attr;
attr = attr->next;
if (tmp->value) free(tmp->value);
free(tmp);
}
}
ui_current->attrs = attrs;
}
void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *ues, char *name, char *config, time_t ts, uid_t uid, gid_t gid, char *socket_name) {
if (!uwsgi_emperor_is_valid(name))

226
core/fork_server.c Normal file
View File

@@ -0,0 +1,226 @@
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
/*
on connection retrieve the uid,gid and pid of the connecting process, in addition to up to 3
file descriptors (emperor pipe, emperor pipe_config, on_demand socket dup()'ed to 0)
if authorized, double fork, get the pid of the second child and exit()
its parent (this will force the Emperor to became its subreaper).
from now on, we can consider the new child as a full-featured vassal
*/
#define VASSAL_HAS_CONFIG 0x02
#define VASSAL_HAS_ON_DEMAND 0x04
static void parse_argv_hook(uint16_t item, char *value, uint16_t vlen, void *data) {
struct uwsgi_string_list **usl = (struct uwsgi_string_list **) data;
uwsgi_string_new_list(usl, uwsgi_concat2n(value, vlen, "", 0));
}
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 upto 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 successfull (new pid: %d)\n", getpid());
// 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;
}
}
end:
close(client_fd);
}
}

View File

@@ -540,6 +540,18 @@ static int uwsgi_hook_retryrpc(char *arg) {
return 0;
}
static int uwsgi_hook_wait_for_fs(char *arg) {
return uwsgi_wait_for_fs(arg, 0);
}
static int uwsgi_hook_wait_for_file(char *arg) {
return uwsgi_wait_for_fs(arg, 1);
}
static int uwsgi_hook_wait_for_dir(char *arg) {
return uwsgi_wait_for_fs(arg, 2);
}
void uwsgi_register_base_hooks() {
uwsgi_register_hook("cd", uwsgi_hook_chdir);
uwsgi_register_hook("chdir", uwsgi_hook_chdir);
@@ -580,61 +592,182 @@ void uwsgi_register_base_hooks() {
uwsgi_register_hook("rpc", uwsgi_hook_rpc);
uwsgi_register_hook("retryrpc", uwsgi_hook_retryrpc);
uwsgi_register_hook("wait_for_fs", uwsgi_hook_wait_for_fs);
uwsgi_register_hook("wait_for_file", uwsgi_hook_wait_for_file);
uwsgi_register_hook("wait_for_dir", uwsgi_hook_wait_for_dir);
// for testing
uwsgi_register_hook("exit", uwsgi_hook_exit);
uwsgi_register_hook("print", uwsgi_hook_print);
uwsgi_register_hook("log", uwsgi_hook_print);
}
int uwsgi_hooks_run_and_return(struct uwsgi_string_list *l, char *phase, char *context, int fatal) {
int final_ret = 0;
struct uwsgi_string_list *usl = NULL;
if (context) {
if (setenv("UWSGI_HOOK_CONTEXT", context, 1)) {
uwsgi_error("uwsgi_hooks_run_and_return()/setenv()");
return -1;
}
}
uwsgi_foreach(usl, l) {
char *colon = strchr(usl->value, ':');
if (!colon) {
uwsgi_log("invalid hook syntax, must be hook:args\n");
exit(1);
}
*colon = 0;
int private = 0;
char *action = usl->value;
// private hook ?
if (action[0] == '!') {
action++;
private = 1;
}
struct uwsgi_hook *uh = uwsgi_hook_by_name(action);
if (!uh) {
uwsgi_log("hook action not found: %s\n", action);
exit(1);
}
*colon = ':';
if (private) {
uwsgi_log("running --- PRIVATE HOOK --- (%s)...\n", phase);
}
else {
uwsgi_log("running \"%s\" (%s)...\n", usl->value, phase);
}
int ret = uh->func(colon+1);
if (ret != 0) {
if (fatal) {
if (context) {
unsetenv("UWSGI_HOOK_CONTEXT");
}
return ret;
}
final_ret = ret;
}
}
if (context) {
unsetenv("UWSGI_HOOK_CONTEXT");
}
return final_ret;
}
void uwsgi_hooks_run(struct uwsgi_string_list *l, char *phase, int fatal) {
int ret = uwsgi_hooks_run_and_return(l, phase, NULL, fatal);
if (fatal && ret != 0) {
uwsgi_log_verbose("FATAL hook failed, destroying instance\n");
if (uwsgi.master_process) {
if (uwsgi.workers) {
if (uwsgi.workers[0].pid == getpid()) {
kill_them_all(0);
return;
}
else {
if (kill(uwsgi.workers[0].pid, SIGINT)) {
uwsgi_error("uwsgi_hooks_run()/kill()");
exit(1);
}
return;
}
}
}
exit(1);
}
}
#if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL)
/*
this is a special hook, allowing the Emperor to enter a vassal
namespace and call hooks in its namespace context.
*/
void uwsgi_hooks_setns_run(struct uwsgi_string_list *l, pid_t pid, uid_t uid, gid_t gid) {
int (*u_setns) (int, int) = (int (*)(int, int)) dlsym(RTLD_DEFAULT, "setns");
if (!u_setns) {
uwsgi_log("your system misses setns() syscall !!!\n");
return;
}
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, l) {
char *colon = strchr(usl->value, ':');
if (!colon) {
uwsgi_log("invalid hook syntax, must be hook:args\n");
exit(1);
// fist of all fork() the current process
pid_t new_pid = fork();
if (new_pid > 0) {
// wait for its death
int status;
if (waitpid(new_pid, &status, 0) < 0) {
uwsgi_error("uwsgi_hooks_setns_run()/waitpid()");
}
}
*colon = 0;
int private = 0;
char *action = usl->value;
// private hook ?
if (action[0] == '!') {
action++;
private = 1;
}
struct uwsgi_hook *uh = uwsgi_hook_by_name(action);
if (!uh) {
uwsgi_log("hook action not found: %s\n", action);
exit(1);
}
*colon = ':';
else if (new_pid == 0) {
// from now on, freeing memory is useless
// now split args to know which namespaces to join
char *action = strchr(usl->value, ' ');
if (!action) {
uwsgi_log("invalid setns hook syntax, must be \"namespaces_list action:...\"\n");
exit(1);
}
char *pidstr = uwsgi_num2str(pid);
char *uidstr = uwsgi_num2str(uid);
char *gidstr = uwsgi_num2str(gid);
if (private) {
uwsgi_log("running --- PRIVATE HOOK --- (%s)...\n", phase);
char *namespaces = uwsgi_concat2n(usl->value, action-usl->value, "", 0);
char *p, *ctx = NULL;
uwsgi_foreach_token(namespaces, ",", p, ctx) {
char *procfile = uwsgi_concat4("/proc/", pidstr, "/ns/", p);
int fd = open(procfile, O_RDONLY);
if (fd < 0) {
uwsgi_error_open(procfile);
exit(1);
}
if (u_setns(fd, 0) < 0){
uwsgi_error("uwsgi_hooks_setns_run()/setns()");
exit(1);
}
}
if (setenv("UWSGI_VASSAL_PID", pidstr, 1)) {
uwsgi_error("uwsgi_hooks_setns_run()/setenv()");
exit(1);
}
if (setenv("UWSGI_VASSAL_UID", uidstr, 1)) {
uwsgi_error("uwsgi_hooks_setns_run()/setenv()");
exit(1);
}
if (setenv("UWSGI_VASSAL_GID", gidstr, 1)) {
uwsgi_error("uwsgi_hooks_setns_run()/setenv()");
exit(1);
}
// now run the action and then exit
action++;
char *colon = strchr(action, ':');
if (!colon) {
uwsgi_log("invalid hook syntax must be action:arg\n");
exit(1);
}
*colon = 0;
struct uwsgi_hook *uh = uwsgi_hook_by_name(action);
if (!uh) {
uwsgi_log("hook action not found: %s\n", action);
exit(1);
}
*colon = ':';
uwsgi_log("running \"%s\" (setns)...\n", usl->value);
exit(uh->func(colon+1));
}
else {
uwsgi_log("running \"%s\" (%s)...\n", usl->value, phase);
}
int ret = uh->func(colon+1);
if (fatal && ret != 0) {
uwsgi_log_verbose("FATAL hook failed, destroying instance\n");
if (uwsgi.master_process) {
if (uwsgi.workers) {
if (uwsgi.workers[0].pid == getpid()) {
kill_them_all(0);
return;
}
else {
if (kill(uwsgi.workers[0].pid, SIGINT)) {
uwsgi_error("uwsgi_hooks_run()/kill()");
exit(1);
}
return;
}
}
}
exit(1);
uwsgi_error("uwsgi_hooks_setns_run()/fork()");
}
}
}
#endif

View File

@@ -9,7 +9,7 @@ extern struct uwsgi_server uwsgi;
static char *last_file = NULL;
void ini_rstrip(char *line) {
static void ini_rstrip(char *line) {
off_t i;
@@ -22,7 +22,7 @@ void ini_rstrip(char *line) {
}
}
char *ini_lstrip(char *line) {
static char *ini_lstrip(char *line) {
off_t i;
char *ptr = line;
@@ -38,7 +38,7 @@ char *ini_lstrip(char *line) {
return ptr;
}
char *ini_get_key(char *key) {
static char *ini_get_key(char *key) {
off_t i;
char *ptr = key;
@@ -54,7 +54,7 @@ char *ini_get_key(char *key) {
return ptr;
}
char *ini_get_line(char *ini, size_t size) {
static char *ini_get_line(char *ini, size_t size) {
size_t i;
char *ptr = ini;
@@ -171,5 +171,58 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
colon[0] = ':';
}
}
void uwsgi_emperor_ini_attrs(char *filename, char *section_asked, struct uwsgi_dyn_dict **attrs) {
if (!section_asked) section_asked = "emperor";
char *ini = uwsgi_simple_file_read(filename);
if (!ini) return;
char *orig_ini = ini;
size_t len = strlen(ini);
char *section = "";
char *key, *val, *ini_line;
while (len) {
ini_line = ini_get_line(ini, len);
if (ini_line == NULL) {
break;
}
// skip empty line
key = ini_lstrip(ini);
ini_rstrip(key);
if (key[0] != 0) {
if (key[0] == '[') {
section = key + 1;
section[strlen(section) - 1] = 0;
}
else if (key[0] == ';' || key[0] == '#') {
// this is a comment
}
else {
// val is always valid, but (obviously) can be ignored
val = ini_get_key(key);
if (!strcmp(section, section_asked)) {
ini_rstrip(key);
struct uwsgi_string_list *usl = uwsgi_string_list_has_item(uwsgi.emperor_collect_attributes, key, strlen(key));
if (usl) {
val = ini_lstrip(val);
ini_rstrip(val);
char *value = uwsgi_str(val);
uwsgi_dyn_dict_new(attrs, usl->value, usl->len, value, strlen(value));
}
}
}
}
len -= (ini_line - ini);
ini += (ini_line - ini);
}
free(orig_ini);
}

View File

@@ -61,6 +61,7 @@ struct http_status_codes hsc[] = {
void uwsgi_init_default() {
uwsgi.cpus = 1;
uwsgi.new_argc = -1;
uwsgi.backtrace_depth = 64;
uwsgi.max_apps = 64;
@@ -105,7 +106,7 @@ void uwsgi_init_default() {
uwsgi.forkbomb_delay = 2;
uwsgi.async = 1;
uwsgi.async = 0;
uwsgi.listen_queue = 100;
uwsgi.cheaper_overload = 3;
@@ -252,9 +253,20 @@ void uwsgi_commandline_config() {
int i;
uwsgi.option_index = -1;
// required in case we want to call getopt_long from the beginning
optind = 0;
int argc = uwsgi.argc;
char **argv = uwsgi.argv;
if (uwsgi.new_argc > -1 && uwsgi.new_argv) {
argc = uwsgi.new_argc;
argv = uwsgi.new_argv;
}
char *optname;
while ((i = getopt_long(uwsgi.argc, uwsgi.argv, uwsgi.short_options, uwsgi.long_options, &uwsgi.option_index)) != -1) {
while ((i = getopt_long(argc, argv, uwsgi.short_options, uwsgi.long_options, &uwsgi.option_index)) != -1) {
if (i == '?') {
uwsgi_log("getopt_long() error\n");
@@ -280,9 +292,9 @@ void uwsgi_commandline_config() {
uwsgi_log("optind:%d argc:%d\n", optind, uwsgi.argc);
#endif
if (optind < uwsgi.argc) {
for (i = optind; i < uwsgi.argc; i++) {
char *lazy = uwsgi.argv[i];
if (optind < argc) {
for (i = optind; i < argc; i++) {
char *lazy = argv[i];
if (lazy[0] != '[') {
uwsgi_opt_load(NULL, lazy, NULL);
// manage magic mountpoint
@@ -407,7 +419,7 @@ pid_t uwsgi_daemonize2() {
// fix/check related options
void sanitize_args() {
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
uwsgi.cores = uwsgi.async;
}

132
core/io.c
View File

@@ -90,7 +90,7 @@ char *uwsgi_simple_file_read(char *filename) {
}
if (fstat(fd, &sb)) {
uwsgi_error("fstat()");
uwsgi_error("uwsgi_simple_file_read()/fstat()");
close(fd);
goto end;
}
@@ -99,7 +99,7 @@ char *uwsgi_simple_file_read(char *filename) {
len = read(fd, buffer, sb.st_size);
if (len != sb.st_size) {
uwsgi_error("read()");
uwsgi_error("uwsgi_simple_file_read()/read()");
free(buffer);
close(fd);
goto end;
@@ -112,7 +112,7 @@ char *uwsgi_simple_file_read(char *filename) {
buffer[sb.st_size] = 0;
return buffer;
end:
return (char *) "";
return NULL;
}
@@ -1502,3 +1502,129 @@ clear:
#endif
}
ssize_t uwsgi_recv_cred_and_fds(int fd, char *buf, size_t buf_len, pid_t *pid, uid_t *uid, gid_t *gid, int *fds, int *fds_count) {
#if defined(SCM_CREDENTIALS) && defined(SCM_RIGHTS)
ssize_t ret = -1;
size_t msg_len = CMSG_SPACE(sizeof(struct ucred)) + CMSG_SPACE(sizeof(int) * (*fds_count));
// allocate space for credentials and file descriptors
void *msg_control = uwsgi_calloc(msg_len);
// read into buf
struct iovec iov;
iov.iov_base = buf;
iov.iov_len = buf_len;
struct msghdr msg;
memset(&msg, 0, sizeof(msg));
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
// set cmsg
msg.msg_control = msg_control;
msg.msg_controllen = msg_len;
ssize_t len = recvmsg(fd, &msg, 0);
if (len <= 0) {
uwsgi_error("uwsgi_recv_cred_and_fds()/recvmsg()");
goto clear;
}
// reset the number of fds
*fds_count = 0;
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
while(cmsg) {
if (cmsg->cmsg_level != SOL_SOCKET) goto next;
if (cmsg->cmsg_type == SCM_RIGHTS) {
size_t fds_len = cmsg->cmsg_len - ((char *) CMSG_DATA(cmsg) - (char *) cmsg);
memcpy(fds, CMSG_DATA(cmsg), fds_len);
*fds_count = fds_len/sizeof(int);
}
else if (cmsg->cmsg_type == SCM_CREDENTIALS) {
struct ucred *u = (struct ucred *) CMSG_DATA(cmsg);
*pid = u->pid;
*uid = u->uid;
*gid = u->gid;
}
next:
cmsg=CMSG_NXTHDR(&msg,cmsg);
}
ret = len;
clear:
free(msg_control);
return ret;
#else
return -1;
#endif
}
int uwsgi_send_fds_and_body(int fd, int *fds, int fds_count, char *body, size_t len) {
int ret = -1;
struct msghdr msg;
void *msg_control = uwsgi_malloc(CMSG_SPACE(sizeof(int) * fds_count));
struct iovec iov;
struct cmsghdr *cmsg;
iov.iov_base = body;
iov.iov_len = len;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_flags = 0;
msg.msg_control = msg_control;
msg.msg_controllen = CMSG_SPACE(sizeof(int) * fds_count);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fds_count);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
unsigned char *fd_ptr = CMSG_DATA(cmsg);
memcpy(fd_ptr, fds, sizeof(int) * fds_count);
ssize_t rlen = sendmsg(fd, &msg, 0);
if (rlen <= 0) {
uwsgi_error("uwsgi_send_fds_and_body()/sendmsg()");
goto end;
}
else {
size_t remains = len - rlen;
while(remains > 0) {
char *buf = body + rlen;
ssize_t wlen = write(fd, buf, remains);
if (wlen == 0) goto end;
if (wlen < 0) {
if (uwsgi_is_again()) {
// wait for write
continue;
}
uwsgi_error("uwsgi_send_fds_and_body()/write()");
goto end;
}
rlen += wlen;
remains -= wlen;
}
}
ret = 0;
end:
free(msg_control);
return ret;
}

View File

@@ -964,7 +964,9 @@ next:
// ok a worker died...
uwsgi.workers[thewid].pid = 0;
// only to be safe :P
uwsgi.workers[thewid].harakiri = 0;
for(i=0;i<uwsgi.cores;i++) {
uwsgi.workers[thewid].cores[i].harakiri = 0;
}
// ok, if we are reloading or dying, just continue the master loop
// as soon as all of the workers have pid == 0, the action (exit, or reload) is triggered

View File

@@ -157,21 +157,27 @@ void uwsgi_master_check_idle() {
}
int uwsgi_master_check_workers_deadline() {
int i;
int i,j;
int ret = 0;
for (i = 1; i <= uwsgi.numproc; i++) {
/* first check for harakiri */
if (uwsgi.workers[i].harakiri > 0) {
if (uwsgi.workers[i].harakiri < (time_t) uwsgi.current_time) {
trigger_harakiri(i);
ret = 1;
for(j=0;j<uwsgi.cores;j++) {
/* first check for harakiri */
if (uwsgi.workers[i].cores[j].harakiri > 0) {
if (uwsgi.workers[i].cores[j].harakiri < (time_t) uwsgi.current_time) {
uwsgi_log_verbose("HARAKIRI triggered by worker %d core %d !!!\n", i, j);
trigger_harakiri(i);
ret = 1;
break;
}
}
}
/* then user-defined harakiri */
if (uwsgi.workers[i].user_harakiri > 0) {
if (uwsgi.workers[i].user_harakiri < (time_t) uwsgi.current_time) {
trigger_harakiri(i);
ret = 1;
/* then user-defined harakiri */
if (uwsgi.workers[i].cores[j].user_harakiri > 0) {
uwsgi_log_verbose("HARAKIRI (user) triggered by worker %d core %d !!!\n", i, j);
if (uwsgi.workers[i].cores[j].user_harakiri < (time_t) uwsgi.current_time) {
trigger_harakiri(i);
ret = 1;
break;
}
}
}
// then for evil memory checkers

View File

@@ -388,6 +388,8 @@ void uwsgi_reload(char **argv) {
int i;
int waitpid_status;
if (uwsgi.new_argv) argv = uwsgi.new_argv;
if (!uwsgi.master_is_reforked) {
// call a series of waitpid to ensure all processes (gateways, mules and daemons) are dead
@@ -630,7 +632,7 @@ void uwsgi_fixup_fds(int wid, int muleid, struct uwsgi_gateway *ug) {
}
int uwsgi_respawn_worker(int wid) {
int i;
int respawns = uwsgi.workers[wid].respawn_count;
// the workers is not accepting (obviously)
uwsgi.workers[wid].accepting = 0;
@@ -639,8 +641,10 @@ int uwsgi_respawn_worker(int wid) {
// ... same for update time
uwsgi.workers[wid].last_spawn = uwsgi.current_time;
// ... and memory/harakiri
uwsgi.workers[wid].harakiri = 0;
uwsgi.workers[wid].user_harakiri = 0;
for(i=0;i<uwsgi.cores;i++) {
uwsgi.workers[wid].cores[i].harakiri = 0;
uwsgi.workers[wid].cores[i].user_harakiri = 0;
}
uwsgi.workers[wid].pending_harakiri = 0;
uwsgi.workers[wid].rss_size = 0;
uwsgi.workers[wid].vsz_size = 0;
@@ -658,8 +662,6 @@ int uwsgi_respawn_worker(int wid) {
// this is required for various checks
uwsgi.workers[wid].delta_requests = 0;
int i;
if (uwsgi.threaded_logger) {
pthread_mutex_lock(&uwsgi.threaded_logger_lock);
}

View File

@@ -198,7 +198,7 @@ void uwsgi_mule_handler() {
#ifdef UWSGI_DEBUG
uwsgi_log_verbose("master sent signal %d to mule %d\n", uwsgi_signal, uwsgi.muleid);
#endif
if (uwsgi_signal_handler(uwsgi_signal)) {
if (uwsgi_signal_handler(NULL, uwsgi_signal)) {
uwsgi_log_verbose("error managing signal %d on mule %d\n", uwsgi_signal, uwsgi.muleid);
}
}
@@ -362,7 +362,7 @@ retry:
#ifdef UWSGI_DEBUG
uwsgi_log_verbose("master sent signal %d to mule %d\n", uwsgi_signal, uwsgi.muleid);
#endif
if (uwsgi_signal_handler(uwsgi_signal)) {
if (uwsgi_signal_handler(NULL, uwsgi_signal)) {
uwsgi_log_verbose("error managing signal %d on mule %d\n", uwsgi_signal, uwsgi.muleid);
}
// set the error condition

View File

@@ -527,6 +527,11 @@ static int uwsgi_proto_check_22(struct wsgi_request *wsgi_req, char *key, char *
return 0;
}
if (!uwsgi_proto_key("HTTP_X_FORWARDED_PROTO", 22)) {
wsgi_req->scheme = buf;
wsgi_req->scheme_len = len;
}
return 0;
}

View File

@@ -477,7 +477,7 @@ int uwsgi_postbuffer_do_in_mem(struct wsgi_request *wsgi_req) {
while (remains > 0) {
if (uwsgi.harakiri_options.workers > 0) {
inc_harakiri(uwsgi.harakiri_options.workers);
inc_harakiri(wsgi_req, uwsgi.harakiri_options.workers);
}
ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, ptr, remains);
@@ -551,7 +551,7 @@ int uwsgi_postbuffer_do_in_disk(struct wsgi_request *wsgi_req) {
// during post buffering we need to constantly reset the harakiri
if (uwsgi.harakiri_options.workers > 0) {
inc_harakiri(uwsgi.harakiri_options.workers);
inc_harakiri(wsgi_req, uwsgi.harakiri_options.workers);
}
// we use the already available post buffering buffer to read chunks....

View File

@@ -702,7 +702,7 @@ static int uwsgi_router_simple_math_divide(struct uwsgi_route *ur, char *arg) {
// harakiri router
static int uwsgi_router_harakiri_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
if (route->custom > 0) {
set_user_harakiri(route->custom);
set_user_harakiri(wsgi_req, route->custom);
}
return UWSGI_ROUTE_NEXT;
}

View File

@@ -7,6 +7,11 @@ int uwsgi_register_rpc(char *name, struct uwsgi_plugin *plugin, uint8_t args, vo
struct uwsgi_rpc *urpc;
int ret = -1;
if (!uwsgi.workers || !uwsgi.shared || !uwsgi.rpc_table_lock) {
uwsgi_log("RPC subsystem still not initialized\n");
return -1;
}
if (uwsgi.mywid == 0 && uwsgi.workers[0].pid != uwsgi.mypid) {
uwsgi_log("only the master and the workers can register RPC functions\n");
return -1;

View File

@@ -2,7 +2,7 @@
extern struct uwsgi_server uwsgi;
int uwsgi_signal_handler(uint8_t sig) {
int uwsgi_signal_handler(struct wsgi_request *wsgi_req, uint8_t sig) {
struct uwsgi_signal_entry *use = NULL;
@@ -41,12 +41,12 @@ int uwsgi_signal_handler(uint8_t sig) {
// set harakiri here (if required and if i am a worker)
if (uwsgi.mywid > 0) {
if (uwsgi.mywid > 0 && wsgi_req) {
uwsgi.workers[uwsgi.mywid].sig = 1;
uwsgi.workers[uwsgi.mywid].signum = sig;
uwsgi.workers[uwsgi.mywid].signals++;
if (uwsgi.harakiri_options.workers > 0) {
set_harakiri(uwsgi.harakiri_options.workers);
set_harakiri(wsgi_req, uwsgi.harakiri_options.workers);
}
}
else if (uwsgi.muleid > 0) {
@@ -65,10 +65,10 @@ int uwsgi_signal_handler(uint8_t sig) {
int ret = uwsgi.p[use->modifier1]->signal_handler(sig, use->handler);
if (uwsgi.mywid > 0) {
if (uwsgi.mywid > 0 && wsgi_req) {
uwsgi.workers[uwsgi.mywid].sig = 0;
if (uwsgi.workers[uwsgi.mywid].harakiri > 0) {
set_harakiri(0);
if (uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].harakiri > 0) {
set_harakiri(wsgi_req, 0);
}
}
else if (uwsgi.muleid > 0) {
@@ -405,7 +405,7 @@ void uwsgi_route_signal(uint8_t sig) {
}
int uwsgi_signal_wait(int signum) {
int uwsgi_signal_wait(struct wsgi_request *wsgi_req, int signum) {
int wait_for_specific_signal = 0;
uint8_t uwsgi_signal = 0;
@@ -430,7 +430,7 @@ cycle:
uwsgi_error("read()");
}
else {
(void) uwsgi_signal_handler(uwsgi_signal);
(void) uwsgi_signal_handler(wsgi_req, uwsgi_signal);
if (wait_for_specific_signal) {
if (signum != uwsgi_signal)
goto cycle;
@@ -443,7 +443,7 @@ cycle:
uwsgi_error("read()");
}
else {
(void) uwsgi_signal_handler(uwsgi_signal);
(void) uwsgi_signal_handler(wsgi_req, uwsgi_signal);
if (wait_for_specific_signal) {
if (signum != uwsgi_signal)
goto cycle;
@@ -457,7 +457,7 @@ cycle:
return received_signal;
}
void uwsgi_receive_signal(int fd, char *name, int id) {
void uwsgi_receive_signal(struct wsgi_request *wsgi_req, int fd, char *name, int id) {
uint8_t uwsgi_signal;
@@ -474,7 +474,7 @@ void uwsgi_receive_signal(int fd, char *name, int id) {
#ifdef UWSGI_DEBUG
uwsgi_log_verbose("master sent signal %d to %s %d\n", uwsgi_signal, name, id);
#endif
if (uwsgi_signal_handler(uwsgi_signal)) {
if (uwsgi_signal_handler(wsgi_req, uwsgi_signal)) {
uwsgi_log_verbose("error managing signal %d on %s %d\n", uwsgi_signal, name, id);
}
}

View File

@@ -456,7 +456,7 @@ void spooler(struct uwsgi_spooler *uspool) {
if (event_queue_wait(spooler_event_queue, timeout, &interesting_fd) > 0) {
if (uwsgi.master_process) {
if (interesting_fd == uwsgi.shared->spooler_signal_pipe[1]) {
uwsgi_receive_signal(interesting_fd, "spooler", (int) getpid());
uwsgi_receive_signal(NULL, interesting_fd, "spooler", (int) getpid());
}
}
}

View File

@@ -494,6 +494,13 @@ clear:
}
char *uwsgi_sanitize_cert_filename(char *base, char *key, uint16_t keylen) {
// stop at the first slash if mountpoints are involved
if (uwsgi.subscription_mountpoints) {
char *slash = memchr(key, '/', keylen);
if (slash) {
keylen = slash - key;
}
}
uint16_t i;
char *filename = uwsgi_concat4n(base, strlen(base), "/", 1, key, keylen, ".pem\0", 5);

View File

@@ -65,16 +65,9 @@ char *uwsgi_lower(char *str, size_t size) {
return str;
}
// check if a string is contained in another one
// check if a char is contained in a string
char *uwsgi_str_contains(char *str, int slen, char what) {
int i;
for (i = 0; i < slen; i++) {
if (str[i] == what) {
return str + i;
}
}
return NULL;
return memchr(str, what, slen);
}
int uwsgi_contains_n(char *s1, size_t s1_len, char *s2, size_t s2_len) {
@@ -126,15 +119,7 @@ int uwsgi_starts_with(char *src, int slen, char *dst, int dlen) {
// unsized check
int uwsgi_startswith(char *src, char *what, int wlen) {
int i;
for (i = 0; i < wlen; i++) {
if (src[i] != what[i])
return -1;
}
return 0;
return memcmp(what, src, wlen);
}
// concatenate strings
@@ -483,3 +468,22 @@ char ** uwsgi_split_quoted(char *what, size_t what_len, char *sep, size_t *rlen)
return ret;
}
char *uwsgi_get_last_char(char *what, char c) {
return strrchr(what, c);
}
// Note by Mathieu Dupuy: memrchr here is better, unfortunately it is not supported
// everywhere. The only safe option looks checking for Linux :(
char *uwsgi_get_last_charn(char *what, size_t len, char c) {
#if defined(__linux__)
return memrchr(what, c, len);
#else
while (len--) {
if (what[len] == c)
return what + len;
}
return NULL;
#endif
}

View File

@@ -20,6 +20,17 @@
extern struct uwsgi_server uwsgi;
char *uwsgi_subscription_algo_name(void *ptr) {
struct uwsgi_string_list *usl = uwsgi.subscription_algos;
while(usl) {
if (usl->custom_ptr == ptr) {
return usl->value;
}
usl = usl->next;
}
return NULL;
}
#ifdef UWSGI_SSL
static void uwsgi_subscription_sni_check(struct uwsgi_subscribe_slot *current_slot, struct uwsgi_subscribe_req *usr) {
if (usr->sni_key_len > 0 && usr->sni_crt_len > 0) {
@@ -72,6 +83,8 @@ int uwsgi_subscription_credentials_check(struct uwsgi_subscribe_slot *slot, stru
}
struct uwsgi_subscribe_slot *uwsgi_get_subscribe_slot(struct uwsgi_subscribe_slot **slot, char *key, uint16_t keylen) {
int retried = 0;
retry:
if (keylen > 0xff)
return NULL;
@@ -125,136 +138,20 @@ struct uwsgi_subscribe_slot *uwsgi_get_subscribe_slot(struct uwsgi_subscribe_slo
break;
}
// if we are here and in mountpoints mode, try the domain only variant
if (uwsgi.subscription_mountpoints && !retried) {
char *slash = memchr(key, '/', keylen);
if (slash) {
keylen = slash - key;
retried = 1;
goto retry;
}
}
return NULL;
}
// least reference count
static struct uwsgi_subscribe_node *uwsgi_subscription_algo_lrc(struct uwsgi_subscribe_slot *current_slot, struct uwsgi_subscribe_node *node) {
// if node is NULL we are in the second step (in lrc mode we do not use the first step)
if (node)
return NULL;
struct uwsgi_subscribe_node *choosen_node = NULL;
node = current_slot->nodes;
uint64_t min_rc = 0;
while (node) {
if (!node->death_mark) {
if (min_rc == 0 || node->reference < min_rc) {
min_rc = node->reference;
choosen_node = node;
if (min_rc == 0 && !(node->next && node->next->reference <= node->reference && node->next->last_requests <= node->last_requests))
break;
}
}
node = node->next;
}
if (choosen_node) {
choosen_node->reference++;
}
return choosen_node;
}
// weighted least reference count
static struct uwsgi_subscribe_node *uwsgi_subscription_algo_wlrc(struct uwsgi_subscribe_slot *current_slot, struct uwsgi_subscribe_node *node) {
// if node is NULL we are in the second step (in wlrc mode we do not use the first step)
if (node)
return NULL;
struct uwsgi_subscribe_node *choosen_node = NULL;
node = current_slot->nodes;
double min_rc = 0;
while (node) {
if (!node->death_mark) {
// node->weight is always >= 1, we can safely use it as divider
double ref = (double) node->reference / (double) node->weight;
double next_node_ref = 0;
if (node->next)
next_node_ref = (double) node->next->reference / (double) node->next->weight;
if (min_rc == 0 || ref < min_rc) {
min_rc = ref;
choosen_node = node;
if (min_rc == 0 && !(node->next && next_node_ref <= ref && node->next->last_requests <= node->last_requests))
break;
}
}
node = node->next;
}
if (choosen_node) {
choosen_node->reference++;
}
return choosen_node;
}
// weighted round robin algo
static struct uwsgi_subscribe_node *uwsgi_subscription_algo_wrr(struct uwsgi_subscribe_slot *current_slot, struct uwsgi_subscribe_node *node) {
// if node is NULL we are in the second step
if (node) {
if (node->death_mark == 0 && node->wrr > 0) {
node->wrr--;
node->reference++;
return node;
}
return NULL;
}
// no wrr > 0 node found, reset them
node = current_slot->nodes;
uint64_t min_weight = 0;
while (node) {
if (!node->death_mark) {
if (min_weight == 0 || node->weight < min_weight)
min_weight = node->weight;
}
node = node->next;
}
// now set wrr
node = current_slot->nodes;
struct uwsgi_subscribe_node *choosen_node = NULL;
while (node) {
if (!node->death_mark) {
node->wrr = node->weight / min_weight;
choosen_node = node;
}
node = node->next;
}
if (choosen_node) {
choosen_node->wrr--;
choosen_node->reference++;
}
return choosen_node;
}
void uwsgi_subscription_set_algo(char *algo) {
if (!algo)
goto wrr;
if (!strcmp(algo, "wrr")) {
uwsgi.subscription_algo = uwsgi_subscription_algo_wrr;
return;
}
if (!strcmp(algo, "lrc")) {
uwsgi.subscription_algo = uwsgi_subscription_algo_lrc;
return;
}
if (!strcmp(algo, "wlrc")) {
uwsgi.subscription_algo = uwsgi_subscription_algo_wlrc;
return;
}
wrr:
uwsgi.subscription_algo = uwsgi_subscription_algo_wrr;
}
struct uwsgi_subscribe_node *uwsgi_get_subscribe_node(struct uwsgi_subscribe_slot **slot, char *key, uint16_t keylen) {
struct uwsgi_subscribe_node *uwsgi_get_subscribe_node(struct uwsgi_subscribe_slot **slot, char *key, uint16_t keylen, struct uwsgi_subscription_client *client) {
if (keylen > 0xff)
return NULL;
@@ -287,14 +184,14 @@ struct uwsgi_subscribe_node *uwsgi_get_subscribe_node(struct uwsgi_subscribe_slo
continue;
}
struct uwsgi_subscribe_node *choosen_node = uwsgi.subscription_algo(current_slot, node);
struct uwsgi_subscribe_node *choosen_node = current_slot->algo(current_slot, node, client);
if (choosen_node)
return choosen_node;
node = node->next;
}
return uwsgi.subscription_algo(current_slot, node);
return current_slot->algo(current_slot, node, client);
}
struct uwsgi_subscribe_node *uwsgi_get_subscribe_node_by_name(struct uwsgi_subscribe_slot **slot, char *key, uint16_t keylen, char *val, uint16_t vallen) {
@@ -436,6 +333,10 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
node->cores = usr->cores;
node->load = usr->load;
node->weight = usr->weight;
node->backup_level = usr->backup_level;
if (usr->proto_len > 0) {
node->proto = usr->proto[0];
}
if (!node->weight)
node->weight = 1;
node->last_requests = 0;
@@ -468,6 +369,10 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
node->cores = usr->cores;
node->load = usr->load;
node->weight = usr->weight;
node->backup_level = usr->backup_level;
if (usr->proto_len > 0) {
node->proto = usr->proto[0];
}
node->unix_check = usr->unix_check;
if (!node->weight)
node->weight = 1;
@@ -488,7 +393,7 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
}
node->next = NULL;
uwsgi_log("[uwsgi-subscription for pid %d] %.*s => new node: %.*s\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address);
uwsgi_log("[uwsgi-subscription for pid %d] %.*s => new node: %.*s (weight: %d, backup: %d)\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address, usr->weight, usr->backup_level);
if (node->notify[0]) {
char buf[1024];
int ret = snprintf(buf, 1024, "[subscription ack] %.*s => new node: %.*s", usr->keylen, usr->key, usr->address_len, usr->address);
@@ -539,6 +444,10 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
current_slot->nodes->cores = usr->cores;
current_slot->nodes->load = usr->load;
current_slot->nodes->weight = usr->weight;
current_slot->nodes->backup_level = usr->backup_level;
if (usr->proto_len > 0) {
current_slot->nodes->proto = usr->proto[0];
}
current_slot->nodes->unix_check = usr->unix_check;
if (!current_slot->nodes->weight)
current_slot->nodes->weight = 1;
@@ -570,13 +479,16 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
current_slot->prev = old_slot;
current_slot->next = NULL;
current_slot->algo = usr->algo;
if (!current_slot->algo) current_slot->algo = uwsgi.subscription_algo;
if (!slot[hash_key] || current_slot->prev == NULL) {
slot[hash_key] = current_slot;
}
uwsgi_log("[uwsgi-subscription for pid %d] new pool: %.*s (hash key: %d)\n", (int) uwsgi.mypid, usr->keylen, usr->key, current_slot->hash);
uwsgi_log("[uwsgi-subscription for pid %d] %.*s => new node: %.*s\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address);
uwsgi_log("[uwsgi-subscription for pid %d] new pool: %.*s (hash key: %d, algo: %s)\n", (int) uwsgi.mypid, usr->keylen, usr->key, current_slot->hash, uwsgi_subscription_algo_name(current_slot->algo));
uwsgi_log("[uwsgi-subscription for pid %d] %.*s => new node: %.*s (weight: %d, backup: %d)\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address, usr->weight, usr->backup_level);
if (current_slot->nodes->notify[0]) {
char buf[1024];
@@ -669,6 +581,30 @@ static void send_subscription(int sfd, char *host, char *message, uint16_t messa
close(fd);
}
static int uwsgi_subscription_ub_fix(struct uwsgi_buffer *ub, uint8_t modifier1, uint8_t modifier2, uint8_t cmd, char *sign) {
#ifdef UWSGI_SSL
if (sign) {
if (uwsgi_buffer_append_keynum(ub, "unix", 4, (uwsgi_now() + (time_t) cmd)))
return -1;
unsigned int signature_len = 0;
char *signature = uwsgi_rsa_sign(sign, ub->buf + 4, ub->pos - 4, &signature_len);
if (signature && signature_len > 0) {
if (uwsgi_buffer_append_keyval(ub, "sign", 4, signature, signature_len)) {
free(signature);
return -1;
}
free(signature);
}
}
#endif
// add uwsgi header
if (uwsgi_buffer_set_uh(ub, 224, cmd)) return -1;
return 0;
}
static struct uwsgi_buffer *uwsgi_subscription_ub(char *key, size_t keysize, uint8_t modifier1, uint8_t modifier2, uint8_t cmd, char *socket_name, char *sign, char *sni_key, char *sni_crt, char *sni_ca) {
struct uwsgi_buffer *ub = uwsgi_buffer_new(4096);
@@ -720,26 +656,7 @@ static struct uwsgi_buffer *uwsgi_subscription_ub(char *key, size_t keysize, uin
goto end;
}
#ifdef UWSGI_SSL
if (sign) {
if (uwsgi_buffer_append_keynum(ub, "unix", 4, (uwsgi_now() + (time_t) cmd)))
goto end;
unsigned int signature_len = 0;
char *signature = uwsgi_rsa_sign(sign, ub->buf + 4, ub->pos - 4, &signature_len);
if (signature && signature_len > 0) {
if (uwsgi_buffer_append_keyval(ub, "sign", 4, signature, signature_len)) {
free(signature);
goto end;
}
free(signature);
}
}
#endif
// add uwsgi header
if (uwsgi_buffer_set_uh(ub, 224, cmd))
goto end;
if (uwsgi_subscription_ub_fix(ub, modifier1, modifier2, cmd, sign)) goto end;
return ub;
@@ -861,13 +778,6 @@ int uwsgi_no_subscriptions(struct uwsgi_subscribe_slot **slot) {
return 1;
}
struct uwsgi_subscribe_slot **uwsgi_subscription_init_ht() {
if (!uwsgi.subscription_algo) {
uwsgi_subscription_set_algo(NULL);
}
return uwsgi_calloc(sizeof(struct uwsgi_subscription_slot *) * UMAX16);
}
void uwsgi_subscribe(char *subscription, uint8_t cmd) {
size_t subfile_size;
@@ -1014,8 +924,27 @@ void uwsgi_subscribe2(char *arg, uint8_t cmd) {
char *s2_sni_key = NULL;
char *s2_sni_crt = NULL;
char *s2_sni_ca = NULL;
char *s2_proto = NULL;
char *s2_algo = NULL;
char *s2_backup = NULL;
if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=', "server", &s2_server, "key", &s2_key, "socket", &s2_socket, "addr", &s2_addr, "weight", &s2_weight, "modifier1", &s2_modifier1, "modifier2", &s2_modifier2, "sign", &s2_sign, "check", &s2_check, "sni_key", &s2_sni_key, "sni_crt", &s2_sni_crt, "sni_ca", &s2_sni_ca, NULL)) {
if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=',
"server", &s2_server,
"key", &s2_key,
"socket", &s2_socket,
"addr", &s2_addr,
"weight", &s2_weight,
"modifier1", &s2_modifier1,
"modifier2", &s2_modifier2,
"sign", &s2_sign,
"check", &s2_check,
"sni_key", &s2_sni_key,
"sni_crt", &s2_sni_crt,
"sni_ca", &s2_sni_ca,
"proto", &s2_proto,
"algo", &s2_algo,
"backup", &s2_backup,
NULL)) {
return;
}
@@ -1027,8 +956,15 @@ void uwsgi_subscribe2(char *arg, uint8_t cmd) {
goto end;
}
int weight = 1;
int backup = 0;
if (uwsgi.auto_weight) weight = uwsgi.numproc * uwsgi.cores;
if (s2_weight) {
uwsgi.weight = atoi(s2_weight);
weight = atoi(s2_weight);
}
if (s2_backup) {
backup = atoi(s2_backup);
}
if (s2_socket) {
@@ -1052,7 +988,74 @@ void uwsgi_subscribe2(char *arg, uint8_t cmd) {
modifier2 = atoi(s2_modifier2);
}
uwsgi_send_subscription(s2_server, s2_key, strlen(s2_key), modifier1, modifier2, cmd, s2_addr, s2_sign, s2_sni_key, s2_sni_crt, s2_sni_ca);
if (s2_addr == NULL) {
// no socket... no subscription
if (!uwsgi.sockets) goto end;
s2_addr = uwsgi_str(uwsgi.sockets->name);
}
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
if (!ub) goto end;
// leave space for the header
ub->pos = 4;
if (uwsgi_buffer_append_keyval(ub, "key", 3, s2_key, strlen(s2_key)))
goto end;
if (uwsgi_buffer_append_keyval(ub, "address", 7, s2_addr, strlen(s2_addr)))
goto end;
if (uwsgi_buffer_append_keynum(ub, "modifier1", 9, modifier1))
goto end;
if (uwsgi_buffer_append_keynum(ub, "modifier2", 9, modifier2))
goto end;
if (uwsgi_buffer_append_keynum(ub, "cores", 5, uwsgi.numproc * uwsgi.cores))
goto end;
if (uwsgi_buffer_append_keynum(ub, "load", 4, uwsgi.shared->load))
goto end;
if (uwsgi_buffer_append_keynum(ub, "weight", 6, weight))
goto end;
if (uwsgi_buffer_append_keynum(ub, "backup", 6, backup))
goto end;
if (s2_sni_key) {
if (uwsgi_buffer_append_keyval(ub, "sni_key", 7, s2_sni_key, strlen(s2_sni_key)))
goto end;
}
if (s2_sni_crt) {
if (uwsgi_buffer_append_keyval(ub, "sni_crt", 7, s2_sni_crt, strlen(s2_sni_crt)))
goto end;
}
if (s2_sni_ca) {
if (uwsgi_buffer_append_keyval(ub, "sni_ca", 6, s2_sni_ca, strlen(s2_sni_ca)))
goto end;
}
if (s2_proto) {
if (uwsgi_buffer_append_keyval(ub, "proto", 5, s2_proto, strlen(s2_proto)))
goto end;
}
if (s2_algo) {
if (uwsgi_buffer_append_keyval(ub, "algo", 4, s2_algo, strlen(s2_algo)))
goto end;
}
if (uwsgi.subscription_notify_socket) {
if (uwsgi_buffer_append_keyval(ub, "notify", 6, uwsgi.subscription_notify_socket, strlen(uwsgi.subscription_notify_socket)))
goto end;
}
else if (uwsgi.notify_socket_fd > -1 && uwsgi.notify_socket) {
if (uwsgi_buffer_append_keyval(ub, "notify", 6, uwsgi.notify_socket, strlen(uwsgi.notify_socket)))
goto end;
}
if (uwsgi_subscription_ub_fix(ub, modifier1, modifier2, cmd, s2_sign)) goto end;
send_subscription(-1, s2_server, ub->buf, ub->pos);
uwsgi_buffer_destroy(ub);
end:
if (s2_server)
free(s2_server);
@@ -1078,6 +1081,12 @@ end:
free(s2_sni_key);
if (s2_sni_ca)
free(s2_sni_ca);
if (s2_proto)
free(s2_proto);
if (s2_algo)
free(s2_algo);
if (s2_backup)
free(s2_backup);
}
void uwsgi_subscribe_all(uint8_t cmd, int verbose) {
@@ -1105,3 +1114,241 @@ void uwsgi_subscribe_all(uint8_t cmd, int verbose) {
}
}
// iphash
static struct uwsgi_subscribe_node *uwsgi_subscription_algo_iphash(struct uwsgi_subscribe_slot *current_slot, struct uwsgi_subscribe_node *node, struct uwsgi_subscription_client *client) {
// if node is NULL we are in the second step (in lrc mode we do not use the first step)
if (node)
return NULL;
// iphash does not support requests without client data
if (!client) return NULL;
if (!client->sockaddr) return NULL;
uint64_t count = 0;
// first step is counting the number of nodes
node = current_slot->nodes;
while(node) {
if (!node->death_mark) count++;
node = node->next;
}
if (count == 0) return NULL;
uint64_t hash = 0;
//hash the ip
if (client->sockaddr->sa.sa_family == AF_INET) {
hash = client->sockaddr->sa_in.sin_addr.s_addr % count;
}
#ifdef AF_INET6
else if (client->sockaddr->sa.sa_family == AF_INET6) {
hash = djb33x_hash((char *)client->sockaddr->sa_in6.sin6_addr.s6_addr, 16) % count;
}
#endif
// now re-iterate until count matches;
count = 0;
struct uwsgi_subscribe_node *choosen_node = NULL;
node = current_slot->nodes;
while (node) {
if (!node->death_mark) {
if (count == hash) {
choosen_node = node;
break;
}
count++;
}
node = node->next;
}
if (choosen_node) {
choosen_node->reference++;
}
return choosen_node;
}
// least reference count
static struct uwsgi_subscribe_node *uwsgi_subscription_algo_lrc(struct uwsgi_subscribe_slot *current_slot, struct uwsgi_subscribe_node *node, struct uwsgi_subscription_client *client) {
uint64_t backup_level = 0;
uint64_t has_backup = 0;
// if node is NULL we are in the second step (in lrc mode we do not use the first step)
if (node)
return NULL;
struct uwsgi_subscribe_node *choosen_node = NULL;
retry:
node = current_slot->nodes;
uint64_t min_rc = 0;
while (node) {
if (!node->death_mark) {
if (node->backup_level == backup_level) {
if (min_rc == 0 || node->reference < min_rc) {
min_rc = node->reference;
choosen_node = node;
if (min_rc == 0 && !(node->next && node->next->reference <= node->reference && node->next->last_requests <= node->last_requests))
break;
}
}
else if (node->backup_level > backup_level && (!has_backup || has_backup > node->backup_level)) {
has_backup = node->backup_level;
}
}
node = node->next;
}
if (choosen_node) {
choosen_node->reference++;
}
else if (has_backup) {
backup_level = has_backup;
goto retry;
}
return choosen_node;
}
// weighted least reference count
static struct uwsgi_subscribe_node *uwsgi_subscription_algo_wlrc(struct uwsgi_subscribe_slot *current_slot, struct uwsgi_subscribe_node *node, struct uwsgi_subscription_client *client) {
uint64_t backup_level = 0;
uint64_t has_backup = 0;
// if node is NULL we are in the second step (in wlrc mode we do not use the first step)
if (node)
return NULL;
struct uwsgi_subscribe_node *choosen_node = NULL;
retry:
node = current_slot->nodes;
has_backup = 0;
double min_rc = 0;
while (node) {
if (!node->death_mark) {
if (node->backup_level == backup_level) {
// node->weight is always >= 1, we can safely use it as divider
double ref = (double) node->reference / (double) node->weight;
double next_node_ref = 0;
if (node->next)
next_node_ref = (double) node->next->reference / (double) node->next->weight;
if (min_rc == 0 || ref < min_rc) {
min_rc = ref;
choosen_node = node;
if (min_rc == 0 && !(node->next && next_node_ref <= ref && node->next->last_requests <= node->last_requests))
break;
}
}
else if (node->backup_level > backup_level && (!has_backup || has_backup > node->backup_level)) {
has_backup = node->backup_level;
}
}
node = node->next;
}
if (choosen_node) {
choosen_node->reference++;
}
else if (has_backup) {
backup_level = has_backup;
goto retry;
}
return choosen_node;
}
// weighted round robin algo (with backup support)
static struct uwsgi_subscribe_node *uwsgi_subscription_algo_wrr(struct uwsgi_subscribe_slot *current_slot, struct uwsgi_subscribe_node *node, struct uwsgi_subscription_client *client) {
uint64_t backup_level = 0;
uint64_t has_backup = 0;
// if node is NULL we are in the second step
if (node) {
if (node->death_mark == 0 && node->wrr > 0) {
node->wrr--;
node->reference++;
return node;
}
return NULL;
}
// no wrr > 0 node found, reset them
node = current_slot->nodes;
uint64_t min_weight = 0;
while (node) {
if (!node->death_mark) {
if (min_weight == 0 || node->weight < min_weight)
min_weight = node->weight;
}
node = node->next;
}
// now set wrr
retry:
node = current_slot->nodes;
has_backup = 0;
struct uwsgi_subscribe_node *choosen_node = NULL;
while (node) {
if (!node->death_mark) {
if (node->backup_level == backup_level) {
node->wrr = node->weight / min_weight;
choosen_node = node;
}
else if (node->backup_level > backup_level && (!has_backup || has_backup > node->backup_level)) {
has_backup = node->backup_level;
}
}
node = node->next;
}
if (choosen_node) {
choosen_node->wrr--;
choosen_node->reference++;
}
else if (has_backup) {
backup_level = has_backup;
goto retry;
}
return choosen_node;
}
void uwsgi_subscription_init_algos() {
uwsgi_register_subscription_algo("wrr", uwsgi_subscription_algo_wrr);
uwsgi_register_subscription_algo("lrc", uwsgi_subscription_algo_lrc);
uwsgi_register_subscription_algo("wlrc", uwsgi_subscription_algo_wlrc);
uwsgi_register_subscription_algo("iphash", uwsgi_subscription_algo_iphash);
}
void uwsgi_subscription_set_algo(char *algo) {
if (!uwsgi.subscription_algos) {
uwsgi_subscription_init_algos();
}
if (!algo)
goto wrr;
uwsgi.subscription_algo = uwsgi_subscription_algo_get(algo, strlen(algo));
if (uwsgi.subscription_algo) return ;
wrr:
uwsgi.subscription_algo = uwsgi_subscription_algo_wrr;
}
// we are lazy for subscription algos, we initialize them only if needed
struct uwsgi_subscribe_slot **uwsgi_subscription_init_ht() {
if (!uwsgi.subscription_algo) {
uwsgi_subscription_set_algo(NULL);
}
return uwsgi_calloc(sizeof(struct uwsgi_subscription_slot *) * UMAX16);
}
struct uwsgi_subscribe_node *(*uwsgi_subscription_algo_get(char *name , size_t len))(struct uwsgi_subscribe_slot *, struct uwsgi_subscribe_node *, struct uwsgi_subscription_client *) {
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.subscription_algos) {
if (!uwsgi_strncmp(usl->value, usl->len, name, len)) {
return (struct uwsgi_subscribe_node *(*)(struct uwsgi_subscribe_slot *, struct uwsgi_subscribe_node *, struct uwsgi_subscription_client *)) usl->custom_ptr;
}
}
return NULL;
}
void uwsgi_register_subscription_algo(char *name, struct uwsgi_subscribe_node *(*func)(struct uwsgi_subscribe_slot *, struct uwsgi_subscribe_node *, struct uwsgi_subscription_client *)) {
struct uwsgi_string_list *usl = uwsgi_string_new_list(&uwsgi.subscription_algos, name);
usl->custom_ptr = func;
}

View File

@@ -42,9 +42,9 @@ int check_hex(char *str, int len) {
}
// increase worker harakiri
void inc_harakiri(int sec) {
void inc_harakiri(struct wsgi_request *wsgi_req, int sec) {
if (uwsgi.master_process) {
uwsgi.workers[uwsgi.mywid].harakiri += sec;
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].harakiri += sec;
}
else {
alarm(uwsgi.harakiri_options.workers + sec);
@@ -52,12 +52,13 @@ void inc_harakiri(int sec) {
}
// set worker harakiri
void set_harakiri(int sec) {
void set_harakiri(struct wsgi_request *wsgi_req, int sec) {
if (!wsgi_req) return;
if (sec == 0) {
uwsgi.workers[uwsgi.mywid].harakiri = 0;
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].harakiri = 0;
}
else {
uwsgi.workers[uwsgi.mywid].harakiri = uwsgi_now() + sec;
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].harakiri = uwsgi_now() + sec;
}
if (!uwsgi.master_process) {
alarm(sec);
@@ -65,7 +66,7 @@ void set_harakiri(int sec) {
}
// set user harakiri
void set_user_harakiri(int sec) {
void set_user_harakiri(struct wsgi_request *wsgi_req, int sec) {
if (!uwsgi.master_process) {
uwsgi_log("!!! unable to set user harakiri without the master process !!!\n");
return;
@@ -79,8 +80,8 @@ void set_user_harakiri(int sec) {
struct uwsgi_spooler *uspool = uwsgi.i_am_a_spooler;
uspool->user_harakiri = 0;
}
else {
uwsgi.workers[uwsgi.mywid].user_harakiri = 0;
else if (wsgi_req) {
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].user_harakiri = 0;
}
}
else {
@@ -91,8 +92,8 @@ void set_user_harakiri(int sec) {
struct uwsgi_spooler *uspool = uwsgi.i_am_a_spooler;
uspool->user_harakiri = uwsgi_now() + sec;
}
else {
uwsgi.workers[uwsgi.mywid].user_harakiri = uwsgi_now() + sec;
else if (wsgi_req) {
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].user_harakiri = uwsgi_now() + sec;
}
}
}
@@ -699,6 +700,18 @@ void uwsgi_as_root() {
}
}
uwsgi_foreach(usl, uwsgi.wait_for_fs) {
if (uwsgi_wait_for_fs(usl->value, 0)) exit(1);
}
uwsgi_foreach(usl, uwsgi.wait_for_file) {
if (uwsgi_wait_for_fs(usl->value, 1)) exit(1);
}
uwsgi_foreach(usl, uwsgi.wait_for_dir) {
if (uwsgi_wait_for_fs(usl->value, 2)) exit(1);
}
uwsgi_hooks_run(uwsgi.hook_as_root, "as root", 1);
uwsgi_foreach(usl, uwsgi.mount_as_root) {
@@ -1105,13 +1118,13 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
}
// leave harakiri mode
if (uwsgi.workers[uwsgi.mywid].harakiri > 0) {
set_harakiri(0);
if (uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].harakiri > 0) {
set_harakiri(wsgi_req, 0);
}
// leave user harakiri mode
if (uwsgi.workers[uwsgi.mywid].user_harakiri > 0) {
set_user_harakiri(0);
if (uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].user_harakiri > 0) {
set_user_harakiri(wsgi_req, 0);
}
if (!wsgi_req->do_not_account) {
@@ -1177,7 +1190,7 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
// yes, this is pretty useless but we cannot ensure all of the plugin have the same behaviour
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 0;
if (uwsgi.max_requests > 0 && uwsgi.workers[uwsgi.mywid].delta_requests >= uwsgi.max_requests
if (uwsgi.max_requests > 0 && uwsgi.workers[uwsgi.mywid].delta_requests >= (uwsgi.max_requests + ((uwsgi.mywid-1) * uwsgi.max_requests_delta))
&& (end_of_request - (uwsgi.workers[uwsgi.mywid].last_spawn * 1000000) >= uwsgi.min_worker_lifetime * 1000000)) {
goodbye_cruel_world();
}
@@ -1368,7 +1381,7 @@ int wsgi_req_async_recv(struct wsgi_request *wsgi_req) {
// enter harakiri mode
if (uwsgi.harakiri_options.workers > 0) {
set_harakiri(uwsgi.harakiri_options.workers);
set_harakiri(wsgi_req, uwsgi.harakiri_options.workers);
}
return 0;
@@ -1400,7 +1413,7 @@ int wsgi_req_recv(int queue, struct wsgi_request *wsgi_req) {
// enter harakiri mode
if (uwsgi.harakiri_options.workers > 0) {
set_harakiri(uwsgi.harakiri_options.workers);
set_harakiri(wsgi_req, uwsgi.harakiri_options.workers);
}
#ifdef UWSGI_ROUTING
@@ -1521,7 +1534,7 @@ int wsgi_req_accept(int queue, struct wsgi_request *wsgi_req) {
thunder_unlock;
uwsgi_receive_signal(interesting_fd, "worker", uwsgi.mywid);
uwsgi_receive_signal(wsgi_req, interesting_fd, "worker", uwsgi.mywid);
if (uwsgi.threads > 1)
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &ret);
@@ -1772,9 +1785,15 @@ void *uwsgi_malloc(size_t size) {
}
void *uwsgi_calloc(size_t size) {
char *ptr = uwsgi_malloc(size);
memset(ptr, 0, size);
// thanks Mathieu Dupuy for pointing out that calloc is faster
// than malloc + memset
char *ptr = calloc(1, size);
if (ptr == NULL) {
uwsgi_error("calloc()");
uwsgi_log("!!! tried memory allocation of %llu bytes !!!\n", (unsigned long long) size);
uwsgi_backtrace(uwsgi.backtrace_depth);
exit(1);
}
return ptr;
}
@@ -1846,24 +1865,6 @@ void init_magic_table(char *magic_table[]) {
magic_table['('] = "%(";
}
char *uwsgi_get_last_char(char *what, char c) {
size_t len = strlen(what);
while (len--) {
if (what[len] == c)
return what + len;
}
return NULL;
}
char *uwsgi_get_last_charn(char *what, size_t len, char c) {
while (len--) {
if (what[len] == c)
return what + len;
}
return NULL;
}
char *uwsgi_num2str(int num) {
char *str = uwsgi_malloc(11);
@@ -1895,13 +1896,7 @@ int uwsgi_long2str2n(unsigned long long num, char *ptr, int size) {
}
int is_unix(char *socket_name, int len) {
int i;
for (i = 0; i < len; i++) {
if (socket_name[i] == ':')
return 0;
}
return 1;
return !memchr(socket_name, ':', len);
}
int is_a_number(char *what) {
@@ -2215,6 +2210,12 @@ void *uwsgi_malloc_shared(size_t size) {
void *uwsgi_calloc_shared(size_t size) {
void *ptr = uwsgi_malloc_shared(size);
// NOTE by Mathieu Dupuy:
// OSes guarantee mmap MAP_ANON memory area to be zero-filled (see man pages)
// we should trust it, but history has taught us it is better to be paranoid.
// Lucky enough this function is called ony in startup phases, so performance
// tips/tricks are irrelevant (So, le'ts call memset...)
memset(ptr, 0, size);
return ptr;
}
@@ -3108,6 +3109,8 @@ pid_t uwsgi_fork(char *name) {
#if defined(__linux__) || defined(__sun__)
int i;
for (i = 0; i < uwsgi.argc; i++) {
// stop fixing original argv if the new one is bigger
if (!uwsgi.orig_argv[i]) break;
strcpy(uwsgi.orig_argv[i], uwsgi.argv[i]);
}
#endif
@@ -4463,3 +4466,26 @@ mode_t uwsgi_mode_t(char *value, int *error) {
return mode;
}
// type -> 1 file, 2 dir, 0 both
int uwsgi_wait_for_fs(char *filename, int type) {
if (!uwsgi.wait_for_fs_timeout) {
uwsgi.wait_for_fs_timeout = 60;
}
uwsgi_log("waiting for %s (max %d seconds) ...\n", filename, uwsgi.wait_for_fs_timeout);
int counter = 0;
for (;;) {
if (counter > uwsgi.wait_for_fs_timeout) {
uwsgi_log("%s unavailable after %d seconds\n", filename, counter);
return -1;
}
struct stat st;
if (stat(filename, &st)) goto retry;
if (type == 1 && !S_ISREG(st.st_mode)) goto retry;
if (type == 2 && !S_ISDIR(st.st_mode)) goto retry;
uwsgi_log_verbose("%s found\n", filename);
return 0;
retry:
sleep(1);
counter++;
}
}

View File

@@ -228,11 +228,19 @@ static struct uwsgi_option uwsgi_base_options[] = {
#if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL)
{"emperor-use-clone", required_argument, 0, "use clone() instead of fork() passing the specified unshare() flags", uwsgi_opt_set_unshare, &uwsgi.emperor_clone, 0},
#endif
{"emperor-use-fork-server", required_argument, 0, "connect to the specified fork server instead of using plain fork() for new vassals", uwsgi_opt_set_str, &uwsgi.emperor_use_fork_server, 0},
{"vassal-fork-base", required_argument, 0, "use plain fork() for the specified vassal (instead of a fork-server)", uwsgi_opt_add_string_list, &uwsgi.vassal_fork_base, 0},
{"emperor-subreaper", no_argument, 0, "force the Emperor to be a sub-reaper (if supported)", uwsgi_opt_true, &uwsgi.emperor_subreaper, 0},
#ifdef UWSGI_CAP
{"emperor-cap", required_argument, 0, "set vassals capability", uwsgi_opt_set_emperor_cap, NULL, 0},
{"vassals-cap", required_argument, 0, "set vassals capability", uwsgi_opt_set_emperor_cap, NULL, 0},
{"vassal-cap", required_argument, 0, "set vassals capability", uwsgi_opt_set_emperor_cap, NULL, 0},
#endif
{"emperor-collect-attribute", required_argument, 0, "collect the specified vassal attribute from imperial monitors", uwsgi_opt_add_string_list, &uwsgi.emperor_collect_attributes, 0},
{"emperor-collect-attr", required_argument, 0, "collect the specified vassal attribute from imperial monitors", uwsgi_opt_add_string_list, &uwsgi.emperor_collect_attributes, 0},
{"emperor-fork-server-attr", required_argument, 0, "set teh vassal's attribute to get when checking for fork-server", uwsgi_opt_set_str, &uwsgi.emperor_fork_server_attr, 0},
{"emperor-wrapper-attr", required_argument, 0, "set the vassal's attribute to get when checking for fork-wrapper", uwsgi_opt_set_str, &uwsgi.emperor_wrapper_attr, 0},
{"emperor-chdir-attr", required_argument, 0, "set the vassal's attribute to get when checking for chdir", uwsgi_opt_set_str, &uwsgi.emperor_chdir_attr, 0},
{"imperial-monitor-list", no_argument, 0, "list enabled imperial monitors", uwsgi_opt_true, &uwsgi.imperial_monitor_list, 0},
{"imperial-monitors-list", no_argument, 0, "list enabled imperial monitors", uwsgi_opt_true, &uwsgi.imperial_monitor_list, 0},
{"vassals-inherit", required_argument, 0, "add config templates to vassals config (uses --inherit)", uwsgi_opt_add_string_list, &uwsgi.vassals_templates, 0},
@@ -262,6 +270,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"reaper", no_argument, 'r', "call waitpid(-1,...) after each request to get rid of zombies", uwsgi_opt_true, &uwsgi.reaper, 0},
{"max-requests", required_argument, 'R', "reload workers after the specified amount of managed requests", uwsgi_opt_set_64bit, &uwsgi.max_requests, 0},
{"max-requests-delta", required_argument, 0, "add (worker_id * delta) to the max_requests value of each worker", uwsgi_opt_set_64bit, &uwsgi.max_requests_delta, 0},
{"min-worker-lifetime", required_argument, 0, "number of seconds worker must run before being reloaded (default is 60)", uwsgi_opt_set_64bit, &uwsgi.min_worker_lifetime, 0},
{"max-worker-lifetime", required_argument, 0, "reload workers after the specified amount of seconds (default is disabled)", uwsgi_opt_set_64bit, &uwsgi.max_worker_lifetime, 0},
@@ -363,6 +372,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"setns-skip", required_argument, 0, "skip the specified entry when sending setns file descriptors", uwsgi_opt_add_string_list, &uwsgi.setns_socket_skip, 0},
{"setns", required_argument, 0, "join a namespace created by an external uWSGI instance", uwsgi_opt_set_str, &uwsgi.setns, 0},
{"setns-preopen", no_argument, 0, "open /proc/self/ns as soon as possible and cache fds", uwsgi_opt_true, &uwsgi.setns_preopen, 0},
{"fork-socket", required_argument, 0, "suspend the execution after early initialization and fork() at every unix socket connection", uwsgi_opt_set_str, &uwsgi.fork_socket, 0},
{"fork-server", required_argument, 0, "suspend the execution after early initialization and fork() at every unix socket connection", uwsgi_opt_set_str, &uwsgi.fork_socket, 0},
#endif
{"jailed", no_argument, 0, "mark the instance as jailed (force the execution of post_jail hooks)", uwsgi_opt_true, &uwsgi.jailed, 0},
#if defined(__FreeBSD__) || defined(__GNU_kFreeBSD__)
@@ -410,6 +421,13 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"hook-as-vassal", required_argument, 0, "run the specified hook before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.hook_as_vassal, 0},
{"hook-as-emperor", required_argument, 0, "run the specified hook in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.hook_as_emperor, 0},
{"hook-as-on-demand-vassal", required_argument, 0, "run the specified hook whenever a vassal enters on-demand mode", uwsgi_opt_add_string_list, &uwsgi.hook_as_on_demand_vassal, 0},
{"hook-as-emperor-before-vassal", required_argument, 0, "run the specified hook before the new vassal is spawned", uwsgi_opt_add_string_list, &uwsgi.hook_as_emperor_before_vassal, 0},
{"hook-as-vassal-before-drop", required_argument, 0, "run the specified hook into vassal, before dropping its privileges", uwsgi_opt_add_string_list, &uwsgi.hook_as_vassal_before_drop, 0},
{"hook-as-emperor-setns", required_argument, 0, "run the specified hook in the emperor entering vassal namespace", uwsgi_opt_add_string_list, &uwsgi.hook_as_emperor_setns, 0},
{"hook-as-mule", required_argument, 0, "run the specified hook in each mule", uwsgi_opt_add_string_list, &uwsgi.hook_as_mule, 0},
{"hook-as-gateway", required_argument, 0, "run the specified hook in each gateway", uwsgi_opt_add_string_list, &uwsgi.hook_as_gateway, 0},
@@ -460,6 +478,11 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"wait-iface", required_argument, 0, "wait for the specified network interface to come up before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_interface, 0},
{"wait-iface-timeout", required_argument, 0, "set the timeout for wait-for-interface", uwsgi_opt_set_int, &uwsgi.wait_for_interface_timeout, 0},
{"wait-for-fs", required_argument, 0, "wait for the specified filesystem item to appear before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_fs, 0},
{"wait-for-file", required_argument, 0, "wait for the specified file to appear before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_fs, 0},
{"wait-for-dir", required_argument, 0, "wait for the specified directory to appear before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_fs, 0},
{"wait-for-fs-timeout", required_argument, 0, "set the timeout for wait-for-fs/file/dir", uwsgi_opt_set_int, &uwsgi.wait_for_fs_timeout, 0},
{"call-asap", required_argument, 0, "call the specified function as soon as possible", uwsgi_opt_add_string_list, &uwsgi.call_asap, 0},
{"call-pre-jail", required_argument, 0, "call the specified function before jailing", uwsgi_opt_add_string_list, &uwsgi.call_pre_jail, 0},
{"call-post-jail", required_argument, 0, "call the specified function after jailing", uwsgi_opt_add_string_list, &uwsgi.call_post_jail, 0},
@@ -589,6 +612,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"notify-socket", required_argument, 0, "enable the notification socket", uwsgi_opt_set_str, &uwsgi.notify_socket, UWSGI_OPT_MASTER},
{"subscription-notify-socket", required_argument, 0, "set the notification socket for subscriptions", uwsgi_opt_set_str, &uwsgi.subscription_notify_socket, UWSGI_OPT_MASTER},
{"subscription-mountpoints", no_argument, 0, "enable mountpoints support for subscription system", uwsgi_opt_true, &uwsgi.subscription_mountpoints, UWSGI_OPT_MASTER},
{"subscription-mountpoint", no_argument, 0, "enable mountpoints support for subscription system", uwsgi_opt_true, &uwsgi.subscription_mountpoints, UWSGI_OPT_MASTER},
#ifdef UWSGI_SSL
{"legion", required_argument, 0, "became a member of a legion", uwsgi_opt_legion, NULL, UWSGI_OPT_MASTER},
@@ -903,6 +928,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"close-on-exec2", no_argument, 0, "set close-on-exec on server sockets (could be required for spawning processes in requests)", uwsgi_opt_true, &uwsgi.close_on_exec2, 0},
{"mode", required_argument, 0, "set uWSGI custom mode", uwsgi_opt_set_str, &uwsgi.mode, 0},
{"env", required_argument, 0, "set environment variable", uwsgi_opt_set_env, NULL, 0},
{"ienv", required_argument, 0, "set environment variable (IMMEDIATE version)", uwsgi_opt_set_env, NULL, UWSGI_OPT_IMMEDIATE},
{"envdir", required_argument, 0, "load a daemontools compatible envdir", uwsgi_opt_add_string_list, &uwsgi.envdirs, 0},
{"early-envdir", required_argument, 0, "load a daemontools compatible envdir ASAP", uwsgi_opt_envdir, NULL, UWSGI_OPT_IMMEDIATE},
{"unenv", required_argument, 0, "unset environment variable", uwsgi_opt_unset_env, NULL, 0},
@@ -1203,7 +1229,7 @@ void gracefully_kill(int signum) {
}
// still not found a way to gracefully reload in async mode
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
exit(UWSGI_RELOAD_CODE);
}
@@ -1449,7 +1475,7 @@ void what_i_am_doing() {
#else
ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, ctime_storage);
#endif
if (uwsgi.harakiri_options.workers > 0 && uwsgi.workers[uwsgi.mywid].harakiri < uwsgi_now()) {
if (uwsgi.harakiri_options.workers > 0 && uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].harakiri < uwsgi_now()) {
uwsgi_log("HARAKIRI: --- uWSGI worker %d core %d (pid: %d) WAS managing request %.*s since %.*s ---\n", (int) uwsgi.mywid, i, (int) uwsgi.mypid, wsgi_req->uri_len, wsgi_req->uri, 24, ctime_storage);
}
else {
@@ -1466,14 +1492,14 @@ void what_i_am_doing() {
#else
ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, ctime_storage);
#endif
if (uwsgi.harakiri_options.workers > 0 && uwsgi.workers[uwsgi.mywid].harakiri < uwsgi_now()) {
if (uwsgi.harakiri_options.workers > 0 && uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].harakiri < uwsgi_now()) {
uwsgi_log("HARAKIRI: --- uWSGI worker %d (pid: %d) WAS managing request %.*s since %.*s ---\n", (int) uwsgi.mywid, (int) uwsgi.mypid, wsgi_req->uri_len, wsgi_req->uri, 24, ctime_storage);
}
else {
uwsgi_log("SIGUSR2: --- uWSGI worker %d (pid: %d) is managing request %.*s since %.*s ---\n", (int) uwsgi.mywid, (int) uwsgi.mypid, wsgi_req->uri_len, wsgi_req->uri, 24, ctime_storage);
}
}
else if (uwsgi.harakiri_options.workers > 0 && uwsgi.workers[uwsgi.mywid].harakiri < uwsgi_now() && uwsgi.workers[uwsgi.mywid].sig) {
else if (uwsgi.harakiri_options.workers > 0 && uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].harakiri < uwsgi_now() && uwsgi.workers[uwsgi.mywid].sig) {
uwsgi_log("HARAKIRI: --- uWSGI worker %d (pid: %d) WAS handling signal %d ---\n", (int) uwsgi.mywid, (int) uwsgi.mypid, uwsgi.workers[uwsgi.mywid].signum);
}
}
@@ -1976,6 +2002,7 @@ static char *uwsgi_at_file_read(char *filename) {
}
void uwsgi_setup(int argc, char *argv[], char *envp[]) {
#ifdef UWSGI_AS_SHARED_LIBRARY
#ifdef __APPLE__
char ***envPtr = _NSGetEnviron();
@@ -2156,6 +2183,8 @@ void uwsgi_setup(int argc, char *argv[], char *envp[]) {
struct group *gr = getgrgid(getgid());
uwsgi.magic_table['G'] = gr ? gr->gr_name : uwsgi.magic_table['g'];
configure:
// you can embed a ini file in the uWSGi binary with default options
#ifdef UWSGI_EMBED_CONFIG
uwsgi_ini_config("", uwsgi.magic_table);
@@ -2180,6 +2209,14 @@ void uwsgi_setup(int argc, char *argv[], char *envp[]) {
// ok, the options dictionary is available, lets manage it
uwsgi_configure();
// stop the execution until a connection arrives on the fork socket
if (uwsgi.fork_socket) {
uwsgi_log_verbose("waiting for fork-socket connections...\n");
uwsgi_fork_server(uwsgi.fork_socket);
// if we are here a new process has been spawned
goto configure;
}
// fixup cwd
if (uwsgi.force_cwd) uwsgi.cwd = uwsgi.force_cwd;
@@ -2645,7 +2682,7 @@ int uwsgi_start(void *v_argv) {
}
}
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
if ((unsigned long) uwsgi.max_fd < (unsigned long) uwsgi.async) {
uwsgi_log_initial("- your current max open files limit is %lu, this is lower than requested async cores !!! -\n", (unsigned long) uwsgi.max_fd);
uwsgi.rl.rlim_cur = uwsgi.async;
@@ -2953,7 +2990,7 @@ unsafe:
uwsgi_log("*** Operational MODE: threaded ***\n");
}
}
else if (uwsgi.async > 1) {
else if (uwsgi.async > 0) {
if (uwsgi.numproc > 1) {
uwsgi_log("*** Operational MODE: preforking+async ***\n");
}
@@ -3321,7 +3358,7 @@ void uwsgi_worker_run() {
// some apps could be mounted only on specific workers
uwsgi_init_worker_mount_apps();
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
// a stack of unused cores
uwsgi.async_queue_unused = uwsgi_malloc(sizeof(struct wsgi_request *) * uwsgi.async);
@@ -3462,7 +3499,7 @@ void uwsgi_ignition() {
uwsgi_log("your loop engine died. R.I.P.\n");
}
else {
if (uwsgi.async < 2) {
if (uwsgi.async < 1) {
simple_loop();
}
else {

110
core/webdav.c Normal file
View File

@@ -0,0 +1,110 @@
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
/*
The following functions are useful to implement simil-webdav support in plugins.
Most of them are not fully webdav compliant, but will work on the vast majority of clients.
*/
// a multi-status response (207) will return an xml with a list
// of <D:response> stanzas
struct uwsgi_buffer *uwsgi_webdav_multistatus_new() {
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
if (uwsgi_buffer_append(ub, "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n", 40)) goto error;
if (uwsgi_buffer_append(ub, "<D:multistatus xmlns:D=\"DAV:\">\n", 31)) goto error;
return ub;
error:
uwsgi_buffer_destroy(ub);
return NULL;
}
int uwsgi_webdav_multistatus_close(struct uwsgi_buffer *ub) {
if (uwsgi_buffer_append(ub, "</D:multistatus>\n", 17)) return -1;
return 0;
}
int uwsgi_webdav_multistatus_response_new(struct uwsgi_buffer *ub) {
if (uwsgi_buffer_append(ub, "<D:response>\n", 13)) return -1;
return 0;
}
int uwsgi_webdav_multistatus_response_close(struct uwsgi_buffer *ub) {
if (uwsgi_buffer_append(ub, "</D:response>\n", 14)) return -1;
return 0;
}
int uwsgi_webdav_multistatus_propstat_new(struct uwsgi_buffer *ub) {
if (uwsgi_buffer_append(ub, "<D:propstat>\n", 13)) return -1;
return 0;
}
int uwsgi_webdav_multistatus_propstat_close(struct uwsgi_buffer *ub) {
if (uwsgi_buffer_append(ub, "</D:propstat>\n", 14)) return -1;
return 0;
}
int uwsgi_webdav_multistatus_prop_new(struct uwsgi_buffer *ub) {
if (uwsgi_buffer_append(ub, "<D:prop>\n", 9)) return -1;
return 0;
}
int uwsgi_webdav_multistatus_prop_close(struct uwsgi_buffer *ub) {
if (uwsgi_buffer_append(ub, "</D:prop>\n", 10)) return -1;
return 0;
}
// shortcut for adding a propfind-response item
int uwsgi_webdav_propfind_item_add(struct uwsgi_buffer *ub, char *href, uint16_t href_len, uint64_t cl, time_t mtime, char *ctype, uint16_t ctype_len, char *displayname, uint16_t displayname_len, char *etag, uint16_t etag_len) {
if (uwsgi_webdav_multistatus_response_new(ub)) return -1;
if (uwsgi_buffer_append(ub, "<D:href>", 8)) return -1;
if (uwsgi_buffer_append(ub, href, href_len)) return -1;
if (uwsgi_buffer_append(ub, "</D:href>\n", 10)) return -1;
if (uwsgi_webdav_multistatus_propstat_new(ub)) return -1;
if (uwsgi_webdav_multistatus_prop_new(ub)) return -1;
if (href[href_len-1] == '/') {
if (uwsgi_buffer_append(ub, "<D:resourcetype><D:collection/></D:resourcetype>\n", 49)) return -1;
}
else {
// getcontentlength
if (uwsgi_buffer_append(ub, "<D:getcontentlength>", 20)) return -1;
if (uwsgi_buffer_num64(ub, cl)) return -1;
if (uwsgi_buffer_append(ub, "</D:getcontentlength>\n", 22)) return -1;
}
// getlastmodified
if (mtime > 0) {
if (uwsgi_buffer_append(ub, "<D:getlastmodified>", 19)) return -1;
if (uwsgi_buffer_httpdate(ub, mtime)) return -1;
if (uwsgi_buffer_append(ub, "</D:getlastmodified>\n", 21)) return -1;
}
// displayname
if (displayname_len > 0) {
if (uwsgi_buffer_append(ub, "<D:displayname>\n", 16)) return -1;
if (uwsgi_buffer_append_xml(ub, displayname, displayname_len)) return -1;
if (uwsgi_buffer_append(ub, "</D:displayname>\n", 17)) return -1;
}
if (ctype_len > 0) {
if (uwsgi_buffer_append(ub, "<D:getcontenttype>", 18)) return -1;
if (uwsgi_buffer_append(ub, ctype, ctype_len)) return -1;
if (uwsgi_buffer_append(ub, "</D:getcontenttype>\n", 20)) return -1;
}
if (etag_len > 0) {
if (uwsgi_buffer_append(ub, "<D:getetag>\n", 12)) return -1;
if (uwsgi_buffer_append_xml(ub, displayname, displayname_len)) return -1;
if (uwsgi_buffer_append(ub, "</D:getetag>\n", 13)) return -1;
}
if (uwsgi_webdav_multistatus_prop_close(ub)) return -1;
if (uwsgi_webdav_multistatus_propstat_close(ub)) return -1;
if (uwsgi_webdav_multistatus_response_close(ub)) return -1;
return 0;
}

View File

@@ -205,7 +205,7 @@ static PyObject *py_uwsgi_asyncio_accept(PyObject *self, PyObject *args) {
// enter harakiri mode
if (uwsgi.harakiri_options.workers > 0) {
set_harakiri(uwsgi.harakiri_options.workers);
set_harakiri(wsgi_req, uwsgi.harakiri_options.workers);
}
uwsgi.async_proto_fd_table[wsgi_req->fd] = wsgi_req;
@@ -314,7 +314,7 @@ static void asyncio_loop() {
uwsgi.schedule_fix = uwsgi_asyncio_schedule_fix;
if (uwsgi.async < 2) {
if (uwsgi.async < 1) {
uwsgi_log("the asyncio loop engine requires async mode (--async <n>)\n");
exit(1);
}

View File

@@ -731,7 +731,7 @@ clear2:
// now wait for process exit/death
// in async mode we need a trick...
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
pid_t diedpid = waitpid(cgi_pid, &waitpid_status, WNOHANG);
if (diedpid < 0) {
uwsgi_error("waitpid()");

View File

@@ -110,6 +110,10 @@ void uwsgi_cr_peer_del(struct corerouter_peer *peer) {
if (peer->out && peer->out_need_free) {
uwsgi_buffer_destroy(peer->out);
}
if (peer->free_key) {
free(peer->key);
}
free(peer);
}
@@ -291,6 +295,16 @@ void corerouter_manage_subscription(char *key, uint16_t keylen, char *val, uint1
usr->notify = val;
usr->notify_len = vallen;
}
else if (!uwsgi_strncmp("algo", 4, key, keylen)) {
usr->algo = uwsgi_subscription_algo_get(val, vallen);
}
else if (!uwsgi_strncmp("backup", 6, key, keylen)) {
usr->backup_level = uwsgi_str_num(val, vallen);
}
else if (!uwsgi_strncmp("proto", 5, key, keylen)) {
usr->proto = val;
usr->proto_len = vallen;
}
}
void corerouter_close_peer(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) {
@@ -1051,6 +1065,7 @@ void corerouter_send_stats(struct uwsgi_corerouter *ucr) {
#ifdef UWSGI_SSL
if (uwsgi_stats_keylong_comma(us, "sni_enabled", (unsigned long long) s_slot->sni_enabled)) goto end0;
#endif
if (uwsgi_stats_keyval_comma(us, "algo", uwsgi_subscription_algo_name(s_slot->algo))) goto end0;
if (uwsgi_stats_key(us , "nodes")) goto end0;
if (uwsgi_stats_list_open(us)) goto end0;
@@ -1074,6 +1089,8 @@ void corerouter_send_stats(struct uwsgi_corerouter *ucr) {
if (uwsgi_stats_keylong_comma(us, "cores", (unsigned long long) s_node->cores)) goto end0;
if (uwsgi_stats_keylong_comma(us, "load", (unsigned long long) s_node->load)) goto end0;
if (uwsgi_stats_keylong_comma(us, "weight", (unsigned long long) s_node->weight)) goto end0;
if (uwsgi_stats_keylong_comma(us, "backup", (unsigned long long) s_node->backup_level)) goto end0;
if (uwsgi_stats_keyvaln_comma(us, "proto", &s_node->proto, 1)) goto end0;
if (uwsgi_stats_keylong_comma(us, "wrr", (unsigned long long) s_node->wrr)) goto end0;
if (uwsgi_stats_keylong_comma(us, "ref", (unsigned long long) s_node->reference)) goto end0;
if (uwsgi_stats_keylong_comma(us, "failcnt", (unsigned long long) s_node->failcnt)) goto end0;

View File

@@ -190,6 +190,11 @@ struct corerouter_peer {
struct corerouter_peer *next;
int current_timeout;
// maps 1:1 with subscription proto
char proto;
int free_key;
};
struct uwsgi_corerouter {

View File

@@ -48,11 +48,18 @@ int uwsgi_cr_map_use_pattern(struct uwsgi_corerouter *ucr, struct corerouter_pee
int uwsgi_cr_map_use_subscription(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) {
peer->un = uwsgi_get_subscribe_node(ucr->subscriptions, peer->key, peer->key_len);
struct uwsgi_subscription_client usc;
usc.fd = peer->session->main_peer->fd;
usc.sockaddr = &peer->session->client_sockaddr;
usc.cookie = NULL;
peer->un = uwsgi_get_subscribe_node(ucr->subscriptions, peer->key, peer->key_len, &usc);
if (peer->un && peer->un->len) {
peer->instance_address = peer->un->name;
peer->instance_address_len = peer->un->len;
peer->modifier1 = peer->un->modifier1;
peer->modifier2 = peer->un->modifier2;
peer->proto = peer->un->proto;
}
else if (ucr->cheap && !ucr->i_am_cheap && uwsgi_no_subscriptions(ucr->subscriptions)) {
uwsgi_gateway_go_cheap(ucr->name, ucr->queue, &ucr->i_am_cheap);
@@ -68,12 +75,17 @@ int uwsgi_cr_map_use_subscription_dotsplit(struct uwsgi_corerouter *ucr, struct
// max 5 split, reduce DOS attempts
int count = 5;
struct uwsgi_subscription_client usc;
usc.fd = peer->session->main_peer->fd;
usc.sockaddr = &peer->session->client_sockaddr;
usc.cookie = NULL;
split:
if (!count) return 0;
#ifdef UWSGI_DEBUG
uwsgi_log("trying with %.*s\n", name_len, name);
#endif
peer->un = uwsgi_get_subscribe_node(ucr->subscriptions, name, name_len);
peer->un = uwsgi_get_subscribe_node(ucr->subscriptions, name, name_len, &usc);
if (!peer->un) {
char *next = memchr(name+1, '.', name_len-1);
if (next) {
@@ -88,6 +100,8 @@ split:
peer->instance_address = peer->un->name;
peer->instance_address_len = peer->un->len;
peer->modifier1 = peer->un->modifier1;
peer->modifier2 = peer->un->modifier2;
peer->proto = peer->un->proto;
}
else if (ucr->cheap && !ucr->i_am_cheap && uwsgi_no_subscriptions(ucr->subscriptions)) {
uwsgi_gateway_go_cheap(ucr->name, ucr->queue, &ucr->i_am_cheap);

View File

@@ -187,7 +187,7 @@ end:
XS(XS_coroae_sighandler) {
int sigfd = (long) XSANY.any_ptr;
uwsgi_receive_signal(sigfd, "worker", uwsgi.mywid);
uwsgi_receive_signal(NULL, sigfd, "worker", uwsgi.mywid);
}
XS(XS_coroae_acceptor) {
@@ -227,7 +227,7 @@ edge:
// enter harakiri mode
if (uwsgi.harakiri_options.workers > 0) {
set_harakiri(uwsgi.harakiri_options.workers);
set_harakiri(wsgi_req, uwsgi.harakiri_options.workers);
}
@@ -356,7 +356,7 @@ static void coroae_wait_condvar(SV *cv) {
static void coroae_loop() {
if (uwsgi.async < 2) {
if (uwsgi.async < 1) {
if (uwsgi.mywid == 1) {
uwsgi_log("the Coro::AnyEvent loop engine requires async mode (--async <n>)\n");
}

View File

@@ -24,7 +24,14 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
try {
// requested fields
mongo::BSONObj p = BSON( "name" << 1 << "config" << 1 << "ts" << 1 << "uid" << 1 << "gid" << 1 << "socket" << 1 );
mongo::BSONObjBuilder builder;
builder.appendElements(BSON("name" << 1 << "config" << 1 << "ts" << 1 << "uid" << 1 << "gid" << 1 << "socket" << 1 ));
struct uwsgi_string_list *e_attrs = uwsgi.emperor_collect_attributes;
while(e_attrs) {
builder.appendElements(BSON(e_attrs->value << 1));
e_attrs = e_attrs->next;
}
mongo::BSONObj p = builder.obj();
mongo::BSONObj q = mongo::fromjson(uems->json);
// the connection object (will be automatically destroyed at each cycle)
mongo::DBClientConnection c;
@@ -76,7 +83,26 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
const char *socket_name = p.getStringField("socket");
if (strlen(socket_name) == 0) socket_name = NULL;
uwsgi_emperor_simple_do(ues, (char *) name, (char *) config, vassal_ts/1000, vassal_uid, vassal_gid, (char *) socket_name);
struct uwsgi_dyn_dict *attrs = NULL;
struct uwsgi_string_list *e_attrs = uwsgi.emperor_collect_attributes;
while(e_attrs) {
const char *attr_value = p.getStringField(e_attrs->value);
if (strlen(attr_value) == 0) attr_value = NULL;
if (attr_value) {
// the value memory is always reallocated
char *value = uwsgi_str((char *)attr_value);
uwsgi_dyn_dict_new(&attrs, e_attrs->value, e_attrs->len, value, strlen(value));
}
e_attrs = e_attrs->next;
}
if (attrs) {
// attrs will be freed in case of error
uwsgi_emperor_simple_do_with_attrs(ues, (char *) name, (char *) config, vassal_ts/1000, vassal_uid, vassal_gid, (char *) socket_name, attrs);
}
else {
uwsgi_emperor_simple_do(ues, (char *) name, (char *) config, vassal_ts/1000, vassal_uid, vassal_gid, (char *) socket_name);
}
}

View File

@@ -5,7 +5,7 @@ NAME='emperor_mongodb'
CFLAGS = ['-I/usr/include/mongo','-I/usr/local/include/mongo']
LDFLAGS = []
LIBS = []
LIBS = ['-lstdc++']
if not 'UWSGI_MONGODB_NOLIB' in os.environ:
LIBS.append('-lmongoclient')
LIBS.append('-lboost_thread')

View File

@@ -9,6 +9,7 @@
static struct uwsgi_fastrouter {
struct uwsgi_corerouter cr;
char *force_key;
} ufr;
extern struct uwsgi_server uwsgi;
@@ -56,7 +57,9 @@ static struct uwsgi_option fastrouter_options[] = {
{"fastrouter-buffer-size", required_argument, 0, "set internal buffer size (default: page size)", uwsgi_opt_set_64bit, &ufr.cr.buffer_size, 0},
{"fastrouter-fallback-on-no-key", no_argument, 0, "move to fallback node even if a subscription key is not found", uwsgi_opt_true, &ufr.cr.fallback_on_no_key, 0},
{0, 0, 0, 0, 0, 0, 0},
{"fastrouter-force-key", required_argument, 0, "skip uwsgi parsing and directly set a key", uwsgi_opt_set_str, &ufr.force_key, 0},
UWSGI_END_OF_OPTIONS
};
static void fr_get_hostname(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
@@ -213,9 +216,15 @@ static ssize_t fr_recv_uwsgi_vars(struct corerouter_peer *main_peer) {
struct corerouter_peer *new_peer = uwsgi_cr_peer_add(main_peer->session);
new_peer->last_hook_read = fr_instance_read;
// find the hostname
if (uwsgi_hooked_parse(main_peer->in->buf+4, pktsize, fr_get_hostname, (void *) new_peer)) {
return -1;
if (!ufr.force_key) {
// find the hostname
if (uwsgi_hooked_parse(main_peer->in->buf+4, pktsize, fr_get_hostname, (void *) new_peer)) {
return -1;
}
}
else {
new_peer->key = ufr.force_key;
new_peer->key_len = strlen(ufr.force_key);
}
// check the hostname;

View File

@@ -83,7 +83,7 @@ static int fiber_init() {
static void fiber_init_apps(void) {
if (!ufiber.enabled) return;
if (uwsgi.async <= 1) {
if (uwsgi.async < 1) {
uwsgi_log("the fiber loop engine requires async mode\n");
exit(1);
}

View File

@@ -342,7 +342,7 @@ static void uwsgi_gccgo_signal_goroutine(void *arg) {
for(;;) {
runtime_pollWait(pdesc, 'r');
retry:
uwsgi_receive_signal(*fd, "worker", uwsgi.mywid);
uwsgi_receive_signal(NULL, *fd, "worker", uwsgi.mywid);
if (uwsgi_is_again()) continue;
goto retry;
}
@@ -389,7 +389,7 @@ retry:
// enter harakiri mode
if (uwsgi.harakiri_options.workers > 0) {
set_harakiri(uwsgi.harakiri_options.workers);
set_harakiri(wsgi_req, uwsgi.harakiri_options.workers);
}
// spawn the new goroutine

View File

@@ -140,7 +140,7 @@ PyObject *py_uwsgi_gevent_signal_handler(PyObject * self, PyObject * args) {
return NULL;
}
uwsgi_receive_signal(signal_socket, "worker", uwsgi.mywid);
uwsgi_receive_signal(NULL, signal_socket, "worker", uwsgi.mywid);
Py_INCREF(Py_None);
return Py_None;
@@ -211,7 +211,7 @@ edge:
// enter harakiri mode
if (uwsgi.harakiri_options.workers > 0) {
set_harakiri(uwsgi.harakiri_options.workers);
set_harakiri(wsgi_req, uwsgi.harakiri_options.workers);
}
// hack to easily pass wsgi_req pointer to the greenlet
@@ -368,7 +368,7 @@ static void gevent_loop() {
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
if (uwsgi.async < 2) {
if (uwsgi.async < 1) {
uwsgi_log("the gevent loop engine requires async mode (--async <n>)\n");
exit(1);
}

View File

@@ -270,7 +270,7 @@ static int uwsgi_glusterfs_request(struct wsgi_request *wsgi_req) {
// skip body on HEAD
if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) {
size_t remains = st.st_size;
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
if (uwsgi_glusterfs_read_async(wsgi_req, fd, remains)) goto end;
}
else {

View File

@@ -116,7 +116,7 @@ static void greenlet_init_apps(void) {
if (!ugl.enabled) return;
if (uwsgi.async <= 1) {
if (uwsgi.async < 1) {
uwsgi_log("the greenlet suspend engine requires async mode\n");
exit(1);
}

View File

@@ -46,6 +46,8 @@ struct uwsgi_http {
int connect_timeout;
int manage_source;
int enable_proxy_protocol;
int proto_http;
};
struct http_session {
@@ -134,6 +136,10 @@ struct http_session {
ssize_t (*func_write)(struct corerouter_peer *);
char *proxy_src;
char *proxy_src_port;
uint16_t proxy_src_len;
uint16_t proxy_src_port_len;
};

View File

@@ -65,15 +65,126 @@ struct uwsgi_option http_options[] = {
{"http-manage-source", no_argument, 0, "manage the SOURCE HTTP method placing the session in raw mode", uwsgi_opt_true, &uhttp.manage_source, 0},
{"http-enable-proxy-protocol", optional_argument, 0, "manage PROXY protocol requests", uwsgi_opt_true, &uhttp.enable_proxy_protocol, 0},
{"http-backend-http", no_argument, 0, "use plain http protocol instead of uwsgi for backend nodes", uwsgi_opt_true, &uhttp.proto_http, 0},
{0, 0, 0, 0, 0, 0, 0},
};
static int rebuild_key_for_mountpoint(struct http_session *hr, struct corerouter_peer *peer) {
if (hr->request_uri_len == 0) return -1;
if (hr->request_uri[0] != '/') return -1;
uint16_t uri_len = hr->request_uri_len -1;
// find QUERY_STRING (if any)
char *qs = memchr(hr->request_uri+1, '?', uri_len);
if (qs) {
uri_len = (qs - hr->request_uri) - 1;
}
// is it / ?
if (uri_len == 0) return 0;
// now find the second slash occurrence (if any)
char *second_slash = memchr(hr->request_uri+1, '/', uri_len);
char *new_key = NULL;
uint16_t new_key_len = 0;
if (second_slash) {
new_key = uwsgi_concat2n(peer->key, peer->key_len, hr->request_uri, second_slash - hr->request_uri);
new_key_len = peer->key_len + (second_slash - hr->request_uri);
}
else {
new_key = uwsgi_concat2n(peer->key, peer->key_len, hr->request_uri, uri_len + 1);
new_key_len = peer->key_len + uri_len + 1;
}
peer->key = new_key;
peer->key_len = new_key_len;
peer->free_key = 1;
return 0;
}
static void http_set_timeout(struct corerouter_peer *peer, int timeout) {
if (peer->current_timeout == timeout) return;
peer->current_timeout = timeout;
peer->timeout = corerouter_reset_timeout(peer->session->corerouter, peer);
}
static int http_header_dumb_check(struct http_session *hr, struct corerouter_peer *peer, char *hh, size_t hhlen) {
size_t i;
char *val = hh;
int status = 0;
uint16_t keylen = 0;
uint16_t vallen = 0;
for (i = 0; i < hhlen; i++) {
if (!status) {
if (hh[i] == ':') {
status = 1;
keylen = i;
}
}
else if (status == 1 && hh[i] != ' ') {
status = 2;
val += i;
vallen+=1;
}
else if (status == 2) {
vallen+=1;
}
}
if (!keylen) return -1;
if (hr->websockets) {
if (!uwsgi_strnicmp("UPGRADE", 7, hh, keylen)) {
if (!uwsgi_strncmp(val, vallen, "websocket", 9)) {
hr->websockets++;
}
return 0;
}
else if (!uwsgi_strncmp("CONNECTION", 10, hh, keylen)) {
if (!uwsgi_strnicmp(val, vallen, "Upgrade", 7)) {
hr->websockets++;
}
return 0;
}
else if (!uwsgi_strnicmp("SEC-WEBSOCKET-VERSION", 21, hh, keylen)) {
hr->websockets++;
return 0;
}
else if (!uwsgi_strnicmp("SEC-WEBSOCKET-KEY", 17, hh, keylen)) {
hr->websocket_key = val;
hr->websocket_key_len = vallen;
return 0;
}
}
if (!uwsgi_strnicmp("CONTENT-LENGTH", 14, hh, keylen)) {
hr->content_length = uwsgi_str_num(val, vallen);
}
// in the future we could support chunked requests...
else if (!uwsgi_strnicmp("TRANSFER_ENCODING", 17, hh, keylen)) {
hr->session.can_keepalive = 0;
}
else if (!uwsgi_strnicmp("CONNECTION", 10, hh, keylen)) {
if (!uwsgi_strnicmp(val, vallen, "close", 5) || !uwsgi_strnicmp(val, vallen, "upgrade", 7)) {
hr->session.can_keepalive = 0;
}
}
else if (peer->key == uwsgi.hostname && hr->raw_body && !uwsgi_strnicmp("ICE-URL", 7, hh, keylen)) {
peer->key = val;
peer->key_len = vallen;
}
#ifdef UWSGI_ZLIB
else if (uhttp.auto_gzip && !uwsgi_strnicmp("ACCEPT-ENCODING", 15, hh, keylen)) {
if ( uwsgi_contains_n(val, vallen, "gzip", 4) ) {
hr->can_gzip = 1;
}
}
#endif
return 0;
}
static char * http_header_to_cgi(char *hh, size_t hhlen, size_t *keylen, size_t *vallen, int *has_prefix) {
size_t i;
char *val = hh;
@@ -138,8 +249,6 @@ static int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, size_t
}
if (!uwsgi_strncmp("HOST", 4, hh, keylen)) {
peer->key = val;
peer->key_len = vallen;
if (uhttp.server_name_as_http_host && uwsgi_buffer_append_keyval(out, "SERVER_NAME", 11, peer->key, peer->key_len)) return -1;
}
@@ -187,23 +296,258 @@ done:
return 0;
}
static int http_headers_parse_first_round(struct corerouter_peer *peer) {
struct http_session *hr = (struct http_session *) peer->session;
char *ptr = peer->session->main_peer->in->buf;
char *watermark = ptr + hr->headers_size;
char *base = ptr;
char *proxy_dst = NULL;
char *proxy_dst_port = NULL;
uint16_t proxy_dst_len = 0;
uint16_t proxy_dst_port_len = 0;
int http_headers_parse(struct corerouter_peer *peer) {
int skip = 0;
//struct uwsgi_buffer *out = peer->out;
int found = 0;
if (uwsgi.enable_proxy_protocol || uhttp.enable_proxy_protocol) {
ptr = proxy1_parse(ptr, watermark, &hr->proxy_src, &hr->proxy_src_len, &proxy_dst, &proxy_dst_len, &hr->proxy_src_port, &hr->proxy_src_port_len, &proxy_dst_port, &proxy_dst_port_len);
// how many bytes to skip ?
skip = ptr - base;
base = ptr;
}
// the following code is only a check for http compliance
// METHOD
while (ptr < watermark) {
if (*ptr == ' ') {
ptr++;
found = 1;
break;
}
else if (*ptr == '\r' || *ptr == '\n') break;
ptr++;
}
// ensure we have a method
if (!found) return -1;
// REQUEST_URI / PATH_INFO / QUERY_STRING
base = ptr;
found = 0;
while (ptr < watermark) {
if (*ptr == ' ') {
// if we want to allow sub-keys, we need to parse the first part of the REQUEST_URI
hr->request_uri = base;
hr->request_uri_len = ptr - base;
ptr++;
found = 1;
break;
}
ptr++;
}
// ensure we have a URI
if (!found) return -1;
// SERVER_PROTOCOL
base = ptr;
found = 0;
while (ptr < watermark) {
if (*ptr == '\r') {
if (ptr + 1 >= watermark)
return 0;
if (*(ptr + 1) != '\n')
return 0;
ptr += 2;
found = 1;
break;
}
ptr++;
}
// ensure we have a protocol
if (!found) return -1;
peer->key = uwsgi.hostname;
peer->key_len = uwsgi.hostname_len;
//HEADERS
base = ptr;
while (ptr < watermark) {
if (*ptr == '\r') {
if (ptr + 1 >= watermark)
break;
if (*(ptr + 1) != '\n')
break;
// multiline header ?
if (ptr + 2 < watermark) {
if (*(ptr + 2) == ' ' || *(ptr + 2) == '\t') {
ptr += 2;
continue;
}
}
if ((ptr - base) > 6 && !uwsgi_strnicmp("HOST: ", 6, base, 6)) {
peer->key = base + 6;
peer->key_len = (ptr - base) - 6;
}
// last line, do not waste time
if (ptr - base == 0) break;
ptr++;
base = ptr + 1;
}
ptr++;
}
return skip;
}
static int http_headers_parse_dumb(struct corerouter_peer *peer, int skip) {
struct http_session *hr = (struct http_session *) peer->session;
char *ptr = peer->session->main_peer->in->buf;
char *watermark = ptr + hr->headers_size;
char *base = ptr + skip;
// leave space for X-Forwarded-For and X-Forwarded-Proto: https
peer->out = uwsgi_buffer_new(hr->headers_size + 256);
// force this buffer to be destroyed as soon as possibile
peer->out_need_free = 1;
peer->out->limit = UMAX16;
peer->out_pos = 0;
//struct uwsgi_buffer *out = peer->out;
int found = 0;
// the following code is only a check for http compliance
// METHOD
while (ptr < watermark) {
if (*ptr == ' ') {
// on SOURCE METHOD, force raw body
if (uhttp.manage_source && !uwsgi_strncmp(base, ptr - base, "SOURCE", 6)) {
hr->raw_body = 1;
}
ptr++;
found = 1;
break;
}
else if (*ptr == '\r' || *ptr == '\n') break;
ptr++;
}
// ensure we have a method
if (!found) return -1;
// REQUEST_URI / PATH_INFO / QUERY_STRING
base = ptr;
found = 0;
while (ptr < watermark) {
if (*ptr == ' ') {
ptr++;
found = 1;
break;
}
ptr++;
}
// ensure we have a URI
if (!found) return -1;
// SERVER_PROTOCOL
base = ptr;
found = 0;
while (ptr < watermark) {
if (*ptr == '\r') {
if (ptr + 1 >= watermark)
return 0;
if (*(ptr + 1) != '\n')
return 0;
if (uhttp.keepalive && !uwsgi_strncmp("HTTP/1.1", 8, base, ptr-base)) {
hr->session.can_keepalive = 1;
}
ptr += 2;
found = 1;
break;
}
ptr++;
}
// ensure we have a protocol
if (!found) return -1;
//HEADERS
base = ptr;
while (ptr < watermark) {
if (*ptr == '\r') {
if (ptr + 1 >= watermark)
break;
if (*(ptr + 1) != '\n')
break;
// multiline header ?
if (ptr + 2 < watermark) {
if (*(ptr + 2) == ' ' || *(ptr + 2) == '\t') {
ptr += 2;
continue;
}
}
// this is an hack with dumb/wrong/useless error checking
if (uhttp.manage_expect) {
if (!uwsgi_strncmp("Expect: 100-continue", 20, base, ptr - base)) {
hr->send_expect_100 = 1;
}
}
// last line, do not waste time
if (ptr - base == 0) break;
if (http_header_dumb_check(hr, peer, base, ptr - base)) return -1;
ptr++;
base = ptr + 1;
}
ptr++;
}
struct uwsgi_buffer *out = peer->out;
if (uwsgi_buffer_append(out, peer->session->main_peer->in->buf, hr->headers_size-1)) return -1;
// X-Forwarded-For
if (uwsgi_buffer_append(out, "X-Forwarded-For: ", 17)) return -1;
if (hr->proxy_src) {
if (uwsgi_buffer_append(out, hr->proxy_src, hr->proxy_src_len)) return -1;
}
else {
if (uwsgi_buffer_append(out, peer->session->client_address, strlen(peer->session->client_address))) return -1;
}
if (uwsgi_buffer_append(out, "\r\n", 2)) return -1;
#ifdef UWSGI_SSL
if (hr->stud_prefix_pos > 0 || hr->session.ugs->mode == UWSGI_HTTP_SSL) {
if (uwsgi_buffer_append(out, "X-Forwarded-Proto: https\r\n", 26)) return -1;
}
#endif
if (uwsgi_buffer_append(out, "\r\n", 2)) return -1;
#ifdef UWSGI_SSL
if (hr->session.ugs->mode == UWSGI_HTTP_FORCE_SSL) {
hr->force_https = 1;
}
#endif
return 0;
}
int http_headers_parse(struct corerouter_peer *peer, int skip) {
struct http_session *hr = (struct http_session *) peer->session;
char *ptr = peer->session->main_peer->in->buf;
char *watermark = ptr + hr->headers_size;
char *base = ptr;
char *base = ptr + skip;
char *query_string = NULL;
char *proxy_src = NULL;
char *proxy_dst = NULL;
char *proxy_src_port = NULL;
char *proxy_dst_port = NULL;
uint16_t proxy_src_len = 0;
uint16_t proxy_dst_len = 0;
uint16_t proxy_src_port_len = 0;
uint16_t proxy_dst_port_len = 0;
peer->out = uwsgi_buffer_new(uwsgi.page_size);
// force this buffer to be destroyed as soon as possibile
@@ -216,11 +560,6 @@ int http_headers_parse(struct corerouter_peer *peer) {
struct uwsgi_buffer *out = peer->out;
int found = 0;
if (uwsgi.enable_proxy_protocol || uhttp.enable_proxy_protocol) {
ptr = proxy1_parse(ptr, watermark, &proxy_src, &proxy_src_len, &proxy_dst, &proxy_dst_len, &proxy_src_port, &proxy_src_port_len, &proxy_dst_port, &proxy_dst_port_len);
base = ptr;
}
// REQUEST_METHOD
while (ptr < watermark) {
if (*ptr == ' ') {
@@ -266,8 +605,6 @@ int http_headers_parse(struct corerouter_peer *peer) {
query_string = ptr + 1;
}
else if (*ptr == ' ') {
hr->request_uri = base;
hr->request_uri_len = ptr - base;
if (uwsgi_buffer_append_keyval(out, "REQUEST_URI", 11, base, ptr - base)) return -1;
if (!query_string) {
// PATH_INFO must be url-decoded !!!
@@ -333,8 +670,6 @@ int http_headers_parse(struct corerouter_peer *peer) {
// SERVER_NAME
if (!uhttp.server_name_as_http_host && uwsgi_buffer_append_keyval(out, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len)) return -1;
peer->key = uwsgi.hostname;
peer->key_len = uwsgi.hostname_len;
// SERVER_PORT
if (uwsgi_buffer_append_keyval(out, "SERVER_PORT", 11, hr->port, hr->port_len)) return -1;
@@ -352,10 +687,10 @@ int http_headers_parse(struct corerouter_peer *peer) {
#endif
// REMOTE_ADDR
if (proxy_src) {
if (uwsgi_buffer_append_keyval(out, "REMOTE_ADDR", 11, proxy_src, proxy_src_len)) return -1;
if (proxy_src_port) {
if (uwsgi_buffer_append_keyval(out, "REMOTE_PORT", 11, proxy_src_port, proxy_src_port_len)) return -1;
if (hr->proxy_src) {
if (uwsgi_buffer_append_keyval(out, "REMOTE_ADDR", 11, hr->proxy_src, hr->proxy_src_len)) return -1;
if (hr->proxy_src_port) {
if (uwsgi_buffer_append_keyval(out, "REMOTE_PORT", 11, hr->proxy_src_port, hr->proxy_src_port_len)) return -1;
}
}
else
@@ -788,8 +1123,8 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
// default hook
new_peer->last_hook_read = hr_instance_read;
// parse HTTP request
if (http_headers_parse(new_peer)) return -1;
int skip = http_headers_parse_first_round(new_peer);
if (skip < 0) return -1;
// check for a valid hostname
if (new_peer->key_len == 0) return -1;
@@ -800,6 +1135,9 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
break;
}
#endif
if (uwsgi.subscription_mountpoints) {
if (rebuild_key_for_mountpoint(hr, new_peer)) return -1;
}
// find an instance using the key
if (ucr->mapper(ucr, new_peer))
return -1;
@@ -808,13 +1146,20 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
if (new_peer->instance_address_len == 0)
return -1;
uint16_t pktsize = new_peer->out->pos-4;
// fix modifiers
new_peer->out->buf[0] = new_peer->session->main_peer->modifier1;
new_peer->out->buf[3] = new_peer->session->main_peer->modifier2;
// fix pktsize
new_peer->out->buf[1] = (uint8_t) (pktsize & 0xff);
new_peer->out->buf[2] = (uint8_t) ((pktsize >> 8) & 0xff);
// parse HTTP request
if (new_peer->proto != 'h' && !uhttp.proto_http) {
if (http_headers_parse(new_peer, skip)) return -1;
uint16_t pktsize = new_peer->out->pos-4;
// fix modifiers
new_peer->out->buf[0] = new_peer->session->main_peer->modifier1;
new_peer->out->buf[3] = new_peer->session->main_peer->modifier2;
// fix pktsize
new_peer->out->buf[1] = (uint8_t) (pktsize & 0xff);
new_peer->out->buf[2] = (uint8_t) ((pktsize >> 8) & 0xff);
}
else {
if (http_headers_parse_dumb(new_peer, skip)) return -1;
}
if (hr->remains > 0) {
if (hr->content_length < hr->remains) {
@@ -969,6 +1314,7 @@ int http_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket
if (uhttp.websockets) {
hr->websockets = 1;
}
hr->func_write = hr_write;
// be sure buffer does not grow over 64k

View File

@@ -843,7 +843,7 @@ static int uwsgi_lua_request(struct wsgi_request *wsgi_req) {
}
lua_pop(L, 1);
lua_pushvalue(L, -1);
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
return UWSGI_AGAIN;
}
}

View File

@@ -7,7 +7,7 @@ LIBS = os.popen('pkg-config --libs mono-2').read().rstrip().split()
GCC_LIST = ['mono_plugin']
if os.uname()[0] == 'Darwin':
LIBS.append('-framework Foundation')
LIBS.append('-framework Foundation')
def post_build(config):
if os.system("sn -k plugins/mono/uwsgi.key") != 0:

View File

@@ -4,6 +4,8 @@ extern struct uwsgi_server uwsgi;
static sapi_module_struct uwsgi_sapi_module;
static int uwsgi_php_init(void);
struct uwsgi_php {
struct uwsgi_string_list *allowed_docroot;
struct uwsgi_string_list *allowed_ext;
@@ -28,6 +30,8 @@ struct uwsgi_php {
struct uwsgi_string_list *exec_after;
char *sapi_name;
int sapi_initialized;
} uphp;
void uwsgi_opt_php_ini(char *opt, char *value, void *foobar) {
@@ -35,6 +39,10 @@ void uwsgi_opt_php_ini(char *opt, char *value, void *foobar) {
uwsgi_sapi_module.php_ini_ignore = 1;
}
void uwsgi_opt_early_php(char *opt, char *value, void *foobar) {
uwsgi_php_init();
}
struct uwsgi_option uwsgi_php_options[] = {
{"php-ini", required_argument, 0, "set php.ini path", uwsgi_opt_php_ini, NULL, 0},
@@ -61,6 +69,9 @@ struct uwsgi_option uwsgi_php_options[] = {
{"php-exec-after", required_argument, 0, "run specified php code after the requested script", uwsgi_opt_add_string_list, &uphp.exec_after, 0},
{"php-exec-end", required_argument, 0, "run specified php code after the requested script", uwsgi_opt_add_string_list, &uphp.exec_after, 0},
{"php-sapi-name", required_argument, 0, "hack the sapi name (required for enabling zend opcode cache)", uwsgi_opt_set_str, &uphp.sapi_name, 0},
{"early-php", no_argument, 0, "initialize an early perl interpreter shared by all loaders", uwsgi_opt_early_php, NULL, UWSGI_OPT_IMMEDIATE},
{"early-php-sapi-name", required_argument, 0, "hack the sapi name (required for enabling zend opcode cache)", uwsgi_opt_set_str, &uphp.sapi_name, UWSGI_OPT_IMMEDIATE},
UWSGI_END_OF_OPTIONS
};
@@ -554,12 +565,15 @@ static sapi_module_struct uwsgi_sapi_module = {
STANDARD_SAPI_MODULE_PROPERTIES
};
int uwsgi_php_init(void) {
static int uwsgi_php_init(void) {
struct uwsgi_string_list *pset = uphp.set;
struct uwsgi_string_list *append_config = uphp.append_config;
sapi_startup(&uwsgi_sapi_module);
if (!uphp.sapi_initialized) {
sapi_startup(&uwsgi_sapi_module);
uphp.sapi_initialized = 1;
}
// applying custom options
while(append_config) {
@@ -590,6 +604,7 @@ int uwsgi_php_init(void) {
if (uphp.sapi_name) {
uwsgi_sapi_module.name = uphp.sapi_name;
}
uwsgi_sapi_module.startup(&uwsgi_sapi_module);
uwsgi_log("PHP %s initialized\n", PHP_VERSION);

View File

@@ -67,6 +67,11 @@ struct uwsgi_perl {
CV *spooler;
int no_plack;
SV **early_psgi_callable;
char *early_psgi_app_name;
PerlInterpreter *early_interpreter;
};
void init_perl_embedded_module(void);
@@ -87,3 +92,5 @@ void uwsgi_perl_exec(char *);
void uwsgi_perl_check_auto_reload(void);
void uwsgi_psgi_preinit_apps(void);
int uwsgi_perl_add_app(struct wsgi_request *, char *, PerlInterpreter **, SV **, time_t);

View File

@@ -337,11 +337,13 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
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);
if (!uperl.early_interpreter) {
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++) {
@@ -369,7 +371,7 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
// our xs_init hook, but we're *not* calling it with
// uperl.embedding as an argument so we won't execute
// BEGIN blocks in app_name twice.
{
if (!uperl.early_interpreter) {
char *perl_e_arg = uwsgi_concat2("#line 0 ", app_name);
char *perl_init_arg[] = { "", "-e", perl_e_arg };
if (perl_parse(interpreters[i], xs_init, 3, perl_init_arg, NULL)) {
@@ -453,46 +455,19 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
PERL_SET_CONTEXT(interpreters[0]);
}
// is it an early loading ?
if (!uwsgi.workers) {
uperl.early_psgi_app_name = app_name;
uperl.early_psgi_callable = callables;
return 0;
}
if (uwsgi_apps_cnt >= uwsgi.max_apps) {
uwsgi_log("ERROR: you cannot load more than %d apps in a worker\n", uwsgi.max_apps);
goto clear;
}
int id = uwsgi_apps_cnt;
struct uwsgi_app *wi = NULL;
if (wsgi_req) {
// we need a copy of app_id
wi = uwsgi_add_app(id, psgi_plugin.modifier1, uwsgi_concat2n(wsgi_req->appid, wsgi_req->appid_len, "", 0), wsgi_req->appid_len, interpreters, callables);
}
else {
wi = uwsgi_add_app(id, psgi_plugin.modifier1, "", 0, interpreters, callables);
}
wi->started_at = now;
wi->startup_time = uwsgi_now() - now;
uwsgi_log("PSGI app %d (%s) loaded in %d seconds at %p (interpreter %p)\n", id, app_name, (int) wi->startup_time, callables[0], interpreters[0]);
free(app_name);
// copy global data to app-specific areas
wi->stream = uperl.tmp_streaming_stash;
wi->input = uperl.tmp_input_stash;
wi->error = uperl.tmp_error_stash;
wi->responder0 = uperl.tmp_stream_responder;
wi->responder1 = uperl.tmp_psgix_logger;
uwsgi_emulate_cow_for_apps(id);
// restore context if required
if (interpreters != uperl.main) {
PERL_SET_CONTEXT(uperl.main[0]);
}
uperl.loaded = 1;
return id;
return uwsgi_perl_add_app(wsgi_req, app_name, interpreters, callables, now);
clear:
if (interpreters != uperl.main) {
@@ -509,6 +484,44 @@ clear2:
return -1;
}
int uwsgi_perl_add_app(struct wsgi_request *wsgi_req, char *app_name, PerlInterpreter **interpreters, SV **callables, time_t now) {
int id = uwsgi_apps_cnt;
struct uwsgi_app *wi = NULL;
if (wsgi_req) {
// we need a copy of app_id
wi = uwsgi_add_app(id, psgi_plugin.modifier1, uwsgi_concat2n(wsgi_req->appid, wsgi_req->appid_len, "", 0), wsgi_req->appid_len, interpreters, callables);
}
else {
wi = uwsgi_add_app(id, psgi_plugin.modifier1, "", 0, interpreters, callables);
}
wi->started_at = now;
wi->startup_time = uwsgi_now() - now;
uwsgi_log("PSGI app %d (%s) loaded in %d seconds at %p (interpreter %p)\n", id, app_name, (int) wi->startup_time, callables[0], interpreters[0]);
free(app_name);
// copy global data to app-specific areas
wi->stream = uperl.tmp_streaming_stash;
wi->input = uperl.tmp_input_stash;
wi->error = uperl.tmp_error_stash;
wi->responder0 = uperl.tmp_stream_responder;
wi->responder1 = uperl.tmp_psgix_logger;
uwsgi_emulate_cow_for_apps(id);
// restore context if required
if (interpreters != uperl.main) {
PERL_SET_CONTEXT(uperl.main[0]);
}
uperl.loaded = 1;
return id;
}
void uwsgi_psgi_preinit_apps() {
if (uperl.exec) {
PERL_SET_CONTEXT(uperl.main[0]);
@@ -524,6 +537,10 @@ void uwsgi_psgi_preinit_apps() {
void uwsgi_psgi_app() {
if (uperl.early_psgi_callable) {
uwsgi_perl_add_app(NULL, uperl.early_psgi_app_name, uperl.main, uperl.early_psgi_callable, uwsgi_now());
}
if (uperl.psgi) {
//load app in the main interpreter list
init_psgi_app(NULL, uperl.psgi, strlen(uperl.psgi), uperl.main);

View File

@@ -26,6 +26,45 @@ static void uwsgi_opt_plshell(char *opt, char *value, void *foobar) {
}
}
EXTERN_C void xs_init (pTHX);
int uwsgi_perl_init(void);
static void uwsgi_opt_early_perl(char *opt, char *value, void *foobar) {
// avoid duplicates
if (uperl.early_interpreter) return;
uwsgi_perl_init();
uperl.early_interpreter = uperl.main[0];
// HACK the following allocations ensure correct xs initialization
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);
char *perl_e_arg = uwsgi_concat2("#line 0 ", value);
char *perl_init_arg[] = { "", "-e", perl_e_arg };
perl_parse(uperl.early_interpreter, xs_init, 3, perl_init_arg, NULL);
free(perl_e_arg);
}
static void uwsgi_opt_early_psgi(char *opt, char *value, void *foobar) {
uwsgi_perl_init();
init_psgi_app(NULL, value, strlen(value), uperl.main);
if (!uperl.early_psgi_callable) exit(1);
}
static void uwsgi_opt_early_exec(char *opt, char *value, void *foobar) {
uwsgi_perl_init();
if (!uperl.early_interpreter) {
perl_parse(uperl.main[0], xs_init, 3, uperl.embedding, NULL);
}
SV *dollar_zero = get_sv("0", GV_ADD);
sv_setsv(dollar_zero, newSVpv(value, strlen(value)));
uwsgi_perl_exec(value);
}
struct uwsgi_option uwsgi_perl_options[] = {
{"psgi", required_argument, 0, "load a psgi app", uwsgi_opt_set_str, &uperl.psgi, 0},
@@ -46,6 +85,9 @@ struct uwsgi_option uwsgi_perl_options[] = {
{"plshell-oneshot", no_argument, 0, "run a perl interactive shell (one shot)", uwsgi_opt_plshell, NULL, 0},
{"perl-no-plack", no_argument, 0, "force the use of do instead of Plack::Util::load_psgi", uwsgi_opt_true, &uperl.no_plack, 0},
{"early-perl", required_argument, 0, "initialize an early perl interpreter shared by all loaders", uwsgi_opt_early_perl, NULL, UWSGI_OPT_IMMEDIATE},
{"early-psgi", required_argument, 0, "load a psgi app soon after uWSGI initialization", uwsgi_opt_early_psgi, NULL, UWSGI_OPT_IMMEDIATE},
{"early-perl-exec", required_argument, 0, "load a perl script soon after uWSGI initialization", uwsgi_opt_early_exec, NULL, UWSGI_OPT_IMMEDIATE},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -363,7 +405,7 @@ SV *build_psgi_env(struct wsgi_request *wsgi_req) {
if (!hv_store(env, "psgi.run_once", 13, newSViv(0), 0)) goto clear;
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
if (!hv_store(env, "psgi.nonblocking", 16, newSViv(1), 0)) goto clear;
}
else {
@@ -437,6 +479,10 @@ int uwsgi_perl_init(){
int argc;
int i;
if (uperl.main) {
goto already_initialized;
}
uperl.embedding[0] = "";
uperl.embedding[1] = "-e";
uperl.embedding[2] = "0";
@@ -477,6 +523,7 @@ int uwsgi_perl_init(){
PERL_SET_CONTEXT(uperl.main[0]);
already_initialized:
#ifdef PERL_VERSION_STRING
uwsgi_log_initial("initialized Perl %s main interpreter at %p\n", PERL_VERSION_STRING, uperl.main[0]);
#else
@@ -584,7 +631,7 @@ int uwsgi_perl_request(struct wsgi_request *wsgi_req) {
}
while (psgi_response(wsgi_req, wsgi_req->async_result) != UWSGI_OK) {
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
FREETMPS;
LEAVE;
return UWSGI_AGAIN;
@@ -814,7 +861,7 @@ static void uwsgi_perl_atexit() {
return;
// managing atexit in async mode is a real pain...skip it for now
if (uwsgi.async > 1)
if (uwsgi.async > 0)
return;
realstuff:
@@ -945,7 +992,15 @@ static int uwsgi_perl_spooler(char *filename, char *buf, uint16_t len, char *bod
return ret;
}
static int uwsgi_perl_hook_perl(char *arg) {
SV *ret = perl_eval_pv(arg, 0);
if (!ret) return -1;
return 0;
}
static void uwsgi_perl_register_features() {
uwsgi_register_hook("perl", uwsgi_perl_hook_perl);
}
struct uwsgi_plugin psgi_plugin = {
@@ -976,4 +1031,5 @@ struct uwsgi_plugin psgi_plugin = {
.magic = uwsgi_perl_magic,
.spooler = uwsgi_perl_spooler,
.on_load = uwsgi_perl_register_features,
};

View File

@@ -148,7 +148,7 @@ int psgi_response(struct wsgi_request *wsgi_req, AV *response) {
chitem = SvPV( chunk, hlen);
if (hlen <= 0) {
SvREFCNT_dec(chunk);
if (uwsgi.async > 1 && wsgi_req->async_force_again) {
if (uwsgi.async > 0 && wsgi_req->async_force_again) {
wsgi_req->async_placeholder = (SV *) *hitem;
return UWSGI_AGAIN;
}
@@ -161,7 +161,7 @@ int psgi_response(struct wsgi_request *wsgi_req, AV *response) {
break;
}
SvREFCNT_dec(chunk);
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
wsgi_req->async_placeholder = (SV *) *hitem;
wsgi_req->async_force_again = 1;
return UWSGI_AGAIN;

View File

@@ -86,9 +86,11 @@ XS(XS_signal) {
XS(XS_set_user_harakiri) {
dXSARGS;
struct wsgi_request *wsgi_req = current_wsgi_req();
psgi_check_args(1);
set_user_harakiri( SvIV(ST(0)) );
set_user_harakiri(wsgi_req, SvIV(ST(0)) );
XSRETURN_UNDEF;
}
@@ -430,10 +432,10 @@ XS(XS_signal_wait) {
wsgi_req->signal_received = -1;
if (items > 0) {
received_signal = uwsgi_signal_wait(SvIV(ST(0)));
received_signal = uwsgi_signal_wait(wsgi_req, SvIV(ST(0)));
}
else {
received_signal = uwsgi_signal_wait(-1);
received_signal = uwsgi_signal_wait(wsgi_req, -1);
}
if (received_signal < 0) {

View File

@@ -237,7 +237,7 @@ void uwsgi_disconnect(struct wsgi_request *);
int uwsgi_ready_fd(struct wsgi_request *);
void set_user_harakiri(int);
void set_user_harakiri(struct wsgi_request *, int);
int uwsgi_metric_set(char *, char *, int64_t);
int uwsgi_metric_inc(char *, char *, int64_t);
@@ -918,7 +918,10 @@ uwsgi.chunked_read_nb = uwsgi_pypy_chunked_read_nb
"""
uwsgi.set_user_harakiri(sec)
"""
uwsgi.set_user_harakiri = lambda x: lib.set_user_harakiri(x)
def uwsgi_pypy_set_user_harakiri(x):
wsgi_req = uwsgi_pypy_current_wsgi_req()
lib.set_user_harakiri(wsgi_req, x)
uwsgi.set_user_harakiri = uwsgi_pypy_set_user_harakiri
print "Initialized PyPy with Python", sys.version
@@ -977,7 +980,7 @@ def uwsgi_pypy_continulet_switch(wsgi_req):
lib.uwsgi.wsgi_req = wsgi_req
def uwsgi_pypy_setup_continulets():
if lib.uwsgi.async <= 1:
if lib.uwsgi.async < 1:
raise Exception("pypy continulets require async mode !!!")
lib.uwsgi.schedule_to_main = uwsgi_pypy_continulet_switch
lib.uwsgi.schedule_to_req = uwsgi_pypy_continulet_schedule

View File

@@ -255,7 +255,7 @@ int uwsgi_response_subhandler_pump(struct wsgi_request *wsgi_req) {
goto clear;
}
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
return UWSGI_AGAIN;
}

View File

@@ -63,6 +63,29 @@ void uwsgi_opt_pyver(char *opt, char *foo, void *bar) {
exit(0);
}
int uwsgi_python_init(void);
void uwsgi_python_preinit_apps(void);
static void uwsgi_early_python(char *opt, char *foo, void *bar) {
static int early_initialized = 0;
if (early_initialized) return;
early_initialized = 1;
uwsgi_python_init();
uwsgi_python_preinit_apps();
}
static void uwsgi_early_python_import(char *opt, char *module, void *bar) {
uwsgi_early_python(opt, NULL, NULL);
if (strchr(module, '/') || uwsgi_endswith(module, ".py")) {
uwsgi_pyimport_by_filename(uwsgi_pythonize(module), module);
}
else {
if (PyImport_ImportModule(module) == NULL) {
PyErr_Print();
}
}
}
void uwsgi_opt_ini_paste(char *opt, char *value, void *foobar) {
@@ -170,6 +193,12 @@ struct uwsgi_option uwsgi_python_options[] = {
{"py-call-osafterfork", no_argument, 0, "enable child processes running cpython to trap OS signals", uwsgi_opt_true, &up.call_osafterfork, 0},
{"early-python", no_argument, 0, "load the python VM as soon as possible (useful for the fork server)", uwsgi_early_python, NULL, UWSGI_OPT_IMMEDIATE},
{"early-pyimport", required_argument, 0, "import a python module in the early phase", uwsgi_early_python_import, NULL, UWSGI_OPT_IMMEDIATE},
{"early-python-import", required_argument, 0, "import a python module in the early phase", uwsgi_early_python_import, NULL, UWSGI_OPT_IMMEDIATE},
{"early-pythonpath", required_argument, 0, "add directory (or glob) to pythonpath (immediate version)", uwsgi_opt_pythonpath, NULL, UWSGI_OPT_IMMEDIATE},
{"early-python-path", required_argument, 0, "add directory (or glob) to pythonpath (immediate version)", uwsgi_opt_pythonpath, NULL, UWSGI_OPT_IMMEDIATE},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -332,7 +361,7 @@ void uwsgi_python_atexit() {
return;
// managing atexit in async mode is a real pain...skip it for now
if (uwsgi.async > 1)
if (uwsgi.async > 0)
return;
realstuff:
@@ -1041,6 +1070,10 @@ void uwsgi_python_destroy_env_holy(struct wsgi_request *wsgi_req) {
// this hook will be executed by master (or worker1 when master is not requested, so COW is in place)
void uwsgi_python_preinit_apps() {
struct uwsgi_string_list *upli = up.shared_import_list;
if (up.pre_initialized) goto ready;
up.pre_initialized = 1;
init_pyargv();
@@ -1072,8 +1105,9 @@ void uwsgi_python_preinit_apps() {
init_uwsgi_vars();
ready:
// load shared imports
struct uwsgi_string_list *upli = up.shared_import_list;
while(upli) {
if (strchr(upli->value, '/') || uwsgi_endswith(upli->value, ".py")) {
uwsgi_pyimport_by_filename(uwsgi_pythonize(upli->value), upli->value);
@@ -1096,7 +1130,7 @@ void uwsgi_python_init_apps() {
}
// prepare for stack suspend/resume
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
up.current_recursion_depth = uwsgi_malloc(sizeof(int)*uwsgi.async);
up.current_frame = uwsgi_malloc(sizeof(struct _frame)*uwsgi.async);
}

View File

@@ -289,7 +289,7 @@ int uwsgi_python_call(struct wsgi_request *wsgi_req, PyObject *callable, PyObjec
if (wsgi_req->async_result) {
while ( manage_python_response(wsgi_req) != UWSGI_OK) {
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
return UWSGI_AGAIN;
}
}

View File

@@ -71,7 +71,7 @@ int uwsgi_request_python_raw(struct wsgi_request *wsgi_req) {
int ret = manage_raw_response(wsgi_req);
if (ret == UWSGI_AGAIN) {
wsgi_req->async_force_again = 1;
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
UWSGI_RELEASE_GIL return UWSGI_AGAIN;
}
continue;

View File

@@ -46,10 +46,10 @@ static PyObject *py_uwsgi_signal_wait(PyObject * self, PyObject * args) {
UWSGI_RELEASE_GIL;
if (wait_for_specific_signal) {
received_signal = uwsgi_signal_wait(uwsgi_signal);
received_signal = uwsgi_signal_wait(wsgi_req, uwsgi_signal);
}
else {
received_signal = uwsgi_signal_wait(-1);
received_signal = uwsgi_signal_wait(wsgi_req, -1);
}
if (received_signal < 0) {
@@ -893,12 +893,13 @@ PyObject *py_uwsgi_log(PyObject * self, PyObject * args) {
}
PyObject *py_uwsgi_set_user_harakiri(PyObject * self, PyObject * args) {
struct wsgi_request *wsgi_req = py_current_wsgi_req();
int sec = 0;
if (!PyArg_ParseTuple(args, "i:set_user_harakiri", &sec)) {
return NULL;
}
set_user_harakiri(sec);
set_user_harakiri(wsgi_req, sec);
Py_INCREF(Py_None);
return Py_None;
@@ -1654,7 +1655,6 @@ PyObject *py_uwsgi_sharedarea_read64(PyObject * self, PyObject * args) {
}
return PyLong_FromLongLong(value);
}
PyObject *py_uwsgi_sharedarea_read32(PyObject * self, PyObject * args) {

View File

@@ -199,6 +199,7 @@ struct uwsgi_python {
struct uwsgi_string_list *sharedarea;
int call_osafterfork;
int pre_initialized;
};

View File

@@ -164,7 +164,7 @@ int uwsgi_response_subhandler_web3(struct wsgi_request *wsgi_req) {
if (!wsgi_req->async_placeholder) {
goto clear;
}
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
return UWSGI_AGAIN;
}
}

View File

@@ -405,7 +405,7 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
while (wi->response_subhandler(wsgi_req) != UWSGI_OK) {
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
UWSGI_RELEASE_GIL
wsgi_req->async_force_again = 1;
return UWSGI_AGAIN;
@@ -442,8 +442,8 @@ void uwsgi_after_request_wsgi(struct wsgi_request *wsgi_req) {
if (up.after_req_hook) {
if (uwsgi.harakiri_no_arh) {
// leave harakiri mode
if (uwsgi.workers[uwsgi.mywid].harakiri > 0)
set_harakiri(0);
if (uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].harakiri > 0)
set_harakiri(wsgi_req, 0);
}
UWSGI_GET_GIL
PyObject *arh = python_call(up.after_req_hook, up.after_req_hook_args, 0, NULL);

View File

@@ -170,7 +170,7 @@ void *uwsgi_request_subhandler_wsgi(struct wsgi_request *wsgi_req, struct uwsgi_
PyDict_SetItemString(wsgi_req->async_environ, "wsgi.file_wrapper", wi->sendfile);
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
PyDict_SetItemString(wsgi_req->async_environ, "x-wsgiorg.fdevent.readable", wi->eventfd_read);
PyDict_SetItemString(wsgi_req->async_environ, "x-wsgiorg.fdevent.writable", wi->eventfd_write);
PyDict_SetItemString(wsgi_req->async_environ, "x-wsgiorg.fdevent.timeout", Py_None);
@@ -269,7 +269,7 @@ int uwsgi_response_subhandler_wsgi(struct wsgi_request *wsgi_req) {
if (!wsgi_req->async_placeholder) {
goto exception;
}
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
return UWSGI_AGAIN;
}
}

View File

@@ -1,75 +1,325 @@
#include "../python/uwsgi_python.h"
//FIXME: [upstream:python] needs PyAPI_FUNC(void)
extern void Py_GetArgcArgv(int *, char ***);
extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
extern char **environ;
PyObject *u_run(PyObject *self, PyObject *args) {
static int new_argc = -1;
static int orig_argc = -1;
static char **new_argv = NULL;
static char **orig_argv = NULL;
static char *new_argv_buf = NULL;
char **argv;
size_t size = 2;
int i;
if (PyTuple_Size(args) < 1) {
return PyErr_Format(PyExc_ValueError, "you have to specify at least one uWSGI option to run() it");
}
PyObject *
pyuwsgi_setup(PyObject *self, PyObject *args, PyObject *kwds)
{
if (new_argv) {
PyErr_SetString(
PyExc_RuntimeError,
"uWSGI already setup"
);
return NULL;
}
PyObject *the_arg = PyTuple_GetItem(args, 0);
if (uwsgi.mywid) {
PyErr_SetString(
PyExc_RuntimeError,
"uWSGI must be setup by master"
);
return NULL;
}
if (PyList_Check(the_arg)) {
size = PyList_Size(the_arg) + 2;
}
else if (PyTuple_Check(the_arg)) {
size = PyTuple_Size(the_arg) + 2;
}
else if (PyString_Check(the_arg)) {
size = 3;
}
PyObject *iterator;
argv = uwsgi_malloc(sizeof(char *) * size);
memset(argv, 0, sizeof(char *) * size);
if (args == NULL || PyObject_Size(args) == 0) {
PyObject *argv = PySys_GetObject("argv");
if (argv == NULL)
return NULL;
// will be overwritten
argv[0] = "uwsgi";
// during site.py maybe
if (argv == Py_None) {
argv = PyTuple_New(0);
iterator = PyObject_GetIter(argv);
Py_DECREF(argv);
}
else {
iterator = PyObject_GetIter(argv);
if (PyObject_Size(argv) > 0) {
// forward past argv0
PyObject *item = PyIter_Next(iterator);
Py_DECREF(item);
}
}
}
else if (
PyObject_Size(args) == 1
&& !PyString_Check(PyTuple_GetItem(args, 0))
) {
iterator = PyObject_GetIter(PyTuple_GetItem(args, 0));
}
else {
iterator = PyObject_GetIter(args);
}
if (PyList_Check(the_arg)) {
for(i=0;i<PyList_Size(the_arg);i++) {
argv[i+1] = PyString_AsString( PyList_GetItem(the_arg, i) );
}
}
else if (PyTuple_Check(the_arg)) {
for(i=0;i<PyTuple_Size(the_arg);i++) {
argv[i+1] = PyString_AsString( PyTuple_GetItem(the_arg, i) );
}
}
else if (PyString_Check(the_arg)) {
argv[1] = PyString_AsString( the_arg );
}
if (iterator == NULL) {
return NULL;
}
uwsgi_init(size-1, argv, environ);
size_t size = 1;
//FIXME: ARGS prior to and including -c/-m are REQUIRED!
PyObject *item = PyString_FromString(orig_argv[0]);
PyObject *args_li = PyList_New(0);
PyList_Append(args_li, item);
size += strlen(orig_argv[0]) + 1;
Py_DECREF(item);
Py_INCREF(Py_None);
return Py_None;
while ((item = PyIter_Next(iterator))) {
//TODO: call str(...) on everything
PyList_Append(args_li, item);
size += PyObject_Length(item) + 1;
Py_DECREF(item);
}
Py_DECREF(iterator);
new_argc = PyObject_Length(args_li);
new_argv = uwsgi_calloc(sizeof(char *) * (new_argc + 1));
new_argv_buf = uwsgi_calloc(size);
int i = 0;
char *new_argv_ptr = new_argv_buf;
for(i=0; i < new_argc; i++) {
PyObject *arg = PyList_GetItem(args_li, i);
char *arg_str = PyString_AsString(arg);
new_argv[i] = new_argv_ptr;
strcpy(new_argv_ptr, arg_str);
new_argv_ptr += strlen(arg_str) + 1;
}
PyObject *args_tup = PyList_AsTuple(args_li);
PyObject_SetAttrString(self, "NEW_ARGV", args_tup);
Py_DECREF(args_tup);
Py_DECREF(args_li);
// TODO: convention here is a goto methinks?
if (PyErr_Occurred()) {
free(new_argv_buf);
free(new_argv);
new_argv = 0;
new_argc = 0;
return NULL;
}
//TODO: ...???
// actually do the thing!
PyThreadState *_tstate = PyThreadState_Get();
uwsgi_setup(orig_argc, orig_argv, environ);
PyThreadState_Swap(_tstate);
Py_INCREF(self);
return self;
}
PyObject *
pyuwsgi_init(PyObject *self, PyObject *args, PyObject *kwds)
{
if (pyuwsgi_setup(self, args, kwds) == NULL) {
return NULL;
}
int rc = uwsgi_run();
// never(?) here
return Py_BuildValue("i", rc);
}
PyObject *
pyuwsgi_run(PyObject *self, PyObject *args, PyObject *kwds)
{
// backcompat
if (new_argv == NULL &&
pyuwsgi_setup(self, args, kwds) == NULL) {
return NULL;
}
int rc = uwsgi_run();
// never(?) here
return Py_BuildValue("i", rc);
}
PyMethodDef methods[] = {
{"run", u_run, METH_VARARGS, "run the uWSGI server"},
{"run",
(PyCFunction) pyuwsgi_run,
METH_VARARGS | METH_KEYWORDS,
"run(...)"
"\n>>> 0"
"\n"
"\n * Call setup(...) if not configured"
"\n * Begin uWSGI mainloop"
"\n NOTE: will not return"
"\n"
},
{"init",
(PyCFunction) pyuwsgi_init,
METH_VARARGS | METH_KEYWORDS,
"init(...)"
"\n>>> 0"
"\n"
"\n * Call setup(...)"
"\n * Begin uWSGI mainloop"
"\n NOTE: will not return"
"\n"
},
{"setup",
(PyCFunction) pyuwsgi_setup,
METH_VARARGS | METH_KEYWORDS,
"setup('--master', ...)"
"\n>>> <module 'uwsgi' from \"uwsgi.so\">"
"\n"
"\n * Initialize uWSGI core with (...)"
"\n MUST only call once [RuntimeException]"
"\n MUST only call from master [RuntimeException]"
"\n"
},
{NULL, NULL, 0, NULL}
};
static void
pyuwsgi_set_orig_argv(PyObject *self)
{
// ask python for the original argc/argv saved in Py_Main()
Py_GetArgcArgv(&orig_argc, &orig_argv);
// [re?]export to uwsgi.orig_argv
PyObject *m_orig_argv;
m_orig_argv = PyTuple_New(orig_argc);
int i = 0;
int i_cm = -1;
for(i=0; i < orig_argc; i++) {
char *arg = orig_argv[i];
//XXX: _PyOS_optarg != 0 also indicates python quit early...
//FIXME: [upstream:python] orig_argv could be mangled; reset
// rel: http://bugs.python.org/issue8202
orig_argv[i + 1] = arg + strlen(arg) + 1;
// look for -c or -m and record the offset
if (i_cm < 0) {
if (strcmp(arg, "-c") || strcmp(arg, "-m")) {
// python's getopt would've failed had + 1 not exist
i_cm = i + 1;
}
else if (!uwsgi_startswith(arg, "-c", 2) ||
!uwsgi_startswith(arg, "-m", 2)) {
//FIXME: ARGS prior to and including -c/-m are REQUIRED,
// but NOT a part of the uWSGI argv! Needed to make
// exec*() self-referential: exec*(...) -> uwsgi
//
// want: uwsgi.binary_argv[:] + uwsgi.argv[:]!
// binary_argv = [binary_path] + args
i_cm = i;
}
}
PyTuple_SetItem(m_orig_argv, i, PyString_FromString(arg));
}
//TODO: howto properly detect uwsgi already running...
// orig_argv == uwsgi.orig_argv (?)
// ^^^ but if Py_Main not called, python/main.c:orig_argv unset
// howto interact/detect things in general
PyObject *m_new_argv = PyTuple_New(0);
PyObject_SetAttrString(self, "NEW_ARGV", m_new_argv);
PyObject_SetAttrString(self, "ORIG_ARGV", m_orig_argv);
Py_DECREF(m_new_argv);
Py_DECREF(m_orig_argv);
}
static PyObject *
pyuwsgi_init_as(char *mod_name)
{
PyObject *m;
m = PyImport_GetModuleDict();
if (m == NULL) {
return NULL;
}
m = PyDict_GetItemString(m, mod_name);
if (!m) {
m = Py_InitModule(mod_name, NULL);
}
if (orig_argc < 0) {
pyuwsgi_set_orig_argv(m);
}
int i;
for (i=0; methods[i].ml_name != NULL; i++) {
PyObject *fun = PyObject_GetAttrString(m, methods[i].ml_name);
if (fun != NULL) {
// already exists
Py_DECREF(fun);
continue;
}
PyErr_Clear();
// rel: Python/modsupport.c:Py_InitModule4
PyObject* name = PyString_FromString(methods[i].ml_name);
// fun(self, ...)
fun = PyCFunction_NewEx(&methods[i], m, name);
Py_DECREF(name);
// module.fun
PyObject_SetAttrString(m, methods[i].ml_name, fun);
Py_DECREF(fun);
}
return m;
}
PyMODINIT_FUNC
initpyuwsgi()
{
(void) Py_InitModule("pyuwsgi", methods);
(void) pyuwsgi_init_as("pyuwsgi");
}
int pyuwsgi_init() { return 0; }
// allow the module to be called `uwsgi`
PyMODINIT_FUNC
inituwsgi()
{
(void) pyuwsgi_init_as("uwsgi");
}
void pyuwsgi_load()
{
if (new_argc > -1) {
uwsgi.new_argc = new_argc;
uwsgi.new_argv = new_argv;
}
}
struct uwsgi_plugin pyuwsgi_plugin = {
.name = "pyuwsgi",
.init = pyuwsgi_init,
.on_load = pyuwsgi_load,
};

View File

@@ -110,7 +110,8 @@ static VALUE rack_uwsgi_warning(VALUE *class, VALUE rbmessage) {
static VALUE rack_uwsgi_user_harakiri(VALUE *class, VALUE sec) {
Check_Type(sec, T_FIXNUM);
set_user_harakiri(NUM2INT(sec));
struct wsgi_request *wsgi_req = current_wsgi_req();
set_user_harakiri(wsgi_req, NUM2INT(sec));
return Qnil;
}
@@ -765,10 +766,10 @@ static VALUE uwsgi_ruby_signal_wait(int argc, VALUE *argv, VALUE *class) {
}
if (wait_for_specific_signal) {
received_signal = uwsgi_signal_wait(uwsgi_signal);
received_signal = uwsgi_signal_wait(wsgi_req, uwsgi_signal);
}
else {
received_signal = uwsgi_signal_wait(-1);
received_signal = uwsgi_signal_wait(wsgi_req, -1);
}
if (received_signal < 0) {

View File

@@ -46,6 +46,7 @@ struct uwsgi_rados_mountpoint {
char *allow_put;
char *allow_delete;
char *allow_mkcol;
char *allow_propfind;
};
static struct uwsgi_option uwsgi_rados_options[] = {
@@ -89,7 +90,7 @@ static void uwsgi_rados_read_async_cb(rados_completion_t comp, void *data) {
}
static int uwsgi_rados_delete(struct wsgi_request *wsgi_req, rados_ioctx_t ctx, char *key, int timeout) {
if (uwsgi.async <= 1) {
if (uwsgi.async < 1) {
return rados_remove(ctx, key);
}
struct uwsgi_rados_io *urio = &urados.urio[wsgi_req->async_id];
@@ -133,7 +134,6 @@ static int uwsgi_rados_delete(struct wsgi_request *wsgi_req, rados_ioctx_t ctx,
ret = rados_aio_get_return_value(comp);
}
rados_aio_release(comp);
end:
return ret;
}
@@ -146,7 +146,7 @@ static int uwsgi_rados_put(struct wsgi_request *wsgi_req, rados_ioctx_t ctx, cha
ssize_t body_len = 0;
char *body = uwsgi_request_body_read(wsgi_req, UMIN(remains, 32768) , &body_len);
if (!body || body == uwsgi.empty) goto error;
if (uwsgi.async <= 1) {
if (uwsgi.async < 1) {
if (rados_write(ctx, key, body, body_len, off) < 0) {
return -1;
}
@@ -313,6 +313,86 @@ static int uwsgi_rados_read_async(struct wsgi_request *wsgi_req, rados_ioctx_t c
return ret;
}
static void uwsgi_rados_propfind(struct wsgi_request *wsgi_req, rados_ioctx_t ctx, char *key, uint64_t size, time_t mtime, int timeout) {
// consume the body
size_t remains = wsgi_req->post_cl;
while(remains > 0) {
ssize_t body_len = 0;
char *body = uwsgi_request_body_read(wsgi_req, UMIN(remains, 32768), &body_len);
if (!body || body == uwsgi.empty) break;
remains -= body_len;
}
if (uwsgi_response_prepare_headers(wsgi_req, "207 Multi-Status", 16)) return;
if (uwsgi_response_add_content_type(wsgi_req, "text/xml; charset=\"utf-8\"", 25)) return;
struct uwsgi_buffer *ub = uwsgi_webdav_multistatus_new();
if (!ub) return;
if (key) {
size_t mime_type_len = 0;
char *mime_type = uwsgi_get_mime_type(key, strlen(key), &mime_type_len);
char *slashed = uwsgi_concat2("/", key);
if (uwsgi_webdav_propfind_item_add(ub, slashed, strlen(key)+1, size, mtime, mime_type, mime_type_len, NULL, 0, NULL, 0)) {
free(slashed);
goto end;
}
free(slashed);
if (uwsgi_webdav_multistatus_close(ub)) goto end;
uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
goto end;
}
// request for /
size_t depth = 0;
uint16_t http_depth_len = 0;
char *http_depth = uwsgi_get_var(wsgi_req, "HTTP_DEPTH", 10, &http_depth_len);
if (http_depth) {
depth = uwsgi_str_num(http_depth, http_depth_len);
}
if (depth == 0) {
if (uwsgi_webdav_propfind_item_add(ub, "/", 1, 0, 0, NULL, 0, NULL, 0, NULL, 0)) {
goto end;
}
if (uwsgi_webdav_multistatus_close(ub)) goto end;
uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
goto end;
}
struct uwsgi_rados_io *urio = &urados.urio[wsgi_req->async_id];
rados_list_ctx_t ctx_list;
if (rados_objects_list_open(ctx, &ctx_list) < 0) {
goto end;
}
char *entry = NULL;
while(rados_objects_list_next(ctx_list, (const char **)&entry, NULL) == 0) {
uint64_t stat_size = 0;
time_t stat_mtime = 0;
if (uwsgi.async > 0) {
if (uwsgi_rados_async_stat(urio, ctx, entry, &stat_size, &stat_mtime, timeout) < 0) goto end;
}
else {
if (rados_stat(ctx, entry, &stat_size, &stat_mtime) < 0) goto end;
}
size_t mime_type_len = 0;
char *mime_type = uwsgi_get_mime_type(entry, strlen(entry), &mime_type_len);
char *slashed = uwsgi_concat2("/", entry);
if (uwsgi_webdav_propfind_item_add(ub, slashed, strlen(entry)+1, stat_size, stat_mtime, mime_type, mime_type_len, NULL, 0, NULL, 0)) {
free(slashed);
goto end;
}
free(slashed);
if (uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos)) goto end;
// reset buffer;
ub->pos = 0;
}
rados_objects_list_close(ctx_list);
if (uwsgi_webdav_multistatus_close(ub)) goto end;
uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
end:
uwsgi_buffer_destroy(ub);
}
static void uwsgi_rados_add_mountpoint(char *arg, size_t arg_len) {
struct uwsgi_rados_mountpoint *urmp = uwsgi_calloc(sizeof(struct uwsgi_rados_mountpoint));
@@ -324,6 +404,7 @@ static void uwsgi_rados_add_mountpoint(char *arg, size_t arg_len) {
"allow_put", &urmp->allow_put,
"allow_delete", &urmp->allow_delete,
"allow_mkcol", &urmp->allow_mkcol,
"allow_propfind", &urmp->allow_propfind,
NULL)) {
uwsgi_log("unable to parse rados mountpoint definition\n");
exit(1);
@@ -431,7 +512,7 @@ static void uwsgi_rados_setup() {
}
// now initialize a pthread_mutex for each async core
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
int i;
urados.urio = uwsgi_calloc(sizeof(struct uwsgi_rados_io) * uwsgi.async);
for(i=0;i<uwsgi.async;i++) {
@@ -502,7 +583,7 @@ static int uwsgi_rados_request(struct wsgi_request *wsgi_req) {
struct uwsgi_rados_io *urio = &urados.urio[wsgi_req->async_id];
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
// no need to lock here (the rid protect us)
if (pipe(urio->fds)) {
uwsgi_error("uwsgi_rados_read_async()/pipe()");
@@ -540,12 +621,28 @@ static int uwsgi_rados_request(struct wsgi_request *wsgi_req) {
goto end;
}
}
if (urmp->allow_propfind) {
if (uwsgi_buffer_append(ub_allow, ", PROPFIND", 10)) {
uwsgi_buffer_destroy(ub_allow);
goto end;
}
}
uwsgi_response_add_header(wsgi_req, "Allow", 5, ub_allow->buf, ub_allow->pos);
uwsgi_buffer_destroy(ub_allow);
goto end;
}
// empty paths are mapped to propfind
if (wsgi_req->path_info_len == 1 && wsgi_req->path_info[0] == '/') {
if (urmp->allow_propfind && !uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PROPFIND", 8)) {
uwsgi_rados_propfind(wsgi_req, ctx, NULL, 0, 0, timeout);
goto end;
}
uwsgi_405(wsgi_req);
goto end;
}
// MKCOL does not require stat
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "MKCOL", 5)) {
if (!urmp->allow_mkcol) {
@@ -566,7 +663,7 @@ static int uwsgi_rados_request(struct wsgi_request *wsgi_req) {
goto end;
}
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
ret = uwsgi_rados_async_stat(urio, ctx, filename, &stat_size, &stat_mtime, timeout);
}
else {
@@ -613,6 +710,15 @@ static int uwsgi_rados_request(struct wsgi_request *wsgi_req) {
goto end;
}
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PROPFIND", 8)) {
if (!urmp->allow_propfind) {
uwsgi_405(wsgi_req);
goto end;
}
uwsgi_rados_propfind(wsgi_req, ctx, filename, stat_size, stat_mtime, timeout);
goto end;
}
if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4) && uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "GET", 3)) {
uwsgi_405(wsgi_req);
goto end;
@@ -631,7 +737,7 @@ static int uwsgi_rados_request(struct wsgi_request *wsgi_req) {
// skip body on HEAD
if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) {
size_t remains = stat_size;
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
if (uwsgi_rados_read_async(wsgi_req, ctx, filename, remains, timeout)) goto end;
}
else {
@@ -640,7 +746,7 @@ static int uwsgi_rados_request(struct wsgi_request *wsgi_req) {
}
end:
if (uwsgi.async > 1) {
if (uwsgi.async > 0) {
close(urio->fds[0]);
close(urio->fds[1]);
}

View File

@@ -279,6 +279,38 @@ sendbody:
}
#ifdef UWSGI_ROUTING
static int uwsgi_rpc_apply_translations(struct wsgi_request *wsgi_req, struct uwsgi_route *ur, struct uwsgi_buffer **ubs, uint64_t *ubs_len, char **argv, uint16_t *argvs) {
uint64_t i;
char **r_argv = (char **) ur->data2;
uint16_t *r_argvs = (uint16_t *) ur->data3;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
for(i=0;i<ur->custom;i++) {
ubs[i] = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, r_argv[i], r_argvs[i]);
if (!ubs[i]) {
*ubs_len = i;
return 0;
}
argv[i] = ubs[i]->buf;
argvs[i] = ubs[i]->pos;
}
*ubs_len = i;
return 1;
}
static char *uwsgi_rpc_get_remote(char *func) {
char *remote = NULL;
char *at = strchr(func, '@');
if (at) {
*at = 0;
remote = at+1;
}
return remote;
}
static int uwsgi_routing_func_rpc(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
int ret = -1;
// this is the list of args
@@ -288,28 +320,13 @@ static int uwsgi_routing_func_rpc(struct wsgi_request *wsgi_req, struct uwsgi_ro
// this is a placeholder for tmp uwsgi_buffers
struct uwsgi_buffer *ubs[UMAX8];
char **r_argv = (char **) ur->data2;
uint16_t *r_argvs = (uint16_t *) ur->data3;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
uint64_t i;
for(i=0;i<ur->custom;i++) {
ubs[i] = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, r_argv[i], r_argvs[i]);
if (!ubs[i]) goto end;
argv[i] = ubs[i]->buf;
argvs[i] = ubs[i]->pos;
}
if (!uwsgi_rpc_apply_translations(wsgi_req, ur, ubs, &i, argv, argvs))
goto end;
// ok we now need to check it it is a local call or a remote one
char *func = uwsgi_str(ur->data);
char *remote = NULL;
char *at = strchr(func, '@');
if (at) {
*at = 0;
remote = at+1;
}
char *remote = uwsgi_rpc_get_remote(func);
uint64_t size;
char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
free(func);
@@ -340,28 +357,13 @@ static int uwsgi_routing_func_rpc_blob(struct wsgi_request *wsgi_req, struct uws
// this is a placeholder for tmp uwsgi_buffers
struct uwsgi_buffer *ubs[UMAX8];
char **r_argv = (char **) ur->data2;
uint16_t *r_argvs = (uint16_t *) ur->data3;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
uint64_t i;
for(i=0;i<ur->custom;i++) {
ubs[i] = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, r_argv[i], r_argvs[i]);
if (!ubs[i]) goto end;
argv[i] = ubs[i]->buf;
argvs[i] = ubs[i]->pos;
}
if (!uwsgi_rpc_apply_translations(wsgi_req, ur, ubs, &i, argv, argvs))
goto end;
// ok we now need to check it it is a local call or a remote one
char *func = uwsgi_str(ur->data);
char *remote = NULL;
char *at = strchr(func, '@');
if (at) {
*at = 0;
remote = at+1;
}
char *remote = uwsgi_rpc_get_remote(func);
uint64_t size;
char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
free(func);
@@ -396,28 +398,13 @@ static int uwsgi_routing_func_rpc_raw(struct wsgi_request *wsgi_req, struct uwsg
// this is a placeholder for tmp uwsgi_buffers
struct uwsgi_buffer *ubs[UMAX8];
char **r_argv = (char **) ur->data2;
uint16_t *r_argvs = (uint16_t *) ur->data3;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
uint64_t i;
for(i=0;i<ur->custom;i++) {
ubs[i] = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, r_argv[i], r_argvs[i]);
if (!ubs[i]) goto end;
argv[i] = ubs[i]->buf;
argvs[i] = ubs[i]->pos;
}
if (!uwsgi_rpc_apply_translations(wsgi_req, ur, ubs, &i, argv, argvs))
goto end;
// ok we now need to check it it is a local call or a remote one
char *func = uwsgi_str(ur->data);
char *remote = NULL;
char *at = strchr(func, '@');
if (at) {
*at = 0;
remote = at+1;
}
char *remote = uwsgi_rpc_get_remote(func);
uint64_t size;
response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
free(func);
@@ -452,28 +439,13 @@ static int uwsgi_routing_func_rpc_var(struct wsgi_request *wsgi_req, struct uwsg
// this is a placeholder for tmp uwsgi_buffers
struct uwsgi_buffer *ubs[UMAX8];
char **r_argv = (char **) ur->data2;
uint16_t *r_argvs = (uint16_t *) ur->data3;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
uint64_t i;
for(i=0;i<ur->custom;i++) {
ubs[i] = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, r_argv[i], r_argvs[i]);
if (!ubs[i]) goto end;
argv[i] = ubs[i]->buf;
argvs[i] = ubs[i]->pos;
}
if (!uwsgi_rpc_apply_translations(wsgi_req, ur, ubs, &i, argv, argvs))
goto end;
// ok we now need to check it it is a local call or a remote one
char *func = uwsgi_str(ur->data);
char *remote = NULL;
char *at = strchr(func, '@');
if (at) {
*at = 0;
remote = at+1;
}
char *remote = uwsgi_rpc_get_remote(func);
uint64_t size;
response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
free(func);
@@ -509,28 +481,13 @@ static int uwsgi_routing_func_rpc_ret(struct wsgi_request *wsgi_req, struct uwsg
// this is a placeholder for tmp uwsgi_buffers
struct uwsgi_buffer *ubs[UMAX8];
char **r_argv = (char **) ur->data2;
uint16_t *r_argvs = (uint16_t *) ur->data3;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
uint64_t i;
for(i=0;i<ur->custom;i++) {
ubs[i] = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, r_argv[i], r_argvs[i]);
if (!ubs[i]) goto end;
argv[i] = ubs[i]->buf;
argvs[i] = ubs[i]->pos;
}
if (!uwsgi_rpc_apply_translations(wsgi_req, ur, ubs, &i, argv, argvs))
goto end;
// ok we now need to check it it is a local call or a remote one
char *func = uwsgi_str(ur->data);
char *remote = NULL;
char *at = strchr(func, '@');
if (at) {
*at = 0;
remote = at+1;
}
char *remote = uwsgi_rpc_get_remote(func);
uint64_t size;
char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
free(func);

View File

@@ -84,7 +84,7 @@ static void stackless_init_apps(void) {
if (!usl.enabled) return;
if (uwsgi.async <= 1) {
if (uwsgi.async < 1) {
uwsgi_log("the stackless suspend engine requires async mode\n");
exit(1);
}

View File

@@ -235,7 +235,7 @@ PyObject *py_uwsgi_tornado_accept(PyObject *self, PyObject *args) {
// enter harakiri mode
if (uwsgi.harakiri_options.workers > 0) {
set_harakiri(uwsgi.harakiri_options.workers);
set_harakiri(wsgi_req, uwsgi.harakiri_options.workers);
}
uwsgi.async_proto_fd_table[wsgi_req->fd] = wsgi_req;
@@ -342,7 +342,7 @@ static void tornado_loop() {
uwsgi.schedule_fix = uwsgi_tornado_schedule_fix;
if (uwsgi.async < 2) {
if (uwsgi.async < 1) {
uwsgi_log("the tornado loop engine requires async mode (--async <n>)\n");
exit(1);
}

131
setup.cpyext.py Normal file
View File

@@ -0,0 +1,131 @@
# encoding: utf-8
"""
This is a hack allowing you installing
uWSGI and uwsgidecorators via pip and easy_install
since 1.9.11 it automatically detects pypy
"""
import os
import sys
import errno
import shlex
import shutil
import uwsgiconfig
from setuptools import setup
from setuptools.dist import Distribution
from setuptools.command.install import install
from setuptools.command.install_lib import install_lib
from setuptools.command.build_ext import build_ext
from distutils.core import Extension
class uWSGIBuildExt(build_ext):
UWSGI_NAME = 'uwsgi'
UWSGI_PLUGIN = 'pyuwsgi'
def build_extensions(self):
self.uwsgi_setup()
#XXX: needs uwsgiconfig fix
self.uwsgi_build()
if 'UWSGI_USE_DISTUTILS' not in os.environ:
#XXX: needs uwsgiconfig fix
#uwsgiconfig.build_uwsgi(self.uwsgi_config)
return
else:
#XXX: needs uwsgiconfig fix
os.unlink(self.uwsgi_config.get('bin_name'))
#FIXME: else build fails :(
for baddie in set(self.compiler.compiler_so) & set((
'-Wstrict-prototypes',
)):
self.compiler.compiler_so.remove(baddie)
build_ext.build_extensions(self)
def uwsgi_setup(self):
default = (
'__pypy__' in sys.builtin_module_names
and 'pypy'
or 'default'
)
profile = (
os.environ.get('UWSGI_PROFILE')
or 'buildconf/%s.ini' % default
)
if not profile.endswith('.ini'):
profile = profile + '.ini'
if not '/' in profile:
profile = 'buildconf/' + profile
#FIXME: update uwsgiconfig to properly set _EVERYTHING_!
config = uwsgiconfig.uConf(profile)
# insert in the beginning so UWSGI_PYTHON_NOLIB is exported
# before the python plugin compiles
ep = config.get('embedded_plugins').split(',')
if self.UWSGI_PLUGIN in ep:
ep.remove(self.UWSGI_PLUGIN)
ep.insert(0, self.UWSGI_PLUGIN)
config.set('embedded_plugins', ','.join(ep))
config.set('as_shared_library', 'true')
config.set('bin_name', self.get_ext_fullpath(self.UWSGI_NAME))
try:
os.makedirs(os.path.dirname(config.get('bin_name')))
except OSError as e:
if e.errno != errno.EEXIST:
raise
self.uwsgi_profile = profile
self.uwsgi_config = config
def uwsgi_build(self):
uwsgiconfig.build_uwsgi(self.uwsgi_config)
#XXX: merge uwsgi_setup (see other comments)
for ext in self.extensions:
if ext.name == self.UWSGI_NAME:
ext.sources = [s + '.c' for s in self.uwsgi_config.gcc_list]
ext.library_dirs = self.uwsgi_config.include_path[:]
ext.libraries = list()
ext.extra_compile_args = list()
for x in uwsgiconfig.uniq_warnings(
self.uwsgi_config.ldflags + self.uwsgi_config.libs,
):
for y in shlex.split(x):
if y.startswith('-l'):
ext.libraries.append(y[2:])
elif y.startswith('-L'):
ext.library_dirs.append(y[2:])
for x in self.uwsgi_config.cflags:
for y in shlex.split(x):
if y:
ext.extra_compile_args.append(y)
setup(
name='uWSGI',
license='GPL2',
version=uwsgiconfig.uwsgi_version,
author='Unbit',
author_email='info@unbit.it',
description='The uWSGI server',
cmdclass={
'build_ext': uWSGIBuildExt,
},
py_modules=[
'uwsgidecorators',
],
ext_modules=[
Extension(uWSGIBuildExt.UWSGI_NAME, sources=[]),
],
entry_points={
'console_scripts': ['uwsgi=%s:run' % uWSGIBuildExt.UWSGI_NAME],
},
)

111
uwsgi.h
View File

@@ -6,7 +6,7 @@
extern "C" {
#endif
#define UWSGI_PLUGIN_API 1
#define UWSGI_PLUGIN_API 2
#define UMAX16 65536
#define UMAX8 256
@@ -1697,6 +1697,8 @@ struct uwsgi_fsmon {
struct uwsgi_fsmon *next;
};
struct uwsgi_subscription_client;
struct uwsgi_server {
// store the machine hostname
@@ -2646,7 +2648,7 @@ struct uwsgi_server {
struct uwsgi_string_list *subscriptions;
struct uwsgi_string_list *subscriptions2;
struct uwsgi_subscribe_node *(*subscription_algo) (struct uwsgi_subscribe_slot *, struct uwsgi_subscribe_node *);
struct uwsgi_subscribe_node *(*subscription_algo) (struct uwsgi_subscribe_slot *, struct uwsgi_subscribe_node *, struct uwsgi_subscription_client *);
int subscription_dotsplit;
int never_swap;
@@ -2727,7 +2729,6 @@ struct uwsgi_server {
int mule_reload_mercy;
int alarm_cheap;
int emperor_no_blacklist;
int metrics_no_cores;
int stats_no_cores;
@@ -2736,6 +2737,28 @@ struct uwsgi_server {
// uWSGI 2.0.7
int vassal_sos;
// uWSGI 2.1
char *fork_socket;
int new_argc;
char **new_argv;
char *emperor_use_fork_server;
struct uwsgi_string_list *vassal_fork_base;
struct uwsgi_string_list *emperor_collect_attributes;
char *emperor_fork_server_attr;
char *emperor_wrapper_attr;
int emperor_subreaper;
struct uwsgi_string_list *hook_as_on_demand_vassal;
uint64_t max_requests_delta;
char *emperor_chdir_attr;
struct uwsgi_string_list *subscription_algos;
int subscription_mountpoints;
struct uwsgi_string_list *hook_as_emperor_before_vassal;
struct uwsgi_string_list *hook_as_vassal_before_drop;
struct uwsgi_string_list *wait_for_fs;
struct uwsgi_string_list *wait_for_dir;
struct uwsgi_string_list *wait_for_file;
int wait_for_fs_timeout;
struct uwsgi_string_list *hook_as_emperor_setns;
};
struct uwsgi_rpc {
@@ -2863,7 +2886,6 @@ struct uwsgi_shared {
struct uwsgi_core {
//time_t harakiri;
uint64_t requests;
uint64_t failed_requests;
@@ -2889,6 +2911,10 @@ struct uwsgi_core {
char *post_buf;
struct wsgi_request req;
// uWSGI 2.1
time_t harakiri;
time_t user_harakiri;
};
struct uwsgi_worker {
@@ -2904,8 +2930,10 @@ struct uwsgi_worker {
uint64_t delta_requests;
uint64_t failed_requests;
time_t harakiri;
time_t user_harakiri;
// renamed in 2.1 (was 'harakiri')
time_t harakiri_unused;
// renamed in 2.1 (was 'user_harakiri')
time_t user_harakiri_unused;
uint64_t harakiri_count;
int pending_harakiri;
@@ -3043,11 +3071,11 @@ void uwsgi_curse(int, int);
void uwsgi_curse_mule(int, int);
void uwsgi_destroy_processes(void);
void set_harakiri(int);
void set_user_harakiri(int);
void set_harakiri(struct wsgi_request *, int);
void set_user_harakiri(struct wsgi_request *, int);
void set_mule_harakiri(int);
void set_spooler_harakiri(int);
void inc_harakiri(int);
void inc_harakiri(struct wsgi_request *, int);
#ifdef __BIG_ENDIAN__
uint16_t uwsgi_swap16(uint16_t);
@@ -3235,7 +3263,7 @@ int uwsgi_register_signal(uint8_t, char *, void *, uint8_t);
int uwsgi_add_file_monitor(uint8_t, char *);
int uwsgi_add_timer(uint8_t, int);
int uwsgi_signal_add_rb_timer(uint8_t, int, int);
int uwsgi_signal_handler(uint8_t);
int uwsgi_signal_handler(struct wsgi_request *, uint8_t);
void uwsgi_route_signal(uint8_t);
@@ -3324,6 +3352,13 @@ struct uwsgi_subscribe_req {
char *notify;
uint16_t notify_len;
uint64_t backup_level;
char *proto;
uint16_t proto_len;
struct uwsgi_subscribe_node *(*algo) (struct uwsgi_subscribe_slot *, struct uwsgi_subscribe_node *, struct uwsgi_subscription_client *);
};
void uwsgi_nuclear_blast();
@@ -3553,6 +3588,11 @@ struct uwsgi_mule_farm *uwsgi_mule_farm_new(struct uwsgi_mule_farm **, struct uw
int uwsgi_farm_has_mule(struct uwsgi_farm *, int);
struct uwsgi_farm *get_farm_by_name(char *);
struct uwsgi_subscription_client {
int fd;
union uwsgi_sockaddr *sockaddr;
char *cookie;
};
struct uwsgi_subscribe_node {
@@ -3592,6 +3632,11 @@ struct uwsgi_subscribe_node {
struct uwsgi_subscribe_slot *slot;
struct uwsgi_subscribe_node *next;
// uWSGI 2.1
uint64_t backup_level;
//here the solution is a bit hacky, we take the first letter of the proto ('u','\0' -> uwsgi, 'h' -> http, 'f' -> fastcgi, 's' -> scgi)
char proto;
};
struct uwsgi_subscribe_slot {
@@ -3614,6 +3659,9 @@ struct uwsgi_subscribe_slot {
uint8_t sni_enabled;
#endif
// uWSGI 2.1 (algo is required)
struct uwsgi_subscribe_node *(*algo) (struct uwsgi_subscribe_slot *, struct uwsgi_subscribe_node *, struct uwsgi_subscription_client *);
};
void mule_send_msg(int, char *, size_t);
@@ -3623,13 +3671,13 @@ void create_signal_pipe(int *);
void create_msg_pipe(int *, int);
struct uwsgi_subscribe_slot *uwsgi_get_subscribe_slot(struct uwsgi_subscribe_slot **, char *, uint16_t);
struct uwsgi_subscribe_node *uwsgi_get_subscribe_node_by_name(struct uwsgi_subscribe_slot **, char *, uint16_t, char *, uint16_t);
struct uwsgi_subscribe_node *uwsgi_get_subscribe_node(struct uwsgi_subscribe_slot **, char *, uint16_t);
struct uwsgi_subscribe_node *uwsgi_get_subscribe_node(struct uwsgi_subscribe_slot **, char *, uint16_t, struct uwsgi_subscription_client *);
int uwsgi_remove_subscribe_node(struct uwsgi_subscribe_slot **, struct uwsgi_subscribe_node *);
struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slot **, struct uwsgi_subscribe_req *);
ssize_t uwsgi_mule_get_msg(int, int, char *, size_t, int);
int uwsgi_signal_wait(int);
int uwsgi_signal_wait(struct wsgi_request *, int);
struct uwsgi_app *uwsgi_add_app(int, uint8_t, char *, int, void *, void *);
int uwsgi_signal_send(int, uint8_t);
int uwsgi_remote_signal_send(char *, uint8_t);
@@ -3891,7 +3939,7 @@ int uwsgi_is_file2(char *, struct stat *);
int uwsgi_is_dir(char *);
int uwsgi_is_link(char *);
void uwsgi_receive_signal(int, char *, int);
void uwsgi_receive_signal(struct wsgi_request *, int, char *, int);
void uwsgi_exec_atexit(void);
struct uwsgi_stats {
@@ -4086,6 +4134,11 @@ struct uwsgi_instance {
int on_demand_fd;
char *socket_name;
time_t cursed_at;
int adopted;
// uWSGI 2.1 (vassal's attributes)
struct uwsgi_dyn_dict *attrs;
};
struct uwsgi_instance *emperor_get_by_fd(int);
@@ -4094,6 +4147,7 @@ void emperor_stop(struct uwsgi_instance *);
void emperor_curse(struct uwsgi_instance *);
void emperor_respawn(struct uwsgi_instance *, time_t);
void emperor_add(struct uwsgi_emperor_scanner *, char *, time_t, char *, uint32_t, uid_t, gid_t, char *);
void emperor_add_with_attrs(struct uwsgi_emperor_scanner *, char *, time_t, char *, uint32_t, uid_t, gid_t, char *, struct uwsgi_dyn_dict *);
void emperor_back_to_ondemand(struct uwsgi_instance *);
void uwsgi_exec_command_with_args(char *);
@@ -4174,6 +4228,7 @@ void uwsgi_master_cleanup_hooks(void);
pid_t uwsgi_daemonize2();
void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *, char *, char *, time_t, uid_t, gid_t, char *);
void uwsgi_emperor_simple_do_with_attrs(struct uwsgi_emperor_scanner *, char *, char *, time_t, uid_t, gid_t, char *, struct uwsgi_dyn_dict *);
#if defined(__linux__)
#define UWSGI_ELF
@@ -4584,6 +4639,7 @@ int uwsgi_umount(char *, char *);
int uwsgi_mount_hook(char *);
int uwsgi_umount_hook(char *);
int uwsgi_hooks_run_and_return(struct uwsgi_string_list *, char *, char *, int);
void uwsgi_hooks_run(struct uwsgi_string_list *, char *, int);
void uwsgi_register_hook(char *, int (*)(char *));
struct uwsgi_hook *uwsgi_hook_by_name(char *);
@@ -4802,6 +4858,35 @@ int uwsgi_notify_socket_manage(int);
int uwsgi_notify_msg(char *, char *, size_t);
void vassal_sos();
int uwsgi_send_fds_and_body(int, int *, int, char *, size_t);
ssize_t uwsgi_recv_cred_and_fds(int, char *, size_t buf_len, pid_t *, uid_t *, gid_t *, int *, int *);
void uwsgi_fork_server(char *);
void uwsgi_emperor_ini_attrs(char *, char *, struct uwsgi_dyn_dict **);
int uwsgi_buffer_httpdate(struct uwsgi_buffer *, time_t);
int uwsgi_buffer_append_xml(struct uwsgi_buffer *, char *, size_t);
struct uwsgi_buffer *uwsgi_webdav_multistatus_new();
int uwsgi_webdav_propfind_item_add(struct uwsgi_buffer *, char *, uint16_t, uint64_t, time_t, char *, uint16_t, char *, uint16_t, char *, uint16_t);
int uwsgi_webdav_multistatus_close(struct uwsgi_buffer *);
int uwsgi_webdav_multistatus_response_new(struct uwsgi_buffer *);
int uwsgi_webdav_multistatus_response_close(struct uwsgi_buffer *);
int uwsgi_webdav_multistatus_propstat_new(struct uwsgi_buffer *);
int uwsgi_webdav_multistatus_propstat_close(struct uwsgi_buffer *);
int uwsgi_webdav_multistatus_prop_new(struct uwsgi_buffer *);
int uwsgi_webdav_multistatus_prop_close(struct uwsgi_buffer *);
struct uwsgi_subscribe_node *(*uwsgi_subscription_algo_get(char * , size_t))(struct uwsgi_subscribe_slot *, struct uwsgi_subscribe_node *, struct uwsgi_subscription_client *);
void uwsgi_subscription_init_algos(void);
void uwsgi_register_subscription_algo(char *, struct uwsgi_subscribe_node *(*) (struct uwsgi_subscribe_slot *, struct uwsgi_subscribe_node *, struct uwsgi_subscription_client *));
char *uwsgi_subscription_algo_name(void *);
>>>>>>> uwsgi-2.1
int uwsgi_wait_for_fs(char *, int);
void uwsgi_hooks_setns_run(struct uwsgi_string_list *, pid_t, uid_t, gid_t);
char *vassal_attr_get(struct uwsgi_instance *, char *);
#ifdef __cplusplus
}
#endif

View File

@@ -1,6 +1,6 @@
# uWSGI build system
uwsgi_version = '2.0.7'
uwsgi_version = '2.1'
import os
import re
@@ -607,7 +607,7 @@ class uConf(object):
'core/setup_utils', 'core/clock', 'core/init', 'core/buffer', 'core/reader', 'core/writer', 'core/alarm', 'core/cron', 'core/hooks',
'core/plugins', 'core/lock', 'core/cache', 'core/daemons', 'core/errors', 'core/hash', 'core/master_events', 'core/chunked',
'core/queue', 'core/event', 'core/signal', 'core/strings', 'core/progress', 'core/timebomb', 'core/ini', 'core/fsmon', 'core/mount',
'core/metrics', 'core/plugins_builder', 'core/sharedarea',
'core/metrics', 'core/plugins_builder', 'core/sharedarea', 'core/fork_server', 'core/webdav',
'core/rpc', 'core/gateway', 'core/loop', 'core/cookie', 'core/querystring', 'core/rb_timers', 'core/transformations', 'core/uwsgi']
# add protocols
self.gcc_list.append('proto/base')