Compare commits

..
234 Commits
Author SHA1 Message Date
Unbit ab4afdbeaa fixed template plugin 2013-11-09 06:39:29 +01:00
Unbit 54e2d698cb prepare for uWSGI 1.9.19 2013-11-09 04:58:52 +01:00
Unbit 8b0565c0b8 added metric api to ruby 2013-11-09 04:31:14 +01:00
unbit 102d6f25ed Merge pull request #447 from flavour/master
Support HTTP Status 509
2013-11-08 03:05:11 -08:00
Fran Boon d0a53aa976 Support HTTP Status 509
Whilst this isn't an official RFC, it's documented on e.g. Wikipedia. http://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_Server_Error
2013-11-08 10:49:48 +00:00
Unbit f8cf808e47 metrics as objects in stats subsystem 2013-11-07 12:10:56 +01:00
Unbit f8bbd2177e added stats pusher default plugins 2013-11-07 11:27:40 +01:00
Unbit f44c145941 do not destroy the stats pusher loop on EINTR 2013-11-07 09:54:16 +01:00
Unbit f34ac9f6aa completed metric threshold subystem 2013-11-07 09:43:01 +01:00
Unbit b971230fd9 use uwsgi.start_tv for srand instead of recomputing it 2013-11-07 08:56:04 +01:00
Unbit 5c6340caac busy_workers and idle_workers must be GAUGE 2013-11-07 07:45:12 +01:00
Unbit c0b97b47d3 implemented #284 2013-11-07 06:43:13 +01:00
Unbit a6b7f6e5bb added better random initialization and rr/rand hash algos 2013-11-06 18:20:38 +01:00
Unbit 1b99f9a750 added no_content_length to the cache router 2013-11-06 11:44:47 +01:00
Unbit a434195318 transformation_template has been moved to a plugin 2013-11-06 11:39:34 +01:00
Unbit a6a8faea78 added 'uwsgi' transformation 2013-11-06 10:52:19 +01:00
Unbit 31458320ab optimization in sendnl routing 2013-11-06 10:35:39 +01:00
Unbit 037a1f7f77 fixed #404 2013-11-05 09:43:11 +01:00
Unbit 10d4d10ac9 do not register metrics if metrics subsystem is not enabled 2013-11-04 15:12:18 +01:00
Unbit 00e8d509f8 metrics for routed and unrouted signals 2013-11-04 15:07:40 +01:00
Unbit c9ca14df4d fixed rbtimers 2013-11-03 19:31:18 +01:00
unbit 841cdfc62d Merge pull request #443 from prymitive/carbon_no_retry
allow disabling retries in carbon
2013-11-02 11:19:08 -07:00
Łukasz Mierzwa fc7026c076 allow disabling retries in carbon 2013-11-02 18:59:25 +01:00
unbit b96581c183 Merge pull request #442 from xrmx/coverityjvm
Add jvm plugins to coverity build profile
2013-11-02 10:35:24 -07:00
Riccardo Magliocchetti 4fa5d72af6 Add jvm plugins to coverity build profile 2013-11-02 18:13:57 +01:00
unbit f4be581666 Merge pull request #441 from xrmx/jvmarch2
plugins/jvm: let override jvm arch
2013-11-02 10:07:39 -07:00
unbit 24fb5518d8 Merge pull request #440 from Kapishin/master
Fix typos
2013-11-02 10:07:08 -07:00
unbit 2e8061d62a Merge pull request #439 from xrmx/coverity0211
More Coverity fixes
2013-11-02 10:06:42 -07:00
Riccardo Magliocchetti 23d70f6936 plugins/jvm: let override jvm arch
On mixed 64 bit kernel / 32 bit userspace linux systems the jvm
does not get recognized automatically if installed.

Permit to force an arch by exporting JVM_ARCH which is way more
easier than exporting the full path for includes and libraries.
2013-11-02 17:54:20 +01:00
Pavlo Kapyshin 95ea88628a Fix typos 2013-11-02 18:40:05 +02:00
Riccardo Magliocchetti 68b411f487 plugins/xslt: correct logical operator
Fixes a null pointer dereference.

Reported by Coverity as CID #1125160
2013-11-02 16:38:10 +01:00
Riccardo Magliocchetti 40bfbc0a44 plugins/pty: Fix a couple of memory issues
Rpoerted by Coverity as CID #1125163 and #1125162
2013-11-02 16:33:48 +01:00
Riccardo Magliocchetti fc9b6ea275 plugins/xslt: fix memory leaks
Rpeorted by Coverity as CID #1125164
2013-11-02 16:25:50 +01:00
Riccardo Magliocchetti 522f3bb3a1 plugins/xslt: fix xmlfile lifecycle
Fixes an use after free and a memory leak.

Reported by Coverity as CID #1125165, #1125167
2013-11-02 16:17:53 +01:00
Riccardo Magliocchetti 743c7ceaa6 plugins/v8: fix double free
Reported by Coverity as CID #1125166
2013-11-02 16:09:58 +01:00
Riccardo Magliocchetti c780cd47ce Update coverity build profile
Add a few more plugins and remove go that does not build.
2013-11-02 15:53:23 +01:00
unbit 54e7e01c05 Merge pull request #437 from prymitive/stats_pusher_retry
Restore retry handling in carbon
2013-11-01 22:35:22 -07:00
Łukasz Mierzwa 7d422d11e4 port carbon plugin to support retries in stats pusher, replaces old non-functional retry handling 2013-11-01 20:07:08 +01:00
Łukasz Mierzwa 5c35b60d1d add retry support to stats pusher 2013-11-01 19:43:15 +01:00
Unbit 94353efb3f correctly support python2.4 2013-11-01 10:02:35 +01:00
Roberto De Ioris 0586a2ba47 fixed #436 2013-11-01 09:54:01 +01:00
Roberto De Ioris be6081c6f7 port the carbon metric feature to latest api 2013-11-01 09:51:00 +01:00
unbit 955fb6479e Merge pull request #435 from prymitive/carbon_use_metrics
enable switching stats source from carbon's own loop to metrics data
2013-11-01 01:50:09 -07:00
Łukasz Mierzwa 1b334e8cf7 enable switching stats source from carbon's own loop to metrics data, fixes #417 2013-10-31 18:38:54 +01:00
Unbit 718e198ac8 little optimization in master fifo 2013-10-28 22:14:50 +01:00
unbit 3757e5a8bb Merge pull request #433 from xrmx/coverity2810-2
More Coverity fixes
2013-10-28 14:13:25 -07:00
Riccardo Magliocchetti d505964321 plugins/gevent: don't dereference null pointer
We should not pass a NULL pointer to Py_DECREF. This is possible
if wsgi_req->socket->edge_trigger is true.

Reported by Coverity as CID #970981.
2013-10-28 19:38:02 +01:00
Riccardo Magliocchetti 1114c1a429 core/fifo: check array index read before dereferencing uwsgi_master_fifo_manage
Reported by Coverity as CID #1100821
2013-10-28 19:29:25 +01:00
Riccardo Magliocchetti f58a9c6119 plugins/router_hash: don't dereference a null pointer
In case this condition is true:

    if (urhc->items[i] == ';') {

but this is false:

    if (found == hashed_result)

for the latest loop iteration value would be set as NULL

This is a bit unfortunate because later we can:
- use it in arithmetics
- dereference it in uwsgi_req_append

To fix that update vallen only if value is not null.

Reported by Coverity sa CID #1100805.
2013-10-28 19:27:06 +01:00
Riccardo Magliocchetti e791cb2c00 core/utils: cleanup if condition
uwsgi.ksm_mappings_current_size cannot be 0 here.
A couple of lines above:

1219 if (uwsgi.ksm_mappings_current_size <= 0) {
1220     uwsgi_log("[uwsgi-KSM] unable to read /proc/self/maps data\n");
1221     return;
1222 }
2013-10-28 19:26:51 +01:00
Unbit f741dbb01b added options for metric thresholds 2013-10-28 17:18:45 +01:00
Unbit d5f0741e8d metrics threshold structures 2013-10-28 17:16:17 +01:00
Unbit b265ed8313 avoid kevent storm for stats pusher thread 2013-10-28 17:09:27 +01:00
Unbit 6cb160bb26 support for WSGI genrators in tornado 2013-10-28 09:55:06 +01:00
Unbit 009a3f2c0d fixed greenlet memory leaks 2013-10-28 07:59:45 +01:00
Unbit 11b3d1fb94 greenlet plugin still need a bit of checks for reference counting 2013-10-27 19:06:18 +01:00
Unbit 7a39472700 various improvements in greenlet plugin 2013-10-27 18:31:31 +01:00
Unbit 4489b48603 added tornado loop engine 2013-10-27 18:08:34 +01:00
Unbit d2f69af964 fixed #428 2013-10-26 05:47:47 +02:00
unbit 34e9dabffc Merge pull request #430 from xrmx/coverity2510
Fix some leaks reported by coverity
2013-10-25 19:14:19 -07:00
unbit 6a4f46639e Merge pull request #432 from TheRealBill/master
Fixing argument for length of the string 'destroy'
2013-10-25 19:09:56 -07:00
Bill Anderson 0d07ff25f9 Fixing argument for length of the string 'destroy' 2013-10-25 13:20:11 -05:00
Riccardo Magliocchetti c1d9c4ef12 core/utils: fix resource leak in uwsgi_write_intfile
The more error condition you squeeze in one line the more chances
to leak :)

Reported by Coverity as CID #1100812
2013-10-25 19:53:04 +02:00
Riccardo Magliocchetti 0227ff7a9b core/utils: fix resource leak
Reported by Coverity as CID #1100814
2013-10-25 19:45:51 +02:00
Riccardo Magliocchetti 082b178ae3 core/io: Fix resource leak
Reported by Coverity as CID #1100815
2013-10-25 19:41:27 +02:00
Riccardo Magliocchetti 0e695cbd6e core/fsmon: fix memory leak
Reported by Coverity as CID #1100817
2013-10-25 19:35:38 +02:00
Riccardo Magliocchetti be2ed4dc4a core/snmp: fix usage of pointer outside of scope
Reported by Coverity as CID #1112122
2013-10-25 19:30:08 +02:00
Riccardo Magliocchetti 4777666588 plugins/rrdtools: don't leak filename
Reported by coverity as CID #1112121
2013-10-25 19:26:58 +02:00
Unbit 5647057ecc fixed UWSGI_PROFILE usage 2013-10-25 09:27:45 +02:00
Unbit 94cb950058 better error reporting for cgroups 2013-10-25 08:26:51 +02:00
Unbit 8d65371bf6 completely skip cgroups initialization when non-root 2013-10-24 21:34:07 +02:00
Unbit c747a36ae1 added PROFILE to Makefile 2013-10-24 18:55:55 +02:00
Unbit e51cb65857 fixed #427 2013-10-24 18:52:03 +02:00
unbit 8fa4fdb8c8 Merge pull request #426 from apoh/master
set python-bin from enviroment variable in Makefile
2013-10-24 06:16:12 -07:00
apoh d584857c78 set python-bin from enviroment variable in Makefile
currently the Makefile can only deal with the python-binary
wich is link to python. If you like to compile uwsgi with a
different pyhton-version you can just use

export PYTHON_BIN=/path/to/your/python
2013-10-23 17:32:36 +02:00
Unbit f0b1d79f8b added metrics api to pypy 2013-10-22 19:37:21 +02:00
Unbit 28566ad772 threads must be implicit in PyPy 2013-10-22 19:29:12 +02:00
Unbit 40c0e139d4 added metric api to python plugin 2013-10-22 16:25:56 +02:00
Unbit 04f2444ea0 added --zabbix-template 2013-10-22 12:11:19 +02:00
Unbit 9f71d28afa snmp integration with metrics subsystem 2013-10-22 10:18:09 +02:00
Unbit af262fb325 completed metric file collector 2013-10-22 07:08:12 +02:00
Unbit 243657b5aa added pluggables metric collectors 2013-10-22 06:29:01 +02:00
Unbit 032302edaa fixed #425 2013-10-22 05:18:57 +02:00
Unbit d4bd658d84 added restorable metrics 2013-10-21 19:01:06 +02:00
Unbit 78843c3e06 added --vassal-set 2013-10-21 18:21:59 +02:00
Unbit 692ba1f6b3 added shortcut mode for --metric 2013-10-21 16:13:33 +02:00
Unbit 400a9d72ef reimplemented metrics initial_value 2013-10-21 15:59:25 +02:00
Unbit 11f8f0385a added router_metrics plugin 2013-10-21 15:48:37 +02:00
Unbit c40d15981c exposed the metric routing var 2013-10-21 14:32:59 +02:00
Unbit baa1bf21f1 expose metrics to request logging 2013-10-21 10:54:19 +02:00
Unbit 3dd3122236 ported rrdtool to the metric api 2013-10-21 10:37:50 +02:00
Unbit 927ef2ccde added sockets metrics 2013-10-19 18:33:41 +02:00
Unbit af6eaf6737 completed perl metric api 2013-10-19 09:54:28 +02:00
unbit 7c543f5627 Merge pull request #424 from prymitive/daemon_fix
daemon throttle code could pass values < 0 to sleep()
2013-10-18 14:11:52 -07:00
Łukasz Mierzwa b06e35c610 fixed sleep in daemons throttle code, sleep() only accepts unsigned int, but in some cases uWSGI could pass value < 0 2013-10-18 22:33:48 +02:00
unbit 842c2148d7 fixed websocket example 2013-10-18 20:18:51 +02:00
unbit a2a94bd78e fixed websocket example for python3 2013-10-18 19:28:55 +02:00
Unbit 4452c30fc8 fixed typecasting 2013-10-18 18:46:17 +02:00
Unbit f462792c8e fixed uwgsi-docs bug 98 2013-10-18 12:13:02 +02:00
Unbit 03879fdc0c first test for metric api from apps (perl only) 2013-10-18 09:35:04 +02:00
Unbit 389d0b95d5 added the zabbix plugin (metrics based) 2013-10-17 16:30:19 +02:00
Unbit 6ec32e192f added puwsgi protocol 2013-10-17 10:15:34 +02:00
Roberto De Ioris 22c034cdca removed uwsgidump protocol 2013-10-17 05:57:43 +02:00
unbit 396d8c3022 Merge pull request #422 from prymitive/metrics_cast
missing cast to long long in metrics
2013-10-16 15:26:13 -07:00
Łukasz Mierzwa a535ecbe17 missing cast to long long in metrics 2013-10-16 22:56:31 +02:00
Unbit fd436c3e4f starting 1.9.19-dev 2013-10-16 20:59:15 +02:00
Unbit e5c245ea2f fixed stdin and embed configs 2013-10-16 20:51:26 +02:00
Unbit 3008b7c83b fixed #420 2013-10-16 05:39:28 +02:00
Unbit eca6cd3066 added --iprint 2013-10-15 20:11:22 +02:00
Unbit 691a41f290 ignore specific vars with prefix UWSGI_ 2013-10-15 18:16:03 +02:00
Unbit df4cf539a1 automatically enable metrics with stats pushers 2013-10-15 16:11:59 +02:00
Unbit baa1167dfe exposed metric api functions 2013-10-15 16:02:52 +02:00
Unbit d8a83ab7cf added metric aliases 2013-10-15 15:04:10 +02:00
Unbit 8184351b3b implemented SUM metrics and parent/child relationship 2013-10-15 14:46:53 +02:00
Unbit 4a4dbbcf69 ported the stats plugin to the metric subsystem 2013-10-15 14:08:01 +02:00
Unbit 56f79efc74 fixed json format for metrics 2013-10-15 11:13:14 +02:00
Unbit ea073a9bbd exposes metrics to stats 2013-10-15 11:11:18 +02:00
Unbit c5b2ca4b20 added delta_requests and write_errors to metrics 2013-10-15 09:02:43 +02:00
Unbit c0f9d8d2ff prepare for file as metric source 2013-10-14 19:19:05 +02:00
Unbit 497660279f Merge branch 'master' of github.com:unbit/uwsgi 2013-10-14 15:11:09 +02:00
Unbit 625395bd26 preliminary metrics subsystem code 2013-10-14 15:10:53 +02:00
Unbit 79a7797409 fixed #415 2013-10-12 08:05:56 +02:00
Unbit 3b13de3e6e check for NULL dictionary values in python autoreloader 2013-10-12 00:34:31 +02:00
Unbit 7f99855527 1.9.18.1 2013-10-11 14:27:26 +02:00
Unbit 8c29178f81 fixed kFreeBSD support 2013-10-11 16:24:46 +02:00
Unbit ed71000033 fixed FreeBSD compilation 2013-10-11 09:44:50 +02:00
Unbit 20860ed069 fixed python3 build 2013-10-11 14:07:02 +02:00
Unbit 2e62f13917 fixed mono options parsing 2013-10-11 05:59:20 +02:00
Unbit 1b2a83ce70 updated gemspec for 1.9.18 2013-10-11 05:51:19 +02:00
Unbit 113ec5ae9e added minimal profiles 2013-10-11 05:05:07 +02:00
root 68e81828d1 finally fixed the problem with python and arm (raspberrypi/sheevaplug) 2013-10-11 02:50:40 +00:00
Unbit 543790dc83 auto-modifier1 only if modifier1 is 0 2013-10-10 09:29:28 +02:00
unbit be24060578 Merge pull request #414 from arkaitzj/master
Still need to loop again when EAGAIN after a read triggered by an event, Fixes #363
2013-10-09 20:14:05 -07:00
Arkaitz Jimenez bdedc1c94c Still need to loop again when EAGAIN after a read triggered by an event 2013-10-10 00:12:57 +02:00
unbit e2454aa898 Merge pull request #413 from prymitive/backlog2
fixed backlog2 example plugin
2013-10-08 18:55:10 -07:00
Łukasz Mierzwa dfa4834be3 fixed backlog2 example plugin 2013-10-08 23:16:03 +02:00
Unbit f204249110 better fallback for non-zero modifiers 2013-10-07 17:50:43 +02:00
Unbit f4c25a6cd1 prepare for 1.9.18 release 2013-10-07 13:23:05 +02:00
Unbit fbfbacce14 fixed attach.py 2013-10-07 13:03:50 +02:00
Unbit a0eed32b3f move uWSGI 1.9 to GPL2 + linking exception 2013-10-07 12:19:33 +02:00
Unbit 9fe9fe1bb6 fixed data:// scheme 2013-10-07 11:37:52 +02:00
Unbit 192312e3ea avoid crashing on non-conformant PSGI response headers 2013-10-07 10:21:39 +02:00
Unbit ee46fe6ba6 Merge branch 'master' of github.com:unbit/uwsgi 2013-10-07 10:11:59 +02:00
Unbit 58abd07a88 support remote sources for perl scripts 2013-10-07 10:11:50 +02:00
Unbit c246a6008e correctly returns http error on connect 2013-10-07 10:11:23 +02:00
Unbit 706f1b59c3 make clang happy 2013-10-07 09:52:32 +02:00
Unbit ddbc8920f7 use uwsgi_open_and_read for perl files 2013-10-07 09:50:56 +02:00
Roberto De Ioris 7e3bf6868e fixed perl autoreload when under clang 2013-10-06 11:01:12 +02:00
Unbit 4c7ecef577 added perl auto reloader 2013-10-06 10:52:27 +02:00
Unbit e3da0aaad4 automatically returns the default app even if the modifier is wrong 2013-10-06 09:26:08 +02:00
Unbit 99e576e40c support pty on NetBSD 2013-10-06 07:04:12 +02:00
Unbit 7604ce3441 --wsgi-accept-buffers 2013-10-05 12:34:57 +02:00
Unbit a0082b5b98 accepting buffer is an option: --wsgi-accept-buffer 2013-10-05 12:32:49 +02:00
Unbit c90c639348 --wsgi-strict disable string/bytes optimizations too 2013-10-05 09:09:53 +02:00
Unbit 2e188dc25a fixed big endian support for uwsgi protocol 2013-10-05 07:15:36 +02:00
Unbit 312d21cb3f added 'before' variants for vassals templating 2013-10-05 07:07:48 +02:00
unbit 4ee138be7c Merge pull request #411 from thekad/master
updating so jvm plugin can compile in arm
2013-10-04 21:22:01 -07:00
Jorge Gallegos 299aef99b3 updating so jvm plugin can compile in arm
This *should* work for all arm versions so far and still works for i386/x86_64
2013-10-04 16:39:54 -07:00
Unbit 06953e4547 fixed uwsgiconfig.py for embed_config 2013-10-04 17:13:10 +02:00
Unbit 7565ee8740 fixed a memleak spotted by cppcheck 2013-10-04 12:29:16 +02:00
Unbit 10377f02a3 run the autoreloader even in non-apps mode when non-lazy 2013-10-04 06:22:06 +02:00
Unbit a41e6e2c61 added --emperor-cap 2013-10-04 06:11:29 +02:00
Unbit 6b2b909d33 apply PR_SET_PDEATHSIG to vassals on linux 2013-10-03 19:46:33 +02:00
Unbit 70cd18bffb added --unshare2 2013-10-03 19:43:43 +02:00
Unbit d6be4bcad9 added --mountpoint-check 2013-10-03 14:42:52 +02:00
Unbit 85530b5d8e added --exit 2013-10-03 11:38:51 +02:00
Unbit e3848e84d3 expose more clone() flags 2013-10-03 10:42:55 +02:00
Unbit 4ec9312b10 pivot_root improvements 2013-10-02 16:52:14 +02:00
Unbit aedf3b2455 reindented core/utils.c 2013-10-02 13:58:18 +02:00
Unbit 2210ec7f71 added call scheme 2013-10-02 10:58:27 +02:00
Unbit a9bee41707 added UWSGI_ADDITIONAL_SOURCES env var and additional_sources buildconf option 2013-10-02 10:52:53 +02:00
Unbit 3adbfd100f allow overriding schemes 2013-10-02 10:39:41 +02:00
Unbit 8d8de4b8da pluginized uwsgi_open_and_read 2013-10-02 10:37:39 +02:00
Unbit 099403d554 fixed #409 2013-10-02 09:39:33 +02:00
Unbit 13938a6aa7 more consistent placeholders support 2013-10-02 09:31:48 +02:00
Unbit 9be3a4aaf8 various consistency fixes for strict mode + autoload 2013-10-02 08:41:43 +02:00
Unbit 009e42f349 fixed #409 2013-10-02 07:42:41 +02:00
Unbit 207dd3bc77 fixed #407 2013-10-02 07:36:14 +02:00
Unbit feec6b3151 do not set upper magic vars in --inherit or --include mode 2013-10-01 18:42:30 +02:00
Unbit bf8207f0f1 added magic vars for original config file 2013-10-01 18:16:01 +02:00
Unbit 9fcbc6ee68 added --set-placeholder/--set-ph 2013-10-01 15:50:46 +02:00
Unbit dcb58aaa34 added UWSGI_EMBED_CONFIG variable 2013-10-01 15:39:07 +02:00
Unbit 7163d8ddd4 fixed #406 2013-10-01 15:30:39 +02:00
Unbit c7b24eec45 fixed regression in --set as a workaround for broken getopt_long 2013-10-01 15:02:33 +02:00
Unbit 1e7098f787 fixed #405 2013-10-01 13:27:50 +02:00
Unbit b28f0d9863 fixed #405 2013-10-01 12:22:30 +02:00
Unbit b49c4f4af9 chdir at every emperor glob interaction 2013-10-01 11:38:29 +02:00
Unbit 2c39aafb0b honour --force-cwd 2013-10-01 11:32:17 +02:00
unbit 1036d9c18b Merge pull request #402 from xrmx/ia64
Ia64 fixes
2013-09-30 08:31:03 -07:00
Unbit f0c8cbf190 try specified rvm paths first 2013-09-30 17:12:54 +02:00
Unbit f51db4481b added sendfile support to raw mode 2013-09-30 15:45:27 +02:00
Unbit 717eba7ab3 implemented raw response for python 2013-09-30 15:25:00 +02:00
Unbit 3cc971ba55 raw sockets must be undeferred 2013-09-30 15:01:58 +02:00
Unbit 23b3d7483f introducing raw mode 2013-09-30 13:43:13 +02:00
unbit ba03837e29 Merge pull request #297 from prymitive/dfix
fixed dump daemon process termination
2013-09-30 04:41:37 -07:00
Łukasz Mierzwa 06952fbaff wait for deamon pid after SIGTERM to prevent it from becoming zombie 2013-09-30 12:56:01 +02:00
Unbit 27be00b4cc fixed #399 2013-09-30 11:47:14 +02:00
unbit b50a377190 Merge pull request #217 from prymitive/idle_fix
zero pids after worker killed due to --idle usage
2013-09-30 01:51:22 -07:00
Unbit 1ed9cb0bec prepare for 1.9.18 2013-09-30 09:46:17 +02:00
unbit a548ede3c7 Merge pull request #400 from xrmx/config-cleanup
Some uwsgiconfig.py cleanups
2013-09-30 00:44:38 -07:00
unbit de26c09030 Merge pull request #401 from prymitive/cheaper_fix_limit
adapted cheaper algos to work properly with cheaper limits
2013-09-30 00:41:45 -07:00
Unbit 19aa7c2560 clear exception on PyObject_CheckReadBuffer error 2013-09-30 09:40:40 +02:00
Unbit 215e0c4cbc typos 2013-09-30 09:26:58 +02:00
Unbit d484acefa4 use buffer protocol in WSGI response 2013-09-30 09:25:25 +02:00
Riccardo Magliocchetti 4032efd3e8 Add proper ifdefery for namespaces on ia64
Fix #398
2013-09-29 21:45:07 +02:00
Riccardo Magliocchetti f9d412bcca uwsgiconfig: restore obsolete linux check on ia64
Fix #397
2013-09-29 21:35:38 +02:00
Łukasz Mierzwa 5f52063b9e cheaper API change to allow signaling cheaper algo if it can spawn new workers or only cheap them. Fixes #394 2013-09-29 20:30:29 +02:00
Riccardo Magliocchetti 87833abb42 uwsgiconfig: add --debug and --asan options
--debug compiles with debug symbols
--asan adds support for compiling with address sanitizer, see
http://clang.llvm.org/docs/AddressSanitizer.html#usage
Should work with clang and gcc 4.8. Does not find as many issues
as valgrind but having lot less overhead could be enabled in more
situations.

While at it handle --cflags and --build together instead of
duplicating code.
2013-09-29 18:29:14 +02:00
Riccardo Magliocchetti 0fcbd5e334 uwsgiconfig: add --verbose switch
Print the whole compilation commandlines

