Compare commits

...
204 Commits
Author SHA1 Message Date
Unbit 50954d34db prepare for 1.9.17 2013-09-22 19:32:11 +02:00
Unbit ef2d9e781f implemented fifo slots and fixed chain reloading 2013-09-22 18:36:28 +02:00
Unbit a9bb310a20 various pty improvements 2013-09-19 11:21:10 +02:00
Unbit 86f37556da fixed logpipe 2013-09-19 11:08:28 +02:00
Unbit a57617c09a added fd: logger and routable log encoders 2013-09-19 06:41:09 +02:00
Unbit 63ac62cf1d allows ANSI sequences in config files via %[ 2013-09-19 05:55:20 +02:00
Unbit ac371730fd rename pypyuwsgi.py to pyuwsgi.py 2013-09-19 04:01:31 +02:00
Unbit 4ed6588c80 fixed #99 2013-09-19 03:59:15 +02:00
Unbit 81d20edc4c more cleanup 2013-09-19 03:55:27 +02:00
Unbit a9fc6adccf fixed #386 2013-09-19 03:41:23 +02:00
Unbit 21ad94ba4e implemented C fifo command 2013-09-18 17:40:02 +02:00
Unbit 571b9f27e1 added + and - fifo commands 2013-09-18 14:44:30 +02:00
Unbit cbf9ccf062 more brutal heartbeat emperor management 2013-09-18 12:03:35 +02:00
Unbit dd8fd8f19c implemented fifo command 'W' 2013-09-18 11:38:39 +02:00
Unbit 1535b8ee13 implemented graceful shutdown 2013-09-18 11:33:50 +02:00
Unbit f2491536dd implemented fifo command P 2013-09-18 11:20:55 +02:00
Unbit 88ce0181b3 added master fifo [2] 2013-09-18 11:16:15 +02:00
Unbit 4ad2658090 added master fifo 2013-09-18 11:08:56 +02:00
unbit 8d80c5e84d Merge pull request #388 from xtfxme/patch-1
pty.c: `--pty-exec` should have a `required_argument`
2013-09-17 23:49:29 -07:00
Unbit bae9235103 added the libtcc plugin (only for hooks) 2013-09-18 07:32:12 +02:00
C Anthony Risinger 8ae2d0d00c pty.c: --pty-exec should have a required_argument 2013-09-17 14:57:15 -05:00
Unbit 373b89e70c finally removed strtok() 2013-09-17 16:03:40 +02:00
Unbit c14e18b270 another round of strtok removals 2013-09-17 15:25:06 +02:00
Unbit 68ec3afd1a another round of strtok removal 2013-09-17 15:14:55 +02:00
Unbit 8918e81256 first attempt to change from strtok to strtok_r 2013-09-17 15:00:33 +02:00
Unbit 469fd697cb fixed #383 2013-09-17 14:16:41 +02:00
Unbit 20844ebfca Merge branch 'master' of github.com:unbit/uwsgi 2013-09-17 14:09:44 +02:00
Unbit 38652076d3 fixed #384 2013-09-17 14:09:00 +02:00
unbit f13ae47fc0 Merge pull request #382 from gdamjan/master
improve php build script
2013-09-16 05:17:39 -07:00
Damjan Georgievski ad4ee9d5c3 improve php build script
use UWSGICONFIG_PHPLIBDIR to specify the directory of the php library,
useful for Debian Wheezy which puts php5.so in /usr/lib/php5

small change: don't use exceptions for flow control
2013-09-16 12:49:14 +02:00
Unbit 03a4e900ea fixed #378 2013-09-16 11:50:37 +02:00
Unbit b52dbf2aa0 added forkptyrouter 2013-09-16 06:38:29 +02:00
Unbit c7a22c3b53 improved logpipe 2013-09-15 12:02:14 +02:00
unbit 775aae3f1e Merge pull request #380 from KLab/logpipe
Add pipe logger.
2013-09-15 03:09:53 -07:00
INADA Naoki 862731ba91 Add pipe logger. 2013-09-15 16:47:58 +09:00
Unbit 8c302eee51 start 1.9.17 now 2013-09-14 15:30:23 +02:00
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
127 changed files with 6344 additions and 737 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
+1 -1
View File
@@ -1,3 +1,3 @@
[uwsgi]
main_plugin = python,gevent,psgi,lua,php,rack,jvm,jwsgi,ring,mono,transformation_toupper,coroae,v8,cgi,xslt,webdav,ssi,ldap
main_plugin = python,gevent,psgi,lua,php,rack,jvm,jwsgi,ring,mono,transformation_toupper,coroae,v8,cgi,xslt,webdav,ssi,ldap,gccgo,rados
inherit = base
+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
View File
+2 -3
View File
@@ -184,8 +184,8 @@ static int uwsgi_alarm_log_add(char *alarms, char *regexp, int negate) {
// map instances to the log
char *list = uwsgi_str(alarms);
char *p = strtok(list, ",");
while (p) {
char *p, *ctx = NULL;
uwsgi_foreach_token(list, ",", p, ctx) {
struct uwsgi_alarm_instance *uai = uwsgi_alarm_get_instance(p);
if (!uai) {
free(list);
@@ -205,7 +205,6 @@ static int uwsgi_alarm_log_add(char *alarms, char *regexp, int negate) {
else {
ual->alarms = uall;
}
p = strtok(NULL, ",");
}
free(list);
return 0;
+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
+40 -9
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) {
@@ -1190,26 +1191,23 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
uc->store = c_store;
if (c_nodes) {
char *p = strtok(c_nodes, ";");
while(p) {
char *p, *ctx = NULL;
uwsgi_foreach_token(c_nodes, ";", p, ctx) {
uwsgi_string_new_list(&uc->nodes, p);
p = strtok(NULL, ";");
}
}
if (c_sync) {
char *p = strtok(c_sync, ";");
while(p) {
char *p, *ctx = NULL;
uwsgi_foreach_token(c_sync, ";", p, ctx) {
uwsgi_string_new_list(&uc->sync_nodes, p);
p = strtok(NULL, ";");
}
}
if (c_udp_servers) {
char *p = strtok(c_udp_servers, ";");
while(p) {
char *p, *ctx = NULL;
uwsgi_foreach_token(c_udp_servers, ";", p, ctx) {
uwsgi_string_new_list(&uc->udp_servers, p);
p = strtok(NULL, ";");
}
}
@@ -1920,3 +1918,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;
}
+19 -3
View File
@@ -55,10 +55,9 @@ int uwsgi_logic_opt_if_not_exists(char *key, char *value) {
int uwsgi_logic_opt_for(char *key, char *value) {
char *p = strtok(uwsgi.logic_opt_data, " ");
while (p) {
char *p, *ctx = NULL;
uwsgi_foreach_token(uwsgi.logic_opt_data, " ", p, ctx) {
add_exported_option(key, uwsgi_substitute(value, "%(_)", p), 0);
p = strtok(NULL, " ");
}
return 1;
@@ -458,6 +457,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;
+174 -18
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,25 @@ 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);
uct = uwsgi.vassals_includes;
while (uct) {
counter += 2;
uct = uct->next;
}
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) {
@@ -1009,6 +1099,15 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
counter += 2;
uct = uct->next;
}
uct = uwsgi.vassals_includes;
while (uct) {
vassal_argv[counter] = "--include";
vassal_argv[counter + 1] = uct->value;
counter += 2;
uct = uct->next;
}
vassal_argv[counter] = NULL;
// disable stdin OR map it to the "on demand" socket
@@ -1037,6 +1136,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 +1148,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 +1160,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 +1221,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) {
@@ -1369,10 +1521,14 @@ void emperor_loop() {
while (ui_current) {
if (ui_current->last_heartbeat > 0) {
if ((ui_current->last_heartbeat + uwsgi.emperor_heartbeat) < uwsgi_now()) {
uwsgi_log("[emperor] vassal %s sent no heartbeat in last %d seconds, respawning it...\n", ui_current->name, uwsgi.emperor_heartbeat);
uwsgi_log("[emperor] vassal %s sent no heartbeat in last %d seconds, brutally respawning it...\n", ui_current->name, uwsgi.emperor_heartbeat);
// set last_heartbeat to 0 avoiding races
ui_current->last_heartbeat = 0;
emperor_respawn(ui_current, uwsgi_now());
if (ui_current->pid > 0) {
if (kill(ui_current->pid, SIGKILL)) {
uwsgi_error("[emperor] kill()");
}
}
}
}
ui_current = ui_current->ui_next;
+122
View File
@@ -0,0 +1,122 @@
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
/*
the --master-fifo option create a unix named pipe (fifo) you can use to send management
commands to the master:
echo r > myfifo
*/
// this var can be accessed by plugins and hooks
void (*uwsgi_fifo_table[256])(int);
static char *uwsgi_fifo_by_slot() {
int count = 0;
struct uwsgi_string_list *usl;
uwsgi_foreach(usl, uwsgi.master_fifo) {
if (count == uwsgi.master_fifo_slot) return usl->value;
count++;
}
return uwsgi.master_fifo->value;
}
static void uwsgi_fifo_set_slot_zero() { uwsgi.master_fifo_slot = 0; }
static void uwsgi_fifo_set_slot_one() { uwsgi.master_fifo_slot = 1; }
static void uwsgi_fifo_set_slot_two() { uwsgi.master_fifo_slot = 2; }
static void uwsgi_fifo_set_slot_three() { uwsgi.master_fifo_slot = 3; }
static void uwsgi_fifo_set_slot_four() { uwsgi.master_fifo_slot = 4; }
static void uwsgi_fifo_set_slot_five() { uwsgi.master_fifo_slot = 5; }
static void uwsgi_fifo_set_slot_six() { uwsgi.master_fifo_slot = 6; }
static void uwsgi_fifo_set_slot_seven() { uwsgi.master_fifo_slot = 7; }
static void uwsgi_fifo_set_slot_eight() { uwsgi.master_fifo_slot = 8; }
static void uwsgi_fifo_set_slot_nine() { uwsgi.master_fifo_slot = 9; }
/*
this is called as soon as possibile allowing plugins (or hooks) to override it
*/
void uwsgi_master_fifo_prepare() {
int i;
for(i=0;i<256;i++) {
uwsgi_fifo_table[i] = NULL;
}
uwsgi_fifo_table['0'] = uwsgi_fifo_set_slot_zero;
uwsgi_fifo_table['1'] = uwsgi_fifo_set_slot_one;
uwsgi_fifo_table['2'] = uwsgi_fifo_set_slot_two;
uwsgi_fifo_table['3'] = uwsgi_fifo_set_slot_three;
uwsgi_fifo_table['4'] = uwsgi_fifo_set_slot_four;
uwsgi_fifo_table['5'] = uwsgi_fifo_set_slot_five;
uwsgi_fifo_table['6'] = uwsgi_fifo_set_slot_six;
uwsgi_fifo_table['7'] = uwsgi_fifo_set_slot_seven;
uwsgi_fifo_table['8'] = uwsgi_fifo_set_slot_eight;
uwsgi_fifo_table['9'] = uwsgi_fifo_set_slot_nine;
uwsgi_fifo_table['-'] = uwsgi_cheaper_decrease;
uwsgi_fifo_table['+'] = uwsgi_cheaper_increase;
uwsgi_fifo_table['c'] = uwsgi_chain_reload;
uwsgi_fifo_table['C'] = uwsgi_go_cheap;
uwsgi_fifo_table['f'] = uwsgi_refork_master;
uwsgi_fifo_table['l'] = uwsgi_log_reopen;
uwsgi_fifo_table['L'] = uwsgi_log_rotate;
uwsgi_fifo_table['p'] = suspend_resume_them_all;
uwsgi_fifo_table['P'] = uwsgi_update_pidfiles;
uwsgi_fifo_table['q'] = gracefully_kill_them_all;
uwsgi_fifo_table['Q'] = kill_them_all;
uwsgi_fifo_table['r'] = grace_them_all;
uwsgi_fifo_table['R'] = reap_them_all;
uwsgi_fifo_table['s'] = stats;
uwsgi_fifo_table['w'] = uwsgi_reload_workers;
uwsgi_fifo_table['W'] = uwsgi_brutally_reload_workers;
}
int uwsgi_master_fifo() {
char *path = uwsgi_fifo_by_slot();
unlink(path);
if (mkfifo(path, S_IRUSR|S_IWUSR)) {
uwsgi_error("uwsgi_master_fifo()/mkfifo()");
exit(1);
}
int fd = open(path, O_RDONLY|O_NONBLOCK);
if (fd < 0) {
uwsgi_error("uwsgi_master_fifo()/open()");
exit(1);
}
uwsgi_socket_nb(fd);
return fd;
}
int uwsgi_master_fifo_manage(int fd) {
char cmd;
ssize_t rlen = read(fd, &cmd, 1);
if (rlen < 0) {
if (uwsgi_is_again()) return 0;
uwsgi_error("uwsgi_master_fifo_manage()/read()");
exit(1);
}
// fifo destroyed, recreate it
else if (rlen == 0) {
close(fd);
uwsgi.master_fifo_fd = uwsgi_master_fifo();
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.master_fifo_fd);
return 0;
}
if (uwsgi_fifo_table[(int) cmd]) {
uwsgi_fifo_table[(int) cmd](0);
}
return 0;
}
+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);
}
}
}
+25 -6
View File
@@ -172,6 +172,11 @@ void uwsgi_init_default() {
// 1 MB default limit
uwsgi.chunked_input_limit = 1024*1024;
// clear reforked status
uwsgi.master_is_reforked = 0;
uwsgi_master_fifo_prepare();
}
void uwsgi_setup_reload() {
@@ -216,21 +221,19 @@ void uwsgi_autoload_plugins_by_name(char *argv_zero) {
p = original_proc_name;
p = strstr(p, "uwsgi_");
if (p != NULL) {
plugins_requested = strtok(uwsgi_str(p + 6), "_");
while (plugins_requested) {
char *ctx = NULL;
uwsgi_foreach_token(uwsgi_str(p + 6), "_", plugins_requested, ctx) {
uwsgi_log("[uwsgi] implicit plugin requested %s\n", plugins_requested);
uwsgi_load_plugin(-1, plugins_requested, NULL);
plugins_requested = strtok(NULL, "_");
}
}
plugins_requested = getenv("UWSGI_PLUGINS");
if (plugins_requested) {
plugins_requested = uwsgi_concat2(plugins_requested, "");
char *p = strtok(plugins_requested, ",");
while (p != NULL) {
char *p, *ctx = NULL;
uwsgi_foreach_token(plugins_requested, ",", p, ctx) {
uwsgi_load_plugin(-1, p, NULL);
p = strtok(NULL, ",");
}
}
@@ -357,6 +360,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 +391,8 @@ pid_t uwsgi_daemonize2() {
uwsgi_write_pidfile(uwsgi.pidfile2);
}
if (uwsgi.log_master) uwsgi_setup_log_master();
return uwsgi.mypid;
}
@@ -449,6 +455,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;
}
+564 -78
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) {
@@ -440,7 +488,6 @@ void uwsgi_logvar_add(struct wsgi_request *wsgi_req, char *key, uint8_t keylen,
void uwsgi_check_logrotate(void) {
char message[1024];
int need_rotation = 0;
int need_reopen = 0;
@@ -464,70 +511,81 @@ void uwsgi_check_logrotate(void) {
}
if (need_rotation) {
char *rot_name = uwsgi.log_backupname;
int need_free = 0;
if (rot_name == NULL) {
char *ts_str = uwsgi_num2str((int) uwsgi_now());
rot_name = uwsgi_concat3(uwsgi.logfile, ".", ts_str);
free(ts_str);
need_free = 1;
}
int ret = snprintf(message, 1024, "[%d] logsize: %llu, triggering rotation to %s...\n", (int) uwsgi_now(), (unsigned long long) uwsgi.shared->logsize, rot_name);
if (ret > 0) {
if (write(uwsgi.original_log_fd, message, ret) != ret) {
// very probably this will never be printed
uwsgi_error("write()");
}
}
if (rename(uwsgi.logfile, rot_name) == 0) {
// reopen logfile dup'it and eventually gracefully reload workers;
int fd = open(uwsgi.logfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP);
if (fd < 0) {
uwsgi_error_open(uwsgi.logfile);
grace_them_all(0);
}
else {
if (dup2(fd, uwsgi.original_log_fd) < 0) {
uwsgi_error("dup2()");
grace_them_all(0);
}
close(fd);
}
}
else {
uwsgi_error("unable to rotate log: rename()");
}
if (need_free)
free(rot_name);
uwsgi_log_rotate();
}
else if (need_reopen) {
int ret = snprintf(message, 1024, "[%d] logsize: %llu, triggering log-reopen...\n", (int) uwsgi_now(), (unsigned long long) uwsgi.shared->logsize);
if (ret > 0) {
if (write(uwsgi.original_log_fd, message, ret) != ret) {
// very probably this will never be printed
uwsgi_error("write()");
}
}
// reopen logfile;
close(uwsgi.original_log_fd);
uwsgi.original_log_fd = open(uwsgi.logfile, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP);
if (uwsgi.original_log_fd < 0) {
uwsgi_error_open(uwsgi.logfile);
grace_them_all(0);
}
ret = snprintf(message, 1024, "[%d] %s reopened.\n", (int) uwsgi_now(), uwsgi.logfile);
if (ret > 0) {
if (write(uwsgi.original_log_fd, message, ret) != ret) {
// very probably this will never be printed
uwsgi_error("write()");
}
}
uwsgi.shared->logsize = lseek(uwsgi.original_log_fd, 0, SEEK_CUR);
uwsgi_log_reopen();
}
}
void uwsgi_log_rotate() {
char message[1024];
if (!uwsgi.logfile) return;
char *rot_name = uwsgi.log_backupname;
int need_free = 0;
if (rot_name == NULL) {
char *ts_str = uwsgi_num2str((int) uwsgi_now());
rot_name = uwsgi_concat3(uwsgi.logfile, ".", ts_str);
free(ts_str);
need_free = 1;
}
int ret = snprintf(message, 1024, "[%d] logsize: %llu, triggering rotation to %s...\n", (int) uwsgi_now(), (unsigned long long) uwsgi.shared->logsize, rot_name);
if (ret > 0) {
if (write(uwsgi.original_log_fd, message, ret) != ret) {
// very probably this will never be printed
uwsgi_error("write()");
}
}
if (rename(uwsgi.logfile, rot_name) == 0) {
// reopen logfile dup'it and eventually gracefully reload workers;
int fd = open(uwsgi.logfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP);
if (fd < 0) {
uwsgi_error_open(uwsgi.logfile);
grace_them_all(0);
}
else {
if (dup2(fd, uwsgi.original_log_fd) < 0) {
uwsgi_error("dup2()");
grace_them_all(0);
}
close(fd);
}
}
else {
uwsgi_error("unable to rotate log: rename()");
}
if (need_free)
free(rot_name);
}
void uwsgi_log_reopen() {
char message[1024];
if (!uwsgi.logfile) return;
int ret = snprintf(message, 1024, "[%d] logsize: %llu, triggering log-reopen...\n", (int) uwsgi_now(), (unsigned long long) uwsgi.shared->logsize);
if (ret > 0) {
if (write(uwsgi.original_log_fd, message, ret) != ret) {
// very probably this will never be printed
uwsgi_error("write()");
}
}
// reopen logfile;
close(uwsgi.original_log_fd);
uwsgi.original_log_fd = open(uwsgi.logfile, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP);
if (uwsgi.original_log_fd < 0) {
uwsgi_error_open(uwsgi.logfile);
grace_them_all(0);
}
ret = snprintf(message, 1024, "[%d] %s reopened.\n", (int) uwsgi_now(), uwsgi.logfile);
if (ret > 0) {
if (write(uwsgi.original_log_fd, message, ret) != ret) {
// very probably this will never be printed
uwsgi_error("write()");
}
}
uwsgi.shared->logsize = lseek(uwsgi.original_log_fd, 0, SEEK_CUR);
}
void log_request(struct wsgi_request *wsgi_req) {
@@ -616,7 +674,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 +1093,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 +1118,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 +1317,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 +1404,45 @@ 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;
if (ule->use_for) {
if (ul && ul->id) {
if (strcmp(ule->use_for, ul->id)) {
goto next;
}
}
else {
goto next;
}
}
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;
next:
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 +1476,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 +1494,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 +1520,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 +1538,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 +1608,374 @@ 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;
char *use_for = strchr(usl->value, ':');
if (use_for) *use_for = 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);
}
struct uwsgi_log_encoder *ule2 = uwsgi_malloc(sizeof(struct uwsgi_log_encoder));
memcpy(ule2, ule, sizeof(struct uwsgi_log_encoder));
if (use_for) {
ule2->use_for = uwsgi_str(use_for+1);
*use_for = ':';
}
// we use a copy
if (space) {
*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;
char *use_for = strchr(usl->value, ':');
if (use_for) *use_for = 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);
}
struct uwsgi_log_encoder *ule2 = uwsgi_malloc(sizeof(struct uwsgi_log_encoder));
memcpy(ule2, ule, sizeof(struct uwsgi_log_encoder));
if (use_for) {
ule2->use_for = uwsgi_str(use_for+1);
*use_for = ':';
}
// we use a copy
if (space) {
*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
}
+83 -42
View File
@@ -222,8 +222,8 @@ int uwsgi_get_tcp_info(int fd) {
#elif defined(__FreeBSD__)
if (!uwsgi.shared->ti.__tcpi_sacked) {
#endif
return 0;
}
return 0;
}
#if defined(__linux__)
uwsgi.shared->load = (uint64_t) uwsgi.shared->ti.tcpi_unacked;
@@ -242,12 +242,12 @@ int uwsgi_get_tcp_info(int fd) {
uwsgi_error("write()");
}
else {
uwsgi_log("asking emperor for reinforcements (backlog: %llu)...\n", (unsigned long long ) uwsgi.shared->load);
uwsgi_log("asking emperor for reinforcements (backlog: %llu)...\n", (unsigned long long) uwsgi.shared->load);
}
}
}
if (uwsgi.shared->load >= uwsgi.shared->max_load) {
uwsgi_log_verbose("*** uWSGI listen queue of socket %d full !!! (%llu/%llu) ***\n", fd, (unsigned long long ) uwsgi.shared->load, (unsigned long long ) uwsgi.shared->max_load);
uwsgi_log_verbose("*** uWSGI listen queue of socket %d full !!! (%llu/%llu) ***\n", fd, (unsigned long long) uwsgi.shared->load, (unsigned long long) uwsgi.shared->max_load);
uwsgi.shared->options[UWSGI_OPTION_BACKLOG_ERRORS]++;
}
@@ -306,7 +306,6 @@ int master_loop(char **argv, char **environ) {
struct uwsgi_rb_timer *min_timeout;
struct uwsgi_rbtree *rb_timers = uwsgi_init_rb_timer();
if (uwsgi.procname_master) {
uwsgi_set_processname(uwsgi.procname_master);
}
@@ -346,6 +345,11 @@ int master_loop(char **argv, char **environ) {
#endif
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_signal_pipe[0]);
if (uwsgi.master_fifo) {
uwsgi.master_fifo_fd = uwsgi_master_fifo();
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.master_fifo_fd);
}
if (uwsgi.spoolers) {
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->spooler_signal_pipe[0]);
}
@@ -393,7 +397,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;
@@ -477,7 +481,7 @@ int master_loop(char **argv, char **environ) {
uwsgi_check_touches(uwsgi.touch_gracefully_stop);
// update exec touches
struct uwsgi_string_list *usl = uwsgi.touch_exec;
while(usl) {
while (usl) {
char *space = strchr(usl->value, ' ');
if (space) {
*space = 0;
@@ -489,16 +493,16 @@ int master_loop(char **argv, char **environ) {
uwsgi_check_touches(uwsgi.touch_exec);
// update signal touches
usl = uwsgi.touch_signal;
while(usl) {
char *space = strchr(usl->value, ' ');
if (space) {
*space = 0;
usl->len = strlen(usl->value);
usl->custom_ptr = space + 1;
}
usl = usl->next;
}
uwsgi_check_touches(uwsgi.touch_signal);
while (usl) {
char *space = strchr(usl->value, ' ');
if (space) {
*space = 0;
usl->len = strlen(usl->value);
usl->custom_ptr = space + 1;
}
usl = usl->next;
}
uwsgi_check_touches(uwsgi.touch_signal);
// fsmon
uwsgi_fsmon_setup();
@@ -741,7 +745,7 @@ int master_loop(char **argv, char **environ) {
#endif
// resubscribe every 10 cycles by default
if (( (uwsgi.subscriptions || uwsgi.subscriptions2) && ((uwsgi.master_cycles % uwsgi.subscribe_freq) == 0 || uwsgi.master_cycles == 1)) && !uwsgi_instance_is_reloading && !uwsgi_instance_is_dying && !uwsgi.workers[0].suspended) {
if (((uwsgi.subscriptions || uwsgi.subscriptions2) && ((uwsgi.master_cycles % uwsgi.subscribe_freq) == 0 || uwsgi.master_cycles == 1)) && !uwsgi_instance_is_reloading && !uwsgi_instance_is_dying && !uwsgi.workers[0].suspended) {
uwsgi_subscribe_all(0, 0);
}
@@ -765,40 +769,34 @@ int master_loop(char **argv, char **environ) {
}
touched = uwsgi_check_touches(uwsgi.touch_workers_reload);
if (touched) {
uwsgi_log_verbose("*** %s has been touched... workers reload !!! ***\n", touched);
uwsgi_block_signal(SIGHUP);
for(i=1;i<=uwsgi.numproc;i++) {
if (uwsgi.workers[i].pid > 0) {
uwsgi_curse(i, SIGHUP);
}
}
uwsgi_unblock_signal(SIGHUP);
continue;
}
uwsgi_log_verbose("*** %s has been touched... workers reload !!! ***\n", touched);
uwsgi_reload_workers();
continue;
}
touched = uwsgi_check_touches(uwsgi.touch_chain_reload);
if (touched) {
if (uwsgi.status.chain_reloading == 0) {
uwsgi_log_verbose("*** %s has been touched... chain reload !!! ***\n", touched);
uwsgi_log_verbose("*** %s has been touched... chain reload !!! ***\n", touched);
uwsgi.status.chain_reloading = 1;
}
else {
uwsgi_log_verbose("*** %s has been touched... but chain reload is already running ***\n", touched);
uwsgi_log_verbose("*** %s has been touched... but chain reload is already running ***\n", touched);
}
}
// be sure to run it as the last touch check
touched = uwsgi_check_touches(uwsgi.touch_exec);
if (touched) {
if (uwsgi_run_command( touched , NULL, -1) >= 0) {
if (uwsgi_run_command(touched, NULL, -1) >= 0) {
uwsgi_log_verbose("[uwsgi-touch-exec] running %s\n", touched);
}
}
touched = uwsgi_check_touches(uwsgi.touch_signal);
if (touched) {
if (touched) {
uint8_t signum = atoi(touched);
uwsgi_route_signal(signum);
uwsgi_log_verbose("[uwsgi-touch-signal] raising %u\n", signum);
}
uwsgi_log_verbose("[uwsgi-touch-signal] raising %u\n", signum);
}
}
continue;
@@ -815,12 +813,18 @@ int master_loop(char **argv, char **environ) {
// reload gateways and daemons only on normal workflow (+outworld status)
if (!uwsgi_instance_is_reloading && !uwsgi_instance_is_dying) {
if (uwsgi_master_check_emperor_death(diedpid)) continue;
if (uwsgi_master_check_spoolers_death(diedpid)) continue;
if (uwsgi_master_check_mules_death(diedpid)) continue;
if (uwsgi_master_check_gateways_death(diedpid)) continue;
if (uwsgi_master_check_daemons_death(diedpid)) continue;
if (uwsgi_master_check_cron_death(diedpid)) continue;
if (uwsgi_master_check_emperor_death(diedpid))
continue;
if (uwsgi_master_check_spoolers_death(diedpid))
continue;
if (uwsgi_master_check_mules_death(diedpid))
continue;
if (uwsgi_master_check_gateways_death(diedpid))
continue;
if (uwsgi_master_check_daemons_death(diedpid))
continue;
if (uwsgi_master_check_cron_death(diedpid))
continue;
}
@@ -885,8 +889,9 @@ next:
// ok, if we are reloading or dying, just continue the master loop
// as soon as all of the workers have pid == 0, the action (exit, or reload) is triggered
if (uwsgi_instance_is_reloading || uwsgi_instance_is_dying) {
if (!uwsgi.workers[thewid].cursed_at) uwsgi.workers[thewid].cursed_at = uwsgi_now();
uwsgi_log("worker %d buried after %d seconds\n", thewid, (int) (uwsgi_now()-uwsgi.workers[thewid].cursed_at));
if (!uwsgi.workers[thewid].cursed_at)
uwsgi.workers[thewid].cursed_at = uwsgi_now();
uwsgi_log("worker %d buried after %d seconds\n", thewid, (int) (uwsgi_now() - uwsgi.workers[thewid].cursed_at));
uwsgi.workers[thewid].cursed_at = 0;
continue;
}
@@ -905,6 +910,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));
@@ -959,3 +969,34 @@ next:
// never here
}
void uwsgi_reload_workers() {
int i;
uwsgi_block_signal(SIGHUP);
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].pid > 0) {
uwsgi_curse(i, SIGHUP);
}
}
uwsgi_unblock_signal(SIGHUP);
}
void uwsgi_chain_reload() {
if (!uwsgi.status.chain_reloading) {
uwsgi_log_verbose("chain reload starting...\n");
uwsgi.status.chain_reloading = 1;
}
else {
uwsgi_log_verbose("chain reload already running...\n");
}
}
void uwsgi_brutally_reload_workers() {
int i;
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].pid > 0) {
uwsgi_log_verbose("killing worker %d (pid: %d)\n", i, (int) uwsgi.workers[i].pid);
uwsgi_curse(i, SIGINT);
}
}
}
+8 -2
View File
@@ -35,11 +35,17 @@ int uwsgi_master_check_reload(char **argv) {
// check for chain reload
void uwsgi_master_check_chain() {
if (!uwsgi.status.chain_reloading) return;
if (uwsgi.status.chain_reloading > uwsgi.numproc) {
int i;
int needed_procs = 0;
for(i=1;i<=uwsgi.numproc;i++) {
if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cheaped == 0) {
needed_procs++;
}
}
if (uwsgi.status.chain_reloading > needed_procs) {
uwsgi.status.chain_reloading = 0;
uwsgi_log_verbose("chain reloading complete\n");
}
int i;
uwsgi_block_signal(SIGHUP);
for(i=1;i<=uwsgi.numproc;i++) {
if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].cursed_at == 0 && i == uwsgi.status.chain_reloading) {
+4
View File
@@ -18,6 +18,10 @@ int uwsgi_master_manage_events(int interesting_fd) {
}
}
if (uwsgi.master_fifo_fd > -1 && interesting_fd == uwsgi.master_fifo_fd) {
return uwsgi_master_fifo_manage(uwsgi.master_fifo_fd);
}
// stats server ?
if (uwsgi.stats && uwsgi.stats_fd > -1) {
if (interesting_fd == uwsgi.stats_fd) {
+115 -16
View File
@@ -115,7 +115,43 @@ 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;
}
}
// then check for fifo
if (uwsgi.cheaper_fifo_delta != 0) {
if (!ignore_algo) {
needed_workers = uwsgi.cheaper_fifo_delta;
ignore_algo = 1;
}
uwsgi.cheaper_fifo_delta = 0;
}
if (!ignore_algo) needed_workers = uwsgi.cheaper_algo();
if (needed_workers > 0) {
for (i = 1; i <= uwsgi.numproc; i++) {
@@ -152,6 +188,11 @@ int uwsgi_calc_cheaper(void) {
return 1;
}
// fake algo to allow control with the fifo
int uwsgi_cheaper_algo_manual(void) {
return 0;
}
/*
-- Cheaper, spare algorithm, adapted from old-fashioned spare system --
@@ -326,23 +367,30 @@ void uwsgi_reload(char **argv) {
int i;
int waitpid_status;
// call a series of waitpid to ensure all processes (gateways, mules and daemons) are dead
for (i = 0; i < (ushared->gateways_cnt + uwsgi.daemons_cnt + uwsgi.mules_cnt); i++) {
waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
if (!uwsgi.master_is_reforked) {
// call a series of waitpid to ensure all processes (gateways, mules and daemons) are dead
for (i = 0; i < (ushared->gateways_cnt + uwsgi.daemons_cnt + uwsgi.mules_cnt); i++) {
waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
}
// call master cleanup hooks
uwsgi_master_cleanup_hooks();
// call atexit user exec
uwsgi_exec_atexit();
if (uwsgi.exit_on_reload) {
uwsgi_log("uWSGI: GAME OVER (insert coin)\n");
exit(0);
}
uwsgi_log("binary reloading uWSGI...\n");
}
else {
uwsgi_log("fork()'ing uWSGI...\n");
}
// call master cleanup hooks
uwsgi_master_cleanup_hooks();
// call atexit user exec
uwsgi_exec_atexit();
if (uwsgi.exit_on_reload) {
uwsgi_log("uWSGI: GAME OVER (insert coin)\n");
exit(0);
}
uwsgi_log("binary reloading uWSGI...\n");
uwsgi_log("chdir() to %s\n", uwsgi.cwd);
if (chdir(uwsgi.cwd)) {
uwsgi_error("chdir()");
@@ -529,6 +577,7 @@ void uwsgi_fixup_fds(int wid, int muleid, struct uwsgi_gateway *ug) {
}
}
if (uwsgi.master_fifo_fd > -1) close(uwsgi.master_fifo_fd);
}
@@ -1485,3 +1534,53 @@ void uwsgi_add_reload_fds() {
add_reload_fds(uwsgi.reload_on_fd, "graceful");
add_reload_fds(uwsgi.brutal_reload_on_fd, "brutal");
}
void uwsgi_refork_master() {
pid_t pid = fork();
if (pid < 0) {
uwsgi_error("uwsgi_refork_master()/fork()");
return;
}
if (pid > 0) {
uwsgi_log_verbose("new master copy spawned with pid %d\n", (int) pid);
return;
}
// detach from the old master
setsid();
uwsgi.master_is_reforked = 1;
uwsgi_reload(uwsgi.argv);
// never here
exit(1);
}
void uwsgi_cheaper_increase() {
uwsgi.cheaper_fifo_delta++;
}
void uwsgi_cheaper_decrease() {
uwsgi.cheaper_fifo_delta--;
}
void uwsgi_go_cheap() {
int i;
int waitpid_status;
if (uwsgi.status.is_cheap) return;
uwsgi_log_verbose("going cheap...\n");
uwsgi.status.is_cheap = 1;
for (i = 1; i <= uwsgi.numproc; i++) {
uwsgi.workers[i].cheaped = 1;
if (uwsgi.workers[i].pid == 0)
continue;
uwsgi_log("killing worker %d (pid: %d)\n", i, (int) uwsgi.workers[i].pid);
kill(uwsgi.workers[i].pid, SIGKILL);
if (waitpid(uwsgi.workers[i].pid, &waitpid_status, 0) < 0) {
if (errno != ECHILD)
uwsgi_error("uwsgi_go_cheap()/waitpid()");
}
}
uwsgi_add_sockets_to_queue(uwsgi.master_queue, -1);
uwsgi_log("cheap mode enabled: waiting for socket connection...\n");
}
+238
View File
@@ -0,0 +1,238 @@
#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, *ctx = NULL;
uwsgi_foreach_token(mflags, ",", p, ctx) {
unsigned long flag = (unsigned long) uwsgi_mount_flag(p);
if (!flag) {
uwsgi_log("unknown mount flag \"%s\"\n", p);
exit(1);
}
mountflags |= flag;
}
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, *ctx = NULL;
uwsgi_foreach_token(mflags, ",", p, ctx) {
unsigned long flag = (unsigned long) uwsgi_mount_flag(p);
if (!flag) {
uwsgi_log("unknown umount flag \"%s\"\n", p);
exit(1);
}
mountflags |= flag;
}
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;
}
+2 -4
View File
@@ -453,8 +453,8 @@ void uwsgi_setup_mules_and_farms() {
create_signal_pipe(uwsgi.farms[i].signal_pipe);
create_msg_pipe(uwsgi.farms[i].queue_pipe, uwsgi.mule_msg_size);
char *p = strtok(mules_list, ",");
while (p != NULL) {
char *p, *ctx = NULL;
uwsgi_foreach_token(mules_list, ",", p, ctx) {
struct uwsgi_mule *um = get_mule_by_id(atoi(p));
if (!um) {
uwsgi_log("invalid mule id: %s\n", p);
@@ -462,8 +462,6 @@ void uwsgi_setup_mules_and_farms() {
}
uwsgi_mule_farm_new(&uwsgi.farms[i].mules, um);
p = strtok(NULL, ",");
}
uwsgi_log("created farm %d name: %s mules:%s\n", i + 1, uwsgi.farms[i].name, strchr(farm_name->value, ':') + 1);
+15 -1
View File
@@ -14,7 +14,9 @@ static void uwsgi_plugin_parse_section(char *filename) {
if (equal) {
*equal = 0;
if (!strcmp(p, "requires")) {
uwsgi_load_plugin(-1, equal + 1, NULL);
if (!plugin_already_loaded(equal+1)) {
uwsgi_load_plugin(-1, equal + 1, NULL);
}
}
}
p = strtok_r(NULL, "\n", &ctx);
@@ -98,6 +100,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 +165,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
}
+37 -4
View File
@@ -187,6 +187,14 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst
return -1;
}
#ifdef __linux__
long somaxconn = uwsgi_num_from_file("/proc/sys/net/core/somaxconn", 1);
if (somaxconn > 0 && uwsgi.listen_queue > somaxconn) {
uwsgi_log("Listen queue size is greater than the system max net.core.somaxconn (%li).\n", somaxconn);
uwsgi_nuclear_blast();
return -1;
}
#endif
if (listen(serverfd, listen_queue) != 0) {
uwsgi_error("listen()");
@@ -1645,8 +1653,8 @@ void uwsgi_map_sockets() {
}
if ((int) uwsgi_str_num(usl->value, colon - usl->value) == uwsgi_get_socket_num(uwsgi_sock)) {
enabled = 0;
char *p = strtok(colon + 1, ",");
while (p != NULL) {
char *p, *ctx = NULL;
uwsgi_foreach_token(colon + 1, ",", p, ctx) {
int w = atoi(p);
if (w < 1 || w > uwsgi.numproc) {
uwsgi_log("invalid worker num: %d\n", w);
@@ -1657,7 +1665,6 @@ void uwsgi_map_sockets() {
uwsgi_log("mapped socket %d (%s) to worker %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi.mywid);
break;
}
p = strtok(NULL, ",");
}
}
@@ -1714,6 +1721,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 +1792,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 +1811,8 @@ void uwsgi_bind_sockets() {
}
stdin_done:
// check for auto_port socket
uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
@@ -1951,3 +1965,22 @@ 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;
}
+481 -55
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;
@@ -1514,14 +1879,12 @@ char *uwsgi_get_optname_by_index(int index) {
int uwsgi_list_has_num(char *list, int num) {
char *list2 = uwsgi_concat2(list, "");
char *p = strtok(list2, ",");
while (p != NULL) {
char *p, *ctx = NULL;
uwsgi_foreach_token(list2, ",", p, ctx) {
if (atoi(p) == num) {
free(list2);
return 1;
}
p = strtok(NULL, ",");
}
free(list2);
@@ -1531,14 +1894,12 @@ int uwsgi_list_has_num(char *list, int num) {
int uwsgi_list_has_str(char *list, char *str) {
char *list2 = uwsgi_str(list);
char *p = strtok(list2, " ");
while (p != NULL) {
char *p, *ctx = NULL;
uwsgi_foreach_token(list2, " ", p, ctx) {
if (!strcasecmp(p, str)) {
free(list2);
return 1;
}
p = strtok(NULL, " ");
}
free(list2);
@@ -1921,9 +2282,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 +2303,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 +2314,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 +2333,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 +2467,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 +2724,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 +2735,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,17 +2759,15 @@ 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);
char *p = strtok(list, ",");
while (p != NULL) {
char *p, *ctx = NULL;
uwsgi_foreach_token(list, ",", p, ctx) {
int u_id = uwsgi_get_unshare_id(p);
if (u_id != -1) {
uwsgi.unshare |= u_id;
*mask |= u_id;
}
p = strtok(NULL, ",");
}
free(list);
}
@@ -2455,8 +2856,8 @@ void uwsgi_build_cap(char *what) {
int pos = 0;
uwsgi.cap_count = 0;
char *p = strtok(caps, ",");
while (p != NULL) {
char *p, *ctx = NULL;
uwsgi_foreach_token(caps, ",", p, ctx) {
if (is_a_number(p)) {
uwsgi.cap_count++;
}
@@ -2466,15 +2867,14 @@ void uwsgi_build_cap(char *what) {
uwsgi.cap_count++;
}
}
p = strtok(NULL, ",");
}
free(caps);
uwsgi.cap = uwsgi_malloc(sizeof(cap_value_t) * uwsgi.cap_count);
caps = uwsgi_str(what);
p = strtok(caps, ",");
while (p != NULL) {
ctx = NULL;
uwsgi_foreach_token(caps, ",", p, ctx) {
if (is_a_number(p)) {
cap_id = atoi(p);
}
@@ -2486,7 +2886,6 @@ void uwsgi_build_cap(char *what) {
uwsgi_log("setting capability %s [%d]\n", p, cap_id);
pos++;
}
p = strtok(NULL, ",");
}
free(caps);
@@ -2875,12 +3274,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 +3338,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 +3717,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 +4156,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);
}
+422 -49
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,9 +194,13 @@ 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},
{"vassals-inherit", required_argument, 0, "add config templates to vassals config (uses --inherit)", uwsgi_opt_add_string_list, &uwsgi.vassals_templates, 0},
{"vassals-include", required_argument, 0, "include config templates to vassals config (uses --include instead of --inherit)", uwsgi_opt_add_string_list, &uwsgi.vassals_includes, 0},
{"vassals-start-hook", required_argument, 0, "run the specified command before each vassal starts", uwsgi_opt_set_str, &uwsgi.vassals_start_hook, 0},
{"vassals-stop-hook", required_argument, 0, "run the specified command after vassal's death", uwsgi_opt_set_str, &uwsgi.vassals_stop_hook, 0},
{"vassal-sos-backlog", required_argument, 0, "ask emperor for sos if backlog queue has more items than the value specified", uwsgi_opt_set_int, &uwsgi.vassal_sos_backlog, 0},
@@ -204,6 +210,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 +227,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 +263,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 +290,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 +305,41 @@ 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-asap", required_argument, 0, "run the specified hook as soon as possible", uwsgi_opt_add_string_list, &uwsgi.hook_asap, 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-asap", required_argument, 0, "run the specified command as soon as possible", uwsgi_opt_add_string_list, &uwsgi.exec_asap, 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 +348,61 @@ 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-asap", required_argument, 0, "mount filesystem as soon as possible", uwsgi_opt_add_string_list, &uwsgi.mount_asap, 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-asap", required_argument, 0, "unmount filesystem as soon as possible", uwsgi_opt_add_string_list, &uwsgi.umount_asap, 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-asap", required_argument, 0, "call the specified function as soon as possible", uwsgi_opt_add_string_list, &uwsgi.call_asap, 0},
{"call-pre-jail", required_argument, 0, "call the specified function before jailing", uwsgi_opt_add_string_list, &uwsgi.call_pre_jail, 0},
{"call-post-jail", required_argument, 0, "call the specified function after jailing", uwsgi_opt_add_string_list, &uwsgi.call_post_jail, 0},
{"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},
@@ -360,7 +462,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"fs-brutal-reload", required_argument, 0, "brutal reload when the specified filesystem object is modified", uwsgi_opt_add_string_list, &uwsgi.fs_brutal_reload, UWSGI_OPT_MASTER},
{"fs-signal", required_argument, 0, "raise a uwsgi signal when the specified filesystem object is modified (syntax: file signal)", uwsgi_opt_add_string_list, &uwsgi.fs_signal, UWSGI_OPT_MASTER},
{"propagate-touch", no_argument, 0, "over-engineering option for system with flaky signal mamagement", uwsgi_opt_true, &uwsgi.propagate_touch, 0},
{"propagate-touch", no_argument, 0, "over-engineering option for system with flaky signal management", uwsgi_opt_true, &uwsgi.propagate_touch, 0},
{"limit-post", required_argument, 0, "limit request body", uwsgi_opt_set_64bit, &uwsgi.limit_post, 0},
{"no-orphans", no_argument, 0, "automatically kill workers if master dies (can be dangerous for availability)", uwsgi_opt_true, &uwsgi.no_orphans, 0},
{"prio", required_argument, 0, "set processes/threads priority", uwsgi_opt_set_rawint, &uwsgi.prio, 0},
@@ -393,6 +495,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"multicast-ttl", required_argument, 0, "set multicast ttl", uwsgi_opt_set_int, &uwsgi.multicast_ttl, 0},
{"multicast-loop", required_argument, 0, "set multicast loop (default 1)", uwsgi_opt_set_int, &uwsgi.multicast_loop, 0},
{"master-fifo", required_argument, 0, "enable the master fifo", uwsgi_opt_add_string_list, &uwsgi.master_fifo, UWSGI_OPT_MASTER},
#ifdef UWSGI_SSL
{"legion", required_argument, 0, "became a member of a legion", uwsgi_opt_legion, NULL, UWSGI_OPT_MASTER},
{"legion-mcast", required_argument, 0, "became a member of a legion (shortcut for multicast)", uwsgi_opt_legion_mcast, NULL, UWSGI_OPT_MASTER},
@@ -464,6 +568,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 +602,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 +622,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 +641,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 +700,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 +738,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 +751,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 +787,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 +831,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 +843,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},
@@ -733,6 +879,7 @@ void show_config(void) {
}
int uwsgi_manage_custom_option(struct uwsgi_custom_option *uco, char *key, char *value) {
int configured;
size_t i, count = 1;
size_t value_len = 0;
if (value)
@@ -758,11 +905,10 @@ int uwsgi_manage_custom_option(struct uwsgi_custom_option *uco, char *key, char
if (value_len > 0) {
tmp_val = uwsgi_str(value);
// fill the array of options
p = strtok(tmp_val, " ");
while (p) {
char *p, *ctx = NULL;
uwsgi_foreach_token(tmp_val, " ", p, ctx) {
opt_argv[pos] = p;
pos++;
p = strtok(NULL, " ");
}
}
else {
@@ -777,8 +923,8 @@ int uwsgi_manage_custom_option(struct uwsgi_custom_option *uco, char *key, char
// now make a copy of the option template
char *tmp_opt = uwsgi_str(uco->value);
// split it
p = strtok(tmp_opt, ";");
while (p) {
char *ctx = NULL;
uwsgi_foreach_token(tmp_opt, ";", p, ctx) {
char *equal = strchr(p, '=');
if (!equal)
goto clear;
@@ -809,9 +955,11 @@ int uwsgi_manage_custom_option(struct uwsgi_custom_option *uco, char *key, char
free(old_value);
free(placeholder);
}
// we can ignore its return value
(void) uwsgi_manage_opt(new_key, new_value);
p = strtok(NULL, ";");
retry:
configured = uwsgi_manage_opt(new_key, new_value);
if (!configured && uwsgi.autoload) {
if (uwsgi_try_autoload(new_key)) goto retry;
}
}
clear:
@@ -922,11 +1070,15 @@ void config_magic_table_fill(char *filename, char **magic_table) {
int base = '0';
char *to_split = uwsgi_str(magic_table['d']);
char *p = strtok(to_split, "/");
while (p && base <= '9') {
magic_table[base] = p;
base++;
p = strtok(NULL, "/");
char *p, *ctx = NULL;
uwsgi_foreach_token(to_split, "/", p, ctx) {
if (base <= '9') {
magic_table[base] = p;
base++;
}
else {
break;
}
}
if (tmp)
@@ -1079,6 +1231,28 @@ void kill_them_all(int signum) {
uwsgi_destroy_processes();
}
// gracefully destroy
void gracefully_kill_them_all(int signum) {
if (uwsgi_instance_is_dying) return;
uwsgi.status.gracefully_destroying = 1;
// unsubscribe if needed
uwsgi_unsubscribe_all();
uwsgi_log_verbose("graceful shutdown triggered...\n");
int i;
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].pid > 0) {
uwsgi_curse(i, SIGHUP);
}
}
uwsgi_destroy_processes();
}
// graceful reload
void grace_them_all(int signum) {
if (uwsgi_instance_is_reloading || uwsgi_instance_is_dying)
@@ -1103,6 +1277,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 +1350,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 +1435,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 +1452,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 +1490,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 +1549,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 +1563,7 @@ static void vacuum(void) {
uwsgi_log("VACUUM: unix socket %s removed.\n", uwsgi_sock->name);
}
}
next:
uwsgi_sock = uwsgi_sock->next;
}
}
@@ -1423,14 +1621,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 +1962,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 +2045,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 +2061,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,
@@ -1875,6 +2082,7 @@ int main(int argc, char *argv[], char *envp[]) {
uwsgi.magic_table['v'] = uwsgi.cwd;
uwsgi.magic_table['h'] = uwsgi.hostname;
uwsgi.magic_table['V'] = UWSGI_VERSION;
uwsgi.magic_table['['] = "\033";
// you can embed a ini file in the uWSGi binary with default options
#ifdef UWSGI_EMBED_CONFIG
@@ -1905,6 +2113,32 @@ int main(int argc, char *argv[], char *envp[]) {
// ok, the options dictionary is available, lets manage it
uwsgi_configure();
// run "asap" hooks
uwsgi_hooks_run(uwsgi.hook_asap, "asap", 1);
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.mount_asap) {
uwsgi_log("mounting \"%s\" (asap)...\n", usl->value);
if (uwsgi_mount_hook(usl->value)) exit(1);
}
uwsgi_foreach(usl, uwsgi.umount_asap) {
uwsgi_log("un-mounting \"%s\" (asap)...\n", usl->value);
if (uwsgi_umount_hook(usl->value)) exit(1);
}
uwsgi_foreach(usl, uwsgi.exec_asap) {
uwsgi_log("running \"%s\" (asap)...\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_asap) {
if (uwsgi_call_symbol(usl->value)) {
uwsgi_log("unable to call function \"%s\"\n", usl->value);
exit(1);
}
}
// manage envdirs ASAP
uwsgi_envdirs(uwsgi.envdirs);
@@ -1942,7 +2176,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
@@ -1955,6 +2189,7 @@ int main(int argc, char *argv[], char *envp[]) {
// setup cheaper algos
uwsgi_register_cheaper_algo("spare", uwsgi_cheaper_algo_spare);
uwsgi_register_cheaper_algo("backlog", uwsgi_cheaper_algo_backlog);
uwsgi_register_cheaper_algo("manual", uwsgi_cheaper_algo_manual);
// setup imperial monitors
uwsgi_register_imperial_monitor("dir", uwsgi_imperial_monitor_directory_init, uwsgi_imperial_monitor_directory);
@@ -2082,6 +2317,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 +2329,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("unable to call function \"%s\"\n", usl->value);
exit(1);
}
}
usl = usl->next;
}
// we could now patch the binary
@@ -2156,9 +2415,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 +2557,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 +2604,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 +2702,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 +2774,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 +2913,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 +2946,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 +3138,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 +3176,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);
@@ -2934,8 +3280,8 @@ void uwsgi_worker_run() {
// eventually remap plugins
if (uwsgi.remap_modifier) {
char *map = strtok(uwsgi.remap_modifier, ",");
while (map != NULL) {
char *map, *ctx = NULL;
uwsgi_foreach_token(uwsgi.remap_modifier, ",", map, ctx) {
char *colon = strchr(map, ':');
if (colon) {
colon[0] = 0;
@@ -2944,7 +3290,6 @@ void uwsgi_worker_run() {
uwsgi.p[rm_dst]->request = uwsgi.p[rm_src]->request;
uwsgi.p[rm_dst]->after_request = uwsgi.p[rm_src]->after_request;
}
map = strtok(NULL, ",");
}
}
@@ -3155,7 +3500,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 +3542,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 +3556,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 +3611,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 +3624,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 +4025,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
@@ -3702,15 +4063,18 @@ void uwsgi_opt_load_dl(char *opt, char *value, void *none) {
void uwsgi_opt_load_plugin(char *opt, char *value, void *none) {
char *plugins_list = uwsgi_concat2(value, "");
char *p = strtok(plugins_list, ",");
while (p != NULL) {
char *p, *ctx = NULL;
uwsgi_foreach_token(plugins_list, ",", p, ctx) {
#ifdef UWSGI_DEBUG
uwsgi_debug("loading plugin %s\n", p);
#endif
if (uwsgi_load_plugin(-1, p, NULL)) {
build_options();
}
p = strtok(NULL, ",");
else if (!uwsgi_startswith(opt, "need-", 5)) {
uwsgi_log("unable to load plugin \"%s\"\n", p);
exit(1);
}
}
free(p);
free(plugins_list);
@@ -4095,7 +4459,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;
@@ -4199,3 +4563,12 @@ void uwsgi_print_sym(char *opt, char *symbol, void *foobar) {
exit(0);
}
void uwsgi_update_pidfiles() {
if (uwsgi.pidfile) {
uwsgi_write_pidfile(uwsgi.pidfile);
}
if (uwsgi.pidfile2) {
uwsgi_write_pidfile(uwsgi.pidfile2);
}
}
+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
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;
+2 -3
View File
@@ -71,8 +71,8 @@ static void carbon_post_init() {
u_server->healthy = 1;
u_server->errors = 0;
char *p = strtok(usl->value, ":");
while (p) {
char *p, *ctx = NULL;
uwsgi_foreach_token(usl->value, ":", p, ctx) {
if (!u_server->hostname) {
u_server->hostname = uwsgi_str(p);
}
@@ -81,7 +81,6 @@ static void carbon_post_init() {
}
else
break;
p = strtok(NULL, ":");
}
if (!u_server->hostname || !u_server->port) {
uwsgi_log("[carbon] invalid carbon server address (%s)\n", usl->value);
+2 -3
View File
@@ -828,8 +828,8 @@ clear2:
// set the start position of args in argv
i = 1;
if (helper) i = 2;
char *p = strtok(qs, "+");
while(p) {
char *p, *ctx = NULL;
uwsgi_foreach_token(qs, "+", p, ctx) {
// create a copy for the url_decoded string
char *arg_copy = uwsgi_str(p);
uint16_t arg_copy_len = strlen(p);
@@ -838,7 +838,6 @@ clear2:
argv[i] = uwsgi_malloc( (arg_copy_len * 2) +1);
escape_shell_arg(arg_copy, arg_copy_len, argv[i]);
i++;
p = strtok(NULL, "+");
}
free(qs);
}
+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");
+204
View File
@@ -0,0 +1,204 @@
/*
uWSGI forkpty-router
*/
#include <uwsgi.h>
#include "../corerouter/cr.h"
extern struct uwsgi_server uwsgi;
#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
static struct uwsgi_forkptyrouter {
struct uwsgi_corerouter cr;
char *cmd;
} ufpty;
extern struct uwsgi_server uwsgi;
struct forkptyrouter_session {
struct corerouter_session session;
pid_t pid;
};
static struct uwsgi_option forkptyrouter_options[] = {
{"forkptyrouter", required_argument, 0, "run the forkptyrouter on the specified address", uwsgi_opt_undeferred_corerouter, &ufpty, 0},
{"forkpty-router", required_argument, 0, "run the forkptyrouter on the specified address", uwsgi_opt_undeferred_corerouter, &ufpty, 0},
{"forkptyrouter-command", required_argument, 0, "run the specified command on every connection (default: /bin/sh)", uwsgi_opt_set_str, &ufpty.cmd, 0},
{"forkpty-router-command", required_argument, 0, "run the specified command on every connection (default: /bin/sh)", uwsgi_opt_set_str, &ufpty.cmd, 0},
{"forkptyrouter-cmd", required_argument, 0, "run the specified command on every connection (default: /bin/sh)", uwsgi_opt_set_str, &ufpty.cmd, 0},
{"forkpty-router-cmd", required_argument, 0, "run the specified command on every connection (default: /bin/sh)", uwsgi_opt_set_str, &ufpty.cmd, 0},
{"forkptyrouter-processes", required_argument, 0, "prefork the specified number of forkptyrouter processes", uwsgi_opt_set_int, &ufpty.cr.processes, 0},
{"forkptyrouter-workers", required_argument, 0, "prefork the specified number of forkptyrouter processes", uwsgi_opt_set_int, &ufpty.cr.processes, 0},
{"forkptyrouter-zerg", required_argument, 0, "attach the forkptyrouter to a zerg server", uwsgi_opt_corerouter_zerg, &ufpty, 0},
{"forkptyrouter-fallback", required_argument, 0, "fallback to the specified node in case of error", uwsgi_opt_add_string_list, &ufpty.cr.fallback, 0},
{"forkptyrouter-events", required_argument, 0, "set the maximum number of concufptyent events", uwsgi_opt_set_int, &ufpty.cr.nevents, 0},
{"forkptyrouter-cheap", no_argument, 0, "run the forkptyrouter in cheap mode", uwsgi_opt_true, &ufpty.cr.cheap, 0},
{"forkptyrouter-timeout", required_argument, 0, "set forkptyrouter timeout", uwsgi_opt_set_int, &ufpty.cr.socket_timeout, 0},
{"forkptyrouter-stats", required_argument, 0, "run the forkptyrouter stats server", uwsgi_opt_set_str, &ufpty.cr.stats_server, 0},
{"forkptyrouter-stats-server", required_argument, 0, "run the forkptyrouter stats server", uwsgi_opt_set_str, &ufpty.cr.stats_server, 0},
{"forkptyrouter-ss", required_argument, 0, "run the forkptyrouter stats server", uwsgi_opt_set_str, &ufpty.cr.stats_server, 0},
{"forkptyrouter-harakiri", required_argument, 0, "enable forkptyrouter harakiri", uwsgi_opt_set_int, &ufpty.cr.harakiri, 0},
{0, 0, 0, 0, 0, 0, 0},
};
// write to backend
static ssize_t fpty_instance_write(struct corerouter_peer *peer) {
ssize_t len = cr_write(peer, "fpty_instance_write()");
// end on empty write
if (!len) return 0;
// the chunk has been sent, start (again) reading from client and instances
if (cr_write_complete(peer)) {
// reset the buffer
peer->out->pos = 0;
cr_reset_hooks(peer);
}
return len;
}
// write to client
static ssize_t fpty_write(struct corerouter_peer *main_peer) {
ssize_t len = cr_write(main_peer, "fpty_write()");
// end on empty write
if (!len) return 0;
// ok this response chunk is sent, let's start reading again
if (cr_write_complete(main_peer)) {
// reset the buffer
main_peer->out->pos = 0;
cr_reset_hooks(main_peer);
}
return len;
}
// read from backend
static ssize_t fpty_instance_read(struct corerouter_peer *peer) {
ssize_t len = cr_read(peer, "fpty_instance_read()");
if (!len) return 0;
// set the input buffer as the main output one
peer->session->main_peer->out = peer->in;
peer->session->main_peer->out_pos = 0;
cr_write_to_main(peer, fpty_write);
return len;
}
// read from client
static ssize_t fpty_read(struct corerouter_peer *main_peer) {
ssize_t len = cr_read(main_peer, "fpty_read()");
if (!len) return 0;
main_peer->session->peers->out = main_peer->in;
main_peer->session->peers->out_pos = 0;
cr_write_to_backend(main_peer->session->peers, fpty_instance_write);
return len;
}
static void fpty_session_close(struct corerouter_session *cs) {
struct forkptyrouter_session *fpty_session = (struct forkptyrouter_session *) cs;
if (fpty_session->pid > 0) {
int waitpid_status = 0;
if (waitpid(fpty_session->pid, &waitpid_status, WNOHANG) < 0) {
uwsgi_error("fpty_session_close()/waitpid()");
}
}
}
// allocate a new session
static int forkptyrouter_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket *ugs, struct corerouter_session *cs, struct sockaddr *sa, socklen_t s_len) {
// set default read hook
cs->main_peer->last_hook_read = fpty_read;
// wait4() on close
cs->close = fpty_session_close;
struct forkptyrouter_session *fpty_session = (struct forkptyrouter_session *) cs;
// add a new peer
struct corerouter_peer *peer = uwsgi_cr_peer_add(cs);
// on new connection generate a new pty
fpty_session->pid = forkpty(&peer->fd, NULL, NULL, NULL);
if (fpty_session->pid < 0) {
uwsgi_error("forkpty()");
return -1;
}
else if (fpty_session->pid == 0) {
if (ufpty.cmd) {
char *space = strchr(ufpty.cmd, ' ');
if (space) {
char *argv[4];
argv[0] = uwsgi_binsh();
argv[1] = "-c";
argv[2] = ufpty.cmd;
argv[3] = NULL;
execve(argv[0], argv, uwsgi.environ);
}
else {
char *argv[2];
argv[0] = ufpty.cmd;
argv[1] = NULL;
execve(argv[0], argv, uwsgi.environ);
}
}
else {
char *argv[2];
argv[0] = "/bin/sh";
argv[1] = NULL;
execve(argv[0], argv, uwsgi.environ);
}
// never here;
uwsgi_error("forkptyrouter_alloc_session()/execve()");
exit(1);
}
ucr->cr_table[peer->fd] = peer;
cr_reset_hooks_and_read(peer, fpty_instance_read);
return 0;
}
static int forkptyrouter_init() {
ufpty.cr.session_size = sizeof(struct forkptyrouter_session);
ufpty.cr.alloc_session = forkptyrouter_alloc_session;
uwsgi_corerouter_init((struct uwsgi_corerouter *) &ufpty);
return 0;
}
static void forkptyrouter_setup() {
ufpty.cr.name = uwsgi_str("uWSGI forkptyrouter");
ufpty.cr.short_name = uwsgi_str("forkptyrouter");
}
struct uwsgi_plugin forkptyrouter_plugin = {
.name = "forkptyrouter",
.options = forkptyrouter_options,
.init = forkptyrouter_init,
.on_load = forkptyrouter_setup
};
+8
View File
@@ -0,0 +1,8 @@
NAME='forkptyrouter'
CFLAGS = []
LDFLAGS = []
LIBS = []
REQUIRES = ['corerouter']
GCC_LIST = ['forkptyrouter']
+4 -6
View File
@@ -123,10 +123,9 @@ static void uwsgi_gccgo_initialize() {
int argc = 0;
if (ugccgo.args) {
char *argv_list = uwsgi_str(ugccgo.args);
char *p = strtok(argv_list, " ");
while(p) {
char *p, *ctx = NULL;
uwsgi_foreach_token(argv_list, " ", p, ctx) {
argc++;
p = strtok(NULL, " ");
}
free(argv_list);
}
@@ -134,12 +133,11 @@ static void uwsgi_gccgo_initialize() {
if (argc > 0) {
char **argv = uwsgi_calloc(sizeof(char *) * (argc + 1));
char *argv_list = uwsgi_str(ugccgo.args);
char *p = strtok(argv_list, " ");
char *p, *ctx = NULL;
int n = 0;
while(p) {
uwsgi_foreach_token(argv_list, " ", p, ctx) {
argv[n] = p;
n++;
p = strtok(NULL, " ");
}
runtime_args(argc, argv);
}
+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;
};
+298
View File
@@ -0,0 +1,298 @@
#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, *ctx = NULL;
uwsgi_foreach_token(servers, ";", p, ctx) {
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;
}
}
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));
+4 -6
View File
@@ -181,10 +181,9 @@ static void uwsgi_opt_ldap_dump_ldif(char *opt, char *foo, void *bar) {
entry = &ule[i];
char *list2 = uwsgi_concat2(entry->names + 1, "");
char *p = strtok(list2, " ");
while (p != NULL) {
char *p, *ctx = NULL;
uwsgi_foreach_token(list2, " ", p, ctx) {
uwsgi_log("%.*s $ ", strlen(p) - 2, p + 1);
p = strtok(NULL, " ");
}
free(list2);
@@ -228,10 +227,9 @@ static void uwsgi_opt_ldap_dump(char *opt, char *foo, void *bar) {
entry = &ule[i];
char *list2 = uwsgi_concat2(entry->names + 1, "");
char *p = strtok(list2, " ");
while (p != NULL) {
char *p, *ctx = NULL;
uwsgi_foreach_token(list2, " ", p, ctx) {
uwsgi_log("%.*s $ ", strlen(p) - 2, p + 1);
p = strtok(NULL, " ");
}
free(list2);
+53
View File
@@ -0,0 +1,53 @@
#include <uwsgi.h>
#include <libtcc.h>
uint64_t uwsgi_libtcc_counter = 0;
static int uwsgi_libtcc_hook(char *arg) {
char *func_base = "uwsgi_libtcc_func";
size_t func_len = strlen(func_base) + sizeof(UMAX64_STR);
char *func_name = uwsgi_malloc(func_len);
if (snprintf(func_name, func_len, "%s%llu", func_base, uwsgi_libtcc_counter) < (int) strlen(func_base)) {
free(func_name);
return -1;
}
uwsgi_libtcc_counter++;
size_t source_len = 64 + func_len + strlen(arg);
char *source = uwsgi_malloc(source_len);
if (snprintf(source, source_len, "void %s() { %s ;}", func_name, arg) < (int) ( strlen(func_base) + strlen(arg))) {
free(func_name);
free(source);
return -1;
}
TCCState *s = tcc_new();
if (tcc_compile_string(s, source)) goto error;
if (tcc_relocate(s, TCC_RELOCATE_AUTO)) goto error;
void (*func)() = tcc_get_symbol(s, func_name);
if (!func) goto error;
free(func_name);
free(source);
// call the function
func();
tcc_delete(s);
return 0;
error:
free(func_name);
free(source);
tcc_delete(s);
return -1;
}
static void uwsgi_libtcc_setup() {
uwsgi_register_hook("tcc", uwsgi_libtcc_hook);
}
struct uwsgi_plugin libtcc_plugin = {
.name = "libtcc",
.on_load = uwsgi_libtcc_setup,
};
+5
View File
@@ -0,0 +1,5 @@
NAME='libtcc'
CFLAGS=[]
LDFLAGS=[]
LIBS=['-ltcc']
GCC_LIST=['libtcc']
+18 -2
View File
@@ -1,6 +1,6 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
ssize_t uwsgi_file_logger(struct uwsgi_logger *ul, char *message, size_t len) {
static ssize_t uwsgi_file_logger(struct uwsgi_logger *ul, char *message, size_t len) {
if (!ul->configured) {
if (ul->arg) {
@@ -18,8 +18,24 @@ ssize_t uwsgi_file_logger(struct uwsgi_logger *ul, char *message, size_t len) {
}
static ssize_t uwsgi_fd_logger(struct uwsgi_logger *ul, char *message, size_t len) {
if (!ul->configured) {
ul->fd = -1;
if (ul->arg) ul->fd = atoi(ul->arg);
ul->configured = 1;
}
if (ul->fd >= 0) {
return write(ul->fd, message, len);
}
return 0;
}
void uwsgi_file_logger_register() {
uwsgi_register_logger("file", uwsgi_file_logger);
uwsgi_register_logger("fd", uwsgi_fd_logger);
}
struct uwsgi_plugin logfile_plugin = {
+60
View File
@@ -0,0 +1,60 @@
#include <uwsgi.h>
/*
The pipe logger
Author: INADA Naoki
every log line is sent to the stdin of an external process
Example:
req-logger = pipe:/usr/local/bin/mylogger
*/
static ssize_t uwsgi_pipe_logger(struct uwsgi_logger *ul, char *message, size_t len) {
if (!ul->configured) {
if (ul->arg) {
int pipefd[2];
// retry later...
if (pipe(pipefd) < 0) return -1;
pid_t pid = fork();
if (pid < 0) return -1;
if (pid > 0) {
close(pipefd[0]);
ul->fd = pipefd[1];
}
else {
// child
setsid();
close(pipefd[1]);
dup2(pipefd[0], STDIN_FILENO);
close(pipefd[0]);
uwsgi_exec_command_with_args(ul->arg);
exit(1); // if here something seriously failed
}
}
ul->configured = 1;
}
int err = write(ul->fd, message, len);
// on failed writes, re-configure the logger
if (err <= 0) {
close(ul->fd);
ul->configured = 0;
return err;
}
return 0;
}
static void uwsgi_pipe_logger_register() {
uwsgi_register_logger("pipe", uwsgi_pipe_logger);
}
struct uwsgi_plugin logpipe_plugin = {
.name = "logpipe",
.on_load = uwsgi_pipe_logger_register,
};
+6
View File
@@ -0,0 +1,6 @@
NAME='logpipe'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['logpipe']
+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},
+360
View File
@@ -0,0 +1,360 @@
#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, *ctx = NULL;
uwsgi_foreach_token(ule->args, "|", p, ctx) {
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 = ':';
}
ule->configured = 1;
}
struct uwsgi_buffer *ub = uwsgi_buffer_new(len + strlen(ule->args));
struct uwsgi_msgpack_item *umi = (struct uwsgi_msgpack_item*) ule->data;
uint32_t tmp_len = 0;
while(umi) {
switch(umi->type) {
case(MSGPACK_NIL):
if (uwsgi_buffer_msgpack_nil(ub)) goto end;
break;
case(MSGPACK_TRUE):
if (uwsgi_buffer_msgpack_true(ub)) goto end;
break;
case(MSGPACK_FALSE):
if (uwsgi_buffer_msgpack_false(ub)) goto end;
break;
case(MSGPACK_STR):
if (uwsgi_buffer_msgpack_str(ub, umi->str, umi->str_len)) goto end;
break;
case(MSGPACK_BIN):
if (uwsgi_buffer_msgpack_bin(ub, umi->str, umi->str_len)) goto end;
break;
case(MSGPACK_MAP):
if (uwsgi_buffer_msgpack_map(ub, umi->num)) goto end;
break;
case(MSGPACK_ARRAY):
if (uwsgi_buffer_msgpack_array(ub, umi->num)) goto end;
break;
case(MSGPACK_INT):
if (uwsgi_buffer_msgpack_int(ub, umi->num)) goto end;
break;
case(MSGPACK_FLOAT):
if (uwsgi_buffer_msgpack_float(ub, umi->fnum)) goto end;
break;
case(MSGPACK_MAGIC):
// msg
tmp_len = len;
if (umi->num == 0) {
if (msg[len-1] == '\n') tmp_len--;
if (uwsgi_buffer_msgpack_str(ub, msg, tmp_len)) goto end;
}
// msgbin
else if (umi->num == 1) {
if (msg[len-1] == '\n') tmp_len--;
if (uwsgi_buffer_msgpack_bin(ub, msg, tmp_len)) goto end;
}
// msgnl
if (umi->num == 2) {
if (uwsgi_buffer_msgpack_str(ub, msg, tmp_len)) goto end;
}
// msgbinnl
else if (umi->num == 3) {
if (uwsgi_buffer_msgpack_bin(ub, msg, tmp_len)) goto end;
}
// unix
else if (umi->num == 4) {
if (uwsgi_buffer_msgpack_int(ub, (int64_t)uwsgi_now())) goto end;
}
// micros
else if (umi->num == 5) {
if (uwsgi_buffer_msgpack_int(ub, (int64_t)uwsgi_micros())) goto end;
}
// strftime
else if (umi->num == 6) {
char sftime[64];
time_t now = uwsgi_now();
int rlen = strftime(sftime, 64, umi->str, localtime(&now));
if (rlen > 0) {
if (uwsgi_buffer_msgpack_str(ub, sftime, rlen)) goto end;
}
else {
if (uwsgi_buffer_msgpack_str(ub, "", 0)) goto end;
}
}
break;
default:
break;
}
umi = umi->next;
}
buf = ub->buf;
*rlen = ub->pos;
ub->buf = NULL;
end:
uwsgi_buffer_destroy(ub);
return buf;
}
static void uwsgi_msgpack_register() {
uwsgi_register_log_encoder("msgpack", uwsgi_msgpack_log_encoder);
}
struct uwsgi_plugin msgpack_plugin = {
.name = "msgpack",
.on_load = uwsgi_msgpack_register,
};
+5
View File
@@ -0,0 +1,5 @@
NAME='msgpack'
CFLAGS=[]
LDFLAGS=[]
LIBS=[]
GCC_LIST = ['msgpack']
+8 -9
View File
@@ -5,25 +5,24 @@ NAME='php'
ld_run_path = None
PHPPATH = 'php-config'
try:
phpdir = os.environ['UWSGICONFIG_PHPDIR']
phpdir = os.environ.get('UWSGICONFIG_PHPDIR')
if phpdir:
ld_run_path = "%s/lib" % phpdir
PHPPATH = "%s/bin/php-config" % phpdir
except:
pass
try:
PHPPATH = os.environ['UWSGICONFIG_PHPPATH']
except:
pass
PHPPATH = os.environ.get('UWSGICONFIG_PHPPATH', PHPPATH)
CFLAGS = [os.popen(PHPPATH + ' --includes').read().rstrip(), '-Wno-sign-compare']
LDFLAGS = os.popen(PHPPATH + ' --ldflags').read().rstrip().split()
if ld_run_path:
LDFLAGS.append('-L%s' % ld_run_path)
os.environ['LD_RUN_PATH'] = ld_run_path
LIBS = [os.popen(PHPPATH + ' --libs').read().rstrip(), '-lphp5']
phplibdir = os.environ.get('UWSGICONFIG_PHPLIBDIR')
if phplibdir:
LIBS.append('-Wl,-rpath=%s' % phplibdir)
GCC_LIST = ['php_plugin']
+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 *);
+19 -3
View File
@@ -383,10 +383,9 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
AV *uperl_argv = GvAV(PL_argvgv);
if (uperl.argv_items) {
char *argv_list = uwsgi_str(uperl.argv_items);
char *p = strtok(argv_list, " ");
while(p) {
char *p, *ctx = NULL;
uwsgi_foreach_token(argv_list, " ", p, ctx) {
av_push(uperl_argv, newSVpv(p, 0));
p = strtok(NULL, " ");
}
}
struct uwsgi_string_list *usl = uperl.argv_item;
@@ -483,6 +482,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 +511,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", required_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);
}
+64 -4
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);
@@ -262,8 +320,9 @@ void init_pyargv() {
char *tmp_ptr = uwsgi_str(up.argv);
#ifdef __sun__
// FIX THIS !!!
ap = strtok(tmp_ptr, " ");
while ((ap = strtok(NULL, " ")) != NULL) {
char *ctx = NULL;
ap = strtok_r(tmp_ptr, " ", &ctx);
while ((ap = strtok_r(NULL, " ", &ctx)) != NULL) {
#else
while ((ap = strsep(&tmp_ptr, " \t")) != NULL) {
#endif
@@ -294,8 +353,9 @@ void init_pyargv() {
#ifdef __sun__
// FIX THIS !!!
ap = strtok(py_argv_copy, " ");
while ((ap = strtok(NULL, " ")) != NULL) {
char *ctx = NULL;
ap = strtok_r(py_argv_copy, " ", &ctx);
while ((ap = strtok_r(NULL, " ", &ctx)) != NULL) {
#else
while ((ap = strsep(&py_argv_copy, " \t")) != NULL) {
#endif
+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

Some files were not shown because too many files have changed in this diff Show More