Compare commits

...
70 Commits
Author SHA1 Message Date
Unbit b6d34067c4 support for multiple tuntap devices 2013-09-14 15:15:47 +02:00
Unbit dbe15195b7 support for multiple routers 2013-09-14 15:07:43 +02:00
Unbit 5642aa1eb5 should be enough for 1.9.16... 2013-09-14 14:40:16 +02:00
Unbit 5dd465ccc1 added internal counters to the tuntap router 2013-09-14 14:31:12 +02:00
Unbit ae78c3007e fixed tuntap firewall 2013-09-14 12:05:13 +02:00
Unbit 16211d9439 preliminary tuntap firewall implementation 2013-09-14 11:04:26 +02:00
unbit 515619fe2a Merge pull request #379 from prymitive/cheaper_mem_limit
allow setting cheaper rss memory limits
2013-09-14 01:25:14 -07:00
Unbit a7d550165d still refactoring tuntap 2013-09-14 10:03:41 +02:00
Unbit efceacd9e5 refactored tuntap plugin 2013-09-14 09:54:57 +02:00
Unbit ea5ebc2d15 added preliminary version of the tuntap plugin 2013-09-14 08:43:56 +02:00
Unbit fba82c203c minor improvements 2013-09-14 08:43:09 +02:00
Łukasz Mierzwa a50516af7a allow setting cheaper rss memory limits 2013-09-14 01:04:19 +02:00
Unbit 6056b51653 implemented priority in rsyslog 2013-09-13 06:17:34 +02:00
Unbit 23a3170c59 fixed a typo 2013-09-12 15:31:15 +02:00
Unbit e136128408 added compress and suffix log encoders 2013-09-11 14:04:26 +02:00
Unbit fce94e0f54 cleanup the rados plugin 2013-09-10 23:42:08 +02:00
unbit 06fa65bc5d Merge pull request #377 from javierguerragiraldez/master
new rados plugin
2013-09-11 06:49:04 -07:00
Javier Guerra 571ec5ca72 cleanup old (commented) flags inherited from glusterfs 2013-09-11 08:30:06 -05:00
Unbit 39bc0ecd46 OpenBSD has not strndup 2013-09-10 21:43:24 +02:00
Javier Guerra 7a5373360c strip mountpoint prefix, better check file not found error. 2013-09-10 12:30:59 -05:00
Javier Guerra 15453ffef6 compilation infrastructure 2013-09-10 12:30:59 -05:00
Javier Guerra a25747a096 use official modifier1 2013-09-10 12:30:59 -05:00
Javier Guerra bb1ef59b52 initial draft 2013-09-10 12:30:59 -05:00
Javier Guerra 6bb3af840d initial draft 2013-09-10 12:30:58 -05:00
Unbit 0223c74ecc added json log encoder 2013-09-10 19:24:50 +02:00
Unbit c7004d7ba4 added nl and format log encoders 2013-09-10 19:15:20 +02:00
Unbit 915d2e9192 Merge branch 'master' of github.com:unbit/uwsgi 2013-09-10 11:59:37 +02:00
Unbit df79b9367b report thunder lock status 2013-09-10 11:59:21 +02:00
Unbit ce3d026037 link with -lrt on solaris 2013-09-10 06:31:07 +02:00
Unbit d0f6c4130b fixed #376 2013-09-10 06:26:22 +02:00
Unbit 26bcf28182 improved gevent waiting for greenlets 2013-09-09 17:52:28 +02:00
unbit 272d1ccc03 improved mount/unmount support in freebsd 2013-09-08 18:39:31 +02:00
unbit 6c440af24e support for platform non defining MS_PRIVATE 2013-09-08 12:48:45 +02:00
unbit 8954520cb9 hardcode support for MS_REC 2013-09-08 12:47:07 +02:00
unbit 31bde74fab fixed msgpack on 32bit 2013-09-08 11:23:06 +02:00
Unbit 13c64a383c added response routes 2013-09-08 08:23:44 +02:00
Unbit 809028f11b added date/time support to msgpack encoder 2013-09-07 15:01:29 +02:00
Unbit dee9d2ba1e improved float/double support 2013-09-07 14:52:01 +02:00
Unbit 29d80ce061 added msgpack plugin, it misses int and float support 2013-09-07 13:06:10 +02:00
Unbit abcd3242d8 added log encoders 2013-09-07 10:40:40 +02:00
unbit f4762299f9 added callint/callret hooks 2013-09-06 12:28:04 +02:00
unbit 107f4309a4 first public implementation of the advanced hook subsystem 2013-09-06 11:57:23 +02:00
unbit d2a8df19ea prepare for advanced hooks 2013-09-06 11:03:02 +02:00
unbit 29efd15534 Merge pull request #374 from gdamjan/master
remount to private subtree after unshare
2013-09-06 00:00:03 -07:00
Damjan Georgievski e7fb216a8d remount to private subtree after unshare
systemd will makes the VFS tree 'shared' on boot, so mount
operations would propagate between the namespace and the
parent system.
make sure the whole VFS tree is private to the namespace.
2013-09-06 08:41:00 +02:00
unbit 952b96cdcb added --jail-attach 2013-09-04 14:20:02 +02:00
unbit 8ee82fc296 do not call pre-jail on reload 2013-09-04 12:28:22 +02:00
unbit afe2bfb856 improved support for FreeBSD jails 2013-09-04 11:36:45 +02:00
unbit 5b63e9aea0 added FreeBSD jail support 2013-09-04 00:30:39 +02:00
Unbit 91f70259e2 some garbage... 2013-09-03 20:24:04 +02:00
Unbit f120cacc03 added support for O_TMPFILE 2013-09-03 07:15:22 +02:00
Unbit aff1d782b8 Merge branch 'master' of github.com:unbit/uwsgi 2013-09-02 15:55:27 +02:00
Unbit b489fd8a24 added --disable-sendfile 2013-09-02 15:55:02 +02:00
unbit 47e0eb68c2 Merge pull request #373 from ivanjr0/master
Adding **kwargs to @harakiri
2013-09-02 05:26:57 -07:00
Ivan Júnior 9498e25245 Adding **kwargs to @harakiri
I can't see any reason why this decorator doesn't have `**kwargs`, so I add it.
2013-09-02 09:23:53 -03:00
Unbit a33e18b589 --pivot_root and --pivot-root 2013-09-02 10:39:15 +02:00
Unbit f2dcdf2289 added --pivot-root (linux only) 2013-09-02 10:38:40 +02:00
Unbit 74c53e8a61 added --drop-after-init and --drop-after-apps 2013-09-02 10:12:46 +02:00
Unbit 1feed87c10 improved request_id management in fastcgi parser 2013-08-31 12:25:10 +02:00
Unbit f89742d81a fixed fastcgi bug exposed by apache mod_fastcgi 2013-08-31 12:08:27 +02:00
Unbit 340b9d603e fixed --persistent-ipcsem 2013-08-31 11:22:39 +02:00
Unbit 1c0fc64243 better ipcsem support 2013-08-31 11:20:52 +02:00
Unbit 1d5173d923 better BUG reporting in smart-attach-daemon 2013-08-30 20:03:58 +02:00
Unbit 49a8bf0b9b report missing internal routing support 2013-08-30 14:58:15 +02:00
Unbit 0a7e5a41a2 added the Zeus mode analysis 2013-08-30 11:27:47 +02:00
Unbit 43ff563429 prepare for 1.9.16 2013-08-30 10:10:34 +02:00
Roberto De Ioris 2daf6f1f66 fixed #75 2013-08-30 08:07:50 +02:00
Unbit 985f56768f follow Rack specifications for QUERY_STRING,SCRIPT_NAME,SERVER_NAME and SERVER_PORT 2013-08-29 18:58:08 +02:00
Unbit 35278588f5 improved smart-attach-daemon 2013-08-29 17:40:32 +02:00
Unbit f6545be647 fixed reference counting bug in rpc and signal handlers 2013-08-29 14:45:08 +02:00
41 changed files with 3516 additions and 101 deletions
+3
View File
@@ -0,0 +1,3 @@
[uwsgi]
main_plugin = rados
inherit = base
+24
View File
@@ -172,6 +172,16 @@ int uwsgi_buffer_u32be(struct uwsgi_buffer *ub, uint32_t num) {
return uwsgi_buffer_append(ub, (char *) buf, 4);
}
int uwsgi_buffer_f32be(struct uwsgi_buffer *ub, float num) {
uint8_t buf[4];
uint32_t *pnum = (uint32_t *) #
buf[3] = (uint8_t) (*pnum & 0xff);
buf[2] = (uint8_t) ((*pnum >> 8) & 0xff);
buf[1] = (uint8_t) ((*pnum >> 16) & 0xff);
buf[0] = (uint8_t) ((*pnum >> 24) & 0xff);
return uwsgi_buffer_append(ub, (char *) buf, 4);
}
int uwsgi_buffer_u32le(struct uwsgi_buffer *ub, uint32_t num) {
uint8_t buf[4];
buf[0] = (uint8_t) (num & 0xff);
@@ -195,6 +205,20 @@ int uwsgi_buffer_u64be(struct uwsgi_buffer *ub, uint64_t num) {
}
int uwsgi_buffer_f64be(struct uwsgi_buffer *ub, double num) {
uint8_t buf[8];
uint64_t *pnum = (uint64_t *) #
buf[7] = (uint8_t) (*pnum & 0xff);
buf[6] = (uint8_t) ((*pnum >> 8) & 0xff);
buf[5] = (uint8_t) ((*pnum >> 16) & 0xff);
buf[4] = (uint8_t) ((*pnum >> 24) & 0xff);
buf[3] = (uint8_t) ((*pnum >> 32) & 0xff);
buf[2] = (uint8_t) ((*pnum >> 40) & 0xff);
buf[1] = (uint8_t) ((*pnum >> 48) & 0xff);
buf[0] = (uint8_t) ((*pnum >> 56) & 0xff);
return uwsgi_buffer_append(ub, (char *) buf, 8);
}
int uwsgi_buffer_append_ipv4(struct uwsgi_buffer *ub, void *addr) {
char ip[INET_ADDRSTRLEN];
if (!inet_ntop(AF_INET, addr, ip, INET_ADDRSTRLEN)) {
+23 -6
View File
@@ -77,8 +77,14 @@ void uwsgi_daemons_smart_check() {
else {
ud->pidfile_checks++;
if (ud->pidfile_checks >= (unsigned int) ud->freq) {
uwsgi_log("[uwsgi-daemons] found changed pidfile for \"%s\" (old_pid: %d new_pid: %d)\n", ud->command, (int) ud->pid, (int) checked_pid);
uwsgi_spawn_daemon(ud);
if (!ud->has_daemonized) {
uwsgi_log_verbose("[uwsgi-daemons] \"%s\" (pid: %d) did not daemonize !!!\n", ud->command, (int) ud->pid);
ud->pidfile_checks = 0;
}
else {
uwsgi_log("[uwsgi-daemons] found changed pidfile for \"%s\" (old_pid: %d new_pid: %d)\n", ud->command, (int) ud->pid, (int) checked_pid);
uwsgi_spawn_daemon(ud);
}
}
}
}
@@ -99,10 +105,20 @@ void uwsgi_daemons_smart_check() {
int uwsgi_daemon_check_pid_death(pid_t diedpid) {
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
if (ud->pid == diedpid && !ud->pidfile) {
uwsgi_log("daemon \"%s\" (pid: %d) annihilated\n", ud->command, (int) diedpid);
ud->pid = -1;
return -1;
if (ud->pid == diedpid) {
if (!ud->pidfile) {
uwsgi_log("daemon \"%s\" (pid: %d) annihilated\n", ud->command, (int) diedpid);
ud->pid = -1;
return -1;
}
else {
if (!ud->has_daemonized) {
ud->has_daemonized = 1;
}
else {
uwsgi_log("[uwsgi-daemons] BUG !!! daemon \"%s\" has already daemonized !!!\n", ud->command);
}
}
}
ud = ud->next;
}
@@ -251,6 +267,7 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
}
if (pid > 0) {
ud->has_daemonized = 0;
ud->pid = pid;
ud->status = 1;
ud->pidfile_checks = 0;
+35 -5
View File
@@ -620,7 +620,7 @@ void emperor_stop(struct uwsgi_instance *c_ui) {
// remove uWSGI instance
if (write(c_ui->pipe[0], "\0", 1) != 1) {
uwsgi_error("write()");
uwsgi_error("emperor_stop()/write()");
}
c_ui->status = 1;
@@ -634,7 +634,7 @@ void emperor_respawn(struct uwsgi_instance *c_ui, time_t mod) {
// reload the uWSGI instance
if (write(c_ui->pipe[0], "\1", 1) != 1) {
uwsgi_error("write()");
uwsgi_error("emperor_respawn/write()");
}
// push the config to the config pipe (if needed)
@@ -862,14 +862,28 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
// once the config is sent we can run hooks (they can fail)
// exec hooks have access to all of the currently defined vars + UWSGI_VASSAL_PID, UWSGI_VASSAL_UID, UWSGI_VASSAL_GID, UWSGI_VASSAL_CONFIG
uwsgi_hooks_run(uwsgi.hook_as_emperor, "as-emperor", 0);
struct uwsgi_string_list *usl;
uwsgi_foreach(usl, uwsgi.mount_as_emperor) {
uwsgi_log("mounting \"%s\" (as-emperor for vassal \"%s\" pid: %d uid: %d gid: %d)...\n", usl->value, n_ui->name, n_ui->pid, n_ui->uid, n_ui->gid);
if (uwsgi_mount_hook(usl->value)) {
exit(1);
}
}
uwsgi_foreach(usl, uwsgi.umount_as_emperor) {
uwsgi_log("un-mounting \"%s\" (as-emperor for vassal \"%s\" pid: %d uid: %d gid: %d)...\n", usl->value, n_ui->name, n_ui->pid, n_ui->uid, n_ui->gid);
if (uwsgi_umount_hook(usl->value)) {
exit(1);
}
}
uwsgi_foreach(usl, uwsgi.exec_as_emperor) {
uwsgi_log("running \"%s\" (as-emperor for vassal \"%s\" pid: %d uid: %d gid: %d)...\n", usl->value, n_ui->name, n_ui->pid, n_ui->uid, n_ui->gid);
char *argv[4];
argv[0] = uwsgi_concat2("UWSGI_VASSAL_CONFIG=", n_ui->name);
char argv_pid[17+11]; snprintf(argv_pid, 17 + 11, "UWSGI_VASSAL_PID=%d", n_ui->pid); argv[1] = argv_pid;
char argv_uid[17+11]; snprintf(argv_uid, 17 + 11, "UWSGI_VASSAL_UID=%d", n_ui->uid); argv[2] = argv_uid;
char argv_gid[17+11]; snprintf(argv_gid, 17 + 11, "UWSGI_VASSAL_GID=%d", n_ui->gid); argv[3] = argv_gid;
char argv_pid[17+11]; snprintf(argv_pid, 17 + 11, "UWSGI_VASSAL_PID=%d", (int) n_ui->pid); argv[1] = argv_pid;
char argv_uid[17+11]; snprintf(argv_uid, 17 + 11, "UWSGI_VASSAL_UID=%d", (int) n_ui->uid); argv[2] = argv_uid;
char argv_gid[17+11]; snprintf(argv_gid, 17 + 11, "UWSGI_VASSAL_GID=%d", (int) n_ui->gid); argv[3] = argv_gid;
int ret = uwsgi_run_command_putenv_and_wait(NULL, usl->value, argv, 4);
uwsgi_log("command \"%s\" exited with code: %d\n", usl->value, ret);
free(argv[0]);
@@ -1131,6 +1145,22 @@ static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) {
uwsgi_log("[emperor] %s start-hook returned %d\n", n_ui->name, start_hook_ret);
}
uwsgi_hooks_run(uwsgi.hook_as_vassal, "as-vassal", 1);
uwsgi_foreach(usl, uwsgi.mount_as_vassal) {
uwsgi_log("mounting \"%s\" (as-vassal)...\n", usl->value);
if (uwsgi_mount_hook(usl->value)) {
exit(1);
}
}
uwsgi_foreach(usl, uwsgi.umount_as_vassal) {
uwsgi_log("un-mounting \"%s\" (as-vassal)...\n", usl->value);
if (uwsgi_umount_hook(usl->value)) {
exit(1);
}
}
// run exec hooks (cannot fail)
uwsgi_foreach(usl, uwsgi.exec_as_vassal) {
uwsgi_log("running \"%s\" (as-vassal)...\n", usl->value);
+217
View File
@@ -0,0 +1,217 @@
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
/*
advanced (pluggable) hooks
they are executed before the other hooks, and can be extended by plugins
if a plugin tries to register an hook with a name already available in the list, its function
will be overridden
*/
struct uwsgi_hook *uwsgi_hook_by_name(char *name) {
struct uwsgi_hook *uh = uwsgi.hooks;
while(uh) {
if (!strcmp(uh->name, name)) {
return uh;
}
uh = uh->next;
}
return NULL;
}
void uwsgi_register_hook(char *name, int (*func)(char *)) {
struct uwsgi_hook *old_uh = NULL, *uh = uwsgi.hooks;
while(uh) {
if (!strcmp(uh->name, name)) {
uh->func = func;
return;
}
old_uh = uh;
uh = uh->next;
}
uh = uwsgi_calloc(sizeof(struct uwsgi_hook));
uh->name = name;
uh->func = func;
if (old_uh) {
old_uh->next = uh;
}
else {
uwsgi.hooks = uh;
}
}
static int uwsgi_hook_chdir(char *arg) {
int ret = chdir(arg);
if (ret) {
uwsgi_error("uwsgi_hook_chdir()");
}
return ret;
}
static int uwsgi_hook_exec(char *arg) {
int ret = uwsgi_run_command_and_wait(NULL, arg);
if (ret != 0) {
uwsgi_log("command \"%s\" exited with non-zero code: %d\n", arg, ret);
}
return ret;
}
static int uwsgi_hook_exit(char *arg) {
int exit_code = 0;
if (strlen(arg) > 1) {
exit_code = atoi(arg);
}
exit(exit_code);
}
static int uwsgi_hook_print(char *arg) {
char *line = uwsgi_concat2(arg, "\n");
uwsgi_log(line);
free(line);
return 0;
}
static int uwsgi_hook_callint(char *arg) {
char *space = strchr(arg, ' ');
if (space) {
*space = 0;
int num = atoi(space+1);
void (*func)(int) = dlsym(RTLD_DEFAULT, arg);
if (!func) {
uwsgi_log("unable to call function \"%s(%d)\"\n", arg, num);
*space = ' ';
return -1;
}
*space = ' ';
func(num);
}
else {
void (*func)(void) = dlsym(RTLD_DEFAULT, arg);
if (!func) {
uwsgi_log("unable to call function \"%s\"\n", arg);
return -1;
}
func();
}
return 0;
}
static int uwsgi_hook_call(char *arg) {
char *space = strchr(arg, ' ');
if (space) {
*space = 0;
void (*func)(char *) = dlsym(RTLD_DEFAULT, arg);
if (!func) {
uwsgi_log("unable to call function \"%s(%s)\"\n", arg, space + 1);
*space = ' ';
return -1;
}
*space = ' ';
func(space + 1);
}
else {
void (*func)(void) = dlsym(RTLD_DEFAULT, arg);
if (!func) {
uwsgi_log("unable to call function \"%s\"\n", arg);
return -1;
}
func();
}
return 0;
}
static int uwsgi_hook_callintret(char *arg) {
char *space = strchr(arg, ' ');
if (space) {
*space = 0;
int num = atoi(space+1);
int (*func)(int) = dlsym(RTLD_DEFAULT, arg);
if (!func) {
uwsgi_log("unable to call function \"%s(%d)\"\n", arg, num);
*space = ' ';
return -1;
}
*space = ' ';
return func(num);
}
int (*func)(void) = dlsym(RTLD_DEFAULT, arg);
if (!func) {
uwsgi_log("unable to call function \"%s\"\n", arg);
return -1;
}
return func();
}
static int uwsgi_hook_callret(char *arg) {
char *space = strchr(arg, ' ');
if (space) {
*space = 0;
int (*func)(char *) = dlsym(RTLD_DEFAULT, arg);
if (!func) {
uwsgi_log("unable to call function \"%s(%s)\"\n", arg, space + 1);
*space = ' ';
return -1;
}
*space = ' ';
return func(space + 1);
}
int (*func)(void) = dlsym(RTLD_DEFAULT, arg);
if (!func) {
uwsgi_log("unable to call function \"%s\"\n", arg);
return -1;
}
return func();
}
void uwsgi_register_base_hooks() {
uwsgi_register_hook("cd", uwsgi_hook_chdir);
uwsgi_register_hook("exec", uwsgi_hook_exec);
uwsgi_register_hook("mount", uwsgi_mount_hook);
uwsgi_register_hook("umount", uwsgi_umount_hook);
uwsgi_register_hook("call", uwsgi_hook_call);
uwsgi_register_hook("callret", uwsgi_hook_callret);
uwsgi_register_hook("callint", uwsgi_hook_callint);
uwsgi_register_hook("callintret", uwsgi_hook_callintret);
// for testing
uwsgi_register_hook("exit", uwsgi_hook_exit);
uwsgi_register_hook("print", uwsgi_hook_print);
}
void uwsgi_hooks_run(struct uwsgi_string_list *l, char *phase, int fatal) {
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);
}
*colon = 0;
struct uwsgi_hook *uh = uwsgi_hook_by_name(usl->value);
if (!uh) {
uwsgi_log("hook not found: %s\n", usl->value);
exit(1);
}
*colon = ':';
uwsgi_log("running \"%s\" (%s)...\n", usl->value, phase);
int ret = uh->func(colon+1);
if (fatal && ret != 0) {
exit(1);
}
}
}
+14
View File
@@ -357,6 +357,7 @@ void uwsgi_setup_workers() {
#ifdef UWSGI_ROUTING
uwsgi_fixup_routes(uwsgi.routes);
uwsgi_fixup_routes(uwsgi.error_routes);
uwsgi_fixup_routes(uwsgi.response_routes);
uwsgi_fixup_routes(uwsgi.final_routes);
#endif
@@ -451,6 +452,19 @@ void sanitize_args() {
exit(1);
}
if (uwsgi.cheaper_rss_limit_soft && uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG] != 1 && uwsgi.force_get_memusage != 1) {
uwsgi_log("enabling cheaper-rss-limit-soft requires enabling also memory-report\n");
exit(1);
}
if (uwsgi.cheaper_rss_limit_hard && !uwsgi.cheaper_rss_limit_soft) {
uwsgi_log("enabling cheaper-rss-limit-hard requires setting also cheaper-rss-limit-soft\n");
exit(1);
}
if ( uwsgi.cheaper_rss_limit_soft && uwsgi.cheaper_rss_limit_hard <= uwsgi.cheaper_rss_limit_soft) {
uwsgi_log("cheaper-rss-limit-hard value must be higher than cheaper-rss-limit-soft value\n");
exit(1);
}
/* here we try to choose if thunder lock is a good thing */
#ifdef UNBIT
if (uwsgi.numproc > 1 && !uwsgi.map_socket) {
+35 -6
View File
@@ -493,7 +493,7 @@ struct uwsgi_lock_item *uwsgi_lock_ipcsem_init(char *id) {
if (uwsgi.ftok) {
myKey = ftok(uwsgi.ftok, counter);
if (myKey < 0) {
uwsgi_error("ftok()");
uwsgi_error("uwsgi_lock_ipcsem_init()/ftok()");
exit(1);
}
counter++;
@@ -504,7 +504,7 @@ struct uwsgi_lock_item *uwsgi_lock_ipcsem_init(char *id) {
}
if (semid < 0) {
uwsgi_error("semget()");
uwsgi_error("uwsgi_lock_ipcsem_init()/semget()");
exit(1);
}
// do this now, to allows triggering of atexit hook in case of problems
@@ -512,7 +512,7 @@ struct uwsgi_lock_item *uwsgi_lock_ipcsem_init(char *id) {
semu.val = 1;
if (semctl(semid, 0, SETVAL, semu)) {
uwsgi_error("semctl()");
uwsgi_error("uwsgi_lock_ipcsem_init()/semctl()");
exit(1);
}
@@ -532,7 +532,13 @@ void uwsgi_lock_ipcsem(struct uwsgi_lock_item *uli) {
retry:
if (semop(semid, &sb, 1)) {
if (errno == EINTR) goto retry;
uwsgi_error("semop()");
uwsgi_error("uwsgi_lock_ipcsem()/semop()");
#ifdef EIDRM
if (errno == EIDRM) {
exit(UWSGI_BRUTAL_RELOAD_CODE);
}
#endif
exit(1);
}
}
@@ -549,7 +555,13 @@ void uwsgi_unlock_ipcsem(struct uwsgi_lock_item *uli) {
retry:
if (semop(semid, &sb, 1)) {
if (errno == EINTR) goto retry;
uwsgi_error("semop()");
uwsgi_error("uwsgi_unlock_ipcsem()/semop()");
#ifdef EIDRM
if (errno == EIDRM) {
exit(UWSGI_BRUTAL_RELOAD_CODE);
}
#endif
exit(1);
}
}
@@ -574,6 +586,8 @@ pid_t uwsgi_lock_ipcsem_check(struct uwsgi_lock_item *uli) {
void uwsgi_ipcsem_clear(void) {
if (uwsgi.persistent_ipcsem) return;
struct uwsgi_lock_item *uli = uwsgi.registered_locks;
if (!uwsgi.workers)
@@ -594,12 +608,27 @@ clear:
#ifdef UWSGI_DEBUG
uwsgi_log("removing sysvipc semaphores...\n");
#endif
#ifdef GETPID
while (uli) {
int semid = 0;
memcpy(&semid, uli->lock_ptr, sizeof(int));
int ret = semctl(semid, 0, GETPID);
if (ret > 0) {
if (ret != (int) getpid() && !kill((pid_t) ret, 0)) {
uwsgi_log("found ipcsem mapped to alive pid %d. skipping ipcsem removal.\n", ret);
return;
}
}
uli = uli->next;
}
uli = uwsgi.registered_locks;
#endif
while (uli) {
int semid = 0;
memcpy(&semid, uli->lock_ptr, sizeof(int));
if (semctl(semid, 0, IPC_RMID)) {
uwsgi_error("semctl()");
uwsgi_error("uwsgi_ipcsem_clear()/semctl()");
}
uli = uli->next;
}
+448 -14
View File
@@ -120,17 +120,54 @@ void uwsgi_log_verbose(const char *fmt, ...) {
static void fix_logpipe_buf(int *fd) {
int so_bufsize;
socklen_t so_bufsize_len = sizeof(int);
if (getsockopt(fd[0], SOL_SOCKET, SO_RCVBUF, &so_bufsize, &so_bufsize_len)) {
uwsgi_error("fix_logpipe_buf()/getsockopt()");
return;
}
if ((size_t)so_bufsize < uwsgi.log_master_bufsize) {
so_bufsize = uwsgi.log_master_bufsize;
if (setsockopt(fd[0], SOL_SOCKET, SO_RCVBUF, &so_bufsize, so_bufsize_len)) {
uwsgi_error("fix_logpipe_buf()/setsockopt()");
}
}
if (getsockopt(fd[1], SOL_SOCKET, SO_SNDBUF, &so_bufsize, &so_bufsize_len)) {
uwsgi_error("fix_logpipe_buf()/getsockopt()");
return;
}
if ((size_t)so_bufsize < uwsgi.log_master_bufsize) {
so_bufsize = uwsgi.log_master_bufsize;
if (setsockopt(fd[1], SOL_SOCKET, SO_SNDBUF, &so_bufsize, so_bufsize_len)) {
uwsgi_error("fix_logpipe_buf()/setsockopt()");
}
}
}
// create the logpipe
void create_logpipe(void) {
if (uwsgi.log_master_stream) {
if (socketpair(AF_UNIX, SOCK_STREAM, 0, uwsgi.shared->worker_log_pipe)) {
uwsgi_error("create_logpipe()/socketpair()\n");
exit(1);
}
}
else {
#if defined(SOCK_SEQPACKET) && defined(__linux__)
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, uwsgi.shared->worker_log_pipe)) {
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, uwsgi.shared->worker_log_pipe)) {
#else
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, uwsgi.shared->worker_log_pipe)) {
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, uwsgi.shared->worker_log_pipe)) {
#endif
uwsgi_error("socketpair()\n");
exit(1);
uwsgi_error("create_logpipe()/socketpair()\n");
exit(1);
}
fix_logpipe_buf(uwsgi.shared->worker_log_pipe);
}
uwsgi_socket_nb(uwsgi.shared->worker_log_pipe[0]);
@@ -149,13 +186,22 @@ void create_logpipe(void) {
}
if (uwsgi.req_log_master) {
if (uwsgi.log_master_req_stream) {
if (socketpair(AF_UNIX, SOCK_STREAM, 0, uwsgi.shared->worker_req_log_pipe)) {
uwsgi_error("create_logpipe()/socketpair()\n");
exit(1);
}
}
else {
#if defined(SOCK_SEQPACKET) && defined(__linux__)
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, uwsgi.shared->worker_req_log_pipe)) {
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, uwsgi.shared->worker_req_log_pipe)) {
#else
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, uwsgi.shared->worker_req_log_pipe)) {
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, uwsgi.shared->worker_req_log_pipe)) {
#endif
uwsgi_error("socketpair()\n");
exit(1);
uwsgi_error("create_logpipe()/socketpair()\n");
exit(1);
}
fix_logpipe_buf(uwsgi.shared->worker_req_log_pipe);
}
uwsgi_socket_nb(uwsgi.shared->worker_req_log_pipe[0]);
@@ -287,6 +333,8 @@ void logto(char *logfile) {
void uwsgi_setup_log() {
uwsgi_setup_log_encoders();
if (uwsgi.daemonize) {
if (uwsgi.has_emperor) {
@@ -1346,6 +1394,34 @@ void uwsgi_add_logchunk(int variable, int pos, char *ptr, size_t len) {
}
}
static void uwsgi_log_func_do(struct uwsgi_string_list *encoders, struct uwsgi_logger *ul, char *msg, size_t len) {
struct uwsgi_string_list *usl = encoders;
// note: msg must not be freed !!!
char *new_msg = msg;
size_t new_msg_len = len;
while(usl) {
struct uwsgi_log_encoder *ule = (struct uwsgi_log_encoder *) usl->custom_ptr;
size_t rlen = 0;
char *buf = ule->func(ule, new_msg, new_msg_len, &rlen);
if (new_msg != msg) {
free(new_msg);
}
new_msg = buf;
new_msg_len = rlen;
usl = usl->next;
}
if (ul) {
ul->func(ul, new_msg, new_msg_len);
}
else {
new_msg_len = (size_t) write(uwsgi.original_log_fd, new_msg, new_msg_len);
}
if (new_msg != msg) {
free(new_msg);
}
}
int uwsgi_master_log(void) {
ssize_t rlen = read(uwsgi.shared->worker_log_pipe[0], uwsgi.log_master_buf, uwsgi.log_master_bufsize);
@@ -1379,7 +1455,7 @@ int uwsgi_master_log(void) {
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, uwsgi.log_master_buf, rlen) >= 0) {
struct uwsgi_logger *ul_route = (struct uwsgi_logger *) url->custom_ptr;
if (ul_route) {
ul_route->func(ul_route, uwsgi.log_master_buf, rlen);
uwsgi_log_func_do(uwsgi.requested_log_encoders, ul_route, uwsgi.log_master_buf, rlen);
finish = 1;
}
}
@@ -1397,14 +1473,14 @@ int uwsgi_master_log(void) {
if (ul->id) {
goto next;
}
ul->func(ul, uwsgi.log_master_buf, rlen);
uwsgi_log_func_do(uwsgi.requested_log_encoders, ul, uwsgi.log_master_buf, rlen);
raw_log = 0;
next:
ul = ul->next;
}
if (raw_log) {
rlen = write(uwsgi.original_log_fd, uwsgi.log_master_buf, rlen);
uwsgi_log_func_do(uwsgi.requested_log_encoders, NULL, uwsgi.log_master_buf, rlen);
}
return 0;
}
@@ -1423,7 +1499,7 @@ int uwsgi_master_req_log(void) {
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, uwsgi.log_master_buf, rlen) >= 0) {
struct uwsgi_logger *ul_route = (struct uwsgi_logger *) url->custom_ptr;
if (ul_route) {
ul_route->func(ul_route, uwsgi.log_master_buf, rlen);
uwsgi_log_func_do(uwsgi.requested_log_req_encoders, ul_route, uwsgi.log_master_buf, rlen);
finish = 1;
}
}
@@ -1441,14 +1517,14 @@ int uwsgi_master_req_log(void) {
if (ul->id) {
goto next;
}
ul->func(ul, uwsgi.log_master_buf, rlen);
uwsgi_log_func_do(uwsgi.requested_log_req_encoders, ul, uwsgi.log_master_buf, rlen);
raw_log = 0;
next:
ul = ul->next;
}
if (raw_log) {
rlen = write(uwsgi.original_log_fd, uwsgi.log_master_buf, rlen);
uwsgi_log_func_do(uwsgi.requested_log_req_encoders, NULL, uwsgi.log_master_buf, rlen);
}
return 0;
}
@@ -1511,3 +1587,361 @@ void uwsgi_threaded_logger_spawn() {
}
}
void uwsgi_register_log_encoder(char *name, char *(*func)(struct uwsgi_log_encoder *, char *, size_t, size_t *)) {
struct uwsgi_log_encoder *old_ule = NULL, *ule = uwsgi.log_encoders;
while(ule) {
if (!strcmp(ule->name, name)) {
ule->func = func;
return;
}
old_ule = ule;
ule = ule->next;
}
ule = uwsgi_calloc(sizeof(struct uwsgi_log_encoder));
ule->name = name;
ule->func = func;
if (old_ule) {
old_ule->next = ule;
}
else {
uwsgi.log_encoders = ule;
}
}
struct uwsgi_log_encoder *uwsgi_log_encoder_by_name(char *name) {
struct uwsgi_log_encoder *ule = uwsgi.log_encoders;
while(ule) {
if (!strcmp(name, ule->name)) return ule;
ule = ule->next;
}
return NULL;
}
void uwsgi_setup_log_encoders() {
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.requested_log_encoders) {
char *space = strchr(usl->value, ' ');
if (space) *space = 0;
struct uwsgi_log_encoder *ule = uwsgi_log_encoder_by_name(usl->value);
if (!ule) {
uwsgi_log("log encoder \"%s\" not found\n", usl->value);
exit(1);
}
if (space) *space = ' ';
struct uwsgi_log_encoder *ule2 = uwsgi_malloc(sizeof(struct uwsgi_log_encoder));
memcpy(ule2, ule, sizeof(struct uwsgi_log_encoder));
// we use a copy
if (space) {
ule2->args = uwsgi_str(space+1);
}
else {
ule2->args = uwsgi_str("");
}
usl->custom_ptr = ule2;
uwsgi_log("[log-encoder] registered %s\n", usl->value);
}
uwsgi_foreach(usl, uwsgi.requested_log_req_encoders) {
char *space = strchr(usl->value, ' ');
if (space) *space = 0;
struct uwsgi_log_encoder *ule = uwsgi_log_encoder_by_name(usl->value);
if (!ule) {
uwsgi_log("log encoder \"%s\" not found\n", usl->value);
exit(1);
}
if (space) *space = ' ';
struct uwsgi_log_encoder *ule2 = uwsgi_malloc(sizeof(struct uwsgi_log_encoder));
memcpy(ule2, ule, sizeof(struct uwsgi_log_encoder));
// we use a copy
if (space) {
ule2->args = uwsgi_str(space+1);
}
else {
ule2->args = uwsgi_str("");
}
usl->custom_ptr = ule2;
uwsgi_log("[log-req-encoder] registered %s\n", usl->value);
}
}
#ifdef UWSGI_ZLIB
static char *uwsgi_log_encoder_gzip(struct uwsgi_log_encoder *ule, char *msg, size_t len, size_t *rlen) {
struct uwsgi_buffer *ub = uwsgi_gzip(msg, len);
if (!ub) return NULL;
*rlen = ub->pos;
// avoid destruction
char *buf = ub->buf;
ub->buf = NULL;
uwsgi_buffer_destroy(ub);
return buf;
}
static char *uwsgi_log_encoder_compress(struct uwsgi_log_encoder *ule, char *msg, size_t len, size_t *rlen) {
size_t c_len = (size_t) compressBound(len);
uLongf destLen = c_len;
char *buf = uwsgi_malloc(c_len);
if (compress((Bytef *) buf, &destLen, (Bytef *)msg, (uLong) len) == Z_OK) {
*rlen = destLen;
return buf;
}
free(buf);
return NULL;
}
#endif
/*
really fast encoder adding only a prefix
*/
static char *uwsgi_log_encoder_prefix(struct uwsgi_log_encoder *ule, char *msg, size_t len, size_t *rlen) {
char *buf = NULL;
struct uwsgi_buffer *ub = uwsgi_buffer_new(len + strlen(ule->args));
if (uwsgi_buffer_append(ub, ule->args, strlen(ule->args))) goto end;
if (uwsgi_buffer_append(ub, msg, len)) goto end;
*rlen = ub->pos;
buf = ub->buf;
ub->buf = NULL;
end:
uwsgi_buffer_destroy(ub);
return buf;
}
/*
really fast encoder adding only a newline
*/
static char *uwsgi_log_encoder_nl(struct uwsgi_log_encoder *ule, char *msg, size_t len, size_t *rlen) {
char *buf = NULL;
struct uwsgi_buffer *ub = uwsgi_buffer_new(len + 1);
if (uwsgi_buffer_append(ub, msg, len)) goto end;
if (uwsgi_buffer_byte(ub, '\n')) goto end;
*rlen = ub->pos;
buf = ub->buf;
ub->buf = NULL;
end:
uwsgi_buffer_destroy(ub);
return buf;
}
/*
really fast encoder adding only a suffix
*/
static char *uwsgi_log_encoder_suffix(struct uwsgi_log_encoder *ule, char *msg, size_t len, size_t *rlen) {
char *buf = NULL;
struct uwsgi_buffer *ub = uwsgi_buffer_new(len + strlen(ule->args));
if (uwsgi_buffer_append(ub, msg, len)) goto end;
if (uwsgi_buffer_append(ub, ule->args, strlen(ule->args))) goto end;
*rlen = ub->pos;
buf = ub->buf;
ub->buf = NULL;
end:
uwsgi_buffer_destroy(ub);
return buf;
}
void uwsgi_log_encoder_parse_vars(struct uwsgi_log_encoder *ule) {
char *ptr = ule->args;
size_t remains = strlen(ptr);
char *base = ptr;
size_t base_len = 0;
char *var = NULL;
size_t var_len = 0;
int status = 0; // 1 -> $ 2-> { end -> }
while(remains--) {
char b = *ptr++;
if (status == 1) {
if (b == '{') {
status = 2;
continue;
}
base_len+=2;
status = 0;
continue;
}
else if (status == 2) {
if (b == '}') {
status = 0;
uwsgi_string_new_list((struct uwsgi_string_list **) &ule->data, uwsgi_concat2n(base, base_len, "", 0));
struct uwsgi_string_list *usl = uwsgi_string_new_list((struct uwsgi_string_list **) &ule->data, uwsgi_concat2n(var, var_len, "", 0));
usl->custom = 1;
var = NULL;
var_len = 0;
base = NULL;
base_len = 0;
continue;
}
if (!var) var = (ptr-1);
var_len++;
continue;
}
// status == 0
if (b == '$') {
status = 1;
}
else {
if (!base) base = (ptr-1);
base_len++;
}
}
if (base) {
if (status == 1) {
base_len+=2;
}
else if (status == 2) {
base_len+=3;
}
uwsgi_string_new_list((struct uwsgi_string_list **) &ule->data, uwsgi_concat2n(base, base_len, "", 0));
}
}
/*
// format: foo ${var} bar
msg (the logline)
msgnl (the logine with newline)
unix (the time_t value)
micros (current microseconds)
strftime (strftime)
*/
static char *uwsgi_log_encoder_format(struct uwsgi_log_encoder *ule, char *msg, size_t len, size_t *rlen) {
if (!ule->configured) {
uwsgi_log_encoder_parse_vars(ule);
ule->configured = 1;
}
struct uwsgi_buffer *ub = uwsgi_buffer_new(strlen(ule->args) + len);
struct uwsgi_string_list *usl = (struct uwsgi_string_list *) ule->data;
char *buf = NULL;
while(usl) {
if (usl->custom) {
if (!uwsgi_strncmp(usl->value, usl->len, "msg", 3)) {
if (msg[len-1] == '\n') {
if (uwsgi_buffer_append(ub, msg, len-1)) goto end;
}
else {
if (uwsgi_buffer_append(ub, msg, len)) goto end;
}
}
else if (!uwsgi_strncmp(usl->value, usl->len, "msgnl", 5)) {
if (uwsgi_buffer_append(ub, msg, len)) goto end;
}
else if (!uwsgi_strncmp(usl->value, usl->len, "unix", 4)) {
if (uwsgi_buffer_num64(ub, uwsgi_now())) goto end;
}
else if (!uwsgi_strncmp(usl->value, usl->len, "micros", 6)) {
if (uwsgi_buffer_num64(ub, uwsgi_micros())) goto end;
}
else if (!uwsgi_starts_with(usl->value, usl->len, "strftime:", 9)) {
char sftime[64];
time_t now = uwsgi_now();
char *buf = uwsgi_concat2n(usl->value+9, usl->len-9,"", 0);
int strftime_len = strftime(sftime, 64, buf, localtime(&now));
free(buf);
if (strftime_len > 0) {
if (uwsgi_buffer_append(ub, sftime, strftime_len)) goto end;
}
}
}
else {
if (uwsgi_buffer_append(ub, usl->value, usl->len)) goto end;
}
usl = usl->next;
}
buf = ub->buf;
*rlen = ub->pos;
ub->buf = NULL;
end:
uwsgi_buffer_destroy(ub);
return buf;
}
static char *uwsgi_log_encoder_json(struct uwsgi_log_encoder *ule, char *msg, size_t len, size_t *rlen) {
if (!ule->configured) {
uwsgi_log_encoder_parse_vars(ule);
ule->configured = 1;
}
struct uwsgi_buffer *ub = uwsgi_buffer_new(strlen(ule->args) + len);
struct uwsgi_string_list *usl = (struct uwsgi_string_list *) ule->data;
char *buf = NULL;
while(usl) {
if (usl->custom) {
if (!uwsgi_strncmp(usl->value, usl->len, "msg", 3)) {
size_t msg_len = len;
if (msg[len-1] == '\n') msg_len--;
char *e_json = uwsgi_malloc(msg_len * 2);
escape_json(msg, msg_len, e_json);
if (uwsgi_buffer_append(ub, e_json, strlen(e_json))){
free(e_json);
goto end;
}
free(e_json);
}
else if (!uwsgi_strncmp(usl->value, usl->len, "msgnl", 5)) {
char *e_json = uwsgi_malloc(len * 2);
escape_json(msg, len, e_json);
if (uwsgi_buffer_append(ub, e_json, strlen(e_json))){
free(e_json);
goto end;
}
free(e_json);
}
else if (!uwsgi_strncmp(usl->value, usl->len, "unix", 4)) {
if (uwsgi_buffer_num64(ub, uwsgi_now())) goto end;
}
else if (!uwsgi_strncmp(usl->value, usl->len, "micros", 6)) {
if (uwsgi_buffer_num64(ub, uwsgi_micros())) goto end;
}
else if (!uwsgi_starts_with(usl->value, usl->len, "strftime:", 9)) {
char sftime[64];
time_t now = uwsgi_now();
char *buf = uwsgi_concat2n(usl->value+9, usl->len-9, "", 0);
int strftime_len = strftime(sftime, 64, buf, localtime(&now));
free(buf);
if (strftime_len > 0) {
char *e_json = uwsgi_malloc(strftime_len * 2);
escape_json(sftime, strftime_len, e_json);
if (uwsgi_buffer_append(ub, e_json, strlen(e_json))){
free(e_json);
goto end;
}
free(e_json);
}
}
}
else {
if (uwsgi_buffer_append(ub, usl->value, usl->len)) goto end;
}
usl = usl->next;
}
buf = ub->buf;
*rlen = ub->pos;
ub->buf = NULL;
end:
uwsgi_buffer_destroy(ub);
return buf;
}
void uwsgi_log_encoders_register_embedded() {
uwsgi_register_log_encoder("prefix", uwsgi_log_encoder_prefix);
uwsgi_register_log_encoder("suffix", uwsgi_log_encoder_suffix);
uwsgi_register_log_encoder("nl", uwsgi_log_encoder_nl);
uwsgi_register_log_encoder("format", uwsgi_log_encoder_format);
uwsgi_register_log_encoder("json", uwsgi_log_encoder_json);
#ifdef UWSGI_ZLIB
uwsgi_register_log_encoder("gzip", uwsgi_log_encoder_gzip);
uwsgi_register_log_encoder("compress", uwsgi_log_encoder_compress);
#endif
}
+5
View File
@@ -905,6 +905,11 @@ next:
else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_QUIET_CODE) {
// noop
}
else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_BRUTAL_RELOAD_CODE) {
uwsgi_log("!!! inconsistent state reported by worker %d (pid: %d) !!!\n", thewid, (int) diedpid);
reap_them_all(0);
continue;
}
else if (uwsgi.workers[thewid].manage_next_request) {
if (WIFSIGNALED(waitpid_status)) {
uwsgi_log("DAMN ! worker %d (pid: %d) died, killed by signal %d :( trying respawn ...\n", thewid, (int) diedpid, (int) WTERMSIG(waitpid_status));
+28 -1
View File
@@ -115,7 +115,34 @@ int uwsgi_calc_cheaper(void) {
last_check = now;
int needed_workers = uwsgi.cheaper_algo();
int ignore_algo = 0;
int needed_workers = 0;
// first check if memory usage is not exceeded
if (uwsgi.cheaper_rss_limit_soft) {
unsigned long long total_rss = 0;
int i;
int active_workers = 0;
for(i=1;i<=uwsgi.numproc;i++) {
if (!uwsgi.workers[i].cheaped) {
total_rss += uwsgi.workers[i].rss_size;
active_workers++;
}
}
if (uwsgi.cheaper_rss_limit_hard && active_workers > 1 && total_rss >= uwsgi.cheaper_rss_limit_hard) {
uwsgi_log("cheaper hard rss memory limit exceeded, cheap one of %d workers\n", active_workers);
needed_workers = -1;
ignore_algo = 1;
}
else if (total_rss >= uwsgi.cheaper_rss_limit_soft) {
#ifdef UWSGI_DEBUG
uwsgi_log("cheaper soft rss memory limit exceeded, can't spawn more workers\n");
#endif
ignore_algo = 1;
}
}
if (!ignore_algo) needed_workers = uwsgi.cheaper_algo();
if (needed_workers > 0) {
for (i = 1; i <= uwsgi.numproc; i++) {
+240
View File
@@ -0,0 +1,240 @@
#include <uwsgi.h>
/*
jail systems (Linux namespaces, FreeBSD jails...) heavily rely on mount/umount
to simplify setups (expecially because the mount command could not be available in
the initial phase of jailing, we need an api to mount/umount filesystems
int uwsgi_mount(char *fs, char *what, char *where, int flags);
int uwsgi_umount(char *where, int flags);
*/
#ifdef __linux__
#ifndef MS_REC
#define MS_REC 16384
#endif
#endif
struct uwsgi_mount_flag {
char *key;
uint64_t value;
};
static struct uwsgi_mount_flag umflags[] = {
#ifdef MS_BIND
{"bind", MS_BIND},
#endif
#ifdef MS_DIRSYNC
{"dirsync", MS_DIRSYNC},
#endif
#ifdef MS_MANDLOCK
{"mandlock", MS_MANDLOCK},
#endif
#ifdef MS_MOVE
{"move", MS_MOVE},
#endif
#ifdef MS_NOATIME
{"noatime", MS_NOATIME},
#endif
#ifdef MS_NODEV
{"nodev", MS_NODEV},
#endif
#ifdef MS_NOEXEC
{"noexec", MS_NOEXEC},
#endif
#ifdef MS_RDONLY
{"rdonly", MS_RDONLY},
{"readonly", MS_RDONLY},
{"ro", MS_RDONLY},
#endif
#ifdef MS_REMOUNT
{"remount", MS_REMOUNT},
#endif
#ifdef MS_SYNCHRONOUS
{"sync", MS_SYNCHRONOUS},
#endif
#ifdef MNT_FORCE
{"force", MNT_FORCE},
#endif
#ifdef MNT_DETACH
{"detach", MNT_DETACH},
#endif
#ifdef MS_REC
{"rec", MS_REC},
{"recursive", MS_REC},
#endif
#ifdef MS_PRIVATE
{"private", MS_PRIVATE},
#endif
#ifdef MS_SHARED
{"shared", MS_SHARED},
#endif
#ifdef MNT_RDONLY
{"rdonly", MNT_RDONLY},
{"readonly", MNT_RDONLY},
{"ro", MNT_RDONLY},
#endif
#ifdef MNT_NOEXEC
{"noexec", MNT_NOEXEC},
#endif
#ifdef MNT_NOSUID
{"nosuid", MNT_NOSUID},
#endif
#ifdef MNT_NOATIME
{"noatime", MNT_NOATIME},
#endif
#ifdef MNT_SNAPSHOT
{"snapshot", MNT_SNAPSHOT},
#endif
{NULL, 0},
};
uint64_t uwsgi_mount_flag(char *mflag) {
struct uwsgi_mount_flag *umf = umflags;
while(umf->key) {
if (!strcmp(umf->key, mflag)) return umf->value;
umf++;
}
return 0;
}
int uwsgi_mount(char *fs, char *what, char *where, char *flags) {
#ifdef __FreeBSD__
struct iovec iov[6];
#endif
unsigned long mountflags = 0;
if (!flags) goto parsed;
char *mflags = uwsgi_str(flags);
char *p = strtok(mflags, ",");
while(p) {
unsigned long flag = (unsigned long) uwsgi_mount_flag(p);
if (!flag) {
uwsgi_log("unknown mount flag \"%s\"\n", p);
exit(1);
}
mountflags |= flag;
p = strtok(NULL, ",");
}
free(mflags);
parsed:
#ifdef __linux__
return mount(what, where, fs, mountflags, NULL);
#elif defined(__FreeBSD__)
iov[0].iov_base = "fstype";
iov[0].iov_len = 7;
iov[1].iov_base = fs;
iov[1].iov_len = strlen(fs) + 1;
iov[2].iov_base = "fspath";
iov[2].iov_len = 7;
iov[3].iov_base = where;
iov[3].iov_len = strlen(where) + 1;
iov[4].iov_base = "target";
iov[4].iov_len = 7;
iov[5].iov_base = what;
iov[5].iov_len = strlen(what) + 1;
return nmount(iov, 6, (int) mountflags);
#endif
return -1;
}
int uwsgi_umount(char *where, char *flags) {
unsigned long mountflags = 0;
if (!flags) goto parsed;
char *mflags = uwsgi_str(flags);
char *p = strtok(mflags, ",");
while(p) {
unsigned long flag = (unsigned long) uwsgi_mount_flag(p);
if (!flag) {
uwsgi_log("unknown umount flag \"%s\"\n", p);
exit(1);
}
mountflags |= flag;
p = strtok(NULL, ",");
}
free(mflags);
parsed:
#ifdef __linux__
// we need a special case for recursive umount
if (mountflags & MS_REC) {
mountflags &= ~MS_REC;
int unmounted = 1;
char *slashed = uwsgi_concat2(where, "/");
while (unmounted) {
unmounted = 0;
FILE *procmounts = fopen("/proc/self/mounts", "r");
if (!procmounts) {
uwsgi_log("the /proc filesystem must be mounted for recursive umount\n");
uwsgi_error("open()");
exit(1);
}
char line[1024];
while (fgets(line, 1024, procmounts) != NULL) {
char *delim0 = strchr(line, ' ');
if (!delim0) continue;
delim0++;
char *delim1 = strchr(delim0, ' ');
if (!delim1) continue;
*delim1 = 0;
if (!uwsgi_starts_with(delim0, strlen(delim0), slashed, strlen(slashed))) goto unmountable;
continue;
unmountable:
if (!umount2(delim0, mountflags)) unmounted++;
}
fclose(procmounts);
}
free(slashed);
}
return umount2(where, mountflags);
#elif defined(__FreeBSD__)
return unmount(where, mountflags);
#endif
return -1;
}
int uwsgi_mount_hook(char *arg) {
char *tmp_arg = uwsgi_str(arg);
char *fs = tmp_arg;
char *what = strchr(fs, ' ');
if (!what) goto error;
*what = 0; what++;
char *where = strchr(what, ' ');
if (!where) goto error;
*where = 0; where++;
char *flags = strchr(where, ' ');
if (flags) {
*flags = 0; flags++;
}
if (uwsgi_mount(fs, what, where, flags)) {
uwsgi_error("uwsgi_mount()");
free(tmp_arg);
return -1;
}
free(tmp_arg);
return 0;
error:
free(tmp_arg);
uwsgi_log("uwsgi_mount_hook() invalid syntax\n");
return -1;
}
int uwsgi_umount_hook(char *arg) {
char *tmp_arg = uwsgi_str(arg);
char *where = tmp_arg;
char *flags = strchr(where, ' ');
if (flags) {
*flags = 0; flags++;
}
if (uwsgi_umount(where, flags)) {
uwsgi_error("uwsgi_umount()");
free(tmp_arg);
return -1;
}
free(tmp_arg);
return 0;
}
+90 -1
View File
@@ -180,6 +180,10 @@ int uwsgi_apply_routes_do(struct uwsgi_route *routes, struct wsgi_request *wsgi_
r_goto = &wsgi_req->error_route_goto;
r_pc = &wsgi_req->error_route_pc;
}
else if (routes == uwsgi.response_routes) {
r_goto = &wsgi_req->response_route_goto;
r_pc = &wsgi_req->response_route_pc;
}
else if (routes == uwsgi.final_routes) {
r_goto = &wsgi_req->final_route_goto;
r_pc = &wsgi_req->final_route_pc;
@@ -306,6 +310,20 @@ int uwsgi_apply_error_routes(struct wsgi_request *wsgi_req) {
return uwsgi_apply_routes_do(uwsgi.error_routes, wsgi_req, NULL, 0);
}
int uwsgi_apply_response_routes(struct wsgi_request *wsgi_req) {
if (!uwsgi.response_routes) return 0;
if (wsgi_req->response_routes_applied) return 0;
// do not forget to check it !!!
if (wsgi_req->is_response_routing) return 0;
wsgi_req->is_response_routing = 1;
int ret = uwsgi_apply_routes_do(uwsgi.response_routes, wsgi_req, NULL, 0);
wsgi_req->response_routes_applied = 1;
return ret;
}
static void *uwsgi_route_get_condition_func(char *name) {
struct uwsgi_route_condition *urc = uwsgi.route_conditions;
@@ -337,6 +355,9 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
else if (!uwsgi_starts_with(opt, strlen(opt), "error", 5)) {
ur = uwsgi.error_routes;
}
else if (!uwsgi_starts_with(opt, strlen(opt), "response", 8)) {
ur = uwsgi.response_routes;
}
uint64_t pos = 0;
while(ur) {
old_ur = ur;
@@ -354,6 +375,9 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
else if (!uwsgi_starts_with(opt, strlen(opt), "error", 5)) {
uwsgi.error_routes = ur;
}
else if (!uwsgi_starts_with(opt, strlen(opt), "response", 8)) {
uwsgi.response_routes = ur;
}
else {
uwsgi.routes = ur;
}
@@ -701,6 +725,11 @@ static int uwsgi_router_goto_func(struct wsgi_request *wsgi_req, struct uwsgi_ro
r_goto = &wsgi_req->final_route_goto;
r_pc = &wsgi_req->final_route_pc;
}
else if (wsgi_req->is_response_routing) {
routes = uwsgi.response_routes;
r_goto = &wsgi_req->response_route_goto;
r_pc = &wsgi_req->response_route_pc;
}
while(routes) {
if (!routes->label) goto next;
if (!uwsgi_strncmp(routes->label, routes->label_len, ub->buf, ub->pos)) {
@@ -806,6 +835,31 @@ static int uwsgi_router_remheader(struct uwsgi_route *ur, char *arg) {
return 0;
}
// clearheaders route
static int uwsgi_router_clearheaders_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
if (!ub) return UWSGI_ROUTE_BREAK;
if (uwsgi_response_prepare_headers(wsgi_req, ub->buf, ub->pos)) {
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_BREAK;
}
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_clearheaders(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_clearheaders_func;
ur->data = arg;
ur->data_len = strlen(arg);
return 0;
}
// signal route
@@ -1630,6 +1684,8 @@ void uwsgi_register_embedded_routers() {
uwsgi_register_router("addheader", uwsgi_router_addheader);
uwsgi_register_router("delheader", uwsgi_router_remheader);
uwsgi_register_router("remheader", uwsgi_router_remheader);
uwsgi_register_router("clearheaders", uwsgi_router_clearheaders);
uwsgi_register_router("resetheaders", uwsgi_router_clearheaders);
uwsgi_register_router("signal", uwsgi_router_signal);
uwsgi_register_router("send", uwsgi_router_send);
uwsgi_register_router("send-crnl", uwsgi_router_send_crnl);
@@ -1750,6 +1806,7 @@ struct uwsgi_route_condition *uwsgi_register_route_condition(char *name, int (*f
}
void uwsgi_routing_dump() {
struct uwsgi_string_list *usl = NULL;
struct uwsgi_route *routes = uwsgi.routes;
if (!routes) goto next;
uwsgi_log("*** dumping internal routing table ***\n");
@@ -1784,8 +1841,25 @@ next:
}
uwsgi_log("*** end of the internal error routing table ***\n");
next2:
routes = uwsgi.response_routes;
if (!routes) goto next3;
uwsgi_log("*** dumping internal response routing table ***\n");
while(routes) {
if (routes->label) {
uwsgi_log("[rule: %llu] label: %s\n", (unsigned long long ) routes->pos, routes->label);
}
else if (!routes->subject_str && !routes->if_func) {
uwsgi_log("[rule: %llu] action: %s\n", (unsigned long long ) routes->pos, routes->action);
}
else {
uwsgi_log("[rule: %llu] subject: %s %s: %s%s action: %s\n", (unsigned long long ) routes->pos, routes->subject_str, routes->if_func ? "func" : "regexp", routes->if_negate ? "!" : "", routes->regexp, routes->action);
}
routes = routes->next;
}
uwsgi_log("*** end of the internal response routing table ***\n");
next3:
routes = uwsgi.final_routes;
if (!routes) return;
if (!routes) goto next4;
uwsgi_log("*** dumping internal final routing table ***\n");
while(routes) {
if (routes->label) {
@@ -1800,5 +1874,20 @@ next2:
routes = routes->next;
}
uwsgi_log("*** end of the internal final routing table ***\n");
next4:
uwsgi_foreach(usl, uwsgi.collect_headers) {
char *space = strchr(usl->value, ' ');
if (!space) {
uwsgi_log("invalid collect header syntax, must be <header> <var>\n");
exit(1);
}
*space = 0;
usl->custom = strlen(usl->value);
*space = ' ';
usl->custom_ptr = space+1;
usl->custom2 = strlen(space+1);
uwsgi_log("collecting header %.*s to var %s\n", usl->custom, usl->value, usl->custom_ptr);
}
}
#endif
+9 -6
View File
@@ -4,6 +4,11 @@ extern struct uwsgi_server uwsgi;
// sendfile() abstraction
ssize_t uwsgi_sendfile_do(int sockfd, int filefd, size_t pos, size_t len) {
// for platform not supporting sendfile we need to rely on boring read/write
// generally that platforms have very low memory, so use a 8k buffer
char buf[8192];
if (uwsgi.disable_sendfile) goto no_sendfile;
#if defined(__FreeBSD__) || defined(__DragonFly__)
off_t sf_len = len;
@@ -18,12 +23,11 @@ ssize_t uwsgi_sendfile_do(int sockfd, int filefd, size_t pos, size_t len) {
#elif defined(__linux__) || defined(__sun__)
off_t off = pos;
return sendfile(sockfd, filefd, &off, len);
#else
// for platform not supporting sendfile we need to rely on boring read/write
// generally that platforms have very low memory, so use a 8k buffer
char buf[8192];
#endif
no_sendfile:
if (pos > 0) {
if (lseek(filefd, pos, SEEK_SET)) {
if (lseek(filefd, pos, SEEK_SET) < 0) {
uwsgi_error("uwsgi_sendfile_do()/seek()");
return -1;
}
@@ -34,7 +38,6 @@ ssize_t uwsgi_sendfile_do(int sockfd, int filefd, size_t pos, size_t len) {
return -1;
}
return write(sockfd, buf, rlen);
#endif
}
+22 -1
View File
@@ -1785,7 +1785,8 @@ void uwsgi_bind_sockets() {
int fd = open("/dev/null", O_RDONLY);
if (fd < 0) {
uwsgi_error_open("/dev/null");
exit(1);
uwsgi_log("WARNING: unable to remap stdin, /dev/null not available\n");
goto stdin_done;
}
if (fd != 0) {
if (dup2(fd, 0) < 0) {
@@ -1803,6 +1804,8 @@ void uwsgi_bind_sockets() {
}
stdin_done:
// check for auto_port socket
uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
@@ -1955,3 +1958,21 @@ void uwsgi_tcp_nodelay(int fd) {
#endif
}
int uwsgi_accept(int server_fd) {
struct sockaddr_un client_src;
memset(&client_src, 0, sizeof(struct sockaddr_un));
socklen_t client_src_len = 0;
#if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL)
return accept4(server_fd, (struct sockaddr *) &client_src, &client_src_len, SOCK_NONBLOCK);
#elif defined(__linux__)
int client_fd = accept(server_fd, (struct sockaddr *) &client_src, &client_src_len);
if (client_fd >= 0) {
uwsgi_socket_nb(client_fd);
}
return client_fd;
#else
return accept(server_fd, (struct sockaddr *) &client_src, &client_src_len);
#endif
}
+4
View File
@@ -71,7 +71,11 @@ SSL_SESSION *uwsgi_ssl_session_get_cb(SSL *ssl, unsigned char *key, int keylen,
}
return NULL;
}
#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL)
SSL_SESSION *sess = d2i_SSL_SESSION(NULL, (const unsigned char **)&value, valsize);
#else
SSL_SESSION *sess = d2i_SSL_SESSION(NULL, (unsigned char **)&value, valsize);
#endif
uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock);
return sess;
}
+318 -11
View File
@@ -344,6 +344,8 @@ void uwsgi_as_root() {
}
#endif
int in_jail = 0;
#if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL)
if (uwsgi.unshare && !uwsgi.reloads) {
@@ -354,9 +356,221 @@ void uwsgi_as_root() {
else {
uwsgi_log("[linux-namespace] applied unshare() mask: %d\n", uwsgi.unshare);
}
in_jail = 1;
}
#endif
#if defined(__FreeBSD__)
if (uwsgi.jail && !uwsgi.reloads) {
struct jail ujail;
char *jarg = uwsgi_str(uwsgi.jail);
char *j_hostname = NULL;
char *j_name = NULL;
char *space = strchr(jarg, ' ');
if (space) {
*space = 0;
j_hostname = space + 1;
space = strchr(j_hostname, ' ');
if (space) {
*space = 0;
j_name = space + 1;
}
}
ujail.version = JAIL_API_VERSION;
ujail.path = jarg;
ujail.hostname = j_hostname ? j_hostname : "";
ujail.jailname = j_name;
ujail.ip4s = 0;
ujail.ip6s = 0;
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.jail_ip4) {
ujail.ip4s++;
}
struct in_addr *saddr = uwsgi_calloc(sizeof(struct in_addr) * ujail.ip4s);
int i = 0;
uwsgi_foreach(usl, uwsgi.jail_ip4) {
if (!inet_pton(AF_INET, usl->value, &saddr[i].s_addr)) {
uwsgi_error("jail()/inet_pton()");
exit(1);
}
i++;
}
ujail.ip4 = saddr;
#ifdef AF_INET6
uwsgi_foreach(usl, uwsgi.jail_ip6) {
ujail.ip6s++;
}
struct in6_addr *saddr6 = uwsgi_calloc(sizeof(struct in6_addr) * ujail.ip6s);
i = 0;
uwsgi_foreach(usl, uwsgi.jail_ip6) {
if (!inet_pton(AF_INET6, usl->value, &saddr6[i].s6_addr)) {
uwsgi_error("jail()/inet_pton()");
exit(1);
}
i++;
}
ujail.ip6 = saddr6;
#endif
int jail_id = jail(&ujail);
if (jail_id < 0) {
uwsgi_error("jail()");
exit(1);
}
if (uwsgi.jidfile) {
if (uwsgi_write_intfile(uwsgi.jidfile, jail_id)) {
uwsgi_log("unable to write jidfile\n");
exit(1);
}
}
uwsgi_log("--- running in FreeBSD jail %d ---\n", jail_id);
in_jail = 1;
}
#ifdef UWSGI_HAS_FREEBSD_LIBJAIL
if (uwsgi.jail_attach && !uwsgi.reloads) {
struct jailparam jparam;
uwsgi_log("attaching to FreeBSD jail %s ...\n", uwsgi.jail_attach);
if (!is_a_number(uwsgi.jail_attach)) {
if (jailparam_init(&jparam, "name")) {
uwsgi_error("jailparam_init()");
exit(1);
}
}
else {
if (jailparam_init(&jparam, "jid")) {
uwsgi_error("jailparam_init()");
exit(1);
}
}
jailparam_import(&jparam, uwsgi.jail_attach);
int jail_id = jailparam_set(&jparam, 1, JAIL_UPDATE|JAIL_ATTACH);
if (jail_id < 0) {
uwsgi_error("jailparam_set()");
exit(1);
}
jailparam_free(&jparam, 1);
uwsgi_log("--- running in FreeBSD jail %d ---\n", jail_id);
in_jail = 1;
}
if (uwsgi.jail2 && !uwsgi.reloads) {
struct uwsgi_string_list *usl = NULL;
unsigned nparams = 0;
uwsgi_foreach(usl, uwsgi.jail2) {
nparams++;
}
struct jailparam *params = uwsgi_malloc(sizeof(struct jailparam) * nparams);
int i = 0;
uwsgi_foreach(usl, uwsgi.jail2) {
uwsgi_log("FreeBSD libjail applying %s\n", usl->value);
char *equal = strchr(usl->value, '=');
if (equal) {
*equal = 0;
}
if (jailparam_init(&params[i], usl->value)) {
uwsgi_error("jailparam_init()");
exit(1);
}
if (equal) {
jailparam_import(&params[i], equal+1);
*equal = '=';
}
else {
jailparam_import(&params[i], "1");
}
i++;
}
int jail_id = jailparam_set(params, nparams, JAIL_CREATE|JAIL_ATTACH);
if (jail_id < 0) {
uwsgi_error("jailparam_set()");
exit(1);
}
jailparam_free(params, nparams);
if (uwsgi.jidfile) {
if (uwsgi_write_intfile(uwsgi.jidfile, jail_id)) {
uwsgi_log("unable to write jidfile\n");
exit(1);
}
}
uwsgi_log("--- running in FreeBSD jail %d ---\n", jail_id);
in_jail = 1;
}
#endif
#endif
if (in_jail) {
uwsgi_hooks_run(uwsgi.hook_post_jail, "post-jail", 1);
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.mount_post_jail) {
uwsgi_log("mounting \"%s\" (post-jail)...\n", usl->value);
if (uwsgi_mount_hook(usl->value)) {
exit(1);
}
}
uwsgi_foreach(usl, uwsgi.umount_post_jail) {
uwsgi_log("un-mounting \"%s\" (post-jail)...\n", usl->value);
if (uwsgi_umount_hook(usl->value)) {
exit(1);
}
}
uwsgi_foreach(usl, uwsgi.exec_post_jail) {
uwsgi_log("running \"%s\" (post-jail)...\n", usl->value);
int ret = uwsgi_run_command_and_wait(NULL, usl->value);
if (ret != 0) {
uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret);
exit(1);
}
}
uwsgi_foreach(usl, uwsgi.call_post_jail) {
if (uwsgi_call_symbol(usl->value)) {
uwsgi_log("unable to call function \"%s\"\n", usl->value);
exit(1);
}
}
if (uwsgi.refork_post_jail) {
uwsgi_log("re-fork()ing...\n");
pid_t pid = fork();
if (pid < 0) {
uwsgi_error("fork()");
exit(1);
}
if (pid > 0) {
// block all signals
sigset_t smask;
sigfillset(&smask);
sigprocmask(SIG_BLOCK, &smask, NULL);
int status;
if (waitpid(pid, &status, 0) < 0) {
uwsgi_error("waitpid()");
}
_exit(0);
}
}
int i;
for (i = 0; i < uwsgi.gp_cnt; i++) {
if (uwsgi.gp[i]->post_jail) {
uwsgi.gp[i]->post_jail();
}
}
}
if (uwsgi.chroot && !uwsgi.reloads) {
if (!uwsgi.master_as_root)
@@ -372,6 +586,52 @@ void uwsgi_as_root() {
#endif
}
#ifdef __linux__
if (uwsgi.pivot_root && !uwsgi.reloads) {
char *arg = uwsgi_str(uwsgi.pivot_root);
char *space = strchr(arg, ' ');
if (!space) {
uwsgi_log("invalid pivot_root syntax, new_root and put_old must be separated by a space\n");
exit(1);
}
*space = 0;
if (chdir(arg)) {
uwsgi_error("pivot_root()/chdir()");
exit(1);
}
space += 1+strlen(arg);
if (space[0] == '/') space++;
if (pivot_root(".", space)) {
uwsgi_error("pivot_root()");
exit(1);
}
if (uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG]) {
uwsgi_log("*** Warning, on linux system you have to bind-mount the /proc fs in your chroot to get memory debug/report.\n");
}
free(arg);
}
#endif
if (uwsgi.refork_as_root) {
uwsgi_log("re-fork()ing...\n");
pid_t pid = fork();
if (pid < 0) {
uwsgi_error("fork()");
exit(1);
}
if (pid > 0) {
// block all signals
sigset_t smask;
sigfillset(&smask);
sigprocmask(SIG_BLOCK, &smask, NULL);
int status;
if (waitpid(pid, &status, 0) < 0) {
uwsgi_error("waitpid()");
}
_exit(0);
}
}
struct uwsgi_string_list *usl;
uwsgi_foreach(usl, uwsgi.wait_for_interface) {
@@ -396,7 +656,22 @@ void uwsgi_as_root() {
}
}
}
uwsgi_hooks_run(uwsgi.hook_as_root, "as root", 1);
uwsgi_foreach(usl, uwsgi.mount_as_root) {
uwsgi_log("mounting \"%s\" (as root)...\n", usl->value);
if (uwsgi_mount_hook(usl->value)) {
exit(1);
}
}
uwsgi_foreach(usl, uwsgi.umount_as_root) {
uwsgi_log("un-mounting \"%s\" (as root)...\n", usl->value);
if (uwsgi_umount_hook(usl->value)) {
exit(1);
}
}
// now run the scripts needed by root
uwsgi_foreach(usl, uwsgi.exec_as_root) {
@@ -614,6 +889,8 @@ void uwsgi_as_root() {
}
}
uwsgi_hooks_run(uwsgi.hook_as_user, "as user", 1);
// now run the scripts needed by the user
uwsgi_foreach(usl, uwsgi.exec_as_user) {
uwsgi_log("running \"%s\" (as uid: %d gid: %d) ...\n", usl->value, (int) getuid(), (int) getgid());
@@ -627,6 +904,7 @@ void uwsgi_as_root() {
uwsgi_foreach(usl, uwsgi.call_as_user) {
if (uwsgi_call_symbol(usl->value)) {
uwsgi_log("unaable to call function \"%s\"\n", usl->value);
exit(1);
}
}
@@ -1443,6 +1721,11 @@ int uwsgi_file_exists(char *filename) {
return !access(filename, R_OK);
}
int uwsgi_file_executable(char *filename) {
// TODO check for http url or stdin
return !access(filename, R_OK|X_OK);
}
char *magic_sub(char *buffer, size_t len, size_t *size, char *magic_table[]) {
size_t i;
@@ -2003,9 +2286,19 @@ void uwsgi_sig_pause() {
sigsuspend(&mask);
}
char *uwsgi_binsh() {
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.binsh) {
if (uwsgi_file_executable(usl->value)) {
return usl->value;
}
}
return "/bin/sh";
}
void uwsgi_exec_command_with_args(char *cmdline) {
char *argv[4];
argv[0] = "/bin/sh";
argv[0] = uwsgi_binsh();
argv[1] = "-c";
argv[2] = cmdline;
argv[3] = NULL;
@@ -2025,7 +2318,7 @@ static int uwsgi_run_command_do(char *command, char *arg) {
#endif
if (command == NULL) {
argv[0] = "/bin/sh";
argv[0] = uwsgi_binsh();
argv[1] = "-c";
argv[2] = arg;
argv[3] = NULL;
@@ -2178,12 +2471,12 @@ pid_t uwsgi_run_command(char *command, int *stdin_fd, int stdout_fd) {
exit(1);
}
argv[0] = "/bin/sh";
argv[0] = uwsgi_binsh();
argv[1] = "-c";
argv[2] = command;
argv[3] = NULL;
execvp("/bin/sh", argv);
execvp(uwsgi_binsh(), argv);
uwsgi_error("execvp()");
//never here
@@ -2989,12 +3282,20 @@ char *uwsgi_chomp2(char *str) {
int uwsgi_tmpfd() {
int fd = -1;
char *tmpdir = getenv("TMPDIR");
if (!tmpdir) {
tmpdir = "/tmp";
}
#ifdef O_TMPFILE
fd = open(tmpdir, O_TMPFILE | O_RDWR);
if (fd >= 0) {
return fd;
}
// fallback to old style
#endif
char *template = uwsgi_concat2(tmpdir, "/uwsgiXXXXXX");
int fd = mkstemp(template);
fd = mkstemp(template);
unlink(template);
free(template);
return fd;
@@ -3045,15 +3346,21 @@ void uwsgi_emulate_cow_for_apps(int id) {
}
}
int uwsgi_write_intfile(char *filename, int n) {
FILE *pidfile = fopen(filename, "w");
if (!pidfile) {
uwsgi_error_open(filename);
exit(1);
}
if (fprintf(pidfile, "%d\n", n) <= 0 || ferror(pidfile) || fclose(pidfile)) {
return -1;
}
return 0;
}
void uwsgi_write_pidfile(char *pidfile_name) {
uwsgi_log("writing pidfile to %s\n", pidfile_name);
FILE *pidfile = fopen(pidfile_name, "w");
if (!pidfile) {
uwsgi_error_open(pidfile_name);
exit(1);
}
if (fprintf(pidfile, "%d\n", (int) getpid()) <= 0 || ferror(pidfile) || fclose(pidfile)) {
if (uwsgi_write_intfile(pidfile_name, (int) getpid())) {
uwsgi_log("could not write pidfile.\n");
}
}
+171 -17
View File
@@ -226,6 +226,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"locks", required_argument, 0, "create the specified number of shared locks", uwsgi_opt_set_int, &uwsgi.locks, 0},
{"lock-engine", required_argument, 0, "set the lock engine", uwsgi_opt_set_str, &uwsgi.lock_engine, 0},
{"ftok", required_argument, 0, "set the ipcsem key via ftok() for avoiding duplicates", uwsgi_opt_set_str, &uwsgi.ftok, 0},
{"persistent-ipcsem", no_argument, 0, "do not remove ipcsem's on shutdown", uwsgi_opt_true, &uwsgi.persistent_ipcsem, 0},
{"sharedarea", required_argument, 'A', "create a raw shared memory area of specified pages", uwsgi_opt_set_int, &uwsgi.sharedareasize, 0},
{"safe-fd", required_argument, 0, "do not close the specified file descriptor", uwsgi_opt_safe_fd, NULL, 0},
@@ -261,7 +262,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"spooler-external", required_argument, 0, "map spoolers requests to a spooler directory managed by an external instance", uwsgi_opt_add_spooler, (void *) UWSGI_SPOOLER_EXTERNAL, UWSGI_OPT_MASTER},
{"spooler-ordered", no_argument, 0, "try to order the execution of spooler tasks", uwsgi_opt_true, &uwsgi.spooler_ordered, 0},
{"spooler-chdir", required_argument, 0, "chdir() to specified directory before each spooler task", uwsgi_opt_set_str, &uwsgi.spooler_chdir, 0},
{"spooler-processes", required_argument, 0, "set the number of processes for spoolers", uwsgi_opt_set_int, &uwsgi.spooler_numproc, 0},
{"spooler-processes", required_argument, 0, "set the number of processes for spoolers", uwsgi_opt_set_int, &uwsgi.spooler_numproc, UWSGI_OPT_IMMEDIATE},
{"spooler-quiet", no_argument, 0, "do not be verbose with spooler tasks", uwsgi_opt_true, &uwsgi.spooler_quiet, 0},
{"spooler-max-tasks", required_argument, 0, "set the maximum number of tasks to run before recycling a spooler", uwsgi_opt_set_int, &uwsgi.spooler_max_tasks, 0},
{"spooler-harakiri", required_argument, 0, "set harakiri timeout for spooler tasks", uwsgi_opt_set_dyn, (void *) UWSGI_OPTION_SPOOLER_HARAKIRI, 0},
@@ -288,6 +289,11 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"pidfile", required_argument, 0, "create pidfile (before privileges drop)", uwsgi_opt_set_str, &uwsgi.pidfile, 0},
{"pidfile2", required_argument, 0, "create pidfile (after privileges drop)", uwsgi_opt_set_str, &uwsgi.pidfile2, 0},
{"chroot", required_argument, 0, "chroot() to the specified directory", uwsgi_opt_set_str, &uwsgi.chroot, 0},
#ifdef __linux__
{"pivot-root", required_argument, 0, "pivot_root() to the specified directories (new_root and put_old must be separated with a space)", uwsgi_opt_set_str, &uwsgi.pivot_root, 0},
{"pivot_root", required_argument, 0, "pivot_root() to the specified directories (new_root and put_old must be separated with a space)", uwsgi_opt_set_str, &uwsgi.pivot_root, 0},
#endif
{"uid", required_argument, 0, "setuid to the specified user/uid", uwsgi_opt_set_uid, NULL, 0},
{"gid", required_argument, 0, "setgid to the specified group/gid", uwsgi_opt_set_gid, NULL, 0},
{"add-gid", required_argument, 0, "add the specified group id to the process credentials", uwsgi_opt_add_string_list, &uwsgi.additional_gids, 0},
@@ -299,9 +305,37 @@ static struct uwsgi_option uwsgi_base_options[] = {
#endif
#ifdef __linux__
{"unshare", required_argument, 0, "unshare() part of the processes and put it in a new namespace", uwsgi_opt_set_unshare, &uwsgi.unshare, 0},
#endif
#ifdef __FreeBSD__
{"jail", required_argument, 0, "put the instance in a FreeBSD jail", uwsgi_opt_set_str, &uwsgi.jail, 0},
{"jail-ip4", required_argument, 0, "add an ipv4 address to the FreeBSD jail", uwsgi_opt_add_string_list, &uwsgi.jail_ip4, 0},
{"jail-ip6", required_argument, 0, "add an ipv6 address to the FreeBSD jail", uwsgi_opt_add_string_list, &uwsgi.jail_ip6, 0},
{"jidfile", required_argument, 0, "save the jid of a FreeBSD jail in the specified file", uwsgi_opt_set_str, &uwsgi.jidfile, 0},
{"jid-file", required_argument, 0, "save the jid of a FreeBSD jail in the specified file", uwsgi_opt_set_str, &uwsgi.jidfile, 0},
#ifdef UWSGI_HAS_FREEBSD_LIBJAIL
{"jail2", required_argument, 0, "add an option to the FreeBSD jail", uwsgi_opt_add_string_list, &uwsgi.jail2, 0},
{"libjail", required_argument, 0, "add an option to the FreeBSD jail", uwsgi_opt_add_string_list, &uwsgi.jail2, 0},
{"jail-attach", required_argument, 0, "attach to the FreeBSD jail", uwsgi_opt_set_str, &uwsgi.jail_attach, 0},
#endif
#endif
{"refork", no_argument, 0, "fork() again after privileges drop. Useful for jailing systems", uwsgi_opt_true, &uwsgi.refork, 0},
{"re-fork", no_argument, 0, "fork() again after privileges drop. Useful for jailing systems", uwsgi_opt_true, &uwsgi.refork, 0},
{"refork-as-root", no_argument, 0, "fork() again before privileges drop. Useful for jailing systems", uwsgi_opt_true, &uwsgi.refork_as_root, 0},
{"re-fork-as-root", no_argument, 0, "fork() again before privileges drop. Useful for jailing systems", uwsgi_opt_true, &uwsgi.refork_as_root, 0},
{"refork-post-jail", no_argument, 0, "fork() again after jailing. Useful for jailing systems", uwsgi_opt_true, &uwsgi.refork_post_jail, 0},
{"re-fork-post-jail", no_argument, 0, "fork() again after jailing. Useful for jailing systems", uwsgi_opt_true, &uwsgi.refork_post_jail, 0},
{"hook-pre-jail", required_argument, 0, "run the specified hook before jailing", uwsgi_opt_add_string_list, &uwsgi.hook_pre_jail, 0},
{"hook-post-jail", required_argument, 0, "run the specified hook after jailing", uwsgi_opt_add_string_list, &uwsgi.hook_post_jail, 0},
{"hook-in-jail", required_argument, 0, "run the specified hook in jail after initialization", uwsgi_opt_add_string_list, &uwsgi.hook_in_jail, 0},
{"hook-as-root", required_argument, 0, "run the specified hook before privileges drop", uwsgi_opt_add_string_list, &uwsgi.hook_as_root, 0},
{"hook-as-user", required_argument, 0, "run the specified hook after privileges drop", uwsgi_opt_add_string_list, &uwsgi.hook_as_user, 0},
{"hook-as-user-atexit", required_argument, 0, "run the specified hook before app exit and reload", uwsgi_opt_add_string_list, &uwsgi.hook_as_user_atexit, 0},
{"hook-pre-app", required_argument, 0, "run the specified hook before app loading", uwsgi_opt_add_string_list, &uwsgi.hook_pre_app, 0},
{"hook-post-app", required_argument, 0, "run the specified hook after app loading", uwsgi_opt_add_string_list, &uwsgi.hook_post_app, 0},
{"hook-as-vassal", required_argument, 0, "run the specified command before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.hook_as_vassal, 0},
{"hook-as-emperor", required_argument, 0, "run the specified command in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.hook_as_emperor, 0},
{"exec-pre-jail", required_argument, 0, "run the specified command before jailing", uwsgi_opt_add_string_list, &uwsgi.exec_pre_jail, 0},
{"exec-post-jail", required_argument, 0, "run the specified command after jailing", uwsgi_opt_add_string_list, &uwsgi.exec_post_jail, 0},
@@ -315,6 +349,22 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"exec-as-vassal", required_argument, 0, "run the specified command before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.exec_as_vassal, 0},
{"exec-as-emperor", required_argument, 0, "run the specified command in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.exec_as_emperor, 0},
{"mount-pre-jail", required_argument, 0, "mount filesystem before jailing", uwsgi_opt_add_string_list, &uwsgi.mount_pre_jail, 0},
{"mount-post-jail", required_argument, 0, "mount filesystem after jailing", uwsgi_opt_add_string_list, &uwsgi.mount_post_jail, 0},
{"mount-in-jail", required_argument, 0, "mount filesystem in jail after initialization", uwsgi_opt_add_string_list, &uwsgi.mount_in_jail, 0},
{"mount-as-root", required_argument, 0, "mount filesystem before privileges drop", uwsgi_opt_add_string_list, &uwsgi.mount_as_root, 0},
{"mount-as-vassal", required_argument, 0, "mount filesystem before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.mount_as_vassal, 0},
{"mount-as-emperor", required_argument, 0, "mount filesystem in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.mount_as_emperor, 0},
{"umount-pre-jail", required_argument, 0, "unmount filesystem before jailing", uwsgi_opt_add_string_list, &uwsgi.umount_pre_jail, 0},
{"umount-post-jail", required_argument, 0, "unmount filesystem after jailing", uwsgi_opt_add_string_list, &uwsgi.umount_post_jail, 0},
{"umount-in-jail", required_argument, 0, "unmount filesystem in jail after initialization", uwsgi_opt_add_string_list, &uwsgi.umount_in_jail, 0},
{"umount-as-root", required_argument, 0, "unmount filesystem before privileges drop", uwsgi_opt_add_string_list, &uwsgi.umount_as_root, 0},
{"umount-as-vassal", required_argument, 0, "unmount filesystem before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.umount_as_vassal, 0},
{"umount-as-emperor", required_argument, 0, "unmount filesystem in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.umount_as_emperor, 0},
{"wait-for-interface", 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-for-interface-timeout", required_argument, 0, "set the timeout for wait-for-interface", uwsgi_opt_set_int, &uwsgi.wait_for_interface_timeout, 0},
@@ -510,6 +560,12 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"logger-list", no_argument, 0, "list enabled loggers", uwsgi_opt_true, &uwsgi.loggers_list, 0},
{"loggers-list", no_argument, 0, "list enabled loggers", uwsgi_opt_true, &uwsgi.loggers_list, 0},
{"threaded-logger", no_argument, 0, "offload log writing to a thread", uwsgi_opt_true, &uwsgi.threaded_logger, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
{"log-encoder", required_argument, 0, "add an item in the log encoder chain", uwsgi_opt_add_string_list, &uwsgi.requested_log_encoders, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
{"log-req-encoder", required_argument, 0, "add an item in the log req encoder chain", uwsgi_opt_add_string_list, &uwsgi.requested_log_req_encoders, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
#ifdef UWSGI_PCRE
{"log-drain", required_argument, 0, "drain (do not show) log lines matching the specified regexp", uwsgi_opt_add_regexp_list, &uwsgi.log_drain_rules, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
{"log-filter", required_argument, 0, "show only log lines matching the specified regexp", uwsgi_opt_add_regexp_list, &uwsgi.log_filter_rules, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
@@ -538,6 +594,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
#endif
{"log-master", no_argument, 0, "delegate logging to master process", uwsgi_opt_true, &uwsgi.log_master, UWSGI_OPT_MASTER},
{"log-master-bufsize", required_argument, 0, "set the buffer size for the master logger. bigger log messages will be truncated", uwsgi_opt_set_64bit, &uwsgi.log_master_bufsize, 0},
{"log-master-stream", no_argument, 0, "create the master logpipe as SOCK_STREAM", uwsgi_opt_true, &uwsgi.log_master_stream, 0},
{"log-master-req-stream", no_argument, 0, "create the master requests logpipe as SOCK_STREAM", uwsgi_opt_true, &uwsgi.log_master_req_stream, 0},
{"log-reopen", no_argument, 0, "reopen log after reload", uwsgi_opt_true, &uwsgi.log_reopen, 0},
{"log-truncate", no_argument, 0, "truncate log on startup", uwsgi_opt_true, &uwsgi.log_truncate, 0},
{"log-maxsize", required_argument, 0, "set maximum logfile size", uwsgi_opt_set_int, &uwsgi.log_maxsize, UWSGI_OPT_LOG_MASTER},
@@ -556,7 +614,12 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"log-micros", no_argument, 0, "report response time in microseconds instead of milliseconds", uwsgi_opt_true, &uwsgi.log_micros, 0},
{"log-x-forwarded-for", no_argument, 0, "use the ip from X-Forwarded-For header instead of REMOTE_ADDR", uwsgi_opt_true, &uwsgi.log_x_forwarded_for, 0},
{"master-as-root", no_argument, 0, "leave master process running as root", uwsgi_opt_true, &uwsgi.master_as_root, 0},
{"drop-after-init", no_argument, 0, "run privileges drop after plugin initialization", uwsgi_opt_true, &uwsgi.drop_after_init, 0},
{"drop-after-apps", no_argument, 0, "run privileges drop after apps loading", uwsgi_opt_true, &uwsgi.drop_after_apps, 0},
{"force-cwd", required_argument, 0, "force the initial working directory to the specified value", uwsgi_opt_set_str, &uwsgi.force_cwd, 0},
{"binsh", required_argument, 0, "override /bin/sh (used by exec hooks, it always fallback to /bin/sh)", uwsgi_opt_add_string_list, &uwsgi.binsh, 0},
{"chdir", required_argument, 0, "chdir to specified directory before apps loading", uwsgi_opt_set_str, &uwsgi.chdir, 0},
{"chdir2", required_argument, 0, "chdir to specified directory after apps loading", uwsgi_opt_set_str, &uwsgi.chdir2, 0},
{"lazy", no_argument, 0, "set lazy mode (load apps in workers instead of master)", uwsgi_opt_true, &uwsgi.lazy, 0},
@@ -570,6 +633,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"cheaper-algo-list", no_argument, 0, "list enabled cheapers algorithms", uwsgi_opt_true, &uwsgi.cheaper_algo_list, 0},
{"cheaper-algos-list", no_argument, 0, "list enabled cheapers algorithms", uwsgi_opt_true, &uwsgi.cheaper_algo_list, 0},
{"cheaper-list", no_argument, 0, "list enabled cheapers algorithms", uwsgi_opt_true, &uwsgi.cheaper_algo_list, 0},
{"cheaper-rss-limit-soft", required_argument, 0, "don't spawn new workers if total resident memory usage of all workers is higher than this limit", uwsgi_opt_set_64bit, &uwsgi.cheaper_rss_limit_soft, UWSGI_OPT_MASTER | UWSGI_OPT_CHEAPER},
{"cheaper-rss-limit-hard", required_argument, 0, "if total workers resident memory usage is higher try to stop workers", uwsgi_opt_set_64bit, &uwsgi.cheaper_rss_limit_hard, UWSGI_OPT_MASTER | UWSGI_OPT_CHEAPER},
{"idle", required_argument, 0, "set idle mode (put uWSGI in cheap mode after inactivity)", uwsgi_opt_set_int, &uwsgi.idle, UWSGI_OPT_MASTER},
{"die-on-idle", no_argument, 0, "shutdown uWSGI when idle", uwsgi_opt_true, &uwsgi.die_on_idle, 0},
{"mount", required_argument, 0, "load application under mountpoint", uwsgi_opt_add_string_list, &uwsgi.mounts, 0},
@@ -627,6 +692,20 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"error-route-if-not", required_argument, 0, "add an error route based on condition (negate version)", uwsgi_opt_add_route, "if-not", 0},
{"error-route-run", required_argument, 0, "always run the specified error route action", uwsgi_opt_add_route, "run", 0},
{"response-route", required_argument, 0, "add a response route", uwsgi_opt_add_route, "path_info", 0},
{"response-route-status", required_argument, 0, "add a response route for the specified status", uwsgi_opt_add_route, "status", 0},
{"response-route-host", required_argument, 0, "add a response route based on Host header", uwsgi_opt_add_route, "http_host", 0},
{"response-route-uri", required_argument, 0, "add a response route based on REQUEST_URI", uwsgi_opt_add_route, "request_uri", 0},
{"response-route-qs", required_argument, 0, "add a response route based on QUERY_STRING", uwsgi_opt_add_route, "query_string", 0},
{"response-route-remote-addr", required_argument, 0, "add a response route based on REMOTE_ADDR", uwsgi_opt_add_route, "remote_addr", 0},
{"response-route-user-agent", required_argument, 0, "add a response route based on HTTP_USER_AGENT", uwsgi_opt_add_route, "user_agent", 0},
{"response-route-remote-user", required_argument, 0, "add a response route based on REMOTE_USER", uwsgi_opt_add_route, "remote_user", 0},
{"response-route-referer", required_argument, 0, "add a response route based on HTTP_REFERER", uwsgi_opt_add_route, "referer", 0},
{"response-route-label", required_argument, 0, "add a response routing label (for use with goto)", uwsgi_opt_add_route, NULL, 0},
{"response-route-if", required_argument, 0, "add a response route based on condition", uwsgi_opt_add_route, "if", 0},
{"response-route-if-not", required_argument, 0, "add a response route based on condition (negate version)", uwsgi_opt_add_route, "if-not", 0},
{"response-route-run", required_argument, 0, "always run the specified response route action", uwsgi_opt_add_route, "run", 0},
{"router-list", no_argument, 0, "list enabled routers", uwsgi_opt_true, &uwsgi.router_list, 0},
{"routers-list", no_argument, 0, "list enabled routers", uwsgi_opt_true, &uwsgi.router_list, 0},
#endif
@@ -651,6 +730,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"add-header", required_argument, 0, "automatically add HTTP headers to response", uwsgi_opt_add_string_list, &uwsgi.additional_headers, 0},
{"rem-header", required_argument, 0, "automatically remove specified HTTP header from the response", uwsgi_opt_add_string_list, &uwsgi.remove_headers, 0},
{"del-header", required_argument, 0, "automatically remove specified HTTP header from the response", uwsgi_opt_add_string_list, &uwsgi.remove_headers, 0},
{"collect-header", required_argument, 0, "store the specified response header in a request var (syntax: header var)", uwsgi_opt_add_string_list, &uwsgi.collect_headers, 0},
{"response-header-collect", required_argument, 0, "store the specified response header in a request var (syntax: header var)", uwsgi_opt_add_string_list, &uwsgi.collect_headers, 0},
{"check-static", required_argument, 0, "check for static files in the specified directory", uwsgi_opt_check_static, NULL, UWSGI_OPT_MIME},
{"check-static-docroot", no_argument, 0, "check for static files in the requested DOCUMENT_ROOT", uwsgi_opt_true, &uwsgi.check_static_docroot, UWSGI_OPT_MIME},
@@ -662,8 +743,13 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"static-safe", required_argument, 0, "skip security checks if the file is under the specified path", uwsgi_opt_add_string_list, &uwsgi.static_safe, UWSGI_OPT_MIME},
{"static-cache-paths", required_argument, 0, "put resolved paths in the uWSGI cache for the specified amount of seconds", uwsgi_opt_set_int, &uwsgi.use_static_cache_paths, UWSGI_OPT_MIME|UWSGI_OPT_MASTER},
{"static-cache-paths-name", required_argument, 0, "use the specified cache for static paths", uwsgi_opt_set_str, &uwsgi.static_cache_paths_name, UWSGI_OPT_MIME|UWSGI_OPT_MASTER},
#ifdef __APPLE__
{"mimefile", required_argument, 0, "set mime types file path (default /etc/apache2/mime.types)", uwsgi_opt_add_string_list, &uwsgi.mime_file, UWSGI_OPT_MIME},
{"mime-file", required_argument, 0, "set mime types file path (default /etc/apache2/mime.types)", uwsgi_opt_add_string_list, &uwsgi.mime_file, UWSGI_OPT_MIME},
#else
{"mimefile", required_argument, 0, "set mime types file path (default /etc/mime.types)", uwsgi_opt_add_string_list, &uwsgi.mime_file, UWSGI_OPT_MIME},
{"mime-file", required_argument, 0, "set mime types file path (default /etc/mime.types)", uwsgi_opt_add_string_list, &uwsgi.mime_file, UWSGI_OPT_MIME},
#endif
{"static-expires-type", required_argument, 0, "set the Expires header based on content type", uwsgi_opt_add_dyn_dict, &uwsgi.static_expires_type, UWSGI_OPT_MIME},
{"static-expires-type-mtime", required_argument, 0, "set the Expires header based on content type and file mtime", uwsgi_opt_add_dyn_dict, &uwsgi.static_expires_type_mtime, UWSGI_OPT_MIME},
@@ -693,6 +779,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"file-serve-mode", required_argument, 0, "set static file serving mode", uwsgi_opt_fileserve_mode, NULL, UWSGI_OPT_MIME},
{"fileserve-mode", required_argument, 0, "set static file serving mode", uwsgi_opt_fileserve_mode, NULL, UWSGI_OPT_MIME},
{"disable-sendfile", no_argument, 0, "disable sendfile() and rely on boring read()/write()", uwsgi_opt_true, &uwsgi.disable_sendfile, 0},
{"check-cache", optional_argument, 0, "check for response data in the specified cache (empty for default cache)", uwsgi_opt_set_str, &uwsgi.use_check_cache, 0},
{"close-on-exec", no_argument, 0, "set close-on-exec on sockets (could be required for spawning processes in requests)", uwsgi_opt_true, &uwsgi.close_on_exec, 0},
{"mode", required_argument, 0, "set uWSGI custom mode", uwsgi_opt_set_str, &uwsgi.mode, 0},
@@ -1366,6 +1454,8 @@ struct uwsgi_plugin unconfigured_plugin = {
void uwsgi_exec_atexit(void) {
if (getpid() == masterpid) {
uwsgi_hooks_run(uwsgi.hook_as_user_atexit, "atexit", 0);
// now run exit scripts needed by the user
struct uwsgi_string_list *usl;
@@ -1935,6 +2025,10 @@ int main(int argc, char *argv[], char *envp[]) {
uwsgi_register_embedded_routers();
#endif
// call here to allows plugin to override hooks
uwsgi_register_base_hooks();
uwsgi_log_encoders_register_embedded();
//initialize embedded plugins
UWSGI_LOAD_EMBEDDED_PLUGINS
// now a bit of magic, if the executable basename contains a 'uwsgi_' string,
@@ -2159,6 +2253,8 @@ int main(int argc, char *argv[], char *envp[]) {
#ifdef UWSGI_ROUTING
uwsgi_routing_dump();
#else
uwsgi_log("!!! no internal routing support, rebuild with pcre support !!!\n");
#endif
// initialize shared sockets
@@ -2169,21 +2265,37 @@ int main(int argc, char *argv[], char *envp[]) {
uwsgi_emperor_start();
}
// run the pre-jail scripts
struct uwsgi_string_list *usl = uwsgi.exec_pre_jail;
while (usl) {
uwsgi_log("running \"%s\" (pre-jail)...\n", usl->value);
int ret = uwsgi_run_command_and_wait(NULL, usl->value);
if (ret != 0) {
uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret);
exit(1);
}
usl = usl->next;
}
if (!uwsgi.reloads) {
uwsgi_hooks_run(uwsgi.hook_pre_jail, "pre-jail", 1);
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.mount_pre_jail) {
uwsgi_log("mounting \"%s\" (pre-jail)...\n", usl->value);
if (uwsgi_mount_hook(usl->value)) {
exit(1);
}
}
uwsgi_foreach(usl, uwsgi.call_pre_jail) {
if (uwsgi_call_symbol(usl->value)) {
uwsgi_log("unaable to call function \"%s\"\n", usl->value);
uwsgi_foreach(usl, uwsgi.umount_pre_jail) {
uwsgi_log("un-mounting \"%s\" (pre-jail)...\n", usl->value);
if (uwsgi_umount_hook(usl->value)) {
exit(1);
}
}
// run the pre-jail scripts
uwsgi_foreach(usl, uwsgi.exec_pre_jail) {
uwsgi_log("running \"%s\" (pre-jail)...\n", usl->value);
int ret = uwsgi_run_command_and_wait(NULL, usl->value);
if (ret != 0) {
uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret);
exit(1);
}
}
uwsgi_foreach(usl, uwsgi.call_pre_jail) {
if (uwsgi_call_symbol(usl->value)) {
uwsgi_log("unaable to call function \"%s\"\n", usl->value);
exit(1);
}
}
}
@@ -2239,7 +2351,24 @@ int uwsgi_start(void *v_argv) {
}
#endif
uwsgi_hooks_run(uwsgi.hook_in_jail, "in-jail", 1);
struct uwsgi_string_list *usl;
uwsgi_foreach(usl, uwsgi.mount_in_jail) {
uwsgi_log("mounting \"%s\" (in-jail)...\n", usl->value);
if (uwsgi_mount_hook(usl->value)) {
exit(1);
}
}
uwsgi_foreach(usl, uwsgi.umount_in_jail) {
uwsgi_log("un-mounting \"%s\" (in-jail)...\n", usl->value);
if (uwsgi_umount_hook(usl->value)) {
exit(1);
}
}
uwsgi_foreach(usl, uwsgi.exec_in_jail) {
uwsgi_log("running \"%s\" (in-jail)...\n", usl->value);
int ret = uwsgi_run_command_and_wait(NULL, usl->value);
@@ -2251,14 +2380,15 @@ int uwsgi_start(void *v_argv) {
uwsgi_foreach(usl, uwsgi.call_in_jail) {
if (uwsgi_call_symbol(usl->value)) {
uwsgi_log("unaable to call function \"%s\"\n", usl->value);
uwsgi_log("unable to call function \"%s\"\n", usl->value);
exit(1);
}
}
uwsgi_file_write_do(uwsgi.file_write_list);
if (!uwsgi.master_as_root && !uwsgi.chown_socket) {
if (!uwsgi.master_as_root && !uwsgi.chown_socket && !uwsgi.drop_after_init && !uwsgi.drop_after_apps) {
uwsgi_as_root();
}
@@ -2363,7 +2493,11 @@ int uwsgi_start(void *v_argv) {
// build mime.types dictionary
if (uwsgi.build_mime_dict) {
if (!uwsgi.mime_file)
#ifdef __APPLE__
uwsgi_string_new_list(&uwsgi.mime_file, "/etc/apache2/mime.types");
#else
uwsgi_string_new_list(&uwsgi.mime_file, "/etc/mime.types");
#endif
struct uwsgi_string_list *umd = uwsgi.mime_file;
while (umd) {
if (!access(umd->value, R_OK)) {
@@ -2406,6 +2540,12 @@ int uwsgi_start(void *v_argv) {
// setup locking
uwsgi_setup_locking();
if (uwsgi.use_thunder_lock) {
uwsgi_log("thunder lock: enabled\n");
}
else {
uwsgi_log("thunder lock: disabled (you can enable it with --thunder-lock)\n");
}
// allocate rpc structures
uwsgi_rpc_init();
@@ -2498,6 +2638,11 @@ int uwsgi_start(void *v_argv) {
}
}
if (uwsgi.drop_after_init) {
uwsgi_as_root();
}
/* gp/plugin initialization */
for (i = 0; i < uwsgi.gp_cnt; i++) {
if (uwsgi.gp[i]->post_init) {
@@ -2737,6 +2882,10 @@ next:
uwsgi_init_all_apps();
}
if (uwsgi.drop_after_apps) {
uwsgi_as_root();
}
// postinit apps (setup specific features after app initialization)
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->postinit_apps) {
@@ -3330,6 +3479,8 @@ void uwsgi_init_all_apps() {
int i, j;
uwsgi_hooks_run(uwsgi.hook_pre_app, "pre app", 1);
// now run the pre-app scripts
struct uwsgi_string_list *usl = uwsgi.exec_pre_app;
while (usl) {
@@ -3345,6 +3496,7 @@ void uwsgi_init_all_apps() {
uwsgi_foreach(usl, uwsgi.call_pre_app) {
if (uwsgi_call_symbol(usl->value)) {
uwsgi_log("unaable to call function \"%s\"\n", usl->value);
exit(1);
}
}
@@ -3396,6 +3548,8 @@ void uwsgi_init_all_apps() {
}
}
uwsgi_hooks_run(uwsgi.hook_post_app, "post app", 1);
usl = uwsgi.exec_post_app;
while (usl) {
uwsgi_log("running \"%s\" (post app)...\n", usl->value);
+36
View File
@@ -120,6 +120,19 @@ error:
//each protocol has its header generator
static int uwsgi_response_add_header_do(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) {
// collect the header ?
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.collect_headers) {
if (!uwsgi_strnicmp(key, key_len, usl->value, usl->custom)) {
if (!uwsgi_req_append(wsgi_req, usl->custom_ptr, usl->custom2, value, value_len)) {
wsgi_req->write_errors++ ; return -1;
}
}
}
if (!wsgi_req->headers) {
wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size);
wsgi_req->headers->limit = UMAX16;
@@ -171,6 +184,16 @@ int uwsgi_response_write_headers_do(struct wsgi_request *wsgi_req) {
return UWSGI_OK;
}
#ifdef UWSGI_ROUTING
// apply response routes
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
// from now on ignore write body requests...
wsgi_req->ignore_body = 1;
return -1;
}
wsgi_req->is_response_routing = 0;
#endif
struct uwsgi_string_list *ah = uwsgi.additional_headers;
while(ah) {
if (uwsgi_response_add_header(wsgi_req, NULL, 0, ah->value, ah->len)) return -1;
@@ -221,6 +244,19 @@ int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_
if (wsgi_req->write_errors) return -1;
if (wsgi_req->ignore_body) return UWSGI_OK;
#ifdef UWSGI_ROUTING
// special case here, we could need to set transformations before
if (!wsgi_req->headers_sent) {
// apply response routes
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
// from now on ignore write body requests...
wsgi_req->ignore_body = 1;
return -1;
}
wsgi_req->is_response_routing = 0;
}
#endif
// if the transformation chain returns 1, we are in buffering mode
if (wsgi_req->transformed_chunk_len == 0 && wsgi_req->transformations) {
int t_ret = uwsgi_apply_transformations(wsgi_req, buf, len);
+66
View File
@@ -0,0 +1,66 @@
/*
*** WORK IN PROGRESS ***
Zeus mode
A Zeus instance can load all of the available imperial monitor plugins, but instead of spawning
vassals it delegates actions to Emperors connected to it.
The Zeus instance try to distribute vassals evenly between Emperors.
Emperors register to one (ore more, maybe...) Zeus instance, passing various informations (like the maximum number
of vassals it can manage)
to spawn a Zeus:
# unencrypted mode
uwsgi --zeus "192.168.173.17:4040 /etc/uwsgi/vassals"
# crypted mode
uwsgi --zeus "192.168.173.17:4040,foobar.crt,foobar.key /etc/uwsgi/vassals"
# crypted + authentication mode
uwsgi --zeus "192.168.173.17:4040,foobar.crt,foobar.key,clients.pem /etc/uwsgi/vassals"
to connect an Emperor to Zeus
# unencrypted mode
uwsgi --emperor zeus:192.168.173.17:4040
# crypted mode
uwsgi --emperor zeus-ssl:192.168.173.17:4040
# crypted + authentication mode
uwsgi --emperor zeus-ssl:192.168.173.17:4040,myself.key
Protocol
(each message is a basic uwsgi packet: modifier1 pktsize modifier2 payload)
modifier2 identifies the type of the message
0 -> I_AM_ALIVE {node: 'node001', max_vassals: '100', running_vassals: '17'} [ emperor -> zeus ]
1 -> NEW_VASSAL {name: 'foobar.ini'} [ zeus -> the choosen emperor ]
2 -> ACCEPTED_VASSAL {name: 'foobar.ini'} [ emperor -> zeus ]
3 -> CONFIG_CHUNK {name: 'foobar.ini', body: '[uwsgi].....'} [ zeus -> the choosen emperor ]
4 -> CONFIG_END {name: 'foobar.ini'} [ zeus -> the choosen emperor ]
5 -> VASSAL_SPAWNED {name: 'foobar.ini'} [the choosen emperor -> zeus]
6 -> VASSAL_REJECTED {name: 'foobar.ini'} [the choosen emperor -> zeus]
7 -> VASSAL_RELOAD {name: 'foobar.ini'} [ zeus -> the choosen emperor ]
8 -> VASSAL_UPDATE {name: 'foobar.ini'} [ zeus -> the choosen emperor ]
9 -> VASSAL_DESTROY {name: 'foobar.ini'} [ zeus -> the choosen emperor ]
10 -> VASSAL_RELOADED {name: 'foobar.ini'} [the choosen emperor -> zeus]
11 -> VASSAL_DESTROYED {name: 'foobar.ini'} [the choosen emperor -> zeus]
*/
+10 -2
View File
@@ -66,11 +66,17 @@ void linux_namespace_start(void *argv) {
uwsgi_error("clone()");
exit(1);
}
#if defined(MS_REC) && defined(MS_PRIVATE)
if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL)) {
uwsgi_error("mount()");
exit(1);
}
#endif
// run the post-jail scripts
if (setenv("UWSGI_JAIL_PID", uwsgi_num2str((int) pid), 1)) {
uwsgi_error("setenv()");
}
uwsgi_hooks_run(uwsgi.hook_post_jail, "post-jail", 1);
struct uwsgi_string_list *usl = uwsgi.exec_post_jail;
while(usl) {
uwsgi_log("running \"%s\" (post-jail)...\n", usl->value);
@@ -84,7 +90,8 @@ void linux_namespace_start(void *argv) {
uwsgi_foreach(usl, uwsgi.call_post_jail) {
if (uwsgi_call_symbol(usl->value)) {
uwsgi_log("unaable to call function \"%s\"\n", usl->value);
uwsgi_log("unable to call function \"%s\"\n", usl->value);
exit(1);
}
}
@@ -173,6 +180,7 @@ void linux_namespace_jail() {
uwsgi_log("remounting /proc\n");
if (mount("proc", "/proc", "proc", 0, NULL)) {
uwsgi_error("mount()");
exit(1);
}
struct uwsgi_string_list *usl = uwsgi.ns_keep_mount;
+69 -15
View File
@@ -19,14 +19,40 @@ static void uwsgi_opt_setup_gevent(char *opt, char *value, void *null) {
static struct uwsgi_option gevent_options[] = {
{"gevent", required_argument, 0, "a shortcut enabling gevent loop engine with the specified number of async cores and optimal parameters", uwsgi_opt_setup_gevent, NULL, UWSGI_OPT_THREADS},
{"gevent-monkey-patch", no_argument, 0, "call gevent.monkey.patch_all() automatically on startup", uwsgi_opt_true, &ugevent.monkey, 0},
{"gevent-wait-for-hub", no_argument, 0, "wait for gevent hub's death instead of the control greenlet", uwsgi_opt_true, &ugevent.wait_for_hub, 0},
{0, 0, 0, 0, 0, 0, 0},
};
/*
Dumb greenlet used for controlling the shutdown (originally uWSGI only wait for the hub)
*/
PyObject *py_uwsgi_gevent_ctrl_gl(PyObject *self, PyObject *args) {
for(;;) {
PyObject *gevent_sleep_args = PyTuple_New(1);
PyTuple_SetItem(gevent_sleep_args, 0, PyInt_FromLong(60));
PyObject *gswitch = PyEval_CallObject(ugevent.greenlet_switch, gevent_sleep_args);
// could be NULL on exception
if (!gswitch) {
// just for being paranid
if (PyErr_Occurred()) {
PyErr_Clear();
break;
}
}
Py_XDECREF(gswitch);
Py_DECREF(gevent_sleep_args);
}
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_gevent_graceful(PyObject *self, PyObject *args) {
int running_cores = 0;
int rounds = 0;
uwsgi_log("Gracefully killing worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid);
uwsgi.workers[uwsgi.mywid].manage_next_request = 0;
@@ -41,29 +67,34 @@ PyObject *py_uwsgi_gevent_graceful(PyObject *self, PyObject *args) {
}
uwsgi_log_verbose("main gevent watchers stopped for worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid);
int running_cores = 0;
retry:
running_cores = 0;
for(i=0;i<uwsgi.async;i++) {
if (uwsgi.workers[uwsgi.mywid].cores[i].in_request) {
struct wsgi_request *wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[i].req;
uwsgi_log_verbose("worker %d (pid: %d) core %d is managing \"%.*s %.*s\" for %.*s\n", uwsgi.mywid, uwsgi.mypid, i,
wsgi_req->method_len, wsgi_req->method, wsgi_req->uri_len, wsgi_req->uri,
wsgi_req->remote_addr_len, wsgi_req->remote_addr);
if (!rounds) {
uwsgi_log_verbose("worker %d (pid: %d) core %d is managing \"%.*s %.*s\" for %.*s\n", uwsgi.mywid, uwsgi.mypid, i,
wsgi_req->method_len, wsgi_req->method, wsgi_req->uri_len, wsgi_req->uri,
wsgi_req->remote_addr_len, wsgi_req->remote_addr);
}
running_cores++;
}
}
if (running_cores > 0) {
uwsgi_log_verbose("waiting for %d running requests on worker %d (pid: %d)...\n", running_cores, uwsgi.mywid, uwsgi.mypid);
} else {
// no need to worry about freeing memory
PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi");
if (uwsgi_dict) {
PyObject *ae = PyDict_GetItemString(uwsgi_dict, "atexit");
if (ae) {
python_call(ae, PyTuple_New(0), 0, NULL);
}
}
}
PyObject *gevent_sleep_args = PyTuple_New(1);
PyTuple_SetItem(gevent_sleep_args, 0, PyInt_FromLong(1));
PyObject *gswitch = python_call(ugevent.greenlet_switch, gevent_sleep_args, 0, NULL);
Py_DECREF(gswitch);
Py_DECREF(gevent_sleep_args);
rounds++;
goto retry;
}
if (!ugevent.wait_for_hub) {
PyObject_CallMethod(ugevent.ctrl_gl, "kill", NULL);
}
Py_INCREF(Py_None);
return Py_None;
@@ -300,6 +331,7 @@ PyMethodDef uwsgi_gevent_signal_def[] = { {"uwsgi_gevent_signal", py_uwsgi_geven
PyMethodDef uwsgi_gevent_my_signal_def[] = { {"uwsgi_gevent_my_signal", py_uwsgi_gevent_my_signal, METH_VARARGS, ""} };
PyMethodDef uwsgi_gevent_signal_handler_def[] = { {"uwsgi_gevent_signal_handler", py_uwsgi_gevent_signal_handler, METH_VARARGS, ""} };
PyMethodDef uwsgi_gevent_unix_signal_handler_def[] = { {"uwsgi_gevent_unix_signal_handler", py_uwsgi_gevent_graceful, METH_VARARGS, ""} };
PyMethodDef uwsgi_gevent_ctrl_gl_def[] = { {"uwsgi_gevent_ctrl_gl_handler", py_uwsgi_gevent_ctrl_gl, METH_VARARGS, ""} };
static void gil_gevent_get() {
pthread_setspecific(up.upt_gil_key, (void *) PyGILState_Ensure());
@@ -450,8 +482,21 @@ static void gevent_loop() {
python_call(ugevent.signal, ge_signal_tuple, 0, NULL);
PyObject *wait_for_me = ugevent.hub;
if (!ugevent.wait_for_hub) {
// spawn the control greenlet
PyObject *uwsgi_greenlet_ctrl_gl_handler = PyCFunction_New(uwsgi_gevent_ctrl_gl_def, NULL);
Py_INCREF(uwsgi_greenlet_ctrl_gl_handler);
PyObject *ctrl_gl_args = PyTuple_New(1);
PyTuple_SetItem(ctrl_gl_args, 0, uwsgi_greenlet_ctrl_gl_handler);
ugevent.ctrl_gl = python_call(ugevent.spawn, ctrl_gl_args, 0, NULL);
Py_INCREF(ugevent.ctrl_gl);
wait_for_me = ugevent.ctrl_gl;
}
for(;;) {
if (!PyObject_CallMethod(ugevent.hub, "join", NULL)) {
if (!PyObject_CallMethod(wait_for_me, "join", NULL)) {
PyErr_Print();
}
else {
@@ -459,6 +504,15 @@ static void gevent_loop() {
}
}
// no need to worry about freeing memory
PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi");
if (uwsgi_dict) {
PyObject *ae = PyDict_GetItemString(uwsgi_dict, "atexit");
if (ae) {
python_call(ae, PyTuple_New(0), 0, NULL);
}
}
if (uwsgi.workers[uwsgi.mywid].manage_next_request == 0) {
uwsgi_log("goodbye to the gevent Hub on worker %d (pid: %d)\n", uwsgi.mywid, uwsgi.mypid);
if (ugevent.destroy) {
+2
View File
@@ -51,7 +51,9 @@ struct uwsgi_gevent {
PyObject *my_signal_watcher;
PyObject *signal_watcher;
PyObject **watchers;
PyObject *ctrl_gl;
int destroy;
int monkey;
int wait_for_hub;
};
+361
View File
@@ -0,0 +1,361 @@
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
/*
msgpack utilities
*/
enum {
MSGPACK_NIL = 0,
MSGPACK_TRUE,
MSGPACK_FALSE,
MSGPACK_INT,
MSGPACK_FLOAT,
MSGPACK_STR,
MSGPACK_BIN,
MSGPACK_ARRAY,
MSGPACK_MAP,
MSGPACK_EXT,
MSGPACK_MAGIC,
};
struct uwsgi_msgpack_item {
uint8_t type;
char *str;
uint32_t str_len;
int64_t num;
double fnum;
int (*func)(char *);
struct uwsgi_msgpack_item *next;
};
struct uwsgi_msgpack_item *uwsgi_msgpack_item_add(struct uwsgi_msgpack_item **list, uint8_t type) {
struct uwsgi_msgpack_item *old_umi = NULL, *umi = *list;
while(umi) {
old_umi = umi;
umi = umi->next;
}
umi = uwsgi_calloc(sizeof(struct uwsgi_msgpack_item));
umi->type = type;
if (old_umi) {
old_umi->next = umi;
}
else {
*list = umi;
}
return umi;
}
int uwsgi_buffer_msgpack_map(struct uwsgi_buffer *ub, uint32_t len) {
if (len <= 15) {
return uwsgi_buffer_byte(ub, 0x80 + len);
}
else if (len <= 0xffff) {
if (uwsgi_buffer_byte(ub, 0xDE)) return -1;
return uwsgi_buffer_u16be(ub, (uint16_t) len);
}
if (uwsgi_buffer_byte(ub, 0xDF)) return -1;
return uwsgi_buffer_u32be(ub, len);
}
int uwsgi_buffer_msgpack_array(struct uwsgi_buffer *ub, uint32_t len) {
if (len <= 15) {
return uwsgi_buffer_byte(ub, 0x90 + len);
}
else if (len <= 0xffff) {
if (uwsgi_buffer_byte(ub, 0xDC)) return -1;
return uwsgi_buffer_u16be(ub, (uint16_t) len);
}
if (uwsgi_buffer_byte(ub, 0xDD)) return -1;
return uwsgi_buffer_u32be(ub, len);
}
int uwsgi_buffer_msgpack_str(struct uwsgi_buffer *ub, char *str, uint32_t len) {
if (len <= 31) {
if (uwsgi_buffer_byte(ub, 0xA0 + len)) return -1;
}
// this is annoying, D9 does not work for older SPEC :(
/*
else if (len <= 0xff) {
if (uwsgi_buffer_byte(ub, 0xD9)) return -1;
if (uwsgi_buffer_byte(ub, (uint8_t) len)) return -1;
}
*/
else if (len <= 0xffff) {
if (uwsgi_buffer_byte(ub, 0xDA)) return -1;
if (uwsgi_buffer_u16be(ub, (uint16_t) len)) return -1;
}
else {
if (uwsgi_buffer_byte(ub, 0xDB)) return -1;
if (uwsgi_buffer_u32be(ub, len)) return -1;
}
return uwsgi_buffer_append(ub, str, len);
}
int uwsgi_buffer_msgpack_bin(struct uwsgi_buffer *ub, char *str, uint32_t len) {
if (len <= 0xff) {
if (uwsgi_buffer_byte(ub, 0xC4)) return -1;
if (uwsgi_buffer_byte(ub, (uint8_t) len)) return -1;
}
else if (len <= 0xffff) {
if (uwsgi_buffer_byte(ub, 0xC5)) return -1;
if (uwsgi_buffer_u16be(ub, (uint16_t) len)) return -1;
}
else {
if (uwsgi_buffer_byte(ub, 0xC6)) return -1;
if (uwsgi_buffer_u32be(ub, len)) return -1;
}
return uwsgi_buffer_append(ub, str, len);
}
int uwsgi_buffer_msgpack_int(struct uwsgi_buffer *ub, int64_t num) {
if (num > 0 && num <= 127) {
return uwsgi_buffer_byte(ub, (uint8_t) num);
}
else if (num < 0 && num >= 31) {
return uwsgi_buffer_byte(ub, 224 | (int8_t) num);
}
else if (num <= 127 && num >= -127) {
if (uwsgi_buffer_byte(ub, 0xD0)) return -1;
return uwsgi_buffer_byte(ub, (int8_t) num);
}
else if (num <= 32767 && num >= -32767) {
if (uwsgi_buffer_byte(ub, 0xD1)) return -1;
return uwsgi_buffer_u16be(ub, (uint16_t) num);
}
else if (num <= 2147483647LL && num >= -2147483648LL) {
if (uwsgi_buffer_byte(ub, 0xD2)) return -1;
return uwsgi_buffer_u32be(ub, (uint32_t) num);
}
if (uwsgi_buffer_byte(ub, 0xD3)) return -1;
return uwsgi_buffer_u64be(ub, (uint64_t)num);
}
int uwsgi_buffer_msgpack_float(struct uwsgi_buffer *ub, double num) {
if (num >= -126.0 && num <= 127.0) {
if (uwsgi_buffer_byte(ub, 0xCA)) return -1;
return uwsgi_buffer_f32be(ub, (float) num);
}
if (uwsgi_buffer_byte(ub, 0xCB)) return -1;
return uwsgi_buffer_f64be(ub, num);
}
int uwsgi_buffer_msgpack_nil(struct uwsgi_buffer *ub) {
return uwsgi_buffer_byte(ub, 0xC0);
}
int uwsgi_buffer_msgpack_true(struct uwsgi_buffer *ub) {
return uwsgi_buffer_byte(ub, 0xC3);
}
int uwsgi_buffer_msgpack_false(struct uwsgi_buffer *ub) {
return uwsgi_buffer_byte(ub, 0xC2);
}
static char *uwsgi_msgpack_log_encoder(struct uwsgi_log_encoder *ule, char *msg, size_t len, size_t *rlen) {
char *buf = NULL;
if (!ule->configured) {
char *p = strtok(ule->args, "|");
while(p) {
char *colon = strchr(p, ':');
if (colon) *colon = 0;
// find the type of item
if (!strcmp(p, "map")) {
struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_MAP);
if (colon) {
new_umi->num = strtoull(colon+1, NULL, 10);
}
}
else if (!strcmp(p, "array")) {
struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_ARRAY);
if (colon) {
new_umi->num = strtoull(colon+1, NULL, 10);
}
}
else if (!strcmp(p, "nil")) {
uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_NIL);
}
else if (!strcmp(p, "true")) {
uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_TRUE);
}
else if (!strcmp(p, "false")) {
uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_FALSE);
}
else if (!strcmp(p, "int")) {
struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_INT);
if (colon) {
new_umi->num = strtoll(colon+1, NULL, 10);
}
}
else if (!strcmp(p, "float")) {
struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_FLOAT);
if (colon) {
new_umi->fnum = strtod(colon+1, NULL);
}
}
else if (!strcmp(p, "str")) {
struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_STR);
if (colon) {
new_umi->str = colon+1;
new_umi->str_len = strlen(colon+1);
}
else {
new_umi->str = "";
}
}
else if (!strcmp(p, "bin")) {
struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_BIN);
if (colon) {
new_umi->str = colon+1;
new_umi->str_len = strlen(colon+1);
}
else {
new_umi->str = "";
}
}
else if (!strcmp(p, "msg")) {
uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_MAGIC);
}
else if (!strcmp(p, "msgbin")) {
struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_MAGIC);
new_umi->num = 1;
}
else if (!strcmp(p, "msgnl")) {
struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_MAGIC);
new_umi->num = 2;
}
else if (!strcmp(p, "msgbinnl")) {
struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_MAGIC);
new_umi->num = 3;
}
else if (!strcmp(p, "unix")) {
struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_MAGIC);
new_umi->num = 4;
}
else if (!strcmp(p, "micros")) {
struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_MAGIC);
new_umi->num = 5;
}
else if (!strcmp(p, "strftime")) {
struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_MAGIC);
new_umi->num = 6;
if (colon) {
new_umi->str = colon+1;
new_umi->str_len = strlen(colon+1);
}
else {
new_umi->str = "";
}
}
if (colon) *colon = ':';
p = strtok(NULL, "|");
}
ule->configured = 1;
}
struct uwsgi_buffer *ub = uwsgi_buffer_new(len + strlen(ule->args));
struct uwsgi_msgpack_item *umi = (struct uwsgi_msgpack_item*) ule->data;
uint32_t tmp_len = 0;
while(umi) {
switch(umi->type) {
case(MSGPACK_NIL):
if (uwsgi_buffer_msgpack_nil(ub)) goto end;
break;
case(MSGPACK_TRUE):
if (uwsgi_buffer_msgpack_true(ub)) goto end;
break;
case(MSGPACK_FALSE):
if (uwsgi_buffer_msgpack_false(ub)) goto end;
break;
case(MSGPACK_STR):
if (uwsgi_buffer_msgpack_str(ub, umi->str, umi->str_len)) goto end;
break;
case(MSGPACK_BIN):
if (uwsgi_buffer_msgpack_bin(ub, umi->str, umi->str_len)) goto end;
break;
case(MSGPACK_MAP):
if (uwsgi_buffer_msgpack_map(ub, umi->num)) goto end;
break;
case(MSGPACK_ARRAY):
if (uwsgi_buffer_msgpack_array(ub, umi->num)) goto end;
break;
case(MSGPACK_INT):
if (uwsgi_buffer_msgpack_int(ub, umi->num)) goto end;
break;
case(MSGPACK_FLOAT):
if (uwsgi_buffer_msgpack_float(ub, umi->fnum)) goto end;
break;
case(MSGPACK_MAGIC):
// msg
tmp_len = len;
if (umi->num == 0) {
if (msg[len-1] == '\n') tmp_len--;
if (uwsgi_buffer_msgpack_str(ub, msg, tmp_len)) goto end;
}
// msgbin
else if (umi->num == 1) {
if (msg[len-1] == '\n') tmp_len--;
if (uwsgi_buffer_msgpack_bin(ub, msg, tmp_len)) goto end;
}
// msgnl
if (umi->num == 2) {
if (uwsgi_buffer_msgpack_str(ub, msg, tmp_len)) goto end;
}
// msgbinnl
else if (umi->num == 3) {
if (uwsgi_buffer_msgpack_bin(ub, msg, tmp_len)) goto end;
}
// unix
else if (umi->num == 4) {
if (uwsgi_buffer_msgpack_int(ub, (int64_t)uwsgi_now())) goto end;
}
// micros
else if (umi->num == 5) {
if (uwsgi_buffer_msgpack_int(ub, (int64_t)uwsgi_micros())) goto end;
}
// strftime
else if (umi->num == 6) {
char sftime[64];
time_t now = uwsgi_now();
int rlen = strftime(sftime, 64, umi->str, localtime(&now));
if (rlen > 0) {
if (uwsgi_buffer_msgpack_str(ub, sftime, rlen)) goto end;
}
else {
if (uwsgi_buffer_msgpack_str(ub, "", 0)) goto end;
}
}
break;
default:
break;
}
umi = umi->next;
}
buf = ub->buf;
*rlen = ub->pos;
ub->buf = NULL;
end:
uwsgi_buffer_destroy(ub);
return buf;
}
static void uwsgi_msgpack_register() {
uwsgi_register_log_encoder("msgpack", uwsgi_msgpack_log_encoder);
}
struct uwsgi_plugin msgpack_plugin = {
.name = "msgpack",
.on_load = uwsgi_msgpack_register,
};
+5
View File
@@ -0,0 +1,5 @@
NAME='msgpack'
CFLAGS=[]
LDFLAGS=[]
LIBS=[]
GCC_LIST = ['msgpack']
+8
View File
@@ -118,6 +118,14 @@ static void *uwsgi_pty_loop(void *arg) {
if client is ready we have something to write to the master pty
*/
// block signals on this thread
sigset_t smask;
sigfillset(&smask);
#ifndef UWSGI_DEBUG
sigdelset(&smask, SIGSEGV);
#endif
pthread_sigmask(SIG_BLOCK, &smask, NULL);
for(;;) {
char buf[8192];
int interesting_fd = -1;
+3
View File
@@ -394,6 +394,7 @@ PyObject *py_uwsgi_register_rpc(PyObject * self, PyObject * args) {
return NULL;
}
Py_INCREF(func);
if (uwsgi_register_rpc(name, &python_plugin, argc, func)) {
return PyErr_Format(PyExc_ValueError, "unable to register rpc function");
@@ -498,6 +499,8 @@ PyObject *py_uwsgi_register_signal(PyObject * self, PyObject * args) {
return NULL;
}
Py_INCREF(handler);
if (uwsgi_register_signal(uwsgi_signal, signal_kind, handler, 0)) {
return PyErr_Format(PyExc_ValueError, "unable to register signal");
}
+12
View File
@@ -818,6 +818,18 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
uwsgi_apps[wsgi_req->app_id].requests++;
env = rb_hash_new();
// the following vars have to always been defined (we skip REQUEST_METHOD and PATH_INFO as they should always be available)
rb_hash_aset(env, rb_str_new2("SCRIPT_NAME"), rb_str_new2(""));
rb_hash_aset(env, rb_str_new2("QUERY_STRING"), rb_str_new2(""));
rb_hash_aset(env, rb_str_new2("SERVER_NAME"), rb_str_new2(uwsgi.hostname));
// SERVER_PORT
char *server_port = strchr(wsgi_req->socket->name, ':');
if (server_port) {
rb_hash_aset(env, rb_str_new2("SERVER_PORT"), rb_str_new(server_port+1, strlen(server_port+1)));
}
else {
rb_hash_aset(env, rb_str_new2("SERVER_PORT"), rb_str_new2("80"));
}
// fill ruby hash
for(i=0;i<wsgi_req->var_cnt;i++) {
+258
View File
@@ -0,0 +1,258 @@
#include <uwsgi.h>
#include <rados/librados.h>
extern struct uwsgi_server uwsgi;
/*
Author: Javier Guerra
based on the uWSGI GlusterFS plugin by Roberto De Ioris
--rados-mount mountpoint=/foo,pool=unbit001,config=/etc/ceph.conf
*/
struct uwsgi_plugin rados_plugin;
struct uwsgi_rados {
int timeout;
struct uwsgi_string_list *mountpoints;
} urados;
static struct uwsgi_option uwsgi_rados_options[] = {
{"rados-mount", required_argument, 0, "virtual mount the specified rados volume in a uri", uwsgi_opt_add_string_list, &urados.mountpoints, UWSGI_OPT_MIME},
{"rados-timeout", required_argument, 0, "timeout for async operations", uwsgi_opt_set_int, &urados.timeout, 0},
{0, 0, 0, 0, 0, 0, 0},
};
static int uwsgi_rados_read_sync(struct wsgi_request *wsgi_req, rados_ioctx_t *ctx, const char *key, size_t remains) {
uint64_t off = 0;
while(remains > 0) {
char buf[8192];
int rlen = rados_read(ctx, key, buf, UMIN(remains, 8192), off);
if (rlen <= 0) return -1;
if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) return -1;
remains -= rlen;
off += rlen;
}
return 0;
}
/*
async read of a resource
the uwsgi_rados_async_io structure is passed between threads
the callback simply signal the main core about the availability of data
*/
struct uwsgi_rados_async_io {
int fd[2];
ssize_t rlen;
};
static void uwsgi_rados_read_async_cb(rados_completion_t comp, void *data) {
struct uwsgi_rados_async_io *aio = (struct uwsgi_rados_async_io *) data;
#ifdef UWSGI_DEBUG
uwsgi_log("[rados-cb] rlen = %d\n", rlen);
#endif
aio->rlen = rados_aio_get_return_value(comp);
// signal the core
if (write(aio->fd[1], "\1", 1) <= 0) {
uwsgi_error("uwsgi_rados_read_async_cb()/write()");
}
}
static int uwsgi_rados_read_async(struct wsgi_request *wsgi_req, rados_ioctx_t *ctx, const char *key, size_t remains) {
uint64_t off = 0;
char buf[8192];
struct uwsgi_rados_async_io aio;
int ret = -1;
if (pipe(aio.fd)) {
uwsgi_error("uwsgi_rados_read_async()/pipe()");
return -1;
}
aio.rlen = -1;
rados_completion_t comp;
if (rados_aio_create_completion(&aio, uwsgi_rados_read_async_cb, NULL, &comp) < 0) goto end;
while(remains > 0) {
// trigger an async read
if (rados_aio_read(ctx, key, comp, buf, 8192, off) < 0) goto end;
// wait for the callback to be executed
if (uwsgi.wait_read_hook(aio.fd[0], urados.timeout) <= 0) goto end;
if (aio.rlen <= 0) goto end;
if (uwsgi_response_write_body_do(wsgi_req, buf, aio.rlen)) goto end;
remains -= aio.rlen;
}
ret = 0;
end:
rados_aio_release(&comp);
close(aio.fd[0]);
close(aio.fd[1]);
return ret;
}
static void uwsgi_rados_add_mountpoint(char *arg, size_t arg_len) {
char *rad_mountpoint = NULL;
char *rad_config = NULL;
char *rad_poolname = NULL;
if (uwsgi_kvlist_parse(arg, arg_len, ',', '=',
"mountpoint", &rad_mountpoint,
"config", &rad_config,
"pool", &rad_poolname,
NULL)) {
uwsgi_log("unable to parse rados mountpoint definition\n");
exit(1);
}
if (!rad_mountpoint|| !rad_poolname) {
uwsgi_log("[rados] mount requires a mountpoint, and a pool name.\n");
exit(1);
}
time_t now = uwsgi_now();
uwsgi_log("[rados] mounting %s ...\n", rad_mountpoint);
rados_t cluster;
if (rados_create(&cluster, NULL) < 0) {
uwsgi_error("Can't create Ceph cluster handle");
exit(1);
}
if (rad_config)
uwsgi_log("Using Ceph conf:%s\n", rad_config);
else
uwsgi_log("Using default Ceph conf.\n");
if (rados_conf_read_file(cluster, rad_config) < 0) {
uwsgi_error("Can't configure Ceph cluster handle");
exit(1);
}
if (rados_connect(cluster) < 0) {
uwsgi_error("Can't connect with Ceph cluster");
exit(1);
}
rados_ioctx_t ctx;
uwsgi_log("Ceph pool: %s\n", rad_poolname);
if (rados_ioctx_create(cluster, rad_poolname, &ctx) < 0) {
uwsgi_error("Can't open rados pool")
rados_shutdown(cluster);
exit(1);
}
int id = uwsgi_apps_cnt;
struct uwsgi_app *ua = uwsgi_add_app(id, rados_plugin.modifier1, rad_mountpoint, strlen(rad_mountpoint), NULL, NULL);
if (!ua) {
uwsgi_log("[rados] unable to mount %s\n", rad_mountpoint);
rados_shutdown(cluster);
exit(1);
}
ua->responder0 = cluster;
ua->responder1 = ctx;
ua->started_at = now;
ua->startup_time = uwsgi_now() - now;
uwsgi_log("Rados app/mountpoint %d (%s) loaded in %d seconds at %p\n", id, rad_mountpoint, (int) ua->startup_time, ctx);
}
// we translate the string list to an app representation
// this happens before fork() if not in lazy/lazy-apps mode
static void uwsgi_rados_setup() {
if (!urados.timeout) {
urados.timeout = uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT];
}
struct uwsgi_string_list *usl = urados.mountpoints;
while(usl) {
uwsgi_rados_add_mountpoint(usl->value, usl->len);
usl = usl->next;
}
}
static int uwsgi_rados_request(struct wsgi_request *wsgi_req) {
char filename[PATH_MAX+1];
if (!wsgi_req->uh->pktsize) {
uwsgi_log( "Empty request. skip.\n");
return -1;
}
if (uwsgi_parse_vars(wsgi_req)) {
return -1;
}
// blocks empty paths
if (wsgi_req->path_info_len == 0 || wsgi_req->path_info_len > PATH_MAX) {
uwsgi_403(wsgi_req);
return UWSGI_OK;
}
wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, rados_plugin.modifier1);
if (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) {
if (uwsgi_apps[uwsgi.default_app].modifier1 == rados_plugin.modifier1) {
wsgi_req->app_id = uwsgi.default_app;
}
}
if (wsgi_req->app_id == -1) {
uwsgi_404(wsgi_req);
return UWSGI_OK;
}
struct uwsgi_app *ua = &uwsgi_apps[wsgi_req->app_id];
if (wsgi_req->path_info_len > ua->mountpoint_len &&
memcmp(wsgi_req->path_info, ua->mountpoint, ua->mountpoint_len) == 0)
{
memcpy(filename, wsgi_req->path_info+ua->mountpoint_len, wsgi_req->path_info_len-ua->mountpoint_len);
} else {
memcpy(filename, wsgi_req->path_info, wsgi_req->path_info_len);
}
filename[wsgi_req->path_info_len] = 0;
struct {
uint64_t size;
time_t mtime;
} st;
rados_ioctx_t ctx = ua->responder1;
int r = rados_stat(ctx, filename, &st.size, &st.mtime);
if (r < 0) {
if (r == -ENOENT)
uwsgi_404(wsgi_req);
else
uwsgi_403(wsgi_req);
return UWSGI_OK;
}
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end;
size_t mime_type_len = 0;
char *mime_type = uwsgi_get_mime_type(wsgi_req->path_info, wsgi_req->path_info_len, &mime_type_len);
if (mime_type) {
if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end;
}
if (uwsgi_response_add_last_modified(wsgi_req, (uint64_t) st.mtime)) goto end;
if (uwsgi_response_add_content_length(wsgi_req, st.size)) goto end;
// skip body on HEAD
if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) {
size_t remains = st.size;
if (uwsgi.async > 1) {
if (uwsgi_rados_read_async(wsgi_req, ctx, filename, remains)) goto end;
}
else {
if (uwsgi_rados_read_sync(wsgi_req, ctx, filename, remains)) goto end;
}
}
end:
return UWSGI_OK;
}
struct uwsgi_plugin rados_plugin = {
.name = "rados",
.modifier1 = 28,
.options = uwsgi_rados_options,
.post_fork = uwsgi_rados_setup,
.request = uwsgi_rados_request,
.after_request = log_request,
};
+7
View File
@@ -0,0 +1,7 @@
import os
NAME='rados'
CFLAGS = []
LDFLAGS = []
LIBS = ['-lrados']
GCC_LIST = ['rados']
+1 -1
View File
@@ -1,4 +1,4 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
+8 -1
View File
@@ -39,10 +39,17 @@ ssize_t uwsgi_rsyslog_logger(struct uwsgi_logger *ul, char *message, size_t len)
uwsgi_socket_nb(ul->fd);
ul->count = 29;
char *comma = strchr(ul->arg, ',');
if (comma) {
ul->data = comma+1;
*comma = 0;
char *prisev = strchr(ul->data, ',');
if (prisev) {
*prisev = 0;
ul->count = atoi(prisev+1);
}
}
else {
ul->data = uwsgi_concat2(uwsgi.hostname," uwsgi");
@@ -83,7 +90,7 @@ ssize_t uwsgi_rsyslog_logger(struct uwsgi_logger *ul, char *message, size_t len)
for (pos=0 ; pos < (int) len ;) {
if (pos > 0 && !u_rsyslog.split_msg) return pos;
msg_len = ( ((int)len)-pos > u_rsyslog.msg_size ? u_rsyslog.msg_size : ((int)len)-pos);
rlen = snprintf(ul->buf, u_rsyslog.packet_size, "<29>%.*s %s: %.*s", 15, ctime_storage+4, (char *) ul->data, msg_len, &message[pos]);
rlen = snprintf(ul->buf, u_rsyslog.packet_size, "<%d>%.*s %s: %.*s", ul->count, 15, ctime_storage+4, (char *) ul->data, msg_len, &message[pos]);
if (rlen > 0 && rlen <= u_rsyslog.packet_size) {
ret = sendto(ul->fd, ul->buf, rlen, 0, (const struct sockaddr *) &ul->addr, ul->addr_len);
if (ret <= 0) return ret;
+309
View File
@@ -0,0 +1,309 @@
#include "common.h"
extern struct uwsgi_tuntap utt;
// create a new peer
struct uwsgi_tuntap_peer *uwsgi_tuntap_peer_create(struct uwsgi_tuntap_router *uttr, int fd) {
struct uwsgi_tuntap_peer *uttp = uwsgi_calloc(sizeof(struct uwsgi_tuntap_peer));
uttp->fd = fd;
// leave space fot he uwsgi header
uttp->buf = uwsgi_malloc(utt.buffer_size + 4);
uttp->write_buf = uwsgi_malloc(utt.buffer_size);
if (uttr->peers_tail) {
uttr->peers_tail->next = uttp;
uttp->prev = uttr->peers_tail;
uttr->peers_tail = uttp;
}
else {
uttr->peers_head = uttp;
uttr->peers_tail = uttp;
}
return uttp;
}
// destroy a peer
void uwsgi_tuntap_peer_destroy(struct uwsgi_tuntap_router *uttr, struct uwsgi_tuntap_peer *uttp) {
struct uwsgi_tuntap_peer *prev = uttp->prev;
struct uwsgi_tuntap_peer *next = uttp->next;
if (prev) {
prev->next = next;
}
if (next) {
next->prev = prev;
}
if (uttp == uttr->peers_head) {
uttr->peers_head = next;
}
if (uttp == uttr->peers_tail) {
uttr->peers_tail = prev;
}
free(uttp->buf);
free(uttp->write_buf);
close(uttp->fd);
free(uttp);
}
// get a peer by addr
struct uwsgi_tuntap_peer *uwsgi_tuntap_peer_get_by_addr(struct uwsgi_tuntap_router *uttr, uint32_t addr) {
struct uwsgi_tuntap_peer *uttp = uttr->peers_head;
while (uttp) {
if (uttp->addr == addr)
return uttp;
uttp = uttp->next;
}
return NULL;
}
// block all reading peers
void uwsgi_tuntap_block_reads(struct uwsgi_tuntap_router *uttr) {
struct uwsgi_tuntap_peer *uttp = uttr->peers_head;
while (uttp) {
if (!uttp->blocked_read) {
if (!uttp->wait_for_write) {
if (event_queue_del_fd(uttr->queue, uttp->fd, event_queue_read())) {
struct uwsgi_tuntap_peer *tmp_uttp = uttp;
uttp = uttp->next;
uwsgi_tuntap_peer_destroy(uttr, tmp_uttp);
continue;
}
}
else {
if (event_queue_fd_readwrite_to_write(uttr->queue, uttp->fd)) {
struct uwsgi_tuntap_peer *tmp_uttp = uttp;
uttp = uttp->next;
uwsgi_tuntap_peer_destroy(uttr, tmp_uttp);
continue;
}
}
uttp->blocked_read = 1;
}
uttp = uttp->next;
}
}
//unblock all reading peers
void uwsgi_tuntap_unblock_reads(struct uwsgi_tuntap_router *uttr) {
struct uwsgi_tuntap_peer *uttp = uttr->peers_head;
while (uttp) {
if (uttp->blocked_read) {
if (!uttp->wait_for_write) {
if (event_queue_add_fd_read(uttr->queue, uttp->fd)) {
struct uwsgi_tuntap_peer *tmp_uttp = uttp;
uttp = uttp->next;
uwsgi_tuntap_peer_destroy(uttr, tmp_uttp);
continue;
}
}
else {
if (event_queue_fd_write_to_readwrite(uttr->queue, uttp->fd)) {
struct uwsgi_tuntap_peer *tmp_uttp = uttp;
uttp = uttp->next;
uwsgi_tuntap_peer_destroy(uttr, tmp_uttp);
continue;
}
}
uttp->blocked_read = 0;
}
uttp = uttp->next;
}
}
// enqueue a packet in the tuntap device
void uwsgi_tuntap_enqueue(struct uwsgi_tuntap_router *uttr) {
ssize_t rlen = write(uttr->fd, uttr->write_buf + uttr->write_pos, uttr->write_pktsize - uttr->write_pos);
// error on the tuntap device, destroy !!!
if (rlen == 0) {
uwsgi_error("uwsgi_tuntap_enqueue()/write()");
exit(1);
}
if (rlen < 0) {
if (uwsgi_is_again())
goto retry;
uwsgi_error("uwsgi_tuntap_enqueue()/write()");
exit(1);
}
uttr->write_pos += rlen;
if (uttr->write_pos >= uttr->write_pktsize) {
uttr->write_pos = 0;
if (uttr->wait_for_write) {
if (event_queue_fd_write_to_read(uttr->queue, uttr->fd)) {
uwsgi_error("uwsgi_tuntap_enqueue()/event_queue_fd_read_to_write()");
exit(1);
}
uttr->wait_for_write = 0;
}
uwsgi_tuntap_unblock_reads(uttr);
return;
}
retry:
if (!uttr->wait_for_write) {
uwsgi_tuntap_block_reads(uttr);
if (event_queue_fd_read_to_write(uttr->queue, uttr->fd)) {
uwsgi_error("uwsgi_tuntap_enqueue()/event_queue_fd_read_to_write()");
exit(1);
}
uttr->wait_for_write = 1;
}
}
// receive a packet from the client
int uwsgi_tuntap_peer_dequeue(struct uwsgi_tuntap_router *uttr, struct uwsgi_tuntap_peer *uttp) {
// get body
if (uttp->header_pos >= 4) {
ssize_t rlen = read(uttp->fd, uttp->buf + uttp->buf_pos, uttp->buf_pktsize - uttp->buf_pos);
if (rlen == 0)
return -1;
if (rlen < 0) {
if (uwsgi_is_again())
return 0;
uwsgi_error("uwsgi_tuntap_peer_dequeue()/read()");
return -1;
}
uttp->buf_pos += rlen;
uttp->rx += rlen;
// a whole pkt has been received
if (uttp->buf_pos >= uttp->buf_pktsize) {
uttp->header_pos = 0;
uttp->buf_pos = 0;
if (uwsgi_tuntap_firewall_check(utt.fw_out, uttp->buf, uttp->buf_pktsize)) return 0;
// if there is no associated address store the source
if (!uttp->addr) {
uint32_t *src_ip = (uint32_t *) & uttp->buf[12];
uttp->addr = *src_ip;
// drop invalid ip addresses
if (!uttp->addr)
return -1;
struct uwsgi_tuntap_peer *tmp_uttp = uwsgi_tuntap_peer_get_by_addr(uttr, uttp->addr);
char ip[INET_ADDRSTRLEN + 1];
memset(ip, 0, INET_ADDRSTRLEN + 1);
if (!inet_ntop(AF_INET, &uttp->addr, ip, INET_ADDRSTRLEN)) {
uwsgi_error("inet_ntop()");
return -1;
}
if (uttp != tmp_uttp) {
uwsgi_log("[tuntap-router] detected ip collision for %s\n", ip);
uwsgi_tuntap_peer_destroy(uttr, tmp_uttp);
}
uwsgi_log("[tuntap-router] registered new peer %s (fd: %d)\n", ip, uttp->fd);
}
memcpy(uttr->write_buf, uttp->buf, uttp->buf_pktsize);
uttr->write_pktsize = uttp->buf_pktsize;
uwsgi_tuntap_enqueue(uttr);
}
return 0;
}
ssize_t rlen = read(uttp->fd, uttp->header + uttp->header_pos, 4 - uttp->header_pos);
if (rlen == 0)
return -1;
if (rlen < 0) {
if (uwsgi_is_again())
return 0;
uwsgi_error("uwsgi_tuntap_peer_dequeue()/read()");
return -1;
}
uttp->header_pos += rlen;
if (uttp->header_pos >= 4) {
uint16_t *pktsize = (uint16_t *) &uttp->header[1];
uttp->buf_pktsize = *pktsize;
uttp->rx += 4;
}
return 0;
}
// enqueue a packet to the client
int uwsgi_tuntap_peer_enqueue(struct uwsgi_tuntap_router *uttr, struct uwsgi_tuntap_peer *uttp) {
ssize_t rlen = write(uttp->fd, uttp->write_buf + uttp->written, uttp->write_buf_pktsize - uttp->written);
if (rlen == 0) {
uwsgi_error("uwsgi_tuntap_peer_enqueue()/write()");
return -1;
}
if (rlen < 0) {
if (uwsgi_is_again())
goto retry;
uwsgi_error("uwsgi_tuntap_peer_enqueue()/write()");
return -1;
}
uttp->written += rlen;
uttp->tx += rlen;
if (uttp->written >= uttp->write_buf_pktsize) {
uttp->written = 0;
uttp->write_buf_pktsize = 0;
if (uttp->wait_for_write) {
// if the write ends while we are writing to the tuntap, block the reads
if (uttr->wait_for_write) {
uttp->blocked_read = 1;
if (event_queue_del_fd(uttr->queue, uttp->fd, event_queue_write())) {
uwsgi_error("uwsgi_tuntap_peer_enqueue()/event_queue_del_fd()");
return -1;
}
}
else {
if (event_queue_fd_readwrite_to_read(uttr->queue, uttp->fd)) {
uwsgi_error("uwsgi_tuntap_peer_enqueue()/event_queue_fd_write_to_read()");
return -1;
}
}
uttp->wait_for_write = 0;
}
return 0;
}
memmove(uttp->write_buf, uttp->write_buf + rlen, uttp->write_buf_pktsize - rlen);
uttp->write_buf_pktsize -= rlen;
retry:
if (!uttp->wait_for_write) {
if (event_queue_fd_read_to_readwrite(uttr->queue, uttp->fd)) {
uwsgi_error("uwsgi_tuntap_peer_enqueue()/event_queue_fd_read_to_write()");
return -1;
}
uttp->wait_for_write = 1;
}
return 0;
}
int uwsgi_tuntap_device(char *name) {
struct ifreq ifr;
int fd = open(UWSGI_TUNTAP_DEVICE, O_RDWR);
if (fd < 0) {
uwsgi_error_open(UWSGI_TUNTAP_DEVICE);
exit(1);
}
memset(&ifr, 0, sizeof(struct ifreq));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
strncpy(ifr.ifr_name, name, IFNAMSIZ);
if (ioctl(fd, TUNSETIFF, (void *) &ifr) < 0) {
uwsgi_error("uwsgi_tuntap_device()/ioctl()");
exit(1);
}
uwsgi_log("initialized tuntap device %s (fd: %d)\n", ifr.ifr_name, fd);
return fd;
}
+79
View File
@@ -0,0 +1,79 @@
#include <uwsgi.h>
#ifdef __linux__
#include <linux/if_tun.h>
#define UWSGI_TUNTAP_DEVICE "/dev/net/tun"
#endif
/*
a peer is a client connected to the router. It has 2 queue, one for read
and one for write. The write queue can be filled up. If the write queue is full, packets are dropped.
*/
struct uwsgi_tuntap_peer {
int fd;
uint32_t addr;
int wait_for_write;
int blocked_read;
size_t written;
char header[4];
uint8_t header_pos;
char *buf;
uint16_t buf_pktsize;
uint16_t buf_pos;
char *write_buf;
uint16_t write_buf_pktsize;
uint16_t write_buf_pos;
struct uwsgi_tuntap_peer *prev;
struct uwsgi_tuntap_peer *next;
// counters
uint64_t tx;
uint64_t rx;
uint64_t dropped;
};
struct uwsgi_tuntap_firewall_rule {
uint8_t action;
uint32_t src;
uint32_t src_mask;
uint32_t dst;
uint32_t dst_mask;
struct uwsgi_tuntap_firewall_rule *next;
};
struct uwsgi_tuntap_router {
int fd;
int server_fd;
int queue;
char *buf;
char *write_buf;
struct uwsgi_tuntap_peer *peers_head;
struct uwsgi_tuntap_peer *peers_tail;
uint16_t write_pktsize;
uint16_t write_pos;
int wait_for_write;
};
struct uwsgi_tuntap {
struct uwsgi_string_list *routers;
struct uwsgi_string_list *devices;
uint16_t buffer_size;
struct uwsgi_tuntap_firewall_rule *fw_in;
struct uwsgi_tuntap_firewall_rule *fw_out;
};
int uwsgi_tuntap_peer_dequeue(struct uwsgi_tuntap_router *, struct uwsgi_tuntap_peer *);
int uwsgi_tuntap_peer_enqueue(struct uwsgi_tuntap_router *, struct uwsgi_tuntap_peer *);
void uwsgi_tuntap_enqueue(struct uwsgi_tuntap_router *);
int uwsgi_tuntap_firewall_check(struct uwsgi_tuntap_firewall_rule *, char *, uint16_t);
struct uwsgi_tuntap_peer *uwsgi_tuntap_peer_create(struct uwsgi_tuntap_router *, int);
struct uwsgi_tuntap_peer *uwsgi_tuntap_peer_get_by_addr(struct uwsgi_tuntap_router *,uint32_t);
void uwsgi_tuntap_peer_destroy(struct uwsgi_tuntap_router *, struct uwsgi_tuntap_peer *);
int uwsgi_tuntap_device(char *);
void uwsgi_tuntap_opt_firewall(char *, char *, void *);
+118
View File
@@ -0,0 +1,118 @@
#include "common.h"
extern struct uwsgi_tuntap utt;
int uwsgi_tuntap_firewall_check(struct uwsgi_tuntap_firewall_rule *direction, char *pkt, uint16_t len) {
// sanity check
if (len < 20) return -1;
uint32_t *src_ip = (uint32_t *) &pkt[12];
uint32_t *dst_ip = (uint32_t *) &pkt[16];
uint32_t src = ntohl(*src_ip);
uint32_t dst = ntohl(*dst_ip);
struct uwsgi_tuntap_firewall_rule *utfr = direction;
while(utfr) {
if (utfr->src) {
uint32_t src_masked = src & utfr->src_mask;
if (src_masked != utfr->src) goto next;
}
if (utfr->dst) {
uint32_t dst_masked = dst & utfr->dst_mask;
if (dst_masked != utfr->dst) goto next;
}
return utfr->action;
next:
utfr = utfr->next;
}
return 0;
}
static void uwsgi_tuntap_firewall_add_rule(struct uwsgi_tuntap_firewall_rule **direction, uint8_t action, uint32_t src, uint32_t src_mask, uint32_t dst, uint32_t dst_mask) {
#ifdef UWSGI_DEBUG
uwsgi_log("[tuntap-router] firewall action %d %x %x %x %x\n",action, src,src_mask,dst,dst_mask);
#endif
struct uwsgi_tuntap_firewall_rule *old_uttr = NULL, *uttr = *direction;
while(uttr) {
old_uttr = uttr;
uttr = uttr->next;
}
uttr = uwsgi_calloc(sizeof(struct uwsgi_tuntap_firewall_rule));
uttr->action = action;
uttr->src = src & src_mask;
uttr->src_mask = src_mask;
uttr->dst = dst & dst_mask;
uttr->dst_mask = dst_mask;
if (old_uttr) {
old_uttr->next = uttr;
}
else {
*direction = uttr;
}
}
void uwsgi_tuntap_opt_firewall(char *opt, char *value, void *direction) {
char *space = strchr(value, ' ');
if (!space) {
if (!strcmp("deny", value)) {
uwsgi_tuntap_firewall_add_rule((struct uwsgi_tuntap_firewall_rule **) direction, 1, 0, 0, 0, 0);
return;
}
uwsgi_tuntap_firewall_add_rule((struct uwsgi_tuntap_firewall_rule **) direction, 0, 0, 0, 0, 0);
return;
}
*space = 0;
uint8_t action = 0;
if (!strcmp(value, "deny")) action = 1;
char *space2 = strchr(space + 1, ' ');
if (!space2) {
uwsgi_log("invalid tuntap firewall rule syntax. must be <action> <src/mask> <dst/mask>");
}
*space2 = 0;
uint32_t src = 0;
uint32_t src_mask = 32;
uint32_t dst = 0;
uint32_t dst_mask = 32;
char *slash = strchr(space + 1 , '/');
if (slash) {
src_mask = atoi(slash+1);
*slash = 0;
}
if (inet_pton(AF_INET, space + 1, &src) != 1) {
uwsgi_error("uwsgi_tuntap_opt_firewall()/inet_pton()");
exit(1);
}
if (slash) *slash = '/';
*space = ' ';
slash = strchr(space2 + 1 , '/');
if (slash) {
dst_mask = atoi(slash+1);
*slash = 0;
}
if (inet_pton(AF_INET, space2 + 1, &dst) != 1) {
uwsgi_error("uwsgi_tuntap_opt_firewall()/inet_pton()");
exit(1);
}
if (slash) *slash = '/';
*space2 = ' ';
uwsgi_tuntap_firewall_add_rule((struct uwsgi_tuntap_firewall_rule **) direction, action, ntohl(src), (0xffffffff << (32-src_mask)), ntohl(dst), (0xffffffff << (32-dst_mask)));
}
+323
View File
@@ -0,0 +1,323 @@
#include "common.h"
extern struct uwsgi_server uwsgi;
struct uwsgi_tuntap utt;
/*
The tuntap router is a non-blocking highly optimized ip router
translating from tuntap device to socket streams.
It is meant as a replacement for the currently available networking namespaces
approaches. Compared to veth or macvlan it is really simple and allows total control
over the routing subsystem (in addition to a simple customizable firewalling engine)
Generally you spawn the tuntap router in the Emperor instance
[uwsgi]
master = true
emperor = /etc/uwsgi
emperor-use-clone = fs,uts,ipc,pid,net
tuntap-router = emperor0 /tmp/tuntap.socket
exec-as-root = ifconfig emperor0 192.168.0.1 netmask 255.255.255.0 up
exec-as-root = iptables -t nat -F
exec-as-root = iptables -t nat -A POSTROUTING -o eth0 -s 192.168.0.0/24 -j MASQUERADE
exec-as-root = echo 1 > /proc/sys/net/ipv4/ip_forward
vassals will run in new namespaces in which they create a tuntap device attached to
the tuntap router. UNIX sockets are the only way to connect to the tuntap router
after jailing.
Firewalling is based on 2 chains (in and out), and each rule is formed by 3 parameters: <action> <src> <dst>
The firewall is applied to traffic from the clients to the tuntap device (out) and the opposite (in)
The first matching rule stop the chain, if no rule applies, the policy is "allow"
the following rules allows access from vassals to the internet, but block
vassals intercommunication
--tuntap-router-firewall-out = allow 192.168.0.0/24 192.168.0.1
--tuntap-router-firewall-out = deny 192.168.0.0/24 192.168.0.0/24
--tuntap-router-firewall-out = allow 192.168.0.0/24 0.0.0.0
--tuntap-router-firewall-out = deny
--tuntap-router-firewall-in = allow 192.168.0.1 192.168.0.0/24
--tuntap-router-firewall-in = deny 192.168.0.0/24 192.168.0.0/24
--tuntap-router-firewall-in = allow 0.0.0.0 192.168.0.0/24
--tuntap-router-firewall-in = deny
Author: Roberto De Ioris
TODO:
- some form of security to disallow raw access to the tuntap router unix socket
- stats server
- port to other platforms ?
*/
static struct uwsgi_option uwsgi_tuntap_options[] = {
{"tuntap-router", required_argument, 0, "run the tuntap router (syntax: <device> <socket> [stats])", uwsgi_opt_add_string_list, &utt.routers, 0},
{"tuntap-device", required_argument, 0, "add a tuntap device to the instance (syntax: <device>[ <socket>])", uwsgi_opt_add_string_list, &utt.devices, 0},
{"tuntap-router-firewall-in", required_argument, 0, "add a firewall rule to the tuntap router (syntax: <action> <src/mask> <dst/mask>)", uwsgi_tuntap_opt_firewall, &utt.fw_in, 0},
{"tuntap-router-firewall-out", required_argument, 0, "add a firewall rule to the tuntap router (syntax: <action> <src/mask> <dst/mask>)", uwsgi_tuntap_opt_firewall, &utt.fw_out, 0},
{NULL, 0, 0, NULL, NULL, NULL, 0},
};
static void *uwsgi_tuntap_loop(void *arg) {
// block signals on this thread
sigset_t smask;
sigfillset(&smask);
#ifndef UWSGI_DEBUG
sigdelset(&smask, SIGSEGV);
#endif
pthread_sigmask(SIG_BLOCK, &smask, NULL);
struct uwsgi_tuntap_router *uttr = (struct uwsgi_tuntap_router *) arg;
uwsgi_socket_nb(uttr->fd);
if (!utt.buffer_size)
utt.buffer_size = 8192;
uttr->buf = uwsgi_malloc(utt.buffer_size);
uttr->write_buf = uwsgi_malloc(utt.buffer_size);
uttr->queue = event_queue_init();
if (event_queue_add_fd_read(uttr->queue, uttr->fd)) {
exit(1);
}
if (event_queue_add_fd_read(uttr->queue, uttr->server_fd)) {
exit(1);
}
uwsgi_socket_nb(uttr->server_fd);
struct uwsgi_tuntap_peer *uttp = uwsgi_tuntap_peer_create(uttr, uttr->server_fd);
for (;;) {
int interesting_fd = -1;
int ret = event_queue_wait(uttr->queue, -1, &interesting_fd);
if (ret <= 0)
continue;
if (interesting_fd == uttr->fd) {
if (uttr->wait_for_write) {
uwsgi_tuntap_enqueue(uttr);
continue;
}
ssize_t rlen = read(uttr->fd, uttr->buf, utt.buffer_size);
if (rlen <= 0) {
uwsgi_error("uwsgi_tuntap_loop()/read()");
exit(1);
}
uint16_t pktsize = rlen;
char *ptr = uttp->write_buf + uttp->write_buf_pktsize;
memcpy(ptr + 4, uttr->buf, rlen);
ptr[0] = 0;
ptr[1] = (uint8_t) (pktsize & 0xff);
ptr[2] = (uint8_t) ((pktsize >> 8) & 0xff);
ptr[3] = 0;
uttp->write_buf_pktsize+= pktsize+4;
if (uwsgi_tuntap_peer_enqueue(uttr, uttp)) {
uwsgi_log("server disconnected...\n");
exit(1);
}
continue;
}
if (interesting_fd == uttr->server_fd) {
// read from the client
if (!uttp->wait_for_write) {
if (uwsgi_tuntap_peer_dequeue(uttr, uttp)) {
uwsgi_log("server disconnected...\n");
exit(1);
}
}
else {
// something is wrong (the tuntap device is blocked)
if (uttr->wait_for_write) {
continue;
}
// write to the client
if (uwsgi_tuntap_peer_enqueue(uttr, uttp)) {
uwsgi_log("server disconnected...\n");
exit(1);
}
}
}
}
return NULL;
}
static void uwsgi_tuntap_client() {
if (!utt.devices) return;
struct uwsgi_string_list *usl;
uwsgi_foreach(usl, utt.devices) {
char *space = strchr(usl->value, ' ');
if (space) {
*space = 0;
struct uwsgi_tuntap_router *uttr = uwsgi_calloc(sizeof(struct uwsgi_tuntap_router));
uttr->fd = uwsgi_tuntap_device(usl->value);
uttr->server_fd = uwsgi_connect(space+1, 30, 0);
if (uttr->server_fd < 0) {
uwsgi_error("uwsgi_tuntap_client()/uwsgi_connect()");
exit(1);
}
*space = ' ';
pthread_t t;
pthread_create(&t, NULL, uwsgi_tuntap_loop, uttr);
}
else {
if (uwsgi_tuntap_device(usl->value) < 0) {
// foo
}
}
}
}
void uwsgi_tuntap_router_loop(int id, void *arg) {
int i;
struct uwsgi_tuntap_router *uttr = (struct uwsgi_tuntap_router *) arg;
uttr->buf = uwsgi_malloc(utt.buffer_size);
uttr->write_buf = uwsgi_malloc(utt.buffer_size);
uttr->queue = event_queue_init();
void *events = event_queue_alloc(64);
if (event_queue_add_fd_read(uttr->queue, uttr->server_fd))
exit(1);
if (event_queue_add_fd_read(uttr->queue, uttr->fd))
exit(1);
for (;;) {
int nevents = event_queue_wait_multi(uttr->queue, -1, events, 64);
for (i = 0; i < nevents; i++) {
int interesting_fd = event_queue_interesting_fd(events, i);
if (interesting_fd == uttr->fd) {
// if writing, continue enqueuing
if (uttr->wait_for_write) {
uwsgi_tuntap_enqueue(uttr);
continue;
}
ssize_t rlen = read(uttr->fd, uttr->buf, utt.buffer_size);
if (rlen <= 0) {
uwsgi_error("uwsgi_tuntap_router_loop()/read()");
exit(1);
}
if (uwsgi_tuntap_firewall_check(utt.fw_in, uttr->buf, rlen)) continue;
uint32_t *dst_ip = (uint32_t *) & uttr->buf[16];
struct uwsgi_tuntap_peer *uttp = uwsgi_tuntap_peer_get_by_addr(uttr, *dst_ip);
if (!uttp)
continue;
// check for full write buffer
if (uttp->write_buf_pktsize + 4 + rlen > utt.buffer_size) {
uttp->dropped++;
continue;
}
uint16_t pktsize = rlen;
char *ptr = uttp->write_buf + uttp->write_buf_pktsize;
memcpy(ptr + 4, uttr->buf, rlen);
ptr[0] = 0;
ptr[1] = (uint8_t) (pktsize & 0xff);
ptr[2] = (uint8_t) ((pktsize >> 8) & 0xff);
ptr[3] = 0;
uttp->write_buf_pktsize+= pktsize+4;
if (uwsgi_tuntap_peer_enqueue(uttr, uttp)) {
uwsgi_tuntap_peer_destroy(uttr, uttp);
}
continue;
}
if (interesting_fd == uttr->server_fd) {
int client_fd = uwsgi_accept(uttr->server_fd);
if (client_fd < 0) {
uwsgi_error("uwsgi_tuntap_server_loop()/accept()");
continue;
}
struct uwsgi_tuntap_peer *uttp = uwsgi_tuntap_peer_create(uttr, client_fd);
if (event_queue_add_fd_read(uttr->queue, uttp->fd)) {
uwsgi_tuntap_peer_destroy(uttr, uttp);
}
continue;
}
struct uwsgi_tuntap_peer *uttp = uttr->peers_head;
while (uttp) {
if (interesting_fd == uttp->fd) {
// read from the client
if (event_queue_interesting_fd_is_read(events, i)) {
if (uwsgi_tuntap_peer_dequeue(uttr, uttp)) {
uwsgi_tuntap_peer_destroy(uttr, uttp);
break;
}
}
if (event_queue_interesting_fd_is_write(events, i)) {
// something is wrong (the tuntap device is blocked)
if (uttr->wait_for_write)
break;
// write to the client
if (uwsgi_tuntap_peer_enqueue(uttr, uttp)) {
uwsgi_tuntap_peer_destroy(uttr, uttp);
break;
}
}
break;
}
uttp = uttp->next;
}
}
}
}
static void uwsgi_tuntap_router() {
if (!utt.routers) return;
if (!utt.buffer_size)
utt.buffer_size = 8192;
struct uwsgi_string_list *usl;
uwsgi_foreach(usl, utt.routers) {
char *space = strchr(usl->value, ' ');
if (!space) {
uwsgi_log("invalid tuntap router syntax, must be <device> <socket> [stats]\n");
exit(1);
}
struct uwsgi_tuntap_router *uttr = uwsgi_calloc(sizeof(struct uwsgi_tuntap_router));
uttr->server_fd = bind_to_unix(space+1, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
*space = 0 ;
uttr->fd = uwsgi_tuntap_device(usl->value);
*space = ' ';
if (register_gateway("uWSGI tuntap router", uwsgi_tuntap_router_loop, uttr) == NULL) {
uwsgi_log("unable to register the tuntap server gateway\n");
exit(1);
}
}
}
struct uwsgi_plugin tuntap_plugin = {
.name = "tuntap",
.options = uwsgi_tuntap_options,
.post_jail = uwsgi_tuntap_client,
.jail = uwsgi_tuntap_router,
};
+5
View File
@@ -0,0 +1,5 @@
NAME='tuntap'
CFLAGS=[]
LDFLAGS=[]
LIBS=[]
GCC_LIST=['common','firewall','tuntap']
+19 -6
View File
@@ -103,6 +103,9 @@ parse:
uint16_t fcgi_len = uwsgi_be16((char *)&fr->cl1);
uint32_t fcgi_all_len = sizeof(struct fcgi_record) + fcgi_len + fr->pad;
uint8_t fcgi_type = fr->type;
uint8_t *sid = (uint8_t *) &wsgi_req->stream_id;
sid[0] = fr->req0;
sid[1] = fr->req1;
// if STDIN, end of the loop
if (fcgi_type == 5) {
wsgi_req->uh->modifier1 = uwsgi.fastcgi_modifier1;
@@ -235,8 +238,9 @@ int uwsgi_proto_fastcgi_write(struct wsgi_request *wsgi_req, char *buf, size_t l
struct fcgi_record fr;
fr.version = 1;
fr.type = 6;
fr.req1 = 0;
fr.req0 = 1;
uint8_t *sid = (uint8_t *) &wsgi_req->stream_id;
fr.req1 = sid[1];
fr.req0 = sid[0];
fr.pad = 0;
fr.reserved = 0;
fr.cl0 = (uint8_t) (fcgi_len & 0xff);
@@ -265,8 +269,16 @@ int uwsgi_proto_fastcgi_write(struct wsgi_request *wsgi_req, char *buf, size_t l
}
void uwsgi_proto_fastcgi_close(struct wsgi_request *wsgi_req) {
// special case here, we run i nvoid context, so we need to wait directly here
(void) uwsgi_write_true_nb(wsgi_req->fd, (char *) FCGI_END_REQUEST, sizeof(FCGI_END_REQUEST), uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
// special case here, we run in void context, so we need to wait directly here
char end_request[24];
memcpy(end_request, FCGI_END_REQUEST, 24);
char *sid = (char *) &wsgi_req->stream_id;
// update with request id
end_request[2] = sid[1];
end_request[3] = sid[0];
end_request[10] = sid[1];
end_request[11] = sid[0];
(void) uwsgi_write_true_nb(wsgi_req->fd, end_request, 24, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
uwsgi_proto_base_close(wsgi_req);
}
@@ -279,8 +291,9 @@ int uwsgi_proto_fastcgi_sendfile(struct wsgi_request *wsgi_req, int fd, size_t p
struct fcgi_record fr;
fr.version = 1;
fr.type = 6;
fr.req1 = 0;
fr.req0 = 1;
uint8_t *sid = (uint8_t *) &wsgi_req->stream_id;
fr.req1 = sid[1];
fr.req0 = sid[0];
fr.pad = 0;
fr.reserved = 0;
fr.cl0 = (uint8_t) (fcgi_len & 0xff);
+1 -1
View File
@@ -2,7 +2,7 @@ Gem::Specification.new do |s|
s.name = 'uwsgi'
s.license = 'GPL-2'
s.version = `python -c "import uwsgiconfig as uc; print uc.uwsgi_version"`.sub(/-dev-.*/,'')
s.date = '2013-08-29'
s.date = '2013-09-14'
s.summary = "uWSGI"
s.description = "The uWSGI server for Ruby/Rack"
s.authors = ["Unbit"]
+121 -2
View File
@@ -10,7 +10,7 @@ extern "C" {
#define UMAX8 256
#define UMAX64_STR "18446744073709551615"
#define MAX64_STR "−9223372036854775808"
#define MAX64_STR "-9223372036854775808"
#define uwsgi_error(x) uwsgi_log("%s: %s [%s line %d]\n", x, strerror(errno), __FILE__, __LINE__);
#define uwsgi_error_realpath(x) uwsgi_log("realpath() of %s failed: %s [%s line %d]\n", x, strerror(errno), __FILE__, __LINE__);
@@ -199,6 +199,10 @@ extern "C" {
#include <sys/sysctl.h>
#include <sys/param.h>
#include <sys/cpuset.h>
#include <sys/jail.h>
#ifdef UWSGI_HAS_FREEBSD_LIBJAIL
#include <jail.h>
#endif
#endif
#include <sys/ipc.h>
@@ -229,7 +233,13 @@ extern "C" {
#include <sched.h>
#include <sys/prctl.h>
#include <linux/limits.h>
#endif
#if defined(__linux) || defined(__FreeBSD__)
#include <sys/mount.h>
#endif
#ifdef __linux__
extern int pivot_root(const char *new_root, const char *put_old);
#endif
@@ -443,6 +453,12 @@ struct uwsgi_dyn_dict {
struct uwsgi_dyn_dict *next;
};
struct uwsgi_hook {
char *name;
int (*func)(char *);
struct uwsgi_hook *next;
};
#ifdef UWSGI_PCRE
struct uwsgi_regexp_list {
@@ -553,6 +569,7 @@ struct uwsgi_daemon {
int status;
int registered;
int has_daemonized;
char *pidfile;
int daemonize;
@@ -853,6 +870,7 @@ struct uwsgi_opt {
#define UWSGI_DE_HIJACKED_CODE 173
#define UWSGI_EXCEPTION_CODE 5
#define UWSGI_QUIET_CODE 29
#define UWSGI_BRUTAL_RELOAD_CODE 31
#define MAX_VARS 64
@@ -985,6 +1003,7 @@ struct uwsgi_plugin {
uint16_t(*rpc) (void *, uint8_t, char **, uint16_t *, char *);
void (*jail) (int (*)(void *), char **);
void (*post_jail) (void);
void (*before_privileges_drop) (void);
int (*mule) (char *);
@@ -1233,6 +1252,15 @@ struct uwsgi_logvar {
struct uwsgi_logvar *next;
};
struct uwsgi_log_encoder {
char *name;
char *(*func)(struct uwsgi_log_encoder *, char *, size_t, size_t *);
int configured;
char *args;
void *data;
struct uwsgi_log_encoder *next;
};
struct uwsgi_transformation {
int (*func)(struct wsgi_request *, struct uwsgi_transformation *);
struct uwsgi_buffer *chunk;
@@ -1465,14 +1493,18 @@ struct wsgi_request {
int is_routing;
int is_final_routing;
int is_error_routing;
int is_response_routing;
int routes_applied;
int response_routes_applied;
// internal routing vm program counter
uint32_t route_pc;
uint32_t error_route_pc;
uint32_t response_route_pc;
uint32_t final_route_pc;
// internal routing goto instruction
uint32_t route_goto;
uint32_t error_route_goto;
uint32_t response_route_goto;
uint32_t final_route_goto;
int ignore_body;
@@ -1648,6 +1680,10 @@ struct uwsgi_server {
// leave master running as root
int master_as_root;
// postpone privileges drop
int drop_after_init;
int drop_after_apps;
// kill the stack on SIGTERM (instead of brutal reloading)
int die_on_term;
@@ -1690,6 +1726,10 @@ struct uwsgi_server {
// enable idle mode
int idle;
// cheaper mode memory usage limits
uint64_t cheaper_rss_limit_soft;
uint64_t cheaper_rss_limit_hard;
// destroy the stack when idle
int die_on_idle;
@@ -1743,6 +1783,7 @@ struct uwsgi_server {
struct uwsgi_string_list *additional_headers;
struct uwsgi_string_list *remove_headers;
struct uwsgi_string_list *collect_headers;
// set cpu affinity
int cpu_affinity;
@@ -1814,8 +1855,22 @@ struct uwsgi_server {
#ifdef __linux__
int unshare;
int emperor_clone;
char *pivot_root;
#endif
#ifdef __FreeBSD__
char *jail;
struct uwsgi_string_list *jail_ip4;
#ifdef AF_INET6
struct uwsgi_string_list *jail_ip6;
#endif
struct uwsgi_string_list *jail2;
char *jidfile;
char *jail_attach;
#endif
int refork;
int refork_as_root;
int refork_post_jail;
int ignore_sigpipe;
int ignore_write_errors;
@@ -1878,6 +1933,8 @@ struct uwsgi_server {
int log_master;
char *log_master_buf;
size_t log_master_bufsize;
int log_master_stream;
int log_master_req_stream;
int log_reopen;
int log_truncate;
@@ -1893,6 +1950,21 @@ struct uwsgi_server {
struct uwsgi_string_list *mime_file;
struct uwsgi_hook *hooks;
struct uwsgi_string_list *hook_pre_jail;
struct uwsgi_string_list *hook_post_jail;
struct uwsgi_string_list *hook_in_jail;
struct uwsgi_string_list *hook_as_root;
struct uwsgi_string_list *hook_as_user;
struct uwsgi_string_list *hook_as_user_atexit;
struct uwsgi_string_list *hook_pre_app;
struct uwsgi_string_list *hook_post_app;
struct uwsgi_string_list *hook_as_vassal;
struct uwsgi_string_list *hook_as_emperor;
struct uwsgi_string_list *exec_pre_jail;
struct uwsgi_string_list *exec_post_jail;
struct uwsgi_string_list *exec_in_jail;
@@ -1923,6 +1995,22 @@ struct uwsgi_server {
struct uwsgi_string_list *call_as_emperor2;
struct uwsgi_string_list *call_as_emperor4;
struct uwsgi_string_list *mount_pre_jail;
struct uwsgi_string_list *mount_post_jail;
struct uwsgi_string_list *mount_in_jail;
struct uwsgi_string_list *mount_as_root;
struct uwsgi_string_list *mount_as_vassal;
struct uwsgi_string_list *mount_as_emperor;
struct uwsgi_string_list *umount_pre_jail;
struct uwsgi_string_list *umount_post_jail;
struct uwsgi_string_list *umount_in_jail;
struct uwsgi_string_list *umount_as_root;
struct uwsgi_string_list *umount_as_vassal;
struct uwsgi_string_list *umount_as_emperor;
struct uwsgi_string_list *wait_for_interface;
int wait_for_interface_timeout;
@@ -1937,6 +2025,10 @@ struct uwsgi_server {
struct uwsgi_string_list *requested_logger;
struct uwsgi_string_list *requested_req_logger;
struct uwsgi_log_encoder *log_encoders;
struct uwsgi_string_list *requested_log_encoders;
struct uwsgi_string_list *requested_log_req_encoders;
#ifdef UWSGI_PCRE
int pcre_jit;
struct uwsgi_regexp_list *log_drain_rules;
@@ -2028,6 +2120,7 @@ struct uwsgi_server {
struct uwsgi_thread **offload_thread;
int check_static_docroot;
int disable_sendfile;
char *daemonize;
char *daemonize2;
@@ -2216,6 +2309,7 @@ struct uwsgi_server {
struct uwsgi_route *routes;
struct uwsgi_route *final_routes;
struct uwsgi_route *error_routes;
struct uwsgi_route *response_routes;
struct uwsgi_route_condition *route_conditions;
struct uwsgi_route_var *route_vars;
#endif
@@ -2232,6 +2326,7 @@ struct uwsgi_server {
char *force_cwd;
char *chdir;
char *chdir2;
struct uwsgi_string_list *binsh;
int vacuum;
int no_server;
@@ -2358,6 +2453,7 @@ struct uwsgi_server {
int locks;
int persistent_ipcsem;
struct uwsgi_lock_item *queue_lock;
struct uwsgi_lock_item **user_lock;
@@ -3462,6 +3558,7 @@ void uwsgi_opt_add_route(char *, char *, void *);
int uwsgi_apply_routes(struct wsgi_request *);
void uwsgi_apply_final_routes(struct wsgi_request *);
int uwsgi_apply_error_routes(struct wsgi_request *);
int uwsgi_apply_response_routes(struct wsgi_request *);
int uwsgi_apply_routes_do(struct uwsgi_route *, struct wsgi_request *, char *, uint16_t);
void uwsgi_register_embedded_routers(void);
void uwsgi_routing_dump();
@@ -3508,6 +3605,7 @@ void uwsgi_setup_post_buffering(void);
struct uwsgi_lock_item *uwsgi_lock_ipcsem_init(char *);
void uwsgi_write_pidfile(char *);
int uwsgi_write_intfile(char *, int);
void uwsgi_protected_close(int);
ssize_t uwsgi_protected_read(int, void *, size_t);
@@ -3752,8 +3850,10 @@ int uwsgi_buffer_u16le(struct uwsgi_buffer *, uint16_t);
int uwsgi_buffer_u16be(struct uwsgi_buffer *, uint16_t);
int uwsgi_buffer_u32be(struct uwsgi_buffer *, uint32_t);
int uwsgi_buffer_u32le(struct uwsgi_buffer *, uint32_t);
int uwsgi_buffer_f32be(struct uwsgi_buffer *, float);
int uwsgi_buffer_u24be(struct uwsgi_buffer *, uint32_t);
int uwsgi_buffer_u64be(struct uwsgi_buffer *, uint64_t);
int uwsgi_buffer_f64be(struct uwsgi_buffer *, double);
int uwsgi_buffer_num64(struct uwsgi_buffer *, int64_t);
int uwsgi_buffer_append_keyval(struct uwsgi_buffer *, char *, uint16_t, char *, uint16_t);
int uwsgi_buffer_append_keyval32(struct uwsgi_buffer *, char *, uint32_t, char *, uint32_t);
@@ -4162,7 +4262,6 @@ void uwsgi_envdir(char *);
void uwsgi_envdirs(struct uwsgi_string_list *);
void uwsgi_opt_envdir(char *, char *, void *);
void uwsgi_add_reload_fds();
void uwsgi_add_reload_fds();
void uwsgi_check_emperor(void);
@@ -4183,6 +4282,26 @@ void uwsgi_cache_rlock(struct uwsgi_cache *);
void uwsgi_cache_rwunlock(struct uwsgi_cache *);
char *uwsgi_cache_item_key(struct uwsgi_cache_item *);
char *uwsgi_binsh(void);
int uwsgi_file_executable(char *);
int uwsgi_mount(char *, char *, char *, char *);
int uwsgi_umount(char *, char *);
int uwsgi_mount_hook(char *);
int uwsgi_umount_hook(char *);
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 *);
void uwsgi_register_base_hooks(void);
void uwsgi_setup_log_encoders(void);
void uwsgi_log_encoders_register_embedded(void);
void uwsgi_register_log_encoder(char *, char *(*)(struct uwsgi_log_encoder *, char *, size_t, size_t *));
int uwsgi_accept(int);
#ifdef __cplusplus
}
#endif
+7 -3
View File
@@ -1,6 +1,6 @@
# uWSGI build system
uwsgi_version = '1.9.15'
uwsgi_version = '1.9.16'
import os
import re
@@ -509,9 +509,9 @@ class uConf(object):
self.gcc_list = ['core/utils', 'core/protocol', 'core/socket', 'core/logging', 'core/master', 'core/master_utils', 'core/emperor',
'core/notify', 'core/mule', 'core/subscription', 'core/stats', 'core/sendfile', 'core/async', 'core/master_checks',
'core/offload', 'core/io', 'core/static', 'core/websockets', 'core/spooler', 'core/snmp', 'core/exceptions', 'core/config',
'core/setup_utils', 'core/clock', 'core/init', 'core/buffer', 'core/reader', 'core/writer', 'core/alarm', 'core/cron',
'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/queue', 'core/event', 'core/signal', 'core/strings', 'core/progress', 'core/timebomb', 'core/ini', 'core/fsmon', 'core/mount',
'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')
@@ -692,6 +692,7 @@ class uConf(object):
if uwsgi_os == 'SunOS':
self.libs.append('-lsendfile')
self.libs.append('-lrt')
self.gcc_list.append('lib/sun_fixes')
self.ldflags.append('-L/lib')
if not uwsgi_os_v.startswith('Nexenta'):
@@ -951,6 +952,9 @@ class uConf(object):
uwsgi_version += self.get('append_version')
if uwsgi_os == 'FreeBSD' and self.has_include('jail.h'):
self.cflags.append('-DUWSGI_HAS_FREEBSD_LIBJAIL')
self.libs.append('-ljail')
if uwsgi_os == 'Linux':
if self.get('embed_config'):
+2 -2
View File
@@ -378,9 +378,9 @@ class harakiri(object):
def __init__(self, seconds):
self.s = seconds
def real_call(self, *args):
def real_call(self, *args, **kwargs):
uwsgi.set_user_harakiri(self.s)
r = self.f(*args)
r = self.f(*args, **kwargs)
uwsgi.set_user_harakiri(0)
return r