Based on a patch from Jonas Smedegaard
2013-09-29 17:36:26 +02:00
Riccardo Magliocchetti 5b55bf5f5c uwsgiconfig: use optparse for arguments passing
This opens the possibility (if desired) to have multiple options
passed at the same time, the same options repeated, etc...
Also it gives an help for free.
2013-09-29 17:28:45 +02:00
Riccardo Magliocchetti b8cc1d962f uwsgiconfig: cleanup report initialization 2013-09-29 13:57:06 +02:00
Unbit 762c73e2ac close workers sockets in gateways 2013-09-28 12:06:22 +02:00
Unbit 57cd0e9135 closed #391 and #392 2013-09-28 12:01:59 +02:00
Roberto De Ioris 5e0a85bff0 use execv instead of execve 2013-09-28 05:56:13 +02:00
unbit d2eaef524c Merge pull request #393 from prymitive/cheaper_limit_typo
fixed stupid typo in cheaper rss limits options validation
2013-09-27 19:51:18 -07:00
Łukasz Mierzwa a98c5a3931 fixed stupid typo in cheaper rss limits options validation 2013-09-27 23:21:45 +02:00
Unbit 040da07323 added forkptyrouter-rows and forkptyrouter-cols 2013-09-27 16:10:55 +02:00
Unbit 34f43ec97b support pty in Debian kFreeBSD 2013-09-27 08:12:45 +02:00
Unbit 7e3cfe94d6 improved forkptyrouter 2013-09-26 20:29:04 +02:00
Unbit e2c3b650a1 completed --pty-uconnect 2013-09-26 20:03:02 +02:00
Unbit 404dfaeda7 fixed initial logging 2013-09-26 19:59:49 +02:00
Unbit a1ec530945 implemented uwsgi protocol for forkptyrouter 2013-09-26 19:28:09 +02:00
Unbit b8dfd617f2 minor fixes 2013-09-26 10:18:16 +02:00
Unbit f34ed4dc47 added --attach-control-daemon 2013-09-26 09:36:31 +02:00
Unbit cd2ff0e585 emperor proxy 2013-09-26 07:51:13 +02:00
Unbit 449955562f expose 'cursed' field in emperor stats 2013-09-26 07:09:57 +02:00
Unbit 41a4bbccfc added Emperor curse support 2013-09-26 07:04:08 +02:00
Unbit 87b17c001d some typo 2013-09-26 05:32:27 +02:00
Unbit 67b7753814 use MAP_FAILED check for mmap() 2013-09-25 16:24:20 +02:00
Unbit b190744b77 on kFreeBSD python atexit will make mess, disable it for now 2013-09-25 09:20:20 +02:00
Unbit 4b603071d8 preliminary support for Debian kFreeBSD 2013-09-25 07:18:17 +02:00
Unbit 16c55f0217 preliminary libffi plugin 2013-09-24 17:45:34 +02:00
Unbit c989f2fb33 added api func uwsgi_split_quoted 2013-09-24 17:45:03 +02:00
Łukasz Mierzwa edbff83fd6 zero pids after worker killed due to --idle usage 2013-04-08 10:32:39 +02:00
107 changed files with 6218 additions and 2082 deletions
+16
View File
@@ -1,3 +1,19 @@
----------------------------------------------------------------------
LINKING EXCEPTION
In addition to the permissions in the GNU General Public License,
the authors give you unlimited permission to link the compiled
version of this library into combinations with other programs,
and to distribute those combinations without any restriction
coming from the use of this file. (The General Public License
restrictions do apply in other respects; for example, they cover
modification of the file, and distribution when not linked into
a combined executable.)
----------------------------------------------------------------------
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
+5 -3
View File
@@ -1,8 +1,10 @@
PYTHON := python
all:
python uwsgiconfig.py --build
$(PYTHON) uwsgiconfig.py --build $(PROFILE)
clean:
python uwsgiconfig.py --clean
$(PYTHON) uwsgiconfig.py --clean
check:
python uwsgiconfig.py --check
$(PYTHON) uwsgiconfig.py --check
+2 -2
View File
@@ -7,7 +7,7 @@ filename = sys.argv[1]
size = os.path.getsize(filename)
f = open(filename, 'r')
print(f.read())
os.write(1, f.read())
f.close()
print(struct.pack("<Q", size))
os.write(1, (struct.pack("<Q", size)))
+1 -1
View File
@@ -17,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, router_expires
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, router_metrics, transformation_template, stats_pusher_socket
as_shared_library = false
locking = auto
+2 -2
View File
@@ -1,4 +1,4 @@
[uwsgi]
# pypy,jvm,ring,jwsgi
main_plugin = erlang,psgi,rack,lua,python,gevent,php,cgi,mono,pyerl,go
# pypy,go
main_plugin = erlang,psgi,rack,lua,python,gevent,php,cgi,pyerl,glusterfs,pty,xslt,msgpack,geoip,v8,pam,ldap,mono,jvm,ring,jwsgi
inherit = base
+33
View File
@@ -0,0 +1,33 @@
[uwsgi]
xml = false
yaml = false
json = false
zeromq = false
ssl = false
pcre = false
routing = false
matheval = false
debug = false
unbit = false
xml_implementation = none
yaml_implementation = none
malloc_implementation = libc
extras =
plugins =
bin_name = uwsgi
append_version =
plugin_dir = .
embedded_plugins = %(main_plugin)s
as_shared_library = false
locking = auto
event = auto
timer = auto
filemonitor = auto
blacklist =
whitelist =
embed_files =
embed_config =
+3
View File
@@ -0,0 +1,3 @@
[uwsgi]
main_plugin = psgi
inherit = minimal
+3
View File
@@ -0,0 +1,3 @@
[uwsgi]
main_plugin = python
inherit = minimal
+3
View File
@@ -0,0 +1,3 @@
[uwsgi]
main_plugin = pypy
inherit = minimal
+3
View File
@@ -0,0 +1,3 @@
[uwsgi]
main_plugin = rack
inherit = minimal
+22 -17
View File
@@ -308,29 +308,42 @@ end:
async_reset_request(uwsgi.wsgi_req);
uwsgi_close_request(uwsgi.wsgi_req);
uwsgi.wsgi_req->async_status = UWSGI_OK;
uwsgi.async_queue_unused_ptr++;
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
}
void async_schedule_to_req_green(void) {
struct wsgi_request *wsgi_req = uwsgi.wsgi_req;
#ifdef UWSGI_ROUTING
if (uwsgi_apply_routes(uwsgi.wsgi_req) == UWSGI_ROUTE_BREAK) {
if (uwsgi_apply_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
goto end;
}
#endif
for(;;) {
if (uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req) <= UWSGI_OK) {
if (uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req) <= UWSGI_OK) {
break;
}
uwsgi.wsgi_req->switches++;
wsgi_req->switches++;
if (uwsgi.schedule_fix) {
uwsgi.schedule_fix(wsgi_req);
}
// switch after each yield
uwsgi.schedule_to_main(uwsgi.wsgi_req);
uwsgi.schedule_to_main(wsgi_req);
}
#ifdef UWSGI_ROUTING
end:
#endif
async_reset_request(uwsgi.wsgi_req);
uwsgi_close_request(uwsgi.wsgi_req);
uwsgi.wsgi_req->async_status = UWSGI_OK;
// re-set the global state
uwsgi.wsgi_req = wsgi_req;
async_reset_request(wsgi_req);
uwsgi_close_request(wsgi_req);
// re-set the global state (routing could have changed it)
uwsgi.wsgi_req = wsgi_req;
wsgi_req->async_status = UWSGI_OK;
uwsgi.async_queue_unused_ptr++;
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = wsgi_req;
}
void async_loop() {
@@ -511,19 +524,11 @@ void async_loop() {
uwsgi.wsgi_req->switches++;
// request ended ?
if (uwsgi.wsgi_req->async_status <= UWSGI_OK) {
if (uwsgi.wsgi_req->async_status <= UWSGI_OK ||
uwsgi.wsgi_req->waiting_fds || uwsgi.wsgi_req->async_timeout) {
// remove from the runqueue
runqueue_remove(current_request);
// push wsgi_request in the unused stack
uwsgi.async_queue_unused_ptr++;
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
}
else if (uwsgi.wsgi_req->waiting_fds || uwsgi.wsgi_req->async_timeout) {
// remove this request from the runqueue
runqueue_remove(current_request);
}
current_request = next_request;
}
+13
View File
@@ -204,6 +204,19 @@ int uwsgi_buffer_u64be(struct uwsgi_buffer *ub, uint64_t num) {
return uwsgi_buffer_append(ub, (char *) buf, 8);
}
int uwsgi_buffer_u64le(struct uwsgi_buffer *ub, uint64_t num) {
uint8_t buf[8];
buf[0] = (uint8_t) (num & 0xff);
buf[1] = (uint8_t) ((num >> 8) & 0xff);
buf[2] = (uint8_t) ((num >> 16) & 0xff);
buf[3] = (uint8_t) ((num >> 24) & 0xff);
buf[4] = (uint8_t) ((num >> 32) & 0xff);
buf[5] = (uint8_t) ((num >> 40) & 0xff);
buf[6] = (uint8_t) ((num >> 48) & 0xff);
buf[7] = (uint8_t) ((num >> 56) & 0xff);
return uwsgi_buffer_append(ub, (char *) buf, 8);
}
int uwsgi_buffer_f64be(struct uwsgi_buffer *ub, double num) {
uint8_t buf[8];
+4 -4
View File
@@ -7,7 +7,7 @@ extern struct uwsgi_server uwsgi;
/* how the cache bitmap works:
a bitmap is a shared mempry area allocated when requested by the user with --cache2
a bitmap is a shared memory area allocated when requested by the user with --cache2
Each block maps to a bit in the bitmap. If the corresponding bit is cleared
the block is usable otherwise the block scanner will search for the next one.
@@ -325,7 +325,7 @@ void uwsgi_cache_init(struct uwsgi_cache *uc) {
exit(1);
}
uc->items = (struct uwsgi_cache_item *) mmap(NULL, uc->filesize, PROT_READ | PROT_WRITE, MAP_SHARED, cache_fd, 0);
if (!uc->items) {
if (uc->items == MAP_FAILED) {
uwsgi_error("uwsgi_cache_init()/mmap() [with store]");
exit(1);
}
@@ -335,7 +335,7 @@ void uwsgi_cache_init(struct uwsgi_cache *uc) {
}
else {
uc->items = (struct uwsgi_cache_item *) mmap(NULL, uc->filesize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
if (!uc->items) {
if (uc->items == MAP_FAILED) {
uwsgi_error("uwsgi_cache_init()/mmap()");
exit(1);
}
@@ -773,7 +773,7 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
cache_unmark_blocks(uc, uci->first_block, uci->valsize);
}
if ( !(flags & UWSGI_CACHE_FLAG_MATH)) {
memcpy(uc->data + (uci->first_block * uc->blocksize), val, vallen);
memcpy(((char *) uc->data) + (uci->first_block * uc->blocksize), val, vallen);
}
else {
int64_t *num = (int64_t *)(((char *) uc->data) + (uci->first_block * uc->blocksize));
+162 -6
View File
@@ -293,8 +293,25 @@ int uwsgi_count_options(struct uwsgi_option *uopt) {
return count;
}
int uwsgi_opt_exists(char *name) {
struct uwsgi_option *op = uwsgi.options;
while (op->name) {
if (!strcmp(name, op->name)) return 1;
op++;
}
return 0;
}
/*
avoid loops here !!!
*/
struct uwsgi_option *uwsgi_opt_get(char *name) {
struct uwsgi_option *op = uwsgi.options;
struct uwsgi_option *op;
int round = 0;
retry:
round++;
if (round > 2) goto end;
op = uwsgi.options;
while (op->name) {
if (!strcmp(name, op->name)) {
@@ -303,10 +320,26 @@ struct uwsgi_option *uwsgi_opt_get(char *name) {
op++;
}
if (uwsgi.autoload) {
if (uwsgi_try_autoload(name)) goto retry;
}
end:
if (uwsgi.strict) {
uwsgi_log("[strict-mode] unknown config directive: %s\n", name);
exit(1);
}
return NULL;
}
void add_exported_option(char *key, char *value, int configured) {
add_exported_option_do(key, value, configured, 0);
}
void add_exported_option_do(char *key, char *value, int configured, int placeholder_only) {
struct uwsgi_string_list *blacklist = uwsgi.blacklist;
struct uwsgi_string_list *whitelist = uwsgi.whitelist;
@@ -394,6 +427,15 @@ add:
uwsgi.exported_opts_cnt++;
uwsgi.dirty_config = 1;
if (placeholder_only) {
if (uwsgi_opt_exists(key)) {
uwsgi_log("you cannot use %s as a placeholder, it is already available as an option\n");
exit(1);
}
uwsgi.exported_opts[id]->configured = 1;
return;
}
struct uwsgi_option *op = uwsgi_opt_get(key);
if (op) {
// requires master ?
@@ -451,17 +493,16 @@ add:
if (op->flags & UWSGI_OPT_MIME) {
uwsgi.build_mime_dict = 1;
}
// enable metrics ?
if (op->flags & UWSGI_OPT_METRICS) {
uwsgi.has_metrics = 1;
}
// immediate ?
if (op->flags & UWSGI_OPT_IMMEDIATE) {
op->func(key, value, op->data);
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() {
@@ -477,3 +518,118 @@ void uwsgi_fallback_config() {
// never here
}
}
int uwsgi_manage_opt(char *key, char *value) {
struct uwsgi_option *op = uwsgi_opt_get(key);
if (op) {
op->func(key, value, op->data);
return 1;
}
return 0;
}
void uwsgi_configure() {
int i;
// and now apply the remaining configs
restart:
for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
if (uwsgi.exported_opts[i]->configured)
continue;
uwsgi.dirty_config = 0;
uwsgi.exported_opts[i]->configured = uwsgi_manage_opt(uwsgi.exported_opts[i]->key, uwsgi.exported_opts[i]->value);
// some option could cause a dirty config tree
if (uwsgi.dirty_config)
goto restart;
}
}
void uwsgi_opt_custom(char *key, char *value, void *data ) {
struct uwsgi_custom_option *uco = (struct uwsgi_custom_option *)data;
size_t i, count = 1;
size_t value_len = 0;
if (value)
value_len = strlen(value);
off_t pos = 0;
char **opt_argv;
char *tmp_val = NULL, *p = NULL;
// now count the number of args
for (i = 0; i < value_len; i++) {
if (value[i] == ' ') {
count++;
}
}
// allocate a tmp array
opt_argv = uwsgi_calloc(sizeof(char *) * count);
//make a copy of the value;
if (value_len > 0) {
tmp_val = uwsgi_str(value);
// fill the array of options
char *p, *ctx = NULL;
uwsgi_foreach_token(tmp_val, " ", p, ctx) {
opt_argv[pos] = p;
pos++;
}
}
else {
// no argument specified
opt_argv[0] = "";
}
#ifdef UWSGI_DEBUG
uwsgi_log("found custom option %s with %d args\n", key, count);
#endif
// now make a copy of the option template
char *tmp_opt = uwsgi_str(uco->value);
// split it
char *ctx = NULL;
uwsgi_foreach_token(tmp_opt, ";", p, ctx) {
char *equal = strchr(p, '=');
if (!equal)
goto clear;
*equal = '\0';
// build the key
char *new_key = uwsgi_str(p);
for (i = 0; i < count; i++) {
char *old_key = new_key;
char *tmp_num = uwsgi_num2str(i + 1);
char *placeholder = uwsgi_concat2((char *) "$", tmp_num);
free(tmp_num);
new_key = uwsgi_substitute(old_key, placeholder, opt_argv[i]);
if (new_key != old_key)
free(old_key);
free(placeholder);
}
// build the value
char *new_value = uwsgi_str(equal + 1);
for (i = 0; i < count; i++) {
char *old_value = new_value;
char *tmp_num = uwsgi_num2str(i + 1);
char *placeholder = uwsgi_concat2((char *) "$", tmp_num);
free(tmp_num);
new_value = uwsgi_substitute(old_value, placeholder, opt_argv[i]);
if (new_value != old_value)
free(old_value);
free(placeholder);
}
// ignore return value here
uwsgi_manage_opt(new_key, new_value);
}
clear:
free(tmp_val);
free(tmp_opt);
free(opt_argv);
}
+16 -16
View File
@@ -139,6 +139,10 @@ int uwsgi_daemon_check_pid_reload(pid_t diedpid) {
}
#endif
if (ud->pid == diedpid && !ud->pidfile) {
if (ud->control) {
gracefully_kill_them_all(0);
return 0;
}
uwsgi_spawn_daemon(ud);
return 1;
}
@@ -229,13 +233,15 @@ void uwsgi_detach_daemons() {
#endif
uwsgi_log("[uwsgi-daemons] stopping daemon (pid: %d): %s\n", (int) ud->pid, ud->command);
// try to gracefully stop daemon, kill it if it won't die
// if mercy is not set than wait up to 3 seconds
// if mercy is not set then wait up to 3 seconds
time_t timeout = uwsgi_now() + (uwsgi.reload_mercy ? uwsgi.reload_mercy : 3);
int waitpid_status;
while (!kill(ud->pid, 0)) {
kill(-ud->pid, SIGTERM);
sleep(1);
waitpid(-ud->pid, &waitpid_status, WNOHANG);
if (uwsgi_now() >= timeout) {
uwsgi_log("[uwsgi-daemons] daemon did not died in time, killing (pid: %d): %s\n", (int) ud->pid, ud->command);
uwsgi_log("[uwsgi-daemons] daemon did not die in time, killing (pid: %d): %s\n", (int) ud->pid, ud->command);
kill(-ud->pid, SIGKILL);
break;
}
@@ -253,11 +259,12 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
// skip unregistered daemons
if (!ud->registered) return;
int devnull = -1;
int throttle = 0;
if (uwsgi.current_time - ud->last_spawn <= 3) {
throttle = ud->respawns - (uwsgi.current_time - ud->last_spawn);
// if ud->respawns == 0 then we can end up with throttle < 0
if (throttle <= 0) throttle = 1;
}
pid_t pid = uwsgi_fork("uWSGI external daemon");
@@ -299,18 +306,7 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
if (!uwsgi.daemons_honour_stdin) {
// /dev/null will became stdin
devnull = open("/dev/null", O_RDONLY);
if (devnull < 0) {
uwsgi_error("/dev/null open()");
exit(1);
}
if (devnull != 0) {
if (dup2(devnull, 0) < 0) {
uwsgi_error("dup2()");
exit(1);
}
close(devnull);
}
uwsgi_remap_fd(0, "/dev/null");
}
if (setsid() < 0) {
@@ -329,7 +325,7 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
if (throttle) {
uwsgi_log("[uwsgi-daemons] throttling \"%s\" for %d seconds\n", ud->command, throttle);
sleep(throttle);
sleep((unsigned int) throttle);
}
uwsgi_log("[uwsgi-daemons] %sspawning \"%s\"\n", ud->respawns > 0 ? "re" : "", ud->command);
@@ -412,6 +408,10 @@ void uwsgi_opt_add_daemon(char *opt, char *value, void *none) {
uwsgi_ud->last_spawn = 0;
uwsgi_ud->daemonize = daemonize;
uwsgi_ud->pidfile = pidfile;
uwsgi_ud->control = 0;
if (!strcmp(opt, "attach-control-daemon")) {
uwsgi_ud->control = 1;
}
#ifdef UWSGI_SSL
uwsgi_ud->legion = legion;
#endif
+263 -59
View File
@@ -339,8 +339,13 @@ void uwsgi_imperial_monitor_glob(struct uwsgi_emperor_scanner *ues) {
struct stat st;
struct uwsgi_instance *ui_current;
if (chdir(uwsgi.cwd)) {
uwsgi_error("uwsgi_imperial_monitor_glob()/chdir()");
exit(1);
}
if (glob(ues->arg, GLOB_MARK | GLOB_NOCHECK, NULL, &g)) {
uwsgi_error("glob()");
uwsgi_error("uwsgi_imperial_monitor_glob()/glob()");
return;
}
@@ -617,6 +622,7 @@ void emperor_del(struct uwsgi_instance *c_ui) {
}
void emperor_stop(struct uwsgi_instance *c_ui) {
if (c_ui->status == 1) return;
// remove uWSGI instance
if (write(c_ui->pipe[0], "\0", 1) != 1) {
@@ -624,10 +630,23 @@ void emperor_stop(struct uwsgi_instance *c_ui) {
}
c_ui->status = 1;
c_ui->cursed_at = uwsgi_now();
uwsgi_log("[emperor] stop the uwsgi instance %s\n", c_ui->name);
}
void emperor_curse(struct uwsgi_instance *c_ui) {
if (c_ui->status == 1) return;
// curse uWSGI instance
c_ui->status = 1;
c_ui->cursed_at = uwsgi_now();
uwsgi_log("[emperor] curse the uwsgi instance %s (pid: %d)\n", c_ui->name, (int) c_ui->pid);
}
void emperor_respawn(struct uwsgi_instance *c_ui, time_t mod) {
struct uwsgi_header uh;
@@ -817,7 +836,7 @@ 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 defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL) && !defined(__ia64__)
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);
@@ -825,7 +844,7 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
else {
#endif
pid = fork();
#if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL)
#if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL) && !defined(__ia64__)
}
#endif
if (pid < 0) {
@@ -940,6 +959,61 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) {
#ifdef __linux__
if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) {
uwsgi_error("prctl()");
}
#ifdef CLONE_NEWUSER
if (uwsgi.emperor_clone & CLONE_NEWUSER) {
if (setuid(0)) {
uwsgi_error("uwsgi_emperor_spawn_vassal()/setuid(0)");
exit(1);
}
}
#endif
#ifdef UWSGI_CAP
#if defined(CAP_LAST_CAP) && defined(PR_CAPBSET_READ) && defined(PR_CAPBSET_DROP)
if (uwsgi.emperor_cap && uwsgi.emperor_cap_count > 0) {
int i;
for(i=0;i<=CAP_LAST_CAP;i++) {
int has_cap = prctl(PR_CAPBSET_READ, i, 0, 0, 0);
if (has_cap == 1) {
if (i == CAP_SETPCAP) continue;
int j;int found = 0;
for(j=0;j<uwsgi.emperor_cap_count;j++) {
if (uwsgi.emperor_cap[j] == (int) i) {
found = 1; break;
}
}
if (found) continue;
if (prctl(PR_CAPBSET_DROP, i, 0, 0, 0)) {
uwsgi_error("uwsgi_emperor_spawn_vassal()/prctl()");
uwsgi_log_verbose("unable to drop capability %lu\n", i);
exit(1);
}
}
}
// just for being paranoid
#ifdef SECBIT_KEEP_CAPS
if (prctl(SECBIT_KEEP_CAPS, 1, 0, 0, 0) < 0) {
uwsgi_error("prctl()");
exit(1);
}
#else
if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) {
uwsgi_error("prctl()");
exit(1);
}
#endif
uwsgi_log("capabilities applied for vassal %s (pid: %d)\n", n_ui->name, (int) getpid());
}
#endif
#endif
#endif
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);
if (setgid(n_ui->gid)) {
@@ -1025,24 +1099,39 @@ static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) {
}
int counter = 4;
struct uwsgi_string_list *uct = uwsgi.vassals_templates;
while (uct) {
counter += 2;
uct = uct->next;
}
uct = uwsgi.vassals_includes;
while (uct) {
counter += 2;
uct = uct->next;
}
struct uwsgi_string_list *uct;
uwsgi_foreach(uct, uwsgi.vassals_templates_before) counter += 2;
uwsgi_foreach(uct, uwsgi.vassals_includes_before) counter += 2;
uwsgi_foreach(uct, uwsgi.vassals_set) counter += 2;
uwsgi_foreach(uct, uwsgi.vassals_templates) counter += 2;
uwsgi_foreach(uct, uwsgi.vassals_includes) counter += 2;
char **vassal_argv = uwsgi_malloc(sizeof(char *) * counter);
// set args
vassal_argv[0] = uwsgi.emperor_wrapper ? uwsgi.emperor_wrapper: uwsgi.binary_path;
char *colon = NULL;
// reset counter
counter = 1;
uwsgi_foreach(uct, uwsgi.vassals_templates_before) {
vassal_argv[counter] = "--inherit";
vassal_argv[counter + 1] = uct->value;
counter += 2;
}
uwsgi_foreach (uct, uwsgi.vassals_includes_before) {
vassal_argv[counter] = "--include";
vassal_argv[counter + 1] = uct->value;
counter += 2;
}
uwsgi_foreach (uct, uwsgi.vassals_set) {
vassal_argv[counter] = "--set";
vassal_argv[counter + 1] = uct->value;
counter += 2;
}
char *colon = NULL;
if (uwsgi.emperor_broodlord) {
colon = strchr(n_ui->name, ':');
if (colon) {
@@ -1050,62 +1139,58 @@ static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) {
}
}
// initialize to a default value
vassal_argv[1] = "--inherit";
vassal_argv[counter] = "--inherit";
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".xml"))
vassal_argv[1] = "--xml";
vassal_argv[counter] = "--xml";
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".ini"))
vassal_argv[1] = "--ini";
vassal_argv[counter] = "--ini";
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".yml"))
vassal_argv[1] = "--yaml";
vassal_argv[counter] = "--yaml";
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".yaml"))
vassal_argv[1] = "--yaml";
vassal_argv[counter] = "--yaml";
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 3), ".js"))
vassal_argv[1] = "--json";
vassal_argv[counter] = "--json";
if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".json"))
vassal_argv[1] = "--json";
vassal_argv[counter] = "--json";
struct uwsgi_string_list *usl = uwsgi.emperor_extra_extension;
while(usl) {
if (uwsgi_endswith(n_ui->name, usl->value)) {
vassal_argv[1] = "--config";
vassal_argv[counter] = "--config";
break;
}
usl = usl->next;
}
if (colon) colon[0] = ':';
if (colon) {
colon[0] = ':';
}
// start config filename...
counter++;
vassal_argv[2] = n_ui->name;
vassal_argv[counter] = n_ui->name;
if (uwsgi.emperor_magic_exec) {
if (!access(n_ui->name, R_OK | X_OK)) {
vassal_argv[2] = uwsgi_concat2("exec://", n_ui->name);
vassal_argv[counter] = uwsgi_concat2("exec://", n_ui->name);
}
}
if (n_ui->use_config) {
vassal_argv[2] = uwsgi_concat2("emperor://", n_ui->name);
vassal_argv[counter] = uwsgi_concat2("emperor://", n_ui->name);
}
counter = 3;
uct = uwsgi.vassals_templates;
while (uct) {
// start templates,includes,inherit...
counter++;
uwsgi_foreach(uct, uwsgi.vassals_templates) {
vassal_argv[counter] = "--inherit";
vassal_argv[counter + 1] = uct->value;
counter += 2;
uct = uct->next;
}
uct = uwsgi.vassals_includes;
while (uct) {
uwsgi_foreach (uct, uwsgi.vassals_includes) {
vassal_argv[counter] = "--include";
vassal_argv[counter + 1] = uct->value;
counter += 2;
uct = uct->next;
}
vassal_argv[counter] = NULL;
@@ -1121,18 +1206,7 @@ static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) {
}
}
else {
int stdin_fd = open("/dev/null", O_RDONLY);
if (stdin_fd < 0) {
uwsgi_error_open("/dev/null");
exit(1);
}
if (stdin_fd != 0) {
if (dup2(stdin_fd, 0) < 0) {
uwsgi_error("dup2()");
exit(1);
}
close(stdin_fd);
}
uwsgi_remap_fd(0, "/dev/null");
}
// close all of the unneded fd
@@ -1471,7 +1545,8 @@ void emperor_loop() {
ssize_t rlen = read(interesting_fd, &byte, 1);
if (rlen <= 0) {
// SAFE
emperor_del(ui_current);
event_queue_del_fd(uwsgi.emperor_queue, interesting_fd, event_queue_read());
emperor_curse(ui_current);
}
else {
if (byte == 17) {
@@ -1577,14 +1652,8 @@ void emperor_loop() {
ui_current = ui;
while (ui_current->ui_next) {
ui_current = ui_current->ui_next;
if (ui_current->status == 1) {
if (ui_current->config)
free(ui_current->config);
// SAFE
emperor_del(ui_current);
break;
}
else if (ui_current->pid == diedpid) {
time_t now = uwsgi_now();
if (ui_current->pid == diedpid) {
if (ui_current->status == 0) {
// respawn an accidentally dead instance if its exit code is not UWSGI_EXILE_CODE
if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_EXILE_CODE) {
@@ -1607,6 +1676,13 @@ void emperor_loop() {
break;
}
}
else if (ui_current->cursed_at > 0 && now - ui_current->cursed_at >= uwsgi.emperor_curse_tolerance) {
ui_current->cursed_at = now;
if (kill(ui_current->pid, SIGKILL)) {
uwsgi_error("[emperor] kill");
}
break;
}
}
@@ -1703,6 +1779,8 @@ void emperor_send_stats(int fd) {
goto end0;
if (uwsgi_stats_keylong_comma(us, "last_run", (unsigned long long) c_ui->last_run))
goto end0;
if (uwsgi_stats_keylong_comma(us, "cursed", (unsigned long long) c_ui->cursed_at))
goto end0;
if (uwsgi_stats_keylong_comma(us, "zerg", (unsigned long long) c_ui->zerg))
goto end0;
@@ -1846,6 +1924,46 @@ void uwsgi_emperor_start() {
}
void uwsgi_check_emperor() {
char *emperor_fd_pass = getenv("UWSGI_EMPEROR_PROXY");
if (emperor_fd_pass) {
for(;;) {
int proxy_fd = uwsgi_connect(emperor_fd_pass, 30, 0);
if (proxy_fd < 0) {
uwsgi_error("uwsgi_check_emperor()/uwsgi_connect()");
sleep(1);
continue;
}
int count = 2;
int *fds = uwsgi_attach_fd(proxy_fd, &count, "uwsgi-emperor", 13);
if (fds && count > 0) {
char *env_emperor_fd = uwsgi_num2str(fds[0]);
if (setenv("UWSGI_EMPEROR_FD", env_emperor_fd, 1)) {
uwsgi_error("uwsgi_check_emperor()/setenv(UWSGI_EMPEROR_FD)");
free(env_emperor_fd);
int i; for(i=0;i<count;i++) close(fds[i]);
goto next;
}
free(env_emperor_fd);
if (count > 1) {
char *env_emperor_fd_config = uwsgi_num2str(fds[1]);
if (setenv("UWSGI_EMPEROR_FD_CONFIG", env_emperor_fd_config, 1)) {
uwsgi_error("uwsgi_check_emperor()/setenv(UWSGI_EMPEROR_FD_CONFIG)");
free(env_emperor_fd_config);
int i; for(i=0;i<count;i++) close(fds[i]);
goto next;
}
free(env_emperor_fd_config);
}
break;
}
next:
if (fds) free(fds);
close(proxy_fd);
sleep(1);
}
unsetenv("UWSGI_EMPEROR_PROXY");
}
char *emperor_env = getenv("UWSGI_EMPEROR_FD");
if (emperor_env) {
uwsgi.has_emperor = 1;
@@ -1901,3 +2019,89 @@ void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *ues, char *name, char
emperor_add(ues, name, ts, new_config, new_config_len, uid, gid, socket_name);
}
}
void uwsgi_master_manage_emperor() {
char byte;
ssize_t rlen = read(uwsgi.emperor_fd, &byte, 1);
if (rlen > 0) {
uwsgi_log_verbose("received message %d from emperor\n", byte);
// remove me
if (byte == 0) {
close(uwsgi.emperor_fd);
if (!uwsgi.status.brutally_reloading)
kill_them_all(0);
}
// reload me
else if (byte == 1) {
// un-lazy the stack to trigger a real reload
uwsgi.lazy = 0;
uwsgi_block_signal(SIGHUP);
grace_them_all(0);
uwsgi_unblock_signal(SIGHUP);
}
}
else {
uwsgi_log("lost connection with my emperor !!!\n");
close(uwsgi.emperor_fd);
if (!uwsgi.status.brutally_reloading)
kill_them_all(0);
sleep(2);
exit(1);
}
}
void uwsgi_master_manage_emperor_proxy() {
struct sockaddr_un epsun;
socklen_t epsun_len = sizeof(struct sockaddr_un);
int ep_client = accept(uwsgi.emperor_fd_proxy, (struct sockaddr *) &epsun, &epsun_len);
if (ep_client < 0) {
uwsgi_error("uwsgi_master_manage_emperor_proxy()/accept()");
return;
}
int num_fds = 1;
if (uwsgi.emperor_fd_config > -1) num_fds++;
struct msghdr ep_msg;
void *ep_msg_control = uwsgi_malloc(CMSG_SPACE(sizeof(int) * num_fds));
struct iovec ep_iov[2];
struct cmsghdr *cmsg;
ep_iov[0].iov_base = "uwsgi-emperor";
ep_iov[0].iov_len = 13;
ep_iov[1].iov_base = &num_fds;
ep_iov[1].iov_len = sizeof(int);
ep_msg.msg_name = NULL;
ep_msg.msg_namelen = 0;
ep_msg.msg_iov = ep_iov;
ep_msg.msg_iovlen = 2;
ep_msg.msg_flags = 0;
ep_msg.msg_control = ep_msg_control;
ep_msg.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds);
cmsg = CMSG_FIRSTHDR(&ep_msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
unsigned char *ep_fd_ptr = CMSG_DATA(cmsg);
memcpy(ep_fd_ptr, &uwsgi.emperor_fd, sizeof(int));
if (num_fds > 1) {
memcpy(ep_fd_ptr + sizeof(int), &uwsgi.emperor_fd_config, sizeof(int));
}
if (sendmsg(ep_client, &ep_msg, 0) < 0) {
uwsgi_error("uwsgi_master_manage_emperor_proxy()/sendmsg()");
}
free(ep_msg_control);
close(ep_client);
}
+1 -1
View File
@@ -99,7 +99,7 @@ int uwsgi_master_fifo() {
}
int uwsgi_master_fifo_manage(int fd) {
char cmd;
unsigned char cmd;
ssize_t rlen = read(fd, &cmd, 1);
if (rlen < 0) {
if (uwsgi_is_again()) return 0;
+1
View File
@@ -38,6 +38,7 @@ void uwsgi_fsmon_setup() {
char *space = strchr(copy, ' ');
if (!space) {
uwsgi_log("[uwsgi-fsmon] invalid syntax: \"%s\"\n", usl->value);
free(copy);
goto next;
}
*space = 0;
+1
View File
@@ -70,6 +70,7 @@ void gateway_respawn(int id) {
if (gw_pid == 0) {
uwsgi_fixup_fds(0, 0, ug);
uwsgi_close_all_sockets();
if (uwsgi.master_as_root)
uwsgi_as_root();
#ifdef __linux__
+21 -1
View File
@@ -17,7 +17,7 @@ uint32_t djb33x_hash(char *key, uint64_t keylen) {
// Murmur2 hash Copyright (C) Austin Appleby
// adapted from nginx
uint32_t murmur2_hash(char *key, uint64_t keylen) {
static uint32_t murmur2_hash(char *key, uint64_t keylen) {
uint32_t h, k;
uint8_t *ukey = (uint8_t *) key;
@@ -56,6 +56,23 @@ uint32_t murmur2_hash(char *key, uint64_t keylen) {
return h;
}
static uint32_t random_hash(char *key, uint64_t keylen) {
return (uint32_t) rand();
}
/*
not atomic, avoid its use in multithreaded modes
*/
static uint32_t rr_hash(char *key, uint64_t keylen) {
static uint32_t rr = 0;
uint32_t max_value = uwsgi_str_num(key, keylen);
uint32_t ret = rr;
rr++;
if (rr > max_value) {
rr = 0;
}
return ret;
}
struct uwsgi_hash_algo *uwsgi_hash_algo_get(char *name) {
struct uwsgi_hash_algo *uha = uwsgi.hash_algos;
@@ -90,4 +107,7 @@ void uwsgi_hash_algo_register(char *name, uint32_t (*func)(char *, uint64_t)) {
void uwsgi_hash_algo_register_all() {
uwsgi_hash_algo_register("djb33x", djb33x_hash);
uwsgi_hash_algo_register("murmur2", murmur2_hash);
uwsgi_hash_algo_register("random", random_hash);
uwsgi_hash_algo_register("rand", random_hash);
uwsgi_hash_algo_register("rr", rr_hash);
}
+4 -1
View File
@@ -51,6 +51,7 @@ struct http_status_codes hsc[] = {
{"503", "Service Unavailable"},
{"504", "Gateway Timeout"},
{"505", "HTTP Version Not Supported"},
{"509", "Bandwidth Limit Exceeded"},
{"", NULL},
};
@@ -75,10 +76,12 @@ void uwsgi_init_default() {
uwsgi.original_log_fd = -1;
uwsgi.emperor_fd_config = -1;
uwsgi.emperor_fd_proxy = -1;
// default emperor scan frequency
uwsgi.emperor_freq = 3;
uwsgi.emperor_throttle = 1000;
uwsgi.emperor_heartbeat = 30;
uwsgi.emperor_curse_tolerance = 30;
// max 3 minutes throttling
uwsgi.emperor_max_throttle = 1000 * 180;
uwsgi.emperor_pid = -1;
@@ -464,7 +467,7 @@ void sanitize_args() {
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) {
if ( uwsgi.cheaper_rss_limit_hard && 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);
}
+303 -189
View File
@@ -116,48 +116,31 @@ end:
}
/*
extremely complex function for reading resources (files, url...)
need a lot of refactoring...
*/
char *uwsgi_open_and_read(char *url, size_t *size, int add_zero, char *magic_table[]) {
static char *uwsgi_scheme_fd(char *url, size_t *size, int add_zero) {
int fd = atoi(url);
return uwsgi_read_fd(fd, size, add_zero);
}
int fd;
struct stat sb;
char *buffer = NULL;
static char *uwsgi_scheme_exec(char *url, size_t *size, int add_zero) {
int cpipe[2];
if (pipe(cpipe)) {
uwsgi_error("pipe()");
exit(1);
}
uwsgi_run_command(url, NULL, cpipe[1]);
char *buffer = uwsgi_read_fd(cpipe[0], size, add_zero);
close(cpipe[0]);
close(cpipe[1]);
return buffer;
}
static char *uwsgi_scheme_http(char *url, size_t *size, int add_zero) {
char byte;
ssize_t len;
char *uri, *colon;
char *domain;
char *ip;
int body = 0;
char *magic_buf;
int body = 0;
char *buffer = NULL;
// stdin ?
if (!strcmp(url, "-")) {
buffer = uwsgi_read_fd(0, size, add_zero);
}
// fd ?
else if (!strncmp("fd://", url, 5)) {
fd = atoi(url + 5);
buffer = uwsgi_read_fd(fd, size, add_zero);
}
// exec ?
else if (!strncmp("exec://", url, 5)) {
int cpipe[2];
if (pipe(cpipe)) {
uwsgi_error("pipe()");
exit(1);
}
uwsgi_run_command(url + 7, NULL, cpipe[1]);
buffer = uwsgi_read_fd(cpipe[0], size, add_zero);
close(cpipe[0]);
close(cpipe[1]);
}
// http url ?
else if (!strncmp("http://", url, 7)) {
domain = url + 7;
uri = strchr(domain, '/');
char *domain = url;
char *uri = strchr(domain, '/');
if (!uri) {
uwsgi_log("invalid http url\n");
exit(1);
@@ -165,14 +148,14 @@ char *uwsgi_open_and_read(char *url, size_t *size, int add_zero, char *magic_tab
uri[0] = 0;
uwsgi_log("domain: %s\n", domain);
colon = uwsgi_get_last_char(domain, ':');
char *colon = uwsgi_get_last_char(domain, ':');
if (colon) {
colon[0] = 0;
}
ip = uwsgi_resolve_ip(domain);
char *ip = uwsgi_resolve_ip(domain);
if (!ip) {
uwsgi_log("unable to resolve address %s\n", domain);
exit(1);
@@ -186,9 +169,10 @@ char *uwsgi_open_and_read(char *url, size_t *size, int add_zero, char *magic_tab
ip = uwsgi_concat2(ip, ":80");
}
fd = uwsgi_connect(ip, 0, 0);
int fd = uwsgi_connect(ip, 0, 0);
if (fd < 0) {
uwsgi_error("uwsgi_scheme_http()/connect()");
exit(1);
}
@@ -196,18 +180,18 @@ char *uwsgi_open_and_read(char *url, size_t *size, int add_zero, char *magic_tab
uri[0] = '/';
len = write(fd, "GET ", 4);
len = write(fd, uri, strlen(uri));
len = write(fd, " HTTP/1.0\r\n", 11);
len = write(fd, "Host: ", 6);
if (write(fd, "GET ", 4) != 4) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
if (write(fd, uri, strlen(uri)) != (ssize_t) strlen(uri)) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
if (write(fd, " HTTP/1.0\r\n", 11) != 11) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
if (write(fd, "Host: ", 6) != 6) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
uri[0] = 0;
len = write(fd, domain, strlen(domain));
if (write(fd, domain, strlen(domain)) != (ssize_t) strlen(domain)) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
uri[0] = '/';
len = write(fd, "\r\nUser-Agent: uWSGI on ", 23);
len = write(fd, uwsgi.hostname, uwsgi.hostname_len);
len = write(fd, "\r\n\r\n", 4);
if (write(fd, "\r\nUser-Agent: uWSGI on ", 23) != 23) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
if (write(fd, uwsgi.hostname, uwsgi.hostname_len) != uwsgi.hostname_len) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
if (write(fd, "\r\n\r\n", 4) != 4) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
int http_status_code_ptr = 0;
@@ -264,57 +248,233 @@ char *uwsgi_open_and_read(char *url, size_t *size, int add_zero, char *magic_tab
buffer[*size - 1] = 0;
}
return buffer;
}
static char *uwsgi_scheme_emperor(char *url, size_t *size, int add_zero) {
if (uwsgi.emperor_fd_config < 0) {
uwsgi_log("this is not a vassal instance\n");
exit(1);
}
else if (!strncmp("emperor://", url, 10)) {
if (uwsgi.emperor_fd_config < 0) {
uwsgi_log("this is not a vassal instance\n");
ssize_t rlen;
struct uwsgi_header uh;
size_t remains = 4;
char *ptr = (char *) &uh;
while(remains) {
int ret = uwsgi_waitfd(uwsgi.emperor_fd_config, 5);
if (ret <= 0) {
uwsgi_log("[uwsgi-vassal] error waiting for config header %s !!!\n", url);
exit(1);
}
ssize_t rlen;
*size = 0;
struct uwsgi_header uh;
size_t remains = 4;
char *ptr = (char *) &uh;
while(remains) {
int ret = uwsgi_waitfd(uwsgi.emperor_fd_config, 5);
if (ret <= 0) {
uwsgi_log("[uwsgi-vassal] error waiting for config header %s !!!\n", url);
exit(1);
}
rlen = read(uwsgi.emperor_fd_config, ptr, remains);
if (rlen <= 0) {
uwsgi_log("[uwsgi-vassal] error reading config header from !!!\n", url);
exit(1);
}
ptr+=rlen;
remains-=rlen;
rlen = read(uwsgi.emperor_fd_config, ptr, remains);
if (rlen <= 0) {
uwsgi_log("[uwsgi-vassal] error reading config header from %s !!!\n", url);
exit(1);
}
ptr+=rlen;
remains-=rlen;
}
remains = uh.pktsize;
if (!remains) {
uwsgi_log("[uwsgi-vassal] invalid config from %s\n", url);
remains = uh.pktsize;
if (!remains) {
uwsgi_log("[uwsgi-vassal] invalid config from %s\n", url);
exit(1);
}
char *buffer = uwsgi_calloc(remains + add_zero);
ptr = buffer;
while (remains) {
int ret = uwsgi_waitfd(uwsgi.emperor_fd_config, 5);
if (ret <= 0) {
uwsgi_log("[uwsgi-vassal] error waiting for config %s !!!\n", url);
exit(1);
}
rlen = read(uwsgi.emperor_fd_config, ptr, remains);
if (rlen <= 0) {
uwsgi_log("[uwsgi-vassal] error reading config from %s !!!\n", url);
exit(1);
}
ptr+=rlen;
remains-=rlen;
}
*size = uh.pktsize + add_zero;
return buffer;
}
static char *uwsgi_scheme_data(char *url, size_t *size, int add_zero) {
char *buffer = NULL;
int fd = open(uwsgi.binary_path, O_RDONLY);
if (fd < 0) {
uwsgi_error_open(uwsgi.binary_path);
exit(1);
}
int slot = atoi(url);
if (slot < 0) {
uwsgi_log("invalid binary data slot requested\n");
exit(1);
}
uwsgi_log("requesting binary data slot %d\n", slot);
off_t fo = lseek(fd, 0, SEEK_END);
if (fo < 0) {
uwsgi_error("lseek()");
uwsgi_log("invalid binary data slot requested\n");
exit(1);
}
int i = 0;
uint64_t datasize = 0;
for (i = 0; i <= slot; i++) {
fo = lseek(fd, -8, SEEK_CUR);
if (fo < 0) {
uwsgi_error("lseek()");
uwsgi_log("invalid binary data slot requested\n");
exit(1);
}
ssize_t len = read(fd, &datasize, 8);
if (len != 8) {
uwsgi_error("read()");
uwsgi_log("invalid binary data slot requested\n");
exit(1);
}
if (datasize == 0) {
uwsgi_log("0 size binary data !!!\n");
exit(1);
}
fo = lseek(fd, -(datasize + 8), SEEK_CUR);
if (fo < 0) {
uwsgi_error("lseek()");
uwsgi_log("invalid binary data slot requested\n");
exit(1);
}
buffer = uwsgi_calloc(remains + add_zero);
ptr = buffer;
while (remains) {
int ret = uwsgi_waitfd(uwsgi.emperor_fd_config, 5);
if (ret <= 0) {
uwsgi_log("[uwsgi-vassal] error waiting for config %s !!!\n", url);
exit(1);
}
rlen = read(uwsgi.emperor_fd_config, ptr, remains);
if (rlen <= 0) {
uwsgi_log("[uwsgi-vassal] error reading config from !!!\n", url);
exit(1);
}
ptr+=rlen;
remains-=rlen;
if (i == slot) {
*size = datasize;
if (add_zero) {
*size += 1;
}
buffer = uwsgi_malloc(*size);
memset(buffer, 0, *size);
len = read(fd, buffer, datasize);
if (len != (ssize_t) datasize) {
uwsgi_error("read()");
uwsgi_log("invalid binary data slot requested\n");
exit(1);
}
}
*size = uh.pktsize + add_zero;
}
close(fd);
return buffer;
}
static char *uwsgi_scheme_call(char *url, size_t *size, int add_zero) {
char *(*func)(void) = dlsym(RTLD_DEFAULT, url);
if (!func) {
uwsgi_log("unable to find symbol %s\n", url);
exit(1);
}
char *s = func();
if (!s) {
uwsgi_log("called symbol %s did not return a string\n", url);
exit(1);
}
*size = strlen(s);
if (add_zero) {
*size += 1;
}
char *buffer = uwsgi_malloc(*size);
memset(buffer, 0, *size);
memcpy(buffer, s, strlen(s));
return buffer;
}
static char *uwsgi_scheme_sym(char *url, size_t *size, int add_zero) {
void *sym_start_ptr = NULL, *sym_end_ptr = NULL;
char **raw_symbol = dlsym(RTLD_DEFAULT, url);
if (raw_symbol) {
sym_start_ptr = *raw_symbol;
sym_end_ptr = sym_start_ptr + strlen(sym_start_ptr);
goto found;
}
char *symbol = uwsgi_concat3("_binary_", url, "_start");
sym_start_ptr = dlsym(RTLD_DEFAULT, symbol);
if (!sym_start_ptr) {
uwsgi_log("unable to find symbol %s\n", symbol);
exit(1);
}
free(symbol);
symbol = uwsgi_concat3("_binary_", url, "_end");
sym_end_ptr = dlsym(RTLD_DEFAULT, symbol);
if (!sym_end_ptr) {
uwsgi_log("unable to find symbol %s\n", symbol);
exit(1);
}
free(symbol);
found:
*size = sym_end_ptr - sym_start_ptr;
if (add_zero) {
*size += 1;
}
char *buffer = uwsgi_malloc(*size);
memset(buffer, 0, *size);
memcpy(buffer, sym_start_ptr, sym_end_ptr - sym_start_ptr);
return buffer;
}
static char *uwsgi_scheme_section(char *url, size_t *size, int add_zero) {
#ifdef UWSGI_ELF
size_t s_len = 0;
char *buffer = uwsgi_elf_section(uwsgi.binary_path, url, &s_len);
if (!buffer) {
uwsgi_log("unable to find section %s in %s\n", url + 10, uwsgi.binary_path);
exit(1);
}
*size = s_len;
if (add_zero)
*size += 1;
return buffer;
#else
uwsgi_log("section:// scheme not supported on this platform\n");
exit(1);
#endif
}
struct uwsgi_string_list *uwsgi_register_scheme(char *name, char * (*func)(char *, size_t *, int)) {
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.schemes) {
if (!strcmp(usl->value, name)) goto found;
}
usl = uwsgi_string_new_list(&uwsgi.schemes, name);
found:
usl->custom_ptr = func;
return usl;
}
char *uwsgi_open_and_read(char *url, size_t *size, int add_zero, char *magic_table[]) {
struct stat sb;
char *buffer = NULL;
ssize_t len;
char *magic_buf;
int fd;
*size = 0;
// stdin ?
if (!strcmp(url, "-")) {
buffer = uwsgi_read_fd(0, size, add_zero);
goto end;
}
#ifdef UWSGI_EMBED_CONFIG
else if (url[0] == 0) {
*size = &UWSGI_EMBED_CONFIG_END - &UWSGI_EMBED_CONFIG;
@@ -324,108 +484,22 @@ char *uwsgi_open_and_read(char *url, size_t *size, int add_zero, char *magic_tab
buffer = uwsgi_malloc(*size);
memset(buffer, 0, *size);
memcpy(buffer, &UWSGI_EMBED_CONFIG, &UWSGI_EMBED_CONFIG_END - &UWSGI_EMBED_CONFIG);
goto end;
}
#endif
else if (!strncmp("data://", url, 7)) {
fd = open(uwsgi.binary_path, O_RDONLY);
if (fd < 0) {
uwsgi_error_open(uwsgi.binary_path);
exit(1);
}
int slot = atoi(url + 7);
if (slot < 0) {
uwsgi_log("invalid binary data slot requested\n");
exit(1);
}
uwsgi_log("requesting binary data slot %d\n", slot);
off_t fo = lseek(fd, 0, SEEK_END);
if (fo < 0) {
uwsgi_error("lseek()");
uwsgi_log("invalid binary data slot requested\n");
exit(1);
}
int i = 0;
uint64_t datasize = 0;
for (i = 0; i <= slot; i++) {
fo = lseek(fd, -9, SEEK_CUR);
if (fo < 0) {
uwsgi_error("lseek()");
uwsgi_log("invalid binary data slot requested\n");
exit(1);
}
ssize_t len = read(fd, &datasize, 8);
if (len != 8) {
uwsgi_error("read()");
uwsgi_log("invalid binary data slot requested\n");
exit(1);
}
if (datasize == 0) {
uwsgi_log("0 size binary data !!!\n");
exit(1);
}
fo = lseek(fd, -(datasize + 9), SEEK_CUR);
if (fo < 0) {
uwsgi_error("lseek()");
uwsgi_log("invalid binary data slot requested\n");
exit(1);
}
if (i == slot) {
*size = datasize;
if (add_zero) {
*size += 1;
}
buffer = uwsgi_malloc(*size);
memset(buffer, 0, *size);
len = read(fd, buffer, datasize);
if (len != (ssize_t) datasize) {
uwsgi_error("read()");
uwsgi_log("invalid binary data slot requested\n");
exit(1);
}
}
}
}
else if (!strncmp("sym://", url, 6)) {
char *symbol = uwsgi_concat3("_binary_", url + 6, "_start");
void *sym_start_ptr = dlsym(RTLD_DEFAULT, symbol);
if (!sym_start_ptr) {
uwsgi_log("unable to find symbol %s\n", symbol);
exit(1);
}
free(symbol);
symbol = uwsgi_concat3("_binary_", url + 6, "_end");
void *sym_end_ptr = dlsym(RTLD_DEFAULT, symbol);
if (!sym_end_ptr) {
uwsgi_log("unable to find symbol %s\n", symbol);
exit(1);
}
free(symbol);
struct uwsgi_string_list *usl = uwsgi_check_scheme(url);
if (!usl) goto fallback;
*size = sym_end_ptr - sym_start_ptr;
if (add_zero) {
*size += 1;
}
buffer = uwsgi_malloc(*size);
memset(buffer, 0, *size);
memcpy(buffer, sym_start_ptr, sym_end_ptr - sym_start_ptr);
}
#ifdef UWSGI_ELF
else if (!strncmp("section://", url, 10)) {
size_t s_len = 0;
buffer = uwsgi_elf_section(uwsgi.binary_path, url + 10, &s_len);
if (!buffer) {
uwsgi_log("unable to find section %s in %s\n", url + 10, uwsgi.binary_path);
exit(1);
}
*size = s_len;
if (add_zero)
*size += 1;
}
#endif
char *(*func)(char *, size_t *, int) = (char *(*)(char *, size_t *, int)) usl->custom_ptr;
buffer = func(url + usl->len + 3, size, add_zero);
if (buffer) goto end;
// never here !!!
uwsgi_log("unable to parse config file %s\n", url);
exit(1);
// fallback to file
else {
fallback:
fd = open(url, O_RDONLY);
if (fd < 0) {
uwsgi_error_open(url);
@@ -457,7 +531,6 @@ char *uwsgi_open_and_read(char *url, size_t *size, int add_zero, char *magic_tab
if (add_zero)
buffer[sb.st_size] = 0;
}
end:
@@ -1097,3 +1170,44 @@ int uwsgi_ready_fd(struct wsgi_request *wsgi_req) {
if (wsgi_req->async_ready_fd) return wsgi_req->async_last_ready_fd;
return -1;
}
void uwsgi_setup_schemes() {
uwsgi_register_scheme("emperor", uwsgi_scheme_emperor);
uwsgi_register_scheme("http", uwsgi_scheme_http);
uwsgi_register_scheme("data", uwsgi_scheme_data);
uwsgi_register_scheme("sym", uwsgi_scheme_sym);
uwsgi_register_scheme("section", uwsgi_scheme_section);
uwsgi_register_scheme("fd", uwsgi_scheme_fd);
uwsgi_register_scheme("exec", uwsgi_scheme_exec);
uwsgi_register_scheme("call", uwsgi_scheme_call);
}
struct uwsgi_string_list *uwsgi_check_scheme(char *file) {
struct uwsgi_string_list *usl;
uwsgi_foreach(usl, uwsgi.schemes) {
char *url = uwsgi_concat2(usl->value, "://");
int ret = uwsgi_startswith(file, url, strlen(url));
free(url);
if (!ret) return usl;
}
return NULL;
}
void uwsgi_remap_fd(int fd, char *filename) {
int fdin = open(filename, O_RDWR);
if (fdin < 0) {
uwsgi_error_open(filename);
exit(1);
}
/* stdin */
if (fdin != fd) {
if (dup2(fdin, fd) < 0) {
uwsgi_error("uwsgi_remap_fd()/dup2()");
exit(1);
}
close(fdin);
}
}
+2
View File
@@ -106,6 +106,8 @@ void uwsgi_json_config(char *file, char *magic_table[]) {
config_iter = json_object_iter_next(config, config_iter);
}
if (colon) colon[0] = ':';
}
#endif
+14 -2
View File
@@ -498,7 +498,7 @@ void uwsgi_check_logrotate(void) {
uwsgi.shared->logsize = lseek(2, 0, SEEK_CUR);
}
if (uwsgi.log_maxsize > 0 && uwsgi.shared->logsize > uwsgi.log_maxsize) {
if (uwsgi.log_maxsize > 0 && (uint64_t) uwsgi.shared->logsize > uwsgi.log_maxsize) {
need_rotation = 1;
}
@@ -980,6 +980,12 @@ void uwsgi_logit_lf(struct wsgi_request *wsgi_req) {
uwsgi.logvectors[wsgi_req->async_id][pos].iov_len = 0;
}
}
// metric
else if (logchunk->type == 4) {
int64_t metric = uwsgi_metric_get(logchunk->ptr, NULL);
uwsgi.logvectors[wsgi_req->async_id][pos].iov_base = uwsgi_64bit2str(metric);
uwsgi.logvectors[wsgi_req->async_id][pos].iov_len = strlen(uwsgi.logvectors[wsgi_req->async_id][pos].iov_base);
}
if (uwsgi.logvectors[wsgi_req->async_id][pos].iov_len == 0 && logchunk->type != 0) {
uwsgi.logvectors[wsgi_req->async_id][pos].iov_base = (char *) empty_var;
@@ -1231,6 +1237,7 @@ void uwsgi_add_logchunk(int variable, int pos, char *ptr, size_t len) {
1 -> offsetof variable
2 -> logvar
3 -> func
4 -> metric
*/
logchunk->type = variable;
@@ -1397,6 +1404,11 @@ void uwsgi_add_logchunk(int variable, int pos, char *ptr, size_t len) {
logchunk->func = uwsgi_lf_headers;
logchunk->free = 1;
}
else if (!uwsgi_starts_with(ptr, len, "metric.", 7)) {
logchunk->type = 4;
logchunk->ptr = uwsgi_concat2n(ptr+7, len - 7, "", 0);
logchunk->free = 1;
}
// logvar
else {
logchunk->type = 2;
@@ -1841,7 +1853,7 @@ void uwsgi_log_encoder_parse_vars(struct uwsgi_log_encoder *ule) {
/*
// format: foo ${var} bar
msg (the logline)
msgnl (the logine with newline)
msgnl (the logline with newline)
unix (the time_t value)
micros (current microseconds)
strftime (strftime)
+65 -50
View File
@@ -2,6 +2,32 @@
extern struct uwsgi_server uwsgi;
void uwsgi_update_load_counters() {
int i;
uint64_t busy_workers = 0;
uint64_t idle_workers = 0;
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
if (uwsgi_worker_is_busy(i) == 0) {
idle_workers++;
}
else {
busy_workers++;
}
}
}
if (busy_workers >= (uint64_t) uwsgi.numproc) {
ushared->overloaded++;
}
ushared->busy_workers = busy_workers;
ushared->idle_workers = idle_workers;
}
void uwsgi_restore_auto_snapshot(int signum) {
if (uwsgi.workers[1].snapshot > 0) {
@@ -32,24 +58,25 @@ void uwsgi_unblock_signal(int signum) {
}
void uwsgi_master_manage_udp(int udp_fd) {
char buf[4096];
struct sockaddr_in udp_client;
char udp_client_addr[16];
int i;
socklen_t udp_len = sizeof(udp_client);
ssize_t rlen = recvfrom(udp_fd, uwsgi.wsgi_req->buffer, uwsgi.buffer_size, 0, (struct sockaddr *) &udp_client, &udp_len);
ssize_t rlen = recvfrom(udp_fd, buf, 4096, 0, (struct sockaddr *) &udp_client, &udp_len);
if (rlen < 0) {
uwsgi_error("recvfrom()");
uwsgi_error("uwsgi_master_manage_udp()/recvfrom()");
}
else if (rlen > 0) {
memset(udp_client_addr, 0, 16);
if (inet_ntop(AF_INET, &udp_client.sin_addr.s_addr, udp_client_addr, 16)) {
if (uwsgi.wsgi_req->buffer[0] == UWSGI_MODIFIER_MULTICAST_ANNOUNCE) {
if (buf[0] == UWSGI_MODIFIER_MULTICAST_ANNOUNCE) {
}
else if (uwsgi.wsgi_req->buffer[0] == 0x30 && uwsgi.snmp) {
manage_snmp(udp_fd, (uint8_t *) uwsgi.wsgi_req->buffer, rlen, &udp_client);
else if (buf[0] == 0x30 && uwsgi.snmp) {
manage_snmp(udp_fd, (uint8_t *) buf, rlen, &udp_client);
}
else {
@@ -57,7 +84,7 @@ void uwsgi_master_manage_udp(int udp_fd) {
int udp_managed = 0;
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->manage_udp) {
if (uwsgi.p[i]->manage_udp(udp_client_addr, udp_client.sin_port, uwsgi.wsgi_req->buffer, rlen)) {
if (uwsgi.p[i]->manage_udp(udp_client_addr, udp_client.sin_port, buf, rlen)) {
udp_managed = 1;
break;
}
@@ -66,49 +93,17 @@ void uwsgi_master_manage_udp(int udp_fd) {
// else a simple udp logger
if (!udp_managed) {
uwsgi_log("[udp:%s:%d] %.*s", udp_client_addr, ntohs(udp_client.sin_port), (int) rlen, uwsgi.wsgi_req->buffer);
uwsgi_log("[udp:%s:%d] %.*s", udp_client_addr, ntohs(udp_client.sin_port), (int) rlen, buf);
}
}
}
else {
uwsgi_error("inet_ntop()");
uwsgi_error("uwsgi_master_manage_udp()/inet_ntop()");
}
}
}
void uwsgi_master_manage_emperor() {
char byte;
ssize_t rlen = read(uwsgi.emperor_fd, &byte, 1);
if (rlen > 0) {
uwsgi_log_verbose("received message %d from emperor\n", byte);
// remove me
if (byte == 0) {
close(uwsgi.emperor_fd);
if (!uwsgi.status.brutally_reloading)
kill_them_all(0);
}
// reload me
else if (byte == 1) {
// un-lazy the stack to trigger a real reload
uwsgi.lazy = 0;
uwsgi_block_signal(SIGHUP);
grace_them_all(0);
uwsgi_unblock_signal(SIGHUP);
}
}
else {
uwsgi_log("lost connection with my emperor !!!\n");
close(uwsgi.emperor_fd);
if (!uwsgi.status.brutally_reloading)
kill_them_all(0);
sleep(2);
exit(1);
}
}
void uwsgi_master_restore_snapshot() {
int i, waitpid_status;
uwsgi_log("[snapshot] restoring workers...\n");
@@ -378,6 +373,7 @@ int master_loop(char **argv, char **environ) {
#ifdef UWSGI_SSL
uwsgi_start_legions();
#endif
uwsgi_metrics_start_collector();
uwsgi_add_reload_fds();
@@ -387,7 +383,18 @@ int master_loop(char **argv, char **environ) {
uwsgi.wsgi_req->buffer = uwsgi.workers[0].cores[0].buffer;
if (uwsgi.has_emperor) {
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.emperor_fd);
if (uwsgi.emperor_proxy) {
uwsgi.emperor_fd_proxy = bind_to_unix(uwsgi.emperor_proxy, uwsgi.listen_queue, 0, 0);
if (uwsgi.emperor_fd_proxy < 0) exit(1);
if (chmod(uwsgi.emperor_proxy, S_IRUSR|S_IWUSR)) {
uwsgi_error("[emperor-proxy] chmod()");
exit(1);
}
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.emperor_fd_proxy);
}
else {
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.emperor_fd);
}
}
if (uwsgi.zerg_server) {
@@ -604,8 +611,10 @@ int master_loop(char **argv, char **environ) {
/* all processes ok, doing status scan after N seconds */
check_interval = uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL];
if (!check_interval)
if (!check_interval) {
check_interval = 1;
uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL] = 1;
}
// add unregistered file monitors
@@ -640,14 +649,14 @@ int master_loop(char **argv, char **environ) {
if (ushared->rb_timers_cnt > 0) {
min_timeout = uwsgi_min_rb_timer(rb_timers, NULL);
if (min_timeout == NULL) {
check_interval = uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL];
}
else {
check_interval = min_timeout->value - uwsgi_now();
if (check_interval <= 0) {
if (min_timeout) {
int delta = min_timeout->value - uwsgi_now();
if (delta <= 0) {
expire_rb_timeouts(rb_timers);
check_interval = 0;
}
// if the timer expires before the check_interval, override it
else if (delta < check_interval) {
check_interval = delta;
}
}
}
@@ -661,6 +670,9 @@ int master_loop(char **argv, char **environ) {
}
}
// update load counter
uwsgi_update_load_counters();
// check uwsgi-cron table
if (ushared->cron_cnt) {
@@ -701,8 +713,10 @@ int master_loop(char **argv, char **environ) {
uwsgi_master_check_idle();
check_interval = uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL];
if (!check_interval)
if (!check_interval) {
check_interval = 1;
uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL] = 1;
}
// get listen_queue status
@@ -735,6 +749,7 @@ int master_loop(char **argv, char **environ) {
uwsgi_master_check_mules_deadline();
uwsgi_master_check_spoolers_deadline();
uwsgi_master_check_crons_deadline();
uwsgi_master_check_mountpoints();
#ifdef __linux__
#ifdef MADV_MERGEABLE
+14
View File
@@ -118,6 +118,9 @@ void uwsgi_master_check_idle() {
if (errno != ECHILD)
uwsgi_error("uwsgi_master_check_idle()/waitpid()");
}
else {
uwsgi.workers[i].pid = 0;
}
}
uwsgi_add_sockets_to_queue(uwsgi.master_queue, -1);
uwsgi_log("cheap mode enabled: waiting for socket connection...\n");
@@ -322,3 +325,14 @@ void uwsgi_master_check_crons_deadline() {
}
}
void uwsgi_master_check_mountpoints() {
struct uwsgi_string_list *usl;
uwsgi_foreach(usl, uwsgi.mountpoints_check) {
if (uwsgi_check_mountpoint(usl->value)) {
uwsgi_log_verbose("mountpoint %s failed, triggering detonation...\n", usl->value);
uwsgi_nuclear_blast();
//never here
exit(1);
}
}
}
+5
View File
@@ -40,6 +40,11 @@ int uwsgi_master_manage_events(int interesting_fd) {
// emperor event ?
if (uwsgi.has_emperor) {
if (uwsgi.emperor_fd_proxy > -1 && interesting_fd == uwsgi.emperor_fd_proxy) {
uwsgi_master_manage_emperor_proxy();
return 0;
}
if (interesting_fd == uwsgi.emperor_fd) {
uwsgi_master_manage_emperor();
return 0;
+72 -7
View File
@@ -151,7 +151,13 @@ int uwsgi_calc_cheaper(void) {
uwsgi.cheaper_fifo_delta = 0;
}
if (!ignore_algo) needed_workers = uwsgi.cheaper_algo();
// if cheaper limits wants to change worker count, then skip cheaper algo
if (!needed_workers) needed_workers = uwsgi.cheaper_algo(!ignore_algo);
// safe check to verify if cheaper algo obeyed ignore_algo value
if (ignore_algo && needed_workers > 0) {
uwsgi_log("BUG! cheaper algo returned %d but it cannot spawn any worker at this time!\n", needed_workers);
needed_workers = 0;
}
if (needed_workers > 0) {
for (i = 1; i <= uwsgi.numproc; i++) {
@@ -189,7 +195,7 @@ int uwsgi_calc_cheaper(void) {
}
// fake algo to allow control with the fifo
int uwsgi_cheaper_algo_manual(void) {
int uwsgi_cheaper_algo_manual(int can_spawn) {
return 0;
}
@@ -228,7 +234,7 @@ int uwsgi_cheaper_algo_manual(void) {
*/
int uwsgi_cheaper_algo_spare(void) {
int uwsgi_cheaper_algo_spare(int can_spawn) {
int i;
static uint64_t overload_count = 0;
@@ -252,7 +258,7 @@ int uwsgi_cheaper_algo_spare(void) {
healthy:
// are we overloaded ?
if (overload_count > uwsgi.cheaper_overload) {
if (can_spawn && overload_count > uwsgi.cheaper_overload) {
#ifdef UWSGI_DEBUG
uwsgi_log("overloaded !!!\n");
@@ -320,7 +326,7 @@ healthy:
*/
int uwsgi_cheaper_algo_backlog(void) {
int uwsgi_cheaper_algo_backlog(int can_spawn) {
int i;
#ifdef __linux__
@@ -329,7 +335,7 @@ int uwsgi_cheaper_algo_backlog(void) {
int backlog = 0;
#endif
if (backlog > (int) uwsgi.cheaper_overload) {
if (can_spawn && backlog > (int) uwsgi.cheaper_overload) {
// activate the first available worker (taking step into account)
int decheaped = 0;
// search for cheaped workers
@@ -865,6 +871,65 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
goto end;
}
if (uwsgi.has_metrics) {
if (uwsgi_stats_key(us, "metrics"))
goto end;
if (uwsgi_stats_object_open(us))
goto end;
uwsgi_rlock(uwsgi.metrics_lock);
struct uwsgi_metric *um = uwsgi.metrics;
while(um) {
int64_t um_val = *um->value;
if (uwsgi_stats_key(us, um->name)) {
uwsgi_rwunlock(uwsgi.metrics_lock);
goto end;
}
if (uwsgi_stats_object_open(us)) {
uwsgi_rwunlock(uwsgi.metrics_lock);
goto end;
}
if (uwsgi_stats_keylong(us, "type", (long long) um->type)) {
uwsgi_rwunlock(uwsgi.metrics_lock);
goto end;
}
if (uwsgi_stats_comma(us)) {
uwsgi_rwunlock(uwsgi.metrics_lock);
goto end;
}
if (uwsgi_stats_keyslong(us, "value", (long long) um_val)) {
uwsgi_rwunlock(uwsgi.metrics_lock);
goto end;
}
if (uwsgi_stats_object_close(us)) {
uwsgi_rwunlock(uwsgi.metrics_lock);
goto end;
}
um = um->next;
if (um) {
if (uwsgi_stats_comma(us)) {
uwsgi_rwunlock(uwsgi.metrics_lock);
goto end;
}
}
}
uwsgi_rwunlock(uwsgi.metrics_lock);
if (uwsgi_stats_object_close(us))
goto end;
if (uwsgi_stats_comma(us))
goto end;
}
if (uwsgi_stats_key(us, "sockets"))
goto end;
@@ -1345,7 +1410,7 @@ end:
return NULL;
}
void uwsgi_register_cheaper_algo(char *name, int (*func) (void)) {
void uwsgi_register_cheaper_algo(char *name, int (*func) (int)) {
struct uwsgi_cheaper_algo *uca = uwsgi.cheaper_algos;
+913 -63
View File
File diff suppressed because it is too large Load Diff
+19 -3
View File
@@ -16,6 +16,7 @@
#ifndef MS_REC
#define MS_REC 16384
#endif
#include <sys/statfs.h>
#endif
struct uwsgi_mount_flag {
@@ -102,7 +103,7 @@ uint64_t uwsgi_mount_flag(char *mflag) {
}
int uwsgi_mount(char *fs, char *what, char *where, char *flags) {
#ifdef __FreeBSD__
#if defined(__FreeBSD__) || defined(__GNU_kFreeBSD__)
struct iovec iov[6];
#endif
unsigned long mountflags = 0;
@@ -121,7 +122,7 @@ int uwsgi_mount(char *fs, char *what, char *where, char *flags) {
parsed:
#ifdef __linux__
return mount(what, where, fs, mountflags, NULL);
#elif defined(__FreeBSD__)
#elif defined(__FreeBSD__) || defined(__GNU_kFreeBSD__)
iov[0].iov_base = "fstype";
iov[0].iov_len = 7;
iov[1].iov_base = fs;
@@ -189,7 +190,7 @@ unmountable:
free(slashed);
}
return umount2(where, mountflags);
#elif defined(__FreeBSD__)
#elif defined(__FreeBSD__) || defined(__GNU_kFreeBSD__)
return unmount(where, mountflags);
#endif
return -1;
@@ -236,3 +237,18 @@ int uwsgi_umount_hook(char *arg) {
free(tmp_arg);
return 0;
}
int uwsgi_check_mountpoint(char *mountpoint) {
#ifdef __linux__
struct statfs sfs;
int ret = statfs(mountpoint, &sfs);
if (ret) {
uwsgi_error("uwsgi_check_mountpoint()/statfs()");
return -1;
}
return 0;
#else
uwsgi_log("this platform does not support mountpoints check !!!\n");
return -1;
#endif
}
+1 -1
View File
@@ -323,7 +323,7 @@ static int u_offload_sendfile_do(struct uwsgi_thread *ut, struct uwsgi_offload_r
if (event_queue_add_fd_write(ut->queue, uor->fd2)) return -1;
return 0;
}
#if defined(__linux__) || defined(__sun__)
#if defined(__linux__) || defined(__sun__) || defined(__GNU_kFreeBSD__)
ssize_t len = sendfile(uor->fd2, uor->fd, &uor->pos, 128 * 1024);
if (len > 0) {
uor->written += len;
+1 -1
View File
@@ -57,7 +57,7 @@ void uwsgi_init_queue() {
uwsgi.queue_header->pos = 0;
uwsgi.queue_header->pull_pos = 0;
}
if (!uwsgi.queue) {
if (uwsgi.queue == MAP_FAILED) {
uwsgi_error("mmap()");
exit(1);
}
+2
View File
@@ -389,6 +389,8 @@ wait:
remains -= len;
*rlen += len;
continue;
}else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
goto wait;
}
*rlen = -1;
if (len == 0) {
+13 -3
View File
@@ -640,7 +640,6 @@ static int uwsgi_router_fixcl(struct uwsgi_route *ur, char *arg) {
return 0;
}
// log route
static int uwsgi_router_log_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
@@ -1199,10 +1198,21 @@ static int uwsgi_router_alarm(struct uwsgi_route *ur, char *arg) {
// send route
static int uwsgi_router_send_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
uwsgi_response_write_body_do(wsgi_req, route->data, route->data_len);
char **subject = (char **) (((char *)(wsgi_req))+route->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+route->subject_len);
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, route, *subject, *subject_len, route->data, route->data_len);
if (!ub) {
return UWSGI_ROUTE_BREAK;
}
if (route->custom) {
uwsgi_response_write_body_do(wsgi_req, "\r\n", 2);
if (uwsgi_buffer_append(ub, "\r\n", 2)) {
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_BREAK;
}
}
uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_send(struct uwsgi_route *ur, char *arg) {
+1 -1
View File
@@ -20,7 +20,7 @@ ssize_t uwsgi_sendfile_do(int sockfd, int filefd, size_t pos, size_t len) {
int sf_ret = sendfile(filefd, sockfd, pos, &sf_len, NULL, 0);
if (sf_ret == 0 || (sf_ret == -1 && errno == EAGAIN)) return sf_len;
return -1;
#elif defined(__linux__) || defined(__sun__)
#elif defined(__linux__) || defined(__sun__) || defined(__GNU_kFreeBSD__)
off_t off = pos;
return sendfile(sockfd, filefd, &off, len);
#endif
+2
View File
@@ -301,8 +301,10 @@ int uwsgi_signal_send(int fd, uint8_t sig) {
else {
uwsgi_error("uwsgi_signal_send()");
}
uwsgi.shared->unrouted_signals++;
return -1;
}
uwsgi.shared->routed_signals++;
return 0;
}
+55 -14
View File
@@ -23,6 +23,7 @@ static uint64_t get_uwsgi_custom_snmp_value(uint64_t, uint8_t *);
static uint8_t snmp_int_to_snmp(uint64_t, uint8_t, uint8_t *);
static ssize_t build_snmp_response(uint8_t, uint8_t, uint8_t *, int, uint8_t *, uint8_t *, uint8_t *);
static ssize_t build_snmp_metric_response(int64_t, uint8_t, uint8_t *, int, uint8_t *, uint8_t *, uint8_t *);
void manage_snmp(int fd, uint8_t * buffer, int size, struct sockaddr_in *client_addr) {
@@ -71,7 +72,7 @@ void manage_snmp(int fd, uint8_t * buffer, int size, struct sockaddr_in *client_
uwsgi_debug("SNMP version: %d\n", version);
#endif
// check for community string (this must be set from the python vm using uwsgi.snmp_community or with --snmp-community arg)
// check for community string (this must be set from the api using uwsgi.snmp_community or with --snmp-community arg)
if (*ptr != SNMP_STRING)
return;
ptr++;
@@ -196,7 +197,7 @@ void manage_snmp(int fd, uint8_t * buffer, int size, struct sockaddr_in *client_
ptr++;
oidlen = *ptr;
if (oidlen != 11)
if (oidlen < 11)
return;
ptr++;
@@ -208,21 +209,33 @@ void manage_snmp(int fd, uint8_t * buffer, int size, struct sockaddr_in *client_
oid_part[0] = *ptr;
if (oid_part[0] != 1 && oid_part[0] != 2)
return;
ptr++;
// old style SNMP metrics
if (oid_part[0] == 1 || oid_part[0] == 2) {
ptr++;
oid_part[1] = *ptr;
if (oid_part[1] < 1 || oid_part[1] > 100)
return;
ptr++;
oid_part[1] = *ptr;
if (oid_part[1] < 1 || oid_part[1] > 100)
return;
ptr++;
// check for null
if (memcmp((char *) ptr, "\x05\x00", 2))
return;
ptr += 2;
// check for null
if (memcmp((char *) ptr, "\x05\x00", 2))
return;
ptr += 2;
size = build_snmp_response(oid_part[0], oid_part[1], buffer, size, seq1, seq2, seq3);
}
// metrics subsystem
else {
size_t metric_asn_len = oidlen - 9;
char *metric_asn = (char *) ptr;
struct uwsgi_metric *um = uwsgi_metric_find_by_asn(metric_asn, metric_asn_len);
if (!um) return;
uwsgi_rlock(uwsgi.metrics_lock);
int64_t value = *um->value;
uwsgi_rwunlock(uwsgi.metrics_lock);
size = build_snmp_metric_response(value, um->type, buffer, size, seq1, seq2, seq3);
}
size = build_snmp_response(oid_part[0], oid_part[1], buffer, size, seq1, seq2, seq3);
if (size > 0) {
if (sendto(fd, buffer, size, 0, (struct sockaddr *) client_addr, sizeof(struct sockaddr_in)) < 0) {
@@ -292,6 +305,7 @@ static uint8_t snmp_int_to_snmp(uint64_t snmp_val, uint8_t oid_type, uint8_t * b
uint8_t tlen;
int i, j;
uint8_t *ptr = (uint8_t *) & snmp_val;
int32_t val32 = (int32_t) snmp_val;
// check for counter, counter64 or gauge
@@ -303,6 +317,7 @@ static uint8_t snmp_int_to_snmp(uint64_t snmp_val, uint8_t oid_type, uint8_t * b
}
else {
tlen = 4;
ptr = (uint8_t *) &val32;
}
buffer[0] = tlen;
@@ -352,6 +367,32 @@ static ssize_t build_snmp_response(uint8_t oid1, uint8_t oid2, uint8_t * buffer,
}
static ssize_t build_snmp_metric_response(int64_t value, uint8_t type, uint8_t * buffer, int size, uint8_t * seq1, uint8_t * seq2, uint8_t * seq3) {
uint8_t oid_sz;
if (type == UWSGI_METRIC_GAUGE) {
buffer[size - 2] = SNMP_GAUGE;
oid_sz = snmp_int_to_snmp(value, SNMP_GAUGE, buffer + (size - 1));
}
else {
buffer[size - 2] = SNMP_COUNTER64;
oid_sz = snmp_int_to_snmp(value, SNMP_COUNTER64, buffer + (size - 1));
}
if (oid_sz < 1)
return -1;
oid_sz--;
buffer[1] += oid_sz;
*seq1 += oid_sz;
*seq2 += oid_sz;
*seq3 += oid_sz;
return size + oid_sz;
}
void uwsgi_opt_snmp(char *opt, char *value, void *foobar) {
uwsgi.snmp = 1;
if (value) {
+39 -16
View File
@@ -1366,7 +1366,7 @@ void uwsgi_add_sockets_to_queue(int queue, int async_id) {
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
if (uwsgi_sock->fd_threads && async_id > -1) {
if (uwsgi_sock->fd_threads && async_id > -1 && uwsgi_sock->fd_threads[async_id] > -1) {
event_queue_add_fd_read(queue, uwsgi_sock->fd_threads[async_id]);
}
else if (uwsgi_sock->fd > -1) {
@@ -1673,18 +1673,7 @@ void uwsgi_map_sockets() {
if (!enabled) {
close(uwsgi_sock->fd);
int fd = open("/dev/null", O_RDONLY);
if (fd < 0) {
uwsgi_error_open("/dev/null");
exit(1);
}
if (fd != uwsgi_sock->fd) {
if (dup2(fd, uwsgi_sock->fd) < 0) {
uwsgi_error("dup2()");
exit(1);
}
close(fd);
}
uwsgi_remap_fd(uwsgi_sock->fd, "/dev/null");
uwsgi_sock->disabled = 1;
}
@@ -1714,6 +1703,10 @@ void uwsgi_bind_sockets() {
while (uwsgi_sock) {
if (!uwsgi_sock->bound && !uwsgi_socket_is_already_bound(uwsgi_sock->name)) {
char *tcp_port = strrchr(uwsgi_sock->name, ':');
int current_defer_accept = uwsgi.no_defer_accept;
if (uwsgi_sock->no_defer) {
uwsgi.no_defer_accept = 1;
}
if (tcp_port == NULL) {
uwsgi_sock->fd = bind_to_unix(uwsgi_sock->name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
uwsgi_sock->family = AF_UNIX;
@@ -1747,6 +1740,7 @@ void uwsgi_bind_sockets() {
uwsgi_log("unable to create server socket on: %s\n", uwsgi_sock->name);
exit(1);
}
uwsgi.no_defer_accept = current_defer_accept;
}
uwsgi_sock->bound = 1;
uwsgi_sock = uwsgi_sock->next;
@@ -1877,7 +1871,20 @@ setup_proto:
if (uwsgi.offload_threads > 0)
uwsgi_sock->can_offload = 1;
}
else if (requested_protocol && !strcmp("raw", requested_protocol)) {
uwsgi_sock->proto = uwsgi_proto_raw_parser;
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body;
uwsgi_sock->proto_write = uwsgi_proto_base_write;
uwsgi_sock->proto_write_headers = uwsgi_proto_base_write;
uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile;
uwsgi_sock->proto_close = uwsgi_proto_base_close;
if (uwsgi.offload_threads > 0)
uwsgi_sock->can_offload = 1;
}
else if (requested_protocol && (!strcmp("fastcgi", requested_protocol) || !strcmp("fcgi", requested_protocol))) {
uwsgi_sock->proto = uwsgi_proto_fastcgi_parser;
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
@@ -1903,7 +1910,7 @@ setup_proto:
uwsgi_sock->proto_close = uwsgi_proto_fastcgi_close;
}
else if (requested_protocol && (!strcmp("scgi", requested_protocol) || !strcmp("scgi", requested_protocol))) {
else if (requested_protocol && !strcmp("scgi", requested_protocol)) {
uwsgi_sock->proto = uwsgi_proto_scgi_parser;
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_cgi_prepare_headers;
@@ -1916,7 +1923,7 @@ setup_proto:
uwsgi_sock->proto_close = uwsgi_proto_base_close;
}
else if (requested_protocol && (!strcmp("scgi-nph", requested_protocol) || !strcmp("scgi-nph", requested_protocol))) {
else if (requested_protocol && !strcmp("scgi-nph", requested_protocol)) {
uwsgi_sock->proto = uwsgi_proto_scgi_parser;
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
@@ -1935,6 +1942,22 @@ setup_proto:
uwsgi.zeromq = 1;
}
#endif
else if (requested_protocol && !strcmp("puwsgi", requested_protocol)) {
uwsgi_sock->proto = uwsgi_proto_puwsgi_parser;
uwsgi_sock->proto_accept = uwsgi_proto_puwsgi_accept;
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
uwsgi_sock->proto_read_body = uwsgi_proto_noop_read_body;
uwsgi_sock->proto_write = uwsgi_proto_base_write;
uwsgi_sock->proto_write_headers = uwsgi_proto_base_write;
uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile;
uwsgi_sock->proto_close = uwsgi_proto_puwsgi_close;
uwsgi_sock->fd_threads = uwsgi_malloc(sizeof(int) * uwsgi.cores);
memset(uwsgi_sock->fd_threads, -1, sizeof(int) * uwsgi.cores);
uwsgi_sock->retry = uwsgi_calloc(sizeof(int) * uwsgi.cores);
uwsgi.is_et = 1;
}
else {
uwsgi_sock->proto = uwsgi_proto_uwsgi_parser;
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
+18 -45
View File
@@ -440,6 +440,11 @@ void uwsgi_stats_pusher_loop(struct uwsgi_thread *ut) {
void *events = event_queue_alloc(1);
for (;;) {
int nevents = event_queue_wait_multi(ut->queue, 1, events, 1);
if (nevents < 0) {
if (errno == EINTR) continue;
uwsgi_log_verbose("ending the stats pusher thread...\n");
return;
}
if (nevents > 0) {
int interesting_fd = event_queue_interesting_fd(events, 0);
char buf[4096];
@@ -457,7 +462,8 @@ void uwsgi_stats_pusher_loop(struct uwsgi_thread *ut) {
struct uwsgi_stats *us = NULL;
while (uspi) {
int delta = uspi->freq ? uspi->freq : uwsgi.stats_pusher_default_freq;
if ((uspi->last_run + delta) <= now) {
if (((uspi->last_run + delta) <= now) || (uspi->needs_retry && (uspi->next_retry <= now))) {
if (uspi->needs_retry) uspi->retries++;
if (uspi->raw) {
uspi->pusher->func(uspi, now, NULL, 0);
}
@@ -470,6 +476,17 @@ void uwsgi_stats_pusher_loop(struct uwsgi_thread *ut) {
uspi->pusher->func(uspi, now, us->base, us->pos);
}
uspi->last_run = now;
if (uspi->needs_retry && uspi->max_retries > 0 && uspi->retries < uspi->max_retries) {
uwsgi_log("[uwsgi-stats-pusher] %s failed (%d), retry in %ds\n", uspi->pusher->name, uspi->retries, uspi->retry_delay);
uspi->next_retry = now + uspi->retry_delay;
} else if (uspi->needs_retry && uspi->retries >= uspi->max_retries) {
uwsgi_log("[uwsgi-stats-pusher] %s failed and maximum number of retries was reached (%d)\n", uspi->pusher->name, uspi->retries);
uspi->needs_retry = 0;
uspi->retries = 0;
} else if (uspi->retries) {
uwsgi_log("[uwsgi-stats-pusher] retry succeeded for %s\n", uspi->pusher->name);
uspi->retries = 0;
}
}
next:
uspi = uspi->next;
@@ -531,50 +548,6 @@ struct uwsgi_stats_pusher *uwsgi_register_stats_pusher(char *name, void (*func)
return pusher;
}
struct uwsgi_stats_pusher_file_conf {
char *path;
char *freq;
char *separator;
};
void uwsgi_stats_pusher_file(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) {
struct uwsgi_stats_pusher_file_conf *uspic = (struct uwsgi_stats_pusher_file_conf *) uspi->data;
if (!uspi->configured) {
uspic = uwsgi_calloc(sizeof(struct uwsgi_stats_pusher_file_conf));
if (uspi->arg) {
if (uwsgi_kvlist_parse(uspi->arg, strlen(uspi->arg), ',', '=', "path", &uspic->path, "separator", &uspic->separator, "freq", &uspic->freq, NULL)) {
free(uspi);
return;
}
}
if (!uspic->path)
uspic->path = "uwsgi.stats";
if (!uspic->separator)
uspic->separator = "\n\n";
if (uspic->freq)
uspi->freq = atoi(uspic->freq);
uspi->configured = 1;
uspi->data = uspic;
}
int fd = open(uspic->path, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP);
if (fd < 0) {
uwsgi_error_open(uspic->path);
return;
}
ssize_t rlen = write(fd, json, json_len);
if (rlen != (ssize_t) json_len) {
uwsgi_error("uwsgi_stats_pusher_file() -> write()\n");
}
rlen = write(fd, uspic->separator, strlen(uspic->separator));
if (rlen != (ssize_t) strlen(uspic->separator)) {
uwsgi_error("uwsgi_stats_pusher_file() -> write()\n");
}
close(fd);
}
static void stats_dump_var(char *k, uint16_t kl, char *v, uint16_t vl, void *data) {
struct uwsgi_stats *us = (struct uwsgi_stats *) data;
if (us->dirty) return;
+104
View File
@@ -379,3 +379,107 @@ char *uwsgi_cheap_string(char *buf, int len) {
return buf - 1;
}
/*
status 0: append mode
status 1: single quote found
status 2: double quote found
status 3: backslash found (on 0)
status 4: backslash found (on 1)
status 5: backslash found (on 2)
*/
char ** uwsgi_split_quoted(char *what, size_t what_len, char *sep, size_t *rlen) {
size_t i;
int status = 0;
char *base = uwsgi_concat2n(what, what_len, "", 0);
char *item = NULL;
char *ptr = NULL;
*rlen = 0;
char **ret = (char **) uwsgi_malloc(sizeof(char *) * (what_len+1));
for(i=0;i<what_len;i++) {
if (!item) {
item = uwsgi_malloc((what_len - i)+1);
ptr = item;
}
if (status == 0) {
if (base[i] == '\\') {
status = 3;
}
else if (base[i] == '"') {
status = 2;
}
else if (base[i] == '\'') {
status = 1;
}
else if (strchr(sep, base[i])) {
*ptr++= 0;
ret[(*rlen)] = item; (*rlen)++;
item = NULL;
}
else {
*ptr++= base[i];
}
continue;
}
// backslash
if (status == 3) {
*ptr++= base[i];
status = 0;
continue;
}
// single quote
if (status == 1) {
if (base[i] == '\\') {
status = 4;
}
else if (base[i] == '\'') {
status = 0;
}
else {
*ptr++= base[i];
}
continue;
}
// double quote
if (status == 2) {
if (base[i] == '\\') {
status = 5;
}
else if (base[i] == '"') {
status = 0;
}
else {
*ptr++= base[i];
}
continue;
}
// backslash single quote
if (status == 4) {
*ptr++= base[i];
status = 1;
continue;
}
// backslash double quote
if (status == 5) {
*ptr++= base[i];
status = 2;
continue;
}
}
if (item) {
*ptr++= 0;
ret[(*rlen)] = item; (*rlen)++;
}
free(base);
return ret;
}
+1094 -871
View File
File diff suppressed because it is too large Load Diff
+205 -177
View File
@@ -53,6 +53,12 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"scgi-modifier1", required_argument, 0, "force the specified modifier1 when using SCGI protocol", uwsgi_opt_set_64bit, &uwsgi.scgi_modifier1, 0},
{"scgi-modifier2", required_argument, 0, "force the specified modifier2 when using SCGI protocol", uwsgi_opt_set_64bit, &uwsgi.scgi_modifier2, 0},
{"raw-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using RAW protocol", uwsgi_opt_add_socket_no_defer, "raw", 0},
{"raw-modifier1", required_argument, 0, "force the specified modifier1 when using RAW protocol", uwsgi_opt_set_64bit, &uwsgi.raw_modifier1, 0},
{"raw-modifier2", required_argument, 0, "force the specified modifier2 when using RAW protocol", uwsgi_opt_set_64bit, &uwsgi.raw_modifier2, 0},
{"puwsgi-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using persistent uwsgi protocol (puwsgi)", uwsgi_opt_add_socket, "puwsgi", 0},
{"protocol", required_argument, 0, "force the specified protocol for default sockets", uwsgi_opt_set_str, &uwsgi.protocol, 0},
{"socket-protocol", required_argument, 0, "force the specified protocol for default sockets", uwsgi_opt_set_str, &uwsgi.protocol, 0},
{"shared-socket", required_argument, 0, "create a shared sacket for advanced jailing or ipc", uwsgi_opt_add_shared_socket, NULL, 0},
@@ -78,7 +84,9 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"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},
{"set", required_argument, 'S', "set a custom placeholder", uwsgi_opt_set_placeholder, NULL, UWSGI_OPT_IMMEDIATE},
{"set", required_argument, 'S', "set a placeholder or an option", uwsgi_opt_set_placeholder, NULL, UWSGI_OPT_IMMEDIATE},
{"set-placeholder", required_argument, 0, "set a placeholder", uwsgi_opt_set_placeholder, (void *) 1, UWSGI_OPT_IMMEDIATE},
{"set-ph", required_argument, 0, "set a placeholder", uwsgi_opt_set_placeholder, (void *) 1, UWSGI_OPT_IMMEDIATE},
{"get", required_argument, 0, "print the specified option value and exit", uwsgi_opt_add_string_list, &uwsgi.get_list, UWSGI_OPT_NO_INITIAL},
{"declare-option", required_argument, 0, "declare a new uWSGI custom option", uwsgi_opt_add_custom_option, NULL, UWSGI_OPT_IMMEDIATE},
@@ -173,11 +181,13 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"master", no_argument, 'M', "enable master process", uwsgi_opt_true, &uwsgi.master_process, 0},
{"honour-stdin", no_argument, 0, "do not remap stdin to /dev/null", uwsgi_opt_true, &uwsgi.honour_stdin, 0},
{"emperor", required_argument, 0, "run the Emperor", uwsgi_opt_add_string_list, &uwsgi.emperor, 0},
{"emperor-proxy-socket", required_argument, 0, "force the vassal to became an Emperor proxy", uwsgi_opt_set_str, &uwsgi.emperor_proxy, 0},
{"emperor-wrapper", required_argument, 0, "set a binary wrapper for vassals", uwsgi_opt_set_str, &uwsgi.emperor_wrapper, 0},
{"emperor-nofollow", no_argument, 0, "do not follow symlinks when checking for mtime", uwsgi_opt_true, &uwsgi.emperor_nofollow, 0},
{"emperor-procname", required_argument, 0, "set the Emperor process name", uwsgi_opt_set_str, &uwsgi.emperor_procname, 0},
{"emperor-freq", required_argument, 0, "set the Emperor scan frequency (default 3 seconds)", uwsgi_opt_set_int, &uwsgi.emperor_freq, 0},
{"emperor-required-heartbeat", required_argument, 0, "set the Emperor tolerance about heartbeats", uwsgi_opt_set_int, &uwsgi.emperor_heartbeat, 0},
{"emperor-curse-tolerance", required_argument, 0, "set the Emperor tolerance about cursed vassals", uwsgi_opt_set_int, &uwsgi.emperor_curse_tolerance, 0},
{"emperor-pidfile", required_argument, 0, "write the Emperor pid in the specified file", uwsgi_opt_set_str, &uwsgi.emperor_pidfile, 0},
{"emperor-tyrant", no_argument, 0, "put the Emperor in Tyrant mode", uwsgi_opt_true, &uwsgi.emperor_tyrant, 0},
{"emperor-tyrant-nofollow", no_argument, 0, "do not follow symlinks when checking for uid/gid in Tyrant mode", uwsgi_opt_true, &uwsgi.emperor_tyrant_nofollow, 0},
@@ -197,15 +207,26 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"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
#ifdef UWSGI_CAP
{"emperor-cap", required_argument, 0, "set vassals capability", uwsgi_opt_set_emperor_cap, NULL, 0},
{"vassals-cap", required_argument, 0, "set vassals capability", uwsgi_opt_set_emperor_cap, NULL, 0},
{"vassal-cap", required_argument, 0, "set vassals capability", uwsgi_opt_set_emperor_cap, NULL, 0},
#endif
{"imperial-monitor-list", no_argument, 0, "list enabled imperial monitors", uwsgi_opt_true, &uwsgi.imperial_monitor_list, 0},
{"imperial-monitors-list", no_argument, 0, "list enabled imperial monitors", uwsgi_opt_true, &uwsgi.imperial_monitor_list, 0},
{"vassals-inherit", required_argument, 0, "add config templates to vassals config (uses --inherit)", uwsgi_opt_add_string_list, &uwsgi.vassals_templates, 0},
{"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-inherit-before", required_argument, 0, "add config templates to vassals config (uses --inherit, parses before the vassal file)", uwsgi_opt_add_string_list, &uwsgi.vassals_templates_before, 0},
{"vassals-include-before", required_argument, 0, "include config templates to vassals config (uses --include instead of --inherit, parses before the vassal file)", uwsgi_opt_add_string_list, &uwsgi.vassals_includes_before, 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},
{"vassals-set", required_argument, 0, "automatically set the specified option (via --set) for every vassal", uwsgi_opt_add_string_list, &uwsgi.vassals_set, 0},
{"vassal-set", required_argument, 0, "automatically set the specified option (via --set) for every vassal", uwsgi_opt_add_string_list, &uwsgi.vassals_set, 0},
{"heartbeat", required_argument, 0, "announce healtness to the emperor", uwsgi_opt_set_int, &uwsgi.heartbeat, 0},
{"auto-snapshot", optional_argument, 0, "automatically make workers snaphost after reload", uwsgi_opt_set_int, &uwsgi.auto_snapshot, UWSGI_OPT_LAZY},
{"reload-mercy", required_argument, 0, "set the maximum time (in seconds) we wait for workers and other processes to die during reload/shutdown", uwsgi_opt_set_int, &uwsgi.reload_mercy, 0},
{"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},
@@ -307,8 +328,9 @@ static struct uwsgi_option uwsgi_base_options[] = {
#endif
#ifdef __linux__
{"unshare", required_argument, 0, "unshare() part of the processes and put it in a new namespace", uwsgi_opt_set_unshare, &uwsgi.unshare, 0},
{"unshare2", required_argument, 0, "unshare() part of the processes and put it in a new namespace after rootfs change", uwsgi_opt_set_unshare, &uwsgi.unshare2, 0},
#endif
#ifdef __FreeBSD__
#if defined(__FreeBSD__) || defined(__GNU_kFreeBSD__)
{"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},
@@ -463,6 +485,11 @@ 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},
{"check-mountpoint", required_argument, 0, "destroy the instance if a filesystem is no more reachable (useful for reliable Fuse management)", uwsgi_opt_add_string_list, &uwsgi.mountpoints_check, UWSGI_OPT_MASTER},
{"mountpoint-check", required_argument, 0, "destroy the instance if a filesystem is no more reachable (useful for reliable Fuse management)", uwsgi_opt_add_string_list, &uwsgi.mountpoints_check, UWSGI_OPT_MASTER},
{"check-mount", required_argument, 0, "destroy the instance if a filesystem is no more reachable (useful for reliable Fuse management)", uwsgi_opt_add_string_list, &uwsgi.mountpoints_check, UWSGI_OPT_MASTER},
{"mount-check", required_argument, 0, "destroy the instance if a filesystem is no more reachable (useful for reliable Fuse management)", uwsgi_opt_add_string_list, &uwsgi.mountpoints_check, UWSGI_OPT_MASTER},
{"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},
@@ -483,13 +510,22 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"reload-on-exception-repr", required_argument, 0, "reload a worker when a specific exception type+value (language-specific) is raised", uwsgi_opt_add_string_list, &uwsgi.reload_on_exception_repr, 0},
{"exception-handler", required_argument, 0, "add an exception handler", uwsgi_opt_add_string_list, &uwsgi.exception_handlers_instance, UWSGI_OPT_MASTER},
{"enable-metrics", no_argument, 0, "enable metrics subsystem", uwsgi_opt_true, &uwsgi.has_metrics, UWSGI_OPT_MASTER},
{"metric", required_argument, 0, "add a custom metric", uwsgi_opt_add_string_list, &uwsgi.additional_metrics, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
{"metric-threshold", required_argument, 0, "add a metric threshold/alarm", uwsgi_opt_add_string_list, &uwsgi.metrics_threshold, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
{"metric-alarm", required_argument, 0, "add a metric threshold/alarm", uwsgi_opt_add_string_list, &uwsgi.metrics_threshold, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
{"metrics-dir", required_argument, 0, "exports metrics as text files in the specified directory", uwsgi_opt_set_str, &uwsgi.metrics_dir, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
{"metrics-dir-restore", no_argument, 0, "restore last value taken from the metrics dir", uwsgi_opt_true, &uwsgi.metrics_dir_restore, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
{"metric-dir", required_argument, 0, "exports metrics as text files in the specified directory", uwsgi_opt_set_str, &uwsgi.metrics_dir, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
{"metric-dir-restore", no_argument, 0, "restore last value taken from the metrics dir", uwsgi_opt_true, &uwsgi.metrics_dir_restore, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
{"udp", required_argument, 0, "run the udp server on the specified address", uwsgi_opt_set_str, &uwsgi.udp_socket, UWSGI_OPT_MASTER},
{"stats", required_argument, 0, "enable the stats server on the specified address", uwsgi_opt_set_str, &uwsgi.stats, UWSGI_OPT_MASTER},
{"stats-server", required_argument, 0, "enable the stats server on the specified address", uwsgi_opt_set_str, &uwsgi.stats, UWSGI_OPT_MASTER},
{"stats-http", no_argument, 0, "prefix stats server json output with http headers", uwsgi_opt_true, &uwsgi.stats_http, UWSGI_OPT_MASTER},
{"stats-minified", no_argument, 0, "minify statistics json output", uwsgi_opt_true, &uwsgi.stats_minified, UWSGI_OPT_MASTER},
{"stats-min", no_argument, 0, "minify statistics json output", uwsgi_opt_true, &uwsgi.stats_minified, UWSGI_OPT_MASTER},
{"stats-push", required_argument, 0, "push the stats json to the specified destination", uwsgi_opt_add_string_list, &uwsgi.requested_stats_pushers, UWSGI_OPT_MASTER},
{"stats-push", required_argument, 0, "push the stats json to the specified destination", uwsgi_opt_add_string_list, &uwsgi.requested_stats_pushers, UWSGI_OPT_MASTER|UWSGI_OPT_METRICS},
{"stats-pusher-default-freq", required_argument, 0, "set the default frequency of stats pushers", uwsgi_opt_set_int, &uwsgi.stats_pusher_default_freq, UWSGI_OPT_MASTER},
{"stats-pushers-default-freq", required_argument, 0, "set the default frequency of stats pushers", uwsgi_opt_set_int, &uwsgi.stats_pusher_default_freq, UWSGI_OPT_MASTER},
{"multicast", required_argument, 0, "subscribe to specified multicast group", uwsgi_opt_set_str, &uwsgi.multicast_group, UWSGI_OPT_MASTER},
@@ -607,7 +643,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"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},
{"log-maxsize", required_argument, 0, "set maximum logfile size", uwsgi_opt_set_64bit, &uwsgi.log_maxsize, UWSGI_OPT_LOG_MASTER},
{"log-backupname", required_argument, 0, "set logfile name after rotation", uwsgi_opt_set_str, &uwsgi.log_backupname, 0},
{"logdate", optional_argument, 0, "prefix logs with date or a strftime string", uwsgi_opt_log_date, NULL, 0},
@@ -834,6 +870,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"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},
{"attach-control-daemon", required_argument, 0, "attach a command/daemon to the master process (the command has to not go in background), when teh daemon dies, the master dies too", 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},
#ifdef UWSGI_SSL
@@ -857,7 +894,10 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"dump-options", no_argument, 0, "dump the full list of available options", uwsgi_opt_true, &uwsgi.dump_options, 0},
{"show-config", no_argument, 0, "show the current config reformatted as ini", uwsgi_opt_true, &uwsgi.show_config, 0},
{"binary-append-data", required_argument, 0, "return the content of a resource to stdout for appending to a uwsgi binary (for data:// usage)", uwsgi_opt_binary_append_data, NULL, UWSGI_OPT_IMMEDIATE},
{"print", required_argument, 0, "simple print", uwsgi_opt_print, NULL, 0},
{"iprint", required_argument, 0, "simple print (immediate version)", uwsgi_opt_print, NULL, UWSGI_OPT_IMMEDIATE},
{"exit", optional_argument, 0, "force exit() of the instance", uwsgi_opt_exit, NULL, UWSGI_OPT_IMMEDIATE},
{"cflags", no_argument, 0, "report uWSGI CFLAGS (useful for building external plugins)", uwsgi_opt_cflags, NULL, UWSGI_OPT_IMMEDIATE},
{"dot-h", no_argument, 0, "dump the uwsgi.h used for building the core (useful for building external plugins)", uwsgi_opt_dot_h, NULL, UWSGI_OPT_IMMEDIATE},
{"version", no_argument, 0, "print uWSGI version", uwsgi_opt_print, UWSGI_VERSION, 0},
@@ -879,140 +919,6 @@ 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)
value_len = strlen(value);
off_t pos = 0;
char **opt_argv;
char *tmp_val = NULL, *p = NULL;
if (strcmp(uco->name, key)) {
return 0;
}
// now count the number of args
for (i = 0; i < value_len; i++) {
if (value[i] == ' ') {
count++;
}
}
// allocate a tmp array
opt_argv = uwsgi_calloc(sizeof(char *) * count);
//make a copy of the value;
if (value_len > 0) {
tmp_val = uwsgi_str(value);
// fill the array of options
char *p, *ctx = NULL;
uwsgi_foreach_token(tmp_val, " ", p, ctx) {
opt_argv[pos] = p;
pos++;
}
}
else {
// no argument specified
opt_argv[0] = "";
}
#ifdef UWSGI_DEBUG
uwsgi_log("found custom option %s with %d args\n", key, count);
#endif
// now make a copy of the option template
char *tmp_opt = uwsgi_str(uco->value);
// split it
char *ctx = NULL;
uwsgi_foreach_token(tmp_opt, ";", p, ctx) {
char *equal = strchr(p, '=');
if (!equal)
goto clear;
*equal = '\0';
// build the key
char *new_key = uwsgi_str(p);
for (i = 0; i < count; i++) {
char *old_key = new_key;
char *tmp_num = uwsgi_num2str(i + 1);
char *placeholder = uwsgi_concat2((char *) "$", tmp_num);
free(tmp_num);
new_key = uwsgi_substitute(old_key, placeholder, opt_argv[i]);
if (new_key != old_key)
free(old_key);
free(placeholder);
}
// build the value
char *new_value = uwsgi_str(equal + 1);
for (i = 0; i < count; i++) {
char *old_value = new_value;
char *tmp_num = uwsgi_num2str(i + 1);
char *placeholder = uwsgi_concat2((char *) "$", tmp_num);
free(tmp_num);
new_value = uwsgi_substitute(old_value, placeholder, opt_argv[i]);
if (new_value != old_value)
free(old_value);
free(placeholder);
}
retry:
configured = uwsgi_manage_opt(new_key, new_value);
if (!configured && uwsgi.autoload) {
if (uwsgi_try_autoload(new_key)) goto retry;
}
}
clear:
free(tmp_val);
free(tmp_opt);
free(opt_argv);
return 1;
}
int uwsgi_manage_opt(char *key, char *value) {
struct uwsgi_option *op = uwsgi.options;
while (op->name) {
if (!strcmp(key, op->name)) {
op->func(key, value, op->data);
return 1;
}
op++;
}
struct uwsgi_custom_option *uco = uwsgi.custom_options;
while (uco) {
if (uwsgi_manage_custom_option(uco, key, value)) {
return 1;
}
uco = uco->next;
}
return 0;
}
void uwsgi_configure() {
int i;
// and now apply the remaining configs
restart:
for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
if (uwsgi.exported_opts[i]->configured)
continue;
uwsgi.dirty_config = 0;
uwsgi.exported_opts[i]->configured = uwsgi_manage_opt(uwsgi.exported_opts[i]->key, uwsgi.exported_opts[i]->value);
if (uwsgi.exported_opts[i]->configured == 0 && uwsgi.autoload) {
uwsgi.dirty_config = uwsgi_try_autoload(uwsgi.exported_opts[i]->key);
}
if (uwsgi.dirty_config)
goto restart;
}
}
void config_magic_table_fill(char *filename, char **magic_table) {
char *tmp = NULL;
@@ -1052,8 +958,11 @@ void config_magic_table_fill(char *filename, char **magic_table) {
fullname = minimal_name;
}
magic_table['b'] = uwsgi.binary_path;
magic_table['p'] = fullname;
magic_table['s'] = uwsgi_get_last_char(fullname, '/') + 1;
magic_table['d'] = uwsgi_concat2n(magic_table['p'], magic_table['s'] - magic_table['p'], "", 0);
if (magic_table['d'][strlen(magic_table['d']) - 1] == '/') {
tmp = magic_table['d'] + (strlen(magic_table['d']) - 1);
@@ -1062,6 +971,23 @@ void config_magic_table_fill(char *filename, char **magic_table) {
#endif
*tmp = 0;
}
// clear optional vars
magic_table['c'] = "";
magic_table['e'] = "";
magic_table['n'] = magic_table['s'];
magic_table['0'] = "";
magic_table['1'] = "";
magic_table['2'] = "";
magic_table['3'] = "";
magic_table['4'] = "";
magic_table['5'] = "";
magic_table['6'] = "";
magic_table['7'] = "";
magic_table['8'] = "";
magic_table['9'] = "";
if (uwsgi_get_last_char(magic_table['d'], '/')) {
magic_table['c'] = uwsgi_str(uwsgi_get_last_char(magic_table['d'], '/') + 1);
if (magic_table['c'][strlen(magic_table['c']) - 1] == '/') {
@@ -1085,16 +1011,31 @@ void config_magic_table_fill(char *filename, char **magic_table) {
if (tmp)
*tmp = '/';
if (uwsgi_get_last_char(filename, '.'))
magic_table['e'] = uwsgi_get_last_char(filename, '.') + 1;
if (uwsgi_get_last_char(magic_table['s'], '.'))
magic_table['e'] = uwsgi_get_last_char(magic_table['s'], '.') + 1;
if (uwsgi_get_last_char(magic_table['s'], '.'))
magic_table['n'] = uwsgi_concat2n(magic_table['s'], uwsgi_get_last_char(magic_table['s'], '.') - magic_table['s'], "", 0);
reuse:
magic_table['x'] = "";
if (section) {
magic_table['x'] = section+1;
*section = ':';
}
// first round ?
if (!uwsgi.magic_table_first_round) {
magic_table['O'] = magic_table['o'];
magic_table['D'] = magic_table['d'];
magic_table['S'] = magic_table['s'];
magic_table['P'] = magic_table['p'];
magic_table['C'] = magic_table['c'];
magic_table['E'] = magic_table['e'];
magic_table['N'] = magic_table['n'];
magic_table['X'] = magic_table['x'];
uwsgi.magic_table_first_round = 1;
}
}
int find_worker_id(pid_t pid) {
@@ -1474,6 +1415,15 @@ void what_i_am_doing() {
int unconfigured_hook(struct wsgi_request *wsgi_req) {
if (wsgi_req->uh->modifier1 == 0 && !uwsgi.no_default_app) {
if (uwsgi_apps_cnt > 0 && wsgi_req->app_id > -1 && wsgi_req->app_id < uwsgi.max_apps) {
struct uwsgi_app *ua = &uwsgi_apps[wsgi_req->app_id];
if (uwsgi.p[ua->modifier1]->request != unconfigured_hook) {
wsgi_req->uh->modifier1 = ua->modifier1;
return uwsgi.p[ua->modifier1]->request(wsgi_req);
}
}
}
uwsgi_log("-- unavailable modifier requested: %d --\n", wsgi_req->uh->modifier1);
return -1;
}
@@ -1506,7 +1456,7 @@ void uwsgi_exec_atexit(void) {
uwsgi_foreach(usl, uwsgi.call_as_user_atexit) {
if (uwsgi_call_symbol(usl->value)) {
uwsgi_log("unaable to call function \"%s\"\n", usl->value);
uwsgi_log("unable to call function \"%s\"\n", usl->value);
}
}
}
@@ -1919,6 +1869,10 @@ static struct uwsgi_clock uwsgi_unix_clock = {
.microseconds = uwsgi_unix_microseconds,
};
void uwsgi_init_random() {
srand((unsigned int) (uwsgi.start_tv.tv_usec * uwsgi.start_tv.tv_sec));
}
#ifdef UWSGI_AS_SHARED_LIBRARY
int uwsgi_init(int argc, char *argv[], char *envp[]) {
@@ -1959,6 +1913,9 @@ int main(int argc, char *argv[], char *envp[]) {
init_magic_table(uwsgi.magic_table);
// initialize schemes
uwsgi_setup_schemes();
// initialize the clock
uwsgi_register_clock(&uwsgi_unix_clock);
uwsgi_set_clock("unix");
@@ -2009,6 +1966,9 @@ int main(int argc, char *argv[], char *envp[]) {
// get startup time
gettimeofday(&uwsgi.start_tv, NULL);
// initialize random engine
uwsgi_init_random();
setlinebuf(stdout);
uwsgi.rl.rlim_cur = 0;
@@ -2066,6 +2026,9 @@ int main(int argc, char *argv[], char *envp[]) {
uwsgi_register_base_hooks();
uwsgi_log_encoders_register_embedded();
// register base metrics (so plugins can override them)
uwsgi_metrics_collectors_setup();
//initialize embedded plugins
UWSGI_LOAD_EMBEDDED_PLUGINS
// now a bit of magic, if the executable basename contains a 'uwsgi_' string,
@@ -2114,6 +2077,9 @@ int main(int argc, char *argv[], char *envp[]) {
// ok, the options dictionary is available, lets manage it
uwsgi_configure();
// fixup cwd
if (uwsgi.force_cwd) uwsgi.cwd = uwsgi.force_cwd;
// run "asap" hooks
uwsgi_hooks_run(uwsgi.hook_asap, "asap", 1);
struct uwsgi_string_list *usl = NULL;
@@ -2197,7 +2163,6 @@ int main(int argc, char *argv[], char *envp[]) {
uwsgi_register_imperial_monitor("glob", uwsgi_imperial_monitor_glob_init, uwsgi_imperial_monitor_glob);
// setup stats pushers
uwsgi_register_stats_pusher("file", uwsgi_stats_pusher_file);
uwsgi_stats_pusher_setup();
// register embedded alarms
@@ -2386,7 +2351,7 @@ int main(int argc, char *argv[], char *envp[]) {
// TODO pluginize basic Linux namespace support
#ifdef __linux__
#if defined(__linux__) && !defined(__ia64__)
if (uwsgi.ns) {
linux_namespace_start((void *) uwsgi.argv);
// never here
@@ -2394,7 +2359,7 @@ int main(int argc, char *argv[], char *envp[]) {
else {
#endif
uwsgi_start((void *) uwsgi.argv);
#ifdef __linux__
#if defined(__linux__) && !defined(__ia64__)
}
#endif
@@ -2411,9 +2376,11 @@ int uwsgi_start(void *v_argv) {
#ifdef __linux__
uwsgi_set_cgroup();
#if !defined(__ia64__)
if (uwsgi.ns) {
linux_namespace_jail();
}
#endif
#endif
uwsgi_hooks_run(uwsgi.hook_in_jail, "in-jail", 1);
@@ -2577,7 +2544,7 @@ int uwsgi_start(void *v_argv) {
if (uwsgi.async > 1) {
if ((unsigned long) uwsgi.max_fd < (unsigned long) uwsgi.async) {
uwsgi_log("- your current max open files limit is %lu, this is lower than requested async cores !!! -\n", (unsigned long) uwsgi.max_fd);
uwsgi_log_initial("- your current max open files limit is %lu, this is lower than requested async cores !!! -\n", (unsigned long) uwsgi.max_fd);
uwsgi.rl.rlim_cur = uwsgi.async;
uwsgi.rl.rlim_max = uwsgi.async;
if (!setrlimit(RLIMIT_NOFILE, &uwsgi.rl)) {
@@ -2589,7 +2556,7 @@ int uwsgi_start(void *v_argv) {
uwsgi.async = (int) uwsgi.max_fd;
}
}
uwsgi_log("- async cores set to %d - fd table size: %d\n", uwsgi.async, (int) uwsgi.max_fd);
uwsgi_log_initial("- async cores set to %d - fd table size: %d\n", uwsgi.async, (int) uwsgi.max_fd);
// optimization, this array maps file descriptor to requests
uwsgi.async_waiting_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
uwsgi.async_proto_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
@@ -2600,16 +2567,16 @@ int uwsgi_start(void *v_argv) {
#endif
if (uwsgi.vhost) {
uwsgi_log("VirtualHosting mode enabled.\n");
uwsgi_log_initial("VirtualHosting mode enabled.\n");
}
// setup locking
uwsgi_setup_locking();
if (uwsgi.use_thunder_lock) {
uwsgi_log("thunder lock: enabled\n");
uwsgi_log_initial("thunder lock: enabled\n");
}
else {
uwsgi_log("thunder lock: disabled (you can enable it with --thunder-lock)\n");
uwsgi_log_initial("thunder lock: disabled (you can enable it with --thunder-lock)\n");
}
// allocate rpc structures
@@ -2764,7 +2731,8 @@ int uwsgi_start(void *v_argv) {
!uwsgi.emperor &&
!uwsgi.command_mode &&
!uwsgi.daemons_cnt &&
!uwsgi.crons
!uwsgi.crons &&
!uwsgi.emperor_proxy
#ifdef UWSGI_SSL
&& !uwsgi.legions
#endif
@@ -2899,6 +2867,9 @@ unsafe:
// set a default request structure (for loading apps...)
uwsgi.wsgi_req = &uwsgi.workers[0].cores[0].req;
// ok, let's inizialize the metrics subsystem
uwsgi_setup_metrics();
// cores are allocated, lets allocate logformat (if required)
if (uwsgi.logformat) {
uwsgi_build_log_format(uwsgi.logformat);
@@ -3105,6 +3076,7 @@ next2:
}
}
// END OF INITIALIZATION
// !!! from now on, we could be in the master or in a worker !!!
@@ -3443,7 +3415,26 @@ void build_options() {
pos += c;
}
}
// custom_options are not added to uwsgi.options
uco = uwsgi.custom_options;
while (uco) {
uwsgi.options[pos].name = uco->name;
if (uco->has_args) {
uwsgi.options[pos].type = required_argument;
}
else {
uwsgi.options[pos].type = no_argument;
}
// custom options should be immediate
uwsgi.options[pos].flags = UWSGI_OPT_IMMEDIATE;
// help shows the option definition
uwsgi.options[pos].help = uco->value;
uwsgi.options[pos].data = uco;
uwsgi.options[pos].func = uwsgi_opt_custom;
pos++;
uco = uco->next;
}
pos = 0;
@@ -3482,21 +3473,6 @@ void build_options() {
op++;
pos++;
}
uco = uwsgi.custom_options;
while (uco) {
uwsgi.long_options[pos].name = uco->name;
if (uco->has_args) {
uwsgi.long_options[pos].has_arg = required_argument;
}
else {
uwsgi.long_options[pos].has_arg = no_argument;
}
uwsgi.long_options[pos].flag = 0;
// add 1000 to avoid short_options collision
uwsgi.long_options[pos].val = 1000 + pos;
pos++;
uco = uco->next;
}
}
/*
@@ -3559,7 +3535,7 @@ void uwsgi_init_all_apps() {
uwsgi_foreach(usl, uwsgi.call_pre_app) {
if (uwsgi_call_symbol(usl->value)) {
uwsgi_log("unaable to call function \"%s\"\n", usl->value);
uwsgi_log("unable to call function \"%s\"\n", usl->value);
exit(1);
}
}
@@ -3627,7 +3603,7 @@ void uwsgi_init_all_apps() {
uwsgi_foreach(usl, uwsgi.call_post_app) {
if (uwsgi_call_symbol(usl->value)) {
uwsgi_log("unaable to call function \"%s\"\n", usl->value);
uwsgi_log("unable to call function \"%s\"\n", usl->value);
}
}
@@ -3923,6 +3899,13 @@ void uwsgi_opt_add_socket(char *opt, char *value, void *protocol) {
uwsgi_sock->proto_name = protocol;
}
void uwsgi_opt_add_socket_no_defer(char *opt, char *value, void *protocol) {
struct uwsgi_socket *uwsgi_sock = uwsgi_new_socket(generate_socket_name(value));
uwsgi_sock->name_len = strlen(uwsgi_sock->name);
uwsgi_sock->proto_name = protocol;
uwsgi_sock->no_defer = 1;
}
void uwsgi_opt_add_lazy_socket(char *opt, char *value, void *protocol) {
struct uwsgi_socket *uwsgi_sock = uwsgi_new_socket(generate_socket_name(value));
uwsgi_sock->proto_name = protocol;
@@ -3931,7 +3914,7 @@ void uwsgi_opt_add_lazy_socket(char *opt, char *value, void *protocol) {
}
void uwsgi_opt_set_placeholder(char *opt, char *value, void *none) {
void uwsgi_opt_set_placeholder(char *opt, char *value, void *ph) {
char *p = strchr(value, '=');
if (!p) {
@@ -3940,7 +3923,7 @@ void uwsgi_opt_set_placeholder(char *opt, char *value, void *none) {
}
p[0] = 0;
add_exported_option(uwsgi_str(value), p + 1, 1);
add_exported_option_do(uwsgi_str(value), p + 1, 0, ph ? 1 : 0);
p[0] = '=';
}
@@ -3998,6 +3981,14 @@ void uwsgi_opt_set_umask(char *opt, char *value, void *mode) {
}
void uwsgi_opt_exit(char *opt, char *value, void *none) {
int exit_code = 1;
if (value) {
exit_code = atoi(value);
}
exit(exit_code);
}
void uwsgi_opt_print(char *opt, char *value, void *str) {
if (str) {
fprintf(stdout, "%s\n", (char *) str);
@@ -4022,7 +4013,18 @@ void uwsgi_opt_set_gid(char *opt, char *value, void *none) {
#ifdef UWSGI_CAP
void uwsgi_opt_set_cap(char *opt, char *value, void *none) {
uwsgi_build_cap(value);
uwsgi.cap_count = uwsgi_build_cap(value, &uwsgi.cap);
if (uwsgi.cap_count == 0) {
uwsgi_log("[security] empty capabilities mask !!!\n");
exit(1);
}
}
void uwsgi_opt_set_emperor_cap(char *opt, char *value, void *none) {
uwsgi.emperor_cap_count = uwsgi_build_cap(value, &uwsgi.emperor_cap);
if (uwsgi.emperor_cap_count == 0) {
uwsgi_log("[security] empty capabilities mask !!!\n");
exit(1);
}
}
#endif
#ifdef __linux__
@@ -4292,39 +4294,45 @@ void uwsgi_opt_deprecated(char *opt, char *value, void *message) {
void uwsgi_opt_load(char *opt, char *filename, void *none) {
// here we need to avoid setting upper magic vars
int orig_magic = uwsgi.magic_table_first_round;
uwsgi.magic_table_first_round = 1;
if (uwsgi_endswith(filename, ".ini")) {
uwsgi_opt_load_ini(opt, filename, none);
return;
goto end;
}
#ifdef UWSGI_XML
if (uwsgi_endswith(filename, ".xml")) {
uwsgi_opt_load_xml(opt, filename, none);
return;
goto end;
}
#endif
#ifdef UWSGI_YAML
if (uwsgi_endswith(filename, ".yaml")) {
uwsgi_opt_load_yml(opt, filename, none);
return;
goto end;
}
if (uwsgi_endswith(filename, ".yml")) {
uwsgi_opt_load_yml(opt, filename, none);
return;
goto end;
}
#endif
#ifdef UWSGI_JSON
if (uwsgi_endswith(filename, ".json")) {
uwsgi_opt_load_json(opt, filename, none);
return;
goto end;
}
if (uwsgi_endswith(filename, ".js")) {
uwsgi_opt_load_json(opt, filename, none);
return;
goto end;
}
#endif
// fallback to pluggable system
uwsgi_opt_load_config(opt, filename, none);
end:
uwsgi.magic_table_first_round = orig_magic;
}
void uwsgi_opt_logic(char *opt, char *arg, void *func) {
@@ -4573,3 +4581,23 @@ void uwsgi_update_pidfiles() {
uwsgi_write_pidfile(uwsgi.pidfile2);
}
}
void uwsgi_opt_binary_append_data(char *opt, char *value, void *none) {
size_t size;
char *buf = uwsgi_open_and_read(value, &size, 0, NULL);
uint64_t file_len = size;
if (write(1, buf, size) != (ssize_t) size) {
uwsgi_error("uwsgi_opt_binary_append_data()/write()");
exit(1);
}
if (write(1, &file_len, 8) != 8) {
uwsgi_error("uwsgi_opt_binary_append_data()/write()");
exit(1);
}
exit(0);
}
+1 -1
View File
@@ -59,7 +59,7 @@ static int uwsgi_websockets_check_pingpong(struct wsgi_request *wsgi_req) {
}
return 0;
}
// pong received, send anther ping
// pong received, send another ping
if (now - wsgi_req->websocket_last_ping >= uwsgi.websockets_ping_freq) {
return uwsgi_websockets_ping(wsgi_req);
}
+3
View File
@@ -151,6 +151,8 @@ void uwsgi_xml_config(char *filename, struct wsgi_request *wsgi_req, char *magic
}
/* We can safely free resources */
if (colon) colon[0] = ':';
xmlFreeDoc(doc);
xmlCleanupParser();
@@ -267,6 +269,7 @@ void uwsgi_xml_config(char *filename, struct wsgi_request *wsgi_req, char *magic
} while (!done);
if (colon) colon[0] = ':';
// we can safely free, as we have a copy of datas
XML_ParserFree(parser);
+1
View File
@@ -280,6 +280,7 @@ next:
}
#endif
if (colon) colon[0] = ':';
}
+3 -2
View File
@@ -123,12 +123,13 @@ int uwsgi_gzip_fix(z_stream *z, uint32_t crc32, struct uwsgi_buffer *ub, size_t
if (!gzipped0) goto end;
if (uwsgi_buffer_append(ub, gzipped0, dlen0)) goto end;
free(gzipped0);
if (uwsgi_buffer_u32le(ub, crc32)) goto end;
if (uwsgi_buffer_u32le(ub, len)) goto end;
if (uwsgi_buffer_u32le(ub, crc32)) goto end2;
if (uwsgi_buffer_u32le(ub, len)) goto end2;
deflateEnd(z);
return 0;
end:
if (gzipped0) free(gzipped0);
end2:
deflateEnd(z);
return -1;
}
+27 -33
View File
@@ -26,9 +26,6 @@ struct uwsgi_carbon {
unsigned long long *last_busyness_values;
unsigned long long *current_busyness_values;
int *was_busy;
int need_retry;
time_t last_update;
time_t next_retry;
int max_retries;
int retry_delay;
char *root_node;
@@ -40,6 +37,7 @@ struct uwsgi_carbon {
int zero_avg;
uint64_t last_requests;
struct uwsgi_stats_pusher *pusher;
int use_metrics;
} u_carbon;
static struct uwsgi_option carbon_options[] = {
@@ -55,6 +53,7 @@ static struct uwsgi_option carbon_options[] = {
{"carbon-name-resolve", no_argument, 0, "allow using hostname as carbon server address (default disabled)", uwsgi_opt_true, &u_carbon.resolve_hostname, 0},
{"carbon-resolve-names", no_argument, 0, "allow using hostname as carbon server address (default disabled)", uwsgi_opt_true, &u_carbon.resolve_hostname, 0},
{"carbon-idle-avg", required_argument, 0, "average values source during idle period (no requests), can be \"last\", \"zero\", \"none\" (default is last)", uwsgi_opt_set_str, &u_carbon.idle_avg, 0},
{"carbon-use-metrics", no_argument, 0, "don't compute all statistics, use metrics subsystem data instead (warning! key names will be different", uwsgi_opt_true, &u_carbon.use_metrics, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -108,7 +107,7 @@ static void carbon_post_init() {
if (u_carbon.freq < 1) u_carbon.freq = 60;
if (u_carbon.timeout < 1) u_carbon.timeout = 3;
if (u_carbon.max_retries <= 0) u_carbon.max_retries = 1;
if (u_carbon.max_retries < 0) u_carbon.max_retries = 0;
if (u_carbon.retry_delay <= 0) u_carbon.retry_delay = 7;
if (!u_carbon.id) {
u_carbon.id = uwsgi_str(uwsgi.sockets->name);
@@ -153,14 +152,13 @@ static void carbon_post_init() {
u_carbon.was_busy = uwsgi_calloc(sizeof(int) * uwsgi.numproc);
}
// set next update to now()+retry_delay, this way we will have first flush just after start
u_carbon.last_update = uwsgi_now() - u_carbon.freq + u_carbon.retry_delay;
uwsgi_log("[carbon] carbon plugin started, %is frequency, %is timeout, max retries %i, retry delay %is\n",
u_carbon.freq, u_carbon.timeout, u_carbon.max_retries, u_carbon.retry_delay);
struct uwsgi_stats_pusher_instance *uspi = uwsgi_stats_pusher_add(u_carbon.pusher, NULL);
uspi->freq = u_carbon.freq;
uspi->retry_delay = u_carbon.retry_delay;
uspi->max_retries = u_carbon.max_retries;
// no need to generate the json
uspi->raw=1;
}
@@ -185,14 +183,15 @@ static int carbon_write(int fd, char *fmt,...) {
return 1;
}
static void carbon_push_stats(int retry_cycle, time_t now) {
static int carbon_push_stats(int retry_cycle, time_t now) {
struct carbon_server_list *usl = u_carbon.servers_data;
if (!u_carbon.servers_data) return;
if (!u_carbon.servers_data) return 0;
int i;
int fd;
int wok;
char *ip;
char *carbon_address = NULL;
int needs_retry;
for (i = 0; i < uwsgi.numproc; i++) {
u_carbon.current_busyness_values[i] = uwsgi.workers[i+1].running_time - u_carbon.last_busyness_values[i];
@@ -200,7 +199,7 @@ static void carbon_push_stats(int retry_cycle, time_t now) {
u_carbon.was_busy[i-1] += uwsgi_worker_is_busy(i+1);
}
u_carbon.need_retry = 0;
needs_retry = 0;
while(usl) {
if (retry_cycle && usl->healthy)
// skip healthy servers during retry cycle
@@ -228,15 +227,7 @@ static void carbon_push_stats(int retry_cycle, time_t now) {
fd = uwsgi_connect(carbon_address, u_carbon.timeout, 0);
if (fd < 0) {
uwsgi_log("[carbon] Could not connect to carbon server at %s\n", carbon_address);
if (usl->errors < u_carbon.max_retries) {
u_carbon.need_retry = 1;
u_carbon.next_retry = uwsgi_now() + u_carbon.retry_delay;
} else {
uwsgi_log("[carbon] Maximum number of retries for %s (%d)\n",
carbon_address, u_carbon.max_retries);
usl->healthy = 0;
usl->errors = 0;
}
needs_retry = 1;
usl->healthy = 0;
usl->errors++;
free(carbon_address);
@@ -246,6 +237,8 @@ static void carbon_push_stats(int retry_cycle, time_t now) {
// put the socket in non-blocking mode
uwsgi_socket_nb(fd);
if (u_carbon.use_metrics) goto metrics_loop;
unsigned long long total_rss = 0;
unsigned long long total_vsz = 0;
unsigned long long total_tx = 0;
@@ -380,6 +373,18 @@ static void carbon_push_stats(int retry_cycle, time_t now) {
wok = carbon_write(fd, "%s%s.%s.harakiri %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) total_harakiri, (unsigned long long) now);
if (!wok) goto clear;
metrics_loop:
if (u_carbon.use_metrics) {
struct uwsgi_metric *um = uwsgi.metrics;
while(um) {
uwsgi_rlock(uwsgi.metrics_lock);
wok = carbon_write(fd, "%s%s.%s.%.*s %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, um->name_len, um->name, (unsigned long long) *um->value, (unsigned long long) now);
uwsgi_rwunlock(uwsgi.metrics_lock);
if (!wok) goto clear;
um = um->next;
}
}
usl->healthy = 1;
usl->errors = 0;
@@ -390,23 +395,12 @@ clear:
nxt:
usl = usl->next;
}
if (!retry_cycle) u_carbon.last_update = uwsgi_now();
if (u_carbon.need_retry)
// timeouts and retries might cause additional lags in carbon cycles, we will adjust timer to fix that
u_carbon.last_update -= u_carbon.timeout;
return needs_retry;
}
static void carbon_push(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) {
if (u_carbon.need_retry && now >= u_carbon.next_retry) {
carbon_push_stats(1, now);
}
else {
// update
u_carbon.need_retry = 0;
carbon_push_stats(0, now);
}
uspi->needs_retry = carbon_push_stats(uspi->retries, now);
}
static void carbon_cleanup() {
+4 -2
View File
@@ -13,7 +13,7 @@
extern struct uwsgi_server uwsgi;
int cheaper_backlog2_algo(void) {
int cheaper_backlog2_algo(int can_spawn) {
int i;
#ifdef __linux__
@@ -22,7 +22,9 @@ int cheaper_backlog2_algo(void) {
int backlog = 0;
#endif
if (backlog > (int)uwsgi.cheaper_overload) {
// if can_spawn == 0 we cannot spawn any new worker
// this is set to 1 if --cheaper-rss-limit-* options are used and running workers are exceeding resources limit
if (can_spawn && backlog > (int)uwsgi.cheaper_overload) {
// activate the first available worker (taking step into account)
int decheaped = 0;
// search for cheaped workers
+12 -12
View File
@@ -142,7 +142,7 @@ int spawn_emergency_worker(int backlog) {
#endif
int cheaper_busyness_algo(void) {
int cheaper_busyness_algo(int can_spawn) {
int i;
// we use microseconds
@@ -243,11 +243,12 @@ int cheaper_busyness_algo(void) {
uwsgi_cheaper_busyness_global.tolerance_counter = 0;
int decheaped = 0;
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].cheaped == 1 && uwsgi.workers[i].pid == 0) {
decheaped++;
if (decheaped >= uwsgi.cheaper_step) break;
if (can_spawn) {
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].cheaped == 1 && uwsgi.workers[i].pid == 0) {
decheaped++;
if (decheaped >= uwsgi.cheaper_step) break;
}
}
}
@@ -271,15 +272,15 @@ int cheaper_busyness_algo(void) {
uwsgi_log("[busyness] %llus average busyness is at %llu%%, will spawn %d new worker(s)\n",
uwsgi.cheaper_overload, avg_busyness, decheaped);
} else {
uwsgi_log("[busyness] %llus average busyness is at %llu%% but we already started maximum number of workers (%d)\n",
uwsgi.cheaper_overload, avg_busyness, uwsgi.numproc);
uwsgi_log("[busyness] %llus average busyness is at %llu%% but we already started maximum number of workers available with current limits (%d)\n",
uwsgi.cheaper_overload, avg_busyness, active_workers);
}
// return the maximum number of workers to spawn
return decheaped;
#ifdef __linux__
} else if (backlog > uwsgi_cheaper_busyness_global.backlog_alert && active_workers < uwsgi.numproc) {
} else if (can_spawn && backlog > uwsgi_cheaper_busyness_global.backlog_alert && active_workers < uwsgi.numproc) {
return spawn_emergency_worker(backlog);
#endif
@@ -347,14 +348,14 @@ int cheaper_busyness_algo(void) {
}
#ifdef __linux__
else if (backlog > uwsgi_cheaper_busyness_global.backlog_alert && active_workers < uwsgi.numproc) {
else if (can_spawn && backlog > uwsgi_cheaper_busyness_global.backlog_alert && active_workers < uwsgi.numproc) {
// we check for backlog overload every cycle
return spawn_emergency_worker(backlog);
}
else if (backlog > 0) {
if (uwsgi_cheaper_busyness_global.backlog_is_nonzero) {
// backlog was > 0 last time, check timestamp and spawn workers if needed
if ((now - uwsgi_cheaper_busyness_global.backlog_nonzero_since)/1000000 >= uwsgi_cheaper_busyness_global.backlog_nonzero_alert) {
if (can_spawn && (now - uwsgi_cheaper_busyness_global.backlog_nonzero_since)/1000000 >= uwsgi_cheaper_busyness_global.backlog_nonzero_alert) {
uwsgi_log("[busyness] backlog was non-zero for %llu second(s), spawning new worker(s)\n", (now - uwsgi_cheaper_busyness_global.backlog_nonzero_since)/1000000);
uwsgi_cheaper_busyness_global.backlog_nonzero_since = now;
return spawn_emergency_worker(backlog);
@@ -391,4 +392,3 @@ struct uwsgi_plugin cheaper_busyness_plugin = {
.options = uwsgi_cheaper_busyness_options,
};
+1 -1
View File
@@ -166,7 +166,7 @@ static void uwsgi_imperial_monitor_zeromq_cmd(struct uwsgi_emperor_scanner *ues)
}
}
// destroy an instance
else if (!uwsgi_strncmp(ez_cmd, ez_cmd_len, "destroy", 6)) {
else if (!uwsgi_strncmp(ez_cmd, ez_cmd_len, "destroy", 7)) {
struct uwsgi_instance *ui = emperor_get(name);
if (!ui) {
uwsgi_log("[emperor-zeromq] unknown instance \"%s\"\n", name);
+6 -4
View File
@@ -190,21 +190,23 @@ static ssize_t fr_instance_connected(struct corerouter_peer *peer) {
// called after receaving the uwsgi header (read vars)
static ssize_t fr_recv_uwsgi_vars(struct corerouter_peer *main_peer) {
struct uwsgi_header *uh = (struct uwsgi_header *) main_peer->in->buf;
// better to store it as the original buf address could change
uint16_t pktsize = uh->pktsize;
// increase buffer if needed
if (uwsgi_buffer_fix(main_peer->in, uh->pktsize+4))
if (uwsgi_buffer_fix(main_peer->in, pktsize+4))
return -1;
ssize_t len = cr_read_exact(main_peer, uh->pktsize+4, "fr_recv_uwsgi_vars()");
ssize_t len = cr_read_exact(main_peer, pktsize+4, "fr_recv_uwsgi_vars()");
if (!len) return 0;
// headers received, ready to choose the instance
if (main_peer->in->pos == (size_t)(uh->pktsize+4)) {
if (main_peer->in->pos == (size_t)(pktsize+4)) {
struct uwsgi_corerouter *ucr = main_peer->session->corerouter;
struct corerouter_peer *new_peer = uwsgi_cr_peer_add(main_peer->session);
new_peer->last_hook_read = fr_instance_read;
// find the hostname
if (uwsgi_hooked_parse(main_peer->in->buf+4, uh->pktsize, fr_get_hostname, (void *) new_peer)) {
if (uwsgi_hooked_parse(main_peer->in->buf+4, pktsize, fr_get_hostname, (void *) new_peer)) {
return -1;
}
+101 -9
View File
@@ -2,6 +2,13 @@
uWSGI forkpty-router
can use the uwsgi protocol, modifier2 means:
0 -> stdin
1-99 -> UNIX signal
100 -> window rows (pktsize is the window size)
101 -> window cols (pktsize is the window size)
*/
#include <uwsgi.h>
@@ -9,9 +16,9 @@
extern struct uwsgi_server uwsgi;
#ifdef __linux__
#if defined(__linux__) || defined(__GNU_kFreeBSD__)
#include <pty.h>
#elif defined(__APPLE__) || defined(__OpenBSD__)
#elif defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__)
#include <util.h>
#elif defined(__FreeBSD__)
#include <libutil.h>
@@ -24,22 +31,45 @@ extern struct uwsgi_server uwsgi;
static struct uwsgi_forkptyrouter {
struct uwsgi_corerouter cr;
char *cmd;
uint16_t win_rows;
uint16_t win_cols;
} ufpty;
extern struct uwsgi_server uwsgi;
struct forkptyrouter_session {
struct corerouter_session session;
// use the uwsgi protocol ?
int uwsgi;
size_t restore_size;
struct winsize w;
pid_t pid;
};
static void uwsgi_opt_forkpty_urouter(char *opt, char *value, void *cr) {
struct uwsgi_corerouter *ucr = (struct uwsgi_corerouter *) cr;
struct uwsgi_gateway_socket *ugs = uwsgi_new_gateway_socket(value, ucr->name);
ugs->no_defer = 1;
ugs->mode = 1;
ucr->has_sockets++;
}
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},
{"forkptyurouter", required_argument, 0, "run the forkptyrouter on the specified address", uwsgi_opt_forkpty_urouter, &ufpty, 0},
{"forkpty-urouter", required_argument, 0, "run the forkptyrouter on the specified address", uwsgi_opt_forkpty_urouter, &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-rows", required_argument, 0, "set forkptyrouter default pty window rows", uwsgi_opt_set_16bit, &ufpty.win_rows, 0},
{"forkptyrouter-cols", required_argument, 0, "set forkptyrouter default pty window cols", uwsgi_opt_set_16bit, &ufpty.win_cols, 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},
@@ -61,6 +91,7 @@ static struct uwsgi_option forkptyrouter_options[] = {
// write to backend
static ssize_t fpty_instance_write(struct corerouter_peer *peer) {
struct forkptyrouter_session *fpty_session = (struct forkptyrouter_session *) peer->session;
ssize_t len = cr_write(peer, "fpty_instance_write()");
// end on empty write
if (!len) return 0;
@@ -68,7 +99,13 @@ static ssize_t fpty_instance_write(struct corerouter_peer *peer) {
// the chunk has been sent, start (again) reading from client and instances
if (cr_write_complete(peer)) {
// reset the buffer
peer->out->pos = 0;
if (fpty_session->uwsgi) {
if (uwsgi_buffer_decapitate(peer->out, peer->out->pos)) return -1;
peer->out->pos = fpty_session->restore_size;
}
else {
peer->out->pos = 0;
}
cr_reset_hooks(peer);
}
@@ -91,6 +128,42 @@ static ssize_t fpty_write(struct corerouter_peer *main_peer) {
return len;
}
static ssize_t fpty_parse_uwsgi(struct corerouter_peer *peer) {
struct forkptyrouter_session *fpty_session = (struct forkptyrouter_session *) peer->session;
for(;;) {
if (peer->in->pos < 4) return 0;
struct uwsgi_header *uh = (struct uwsgi_header *) peer->in->buf;
uint16_t pktsize = uh->pktsize;
switch(uh->modifier2) {
case 0:
// stdin
if ((size_t) (pktsize+4) > peer->in->pos) return 0;
if (uwsgi_buffer_decapitate(peer->in, 4)) return -1;
return pktsize;
case 100:
if (uwsgi_buffer_decapitate(peer->in, 4)) return -1;
fpty_session->w.ws_row = pktsize;
ioctl(peer->session->peers->fd, TIOCSWINSZ, &fpty_session->w);
// rows
break;
case 101:
if (uwsgi_buffer_decapitate(peer->in, 4)) return -1;
fpty_session->w.ws_col = pktsize;
ioctl(peer->session->peers->fd, TIOCSWINSZ, &fpty_session->w);
// cols
break;
default:
if (uwsgi_buffer_decapitate(peer->in, 4)) return -1;
// send signal
kill(fpty_session->pid, uh->modifier2);
break;
}
}
return 0;
}
// read from backend
static ssize_t fpty_instance_read(struct corerouter_peer *peer) {
ssize_t len = cr_read(peer, "fpty_instance_read()");
@@ -106,10 +179,22 @@ static ssize_t fpty_instance_read(struct corerouter_peer *peer) {
// read from client
static ssize_t fpty_read(struct corerouter_peer *main_peer) {
struct forkptyrouter_session *fpty_session = (struct forkptyrouter_session *) main_peer->session;
ssize_t len = cr_read(main_peer, "fpty_read()");
if (!len) return 0;
main_peer->session->peers->out = main_peer->in;
if (fpty_session->uwsgi) {
ssize_t rlen = fpty_parse_uwsgi(main_peer);
if (rlen < 0) return -1;
if (rlen == 0) return 1;
fpty_session->restore_size = main_peer->in->pos - rlen;
main_peer->session->peers->out = main_peer->in;
main_peer->session->peers->out->pos = rlen;
}
else {
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);
@@ -137,12 +222,19 @@ static int forkptyrouter_alloc_session(struct uwsgi_corerouter *ucr, struct uwsg
cs->close = fpty_session_close;
struct forkptyrouter_session *fpty_session = (struct forkptyrouter_session *) cs;
if (ugs->mode == 1) {
fpty_session->uwsgi = 1;
}
// default terminal size
fpty_session->w.ws_row = ufpty.win_rows ? ufpty.win_rows : 24;
fpty_session->w.ws_col = ufpty.win_cols ? ufpty.win_cols : 80;
// 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);
fpty_session->pid = forkpty(&peer->fd, NULL, NULL, &fpty_session->w);
if (fpty_session->pid < 0) {
uwsgi_error("forkpty()");
return -1;
@@ -156,23 +248,23 @@ static int forkptyrouter_alloc_session(struct uwsgi_corerouter *ucr, struct uwsg
argv[1] = "-c";
argv[2] = ufpty.cmd;
argv[3] = NULL;
execve(argv[0], argv, uwsgi.environ);
execv(argv[0], argv);
}
else {
char *argv[2];
argv[0] = ufpty.cmd;
argv[1] = NULL;
execve(argv[0], argv, uwsgi.environ);
execv(argv[0], argv);
}
}
else {
char *argv[2];
argv[0] = "/bin/sh";
argv[1] = NULL;
execve(argv[0], argv, uwsgi.environ);
execv(argv[0], argv);
}
// never here;
uwsgi_error("forkptyrouter_alloc_session()/execve()");
uwsgi_error("forkptyrouter_alloc_session()/execv()");
exit(1);
}
+3 -1
View File
@@ -291,7 +291,9 @@ request:
}
end:
Py_DECREF(greenlet_switch);
if (greenlet_switch) {
Py_DECREF(greenlet_switch);
}
end2:
Py_DECREF(current_greenlet);
+39 -3
View File
@@ -16,6 +16,22 @@ static struct uwsgi_option greenlet_options[] = {
{ 0, 0, 0, 0, 0, 0, 0 }
};
struct wsgi_request *uwsgi_greenlet_current_wsgi_req(void) {
struct wsgi_request *wsgi_req = NULL;
PyObject *current_greenlet = (PyObject *)PyGreenlet_GetCurrent();
PyObject *py_wsgi_req = PyObject_GetAttrString(current_greenlet, "uwsgi_wsgi_req");
// not in greenlet
if (!py_wsgi_req) {
uwsgi_log("[BUG] current_wsgi_req NOT FOUND !!!\n");
goto end;
}
wsgi_req = (struct wsgi_request*) PyLong_AsLong(py_wsgi_req);
Py_DECREF(py_wsgi_req);
end:
Py_DECREF(current_greenlet);
return wsgi_req;
}
static void gil_greenlet_get() {
pthread_setspecific(up.upt_gil_key, (void *) PyGILState_Ensure());
}
@@ -26,9 +42,11 @@ static void gil_greenlet_release() {
static PyObject *py_uwsgi_greenlet_request(PyObject * self, PyObject *args) {
struct wsgi_request *wsgi_req = uwsgi.wsgi_req;
async_schedule_to_req_green();
Py_DECREF(ugl.gl[uwsgi.wsgi_req->async_id]);
Py_DECREF(ugl.gl[wsgi_req->async_id]);
Py_INCREF(Py_None);
return Py_None;
@@ -46,6 +64,7 @@ static void greenlet_schedule_to_req() {
if (!uwsgi.wsgi_req->suspended) {
ugl.gl[id] = PyGreenlet_New(ugl.callable, NULL);
PyObject_SetAttrString((PyObject *)ugl.gl[id], "uwsgi_wsgi_req", PyLong_FromLong((long) uwsgi.wsgi_req));
uwsgi.wsgi_req->suspended = 1;
}
@@ -54,7 +73,13 @@ static void greenlet_schedule_to_req() {
uwsgi.p[modifier1]->suspend(NULL);
}
PyGreenlet_Switch(ugl.gl[id], NULL, NULL);
PyObject *ret = PyGreenlet_Switch(ugl.gl[id], NULL, NULL);
if (!ret) {
PyErr_Print();
uwsgi_log_verbose("[BUG] unable to switch greenlet !!!\n");
exit(1);
}
Py_DECREF(ret);
if (uwsgi.p[modifier1]->resume) {
uwsgi.p[modifier1]->resume(NULL);
@@ -71,7 +96,13 @@ static void greenlet_schedule_to_main(struct wsgi_request *wsgi_req) {
if (uwsgi.p[wsgi_req->uh->modifier1]->suspend) {
uwsgi.p[wsgi_req->uh->modifier1]->suspend(wsgi_req);
}
PyGreenlet_Switch(ugl.main, NULL, NULL);
PyObject *ret = PyGreenlet_Switch(ugl.main, NULL, NULL);
if (!ret) {
PyErr_Print();
uwsgi_log_verbose("[BUG] unable to switch greenlet !!!\n");
exit(1);
}
Py_DECREF(ret);
if (uwsgi.p[wsgi_req->uh->modifier1]->resume) {
uwsgi.p[wsgi_req->uh->modifier1]->resume(wsgi_req);
}
@@ -93,6 +124,9 @@ static void greenlet_init_apps(void) {
up.gil_release = gil_greenlet_release;
}
// map wsgi_req to greenlet object
uwsgi.current_wsgi_req = uwsgi_greenlet_current_wsgi_req;
// blindy call it as the stackless gil engine is already set
UWSGI_GET_GIL
@@ -101,7 +135,9 @@ static void greenlet_init_apps(void) {
ugl.gl = uwsgi_malloc( sizeof(PyGreenlet *) * uwsgi.async );
ugl.main = PyGreenlet_GetCurrent();
Py_INCREF(ugl.main);
ugl.callable = PyCFunction_New(uwsgi_greenlet_request_method, NULL);
Py_INCREF(ugl.callable);
uwsgi_log("enabled greenlet engine\n");
uwsgi.schedule_to_main = greenlet_schedule_to_main;
+7 -1
View File
@@ -7,12 +7,18 @@ JVM_INCPATH = None
JVM_LIBPATH = None
operating_system = os.uname()[0].lower()
arch = os.uname()[4]
try:
arch = os.environ['JVM_ARCH']
except:
arch = os.uname()[4].lower()
if arch in ('i686', 'x86', 'x86_32'):
arch = 'i386'
elif arch in ('x86_64',):
arch = 'amd64'
elif arch.startswith('arm'):
arch = 'arm'
# try to detect the JVM
if operating_system == 'darwin':
+71
View File
@@ -0,0 +1,71 @@
#include <uwsgi.h>
#include <ffi.h>
ffi_type *uwsgi_libffi_get_type(char *what, size_t *skip) {
if (!uwsgi_startswith(what, "int:", 4)) { *skip = 4; return &ffi_type_sint32;}
if (!uwsgi_startswith(what, "sint:", 5)) { *skip = 5; return &ffi_type_sint32;}
if (!uwsgi_startswith(what, "uint:", 5)) { *skip = 5;return &ffi_type_uint32;}
return &ffi_type_pointer;
}
void *uwsgi_libffi_get_value(char *what, ffi_type *t) {
if (t == &ffi_type_sint32) {
int32_t *num = uwsgi_malloc(sizeof(int32_t));
*num = atoi(what);
return num;
}
return NULL;
}
static int uwsgi_libffi_hook(char *arg) {
size_t argc = 0;
size_t i;
char **argv = uwsgi_split_quoted(arg, strlen(arg), " \t", &argc);
if (!argc) goto end;
void *func = dlsym(RTLD_DEFAULT, argv[0]);
if (!func) goto destroy;
ffi_cif cif;
ffi_type **args_type = (ffi_type **) uwsgi_malloc(sizeof(ffi_type) * (argc-1));
void **values = uwsgi_malloc(sizeof(void*) * (argc-1));
for(i=1;i<argc;i++) {
size_t skip = 0;
args_type[i-1] = uwsgi_libffi_get_type(argv[i], &skip);
void *v = uwsgi_libffi_get_value(argv[i] + skip, args_type[i-1]);
values[i-1] = v ? v : &argv[i];
uwsgi_log("%d = %s %p\n", i, argv[i], values[i-1]);
}
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, argc-1, &ffi_type_sint64, args_type) == FFI_OK) {
int64_t rc = 0;
uwsgi_log("ready to call\n");
ffi_call(&cif, func, &rc, values);
}
uwsgi_log("ready to call2\n");
for(i=0;i<(argc-1);i++) {
char **ptr = (char **) values[i];
if (*ptr != argv[i+1]) {
free(values[i]);
}
}
free(args_type);
free(values);
destroy:
for(i=0;i<argc;i++) {
free(argv[i]);
}
end:
free(argv);
return -1;
}
static void uwsgi_libffi_setup() {
uwsgi_register_hook("ffi", uwsgi_libffi_hook);
}
struct uwsgi_plugin libffi_plugin = {
.name = "libffi",
.on_load = uwsgi_libffi_setup,
};
+5
View File
@@ -0,0 +1,5 @@
NAME='libffi'
CFLAGS=[]
LDFLAGS=[]
LIBS=['-lffi']
GCC_LIST=['libffi']
+1
View File
@@ -84,6 +84,7 @@ struct uwsgi_option uwsgi_mono_options[] = {
{"mono-assembly", required_argument, 0, "load the specified main assembly (default: uwsgi.dll)", uwsgi_opt_set_str, &umono.assembly_name, 0},
{"mono-exec", required_argument, 0, "exec the specified assembly just before app loading", uwsgi_opt_add_string_list, &umono.exec, 0},
{"mono-index", required_argument, 0, "add an asp.net index file", uwsgi_opt_add_string_list, &umono.index, 0},
{0, 0, 0, 0, 0, 0, 0},
};
static MonoString *uwsgi_mono_method_GetFilePath(MonoObject *this) {
+7
View File
@@ -53,6 +53,11 @@ struct uwsgi_perl {
struct uwsgi_string_list *exec;
struct uwsgi_string_list *exec_post_fork;
int auto_reload;
time_t last_auto_reload;
struct uwsgi_string_list *auto_reload_ignore;
HV *auto_reload_hash;
};
void init_perl_embedded_module(void);
@@ -70,3 +75,5 @@ PerlInterpreter *uwsgi_perl_new_interpreter(void);
int uwsgi_perl_mule(char *);
void uwsgi_perl_run_hook(SV *);
void uwsgi_perl_exec(char *);
void uwsgi_perl_check_auto_reload(void);
+6 -27
View File
@@ -260,7 +260,6 @@ static void uwsgi_perl_free_stashes(void) {
int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, PerlInterpreter **interpreters) {
struct stat st;
int i;
SV **callables;
@@ -268,31 +267,14 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
char *app_name = uwsgi_concat2n(app, app_len, "", 0);
// prepare for $0
uperl.embedding[1] = app_name;
int fd = open(app_name, O_RDONLY);
if (fd < 0) {
uwsgi_error_open(app_name);
goto clear2;
}
size_t size;
char *buf = uwsgi_open_and_read(app_name, &size, 1, NULL);
if (fstat(fd, &st)) {
uwsgi_error("fstat()");
close(fd);
goto clear2;
if (uwsgi_file_exists(app_name)) {
// prepare for $0 (if the file is local)
uperl.embedding[1] = app_name;
}
char *buf = uwsgi_calloc(st.st_size+1);
if (read(fd, buf, st.st_size) != st.st_size) {
uwsgi_error("read()");
close(fd);
free(buf);
goto clear2;
}
close(fd);
// the first (default) app, should always be loaded in the main interpreter
if (interpreters == NULL) {
if (uwsgi_apps_cnt) {
@@ -309,10 +291,7 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
}
}
if (!interpreters) {
goto clear2;
}
if (!interpreters) goto clear2;
callables = uwsgi_calloc(sizeof(SV *) * uwsgi.threads);
uperl.tmp_streaming_stash = uwsgi_calloc(sizeof(HV *) * uwsgi.threads);
+58
View File
@@ -23,10 +23,60 @@ struct uwsgi_option uwsgi_perl_options[] = {
{"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},
{"perl-auto-reload", required_argument, 0, "enable perl auto-reloader with the specified frequency", uwsgi_opt_set_int, &uperl.auto_reload, UWSGI_OPT_MASTER},
{"perl-auto-reload-ignore", required_argument, 0, "ignore the specified files when auto-reload is enabled", uwsgi_opt_add_string_list, &uperl.auto_reload_ignore, UWSGI_OPT_MASTER},
{0, 0, 0, 0, 0, 0, 0},
};
int uwsgi_perl_check_mtime(time_t now, HV *list, SV *key) {
// insert item with the current time
if (!hv_exists_ent(list, key, 0)) {
// useless if...
if (hv_store_ent(list, key, newSViv(now), 0)) return 0;
}
else {
// compare mtime
struct stat st;
if (stat(SvPV_nolen(key), &st)) return 0;
HE *mtime = hv_fetch_ent(list, key, 0, 0);
if (!mtime) return 0;
if (st.st_mtime > SvIV(HeVAL(mtime))) {
uwsgi_log_verbose("[perl-auto-reloader] %s has been modified !!!\n", SvPV_nolen(key));
kill(uwsgi.workers[0].pid, SIGHUP);
return 1;
}
}
return 0;
}
void uwsgi_perl_check_auto_reload() {
time_t now = uwsgi_now();
HE *he;
if (!uperl.auto_reload_hash) {
uperl.auto_reload_hash = newHV();
// useless return value
if (!SvREFCNT_inc(uperl.auto_reload_hash)) return;
}
GV *gv_inc = gv_fetchpv("INC", TRUE, SVt_PV);
if (!gv_inc) return;
HV *inc = GvHV(gv_inc);
hv_iterinit(inc);
while((he = hv_iternext(inc))) {
SV *filename = hv_iterval(inc, he);
struct uwsgi_string_list *usl;
int found = 0;
uwsgi_foreach(usl, uperl.auto_reload_ignore) {
if (!strcmp(usl->value, SvPV_nolen(filename))) {
found = 1; break;
}
}
if (found) continue;
if (uwsgi_perl_check_mtime(now, uperl.auto_reload_hash, filename)) return;
}
}
SV *uwsgi_perl_obj_new(char *class, size_t class_len) {
SV *newobj;
@@ -563,6 +613,14 @@ void uwsgi_perl_after_request(struct wsgi_request *wsgi_req) {
// clear the env
SvREFCNT_dec(wsgi_req->async_environ);
// now we can check for changed files
if (uperl.auto_reload) {
time_t now = uwsgi_now();
if (now - uperl.last_auto_reload > uperl.auto_reload) {
uwsgi_perl_check_auto_reload();
}
}
}
int uwsgi_perl_magic(char *mountpoint, char *lazy) {
+11 -1
View File
@@ -76,10 +76,20 @@ int psgi_response(struct wsgi_request *wsgi_req, AV *response) {
if (!headers) { uwsgi_log("invalid PSGI headers\n"); return UWSGI_OK;}
// generate headers
for(i=0; i<=av_len(headers); i++) {
int headers_len = (int) av_len(headers);
for(i=0; i<=headers_len; i++) {
hitem = av_fetch(headers,i,0);
if (!*hitem) {
uwsgi_log("invalid PSGI headers\n"); return UWSGI_OK;
}
chitem = SvPV(*hitem, hlen);
if (i+1 > headers_len) {
uwsgi_log("invalid PSGI headers\n"); return UWSGI_OK;
}
hitem = av_fetch(headers,i+1,0);
if (!*hitem) {
uwsgi_log("invalid PSGI headers\n"); return UWSGI_OK;
}
chitem2 = SvPV(*hitem, hlen2);
if (uwsgi_response_add_header(wsgi_req, chitem, hlen, chitem2, hlen2)) return UWSGI_OK;
i++;
+104
View File
@@ -524,6 +524,103 @@ XS(XS_add_rb_timer) {
XSRETURN(1);
}
XS(XS_metric_inc) {
dXSARGS;
char *metric = NULL;
STRLEN metric_len = 0;
int64_t value = 1;
psgi_check_args(1);
metric = SvPV(ST(0), metric_len);
if (items > 1) {
value = (int64_t) SvIV(ST(1));
}
if (uwsgi_metric_inc(metric, NULL, value)) {
croak("unable to update metric");
XSRETURN_UNDEF;
}
XSRETURN_YES;
}
XS(XS_metric_dec) {
dXSARGS;
char *metric = NULL;
STRLEN metric_len = 0;
int64_t value = 1;
psgi_check_args(1);
metric = SvPV(ST(0), metric_len);
if (items > 1) {
value = (int64_t) SvIV(ST(1));
}
if (uwsgi_metric_dec(metric, NULL, value)) {
croak("unable to update metric");
XSRETURN_UNDEF;
}
XSRETURN_YES;
}
XS(XS_metric_mul) {
dXSARGS;
char *metric = NULL;
STRLEN metric_len = 0;
int64_t value = 1;
psgi_check_args(1);
metric = SvPV(ST(0), metric_len);
if (items > 1) {
value = (int64_t) SvIV(ST(1));
}
if (uwsgi_metric_mul(metric, NULL, value)) {
croak("unable to update metric");
XSRETURN_UNDEF;
}
XSRETURN_YES;
}
XS(XS_metric_div) {
dXSARGS;
char *metric = NULL;
STRLEN metric_len = 0;
int64_t value = 1;
psgi_check_args(1);
metric = SvPV(ST(0), metric_len);
if (items > 1) {
value = (int64_t) SvIV(ST(1));
}
if (uwsgi_metric_div(metric, NULL, value)) {
croak("unable to update metric");
XSRETURN_UNDEF;
}
XSRETURN_YES;
}
XS(XS_metric_set) {
dXSARGS;
char *metric = NULL;
STRLEN metric_len = 0;
int64_t value = 0;
psgi_check_args(2);
metric = SvPV(ST(0), metric_len);
value = (int64_t) SvIV(ST(1));
if (uwsgi_metric_set(metric, NULL, value)) {
croak("unable to update metric");
XSRETURN_UNDEF;
}
XSRETURN_YES;
}
XS(XS_metric_get) {
dXSARGS;
char *metric = NULL;
STRLEN metric_len = 0;
psgi_check_args(1);
metric = SvPV(ST(0), metric_len);
ST(0) = newSViv(uwsgi_metric_get(metric, NULL));
sv_2mortal(ST(0));
XSRETURN(1);
}
void init_perl_embedded_module() {
@@ -561,5 +658,12 @@ void init_perl_embedded_module() {
psgi_xs(add_rb_timer);
psgi_xs(set_user_harakiri);
psgi_xs(metric_inc);
psgi_xs(metric_dec);
psgi_xs(metric_mul);
psgi_xs(metric_div);
psgi_xs(metric_get);
psgi_xs(metric_set);
}
+52 -8
View File
@@ -1,7 +1,7 @@
#include <uwsgi.h>
#ifdef __linux__
#if defined(__linux__) || defined(__GNU_kFreeBSD__)
#include <pty.h>
#elif defined(__APPLE__) || defined(__OpenBSD__)
#elif defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__)
#include <util.h>
#elif defined(__FreeBSD__)
#include <libutil.h>
@@ -21,6 +21,7 @@ struct uwsgi_pty_client {
static struct uwsgi_pty {
char *addr;
char *remote;
char *uremote;
int queue;
int server_fd;
int master_fd;
@@ -76,7 +77,8 @@ 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-connect", required_argument, 0, "connect the current terminal to a pty server", uwsgi_opt_set_str, &upty.remote, UWSGI_OPT_NO_INITIAL},
{"pty-uconnect", required_argument, 0, "connect the current terminal to a pty server (using uwsgi protocol)", uwsgi_opt_set_str, &upty.uremote, UWSGI_OPT_NO_INITIAL},
{"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},
@@ -147,6 +149,7 @@ static void *uwsgi_pty_loop(void *arg) {
if (rlen == 0) exit(1);
if (rlen < 0) {
uwsgi_error("uwsgi_pty_loop()/read()");
continue;
}
if (upty.log && upty.original_log >= 0) {
if (write(upty.original_log, buf, rlen) != rlen) {
@@ -256,17 +259,40 @@ static void uwsgi_pty_init() {
}
static int uwsgi_pty_client() {
if (!upty.remote) return 0;
static void uwsgi_pty_winch() {
// 2 uwsgi packets
char uwsgi_pkt[8];
#ifdef TIOCGWINSZ
struct winsize w;
ioctl(0, TIOCGWINSZ, &w);
uwsgi_pkt[0] = 0;
uwsgi_pkt[1] = (uint8_t) (w.ws_row & 0xff);
uwsgi_pkt[2] = (uint8_t) ((w.ws_row >> 8) & 0xff);
uwsgi_pkt[3] = 100;
uwsgi_pkt[4] = 0;
uwsgi_pkt[5] = (uint8_t) (w.ws_col & 0xff);
uwsgi_pkt[6] = (uint8_t) ((w.ws_col >> 8) & 0xff);
uwsgi_pkt[7] = 101;
#endif
if (write(upty.server_fd, uwsgi_pkt, 8) != 8) {
uwsgi_error("uwsgi_pty_winch()/write()");
exit(1);
}
}
uwsgi_log("[pty] connecting to %s ...\n", upty.remote);
static int uwsgi_pty_client() {
if (!upty.remote && !upty.uremote) return 0;
char *remote = upty.uremote ? upty.uremote : upty.remote;
uwsgi_log("[pty] connecting to %s ...\n", 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);
upty.server_fd = uwsgi_connect(remote, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], 0);
if (upty.server_fd < 0) {
uwsgi_error("uwsgi_pty_client()/connect()");
exit(1);
@@ -277,8 +303,15 @@ static int uwsgi_pty_client() {
uwsgi_log("[pty] connected.\n");
uwsgi_pty_setterm(0);
if (upty.uremote) {
signal(SIGWINCH, uwsgi_pty_winch);
// send current terminal size
uwsgi_pty_winch();
}
upty.queue = event_queue_init();
event_queue_add_fd_read(upty.queue, upty.server_fd);
event_queue_add_fd_read(upty.queue, 0);
@@ -287,10 +320,21 @@ static int uwsgi_pty_client() {
char buf[8192];
int interesting_fd = -1;
int ret = event_queue_wait(upty.queue, -1, &interesting_fd);
if (ret <= 0) break;
if (ret == 0) break;
if (ret < 0) {
if (errno == EINTR) continue;
break;
}
if (interesting_fd == 0) {
ssize_t rlen = read(0, buf, 8192);
if (rlen <= 0) break;
if (upty.uremote) {
struct uwsgi_header uh;
uh.modifier1 = 0;
uh.pktsize = rlen;
uh.modifier2 = 0;
if (write(upty.server_fd, &uh, 4) != 4) break;
}
if (write(upty.server_fd, buf, rlen) != rlen) break;
continue;
}
+1
View File
@@ -313,6 +313,7 @@ static void uwsgi_pypy_onload() {
#ifdef UWSGI_PYPY_HOME
upypy.home = UWSGI_PYPY_HOME;
#endif
uwsgi.has_threads = 1;
}
static int uwsgi_pypy_mule(char *opt) {
+13
View File
@@ -235,6 +235,13 @@ int uwsgi_ready_fd(struct wsgi_request *);
void set_user_harakiri(int);
int uwsgi_metric_set(char *, char *, int64_t);
int uwsgi_metric_inc(char *, char *, int64_t);
int uwsgi_metric_dec(char *, char *, int64_t);
int uwsgi_metric_mul(char *, char *, int64_t);
int uwsgi_metric_div(char *, char *, int64_t);
int64_t uwsgi_metric_get(char *, char *);
%s
''' % ('\n'.join(uwsgi_cdef), hooks)
@@ -534,6 +541,12 @@ uwsgi.call = uwsgi_pypy_call
uwsgi.signal = lambda x: lib.uwsgi_signal_send(lib.uwsgi.signal_socket, x)
uwsgi.metric_get = lambda x: lib.uwsgi_metric_get(x, ffi.NULL)
uwsgi.metric_set = lambda x, y: lib.uwsgi_metric_set(x, ffi.NULL, y)
uwsgi.metric_inc = lambda x, y=1: lib.uwsgi_metric_inc(x, ffi.NULL, y)
uwsgi.metric_dec = lambda x, y=1: lib.uwsgi_metric_dec(x, ffi.NULL, y)
uwsgi.metric_mul = lambda x, y=1: lib.uwsgi_metric_mul(x, ffi.NULL, y)
uwsgi.metric_div = lambda x, y=1: lib.uwsgi_metric_div(x, ffi.NULL, y)
def uwsgi_pypy_uwsgi_cache_get(key, cache=ffi.NULL):
vallen = ffi.new('uint64_t*')
+5
View File
@@ -227,6 +227,10 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
PyObject *callables_dict = get_uwsgi_pydict((char *)arg1);
if (callables_dict) {
wi->callable = PyDict_GetItem(callables_dict, (PyObject *)wi->callable);
if (!wi->callable) {
uwsgi_log("skipping broken app %s\n", wsgi_req->appid);
goto multiapp;
}
}
}
}
@@ -357,6 +361,7 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
uwsgi_apps_cnt++;
multiapp:
if (multiapp > 1) {
for(i=1;i<multiapp;i++) {
PyObject *app_mnt = PyList_GetItem(app_list, i);
+21 -3
View File
@@ -156,8 +156,14 @@ struct uwsgi_option uwsgi_python_options[] = {
{"wsgi-env-behavior", required_argument, 0, "set the strategy for allocating/deallocating the WSGI env", uwsgi_opt_set_str, &up.wsgi_env_behaviour, 0},
{"start_response-nodelay", no_argument, 0, "send WSGI http headers as soon as possible (PEP violation)", uwsgi_opt_true, &up.start_response_nodelay, 0},
{"wsgi-strict", no_argument, 0, "try to be fully PEP compliant disabling optimizations", uwsgi_opt_true, &up.wsgi_strict, 0},
{"wsgi-accept-buffer", no_argument, 0, "accept CPython buffer-compliant objects as WSGI response in addition to string/bytes", uwsgi_opt_true, &up.wsgi_accept_buffer, 0},
{"wsgi-accept-buffers", no_argument, 0, "accept CPython buffer-compliant objects as WSGI response in addition to string/bytes", uwsgi_opt_true, &up.wsgi_accept_buffer, 0},
{"python-version", no_argument, 0, "report python version", uwsgi_opt_pyver, NULL, UWSGI_OPT_IMMEDIATE},
{"python-raw", required_argument, 0, "load a python file for managing raw requests", uwsgi_opt_set_str, &up.raw, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -308,6 +314,10 @@ realstuff:
// this time we use this higher level function
// as this code can be executed in a signal handler
#ifdef __GNU_kFreeBSD__
return;
#endif
if (!Py_IsInitialized()) {
return;
}
@@ -1068,7 +1078,6 @@ void uwsgi_python_init_apps() {
up.loaders[LOADER_CALLABLE] = uwsgi_callable_loader;
up.loaders[LOADER_STRING_CALLABLE] = uwsgi_string_callable_loader;
struct uwsgi_string_list *upli = up.import_list;
while(upli) {
if (strchr(upli->value, '/') || uwsgi_endswith(upli->value, ".py")) {
@@ -1119,6 +1128,12 @@ next:
uppa = uppa->next;
}
if (up.raw) {
up.raw_callable = uwsgi_file_loader(up.raw);
if (up.raw_callable) {
Py_INCREF(up.raw_callable);
}
}
if (up.wsgi_config != NULL) {
init_uwsgi_app(LOADER_UWSGI, up.wsgi_config, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI);
@@ -1354,8 +1369,10 @@ void *uwsgi_python_autoreloader_thread(void *foobar) {
UWSGI_RELEASE_GIL;
sleep(up.auto_reload);
UWSGI_GET_GIL;
// do not start monitoring til the first app is loaded (required for lazy mode)
if (uwsgi_apps_cnt == 0) continue;
if (uwsgi.lazy || uwsgi.lazy_apps) {
// do not start monitoring til the first app is loaded (required for lazy mode)
if (uwsgi_apps_cnt == 0) continue;
}
#ifdef UWSGI_PYTHON_OLD
int pos = 0;
#else
@@ -1363,6 +1380,7 @@ void *uwsgi_python_autoreloader_thread(void *foobar) {
#endif
PyObject *mod_name, *mod;
while (PyDict_Next(modules, &pos, &mod_name, &mod)) {
if (mod == NULL) continue;
int found = 0;
struct uwsgi_string_list *usl = up.auto_reload_ignore;
while(usl) {
+90
View File
@@ -0,0 +1,90 @@
#include "uwsgi_python.h"
extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
static int manage_raw_response(struct wsgi_request *wsgi_req) {
int ret = 0;
if (!wsgi_req->async_force_again) {
ret = uwsgi_python_send_body(wsgi_req, (PyObject *) wsgi_req->async_result);
if (ret == 0) {
if (PyInt_Check((PyObject *) wsgi_req->async_result) || PyObject_HasAttrString((PyObject *) wsgi_req->async_result, "fileno")) {
// is it a file ?
int fd = PyObject_AsFileDescriptor((PyObject *) wsgi_req->async_result);
if (fd >= 0) {
wsgi_req->sendfile_fd = fd;
uwsgi_response_sendfile_do(wsgi_req, fd, 0, 0);
wsgi_req->sendfile_fd = -1;
return UWSGI_OK;
}
}
}
}
if (ret == 0) {
if (!wsgi_req->async_placeholder) {
wsgi_req->async_placeholder = PyObject_GetIter((PyObject *) wsgi_req->async_result);
if (!wsgi_req->async_placeholder)
return UWSGI_OK;
}
PyObject *pychunk = PyIter_Next((PyObject *) wsgi_req->async_placeholder);
if (!pychunk)
return UWSGI_OK;
ret = uwsgi_python_send_body(wsgi_req, pychunk);
if (ret == 0) {
if (PyInt_Check(pychunk) || PyObject_HasAttrString(pychunk, "fileno")) {
// is it a file ?
int fd = PyObject_AsFileDescriptor(pychunk);
if (fd >= 0) {
wsgi_req->sendfile_fd = fd;
uwsgi_response_sendfile_do(wsgi_req, fd, 0, 0);
wsgi_req->sendfile_fd = -1;
}
}
}
Py_DECREF(pychunk);
return UWSGI_AGAIN;
}
return UWSGI_OK;
}
int uwsgi_request_python_raw(struct wsgi_request *wsgi_req) {
if (!up.raw_callable)
return UWSGI_OK;
// back from async
if (wsgi_req->async_force_again) {
UWSGI_GET_GIL int ret = manage_raw_response(wsgi_req);
if (ret == UWSGI_AGAIN) {
wsgi_req->async_force_again = 1;
UWSGI_RELEASE_GIL return UWSGI_AGAIN;
}
goto end;
}
UWSGI_GET_GIL PyObject * args = PyTuple_New(1);
PyTuple_SetItem(args, 0, PyInt_FromLong(wsgi_req->fd));
wsgi_req->async_result = PyEval_CallObject(up.raw_callable, args);
Py_DECREF(args);
if (wsgi_req->async_result) {
for (;;) {
int ret = manage_raw_response(wsgi_req);
if (ret == UWSGI_AGAIN) {
wsgi_req->async_force_again = 1;
if (uwsgi.async > 1) {
UWSGI_RELEASE_GIL return UWSGI_AGAIN;
}
continue;
}
break;
}
}
end:
if (PyErr_Occurred())
PyErr_Print();
if (wsgi_req->async_result) {
Py_DECREF((PyObject *) wsgi_req->async_result);
}
UWSGI_RELEASE_GIL;
return UWSGI_OK;
}
+111
View File
@@ -3169,6 +3169,111 @@ static PyMethodDef uwsgi_queue_methods[] = {
{NULL, NULL},
};
PyObject *py_uwsgi_metric_inc(PyObject * self, PyObject * args) {
char *key;
int64_t value = 1;
if (!PyArg_ParseTuple(args, "s|l:metric_inc", &key, &value)) return NULL;
UWSGI_RELEASE_GIL
if (uwsgi_metric_inc(key, NULL, value)) {
UWSGI_GET_GIL
Py_INCREF(Py_None);
return Py_None;
}
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
}
PyObject *py_uwsgi_metric_dec(PyObject * self, PyObject * args) {
char *key;
int64_t value = 1;
if (!PyArg_ParseTuple(args, "s|l:metric_dec", &key, &value)) return NULL;
UWSGI_RELEASE_GIL
if (uwsgi_metric_dec(key, NULL, value)) {
UWSGI_GET_GIL
Py_INCREF(Py_None);
return Py_None;
}
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
}
PyObject *py_uwsgi_metric_mul(PyObject * self, PyObject * args) {
char *key;
int64_t value = 1;
if (!PyArg_ParseTuple(args, "s|l:metric_mul", &key, &value)) return NULL;
UWSGI_RELEASE_GIL
if (uwsgi_metric_mul(key, NULL, value)) {
UWSGI_GET_GIL
Py_INCREF(Py_None);
return Py_None;
}
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
}
PyObject *py_uwsgi_metric_div(PyObject * self, PyObject * args) {
char *key;
int64_t value = 1;
if (!PyArg_ParseTuple(args, "s|l:metric_div", &key, &value)) return NULL;
UWSGI_RELEASE_GIL
if (uwsgi_metric_div(key, NULL, value)) {
UWSGI_GET_GIL
Py_INCREF(Py_None);
return Py_None;
}
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
}
PyObject *py_uwsgi_metric_set(PyObject * self, PyObject * args) {
char *key;
int64_t value = 1;
if (!PyArg_ParseTuple(args, "s|l:metric_set", &key, &value)) return NULL;
UWSGI_RELEASE_GIL
if (uwsgi_metric_set(key, NULL, value)) {
UWSGI_GET_GIL
Py_INCREF(Py_None);
return Py_None;
}
UWSGI_GET_GIL
Py_INCREF(Py_True);
return Py_True;
}
PyObject *py_uwsgi_metric_get(PyObject * self, PyObject * args) {
char *key;
if (!PyArg_ParseTuple(args, "s:metric_get", &key)) return NULL;
UWSGI_RELEASE_GIL
int64_t value = uwsgi_metric_get(key, NULL);
UWSGI_GET_GIL
return PyLong_FromLongLong(value);
}
static PyMethodDef uwsgi_metrics_methods[] = {
{"metric_inc", py_uwsgi_metric_inc, METH_VARARGS, ""},
{"metric_dec", py_uwsgi_metric_dec, METH_VARARGS, ""},
{"metric_mul", py_uwsgi_metric_mul, METH_VARARGS, ""},
{"metric_div", py_uwsgi_metric_div, METH_VARARGS, ""},
{"metric_get", py_uwsgi_metric_get, METH_VARARGS, ""},
{"metric_set", py_uwsgi_metric_set, METH_VARARGS, ""},
{NULL, NULL},
};
void init_uwsgi_module_spooler(PyObject * current_uwsgi_module) {
@@ -3204,6 +3309,12 @@ void init_uwsgi_module_advanced(PyObject * current_uwsgi_module) {
Py_DECREF(func);
}
for (uwsgi_function = uwsgi_metrics_methods; uwsgi_function->ml_name != NULL; uwsgi_function++) {
PyObject *func = PyCFunction_New(uwsgi_function, NULL);
PyDict_SetItemString(uwsgi_module_dict, uwsgi_function->ml_name, func);
Py_DECREF(func);
}
}
void init_uwsgi_module_cache(PyObject * current_uwsgi_module) {
+10 -1
View File
@@ -1,4 +1,4 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
#include <Python.h>
#include <frameobject.h>
@@ -180,6 +180,11 @@ struct uwsgi_python {
int start_response_nodelay;
char *programname;
int wsgi_strict;
int wsgi_accept_buffer;
char *raw;
PyObject *raw_callable;
};
@@ -276,6 +281,10 @@ struct uwsgi_buffer *uwsgi_python_exception_repr(struct wsgi_request *);
struct uwsgi_buffer *uwsgi_python_backtrace(struct wsgi_request *);
void uwsgi_python_exception_log(struct wsgi_request *);
int uwsgi_python_send_body(struct wsgi_request *, PyObject *);
int uwsgi_request_python_raw(struct wsgi_request *);
#define py_current_wsgi_req() current_wsgi_req();\
if (!wsgi_req) {\
return PyErr_Format(PyExc_SystemError, "you can call uwsgi api function only from the main callable");\
+11 -3
View File
@@ -11,7 +11,7 @@ def get_python_version():
return version
NAME='python'
GCC_LIST = ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'web3_subhandler', 'pump_subhandler', 'gil', 'uwsgi_pymodule', 'profiler', 'symimporter', 'tracebacker']
GCC_LIST = ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'web3_subhandler', 'pump_subhandler', 'gil', 'uwsgi_pymodule', 'profiler', 'symimporter', 'tracebacker', 'raw']
CFLAGS = ['-I' + sysconfig.get_python_inc(), '-I' + sysconfig.get_python_inc(plat_specific=True) ]
LDFLAGS = []
@@ -32,9 +32,17 @@ if not 'UWSGI_PYTHON_NOLIB' in os.environ:
# try 3.x style config dir
if not os.path.exists(libdir):
libdir = '%s/lib/python%s/config-%s' % (sys.prefix, version, get_python_version())
libpath = '%s/%s' % (libdir, sysconfig.get_config_var('LDLIBRARY'))
if not os.path.exists(libpath):
# get cpu type
uname = os.uname()
if uname[4].startswith('arm'):
libpath = '%s/%s' % (libdir, sysconfig.get_config_var('LIBRARY'))
if not os.path.exists(libpath):
libpath = '%s/%s' % (libdir, sysconfig.get_config_var('LDLIBRARY'))
else:
libpath = '%s/%s' % (libdir, sysconfig.get_config_var('LDLIBRARY'))
if not os.path.exists(libpath):
libpath = '%s/%s' % (libdir, sysconfig.get_config_var('LIBRARY'))
if not os.path.exists(libpath):
libpath = '%s/libpython%s.a' % (libdir, version)
LIBS.append(libpath)
+2
View File
@@ -292,6 +292,8 @@ PyObject *py_eventfd_write(PyObject * self, PyObject * args) {
int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
if (wsgi_req->is_raw) return uwsgi_request_python_raw(wsgi_req);
struct uwsgi_app *wi;
if (wsgi_req->async_force_again) {
+78 -20
View File
@@ -5,6 +5,78 @@ extern struct uwsgi_python up;
extern struct uwsgi_plugin python_plugin;
extern PyTypeObject uwsgi_InputType;
/*
Albeit PEP 333/3333 is clear about what kind of return object we must
expect from a WSGI callable, we CAN use the buffer api to optimize for lower-level
returns type: bytes, bytearray, array.array
to enable this optimization add --wsgi-accept-buffer
NOTE: this is a violation of the standards !!! use only if you know the implications !!!
*/
int uwsgi_python_send_body(struct wsgi_request *wsgi_req, PyObject *chunk) {
char *content = NULL;
size_t content_len = 0;
if (!up.wsgi_accept_buffer && !wsgi_req->is_raw) goto strict;
#if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER)
Py_buffer pbuf;
int has_buffer = 0;
#endif
#if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER)
if (PyObject_CheckBuffer(chunk)) {
if (!PyObject_GetBuffer(chunk, &pbuf, PyBUF_SIMPLE)) {
content = (char *) pbuf.buf;
content_len = (size_t) pbuf.len;
has_buffer = 1;
goto found;
}
}
#else
if (PyObject_CheckReadBuffer(chunk)) {
#ifdef UWSGI_PYTHON_OLD
int buffer_len = 0;
if (!PyObject_AsCharBuffer(chunk, (const char **) &content, &buffer_len)) {
#else
if (!PyObject_AsCharBuffer(chunk, (const char **) &content, (Py_ssize_t *) &content_len)) {
#endif
PyErr_Clear();
goto found;
}
#ifdef UWSGI_PYTHON_OLD
content_len = buffer_len;
#endif
}
#endif
strict:
// fallback
if (PyString_Check(chunk)) {
content = PyString_AsString(chunk);
content_len = PyString_Size(chunk);
}
found:
if (content) {
UWSGI_RELEASE_GIL
uwsgi_response_write_body_do(wsgi_req, content, content_len);
UWSGI_GET_GIL
#if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER)
if (has_buffer) PyBuffer_Release(&pbuf);
#endif
uwsgi_py_check_write_errors {
uwsgi_py_write_exception(wsgi_req);
return -1;
}
return 1;
}
return 0;
}
/*
this is a hack for supporting non-file object passed to wsgi.file_wrapper
*/
@@ -169,19 +241,11 @@ int uwsgi_response_subhandler_wsgi(struct wsgi_request *wsgi_req) {
PyObject *pychunk;
// return or yield ?
if (PyString_Check((PyObject *)wsgi_req->async_result)) {
char *content = PyString_AsString((PyObject *)wsgi_req->async_result);
size_t content_len = PyString_Size((PyObject *)wsgi_req->async_result);
UWSGI_RELEASE_GIL
uwsgi_response_write_body_do(wsgi_req, content, content_len);
UWSGI_GET_GIL
uwsgi_py_check_write_errors {
uwsgi_py_write_exception(wsgi_req);
}
goto clear;
// in strict mode we do not optimize apps directly returning strings (or bytes)
if (!up.wsgi_strict) {
if (uwsgi_python_send_body(wsgi_req, (PyObject *)wsgi_req->async_result)) goto clear;
}
if (wsgi_req->sendfile_obj == wsgi_req->async_result) {
if (wsgi_req->sendfile_fd >= 0) {
UWSGI_RELEASE_GIL
@@ -222,19 +286,13 @@ exception:
if (PyString_Check(pychunk)) {
char *content = PyString_AsString(pychunk);
size_t content_len = PyString_Size(pychunk);
UWSGI_RELEASE_GIL
uwsgi_response_write_body_do(wsgi_req, content, content_len);
UWSGI_GET_GIL
uwsgi_py_check_write_errors {
uwsgi_py_write_exception(wsgi_req);
int ret = uwsgi_python_send_body(wsgi_req, pychunk);
if (ret != 0) {
if (ret < 0) {
Py_DECREF(pychunk);
goto clear;
}
}
else if (wsgi_req->sendfile_obj == pychunk) {
if (wsgi_req->sendfile_fd >= 0) {
UWSGI_RELEASE_GIL
+89
View File
@@ -7,6 +7,88 @@ extern struct uwsgi_plugin rack_plugin;
#define uwsgi_rack_api(x, y, z) rb_define_module_function(rb_uwsgi_embedded, x, y, z)
static VALUE rack_uwsgi_metric_get(VALUE *class, VALUE key) {
Check_Type(key, T_STRING);
int64_t value = uwsgi_metric_get(RSTRING_PTR(key), NULL);
return LONG2NUM(value);
}
static VALUE rack_uwsgi_metric_set(VALUE *class, VALUE key, VALUE val) {
Check_Type(key, T_STRING);
Check_Type(val, T_FIXNUM); // should be T_BIGNUM...
if (uwsgi_metric_set(RSTRING_PTR(key), NULL, NUM2LONG(val) )) {
return Qnil;
}
return Qtrue;
}
static VALUE rack_uwsgi_metric_inc(int argc, VALUE *argv, VALUE *class) {
int64_t value = 1;
if (argc == 0) return Qnil;
Check_Type(argv[0], T_STRING);
if (argc > 1) {
Check_Type(argv[1], T_FIXNUM); // should be T_BIGNUM...
value = NUM2LONG(argv[1]);
}
if (uwsgi_metric_inc(RSTRING_PTR(argv[0]), NULL, value )) {
return Qnil;
}
return Qtrue;
}
static VALUE rack_uwsgi_metric_dec(int argc, VALUE *argv, VALUE *class) {
int64_t value = 1;
if (argc == 0) return Qnil;
Check_Type(argv[0], T_STRING);
if (argc > 1) {
Check_Type(argv[1], T_FIXNUM); // should be T_BIGNUM...
value = NUM2LONG(argv[1]);
}
if (uwsgi_metric_dec(RSTRING_PTR(argv[0]), NULL, value )) {
return Qnil;
}
return Qtrue;
}
static VALUE rack_uwsgi_metric_mul(int argc, VALUE *argv, VALUE *class) {
int64_t value = 1;
if (argc == 0) return Qnil;
Check_Type(argv[0], T_STRING);
if (argc > 1) {
Check_Type(argv[1], T_FIXNUM); // should be T_BIGNUM...
value = NUM2LONG(argv[1]);
}
if (uwsgi_metric_mul(RSTRING_PTR(argv[0]), NULL, value )) {
return Qnil;
}
return Qtrue;
}
static VALUE rack_uwsgi_metric_div(int argc, VALUE *argv, VALUE *class) {
int64_t value = 1;
if (argc == 0) return Qnil;
Check_Type(argv[0], T_STRING);
if (argc > 1) {
Check_Type(argv[1], T_FIXNUM); // should be T_BIGNUM...
value = NUM2LONG(argv[1]);
}
if (uwsgi_metric_div(RSTRING_PTR(argv[0]), NULL, value )) {
return Qnil;
}
return Qtrue;
}
static VALUE rack_uwsgi_warning(VALUE *class, VALUE rbmessage) {
Check_Type(rbmessage, T_STRING);
@@ -1099,6 +1181,13 @@ void uwsgi_rack_init_api() {
uwsgi_rack_api("cache_clear", rack_uwsgi_cache_clear, -1);
uwsgi_rack_api("cache_clear!", rack_uwsgi_cache_clear_exc, -1);
uwsgi_rack_api("metric_get", rack_uwsgi_metric_get, 1);
uwsgi_rack_api("metric_set", rack_uwsgi_metric_set, 2);
uwsgi_rack_api("metric_inc", rack_uwsgi_metric_inc, -1);
uwsgi_rack_api("metric_dec", rack_uwsgi_metric_dec, -1);
uwsgi_rack_api("metric_mul", rack_uwsgi_metric_mul, -1);
uwsgi_rack_api("metric_div", rack_uwsgi_metric_div, -1);
VALUE uwsgi_rb_opt_hash = rb_hash_new();
int i;
for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
+12 -12
View File
@@ -416,6 +416,18 @@ void uwsgi_ruby_gem_set_apply(char *gemset) {
void uwsgi_ruby_gemset(char *gemset) {
struct uwsgi_string_list *rvm_paths = ur.rvm_path;
while(rvm_paths) {
char *filename = uwsgi_concat3(rvm_paths->value, "/environments/", gemset);
if (uwsgi_file_exists(filename)) {
uwsgi_ruby_gem_set_apply(filename);
free(filename);
return;
}
free(filename);
rvm_paths = rvm_paths->next;
}
char *home = getenv("HOME");
if (home) {
@@ -436,18 +448,6 @@ void uwsgi_ruby_gemset(char *gemset) {
}
free(filename);
struct uwsgi_string_list *rvm_paths = ur.rvm_path;
while(rvm_paths) {
char *filename = uwsgi_concat3(rvm_paths->value, "/environments/", gemset);
if (uwsgi_file_exists(filename)) {
uwsgi_ruby_gem_set_apply(filename);
free(filename);
return;
}
free(filename);
rvm_paths = rvm_paths->next;
}
uwsgi_log("ERROR: unable to load gemset %s !!!\n", gemset);
exit(1);
+8 -1
View File
@@ -57,6 +57,8 @@ struct uwsgi_router_cache_conf {
char *status_str;
int status;
char *no_offload;
char *no_cl;
};
// this is allocated for each transformation
@@ -189,7 +191,9 @@ static int uwsgi_routing_func_cache(struct wsgi_request *wsgi_req, struct uwsgi_
if (expires) {
if (uwsgi_response_add_expires(wsgi_req, expires)) goto error;
}
if (uwsgi_response_add_content_length(wsgi_req, valsize)) goto error;
if (!urcc->no_cl) {
if (uwsgi_response_add_content_length(wsgi_req, valsize)) goto error;
}
if (wsgi_req->socket->can_offload && !ur->custom && !urcc->no_offload) {
if (!uwsgi_offload_request_memory_do(wsgi_req, value, valsize)) {
wsgi_req->via = UWSGI_VIA_OFFLOAD;
@@ -378,6 +382,9 @@ static int uwsgi_router_cache(struct uwsgi_route *ur, char *args) {
"mime", &urcc->mime,
"name", &urcc->name,
"no_offload", &urcc->no_offload,
"no_content_length", &urcc->no_cl,
"no_cl", &urcc->no_cl,
"nocl", &urcc->no_cl,
NULL)) {
uwsgi_log("invalid route syntax: %s\n", args);
exit(1);
+1 -1
View File
@@ -81,7 +81,7 @@ static int uwsgi_routing_func_hash(struct wsgi_request *wsgi_req, struct uwsgi_r
vallen = urhc->items_len;
}
// last item
else {
else if (value != NULL) {
vallen = (urhc->items + urhc->items_len) - value;
}
}
+135
View File
@@ -0,0 +1,135 @@
#include <uwsgi.h>
#ifdef UWSGI_ROUTING
struct uwsgi_router_metric_conf {
// the name of the metric
char *name;
size_t name_len;
// the value for the metric
char *value;
size_t value_len;
int (*func)(char *, char *, int64_t);
};
// metricinc/metricdec/metricmul/metricdiv/metricset
static int uwsgi_routing_func_metricmath(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_router_metric_conf *urmc = (struct uwsgi_router_metric_conf *) ur->data2;
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, urmc->name, urmc->name_len);
if (!ub) return UWSGI_ROUTE_BREAK;
struct uwsgi_buffer *ub_val = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urmc->value, urmc->value_len);
if (!ub_val) {
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_BREAK;
}
int64_t num = strtol(ub_val->buf, NULL, 10);
uwsgi_buffer_destroy(ub_val);
if (urmc->func(ub->buf, NULL, num)) {
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_BREAK;
}
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_NEXT;
}
static struct uwsgi_router_metric_conf *uwsgi_router_metricmath(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_metricmath;
ur->data = args;
ur->data_len = strlen(args);
struct uwsgi_router_metric_conf *urmc = uwsgi_calloc(sizeof(struct uwsgi_router_metric_conf));
char *comma = strchr(args, ',');
if (comma) {
urmc->value = comma+1;
urmc->value_len = strlen(urmc->value);
*comma = 0;
}
else {
urmc->value = "1";
urmc->value_len = 1;
}
urmc->name = args;
urmc->name_len = strlen(args);
if (comma) *comma = ',';
ur->data2 = urmc;
return urmc;
}
static int uwsgi_router_metricinc(struct uwsgi_route *ur, char *args) {
struct uwsgi_router_metric_conf *urmc = uwsgi_router_metricmath(ur, args);
if (!urmc) return -1;
urmc->func = uwsgi_metric_inc;
return 0;
}
static int uwsgi_router_metricdec(struct uwsgi_route *ur, char *args) {
struct uwsgi_router_metric_conf *urmc = uwsgi_router_metricmath(ur, args);
if (!urmc) return -1;
urmc->func = uwsgi_metric_dec;
return 0;
}
static int uwsgi_router_metricmul(struct uwsgi_route *ur, char *args) {
struct uwsgi_router_metric_conf *urmc = uwsgi_router_metricmath(ur, args);
if (!urmc) return -1;
urmc->func = uwsgi_metric_mul;
return 0;
}
static int uwsgi_router_metricdiv(struct uwsgi_route *ur, char *args) {
struct uwsgi_router_metric_conf *urmc = uwsgi_router_metricmath(ur, args);
if (!urmc) return -1;
urmc->func = uwsgi_metric_div;
return 0;
}
static int uwsgi_router_metricset(struct uwsgi_route *ur, char *args) {
struct uwsgi_router_metric_conf *urmc = uwsgi_router_metricmath(ur, args);
if (!urmc) return -1;
urmc->func = uwsgi_metric_set;
return 0;
}
static char *uwsgi_route_var_metric(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
int64_t metric = uwsgi_metric_getn(key, keylen, NULL, 0);
char *ret = uwsgi_64bit2str(metric);
*vallen = strlen(ret);
return ret;
}
static void router_metrics_register() {
uwsgi_register_router("metricinc", uwsgi_router_metricinc);
uwsgi_register_router("metricdec", uwsgi_router_metricdec);
uwsgi_register_router("metricmul", uwsgi_router_metricmul);
uwsgi_register_router("metricdiv", uwsgi_router_metricdiv);
uwsgi_register_router("metricset", uwsgi_router_metricset);
struct uwsgi_route_var *urv = uwsgi_register_route_var("metric", uwsgi_route_var_metric);
urv->need_free = 1;
}
struct uwsgi_plugin router_metrics_plugin = {
.name = "router_metrics",
.on_load = router_metrics_register,
};
#else
struct uwsgi_plugin router_metrics_plugin = {
.name = "router_metrics",
};
#endif
+6
View File
@@ -0,0 +1,6 @@
NAME='router_metrics'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['plugin']
+8 -1
View File
@@ -16,6 +16,8 @@ struct uwsgi_router_file_conf {
size_t content_type_len;
char *mime;
char *no_cl;
};
int uwsgi_routing_func_static(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
@@ -64,7 +66,9 @@ int uwsgi_routing_func_file(struct wsgi_request *wsgi_req, struct uwsgi_route *u
goto end2;
}
uwsgi_buffer_destroy(ub_s);
if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end2;
if (!urfc->no_cl) {
if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end2;
}
if (urfc->mime) {
size_t mime_type_len = 0;
char *mime_type = uwsgi_get_mime_type(ub->buf, ub->pos, &mime_type_len);
@@ -248,6 +252,9 @@ static int uwsgi_router_file(struct uwsgi_route *ur, char *args) {
"filename", &urfc->filename,
"status", &urfc->status,
"content_type", &urfc->content_type,
"nocl", &urfc->no_cl,
"no_cl", &urfc->no_cl,
"no_content_length", &urfc->no_cl,
"mime", &urfc->mime,
NULL)) {
uwsgi_log("invalid file route syntax: %s\n", args);
+118 -107
View File
@@ -1,30 +1,38 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
struct uwsgi_rrdtool {
static struct uwsgi_rrdtool {
void *lib;
char *lib_name;
int (*create)(int, char **);
int (*update)(int, char **);
struct uwsgi_string_list *rrd;
int max_ds;
int freq;
char *update_area;
struct uwsgi_string_list *directory;
struct uwsgi_stats_pusher *pusher;
} u_rrd;
struct uwsgi_option rrdtool_options[] = {
{"rrdtool", required_argument, 0, "collect requests data in the specified rrd file", uwsgi_opt_add_string_list, &u_rrd.rrd, UWSGI_OPT_MASTER},
static struct uwsgi_option rrdtool_options[] = {
{"rrdtool", required_argument, 0, "store rrd files in the specified directory", uwsgi_opt_add_string_list, &u_rrd.directory, UWSGI_OPT_MASTER|UWSGI_OPT_METRICS},
{"rrdtool-freq", required_argument, 0, "set collect frequency", uwsgi_opt_set_int, &u_rrd.freq, 0},
{"rrdtool-max-ds", required_argument, 0, "set maximum number of data sources", uwsgi_opt_set_int, &u_rrd.max_ds, 0},
{"rrdtool-lib", required_argument, 0, "set the name of rrd library (default: librrd.so)", uwsgi_opt_set_str, &u_rrd.lib_name, 0},
{0, 0, 0, 0, 0, 0, 0},
};
int rrdtool_init() {
static int rrdtool_init() {
u_rrd.lib = dlopen("librrd.so", RTLD_LAZY);
if (!u_rrd.lib_name) {
u_rrd.lib_name = "librrd.so";
}
u_rrd.lib = dlopen(u_rrd.lib_name, RTLD_LAZY);
if (!u_rrd.lib) return -1;
u_rrd.create = dlsym(u_rrd.lib, "rrd_create");
@@ -39,137 +47,140 @@ int rrdtool_init() {
return -1;
}
if (!u_rrd.max_ds) u_rrd.max_ds = 30;
uwsgi_log_initial("*** RRDtool library available at %p ***\n", u_rrd.lib);
return 0;
}
void rrdtool_post_init() {
/*
struct uwsgi_string_list *usl = u_rrd.rrd;
char **argv;
int i;
create .rrd files if needed
if (!u_rrd.lib || !u_rrd.create) return;
*/
static void rrdtool_post_init() {
if (!u_rrd.create) return;
// do not waste time if no --rrdtool option is defiend
if (!u_rrd.rrd) return;
if (!u_rrd.directory) return;
if (uwsgi.numproc > u_rrd.max_ds) {
uwsgi_log("!!! NOT ENOUGH SLOTS IN RRDTOOL DS TO HOST WORKERS DATA (increase them with --rrdtool-max-ds) !!!\n");
dlclose(u_rrd.lib);
return;
}
// alloc space for DS_REQ + DS WORKER + RRA + create + filename
argv = uwsgi_malloc( sizeof(char *) * (1 + u_rrd.max_ds + 4 + 1 +1));
if (!u_rrd.freq) u_rrd.freq = 300;
char *argv[7];
argv[0] = "create";
argv[2] = "DS:requests:DERIVE:600:0:U";
// create DS for workers
for(i=0;i<u_rrd.max_ds;i++) {
int max_size = sizeof("DS:worker65536:DERIVE:600:0:U")+1;
argv[3+i] = uwsgi_malloc( max_size );
if (snprintf(argv[3+i], max_size, "DS:worker%d:DERIVE:600:0:U", i+1) < 25) {
uwsgi_log("unable to create args for rrd_create()\n");
exit(1);
}
}
// create RRA
argv[3+u_rrd.max_ds] = "RRA:AVERAGE:0.5:1:288" ;
argv[3+u_rrd.max_ds+1] = "RRA:AVERAGE:0.5:12:168" ;
argv[3+u_rrd.max_ds+2] = "RRA:AVERAGE:0.5:288:31" ;
argv[3+u_rrd.max_ds+3] = "RRA:AVERAGE:0.5:2016:52";
argv[3] = "RRA:AVERAGE:0.5:1:288" ;
argv[4] = "RRA:AVERAGE:0.5:12:168" ;
argv[5] = "RRA:AVERAGE:0.5:288:31" ;
argv[6] = "RRA:AVERAGE:0.5:2016:52";
while(usl) {
if (!uwsgi_file_exists(usl->value)) {
argv[1] = usl->value;
if (u_rrd.create((1 + u_rrd.max_ds + 4 + 1 +1), argv)) {
uwsgi_error("rrd_create()");
exit(1);
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, u_rrd.directory) {
char *dir = uwsgi_expand_path(usl->value, strlen(usl->value), NULL);
if (!dir) {
uwsgi_error("rrdtool_post_init()/uwsgi_expand_path()");
exit(1);
}
struct uwsgi_metric *um = uwsgi.metrics;
// here locking is useless, but maybe in the future we could move this part
// somewhere else
int created = 0;
uwsgi_rlock(uwsgi.metrics_lock);
while(um) {
char *filename = uwsgi_concat4(dir, "/", um->name, ".rrd");
if (!uwsgi_file_exists(filename)) {
argv[1] = filename;
if (um->type == UWSGI_METRIC_GAUGE) {
argv[2] = "DS:metric:GAUGE:600:0:U";
}
else {
argv[2] = "DS:metric:DERIVE:600:0:U";
}
if (u_rrd.create(7, argv)) {
uwsgi_log("unable to create rrd file for metric \"%s\"\n", um->name);
uwsgi_error("rrd_create()");
exit(1);
}
created++;
}
free(filename);
um = um->next;
}
char *new_usl_value = uwsgi_malloc(PATH_MAX+1);
if (!realpath(usl->value, new_usl_value)) {
uwsgi_error("realpath()");
exit(1);
}
usl->value = new_usl_value;
usl = usl->next;
uwsgi_rwunlock(uwsgi.metrics_lock);
uwsgi_log("created %d new rrd files in %s\n", created, dir);
struct uwsgi_stats_pusher_instance *uspi = uwsgi_stats_pusher_add(u_rrd.pusher, NULL);
uspi->freq = u_rrd.freq;
uspi->data = dir;
// no need to generate the json
uspi->raw=1;
}
// free DS
for(i=0;i<u_rrd.max_ds;i++) {
free(argv[3+i]);
}
free(argv);
//now allocate memory for updates
u_rrd.update_area = uwsgi_malloc( 1+((1+sizeof(UMAX64_STR)) * (u_rrd.max_ds+1))+1 );
memset(u_rrd.update_area, 0, 1+((1+sizeof(UMAX64_STR)) * (u_rrd.max_ds+1))+1 );
u_rrd.update_area[0] = 'N';
if (u_rrd.freq < 1) u_rrd.freq = 300;
}
void rrdtool_master_cycle() {
static void rrdtool_push(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) {
static time_t last_update = 0;
char *ptr;
int rlen, i;
char *argv[3];
struct uwsgi_string_list *usl = u_rrd.rrd;
if (!u_rrd.update) return ;
if (!u_rrd.lib || !u_rrd.create || !u_rrd.rrd) return ;
if (last_update == 0) last_update = uwsgi_now();
// update
if (uwsgi.current_time - last_update >= u_rrd.freq) {
ptr = u_rrd.update_area+1;
rlen = snprintf(ptr, 1+sizeof(UMAX64_STR), ":%llu", (unsigned long long )uwsgi.workers[0].requests);
if (rlen < 2) return;
ptr+=rlen;
for(i=0;i<u_rrd.max_ds;i++) {
if (i+1 <= uwsgi.numproc) {
rlen = snprintf(ptr, 1+sizeof(UMAX64_STR), ":%llu", (unsigned long long )uwsgi.workers[1+i].requests);
if (rlen < 2) return;
}
else {
memcpy(ptr, ":U", 2);
rlen = 2;
}
ptr+=rlen;
// standard stats pusher
if (!uspi->data) {
if (!uspi->arg) {
uwsgi_log("invalid rrdtool stats pusher syntax\n");
exit(1);
}
last_update = uwsgi.current_time;
argv[0] = "update";
argv[2] = u_rrd.update_area;
while(usl) {
argv[1] = usl->value;
if (u_rrd.update(3, argv)) {
uwsgi_log_verbose("ERROR: rrd_update(\"%s\", \"%s\")\n", argv[1], argv[2]);
}
usl = usl->next;
uspi->data = uwsgi_expand_path(uspi->arg, strlen(uspi->arg), NULL);
if (!uspi->data) {
uwsgi_error("rrdtool_push()/uwsgi_expand_path()");
exit(1);
}
if (!u_rrd.freq) u_rrd.freq = 300;
uspi->freq = u_rrd.freq;
}
// 1k will be more than enough
char buf[1024];
char *argv[3];
argv[0] = "update";
struct uwsgi_metric *um = uwsgi.metrics;
while(um) {
uwsgi_rlock(uwsgi.metrics_lock);
int ret = snprintf(buf, 1024, "N:%lld", (long long) (*um->value));
uwsgi_rwunlock(uwsgi.metrics_lock);
if (ret < 3) {
uwsgi_log("unable to update rrdtool metric for %s\n", um->name);
goto next;
}
char *filename = uwsgi_concat4(uspi->data, "/", um->name, ".rrd");
argv[1] = filename;
argv[2] = buf;
if (u_rrd.update(3, argv)) {
uwsgi_log_verbose("ERROR: rrd_update(\"%s\", \"%s\")\n", argv[1], argv[2]);
}
free(filename);
next:
um = um->next;
}
}
static void rrdtool_register() {
u_rrd.pusher = uwsgi_register_stats_pusher("rrdtool", rrdtool_push);
u_rrd.pusher->raw = 1;
}
struct uwsgi_plugin rrdtool_plugin = {
.name = "rrdtool",
.options = rrdtool_options,
.master_cycle = rrdtool_master_cycle,
.post_init = rrdtool_post_init,
.on_load = rrdtool_register,
// this is the best phase to create rrd files (if needed)
.preinit_apps = rrdtool_post_init,
// here we get pointers to rrdtool functions
.init = rrdtool_init,
};
+57
View File
@@ -0,0 +1,57 @@
#include <uwsgi.h>
struct uwsgi_stats_pusher_file_conf {
char *path;
char *freq;
char *separator;
};
static void stats_pusher_file(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) {
struct uwsgi_stats_pusher_file_conf *uspic = (struct uwsgi_stats_pusher_file_conf *) uspi->data;
if (!uspi->configured) {
uspic = uwsgi_calloc(sizeof(struct uwsgi_stats_pusher_file_conf));
if (uspi->arg) {
if (uwsgi_kvlist_parse(uspi->arg, strlen(uspi->arg), ',', '=', "path", &uspic->path, "separator", &uspic->separator, "freq", &uspic->freq, NULL)) {
free(uspi);
return;
}
}
if (!uspic->path)
uspic->path = "uwsgi.stats";
if (!uspic->separator)
uspic->separator = "\n\n";
if (uspic->freq)
uspi->freq = atoi(uspic->freq);
uspi->configured = 1;
uspi->data = uspic;
}
int fd = open(uspic->path, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP);
if (fd < 0) {
uwsgi_error_open(uspic->path);
return;
}
ssize_t rlen = write(fd, json, json_len);
if (rlen != (ssize_t) json_len) {
uwsgi_error("uwsgi_stats_pusher_file() -> write()\n");
}
rlen = write(fd, uspic->separator, strlen(uspic->separator));
if (rlen != (ssize_t) strlen(uspic->separator)) {
uwsgi_error("uwsgi_stats_pusher_file() -> write()\n");
}
close(fd);
}
static void stats_pusher_file_init(void) {
uwsgi_register_stats_pusher("file", stats_pusher_file);
}
struct uwsgi_plugin stats_pusher_file_plugin = {
.name = "stats_pusher_file",
.on_load = stats_pusher_file_init,
};
+7
View File
@@ -0,0 +1,7 @@
NAME='stats_pusher_file'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['plugin']
+111
View File
@@ -0,0 +1,111 @@
#include <uwsgi.h>
/*
this is a stats pusher plugin for sendign metrics over a udp socket
--stats-push socket:address[,prefix]
example:
--stats-push socket:127.0.0.1:8125,myinstance
it exports values exposed by the metric subsystem
(it is based on the statsd plugin)
*/
extern struct uwsgi_server uwsgi;
// configuration of a socket node
struct socket_node {
int fd;
union uwsgi_sockaddr addr;
socklen_t addr_len;
char *prefix;
uint16_t prefix_len;
};
static int socket_send_metric(struct uwsgi_buffer *ub, struct uwsgi_stats_pusher_instance *uspi, struct uwsgi_metric *um) {
struct socket_node *sn = (struct socket_node *) uspi->data;
// reset the buffer
ub->pos = 0;
if (uwsgi_buffer_append(ub, sn->prefix, sn->prefix_len)) return -1;
if (uwsgi_buffer_append(ub, ".", 1)) return -1;
if (uwsgi_buffer_append(ub, um->name, um->name_len)) return -1;
if (uwsgi_buffer_append(ub, " ", 1)) return -1;
if (uwsgi_buffer_num64(ub, (int64_t) um->type)) return -1;
if (uwsgi_buffer_append(ub, " ", 1)) return -1;
if (uwsgi_buffer_num64(ub, *um->value)) return -1;
if (sendto(sn->fd, ub->buf, ub->pos, 0, (struct sockaddr *) &sn->addr.sa_in, sn->addr_len) < 0) {
uwsgi_error("socket_send_metric()/sendto()");
}
return 0;
}
static void stats_pusher_socket(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) {
if (!uspi->configured) {
struct socket_node *sn = uwsgi_calloc(sizeof(struct socket_node));
char *comma = strchr(uspi->arg, ',');
if (comma) {
sn->prefix = comma+1;
sn->prefix_len = strlen(sn->prefix);
*comma = 0;
}
else {
sn->prefix = "uwsgi";
sn->prefix_len = 5;
}
char *colon = strchr(uspi->arg, ':');
if (!colon) {
uwsgi_log("invalid socket address %s\n", uspi->arg);
if (comma) *comma = ',';
free(sn);
return;
}
sn->addr_len = socket_to_in_addr(uspi->arg, colon, 0, &sn->addr.sa_in);
sn->fd = socket(AF_INET, SOCK_DGRAM, 0);
if (sn->fd < 0) {
uwsgi_error("stats_pusher_socket()/socket()");
if (comma) *comma = ',';
free(sn);
return;
}
uwsgi_socket_nb(sn->fd);
if (comma) *comma = ',';
uspi->data = sn;
uspi->configured = 1;
}
// we use the same buffer for all of the packets
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
struct uwsgi_metric *um = uwsgi.metrics;
while(um) {
uwsgi_rlock(uwsgi.metrics_lock);
socket_send_metric(ub, uspi, um);
uwsgi_rwunlock(uwsgi.metrics_lock);
um = um->next;
}
uwsgi_buffer_destroy(ub);
}
static void stats_pusher_socket_init(void) {
struct uwsgi_stats_pusher *usp = uwsgi_register_stats_pusher("socket", stats_pusher_socket);
// we use a custom format not the JSON one
usp->raw = 1;
}
struct uwsgi_plugin stats_pusher_socket_plugin = {
.name = "stats_pusher_socket",
.on_load = stats_pusher_socket_init,
};
@@ -0,0 +1,7 @@
NAME='stats_pusher_socket'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['plugin']
+23 -46
View File
@@ -10,7 +10,7 @@ example:
--stats-push statsd:127.0.0.1:8125,myinstance
it is pretty minimal, but will be extended after the 2.0 metric subsystem will be released
it exports values exposed by the metric subsystem
*/
@@ -25,45 +25,23 @@ struct statsd_node {
uint16_t prefix_len;
};
static int statsd_send_worker_gauge(struct uwsgi_buffer *ub, struct uwsgi_stats_pusher_instance *uspi, int wid, char *metric, uint16_t metric_len, int64_t value) {
static int statsd_send_metric(struct uwsgi_buffer *ub, struct uwsgi_stats_pusher_instance *uspi, char *metric, size_t metric_len, int64_t value, char type[2]) {
struct statsd_node *sn = (struct statsd_node *) uspi->data;
// reset the buffer
ub->pos = 0;
if (uwsgi_buffer_append(ub, sn->prefix, sn->prefix_len)) return -1;
if (uwsgi_buffer_append(ub, ".worker", 7)) return -1;
if (uwsgi_buffer_num64(ub, wid)) return -1;
if (uwsgi_buffer_append(ub, ".", 1)) return -1;
if (uwsgi_buffer_append(ub, metric, metric_len)) return -1;
if (uwsgi_buffer_append(ub, ":", 1)) return -1;
if (uwsgi_buffer_num64(ub, value)) return -1;
if (uwsgi_buffer_append(ub, "|g", 2)) return -1;
if (sendto(sn->fd, ub->buf, ub->pos, 0, (struct sockaddr *) &sn->addr.sa_in, sn->addr_len) < 0) {
uwsgi_error("stats_pusher_statsd()/sendto()");
}
return 0;
}
static int statsd_send_core_gauge(struct uwsgi_buffer *ub, struct uwsgi_stats_pusher_instance *uspi, int wid, int coreid, char *metric, uint16_t metric_len, int64_t value) {
struct statsd_node *sn = (struct statsd_node *) uspi->data;
// reset the buffer
ub->pos = 0;
if (uwsgi_buffer_append(ub, sn->prefix, sn->prefix_len)) return -1;
if (uwsgi_buffer_append(ub, ".worker", 7)) return -1;
if (uwsgi_buffer_num64(ub, wid)) return -1;
if (uwsgi_buffer_append(ub, ".core", 5)) return -1;
if (uwsgi_buffer_num64(ub, coreid)) return -1;
if (uwsgi_buffer_append(ub, ".", 1)) return -1;
if (uwsgi_buffer_append(ub, metric, metric_len)) return -1;
if (uwsgi_buffer_append(ub, ":", 1)) return -1;
if (uwsgi_buffer_append(ub, sn->prefix, sn->prefix_len)) return -1;
if (uwsgi_buffer_append(ub, ".", 1)) return -1;
if (uwsgi_buffer_append(ub, metric, metric_len)) return -1;
if (uwsgi_buffer_append(ub, ":", 1)) return -1;
if (uwsgi_buffer_num64(ub, value)) return -1;
if (uwsgi_buffer_append(ub, "|g", 2)) return -1;
if (uwsgi_buffer_append(ub, type, 2)) return -1;
if (sendto(sn->fd, ub->buf, ub->pos, 0, (struct sockaddr *) &sn->addr.sa_in, sn->addr_len) < 0) {
uwsgi_error("stats_pusher_statsd()/sendto()");
}
if (sendto(sn->fd, ub->buf, ub->pos, 0, (struct sockaddr *) &sn->addr.sa_in, sn->addr_len) < 0) {
uwsgi_error("statsd_send_metric()/sendto()");
}
return 0;
return 0;
}
@@ -106,20 +84,19 @@ static void stats_pusher_statsd(struct uwsgi_stats_pusher_instance *uspi, time_t
// we use the same buffer for all of the packets
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
int i, j;
// send workers metrics
for(i=1;i<=uwsgi.numproc;i++) {
if (statsd_send_worker_gauge(ub, uspi, i, "requests", 8, uwsgi.workers[i].requests)) goto end;
for(j=0;j<uwsgi.cores;j++) {
if (statsd_send_core_gauge(ub, uspi, i, j, "exceptions", 10, uwsgi.workers[i].cores[j].exceptions)) goto end;
if (statsd_send_core_gauge(ub, uspi, i, j, "requests", 8, uwsgi.workers[i].cores[j].requests)) goto end;
if (statsd_send_core_gauge(ub, uspi, i, j, "routed_requests", 15, uwsgi.workers[i].cores[j].routed_requests)) goto end;
if (statsd_send_core_gauge(ub, uspi, i, j, "static_requests", 15, uwsgi.workers[i].cores[j].static_requests)) goto end;
if (statsd_send_core_gauge(ub, uspi, i, j, "offloaded_requests", 18, uwsgi.workers[i].cores[j].offloaded_requests)) goto end;
struct uwsgi_metric *um = uwsgi.metrics;
while(um) {
uwsgi_rlock(uwsgi.metrics_lock);
// ignore return value
if (um->type == UWSGI_METRIC_GAUGE) {
statsd_send_metric(ub, uspi, um->name, um->name_len, *um->value, "|g");
}
else {
statsd_send_metric(ub, uspi, um->name, um->name_len, *um->value, "|m");
}
uwsgi_rwunlock(uwsgi.metrics_lock);
um = um->next;
}
end:
uwsgi_buffer_destroy(ub);
}
+414
View File
@@ -0,0 +1,414 @@
#include "../python/uwsgi_python.h"
extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
struct uwsgi_tornado {
PyObject *ioloop;
PyObject *functools;
PyObject *request;
PyObject *read;
PyObject *write;
PyObject *hook_fd;
PyObject *hook_timeout;
PyObject *hook_fix;
} utornado;
#define free_req_queue uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = wsgi_req
static void uwsgi_opt_setup_tornado(char *opt, char *value, void *null) {
// set async mode
uwsgi_opt_set_int(opt, value, &uwsgi.async);
if (uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] < 30) {
uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] = 30;
}
// set loop engine
uwsgi.loop = "tornado";
}
static struct uwsgi_option tornado_options[] = {
{"tornado", required_argument, 0, "a shortcut enabling tornado loop engine with the specified number of async cores and optimal parameters", uwsgi_opt_setup_tornado, NULL, UWSGI_OPT_THREADS},
{0, 0, 0, 0, 0, 0, 0},
};
static void gil_tornado_get() {
pthread_setspecific(up.upt_gil_key, (void *) PyGILState_Ensure());
}
static void gil_tornado_release() {
PyGILState_Release((PyGILState_STATE) pthread_getspecific(up.upt_gil_key));
}
static int uwsgi_tornado_wait_read_hook(int fd, int timeout) {
/*
def hook_fd(wsgi_req, fd, events):
uwsgi.resume(wsgi_req)
def hook_timeout(wsgi_req):
wsgi_req->timed_out = 1;
uwsgi.resume(wsgi_req)
io_loop.add_handler(fd, functools.partial(hook, wsgi_req), io_loop.READ)
t = io_loop.add_timeout(timeout, functools.partial(hook, wsgi_req))
uwsgi.suspend()
io_loop.remove_handler(fd)
io_loop.remove_timeout(t)
if wsgi_req->timed_out: return 0
*/
struct wsgi_request *wsgi_req = current_wsgi_req();
PyObject *cb_fd = PyObject_CallMethod(utornado.functools, "partial", "Ol", utornado.hook_fd, (long) wsgi_req);
if (!cb_fd) goto error;
PyObject *cb_timeout = PyObject_CallMethod(utornado.functools, "partial", "Ol", utornado.hook_timeout, (long) wsgi_req);
if (!cb_timeout) {
Py_DECREF(cb_fd);
goto error;
}
if (PyObject_CallMethod(utornado.ioloop, "add_handler", "iOO", fd, cb_fd, utornado.read) == NULL) {
Py_DECREF(cb_fd);
Py_DECREF(cb_timeout);
goto error;
}
PyObject *ob_timeout = PyObject_CallMethod(utornado.ioloop, "add_timeout", "iO", uwsgi_now() + timeout, cb_timeout);
if (!ob_timeout) {
Py_DECREF(cb_fd);
Py_DECREF(cb_timeout);
goto error;
}
// back to ioloop
if (uwsgi.schedule_to_main) uwsgi.schedule_to_main(wsgi_req);
// back from ioloop
if (PyObject_CallMethod(utornado.ioloop, "remove_handler", "i", fd) == NULL) PyErr_Print();
if (PyObject_CallMethod(utornado.ioloop, "remove_timeout", "O", ob_timeout) == NULL) PyErr_Print();
Py_DECREF(ob_timeout);
Py_DECREF(cb_fd);
Py_DECREF(cb_timeout);
if (wsgi_req->async_timed_out) return 0;
return 1;
error:
PyErr_Print();
return -1;
}
static int uwsgi_tornado_wait_write_hook(int fd, int timeout) {
struct wsgi_request *wsgi_req = current_wsgi_req();
PyObject *cb_fd = PyObject_CallMethod(utornado.functools, "partial", "Ol", utornado.hook_fd, (long) wsgi_req);
if (!cb_fd) goto error;
PyObject *cb_timeout = PyObject_CallMethod(utornado.functools, "partial", "Ol", utornado.hook_timeout, (long) wsgi_req);
if (!cb_timeout) {
Py_DECREF(cb_fd);
goto error;
}
if (PyObject_CallMethod(utornado.ioloop, "add_handler", "iOO", fd, cb_fd, utornado.write) == NULL) {
Py_DECREF(cb_fd);
Py_DECREF(cb_timeout);
goto error;
}
PyObject *ob_timeout = PyObject_CallMethod(utornado.ioloop, "add_timeout", "iO", uwsgi_now() + timeout, cb_timeout);
if (!ob_timeout) {
Py_DECREF(cb_fd);
Py_DECREF(cb_timeout);
goto error;
}
// back to ioloop
if (uwsgi.schedule_to_main) {
uwsgi.schedule_to_main(wsgi_req);
}
// back from ioloop
if (PyObject_CallMethod(utornado.ioloop, "remove_handler", "i", fd) == NULL) PyErr_Print();
if (PyObject_CallMethod(utornado.ioloop, "remove_timeout", "O", ob_timeout) == NULL) PyErr_Print();
Py_DECREF(ob_timeout);
Py_DECREF(cb_fd);
Py_DECREF(cb_timeout);
if (wsgi_req->async_timed_out) return 0;
return 1;
error:
PyErr_Print();
return -1;
}
PyObject *py_uwsgi_tornado_request(PyObject *self, PyObject *args) {
int fd = -1;
PyObject *events = NULL;
if (!PyArg_ParseTuple(args, "iO:uwsgi_tornado_request", &fd, &events)) {
uwsgi_log_verbose("[BUG] invalid arguments for tornado callback !!!\n");
exit(1);
}
struct wsgi_request *wsgi_req = find_wsgi_req_proto_by_fd(fd);
uwsgi.wsgi_req = wsgi_req;
int status = wsgi_req->socket->proto(wsgi_req);
if (status > 0) goto again;
if (PyObject_CallMethod(utornado.ioloop, "remove_handler", "i", fd) == NULL) {
PyErr_Print();
goto end;
}
if (status == 0) {
// we call this two time... overengineering :(
uwsgi.async_proto_fd_table[wsgi_req->fd] = NULL;
uwsgi.schedule_to_req();
goto again;
}
end:
uwsgi.async_proto_fd_table[wsgi_req->fd] = NULL;
uwsgi_close_request(uwsgi.wsgi_req);
free_req_queue;
again:
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_tornado_accept(PyObject *self, PyObject *args) {
int fd = -1;
PyObject *events = NULL;
if (!PyArg_ParseTuple(args, "iO:uwsgi_tornado_accept", &fd, &events)) {
return NULL;
}
struct wsgi_request *wsgi_req = find_first_available_wsgi_req();
if (wsgi_req == NULL) {
uwsgi_async_queue_is_full(uwsgi_now());
goto end;
}
uwsgi.wsgi_req = wsgi_req;
// TODO better to move it to a function api ...
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while(uwsgi_sock) {
if (uwsgi_sock->fd == fd) break;
uwsgi_sock = uwsgi_sock->next;
}
if (!uwsgi_sock) {
free_req_queue;
goto end;
}
// fill wsgi_request structure
wsgi_req_setup(wsgi_req, wsgi_req->async_id, uwsgi_sock );
// mark core as used
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 1;
// accept the connection (since uWSGI 1.5 all of the sockets are non-blocking)
if (wsgi_req_simple_accept(wsgi_req, uwsgi_sock->fd)) {
// in case of errors (or thundering herd, just reset it)
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 0;
free_req_queue;
goto end;
}
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]);
}
uwsgi.async_proto_fd_table[wsgi_req->fd] = wsgi_req;
// add callback for protocol
if (PyObject_CallMethod(utornado.ioloop, "add_handler", "iOO", wsgi_req->fd, utornado.request, utornado.read) == NULL) {
free_req_queue;
PyErr_Print();
}
end:
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_tornado_hook_fd(PyObject *self, PyObject *args) {
long wsgi_req_ptr = 0;
int fd = -1;
PyObject *events = NULL;
if (!PyArg_ParseTuple(args, "liO:uwsgi_tornado_hook_fd", &wsgi_req_ptr, &fd, &events)) {
return NULL;
}
uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
uwsgi.schedule_to_req();
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_tornado_hook_timeout(PyObject *self, PyObject *args) {
long wsgi_req_ptr = 0;
if (!PyArg_ParseTuple(args, "l", &wsgi_req_ptr)) {
return NULL;
}
uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
uwsgi.wsgi_req->async_timed_out = 1;
uwsgi.schedule_to_req();
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_tornado_hook_fix(PyObject *self, PyObject *args) {
long wsgi_req_ptr = 0;
if (!PyArg_ParseTuple(args, "l", &wsgi_req_ptr)) {
return NULL;
}
uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
uwsgi.schedule_to_req();
Py_INCREF(Py_None);
return Py_None;
}
PyMethodDef uwsgi_tornado_accept_def[] = { {"uwsgi_tornado_accept", py_uwsgi_tornado_accept, METH_VARARGS, ""} };
PyMethodDef uwsgi_tornado_request_def[] = { {"uwsgi_tornado_request", py_uwsgi_tornado_request, METH_VARARGS, ""} };
PyMethodDef uwsgi_tornado_hook_fd_def[] = { {"uwsgi_tornado_hook_fd", py_uwsgi_tornado_hook_fd, METH_VARARGS, ""} };
PyMethodDef uwsgi_tornado_hook_timeout_def[] = { {"uwsgi_tornado_hook_timeout", py_uwsgi_tornado_hook_timeout, METH_VARARGS, ""} };
PyMethodDef uwsgi_tornado_hook_fix_def[] = { {"uwsgi_tornado_hook_fix", py_uwsgi_tornado_hook_fix, METH_VARARGS, ""} };
static void uwsgi_tornado_schedule_fix(struct wsgi_request *wsgi_req) {
PyObject *cb_fix = PyObject_CallMethod(utornado.functools, "partial", "Ol", utornado.hook_fix, (long) wsgi_req);
if (!cb_fix) goto error;
if (PyObject_CallMethod(utornado.ioloop, "add_callback", "O", cb_fix) == NULL) {
Py_DECREF(cb_fix);
goto error;
}
Py_DECREF(cb_fix);
return;
error:
PyErr_Print();
}
static void tornado_loop() {
if (!uwsgi.has_threads && uwsgi.mywid == 1) {
uwsgi_log("!!! Running tornado without threads IS NOT recommended, enable them with --enable-threads !!!\n");
}
if (uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] < 30) {
uwsgi_log("!!! Running tornado with a socket-timeout lower than 30 seconds is not recommended, tune it with --socket-timeout !!!\n");
}
// get the GIL
UWSGI_GET_GIL
up.gil_get = gil_tornado_get;
up.gil_release = gil_tornado_release;
uwsgi.wait_write_hook = uwsgi_tornado_wait_write_hook;
uwsgi.wait_read_hook = uwsgi_tornado_wait_read_hook;
uwsgi.schedule_fix = uwsgi_tornado_schedule_fix;
if (uwsgi.async < 2) {
uwsgi_log("the tornado loop engine requires async mode (--async <n>)\n");
exit(1);
}
if (!uwsgi.schedule_to_main) {
uwsgi_log("*** DANGER *** tornado mode without coroutine/greenthread engine loaded !!!\n");
}
PyObject *tornado_dict = get_uwsgi_pydict("tornado.ioloop");
if (!tornado_dict) uwsgi_pyexit;
PyObject *tornado_IOLoop = PyDict_GetItemString(tornado_dict, "IOLoop");
if (!tornado_IOLoop) uwsgi_pyexit;
utornado.ioloop = PyObject_CallMethod(tornado_IOLoop, "instance", NULL);
if (!utornado.ioloop) uwsgi_pyexit;
// main greenlet waiting for connection (one greenlet per-socket)
PyObject *uwsgi_tornado_accept = PyCFunction_New(uwsgi_tornado_accept_def, NULL);
Py_INCREF(uwsgi_tornado_accept);
utornado.request = PyCFunction_New(uwsgi_tornado_request_def, NULL);
if (!utornado.request) uwsgi_pyexit;
utornado.hook_fd = PyCFunction_New(uwsgi_tornado_hook_fd_def, NULL);
if (!utornado.hook_fd) uwsgi_pyexit;
utornado.hook_timeout = PyCFunction_New(uwsgi_tornado_hook_timeout_def, NULL);
if (!utornado.hook_timeout) uwsgi_pyexit;
utornado.hook_fix = PyCFunction_New(uwsgi_tornado_hook_fix_def, NULL);
if (!utornado.hook_fix) uwsgi_pyexit;
utornado.read = PyObject_GetAttrString(utornado.ioloop, "READ");
if (!utornado.read) uwsgi_pyexit;
utornado.write = PyObject_GetAttrString(utornado.ioloop, "WRITE");
if (!utornado.write) uwsgi_pyexit;
utornado.functools = PyImport_ImportModule("functools");
if (!utornado.functools) uwsgi_pyexit;
Py_INCREF(utornado.request);
Py_INCREF(utornado.hook_fd);
Py_INCREF(utornado.hook_timeout);
Py_INCREF(utornado.hook_fix);
Py_INCREF(utornado.read);
Py_INCREF(utornado.write);
// call add_handler on each socket
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while(uwsgi_sock) {
if (PyObject_CallMethod(utornado.ioloop, "add_handler", "iOO", uwsgi_sock->fd, uwsgi_tornado_accept, utornado.read) == NULL) {
uwsgi_pyexit;
}
uwsgi_sock = uwsgi_sock->next;
}
if (PyObject_CallMethod(utornado.ioloop, "start", NULL) == NULL) {
uwsgi_pyexit;
}
// never here ?
}
static void tornado_init() {
uwsgi_register_loop( (char *) "tornado", tornado_loop);
}
struct uwsgi_plugin tornado_plugin = {
.name = "tornado",
.options = tornado_options,
.on_load = tornado_init,
};
+8
View File
@@ -0,0 +1,8 @@
from distutils import sysconfig
NAME='tornado'
CFLAGS = ['-I' + sysconfig.get_python_inc(), '-I' + sysconfig.get_python_inc(plat_specific=True)]
LDFLAGS = []
LIBS = []
GCC_LIST = ['tornado']
+42
View File
@@ -0,0 +1,42 @@
#include <uwsgi.h>
#ifdef UWSGI_ROUTING
// apply templating
static int transform_template(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
struct uwsgi_route *ur = (struct uwsgi_route *) ut->data;
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, ut->chunk->buf, ut->chunk->pos);
if (!ub) return -1;
uwsgi_buffer_map(ut->chunk, ub->buf, ub->pos);
ub->buf = NULL;
uwsgi_buffer_destroy(ub);
return 0;
}
static int uwsgi_router_template_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
uwsgi_add_transformation(wsgi_req, transform_template, route);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_template(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_template_func;
return 0;
}
static void transformation_template_register(void) {
uwsgi_register_router("template", uwsgi_router_template);
}
struct uwsgi_plugin transformation_template_plugin = {
.name = "transformation_template",
.on_load = transformation_template_register,
};
#else
struct uwsgi_plugin transformation_template_plugin = {
.name = "transformation_template",
};
#endif
@@ -0,0 +1,6 @@
NAME='transformation_template'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['tt']
+1 -1
View File
@@ -104,7 +104,7 @@ static int u_green_init() {
ug.contexts[i].uc_stack.ss_sp = mmap(NULL, ug.u_stack_size + (uwsgi.page_size*2) , PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0) + uwsgi.page_size;
if (!ug.contexts[i].uc_stack.ss_sp) {
if (ug.contexts[i].uc_stack.ss_sp == MAP_FAILED) {
uwsgi_error("mmap()");
exit(1);
}
+1 -1
View File
@@ -152,8 +152,8 @@ static v8::Handle < v8::Value > uwsgi_v8_commonjs_require(const v8::Arguments &
free(tmp_filename);
return ret;
}
free(tmp_filename);
}
free(tmp_filename);
usl = usl->next;
}
}
+6 -6
View File
@@ -92,9 +92,9 @@ static char *uwsgi_xslt_apply(xmlDoc *doc, char *xsltfile, char *params, int *rl
if (!ss) {
if (vparams) {
int i; for(i=1;i<(count*2);i+=2) free(vparams[i]);
free(tmp_params);
free(vparams);
}
free(tmp_params);
return NULL;
}
@@ -103,9 +103,9 @@ static char *uwsgi_xslt_apply(xmlDoc *doc, char *xsltfile, char *params, int *rl
xsltFreeStylesheet(ss);
if (vparams) {
int i; for(i=1;i<(count*2);i+=2) free(vparams[i]);
free(tmp_params);
free(vparams);
}
free(tmp_params);
return NULL;
}
@@ -115,9 +115,9 @@ static char *uwsgi_xslt_apply(xmlDoc *doc, char *xsltfile, char *params, int *rl
xmlFreeDoc(res);
if (vparams) {
int i; for(i=1;i<(count*2);i+=2) free(vparams[i]);
free(tmp_params);
free(vparams);
}
free(tmp_params);
if (ret < 0) return NULL;
return (char *) output;
}
@@ -183,10 +183,9 @@ static int uwsgi_request_xslt(struct wsgi_request *wsgi_req) {
return UWSGI_OK;
}
free(xmlfile);
if (!uwsgi_is_file(filename)) {
uwsgi_403(wsgi_req);
free(xmlfile);
return UWSGI_OK;
}
filename_len = strlen(filename);
@@ -276,6 +275,7 @@ apply:
}
// we have both the file and the stylesheet, let's run the engine
xmlDoc *doc = xmlParseFile(xmlfile);
free(xmlfile);
if (!doc) {
uwsgi_500(wsgi_req);
return UWSGI_OK;
@@ -441,7 +441,7 @@ static int uwsgi_router_xslt(struct uwsgi_route *ur, char *args) {
exit(1);
}
if (!urxc->doc && !urxc->stylesheet) {
if (!urxc->doc || !urxc->stylesheet) {
uwsgi_log("invalid route syntax: you need to specify a doc and a stylesheet\n");
exit(1);
}
+198
View File
@@ -0,0 +1,198 @@
#include <uwsgi.h>
/*
this is a stats pusher plugin for the zabbix server:
--stats-push zabbix:address[,prefix]
example:
--stats-push zabbix:127.0.0.1:10051,myinstance
it exports values exposed by the metric subsystem
*/
extern struct uwsgi_server uwsgi;
static char *zabbix_template = NULL;
static void uwsgi_opt_zabbix_template(char *opt, char *value, void *none) {
if (value) {
zabbix_template = value;
}
else {
zabbix_template = "";
}
}
static struct uwsgi_option zabbix_options[] = {
{"zabbix-template", optional_argument, 0, "print (or store to a file) the zabbix template for the current metrics setup", uwsgi_opt_zabbix_template, NULL, UWSGI_OPT_METRICS},
{0, 0, 0, 0, 0, 0, 0},
};
// configuration of a zabbix node
struct zabbix_node {
char *addr;
char *prefix;
uint16_t prefix_len;
// we reuse the same buffer
struct uwsgi_buffer *ub;
};
/*
{
"request":"sender data",
"data": [
{"host":uwsgi.hostname, "key":"foo", "value":"bar"},
...
]
}
*/
static void stats_pusher_zabbix(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) {
if (!uspi->configured) {
struct zabbix_node *zn = uwsgi_calloc(sizeof(struct zabbix_node));
if (!uspi->arg || strlen(uspi->arg) == 0) {
zn->addr = uwsgi_str("127.0.0.1:10051");
}
else {
zn->addr = uwsgi_str(uspi->arg);
}
char *comma = strchr(zn->addr, ',');
if (comma) {
zn->prefix = comma+1;
zn->prefix_len = strlen(zn->prefix);
*comma = 0;
}
else {
zn->prefix = "uwsgi";
zn->prefix_len = 5;
}
zn->ub = uwsgi_buffer_new(uwsgi.page_size);
uwsgi_buffer_append(zn->ub, "ZBXD\1\0\0\0\0\0\0\0\0{\"request\":\"sender data\",\"data\":[", 46);
uspi->data = zn;
uspi->configured = 1;
}
struct zabbix_node *zn = (struct zabbix_node *) uspi->data ;
// we use the same buffer for all of the packets
zn->ub->pos = 46;
struct uwsgi_metric *um = uwsgi.metrics;
int error = 0;
uwsgi_rlock(uwsgi.metrics_lock);
while(um) {
if (uwsgi_buffer_append(zn->ub, "{\"host\":\"", 9)) { error = 1; goto end;}
if (uwsgi_buffer_append(zn->ub, uwsgi.hostname, uwsgi.hostname_len)) { error = 1; goto end;}
if (uwsgi_buffer_append(zn->ub, "\",\"key\":\"", 9)) { error = 1; goto end;}
if (uwsgi_buffer_append(zn->ub, zn->prefix, zn->prefix_len)) { error = 1; goto end;}
if (uwsgi_buffer_append(zn->ub, ".", 1)) { error = 1; goto end;}
if (uwsgi_buffer_append(zn->ub, um->name, um->name_len)) { error = 1; goto end;}
if (uwsgi_buffer_append(zn->ub, "\",\"value\":\"", 11)) { error = 1; goto end;}
if (uwsgi_buffer_num64(zn->ub, *um->value)) { error = 1; goto end;}
if (uwsgi_buffer_append(zn->ub, "\"}", 2)) { error = 1; goto end;}
um = um->next;
if (um) {
if (uwsgi_buffer_append(zn->ub, ",", 1)) { error = 1; goto end;}
}
}
if (uwsgi_buffer_append(zn->ub, "]}", 2)) error = 1;
end:
uwsgi_rwunlock(uwsgi.metrics_lock);
if (error) return;
uint64_t pktsize = zn->ub->pos - 13;
zn->ub->pos = 5;
if (uwsgi_buffer_u64le(zn->ub, pktsize)) error = 1;
if (error) return;
int fd = uwsgi_connect(zn->addr, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], 0);
if (fd < 0) {
uwsgi_error("stats_pusher_zabbix()/connect()");
return;
}
if (write(fd, zn->ub->buf, pktsize + 13) != (ssize_t) (pktsize + 13)) {
uwsgi_error("stats_pusher_zabbix()/write()");
}
// fake read for simplify debug with strace
char buf[4096];
if (read(fd, buf, 4096) <= 0) {
uwsgi_error("stats_pusher_zabbix()/read()");
}
close(fd);
}
static void stats_pusher_zabbix_init(void) {
struct uwsgi_stats_pusher *usp = uwsgi_register_stats_pusher("zabbix", stats_pusher_zabbix);
// we use a custom format not the JSON one
usp->raw = 1;
}
static void zabbix_template_print() {
if (!zabbix_template) return;
int fd = 1 ;
if (zabbix_template[0] != 0) {
fd = open(zabbix_template, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP);
if (fd < 0) {
uwsgi_error_open(zabbix_template);
exit(1);
}
}
struct uwsgi_metric *um = uwsgi.metrics;
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
if (uwsgi_buffer_append(ub,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", 39)) goto error;
if (uwsgi_buffer_append(ub,"<zabbix_export>\n", 16)) goto error;
if (uwsgi_buffer_append(ub,"<version>2.0</version><groups><group><name>uWSGI</name></group></groups>\n", 73)) goto error;
if (uwsgi_buffer_append(ub,"\t<templates><template><template>uWSGI metrics</template><name>uWSGI metrics</name>\n", 83)) goto error;
if (uwsgi_buffer_append(ub,"\t<groups><group><name>uWSGI</name></group></groups>\n", 52)) goto error;
if (uwsgi_buffer_append(ub,"\t<items>\n", 9)) goto error;
while(um) {
if (uwsgi_buffer_append(ub,"\t\t<item>\n", 9)) goto error;
if (uwsgi_buffer_append(ub,"\t\t\t<name>", 9)) goto error;
if (uwsgi_buffer_append(ub, um->name, um->name_len)) goto error;
if (uwsgi_buffer_append(ub,"</name>\n", 8)) goto error;
if (uwsgi_buffer_append(ub,"\t\t\t<type>2</type>\n", 18)) goto error;
if (uwsgi_buffer_append(ub,"\t\t\t<key>", 8)) goto error;
if (uwsgi_buffer_append(ub, um->name, um->name_len)) goto error;
if (uwsgi_buffer_append(ub,"</key>\n", 7)) goto error;
if (uwsgi_buffer_append(ub,"\t\t\t<value_type>3</value_type>\n", 30)) goto error;
if (uwsgi_buffer_append(ub,"\t\t</item>\n", 10)) goto error;
um = um->next;
}
if (uwsgi_buffer_append(ub,"\t</items></template></templates>\n", 33)) goto error;
if (uwsgi_buffer_append(ub,"</zabbix_export>\n", 17)) goto error;
if (write(fd, ub->buf, ub->pos) != (ssize_t) ub->pos) {
uwsgi_error("zabbix_template_print()/wrtie()");
exit(1);
}
uwsgi_buffer_destroy(ub);
if (zabbix_template[0] != 0) {
uwsgi_log("zabbix template written to %s\n", zabbix_template);
close(fd);
}
return;
error:
uwsgi_buffer_destroy(ub);
uwsgi_log("error generating zabbix template\n");
exit(1);
}
struct uwsgi_plugin zabbix_plugin = {
.name = "zabbix",
.options = zabbix_options,
.on_load = stats_pusher_zabbix_init,
.preinit_apps = zabbix_template_print,
};
+7
View File
@@ -0,0 +1,7 @@
NAME='zabbix'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['plugin']
+13 -2
View File
@@ -1,8 +1,14 @@
#include "../uwsgi.h"
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
int uwsgi_proto_raw_parser(struct wsgi_request *wsgi_req) {
wsgi_req->is_raw = 1;
wsgi_req->uh->modifier1 = uwsgi.raw_modifier1;
wsgi_req->uh->modifier2 = uwsgi.raw_modifier2;
return UWSGI_OK;
}
uint16_t proto_base_add_uwsgi_header(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, char *val, uint16_t vallen) {
@@ -213,3 +219,8 @@ ssize_t uwsgi_proto_base_read_body(struct wsgi_request *wsgi_req, char *buf, siz
}
return read(wsgi_req->fd, buf, len);
}
ssize_t uwsgi_proto_noop_read_body(struct wsgi_request *wsgi_req, char *buf, size_t len) {
uwsgi_log_verbose("!!! the current protocol does not support request body !!!\n");
return -1;
}
+91
View File
@@ -0,0 +1,91 @@
/* async uwsgi protocol parser */
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
/*
perfect framing is required in persistent mode, so we need at least 2 syscall to assemble
a uwsgi header: 4 bytes header + payload
increase write_errors on error to force socket close
*/
int uwsgi_proto_puwsgi_parser(struct wsgi_request *wsgi_req) {
ssize_t len;
char *ptr = (char *) wsgi_req->uh;
if (wsgi_req->proto_parser_pos < 4) {
len = read(wsgi_req->fd, ptr + wsgi_req->proto_parser_pos, 4 - wsgi_req->proto_parser_pos);
if (len > 0) {
wsgi_req->proto_parser_pos += len;
if (wsgi_req->proto_parser_pos == 4) {
#ifdef __BIG_ENDIAN__
wsgi_req->uh->pktsize = uwsgi_swap16(wsgi_req->uh->pktsize);
#endif
if (wsgi_req->uh->pktsize > uwsgi.buffer_size) {
uwsgi_log("invalid request block size: %u (max %u)...skip\n", wsgi_req->uh->pktsize, uwsgi.buffer_size);
wsgi_req->write_errors++;
return -1;
}
}
return UWSGI_AGAIN;
}
goto negative;
}
len = read(wsgi_req->fd, ptr + wsgi_req->proto_parser_pos, wsgi_req->uh->pktsize - (wsgi_req->proto_parser_pos-4));
if (len > 0) {
wsgi_req->proto_parser_pos += len;
if ((wsgi_req->proto_parser_pos-4) == wsgi_req->uh->pktsize) {
return UWSGI_OK;
}
return UWSGI_AGAIN;
}
negative:
if (len < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
return UWSGI_AGAIN;
}
uwsgi_error("uwsgi_proto_uwsgi_parser()");
wsgi_req->write_errors++;
return -1;
}
// 0 len
if (wsgi_req->proto_parser_pos > 0) {
uwsgi_error("uwsgi_proto_uwsgi_parser()");
}
wsgi_req->write_errors++;
return -1;
}
/*
close the connection on errors, otherwise force edge triggering
*/
void uwsgi_proto_puwsgi_close(struct wsgi_request *wsgi_req) {
// check for errors or incomplete packets
if (wsgi_req->write_errors || (size_t) (wsgi_req->uh->pktsize + 4) != wsgi_req->proto_parser_pos) {
close(wsgi_req->fd);
wsgi_req->socket->retry[wsgi_req->async_id] = 0;
wsgi_req->socket->fd_threads[wsgi_req->async_id] = -1;
}
else {
wsgi_req->socket->retry[wsgi_req->async_id] = 1;
wsgi_req->socket->fd_threads[wsgi_req->async_id] = wsgi_req->fd;
}
}
int uwsgi_proto_puwsgi_accept(struct wsgi_request *wsgi_req, int fd) {
if (wsgi_req->socket->retry[wsgi_req->async_id]) {
wsgi_req->fd = wsgi_req->socket->fd_threads[wsgi_req->async_id];
int ret = uwsgi_wait_read_req(wsgi_req);
if (ret <= 0) {
close(wsgi_req->fd);
wsgi_req->socket->retry[wsgi_req->async_id] = 0;
wsgi_req->socket->fd_threads[wsgi_req->async_id] = -1;
return -1;
}
return wsgi_req->socket->fd_threads[wsgi_req->async_id];
}
return uwsgi_proto_base_accept(wsgi_req, fd);
}
+3
View File
@@ -10,6 +10,9 @@ int uwsgi_proto_uwsgi_parser(struct wsgi_request *wsgi_req) {
if (len > 0) {
wsgi_req->proto_parser_pos += len;
if (wsgi_req->proto_parser_pos >= 4) {
#ifdef __BIG_ENDIAN__
wsgi_req->uh->pktsize = uwsgi_swap16(wsgi_req->uh->pktsize);
#endif
if ((wsgi_req->proto_parser_pos-4) == wsgi_req->uh->pktsize) {
return UWSGI_OK;
}
-108
View File
@@ -1,108 +0,0 @@
/* async uwsgi protocol parser */
#include "../uwsgi.h"
extern struct uwsgi_server uwsgi;
#define PROTO_STATUS_RECV_HDR 0
#define PROTO_STATUS_RECV_VARS 1
int uwsgi_proto_uwsgi_parser(struct wsgi_request *wsgi_req) {
uint8_t *hdr_buf = (uint8_t *) & wsgi_req->uh;
ssize_t len;
struct iovec iov[1];
struct cmsghdr *cmsg;
if (wsgi_req->proto_parser_status == PROTO_STATUS_RECV_HDR) {
if (wsgi_req->proto_parser_pos > 0) {
len = read(wsgi_req->poll.fd, hdr_buf + wsgi_req->proto_parser_pos, 4 - wsgi_req->proto_parser_pos);
}
else {
iov[0].iov_base = hdr_buf;
iov[0].iov_len = 4;
wsgi_req->msg.msg_name = NULL;
wsgi_req->msg.msg_namelen = 0;
wsgi_req->msg.msg_iov = iov;
wsgi_req->msg.msg_iovlen = 1;
wsgi_req->msg.msg_control = &wsgi_req->msg_control;
wsgi_req->msg.msg_controllen = sizeof(wsgi_req->msg_control);
wsgi_req->msg.msg_flags = 0;
len = recvmsg(wsgi_req->poll.fd, &wsgi_req->msg, 0);
}
if (len <= 0) {
uwsgi_error("read()");
return -1;
}
wsgi_req->proto_parser_pos += len;
// header ready ?
if (wsgi_req->proto_parser_pos == 4) {
wsgi_req->proto_parser_status = PROTO_STATUS_RECV_VARS;
wsgi_req->proto_parser_pos = 0;
/* big endian ? */
#ifdef __BIG_ENDIAN__
wsgi_req->uh.pktsize = uwsgi_swap16(wsgi_req->uh.pktsize);
#endif
uwsgi_debug("uwsgi payload size: %d (0x%X) modifier1: %d modifier2: %d\n", wsgi_req->uh.pktsize, wsgi_req->uh.pktsize, wsgi_req->uh.modifier1, wsgi_req->uh.modifier2);
/* check for max buffer size */
if (wsgi_req->uh.pktsize > uwsgi.buffer_size) {
uwsgi_log("invalid request block size. requested %d bytes available %d bytes...skip\n", wsgi_req->uh.pktsize, uwsgi.buffer_size);
return -1;
}
if (!wsgi_req->uh.pktsize)
return UWSGI_OK;
}
return UWSGI_AGAIN;
}
else if (wsgi_req->proto_parser_status == PROTO_STATUS_RECV_VARS) {
len = read(wsgi_req->poll.fd, wsgi_req->buffer + wsgi_req->proto_parser_pos, wsgi_req->uh.pktsize - wsgi_req->proto_parser_pos);
if (len <= 0) {
uwsgi_error("read()");
return -1;
}
wsgi_req->proto_parser_pos += len;
// body ready ?
if (wsgi_req->proto_parser_pos >= wsgi_req->uh.pktsize) {
// older OSX versions make mess with CMSG_FIRSTHDR
#ifdef __APPLE__
if (!wsgi_req->msg.msg_controllen)
return UWSGI_OK;
#endif
cmsg = CMSG_FIRSTHDR(&wsgi_req->msg);
while (cmsg != NULL) {
if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type && SCM_RIGHTS) {
// upgrade connection to the new socket
uwsgi_log("upgrading fd %d to ", wsgi_req->poll.fd);
close(wsgi_req->poll.fd);
memcpy(&wsgi_req->poll.fd, CMSG_DATA(cmsg), sizeof(int));
uwsgi_log("%d\n", wsgi_req->poll.fd);
}
cmsg = CMSG_NXTHDR(&wsgi_req->msg, cmsg);
}
return UWSGI_OK;
}
return UWSGI_AGAIN;
}
// never here
return -1;
}

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