mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-04-28 10:53:37 +00:00
uwsgi-2.1 merged to master
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -22,3 +22,7 @@ core/dot_h.c
|
||||
+# coverity
|
||||
+/cov-int/
|
||||
+uwsgi.tar.xz
|
||||
|
||||
/build/
|
||||
/dist/
|
||||
/uWSGI.egg-info/
|
||||
|
||||
@@ -29,3 +29,4 @@ Danila Shtan <danila@shtan.ru>
|
||||
Ævar Arnfjörð Bjarmason
|
||||
Yu Zhao (getcwd)
|
||||
Mathieu Dupuy
|
||||
Mike Kaplinskiy
|
||||
|
||||
@@ -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
|
||||
|
||||
15
core/async.c
15
core/async.c
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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, """, 6)) return -1;
|
||||
}
|
||||
else if (buf[i] == '\'') {
|
||||
if (uwsgi_buffer_append(ub, "'", 6)) return -1;
|
||||
}
|
||||
else if (buf[i] == '<') {
|
||||
if (uwsgi_buffer_append(ub, "<", 4)) return -1;
|
||||
}
|
||||
else if (buf[i] == '>') {
|
||||
if (uwsgi_buffer_append(ub, ">", 4)) return -1;
|
||||
}
|
||||
else if (buf[i] == '&') {
|
||||
if (uwsgi_buffer_append(ub, "&", 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);
|
||||
}
|
||||
|
||||
516
core/emperor.c
516
core/emperor.c
@@ -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
226
core/fork_server.c
Normal 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);
|
||||
|
||||
}
|
||||
}
|
||||
217
core/hooks.c
217
core/hooks.c
@@ -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
|
||||
|
||||
63
core/ini.c
63
core/ini.c
@@ -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);
|
||||
}
|
||||
|
||||
24
core/init.c
24
core/init.c
@@ -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
132
core/io.c
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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....
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
118
core/utils.c
118
core/utils.c
@@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
53
core/uwsgi.c
53
core/uwsgi.c
@@ -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
110
core/webdav.c
Normal 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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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()");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -199,6 +199,7 @@ struct uwsgi_python {
|
||||
struct uwsgi_string_list *sharedarea;
|
||||
|
||||
int call_osafterfork;
|
||||
int pre_initialized;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
131
setup.cpyext.py
Normal 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
111
uwsgi.h
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
Reference in New Issue
Block a user