Compare commits

...
168 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
Unbit f387d27582 prepare for 1.9.15 2013-08-29 10:49:21 +02:00
Unbit 5d8e5d943f improved smartos support 2013-08-29 10:30:01 +00:00
Unbit 4046f76cb2 completed emperor hooks 2013-08-28 15:00:22 +02:00
Unbit 8baeb0af2f prepare for more emperor hooks 2013-08-28 13:25:52 +02:00
Unbit 63e0105a0f added interface waiting infrastructure 2013-08-28 12:43:26 +02:00
Unbit 70daa57caf Merge branch 'master' of github.com:unbit/uwsgi 2013-08-28 11:49:07 +02:00
Unbit db0f7951a9 added --exec-as-vassal and fixed 'fs' unshare 2013-08-28 11:48:51 +02:00
unbit 45a7a3066d Merge pull request #368 from Kapishin/master
Fix two typos in comments
2013-08-27 23:07:20 -07:00
Pavlo Kapyshin c73a6723d7 Fix two typos in comments 2013-08-28 08:57:58 +03:00
Unbit fb55f57531 added --emperor-use-clone 2013-08-27 21:47:00 +02:00
unbit 8cf4d5802a fixed FreeBSD support for pty plugin 2013-08-26 17:42:25 +02:00
Unbit e3c042e567 pty requires -lutil on linux 2013-08-26 15:44:31 +02:00
Unbit 5435f8927c added vassal's hooks 2013-08-26 10:13:08 +02:00
Unbit e1e65c46ac added --refork option 2013-08-26 10:05:41 +02:00
Unbit e1f3665a8e do not set sys,argv in pypy if already available 2013-08-26 05:38:19 +02:00
Unbit ef09a010cf allows pypy plugin to detect already available pypy environment 2013-08-26 05:01:28 +02:00
Unbit 3f5d79c755 added UWSGI_AS_LIB 2013-08-25 19:42:59 +02:00
unbit 3b5468f39f added FreeBSD support to pty plugin 2013-08-25 18:43:44 +02:00
Roberto De Ioris 5598c7cc22 added pty support to OpenBSD 2013-08-25 20:41:28 +02:00
Unbit d6fdb812a2 improved postfork() decorator 2013-08-25 18:35:56 +02:00
Unbit e6d5f6c612 fixed #366 2013-08-23 20:49:39 +02:00
Unbit 8f10daa2bf fixed pty binding 2013-08-23 19:16:38 +02:00
Unbit f027153452 exit on failed --pty-connect 2013-08-23 18:48:07 +02:00
Unbit 0ebda93a50 fixed #365 2013-08-23 18:41:10 +02:00
Unbit dc4e8950d2 sanitize pty options 2013-08-23 17:50:31 +02:00
Unbit 0f5336028f added OSX support for the pty plugin 2013-08-23 16:28:12 +02:00
Unbit e02341bffe include pty.h only on linux 2013-08-23 16:21:40 +02:00
Unbit ac92ff4079 added the pty plugin 2013-08-23 16:19:33 +02:00
Unbit a5da77bc54 added --add-gid 2013-08-23 14:46:06 +02:00
Unbit 0441e88b82 track unix sockets inode to reduce accidental removal on vacuum 2013-08-23 14:28:01 +02:00
Unbit 815f4abec0 fixed #364 2013-08-23 13:59:13 +02:00
Unbit 4f9e2ff3f6 added --perl-exec and --perl-exec-post-fork 2013-08-23 11:50:18 +02:00
Unbit ce8dd001bf ported uwsgi.cache_keys to pypy 2013-08-23 11:06:24 +02:00
Unbit d4e90f5215 added uwsgi.cache_keys function api 2013-08-23 10:43:13 +02:00
unbit da13562890 Merge pull request #362 from KLab/log-ftime
Add `%(ftime)` to logformat.
2013-08-20 00:58:20 -07:00
INADA Naoki d320075ab0 Add %(ftime) to logformat. 2013-08-20 16:45:59 +09:00
Unbit 4061826da4 try to fix python3 static files handling 2013-08-20 07:32:41 +02:00
Unbit 2854321891 improved python3 exceptions management 2013-08-16 07:09:50 +02:00
Unbit c4181cdc55 fixed type in pypy wsgi.input.read 2013-08-14 11:59:42 +02:00
Unbit 327582b695 added --worker-exec2 2013-08-14 10:16:39 +02:00
Unbit f56b9be4c5 allow post_fork hook on general plugins 2013-08-13 19:19:22 +02:00
Unbit 28ccace24f implemented --call hooks 2013-08-12 12:42:32 +02:00
Unbit 13f82176e3 added init_func support for plugins, and --need-plugin variant 2013-08-11 10:22:36 +02:00
Unbit be4d324f6b better symbol detection for pypy 2013-08-11 08:41:02 +02:00
Unbit 36486caabb sizeof on string includes NULL ... 2013-08-11 08:27:20 +02:00
Unbit b3af255727 Merge branch 'master' of github.com:unbit/uwsgi 2013-08-11 07:09:04 +02:00
Unbit a56f726f7d fixed a typo 2013-08-11 07:06:30 +02:00
unbit 24d6470f38 Merge pull request #359 from ryanpetrello/master
Add plugin support for the pecan WSGI framework (http://pecanpy.org).
2013-08-09 23:47:37 -07:00
Ryan Petrello 7e079e4c40 Add my name to the contributors list. 2013-08-10 01:00:12 -04:00
Ryan Petrello 0d9bc03c53 Add plugin support for the pecan WSGI framework (http://pecanpy.org). 2013-08-10 00:44:40 -04:00
Unbit 7598666768 added UWSGI_REMOVE_INCLUDES 2013-08-08 18:27:54 +02:00
Unbit cd6f027705 avoid unix nameclash on cygwin 2013-08-08 11:23:09 +02:00
Roberto De Ioris 0803a7f0b0 added router_expires 2013-08-07 08:14:38 +02:00
Roberto De Ioris 0eb956db4a example mv again 2013-08-06 07:39:20 +02:00
Roberto De Ioris 76c6ae6d16 mv again 2013-08-06 07:38:11 +02:00
Roberto De Ioris 40054e3494 another series of mv 2013-08-06 07:36:16 +02:00
Roberto De Ioris 8927dfd538 moved example files 2013-08-06 07:33:40 +02:00
Roberto De Ioris 68f734fcad announce legion's death on reload 2013-08-06 07:15:35 +02:00
Roberto De Ioris af4c7f74d5 fixed legion death 2013-08-06 07:08:42 +02:00
Roberto De Ioris 4581d1e7ce announce legion death on uwsgi exit 2013-08-06 06:58:04 +02:00
Unbit d465f61506 fix volfile report 2013-07-31 10:14:22 +02:00
Unbit 5cae9b9ba4 fixed glusterfs volfile support 2013-07-31 10:05:49 +02:00
unbit 428a2d9366 Merge pull request #350 from prymitive/matheval_fix
fix matheval check in build profiles
2013-07-30 19:52:39 -07:00
unbit 1c00b54b06 Merge pull request #351 from prymitive/dot_h
handle core/dot_h.c as other build objects
2013-07-30 08:57:39 -07:00
Unbit 6228fb91da preliminary async support for glusterfs 2013-07-30 16:42:56 +02:00
Łukasz Mierzwa 307cf3a0ef add autogenerated core/dot_h.c to .gitignore, so it won't be added by mistake to git, also remove it during make clean 2013-07-30 10:54:33 +02:00
Łukasz Mierzwa f723a804c0 fix matheval check in build profiles, currently matheval is always required while it should be only used if present or if requested by user 2013-07-30 10:27:02 +02:00
Unbit 24ac19e2d6 added last-modified to glusterfs 2013-07-29 17:40:06 +02:00
Unbit 38147d50ff check for matheval 2013-07-29 16:55:28 +02:00
Unbit 9f7db10582 first working glusterfs plugin prototype 2013-07-29 16:50:00 +02:00
Unbit ed35a50e6c rewrite ruby libdir on heroku 2013-07-29 08:49:25 +02:00
Unbit fae08f49cf another heroku workaround 2013-07-29 08:45:33 +02:00
Unbit 35f5b5b2eb improved ruby libdir detection for static builds 2013-07-29 08:25:06 +02:00
Unbit b785c8fccf added a check for ruby --enable-load-relative 2013-07-28 08:50:44 +02:00
Unbit 597c3cd7f1 try removing ruby_sysinit 2013-07-28 06:23:39 +02:00
Unbit bbbe01ef4b change ruby_process_options with ruby_options [5] 2013-07-27 23:49:49 +02:00
Unbit ea1e1cb65f change ruby_process_options with ruby_options [4] 2013-07-27 23:42:05 +02:00
Unbit a1d31ae954 change ruby_process_options with ruby_options [3] 2013-07-27 23:19:15 +02:00
Unbit fa0ed9489a change ruby_process_options with ruby_options [2] 2013-07-27 23:13:37 +02:00
Unbit 7bb7b351e0 change ruby_process_options with ruby_options 2013-07-27 23:01:09 +02:00
Unbit cb45f207a6 another attempt to make heroku happy [6] 2013-07-27 22:46:31 +02:00
Unbit 82ffb60bdd another attempt to make heroku happy [5] 2013-07-27 22:42:16 +02:00
Unbit ec38ce9a26 another attempt to make heroku happy [4] 2013-07-27 22:37:43 +02:00
Unbit 8279926bab another attempt to make heroku happy [3] 2013-07-27 22:18:18 +02:00
Unbit ac17b0910e another attempt to make heroku happy [2] 2013-07-27 22:09:29 +02:00
Unbit aae3e7ff17 another attempt to make heroku happy 2013-07-27 22:04:02 +02:00
Unbit 4cfff98cd1 try to workaround heroku 2013-07-27 22:01:21 +02:00
Unbit 19ee50949c skeleton for glusterfs plugin 2013-07-27 21:48:00 +02:00
Unbit ec27d624c3 fixed http-keepalive memleak 2013-07-26 12:17:23 +02:00
Unbit 0dc8803ff8 added --force-gateway 2013-07-26 12:03:38 +02:00
Unbit e8ea1a55f9 fixed #112 2013-07-25 21:56:29 +02:00
Unbit a0cb71ca78 added --strict mode 2013-07-25 21:24:04 +02:00
Unbit 5c5aef3827 1.9.15 development starts 2013-07-23 11:00:18 +02:00
Unbit 737a7f4d51 attempt to fix spooler's body in python 2013-07-23 08:40:11 +02:00
Unbit c3ee774d56 Merge branch 'master' of github.com:unbit/uwsgi 2013-07-23 06:28:29 +02:00
Unbit 2d5adacc65 preliminary python profiler for python3 2013-07-23 06:28:10 +02:00
unbit b7a8cc0297 Merge pull request #345 from pingswept/patch-1
Convert tabs to spaces to fix indentation error
2013-07-22 12:36:44 -07:00
Brandon Stafford 317b0f79a8 Convert tabs to spaces to fix indentation error
The uwsgi.websocket_handshake call on line 52 was not indented properly, causing the Python interpreter to choke. Converting the few tabs sprinkled through the document to spaces fixes that error.
2013-07-22 15:22:44 -04:00
91 changed files with 5363 additions and 471 deletions
+2
View File
@@ -9,3 +9,5 @@
/uwsgibuild.*
/t/ring/target
core/dot_h.c
+1
View File
@@ -24,3 +24,4 @@ Stephen Pierce
Mingli Yuan
Natanael Copa
Roberto Leandrini
Ryan Petrello
+2 -1
View File
@@ -6,6 +6,7 @@ zeromq = auto
ssl = auto
pcre = auto
routing = auto
matheval = auto
debug = false
unbit = false
xml_implementation = libxml2
@@ -16,7 +17,7 @@ plugins =
bin_name = uwsgi
append_version =
plugin_dir = .
embedded_plugins = %(main_plugin)s, ping, cache, nagios, rrdtool, carbon, rpc, corerouter, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool, redislog, mongodblog, router_rewrite, router_http, logfile, router_cache, rawrouter, router_static, sslrouter, spooler, cheaper_busyness, symcall, transformation_tofile, transformation_gzip, transformation_chunked, transformation_offload, router_memcached, router_redis, router_hash
embedded_plugins = %(main_plugin)s, ping, cache, nagios, rrdtool, carbon, rpc, corerouter, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool, redislog, mongodblog, router_rewrite, router_http, logfile, router_cache, rawrouter, router_static, sslrouter, spooler, cheaper_busyness, symcall, transformation_tofile, transformation_gzip, transformation_chunked, transformation_offload, router_memcached, router_redis, router_hash, router_expires
as_shared_library = false
locking = auto
+4
View File
@@ -0,0 +1,4 @@
[uwsgi]
main_plugin = glusterfs
inherit = base
matheval = false
+3
View File
@@ -0,0 +1,3 @@
[uwsgi]
main_plugin = rados
inherit = base
+1 -1
View File
@@ -368,7 +368,7 @@ void async_loop() {
uwsgi.schedule_to_req = async_schedule_to_req;
if (!uwsgi.schedule_to_main) {
uwsgi_log("*** WARNING *** async mode without coroutine/greenthread engine loaded !!!\n");
uwsgi_log("*** DANGER *** async mode without coroutine/greenthread engine loaded !!!\n");
}
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
+29 -1
View File
@@ -3,6 +3,9 @@
extern struct uwsgi_server uwsgi;
struct uwsgi_buffer *uwsgi_buffer_new(size_t len) {
#ifdef UWSGI_DEBUG_BUFFER
uwsgi_log("[uwsgi-buffer] allocating a new buffer of %llu\n", (unsigned long long) len);
#endif
struct uwsgi_buffer *ub = uwsgi_calloc(sizeof(struct uwsgi_buffer));
if (len) {
@@ -169,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);
@@ -192,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)) {
@@ -271,8 +298,9 @@ int uwsgi_buffer_append_base64(struct uwsgi_buffer *ub, char *s, size_t len) {
void uwsgi_buffer_destroy(struct uwsgi_buffer *ub) {
#ifdef UWSGI_DEBUG_BUFFER
uwsgi_log("[uwsgi-buffer] destroying buffer of %llu bytes\n", (unsigned long long) ub->len);
if (ub->freed) {
uwsgi_log("[BUG] buffer at %p already destroyed !!!\n", ub);
uwsgi_log("[uwsgi-buffer][BUG] buffer at %p already destroyed !!!\n", ub);
}
ub->freed = 1;
#endif
+34
View File
@@ -204,6 +204,7 @@ static void uwsgi_cache_add_items(struct uwsgi_cache *uc) {
next:
usl = usl->next;
}
}
static void uwsgi_cache_load_files(struct uwsgi_cache *uc) {
@@ -1920,3 +1921,36 @@ void uwsgi_cache_setup_nodes(struct uwsgi_cache *uc) {
}
}
struct uwsgi_cache_item *uwsgi_cache_keys(struct uwsgi_cache *uc, uint64_t *pos, struct uwsgi_cache_item **uci) {
// security check
if (*pos >= uc->hashsize) return NULL;
// iterate hashtable
uint64_t orig_pos = *pos;
for(;*pos<uc->hashsize;(*pos)++) {
// get the cache slot
uint64_t slot = uc->hashtable[*pos];
if (*pos == orig_pos && *uci) {
slot = (*uci)->next;
}
if (slot == 0) continue;
*uci = cache_item(slot);
return *uci;
}
(*pos)++;
return NULL;
}
void uwsgi_cache_rlock(struct uwsgi_cache *uc) {
uwsgi_rlock(uc->lock);
}
void uwsgi_cache_rwunlock(struct uwsgi_cache *uc) {
uwsgi_rwunlock(uc->lock);
}
char *uwsgi_cache_item_key(struct uwsgi_cache_item *uci) {
return uci->key;
}
+17
View File
@@ -458,6 +458,23 @@ add:
uwsgi.exported_opts[id]->configured = 1;
}
}
else if (uwsgi.strict) {
uwsgi_log("[strict-mode] unknown config directive: %s\n", key);
exit(1);
}
}
void uwsgi_fallback_config() {
if (uwsgi.fallback_config && uwsgi.last_exit_code == 1) {
uwsgi_log_verbose("!!! %s (pid: %d) exited with status %d !!!\n", uwsgi.binary_path, (int) getpid(), uwsgi.last_exit_code);
uwsgi_log_verbose("!!! Fallback config to %s !!!\n", uwsgi.fallback_config);
char *argv[3];
argv[0] = uwsgi.binary_path;
argv[1] = uwsgi.fallback_config;
argv[2] = NULL;
execvp(uwsgi.binary_path, argv);
uwsgi_error("execvp()");
// never here
}
}
+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;
+153 -16
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)
@@ -790,15 +790,10 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
}
}
static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *);
int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
int i;
char *colon = NULL;
int counter;
char **uenvs;
char *uef;
char **vassal_argv;
pid_t pid;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe)) {
@@ -822,9 +817,19 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
// TODO pre-start hook
// a new uWSGI instance will start
#if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL)
if (uwsgi.emperor_clone) {
char stack[PTHREAD_STACK_MIN];
pid = clone((int (*)(void *))uwsgi_emperor_spawn_vassal, stack + PTHREAD_STACK_MIN, SIGCHLD | uwsgi.emperor_clone, (void *) n_ui);
}
else {
#endif
pid = fork();
#if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL)
}
#endif
if (pid < 0) {
uwsgi_error("fork()")
uwsgi_error("uwsgi_emperor_spawn_vassal()/fork()")
}
else if (pid > 0) {
n_ui->pid = pid;
@@ -854,9 +859,86 @@ 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", (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]);
}
// 4 call hooks
// config / config + pid / config + pid + uid + gid
// call
uwsgi_foreach(usl, uwsgi.call_as_emperor) {
void (*func)(void) = dlsym(RTLD_DEFAULT, usl->value);
if (!func) {
uwsgi_log("unable to call function \"%s\"\n", usl->value);
}
else {
func();
}
}
uwsgi_foreach(usl, uwsgi.call_as_emperor1) {
void (*func)(char *) = dlsym(RTLD_DEFAULT, usl->value);
if (!func) {
uwsgi_log("unable to call function \"%s\"\n", usl->value);
}
else {
func(n_ui->name);
}
}
uwsgi_foreach(usl, uwsgi.call_as_emperor2) {
void (*func)(char *, pid_t) = dlsym(RTLD_DEFAULT, usl->value);
if (!func) {
uwsgi_log("unable to call function \"%s\"\n", usl->value);
}
else {
func(n_ui->name, n_ui->pid);
}
}
uwsgi_foreach(usl, uwsgi.call_as_emperor4) {
void (*func)(char *, pid_t, uid_t, gid_t) = dlsym(RTLD_DEFAULT, usl->value);
if (!func) {
uwsgi_log("unable to call function \"%s\"\n", usl->value);
}
else {
func(n_ui->name, n_ui->pid, n_ui->uid, n_ui->gid);
}
}
return 0;
}
else {
uwsgi_emperor_spawn_vassal(n_ui);
}
return -1;
}
static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) {
if (uwsgi.emperor_tyrant) {
uwsgi_log("[emperor-tyrant] dropping privileges to %d %d for instance %s\n", (int) n_ui->uid, (int) n_ui->gid, n_ui->name);
@@ -879,7 +961,7 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
unsetenv("UWSGI_RELOADS");
unsetenv("NOTIFY_SOCKET");
uef = uwsgi_num2str(n_ui->pipe[1]);
char *uef = uwsgi_num2str(n_ui->pipe[1]);
if (setenv("UWSGI_EMPEROR_FD", uef, 1)) {
uwsgi_error("setenv()");
exit(1);
@@ -905,7 +987,7 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
free(uef);
}
uenvs = environ;
char **uenvs = environ;
while (*uenvs) {
if (!strncmp(*uenvs, "UWSGI_VASSAL_", 13) && strchr(*uenvs, '=')) {
char *oe = uwsgi_concat2n(*uenvs, strchr(*uenvs, '=') - *uenvs, "", 0), *ne;
@@ -942,17 +1024,19 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
close(n_ui->pipe_config[0]);
}
counter = 4;
int counter = 4;
struct uwsgi_string_list *uct = uwsgi.vassals_templates;
while (uct) {
counter += 2;
uct = uct->next;
}
vassal_argv = uwsgi_malloc(sizeof(char *) * counter);
char **vassal_argv = uwsgi_malloc(sizeof(char *) * counter);
// set args
vassal_argv[0] = uwsgi.binary_path;
char *colon = NULL;
if (uwsgi.emperor_broodlord) {
colon = strchr(n_ui->name, ':');
if (colon) {
@@ -1037,6 +1121,7 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
}
// close all of the unneded fd
int i;
for (i = 3; i < (int) uwsgi.max_fd; i++) {
if (uwsgi_fd_is_safe(i)) continue;
if (n_ui->use_config) {
@@ -1048,6 +1133,7 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
}
}
// run start hook (can fail)
if (uwsgi.vassals_start_hook) {
uwsgi_log("[emperor] running vassal start-hook: %s %s\n", uwsgi.vassals_start_hook, n_ui->name);
if (uwsgi.emperor_absolute_dir) {
@@ -1059,6 +1145,60 @@ int uwsgi_emperor_vassal_start(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);
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);
}
}
// run low-level hooks
uwsgi_foreach(usl, uwsgi.call_as_vassal) {
void (*func)(void) = dlsym(RTLD_DEFAULT, usl->value);
if (!func) {
uwsgi_log("unable to call function \"%s\"\n", usl->value);
exit(1);
}
func();
}
uwsgi_foreach(usl, uwsgi.call_as_vassal1) {
void (*func)(char *) = dlsym(RTLD_DEFAULT, usl->value);
if (!func) {
uwsgi_log("unable to call function \"%s\"\n", usl->value);
exit(1);
}
func(n_ui->name);
}
uwsgi_foreach(usl, uwsgi.call_as_vassal3) {
void (*func)(char *, uid_t, gid_t) = dlsym(RTLD_DEFAULT, usl->value);
if (!func) {
uwsgi_log("unable to call function \"%s\"\n", usl->value);
exit(1);
}
func(n_ui->name, n_ui->uid, n_ui->gid);
}
// start !!!
if (execvp(vassal_argv[0], vassal_argv)) {
uwsgi_error("execvp()");
@@ -1066,9 +1206,6 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
uwsgi_log("[emperor] is the uwsgi binary in your system PATH ?\n");
// never here
exit(UWSGI_EXILE_CODE);
}
return -1;
}
void uwsgi_imperial_monitor_glob_init(struct uwsgi_emperor_scanner *ues) {
+1 -1
View File
@@ -41,7 +41,7 @@ struct uwsgi_gateway *register_gateway(char *name, void (*loop) (int, void *), v
uwsgi_socket_nb(ug->internal_subscription_pipe[0]);
uwsgi_socket_nb(ug->internal_subscription_pipe[1]);
if (!uwsgi.master_process)
if (!uwsgi.master_process && !uwsgi.force_gateway)
gateway_respawn(ushared->gateways_cnt);
ushared->gateways_cnt++;
+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);
}
}
}
+16
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
@@ -387,6 +388,8 @@ pid_t uwsgi_daemonize2() {
uwsgi_write_pidfile(uwsgi.pidfile2);
}
if (uwsgi.log_master) uwsgi_setup_log_master();
return uwsgi.mypid;
}
@@ -449,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) {
+25 -2
View File
@@ -79,6 +79,9 @@ void uwsgi_parse_legion(char *key, uint16_t keylen, char *value, uint16_t vallen
ul->scroll = value;
ul->scroll_len = vallen;
}
else if (!uwsgi_strncmp(key, keylen, "dead", 4)) {
ul->dead = 1;
}
}
// this function is called when a node is added or removed (heavy locking is needed)
@@ -611,6 +614,14 @@ static void *legion_loop(void *foobar) {
usl = usl->next;
}
}
// remove node announcing death
else if (legion_msg.dead) {
uwsgi_log("[uwsgi-legion] %s: %.*s valor: %llu uuid: %.*s announced its death to Legion %s\n", node->valor > 0 ? "node" : "arbiter", node->name_len, node->name, node->valor, 36, node->uuid, ul->legion);
uwsgi_wlock(ul->lock);
uwsgi_legion_remove_node(ul, node);
uwsgi_rwunlock(ul->lock);
continue;
}
node->last_seen = uwsgi_now();
node->lord_valor = legion_msg.lord_valor;
@@ -752,8 +763,11 @@ int uwsgi_legion_announce(struct uwsgi_legion *ul) {
if (uwsgi_buffer_append_keyval(ub, "scroll", 6, ul->scroll, ul->scroll_len))
goto err;
}
#ifdef UWSGI_UUID
#endif
if (ul->dead) {
if (uwsgi_buffer_append_keyval(ub, "dead", 4, "1", 1))
goto err;
}
unsigned char *encrypted = uwsgi_malloc(ub->pos + 4 + EVP_MAX_BLOCK_LENGTH);
if (EVP_EncryptInit_ex(ul->encrypt_ctx, NULL, NULL, NULL, NULL) <= 0) {
@@ -1122,6 +1136,14 @@ void uwsgi_legion_action_register(char *name, int (*func) (struct uwsgi_legion *
}
}
void uwsgi_legion_announce_death(void) {
struct uwsgi_legion *legion = uwsgi.legions;
while (legion) {
legion->dead = 1;
uwsgi_legion_announce(legion);
legion = legion->next;
}
}
void uwsgi_legion_atexit(void) {
struct uwsgi_legion *legion = uwsgi.legions;
@@ -1140,6 +1162,7 @@ next:
legion = legion->next;
}
uwsgi_legion_announce_death();
}
int uwsgi_legion_i_am_the_lord(char *name) {
+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;
}
+470 -18
View File
@@ -45,7 +45,7 @@ void uwsgi_log(const char *fmt, ...) {
}
else {
gettimeofday(&tv, NULL);
#ifdef __sun__
#if defined(__sun__) && !defined(__clang__)
ctime_r((const time_t *) &tv.tv_sec, ctime_storage, 26);
#else
ctime_r((const time_t *) &tv.tv_sec, ctime_storage);
@@ -97,7 +97,7 @@ void uwsgi_log_verbose(const char *fmt, ...) {
}
else {
gettimeofday(&tv, NULL);
#ifdef __sun__
#if defined(__sun__) && !defined(__clang__)
ctime_r((const time_t *) &tv.tv_sec, ctime_storage, 26);
#else
ctime_r((const time_t *) &tv.tv_sec, ctime_storage);
@@ -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) {
@@ -616,7 +664,7 @@ void uwsgi_logit_simple(struct wsgi_request *wsgi_req) {
break;
}
#ifdef __sun__
#if defined(__sun__) && !defined(__clang__)
ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, time_request, 26);
#else
ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, time_request);
@@ -1035,7 +1083,7 @@ static ssize_t uwsgi_lf_epoch(struct wsgi_request * wsgi_req, char **buf) {
static ssize_t uwsgi_lf_ctime(struct wsgi_request * wsgi_req, char **buf) {
*buf = uwsgi_malloc(26);
#ifdef __sun__
#if defined(__sun__) && !defined(__clang__)
ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, *buf, 26);
#else
ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, *buf);
@@ -1060,6 +1108,19 @@ static ssize_t uwsgi_lf_ltime(struct wsgi_request * wsgi_req, char **buf) {
return ret;
}
static ssize_t uwsgi_lf_ftime(struct wsgi_request * wsgi_req, char **buf) {
if (!uwsgi.log_strftime) {
return uwsgi_lf_ltime(wsgi_req, buf);
}
*buf = uwsgi_malloc(64);
time_t now = wsgi_req->start_of_request / 1000000;
size_t ret = strftime(*buf, 64, uwsgi.log_strftime, localtime(&now));
if (ret == 0) {
*buf[0] = 0;
return 0;
}
return ret;
}
static ssize_t uwsgi_lf_micros(struct wsgi_request * wsgi_req, char **buf) {
*buf = uwsgi_num2str(wsgi_req->end_of_request - wsgi_req->start_of_request);
@@ -1246,6 +1307,11 @@ void uwsgi_add_logchunk(int variable, int pos, char *ptr, size_t len) {
logchunk->func = uwsgi_lf_ltime;
logchunk->free = 1;
}
else if (!uwsgi_strncmp(ptr, len, "ftime", 5)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_ftime;
logchunk->free = 1;
}
else if (!uwsgi_strncmp(ptr, len, "ctime", 5)) {
logchunk->type = 3;
logchunk->func = uwsgi_lf_ctime;
@@ -1328,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);
@@ -1361,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;
}
}
@@ -1379,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;
}
@@ -1405,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;
}
}
@@ -1423,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;
}
@@ -1493,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
}
+6 -1
View File
@@ -393,7 +393,7 @@ int master_loop(char **argv, char **environ) {
}
if (uwsgi.stats) {
char *tcp_port = strchr(uwsgi.stats, ':');
char *tcp_port = strrchr(uwsgi.stats, ':');
if (tcp_port) {
// disable deferred accept for this socket
int current_defer_accept = uwsgi.no_defer_accept;
@@ -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;
}
+12
View File
@@ -98,6 +98,12 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
colon[0] = ':';
}
char *init_func = strchr(plugin_name, '|');
if (init_func) {
init_func[0] = 0;
init_func++;
}
if (!uwsgi_endswith(plugin_name, "_plugin.so")) {
plugin_name = uwsgi_concat2(plugin_name, "_plugin.so");
need_free = 1;
@@ -157,6 +163,12 @@ success:
uwsgi_log("!!! UNABLE to load uWSGI plugin: %s !!!\n", dlerror());
}
else {
if (init_func) {
void (*plugin_init_func)() = dlsym(plugin_handle, init_func);
if (plugin_init_func) {
plugin_init_func();
}
}
char *plugin_entry_symbol = uwsgi_concat2n(plugin_symbol_name_start, strlen(plugin_symbol_name_start) - 3, "", 0);
up = dlsym(plugin_handle, plugin_entry_symbol);
if (!up) {
+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
}
+26 -1
View File
@@ -1714,6 +1714,10 @@ void uwsgi_bind_sockets() {
uwsgi_chown(uwsgi_sock->name, uwsgi.chown_socket);
}
uwsgi_log("uwsgi socket %d bound to UNIX address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd);
struct stat st;
if (uwsgi_sock->name[0] != '@' && !stat(uwsgi_sock->name, &st)) {
uwsgi_sock->inode = st.st_ino;
}
}
else {
#ifdef AF_INET6
@@ -1781,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) {
@@ -1799,6 +1804,8 @@ void uwsgi_bind_sockets() {
}
stdin_done:
// check for auto_port socket
uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
@@ -1951,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
}
+3
View File
@@ -227,15 +227,18 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core
#endif
if (write(fd, &uh, 4) != 4) {
uwsgi_log("[spooler] unable to write header for %s\n", filename);
goto clear;
}
if (write(fd, buffer, size) != size) {
uwsgi_log("[spooler] unable to write args for %s\n", filename);
goto clear;
}
if (body && body_len > 0) {
if ((size_t) write(fd, body, body_len) != body_len) {
uwsgi_log("[spooler] unable to write body for %s\n", filename);
goto clear;
}
}
+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;
}
+471 -37
View File
@@ -191,6 +191,8 @@ void daemonize(char *logfile) {
// get current working directory
char *uwsgi_get_cwd() {
if (uwsgi.force_cwd) return uwsgi.force_cwd;
// set this to static to avoid useless reallocations in stats mode
static size_t newsize = 256;
@@ -342,6 +344,8 @@ void uwsgi_as_root() {
}
#endif
int in_jail = 0;
#if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL)
if (uwsgi.unshare && !uwsgi.reloads) {
@@ -352,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)
@@ -370,18 +586,110 @@ 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) {
if (!uwsgi.wait_for_interface_timeout) {
uwsgi.wait_for_interface_timeout = 60;
}
uwsgi_log("waiting for interface %s (max %d seconds) ...\n", usl->value, uwsgi.wait_for_interface_timeout);
int counter = 0;
for(;;) {
if (counter > uwsgi.wait_for_interface_timeout) {
uwsgi_log("interface %s unavailable after %d seconds\n", usl->value, counter);
exit(1);
}
unsigned int index = if_nametoindex(usl->value);
if (index > 0) {
uwsgi_log("interface %s found with index %u\n", usl->value, index);
break;
}
else {
sleep(1);
counter++;
}
}
}
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
struct uwsgi_string_list *usl = uwsgi.exec_as_root;
while (usl) {
uwsgi_foreach(usl, uwsgi.exec_as_root) {
uwsgi_log("running \"%s\" (as root)...\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;
}
uwsgi_foreach(usl, uwsgi.call_as_root) {
if (uwsgi_call_symbol(usl->value)) {
uwsgi_log("unaable to call function \"%s\"\n", usl->value);
}
}
if (uwsgi.gidname) {
struct group *ugroup = getgrnam(uwsgi.gidname);
if (ugroup) {
@@ -480,6 +788,31 @@ void uwsgi_as_root() {
exit(1);
}
}
struct uwsgi_string_list *usl;
size_t ags = 0;
uwsgi_foreach(usl, uwsgi.additional_gids) ags++;
if (ags > 0) {
gid_t *ags_list = uwsgi_calloc(sizeof(gid_t) * ags);
size_t g_pos = 0;
uwsgi_foreach(usl, uwsgi.additional_gids) {
ags_list[g_pos] = atoi(usl->value);
if (!ags_list[g_pos]) {
struct group *g = getgrnam(usl->value);
if (g) {
ags_list[g_pos] = g->gr_gid;
}
else {
uwsgi_log("unable to find group %s\n", usl->value);
exit(1);
}
}
g_pos++;
}
if (setgroups(ags, ags_list)) {
uwsgi_error("setgroups()");
exit(1);
}
}
int additional_groups = getgroups(0, NULL);
if (additional_groups > 0) {
gid_t *gids = uwsgi_calloc(sizeof(gid_t) * additional_groups);
@@ -536,18 +869,45 @@ void uwsgi_as_root() {
}
#endif
if (uwsgi.refork) {
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);
}
}
uwsgi_hooks_run(uwsgi.hook_as_user, "as user", 1);
// now run the scripts needed by the user
usl = uwsgi.exec_as_user;
while (usl) {
uwsgi_foreach(usl, uwsgi.exec_as_user) {
uwsgi_log("running \"%s\" (as uid: %d gid: %d) ...\n", usl->value, (int) getuid(), (int) getgid());
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;
}
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);
}
}
// we could now patch the binary
if (uwsgi.unprivileged_binary_patch) {
uwsgi.argv[0] = uwsgi.unprivileged_binary_patch;
@@ -1361,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;
@@ -1921,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;
@@ -1932,23 +2307,9 @@ void uwsgi_exec_command_with_args(char *cmdline) {
exit(1);
}
int uwsgi_run_command_and_wait(char *command, char *arg) {
static int uwsgi_run_command_do(char *command, char *arg) {
char *argv[4];
int waitpid_status = 0;
pid_t pid = fork();
if (pid < 0) {
return -1;
}
if (pid > 0) {
if (waitpid(pid, &waitpid_status, 0) < 0) {
uwsgi_error("waitpid()");
return -1;
}
return WEXITSTATUS(waitpid_status);
}
#ifdef __linux__
if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) {
@@ -1957,7 +2318,7 @@ int uwsgi_run_command_and_wait(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;
@@ -1976,6 +2337,54 @@ int uwsgi_run_command_and_wait(char *command, char *arg) {
exit(1);
}
int uwsgi_run_command_and_wait(char *command, char *arg) {
int waitpid_status = 0;
pid_t pid = fork();
if (pid < 0) {
return -1;
}
if (pid > 0) {
if (waitpid(pid, &waitpid_status, 0) < 0) {
uwsgi_error("uwsgi_run_command_and_wait()/waitpid()");
return -1;
}
return WEXITSTATUS(waitpid_status);
}
return uwsgi_run_command_do(command, arg);
}
int uwsgi_run_command_putenv_and_wait(char *command, char *arg, char **envs, unsigned int nenvs) {
int waitpid_status = 0;
pid_t pid = fork();
if (pid < 0) {
return -1;
}
if (pid > 0) {
if (waitpid(pid, &waitpid_status, 0) < 0) {
uwsgi_error("uwsgi_run_command_and_wait()/waitpid()");
return -1;
}
return WEXITSTATUS(waitpid_status);
}
unsigned int i;
for(i=0;i<nenvs;i++) {
if (putenv(envs[i])) {
uwsgi_error("uwsgi_run_command_putenv_and_wait()/putenv()");
exit(1);
}
}
return uwsgi_run_command_do(command, arg);
}
pid_t uwsgi_run_command(char *command, int *stdin_fd, int stdout_fd) {
char *argv[4];
@@ -2062,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
@@ -2319,9 +2728,6 @@ static struct uwsgi_unshare_id uwsgi_unshare_list[] = {
#ifdef CLONE_FILES
{"files", CLONE_FILES},
#endif
#ifdef CLONE_FS
{"fs", CLONE_FS},
#endif
#ifdef CLONE_NEWIPC
{"ipc", CLONE_NEWIPC},
#endif
@@ -2333,6 +2739,7 @@ static struct uwsgi_unshare_id uwsgi_unshare_list[] = {
#endif
#ifdef CLONE_NEWNS
{"ns", CLONE_NEWNS},
{"fs", CLONE_NEWNS},
{"mount", CLONE_NEWNS},
#endif
#ifdef CLONE_SYSVSEM
@@ -2356,7 +2763,7 @@ static int uwsgi_get_unshare_id(char *name) {
return -1;
}
void uwsgi_build_unshare(char *what) {
void uwsgi_build_unshare(char *what, int *mask) {
char *list = uwsgi_str(what);
@@ -2364,7 +2771,7 @@ void uwsgi_build_unshare(char *what) {
while (p != NULL) {
int u_id = uwsgi_get_unshare_id(p);
if (u_id != -1) {
uwsgi.unshare |= u_id;
*mask |= u_id;
}
p = strtok(NULL, ",");
}
@@ -2875,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;
@@ -2931,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");
}
}
@@ -3304,6 +3725,13 @@ error:
return -1;
}
int uwsgi_call_symbol(char *symbol) {
void (*func)(void) = dlsym(RTLD_DEFAULT, symbol);
if (!func) return -1;
func();
return 0;
}
int uwsgi_plugin_modifier1(char *plugin) {
int ret = -1;
char *symbol_name = uwsgi_concat2(plugin, "_plugin");
@@ -3736,3 +4164,9 @@ void uwsgi_envdirs(struct uwsgi_string_list *envdirs) {
void uwsgi_opt_envdir(char *opt, char *value, void *foobar) {
uwsgi_envdir(value);
}
void uwsgi_exit(int status) {
uwsgi.last_exit_code = status;
// disable macro expansion
(exit)(status);
}
+330 -28
View File
@@ -59,7 +59,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"undeferred-shared-socket", required_argument, 0, "create a shared sacket for advanced jailing or ipc (undeferred mode)", uwsgi_opt_add_shared_socket, NULL, 0},
{"processes", required_argument, 'p', "spawn the specified number of workers/processes", uwsgi_opt_set_int, &uwsgi.numproc, 0},
{"workers", required_argument, 'p', "spawn the specified number of workers/processes", uwsgi_opt_set_int, &uwsgi.numproc, 0},
{"thunder-lock", no_argument, 0, "serialize accept() usage (if possibie)", uwsgi_opt_true, &uwsgi.use_thunder_lock, 0},
{"thunder-lock", no_argument, 0, "serialize accept() usage (if possible)", uwsgi_opt_true, &uwsgi.use_thunder_lock, 0},
{"harakiri", required_argument, 't', "set harakiri timeout", uwsgi_opt_set_dyn, (void *) UWSGI_OPTION_HARAKIRI, 0},
{"harakiri-verbose", no_argument, 0, "enable verbose mode for harakiri", uwsgi_opt_true, &uwsgi.harakiri_verbose, 0},
{"harakiri-no-arh", no_argument, 0, "do not enable harakiri during after-request-hook", uwsgi_opt_true, &uwsgi.harakiri_no_arh, 0},
@@ -72,6 +72,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"xml", required_argument, 'x', "load config from xml file", uwsgi_opt_load_xml, NULL, UWSGI_OPT_IMMEDIATE},
#endif
{"config", required_argument, 0, "load configuration using the pluggable system", uwsgi_opt_load_config, NULL, UWSGI_OPT_IMMEDIATE},
{"fallback-config", required_argument, 0, "re-exec uwsgi with the specified config when exit code is 1", uwsgi_opt_set_str, &uwsgi.fallback_config, UWSGI_OPT_IMMEDIATE},
{"strict", no_argument, 0, "enable strict mode (placeholder cannot be used)", uwsgi_opt_true, &uwsgi.strict, UWSGI_OPT_IMMEDIATE},
{"skip-zero", no_argument, 0, "skip check of file descriptor 0", uwsgi_opt_true, &uwsgi.skip_zero, 0},
{"skip-atexit", no_argument, 0, "skip atexit hooks (ignored by the master)", uwsgi_opt_true, &uwsgi.skip_atexit, 0},
@@ -192,6 +194,9 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"emperor-on-demand-exec", required_argument, 0, "use the output of the specified command as on demand socket name (the vassal name is passed as the only argument)", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_exec, 0},
{"emperor-extra-extension", required_argument, 0, "allows the specified extension in the Emperor (vassal will be called with --config)", uwsgi_opt_add_string_list, &uwsgi.emperor_extra_extension, 0},
{"emperor-extra-ext", required_argument, 0, "allows the specified extension in the Emperor (vassal will be called with --config)", uwsgi_opt_add_string_list, &uwsgi.emperor_extra_extension, 0},
#if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL)
{"emperor-use-clone", required_argument, 0, "use clone() instead of fork() passing the specified unshare() flags", uwsgi_opt_set_unshare, &uwsgi.emperor_clone, 0},
#endif
{"imperial-monitor-list", no_argument, 0, "list enabled imperial monitors", uwsgi_opt_true, &uwsgi.imperial_monitor_list, 0},
{"imperial-monitors-list", no_argument, 0, "list enabled imperial monitors", uwsgi_opt_true, &uwsgi.imperial_monitor_list, 0},
{"vassals-inherit", required_argument, 0, "add config templates to vassals config", uwsgi_opt_add_string_list, &uwsgi.vassals_templates, 0},
@@ -204,6 +209,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"worker-reload-mercy", required_argument, 0, "set the maximum time (in seconds) a worker can take to reload/shutdown (default is 60)", uwsgi_opt_set_int, &uwsgi.worker_reload_mercy, 0},
{"exit-on-reload", no_argument, 0, "force exit even if a reload is requested", uwsgi_opt_true, &uwsgi.exit_on_reload, 0},
{"die-on-term", no_argument, 0, "exit instead of brutal reload on SIGTERM", uwsgi_opt_true, &uwsgi.die_on_term, 0},
{"force-gateway", no_argument, 0, "force teh spawn of the first registered gateway without a master", uwsgi_opt_true, &uwsgi.force_gateway, 0},
{"help", no_argument, 'h', "show this help", uwsgi_help, NULL, UWSGI_OPT_IMMEDIATE},
{"usage", no_argument, 'h', "show this help", uwsgi_help, NULL, UWSGI_OPT_IMMEDIATE},
@@ -220,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},
@@ -255,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},
@@ -282,8 +289,14 @@ 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},
{"immediate-uid", required_argument, 0, "setuid to the specified user/uid IMMEDIATELY", uwsgi_opt_set_immediate_uid, NULL, UWSGI_OPT_IMMEDIATE},
{"immediate-gid", required_argument, 0, "setgid to the specified group/gid IMMEDIATELY", uwsgi_opt_set_immediate_gid, NULL, UWSGI_OPT_IMMEDIATE},
{"no-initgroups", no_argument, 0, "disable additional groups set via initgroups()", uwsgi_opt_true, &uwsgi.no_initgroups, 0},
@@ -291,8 +304,39 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"cap", required_argument, 0, "set process capability", uwsgi_opt_set_cap, NULL, 0},
#endif
#ifdef __linux__
{"unshare", required_argument, 0, "unshare() part of the processes and put it in a new namespace", uwsgi_opt_set_unshare, 0},
{"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},
{"exec-in-jail", required_argument, 0, "run the specified command in jail after initialization", uwsgi_opt_add_string_list, &uwsgi.exec_in_jail, 0},
@@ -301,6 +345,58 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"exec-as-user-atexit", required_argument, 0, "run the specified command before app exit and reload", uwsgi_opt_add_string_list, &uwsgi.exec_as_user_atexit, 0},
{"exec-pre-app", required_argument, 0, "run the specified command before app loading", uwsgi_opt_add_string_list, &uwsgi.exec_pre_app, 0},
{"exec-post-app", required_argument, 0, "run the specified command after app loading", uwsgi_opt_add_string_list, &uwsgi.exec_post_app, 0},
{"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},
{"wait-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-interface-timeout", required_argument, 0, "set the timeout for wait-for-interface", uwsgi_opt_set_int, &uwsgi.wait_for_interface_timeout, 0},
{"wait-for-iface", required_argument, 0, "wait for the specified network interface to come up before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_interface, 0},
{"wait-for-iface-timeout", required_argument, 0, "set the timeout for wait-for-interface", uwsgi_opt_set_int, &uwsgi.wait_for_interface_timeout, 0},
{"wait-iface", required_argument, 0, "wait for the specified network interface to come up before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_interface, 0},
{"wait-iface-timeout", required_argument, 0, "set the timeout for wait-for-interface", uwsgi_opt_set_int, &uwsgi.wait_for_interface_timeout, 0},
{"call-pre-jail", required_argument, 0, "call the specified function before jailing", uwsgi_opt_add_string_list, &uwsgi.call_pre_jail, 0},
{"call-post-jail", required_argument, 0, "call the specified function after jailing", uwsgi_opt_add_string_list, &uwsgi.call_post_jail, 0},
{"call-in-jail", required_argument, 0, "call the specified function in jail after initialization", uwsgi_opt_add_string_list, &uwsgi.call_in_jail, 0},
{"call-as-root", required_argument, 0, "call the specified function before privileges drop", uwsgi_opt_add_string_list, &uwsgi.call_as_root, 0},
{"call-as-user", required_argument, 0, "call the specified function after privileges drop", uwsgi_opt_add_string_list, &uwsgi.call_as_user, 0},
{"call-as-user-atexit", required_argument, 0, "call the specified function before app exit and reload", uwsgi_opt_add_string_list, &uwsgi.call_as_user_atexit, 0},
{"call-pre-app", required_argument, 0, "call the specified function before app loading", uwsgi_opt_add_string_list, &uwsgi.call_pre_app, 0},
{"call-post-app", required_argument, 0, "call the specified function after app loading", uwsgi_opt_add_string_list, &uwsgi.call_post_app, 0},
{"call-as-vassal", required_argument, 0, "call the specified function() before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.call_as_vassal, 0},
{"call-as-vassal1", required_argument, 0, "call the specified function(char *) before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.call_as_vassal1, 0},
{"call-as-vassal3", required_argument, 0, "call the specified function(char *, uid_t, gid_t) before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.call_as_vassal3, 0},
{"call-as-emperor", required_argument, 0, "call the specified function() in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.call_as_emperor, 0},
{"call-as-emperor1", required_argument, 0, "call the specified function(char *) in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.call_as_emperor1, 0},
{"call-as-emperor2", required_argument, 0, "call the specified function(char *, pid_t) in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.call_as_emperor2, 0},
{"call-as-emperor4", required_argument, 0, "call the specified function(char *, pid_t, uid_t, gid_t) in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.call_as_emperor4, 0},
{"ini", required_argument, 0, "load config from ini file", uwsgi_opt_load_ini, NULL, UWSGI_OPT_IMMEDIATE},
#ifdef UWSGI_YAML
{"yaml", required_argument, 'y', "load config from yaml file", uwsgi_opt_load_yml, NULL, UWSGI_OPT_IMMEDIATE},
@@ -464,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},
@@ -492,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},
@@ -510,6 +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},
@@ -523,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},
@@ -580,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
@@ -604,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},
@@ -615,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},
@@ -646,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},
@@ -688,6 +823,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"loop-list", no_argument, 0, "list enabled loop engines", uwsgi_opt_true, &uwsgi.loop_list, 0},
{"loops-list", no_argument, 0, "list enabled loop engines", uwsgi_opt_true, &uwsgi.loop_list, 0},
{"worker-exec", required_argument, 0, "run the specified command as worker", uwsgi_opt_set_str, &uwsgi.worker_exec, 0},
{"worker-exec2", required_argument, 0, "run the specified command as worker (after post_fork hook)", uwsgi_opt_set_str, &uwsgi.worker_exec2, 0},
{"attach-daemon", required_argument, 0, "attach a command/daemon to the master process (the command has to not go in background)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
{"smart-attach-daemon", required_argument, 0, "attach a command/daemon to the master process managed by a pidfile (the command has to daemonize)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
{"smart-attach-daemon2", required_argument, 0, "attach a command/daemon to the master process managed by a pidfile (the command has to NOT daemonize)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
@@ -699,6 +835,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"daemons-honour-stdin", no_argument, 0, "do not change the stdin of external daemons to /dev/null", uwsgi_opt_true, &uwsgi.daemons_honour_stdin, UWSGI_OPT_MASTER},
{"plugins", required_argument, 0, "load uWSGI plugins", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE},
{"plugin", required_argument, 0, "load uWSGI plugins", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE},
{"need-plugins", required_argument, 0, "load uWSGI plugins (exit on error)", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE},
{"need-plugin", required_argument, 0, "load uWSGI plugins (exit on error)", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE},
{"plugins-dir", required_argument, 0, "add a directory to uWSGI plugin search path", uwsgi_opt_add_string_list, &uwsgi.plugins_dir, UWSGI_OPT_IMMEDIATE},
{"plugin-dir", required_argument, 0, "add a directory to uWSGI plugin search path", uwsgi_opt_add_string_list, &uwsgi.plugins_dir, UWSGI_OPT_IMMEDIATE},
{"plugins-list", no_argument, 0, "list enabled plugins", uwsgi_opt_true, &uwsgi.plugins_list, 0},
@@ -1103,6 +1241,10 @@ void grace_them_all(int signum) {
uwsgi_log("...gracefully killing workers...\n");
#ifdef UWSGI_SSL
uwsgi_legion_announce_death();
#endif
if (uwsgi.unsubscribe_on_graceful_reload) {
uwsgi_unsubscribe_all();
}
@@ -1172,6 +1314,10 @@ void reap_them_all(int signum) {
uwsgi_log("...brutally killing workers...\n");
#ifdef UWSGI_SSL
uwsgi_legion_announce_death();
#endif
// unsubscribe if needed
uwsgi_unsubscribe_all();
@@ -1253,7 +1399,7 @@ void what_i_am_doing() {
for (i = 0; i < uwsgi.cores; i++) {
wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[i].req;
if (wsgi_req->uri_len > 0) {
#ifdef __sun__
#if defined(__sun__) && !defined(__clang__)
ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, ctime_storage, 26);
#else
ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, ctime_storage);
@@ -1270,7 +1416,7 @@ void what_i_am_doing() {
else {
wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[0].req;
if (wsgi_req->uri_len > 0) {
#ifdef __sun__
#if defined(__sun__) && !defined(__clang__)
ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, ctime_storage, 26);
#else
ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, ctime_storage);
@@ -1308,16 +1454,24 @@ 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 = uwsgi.exec_as_user_atexit;
while (usl) {
struct uwsgi_string_list *usl;
uwsgi_foreach(usl, uwsgi.exec_as_user_atexit) {
uwsgi_log("running \"%s\" (as uid: %d gid: %d) ...\n", usl->value, (int) getuid(), (int) getgid());
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);
}
usl = usl->next;
}
uwsgi_foreach(usl, uwsgi.call_as_user_atexit) {
if (uwsgi_call_symbol(usl->value)) {
uwsgi_log("unaable to call function \"%s\"\n", usl->value);
}
}
}
}
@@ -1359,6 +1513,13 @@ static void vacuum(void) {
}
while (uwsgi_sock) {
if (uwsgi_sock->family == AF_UNIX && uwsgi_sock->name[0] != '@') {
struct stat st;
if (!stat(uwsgi_sock->name, &st)) {
if (st.st_ino != uwsgi_sock->inode) {
uwsgi_log("VACUUM WARNING: unix socket %s changed inode. Skip removal\n", uwsgi_sock->name);
goto next;
}
}
if (unlink(uwsgi_sock->name)) {
uwsgi_error("unlink()");
}
@@ -1366,6 +1527,7 @@ static void vacuum(void) {
uwsgi_log("VACUUM: unix socket %s removed.\n", uwsgi_sock->name);
}
}
next:
uwsgi_sock = uwsgi_sock->next;
}
}
@@ -1423,14 +1585,17 @@ void signal_pidfile(int sig, char *filename) {
exit(0);
}
void fixup_argv_and_environ(int argc, char **argv, char **environ) {
static void fixup_argv_and_environ(int argc, char **argv, char **environ, char **envp) {
uwsgi.orig_argv = argv;
uwsgi.argv = argv;
uwsgi.argc = argc;
uwsgi.environ = environ;
// avoid messing with fake environ
if (envp && *environ != *envp) return;
#if defined(__linux__) || defined(__sun__)
int i;
@@ -1761,6 +1926,8 @@ int main(int argc, char *argv[], char *envp[]) {
uwsgi_register_clock(&uwsgi_unix_clock);
uwsgi_set_clock("unix");
// fallback config
atexit(uwsgi_fallback_config);
// manage/flush logs
atexit(uwsgi_flush_logs);
// clear sockets, pidfiles...
@@ -1842,7 +2009,7 @@ int main(int argc, char *argv[], char *envp[]) {
uwsgi.binary_path = uwsgi_get_binary_path(argv[0]);
// ok we can now safely play with argv and environ
fixup_argv_and_environ(argc, argv, environ);
fixup_argv_and_environ(argc, argv, environ, envp);
if (gethostname(uwsgi.hostname, 255)) {
uwsgi_error("gethostname()");
@@ -1858,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,
@@ -1942,7 +2113,7 @@ int main(int argc, char *argv[], char *envp[]) {
uwsgi_opt_flock(NULL, uwsgi.flock_wait2, NULL);
// setup master logging
if (uwsgi.log_master)
if (uwsgi.log_master && !uwsgi.daemonize2)
uwsgi_setup_log_master();
// setup offload engines
@@ -2082,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
@@ -2092,16 +2265,38 @@ 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);
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.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);
}
}
usl = usl->next;
}
// we could now patch the binary
@@ -2156,9 +2351,44 @@ 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);
if (ret != 0) {
uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret);
exit(1);
}
}
uwsgi_foreach(usl, uwsgi.call_in_jail) {
if (uwsgi_call_symbol(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();
}
@@ -2263,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)) {
@@ -2306,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();
@@ -2398,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) {
@@ -2465,6 +2710,11 @@ int uwsgi_start(void *v_argv) {
else if (!uwsgi.sockets && ushared->gateways_cnt && !uwsgi.no_server && !uwsgi.master_process) {
// here we will have a zombie... sorry
uwsgi_log("...you should enable the master process... really...\n");
if (uwsgi.force_gateway) {
struct uwsgi_gateway *ug = &ushared->gateways[0];
ug->loop(0, ug->data);
// when we are here the gateway is dead :(
}
exit(0);
}
@@ -2599,7 +2849,7 @@ unsafe:
}
}
// initialize locks and socket as soon as possibile, as the master could enqueue tasks
// initialize locks and socket as soon as possible, as the master could enqueue tasks
if (uwsgi.spoolers != NULL && (uwsgi.sockets || uwsgi.loop)) {
create_signal_pipe(uwsgi.shared->spooler_signal_pipe);
struct uwsgi_spooler *uspool = uwsgi.spoolers;
@@ -2632,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) {
@@ -2820,7 +3074,7 @@ next2:
exit(1);
}
if (uwsgi.sockets->fd != 0) {
if (uwsgi.sockets->fd != 0 && !uwsgi.honour_stdin) {
if (dup2(uwsgi.sockets->fd, 0) < 0) {
uwsgi_error("dup2()");
}
@@ -2858,6 +3112,34 @@ next2:
}
}
for (i = 0; i < uwsgi.gp_cnt; i++) {
if (uwsgi.gp[i]->post_fork) {
uwsgi.gp[i]->post_fork();
}
}
if (uwsgi.worker_exec2) {
char *w_argv[2];
w_argv[0] = uwsgi.worker_exec2;
w_argv[1] = NULL;
uwsgi.sockets->arg &= (~O_NONBLOCK);
if (fcntl(uwsgi.sockets->fd, F_SETFL, uwsgi.sockets->arg) < 0) {
uwsgi_error("fcntl()");
exit(1);
}
if (uwsgi.sockets->fd != 0 && !uwsgi.honour_stdin) {
if (dup2(uwsgi.sockets->fd, 0) < 0) {
uwsgi_error("dup2()");
}
}
execvp(w_argv[0], w_argv);
// never here
uwsgi_error("execvp()");
exit(1);
}
uwsgi_worker_run();
// never here
_exit(0);
@@ -3155,7 +3437,7 @@ void build_options() {
/*
this function build the help output from the uwsgi.options structure
this function builds the help output from the uwsgi.options structure
*/
void uwsgi_help(char *opt, char *val, void *none) {
@@ -3197,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) {
@@ -3209,6 +3493,13 @@ void uwsgi_init_all_apps() {
usl = usl->next;
}
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);
}
}
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->init_apps) {
@@ -3257,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);
@@ -3268,6 +3561,11 @@ void uwsgi_init_all_apps() {
usl = usl->next;
}
uwsgi_foreach(usl, uwsgi.call_post_app) {
if (uwsgi_call_symbol(usl->value)) {
uwsgi_log("unaable to call function \"%s\"\n", usl->value);
}
}
}
@@ -3664,8 +3962,8 @@ void uwsgi_opt_set_cap(char *opt, char *value, void *none) {
}
#endif
#ifdef __linux__
void uwsgi_opt_set_unshare(char *opt, char *value, void *none) {
uwsgi_build_unshare(value);
void uwsgi_opt_set_unshare(char *opt, char *value, void *mask) {
uwsgi_build_unshare(value, (int *) mask);
}
#endif
@@ -3710,6 +4008,10 @@ void uwsgi_opt_load_plugin(char *opt, char *value, void *none) {
if (uwsgi_load_plugin(-1, p, NULL)) {
build_options();
}
else if (!uwsgi_startswith(opt, "need-", 5)) {
uwsgi_log("unable to load plugin \"%s\"\n", p);
exit(1);
}
p = strtok(NULL, ",");
}
free(p);
@@ -4095,7 +4397,7 @@ void uwsgi_opt_cflags(char *opt, char *filename, void *foobar) {
}
char *uwsgi_get_cflags() {
size_t len = sizeof(UWSGI_CFLAGS);
size_t len = sizeof(UWSGI_CFLAGS) -1;
char *src = UWSGI_CFLAGS;
char *ptr = uwsgi_malloc((len / 2) + 1);
char *base = ptr;
+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]
*/
View File
+2
View File
@@ -9,6 +9,8 @@ end
major,minor = RUBY_VERSION.split('.')
if major.to_i >= 2 or (major.to_i == 1 and minor.to_i >= 9)
# a trick for installations with messy PATH
ENV['UWSGICONFIG_RUBYPATH'] = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name']).sub(/.*\s.*/m, '"\&"')
system("bash install.sh ruby2 #{Dir.pwd}/uwsgi.ruby")
else
system("bash install.sh rack #{Dir.pwd}/uwsgi.ruby")
-54
View File
@@ -1,54 +0,0 @@
import uwsgi
if uwsgi.loop == 'gevent':
import gevent
from threading import Thread
import time
from uwsgidecorators import postfork
def foobar():
while True:
time.sleep(3)
print "threee second elapsed in worker %d" % uwsgi.worker_id()
@postfork
def spawn_thread():
t = Thread(target=foobar)
t.daemon = True
t.start()
@postfork
def spawn_thread2():
t = Thread(target=foobar)
t.daemon = True
t.start()
def gl_func():
while True:
gevent.sleep(2)
print "i am a greenltet running in worker %d" % uwsgi.worker_id()
@postfork
def spawn_greenlet():
gevent.spawn(gl_func)
print uwsgi.version
print uwsgi.workers()
try:
uwsgi.cache_set('foo', "Hello World from cache")
except:
pass
def application(env, start_response):
print env['wsgi.input'].read()
if uwsgi.loop == 'gevent':
gevent.sleep()
start_response('200 OK', [('Content-Type', 'text/html')])
yield "foobar<br/>"
if uwsgi.loop == 'gevent':
gevent.sleep(3)
yield str(env['wsgi.input'].fileno())
yield "<h1>Hello World</h1>"
try:
yield uwsgi.cache_get('foo')
except:
pass
-31
View File
@@ -1,31 +0,0 @@
import uwsgi
import time
import rrdtool
# rrdtool create test.rrd --start 1270879004 -s 10 DS:requests:COUNTER:300:U:U RRA:AVERAGE:0.5:3:105120
s_freq = 10
# this task will be executed every s_freq seconds
def rrdtool_updater(sig, sec):
rrdtool.update('test.rrd', str(int(time.time()))+':'+str(uwsgi.total_requests()))
uwsgi.register_timer(0, s_freq, uwsgi.KIND_WORKER, rrdtool_updater)
def hello_world(env, start_response):
start_response('200 Ok', [('Content-type', 'text/plain')])
return 'Hello world !'
def graph(env, start_response):
start_response('200 Ok', [('Content-type', 'image/png')])
now = int(time.time())
graph_range = (3600*24)
rrdtool.graph('uwsgi_graph.png', '--start', str(now - graph_range), '--end', str(now), 'DEF:urequests=test.rrd:requests:AVERAGE', 'LINE2:urequests#00FF00')
# send file to client
uwsgi.sendfile('uwsgi_graph.png')
uwsgi.applications = {'/': hello_world, '/graph':graph}
+15 -1
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);
@@ -82,6 +88,13 @@ void linux_namespace_start(void *argv) {
usl = usl->next;
}
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);
}
}
uwsgi_log("waiting for jailed master (pid: %d) death...\n", (int) pid);
pid = waitpid(pid, &waitpid_status, 0);
if (pid < 0) {
@@ -167,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;
+12 -9
View File
@@ -201,7 +201,18 @@ edge:
// mark core as used
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 1;
wsgi_req->start_of_request = uwsgi_micros();
// accept the connection
if (wsgi_req_simple_accept(wsgi_req, uwsgi_sock->fd)) {
free_req_queue;
if (uwsgi_sock->retry && uwsgi_sock->retry[wsgi_req->async_id]) {
goto edge;
}
// in case of errors (or thundering herd, just rest it)
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 0;
goto clear;
}
wsgi_req->start_of_request = uwsgi_micros();
wsgi_req->start_of_request_in_sec = wsgi_req->start_of_request/1000000;
// enter harakiri mode
@@ -209,14 +220,6 @@ edge:
set_harakiri(uwsgi.shared->options[UWSGI_OPTION_HARAKIRI]);
}
// accept the connection
if (wsgi_req_simple_accept(wsgi_req, uwsgi_sock->fd)) {
free_req_queue;
if (uwsgi_sock->retry && uwsgi_sock->retry[wsgi_req->async_id]) {
goto edge;
}
goto clear;
}
// here we spawn an async {} block
CV *async_xs_call = newXS(NULL, XS_coroae_accept_request, "uwsgi::coroae");
+77 -23
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;
@@ -164,14 +195,6 @@ edge:
// mark core as used
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 1;
wsgi_req->start_of_request = uwsgi_micros();
wsgi_req->start_of_request_in_sec = wsgi_req->start_of_request/1000000;
// enter harakiri mode
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
set_harakiri(uwsgi.shared->options[UWSGI_OPTION_HARAKIRI]);
}
// accept the connection (since uWSGI 1.5 all of the sockets are non-blocking)
if (wsgi_req_simple_accept(wsgi_req, uwsgi_sock->fd)) {
free_req_queue;
@@ -183,6 +206,14 @@ edge:
goto clear;
}
wsgi_req->start_of_request = uwsgi_micros();
wsgi_req->start_of_request_in_sec = wsgi_req->start_of_request/1000000;
// enter harakiri mode
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
set_harakiri(uwsgi.shared->options[UWSGI_OPTION_HARAKIRI]);
}
// hack to easily pass wsgi_req pointer to the greenlet
PyTuple_SetItem(ugevent.greenlet_args, 1, PyLong_FromLong((long)wsgi_req));
@@ -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;
};
+299
View File
@@ -0,0 +1,299 @@
#include <uwsgi.h>
#include <api/glfs.h>
#ifdef UWSGI_MATHEVAL
#error currently the glusterfs plugins is not compatible with uWSGI built with matheval support
#endif
extern struct uwsgi_server uwsgi;
/*
Author: Roberto De Ioris
--glusterfs-mount mountpoint=/foo,server=192.168.173.13:24007;192.168.173.17:0,volfile=foo.vol;volume=unbit001
*/
struct uwsgi_plugin glusterfs_plugin;
struct uwsgi_glusterfs {
int timeout;
struct uwsgi_string_list *mountpoints;
} uglusterfs;
static struct uwsgi_option uwsgi_glusterfs_options[] = {
{"glusterfs-mount", required_argument, 0, "virtual mount the specified glusterfs volume in a uri", uwsgi_opt_add_string_list, &uglusterfs.mountpoints, UWSGI_OPT_MIME},
{"glusterfs-timeout", required_argument, 0, "timeout for glusterfs async mode", uwsgi_opt_set_int, &uglusterfs.timeout, 0},
{0, 0, 0, 0, 0, 0, 0},
};
static int uwsgi_glusterfs_read_sync(struct wsgi_request *wsgi_req, glfs_fd_t *fd, size_t remains) {
while(remains > 0) {
char buf[8192];
ssize_t rlen = glfs_read (fd, buf, UMIN(remains, 8192), 0);
if (rlen <= 0) return -1;
if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) return -1;
remains -= rlen;
}
return 0;
}
/*
async read of a resource
the uwsgi_glusterfs_async_io structure is passed between threads
the callback simply signal the main core about the availability of data
*/
struct uwsgi_glusterfs_async_io {
int fd[2];
ssize_t rlen;
};
static void uwsgi_glusterfs_read_async_cb(glfs_fd_t *fd, ssize_t rlen, void *data) {
struct uwsgi_glusterfs_async_io *aio = (struct uwsgi_glusterfs_async_io *) data;
#ifdef UWSGI_DEBUG
uwsgi_log("[glusterfs-cb] rlen = %d\n", rlen);
#endif
aio->rlen = rlen;
// signal the core
if (write(aio->fd[1], "\1", 1) <= 0) {
uwsgi_error("uwsgi_glusterfs_read_async_cb()/write()");
}
}
static int uwsgi_glusterfs_read_async(struct wsgi_request *wsgi_req, glfs_fd_t *fd, size_t remains) {
char buf[8192];
struct uwsgi_glusterfs_async_io aio;
int ret = -1;
if (pipe(aio.fd)) {
uwsgi_error("uwsgi_glusterfs_read_async()/pipe()");
return -1;
}
aio.rlen = -1;
while(remains > 0) {
// trigger an async read
if (glfs_read_async(fd, buf, 8192, 0, uwsgi_glusterfs_read_async_cb, &aio)) goto end;
// wait for the callback to be executed
if (uwsgi.wait_read_hook(aio.fd[0], uglusterfs.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:
close(aio.fd[0]);
close(aio.fd[1]);
return ret;
}
static int uwsgi_glusterfs_try(struct uwsgi_app *ua, char *node) {
int ret = -1;
char *colon = strchr(node, ':');
// unix socket
if (!colon) {
if (glfs_set_volfile_server((glfs_t *)ua->interpreter, "unix", node, 0)) {
uwsgi_error("[glusterfs] glfs_set_volfile_server()");
return -1;
}
goto connect;
}
*colon = 0;
if (glfs_set_volfile_server((glfs_t *)ua->interpreter, "tcp", node, atoi(colon+1))) {
uwsgi_error("[glusterfs] glfs_set_volfile_server()");
return -1;
}
connect:
ret = glfs_init((glfs_t *)ua->interpreter);
if (ret) { uwsgi_error("[glusterfs] glfs_init()"); }
else {
if (colon) *colon = ':';
uwsgi_log("[glusterfs] worker %d connected to %s\n", uwsgi.mywid, node);
}
return ret;
}
static void uwsgi_glusterfs_connect_do(struct uwsgi_app *ua) {
char *servers = uwsgi_str(ua->callable);
char *p = strtok(servers, ";");
while(p) {
uwsgi_log("[glusterfs] try connect to %s for mountpoint %.*s on worker %d ...\n", p, ua->mountpoint_len, ua->mountpoint, uwsgi.mywid);
if (uwsgi_glusterfs_try(ua, p)) {
goto end;
}
p = strtok(NULL, ";");
}
end:
free(servers);
}
static void uwsgi_glusterfs_connect() {
int i;
// search for all of the glusterfs apps and connect to the server-based ones
for (i = 0; i < uwsgi_apps_cnt; i++) {
if (uwsgi_apps[i].modifier1 != glusterfs_plugin.modifier1) continue;
if (!uwsgi_apps[i].callable) {
if (glfs_init((glfs_t *)uwsgi_apps[i].interpreter)) {
uwsgi_error("[glusterfs] glfs_init()");
exit(1);
}
uwsgi_log("[glusterfs] worker %d connected using volfile\n", uwsgi.mywid);
continue;
}
uwsgi_glusterfs_connect_do(&uwsgi_apps[i]);
}
}
static void uwsgi_glusterfs_add_mountpoint(char *arg, size_t arg_len) {
char *ugfs_mountpoint = NULL;
char *ugfs_server = NULL;
char *ugfs_volfile = NULL;
char *ugfs_volume = NULL;
if (uwsgi_kvlist_parse(arg, arg_len, ',', '=',
"mountpoint", &ugfs_mountpoint,
"server", &ugfs_server,
"servers", &ugfs_server,
"volfile", &ugfs_volfile,
"volume", &ugfs_volume,
NULL)) {
uwsgi_log("unable to parse glusterfs mountpoint definition\n");
exit(1);
}
if (!ugfs_mountpoint || (!ugfs_server && !ugfs_volfile) || !ugfs_volume) {
uwsgi_log("[glusterfs] mount requires a mountpoint, a volume and at least one server or volfile\n");
exit(1);
}
int id = uwsgi_apps_cnt;
time_t now = uwsgi_now();
uwsgi_log("[glusterfs] mounting %s ...\n", ugfs_mountpoint);
// this should fail only if memory is not available
glfs_t *volume = glfs_new(ugfs_volume);
if (!volume) {
uwsgi_error("unable to initialize glusterfs mountpoint: glfs_new()");
exit(1);
}
if (ugfs_volfile) {
if (glfs_set_volfile(volume, ugfs_volfile)) {
uwsgi_error("unable to set glusterfs volfile: glfs_set_volfile\n");
exit(1);
}
}
/*
here we pass ugfs_server as the callable field.
After fork() if this field is defined we will start trying to connect to each one of the configuratio nodes
This is required to have fallback management
*/
struct uwsgi_app *ua = uwsgi_add_app(id, glusterfs_plugin.modifier1, ugfs_mountpoint, strlen(ugfs_mountpoint), volume, ugfs_server);
if (!ua) {
uwsgi_log("[glusterfs] unable to mount %s\n", ugfs_mountpoint);
exit(1);
}
ua->started_at = now;
ua->startup_time = uwsgi_now() - now;
uwsgi_log("GlusterFS app/mountpoint %d (%s) loaded in %d seconds at %p\n", id, ugfs_mountpoint, (int) ua->startup_time, volume);
}
// we translate the string list to an app representation
// this happens before fork() if not in lazy/lazy-apps mode
static void uwsgi_glusterfs_setup() {
if (!uglusterfs.timeout) {
uglusterfs.timeout = uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT];
}
struct uwsgi_string_list *usl = uglusterfs.mountpoints;
while(usl) {
uwsgi_glusterfs_add_mountpoint(usl->value, usl->len);
usl = usl->next;
}
}
static int uwsgi_glusterfs_request(struct wsgi_request *wsgi_req) {
char filename[PATH_MAX+1];
/* Standard GlusterFS request */
if (!wsgi_req->uh->pktsize) {
uwsgi_log( "Empty GlusterFS 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, glusterfs_plugin.modifier1);
if (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) {
if (uwsgi_apps[uwsgi.default_app].modifier1 == glusterfs_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];
memcpy(filename, wsgi_req->path_info, wsgi_req->path_info_len);
filename[wsgi_req->path_info_len] = 0;
glfs_fd_t *fd = glfs_open((glfs_t *) ua->interpreter, filename, O_RDONLY);
if (!fd) {
uwsgi_404(wsgi_req);
return UWSGI_OK;
}
struct stat st;
if (glfs_fstat(fd, &st)) {
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.st_mtime)) goto end;
if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end;
// skip body on HEAD
if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) {
size_t remains = st.st_size;
if (uwsgi.async > 1) {
if (uwsgi_glusterfs_read_async(wsgi_req, fd, remains)) goto end;
}
else {
if (uwsgi_glusterfs_read_sync(wsgi_req, fd, remains)) goto end;
}
}
end:
glfs_close(fd);
return UWSGI_OK;
}
struct uwsgi_plugin glusterfs_plugin = {
.name = "glusterfs",
.modifier1 = 27,
.options = uwsgi_glusterfs_options,
.post_fork = uwsgi_glusterfs_setup,
.fixup = uwsgi_glusterfs_connect,
.request = uwsgi_glusterfs_request,
.after_request = log_request,
};
+7
View File
@@ -0,0 +1,7 @@
import os
NAME='glusterfs'
CFLAGS = os.popen('pkg-config --cflags glusterfs-api').read().rstrip().split()
LDFLAGS = []
LIBS = os.popen('pkg-config --libs glusterfs-api').read().rstrip().split()
GCC_LIST = ['glusterfs']
+27 -4
View File
@@ -10,6 +10,7 @@ struct uwsgi_http uhttp;
struct uwsgi_option http_options[] = {
{"http", required_argument, 0, "add an http router/server on the specified address", uwsgi_opt_corerouter, &uhttp, 0},
{"httprouter", required_argument, 0, "add an http router/server on the specified address", uwsgi_opt_corerouter, &uhttp, 0},
#ifdef UWSGI_SSL
{"https", required_argument, 0, "add an https router/server on the specified address with specified certificate and key", uwsgi_opt_https, &uhttp, 0},
{"https2", required_argument, 0, "add an https/spdy router/server using keyval options", uwsgi_opt_https2, &uhttp, 0},
@@ -207,8 +208,19 @@ int http_headers_parse(struct corerouter_peer *peer) {
while (ptr < watermark) {
if (*ptr == '?' && !query_string) {
// PATH_INFO must be url-decoded !!!
hr->path_info_len = ptr - base;
hr->path_info = uwsgi_malloc(hr->path_info_len);
if (!hr->path_info) {
hr->path_info_len = ptr - base;
hr->path_info = uwsgi_malloc(hr->path_info_len);
}
else {
size_t new_path_info = ptr - base;
if (new_path_info > hr->path_info_len) {
char *tmp_buf = realloc(hr->path_info, new_path_info);
if (!tmp_buf) return -1;
hr->path_info = tmp_buf;
}
hr->path_info_len = new_path_info;
}
http_url_decode(base, &hr->path_info_len, hr->path_info);
if (uwsgi_buffer_append_keyval(out, "PATH_INFO", 9, hr->path_info, hr->path_info_len)) return -1;
query_string = ptr + 1;
@@ -219,8 +231,19 @@ int http_headers_parse(struct corerouter_peer *peer) {
if (uwsgi_buffer_append_keyval(out, "REQUEST_URI", 11, base, ptr - base)) return -1;
if (!query_string) {
// PATH_INFO must be url-decoded !!!
hr->path_info_len = ptr - base;
hr->path_info = uwsgi_malloc(hr->path_info_len);
if (!hr->path_info) {
hr->path_info_len = ptr - base;
hr->path_info = uwsgi_malloc(hr->path_info_len);
}
else {
size_t new_path_info = ptr - base;
if (new_path_info > hr->path_info_len) {
char *tmp_buf = realloc(hr->path_info, new_path_info);
if (!tmp_buf) return -1;
hr->path_info = tmp_buf;
}
hr->path_info_len = new_path_info;
}
http_url_decode(base, &hr->path_info_len, hr->path_info);
if (uwsgi_buffer_append_keyval(out, "PATH_INFO", 9, hr->path_info, hr->path_info_len)) return -1;
if (uwsgi_buffer_append_keyval(out, "QUERY_STRING", 12, "", 0)) return -1;
+2
View File
@@ -28,6 +28,7 @@ struct uwsgi_jvm {
jclass list_class;
jclass set_class;
jclass iterator_class;
jclass bool_class;
jclass runtime_exception;
jclass io_exception;
@@ -101,6 +102,7 @@ int uwsgi_jvm_call_bool(jobject, jmethodID, ...);
int uwsgi_jvm_consume_input_stream(struct wsgi_request *, size_t, jobject);
jobject uwsgi_jvm_num(long);
jobject uwsgi_jvm_request_body_input_stream(void);
jobject uwsgi_jvm_bool(long);
size_t uwsgi_jvm_array_len(jobject);
jobject uwsgi_jvm_array_get(jobject, long);
+19 -3
View File
@@ -896,6 +896,19 @@ jobject uwsgi_jvm_num(long num) {
return o;
}
jobject uwsgi_jvm_bool(long b) {
static jmethodID mid = 0;
if (!mid) {
mid = uwsgi_jvm_get_method_id(ujvm.int_class, "<init>", "(I)V");
if (!mid) return NULL;
}
jobject o = (*ujvm_env)->NewObject(ujvm_env, ujvm.bool_class, mid, b);
if (uwsgi_jvm_exception()) {
return NULL;
}
return o;
}
jobject uwsgi_jvm_str(char *str, size_t len) {
jobject new_str;
if (len > 0) {
@@ -1063,6 +1076,9 @@ static void uwsgi_jvm_create(void) {
ujvm.int_class = uwsgi_jvm_class("java/lang/Integer");
if (!ujvm.int_class) exit(1);
ujvm.bool_class = uwsgi_jvm_class("java/lang/Boolean");
if (!ujvm.bool_class) exit(1);
ujvm.long_class = uwsgi_jvm_class("java/lang/Long");
if (!ujvm.long_class) exit(1);
@@ -1116,7 +1132,7 @@ static void uwsgi_jvm_create(void) {
jobject j_opt_value = uwsgi_jvm_hashmap_get(opt_hm, (jobject) j_opt_key);
if (uwsgi_jvm_object_is_instance(j_opt_value, ujvm.list_class)) {
if (uwsgi.exported_opts[j]->value == NULL) {
uwsgi_jvm_list_add(j_opt_value, (jobject) 1);
uwsgi_jvm_list_add(j_opt_value, uwsgi_jvm_bool(JNI_TRUE));
}
else {
uwsgi_jvm_list_add(j_opt_value, uwsgi_jvm_str(uwsgi.exported_opts[j]->value, 0));
@@ -1126,7 +1142,7 @@ static void uwsgi_jvm_create(void) {
jobject ll = uwsgi_jvm_list();
uwsgi_jvm_list_add(ll, j_opt_value);
if (uwsgi.exported_opts[j]->value == NULL) {
uwsgi_jvm_list_add(ll, (jobject) 1);
uwsgi_jvm_list_add(ll, uwsgi_jvm_bool(JNI_TRUE));
}
else {
uwsgi_jvm_list_add(ll, uwsgi_jvm_str(uwsgi.exported_opts[j]->value, 0));
@@ -1136,7 +1152,7 @@ static void uwsgi_jvm_create(void) {
}
else {
if (uwsgi.exported_opts[j]->value == NULL) {
uwsgi_jvm_hashmap_put(opt_hm, j_opt_key, (jobject) 1);
uwsgi_jvm_hashmap_put(opt_hm, j_opt_key, uwsgi_jvm_bool(JNI_TRUE));
}
else {
uwsgi_jvm_hashmap_put(opt_hm, j_opt_key, uwsgi_jvm_str(uwsgi.exported_opts[j]->value, 0));
+1 -1
View File
@@ -77,7 +77,7 @@ struct uwsgi_mono {
struct uwsgi_option uwsgi_mono_options[] = {
{"mono-app", required_argument, 0, "load a Mono asp.net app from the specified directory", uwsgi_opt_add_string_list, &umono.app, 0},
{"mono-gc-freq", required_argument, 0, "run the Mono GC every <n> requests (default, run after every request)", uwsgi_opt_set_64bit, &umono.gc_freq, 0},
{"mono-gc-freq", required_argument, 0, "run the Mono GC every <n> requests (default: run after every request)", uwsgi_opt_set_64bit, &umono.gc_freq, 0},
{"mono-key", required_argument, 0, "select the ApplicationHost based on the specified CGI var", uwsgi_opt_add_string_list, &umono.key, 0},
{"mono-version", required_argument, 0, "set the Mono jit version", uwsgi_opt_set_str, &umono.version, 0},
{"mono-config", required_argument, 0, "set the Mono config file", uwsgi_opt_set_str, &umono.config, 0},
+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']
+5 -1
View File
@@ -1,5 +1,5 @@
#undef __USE_GNU
#include "../../uwsgi.h"
#include <uwsgi.h>
#ifdef __APPLE__
#define HAS_BOOL 1
@@ -50,6 +50,9 @@ struct uwsgi_perl {
SV *atexit;
int loaded;
struct uwsgi_string_list *exec;
struct uwsgi_string_list *exec_post_fork;
};
void init_perl_embedded_module(void);
@@ -66,3 +69,4 @@ int init_psgi_app(struct wsgi_request *, char *, uint16_t, PerlInterpreter **);
PerlInterpreter *uwsgi_perl_new_interpreter(void);
int uwsgi_perl_mule(char *);
void uwsgi_perl_run_hook(SV *);
void uwsgi_perl_exec(char *);
+17
View File
@@ -483,6 +483,16 @@ void uwsgi_psgi_app() {
//load app in the main interpreter list
init_psgi_app(NULL, uperl.psgi, strlen(uperl.psgi), uperl.main);
}
// create a perl environment (if needed)
else if (uperl.exec) {
PERL_SET_CONTEXT(uperl.main[0]);
perl_parse(uperl.main[0], xs_init, 2, uperl.embedding, NULL);
}
struct uwsgi_string_list *usl;
uwsgi_foreach(usl, uperl.exec) {
uwsgi_perl_exec(usl->value);
}
}
@@ -502,3 +512,10 @@ int uwsgi_perl_mule(char *opt) {
}
void uwsgi_perl_exec(char *filename) {
size_t size = 0;
char *buf = uwsgi_open_and_read(filename, &size, 1, NULL);
perl_eval_pv(buf, 0);
free(buf);
}
+7
View File
@@ -21,6 +21,8 @@ struct uwsgi_option uwsgi_perl_options[] = {
#endif
{"perl-args", required_argument, 0, "add items (space separated) to @ARGV", uwsgi_opt_set_str, &uperl.argv_items, 0},
{"perl-arg", required_argument, 0, "add an item to @ARGV", uwsgi_opt_add_string_list, &uperl.argv_item, 0},
{"perl-exec", required_argument, 0, "exec the specified perl file before fork()", uwsgi_opt_add_string_list, &uperl.exec, 0},
{"perl-exec-post-fork", required_argument, 0, "exec the specified perl file after fork()", uwsgi_opt_add_string_list, &uperl.exec_post_fork, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -588,6 +590,11 @@ void uwsgi_perl_post_fork() {
SvREADONLY_on(GvSV(tmpgv));
}
struct uwsgi_string_list *usl;
uwsgi_foreach(usl, uperl.exec_post_fork) {
uwsgi_perl_exec(usl->value);
}
if (uperl.postfork) {
uwsgi_perl_run_hook(uperl.postfork);
}
+316
View File
@@ -0,0 +1,316 @@
#include <uwsgi.h>
#ifdef __linux__
#include <pty.h>
#elif defined(__APPLE__) || defined(__OpenBSD__)
#include <util.h>
#elif defined(__FreeBSD__)
#include <libutil.h>
#endif
#ifndef __FreeBSD__
#include <utmp.h>
#endif
extern struct uwsgi_server uwsgi;
struct uwsgi_pty_client {
int fd;
struct uwsgi_pty_client *prev;
struct uwsgi_pty_client *next;
};
static struct uwsgi_pty {
char *addr;
char *remote;
int queue;
int server_fd;
int master_fd;
int slave_fd;
int log;
int original_log;
int input;
int original_input;
int no_isig;
char *command;
pid_t command_pid;
struct uwsgi_pty_client *head;
struct uwsgi_pty_client *tail;
} upty;
static struct uwsgi_pty_client *uwsgi_pty_client_new(int fd) {
struct uwsgi_pty_client *upc = uwsgi_calloc(sizeof(struct uwsgi_pty_client));
upc->fd = fd;
if (upty.tail) {
upc->prev = upty.tail;
upty.tail->next = upc;
}
upty.tail = upc;
if (!upty.head) upty.head = upc;
return upc;
}
static void uwsgi_pty_client_remove(struct uwsgi_pty_client *upc) {
struct uwsgi_pty_client *prev = upc->prev;
struct uwsgi_pty_client *next = upc->next;
if (prev) {
prev->next = next;
}
if (next) {
next->prev = prev;
}
if (upc == upty.head) {
upty.head = next;
}
if (upc == upty.tail) {
upty.tail = prev;
}
close(upc->fd);
free(upc);
}
static struct uwsgi_option uwsgi_pty_options[] = {
{"pty-socket", required_argument, 0, "bind the pty server on the specified address", uwsgi_opt_set_str, &upty.addr, 0},
{"pty-log", no_argument, 0, "send stdout/stderr to the log engine too", uwsgi_opt_true, &upty.log, 0},
{"pty-input", no_argument, 0, "read from original stdin in addition to pty", uwsgi_opt_true, &upty.input, 0},
{"pty-connect", required_argument, 0, "connect the current terminal to a pty server", uwsgi_opt_set_str, &upty.remote, 0},
{"pty-no-isig", no_argument, 0, "disable ISIG terminal attribute in client mode", uwsgi_opt_true, &upty.no_isig, 0},
{"pty-exec", no_argument, 0, "run the specified command soon after the pty thread is spawned", uwsgi_opt_set_str, &upty.command, 0},
{0, 0, 0, 0, 0, 0, 0},
};
void uwsgi_pty_setterm(int fd) {
struct termios tio;
tcgetattr(fd, &tio);
tio.c_iflag |= IGNPAR;
tio.c_iflag &= ~(ISTRIP | IMAXBEL | BRKINT | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
#ifdef IUCLC
tio.c_iflag &= ~IUCLC;
#endif
tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL);
if (upty.no_isig) {
tio.c_lflag &= ~(ISIG);
}
#ifdef IEXTEN
tio.c_lflag &= ~IEXTEN;
#endif
tio.c_oflag &= ~OPOST;
tio.c_cc[VMIN] = 1;
tio.c_cc[VTIME] = 0;
#ifdef B38400
cfsetispeed(&tio, B38400);
cfsetospeed(&tio, B38400);
#endif
tcsetattr(fd, TCSANOW, &tio);
}
static void *uwsgi_pty_loop(void *arg) {
/*
if slave is ready there is something to send to the clients (and logs)
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;
int ret = event_queue_wait(upty.queue, -1, &interesting_fd);
if (ret == 0) continue;
if (ret < 0) continue;
if (upty.input && interesting_fd == upty.original_input) {
ssize_t rlen = read(upty.original_input, buf, 8192);
if (rlen <= 0) continue;
if (write(upty.master_fd, buf, rlen) != rlen) {
// what to do ?
}
continue;
}
if (interesting_fd == upty.master_fd) {
ssize_t rlen = read(upty.master_fd, buf, 8192);
if (rlen == 0) exit(1);
if (rlen < 0) {
uwsgi_error("uwsgi_pty_loop()/read()");
}
if (upty.log && upty.original_log >= 0) {
if (write(upty.original_log, buf, rlen) != rlen) {
// what to do ?
}
}
struct uwsgi_pty_client *upc = upty.head;
while(upc) {
if (write(upc->fd, buf, rlen) != rlen) {
struct uwsgi_pty_client *tmp_upc = upc->next;
uwsgi_pty_client_remove(upc);
upc = tmp_upc;
continue;
}
upc = upc->next;
}
continue;
}
if (interesting_fd == upty.server_fd) {
struct sockaddr_un client_src;
memset(&client_src, 0, sizeof(struct sockaddr_un));
socklen_t client_src_len = 0;
int client_fd = accept(upty.server_fd, (struct sockaddr *) &client_src, &client_src_len);
if (client_fd < 0) {
uwsgi_error("accept()");
continue;
}
struct uwsgi_pty_client *upc = uwsgi_pty_client_new(client_fd);
event_queue_add_fd_read(upty.queue, upc->fd);
continue;
}
struct uwsgi_pty_client *upc = upty.head;
while(upc) {
if (interesting_fd == upc->fd) {
ssize_t rlen = read(upc->fd, buf, 8192);
if (rlen <= 0) {
uwsgi_pty_client_remove(upc);
break;
}
if (write(upty.master_fd, buf, rlen) != rlen) {
}
break;
}
upc = upc->next;
}
continue;
}
}
static void uwsgi_pty_init() {
if (!upty.addr) return;
if (!uwsgi.master_process) return;
if (uwsgi.mywid > 1) return;
char *tcp_port = strrchr(upty.addr, ':');
if (tcp_port) {
// disable deferred accept for this socket
int current_defer_accept = uwsgi.no_defer_accept;
uwsgi.no_defer_accept = 1;
upty.server_fd = bind_to_tcp(upty.addr, uwsgi.listen_queue, tcp_port);
uwsgi.no_defer_accept = current_defer_accept;
}
else {
upty.server_fd = bind_to_unix(upty.addr, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
}
if (upty.log) {
upty.original_log = dup(1);
}
if (upty.input) {
upty.original_input = dup(0);
}
if (openpty(&upty.master_fd, &upty.slave_fd, NULL, NULL, NULL)) {
uwsgi_error("uwsgi_pty_init()/openpty()");
exit(1);
}
uwsgi_log("pty server %s (fd: %d) enabled on %s master: %d slave: %d\n", upty.addr, upty.server_fd, ttyname(upty.slave_fd), upty.master_fd, upty.slave_fd);
upty.queue = event_queue_init();
event_queue_add_fd_read(upty.queue, upty.master_fd);
event_queue_add_fd_read(upty.queue, upty.server_fd);
if (upty.input) {
event_queue_add_fd_read(upty.queue, upty.original_input);
uwsgi_pty_setterm(upty.original_input);
}
login_tty(upty.slave_fd);
if (upty.command) {
upty.command_pid = uwsgi_run_command(upty.command, NULL, -1);
}
pthread_t t;
pthread_create(&t, NULL, uwsgi_pty_loop, NULL);
}
static int uwsgi_pty_client() {
if (!upty.remote) return 0;
uwsgi_log("[pty] connecting to %s ...\n", upty.remote);
// save current terminal settings
if (!tcgetattr(0, &uwsgi.termios)) {
uwsgi.restore_tc = 1;
}
upty.server_fd = uwsgi_connect(upty.remote, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], 0);
if (upty.server_fd < 0) {
uwsgi_error("uwsgi_pty_client()/connect()");
exit(1);
}
uwsgi_socket_nb(upty.server_fd);
uwsgi_socket_nb(0);
uwsgi_log("[pty] connected.\n");
uwsgi_pty_setterm(0);
upty.queue = event_queue_init();
event_queue_add_fd_read(upty.queue, upty.server_fd);
event_queue_add_fd_read(upty.queue, 0);
for(;;) {
char buf[8192];
int interesting_fd = -1;
int ret = event_queue_wait(upty.queue, -1, &interesting_fd);
if (ret <= 0) break;
if (interesting_fd == 0) {
ssize_t rlen = read(0, buf, 8192);
if (rlen <= 0) break;
if (write(upty.server_fd, buf, rlen) != rlen) break;
continue;
}
if (interesting_fd == upty.server_fd) {
ssize_t rlen = read(upty.server_fd, buf, 8192);
if (rlen <= 0) break;
if (write(0, buf, rlen) != rlen) break;
continue;
}
}
exit(0);
// never here
return 0;
}
struct uwsgi_plugin pty_plugin = {
.name = "pty",
.options = uwsgi_pty_options,
.init = uwsgi_pty_client,
.post_fork = uwsgi_pty_init,
};
+12
View File
@@ -0,0 +1,12 @@
NAME='pty'
import os
uwsgi_os = os.uname()[0]
CFLAGS = []
LDFLAGS = []
if uwsgi_os in ('Linux', 'FreeBSD'):
LIBS = ['-lutil']
else:
LIBS = []
GCC_LIST = ['pty']
+52 -38
View File
@@ -25,11 +25,11 @@ struct uwsgi_pypy {
} upypy;
// the functions exposed by libpypy-c
char *(*rpython_startup_code)(void);
int (*pypy_setup_home)(char *, int);
int (*pypy_execute_source)(char *);
void (*pypy_thread_attach)(void);
void (*pypy_init_threads)(void);
char *(*u_rpython_startup_code)(void);
int (*u_pypy_setup_home)(char *, int);
int (*u_pypy_execute_source)(char *);
void (*u_pypy_thread_attach)(void);
void (*u_pypy_init_threads)(void);
// the hooks you can override with pypy
void (*uwsgi_pypy_hook_loader)(char *);
@@ -52,12 +52,18 @@ static int uwsgi_pypy_init() {
exit(1);
}
if (upypy.lib) {
if (dlsym(RTLD_DEFAULT, "rpython_startup_code")) {
uwsgi_log("PyPy runtime detected, skipping libpypy-c loading\n");
goto ready;
}
else if (upypy.lib) {
upypy.handler = dlopen(upypy.lib, RTLD_NOW | RTLD_GLOBAL);
}
else {
if (upypy.home) {
#ifdef __APPLE__
#ifdef __CYGWIN__
char *libpath = uwsgi_concat2(upypy.home, "/libpypy-c.dll");
#elif defined(__APPLE__)
char *libpath = uwsgi_concat2(upypy.home, "/libpypy-c.dylib");
#else
char *libpath = uwsgi_concat2(upypy.home, "/libpypy-c.so");
@@ -69,7 +75,9 @@ static int uwsgi_pypy_init() {
}
// fallback to standard library search path
if (!upypy.handler) {
#ifdef __APPLE__
#ifdef __CYGWIN__
upypy.handler = dlopen("libpypy-c.dll", RTLD_NOW | RTLD_GLOBAL);
#elif defined(__APPLE__)
upypy.handler = dlopen("libpypy-c.dylib", RTLD_NOW | RTLD_GLOBAL);
#else
upypy.handler = dlopen("libpypy-c.so", RTLD_NOW | RTLD_GLOBAL);
@@ -82,35 +90,24 @@ static int uwsgi_pypy_init() {
exit(1);
}
rpython_startup_code = dlsym(upypy.handler, "rpython_startup_code");
if (!rpython_startup_code) {
u_rpython_startup_code = dlsym(upypy.handler, "rpython_startup_code");
if (!u_rpython_startup_code) {
uwsgi_log("unable to find rpython_startup_code() symbol\n");
exit(1);
}
pypy_setup_home = dlsym(upypy.handler, "pypy_setup_home");
if (!pypy_setup_home) {
u_pypy_setup_home = dlsym(upypy.handler, "pypy_setup_home");
if (!u_pypy_setup_home) {
uwsgi_log("unable to find pypy_setup_home() symbol\n");
exit(1);
}
pypy_execute_source = dlsym(upypy.handler, "pypy_execute_source");
if (!pypy_execute_source) {
uwsgi_log("unable to find pypy_execute_source() symbol\n");
exit(1);
}
pypy_thread_attach = dlsym(upypy.handler, "pypy_thread_attach");
if (!pypy_thread_attach) {
uwsgi_log("!!! WARNING your libpypy-c does not export pypy_thread_attach, multithreading will not work !!!\n");
}
pypy_init_threads = dlsym(upypy.handler, "pypy_init_threads");
if (!pypy_init_threads) {
u_pypy_init_threads = dlsym(upypy.handler, "pypy_init_threads");
if (!u_pypy_init_threads) {
uwsgi_log("!!! WARNING your libpypy-c does not export pypy_init_threads, multithreading will not work !!!\n");
}
rpython_startup_code();
u_rpython_startup_code();
if (!upypy.home) {
upypy.home = getenv("PYPY_HOME");
@@ -120,11 +117,11 @@ static int uwsgi_pypy_init() {
}
}
if (pypy_setup_home(upypy.home, 0)) {
if (u_pypy_setup_home(upypy.home, 0)) {
char *retry = uwsgi_concat2(upypy.home, "/lib_pypy");
if (uwsgi_is_dir(retry)) {
// this time we use debug
if (!pypy_setup_home(retry, 1)) {
if (!u_pypy_setup_home(retry, 1)) {
free(retry);
goto ready;
}
@@ -134,12 +131,29 @@ static int uwsgi_pypy_init() {
}
ready:
u_pypy_execute_source = dlsym(upypy.handler, "pypy_execute_source");
if (!u_pypy_execute_source) {
uwsgi_log("unable to find pypy_execute_source() symbol\n");
exit(1);
}
u_pypy_thread_attach = dlsym(upypy.handler, "pypy_thread_attach");
if (!u_pypy_thread_attach) {
uwsgi_log("!!! WARNING your libpypy-c does not export pypy_thread_attach, multithreading will not work !!!\n");
}
if (upypy.setup) {
buffer = uwsgi_open_and_read(upypy.setup, &rlen, 1, NULL);
}
else {
char *start = dlsym(RTLD_DEFAULT, "uwsgi_pypy_setup_start");
if (!start) {
start = dlsym(RTLD_DEFAULT, "_uwsgi_pypy_setup_start");
}
char *end = dlsym(RTLD_DEFAULT, "uwsgi_pypy_setup_end");
if (!end) {
end = dlsym(RTLD_DEFAULT, "_uwsgi_pypy_setup_end");
}
if (start && end) {
buffer = uwsgi_concat2n(start, end-start, "", 0);
}
@@ -149,7 +163,7 @@ ready:
uwsgi_log("you have to load a pypy setup file with --pypy-setup\n");
exit(1);
}
if (pypy_execute_source(buffer)) {
if (u_pypy_execute_source(buffer)) {
exit(1);
}
free(buffer);
@@ -170,7 +184,7 @@ static void uwsgi_pypy_preinit_apps() {
struct uwsgi_string_list *usl = upypy.eval;
while(usl) {
if (pypy_execute_source(usl->value)) {
if (u_pypy_execute_source(usl->value)) {
exit(1);
}
usl = usl->next;
@@ -180,7 +194,7 @@ static void uwsgi_pypy_preinit_apps() {
while(usl) {
size_t rlen = 0;
char *buffer = uwsgi_open_and_read(usl->value, &rlen, 1, NULL);
if (pypy_execute_source(buffer)) {
if (u_pypy_execute_source(buffer)) {
exit(1);
}
free(buffer);
@@ -243,14 +257,14 @@ static struct uwsgi_option uwsgi_pypy_options[] = {
};
static void uwsgi_pypy_enable_threads() {
if (pypy_init_threads) {
pypy_init_threads();
if (u_pypy_init_threads) {
u_pypy_init_threads();
}
}
static void uwsgi_pypy_init_thread() {
if (pypy_thread_attach) {
pypy_thread_attach();
if (u_pypy_thread_attach) {
u_pypy_thread_attach();
}
}
@@ -274,7 +288,7 @@ static uint16_t uwsgi_pypy_rpc(void *func, uint8_t argc, char **argv, uint16_t a
static void uwsgi_pypy_post_fork() {
struct uwsgi_string_list *usl = upypy.eval_post_fork;
while(usl) {
if (pypy_execute_source(usl->value)) {
if (u_pypy_execute_source(usl->value)) {
exit(1);
}
usl = usl->next;
@@ -283,7 +297,7 @@ static void uwsgi_pypy_post_fork() {
while(usl) {
size_t rlen = 0;
char *buffer = uwsgi_open_and_read(usl->value, &rlen, 1, NULL);
if (pypy_execute_source(buffer)) {
if (u_pypy_execute_source(buffer)) {
exit(1);
}
free(buffer);
@@ -306,7 +320,7 @@ static int uwsgi_pypy_mule(char *opt) {
if (uwsgi_endswith(opt, ".py")) {
size_t rlen = 0;
char *buffer = uwsgi_open_and_read(opt, &rlen, 1, NULL);
pypy_execute_source(buffer);
u_pypy_execute_source(buffer);
free(buffer);
return 1;
}
+38 -4
View File
@@ -125,6 +125,20 @@ struct uwsgi_buffer {
...;
};
struct uwsgi_lock_item {
...;
};
struct uwsgi_cache {
struct uwsgi_lock_item *lock;
...;
};
struct uwsgi_cache_item {
uint64_t keysize;
...;
};
struct uwsgi_server {
char hostname[];
int mywid;
@@ -184,6 +198,11 @@ int uwsgi_cache_magic_set(char *, uint16_t, char *, uint64_t, uint64_t, uint64_t
int uwsgi_cache_magic_del(char *, uint16_t, char *);
int uwsgi_cache_magic_exists(char *, uint16_t, char *);
int uwsgi_cache_magic_clear(char *);
struct uwsgi_cache *uwsgi_cache_by_name(char *);
void uwsgi_cache_rlock(struct uwsgi_cache *);
void uwsgi_cache_rwunlock(struct uwsgi_cache *);
char *uwsgi_cache_item_key(struct uwsgi_cache_item *);
struct uwsgi_cache_item *uwsgi_cache_keys(struct uwsgi_cache *, uint64_t *, struct uwsgi_cache_item **);
int uwsgi_add_file_monitor(uint8_t, char *);
int uwsgi_add_timer(uint8_t, int);
@@ -244,8 +263,9 @@ it sucks, i will fix it in the near future...
"""
wsgi_application = None
sys.argv.insert(0, ffi.string(lib.uwsgi_binary_path()))
# fix argv if needed
if len(sys.argv) == 0:
sys.argv.insert(0, ffi.string(lib.uwsgi_binary_path()))
"""
@@ -332,7 +352,7 @@ class WSGIinput(object):
self.wsgi_req = wsgi_req
def read(self, size=0):
rlen = ffi.new('int64_t*')
rlen = ffi.new('ssize_t*')
chunk = lib.uwsgi_request_body_read(self.wsgi_req, size, rlen)
if chunk != ffi.NULL:
return ffi.string(chunk, rlen[0])
@@ -473,7 +493,6 @@ def uwsgi_pypy_uwsgi_register_rpc(name, func, argc=0):
rpc_func = uwsgi_pypy_RPC(func)
cb = ffi.callback("int(int, char*[], int[], char*)", rpc_func)
uwsgi_gc.append(cb)
print lib.pypy_plugin
if lib.uwsgi_register_rpc(ffi.new("char[]", name), ffi.addressof(lib.pypy_plugin), argc, cb) < 0:
raise Exception("unable to register rpc func %s" % name)
uwsgi.register_rpc = uwsgi_pypy_uwsgi_register_rpc
@@ -541,6 +560,21 @@ def uwsgi_pypy_uwsgi_cache_del(key, cache=ffi.NULL):
raise Exception('unable to delete item from the cache')
uwsgi.cache_del = uwsgi_pypy_uwsgi_cache_del
def uwsgi_pypy_uwsgi_cache_keys(cache=ffi.NULL):
uc = lib.uwsgi_cache_by_name(cache)
if uc == ffi.NULL:
raise Exception('no local uWSGI cache available')
l = []
lib.uwsgi_cache_rlock(uc)
pos = ffi.new('uint64_t *')
uci = ffi.new('struct uwsgi_cache_item **')
while True:
uci[0] = lib.uwsgi_cache_keys(uc, pos, uci)
if uci[0] == ffi.NULL: break
l.append(ffi.string(lib.uwsgi_cache_item_key(uci[0]), uci[0].keysize))
lib.uwsgi_cache_rwunlock(uc)
return l
uwsgi.cache_keys = uwsgi_pypy_uwsgi_cache_keys
def uwsgi_pypy_uwsgi_add_timer(signum, secs):
if lib.uwsgi_add_timer(signum, secs) < 0:
+1 -1
View File
@@ -2,7 +2,7 @@ NAME='pypy'
LDFLAGS = []
LIBS = []
GCC_LIST = ['pypy_plugin']
BINARY_LIST = [ ('uwsgi_pypy_setup','pypy_setup.py')]
BINARY_LIST = [ ('_uwsgi_pypy_setup','pypy_setup.py')]
CFLAGS = []
try:
import __pypy__
+9
View File
@@ -13,6 +13,15 @@ int PyFrame_GetLineNumber(PyFrameObject *frame) {
}
#endif
#ifdef PYTHREE
#undef PyString_AsString
static char *PyString_AsString(PyObject *o) {
PyObject *zero = PyUnicode_AsLatin1String(o);
if (!zero) return "";
return PyBytes_AsString(zero);
}
#endif
int uwsgi_python_profiler_call(PyObject *obj, PyFrameObject *frame, int what, PyObject *arg) {
static uint64_t last_ts = 0;
+46 -1
View File
@@ -607,6 +607,52 @@ PyObject *uwsgi_file_loader(void *arg1) {
}
PyObject *uwsgi_pecan_loader(void *arg1) {
char *pecan = (char *) arg1;
PyObject *pecan_module, *pecan_dict, *pecan_deploy;
PyObject *pecan_arg, *pecan_app;
uwsgi_log( "Loading pecan environment: %s\n", pecan);
pecan_module = PyImport_ImportModule("pecan.deploy");
if (!pecan_module) {
PyErr_Print();
exit(UWSGI_FAILED_APP_CODE);
}
pecan_dict = PyModule_GetDict(pecan_module);
if (!pecan_dict) {
PyErr_Print();
exit(UWSGI_FAILED_APP_CODE);
}
pecan_deploy = PyDict_GetItemString(pecan_dict, "deploy");
if (!pecan_deploy) {
PyErr_Print();
exit(UWSGI_FAILED_APP_CODE);
}
pecan_arg = PyTuple_New(1);
if (!pecan_arg) {
PyErr_Print();
exit(UWSGI_FAILED_APP_CODE);
}
if (PyTuple_SetItem(pecan_arg, 0, UWSGI_PYFROMSTRING(pecan))) {
PyErr_Print();
exit(UWSGI_FAILED_APP_CODE);
}
pecan_app = PyEval_CallObject(pecan_deploy, pecan_arg);
if (!pecan_app) {
PyErr_Print();
exit(UWSGI_FAILED_APP_CODE);
}
return pecan_app;
}
PyObject *uwsgi_paste_loader(void *arg1) {
char *paste = (char *) arg1;
@@ -668,7 +714,6 @@ PyObject *uwsgi_paste_loader(void *arg1) {
exit(UWSGI_FAILED_APP_CODE);
}
return paste_app;
}
+7
View File
@@ -121,6 +121,9 @@ struct uwsgi_option uwsgi_python_options[] = {
{"pyargv", required_argument, 0, "manually set sys.argv", uwsgi_opt_set_str, &up.argv, 0},
{"optimize", required_argument, 'O', "set python optimization level", uwsgi_opt_set_int, &up.optimize, 0},
{"pecan", required_argument, 0, "load a pecan config file", uwsgi_opt_set_str, &up.pecan, 0},
{"paste", required_argument, 0, "load a paste.deploy config file", uwsgi_opt_set_str, &up.paste, 0},
{"paste-logger", no_argument, 0, "enable paste fileConfig logger", uwsgi_opt_true, &up.paste_logger, 0},
@@ -1058,6 +1061,7 @@ void uwsgi_python_init_apps() {
up.loaders[LOADER_DYN] = uwsgi_dyn_loader;
up.loaders[LOADER_UWSGI] = uwsgi_uwsgi_loader;
up.loaders[LOADER_FILE] = uwsgi_file_loader;
up.loaders[LOADER_PECAN] = uwsgi_pecan_loader;
up.loaders[LOADER_PASTE] = uwsgi_paste_loader;
up.loaders[LOADER_EVAL] = uwsgi_eval_loader;
up.loaders[LOADER_MOUNT] = uwsgi_mount_loader;
@@ -1123,6 +1127,9 @@ next:
if (up.file_config != NULL) {
init_uwsgi_app(LOADER_FILE, up.file_config, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI);
}
if (up.pecan != NULL) {
init_uwsgi_app(LOADER_PECAN, up.pecan, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI);
}
if (up.paste != NULL) {
init_uwsgi_app(LOADER_PASTE, up.paste, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI);
}
+58
View File
@@ -27,9 +27,20 @@ char *uwsgi_python_get_exception_type(PyObject *exc) {
PyObject *module_name = PyObject_GetAttrString(exc, "__module__");
if (module_name) {
#ifdef PYTHREE
char *mod_name = NULL;
PyObject *zero = PyUnicode_AsUTF8String(module_name);
if (zero) {
mod_name = PyString_AsString(zero);
}
#else
char *mod_name = PyString_AsString(module_name);
#endif
if (mod_name && strcmp(mod_name, "exceptions") ) {
char *ret = uwsgi_concat3(mod_name, ".", class_name);
#ifdef PYTHREE
Py_DECREF(zero);
#endif
Py_DECREF(module_name);
return ret;
}
@@ -81,6 +92,38 @@ struct uwsgi_buffer *uwsgi_python_backtrace(struct wsgi_request *wsgi_req) {
int64_t line_no = PyInt_AsLong(tb_lineno);
#ifdef PYTHREE
PyObject *zero = PyUnicode_AsUTF8String(tb_filename);
if (!zero) goto end0;
// filename
if (uwsgi_buffer_u16le(ub, PyString_Size(zero))) { Py_DECREF(zero); goto end0; }
if (uwsgi_buffer_append(ub, PyString_AsString(zero), PyString_Size(zero))) { Py_DECREF(zero); goto end0; }
Py_DECREF(zero);
// lineno
if (uwsgi_buffer_append_valnum(ub, line_no)) goto end0;
zero = PyUnicode_AsUTF8String(tb_function);
if (!zero) goto end0;
// function
if (uwsgi_buffer_u16le(ub, PyString_Size(zero))) { Py_DECREF(zero); goto end0; }
if (uwsgi_buffer_append(ub, PyString_AsString(zero), PyString_Size(zero))) { Py_DECREF(zero); goto end0; }
Py_DECREF(zero);
zero = PyUnicode_AsUTF8String(tb_text);
if (!zero) goto end0;
// text
if (uwsgi_buffer_u16le(ub, PyString_Size(zero))) { Py_DECREF(zero); goto end0; }
if (uwsgi_buffer_append(ub, PyString_AsString(zero), PyString_Size(zero))) { Py_DECREF(zero); goto end0; }
Py_DECREF(zero);
#else
// filename
if (uwsgi_buffer_u16le(ub, PyString_Size(tb_filename))) goto end0;
if (uwsgi_buffer_append(ub, PyString_AsString(tb_filename), PyString_Size(tb_filename))) goto end0;
@@ -95,6 +138,7 @@ struct uwsgi_buffer *uwsgi_python_backtrace(struct wsgi_request *wsgi_req) {
// text
if (uwsgi_buffer_u16le(ub, PyString_Size(tb_text))) goto end0;
if (uwsgi_buffer_append(ub, PyString_AsString(tb_text), PyString_Size(tb_text))) goto end0;
#endif
// custom (unused)
if (uwsgi_buffer_u16le(ub, 0)) goto end0;
@@ -152,15 +196,29 @@ struct uwsgi_buffer *uwsgi_python_exception_msg(struct wsgi_request *wsgi_req) {
// value could be NULL ?
if (!value) goto end;
#ifdef PYTHREE
char *msg = NULL;
PyObject *zero = PyUnicode_AsUTF8String( PyObject_Str(value) );
if (zero) {
msg = PyString_AsString( zero );
}
#else
char *msg = PyString_AsString( PyObject_Str(value) );
#endif
if (msg) {
size_t msg_len = strlen(msg);
ub = uwsgi_buffer_new(msg_len);
if (uwsgi_buffer_append(ub, msg, msg_len)) {
#ifdef PYTHREE
Py_DECREF(zero);
#endif
uwsgi_buffer_destroy(ub);
ub = NULL;
goto end;
}
#ifdef PYTHREE
Py_DECREF(zero);
#endif
}
end:
PyErr_Restore(type, value, traceback);
+38
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");
}
@@ -1805,6 +1808,7 @@ PyObject *py_uwsgi_send_spool(PyObject * self, PyObject * args, PyObject *kw) {
if (PyString_Check(pybody)) {
body = PyString_AsString(pybody);
body_len = PyString_Size(pybody);
Py_INCREF(pybody);
uwsgi_py_dict_del(spool_dict, "body");
}
}
@@ -1896,6 +1900,10 @@ PyObject *py_uwsgi_send_spool(PyObject * self, PyObject * args, PyObject *kw) {
i = spool_request(uspool, spool_filename, uwsgi.workers[0].requests + 1, async_id, spool_buffer, cur_buf - spool_buffer, priority, at, body, body_len);
UWSGI_GET_GIL
if (pybody) {
Py_DECREF(pybody);
}
if (priority) {
free(priority);
@@ -3104,6 +3112,35 @@ PyObject *py_uwsgi_cache_num(PyObject * self, PyObject * args) {
}
PyObject *py_uwsgi_cache_keys(PyObject * self, PyObject * args) {
char *cache = NULL;
struct uwsgi_cache_item *uci = NULL;
uint64_t pos = 0;
if (!PyArg_ParseTuple(args, "|s:cache_keys", &cache)) {
return NULL;
}
struct uwsgi_cache *uc = uwsgi_cache_by_name(cache);
if (!uc) {
return PyErr_Format(PyExc_ValueError, "no local uWSGI cache available");
}
PyObject *l = PyList_New(0);
uwsgi_rlock(uc->lock);
for(;;) {
uci = uwsgi_cache_keys(uc, &pos, &uci);
if (!uci) break;
PyObject *ci = PyString_FromStringAndSize(uci->key, uci->keysize);
PyList_Append(l, ci);
Py_DECREF(ci);
}
uwsgi_rwunlock(uc->lock);
return l;
}
static PyMethodDef uwsgi_cache_methods[] = {
{"cache_get", py_uwsgi_cache_get, METH_VARARGS, ""},
{"cache_set", py_uwsgi_cache_set, METH_VARARGS, ""},
@@ -3116,6 +3153,7 @@ static PyMethodDef uwsgi_cache_methods[] = {
{"cache_mul", py_uwsgi_cache_mul, METH_VARARGS, ""},
{"cache_div", py_uwsgi_cache_div, METH_VARARGS, ""},
{"cache_num", py_uwsgi_cache_num, METH_VARARGS, ""},
{"cache_keys", py_uwsgi_cache_keys, METH_VARARGS, ""},
{NULL, NULL},
};
+5 -1
View File
@@ -81,8 +81,9 @@ PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromString(char *, Py_ssize_t);
#define LOADER_CALLABLE 5
#define LOADER_STRING_CALLABLE 6
#define LOADER_MOUNT 7
#define LOADER_PECAN 8
#define LOADER_MAX 8
#define LOADER_MAX 9
typedef struct uwsgi_Input {
PyObject_HEAD
@@ -124,6 +125,8 @@ struct uwsgi_python {
PyObject *loader_dict;
PyObject* (*loaders[LOADER_MAX]) (void *);
char *pecan;
char *wsgi_config;
char *file_config;
char *paste;
@@ -218,6 +221,7 @@ PyObject *uwsgi_uwsgi_loader(void *);
PyObject *uwsgi_dyn_loader(void *);
PyObject *uwsgi_file_loader(void *);
PyObject *uwsgi_eval_loader(void *);
PyObject *uwsgi_pecan_loader(void *);
PyObject *uwsgi_paste_loader(void *);
PyObject *uwsgi_callable_loader(void *);
PyObject *uwsgi_string_callable_loader(void *);
+3
View File
@@ -468,6 +468,9 @@ PyObject *py_uwsgi_sendfile(PyObject * self, PyObject * args) {
#ifdef PYTHREE
wsgi_req->sendfile_fd = PyObject_AsFileDescriptor(wsgi_req->async_sendfile);
if (wsgi_req->sendfile_fd >= 0) {
Py_INCREF((PyObject *)wsgi_req->async_sendfile);
}
#else
if (PyFile_Check((PyObject *)wsgi_req->async_sendfile)) {
Py_INCREF((PyObject *)wsgi_req->async_sendfile);
+46 -6
View File
@@ -28,6 +28,11 @@ struct uwsgi_option uwsgi_rack_options[] = {
{"ruby-gc-freq", required_argument, 0, "set ruby GC frequency", uwsgi_opt_set_int, &ur.gc_freq, 0},
{"rb-gc-freq", required_argument, 0, "set ruby GC frequency", uwsgi_opt_set_int, &ur.gc_freq, 0},
#ifdef RUBY19
{"rb-lib", required_argument, 0, "add a directory to the ruby libdir search path", uwsgi_opt_add_string_list, &ur.libdir, 0},
{"ruby-lib", required_argument, 0, "add a directory to the ruby libdir search path", uwsgi_opt_add_string_list, &ur.libdir, 0},
#endif
{"rb-require", required_argument, 0, "import/require a ruby module/script", uwsgi_opt_add_string_list, &ur.rbrequire, 0},
{"ruby-require", required_argument, 0, "import/require a ruby module/script", uwsgi_opt_add_string_list, &ur.rbrequire, 0},
{"rbrequire", required_argument, 0, "import/require a ruby module/script", uwsgi_opt_add_string_list, &ur.rbrequire, 0},
@@ -456,9 +461,9 @@ static void rack_hack_dollar_zero(VALUE name, ID id) {
int uwsgi_rack_init(){
#ifdef RUBY19
int argc = 2;
char *sargv[] = { (char *) "uwsgi", (char *) "-e0" };
char **argv = sargv;
int argc = 2;
char *sargv[] = { (char *) "uwsgi", (char *) "-e0" };
char **argv = sargv;
#endif
if (ur.gemset) {
@@ -467,13 +472,37 @@ int uwsgi_rack_init(){
#ifdef RUBY19
ruby_sysinit(&argc, &argv);
RUBY_INIT_STACK
RUBY_INIT_STACK
#ifdef UWSGI_RUBY_HEROKU
uwsgi_log("*** Heroku system detected ***\n");
#endif
#ifdef RUBY_EXEC_PREFIX
if (!strcmp(RUBY_EXEC_PREFIX, "")) {
uwsgi_log("*** detected a ruby vm built with --enable-load-relative ***\n");
uwsgi_log("*** if you get errors about rubygems.rb, you can:\n");
uwsgi_log("*** 1) add a directory to the libdir search path using --ruby-libdir ***\n");
uwsgi_log("*** 2) force the RUBY_EXEC_PREFIX with --chdir ***\n");
#ifdef UWSGI_RUBY_LIBDIR
uwsgi_string_new_list(&ur.libdir, UWSGI_RUBY_LIBDIR);
#endif
#ifdef UWSGI_RUBY_ARCHDIR
uwsgi_string_new_list(&ur.libdir, UWSGI_RUBY_ARCHDIR);
#endif
}
#endif
ruby_init();
ruby_process_options(argc, argv);
struct uwsgi_string_list *usl = ur.libdir;
while(usl) {
ruby_incpush(usl->value);
uwsgi_log("[ruby-libdir] pushed %s\n", usl->value);
usl = usl->next;
}
ruby_options(argc, argv);
#else
ruby_init();
ruby_init_loadpath();
#endif
ruby_show_version();
ruby_script("uwsgi");
@@ -487,7 +516,6 @@ int uwsgi_rack_init(){
rb_gc_register_address(&ur.signals_protector);
rb_gc_register_address(&ur.rpc_protector);
uwsgi_rack_init_api();
return 0;
@@ -790,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++) {
+1
View File
@@ -54,6 +54,7 @@ struct uwsgi_rack {
char *gemset;
struct uwsgi_string_list *libdir;
};
void uwsgi_rack_init_api(void);
+14
View File
@@ -47,5 +47,19 @@ if has_shared == 'yes':
os.environ['LD_RUN_PATH'] = libpath
LIBS.append(os.popen(RUBYPATH + " -e \"require 'rbconfig';print '-l' + %s::CONFIG['RUBY_SO_NAME']\"" % rbconfig).read().rstrip())
else:
rubylibdir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print RbConfig::CONFIG['rubylibdir']\"").read().rstrip()
rubyarchdir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print RbConfig::CONFIG['archdir']\"").read().rstrip()
# detect Heroku system
heroku = False
if rubylibdir.startswith('/tmp/build_'):
heroku = True
rubylibdir = '/app/' + '/'.join(rubylibdir.split('/')[3:])
if rubyarchdir.startswith('/tmp/build_'):
heroku = True
rubyarchdir = '/app/' + '/'.join(rubyarchdir.split('/')[3:])
if heroku:
CFLAGS.append('-DUWSGI_RUBY_HEROKU')
CFLAGS.append('-DUWSGI_RUBY_LIBDIR="\\"%s\\""' % rubylibdir)
CFLAGS.append('-DUWSGI_RUBY_ARCHDIR="\\"%s\\""' % rubyarchdir)
GCC_LIST.append("%s/%s" % (libpath, os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['LIBRUBY_A']\"" % rbconfig).read().rstrip()))
+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;
+125
View File
@@ -0,0 +1,125 @@
#include <uwsgi.h>
#ifdef UWSGI_ROUTING
extern struct uwsgi_server uwsgi;
/*
by Unbit
syntax:
route = /^foobar1(.*)/ expires:filename=foo$1poo,value=30
route = /^foobar1(.*)/ expires:unix=${time[unix]},value=30
*/
struct uwsgi_router_expires_conf {
char *filename;
size_t filename_len;
char *unixt;
size_t unixt_len;
char *value;
size_t value_len;
};
static int uwsgi_routing_func_expires(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_router_expires_conf *urec = (struct uwsgi_router_expires_conf *) ur->data2;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
uint64_t expires = 0;
if (urec->filename) {
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urec->filename, urec->filename_len);
if (!ub) return UWSGI_ROUTE_BREAK;
struct stat st;
if (stat(ub->buf, &st)) {
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_BREAK;
}
expires = st.st_mtime;
uwsgi_buffer_destroy(ub);
}
else if (urec->unixt) {
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urec->unixt, urec->unixt_len);
if (!ub) return UWSGI_ROUTE_BREAK;
expires = strtoul(ub->buf, NULL, 10);
uwsgi_buffer_destroy(ub);
}
if (urec->value) {
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urec->value, urec->value_len);
if (!ub) return UWSGI_ROUTE_BREAK;
expires += atoi(ub->buf);
uwsgi_buffer_destroy(ub);
}
char expires_str[7 + 2 + 31];
int len = uwsgi_http_date((time_t) expires, expires_str + 9);
if (!len) return UWSGI_ROUTE_BREAK;
memcpy(expires_str, "Expires: ", 9);
uwsgi_additional_header_add(wsgi_req, expires_str, 9 + len);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_expires(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_expires;
ur->data = args;
ur->data_len = strlen(args);
struct uwsgi_router_expires_conf *urec = uwsgi_calloc(sizeof(struct uwsgi_router_expires_conf));
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
"filename", &urec->filename,
"file", &urec->filename,
"unix", &urec->unixt,
"value", &urec->value,
NULL)) {
uwsgi_log("invalid route syntax: %s\n", args);
exit(1);
}
if (urec->filename) {
urec->filename_len = strlen(urec->filename);
}
if (urec->unixt) {
urec->unixt_len = strlen(urec->unixt);
}
if (urec->value) {
urec->value_len = strlen(urec->value);
}
ur->data2 = urec;
return 0;
}
static void router_expires_register() {
uwsgi_register_router("expires", uwsgi_router_expires);
}
struct uwsgi_plugin router_expires_plugin = {
.name = "router_expires",
.on_load = router_expires_register,
};
#else
struct uwsgi_plugin router_expires_plugin = {
.name = "router_expires",
};
#endif
+6
View File
@@ -0,0 +1,6 @@
NAME='router_expires'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['expires']
+9 -2
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");
@@ -73,7 +80,7 @@ ssize_t uwsgi_rsyslog_logger(struct uwsgi_logger *ul, char *message, size_t len)
// drop newline
if (message[len-1] == '\n') len--;
#ifdef __sun__
#if defined(__sun__) && !defined(__clang__)
ctime_r(&current_time, ctime_storage, 26);
#else
ctime_r(&current_time, ctime_storage);
@@ -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);
View File
View File
View File
+17 -17
View File
@@ -3,11 +3,11 @@ import uwsgi
import time
def application(env, sr):
ws_scheme = 'ws'
if 'HTTPS' in env or env['wsgi.url_scheme'] == 'https':
ws_scheme = 'wss'
if env['PATH_INFO'] == '/':
sr('200 OK', [('Content-Type','text/html')])
return """
@@ -20,19 +20,19 @@ def application(env, sr):
s.send("ciao");
};
s.onmessage = function(e) {
var bb = document.getElementById('blackboard')
var html = bb.innerHTML;
bb.innerHTML = html + '<br/>' + e.data;
var bb = document.getElementById('blackboard')
var html = bb.innerHTML;
bb.innerHTML = html + '<br/>' + e.data;
};
s.onerror = function(e) {
alert(e);
}
s.onclose = function(e) {
alert("connection closed");
}
s.onerror = function(e) {
alert(e);
}
s.onclose = function(e) {
alert("connection closed");
}
function invia() {
var value = document.getElementById('testo').value;
s.send(value);
@@ -43,13 +43,13 @@ def application(env, sr):
<h1>WebSocket</h1>
<input type="text" id="testo"/>
<input type="button" value="invia" onClick="invia();"/>
<div id="blackboard" style="width:640px;height:480px;background-color:black;color:white;border: solid 2px red;overflow:auto">
</div>
<div id="blackboard" style="width:640px;height:480px;background-color:black;color:white;border: solid 2px red;overflow:auto">
</div>
</body>
</html>
""" % (ws_scheme, env['HTTP_HOST'])
elif env['PATH_INFO'] == '/foobar/':
uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', ''))
uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', ''))
print "websockets..."
while True:
msg = uwsgi.websocket_recv()
-45
View File
@@ -1,45 +0,0 @@
#!./uwsgi
import uwsgi
from bottle import route, default_app, request, response, redirect
@route('/')
def chat():
return """<iframe src="/recv"></iframe>
<iframe src="/sender"></iframe>"""
@route('/sender')
def sender():
return """<form method="GET" action="/send">
<textarea name="message"></textarea><br/>
<input type="submit" value="send" />
</form>"""
@route('/recv')
def recv():
response.header['Transfer-Encoding'] = 'chunked'
# this will flush headers
yield ""
running = True
while running:
# this will put the core in pause (for max 10 seconds) and remove it from the sched queue, so the /send can write to its socket
if not uwsgi.green_pause(10):
running = False
# this will maintain the connection opened if no data arrives
yield "<span/>"
@route('/send')
def send():
# this will write to all the core in PAUSED state
uwsgi.green_write_all(request.GET['message'] + "<br/>")
# this will unpause all the paused cores, so they will be re-inserted in the sched queue
uwsgi.green_unpause_all()
redirect('/sender')
application = default_app()
-76
View File
@@ -1,76 +0,0 @@
import uuid
import uwsgi
import os
def application(env, start_response):
print(env.__class__)
print(env['PATH_INFO'])
print(env['REQUEST_METHOD'])
print(env['wsgi.input'])
if env['PATH_INFO'].startswith('/progress/'):
start_response('200 Ok', [('Content-type', 'application/json')])
filename = 'foobar/' + env['PATH_INFO'][10:]
print filename
if os.path.exists(filename):
return uwsgi.sendfile(filename)
else:
return "{ 'state': 'done' }"
if env['REQUEST_METHOD'] == 'POST':
start_response('200 Ok', [('Content-type', 'text/plain')])
#for x in env['wsgi.input']:
# yield x
body = env['wsgi.input'].read(int(env['CONTENT_LENGTH']))
body += env['wsgi.input'].readline()
#print body
body += env['wsgi.input'].read(100)
body += env['wsgi.input'].read(100)
body += env['wsgi.input'].read()
return body
else:
start_response('200 Ok', [('Content-type', 'text/html')])
x_progress_id = str(uuid.uuid4())
return """
<html>
<head>
<script src="/static/jquery-1.5.1.min.js" /></script>
<script language="Javascript">
var interval;
function redrawProgressBar() {
interval = setInterval(getData, 1000);
}
function getData() {
var jsr = $.getJSON("/progress/%s.js",
function(data) {
if (data) {
if (data.state == 'uploading') {
$('#progress').html(data.received + '/' + data.size);
return;
}
}
alert("fine");
clearInterval(interval);
}
);
jsr.error(function() { clearInterval(interval); });
}
</script>
</head>
<body>
upload progress: <div id="progress"> 0%%</div>
<form method="POST" enctype="multipart/form-data" action="?X-Progress-ID=%s" onsubmit="redrawProgressBar(); return true;">
<textarea name="pluto">
</textarea>
<input type="file" name="pippo" />
<input type="submit" value="invia" />
</form>
</body>
</html>
""" % (x_progress_id, x_progress_id)
+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-07-21'
s.date = '2013-09-14'
s.summary = "uWSGI"
s.description = "The uWSGI server for Ruby/Rack"
s.authors = ["Unbit"]
+185 -5
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__);
@@ -130,6 +130,7 @@ extern "C" {
uwsgi.gp_cnt++;\
}\
#define uwsgi_foreach(x, y) for(x=y;x;x = x->next)
#ifndef __need_IOV_MAX
@@ -137,9 +138,13 @@ extern "C" {
#endif
#ifdef __sun__
#ifndef _XPG4_2
#define _XPG4_2
#endif
#ifndef __EXTENSIONS__
#define __EXTENSIONS__
#endif
#endif
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
@@ -165,6 +170,7 @@ extern "C" {
#endif
#endif
#include <sys/socket.h>
#include <net/if.h>
#ifdef __linux__
#ifndef MSG_FASTOPEN
#define MSG_FASTOPEN 0x20000000
@@ -193,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>
@@ -223,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
@@ -437,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 {
@@ -547,6 +569,7 @@ struct uwsgi_daemon {
int status;
int registered;
int has_daemonized;
char *pidfile;
int daemonize;
@@ -609,6 +632,8 @@ struct uwsgi_legion {
int quorum;
int changed;
// if set the next packet will be a death-announce
int dead;
// set to 1 first time when quorum is reached
int joined;
@@ -845,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
@@ -926,6 +952,9 @@ struct uwsgi_socket {
int lazy;
int shared;
int from_shared;
// used for avoiding vacuum mess
ino_t inode;
};
struct uwsgi_server;
@@ -974,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 *);
@@ -1222,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;
@@ -1454,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;
@@ -1561,12 +1604,17 @@ void uwsgi_opt_load_config(char *, char *, void *);
#define uwsgi_instance_is_dying (uwsgi.status.gracefully_destroying || uwsgi.status.brutally_destroying)
#define uwsgi_instance_is_reloading (uwsgi.status.gracefully_reloading || uwsgi.status.brutally_reloading)
#define exit(x) uwsgi_exit(x)
struct uwsgi_server {
// store the machine hostname
char hostname[256];
int hostname_len;
// used to store the exit code for atexit hooks
int last_exit_code;
int (*proto_hooks[UWSGI_PROTO_MAX_CHECK]) (struct wsgi_request *, char *, char *, uint16_t);
struct uwsgi_configurator *configurators;
@@ -1632,9 +1680,16 @@ 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;
// force the first gateway without a master
int force_gateway;
// disable fd passing on unix socket
int no_fd_passing;
@@ -1671,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;
@@ -1724,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;
@@ -1752,6 +1812,8 @@ struct uwsgi_server {
int dump_options;
// show ini representation of the current config
int show_config;
// enable strict mode (only registered options can be used)
int strict;
// list loaded features
int cheaper_algo_list;
@@ -1783,6 +1845,7 @@ struct uwsgi_server {
char *uidname;
char *gidname;
int no_initgroups;
struct uwsgi_string_list *additional_gids;
#ifdef UWSGI_CAP
cap_value_t *cap;
@@ -1791,8 +1854,24 @@ 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;
uint64_t write_errors_tolerance;
@@ -1809,8 +1888,9 @@ struct uwsgi_server {
// mostly useless
char *mode;
// binary path the worker image
// binary patch the worker image
char *worker_exec;
char *worker_exec2;
// this must be UN-shared
struct uwsgi_gateway_socket *gateway_sockets;
@@ -1853,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;
@@ -1868,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;
@@ -1877,6 +1974,46 @@ struct uwsgi_server {
struct uwsgi_string_list *exec_pre_app;
struct uwsgi_string_list *exec_post_app;
struct uwsgi_string_list *exec_as_vassal;
struct uwsgi_string_list *exec_as_emperor;
struct uwsgi_string_list *call_pre_jail;
struct uwsgi_string_list *call_post_jail;
struct uwsgi_string_list *call_in_jail;
struct uwsgi_string_list *call_as_root;
struct uwsgi_string_list *call_as_user;
struct uwsgi_string_list *call_as_user_atexit;
struct uwsgi_string_list *call_pre_app;
struct uwsgi_string_list *call_post_app;
struct uwsgi_string_list *call_as_vassal;
struct uwsgi_string_list *call_as_vassal1;
struct uwsgi_string_list *call_as_vassal3;
struct uwsgi_string_list *call_as_emperor;
struct uwsgi_string_list *call_as_emperor1;
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;
char *privileged_binary_patch;
char *unprivileged_binary_patch;
char *privileged_binary_patch_arg;
@@ -1888,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;
@@ -1979,6 +2120,7 @@ struct uwsgi_server {
struct uwsgi_thread **offload_thread;
int check_static_docroot;
int disable_sendfile;
char *daemonize;
char *daemonize2;
@@ -2160,13 +2302,14 @@ struct uwsgi_server {
mode_t chmod_logfile_value;
int listen_queue;
char *file_config;
char *fallback_config;
#ifdef UWSGI_ROUTING
struct uwsgi_router *routers;
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
@@ -2180,8 +2323,10 @@ struct uwsgi_server {
int skip_zero;
int skip_atexit;
char *force_cwd;
char *chdir;
char *chdir2;
struct uwsgi_string_list *binsh;
int vacuum;
int no_server;
@@ -2308,6 +2453,7 @@ struct uwsgi_server {
int locks;
int persistent_ipcsem;
struct uwsgi_lock_item *queue_lock;
struct uwsgi_lock_item **user_lock;
@@ -3109,6 +3255,8 @@ void uwsgi_add_sockets_to_queue(int, int);
void uwsgi_del_sockets_from_queue(int);
int uwsgi_run_command_and_wait(char *, char *);
int uwsgi_run_command_putenv_and_wait(char *, char *, char **, unsigned int);
int uwsgi_call_symbol(char *);
void uwsgi_manage_signal_cron(time_t);
pid_t uwsgi_run_command(char *, int *, int);
@@ -3249,7 +3397,7 @@ int uwsgi_is_bad_connection(int);
int uwsgi_long2str2n(unsigned long long, char *, int);
#ifdef __linux__
void uwsgi_build_unshare(char *);
void uwsgi_build_unshare(char *, int *);
#ifdef MADV_MERGEABLE
void uwsgi_linux_ksm_map(void);
#endif
@@ -3410,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();
@@ -3456,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);
@@ -3700,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);
@@ -3872,6 +4024,7 @@ void uwsgi_opt_legion_hook(char *, char *, void *);
void uwsgi_legion_register_hook(struct uwsgi_legion *, char *, char *);
void uwsgi_opt_legion_scroll(char *, char *, void *);
void uwsgi_legion_add(struct uwsgi_legion *);
void uwsgi_legion_announce_death(void);
char *uwsgi_ssl_rand(size_t);
void uwsgi_start_legions(void);
int uwsgi_legion_announce(struct uwsgi_legion *);
@@ -4109,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);
@@ -4122,6 +4274,34 @@ int uwsgi_register_fsmon(struct uwsgi_string_list *);
int uwsgi_fsmon_event(int);
void uwsgi_fsmon_setup();
void uwsgi_exit(int) __attribute__ ((__noreturn__));
void uwsgi_fallback_config();
struct uwsgi_cache_item *uwsgi_cache_keys(struct uwsgi_cache *, uint64_t *, struct uwsgi_cache_item **);
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
+28 -10
View File
@@ -1,6 +1,6 @@
# uWSGI build system
uwsgi_version = '1.9.14'
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')
@@ -570,6 +570,14 @@ class uConf(object):
if additional_include_paths:
for ipath in additional_include_paths.split():
self.include_path.append(ipath)
if 'UWSGI_REMOVE_INCLUDES' in os.environ:
for inc in os.environ['UWSGI_REMOVE_INCLUDES'].split(','):
try:
self.include_path.remove(inc)
except:
pass
if not mute:
print("detected include path: %s" % self.include_path)
@@ -649,6 +657,10 @@ class uConf(object):
kvm_list = ['FreeBSD', 'OpenBSD', 'NetBSD', 'DragonFly']
if 'UWSGI_AS_LIB' in os.environ:
self.set('as_shared_library', 'true')
self.set('bin_name', os.environ['UWSGI_AS_LIB'])
if self.has_include('ifaddrs.h'):
self.cflags.append('-DUWSGI_HAS_IFADDRS')
report['ifaddrs'] = True
@@ -680,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'):
@@ -918,10 +931,11 @@ class uConf(object):
self.libs.append('-lcap')
report['capabilities'] = True
if self.has_include('matheval.h'):
self.cflags.append("-DUWSGI_MATHEVAL")
self.libs.append('-lmatheval')
report['matheval'] = True
if self.get('matheval'):
if (self.get('matheval') == 'auto' and self.has_include('matheval.h')) or self.get('matheval') == 'true':
self.cflags.append("-DUWSGI_MATHEVAL")
self.libs.append('-lmatheval')
report['matheval'] = True
has_json = False
has_uuid = False
@@ -938,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'):
@@ -1113,7 +1130,7 @@ class uConf(object):
report['xml'] = 'expat'
if self.get('plugin_dir'):
self.cflags.append('-DUWSGI_PLUGIN_DIR=\\"%s\\"' % self.get('plugin_dir'))
self.cflags.append('-DUWSGI_PLUGIN_DIR="\\"%s\\""' % self.get('plugin_dir'))
report['plugin_dir'] = self.get('plugin_dir')
if self.get('debug'):
@@ -1322,10 +1339,10 @@ if __name__ == "__main__":
bconf = os.environ.get('UWSGI_PROFILE','default.ini')
try:
bconf = sys.argv[3]
if not bconf.endswith('.ini'):
bconf += '.ini'
except:
pass
if not bconf.endswith('.ini'):
bconf += '.ini'
if not '/' in bconf:
bconf = 'buildconf/%s' % bconf
uc = uConf(bconf)
@@ -1350,6 +1367,7 @@ if __name__ == "__main__":
os.system("rm -f lib/*.o")
os.system("rm -f plugins/*/*.o")
os.system("rm -f build/*.o")
os.system("rm -f core/dot_h.c")
elif cmd == '--check':
os.system("cppcheck --max-configs=1000 --enable=all -q core/ plugins/ proto/ lib/ apache2/")
+15 -3
View File
@@ -49,7 +49,19 @@ uwsgi.post_fork_hook = postfork_chain_hook
class postfork(object):
def __init__(self, f):
postfork_chain.append(f)
if callable(f):
self.wid = 0
self.f = f
else:
self.f = None
self.wid = f
postfork_chain.append(self)
def __call__(self, *args, **kwargs):
if self.f:
if self.wid > 0 and self.wid != uwsgi.worker_id():
return
return self.f()
self.f = args[0]
class _spoolraw(object):
@@ -366,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