Compare commits

..
186 Commits
Author SHA1 Message Date
Unbit b0159ea23b prepare for 2.0.2 2014-02-26 17:06:47 +01:00
Unbit d3493df032 do not expode if Devel::StackTrace is missing 2014-02-26 17:06:21 +01:00
Unbit 757c76b569 fix -bash in perl hooks 2014-02-26 12:12:41 +01:00
Unbit 30eebfd335 better perl do usage and --perl-no-plack flag 2014-02-26 12:07:00 +01:00
Unbit c5d7d30439 try to better address #553 2014-02-26 11:39:00 +01:00
unbit 04bc3e117d Merge pull request #553 from avar/avar/do-not-run-psgi-begin-blocks-twice
perl: Don't run BEGIN blocks twice in the provided *.psgi
2014-02-26 08:24:11 +01:00
Ævar Arnfjörð Bjarmason 3480c30674 perl: Don't run BEGIN blocks twice in the provided *.psgi
The psgi loaded was calling perl_parse() with the script ostensibly to
set up xsinit.

However it would also call perl_parse() with the path to our *.psgi
file, whith the result that any BEGIN block in the *.psgi file would be
run twice, but anything outside BEGIN blocks would only run once.

This means that any code within explicit BEGIN blocks will run twice,
and any "use" statement in the *.psgi file will run its import() routine
twice, but due to the module being in %INC already we won't actually
compile things twice.

The previous behavior dates all the way back to the initial introduction
of the PSGI plugin in 299fd9c.

Then when support for local::lib was added in 7cbe751 we initially did a
perl_eval_pv() of a "use" statement like I'm doing here again now, but
later on in 1561dd3 changed it to call perl_parse with the commit
message "another PSGI loading fix".

Since there's no info on what that fixed or what was broken before I
have no idea if I'm introducing a regression here, but I don't see why
this way of loding local::lib shouldn't work, and it correctly munges
@INC for me when I try it.

We may still have this bug in the remaining perl_parse() calls that
remain for supporting "preinit" and "mule".

I haven't tested those modes (I don't use them), but when we load the
Perl apps we should only perl_parse() once with -e1, and then
perl_eval_pv() to actually load the application. We should not call
perl_parse() on code that we're just about to perl_eval_pv(), or we'll
run into this bug.

To test this just run:

    ./uwsgi --http 127.0.0.1:8080 --psgi ./t/perl/test.psgi

It'll no longer PANIC on the BEGIN block being run twice now, at least
in that simplistic non-"preinit" non-"mule" mode.
2014-02-25 18:07:42 +00:00
Unbit a7e6dfc469 fixed python 3 on old compilers, fixes #551 2014-02-25 07:05:46 +01:00
Unbit 5e276b43ad fix poll() usage in #546 2014-02-24 09:14:14 +01:00
Roberto De Ioris 9e6a21602a more cgi improvements 2014-02-22 11:40:23 +01:00
Roberto De Ioris 952c4ce854 minor fixes in non-blocking reads 2014-02-22 11:13:50 +01:00
Roberto De Ioris 951f24e711 fixed #546 2014-02-22 10:46:46 +01:00
Unbit 7bda4c9b63 allow starting in spooler mode only 2014-02-21 08:48:21 +01:00
Unbit 1b25516ced spawn spoolers if requested 2014-02-21 08:42:22 +01:00
Unbit b3020e60f9 fixed long standing bug with caches 2014-02-20 14:19:40 +01:00
Unbit 808d37f33a fixed ftime log var 2014-02-20 10:52:05 +01:00
Unbit 8c8a7f77d1 added async remote signal management 2014-02-20 10:48:30 +01:00
Unbit 3f601af740 fix end-for and end-if 2014-02-20 10:28:30 +01:00
Unbit 7b901ab81e fixed #536 2014-02-20 09:19:41 +01:00
Roberto De Ioris 930eb1e6aa fixed #541 2014-02-20 07:52:47 +01:00
Unbit 77e5931da7 avoid loop in response and error internal routing 2014-02-15 09:35:38 +01:00
Unbit 3e6ddbb3d5 added --php-exec-before/--php-exec-after 2014-02-15 08:59:56 +01:00
Unbit 623bce274a prepare for 2.0.2 2014-02-15 07:31:39 +01:00
Unbit 6c986f8082 fixed pypy execute_source usage 2014-02-15 07:30:17 +01:00
Unbit 10a02064ba Merge branch 'master' of ssh://github.com/unbit/uwsgi 2014-02-13 06:25:18 +01:00
Unbit 774f5a81a5 added --geoip-use-disk, fixes #519 2014-02-13 06:25:07 +01:00
unbit e270593cc0 Merge pull request #533 from ramm/master
typo fix
2014-02-13 06:24:13 +01:00
Unbit b559354845 more tests for bitmap cache 2014-02-13 06:16:02 +01:00
Unbit 46a2fefb04 added overlap check for cache 2014-02-13 06:06:29 +01:00
Unbit c6c9baa7b5 initial test suite for bitmap cache mode 2014-02-12 18:54:39 +01:00
Danila Shtan c37710f4c2 Add myself to contributors
as agreed at https://github.com/unbit/uwsgi/pull/530#issuecomment-34859953
2014-02-12 22:35:10 +05:00
Danila Shtan 943c20b88c typo fix 2014-02-12 22:33:40 +05:00
Unbit a442614db0 fixed #531 2014-02-12 17:00:47 +01:00
Unbit 5830af37ba restore back needed_bytes 2014-02-12 16:25:02 +01:00
unbit de4c563169 Merge pull request #530 from ramm/master
fixed bitmap allocation bugs
2014-02-12 16:22:56 +01:00
Danila Shtan 77f008e24c fix unmark interval inside cache_update 2014-02-12 18:20:39 +05:00
Danila Shtan df0bd832b4 bitmap allocation fix
fix cache_mark offset bug and change cache_unmark according to previous changes)
2014-02-12 17:36:40 +05:00
Danila Shtan 07c42c262f fix comment typos 2014-02-12 15:44:41 +05:00
Danila Shtan cb131836ae remove extra bit in bitmap_pos optimisation
looks like it was added because there was an error in counting last_byte_bit position in cache_mark_blocks()
2014-02-12 15:42:46 +05:00
Danila Shtan 2c6855a969 fix bitmap allocation 2014-02-12 15:37:44 +05:00
Roberto De Ioris 79ca1940de fixed #527 2014-02-12 06:59:24 +01:00
Roberto De Ioris d46879dca9 fixed #528 2014-02-12 06:33:47 +01:00
Roberto De Ioris 9b889f7b77 another spooler-related fix (fd leak) 2014-02-12 06:28:49 +01:00
Roberto De Ioris 1128d09187 fixed #526 2014-02-12 06:05:29 +01:00
Roberto De Ioris d3d4d04fac fixed #524 2014-02-11 06:27:01 +01:00
unbit 4a554db63b Merge pull request #521 from methane/patch-1
logpipe: Don't setsid() twice.
2014-02-10 12:02:27 +01:00
INADA Naoki 8b799b4f9f logpipe: Don't setsid() twice. 2014-02-10 20:00:50 +09:00
Unbit ef17013945 sethostname fix for sun [2] 2014-02-09 07:34:51 +01:00
Unbit a225d53825 sethostname fix for sun 2014-02-09 07:33:31 +01:00
Unbit d4298469ba fixed race condition in u_pypy_thread_attach() 2014-02-08 14:20:49 +01:00
unbit 395de489b8 Merge pull request #518 from xrmx/coverity0802
Some coverity fixes
2014-02-08 13:56:36 +01:00
Riccardo Magliocchetti 6e6efc5605 plugins/logpipe: check setsid return code
Reported by Coverity as CID #1167589
2014-02-08 12:52:20 +01:00
Riccardo Magliocchetti ce260ecbb6 spooler: filename cannot be null
Since it is allocated by uwsgi_malloc.
Reported by Coverity as CID #1153071
2014-02-08 12:49:17 +01:00
Riccardo Magliocchetti e143e25b3c spooler: fix use after free
Reported by Coverity as CID #1153073
2014-02-08 12:45:47 +01:00
Riccardo Magliocchetti e9a58bac46 ssl: avoid null pointer dereference
name is checked not to be null earlier, if it is here just error
out.

Reported by Coverity as CID #1167590
2014-02-08 12:39:58 +01:00
Riccardo Magliocchetti 1448fbc5a3 ssl: Fix fd leak on write error
Reported by Coverity as CID #1167591
2014-02-08 12:36:09 +01:00
Unbit b801f839fc check for heartbeat only if heartneat is enabled 2014-02-06 07:02:58 +01:00
Unbit bcb8321480 improved heartbeat mode 2014-02-06 05:34:29 +01:00
Unbit 5cd9e64073 positive tests for psgi input 2014-02-05 13:40:52 +01:00
Unbit d878b65401 added first round of tests for psgi input with offset 2014-02-05 12:37:46 +01:00
Unbit ded149fc80 fixed perl stacktrace usage 2014-02-05 11:34:14 +01:00
Unbit f041d1095d perl refactoring 2014-02-05 11:21:01 +01:00
unbit 886842de12 Merge pull request #516 from comel/cgi-fix
CGI: remove double header_size check.
2014-02-04 08:18:36 -08:00
Andjelko Horvat b4915f778e CGI: remove double header_size check. 2014-02-04 16:32:36 +01:00
unbit a25e02bbb3 Merge pull request #514 from comel/cgi-fix
CGI: search and set Status header in RFC 3875 compliant way.
2014-02-04 07:13:14 -08:00
Unbit 16aec7c44b fixed sni subscriptions 2014-02-04 14:52:00 +01:00
Andjelko Horvat 42dfa20f27 CGI: search and set Status header in RFC 3875 compliant way. 2014-02-03 12:03:25 +01:00
Unbit 2092050f00 allow building without ssl 2014-02-02 18:54:49 +01:00
Unbit b5a0434710 fixed #513 2014-02-02 04:56:21 +01:00
Unbit 2737cd5c35 improved embedding 2014-01-31 08:55:10 +01:00
Unbit 7a29d9649c added --pypy-paste and paste logging 2014-01-31 08:34:56 +01:00
Unbit 27cc164ebe added --pypy-ini-paste 2014-01-31 08:24:22 +01:00
Unbit 40be8fc916 fixed rpc 2014-01-29 09:08:44 +01:00
Unbit f219afc6e0 start unsubscribed 2014-01-29 08:42:32 +01:00
unbit f20f72ceb1 Merge pull request #509 from xiaost-bytedance/master
[spooler]memory leak bugfix & simplified code
2014-01-28 14:46:54 -08:00
xiaost 6555c2804c simplified the python spooler code 2014-01-29 04:56:54 +08:00
xiaost c05082a8e4 fixed python spooler memory leak 2014-01-29 04:39:51 +08:00
Unbit 62dab40a22 added j magic var 2014-01-23 00:50:28 +01:00
Unbit 02e68ae578 reintroduced no orphans 2014-01-22 15:38:26 +01:00
Unbit ba1fb72427 fixed sni 2014-01-19 13:50:49 +01:00
Unbit df9a76a171 improve dotsplit support 2014-01-19 13:36:21 +01:00
Unbit 98e7e0845d sub-emperor can be loyal 2014-01-19 08:27:05 +01:00
Unbit 6c9f73ae7f added sticky hook 2014-01-18 08:45:55 +01:00
Unbit b12658102d added creat hook 2014-01-18 08:18:10 +01:00
Unbit c51b74a32b improved emperor death procedure 2014-01-16 15:05:22 +01:00
Unbit b0e6d19d5c added --http-server-name-as-http-host 2014-01-16 07:12:56 +01:00
Unbit 7ff3584ad7 imrpvoed ruby1.8.7 support 2014-01-15 17:22:56 +01:00
Unbit 57b6d1f51b spawn without socker when setns is in place 2014-01-14 04:31:18 +01:00
Roberto De Ioris 1646f9c199 fixed notifications 2014-01-13 12:36:08 +01:00
Unbit 260b49c3f6 more clear error report when unix sockets are not removable 2014-01-13 06:38:27 +01:00
Unbit 58af067bef fixed #507 2014-01-13 06:26:07 +01:00
Unbit d1285c6dc4 fixed harakiri tracebacker 2014-01-12 10:25:32 +01:00
Unbit d4e9f3a2d4 allow sni to use stream as certificates 2014-01-12 10:03:01 +01:00
Unbit a15de85811 another refactoring of subscription subsystem 2014-01-12 09:22:10 +01:00
Unbit 4b09ead07d refactored recured subscription system 2014-01-12 09:04:57 +01:00
Unbit 338aca9da5 fixed subscription uid check 2014-01-12 08:17:52 +01:00
Unbit 3f0b9390d9 added subscriptions-sign-skip-uid 2014-01-12 08:01:21 +01:00
Unbit e14b189c77 improved pid namespace daemons 2014-01-11 11:51:44 +01:00
Unbit cabb179a84 minor fix 2014-01-11 10:49:59 +01:00
Unbit ad9b48b69e fixed vars stats item 2014-01-11 10:01:54 +01:00
Unbit 08443d5463 fixed logfile-chown 2014-01-11 07:36:01 +01:00
Unbit 5d11a5cd77 improved legion reload 2014-01-11 07:27:26 +01:00
Unbit 3aba97745c added as-gateway hook 2014-01-11 07:09:18 +01:00
Unbit 0b596bdf42 Merge branch 'master' of https://github.com/unbit/uwsgi 2014-01-09 20:13:42 +01:00
Unbit 4c4b08c36f fixed tuntap netmask 2014-01-09 20:13:23 +01:00
Unbit 1f0827abc8 fixed a busyness bug 2014-01-09 15:42:51 +01:00
Unbit 2ea67c67df notify subscriptions 2014-01-09 13:13:20 +01:00
Unbit 8eebc9f400 allows passing notify object to subscription packets 2014-01-09 12:59:36 +01:00
Unbit 2ad6a1c8e8 prepare for notification socket 2014-01-09 12:43:28 +01:00
Unbit d39d0e8403 updated copyright notes 2014-01-09 05:56:50 +01:00
Unbit 2838fffbde added inject-before and inject-after 2014-01-09 05:12:17 +01:00
Unbit 45bc51541a better to use lstat for inode 2014-01-08 20:06:38 +01:00
Unbit 3427a17191 added %i magic var 2014-01-08 20:03:05 +01:00
Unbit 0cf61abf9d improved ruby builder 2014-01-08 14:35:40 +00:00
Unbit 53fde5fcdd added for-readline 2014-01-08 11:06:29 +01:00
Unbit e81f068e4b a fix from nginx for SNI client authentication 2014-01-08 07:55:46 +01:00
Unbit aaee226183 fix sni subscription 2014-01-08 06:53:09 +01:00
Unbit d7bba38d7a better re-fork management for daemons 2014-01-08 06:20:37 +01:00
Unbit 18fa1172db re-fork on NEWPID daemon usage 2014-01-08 06:17:33 +01:00
Unbit 9e95312169 added ns_pid keyval option for daemons 2014-01-08 06:07:04 +01:00
Unbit 216aff3820 allows fixed binding for resubscription 2014-01-07 15:23:13 +01:00
Unbit eae335a43e added support for yajl 1.0 2014-01-07 09:22:49 +01:00
unbit e0cf245a0e Merge pull request #502 from prymitive/cast_fix
cast internal_counter to expected type
2014-01-05 03:26:51 -08:00
Łukasz Mierzwa d463f9e7d9 cast internal_counter to expected type 2014-01-05 12:19:15 +01:00
Unbit 06c62033dd Merge branch 'master' of https://github.com/unbit/uwsgi 2014-01-05 11:34:51 +01:00
Unbit 72ea5ab54a support embedding external plugins 2014-01-05 11:34:40 +01:00
Roberto De Ioris 843a3b18ad fixed hv_delete on clang 2014-01-05 09:35:49 +01:00
Unbit 37acca060b added --spooler-frequency 2014-01-05 09:19:40 +01:00
Unbit a0ff5b91b8 cast non-bytes arguments to bytes in python3 spool api 2014-01-05 09:08:29 +01:00
Unbit ea19e1e67b perl spool arg must be a hashref 2014-01-05 09:01:17 +01:00
Unbit c20e3fb1a8 fix debug un-needed option in default profile 2014-01-05 08:36:07 +01:00
Unbit a57c2997f4 prepare for 2.0.1 2014-01-05 08:35:33 +01:00
Unbit 3d051e5d79 completed perl spooler support 2014-01-05 08:35:03 +01:00
Unbit 3b0d18c1ec directly call .to_s in the rack spool request 2014-01-05 06:25:31 +01:00
Unbit 89e04c5d17 fixed UWSGI_PROFILE_OVERRIDE 2014-01-05 06:06:47 +01:00
Roberto De Ioris 84ea262203 some minor tycasting fix 2014-01-05 05:22:09 +01:00
Unbit 15fa2be4ee preliminary refactoring for the spooler 2014-01-04 19:28:01 +01:00
Unbit f18ceea9bf fixed resubscription when different sockets type are in place 2014-01-04 10:12:03 +01:00
Unbit e4a993ac31 improved fsmon api 2014-01-04 07:22:20 +01:00
Unbit cf2c20418c implemented hook touch 2014-01-04 06:36:10 +01:00
Unbit d155197d98 added alarm legion action 2014-01-04 06:14:51 +01:00
Unbit fbc1551112 do not forward signature in resubscriptions 2014-01-04 06:09:27 +01:00
Unbit b3bba48d1a add buffer-size configuration to the other routers 2014-01-03 17:24:40 +01:00
Unbit 18972d95a8 improved subscription system 2014-01-03 17:22:23 +01:00
Unbit 8aa8d6070b error check on greenlet error 2014-01-03 15:08:07 +01:00
Unbit 3f0e9f899a fixed daemons touch stop 2014-01-03 12:41:02 +01:00
Unbit 00bf0aa713 improved legion_action api 2014-01-03 11:44:47 +01:00
Unbit 60675724d3 added support for custom log messages in legion actions 2014-01-03 11:05:18 +01:00
Unbit b45deb780d added uwsgi.legion_death_on_lord_error 2014-01-03 10:59:27 +01:00
Unbit 24e144268b announce legion dead on lord hook failure 2014-01-03 10:26:26 +01:00
Unbit b870b8c6d8 fixed json build check for true 2014-01-03 09:24:12 +01:00
Roberto De Ioris 62be7482d4 prepare for touch event 2014-01-03 08:51:23 +01:00
Roberto De Ioris 0c8f473e6f rset fd flags only if close_on_exec2 is enabled 2014-01-02 17:20:52 +01:00
unbit 8b19fd3f94 Merge pull request #498 from kunkku/close-serverfd
core/socket: close TCP server fd when spawning
2014-01-02 08:17:26 -08:00
Kaarle Ritvanen 7553ce3a48 option for closing server sockets when spawning
If server fd is not closed, it is not possible to restart uwsgi if the
spawned process is still running as it keeps the address/port bound.
2014-01-02 12:29:50 +02:00
unbit 9ff67391c0 Merge pull request #499 from kunkku/socket-refactor
core/socket: eliminate some duplicated code from bind_to_* functions
2014-01-01 21:21:03 -08:00
Kaarle Ritvanen 4f4f9b93aa core/socket: move SO_REUSEADDR setting to create_server_socket 2014-01-02 00:51:52 +02:00
Kaarle Ritvanen 51a8f31f17 core/socket: move listen queue size checking to create_server_socket 2014-01-02 00:51:52 +02:00
Kaarle Ritvanen 32b7126836 core/socket: move socket buffer size setting to create_server_socket 2014-01-02 00:47:22 +02:00
Kaarle Ritvanen 4d43a66581 core/socket: common socket creation function for bind_to_* 2014-01-02 00:08:32 +02:00
Unbit 0f95ef6d5a added alarm-metric alias 2013-12-31 12:36:07 +01:00
Unbit c0c43a7d47 added --alarm-backlog 2013-12-31 12:09:32 +01:00
Unbit 4361ef2dc6 more hooks 2013-12-31 09:24:23 +01:00
Unbit b7298aba85 more straight ruby lib detection 2013-12-30 16:43:02 +01:00
Unbit 0d4172a271 prepare for 2.0 2013-12-30 09:44:59 +01:00
Unbit e842a181aa fixed #478 2013-12-30 06:44:54 +01:00
Unbit 1ba0935579 fixed lua prepare_headers 2013-12-28 18:39:30 +01:00
unbit 920d1e5cfe Merge pull request #497 from xrmx/coverity2812
More coverity fixes
2013-12-28 09:28:31 -08:00
Riccardo Magliocchetti 473b4f1e57 plugins/lua: check return value of uwsgi_response_prepare_headers
Reported by Coverity as CID #1100802
2013-12-28 16:11:59 +01:00
Riccardo Magliocchetti b5c19bc1f8 plugins/php: check return value of uwsgi_response_prepare_headers
Reported by Coverity as CID #1100794
2013-12-28 16:06:58 +01:00
Riccardo Magliocchetti 79222adfe7 plugins/sslrouter: check return value of uwsgi_cr_set_hooks
Reported by Coverity as CID #971229
2013-12-28 15:56:46 +01:00
Riccardo Magliocchetti 8b90efc567 plugins/http: check return value of uwsgi_cr_set_hooks
Reported by Coverity as CID #970970
2013-12-28 15:54:59 +01:00
Riccardo Magliocchetti 4667eedc2b core/static: check return value of uwsgi_response_prepare_headers
Reported by Coverity as CID #970965
2013-12-28 15:49:04 +01:00
Riccardo Magliocchetti 752252c9e4 core/emperor: check return value of uwsgi_stats_str
Reported by Coverity as CID #970959
2013-12-28 15:45:05 +01:00
Unbit 6d91b7317d try to address a strange crash 2013-12-28 07:10:23 +01:00
unbit cddd1148fd Merge pull request #496 from xrmx/coverity2712
More Coverity fixes
2013-12-27 18:02:23 -08:00
Riccardo Magliocchetti c2096e8373 plugins/python: check return value of bind to unix
Reported by Coverity as CID #995784
2013-12-27 19:25:00 +01:00
Riccardo Magliocchetti 4f57ef33af Revert "yaml: fix memory leak"
This reverts commit ba3ac9ad09.

Since it looks like add_export_option does not copy the string we
shouldn't free it.
2013-12-27 19:16:59 +01:00
Riccardo Magliocchetti aa34beade1 core/legion: fix memory leak
Reported by coverity as CID #971022.
2013-12-27 19:09:49 +01:00
Riccardo Magliocchetti 1149e60125 core/subscription: fix memory leak
Reported by Coverity as CID #971040.
2013-12-27 19:06:12 +01:00
Riccardo Magliocchetti 7def85636e linux_ns: fix memory leak
Reported by Coverity as CID #971052.
2013-12-27 18:53:49 +01:00
Riccardo Magliocchetti d44692b268 plugins/xslt: fix compilation
After 594880fb46
2013-12-27 18:50:46 +01:00
Riccardo Magliocchetti 46322b84b4 plugins/python: fix memory leak
Reported by Coverity as CID #971056
2013-12-27 18:45:44 +01:00
Riccardo Magliocchetti 5785c61a13 core/legion: fix memory leak
Reported by Coverity as CID #1010086
2013-12-27 18:24:02 +01:00
Riccardo Magliocchetti 594880fb46 plugins/xslt: fix memory leak on error path
Reported by Coverity as CID #1125165
2013-12-27 18:17:49 +01:00
Unbit 4373306f78 added --declare-option2 2013-12-27 10:45:41 +01:00
82 changed files with 2803 additions and 1385 deletions
+1
View File
@@ -25,3 +25,4 @@ Mingli Yuan
Natanael Copa
Roberto Leandrini
Ryan Petrello
Danila Shtan <danila@shtan.ru>
+1 -1
View File
@@ -2,7 +2,7 @@
*** mod_proxy_uwsgi ***
Copyright 2009-2013 Unbit S.a.s. <info@unbit.it>
Copyright 2009-2014 Unbit S.a.s. <info@unbit.it>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
+1 -1
View File
@@ -2,7 +2,7 @@
*** uWSGI/mod_uwsgi ***
Copyright 2009-2013 Unbit S.a.s. <info@unbit.it>
Copyright 2009-2014 Unbit S.a.s. <info@unbit.it>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
-1
View File
@@ -1,4 +1,3 @@
[uwsgi]
main_plugin = python,gevent
inherit = base
debug = false
+18
View File
@@ -387,6 +387,23 @@ end:
}
static int uwsgi_async_wait_milliseconds_hook(int timeout) {
struct wsgi_request *wsgi_req = current_wsgi_req();
timeout = timeout / 1000;
if (!timeout) timeout = 1;
async_add_timeout(wsgi_req, timeout);
wsgi_req->async_force_again = 1;
if (uwsgi.schedule_to_main) {
uwsgi.schedule_to_main(wsgi_req);
}
if (wsgi_req->async_timed_out) {
wsgi_req->async_timed_out = 0;
return 0;
}
return -1;
}
void async_loop() {
if (uwsgi.async < 2) {
@@ -414,6 +431,7 @@ void async_loop() {
uwsgi.wait_write_hook = async_wait_fd_write;
uwsgi.wait_read_hook = async_wait_fd_read;
uwsgi.wait_read2_hook = async_wait_fd_read2;
uwsgi.wait_milliseconds_hook = uwsgi_async_wait_milliseconds_hook;
if (uwsgi.signal_socket > -1) {
event_queue_add_fd_read(uwsgi.async_queue, uwsgi.signal_socket);
+102 -84
View File
@@ -32,7 +32,7 @@ static uint64_t uwsgi_cache_find_free_blocks(struct uwsgi_cache *uc, uint64_t ne
// which is the first free bit?
uint64_t bitmap_byte = 0;
uint8_t bitmap_bit = 0;
if (uc->blocks_bitmap_pos > 0) {
bitmap_byte = uc->blocks_bitmap_pos/8;
bitmap_bit = uc->blocks_bitmap_pos % 8;
@@ -45,6 +45,8 @@ static uint64_t uwsgi_cache_find_free_blocks(struct uwsgi_cache *uc, uint64_t ne
uint64_t j;
uint64_t found = 0;
uint64_t need_to_scan = uc->blocks_bitmap_size;
// we make an addition round for the corner case of a single byte map not starting from 0
if (bitmap_bit > 0) need_to_scan++;
j = bitmap_byte;
//uwsgi_log("start scanning %llu bytes starting from %llu need: %llu\n", (unsigned long long) need_to_scan, (unsigned long long) bitmap_byte, (unsigned long long) needed_blocks);
while(need_to_scan) {
@@ -73,7 +75,9 @@ static uint64_t uwsgi_cache_find_free_blocks(struct uwsgi_cache *uc, uint64_t ne
}
found++;
if (found == needed_blocks) {
//printf("found %llu consecutive bit starting from byte %llu\n", found, base);
#ifdef UWSGI_DEBUG
printf("found %llu consecutive bit starting from byte %llu\n", (unsigned long long) found, (unsigned long long) base);
#endif
return ((base*8) + base_bit);
}
}
@@ -82,12 +86,14 @@ static uint64_t uwsgi_cache_find_free_blocks(struct uwsgi_cache *uc, uint64_t ne
}
j++;
need_to_scan--;
// check for overlap
if (j >= need_to_scan) {
// check for overlap (that is not supported)
if (j >= uc->blocks_bitmap_size) {
j = 0;
found = 0;
base = 0xffffffffffffffffLLU;
base_bit = 0;
// we use bitmap_bit only at the first round
bitmap_bit = 0;
}
}
@@ -102,19 +108,27 @@ static uint64_t cache_mark_blocks(struct uwsgi_cache *uc, uint64_t index, uint64
uint64_t first_byte = index/8;
uint8_t first_byte_bit = index % 8;
uint64_t last_byte = (index+needed_blocks)/8;
uint8_t last_byte_bit = (index+needed_blocks) % 8;
// offset starts with 0, so actual last bit is index + needed_blocks - 1
uint64_t last_byte = (index + needed_blocks - 1) / 8;
uint8_t last_byte_bit = (index + needed_blocks - 1) % 8;
uint64_t needed_bytes = (last_byte - first_byte) + 1;
//uwsgi_log("%llu %u %llu %u\n", first_byte, first_byte_bit, last_byte, last_byte_bit);
uint8_t mask = 0xff >> first_byte_bit;
if (needed_bytes == 1) {
// kinda hacky, but it does the job
mask >>= (7 - last_byte_bit);
mask <<= (7 - last_byte_bit);
}
uc->blocks_bitmap[first_byte] |= mask;
uint64_t needed_bytes = (last_byte - first_byte)+1;
if (needed_bytes > 1) {
mask = 0xff << (8 - last_byte_bit);
uc->blocks_bitmap[last_byte-1] |= mask;
mask = 0xff << (7 - last_byte_bit);
uc->blocks_bitmap[last_byte] |= mask;
}
if (needed_bytes > 2) {
@@ -130,19 +144,28 @@ static void cache_unmark_blocks(struct uwsgi_cache *uc, uint64_t index, uint64_t
uint64_t first_byte = index/8;
uint8_t first_byte_bit = index % 8;
uint64_t last_byte = (index+needed_blocks)/8;
uint8_t last_byte_bit = (index+needed_blocks) % 8;
// offset starts with 0, so actual last bit is index + needed_blocks - 1
uint64_t last_byte = (index + needed_blocks - 1)/8;
uint8_t last_byte_bit = (index + needed_blocks - 1) % 8;
// here we use XOR (0+0 = 0 | 1+0 = 1 | 0+1 = 1| 1+1 = 0|
uint64_t needed_bytes = (last_byte - first_byte) + 1;
uint8_t mask = 0xff >> first_byte_bit;
uc->blocks_bitmap[first_byte] ^= mask;
uint8_t mask = 0xff >> first_byte_bit;
uint64_t needed_bytes = (last_byte - first_byte)+1;
if (needed_bytes == 1) {
// kinda hacky, but it does the job
mask >>= (7 - last_byte_bit);
mask <<= (7 - last_byte_bit);
}
// here we use AND (0+0 = 0 | 1+0 = 0 | 0+1 = 0| 1+1 = 1)
// 0 in mask means "unmark", 1 in mask means "do not change"
// so we need to invert the mask
uc->blocks_bitmap[first_byte] &= ~mask;
if (needed_bytes > 1) {
mask = 0xff << (8 - last_byte_bit);
uc->blocks_bitmap[last_byte-1] ^= mask;
mask = 0xff << (7 - last_byte_bit);
uc->blocks_bitmap[last_byte] &= ~mask;
}
if (needed_bytes > 2) {
@@ -283,16 +306,24 @@ next2:
void uwsgi_cache_init(struct uwsgi_cache *uc) {
uc->hashtable = uwsgi_calloc_shared(sizeof(uint64_t) * uc->hashsize);
uc->unused_blocks_stack = uwsgi_calloc_shared(sizeof(uint64_t) * uc->blocks);
// the first cache item is always zero
uc->first_available_block = 1;
uc->unused_blocks_stack = uwsgi_calloc_shared(sizeof(uint64_t) * uc->max_items);
uc->unused_blocks_stack_ptr = 0;
uc->filesize = ( (sizeof(struct uwsgi_cache_item)+uc->keysize) * uc->max_items) + (uc->blocksize * uc->blocks);
uint64_t i;
for (i = 1; i < uc->max_items; i++) {
uc->unused_blocks_stack_ptr++;
uc->unused_blocks_stack[uc->unused_blocks_stack_ptr] = i;
}
if (uc->use_blocks_bitmap) {
uc->blocks_bitmap_size = uc->blocks/8;
if (uc->blocks % 8 > 0) uc->blocks_bitmap_size++;
uint8_t m = uc->blocks % 8;
if (m > 0) uc->blocks_bitmap_size++;
uc->blocks_bitmap = uwsgi_calloc_shared(uc->blocks_bitmap_size);
if (m > 0) {
uc->blocks_bitmap[uc->blocks_bitmap_size-1] = 0xff >> m;
}
}
//uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
@@ -361,7 +392,7 @@ void uwsgi_cache_init(struct uwsgi_cache *uc) {
uc->name,
(unsigned long long) uc->filesize / (1024 * 1024),
(unsigned long long) sizeof(struct uwsgi_cache_item)+uc->keysize,
(unsigned long long) ((sizeof(struct uwsgi_cache_item)+uc->keysize) * uc->max_items), (unsigned long long) (uc->blocksize * uc->max_items),
(unsigned long long) ((sizeof(struct uwsgi_cache_item)+uc->keysize) * uc->max_items), (unsigned long long) (uc->blocksize * uc->blocks),
(unsigned long long) uc->blocks_bitmap_size);
uwsgi_cache_setup_nodes(uc);
@@ -523,50 +554,52 @@ char *uwsgi_cache_get4(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint6
int uwsgi_cache_del2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint64_t index, uint16_t flags) {
struct uwsgi_cache_item *uci;
int ret = -1;
if (!index)
index = uwsgi_cache_get_index(uc, key, keylen);
if (!index) index = uwsgi_cache_get_index(uc, key, keylen);
if (index) {
uci = cache_item(index);
if (uci->keysize > 0) {
// unmark blocks
if (uc->blocks_bitmap) cache_unmark_blocks(uc, uci->first_block, uci->valsize);
// put back the block in unused stack
uc->unused_blocks_stack_ptr++;
uc->unused_blocks_stack[uc->unused_blocks_stack_ptr] = index;
// unlink prev and next (if any)
if (uci->prev) {
struct uwsgi_cache_item *ucii = cache_item(uci->prev);
ucii->next = uci->next;
}
else {
// set next as the new entry point (could be 0)
uc->hashtable[uci->hash % uc->hashsize] = uci->next;
}
if (uci->next) {
struct uwsgi_cache_item *ucii = cache_item(uci->next);
ucii->prev = uci->prev;
}
if (!uci->prev && !uci->next) {
// reset hashtable entry
uc->hashtable[uci->hash % uc->hashsize] = 0;
}
uc->n_items--;
}
ret = 0;
uci->keysize = 0;
uci->valsize = 0;
uc->unused_blocks_stack_ptr++;
uc->unused_blocks_stack[uc->unused_blocks_stack_ptr] = index;
// unmark blocks
if (uc->blocks_bitmap) {
cache_unmark_blocks(uc, uci->first_block, uci->valsize);
}
ret = 0;
// relink collisioned entry
if (uci->prev) {
struct uwsgi_cache_item *ucii = cache_item(uci->prev);
ucii->next = uci->next;
}
else {
// set next as the new entry point (could be 0)
uc->hashtable[uci->hash % uc->hashsize] = uci->next;
}
if (uci->next) {
struct uwsgi_cache_item *ucii = cache_item(uci->next);
ucii->prev = uci->prev;
}
if (!uci->prev && !uci->next) {
// reset hashtable entry
//uwsgi_log("!!! resetted hashtable entry !!!\n");
uc->hashtable[uci->hash % uc->hashsize] = 0;
}
uci->hash = 0;
uci->prev = 0;
uci->next = 0;
uci->expires = 0;
uc->n_items--;
if (uc->use_last_modified) {
uc->last_modified_at = uwsgi_now();
}
@@ -584,7 +617,10 @@ void uwsgi_cache_fix(struct uwsgi_cache *uc) {
uint64_t i;
unsigned long long restored = 0;
for (i = 0; i < uc->max_items; i++) {
// reset unused blocks
uc->unused_blocks_stack_ptr = 0;
for (i = 1; i < uc->max_items; i++) {
// valid record ?
struct uwsgi_cache_item *uci = cache_item(i);
if (uci->keysize) {
@@ -596,7 +632,6 @@ void uwsgi_cache_fix(struct uwsgi_cache *uc) {
}
else {
// put this record in unused stack
uc->first_available_block = i;
uc->unused_blocks_stack_ptr++;
uc->unused_blocks_stack[uc->unused_blocks_stack_ptr] = i;
}
@@ -613,7 +648,6 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
struct uwsgi_cache_item *uci, *ucii;
// used to reset key allocation in bitmap mode
uint8_t rollback_mode = 0;
int ret = -1;
time_t now = 0;
@@ -631,24 +665,14 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
//uwsgi_log("putting cache data in key %.*s %d\n", keylen, key, vallen);
index = uwsgi_cache_get_index(uc, key, keylen);
if (!index) {
if (uc->first_available_block >= uc->max_items && !uc->unused_blocks_stack_ptr) {
if (!uc->unused_blocks_stack_ptr) {
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
uc->full++;
goto end;
}
if (uc->unused_blocks_stack_ptr) {
//uwsgi_log("!!! REUSING CACHE SLOT !!! (faci: %llu)\n", (unsigned long long) uwsgi.shared->cache_first_available_block);
index = uc->unused_blocks_stack[uc->unused_blocks_stack_ptr];
uc->unused_blocks_stack_ptr--;
}
else {
rollback_mode = 1;
index = uc->first_available_block;
if (uc->first_available_block < uc->max_items) {
rollback_mode = 2;
uc->first_available_block++;
}
}
index = uc->unused_blocks_stack[uc->unused_blocks_stack_ptr];
uc->unused_blocks_stack_ptr--;
uci = cache_item(index);
if (!uc->blocks_bitmap) {
@@ -656,26 +680,20 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
}
else {
uci->first_block = uwsgi_cache_find_free_blocks(uc, vallen);
//uwsgi_log("first block = %llu\n", uci->first_block);
if (uci->first_block == 0xffffffffffffffffLLU) {
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
uc->full++;
if (rollback_mode == 0) {
uc->unused_blocks_stack_ptr++;
}
else if (rollback_mode == 2) {
uc->first_available_block--;
}
uc->unused_blocks_stack_ptr++;
goto end;
}
// mark used blocks;
uint64_t needed_blocks = cache_mark_blocks(uc, uci->first_block, vallen);
// optimize the scan
if (uc->blocks_bitmap_pos + (needed_blocks+1) > uc->blocks) {
if (uc->blocks_bitmap_pos + needed_blocks > uc->blocks) {
uc->blocks_bitmap_pos = 0;
}
else {
uc->blocks_bitmap_pos = uci->first_block + needed_blocks + 1;
uc->blocks_bitmap_pos = uci->first_block + needed_blocks;
}
}
if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) {
@@ -763,14 +781,14 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
// mark used blocks;
uint64_t needed_blocks = cache_mark_blocks(uc, uci->first_block, vallen);
// optimize the scan
if (uc->blocks_bitmap_pos + (needed_blocks+1) > uc->blocks) {
if (uc->blocks_bitmap_pos + needed_blocks > uc->blocks) {
uc->blocks_bitmap_pos = 0;
}
else {
uc->blocks_bitmap_pos = uci->first_block + needed_blocks + 1;
uc->blocks_bitmap_pos = uci->first_block + needed_blocks;
}
// unmark the old blocks
cache_unmark_blocks(uc, uci->first_block, uci->valsize);
cache_unmark_blocks(uc, old_first_block, uci->valsize);
}
if ( !(flags & UWSGI_CACHE_FLAG_MATH)) {
memcpy(((char *) uc->data) + (uci->first_block * uc->blocksize), val, vallen);
@@ -1788,7 +1806,7 @@ int uwsgi_cache_magic_clear(char *cache) {
if (uc) {
uint64_t i;
uwsgi_wlock(uc->lock);
for (i = 1; i < uwsgi.caches->max_items; i++) {
for (i = 1; i < uc->max_items; i++) {
if (uwsgi_cache_del2(uc, NULL, 0, i, 0)) {
uwsgi_rwunlock(uc->lock);
return -1;
+18 -1
View File
@@ -81,6 +81,22 @@ int uwsgi_logic_opt_for_glob(char *key, char *value) {
return 1;
}
int uwsgi_logic_opt_for_readline(char *key, char *value) {
char line[1024];
FILE *fh = fopen(uwsgi.logic_opt_data, "r");
if (fh) {
while (fgets(line, 1024, fh)) {
add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi_chomp(uwsgi_str(line))), 0);
}
fclose(fh);
return 1;
}
uwsgi_error_open(uwsgi.logic_opt_data);
return 0;
}
int uwsgi_logic_opt_for_times(char *key, char *value) {
int num = atoi(uwsgi.logic_opt_data);
@@ -384,7 +400,8 @@ void add_exported_option_do(char *key, char *value, int configured, int placehol
if (uwsgi.logic_opt_running)
goto add;
if (!strcmp(key, "end") || !strcmp(key, "endfor") || !strcmp(key, "endif")) {
if (!strcmp(key, "end") || !strcmp(key, "endfor") || !strcmp(key, "endif")
|| !strcmp(key, "end-if") || !strcmp(key, "end-for")) {
if (uwsgi.logic_opt_data) {
free(uwsgi.logic_opt_data);
}
+60 -15
View File
@@ -55,7 +55,7 @@ void uwsgi_daemons_smart_check() {
if (ud->pid > 0) {
if (!kill(ud->pid, 0)) {
uwsgi_log("[uwsgi_daemons] stopping legion \"%s\" daemon: %s (pid: %d)\n", ud->legion, ud->command, ud->pid);
kill(-ud->pid, ud->stop_signal);
kill(-(ud->pid), ud->stop_signal);
}
else {
// pid already died
@@ -237,12 +237,12 @@ void uwsgi_detach_daemons() {
time_t timeout = uwsgi_now() + (uwsgi.reload_mercy ? uwsgi.reload_mercy : 3);
int waitpid_status;
while (!kill(ud->pid, 0)) {
kill(-ud->pid, ud->stop_signal);
kill(-(ud->pid), ud->stop_signal);
sleep(1);
waitpid(-ud->pid, &waitpid_status, WNOHANG);
waitpid(ud->pid, &waitpid_status, WNOHANG);
if (uwsgi_now() >= timeout) {
uwsgi_log("[uwsgi-daemons] daemon did not die in time, killing (pid: %d): %s\n", (int) ud->pid, ud->command);
kill(-ud->pid, SIGKILL);
kill(-(ud->pid), SIGKILL);
break;
}
}
@@ -253,18 +253,19 @@ void uwsgi_detach_daemons() {
}
}
static int daemon_spawn(void *);
void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
// skip unregistered daemons
if (!ud->registered) return;
int throttle = 0;
ud->throttle = 0;
if (uwsgi.current_time - ud->last_spawn <= 3) {
throttle = ud->respawns - (uwsgi.current_time - ud->last_spawn);
ud->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;
if (ud->throttle <= 0) ud->throttle = 1;
}
pid_t pid = uwsgi_fork("uWSGI external daemon");
@@ -291,6 +292,50 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
uwsgi_close_all_sockets();
uwsgi_close_all_fds();
#if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL) && defined(CLONE_NEWPID)
if (ud->ns_pid) {
// we need to create a new session
if (setsid() < 0) {
uwsgi_error("setsid()");
exit(1);
}
// avoid the need to set stop_signal in attach-daemon2
signal(SIGTERM, end_me);
char stack[PTHREAD_STACK_MIN];
pid_t pid = clone((int (*)(void *))daemon_spawn, stack + PTHREAD_STACK_MIN, SIGCHLD | CLONE_NEWPID, (void *) ud);
if (pid > 0) {
#ifdef PR_SET_PDEATHSIG
if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) {
uwsgi_error("uwsgi_spawn_daemon()/prctl()");
}
#endif
// block all signals except SIGTERM
sigset_t smask;
sigfillset(&smask);
sigdelset(&smask, SIGTERM);
sigprocmask(SIG_BLOCK, &smask, NULL);
int status;
if (waitpid(pid, &status, 0) < 0) {
uwsgi_error("uwsgi_spawn_daemon()/waitpid()");
}
_exit(0);
}
uwsgi_error("uwsgi_spawn_daemon()/clone()");
exit(1);
}
#endif
daemon_spawn((void *) ud);
}
}
static int daemon_spawn(void *arg) {
struct uwsgi_daemon *ud = (struct uwsgi_daemon *) arg;
if (ud->gid) {
if (setgid(ud->gid)) {
uwsgi_error("uwsgi_spawn_daemon()/setgid()");
@@ -307,7 +352,7 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
if (ud->daemonize) {
/* refork... */
pid = fork();
pid_t pid = fork();
if (pid < 0) {
uwsgi_error("fork()");
exit(1);
@@ -329,7 +374,7 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
}
if (!ud->pidfile) {
#ifdef __linux__
#ifdef PR_SET_PDEATHSIG
if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) {
uwsgi_error("prctl()");
}
@@ -337,9 +382,9 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
}
if (throttle) {
uwsgi_log("[uwsgi-daemons] throttling \"%s\" for %d seconds\n", ud->command, throttle);
sleep((unsigned int) throttle);
if (ud->throttle) {
uwsgi_log("[uwsgi-daemons] throttling \"%s\" for %d seconds\n", ud->command, ud->throttle);
sleep((unsigned int) ud->throttle);
}
uwsgi_log("[uwsgi-daemons] %sspawning \"%s\" (uid: %d gid: %d)\n", ud->respawns > 0 ? "re" : "", ud->command, (int) getuid(), (int) getgid());
@@ -348,9 +393,6 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
// never here;
exit(1);
}
return;
}
@@ -454,6 +496,7 @@ void uwsgi_opt_add_daemon2(char *opt, char *value, void *none) {
char *d_stdin = NULL;
char *d_uid = NULL;
char *d_gid = NULL;
char *d_ns_pid = NULL;
char *arg = uwsgi_str(value);
@@ -474,6 +517,7 @@ void uwsgi_opt_add_daemon2(char *opt, char *value, void *none) {
"stdin", &d_stdin,
"uid", &d_uid,
"gid", &d_gid,
"ns_pid", &d_ns_pid,
NULL)) {
uwsgi_log("invalid --%s keyval syntax\n", opt);
exit(1);
@@ -519,6 +563,7 @@ void uwsgi_opt_add_daemon2(char *opt, char *value, void *none) {
#ifdef UWSGI_SSL
uwsgi_ud->legion = d_legion;
#endif
uwsgi_ud->ns_pid = d_ns_pid ? 1 : 0;
if (d_touch) {
size_t i,rlen = 0;
+58 -4
View File
@@ -18,6 +18,8 @@ int emperor_throttle_level;
struct uwsgi_instance *ui;
time_t on_royal_death = 0;
/*
blacklist subsystem
@@ -482,6 +484,10 @@ void uwsgi_register_imperial_monitor(char *name, void (*init) (struct uwsgi_empe
// the sad death of an Emperor
static void royal_death(int signum) {
if (on_royal_death) {
uwsgi_log("[emperor] *** RAGNAROK ALREADY EVOKED (mercyless in %d seconds)***\n", uwsgi.reload_mercy - (uwsgi_now() - on_royal_death));
return;
}
struct uwsgi_instance *c_ui = ui->ui_next;
@@ -502,8 +508,14 @@ static void royal_death(int signum) {
}
uwsgi_log("[emperor] *** RAGNAROK EVOKED ***\n");
uwsgi_notify("The Emperor is buried.");
exit(0);
while (c_ui) {
emperor_stop(c_ui);
c_ui = c_ui->ui_next;
}
if (!uwsgi.reload_mercy) uwsgi.reload_mercy = 30;
on_royal_death = uwsgi_now();
}
// massive reload of vassals
@@ -1520,8 +1532,43 @@ void emperor_loop() {
int freq = 0;
uwsgi_hooks_run(uwsgi.hook_emperor_start, "emperor-start", 1);
// signal parent-Emperor about my loyalty
if (uwsgi.has_emperor && !uwsgi.loyal) {
uwsgi_log("announcing my loyalty to the Emperor...\n");
char byte = 17;
if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
uwsgi_error("write()");
}
uwsgi.loyal = 1;
}
for (;;) {
if (on_royal_death) {
if (!ui->ui_next) break;
if (uwsgi_now() - on_royal_death >= uwsgi.reload_mercy) {
ui_current = ui->ui_next;
while (ui_current) {
uwsgi_log_verbose("[emperor] NO MERCY for vassal %s !!!\n", ui_current->name);
kill(ui_current->pid, SIGKILL);
ui_current = ui_current->ui_next;
}
break;
}
ui_current = ui->ui_next;
while (ui_current) {
struct uwsgi_instance *dead_vassal = ui_current;
ui_current = ui_current->ui_next;
pid_t dead_pid = waitpid(dead_vassal->pid, &waitpid_status, WNOHANG);
if (dead_pid > 0 || dead_pid < 0) {
emperor_del(dead_vassal);
}
}
sleep(1);
continue;
}
if (!i_am_alone) {
diedpid = waitpid(uwsgi.emperor_pid, &waitpid_status, WNOHANG);
@@ -1612,6 +1659,9 @@ void emperor_loop() {
ui_current = ui->ui_next;
while (ui_current) {
if (ui_current->last_heartbeat > 0) {
#ifdef UWSGI_DEBUG
uwsgi_log("%d %d %d %d\n", ui_current->last_heartbeat, uwsgi.emperor_heartbeat, ui_current->last_heartbeat + uwsgi.emperor_heartbeat, uwsgi_now());
#endif
if ((ui_current->last_heartbeat + uwsgi.emperor_heartbeat) < uwsgi_now()) {
uwsgi_log("[emperor] vassal %s sent no heartbeat in last %d seconds, brutally respawning it...\n", ui_current->name, uwsgi.emperor_heartbeat);
// set last_heartbeat to 0 avoiding races
@@ -1705,6 +1755,10 @@ void emperor_loop() {
}
uwsgi_log_verbose("The Emperor is buried.\n");
uwsgi_notify("The Emperor is buried.");
exit(0);
}
void emperor_send_stats(int fd) {
@@ -1746,7 +1800,8 @@ void emperor_send_stats(int fd) {
goto end0;
struct uwsgi_emperor_scanner *ues = emperor_scanners;
while (ues) {
uwsgi_stats_str(us, ues->arg);
if (uwsgi_stats_str(us, ues->arg))
goto end0;
ues = ues->next;
if (ues) {
if (uwsgi_stats_comma(us))
@@ -1994,7 +2049,6 @@ next:
uwsgi.has_emperor = 1;
uwsgi.emperor_fd = atoi(emperor_env);
uwsgi.master_process = 1;
uwsgi.no_orphans = 1;
uwsgi_log("*** has_emperor mode detected (fd: %d) ***\n", uwsgi.emperor_fd);
if (getenv("UWSGI_EMPEROR_FD_CONFIG")) {
+137 -162
View File
@@ -8,207 +8,182 @@ extern struct uwsgi_server uwsgi;
#endif
#endif
void uwsgi_fsmon_setup() {
struct uwsgi_string_list *usl = uwsgi.fs_reload;
while(usl) {
if (uwsgi_register_fsmon(usl)) {
uwsgi_log("[uwsgi-fsmon] unable to register monitor for \"%s\"\n", usl->value);
}
else {
uwsgi_log("[uwsgi-fsmon] registered monitor for \"%s\"\n", usl->value);
}
usl = usl->next;
}
usl = uwsgi.fs_brutal_reload;
while(usl) {
if (uwsgi_register_fsmon(usl)) {
uwsgi_log("[uwsgi-fsmon] unable to register monitor for \"%s\"\n", usl->value);
}
else {
uwsgi_log("[uwsgi-fsmon] registered monitor for \"%s\"\n", usl->value);
}
usl = usl->next;
}
usl = uwsgi.fs_signal;
while(usl) {
char *copy = uwsgi_str(usl->value);
char *space = strchr(copy, ' ');
if (!space) {
uwsgi_log("[uwsgi-fsmon] invalid syntax: \"%s\"\n", usl->value);
free(copy);
goto next;
}
*space = 0;
usl->value = copy;
usl->len = strlen(copy);
usl->custom_ptr = space+1;
if (uwsgi_register_fsmon(usl)) {
uwsgi_log("[uwsgi-fsmon] unable to register monitor for \"%s\"\n", usl->value);
}
else {
uwsgi_log("[uwsgi-fsmon] registered monitor for \"%s\"\n", usl->value);
}
next:
usl = usl->next;
}
}
int uwsgi_register_fsmon(struct uwsgi_string_list *usl) {
static int fsmon_add(struct uwsgi_fsmon *fs) {
#ifdef UWSGI_EVENT_FILEMONITOR_USE_INOTIFY
#ifndef OBSOLETE_LINUX_KERNEL
static int inotify_fd = -1;
if (inotify_fd == -1) {
inotify_fd = inotify_init();
if (inotify_fd < 0) {
uwsgi_error("uwsgi_register_fsmon()/inotify_init()");
uwsgi_error("fsmon_add()/inotify_init()");
return -1;
}
if (event_queue_add_fd_read(uwsgi.master_queue, inotify_fd)) {
uwsgi_error("uwsgi_register_fsmon()/event_queue_add_fd_read()");
uwsgi_error("fsmon_add()/event_queue_add_fd_read()");
return -1;
}
}
int wd = inotify_add_watch(inotify_fd, usl->value, IN_ATTRIB | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_MOVED_FROM | IN_MOVED_TO);
int wd = inotify_add_watch(inotify_fd, fs->path, IN_ATTRIB | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_MOVED_FROM | IN_MOVED_TO);
if (wd < 0) {
uwsgi_error("uwsgi_register_fsmon()/inotify_add_watch()");
uwsgi_error("fsmon_add()/inotify_add_watch()");
return -1;
}
usl->custom = inotify_fd;
usl->custom2 = wd;
fs->fd = inotify_fd;
fs->id = wd;
return 0;
#endif
#endif
#ifdef UWSGI_EVENT_FILEMONITOR_USE_KQUEUE
struct kevent kev;
int fd = open(usl->value, O_RDONLY);
if (fd < 0) {
uwsgi_error_open(usl->value);
uwsgi_error("uwsgi_register_fsmon()/open()");
return -1;
}
struct kevent kev;
int fd = open(fs->path, O_RDONLY);
if (fd < 0) {
uwsgi_error_open(fs->path);
uwsgi_error("fsmon_add()/open()");
return -1;
}
EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE | NOTE_DELETE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE, 0, 0);
if (kevent(uwsgi.master_queue, &kev, 1, NULL, 0, NULL) < 0) {
uwsgi_error("uwsgi_register_fsmon()/kevent()");
return -1;
}
usl->custom = fd;
usl->custom2 = fd;
EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE | NOTE_DELETE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE, 0, 0);
if (kevent(uwsgi.master_queue, &kev, 1, NULL, 0, NULL) < 0) {
uwsgi_error("fsmon_add()/kevent()");
return -1;
}
fs->fd = fd;
return 0;
#endif
uwsgi_log("[uwsgi-fsmon] filesystem monitoring interface not available in this platform !!!\n");
return 1;
}
static struct uwsgi_string_list *uwsgi_fsmon_ack(int interesting_fd) {
int found_fd = -1;
struct uwsgi_string_list *usl = uwsgi.fs_reload;
while(usl) {
if ((int)usl->custom == interesting_fd) {
found_fd = usl->custom;
goto found;
}
usl = usl->next;
static void fsmon_reload(struct uwsgi_fsmon *fs) {
uwsgi_block_signal(SIGHUP);
grace_them_all(0);
uwsgi_unblock_signal(SIGHUP);
}
static void fsmon_brutal_reload(struct uwsgi_fsmon *fs) {
if (uwsgi.die_on_term) {
uwsgi_block_signal(SIGQUIT);
reap_them_all(0);
uwsgi_unblock_signal(SIGQUIT);
}
usl = uwsgi.fs_brutal_reload;
while(usl) {
if ((int)usl->custom == interesting_fd) {
found_fd = usl->custom;
goto found;
}
usl = usl->next;
}
usl = uwsgi.fs_signal;
while(usl) {
if ((int)usl->custom == interesting_fd) {
found_fd = usl->custom;
goto found;
}
usl = usl->next;
}
found:
if (found_fd == -1) return NULL;
else {
uwsgi_block_signal(SIGTERM);
reap_them_all(0);
uwsgi_unblock_signal(SIGTERM);
}
}
static void fsmon_signal(struct uwsgi_fsmon *fs) {
uwsgi_route_signal(atoi((char *) fs->data));
}
void uwsgi_fsmon_setup() {
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.fs_reload) {
uwsgi_register_fsmon(usl->value, fsmon_reload, NULL);
}
uwsgi_foreach(usl, uwsgi.fs_brutal_reload) {
uwsgi_register_fsmon(usl->value, fsmon_brutal_reload, NULL);
}
uwsgi_foreach(usl, uwsgi.fs_signal) {
char *copy = uwsgi_str(usl->value);
char *space = strchr(copy, ' ');
if (!space) {
uwsgi_log("[uwsgi-fsmon] invalid syntax: \"%s\"\n", usl->value);
free(copy);
continue;
}
*space = 0;
uwsgi_register_fsmon(copy, fsmon_signal, space + 1);
}
struct uwsgi_fsmon *fs = uwsgi.fsmon;
while (fs) {
if (fsmon_add(fs)) {
uwsgi_log("[uwsgi-fsmon] unable to register monitor for \"%s\"\n", fs->path);
}
else {
uwsgi_log("[uwsgi-fsmon] registered monitor for \"%s\"\n", fs->path);
}
fs = fs->next;
}
}
struct uwsgi_fsmon *uwsgi_register_fsmon(char *path, void (*func) (struct uwsgi_fsmon *), void *data) {
struct uwsgi_fsmon *old_fs = NULL, *fs = uwsgi.fsmon;
while(fs) {
old_fs = fs;
fs = fs->next;
}
fs = uwsgi_calloc(sizeof(struct uwsgi_fsmon));
fs->path = path;
fs->func = func;
fs->data = data;
if (old_fs) {
old_fs->next = fs;
}
else {
uwsgi.fsmon = fs;
}
return fs;
}
static struct uwsgi_fsmon *uwsgi_fsmon_ack(int interesting_fd) {
struct uwsgi_fsmon *found_fs = NULL;
struct uwsgi_fsmon *fs = uwsgi.fsmon;
while (fs) {
if (fs->fd == interesting_fd) {
found_fs = fs;
break;
}
fs = fs->next;
}
#ifdef UWSGI_EVENT_FILEMONITOR_USE_INOTIFY
#ifndef OBSOLETE_LINUX_KERNEL
if (!found_fs)
return NULL;
found_fs = NULL;
unsigned int isize = 0;
if (ioctl(found_fd, FIONREAD, &isize) < 0) {
uwsgi_error("uwsgi_fsmon_ack()/ioctl()");
return 0;
}
if (isize == 0) return NULL;
if (ioctl(interesting_fd, FIONREAD, &isize) < 0) {
uwsgi_error("uwsgi_fsmon_ack()/ioctl()");
return NULL;
}
if (isize == 0)
return NULL;
struct inotify_event *ie = uwsgi_malloc(isize);
// read from the inotify descriptor
ssize_t len = read(found_fd, ie, isize);
if (len < 0) { free(ie); uwsgi_error("uwsgi_fsmon_ack()/read()"); return NULL;}
found_fd = ie->wd;
ssize_t len = read(interesting_fd, ie, isize);
if (len < 0) {
free(ie);
uwsgi_error("uwsgi_fsmon_ack()/read()");
return NULL;
}
fs = uwsgi.fsmon;
while (fs) {
if (fs->fd == interesting_fd && fs->id == ie->wd) {
found_fs = fs;
break;
}
fs = fs->next;
}
free(ie);
#endif
#endif
// search for the item id and print it
usl = uwsgi.fs_reload;
while(usl) {
if ((int)usl->custom2 == found_fd) {
uwsgi_log("[uwsgi-fsmon] \"%s\" has been modified\n", usl->value);
return uwsgi.fs_reload;
}
usl = usl->next;
}
usl = uwsgi.fs_brutal_reload;
while(usl) {
if ((int)usl->custom2 == found_fd) {
uwsgi_log("[uwsgi-fsmon] \"%s\" has been modified\n", usl->value);
return uwsgi.fs_brutal_reload;
}
usl = usl->next;
}
usl = uwsgi.fs_signal;
while(usl) {
if ((int)usl->custom2 == found_fd) {
uwsgi_log("[uwsgi-fsmon] \"%s\" has been modified\n", usl->value);
return usl;
}
usl = usl->next;
}
return NULL;
return found_fs;
}
int uwsgi_fsmon_event(int interesting_fd) {
struct uwsgi_string_list *usl = uwsgi_fsmon_ack(interesting_fd);
struct uwsgi_fsmon *fs = uwsgi_fsmon_ack(interesting_fd);
if (!fs)
return 0;
if (!usl) return 0;
if (usl == uwsgi.fs_reload) {
uwsgi_block_signal(SIGHUP);
grace_them_all(0);
uwsgi_unblock_signal(SIGHUP);
return 1;
}
if (usl == uwsgi.fs_brutal_reload) {
if (uwsgi.die_on_term) {
uwsgi_block_signal(SIGQUIT);
reap_them_all(0);
uwsgi_unblock_signal(SIGQUIT);
}
else {
uwsgi_block_signal(SIGTERM);
reap_them_all(0);
uwsgi_unblock_signal(SIGTERM);
}
return 1;
}
// fallback to signal
uwsgi_route_signal(atoi(usl->custom_ptr));
uwsgi_log_verbose("[uwsgi-fsmon] detected event on \"%s\"\n", fs->path);
fs->func(fs);
return 1;
}
+2
View File
@@ -92,6 +92,8 @@ void gateway_respawn(int id) {
signal(SIGSTOP, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
uwsgi_hooks_run(uwsgi.hook_as_gateway, "as-gateway", 1);
if (ug->gid) {
uwsgi_log("%s %d setgid() to %d\n", ug->name, ug->num, (int) ug->gid);
if (setgid(ug->gid)) {
+48
View File
@@ -47,6 +47,18 @@ void uwsgi_register_hook(char *name, int (*func)(char *)) {
}
}
static int uwsgi_hook_alarm(char *arg) {
char *space = strchr(arg,' ');
if (!space) {
uwsgi_log("invalid alarm hook syntax, must be: <alarm> <msg>\n");
return -1;
}
*space = 0;
uwsgi_alarm_trigger(arg, space+1, strlen(space+1));
*space = ' ';
return 0;
}
static int uwsgi_hook_chdir(char *arg) {
int ret = chdir(arg);
if (ret) {
@@ -154,6 +166,17 @@ static int uwsgi_hook_write(char *arg) {
return 0;
}
static int uwsgi_hook_creat(char *arg) {
int fd = open(arg, O_WRONLY|O_CREAT|O_TRUNC, 0666);
if (fd < 0) {
uwsgi_error_open(arg);
return -1;
}
close(fd);
return 0;
}
static int uwsgi_hook_append(char *arg) {
char *space = strchr(arg, ' ');
if (!space) {
@@ -262,6 +285,20 @@ static int uwsgi_hook_chmod(char *arg) {
return ret;
}
static int uwsgi_hook_sticky(char *arg) {
struct stat st;
if (stat(arg, &st)) {
uwsgi_error("uwsgi_hook_sticky()/stat()");
return -1;
}
if (chmod(arg, st.st_mode | S_ISVTX)) {
uwsgi_error("uwsgi_hook_sticky()/chmod()");
return -1;
}
return 0;
}
static int uwsgi_hook_chown(char *arg) {
char *space = strchr(arg, ' ');
if (!space) {
@@ -342,6 +379,9 @@ static int uwsgi_hook_chown2(char *arg) {
}
#ifdef __sun__
extern int sethostname(char *, int);
#endif
static int uwsgi_hook_hostname(char *arg) {
#ifdef __CYGWIN__
return -1;
@@ -456,8 +496,13 @@ void uwsgi_register_base_hooks() {
uwsgi_register_hook("chown", uwsgi_hook_chown);
uwsgi_register_hook("chown2", uwsgi_hook_chown2);
uwsgi_register_hook("sticky", uwsgi_hook_sticky);
uwsgi_register_hook("exec", uwsgi_hook_exec);
uwsgi_register_hook("create", uwsgi_hook_creat);
uwsgi_register_hook("creat", uwsgi_hook_creat);
uwsgi_register_hook("write", uwsgi_hook_write);
uwsgi_register_hook("writen", uwsgi_hook_writen);
uwsgi_register_hook("append", uwsgi_hook_append);
@@ -476,9 +521,12 @@ void uwsgi_register_base_hooks() {
uwsgi_register_hook("hostname", uwsgi_hook_hostname);
uwsgi_register_hook("alarm", uwsgi_hook_alarm);
// for testing
uwsgi_register_hook("exit", uwsgi_hook_exit);
uwsgi_register_hook("print", uwsgi_hook_print);
uwsgi_register_hook("log", uwsgi_hook_print);
}
void uwsgi_hooks_run(struct uwsgi_string_list *l, char *phase, int fatal) {
+3 -1
View File
@@ -123,7 +123,7 @@ void uwsgi_init_default() {
// a workers hould be running for at least 10 seconds
uwsgi.min_worker_lifetime = 10;
uwsgi.shared->spooler_frequency = 30;
uwsgi.spooler_frequency = 30;
uwsgi.shared->spooler_signal_pipe[0] = -1;
uwsgi.shared->spooler_signal_pipe[1] = -1;
@@ -183,6 +183,8 @@ void uwsgi_init_default() {
uwsgi.master_fifo_fd = -1;
uwsgi_master_fifo_prepare();
uwsgi.notify_socket_fd = -1;
}
void uwsgi_setup_reload() {
+62 -4
View File
@@ -517,12 +517,28 @@ fallback:
goto end;
}
// is it a potential virtual file (/proc, /sys...) ?
int is_virtual = 0;
if (sb.st_size == 0) {
is_virtual = 1;
sb.st_size = 4096;
}
buffer = uwsgi_malloc(sb.st_size + add_zero);
len = read(fd, buffer, sb.st_size);
if (len != sb.st_size) {
uwsgi_error("read()");
exit(1);
if (!is_virtual) {
if (len != sb.st_size) {
}
}
else {
if (len >= 0) {
sb.st_size = len;
}
else {
uwsgi_error("read()");
exit(1);
}
}
close(fd);
@@ -535,7 +551,46 @@ fallback:
end:
if (magic_table) {
// here we inject blobs
struct uwsgi_string_list *usl = NULL;
if (uwsgi.inject_before || uwsgi.inject_after) {
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
uwsgi_foreach(usl, uwsgi.inject_before) {
size_t rlen = 0;
char *before = uwsgi_open_and_read(usl->value, &rlen, 0, NULL);
if (uwsgi_buffer_append(ub, before, rlen)) {
uwsgi_log("unable to inject data in the config file\n");
exit(1);
}
free(before);
}
if (uwsgi_buffer_append(ub, buffer, *size - add_zero)) {
uwsgi_log("unable to inject data in the config file\n");
exit(1);
}
uwsgi_foreach(usl, uwsgi.inject_after) {
size_t rlen = 0;
char *after = uwsgi_open_and_read(usl->value, &rlen, 0, NULL);
if (uwsgi_buffer_append(ub, after, rlen)) {
uwsgi_log("unable to inject data in the config file\n");
exit(1);
}
free(after);
}
if (add_zero) {
if (uwsgi_buffer_append(ub, "\0", 1)) {
uwsgi_log("unable to inject data in the config file\n");
exit(1);
}
}
*size = ub->pos;
// free resources
free(buffer);
buffer = ub->buf;
// aboid destroying buffer
ub->buf = NULL;
uwsgi_buffer_destroy(ub);
}
magic_buf = magic_sub(buffer, *size, size, magic_table);
free(buffer);
return magic_buf;
@@ -912,6 +967,7 @@ int uwsgi_read_nb(int fd, char *buf, size_t remains, int timeout) {
ssize_t uwsgi_read_true_nb(int fd, char *buf, size_t len, int timeout) {
int ret;
errno = 0;
ssize_t rlen = read(fd, buf, len);
if (rlen > 0) {
return rlen;
@@ -922,8 +978,10 @@ ssize_t uwsgi_read_true_nb(int fd, char *buf, size_t len, int timeout) {
}
return -1;
wait:
errno = 0;
ret = uwsgi.wait_read_hook(fd, timeout);
if (ret > 0) {
errno = 0;
rlen = read(fd, buf, len);
if (rlen > 0) {
return rlen;
+118 -1
View File
@@ -4,7 +4,124 @@
extern struct uwsgi_server uwsgi;
#ifdef UWSGI_JSON_YAJL
#if defined(UWSGI_JSON_YAJL_OLD)
#include <yajl/yajl_parse.h>
struct uwsgi_yajl_old_state {
char *object;
char *key;
int in_object;
int is_array;
};
static int uwsgi_yajl_cb_null(void *ctx) {
struct uwsgi_yajl_old_state *uyos = (struct uwsgi_yajl_old_state *) ctx;
if (!uyos->key) return 1;
add_exported_option(uyos->key, strdup("0"), 0);
return 1;
}
static int uwsgi_yajl_cb_boolean(void *ctx, int b) {
struct uwsgi_yajl_old_state *uyos = (struct uwsgi_yajl_old_state *) ctx;
if (!uyos->key) return 1;
if (b) {
add_exported_option(uyos->key, strdup("1"), 0);
}
else {
add_exported_option(uyos->key, strdup("0"), 0);
}
return 1;
}
static int uwsgi_yajl_cb_integer(void *ctx, long n) {
struct uwsgi_yajl_old_state *uyos = (struct uwsgi_yajl_old_state *) ctx;
if (!uyos->key) return 1;
add_exported_option(uyos->key, uwsgi_64bit2str((int64_t) n), 0);
return 1;
}
static int uwsgi_yajl_cb_double(void *ctx, double n) {
return uwsgi_yajl_cb_integer(ctx, (long) n);
}
static int uwsgi_yajl_cb_string(void *ctx, const unsigned char *s, unsigned int s_len) {
struct uwsgi_yajl_old_state *uyos = (struct uwsgi_yajl_old_state *) ctx;
if (!uyos->key) return 1;
add_exported_option(uyos->key, uwsgi_concat2n((char *)s, (size_t)s_len, "", 0), 0);
return 1;
}
static int uwsgi_yajl_cb_number(void *ctx, const char *n, unsigned int n_len) {
return uwsgi_yajl_cb_string(ctx, (const unsigned char *)n, n_len);
}
static int uwsgi_yajl_cb_map_key(void *ctx, const unsigned char *s, unsigned int s_len) {
struct uwsgi_yajl_old_state *uyos = (struct uwsgi_yajl_old_state *) ctx;
if (!uyos->in_object) {
if (!uwsgi_strncmp(uyos->object, strlen(uyos->object), (char *)s, (size_t)s_len)) {
uyos->in_object = 1;
}
return 1;
}
uyos->key = uwsgi_concat2n((char *)s, (size_t)s_len, "", 0);
return 1;
}
static yajl_callbacks callbacks = {
.yajl_null = uwsgi_yajl_cb_null,
.yajl_boolean = uwsgi_yajl_cb_boolean,
.yajl_integer = uwsgi_yajl_cb_integer,
.yajl_double = uwsgi_yajl_cb_double,
.yajl_number = uwsgi_yajl_cb_number,
.yajl_string = uwsgi_yajl_cb_string,
.yajl_start_map = NULL,
.yajl_map_key = uwsgi_yajl_cb_map_key,
.yajl_end_map = NULL,
.yajl_start_array = NULL,
.yajl_end_array = NULL,
};
void uwsgi_json_config(char *file, char *magic_table[]) {
size_t len = 0;
char *object_asked = "uwsgi";
char *colon;
if (uwsgi_check_scheme(file)) {
colon = uwsgi_get_last_char(file, '/');
colon = uwsgi_get_last_char(colon, ':');
}
else {
colon = uwsgi_get_last_char(file, ':');
}
if (colon) {
colon[0] = 0;
if (colon[1] != 0) {
object_asked = colon + 1;
}
}
struct uwsgi_yajl_old_state uyos;
memset(&uyos, 0, sizeof(struct uwsgi_yajl_old_state));
uyos.object = object_asked;
uwsgi_log_initial("[uWSGI] getting JSON configuration from %s\n", file);
char *json_data = uwsgi_open_and_read(file, &len, 1, magic_table);
yajl_handle hand = yajl_alloc(&callbacks, NULL, NULL, &uyos);
yajl_status s = yajl_parse(hand, (const unsigned char *)json_data, len);
if (s != yajl_status_ok) {
uwsgi_log("%s\n", yajl_get_error(hand, 1, (const unsigned char *)json_data, len));
exit(1);
}
}
#elif defined(UWSGI_JSON_YAJL)
#include <yajl/yajl_tree.h>
void uwsgi_json_config(char *file, char *magic_table[]) {
+61 -11
View File
@@ -279,9 +279,12 @@ static void legions_check_nodes_step2() {
// go on if i am not an arbiter
else if (ul->valor > 0) {
// no potential Lord is available, i will propose myself
best_valor = ul->valor;
memcpy(best_uuid, ul->uuid, 36);
i_am_the_best = 1;
// but only if i am not suspended...
if (uwsgi_now() > ul->suspended_til) {
best_valor = ul->valor;
memcpy(best_uuid, ul->uuid, 36);
i_am_the_best = 1;
}
}
else {
// empty lord
@@ -337,13 +340,20 @@ static void legions_check_nodes_step2() {
}
if (i_am_the_best) {
if (!ul->i_am_the_lord) {
uwsgi_log("[uwsgi-legion] i am now the Lord of the Legion %s\n", ul->legion);
// triggering lord hooks
uwsgi_log("[uwsgi-legion] attempting to become the Lord of the Legion %s\n", ul->legion);
struct uwsgi_string_list *usl = ul->lord_hooks;
while (usl) {
int ret = uwsgi_legion_action_call("lord", ul, usl);
if (ret) {
uwsgi_log("[uwsgi-legion] ERROR, lord hook returned: %d\n", ret);
if (uwsgi.legion_death_on_lord_error) {
ul->dead = 1;
uwsgi_legion_announce(ul);
ul->suspended_til = uwsgi_now() + uwsgi.legion_death_on_lord_error;
uwsgi_log("[uwsgi-legion] suspending myself from Legion \"%s\" for %d seconds\n", ul->legion, uwsgi.legion_death_on_lord_error);
goto next;
}
}
usl = usl->next;
}
@@ -356,6 +366,7 @@ static void legions_check_nodes_step2() {
else {
ul->lord_scroll_len = 0;
}
uwsgi_log("[uwsgi-legion] i am now the Lord of the Legion %s\n", ul->legion);
ul->i_am_the_lord = uwsgi_now();
// trick: reduce the time needed by the old lord to unlord itself
uwsgi_legion_announce(ul);
@@ -400,7 +411,7 @@ static void legions_check_nodes_step2() {
}
ul->last_warning = uwsgi_now();
}
next:
ul = ul->next;
}
}
@@ -496,8 +507,15 @@ static void *legion_loop(void *foobar) {
last_round = now;
// wait for event
int interesting_fd = -1;
if (uwsgi_instance_is_reloading || uwsgi_instance_is_dying) return NULL;
int rlen = event_queue_wait(uwsgi.legion_queue, timeout, &interesting_fd);
if (rlen < 0 && errno != EINTR) {
if (uwsgi_instance_is_reloading || uwsgi_instance_is_dying) return NULL;
uwsgi_nuclear_blast();
return NULL;
}
now = uwsgi_now();
if (timeout == 0 || rlen == 0 || (now - last_round) >= timeout) {
struct uwsgi_legion *legions = uwsgi.legions;
@@ -591,6 +609,8 @@ static void *legion_loop(void *foobar) {
// check if the node is already accounted
struct uwsgi_legion_node *node = uwsgi_legion_get_node(ul, legion_msg.valor, legion_msg.name, legion_msg.name_len, legion_msg.uuid);
if (!node) {
// if a lord hook election fails, a node can announce itself as dead for long time...
if (legion_msg.dead) continue;
// add the new node
uwsgi_wlock(ul->lock);
node = uwsgi_legion_add_node(ul, legion_msg.valor, legion_msg.name, legion_msg.name_len, legion_msg.uuid);
@@ -648,7 +668,12 @@ int uwsgi_legion_action_call(char *phase, struct uwsgi_legion *ul, struct uwsgi_
return -1;
}
uwsgi_log("[uwsgi-legion] (phase: %s legion: %s) calling %s\n", phase, ul->legion, usl->value);
if (ula->log_msg) {
uwsgi_log("[uwsgi-legion] (phase: %s legion: %s) %s\n", phase, ul->legion, ula->log_msg);
}
else {
uwsgi_log("[uwsgi-legion] (phase: %s legion: %s) calling %s\n", phase, ul->legion, usl->value);
}
return ula->func(ul, usl->value + usl->custom);
}
@@ -667,6 +692,18 @@ static int legion_action_log(struct uwsgi_legion *ul, char *arg) {
return 0;
}
static int legion_action_alarm(struct uwsgi_legion *ul, char *arg) {
char *space = strchr(arg,' ');
if (!space) {
uwsgi_log("invalid alarm action syntax, must be: <alarm> <msg>\n");
return -1;
}
*space = 0;
uwsgi_alarm_trigger(arg, space+1, strlen(space+1));
*space = ' ';
return 0;
}
void uwsgi_start_legions() {
pthread_t legion_loop_t;
@@ -675,8 +712,10 @@ void uwsgi_start_legions() {
// register embedded actions
uwsgi_legion_action_register("cmd", legion_action_cmd);
uwsgi_legion_action_register("exec", legion_action_cmd);
uwsgi_legion_action_register("signal", legion_action_signal);
uwsgi_legion_action_register("log", legion_action_log);
uwsgi_legion_action_register("alarm", legion_action_alarm);
uwsgi.legion_queue = event_queue_init();
struct uwsgi_legion *legion = uwsgi.legions;
@@ -736,13 +775,19 @@ void uwsgi_legion_add(struct uwsgi_legion *ul) {
}
int uwsgi_legion_announce(struct uwsgi_legion *ul) {
time_t now = uwsgi_now();
if (now <= ul->suspended_til) return 0;
ul->suspended_til = 0;
struct uwsgi_buffer *ub = uwsgi_buffer_new(4096);
unsigned char *encrypted = NULL;
if (uwsgi_buffer_append_keyval(ub, "legion", 6, ul->legion, ul->legion_len))
goto err;
if (uwsgi_buffer_append_keynum(ub, "valor", 5, ul->valor))
goto err;
if (uwsgi_buffer_append_keynum(ub, "unix", 4, uwsgi_now()))
if (uwsgi_buffer_append_keynum(ub, "unix", 4, now))
goto err;
if (uwsgi_buffer_append_keynum(ub, "lord", 4, ul->i_am_the_lord ? ul->i_am_the_lord : 0))
goto err;
@@ -769,7 +814,7 @@ int uwsgi_legion_announce(struct uwsgi_legion *ul) {
goto err;
}
unsigned char *encrypted = uwsgi_malloc(ub->pos + 4 + EVP_MAX_BLOCK_LENGTH);
encrypted = uwsgi_malloc(ub->pos + 4 + EVP_MAX_BLOCK_LENGTH);
if (EVP_EncryptInit_ex(ul->encrypt_ctx, NULL, NULL, NULL, NULL) <= 0) {
uwsgi_error("[uwsgi-legion] EVP_EncryptInit_ex()");
goto err;
@@ -808,6 +853,7 @@ int uwsgi_legion_announce(struct uwsgi_legion *ul) {
return 0;
err:
uwsgi_buffer_destroy(ub);
free(encrypted);
return -1;
}
@@ -824,6 +870,7 @@ void uwsgi_opt_legion_mcast(char *opt, char *value, void *foobar) {
exit(1);
}
uwsgi_legion_register_node(ul, uwsgi_str(ul->addr));
free(legion);
}
void uwsgi_opt_legion_node(char *opt, char *value, void *foobar) {
@@ -1112,10 +1159,11 @@ struct uwsgi_legion_action *uwsgi_legion_action_get(char *name) {
return NULL;
}
void uwsgi_legion_action_register(char *name, int (*func) (struct uwsgi_legion *, char *)) {
if (uwsgi_legion_action_get(name)) {
struct uwsgi_legion_action *uwsgi_legion_action_register(char *name, int (*func) (struct uwsgi_legion *, char *)) {
struct uwsgi_legion_action *found_ula = uwsgi_legion_action_get(name);
if (found_ula) {
uwsgi_log("[uwsgi-legion] action \"%s\" is already registered !!!\n", name);
return;
return found_ula;
}
struct uwsgi_legion_action *old_ula = NULL, *ula = uwsgi.legion_actions;
@@ -1134,6 +1182,8 @@ void uwsgi_legion_action_register(char *name, int (*func) (struct uwsgi_legion *
else {
uwsgi.legion_actions = ula;
}
return ula;
}
void uwsgi_legion_announce_death(void) {
+1 -1
View File
@@ -1116,7 +1116,7 @@ static ssize_t uwsgi_lf_ltime(struct wsgi_request * wsgi_req, char **buf) {
}
static ssize_t uwsgi_lf_ftime(struct wsgi_request * wsgi_req, char **buf) {
if (!uwsgi.log_strftime) {
if (!uwsgi.logformat_strftime || !uwsgi.log_strftime) {
return uwsgi_lf_ltime(wsgi_req, buf);
}
*buf = uwsgi_malloc(64);
+35 -1
View File
@@ -242,6 +242,17 @@ static void master_check_listen_queue() {
if (uwsgi_sock->queue > 0 && uwsgi_sock->queue >= uwsgi_sock->max_queue) {
uwsgi_log_verbose("*** uWSGI listen queue of socket \"%s\" (fd: %d) full !!! (%llu/%llu) ***\n", uwsgi_sock->name, uwsgi_sock->fd, (unsigned long long) uwsgi_sock->queue, (unsigned long long) uwsgi_sock->max_queue);
}
if (uwsgi.alarm_backlog) {
char buf[1024];
int ret = snprintf(buf, 1024, "listen queue of socket \"%s\" (fd: %d) full !!! (%llu/%llu)", uwsgi_sock->name, uwsgi_sock->fd, (unsigned long long) uwsgi_sock->queue, (unsigned long long) uwsgi_sock->max_queue);
if (ret > 0 && ret < 1024) {
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.alarm_backlog) {
uwsgi_alarm_trigger(usl->value, buf, ret);
}
}
}
uwsgi_sock = uwsgi_sock->next;
}
@@ -323,6 +334,12 @@ int master_loop(char **argv, char **environ) {
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.master_fifo_fd);
}
if (uwsgi.notify_socket) {
uwsgi.notify_socket_fd = bind_to_unix_dgram(uwsgi.notify_socket);
uwsgi_log("notification socket enabled on %s (fd: %d)\n", uwsgi.notify_socket, uwsgi.notify_socket_fd);
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.notify_socket_fd);
}
if (uwsgi.spoolers) {
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->spooler_signal_pipe[0]);
}
@@ -508,6 +525,16 @@ int master_loop(char **argv, char **environ) {
}
ud = ud->next;
}
// hook touches
uwsgi_foreach(usl, uwsgi.hook_touch) {
char *space = strchr(usl->value, ' ');
if (space) {
*space = 0;
usl->len = strlen(usl->value);
uwsgi_string_new_list((struct uwsgi_string_list **)&usl->custom_ptr, space+1);
}
}
uwsgi_check_touches(uwsgi.hook_touch);
// fsmon
uwsgi_fsmon_setup();
@@ -555,6 +582,7 @@ int master_loop(char **argv, char **environ) {
}
// here really starts the master loop
uwsgi_hooks_run(uwsgi.hook_master_start, "master-start", 1);
for (;;) {
//uwsgi_log("uwsgi.ready_to_reload %d %d\n", uwsgi.ready_to_reload, uwsgi.numproc);
@@ -807,7 +835,7 @@ int master_loop(char **argv, char **environ) {
touched = uwsgi_check_touches(ud->touch);
if (touched) {
uwsgi_log_verbose("*** %s has been touched... reloading daemon \"%s\" (pid: %d) !!! ***\n", touched, ud->command, (int) ud->pid);
if (kill(ud->pid, ud->stop_signal)) {
if (kill(-ud->pid, ud->stop_signal)) {
uwsgi_error("[uwsgi-daemon/touch] kill()");
}
}
@@ -815,6 +843,12 @@ int master_loop(char **argv, char **environ) {
ud = ud->next;
}
// hook touches
touched = uwsgi_check_touches(uwsgi.hook_touch);
if (touched) {
uwsgi_hooks_run((struct uwsgi_string_list *) touched, "touch", 0);
}
}
// allows the KILL signal to be delivered;
+4
View File
@@ -22,6 +22,10 @@ int uwsgi_master_manage_events(int interesting_fd) {
return uwsgi_master_fifo_manage(uwsgi.master_fifo_fd);
}
if (uwsgi.notify_socket_fd > -1 && interesting_fd == uwsgi.notify_socket_fd) {
return uwsgi_notify_socket_manage(interesting_fd);
}
// stats server ?
if (uwsgi.stats && uwsgi.stats_fd > -1) {
if (interesting_fd == uwsgi.stats_fd) {
+29 -9
View File
@@ -43,13 +43,6 @@ void uwsgi_destroy_processes() {
uwsgi_signal_spoolers(SIGKILL);
if (uwsgi.emperor_pid >= 0) {
kill(uwsgi.emperor_pid, SIGKILL);
waitpid(uwsgi.emperor_pid, &waitpid_status, 0);
uwsgi_log("The Emperor has been buried (pid: %d)\n", (int) uwsgi.emperor_pid);
}
uwsgi_detach_daemons();
for (i = 0; i < ushared->gateways_cnt; i++) {
@@ -68,6 +61,26 @@ void uwsgi_destroy_processes() {
uwsgi_log("mule %d has been buried (pid: %d)\n", i, (int) uwsgi.mules[i].pid);
}
}
if (uwsgi.emperor_pid > 0) {
kill(uwsgi.emperor_pid, SIGINT);
time_t timeout = uwsgi_now() + (uwsgi.reload_mercy ? uwsgi.reload_mercy : 3);
// increase timeout for being more tolerant
timeout+=2;
int waitpid_status;
while (uwsgi_now() < timeout) {
pid_t diedpid = waitpid(uwsgi.emperor_pid, &waitpid_status, WNOHANG);
if (diedpid == uwsgi.emperor_pid) {
goto nomoremperor;
}
uwsgi_log("waiting for Emperor death...\n");
sleep(1);
}
kill(uwsgi.emperor_pid, SIGKILL);
waitpid(uwsgi.emperor_pid, &waitpid_status, 0);
nomoremperor:
uwsgi_log("The Emperor has been buried (pid: %d)\n", (int) uwsgi.emperor_pid);
}
}
@@ -407,6 +420,7 @@ void uwsgi_reload(char **argv) {
/* check fd table (a module can obviosly open some fd on initialization...) */
uwsgi_log("closing all non-uwsgi socket fds > 2 (max_fd = %d)...\n", (int) uwsgi.max_fd);
for (i = 3; i < (int) uwsgi.max_fd; i++) {
if (uwsgi.close_on_exec2) fcntl(i, F_SETFD, 0);
if (uwsgi_fd_is_safe(i)) continue;
@@ -545,9 +559,10 @@ void uwsgi_fixup_fds(int wid, int muleid, struct uwsgi_gateway *ug) {
}
}
if (uwsgi.shared->spooler_signal_pipe[0] != -1)
close(uwsgi.shared->spooler_signal_pipe[0]);
if (uwsgi.i_am_a_spooler && uwsgi.i_am_a_spooler->pid != getpid()) {
if (uwsgi.shared->spooler_signal_pipe[0] != -1)
close(uwsgi.shared->spooler_signal_pipe[0]);
if (uwsgi.shared->spooler_signal_pipe[1] != -1)
close(uwsgi.shared->spooler_signal_pipe[1]);
}
@@ -587,6 +602,8 @@ void uwsgi_fixup_fds(int wid, int muleid, struct uwsgi_gateway *ug) {
if (uwsgi.master_fifo_fd > -1) close(uwsgi.master_fifo_fd);
if (uwsgi.notify_socket_fd > -1) close(uwsgi.notify_socket_fd);
#ifdef __linux__
for(i=0;i<uwsgi.setns_fds_count;i++) {
close(uwsgi.setns_fds[i]);
@@ -972,6 +989,9 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
if (uwsgi_stats_keylong_comma(us, "queue", (unsigned long long) uwsgi_sock->queue))
goto end;
if (uwsgi_stats_keylong_comma(us, "max_queue", (unsigned long long) uwsgi_sock->max_queue))
goto end;
if (uwsgi_stats_keylong_comma(us, "shared", (unsigned long long) uwsgi_sock->shared))
goto end;
+36
View File
@@ -75,3 +75,39 @@ void uwsgi_systemd_init(char *systemd_socket) {
uwsgi.notify_ready = uwsgi_systemd_notify_ready;
}
int uwsgi_notify_socket_manage(int fd) {
char buf[8192];
ssize_t rlen = read(fd, buf, 8192);
if (rlen < 0) {
if (uwsgi_is_again()) return 0;
uwsgi_error("uwsgi_notify_socket_manage()/read()");
exit(1);
}
if (rlen > 0) {
uwsgi_log_verbose("[notify-socket] %.*s\n", rlen, buf);
}
return 0;
}
int uwsgi_notify_msg(char *dst, char *msg, size_t len) {
static int notify_fd = -1;
if (notify_fd < 0) {
notify_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (notify_fd < 0) {
uwsgi_error("uwsgi_notify_msg()/socket()");
return -1;
}
}
struct sockaddr_un un_addr;
memset(&un_addr, 0, sizeof(struct sockaddr_un));
un_addr.sun_family = AF_UNIX;
// use 102 as the magic number
strncat(un_addr.sun_path, dst, 102);
if (sendto(notify_fd, msg, len, 0, (struct sockaddr *) &un_addr, sizeof(un_addr)) < 0) {
return -1;
}
return 0;
}
+1
View File
@@ -312,6 +312,7 @@ int uwsgi_apply_error_routes(struct wsgi_request *wsgi_req) {
int uwsgi_apply_response_routes(struct wsgi_request *wsgi_req) {
if (!uwsgi.response_routes) return 0;
if (wsgi_req->response_routes_applied) return 0;
+12 -10
View File
@@ -269,20 +269,22 @@ int uwsgi_remote_signal_send(char *addr, uint8_t sig) {
uh.pktsize = 0;
uh.modifier2 = sig;
int fd = uwsgi_connect(addr, uwsgi.socket_timeout, 0);
if (fd < 0)
return -1;
int fd = uwsgi_connect(addr, 0, 1);
if (fd < 0) return -1;
if (write(fd, (char *) &uh, 4) != 4) {
uwsgi_error("uwsgi_remote_signal_send()");
close(fd);
return -1;
}
// wait for connection
if (uwsgi.wait_write_hook(fd, uwsgi.socket_timeout) <= 0) goto end;
int ret = uwsgi_read_response(fd, &uh, uwsgi.socket_timeout, NULL);
if (uwsgi_write_true_nb(fd, (char *) &uh, 4, uwsgi.socket_timeout)) goto end;
if (uwsgi_read_whole_true_nb(fd, (char *) &uh, 4, uwsgi.socket_timeout)) goto end;
close(fd);
return ret;
return uh.modifier2;
end:
close(fd);
return -1;
}
+61 -90
View File
@@ -76,18 +76,66 @@ char *uwsgi_getsockname(int fd) {
return NULL;
}
static int create_server_socket(int domain, int type) {
int serverfd = socket(domain, type, 0);
if (serverfd < 0) {
uwsgi_error("socket()");
uwsgi_nuclear_blast();
return -1;
}
if (uwsgi.close_on_exec2 && fcntl(serverfd, F_SETFD, FD_CLOEXEC) < 0)
uwsgi_error("fcntl()");
if (domain != AF_UNIX) {
int reuse = 1;
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) {
uwsgi_error("SO_REUSEADDR setsockopt()");
uwsgi_nuclear_blast();
return -1;
}
}
if (type == SOCK_STREAM) {
if (uwsgi.so_sndbuf) {
socklen_t sndbuf = (socklen_t) uwsgi.so_sndbuf;
if (setsockopt(serverfd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(socklen_t)) < 0) {
uwsgi_error("SO_SNDBUF setsockopt()");
uwsgi_nuclear_blast();
return -1;
}
}
if (uwsgi.so_rcvbuf) {
socklen_t rcvbuf = (socklen_t) uwsgi.so_rcvbuf;
if (setsockopt(serverfd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(socklen_t)) < 0) {
uwsgi_error("SO_RCVBUF setsockopt()");
uwsgi_nuclear_blast();
return -1;
}
}
#ifdef __linux__
long somaxconn = uwsgi_num_from_file("/proc/sys/net/core/somaxconn", 1);
if (somaxconn > 0 && uwsgi.listen_queue > somaxconn) {
uwsgi_log("Listen queue size is greater than the system max net.core.somaxconn (%li).\n", somaxconn);
uwsgi_nuclear_blast();
return -1;
}
#endif
}
return serverfd;
}
int bind_to_unix_dgram(char *socket_name) {
int serverfd;
struct sockaddr_un *uws_addr;
socklen_t len;
serverfd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (serverfd < 0) {
uwsgi_error("socket()");
uwsgi_nuclear_blast();
return -1;
}
serverfd = create_server_socket(AF_UNIX, SOCK_DGRAM);
if (serverfd < 0) return -1;
if (unlink(socket_name) != 0 && errno != ENOENT) {
uwsgi_error("error removing unix socket, unlink()");
@@ -140,15 +188,11 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst
}
memset(uws_addr, 0, sizeof(struct sockaddr_un));
serverfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (serverfd < 0) {
uwsgi_error("socket()");
uwsgi_nuclear_blast();
return -1;
}
serverfd = create_server_socket(AF_UNIX, SOCK_STREAM);
if (serverfd < 0) return -1;
if (abstract_socket == 0) {
if (unlink(socket_name) != 0 && errno != ENOENT) {
uwsgi_error("unlink()");
uwsgi_error("error removing unix socket, unlink()");
}
}
@@ -156,24 +200,6 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst
uwsgi_log("setting abstract socket mode (warning: only Linux supports this)\n");
}
if (uwsgi.so_sndbuf) {
socklen_t sndbuf = (socklen_t) uwsgi.so_sndbuf;
if (setsockopt(serverfd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(socklen_t)) < 0) {
uwsgi_error("SO_SNDBUF setsockopt()");
uwsgi_nuclear_blast();
return -1;
}
}
if (uwsgi.so_rcvbuf) {
socklen_t rcvbuf = (socklen_t) uwsgi.so_rcvbuf;
if (setsockopt(serverfd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(socklen_t)) < 0) {
uwsgi_error("SO_RCVBUF setsockopt()");
uwsgi_nuclear_blast();
return -1;
}
}
uws_addr->sun_family = AF_UNIX;
if (socket_name[0] == '@') {
memcpy(uws_addr->sun_path + abstract_socket, socket_name + 1, UMIN(strlen(socket_name + 1), 101));
@@ -203,15 +229,6 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst
return -1;
}
#ifdef __linux__
long somaxconn = uwsgi_num_from_file("/proc/sys/net/core/somaxconn", 1);
if (somaxconn > 0 && uwsgi.listen_queue > somaxconn) {
uwsgi_log("Listen queue size is greater than the system max net.core.somaxconn (%li).\n", somaxconn);
uwsgi_nuclear_blast();
return -1;
}
#endif
if (listen(serverfd, listen_queue) != 0) {
uwsgi_error("listen()");
uwsgi_nuclear_blast();
@@ -243,7 +260,6 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
struct sockaddr_in uws_addr;
char *udp_port;
int bcast = 1;
int reuse = 1;
struct ip_mreq mc;
@@ -288,15 +304,8 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
}
serverfd = socket(AF_INET, SOCK_DGRAM, 0);
if (serverfd < 0) {
uwsgi_error("socket()");
return -1;
}
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) {
uwsgi_error("setsockopt()");
}
serverfd = create_server_socket(AF_INET, SOCK_DGRAM);
if (serverfd < 0) return -1;
if (multicast) {
// if multicast is enabled remember to bind to INADDR_ANY
@@ -649,7 +658,6 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
#else
struct sockaddr_in uws_addr;
#endif
int reuse = 1;
int family = AF_INET;
socklen_t addr_len = sizeof(struct sockaddr_in);
@@ -667,37 +675,9 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
#endif
serverfd = socket(family, SOCK_STREAM, 0);
if (serverfd < 0) {
uwsgi_error("socket()");
uwsgi_nuclear_blast();
return -1;
}
serverfd = create_server_socket(family, SOCK_STREAM);
if (serverfd < 0) return -1;
if (uwsgi.so_sndbuf) {
socklen_t sndbuf = (socklen_t) uwsgi.so_sndbuf;
if (setsockopt(serverfd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(socklen_t)) < 0) {
uwsgi_error("SO_SNDBUF setsockopt()");
uwsgi_nuclear_blast();
return -1;
}
}
if (uwsgi.so_rcvbuf) {
socklen_t rcvbuf = (socklen_t) uwsgi.so_rcvbuf;
if (setsockopt(serverfd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(socklen_t)) < 0) {
uwsgi_error("SO_RCVBUF setsockopt()");
uwsgi_nuclear_blast();
return -1;
}
}
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) {
uwsgi_error("SO_REUSEADDR setsockopt()");
uwsgi_nuclear_blast();
return -1;
}
#ifdef __linux__
#ifndef IP_FREEBIND
#define IP_FREEBIND 15
@@ -781,15 +761,6 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
return -1;
}
#ifdef __linux__
long somaxconn = uwsgi_num_from_file("/proc/sys/net/core/somaxconn", 1);
if (somaxconn > 0 && uwsgi.listen_queue > somaxconn) {
uwsgi_log("Listen queue size is greater than the system max net.core.somaxconn (%li).\n", somaxconn);
uwsgi_nuclear_blast();
return -1;
}
#endif
if (listen(serverfd, listen_queue) != 0) {
uwsgi_error("listen()");
uwsgi_nuclear_blast();
+108 -30
View File
@@ -72,12 +72,12 @@ struct uwsgi_spooler *uwsgi_new_spooler(char *dir) {
}
struct uwsgi_spooler *uwsgi_get_spooler_by_name(char *name) {
struct uwsgi_spooler *uwsgi_get_spooler_by_name(char *name, size_t name_len) {
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
if (!strcmp(uspool->dir, name)) {
if (!uwsgi_strncmp(uspool->dir, strlen(uspool->dir), name, name_len)) {
return uspool;
}
uspool = uspool->next;
@@ -167,47 +167,122 @@ void destroy_spool(char *dir, char *file) {
}
struct spooler_req {
char *spooler;
size_t spooler_len;
char *priority;
size_t priority_len;
time_t at;
};
int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core_id, char *buffer, int size, char *priority, time_t at, char *body, size_t body_len) {
static void spooler_req_parser_hook(char *key, uint16_t key_len, char *value, uint16_t value_len, void *data) {
struct spooler_req *sr = (struct spooler_req *) data;
if (!uwsgi_strncmp(key, key_len, "spooler", 7)) {
sr->spooler = value;
sr->spooler_len = value_len;
return;
}
if (!uwsgi_strncmp(key, key_len, "priority", 8)) {
sr->priority = value;
sr->priority_len = value_len;
return;
}
if (!uwsgi_strncmp(key, key_len, "at", 2)) {
sr->at = uwsgi_str_num(value, value_len);
return;
}
}
char *uwsgi_spool_request(struct wsgi_request *wsgi_req, char *buf, size_t len, char *body, size_t body_len) {
struct timeval tv;
int fd;
struct uwsgi_header uh;
static uint64_t internal_counter = 0;
int core_id = 0;
int fd = -1;
struct spooler_req sr;
if (len > 0xffff) {
uwsgi_log("[uwsgi-spooler] args buffer is limited to 64k, use the 'body' for bigger values\n");
return NULL;
}
// parse the request buffer
memset(&sr, 0, sizeof(struct spooler_req));
uwsgi_hooked_parse(buf, len, spooler_req_parser_hook, &sr);
struct uwsgi_spooler *uspool = uwsgi.spoolers;
if (!uspool) {
uspool = uwsgi.spoolers;
uwsgi_log("[uwsgi-spooler] no spooler available\n");
return NULL;
}
// if it is a number, get the spooler by id instead of by name
if (sr.spooler && sr.spooler_len) {
uspool = uwsgi_get_spooler_by_name(sr.spooler, sr.spooler_len);
if (!uspool) {
uwsgi_log("[uwsgi-spooler] unable to find spooler \"%.*s\"\n", sr.spooler_len, sr.spooler);
return NULL;
}
}
if (wsgi_req) {
core_id = wsgi_req->async_id;
}
// this lock is for threads, the pid value in filename will avoid multiprocess races
uwsgi_lock(uspool->lock);
// we increase it even if the request fails
internal_counter++;
gettimeofday(&tv, NULL);
if (priority) {
if (snprintf(filename, 1024, "%s/%s", uspool->dir, priority) <= 0) {
char *filename = NULL;
size_t filename_len = 0;
if (sr.priority && sr.priority_len) {
filename_len = strlen(uspool->dir) + sr.priority_len + strlen(uwsgi.hostname) + 256;
filename = uwsgi_malloc(filename_len);
int ret = snprintf(filename, filename_len, "%s/%.*s", uspool->dir, (int) sr.priority_len, sr.priority);
if (ret <= 0 || ret >= (int) filename_len) {
uwsgi_log("[uwsgi-spooler] error generating spooler filename\n");
free(filename);
uwsgi_unlock(uspool->lock);
return 0;
return NULL;
}
// no need to check for errors...
(void) mkdir(filename, 0777);
if (snprintf(filename, 1024, "%s/%s/uwsgi_spoolfile_on_%s_%d_%d_%d_%llu_%llu", uspool->dir, priority, uwsgi.hostname, (int) getpid(), rn, core_id, (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec) <= 0) {
ret = snprintf(filename, filename_len, "%s/%.*s/uwsgi_spoolfile_on_%s_%d_%llu_%d_%llu_%llu", uspool->dir, (int)sr.priority_len, sr.priority, uwsgi.hostname, (int) getpid(), (unsigned long long) internal_counter, core_id,
(unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec);
if (ret <= 0 || ret >=(int) filename_len) {
uwsgi_log("[uwsgi-spooler] error generating spooler filename\n");
free(filename);
uwsgi_unlock(uspool->lock);
return 0;
return NULL;
}
}
else {
if (snprintf(filename, 1024, "%s/uwsgi_spoolfile_on_%s_%d_%d_%d_%llu_%llu", uspool->dir, uwsgi.hostname, (int) getpid(), rn, core_id, (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec) <= 0) {
filename_len = strlen(uspool->dir) + strlen(uwsgi.hostname) + 256;
filename = uwsgi_malloc(filename_len);
int ret = snprintf(filename, filename_len, "%s/uwsgi_spoolfile_on_%s_%d_%llu_%d_%llu_%llu", uspool->dir, uwsgi.hostname, (int) getpid(), (unsigned long long) internal_counter, core_id,
(unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec);
if (ret <= 0 || ret >= (int) filename_len) {
uwsgi_log("[uwsgi-spooler] error generating spooler filename\n");
free(filename);
uwsgi_unlock(uspool->lock);
return 0;
return NULL;
}
}
fd = open(filename, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
if (fd < 0) {
uwsgi_error_open(filename);
free(filename);
uwsgi_unlock(uspool->lock);
return 0;
return NULL;
}
// now lock the file, it will no be runnable, until the lock is not removed
@@ -215,13 +290,15 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core
// in such case the spooler will detect a zeroed file and will retry later
if (uwsgi_fcntl_lock(fd)) {
close(fd);
free(filename);
uwsgi_unlock(uspool->lock);
return 0;
return NULL;
}
struct uwsgi_header uh;
uh.modifier1 = 17;
uh.modifier2 = 0;
uh.pktsize = (uint16_t) size;
uh.pktsize = (uint16_t) len;
#ifdef __BIG_ENDIAN__
uh.pktsize = uwsgi_swap16(uh.pktsize);
#endif
@@ -231,7 +308,7 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core
goto clear;
}
if (write(fd, buffer, size) != size) {
if (write(fd, buf, len) != (ssize_t) len) {
uwsgi_log("[spooler] unable to write args for %s\n", filename);
goto clear;
}
@@ -243,28 +320,28 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core
}
}
if (at > 0) {
if (sr.at > 0) {
#ifdef __UCLIBC__
struct timespec ts[2];
ts[0].tv_sec = at;
ts[0].tv_sec = sr.at;
ts[0].tv_nsec = 0;
ts[1].tv_sec = at;
ts[1].tv_sec = sr.at;
ts[1].tv_nsec = 0;
if (futimens(fd, ts)) {
uwsgi_error("futimens()");
uwsgi_error("uwsgi_spooler_request()/futimens()");
}
#else
struct timeval tv[2];
tv[0].tv_sec = at;
tv[0].tv_sec = sr.at;
tv[0].tv_usec = 0;
tv[1].tv_sec = at;
tv[1].tv_sec = sr.at;
tv[1].tv_usec = 0;
#ifdef __sun__
if (futimesat(fd, NULL, tv)) {
#else
if (futimes(fd, tv)) {
#endif
uwsgi_error("futimes()");
uwsgi_error("uwsgi_spooler_request()/futimes()");
}
#endif
}
@@ -273,7 +350,7 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core
close(fd);
if (!uwsgi.spooler_quiet)
uwsgi_log("[spooler] written %lu bytes to file %s\n", (unsigned long) size + body_len + 4, filename);
uwsgi_log("[spooler] written %lu bytes to file %s\n", (unsigned long) len + body_len + 4, filename);
// and here waiting threads can continue
uwsgi_unlock(uspool->lock);
@@ -293,18 +370,19 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core
spoolers = spoolers->next;
}
return 1;
return filename;
clear:
uwsgi_unlock(uspool->lock);
uwsgi_error("write()");
uwsgi_error("uwsgi_spool_request()/write()");
if (unlink(filename)) {
uwsgi_error("unlink()");
uwsgi_error("uwsgi_spool_request()/unlink()");
}
free(filename);
// unlock the file too
close(fd);
return 0;
return NULL;
}
@@ -367,7 +445,7 @@ void spooler(struct uwsgi_spooler *uspool) {
spooler_readdir(uspool, NULL);
}
int timeout = uwsgi.shared->spooler_frequency;
int timeout = uwsgi.shared->spooler_frequency ? uwsgi.shared->spooler_frequency : uwsgi.spooler_frequency;
if (wakeup > 0) {
timeout = 0;
}
+109 -13
View File
@@ -95,15 +95,38 @@ static int uwsgi_sni_cb(SSL *ssl, int *ad, void *arg) {
const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
if (!servername) return SSL_TLSEXT_ERR_NOACK;
size_t servername_len = strlen(servername);
// reduce DOS attempts
int count = 5;
struct uwsgi_string_list *usl = uwsgi.sni;
while(usl) {
if (!uwsgi_strncmp(usl->value, usl->len, (char *)servername, servername_len)) {
SSL_set_SSL_CTX(ssl, usl->custom_ptr);
return SSL_TLSEXT_ERR_OK;
}
usl = usl->next;
}
while(count > 0) {
struct uwsgi_string_list *usl = uwsgi.sni;
while(usl) {
if (!uwsgi_strncmp(usl->value, usl->len, (char *)servername, servername_len)) {
SSL_set_SSL_CTX(ssl, (SSL_CTX *) usl->custom_ptr);
// the following steps are taken from nginx
SSL_set_verify(ssl, SSL_CTX_get_verify_mode((SSL_CTX *)usl->custom_ptr),
SSL_CTX_get_verify_callback((SSL_CTX *)usl->custom_ptr));
SSL_set_verify_depth(ssl, SSL_CTX_get_verify_depth((SSL_CTX *)usl->custom_ptr));
#ifdef SSL_CTRL_CLEAR_OPTIONS
SSL_clear_options(ssl, SSL_get_options(ssl) & ~SSL_CTX_get_options((SSL_CTX *)usl->custom_ptr));
#endif
SSL_set_options(ssl, SSL_CTX_get_options((SSL_CTX *)usl->custom_ptr));
return SSL_TLSEXT_ERR_OK;
}
usl = usl->next;
}
if (!uwsgi.subscription_dotsplit) break;
char *next = memchr(servername+1, '.', servername_len-1);
if (next) {
servername_len -= next - servername;
servername = next;
count--;
continue;
}
break;
}
if (uwsgi.subscription_dotsplit) goto end;
#ifdef UWSGI_PCRE
struct uwsgi_regexp_list *url = uwsgi.sni_regexp;
@@ -126,7 +149,7 @@ static int uwsgi_sni_cb(SSL *ssl, int *ad, void *arg) {
if (uwsgi_file_exists(sni_dir_client_ca)) {
client_ca = sni_dir_client_ca;
}
usl = uwsgi_ssl_add_sni_item(uwsgi_str((char *)servername), sni_dir_cert, sni_dir_key, uwsgi.sni_dir_ciphers, client_ca);
struct uwsgi_string_list *usl = uwsgi_ssl_add_sni_item(uwsgi_str((char *)servername), sni_dir_cert, sni_dir_key, uwsgi.sni_dir_ciphers, client_ca);
if (!usl) goto done;
free(sni_dir_cert);
free(sni_dir_key);
@@ -139,13 +162,39 @@ done:
free(sni_dir_key);
free(sni_dir_client_ca);
}
end:
return SSL_TLSEXT_ERR_NOACK;
}
#endif
char *uwsgi_write_pem_to_file(char *name, char *buf, size_t len, char *ext) {
if (!uwsgi.ssl_tmp_dir) return NULL;
char *filename = uwsgi_concat4(uwsgi.ssl_tmp_dir, "/", name, ext);
int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR);
if (fd < 0) {
uwsgi_error_open(filename);
free(filename);
return NULL;
}
if (write(fd, buf, len) != (ssize_t) len) {
uwsgi_log("unable to write pem data in file %s\n", filename);
uwsgi_error("uwsgi_write_pem_to_file()/write()");
free(filename);
close(fd);
return NULL;
}
close(fd);
return filename;
}
SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ciphers, char *client_ca) {
int crt_need_free = 0;
int key_need_free = 0;
int client_ca_need_free = 0;
SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
if (!ctx) {
uwsgi_log("[uwsgi-ssl] unable to initialize context \"%s\"\n", name);
@@ -165,11 +214,27 @@ SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ci
#ifdef SSL_MODE_RELEASE_BUFFERS
SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
#endif
/*
we need to support both file-based certs and stream based
as dealing with openssl memory bio for keys is really overkill,
we store them in a tmp directory
*/
if (uwsgi.ssl_tmp_dir && !uwsgi_starts_with(crt, strlen(crt), "-----BEGIN ", 11)) {
crt = uwsgi_write_pem_to_file(name, crt, strlen(crt), ".crt");
if (!crt) {
SSL_CTX_free(ctx);
return NULL;
}
crt_need_free = 1;
}
if (SSL_CTX_use_certificate_chain_file(ctx, crt) <= 0) {
uwsgi_log("[uwsgi-ssl] unable to assign certificate %s for context \"%s\"\n", crt, name);
SSL_CTX_free(ctx);
return NULL;
uwsgi_log("[uwsgi-ssl] unable to assign certificate %s for context \"%s\"\n", crt, name);
SSL_CTX_free(ctx);
if (crt_need_free) free(crt);
return NULL;
}
// this part is based from stud
@@ -192,12 +257,25 @@ SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ci
}
}
if (crt_need_free) free(crt);
if (uwsgi.ssl_tmp_dir && !uwsgi_starts_with(key, strlen(key), "-----BEGIN ", 11)) {
key = uwsgi_write_pem_to_file(name, key, strlen(key), ".key");
if (!key) {
SSL_CTX_free(ctx);
return NULL;
}
key_need_free = 1;
}
if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) <= 0) {
uwsgi_log("[uwsgi-ssl] unable to assign key %s for context \"%s\"\n", key, name);
SSL_CTX_free(ctx);
if (key_need_free) free(key);
return NULL;
}
if (key_need_free) free(key);
// if ciphers are specified, prefer server ciphers
if (ciphers && strlen(ciphers) > 0) {
@@ -225,19 +303,37 @@ SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ci
}
// in the future we should allow to set the verify depth
SSL_CTX_set_verify_depth(ctx, 1);
if (uwsgi.ssl_tmp_dir && !uwsgi_starts_with(client_ca, strlen(client_ca), "-----BEGIN ", 11)) {
if (!name) {
SSL_CTX_free(ctx);
return NULL;
}
client_ca = uwsgi_write_pem_to_file(name, client_ca, strlen(client_ca), ".ca");
if (!client_ca) {
SSL_CTX_free(ctx);
return NULL;
}
client_ca_need_free = 1;
}
if (SSL_CTX_load_verify_locations(ctx, client_ca, NULL) == 0) {
uwsgi_log("[uwsgi-ssl] unable to set ssl verify locations (%s) for context \"%s\"\n", client_ca, name);
SSL_CTX_free(ctx);
if (client_ca_need_free) free(client_ca);
return NULL;
}
STACK_OF(X509_NAME) * list = SSL_load_client_CA_file(client_ca);
if (!list) {
uwsgi_log("unable to load client CA certificate (%s) for context \"%s\"\n", client_ca, name);
SSL_CTX_free(ctx);
if (client_ca_need_free) free(client_ca);
return NULL;
}
SSL_CTX_set_client_CA_list(ctx, list);
if (client_ca_need_free) free(client_ca);
}
+2 -1
View File
@@ -450,7 +450,8 @@ int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, si
if (wsgi_req->if_modified_since_len) {
time_t ims = parse_http_date(wsgi_req->if_modified_since, wsgi_req->if_modified_since_len);
if (st->st_mtime <= ims) {
uwsgi_response_prepare_headers(wsgi_req, "304 Not Modified", 16);
if (uwsgi_response_prepare_headers(wsgi_req, "304 Not Modified", 16))
return -1;
return uwsgi_response_write_headers_do(wsgi_req);
}
}
+1 -1
View File
@@ -578,7 +578,7 @@ static void stats_dump_var(char *k, uint16_t kl, char *v, uint16_t vl, void *dat
int uwsgi_stats_dump_vars(struct uwsgi_stats *us, struct uwsgi_core *uc) {
if (!uc->in_request) return 0;
struct uwsgi_header *uh = (struct uwsgi_header *) uwsgi.workers[0].cores[0].buffer;
struct uwsgi_header *uh = (struct uwsgi_header *) uc->buffer;
uint16_t pktsize = uh->pktsize;
if (!pktsize) return 0;
char *dst = uwsgi.workers[0].cores[0].buffer;
+435 -326
View File
@@ -23,46 +23,52 @@ extern struct uwsgi_server uwsgi;
#ifdef UWSGI_SSL
static void uwsgi_subscription_sni_check(struct uwsgi_subscribe_slot *current_slot, struct uwsgi_subscribe_req *usr) {
if (usr->sni_key_len > 0 && usr->sni_crt_len > 0) {
if (!current_slot->sni_enabled) {
char *sni_key = uwsgi_concat2n(usr->sni_key, usr->sni_key_len, "", 0);
char *sni_crt = uwsgi_concat2n(usr->sni_crt, usr->sni_crt_len, "", 0);
char *sni_ca = NULL;
if (usr->sni_ca_len > 0) {
sni_ca = uwsgi_concat2n(usr->sni_ca, usr->sni_ca_len, "", 0);
}
char *servername = NULL;
char *colon = memchr(current_slot->key, ':', current_slot->keylen);
if (colon) {
servername = uwsgi_concat2n(current_slot->key, colon-current_slot->key, "", 0);
}
else {
servername = uwsgi_concat2n(current_slot->key, current_slot->keylen, "", 0);
}
if (uwsgi_ssl_add_sni_item(servername, sni_crt, sni_key, uwsgi.sni_dir_ciphers , sni_ca)) {
current_slot->sni_enabled = 1;
}
if (sni_key) free(sni_key);
if (sni_crt) free(sni_crt);
if (sni_ca) free(sni_ca);
}
}
if (!current_slot->sni_enabled) {
char *sni_key = uwsgi_concat2n(usr->sni_key, usr->sni_key_len, "", 0);
char *sni_crt = uwsgi_concat2n(usr->sni_crt, usr->sni_crt_len, "", 0);
char *sni_ca = NULL;
if (usr->sni_ca_len > 0) {
sni_ca = uwsgi_concat2n(usr->sni_ca, usr->sni_ca_len, "", 0);
}
char *servername = NULL;
char *colon = memchr(current_slot->key, ':', current_slot->keylen);
if (colon) {
servername = uwsgi_concat2n(current_slot->key, colon - current_slot->key, "", 0);
}
else {
servername = uwsgi_concat2n(current_slot->key, current_slot->keylen, "", 0);
}
if (uwsgi_ssl_add_sni_item(servername, sni_crt, sni_key, uwsgi.sni_dir_ciphers, sni_ca)) {
current_slot->sni_enabled = 1;
}
if (sni_key)
free(sni_key);
if (sni_crt)
free(sni_crt);
if (sni_ca)
free(sni_ca);
}
}
}
#endif
int uwsgi_subscription_credentials_check(struct uwsgi_subscribe_slot *slot, struct uwsgi_subscribe_req *usr) {
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.subscriptions_credentials_check_dir) {
char *filename = uwsgi_concat2n(usl->value, usl->len, slot->key, slot->keylen);
struct stat st;
int ret = stat(filename, &st);
free(filename);
if (ret != 0) continue;
if (st.st_uid != usr->uid) continue;
if (st.st_gid != usr->gid) continue;
// accepted...
return 1;
}
return 0;
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.subscriptions_credentials_check_dir) {
char *filename = uwsgi_concat2n(usl->value, usl->len, slot->key, slot->keylen);
struct stat st;
int ret = stat(filename, &st);
free(filename);
if (ret != 0)
continue;
if (st.st_uid != usr->uid)
continue;
if (st.st_gid != usr->gid)
continue;
// accepted...
return 1;
}
return 0;
}
struct uwsgi_subscribe_slot *uwsgi_get_subscribe_slot(struct uwsgi_subscribe_slot **slot, char *key, uint16_t keylen) {
@@ -346,7 +352,7 @@ int uwsgi_remove_subscribe_node(struct uwsgi_subscribe_slot **slot, struct uwsgi
// first check if i am the only node
if ((!prev_slot && !next_slot) || next_slot == node_slot) {
#ifdef UWSGI_SSL
if (uwsgi.subscriptions_sign_check_dir) {
if (node_slot->sign_ctx) {
EVP_PKEY_free(node_slot->sign_public_key);
EVP_MD_CTX_destroy(node_slot->sign_ctx);
}
@@ -375,7 +381,7 @@ int uwsgi_remove_subscribe_node(struct uwsgi_subscribe_slot **slot, struct uwsgi
}
#ifdef UWSGI_SSL
if (uwsgi.subscriptions_sign_check_dir) {
if (node_slot->sign_ctx) {
EVP_PKEY_free(node_slot->sign_public_key);
EVP_MD_CTX_destroy(node_slot->sign_ctx);
}
@@ -388,6 +394,11 @@ end:
return ret;
}
#ifdef UWSGI_SSL
static int subscription_new_sign_ctx(struct uwsgi_subscribe_slot *, struct uwsgi_subscribe_req *);
static int subscription_is_safe(struct uwsgi_subscribe_req *);
#endif
struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slot **slot, struct uwsgi_subscribe_req *usr) {
struct uwsgi_subscribe_slot *current_slot = uwsgi_get_subscribe_slot(slot, usr->key, usr->keylen), *old_slot = NULL, *a_slot;
@@ -396,13 +407,6 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
if (usr->address_len > 0xff || usr->address_len == 0)
return NULL;
#ifdef UWSGI_SSL
if (uwsgi.subscriptions_sign_check_dir) {
if (usr->sign_len == 0 || usr->base_len == 0)
return NULL;
}
#endif
if (current_slot) {
#ifdef UWSGI_SSL
if (uwsgi.subscriptions_sign_check_dir && !uwsgi_subscription_sign_check(current_slot, usr)) {
@@ -419,7 +423,7 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
if (!uwsgi_strncmp(node->name, node->len, usr->address, usr->address_len)) {
#ifdef UWSGI_SSL
// this should avoid sending sniffed packets...
if (uwsgi.subscriptions_sign_check_dir && usr->unix_check <= node->unix_check) {
if (current_slot->sign_ctx && !subscription_is_safe(usr) && usr->unix_check <= node->unix_check) {
uwsgi_log("[uwsgi-subscription for pid %d] invalid (sniffed ?) packet sent for slot: %.*s node: %.*s unix_check: %lu\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address, (unsigned long) usr->unix_check);
return NULL;
}
@@ -440,12 +444,12 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
}
#ifdef UWSGI_SSL
if (uwsgi.subscriptions_sign_check_dir && usr->unix_check < (uwsgi_now() - (time_t) uwsgi.subscriptions_sign_check_tolerance)) {
if (current_slot->sign_ctx && !subscription_is_safe(usr) && usr->unix_check < (uwsgi_now() - (time_t) uwsgi.subscriptions_sign_check_tolerance)) {
uwsgi_log("[uwsgi-subscription for pid %d] invalid (sniffed ?) packet sent for slot: %.*s node: %.*s unix_check: %lu\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address, (unsigned long) usr->unix_check);
return NULL;
return NULL;
}
// check here as we are sure the node will be added
uwsgi_subscription_sni_check(current_slot, usr);
uwsgi_subscription_sni_check(current_slot, usr);
#endif
node = uwsgi_malloc(sizeof(struct uwsgi_subscribe_node));
@@ -469,6 +473,11 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
node->pid = usr->pid;
node->uid = usr->uid;
node->gid = usr->gid;
node->notify[0] = 0;
if (usr->notify_len > 0 && usr->notify_len < 102) {
memcpy(node->notify, usr->notify, usr->notify_len);
node->notify[usr->notify_len] = 0;
}
node->last_check = uwsgi_now();
node->slot = current_slot;
memcpy(node->name, usr->address, usr->address_len);
@@ -476,54 +485,28 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
old_node->next = node;
}
node->next = NULL;
uwsgi_log("[uwsgi-subscription for pid %d] %.*s => new node: %.*s\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address);
if (node->notify[0]) {
char buf[1024];
int ret = snprintf(buf, 1024, "[subscription ack] %.*s => new node: %.*s", usr->keylen, usr->key, usr->address_len, usr->address);
if (ret > 0 && ret < 1024)
uwsgi_notify_msg(node->notify, buf, ret);
}
return node;
}
else {
current_slot = uwsgi_malloc(sizeof(struct uwsgi_subscribe_slot));
#ifdef UWSGI_SSL
FILE *kf = NULL;
if (uwsgi.subscriptions_sign_check_dir) {
if (usr->unix_check < (uwsgi_now() - (time_t) uwsgi.subscriptions_sign_check_tolerance)) {
uwsgi_log("[uwsgi-subscription for pid %d] invalid (sniffed ?) packet sent for slot: %.*s node: %.*s unix_check: %lu\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address, (unsigned long) usr->unix_check);
return NULL;
}
char *keyfile = uwsgi_sanitize_cert_filename(uwsgi.subscriptions_sign_check_dir, usr->key, usr->keylen);
kf = fopen(keyfile, "r");
free(keyfile);
if (!kf)
return NULL;
current_slot->sign_ctx = NULL;
if (uwsgi.subscriptions_sign_check_dir && !subscription_new_sign_ctx(current_slot, usr)) {
free(current_slot);
return NULL;
}
#endif
current_slot = uwsgi_malloc(sizeof(struct uwsgi_subscribe_slot));
uint32_t hash = djb33x_hash(usr->key, usr->keylen);
int hash_key = hash % 0xffff;
current_slot->hash = hash_key;
#ifdef UWSGI_SSL
if (uwsgi.subscriptions_sign_check_dir) {
current_slot->sign_public_key = PEM_read_PUBKEY(kf, NULL, NULL, NULL);
fclose(kf);
if (!current_slot->sign_public_key) {
uwsgi_log("unable to load public key for %.*s\n", usr->keylen, usr->key);
free(current_slot);
return NULL;
}
current_slot->sign_ctx = EVP_MD_CTX_create();
if (!current_slot->sign_ctx) {
uwsgi_log("unable to initialize EVP context for %.*s\n", usr->keylen, usr->key);
EVP_PKEY_free(current_slot->sign_public_key);
free(current_slot);
return NULL;
}
if (!uwsgi_subscription_sign_check(current_slot, usr)) {
EVP_PKEY_free(current_slot->sign_public_key);
EVP_MD_CTX_destroy(current_slot->sign_ctx);
free(current_slot);
return NULL;
}
}
#endif
current_slot->keylen = usr->keylen;
memcpy(current_slot->key, usr->key, usr->keylen);
if (uwsgi.subscriptions_credentials_check_dir) {
@@ -561,6 +544,11 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
current_slot->nodes->pid = usr->pid;
current_slot->nodes->uid = usr->uid;
current_slot->nodes->gid = usr->gid;
current_slot->nodes->notify[0] = 0;
if (usr->notify_len > 0 && usr->notify_len < 102) {
memcpy(current_slot->nodes->notify, usr->notify, usr->notify_len);
current_slot->nodes->notify[usr->notify_len] = 0;
}
memcpy(current_slot->nodes->name, usr->address, usr->address_len);
current_slot->nodes->last_check = uwsgi_now();
@@ -587,98 +575,153 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
uwsgi_log("[uwsgi-subscription for pid %d] new pool: %.*s (hash key: %d)\n", (int) uwsgi.mypid, usr->keylen, usr->key, current_slot->hash);
uwsgi_log("[uwsgi-subscription for pid %d] %.*s => new node: %.*s\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address);
if (current_slot->nodes->notify[0]) {
char buf[1024];
int ret = snprintf(buf, 1024, "[subscription ack] %.*s => new node: %.*s", usr->keylen, usr->key, usr->address_len, usr->address);
if (ret > 0 && ret < 1024)
uwsgi_notify_msg(current_slot->nodes->notify, buf, ret);
}
return current_slot->nodes;
}
}
static void send_subscription(char *host, char *message, uint16_t message_size) {
static void send_subscription(int sfd, char *host, char *message, uint16_t message_size) {
int fd;
struct sockaddr_in udp_addr;
struct sockaddr_un un_addr;
ssize_t ret;
int fd = sfd;
struct sockaddr_in udp_addr;
struct sockaddr_un un_addr;
ssize_t ret;
char *udp_port = strchr(host, ':');
if (udp_port) {
udp_port[0] = 0;
char *udp_port = strchr(host, ':');
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
uwsgi_error("send_subscription()/socket()");
return;
}
memset(&udp_addr, 0, sizeof(struct sockaddr_in));
udp_addr.sin_family = AF_INET;
udp_addr.sin_port = htons(atoi(udp_port + 1));
udp_addr.sin_addr.s_addr = inet_addr(host);
}
else {
fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (fd < 0) {
uwsgi_error("send_subscription()/socket()");
return;
}
memset(&un_addr, 0, sizeof(struct sockaddr_un));
un_addr.sun_family = AF_UNIX;
// use 102 as the magic number
strncat(un_addr.sun_path, host, 102);
}
if (udp_port) {
ret = sendto(fd, message, message_size, 0, (struct sockaddr *) &udp_addr, sizeof(udp_addr));
udp_port[0] = ':';
}
else {
if (uwsgi.subscriptions_use_credentials) {
// could be useless as internally the socket could add them automagically
ret = uwsgi_pass_cred2(fd, message, message_size, (struct sockaddr *) &un_addr, sizeof(un_addr));
if (fd == -1) {
if (udp_port) {
fd = socket(AF_INET, SOCK_DGRAM, 0);
}
else {
ret = sendto(fd, message, message_size, 0, (struct sockaddr *) &un_addr, sizeof(un_addr));
fd = socket(AF_UNIX, SOCK_DGRAM, 0);
}
if (fd < 0) {
uwsgi_error("send_subscription()/socket()");
return;
}
uwsgi_socket_nb(fd);
}
else if (fd == -2) {
static int unix_fd = -1;
static int inet_fd = -1;
if (udp_port) {
if (inet_fd == -1) {
inet_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (inet_fd < 0) {
uwsgi_error("send_subscription()/socket()");
return;
}
uwsgi_socket_nb(inet_fd);
}
fd = inet_fd;
}
else {
if (unix_fd == -1) {
unix_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (unix_fd < 0) {
uwsgi_error("send_subscription()/socket()");
return;
}
uwsgi_socket_nb(unix_fd);
}
fd = unix_fd;
}
}
if (ret < 0) {
uwsgi_error("send_subscription()/sendto()");
}
close(fd);
}
void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8_t modifier1, uint8_t modifier2, uint8_t cmd, char *socket_name, char *sign, char *sni_key, char *sni_crt, char *sni_ca) {
if (socket_name == NULL && !uwsgi.sockets)
return;
if (!socket_name) {
socket_name = uwsgi.sockets->name;
}
struct uwsgi_buffer *ub = uwsgi_buffer_new(4096);
if (udp_port) {
udp_port[0] = 0;
memset(&udp_addr, 0, sizeof(struct sockaddr_in));
udp_addr.sin_family = AF_INET;
udp_addr.sin_port = htons(atoi(udp_port + 1));
udp_addr.sin_addr.s_addr = inet_addr(host);
ret = sendto(fd, message, message_size, 0, (struct sockaddr *) &udp_addr, sizeof(udp_addr));
udp_port[0] = ':';
}
else {
memset(&un_addr, 0, sizeof(struct sockaddr_un));
un_addr.sun_family = AF_UNIX;
// use 102 as the magic number
strncat(un_addr.sun_path, host, 102);
if (uwsgi.subscriptions_use_credentials) {
// could be useless as internally the socket could add them automagically
ret = uwsgi_pass_cred2(fd, message, message_size, (struct sockaddr *) &un_addr, sizeof(un_addr));
}
else {
ret = sendto(fd, message, message_size, 0, (struct sockaddr *) &un_addr, sizeof(un_addr));
}
}
if (ret < 0) {
uwsgi_error("send_subscription()/sendto()");
}
if (sfd == -1)
close(fd);
}
static struct uwsgi_buffer *uwsgi_subscription_ub(char *key, size_t keysize, uint8_t modifier1, uint8_t modifier2, uint8_t cmd, char *socket_name, char *sign, char *sni_key, char *sni_crt, char *sni_ca) {
struct uwsgi_buffer *ub = uwsgi_buffer_new(4096);
// make space for uwsgi header
ub->pos = 4;
if (uwsgi_buffer_append_keyval(ub, "key", 3, key, keysize)) goto end;
if (uwsgi_buffer_append_keyval(ub, "address", 7, socket_name, strlen(socket_name))) goto end;
if (uwsgi_buffer_append_keynum(ub, "modifier1", 9, modifier1)) goto end;
if (uwsgi_buffer_append_keynum(ub, "modifier2", 9, modifier2)) goto end;
if (uwsgi_buffer_append_keynum(ub, "cores", 5, uwsgi.numproc * uwsgi.cores)) goto end;
if (uwsgi_buffer_append_keynum(ub, "load", 4, uwsgi.shared->load)) goto end;
if (uwsgi_buffer_append_keyval(ub, "key", 3, key, keysize))
goto end;
if (uwsgi_buffer_append_keyval(ub, "address", 7, socket_name, strlen(socket_name)))
goto end;
if (uwsgi_buffer_append_keynum(ub, "modifier1", 9, modifier1))
goto end;
if (uwsgi_buffer_append_keynum(ub, "modifier2", 9, modifier2))
goto end;
if (uwsgi_buffer_append_keynum(ub, "cores", 5, uwsgi.numproc * uwsgi.cores))
goto end;
if (uwsgi_buffer_append_keynum(ub, "load", 4, uwsgi.shared->load))
goto end;
if (uwsgi.auto_weight) {
if (uwsgi_buffer_append_keynum(ub, "weight", 6, uwsgi.numproc * uwsgi.cores )) goto end;
if (uwsgi_buffer_append_keynum(ub, "weight", 6, uwsgi.numproc * uwsgi.cores))
goto end;
}
else {
if (uwsgi_buffer_append_keynum(ub, "weight", 6, uwsgi.weight )) goto end;
if (uwsgi_buffer_append_keynum(ub, "weight", 6, uwsgi.weight))
goto end;
}
if (sni_key) {
if (uwsgi_buffer_append_keyval(ub, "sni_key", 7, sni_key, strlen(sni_key)))
goto end;
}
if (sni_crt) {
if (uwsgi_buffer_append_keyval(ub, "sni_crt", 7, sni_crt, strlen(sni_crt)))
goto end;
}
if (sni_ca) {
if (uwsgi_buffer_append_keyval(ub, "sni_ca", 6, sni_ca, strlen(sni_ca)))
goto end;
}
if (uwsgi.subscription_notify_socket) {
if (uwsgi_buffer_append_keyval(ub, "notify", 6, uwsgi.subscription_notify_socket, strlen(uwsgi.subscription_notify_socket)))
goto end;
}
else if (uwsgi.notify_socket_fd > -1 && uwsgi.notify_socket) {
if (uwsgi_buffer_append_keyval(ub, "notify", 6, uwsgi.notify_socket, strlen(uwsgi.notify_socket)))
goto end;
}
#ifdef UWSGI_SSL
if (sign) {
if (uwsgi_buffer_append_keynum(ub, "unix", 4, (uwsgi_now() + (time_t) cmd) )) goto end;
if (uwsgi_buffer_append_keynum(ub, "unix", 4, (uwsgi_now() + (time_t) cmd)))
goto end;
unsigned int signature_len = 0;
char *signature = uwsgi_rsa_sign(sign, ub->buf + 4, ub->pos - 4, &signature_len);
@@ -692,29 +735,98 @@ void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8
}
#endif
if (sni_key) {
if (uwsgi_buffer_append_keyval(ub, "sni_key", 7, sni_key, strlen(sni_key))) goto end;
}
if (sni_crt) {
if (uwsgi_buffer_append_keyval(ub, "sni_crt", 7, sni_crt, strlen(sni_crt))) goto end;
}
if (sni_ca) {
if (uwsgi_buffer_append_keyval(ub, "sni_ca", 6, sni_ca, strlen(sni_ca))) goto end;
}
// add uwsgi header
if (uwsgi_buffer_set_uh(ub, 224, cmd)) goto end;
if (uwsgi_buffer_set_uh(ub, 224, cmd))
goto end;
return ub;
send_subscription(udp_address, ub->buf, ub->pos);
end:
uwsgi_buffer_destroy(ub);
return NULL;
}
void uwsgi_send_subscription_from_fd(int fd, char *udp_address, char *key, size_t keysize, uint8_t modifier1, uint8_t modifier2, uint8_t cmd, char *socket_name, char *sign, char *sni_key, char *sni_crt, char *sni_ca) {
if (socket_name == NULL && !uwsgi.sockets)
return;
if (!socket_name) {
socket_name = uwsgi.sockets->name;
}
struct uwsgi_buffer *ub = uwsgi_subscription_ub(key, keysize, modifier1, modifier2, cmd, socket_name, sign, sni_key, sni_crt, sni_ca);
if (!ub)
return;
send_subscription(fd, udp_address, ub->buf, ub->pos);
uwsgi_buffer_destroy(ub);
}
void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8_t modifier1, uint8_t modifier2, uint8_t cmd, char *socket_name, char *sign, char *sni_key, char *sni_crt, char *sni_ca) {
uwsgi_send_subscription_from_fd(-1, udp_address, key, keysize, modifier1, modifier2, cmd, socket_name, sign, sni_key, sni_crt, sni_ca);
}
#ifdef UWSGI_SSL
static int subscription_is_safe(struct uwsgi_subscribe_req *usr) {
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.subscriptions_sign_skip_uid) {
if (usl->custom == 0) {
usl->custom = atoi(usl->value);
}
if (usr->uid > 0 && usr->uid == (uid_t) usl->custom) {
return 1;
}
}
return 0;
}
static int subscription_new_sign_ctx(struct uwsgi_subscribe_slot *slot, struct uwsgi_subscribe_req *usr) {
if (subscription_is_safe(usr)) return 1;
if (usr->sign_len == 0 || usr->base_len == 0)
return 0;
if (usr->unix_check < (uwsgi_now() - (time_t) uwsgi.subscriptions_sign_check_tolerance)) {
uwsgi_log("[uwsgi-subscription for pid %d] invalid (sniffed ?) packet sent for slot: %.*s node: %.*s unix_check: %lu\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address, (unsigned long) usr->unix_check);
return 0;
}
char *keyfile = uwsgi_sanitize_cert_filename(uwsgi.subscriptions_sign_check_dir, usr->key, usr->keylen);
FILE *kf = fopen(keyfile, "r");
free(keyfile);
if (!kf) return 0;
slot->sign_public_key = PEM_read_PUBKEY(kf, NULL, NULL, NULL);
fclose(kf);
if (!slot->sign_public_key) {
uwsgi_log("unable to load public key for %.*s\n", usr->keylen, usr->key);
return 0;
}
slot->sign_ctx = EVP_MD_CTX_create();
if (!slot->sign_ctx) {
uwsgi_log("unable to initialize EVP context for %.*s\n", usr->keylen, usr->key);
EVP_PKEY_free(slot->sign_public_key);
return 0;
}
if (!uwsgi_subscription_sign_check(slot, usr)) {
EVP_PKEY_free(slot->sign_public_key);
EVP_MD_CTX_destroy(slot->sign_ctx);
return 0;
}
return 1;
}
int uwsgi_subscription_sign_check(struct uwsgi_subscribe_slot *slot, struct uwsgi_subscribe_req *usr) {
if (subscription_is_safe(usr)) return 1;
if (usr->sign_len == 0 || usr->base_len == 0)
return 0;
if (!slot->sign_ctx) {
if (!subscription_new_sign_ctx(slot, usr)) return 0;
}
if (EVP_VerifyInit_ex(slot->sign_ctx, uwsgi.subscriptions_sign_check_md, NULL) == 0) {
ERR_print_errors_fp(stderr);
@@ -756,134 +868,133 @@ struct uwsgi_subscribe_slot **uwsgi_subscription_init_ht() {
void uwsgi_subscribe(char *subscription, uint8_t cmd) {
size_t subfile_size;
size_t i;
char *key = NULL;
int keysize = 0;
char *modifier1 = NULL;
int modifier1_len = 0;
char *socket_name = NULL;
char *udp_address = subscription;
char *udp_port = NULL;
char *subscription_key = NULL;
char *sign = NULL;
size_t subfile_size;
size_t i;
char *key = NULL;
int keysize = 0;
char *modifier1 = NULL;
int modifier1_len = 0;
char *socket_name = NULL;
char *udp_address = subscription;
char *udp_port = NULL;
char *subscription_key = NULL;
char *sign = NULL;
// check for explicit socket_name
char *equal = strchr(subscription, '=');
if (equal) {
socket_name = subscription;
if (socket_name[0] == '=') {
equal = strchr(socket_name + 1, '=');
if (!equal)
return;
*equal = '\0';
struct uwsgi_socket *us = uwsgi_get_shared_socket_by_num(atoi(socket_name + 1));
if (!us)
return;
socket_name = us->name;
}
*equal = '\0';
udp_address = equal + 1;
}
// check for explicit socket_name
char *equal = strchr(subscription, '=');
if (equal) {
socket_name = subscription;
if (socket_name[0] == '=') {
equal = strchr(socket_name + 1, '=');
if (!equal)
return;
*equal = '\0';
struct uwsgi_socket *us = uwsgi_get_shared_socket_by_num(atoi(socket_name + 1));
if (!us)
return;
socket_name = us->name;
}
*equal = '\0';
udp_address = equal + 1;
}
// check for unix socket
if (udp_address[0] != '/') {
udp_port = strchr(udp_address, ':');
if (!udp_port) {
if (equal)
*equal = '=';
return;
}
subscription_key = strchr(udp_port + 1, ':');
}
else {
subscription_key = strchr(udp_address + 1, ':');
}
// check for unix socket
if (udp_address[0] != '/') {
udp_port = strchr(udp_address, ':');
if (!udp_port) {
if (equal)
*equal = '=';
return;
}
subscription_key = strchr(udp_port + 1, ':');
}
else {
subscription_key = strchr(udp_address + 1, ':');
}
if (!subscription_key) {
if (equal)
*equal = '=';
return;
}
if (!subscription_key) {
if (equal)
*equal = '=';
return;
}
udp_address = uwsgi_concat2n(udp_address, subscription_key - udp_address, "", 0);
udp_address = uwsgi_concat2n(udp_address, subscription_key - udp_address, "", 0);
if (subscription_key[1] == '@') {
if (!uwsgi_file_exists(subscription_key + 2))
goto clear;
char *lines = uwsgi_open_and_read(subscription_key + 2, &subfile_size, 1, NULL);
if (subfile_size > 0) {
key = lines;
for (i = 0; i < subfile_size; i++) {
if (lines[i] == 0) {
if (keysize > 0) {
if (key[0] != '#' && key[0] != '\n') {
modifier1 = strchr(key, ',');
if (modifier1) {
modifier1[0] = 0;
modifier1++;
modifier1_len = strlen(modifier1);
keysize = strlen(key);
}
uwsgi_send_subscription(udp_address, key, keysize, uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign, NULL, NULL, NULL);
modifier1 = NULL;
modifier1_len = 0;
}
}
break;
}
else if (lines[i] == '\n') {
if (keysize > 0) {
if (key[0] != '#' && key[0] != '\n') {
lines[i] = 0;
modifier1 = strchr(key, ',');
if (modifier1) {
modifier1[0] = 0;
modifier1++;
modifier1_len = strlen(modifier1);
keysize = strlen(key);
}
uwsgi_send_subscription(udp_address, key, keysize, uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign, NULL, NULL, NULL);
modifier1 = NULL;
modifier1_len = 0;
lines[i] = '\n';
}
}
key = lines + i + 1;
keysize = 0;
continue;
}
keysize++;
}
if (!uwsgi_file_exists(subscription_key + 2))
goto clear;
char *lines = uwsgi_open_and_read(subscription_key + 2, &subfile_size, 1, NULL);
if (subfile_size > 0) {
key = lines;
for (i = 0; i < subfile_size; i++) {
if (lines[i] == 0) {
if (keysize > 0) {
if (key[0] != '#' && key[0] != '\n') {
modifier1 = strchr(key, ',');
if (modifier1) {
modifier1[0] = 0;
modifier1++;
modifier1_len = strlen(modifier1);
keysize = strlen(key);
}
uwsgi_send_subscription(udp_address, key, keysize, uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign, NULL, NULL, NULL);
modifier1 = NULL;
modifier1_len = 0;
}
}
break;
}
else if (lines[i] == '\n') {
if (keysize > 0) {
if (key[0] != '#' && key[0] != '\n') {
lines[i] = 0;
modifier1 = strchr(key, ',');
if (modifier1) {
modifier1[0] = 0;
modifier1++;
modifier1_len = strlen(modifier1);
keysize = strlen(key);
}
uwsgi_send_subscription(udp_address, key, keysize, uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign, NULL, NULL, NULL);
modifier1 = NULL;
modifier1_len = 0;
lines[i] = '\n';
}
}
key = lines + i + 1;
keysize = 0;
continue;
}
keysize++;
}
}
free(lines);
}
else {
modifier1 = strchr(subscription_key + 1, ',');
if (modifier1) {
modifier1[0] = 0;
modifier1++;
free(lines);
}
}
else {
modifier1 = strchr(subscription_key + 1, ',');
if (modifier1) {
modifier1[0] = 0;
modifier1++;
sign = strchr(modifier1 + 1, ',');
if (sign) {
*sign = 0;
sign++;
}
modifier1_len = strlen(modifier1);
}
sign = strchr(modifier1 + 1, ',');
if (sign) {
*sign = 0;
sign++;
}
modifier1_len = strlen(modifier1);
}
uwsgi_send_subscription(udp_address, subscription_key + 1, strlen(subscription_key + 1), uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign, NULL, NULL, NULL);
if (modifier1)
modifier1[-1] = ',';
if (sign)
sign[-1] = ',';
}
uwsgi_send_subscription(udp_address, subscription_key + 1, strlen(subscription_key + 1), uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign, NULL, NULL, NULL);
if (modifier1)
modifier1[-1] = ',';
if (sign)
sign[-1] = ',';
}
clear:
if (equal)
*equal = '=';
free(udp_address);
if (equal)
*equal = '=';
free(udp_address);
}
@@ -902,27 +1013,16 @@ void uwsgi_subscribe2(char *arg, uint8_t cmd) {
char *s2_sni_crt = NULL;
char *s2_sni_ca = NULL;
if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=',
"server", &s2_server,
"key", &s2_key,
"socket", &s2_socket,
"addr", &s2_addr,
"weight", &s2_weight,
"modifier1", &s2_modifier1,
"modifier2", &s2_modifier2,
"sign", &s2_sign,
"check", &s2_check,
"sni_key", &s2_sni_key,
"sni_crt", &s2_sni_crt,
"sni_ca", &s2_sni_ca,
NULL)) {
if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=', "server", &s2_server, "key", &s2_key, "socket", &s2_socket, "addr", &s2_addr, "weight", &s2_weight, "modifier1", &s2_modifier1, "modifier2", &s2_modifier2, "sign", &s2_sign, "check", &s2_check, "sni_key", &s2_sni_key, "sni_crt", &s2_sni_crt, "sni_ca", &s2_sni_ca, NULL)) {
return;
}
if (!s2_server || !s2_key) goto end;
if (!s2_server || !s2_key)
goto end;
if (s2_check) {
if (uwsgi_file_exists(s2_check)) goto end;
if (uwsgi_file_exists(s2_check))
goto end;
}
if (s2_weight) {
@@ -952,39 +1052,48 @@ void uwsgi_subscribe2(char *arg, uint8_t cmd) {
uwsgi_send_subscription(s2_server, s2_key, strlen(s2_key), modifier1, modifier2, cmd, s2_addr, s2_sign, s2_sni_key, s2_sni_crt, s2_sni_ca);
end:
if (s2_server) free(s2_server);
if (s2_key) free(s2_key);
if (s2_socket) free(s2_socket);
if (s2_addr) free(s2_addr);
if (s2_weight) free(s2_weight);
if (s2_modifier1) free(s2_modifier1);
if (s2_modifier2) free(s2_modifier2);
if (s2_sign) free(s2_sign);
if (s2_check) free(s2_check);
if (s2_server)
free(s2_server);
if (s2_key)
free(s2_key);
if (s2_socket)
free(s2_socket);
if (s2_addr)
free(s2_addr);
if (s2_weight)
free(s2_weight);
if (s2_modifier1)
free(s2_modifier1);
if (s2_modifier2)
free(s2_modifier2);
if (s2_sign)
free(s2_sign);
if (s2_check)
free(s2_check);
}
void uwsgi_subscribe_all(uint8_t cmd, int verbose) {
if (uwsgi.subscriptions_blocked) return;
if (uwsgi.subscriptions_blocked)
return;
// -- subscribe
struct uwsgi_string_list *subscriptions = uwsgi.subscriptions;
while (subscriptions) {
while (subscriptions) {
if (verbose) {
uwsgi_log("%s %s\n", cmd ? "unsubscribing from" : "subscribing to", subscriptions->value);
uwsgi_log("%s %s\n", cmd ? "unsubscribing from" : "subscribing to", subscriptions->value);
}
uwsgi_subscribe(subscriptions->value, cmd);
subscriptions = subscriptions->next;
}
uwsgi_subscribe(subscriptions->value, cmd);
subscriptions = subscriptions->next;
}
// --subscribe2
subscriptions = uwsgi.subscriptions2;
while (subscriptions) {
if (verbose) {
uwsgi_log("%s %s\n", cmd ? "unsubscribing from" : "subscribing to", subscriptions->value);
}
uwsgi_subscribe2(subscriptions->value, cmd);
subscriptions = subscriptions->next;
}
while (subscriptions) {
if (verbose) {
uwsgi_log("%s %s\n", cmd ? "unsubscribing from" : "subscribing to", subscriptions->value);
}
uwsgi_subscribe2(subscriptions->value, cmd);
subscriptions = subscriptions->next;
}
}
+51 -32
View File
@@ -754,7 +754,11 @@ void uwsgi_as_root() {
}
if (uwsgi.logfile_chown) {
if (fchown(2, uwsgi.uid, uwsgi.gid)) {
int log_fd = 2;
if (uwsgi.log_master && uwsgi.original_log_fd > -1) {
log_fd = uwsgi.original_log_fd;
}
if (fchown(log_fd, uwsgi.uid, uwsgi.gid)) {
uwsgi_error("fchown()");
exit(1);
}
@@ -978,19 +982,44 @@ nonroot:
}
}
static void close_and_free_request(struct wsgi_request *wsgi_req) {
// close the connection with the client
if (!wsgi_req->fd_closed) {
// NOTE, if we close the socket before receiving eventually sent data, socket layer will send a RST
wsgi_req->socket->proto_close(wsgi_req);
}
if (wsgi_req->post_file) {
fclose(wsgi_req->post_file);
}
if (wsgi_req->post_read_buf) {
free(wsgi_req->post_read_buf);
}
if (wsgi_req->post_readline_buf) {
free(wsgi_req->post_readline_buf);
}
if (wsgi_req->proto_parser_buf) {
free(wsgi_req->proto_parser_buf);
}
}
// destroy a request
void uwsgi_destroy_request(struct wsgi_request *wsgi_req) {
wsgi_req->socket->proto_close(wsgi_req);
close_and_free_request(wsgi_req);
int foo;
if (uwsgi.threads > 1) {
// now the thread can die...
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &foo);
}
memset(wsgi_req, 0, sizeof(struct wsgi_request));
if (uwsgi.threads > 1) {
// now the thread can die...
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &foo);
}
memset(wsgi_req, 0, sizeof(struct wsgi_request));
}
@@ -1049,27 +1078,8 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
uwsgi_apply_final_routes(wsgi_req);
#endif
// close the connection with the client
if (!wsgi_req->fd_closed) {
// NOTE, if we close the socket before receiving eventually sent data, socket layer will send a RST
wsgi_req->socket->proto_close(wsgi_req);
}
if (wsgi_req->post_file) {
fclose(wsgi_req->post_file);
}
if (wsgi_req->post_read_buf) {
free(wsgi_req->post_read_buf);
}
if (wsgi_req->post_readline_buf) {
free(wsgi_req->post_readline_buf);
}
if (wsgi_req->proto_parser_buf) {
free(wsgi_req->proto_parser_buf);
}
// close socket and free parsers-allocated memory
close_and_free_request(wsgi_req);
// after_request hook
if (!wsgi_req->is_raw && uwsgi.p[wsgi_req->uh->modifier1]->after_request)
@@ -1432,7 +1442,7 @@ void uwsgi_heartbeat() {
return;
time_t now = uwsgi_now();
if (uwsgi.next_heartbeat < now) {
if (uwsgi.next_heartbeat <= now) {
char byte = 26;
if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
uwsgi_error("write()");
@@ -1456,7 +1466,15 @@ int wsgi_req_accept(int queue, struct wsgi_request *wsgi_req) {
// heartbeat
// in multithreaded mode we are now locked
if (uwsgi.has_emperor && uwsgi.heartbeat) {
time_t now = uwsgi_now();
// overengineering ... (reduce skew problems)
timeout = uwsgi.heartbeat;
if (!uwsgi.next_heartbeat) {
uwsgi.next_heartbeat = now;
}
if (uwsgi.next_heartbeat >= now) {
timeout = uwsgi.next_heartbeat - now;
}
}
// need edge trigger ?
@@ -1479,7 +1497,7 @@ int wsgi_req_accept(int queue, struct wsgi_request *wsgi_req) {
}
// check for heartbeat
if (timeout > 0) {
if (uwsgi.has_emperor && uwsgi.heartbeat) {
uwsgi_heartbeat();
// no need to continue if timed-out
if (ret == 0) {
@@ -4182,7 +4200,8 @@ char *uwsgi_str_to_hex(char *src, size_t slen) {
char *ptr = dst;
size_t i;
for (i = 0; i < slen; i++) {
memcpy(ptr, uwsgi_hex_table[(int) src[i]], 2);
uint8_t pos = (uint8_t) src[i];
memcpy(ptr, uwsgi_hex_table[pos], 2);
ptr += 2;
}
return dst;
+76 -12
View File
@@ -2,7 +2,7 @@
*** uWSGI ***
Copyright (C) 2009-2013 Unbit S.a.s. <info@unbit.it>
Copyright (C) 2009-2014 Unbit S.a.s. <info@unbit.it>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@@ -99,10 +99,12 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"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},
{"declare-option2", required_argument, 0, "declare a new uWSGI custom option (non-immediate)", uwsgi_opt_add_custom_option, NULL, 0},
{"for", required_argument, 0, "(opt logic) for cycle", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for, UWSGI_OPT_IMMEDIATE},
{"for-glob", required_argument, 0, "(opt logic) for cycle (expand glob)", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for_glob, UWSGI_OPT_IMMEDIATE},
{"for-times", required_argument, 0, "(opt logic) for cycle (expand the specified num to a list starting from 1)", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for_times, UWSGI_OPT_IMMEDIATE},
{"for-readline", required_argument, 0, "(opt logic) for cycle (expand the specified file to a list of lines)", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for_readline, UWSGI_OPT_IMMEDIATE},
{"endfor", optional_argument, 0, "(opt logic) end for cycle", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE},
{"end-for", optional_argument, 0, "(opt logic) end for cycle", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE},
@@ -149,6 +151,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"inherit", required_argument, 0, "use the specified file as config template", uwsgi_opt_load, NULL, 0},
{"include", required_argument, 0, "include the specified file as immediate configuration", uwsgi_opt_load, NULL, UWSGI_OPT_IMMEDIATE},
{"inject-before", required_argument, 0, "inject a text file before the config file (advanced templating)", uwsgi_opt_add_string_list, &uwsgi.inject_before, UWSGI_OPT_IMMEDIATE},
{"inject-after", required_argument, 0, "inject a text file after the config file (advanced templating)", uwsgi_opt_add_string_list, &uwsgi.inject_after, UWSGI_OPT_IMMEDIATE},
{"daemonize", required_argument, 'd', "daemonize uWSGI", uwsgi_opt_set_str, &uwsgi.daemonize, 0},
{"daemonize2", required_argument, 0, "daemonize uWSGI after app loading", uwsgi_opt_set_str, &uwsgi.daemonize2, 0},
{"stop", required_argument, 0, "stop an instance", uwsgi_opt_pidfile_signal, (void *) SIGINT, UWSGI_OPT_IMMEDIATE},
@@ -298,6 +302,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"spooler-quiet", no_argument, 0, "do not be verbose with spooler tasks", uwsgi_opt_true, &uwsgi.spooler_quiet, 0},
{"spooler-max-tasks", required_argument, 0, "set the maximum number of tasks to run before recycling a spooler", uwsgi_opt_set_int, &uwsgi.spooler_max_tasks, 0},
{"spooler-harakiri", required_argument, 0, "set harakiri timeout for spooler tasks", uwsgi_opt_set_int, &uwsgi.harakiri_options.spoolers, 0},
{"spooler-frequency", required_argument, 0, "set spooler frequency", uwsgi_opt_set_int, &uwsgi.spooler_frequency, 0},
{"spooler-freq", required_argument, 0, "set spooler frequency", uwsgi_opt_set_int, &uwsgi.spooler_frequency, 0},
{"mule", optional_argument, 0, "add a mule", uwsgi_opt_add_mule, NULL, UWSGI_OPT_MASTER},
{"mules", required_argument, 0, "add the specified number of mules", uwsgi_opt_add_mules, NULL, UWSGI_OPT_MASTER},
@@ -384,6 +390,11 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"hook-accepting-once", required_argument, 0, "run the specified hook after each worker enter the accepting phase (once per-instance)", uwsgi_opt_add_string_list, &uwsgi.hook_accepting_once, 0},
{"hook-accepting1-once", required_argument, 0, "run the specified hook after the first worker enters the accepting phase (once per instance)", uwsgi_opt_add_string_list, &uwsgi.hook_accepting1_once, 0},
{"hook-master-start", required_argument, 0, "run the specified hook when the Master starts", uwsgi_opt_add_string_list, &uwsgi.hook_master_start, 0},
{"hook-touch", required_argument, 0, "run the specified hook when the specified file is touched (syntax: <file> <action>)", uwsgi_opt_add_string_list, &uwsgi.hook_touch, 0},
{"hook-emperor-start", required_argument, 0, "run the specified hook when the Emperor starts", uwsgi_opt_add_string_list, &uwsgi.hook_emperor_start, 0},
{"hook-emperor-stop", required_argument, 0, "run the specified hook when the Emperor send a stop message", uwsgi_opt_add_string_list, &uwsgi.hook_emperor_stop, 0},
{"hook-emperor-reload", required_argument, 0, "run the specified hook when the Emperor send a reload message", uwsgi_opt_add_string_list, &uwsgi.hook_emperor_reload, 0},
{"hook-emperor-lost", required_argument, 0, "run the specified hook when the Emperor connection is lost", uwsgi_opt_add_string_list, &uwsgi.hook_emperor_lost, 0},
@@ -393,6 +404,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"hook-as-mule", required_argument, 0, "run the specified hook in each mule", uwsgi_opt_add_string_list, &uwsgi.hook_as_mule, 0},
{"hook-as-gateway", required_argument, 0, "run the specified hook in each gateway", uwsgi_opt_add_string_list, &uwsgi.hook_as_gateway, 0},
{"after-request-hook", required_argument, 0, "run the specified function/symbol after each request", uwsgi_opt_add_string_list, &uwsgi.after_request_hooks, 0},
{"after-request-call", required_argument, 0, "run the specified function/symbol after each request", uwsgi_opt_add_string_list, &uwsgi.after_request_hooks, 0},
@@ -542,6 +555,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"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},
{"alarm-metric", 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, "export metrics as text files to 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, "export metrics as text files to the specified directory", uwsgi_opt_set_str, &uwsgi.metrics_dir, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
@@ -562,12 +576,16 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"master-fifo", required_argument, 0, "enable the master fifo", uwsgi_opt_add_string_list, &uwsgi.master_fifo, UWSGI_OPT_MASTER},
{"notify-socket", required_argument, 0, "enable the notification socket", uwsgi_opt_set_str, &uwsgi.notify_socket, UWSGI_OPT_MASTER},
{"subscription-notify-socket", required_argument, 0, "set the notification socket for subscriptions", uwsgi_opt_set_str, &uwsgi.subscription_notify_socket, UWSGI_OPT_MASTER},
#ifdef UWSGI_SSL
{"legion", required_argument, 0, "became a member of a legion", uwsgi_opt_legion, NULL, UWSGI_OPT_MASTER},
{"legion-mcast", required_argument, 0, "became a member of a legion (shortcut for multicast)", uwsgi_opt_legion_mcast, NULL, UWSGI_OPT_MASTER},
{"legion-node", required_argument, 0, "add a node to a legion", uwsgi_opt_legion_node, NULL, UWSGI_OPT_MASTER},
{"legion-freq", required_argument, 0, "set the frequency of legion packets", uwsgi_opt_set_int, &uwsgi.legion_freq, UWSGI_OPT_MASTER},
{"legion-tolerance", required_argument, 0, "set the tolerance of legion subsystem", uwsgi_opt_set_int, &uwsgi.legion_tolerance, UWSGI_OPT_MASTER},
{"legion-death-on-lord-error", required_argument, 0, "declare itself as a dead node for the specified amount of seconds if one of the lord hooks fails", uwsgi_opt_set_int, &uwsgi.legion_death_on_lord_error, UWSGI_OPT_MASTER},
{"legion-skew-tolerance", required_argument, 0, "set the clock skew tolerance of legion subsystem (default 30 seconds)", uwsgi_opt_set_int, &uwsgi.legion_skew_tolerance, UWSGI_OPT_MASTER},
{"legion-lord", required_argument, 0, "action to call on Lord election", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER},
{"legion-unlord", required_argument, 0, "action to call on Lord dismiss", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER},
@@ -582,6 +600,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"legion-scroll-list-max-size", required_argument, 0, "set max size of legion scroll list buffer", uwsgi_opt_set_64bit, &uwsgi.legion_scroll_list_max_size, 0},
{"subscriptions-sign-check", required_argument, 0, "set digest algorithm and certificate directory for secured subscription system", uwsgi_opt_scd, NULL, UWSGI_OPT_MASTER},
{"subscriptions-sign-check-tolerance", required_argument, 0, "set the maximum tolerance (in seconds) of clock skew for secured subscription system", uwsgi_opt_set_int, &uwsgi.subscriptions_sign_check_tolerance, UWSGI_OPT_MASTER},
{"subscriptions-sign-skip-uid", required_argument, 0, "skip signature check for the specified uid when using unix sockets credentials", uwsgi_opt_add_string_list, &uwsgi.subscriptions_sign_skip_uid, UWSGI_OPT_MASTER},
#endif
{"subscriptions-credentials-check", required_argument, 0, "add a directory to search for subscriptions key credentials", uwsgi_opt_add_string_list, &uwsgi.subscriptions_credentials_check_dir, UWSGI_OPT_MASTER},
{"subscriptions-use-credentials", no_argument, 0, "enable management of SCM_CREDENTIALS in subscriptions UNIX sockets", uwsgi_opt_true, &uwsgi.subscriptions_use_credentials, 0},
@@ -594,6 +613,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"subscribe-freq", required_argument, 0, "send subscription announce at the specified interval", uwsgi_opt_set_int, &uwsgi.subscribe_freq, 0},
{"subscription-tolerance", required_argument, 0, "set tolerance for subscription servers", uwsgi_opt_set_int, &uwsgi.subscription_tolerance, 0},
{"unsubscribe-on-graceful-reload", no_argument, 0, "force unsubscribe request even during graceful reload", uwsgi_opt_true, &uwsgi.unsubscribe_on_graceful_reload, 0},
{"start-unsubscribed", no_argument, 0, "configure subscriptions but do not send them (useful with master fifo)", uwsgi_opt_true, &uwsgi.subscriptions_blocked, 0},
{"snmp", optional_argument, 0, "enable the embedded snmp server", uwsgi_opt_snmp, NULL, 0},
{"snmp-community", required_argument, 0, "set the snmp community string", uwsgi_opt_snmp_community, NULL, 0},
#ifdef UWSGI_SSL
@@ -609,6 +629,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
#ifdef UWSGI_PCRE
{"sni-regexp", required_argument, 0, "add an SNI-governed SSL context (the key is a regexp)", uwsgi_opt_sni, NULL, 0},
#endif
{"ssl-tmp-dir", required_argument, 0, "store ssl-related temp files in the specified directory", uwsgi_opt_set_str, &uwsgi.ssl_tmp_dir, 0},
#endif
{"check-interval", required_argument, 0, "set the interval (in seconds) of master checks", uwsgi_opt_set_int, &uwsgi.master_interval, UWSGI_OPT_MASTER},
{"forkbomb-delay", required_argument, 0, "sleep for the specified number of seconds when a forkbomb is detected", uwsgi_opt_set_int, &uwsgi.forkbomb_delay, UWSGI_OPT_MASTER},
@@ -655,6 +676,12 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"alarm-fd", required_argument, 0, "raise the specified alarm when an fd is read for read (by default it reads 1 byte, set 8 for eventfd)", uwsgi_opt_add_string_list, &uwsgi.alarm_fd_list, UWSGI_OPT_MASTER},
{"alarm-segfault", required_argument, 0, "raise the specified alarm when the segmentation fault handler is executed", uwsgi_opt_add_string_list, &uwsgi.alarm_segfault, UWSGI_OPT_MASTER},
{"segfault-alarm", required_argument, 0, "raise the specified alarm when the segmentation fault handler is executed", uwsgi_opt_add_string_list, &uwsgi.alarm_segfault, UWSGI_OPT_MASTER},
{"alarm-backlog", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER},
{"backlog-alarm", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER},
{"lq-alarm", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER},
{"alarm-lq", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER},
{"alarm-listen-queue", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER},
{"listen-queue-alarm", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER},
#ifdef UWSGI_PCRE
{"log-alarm", required_argument, 0, "raise the specified alarm when a log line matches the specified regexp, syntax: <alarm>[,alarm...] <regexp>", uwsgi_opt_add_string_list, &uwsgi.alarm_logs_list, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
{"alarm-log", required_argument, 0, "raise the specified alarm when a log line matches the specified regexp, syntax: <alarm>[,alarm...] <regexp>", uwsgi_opt_add_string_list, &uwsgi.alarm_logs_list, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
@@ -860,7 +887,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"disable-sendfile", no_argument, 0, "disable sendfile() and rely on boring read()/write()", uwsgi_opt_true, &uwsgi.disable_sendfile, 0},
{"check-cache", optional_argument, 0, "check for response data in the specified cache (empty for default cache)", uwsgi_opt_set_str, &uwsgi.use_check_cache, 0},
{"close-on-exec", no_argument, 0, "set close-on-exec on sockets (could be required for spawning processes in requests)", uwsgi_opt_true, &uwsgi.close_on_exec, 0},
{"close-on-exec", no_argument, 0, "set close-on-exec on connection sockets (could be required for spawning processes in requests)", uwsgi_opt_true, &uwsgi.close_on_exec, 0},
{"close-on-exec2", no_argument, 0, "set close-on-exec on server sockets (could be required for spawning processes in requests)", uwsgi_opt_true, &uwsgi.close_on_exec2, 0},
{"mode", required_argument, 0, "set uWSGI custom mode", uwsgi_opt_set_str, &uwsgi.mode, 0},
{"env", required_argument, 0, "set environment variable", uwsgi_opt_set_env, NULL, 0},
{"envdir", required_argument, 0, "load a daemontools compatible envdir", uwsgi_opt_add_string_list, &uwsgi.envdirs, 0},
@@ -998,6 +1026,17 @@ void config_magic_table_fill(char *filename, char **magic_table) {
magic_table['b'] = uwsgi.binary_path;
magic_table['p'] = fullname;
// compute filename hash
uint32_t hash = djb33x_hash(magic_table['p'], strlen(magic_table['p']));
char *hex = uwsgi_str_to_hex((char *)&hash, 4);
magic_table['j'] = uwsgi_concat2n(hex, 8, "", 0);
free(hex);
struct stat st;
if (!lstat(fullname, &st)) {
magic_table['i'] = uwsgi_num2str(st.st_ino);
}
magic_table['s'] = uwsgi_get_last_char(fullname, '/') + 1;
magic_table['d'] = uwsgi_concat2n(magic_table['p'], magic_table['s'] - magic_table['p'], "", 0);
@@ -1070,6 +1109,8 @@ reuse:
magic_table['E'] = magic_table['e'];
magic_table['N'] = magic_table['n'];
magic_table['X'] = magic_table['x'];
magic_table['I'] = magic_table['i'];
magic_table['J'] = magic_table['j'];
uwsgi.magic_table_first_round = 1;
}
@@ -1875,6 +1916,17 @@ int main(int argc, char *argv[], char *envp[]) {
return uwsgi_run();
}
static char *uwsgi_at_file_read(char *filename) {
size_t size = 0;
char *buffer = uwsgi_open_and_read(filename, &size, 1, NULL);
if (size > 1) {
if (buffer[size-2] == '\n' || buffer[size-2] == '\r') {
buffer[size-2] = 0;
}
}
return buffer;
}
void uwsgi_setup(int argc, char *argv[], char *envp[]) {
#ifdef UWSGI_AS_SHARED_LIBRARY
#ifdef __APPLE__
@@ -2072,7 +2124,7 @@ void uwsgi_setup(int argc, char *argv[], char *envp[]) {
uwsgi_apply_config_pass('$', (char *(*)(char *)) getenv);
// third pass: FILEs
uwsgi_apply_config_pass('@', uwsgi_simple_file_read);
uwsgi_apply_config_pass('@', uwsgi_at_file_read);
// last pass: REFERENCEs
uwsgi_apply_config_pass('%', uwsgi_manage_placeholder);
@@ -2731,7 +2783,11 @@ int uwsgi_start(void *v_argv) {
!uwsgi.command_mode &&
!uwsgi.daemons_cnt &&
!uwsgi.crons &&
!uwsgi.spoolers &&
!uwsgi.emperor_proxy
#ifdef __linux__
&& !uwsgi.setns_socket
#endif
#ifdef UWSGI_SSL
&& !uwsgi.legions
#endif
@@ -2886,7 +2942,7 @@ unsafe:
}
// initialize locks and socket as soon as possible, as the master could enqueue tasks
if (uwsgi.spoolers != NULL && (uwsgi.sockets || uwsgi.loop)) {
if (uwsgi.spoolers != NULL) {
create_signal_pipe(uwsgi.shared->spooler_signal_pipe);
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
@@ -3024,15 +3080,13 @@ next:
if (uwsgi.spoolers != NULL && (uwsgi.sockets || uwsgi.loop)) {
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
if (uspool->mode == UWSGI_SPOOLER_EXTERNAL)
goto next2;
uspool->pid = spooler_start(uspool);
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
if (uspool->mode == UWSGI_SPOOLER_EXTERNAL)
goto next2;
uspool->pid = spooler_start(uspool);
next2:
uspool = uspool->next;
}
uspool = uspool->next;
}
if (!uwsgi.master_process) {
@@ -3108,6 +3162,16 @@ int uwsgi_run() {
//from now on the process is a real worker
}
#if defined(__linux__) && defined(PR_SET_PDEATHSIG)
// avoid workers running without master at all costs !!! (dangerous)
if (uwsgi.master_process && uwsgi.no_orphans) {
if (prctl(PR_SET_PDEATHSIG, SIGKILL)) {
uwsgi_error("uwsgi_run()/prctl()");
}
}
#endif
// eventually maps (or disable) sockets for the worker
uwsgi_map_sockets();
+31 -23
View File
@@ -82,12 +82,14 @@ int uwsgi_response_prepare_headers(struct wsgi_request *wsgi_req, char *status,
wsgi_req->status = uwsgi_str3_num(status);
#ifdef UWSGI_ROUTING
// apply error routes
if (uwsgi_apply_error_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
// from now on ignore write body requests...
wsgi_req->ignore_body = 1;
return -1;
if (wsgi_req->is_error_routing == 0) {
if (uwsgi_apply_error_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
// from now on ignore write body requests...
wsgi_req->ignore_body = 1;
return -1;
}
wsgi_req->is_error_routing = 0;
}
wsgi_req->is_error_routing = 0;
#endif
if (status_len <= 4) {
char *new_sc = NULL;
@@ -186,12 +188,14 @@ static int uwsgi_response_write_headers_do0(struct wsgi_request *wsgi_req) {
#ifdef UWSGI_ROUTING
// apply response routes
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
// from now on ignore write body requests...
wsgi_req->ignore_body = 1;
return -1;
}
wsgi_req->is_response_routing = 0;
if (wsgi_req->is_response_routing == 0) {
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
// from now on ignore write body requests...
wsgi_req->ignore_body = 1;
return -1;
}
wsgi_req->is_response_routing = 0;
}
#endif
struct uwsgi_string_list *ah = uwsgi.additional_headers;
@@ -352,12 +356,14 @@ int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_
// special case here, we could need to set transformations before
if (!wsgi_req->headers_sent) {
// apply response routes
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
// from now on ignore write body requests...
wsgi_req->ignore_body = 1;
return -1;
}
wsgi_req->is_response_routing = 0;
if (wsgi_req->is_response_routing == 0) {
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
// from now on ignore write body requests...
wsgi_req->ignore_body = 1;
return -1;
}
wsgi_req->is_response_routing = 0;
}
}
#endif
@@ -435,12 +441,14 @@ int uwsgi_response_writev_body_do(struct wsgi_request *wsgi_req, struct iovec *i
// special case here, we could need to set transformations before
if (!wsgi_req->headers_sent) {
// apply response routes
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
// from now on ignore write body requests...
wsgi_req->ignore_body = 1;
return -1;
}
wsgi_req->is_response_routing = 0;
if (wsgi_req->is_response_routing == 0) {
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
// from now on ignore write body requests...
wsgi_req->ignore_body = 1;
return -1;
}
wsgi_req->is_response_routing = 0;
}
}
#endif
+3 -5
View File
@@ -226,7 +226,7 @@ void uwsgi_yaml_config(char *file, char *magic_table[]) {
current_depth = depth;
// end the parsing cycle
if (in_uwsgi_section)
goto exit;
return;
}
else if (depth > current_depth && !in_uwsgi_section) {
goto next;
@@ -240,7 +240,7 @@ void uwsgi_yaml_config(char *file, char *magic_table[]) {
// skip list and {} defined dict
if (key[0] == '-' || key[0] == '[' || key[0] == '{') {
if (in_uwsgi_section)
goto exit;
return;
goto next;
}
@@ -260,7 +260,7 @@ void uwsgi_yaml_config(char *file, char *magic_table[]) {
val = strstr(key, ":\t");
}
if (!val)
goto exit;
return;
// get the right key
val[0] = 0;
// yeah overengeneering....
@@ -282,8 +282,6 @@ next:
if (colon) colon[0] = ':';
exit:
free(yaml);
}
#endif
+4 -1
View File
@@ -61,6 +61,7 @@ void linux_namespace_start(void *argv) {
for (;;) {
char stack[PTHREAD_STACK_MIN];
int waitpid_status;
char *pid_str = NULL;
uwsgi_log("*** jailing uWSGI in %s ***\n", uwsgi.ns);
int clone_flags = SIGCHLD | CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWIPC | CLONE_NEWNS;
if (uwsgi.ns_net) {
@@ -77,10 +78,12 @@ void linux_namespace_start(void *argv) {
exit(1);
}
#endif
pid_str = uwsgi_num2str((int) pid);
// run the post-jail scripts
if (setenv("UWSGI_JAIL_PID", uwsgi_num2str((int) pid), 1)) {
if (setenv("UWSGI_JAIL_PID", pid_str, 1)) {
uwsgi_error("setenv()");
}
free(pid_str);
uwsgi_hooks_run(uwsgi.hook_post_jail, "post-jail", 1);
struct uwsgi_string_list *usl = uwsgi.exec_post_jail;
while(usl) {
+217 -132
View File
@@ -2,6 +2,8 @@
extern struct uwsgi_server uwsgi;
#define kill_on_error if (!uc.do_not_kill_on_error) { if (kill(cgi_pid, SIGKILL)) uwsgi_error("kill()");}
struct uwsgi_cgi {
struct uwsgi_dyn_dict *mountpoint;
struct uwsgi_dyn_dict *helpers;
@@ -16,6 +18,8 @@ struct uwsgi_cgi {
int has_mountpoints;
struct uwsgi_dyn_dict *default_cgi;
int path_info;
int do_not_kill_on_error;
int async_max_attempts;
} uc ;
static void uwsgi_opt_add_cgi(char *opt, char *value, void *foobar) {
@@ -62,6 +66,9 @@ struct uwsgi_option uwsgi_cgi_options[] = {
{"cgi-path-info", no_argument, 0, "disable PATH_INFO management in cgi scripts", uwsgi_opt_true, &uc.path_info, 0},
{"cgi-do-not-kill-on-error", no_argument, 0, "do not send SIGKILL to cgi script on errors", uwsgi_opt_true, &uc.do_not_kill_on_error, 0},
{"cgi-async-max-attempts", no_argument, 0, "max waitpid() attempts in cgi async mode (default 10)", uwsgi_opt_set_int, &uc.async_max_attempts, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -179,78 +186,154 @@ static char *uwsgi_cgi_get_helper(char *filename) {
}
static int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len) {
size_t i;
/*
start reading each line until Status or Location are found
-1 error
0 not found
1 found
*/
static int uwsgi_cgi_check_status(struct wsgi_request *wsgi_req, char *buf, size_t len) {
char *key = buf, *value = NULL;
size_t header_size = 0;
int status_sent = 0;
size_t i;
for(i=0;i<len;i++) {
// end of a line
if (buf[i] == '\n') {
// end of headers
if (key == NULL) {
i++;
goto send_body;
// end of a line
if (buf[i] == '\n') {
// end of headers
if (key == NULL) {
// Default status
#ifdef UWSGI_DEBUG
uwsgi_log("setting default Status header\n");
#endif
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1;
return 1;
}
// invalid header
else if (value == NULL) {
return -1;
// invalid header
else if (value == NULL) return -1;
header_size = (buf+i) - key;
// security check
if (buf+i > buf) {
// remove \r
if ((buf[i-1]) == '\r') {
header_size--;
}
}
// enough space for Status ?
if (header_size >= 11) {
// "Status: NNN"
if (!strncasecmp("Status: ", key, 8)) {
#ifdef UWSGI_DEBUG
uwsgi_log("found Status header: %.*s\n", header_size, key);
#endif
if (uwsgi_response_prepare_headers(wsgi_req, key+8, header_size - 8)) return -1;
return 1;
}
// Location: X
if (!strncasecmp("Location: ", key, 10)) {
#ifdef UWSGI_DEBUG
uwsgi_log("found Location header: %.*s\n", header_size, key);
#endif
if (uwsgi_response_prepare_headers(wsgi_req, "302 Found", 9)) return -1;
return 1;
}
}
header_size = (buf+i) - key;
// security check
if (buf+i > buf) {
if ((buf[i-1]) == '\r') {
header_size--;
key = NULL;
value = NULL;
}
else if (buf[i] == ':') {
value = buf+i;
}
else if (buf[i] != '\r') {
if (key == NULL) key = buf + i;
}
}
// no Status/Location found
return 0;
}
static int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, int fd, char *buf, size_t blen) {
size_t i;
size_t header_size = 0;
int status_sent = 0;
size_t remains = blen;
char *ptr = buf;
size_t len = 0;
while(remains > 0) {
ssize_t rlen = uwsgi_read_true_nb(fd, ptr, remains, uc.timeout);
if (rlen < 0) {
if (!errno) return 1;
return -1;
}
// timed out
if (rlen == 0) return -1;
remains -= rlen;
len += rlen;
ptr += rlen;
// Search for Status/Location headers
if (!status_sent) {
status_sent = uwsgi_cgi_check_status(wsgi_req, buf, len);
if (status_sent < 0) return -1;
// need more data ?
if (status_sent == 0) continue;
}
// send headers
char *key = buf;
char *value = NULL;
for(i=0;i<len;i++) {
// end of a line
if (buf[i] == '\n') {
// end of headers
if (key == NULL) {
i++;
goto send_body;
}
// invalid header
else if (value == NULL) {
return -1;
}
header_size = (buf+i) - key;
// security check
if (buf+i > buf) {
if ((buf[i-1]) == '\r') {
header_size--;
}
}
}
#ifdef UWSGI_DEBUG
uwsgi_log("found CGI header: %.*s\n", header_size, key);
uwsgi_log("found CGI header: %.*s\n", header_size, key);
#endif
if (status_sent == 0) {
// "Status: NNN"
// Ignore "Status: NNN" header
if (header_size >= 11) {
if (!strncasecmp("Status: ", key, 8)) {
if (uwsgi_response_prepare_headers(wsgi_req, key+8, header_size - 8)) return -1;
status_sent = 1;
key = NULL;
value = NULL;
continue;
}
}
uwsgi_response_add_header(wsgi_req, NULL, 0, key, header_size);
key = NULL;
value = NULL;
}
// default status
if (status_sent == 0) {
// Location: X
if (header_size >= 11) {
if (!strncasecmp("Location: ", key, 10)) {
if (uwsgi_response_prepare_headers(wsgi_req, "302 Found", 9)) return -1;
status_sent = 1;
}
}
if (status_sent == 0) {
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1;
status_sent = 1;
}
else if (buf[i] == ':') {
value = buf+i;
}
uwsgi_response_add_header(wsgi_req, NULL, 0, key, header_size);
key = NULL;
value = NULL;
}
else if (buf[i] == ':') {
value = buf+i;
}
else if (buf[i] != '\r') {
if (key == NULL) {
key = buf + i;
else if (buf[i] != '\r') {
if (key == NULL) {
key = buf + i;
}
}
}
}
@@ -552,7 +635,6 @@ static int uwsgi_cgi_run(struct wsgi_request *wsgi_req, char *docroot, size_t do
int post_pipe[2];
int nargs = 0;
int waitpid_status;
ssize_t len;
int i;
char **argv;
@@ -590,126 +672,96 @@ static int uwsgi_cgi_run(struct wsgi_request *wsgi_req, char *docroot, size_t do
close(cgi_pipe[1]);
close(post_pipe[0]);
uwsgi_socket_nb(cgi_pipe[0]);
uwsgi_socket_nb(post_pipe[1]);
// ok start sending post data...
size_t remains = wsgi_req->post_cl;
while(remains > 0) {
ssize_t rlen = 0;
char *buf = uwsgi_request_body_read(wsgi_req, 8192, &rlen);
if (!buf) {
close(post_pipe[1]);
goto clear2;
}
if (buf == uwsgi.empty) break;
// write data to the node
if (uwsgi_write_true_nb(post_pipe[1], buf, rlen, uc.timeout)) {
close(post_pipe[1]);
goto clear2;
}
remains -= rlen;
}
close(post_pipe[1]);
// wait for data
char *headers_buf = uwsgi_malloc(uc.buffer_size);
char *ptr = headers_buf;
remains = uc.buffer_size;
int completed = 0;
while(remains > 0) {
int ret = uwsgi.wait_read_hook(cgi_pipe[0], uc.timeout);
if (ret > 0) {
len = read(cgi_pipe[0], ptr, remains);
if (len > 0) {
ptr+=len;
remains -= len;
}
else if (len == 0) {
completed = 1;
break;
}
else {
uwsgi_error("read()");
goto clear;
}
continue;
}
else if (ret == 0) {
uwsgi_log("CGI timeout !!!\n");
goto clear;
}
break;
}
char *buf = uwsgi_malloc(uc.buffer_size);
if (uwsgi_cgi_parse(wsgi_req, headers_buf, uc.buffer_size-remains)) {
uwsgi_log("invalid CGI output !!!\n");
int completed = uwsgi_cgi_parse(wsgi_req, cgi_pipe[0], buf, uc.buffer_size);
if (completed < 0) {
uwsgi_log("invalid CGI response !!!\n");
kill_on_error
goto clear;
}
while (!completed) {
int ret = uwsgi.wait_read_hook(cgi_pipe[0], uc.timeout);
if (ret > 0) {
len = read(cgi_pipe[0], headers_buf, uc.buffer_size);
if (len > 0) {
uwsgi_response_write_body_do(wsgi_req, headers_buf, len);
}
// end of output
else if (len == 0) {
break;
}
else {
uwsgi_error("read()");
ssize_t rlen = uwsgi_read_true_nb(cgi_pipe[0], buf, uc.buffer_size, uc.timeout);
if (rlen > 0) {
if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) {
kill_on_error
goto clear;
}
continue;
}
else if (ret == 0) {
uwsgi_log("CGI timeout !!!\n");
goto clear;
}
break;
else if (rlen == 0) {
uwsgi_log("CGI timeout !!!\n");
kill_on_error
goto clear;
}
else {
if (errno) {
uwsgi_req_error("error reading CGI response\n");
kill_on_error
}
goto clear;
}
}
clear:
free(headers_buf);
free(buf);
clear2:
close(cgi_pipe[0]);
close(post_pipe[1]);
// now wait for process exit/death
if (waitpid(cgi_pid, &waitpid_status, 0) < 0) {
uwsgi_error("waitpid()");
// in async mode we need a trick...
if (uwsgi.async > 1) {
pid_t diedpid = waitpid(cgi_pid, &waitpid_status, WNOHANG);
if (diedpid < 0) {
uwsgi_error("waitpid()");
}
else if (diedpid == 0) {
// pass the pid of the cgi to async_plagued (the after request hook will clear the process)
wsgi_req->async_plagued = (int) cgi_pid;
}
}
else {
if (waitpid(cgi_pid, &waitpid_status, 0) < 0) {
uwsgi_error("waitpid()");
}
}
return UWSGI_OK;
}
// close all the fd except wsgi_req->poll.fd and 2;
for(i=0;i< (int)uwsgi.max_fd;i++) {
if (post_pipe[0] == i) {
continue;
}
if (wsgi_req->post_file) {
if (fileno(wsgi_req->post_file) == i) {
continue;
}
}
if (i != wsgi_req->fd && i != 2 && i != cgi_pipe[1]) {
close(i);
}
}
// now map wsgi_req->poll.fd (or async_post) to 0 & cgi_pipe[1] to 1
if (post_pipe[0] != 0) {
dup2(post_pipe[0], 0);
close(post_pipe[0]);
}
#ifdef UWSGI_DEBUG
uwsgi_log("mapping cgi_pipe %d to 1\n", cgi_pipe[1]);
#endif
dup2(post_pipe[0], 0);
close(post_pipe[0]);
dup2(cgi_pipe[1],1);
close(cgi_pipe[1]);
// close all the fd > 2
for(i=3;i<(int)uwsgi.max_fd;i++) {
close(i);
}
// fill cgi env
for(i=0;i<wsgi_req->var_cnt;i++) {
// no need to free the putenv() memory
@@ -873,6 +925,39 @@ clear2:
static void uwsgi_cgi_after_request(struct wsgi_request *wsgi_req) {
if (wsgi_req->async_plagued > 0) {
int waitpid_status;
pid_t cgi_pid = (pid_t) wsgi_req->async_plagued;
int max_attempts = uc.async_max_attempts;
if (!max_attempts) max_attempts = 10;
while(max_attempts) {
pid_t diedpid = waitpid(cgi_pid, &waitpid_status, WNOHANG);
if (diedpid < 0) {
uwsgi_error("waitpid()");
break;
}
else if (diedpid == 0) {
int ret = uwsgi.wait_milliseconds_hook(1000);
if (ret < 0) {
kill_on_error
if (waitpid(cgi_pid, &waitpid_status, 0) < 0) {
uwsgi_error("waitpid()");
}
}
}
else {
break;
}
max_attempts--;
}
if (max_attempts == 0) {
kill_on_error
if (waitpid(cgi_pid, &waitpid_status, 0) < 0) {
uwsgi_error("waitpid()");
}
}
}
log_request(wsgi_req);
}
+5 -3
View File
@@ -201,9 +201,11 @@ int cheaper_busyness_algo(int can_spawn) {
}
avg_busyness = (active_workers ? total_busyness / active_workers : 0);
uwsgi_wlock(uwsgi.metrics_lock);
uwsgi_cheaper_busyness_global.total_avg_busyness = avg_busyness;
uwsgi_rwunlock(uwsgi.metrics_lock);
if (uwsgi.has_metrics) {
uwsgi_wlock(uwsgi.metrics_lock);
uwsgi_cheaper_busyness_global.total_avg_busyness = avg_busyness;
uwsgi_rwunlock(uwsgi.metrics_lock);
}
if (uwsgi_cheaper_busyness_global.verbose)
uwsgi_log("[busyness] %ds average busyness of %d worker(s) is at %d%%\n",
+10 -2
View File
@@ -41,7 +41,9 @@ struct corerouter_peer *uwsgi_cr_peer_add(struct corerouter_session *cs) {
peers->session = cs;
peers->fd = -1;
// create input buffer
peers->in = uwsgi_buffer_new(uwsgi.page_size);
size_t bufsize = cs->corerouter->buffer_size;
if (!bufsize) bufsize = uwsgi.page_size;
peers->in = uwsgi_buffer_new(bufsize);
// add timeout
peers->timeout = cr_add_timeout(cs->corerouter, peers);
peers->prev = old_peers;
@@ -284,6 +286,10 @@ void corerouter_manage_subscription(char *key, uint16_t keylen, char *val, uint1
usr->sni_ca = val;
usr->sni_ca_len = vallen;
}
else if (!uwsgi_strncmp("notify", 6, key, keylen)) {
usr->notify = val;
usr->notify_len = vallen;
}
}
void corerouter_close_peer(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) {
@@ -562,7 +568,9 @@ struct corerouter_session *corerouter_alloc_session(struct uwsgi_corerouter *ucr
struct corerouter_peer *peer = uwsgi_calloc(sizeof(struct corerouter_peer));
// main_peer has only input buffer as output buffer is taken from backend peers
peer->in = uwsgi_buffer_new(uwsgi.page_size);
size_t bufsize = ucr->buffer_size;
if (!bufsize) bufsize = uwsgi.page_size;
peer->in = uwsgi_buffer_new(bufsize);
ucr->cr_table[new_connection] = peer;
cs->main_peer = peer;
+5
View File
@@ -265,6 +265,11 @@ struct uwsgi_corerouter {
uid_t uid;
gid_t gid;
struct uwsgi_string_list *resubscribe;
char *resubscribe_bind;
size_t buffer_size;
};
// a session is started when a client connect to the router
+45 -4
View File
@@ -154,10 +154,6 @@ void uwsgi_corerouter_manage_subscription(struct uwsgi_corerouter *ucr, int id,
if (node && node->len) {
#ifdef UWSGI_SSL
if (uwsgi.subscriptions_sign_check_dir) {
if (usr.sign_len == 0 || usr.base_len == 0)
return;
if (usr.unix_check <= node->unix_check)
return;
if (!uwsgi_subscription_sign_check(node->slot, &usr)) {
return;
}
@@ -187,6 +183,51 @@ void uwsgi_corerouter_manage_subscription(struct uwsgi_corerouter *ucr, int id,
}
}
}
// resubscribe if needed ?
if (ucr->resubscribe) {
static char *address = NULL;
if (!address) {
struct uwsgi_gateway_socket *augs = uwsgi.gateway_sockets;
while (augs) {
if (!strcmp(ucr->name, augs->owner)) {
if (!augs->subscription) {
address = augs->name;
break;
}
}
augs = augs->next;
}
}
struct uwsgi_string_list *usl = NULL;
char *sni_key = NULL;
char *sni_cert = NULL;
char *sni_ca = NULL;
if (usr.sni_key_len) {
sni_key = uwsgi_concat2n(usr.sni_key, usr.sni_key_len, "", 0);
}
if (usr.sni_crt_len) {
sni_cert = uwsgi_concat2n(usr.sni_crt, usr.sni_crt_len, "", 0);
}
if (usr.sni_ca_len) {
sni_ca = uwsgi_concat2n(usr.sni_ca, usr.sni_ca_len, "", 0);
}
uwsgi_foreach(usl, ucr->resubscribe) {
if (ucr->resubscribe_bind) {
static int rfd = -1;
if (rfd == -1) {
rfd = bind_to_udp(ucr->resubscribe_bind, 0, 0);
}
uwsgi_send_subscription_from_fd(rfd, usl->value, usr.key, usr.keylen, usr.modifier1, usr.modifier2, bbuf[3], address, NULL, sni_key, sni_cert, sni_ca);
}
else {
uwsgi_send_subscription_from_fd(-2, usl->value, usr.key, usr.keylen, usr.modifier1, usr.modifier2, bbuf[3], address, NULL, sni_key, sni_cert, sni_ca);
}
}
if (sni_key) free(sni_key);
if (sni_cert) free(sni_cert);
if (sni_ca) free(sni_ca);
}
}
}
+4
View File
@@ -65,8 +65,11 @@ int uwsgi_cr_map_use_subscription_dotsplit(struct uwsgi_corerouter *ucr, struct
char *name = peer->key;
uint16_t name_len = peer->key_len;
// max 5 split, reduce DOS attempts
int count = 5;
split:
if (!count) return 0;
#ifdef UWSGI_DEBUG
uwsgi_log("trying with %.*s\n", name_len, name);
#endif
@@ -76,6 +79,7 @@ split:
if (next) {
name_len -= next - name;
name = next;
count--;
goto split;
}
}
+3 -15
View File
@@ -386,21 +386,9 @@ static void coroae_loop() {
exit(1);
}
perl_eval_pv("use Coro;", 0);
if (SvTRUE(ERRSV)) {
uwsgi_log("unable to load Coro module\n");
exit(1);
}
perl_eval_pv("use AnyEvent;", 0);
if (SvTRUE(ERRSV)) {
uwsgi_log("unable to load AnyEvent module\n");
exit(1);
}
perl_eval_pv("use Coro::AnyEvent;", 0);
if (SvTRUE(ERRSV)) {
uwsgi_log("unable to load Coro::AnyEvent module\n");
exit(1);
}
perl_eval_pv("use Coro;", 1);
perl_eval_pv("use AnyEvent;", 1);
perl_eval_pv("use Coro::AnyEvent;", 1);
uwsgi.current_wsgi_req = coroae_current_wsgi_req;
uwsgi.wait_write_hook = coroae_wait_fd_write;
+8 -1
View File
@@ -37,7 +37,7 @@ static struct uwsgi_option fastrouter_options[] = {
{"fastrouter-events", required_argument, 0, "set the maximum number of concurrent events", uwsgi_opt_set_int, &ufr.cr.nevents, 0},
{"fastrouter-quiet", required_argument, 0, "do not report failed connections to instances", uwsgi_opt_true, &ufr.cr.quiet, 0},
{"fastrouter-cheap", no_argument, 0, "run the fastrouter in cheap mode", uwsgi_opt_true, &ufr.cr.cheap, 0},
{"fastrouter-subscription-server", required_argument, 0, "run the fastrouter subscription server on the spcified address", uwsgi_opt_corerouter_ss, &ufr, 0},
{"fastrouter-subscription-server", required_argument, 0, "run the fastrouter subscription server on the specified address", uwsgi_opt_corerouter_ss, &ufr, 0},
{"fastrouter-subscription-slot", required_argument, 0, "*** deprecated ***", uwsgi_opt_deprecated, (void *) "useless thanks to the new implementation", 0},
{"fastrouter-timeout", required_argument, 0, "set fastrouter timeout", uwsgi_opt_set_int, &ufr.cr.socket_timeout, 0},
@@ -48,6 +48,13 @@ static struct uwsgi_option fastrouter_options[] = {
{"fastrouter-stats-server", required_argument, 0, "run the fastrouter stats server", uwsgi_opt_set_str, &ufr.cr.stats_server, 0},
{"fastrouter-ss", required_argument, 0, "run the fastrouter stats server", uwsgi_opt_set_str, &ufr.cr.stats_server, 0},
{"fastrouter-harakiri", required_argument, 0, "enable fastrouter harakiri", uwsgi_opt_set_int, &ufr.cr.harakiri, 0},
{"fastrouter-uid", required_argument, 0, "drop fastrouter privileges to the specified uid", uwsgi_opt_uid, &ufr.cr.uid, 0 },
{"fastrouter-gid", required_argument, 0, "drop fastrouter privileges to the specified gid", uwsgi_opt_gid, &ufr.cr.gid, 0 },
{"fastrouter-resubscribe", required_argument, 0, "forward subscriptions to the specified subscription server", uwsgi_opt_add_string_list, &ufr.cr.resubscribe, 0},
{"fastrouter-resubscribe-bind", required_argument, 0, "bind to the specified address when re-subscribing", uwsgi_opt_set_str, &ufr.cr.resubscribe_bind, 0},
{"fastrouter-buffer-size", required_argument, 0, "set internal buffer size (default: page size)", uwsgi_opt_set_64bit, &ufr.cr.buffer_size, 0},
{0, 0, 0, 0, 0, 0, 0},
};
+3
View File
@@ -24,6 +24,9 @@ else:
CFLAGS.append('-I' + archdir)
CFLAGS.append('-I' + archdir + '/' + arch)
CFLAGS.append('-I' + includedir + '/' + arch)
archdir2 = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['rubyarchhdrdir']\"" % rbconfig).read().rstrip()
if archdir2:
CFLAGS.append('-I' + archdir2)
LDFLAGS = []
LIBS = []
+5 -3
View File
@@ -8,18 +8,20 @@ struct uwsgi_geoip {
char *city_db;
GeoIP *country;
GeoIP *city;
int use_disk;
} ugeoip;
struct uwsgi_option uwsgi_geoip_options[] = {
{"geoip-country", required_argument, 0, "load the specified geoip country database", uwsgi_opt_set_str, &ugeoip.country_db, 0},
{"geoip-city", required_argument, 0, "load the specified geoip city database", uwsgi_opt_set_str, &ugeoip.city_db, 0},
{ 0, 0, 0, 0, 0, 0, 0 }
{"geoip-use-disk", no_argument, 0, "do not cache geoip databases in memory", uwsgi_opt_true, &ugeoip.use_disk, 0},
UWSGI_END_OF_OPTIONS
};
static int uwsgi_geoip_init() {
if (ugeoip.country_db) {
ugeoip.country = GeoIP_open(ugeoip.country_db, GEOIP_MEMORY_CACHE);
ugeoip.country = GeoIP_open(ugeoip.country_db, ugeoip.use_disk ? GEOIP_STANDARD : GEOIP_MEMORY_CACHE);
if (!ugeoip.country) {
uwsgi_log("unable to open GeoIP country database: %s\n", ugeoip.country_db);
exit(1);
@@ -27,7 +29,7 @@ static int uwsgi_geoip_init() {
}
if (ugeoip.city_db) {
ugeoip.city = GeoIP_open(ugeoip.city_db, GEOIP_MEMORY_CACHE);
ugeoip.city = GeoIP_open(ugeoip.city_db, ugeoip.use_disk ? GEOIP_STANDARD : GEOIP_MEMORY_CACHE);
if (!ugeoip.city) {
uwsgi_log("unable to open GeoIP city database: %s\n", ugeoip.city_db);
exit(1);
+4
View File
@@ -132,6 +132,10 @@ static void greenlet_init_apps(void) {
PyGreenlet_Import();
if (PyErr_Occurred()){
PyErr_Print();
exit(1);
}
ugl.gl = uwsgi_malloc( sizeof(PyGreenlet *) * uwsgi.async );
ugl.main = PyGreenlet_GetCurrent();
+5
View File
@@ -79,6 +79,11 @@ static void uwsgi_gridfs_do(struct wsgi_request *wsgi_req, struct uwsgi_gridfs_m
}
uwsgi_response_add_content_length(wsgi_req, gfile.getContentLength());
char http_last_modified[49];
time_t t = gfile.getUploadDate().toTimeT();
int size = uwsgi_http_date(t, http_last_modified);
uwsgi_response_add_header(wsgi_req, (char *)"Last-Modified", 13, http_last_modified, size);
if (ugm->etag) {
std::string g_md5 = gfile.getMD5();
if (!g_md5.empty()) {
+2
View File
@@ -40,6 +40,8 @@ struct uwsgi_http {
size_t spdy3_settings_size;
#endif
int server_name_as_http_host;
};
struct http_session {
+13 -4
View File
@@ -54,8 +54,12 @@ struct uwsgi_option http_options[] = {
{"http-ss", required_argument, 0, "run the http router stats server", uwsgi_opt_set_str, &uhttp.cr.stats_server, 0},
{"http-harakiri", required_argument, 0, "enable http router harakiri", uwsgi_opt_set_int, &uhttp.cr.harakiri, 0},
{"http-stud-prefix", required_argument, 0, "expect a stud prefix (1byte family + 4/16 bytes address) on connections from the specified address", uwsgi_opt_add_addr_list, &uhttp.stud_prefix, 0},
{"http-uid", required_argument, 0, "drop http routr privileges to the specified uid", uwsgi_opt_uid, &uhttp.cr.uid, 0 },
{"http-gid", required_argument, 0, "drop http routr privileges to the specified gid", uwsgi_opt_gid, &uhttp.cr.gid, 0 },
{"http-uid", required_argument, 0, "drop http router privileges to the specified uid", uwsgi_opt_uid, &uhttp.cr.uid, 0 },
{"http-gid", required_argument, 0, "drop http router privileges to the specified gid", uwsgi_opt_gid, &uhttp.cr.gid, 0 },
{"http-resubscribe", required_argument, 0, "forward subscriptions to the specified subscription server", uwsgi_opt_add_string_list, &uhttp.cr.resubscribe, 0},
{"http-buffer-size", required_argument, 0, "set internal buffer size (default: page size)", uwsgi_opt_set_64bit, &uhttp.cr.buffer_size, 0},
{"http-server-name-as-http-host", required_argument, 0, "force SERVER_NAME to HTTP_HOST", uwsgi_opt_true, &uhttp.server_name_as_http_host, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -120,6 +124,7 @@ int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, uint16_t hhlen
if (!uwsgi_strncmp("HOST", 4, hh, keylen)) {
peer->key = val;
peer->key_len = vallen;
if (uhttp.server_name_as_http_host && uwsgi_buffer_append_keyval(out, "SERVER_NAME", 11, peer->key, peer->key_len)) return -1;
}
else if (!uwsgi_strncmp("CONTENT_LENGTH", 14, hh, keylen)) {
@@ -294,7 +299,7 @@ int http_headers_parse(struct corerouter_peer *peer) {
if (uwsgi_buffer_append_keyval(out, "SCRIPT_NAME", 11, "", 0)) return -1;
// SERVER_NAME
if (uwsgi_buffer_append_keyval(out, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len)) return -1;
if (!uhttp.server_name_as_http_host && uwsgi_buffer_append_keyval(out, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len)) return -1;
peer->key = uwsgi.hostname;
peer->key_len = uwsgi.hostname_len;
@@ -618,6 +623,9 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
// is it http body ?
if (hr->rnrn == 4) {
// something bad happened in keepalive mode...
if (!main_peer->session->peers) return -1;
if (hr->content_length == 0 && !hr->raw_body) {
// ignore data...
main_peer->in->pos = 0;
@@ -871,7 +879,8 @@ int http_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket
break;
#endif
default:
uwsgi_cr_set_hooks(cs->main_peer, cs->main_peer->last_hook_read, NULL);
if (uwsgi_cr_set_hooks(cs->main_peer, cs->main_peer->last_hook_read, NULL))
return -1;
cs->close = hr_session_close;
break;
}
+4 -1
View File
@@ -28,7 +28,10 @@ static ssize_t uwsgi_pipe_logger(struct uwsgi_logger *ul, char *message, size_t
}
else {
// child
setsid();
if (setsid() < 0) {
uwsgi_error("setsid()");
exit(1);
}
close(pipefd[1]);
dup2(pipefd[0], STDIN_FILENO);
close(pipefd[0]);
+2 -1
View File
@@ -798,7 +798,8 @@ static int uwsgi_lua_request(struct wsgi_request *wsgi_req) {
// send status
if (lua_type(L, -3) == LUA_TSTRING || lua_type(L, -3) == LUA_TNUMBER) {
http = lua_tolstring(L, -3, &slen);
uwsgi_response_prepare_headers(wsgi_req, (char *) http, slen);
if (uwsgi_response_prepare_headers(wsgi_req, (char *) http, slen))
goto clear2;
}
else {
uwsgi_log("[uwsgi-lua] invalid response status !!!\n");
+23 -4
View File
@@ -31,6 +31,9 @@ struct uwsgi_php {
int dump_config;
char *server_software;
size_t server_software_len;
struct uwsgi_string_list *exec_before;
struct uwsgi_string_list *exec_after;
} uphp;
void uwsgi_opt_php_ini(char *opt, char *value, void *foobar) {
@@ -59,8 +62,11 @@ struct uwsgi_option uwsgi_php_options[] = {
#endif
{"php-var", required_argument, 0, "add/overwrite a CGI variable at each request", uwsgi_opt_add_string_list, &uphp.vars, 0},
{"php-dump-config", no_argument, 0, "dump php config (if modified via --php-set or append options)", uwsgi_opt_true, &uphp.dump_config, 0},
{0, 0, 0, 0, 0, 0, 0},
{"php-exec-before", required_argument, 0, "run specified php code before the requested script", uwsgi_opt_add_string_list, &uphp.exec_before, 0},
{"php-exec-begin", required_argument, 0, "run specified php code before the requested script", uwsgi_opt_add_string_list, &uphp.exec_before, 0},
{"php-exec-after", required_argument, 0, "run specified php code after the requested script", uwsgi_opt_add_string_list, &uphp.exec_after, 0},
{"php-exec-end", required_argument, 0, "run specified php code after the requested script", uwsgi_opt_add_string_list, &uphp.exec_after, 0},
UWSGI_END_OF_OPTIONS
};
@@ -92,11 +98,13 @@ static int sapi_uwsgi_send_headers(sapi_headers_struct *sapi_headers)
int hrc = SG(sapi_headers).http_response_code;
if (!hrc) hrc = 200;
uwsgi_num2str2n(hrc, status, 4);
uwsgi_response_prepare_headers(wsgi_req, status, 3);
if (uwsgi_response_prepare_headers(wsgi_req, status, 3))
return SAPI_HEADER_SEND_FAILED;
}
else {
char *sl = SG(sapi_headers).http_status_line;
uwsgi_response_prepare_headers(wsgi_req, sl + 9 , strlen(sl + 9));
if (uwsgi_response_prepare_headers(wsgi_req, sl + 9 , strlen(sl + 9)))
return SAPI_HEADER_SEND_FAILED;
}
h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
@@ -888,8 +896,19 @@ secure3:
return -1;
}
struct uwsgi_string_list *usl=NULL;
uwsgi_foreach(usl, uphp.exec_before) {
if (zend_eval_string_ex(usl->value, NULL, "uWSGI php exec before", 1 TSRMLS_CC) == FAILURE) goto end;
}
php_execute_script(&file_handle TSRMLS_CC);
uwsgi_foreach(usl, uphp.exec_after) {
if (zend_eval_string_ex(usl->value, NULL, "uWSGI php exec after", 1 TSRMLS_CC) == FAILURE) goto end;
}
end:
php_request_shutdown(NULL);
return 0;
+3
View File
@@ -65,6 +65,8 @@ struct uwsgi_perl {
int shell_oneshot;
CV *spooler;
int no_plack;
};
void init_perl_embedded_module(void);
@@ -84,3 +86,4 @@ void uwsgi_perl_run_hook(SV *);
void uwsgi_perl_exec(char *);
void uwsgi_perl_check_auto_reload(void);
void uwsgi_psgi_preinit_apps(void);
+129 -71
View File
@@ -107,11 +107,67 @@ XS(XS_input_read) {
SV *read_buf = ST(1);
unsigned long arg_len = SvIV(ST(2));
long offset = 0;
if (items > 2) {
offset = (long) SvIV(ST(3));
}
ssize_t rlen = 0;
char *buf = uwsgi_request_body_read(wsgi_req, arg_len, &rlen);
if (buf) {
sv_setpvn(read_buf, buf, rlen);
if (rlen > 0 && offset != 0) {
STRLEN orig_len;
// get data from original string
char *orig = SvPV(read_buf, orig_len);
size_t new_size = orig_len;
// still valid ?
if (offset > 0) {
// if the new string is bigger than the old one, allocate a bigger chunk
if ((size_t) rlen + offset > orig_len) {
new_size = rlen + offset;
}
// if offset is bigger than orig_len, pad with "\0", so we use (slower) calloc
char *new_buf = uwsgi_calloc(new_size);
// put back older value
memcpy(new_buf, orig, orig_len);
// put the new value
memcpy(new_buf + offset, buf, rlen);
sv_setpvn(read_buf, new_buf, new_size);
// free the new value
free(new_buf);
}
// negative (a little bit more complex)
else {
long orig_offset = 0;
// first of all get the new orig_len;
offset = abs(offset);
if (offset > (long) orig_len) {
new_size = offset;
orig_offset = offset - orig_len;
offset = 0;
}
else {
offset = orig_len - offset;
}
if ((size_t) rlen + offset > new_size) {
new_size = rlen + offset;
}
char *new_buf = uwsgi_calloc(new_size);
// put back older value
memcpy(new_buf + orig_offset, orig, orig_len);
// put the new value
memcpy(new_buf + offset, buf, rlen);
sv_setpvn(read_buf, new_buf, new_size);
// free the new value
free(new_buf);
}
}
else {
sv_setpvn(read_buf, buf, rlen);
}
goto ret;
}
@@ -171,20 +227,6 @@ XS(XS_error_print) {
XSRETURN(0);
}
XS(XS_uwsgi_stacktrace) {
dXSARGS;
psgi_check_args(0);
uwsgi_log("%s", SvPV_nolen(ERRSV));
uwsgi_log("*** uWSGI perl stacktrace ***\n");
SV *ret = perl_eval_pv("Devel::StackTrace->new->as_string;", 0);
uwsgi_log("%s", SvPV_nolen(ret));
uwsgi_log("*** end of perl stacktrace ***\n\n");
XSRETURN(0);
}
/* automatically generated */
@@ -197,6 +239,7 @@ xs_init(pTHX)
{
char *file = __FILE__;
dXSUB_SYS;
HV *stash;
/* DynaLoader is a special case */
newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
@@ -218,13 +261,16 @@ xs_init(pTHX)
newXS("uwsgi::streaming::write", XS_streaming_write, "uwsgi::streaming");
newXS("uwsgi::streaming::close", XS_streaming_close, "uwsgi::streaming");
newXS("uwsgi::stacktrace", XS_uwsgi_stacktrace, "uwsgi");
uperl.tmp_streaming_stash[uperl.tmp_current_i] = gv_stashpv("uwsgi::streaming", 0);
nonworker:
stash = gv_stashpv("uwsgi", 1);
newCONSTSUB(stash, "VERSION", newSVpv(UWSGI_VERSION, 0));
newCONSTSUB(stash, "SPOOL_OK", newSViv(-2));
newCONSTSUB(stash, "SPOOL_RETRY", newSViv(-1));
newCONSTSUB(stash, "SPOOL_IGNORE", newSViv(0));
init_perl_embedded_module();
}
@@ -267,9 +313,6 @@ 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);
size_t size;
char *buf = uwsgi_open_and_read(app_name, &size, 1, NULL);
if (uwsgi_file_exists(app_name)) {
// prepare for $0 (if the file is local)
uperl.embedding[1] = app_name;
@@ -322,43 +365,31 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
uperl.tmp_current_i = i;
if (uperl.locallib) {
uwsgi_log("using %s as local::lib directory\n", uperl.locallib);
uperl.embedding[1] = uwsgi_concat2("-Mlocal::lib=", uperl.locallib);
uperl.embedding[2] = app_name;
if (perl_parse(interpreters[i], xs_init, 3, uperl.embedding, NULL)) {
// what to do here ? i hope no-one will use threads with dynamic apps... but clear the whole stuff...
free(uperl.embedding[1]);
uperl.embedding[1] = app_name;
free(callables);
uwsgi_perl_free_stashes();
goto clear;
}
free(uperl.embedding[1]);
uperl.embedding[1] = app_name;
}
else {
if (perl_parse(interpreters[i], xs_init, 2, uperl.embedding, NULL)) {
// We need to initialize the interpreter to execute
// our xs_init hook, but we're *not* calling it with
// uperl.embedding as an argument so we won't execute
// BEGIN blocks in app_name twice.
{
char *perl_init_arg[] = { "", "-e", "0" };
if (perl_parse(interpreters[i], xs_init, 3, perl_init_arg, NULL)) {
// what to do here ? i hope no-one will use threads with dynamic apps... but clear the whole stuff...
free(callables);
uwsgi_perl_free_stashes();
goto clear;
}
}
perl_eval_pv("use IO::Handle;", 0);
perl_eval_pv("use IO::File;", 0);
perl_eval_pv("use IO::Socket;", 0);
perl_eval_pv("use Scalar::Util;", 0);
if (!uperl.no_die_catch) {
perl_eval_pv("use Devel::StackTrace;", 0);
if (!SvTRUE(ERRSV)) {
uperl.stacktrace_available = 1;
perl_eval_pv("$SIG{__DIE__} = \\&uwsgi::stacktrace;", 0);
}
}
if (uperl.locallib) {
uwsgi_log("using %s as local::lib directory\n", uperl.locallib);
char *local_lib_use = uwsgi_concat3("use local::lib qw(", uperl.locallib, ");");
perl_eval_pv(local_lib_use, 1);
free(local_lib_use);
}
perl_eval_pv("use IO::Handle;", 1);
perl_eval_pv("use IO::File;", 1);
perl_eval_pv("use IO::Socket;", 1);
perl_eval_pv("use Scalar::Util;", 1);
if (uperl.argv_items || uperl.argv_item) {
AV *uperl_argv = GvAV(PL_argvgv);
if (uperl.argv_items) {
@@ -375,12 +406,32 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
}
}
SV *dollar_zero = get_sv("0", GV_ADD);
sv_setsv(dollar_zero, newSVpv(app, app_len));
callables[i] = perl_eval_pv(uwsgi_concat4("#line 1 ", app_name, "\n", buf), 0);
if (!callables[i]) {
SV *has_plack = NULL;
if (!uperl.no_plack) {
has_plack = perl_eval_pv("use Plack::Util;", 0);
}
if (!has_plack || SvTRUE(ERRSV)) {
if (!uperl.no_plack) {
uwsgi_log("Plack::Util is not installed, using \"do\" instead of \"load_psgi\"\n");
}
char *code = uwsgi_concat3("my $app = do '", app_name, "'; if ( !$app && ( my $error = $@ || $! )) { die $error; }; $app");
callables[i] = perl_eval_pv(code, 0);
free(code);
}
else {
char *code = uwsgi_concat3("Plack::Util::load_psgi '", app_name , "';");
callables[i] = perl_eval_pv(code, 0);
free(code);
}
if (!callables[i] || SvTYPE(callables[i]) == SVt_NULL || SvTRUE(ERRSV)) {
if (SvTRUE(ERRSV)) {
uwsgi_log("%s", SvPV_nolen(ERRSV));
}
uwsgi_log("unable to find PSGI function entry point.\n");
// what to do here ? i hope no-one will use threads with dynamic apps...
free(callables);
@@ -388,18 +439,16 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
goto clear;
}
if (!uperl.no_die_catch) {
perl_eval_pv("use Devel::StackTrace; $SIG{__DIE__} = sub { print Devel::StackTrace->new()->as_string() };", 0);
if(SvTRUE(ERRSV)) {
uwsgi_log("%s", SvPV_nolen(ERRSV));
}
}
PERL_SET_CONTEXT(interpreters[0]);
}
free(buf);
if(SvTRUE(ERRSV)) {
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
free(callables);
uwsgi_perl_free_stashes();
goto clear;
}
if (uwsgi_apps_cnt >= uwsgi.max_apps) {
uwsgi_log("ERROR: you cannot load more than %d apps in a worker\n", uwsgi.max_apps);
goto clear;
@@ -456,6 +505,19 @@ clear2:
return -1;
}
void uwsgi_psgi_preinit_apps() {
if (uperl.exec) {
PERL_SET_CONTEXT(uperl.main[0]);
perl_parse(uperl.main[0], xs_init, 3, uperl.embedding, NULL);
struct uwsgi_string_list *usl;
uwsgi_foreach(usl, uperl.exec) {
SV *dollar_zero = get_sv("0", GV_ADD);
sv_setsv(dollar_zero, newSVpv(usl->value, usl->len));
uwsgi_perl_exec(usl->value);
}
}
}
void uwsgi_psgi_app() {
if (uperl.psgi) {
@@ -463,15 +525,11 @@ void uwsgi_psgi_app() {
init_psgi_app(NULL, uperl.psgi, strlen(uperl.psgi), uperl.main);
}
// create a perl environment (if needed)
else if (uperl.exec || uperl.shell) {
else if (!uperl.exec && uperl.shell) {
PERL_SET_CONTEXT(uperl.main[0]);
perl_parse(uperl.main[0], xs_init, 2, uperl.embedding, NULL);
perl_parse(uperl.main[0], xs_init, 3, uperl.embedding, NULL);
}
struct uwsgi_string_list *usl;
uwsgi_foreach(usl, uperl.exec) {
uwsgi_perl_exec(usl->value);
}
}
@@ -480,7 +538,7 @@ int uwsgi_perl_mule(char *opt) {
if (uwsgi_endswith(opt, ".pl")) {
PERL_SET_CONTEXT(uperl.main[0]);
uperl.embedding[1] = opt;
if (perl_parse(uperl.main[0], xs_init, 2, uperl.embedding, NULL)) {
if (perl_parse(uperl.main[0], xs_init, 3, uperl.embedding, NULL)) {
return 0;
}
perl_run(uperl.main[0]);
@@ -495,6 +553,6 @@ int uwsgi_perl_mule(char *opt) {
void uwsgi_perl_exec(char *filename) {
size_t size = 0;
char *buf = uwsgi_open_and_read(filename, &size, 1, NULL);
perl_eval_pv(buf, 0);
perl_eval_pv(buf, 1);
free(buf);
}
+5
View File
@@ -44,6 +44,8 @@ struct uwsgi_option uwsgi_perl_options[] = {
{"plshell", optional_argument, 0, "run a perl interactive shell", uwsgi_opt_plshell, NULL, 0},
{"plshell-oneshot", no_argument, 0, "run a perl interactive shell (one shot)", uwsgi_opt_plshell, NULL, 0},
{"perl-no-plack", no_argument, 0, "force the use of do instead of Plack::Util::load_psgi", uwsgi_opt_true, &uperl.no_plack, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -705,6 +707,8 @@ void uwsgi_perl_post_fork() {
struct uwsgi_string_list *usl;
uwsgi_foreach(usl, uperl.exec_post_fork) {
SV *dollar_zero = get_sv("0", GV_ADD);
sv_setsv(dollar_zero, newSVpv(usl->value, usl->len));
uwsgi_perl_exec(usl->value);
}
@@ -950,6 +954,7 @@ struct uwsgi_plugin psgi_plugin = {
.init = uwsgi_perl_init,
.options = uwsgi_perl_options,
.preinit_apps = uwsgi_psgi_preinit_apps,
.init_apps = uwsgi_psgi_app,
.mount_app = uwsgi_perl_mount_app,
+60
View File
@@ -897,6 +897,64 @@ XS(XS_chunked_read_nb) {
XSRETURN(1);
}
XS(XS_spool) {
dXSARGS;
psgi_check_args(1);
SV *arg = ST(0);
HV *env = NULL;
char *body = NULL;
STRLEN body_len = 0;
if (SvROK(arg)) {
env = (HV *) SvRV(arg);
}
else {
croak("spool argument must be a hashref");
XSRETURN_UNDEF;
}
if (SvTYPE(env) != SVt_PVHV) {
croak("spool argument must be a hashref");
XSRETURN_UNDEF;
}
if (hv_exists(env, "body", 4)) {
SV **body_sv = hv_fetch(env, "body", 4, 0);
body = SvPV(*body_sv, body_len);
(void)hv_delete(env, "body", 4, 0);
}
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
HE *he;
hv_iterinit(env);
while((he = hv_iternext(env))) {
I32 klen;
STRLEN vlen;
char *key = hv_iterkey(he, &klen);
char *value = SvPV(hv_iterval(env, he), vlen);
if (uwsgi_buffer_append_keyval(ub, key, klen, value, vlen)) {
croak("unable to serialize hash to spool file");
uwsgi_buffer_destroy(ub);
XSRETURN_UNDEF;
}
}
char *filename = uwsgi_spool_request(current_wsgi_req(), ub->buf, ub->pos, body, body_len);
uwsgi_buffer_destroy(ub);
if (filename) {
ST(0) = newSVpv(filename, strlen(filename));
free(filename);
XSRETURN(1);
}
croak("unable to spool request");
XSRETURN_UNDEF;
}
void init_perl_embedded_module() {
psgi_xs(reload);
@@ -957,4 +1015,6 @@ void init_perl_embedded_module() {
psgi_xs(sharedarea_wait);
psgi_xs(spooler);
psgi_xs(spool);
}
+41 -25
View File
@@ -16,12 +16,15 @@ struct uwsgi_pypy {
char *home;
char *wsgi;
char *wsgi_file;
char *paste;
struct uwsgi_string_list *eval;
struct uwsgi_string_list *eval_post_fork;
struct uwsgi_string_list *exec;
struct uwsgi_string_list *exec_post_fork;
struct uwsgi_string_list *pp;
pthread_mutex_t attach_thread_lock;
} upypy;
// the functions exposed by libpypy-c
@@ -32,8 +35,10 @@ void (*u_pypy_thread_attach)(void);
void (*u_pypy_init_threads)(void);
// the hooks you can override with pypy
void (*uwsgi_pypy_hook_execute_source)(char *);
void (*uwsgi_pypy_hook_loader)(char *);
void (*uwsgi_pypy_hook_file_loader)(char *);
void (*uwsgi_pypy_hook_paste_loader)(char *);
void (*uwsgi_pypy_hook_pythonpath)(char *);
void (*uwsgi_pypy_hook_request)(void *, int);
void (*uwsgi_pypy_post_fork_hook)(void);
@@ -182,23 +187,21 @@ ready:
static void uwsgi_pypy_preinit_apps() {
struct uwsgi_string_list *usl = upypy.eval;
while(usl) {
if (u_pypy_execute_source(usl->value)) {
exit(1);
}
usl = usl->next;
if (!uwsgi_pypy_hook_execute_source) {
uwsgi_log("*** WARNING your pypy setup code does not expose a callback for \"execute_source\" ***\n");
return;
}
usl = upypy.exec;
while(usl) {
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, upypy.eval) {
uwsgi_pypy_hook_execute_source(usl->value);
}
uwsgi_foreach(usl, upypy.exec) {
size_t rlen = 0;
char *buffer = uwsgi_open_and_read(usl->value, &rlen, 1, NULL);
if (u_pypy_execute_source(buffer)) {
exit(1);
}
uwsgi_pypy_hook_execute_source(buffer);
free(buffer);
usl = usl->next;
}
}
@@ -231,6 +234,10 @@ static void uwsgi_pypy_init_apps() {
if (uwsgi_pypy_hook_file_loader && upypy.wsgi_file) {
uwsgi_pypy_hook_file_loader(upypy.wsgi_file);
}
if (uwsgi_pypy_hook_paste_loader && upypy.paste) {
uwsgi_pypy_hook_paste_loader(upypy.paste);
}
}
/*
@@ -240,12 +247,20 @@ static void uwsgi_pypy_atexit() {
}
*/
static void uwsgi_opt_pypy_ini_paste(char *opt, char *value, void *foobar) {
uwsgi_opt_load_ini(opt, value, NULL);
upypy.paste = value;
}
static struct uwsgi_option uwsgi_pypy_options[] = {
{"pypy-lib", required_argument, 0, "set the path/name of the pypy library", uwsgi_opt_set_str, &upypy.lib, 0},
{"pypy-setup", required_argument, 0, "set the path of the python setup script", uwsgi_opt_set_str, &upypy.setup, 0},
{"pypy-home", required_argument, 0, "set the home of pypy library", uwsgi_opt_set_str, &upypy.home, 0},
{"pypy-wsgi", required_argument, 0, "load a WSGI module", uwsgi_opt_set_str, &upypy.wsgi, 0},
{"pypy-wsgi-file", required_argument, 0, "load a WSGI/mod_wsgi file", uwsgi_opt_set_str, &upypy.wsgi_file, 0},
{"pypy-ini-paste", required_argument, 0, "load a paste.deploy config file containing uwsgi section", uwsgi_opt_pypy_ini_paste, NULL, UWSGI_OPT_IMMEDIATE},
{"pypy-paste", required_argument, 0, "load a paste.deploy config file", uwsgi_opt_set_str, &upypy.paste, 0},
{"pypy-eval", required_argument, 0, "evaluate pypy code before fork()", uwsgi_opt_add_string_list, &upypy.eval, 0},
{"pypy-eval-post-fork", required_argument, 0, "evaluate pypy code soon after fork()", uwsgi_opt_add_string_list, &upypy.eval_post_fork, 0},
{"pypy-exec", required_argument, 0, "execute pypy code from file before fork()", uwsgi_opt_add_string_list, &upypy.exec, 0},
@@ -264,7 +279,9 @@ static void uwsgi_pypy_enable_threads() {
static void uwsgi_pypy_init_thread() {
if (u_pypy_thread_attach) {
pthread_mutex_lock(&upypy.attach_thread_lock);
u_pypy_thread_attach();
pthread_mutex_unlock(&upypy.attach_thread_lock);
}
}
@@ -286,22 +303,16 @@ static uint64_t uwsgi_pypy_rpc(void *func, uint8_t argc, char **argv, uint16_t a
}
static void uwsgi_pypy_post_fork() {
struct uwsgi_string_list *usl = upypy.eval_post_fork;
while(usl) {
if (u_pypy_execute_source(usl->value)) {
exit(1);
}
usl = usl->next;
pthread_mutex_init(&upypy.attach_thread_lock, NULL);
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, upypy.eval_post_fork) {
uwsgi_pypy_hook_execute_source(usl->value);
}
usl = upypy.exec_post_fork;
while(usl) {
uwsgi_foreach(usl, upypy.exec_post_fork) {
size_t rlen = 0;
char *buffer = uwsgi_open_and_read(usl->value, &rlen, 1, NULL);
if (u_pypy_execute_source(buffer)) {
exit(1);
}
uwsgi_pypy_hook_execute_source(buffer);
free(buffer);
usl = usl->next;
}
if (uwsgi_pypy_post_fork_hook) {
@@ -318,10 +329,15 @@ static void uwsgi_pypy_onload() {
static int uwsgi_pypy_mule(char *opt) {
if (!uwsgi_pypy_hook_execute_source) {
uwsgi_log("!!! no \"execute_source\" callback in your pypy setup code !!!\n");
exit(1);
}
if (uwsgi_endswith(opt, ".py")) {
size_t rlen = 0;
char *buffer = uwsgi_open_and_read(opt, &rlen, 1, NULL);
u_pypy_execute_source(buffer);
uwsgi_pypy_hook_execute_source(buffer);
free(buffer);
return 1;
}
+31
View File
@@ -24,8 +24,10 @@ ssize_t read(int, void *, size_t);
ssize_t write(int, const void *, size_t);
int close(int);
void (*uwsgi_pypy_hook_execute_source)(char *);
void (*uwsgi_pypy_hook_loader)(char *);
void (*uwsgi_pypy_hook_file_loader)(char *);
void (*uwsgi_pypy_hook_paste_loader)(char *);
void (*uwsgi_pypy_hook_pythonpath)(char *);
void (*uwsgi_pypy_hook_request)(struct wsgi_request *);
void (*uwsgi_pypy_post_fork_hook)(void);
@@ -276,6 +278,14 @@ wsgi_application = None
if len(sys.argv) == 0:
sys.argv.insert(0, ffi.string(lib.uwsgi_binary_path()))
"""
execute source, we expose it as cffi callback to avoid deadlocks
after GIL initialization
"""
@ffi.callback("void(char *)")
def uwsgi_pypy_execute_source(s):
source = ffi.string(s)
exec(source)
"""
load a wsgi module
@@ -304,6 +314,25 @@ def uwsgi_pypy_file_loader(filename):
mod = imp.load_source('uwsgi_file_wsgi', w)
wsgi_application = getattr(mod, c)
"""
load a .ini paste app
"""
@ffi.callback("void(char *)")
def uwsgi_pypy_paste_loader(config):
global wsgi_application
c = ffi.string(config)
if c.startswith('config:'):
c = c[7:]
if c[0] != '/':
c = os.getcwd() + '/' + c
try:
from paste.script.util.logging_config import fileConfig
fileConfig(c)
except ImportError:
print "PyPy WARNING: unable to load paste.script.util.logging_config"
from paste.deploy import loadapp
wsgi_application = loadapp('config:%s' % c)
"""
.post_fork_hook
"""
@@ -460,8 +489,10 @@ def uwsgi_pypy_wsgi_handler(wsgi_req):
if hasattr(response, 'close'):
response.close()
lib.uwsgi_pypy_hook_execute_source = uwsgi_pypy_execute_source
lib.uwsgi_pypy_hook_loader = uwsgi_pypy_loader
lib.uwsgi_pypy_hook_file_loader = uwsgi_pypy_file_loader
lib.uwsgi_pypy_hook_paste_loader = uwsgi_pypy_paste_loader
lib.uwsgi_pypy_hook_pythonpath = uwsgi_pypy_pythonpath
lib.uwsgi_pypy_hook_request = uwsgi_pypy_wsgi_handler
lib.uwsgi_pypy_post_fork_hook = uwsgi_pypy_post_fork_hook
+34 -41
View File
@@ -1616,25 +1616,25 @@ int uwsgi_python_spooler(char *filename, char *buf, uint16_t len, char *body, si
return 0;
}
int retval = -1;
PyObject *spool_dict = PyDict_New();
PyObject *pyargs, *ret;
PyObject *pyargs = PyTuple_New(1);
PyObject *ret = NULL;
PyObject *value = PyString_FromString(filename);
PyDict_SetItemString(spool_dict, "spooler_task_name", value);
Py_DECREF(value);
if (uwsgi_hooked_parse(buf, len, uwsgi_python_add_item, spool_dict)) {
Py_DECREF(spool_dict);
// malformed packet, destroy it
UWSGI_RELEASE_GIL;
return -2;
retval = -2;
goto clear;
}
pyargs = PyTuple_New(1);
PyObject *zero = PyString_FromString(filename);
PyDict_SetItemString(spool_dict, "spooler_task_name", zero);
Py_DECREF(zero);
if (body && body_len > 0) {
PyDict_SetItemString(spool_dict, "body", PyString_FromStringAndSize(body, body_len));
PyObject *value = PyString_FromStringAndSize(body, body_len);
PyDict_SetItemString(spool_dict, "body", value);
Py_DECREF(value);
}
PyTuple_SetItem(pyargs, 0, spool_dict);
@@ -1642,32 +1642,25 @@ int uwsgi_python_spooler(char *filename, char *buf, uint16_t len, char *body, si
if (ret) {
if (!PyInt_Check(ret)) {
Py_DECREF(ret);
Py_DECREF(spool_dict);
Py_DECREF(pyargs);
// error, retry
UWSGI_RELEASE_GIL;
return -1;
}
int retval = (int) PyInt_AsLong(ret);
Py_DECREF(ret);
Py_DECREF(spool_dict);
Py_DECREF(pyargs);
UWSGI_RELEASE_GIL;
return retval;
retval = -1; // error, retry
} else {
retval = (int) PyInt_AsLong(ret);
}
goto clear;
}
if (PyErr_Occurred())
PyErr_Print();
Py_DECREF(spool_dict);
Py_DECREF(pyargs);
// error, retry
retval = -1;
clear:
Py_XDECREF(ret);
Py_XDECREF(pyargs);
Py_XDECREF(spool_dict);
UWSGI_RELEASE_GIL;
return -1;
return retval;
}
void uwsgi_python_resume(struct wsgi_request *wsgi_req) {
@@ -1795,25 +1788,25 @@ static void uwsgi_python_harakiri(int wid) {
if (up.tracebacker) {
char buf[8192];
char *address = uwsgi_concat2(up.tracebacker, uwsgi_num2str(wid));
char *wid_str = uwsgi_num2str(wid);
char *address = uwsgi_concat2(up.tracebacker, wid_str);
int fd = uwsgi_connect(address, -1, 0);
if (fd < 1)
goto exit;
int ret = uwsgi_waitfd(fd, uwsgi.socket_timeout);
if (ret <= 0) {
goto cleanup;
}
ssize_t len = read(fd, buf, 8192);
if (len <= 0) {
goto cleanup;
}
uwsgi_log("%.*s", (int) len, buf);
for(;;) {
int ret = uwsgi_waitfd(fd, uwsgi.socket_timeout);
if (ret <= 0) goto cleanup;
ssize_t len = read(fd, buf, 8192);
if (len <= 0) goto cleanup;
uwsgi_log("%.*s", (int) len, buf);
}
cleanup:
close(fd);
exit:
free(wid_str);
free(address);
}
+6 -1
View File
@@ -60,6 +60,12 @@ void *uwsgi_python_tracebacker_thread(void *foobar) {
int current_defer_accept = uwsgi.no_defer_accept;
uwsgi.no_defer_accept = 1;
int fd = bind_to_unix(sock_path, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
if (fd < 0) {
uwsgi.no_defer_accept = current_defer_accept;
free(str_wid);
free(sock_path);
return NULL;
}
uwsgi.no_defer_accept = current_defer_accept;
PyObject *traceback_module = PyImport_ImportModule("traceback");
@@ -108,7 +114,6 @@ void *uwsgi_python_tracebacker_thread(void *foobar) {
}
PyObject *frame = PyIter_Next(frames_iter);
while(frame) {
PyObject *thread_id = PyTuple_GetItem(frame, 0);
if (!thread_id) goto next2;
+49 -112
View File
@@ -1289,7 +1289,7 @@ PyObject *py_uwsgi_mule_get_msg(PyObject * self, PyObject * args, PyObject *kwar
int timeout = -1;
int manage_signals = 1, manage_farms = 1;
static char *kwlist[] = {"signals", "buffer_size", "timeout", "farms", NULL};
static char *kwlist[] = {"signals", "farms", "buffer_size", "timeout", NULL};
if (uwsgi.muleid == 0) {
return PyErr_Format(PyExc_ValueError, "you can receive mule messages only in a mule !!!");
@@ -1745,25 +1745,13 @@ PyObject *py_uwsgi_send_spool(PyObject * self, PyObject * args, PyObject *kw) {
PyObject *spool_dict, *spool_vars;
PyObject *zero, *key, *val;
uint16_t keysize, valsize;
char *cur_buf;
int i;
char spool_filename[1024];
struct wsgi_request *wsgi_req = py_current_wsgi_req();
char *priority = NULL;
long numprio = 0;
time_t at = 0;
char *body = NULL;
size_t body_len= 0;
// this is a counter for non-request-related tasks (like threads or greenlet)
static int internal_counter = 0xffff;
struct uwsgi_spooler *uspool = uwsgi.spoolers;
spool_dict = PyTuple_GetItem(args, 0);
if (spool_dict) {
if (!PyDict_Check(spool_dict)) {
return PyErr_Format(PyExc_ValueError, "The argument of spooler callable must be a dictionary");
}
@@ -1774,46 +1762,10 @@ PyObject *py_uwsgi_send_spool(PyObject * self, PyObject * args, PyObject *kw) {
spool_dict = kw;
}
if (!spool_dict) {
return PyErr_Format(PyExc_ValueError, "The argument of spooler callable must be a dictionary");
}
// TODO if "spooler" is a num, get the spooler by id, otherwise get it by directory
PyObject *py_spooler = uwsgi_py_dict_get(spool_dict, "spooler");
if (py_spooler) {
if (PyString_Check(py_spooler)) {
uspool = uwsgi_get_spooler_by_name(PyString_AsString(py_spooler));
if (!uspool) {
return PyErr_Format(PyExc_ValueError, "Unknown spooler requested");
}
}
}
PyObject *pyprio = uwsgi_py_dict_get(spool_dict, "priority");
if (pyprio) {
if (PyInt_Check(pyprio)) {
numprio = PyInt_AsLong(pyprio);
uwsgi_py_dict_del(spool_dict, "priority");
}
}
PyObject *pyat = uwsgi_py_dict_get(spool_dict, "at");
if (pyat) {
if (PyInt_Check(pyat)) {
at = (time_t) PyInt_AsLong(pyat);
uwsgi_py_dict_del(spool_dict, "at");
}
else if (PyLong_Check(pyat)) {
at = (time_t) PyLong_AsLong(pyat);
uwsgi_py_dict_del(spool_dict, "at");
}
else if (PyFloat_Check(pyat)) {
at = (time_t) PyFloat_AsDouble(pyat);
uwsgi_py_dict_del(spool_dict, "at");
}
}
PyObject *pybody = uwsgi_py_dict_get(spool_dict, "body");
if (pybody) {
if (PyString_Check(pybody)) {
@@ -1830,9 +1782,8 @@ PyObject *py_uwsgi_send_spool(PyObject * self, PyObject * args, PyObject *kw) {
return Py_None;
}
char *spool_buffer = uwsgi_malloc(UMAX16);
cur_buf = spool_buffer;
int i;
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
for (i = 0; i < PyList_Size(spool_vars); i++) {
zero = PyList_GetItem(spool_vars, i);
@@ -1841,98 +1792,84 @@ PyObject *py_uwsgi_send_spool(PyObject * self, PyObject * args, PyObject *kw) {
key = PyTuple_GetItem(zero, 0);
val = PyTuple_GetItem(zero, 1);
#ifdef UWSGI_DEBUG
uwsgi_log("ob_type %s %s\n", key->ob_type->tp_name, val->ob_type->tp_name);
#endif
if (PyString_Check(key) && PyString_Check(val)) {
if (PyString_Check(key)) {
keysize = PyString_Size(key);
valsize = PyString_Size(val);
if (cur_buf + keysize + 2 + valsize + 2 <= spool_buffer + UMAX16) {
*cur_buf++ = (uint8_t) (keysize & 0xff);
*cur_buf++ = (uint8_t) ((keysize >> 8) & 0xff);
memcpy(cur_buf, PyString_AsString(key), keysize);
cur_buf += keysize;
*cur_buf++ = (uint8_t) (valsize & 0xff);
*cur_buf++ = (uint8_t) ((valsize >> 8) & 0xff);
memcpy(cur_buf, PyString_AsString(val), valsize);
cur_buf += valsize;
if (PyString_Check(val)) {
valsize = PyString_Size(val);
if (uwsgi_buffer_append_keyval(ub, PyString_AsString(key), keysize, PyString_AsString(val), valsize)) {
Py_DECREF(zero);
uwsgi_buffer_destroy(ub);
goto error;
}
}
else {
Py_DECREF(zero);
free(spool_buffer);
return PyErr_Format(PyExc_ValueError, "spooler packet cannot be more than %d bytes", UMAX16);
#ifdef PYTHREE
PyObject *str = PyObject_Bytes(val);
#else
PyObject *str = PyObject_Str(val);
#endif
if (!str) {
Py_DECREF(zero);
uwsgi_buffer_destroy(ub);
goto error;
}
if (uwsgi_buffer_append_keyval(ub, PyString_AsString(key), keysize, PyString_AsString(str), PyString_Size(str))) {
Py_DECREF(zero);
Py_DECREF(str);
uwsgi_buffer_destroy(ub);
goto error;
}
Py_DECREF(str);
}
}
else {
Py_DECREF(zero);
free(spool_buffer);
return PyErr_Format(PyExc_ValueError, "spooler callable dictionary must contains only strings");
uwsgi_buffer_destroy(ub);
goto error;
}
}
else {
free(spool_buffer);
Py_DECREF(zero);
Py_INCREF(Py_None);
return Py_None;
uwsgi_buffer_destroy(ub);
goto error;
}
Py_DECREF(zero);
}
else {
free(spool_buffer);
Py_INCREF(Py_None);
return Py_None;
uwsgi_buffer_destroy(ub);
goto error;
}
}
if (numprio) {
priority = uwsgi_num2str(numprio);
}
int async_id;
if (wsgi_req) {
async_id = wsgi_req->async_id;
}
else {
// the GIL is protecting this counter...
async_id = internal_counter;
internal_counter++;
}
UWSGI_RELEASE_GIL
i = spool_request(uspool, spool_filename, uwsgi.workers[0].requests + 1, async_id, spool_buffer, cur_buf - spool_buffer, priority, at, body, body_len);
char *filename = uwsgi_spool_request(wsgi_req, ub->buf, ub->pos, body, body_len);
uwsgi_buffer_destroy(ub);
UWSGI_GET_GIL
if (pybody) {
Py_DECREF(pybody);
}
if (priority) {
free(priority);
}
free(spool_buffer);
Py_DECREF(spool_vars);
if (i > 0) {
char *slash = uwsgi_get_last_char(spool_filename, '/');
if (slash) {
return PyString_FromString(slash+1);
}
return PyString_FromString(spool_filename);
if (filename) {
PyObject *ret = PyString_FromString(filename);
free(filename);
return ret;
}
return PyErr_Format(PyExc_ValueError, "unable to spool job");
error:
#ifdef PYTHREE
return PyErr_Format(PyExc_ValueError, "spooler callable dictionary must contains only bytes");
#else
return PyErr_Format(PyExc_ValueError, "spooler callable dictionary must contains only strings");
#endif
}
PyObject *py_uwsgi_spooler_pid(PyObject * self, PyObject * args) {
+2 -1
View File
@@ -21,12 +21,13 @@ 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 (!up.wsgi_accept_buffer && !wsgi_req->is_raw) goto strict;
#if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER)
if (PyObject_CheckBuffer(chunk)) {
if (!PyObject_GetBuffer(chunk, &pbuf, PyBUF_SIMPLE)) {
+30 -68
View File
@@ -932,35 +932,36 @@ static VALUE uwsgi_ruby_signal(int argc, VALUE *argv, VALUE *class) {
return Qtrue;
}
int rack_uwsgi_build_spool(VALUE rbkey, VALUE rbval, VALUE argv) {
char **sa = (char **) argv;
static int rack_uwsgi_build_spool(VALUE rbkey, VALUE rbval, VALUE argv) {
struct uwsgi_buffer *ub = (struct uwsgi_buffer *) argv;
char *cur_buf = sa[0];
char *watermark = sa[1];
if (TYPE(rbkey) != T_STRING || TYPE(rbval) != T_STRING) {
if (TYPE(rbkey) != T_STRING) {
rb_raise(rb_eRuntimeError, "spool hash must contains only strings");
return ST_STOP;
}
char *key = RSTRING_PTR(rbkey); uint16_t keylen = RSTRING_LEN(rbkey);
char *val = RSTRING_PTR(rbval); uint16_t vallen = RSTRING_LEN(rbval);
if (cur_buf + (2+keylen+2+vallen) > watermark) {
rb_raise(rb_eRuntimeError, "spool hash size can be no more than 64K");
return ST_STOP;
if (TYPE(rbval) == T_STRING) {
char *val = RSTRING_PTR(rbval); uint16_t vallen = RSTRING_LEN(rbval);
if (uwsgi_buffer_append_keyval(ub, key, keylen, val, vallen)) {
rb_raise(rb_eRuntimeError, "error building the spool packet");
return ST_STOP;
}
}
else {
//VALUE str = rb_any_to_s(rbval);
VALUE str = rb_funcall( rbval, rb_intern("to_s"), 0);
if (!str) {
rb_raise(rb_eRuntimeError, "error building the spool packet");
return ST_STOP;
}
char *val = RSTRING_PTR(str); uint16_t vallen = RSTRING_LEN(str);
if (uwsgi_buffer_append_keyval(ub, key, keylen, val, vallen)) {
rb_raise(rb_eRuntimeError, "error building the spool packet");
return ST_STOP;
}
}
*cur_buf++ = (uint8_t) (keylen & 0xff);
*cur_buf++ = (uint8_t) ((keylen >> 8) & 0xff);
memcpy(cur_buf, key, keylen); cur_buf += keylen;
*cur_buf++ = (uint8_t) (vallen & 0xff);
*cur_buf++ = (uint8_t) ((vallen >> 8) & 0xff);
memcpy(cur_buf, val, vallen); cur_buf += vallen;
// fix the ptr
sa[0] = cur_buf;
return ST_CONTINUE;
}
@@ -968,38 +969,12 @@ int rack_uwsgi_build_spool(VALUE rbkey, VALUE rbval, VALUE argv) {
static VALUE rack_uwsgi_send_spool(VALUE *class, VALUE args) {
char spool_filename[1024];
struct wsgi_request *wsgi_req = current_wsgi_req();
char *priority = NULL;
long numprio = 0;
time_t at = 0;
char *body = NULL;
size_t body_len= 0;
Check_Type(args, T_HASH);
// priority
#ifdef RUBY19
VALUE rbprio = rb_hash_lookup(args, rb_str_new2("priority"));
#else
VALUE rbprio = rb_hash_aref(args, rb_str_new2("priority"));
#endif
if (TYPE(rbprio) == T_FIXNUM) {
numprio = NUM2INT(rbprio);
rb_hash_delete(args, rb_str_new2("priority"));
}
// at
#ifdef RUBY19
VALUE rbat = rb_hash_lookup(args, rb_str_new2("at"));
#else
VALUE rbat = rb_hash_aref(args, rb_str_new2("at"));
#endif
if (TYPE(rbat) == T_FIXNUM) {
at = NUM2INT(rbat);
rb_hash_delete(args, rb_str_new2("at"));
}
// body
#ifdef RUBY19
VALUE rbbody = rb_hash_lookup(args, rb_str_new2("body"));
@@ -1012,31 +987,18 @@ static VALUE rack_uwsgi_send_spool(VALUE *class, VALUE args) {
rb_hash_delete(args, rb_str_new2("body"));
}
char *spool_buffer = uwsgi_malloc(UMAX16);
char *argv[2];
argv[0] = spool_buffer;
argv[1] = spool_buffer + UMAX16 ;
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
rb_hash_foreach(args, rack_uwsgi_build_spool, (VALUE) argv);
rb_hash_foreach(args, rack_uwsgi_build_spool, (VALUE) ub);
if (numprio) {
priority = uwsgi_num2str((int)numprio);
}
char *filename = uwsgi_spool_request(wsgi_req, ub->buf, ub->pos, body, body_len);
int ret = spool_request(uwsgi.spoolers, spool_filename, (int)(uwsgi.workers[0].requests + 1), wsgi_req->async_id, spool_buffer, (int)(argv[0] - spool_buffer), priority, at, body, body_len);
uwsgi_buffer_destroy(ub);
if (priority) {
free(priority);
}
free(spool_buffer);
if (ret > 0) {
char *slash = uwsgi_get_last_char(spool_filename, '/');
if (slash) {
return rb_str_new2(slash+1);
}
return rb_str_new2(spool_filename);
if (filename) {
VALUE ret = rb_str_new2(filename);
free(filename);
return ret;
}
rb_raise(rb_eRuntimeError, "unable to spool job");
+14 -6
View File
@@ -459,6 +459,10 @@ static void rack_hack_dollar_zero(VALUE name, ID id) {
rb_obj_taint(ur.dollar_zero);
}
#ifndef RUBY19
void Init_stack(VALUE*);
#endif
int uwsgi_rack_init(){
#ifdef RUBY19
@@ -483,14 +487,16 @@ int uwsgi_rack_init(){
uwsgi_log("*** if you get errors about rubygems.rb, you can:\n");
uwsgi_log("*** 1) add a directory to the libdir search path using --ruby-libdir ***\n");
uwsgi_log("*** 2) force the RUBY_EXEC_PREFIX with --chdir ***\n");
#ifdef UWSGI_RUBY_LIBDIR
uwsgi_string_new_list(&ur.libdir, UWSGI_RUBY_LIBDIR);
#endif
#ifdef UWSGI_RUBY_ARCHDIR
uwsgi_string_new_list(&ur.libdir, UWSGI_RUBY_ARCHDIR);
#endif
}
#endif
#ifdef UWSGI_RUBY_LIBDIR
uwsgi_string_new_list(&ur.libdir, UWSGI_RUBY_LIBDIR);
#endif
#ifdef UWSGI_RUBY_ARCHDIR
uwsgi_string_new_list(&ur.libdir, UWSGI_RUBY_ARCHDIR);
#endif
ruby_init();
struct uwsgi_string_list *usl = ur.libdir;
while(usl) {
@@ -501,6 +507,8 @@ int uwsgi_rack_init(){
ruby_options(argc, argv);
#else
ruby_init();
VALUE dummy;
Init_stack(&dummy);
ruby_init_loadpath();
#endif
+1 -1
View File
@@ -1,4 +1,4 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
#include <ruby.h>
+3 -1
View File
@@ -30,10 +30,12 @@ else:
CFLAGS.append('-I' + includedir)
archdir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['archdir']\"" % rbconfig).read().rstrip()
arch = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['arch']\"" % rbconfig).read().rstrip()
archdir2 = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['rubyarchhdrdir']\"" % rbconfig).read().rstrip()
CFLAGS.append('-I' + archdir)
CFLAGS.append('-I' + archdir + '/' + arch)
CFLAGS.append('-I' + includedir + '/' + arch)
if archdir2:
CFLAGS.append('-I' + archdir2)
LDFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['LDFLAGS']\"" % rbconfig).read().rstrip().split()
libpath = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['libdir']\"" % rbconfig).read().rstrip()
+2
View File
@@ -56,6 +56,8 @@ static struct uwsgi_option rawrouter_options[] = {
{"rawrouter-xclient", no_argument, 0, "use the xclient protocol to pass the client addres", uwsgi_opt_true, &urr.xclient, 0},
{"rawrouter-buffer-size", required_argument, 0, "set internal buffer size (default: page size)", uwsgi_opt_set_64bit, &urr.cr.buffer_size, 0},
{0, 0, 0, 0, 0, 0, 0},
};
+3
View File
@@ -24,6 +24,9 @@ else:
CFLAGS.append('-I' + archdir)
CFLAGS.append('-I' + archdir + '/' + arch)
CFLAGS.append('-I' + includedir + '/' + arch)
archdir2 = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['rubyarchhdrdir']\"" % rbconfig).read().rstrip()
if archdir2:
CFLAGS.append('-I' + archdir2)
LDFLAGS = []
LIBS = []
+38 -2
View File
@@ -13,6 +13,26 @@ pthread_mutex_t ur_basicauth_crypt_mutex;
extern struct uwsgi_server uwsgi;
static char *htpasswd_check_sha1(char *pwd) {
#ifdef UWSGI_SSL
char sha1[20];
uwsgi_sha1(pwd, strlen(pwd), sha1);
size_t len = 0;
char *b64 = uwsgi_base64_encode(sha1, 20, &len);
if (!b64) return NULL;
// we add a new line for being fgets-friendly
char *crypted = uwsgi_concat3n("{SHA}", 5, b64, len, "\n", 1);
free(b64);
return crypted;
#else
uwsgi_log("*** WARNING, rebuild uWSGI with SSL support for htpasswd sha1 feature ***\n");
return NULL;
#endif
}
static uint16_t htpasswd_check(char *filename, char *auth) {
char line[1024];
@@ -25,11 +45,23 @@ static uint16_t htpasswd_check(char *filename, char *auth) {
return 0;
}
while(fgets(line, 1024, htpasswd)) {
char *crypted = NULL;
int need_free = 0;
char *colon2 = strchr(line, ':');
if (!colon2) break;
char *cpwd = colon2+1;
size_t clen = strlen(cpwd);
// now we check which algo to use
// {SHA} ?
if (!uwsgi_starts_with(cpwd, clen, "{SHA}", 5)) {
crypted = htpasswd_check_sha1(colon+1);
if (crypted) need_free = 1;
goto check;
}
if (clen < 13) break;
if (clen > 13) cpwd[13] = 0;
@@ -39,20 +71,24 @@ static uint16_t htpasswd_check(char *filename, char *auth) {
cd.initialized = 0;
// we do as nginx here
cd.current_salt[0] = ~cpwd[0];
char *crypted = crypt_r( colon+1, cpwd, &cd);
crypted = crypt_r( colon+1, cpwd, &cd);
#else
if (uwsgi.threads > 1) pthread_mutex_lock(&ur_basicauth_crypt_mutex);
char *crypted = crypt( colon+1, cpwd);
crypted = crypt( colon+1, cpwd);
if (uwsgi.threads > 1) pthread_mutex_unlock(&ur_basicauth_crypt_mutex);
#endif
check:
if (!crypted) continue;
if (!strcmp( crypted, cpwd )) {
if (!uwsgi_strncmp(auth, colon-auth, line, colon2-line)) {
fclose(htpasswd);
if (need_free) free(crypted);
return colon-auth;
}
}
if (need_free) free(crypted);
}
fclose(htpasswd);
+6 -5
View File
@@ -1,12 +1,12 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
/* request 110 */
int uwsgi_request_signal(struct wsgi_request *wsgi_req) {
ssize_t len;
uint8_t ret_status = 1;
struct uwsgi_header uh;
if (uwsgi_signal_send(uwsgi.signal_socket, wsgi_req->uh->modifier2) < 0) {
ret_status = 0;
@@ -15,10 +15,11 @@ int uwsgi_request_signal(struct wsgi_request *wsgi_req) {
uh.modifier1 = 255;
uh.pktsize = 0;
uh.modifier2 = ret_status;
len = write(wsgi_req->fd, &uh, 4);
if (len != 4) {
uwsgi_error("write()");
if (uwsgi_response_write_body_do(wsgi_req, (char *) &uh, 4)) {
return -1;
}
return UWSGI_OK;
}
+7 -10
View File
@@ -1,4 +1,4 @@
#include "../../uwsgi.h"
#include <uwsgi.h>
/*
@@ -10,15 +10,11 @@ extern struct uwsgi_server uwsgi;
int uwsgi_request_spooler(struct wsgi_request *wsgi_req) {
int i;
char spool_filename[1024];
struct uwsgi_header uh;
// get the spooler from the modifier2
// TODO get the spooler from the modifier2
struct uwsgi_spooler *uspool = uwsgi.spoolers;
if (uspool == NULL) {
if (uwsgi.spoolers == NULL) {
uwsgi_log("the spooler is inactive !!!...skip\n");
uh.modifier1 = 255;
uh.pktsize = 0;
@@ -27,20 +23,21 @@ int uwsgi_request_spooler(struct wsgi_request *wsgi_req) {
return -1;
}
i = spool_request(uspool, spool_filename, uwsgi.workers[0].requests + 1, wsgi_req->async_id, wsgi_req->buffer, wsgi_req->uh->pktsize, NULL, 0, NULL, 0);
char *filename = uwsgi_spool_request(wsgi_req, wsgi_req->buffer, wsgi_req->uh->pktsize, NULL, 0);
uh.modifier1 = 255;
uh.pktsize = 0;
if (i > 0) {
if (filename) {
uh.modifier2 = 1;
if (uwsgi_response_write_body_do(wsgi_req, (char *) &uh, 4)) {
uwsgi_log("disconnected client, remove spool file.\n");
/* client disconnect, remove spool file */
if (unlink(spool_filename)) {
if (unlink(filename)) {
uwsgi_error("uwsgi_request_spooler()/unlink()");
uwsgi_log("something horrible happened !!! check your spooler ASAP !!!\n");
exit(1);
}
}
free(filename);
return 0;
}
else {
+3 -1
View File
@@ -155,6 +155,7 @@ static struct uwsgi_option sslrouter_options[] = {
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
{"sslrouter-sni", no_argument, 0, "use SNI to route requests", uwsgi_opt_true, &usr.sni, 0},
#endif
{"sslrouter-buffer-size", required_argument, 0, "set internal buffer size (default: page size)", uwsgi_opt_set_64bit, &usr.cr.buffer_size, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -362,7 +363,8 @@ static int sslrouter_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_ga
SSL_set_fd(sr->ssl, cs->main_peer->fd);
SSL_set_accept_state(sr->ssl);
uwsgi_cr_set_hooks(cs->main_peer, sr_read, NULL);
if (uwsgi_cr_set_hooks(cs->main_peer, sr_read, NULL))
return -1;
return 0;
}
-1
View File
@@ -72,7 +72,6 @@ static void uwsgi_symcall_init(){
exit(1);
}
*space = ' ';
usl = usl->next;
}
}
+9 -3
View File
@@ -14,13 +14,18 @@ int uwsgi_tuntap_peer_rules_check(struct uwsgi_tuntap_router *uttr, struct uwsgi
uint32_t dst = ntohl(*dst_ip);
#ifdef UWSGI_DEBUG
uwsgi_log("%X %X\n", src, dst);
uwsgi_log("%d %X %X\n",direction, src, dst);
#endif
int i;
for(i=0;i<uttp->rules_cnt;i++) {
struct uwsgi_tuntap_peer_rule *rule = &uttp->rules[i];
#ifdef UWSGI_DEBUG
uwsgi_log("cnt = %i/%d direction = %d action = %d %X %X\n", i, uttp->rules_cnt, rule->direction, rule->action, rule->src_mask, rule->dst_mask);
#endif
if (rule->direction != direction) continue;
if (rule->src) {
@@ -33,6 +38,7 @@ int uwsgi_tuntap_peer_rules_check(struct uwsgi_tuntap_router *uttr, struct uwsgi
if (dst_masked != rule->dst) continue;
}
if (rule->action == 0) return 0;
if (rule->action == 1) return 1;
if (rule->action == 2) {
@@ -295,7 +301,7 @@ void uwsgi_tuntap_peer_send_rules(int fd, struct uwsgi_tuntap_peer *peer) {
char *slash = strchr(argv[1],'/');
if (slash) {
utpr.src_mask = (0xffffffff << ((atoi(slash+1))-utpr.src_mask));
utpr.src_mask = (0xffffffff << ((atoi(slash+1))-32));
*slash = 0;
}
if (inet_pton(AF_INET, argv[1], &utpr.src) != 1) {
@@ -307,7 +313,7 @@ void uwsgi_tuntap_peer_send_rules(int fd, struct uwsgi_tuntap_peer *peer) {
slash = strchr(argv[2],'/');
if (slash) {
utpr.dst_mask = (0xffffffff << ((atoi(slash+1))-utpr.dst_mask));
utpr.dst_mask = (0xffffffff << ((atoi(slash+1))-32));
*slash = 0;
}
if (inet_pton(AF_INET, argv[2], &utpr.dst) != 1) {
+5 -4
View File
@@ -134,6 +134,7 @@ static int uwsgi_request_xslt(struct wsgi_request *wsgi_req) {
size_t stylesheet_len = 0;
char *params = NULL;
xmlDoc *doc = NULL;
if (uwsgi_parse_vars(wsgi_req)) {
return -1;
@@ -271,16 +272,16 @@ static int uwsgi_request_xslt(struct wsgi_request *wsgi_req) {
return UWSGI_OK;
apply:
if (wsgi_req->query_string_len > 0) {
params = uwsgi_concat2n(wsgi_req->query_string, wsgi_req->query_string_len, "", 0);
}
// we have both the file and the stylesheet, let's run the engine
xmlDoc *doc = xmlParseFile(xmlfile);
doc = xmlParseFile(xmlfile);
free(xmlfile);
if (!doc) {
uwsgi_500(wsgi_req);
return UWSGI_OK;
}
if (wsgi_req->query_string_len > 0) {
params = uwsgi_concat2n(wsgi_req->query_string, wsgi_req->query_string_len, "", 0);
}
output = uwsgi_xslt_apply(doc, stylesheet, params, &output_rlen);
xmlFreeDoc(doc);
if (params) free(params);
+12
View File
@@ -0,0 +1,12 @@
[uwsgi]
socket = /tmp/foo
cache2 = name=items_1,blocks=4,items=2,bitmap=1,blocksize=1
cache2 = name=items_2,blocks=4,items=3,bitmap=1,blocksize=1
cache2 = name=items_3,blocks=4,items=4,bitmap=1,blocksize=1
cache2 = name=items_4,blocks=5,items=5,bitmap=1,blocksize=1
cache2 = name=items_17,blocks=17,items=17,bitmap=1,blocksize=1
cache2 = name=items_4_10,blocks=5,items=5,bitmap=1,blocksize=10
cache2 = name=items_1_100000,blocks=1000,items=2,bitmap=1,blocksize=100
cache2 = name=items_non_bitmap,items=2,blocksize=20
pyrun = t/cachebitmap.py
+106
View File
@@ -0,0 +1,106 @@
import uwsgi
import unittest
import random
import string
class BitmapTest(unittest.TestCase):
__caches__ = ['items_1', 'items_2', 'items_3', 'items_4', 'items_17', 'items_4_10', 'items_1_100000', 'items_non_bitmap']
def setUp(self):
for cache in self.__caches__:
uwsgi.cache_clear(cache)
def test_failed_by_one(self):
self.assertIsNone(uwsgi.cache_update('key1', 'HELLO', 0, 'items_1'))
def test_ok_four_bytes(self):
self.assertTrue(uwsgi.cache_update('key1', 'HELL', 0, 'items_1'))
def test_two_items_using_four_blocks(self):
self.assertTrue(uwsgi.cache_update('key1', 'HE', 0, 'items_2'))
self.assertTrue(uwsgi.cache_update('key2', 'LL', 0, 'items_2'))
self.assertTrue(uwsgi.cache_del('key1', 'items_2'))
self.assertIsNone(uwsgi.cache_update('key1', 'HEL', 0, 'items_2'))
self.assertTrue(uwsgi.cache_update('key1', 'HE', 0, 'items_2'))
def test_overlapping(self):
self.assertTrue(uwsgi.cache_update('key1', 'HE', 0, 'items_2'))
self.assertIsNone(uwsgi.cache_update('key1', 'HELL', 0, 'items_2'))
self.assertTrue(uwsgi.cache_del('key1', 'items_2'))
self.assertTrue(uwsgi.cache_update('key1', 'HELL', 0, 'items_2'))
def test_big_item(self):
self.assertIsNone(uwsgi.cache_update('key1', 'HELLOHELLOHELLOHEL', 0, 'items_17'))
self.assertTrue(uwsgi.cache_update('key1', 'HELLOHELLOHELLOHE', 0, 'items_17'))
def test_set(self):
self.assertTrue(uwsgi.cache_set('key1', 'HELLO', 0, 'items_17'))
self.assertIsNone(uwsgi.cache_set('key1', 'HELLO', 0, 'items_17'))
self.assertTrue(uwsgi.cache_del('key1', 'items_17'))
self.assertTrue(uwsgi.cache_set('key1', 'HELLO', 0, 'items_17'))
self.assertIsNone(uwsgi.cache_set('key1', 'HELLO', 0, 'items_17'))
def test_too_much_items(self):
self.assertTrue(uwsgi.cache_set('key1', 'HELLO', 0, 'items_4_10'))
self.assertTrue(uwsgi.cache_set('key2', 'HELLO', 0, 'items_4_10'))
self.assertTrue(uwsgi.cache_set('key3', 'HELLO', 0, 'items_4_10'))
self.assertTrue(uwsgi.cache_set('key4', 'HELLO', 0, 'items_4_10'))
self.assertIsNone(uwsgi.cache_set('key5', 'HELLO', 0, 'items_4_10'))
def test_big_delete(self):
self.assertTrue(uwsgi.cache_set('key1', 'X' * 50 , 0, 'items_4_10'))
self.assertTrue(uwsgi.cache_del('key1', 'items_4_10'))
self.assertTrue(uwsgi.cache_set('key1', 'HELLOHELLO', 0, 'items_4_10'))
self.assertTrue(uwsgi.cache_set('key2', 'HELLOHELLO', 0, 'items_4_10'))
self.assertTrue(uwsgi.cache_set('key3', 'HELLOHELLO', 0, 'items_4_10'))
self.assertTrue(uwsgi.cache_set('key4', 'HELLOHELLO', 0, 'items_4_10'))
self.assertIsNone(uwsgi.cache_set('key5', 'HELLOHELLO', 0, 'items_4_10'))
def test_big_update(self):
self.assertTrue(uwsgi.cache_set('key1', 'X' * 40 , 0, 'items_4_10'))
self.assertTrue(uwsgi.cache_update('key1', 'X' * 10 , 0, 'items_4_10'))
self.assertTrue(uwsgi.cache_del('key1', 'items_4_10'))
self.assertIsNone(uwsgi.cache_update('key1', 'X' * 51 , 0, 'items_4_10'))
self.assertTrue(uwsgi.cache_update('key1', 'X' * 50 , 0, 'items_4_10'))
def test_multi_clear(self):
for i in range(0, 100):
self.assertTrue(uwsgi.cache_clear('items_4_10'))
def test_multi_delete(self):
for i in range(0, 100):
self.assertTrue(uwsgi.cache_set('key1', 'X' * 50 , 0, 'items_4_10'))
self.assertTrue(uwsgi.cache_del('key1', 'items_4_10'))
for i in range(0, 100):
self.assertIsNone(uwsgi.cache_set('key1', 'X' * 51 , 0, 'items_4_10'))
self.assertIsNone(uwsgi.cache_del('key1', 'items_4_10'))
for i in range(0, 100):
self.assertTrue(uwsgi.cache_set('key1', 'X' * 50 , 0, 'items_4_10'))
self.assertTrue(uwsgi.cache_del('key1', 'items_4_10'))
def test_big_key(self):
self.assertTrue(uwsgi.cache_set('K' * 2048, 'X' * 50 , 0, 'items_4_10'))
self.assertIsNone(uwsgi.cache_set('K' * 2049, 'X' * 50 , 0, 'items_4_10'))
def rand_blob(self, n=32):
return ''.join([random.choice(string.ascii_letters + string.digits) for n in range(n)])
def test_big_random(self):
blob = self.rand_blob(100000)
self.assertTrue(uwsgi.cache_set('KEY', blob, 0, 'items_1_100000'))
get_blob = uwsgi.cache_get('KEY', 'items_1_100000')
self.assertEqual(blob, get_blob)
self.assertTrue(uwsgi.cache_del('KEY', 'items_1_100000'))
self.assertIsNone(uwsgi.cache_set('KEY', 'X' * 100001, 0, 'items_1_100000'))
self.assertTrue(uwsgi.cache_set('KEY', 'X' * 10000, 0, 'items_1_100000'))
def test_non_bitmap(self):
self.assertTrue(uwsgi.cache_set('KEY', 'X' * 20, 0, 'items_non_bitmap'))
self.assertTrue(uwsgi.cache_del('KEY', 'items_non_bitmap'))
self.assertIsNone(uwsgi.cache_set('KEY', 'X' * 21, 0, 'items_non_bitmap'))
self.assertTrue(uwsgi.cache_set('KEY', 'X' * 20, 0, 'items_non_bitmap'))
unittest.main()
+8
View File
@@ -0,0 +1,8 @@
my $app = sub {
my ($env) = @_;
my $orig = $env->{QUERY_STRING};
if ($env->{CONTENT_LENGTH} > 0) {
$env->{'psgi.input'}->read($orig, $env->{CONTENT_LENGTH}, $env->{HTTP_UWSGI_OFFSET});
}
return [ 200, ['Content-Type' => 'text/plain'], [$orig."\n"]];
};
+4
View File
@@ -1,5 +1,9 @@
use strict;
use warnings;
BEGIN {
die "PANIC: We should only load this once" if ++$main::count_BEGIN > 1;
}
die "PANIC: We should only run this once" if ++$main::count_runs > 1;
uwsgi::register_rpc('hello', sub {
my ($one, $two, $three) = @_;
+45
View File
@@ -0,0 +1,45 @@
#!/usr/bin/perl
#uwsgi --http-socket :9090 --psgi apps/input_with_offset.pl
use IO::Socket::INET;
my @tests;
my $base = 'one_two_three_four';
push @tests, ['-1', 'HELLO', 'one_two_three_fouHELLO'];
push @tests, ['-2', 'HELLO', 'one_two_three_foHELLO'];
push @tests, ['-2', 'HELLOHELLOHELLOTEST2TEST3', 'one_two_three_foHELLOHELLOHELLOTEST2TEST3'];
push @tests, ['-12', 'HELLOHELLOHELLOTEST2TEST3', 'one_twHELLOHELLOHELLOTEST2TEST3'];
push @tests, ['-22', 'HELLOHELLOHELLOTEST2TEST3', "HELLOHELLOHELLOTEST2TEST3"];
push @tests, ['-22', 'HELLO', "HELLOne_two_three_four"];
push @tests, ['-23', 'HELLO', "HELLOone_two_three_four"];
push @tests, ['-25', 'HELLO', "HELLO\0\0one_two_three_four"];
push @tests, ['1', 'HELLO', "oHELLOo_three_four"];
push @tests, ['3', 'HELLO', "oneHELLOthree_four"];
push @tests, ['30', 'HELLO', "one_two_three_four\0\0\0\0\0\0\0\0\0\0\0\0HELLO"];
foreach(@tests) {
print "testing: offset(".$_->[0].") body(".$_->[1].")\n";
my $req = "POST /?".$base." HTTP/1.0\r\nContent-Length: ".length($_->[1])."\r\nuWSGI-Offset: ".$_->[0]."\r\n\r\n".$_->[1];
my $s = IO::Socket::INET->new(PeerAddr => $ARGV[0]);
$s->send($req);
my $response = '';
while(1) {
$s->recv(my $buf, 4096);
last unless length($buf);
$response .= $buf;
}
$s->close;
my $expected = "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n\r\n".$_->[2]."\n";
if ($response ne $expected) {
print "TEST FOR offset(".$_->[0].") body(".$_->[1].") FAILED:\nEXPECTED\n---\n".$expected."\n---\nGOT\n---\n".$response."\n---\n";
exit;
}
}
print "test result: SUCCESS\n";
+1 -1
View File
@@ -2,7 +2,7 @@ Gem::Specification.new do |s|
s.name = 'uwsgi'
s.license = 'GPL-2'
s.version = `python -c "import uwsgiconfig as uc; print uc.uwsgi_version"`.sub(/-dev-.*/,'')
s.date = '2013-12-11'
s.date = '2014-02-26'
s.summary = "uWSGI"
s.description = "The uWSGI server for Ruby/Rack"
s.authors = ["Unbit"]
+52 -4
View File
@@ -602,6 +602,8 @@ struct uwsgi_daemon {
char *legion;
#endif
int ns_pid;
int throttle;
};
struct uwsgi_logger {
@@ -696,12 +698,15 @@ struct uwsgi_legion {
struct uwsgi_string_list *join_hooks;
struct uwsgi_string_list *node_joined_hooks;
struct uwsgi_string_list *node_left_hooks;
time_t suspended_til;
struct uwsgi_legion *next;
};
struct uwsgi_legion_action {
char *name;
int (*func) (struct uwsgi_legion *, char *);
char *log_msg;
struct uwsgi_legion_action *next;
};
#endif
@@ -1656,6 +1661,15 @@ struct uwsgi_harakiri_options {
int mules;
};
struct uwsgi_fsmon {
char *path;
int fd;
int id;
void *data;
void (*func)(struct uwsgi_fsmon *);
struct uwsgi_fsmon *next;
};
struct uwsgi_server {
// store the machine hostname
@@ -2037,6 +2051,8 @@ struct uwsgi_server {
struct uwsgi_hook *hooks;
struct uwsgi_string_list *hook_touch;
struct uwsgi_string_list *hook_asap;
struct uwsgi_string_list *hook_pre_jail;
struct uwsgi_string_list *hook_post_jail;
@@ -2051,6 +2067,9 @@ struct uwsgi_server {
struct uwsgi_string_list *hook_accepting_once;
struct uwsgi_string_list *hook_accepting1_once;
struct uwsgi_string_list *hook_emperor_start;
struct uwsgi_string_list *hook_master_start;
struct uwsgi_string_list *hook_emperor_stop;
struct uwsgi_string_list *hook_emperor_reload;
struct uwsgi_string_list *hook_emperor_lost;
@@ -2058,6 +2077,7 @@ struct uwsgi_server {
struct uwsgi_string_list *hook_as_vassal;
struct uwsgi_string_list *hook_as_emperor;
struct uwsgi_string_list *hook_as_mule;
struct uwsgi_string_list *hook_as_gateway;
struct uwsgi_string_list *exec_asap;
@@ -2147,6 +2167,7 @@ struct uwsgi_server {
struct uwsgi_alarm_fd *alarm_fds;
struct uwsgi_string_list *alarm_fd_list;
struct uwsgi_string_list *alarm_segfault;
struct uwsgi_string_list *alarm_backlog;
struct uwsgi_alarm *alarms;
struct uwsgi_alarm_instance *alarm_instances;
struct uwsgi_alarm_log *alarm_logs;
@@ -2166,6 +2187,7 @@ struct uwsgi_server {
char *subscriptions_sign_check_dir;
int subscriptions_sign_check_tolerance;
const EVP_MD *subscriptions_sign_check_md;
struct uwsgi_string_list *subscriptions_sign_skip_uid;
#endif
struct uwsgi_string_list *subscriptions_credentials_check_dir;
@@ -2279,6 +2301,8 @@ struct uwsgi_server {
struct uwsgi_string_list *fs_brutal_reload;
struct uwsgi_string_list *fs_signal;
struct uwsgi_fsmon *fsmon;
struct uwsgi_string_list *signal_timers;
struct uwsgi_string_list *rb_signal_timers;
@@ -2308,6 +2332,7 @@ struct uwsgi_server {
int spooler_max_tasks;
int spooler_ordered;
int spooler_quiet;
int spooler_frequency;
int snmp;
char *snmp_addr;
@@ -2512,6 +2537,8 @@ struct uwsgi_server {
void (*gbcw_hook) (void);
int close_on_exec;
int close_on_exec2;
int tcp_nodelay;
char *loop;
@@ -2603,6 +2630,7 @@ struct uwsgi_server {
char *ssl_sessions_use_cache;
int ssl_sessions_timeout;
struct uwsgi_cache *ssl_sessions_cache;
char *ssl_tmp_dir;
#ifdef UWSGI_PCRE
struct uwsgi_regexp_list *sni_regexp;
#endif
@@ -2620,6 +2648,7 @@ struct uwsgi_server {
int legion_skew_tolerance;
uint16_t legion_scroll_max_size;
uint64_t legion_scroll_list_max_size;
int legion_death_on_lord_error;
#endif
#ifdef __linux__
@@ -2658,6 +2687,14 @@ struct uwsgi_server {
struct uwsgi_string_list *schemes;
// inject text files (useful for advanced templating)
struct uwsgi_string_list *inject_before;
struct uwsgi_string_list *inject_after;
// this is a unix socket receiving external notifications (like subscription replies)
char *notify_socket;
int notify_socket_fd;
char *subscription_notify_socket;
};
struct uwsgi_rpc {
@@ -2953,7 +2990,7 @@ void snmp_init(void);
void uwsgi_master_manage_snmp(int);
int spool_request(struct uwsgi_spooler *uspool, char *, int, int, char *, int, char *, time_t, char *, size_t);
char *uwsgi_spool_request(struct wsgi_request *, char *, size_t, char *, size_t);
void spooler(struct uwsgi_spooler *);
pid_t spooler_start(struct uwsgi_spooler *);
@@ -3238,6 +3275,9 @@ struct uwsgi_subscribe_req {
pid_t pid;
uid_t uid;
gid_t gid;
char *notify;
uint16_t notify_len;
};
void uwsgi_nuclear_blast();
@@ -3501,6 +3541,8 @@ struct uwsgi_subscribe_node {
uid_t uid;
gid_t gid;
char notify[102];
struct uwsgi_subscribe_slot *slot;
struct uwsgi_subscribe_node *next;
@@ -3552,6 +3594,7 @@ int uwsgi_read_response(int, struct uwsgi_header *, int, char **);
char *uwsgi_simple_file_read(char *);
void uwsgi_send_subscription(char *, char *, size_t, uint8_t, uint8_t, uint8_t, char *, char *, char *, char *, char *);
void uwsgi_send_subscription_from_fd(int, char *, char *, size_t, uint8_t, uint8_t, uint8_t, char *, char *, char *, char *, char *);
void uwsgi_subscribe(char *, uint8_t);
void uwsgi_subscribe2(char *, uint8_t);
@@ -3591,7 +3634,7 @@ void *uwsgi_calloc_shared(size_t);
struct uwsgi_spooler *uwsgi_new_spooler(char *);
struct uwsgi_spooler *uwsgi_get_spooler_by_name(char *);
struct uwsgi_spooler *uwsgi_get_spooler_by_name(char *, size_t);
int uwsgi_zerg_attach(char *);
@@ -3646,6 +3689,7 @@ void uwsgi_opt_add_unique_legion_cron(char *, char *, void *);
void uwsgi_opt_sni(char *, char *, void *);
struct uwsgi_string_list *uwsgi_ssl_add_sni_item(char *, char *, char *, char *, char *);
void uwsgi_ssl_del_sni_item(char *, uint16_t);
char *uwsgi_write_pem_to_file(char *, char *, size_t, char *);
#endif
void uwsgi_opt_flock(char *, char *, void *);
void uwsgi_opt_flock_wait(char *, char *, void *);
@@ -3699,6 +3743,7 @@ void uwsgi_opt_logic(char *, char *, void *);
int uwsgi_logic_opt_for(char *, char *);
int uwsgi_logic_opt_for_glob(char *, char *);
int uwsgi_logic_opt_for_times(char *, char *);
int uwsgi_logic_opt_for_readline(char *, char *);
int uwsgi_logic_opt_if_env(char *, char *);
int uwsgi_logic_opt_if_not_env(char *, char *);
int uwsgi_logic_opt_if_opt(char *, char *);
@@ -4219,7 +4264,7 @@ void uwsgi_start_legions(void);
int uwsgi_legion_announce(struct uwsgi_legion *);
struct uwsgi_legion *uwsgi_legion_get_by_name(char *);
struct uwsgi_legion_action *uwsgi_legion_action_get(char *);
void uwsgi_legion_action_register(char *, int (*)(struct uwsgi_legion *, char *));
struct uwsgi_legion_action *uwsgi_legion_action_register(char *, int (*)(struct uwsgi_legion *, char *));
int uwsgi_legion_action_call(char *, struct uwsgi_legion *, struct uwsgi_string_list *);
void uwsgi_legion_atexit(void);
#endif
@@ -4467,7 +4512,7 @@ int uwsgi_init(int, char **, char **);
#endif
int uwsgi_master_check_cron_death(int);
int uwsgi_register_fsmon(struct uwsgi_string_list *);
struct uwsgi_fsmon *uwsgi_register_fsmon(char *, void (*)(struct uwsgi_fsmon *), void *data);
int uwsgi_fsmon_event(int);
void uwsgi_fsmon_setup();
@@ -4694,6 +4739,9 @@ int uwsgi_socket_passcred(int);
void uwsgi_dump_worker(int, char *);
mode_t uwsgi_mode_t(char *, int *);
int uwsgi_notify_socket_manage(int);
int uwsgi_notify_msg(char *, char *, size_t);
#ifdef __cplusplus
}
#endif
+47 -16
View File
@@ -1,6 +1,6 @@
# uWSGI build system
uwsgi_version = '2.0-rc1'
uwsgi_version = '2.0.2'
import os
import re
@@ -244,7 +244,10 @@ def build_uwsgi(uc, print_only=False, gcll=None):
ep = uc.get('embedded_plugins').split(',')
epc = "-DUWSGI_DECLARE_EMBEDDED_PLUGINS=\""
eplc = "-DUWSGI_LOAD_EMBEDDED_PLUGINS=\""
for p in ep:
for item in ep:
# allow name=path syntax
kv = item.split('=')
p = kv[0]
if p is None or p == 'None':
continue
p = p.strip()
@@ -358,15 +361,25 @@ def build_uwsgi(uc, print_only=False, gcll=None):
if len(ep) > 0:
push_print("*** uWSGI compiling embedded plugins ***")
for p in ep:
for item in ep:
# allows name=path syntax
kv = item.split('=')
if len(kv) > 1:
p = kv[1]
p = p.strip()
path = os.path.abspath(p)
else:
p = kv[0]
p = p.strip()
path = 'plugins/%s' % p
if p is None or p == 'None':
continue
p = p.strip()
if p == 'ugreen':
if uwsgi_os == 'OpenBSD' or uwsgi_cpu[0:3] == 'arm' or uwsgi_os == 'Haiku' or uwsgi_os.startswith('CYGWIN') or (uwsgi_os == 'Darwin' and uwsgi_os_k.startswith('8')):
continue
path = 'plugins/%s' % p
path = path.rstrip('/')
if not os.path.isdir(path):
@@ -493,9 +506,9 @@ def build_uwsgi(uc, print_only=False, gcll=None):
bin_name = os.environ.get('UWSGI_BIN_NAME', uc.get('bin_name'))
if uc.embed_config:
gcc_list.append(uc.embed_config)
gcc_list.append("%s.o" % binarize(uc.embed_config))
for ef in binary_list:
gcc_list.append("build/%s" % ef)
gcc_list.append("%s.o" % ef)
additional_sources = os.environ.get('UWSGI_ADDITIONAL_SOURCES')
if not additional_sources:
@@ -734,7 +747,7 @@ class uConf(object):
if 'UWSGI_PROFILE_OVERRIDE' in os.environ:
for item in os.environ['UWSGI_PROFILE_OVERRIDE'].split(';'):
k,v = item.split('=', 2)
uc.set(k, v)
self.set(k, v)
if 'UWSGI_AS_LIB' in os.environ:
self.set('as_shared_library', 'true')
@@ -1041,13 +1054,16 @@ class uConf(object):
if not self.embed_config:
self.embed_config = self.get('embed_config')
if self.embed_config:
binary_link_cmd = "ld -r -b binary -o %s.o %s" % (self.embed_config, self.embed_config)
binary_link_cmd = "ld -r -b binary -o %s.o %s" % (binarize(self.embed_config), self.embed_config)
print(binary_link_cmd)
os.system(binary_link_cmd)
self.cflags.append("-DUWSGI_EMBED_CONFIG=_binary_%s_start" % self.embed_config.replace('.','_'))
self.cflags.append("-DUWSGI_EMBED_CONFIG_END=_binary_%s_end" % self.embed_config.replace('.','_'))
if self.get('embed_files'):
for ef in self.get('embed_files').split(','):
self.cflags.append("-DUWSGI_EMBED_CONFIG=_binary_%s_start" % binarize(self.embed_config))
self.cflags.append("-DUWSGI_EMBED_CONFIG_END=_binary_%s_end" % binarize(self.embed_config))
embed_files = os.environ.get('UWSGI_EMBED_FILES')
if not embed_files:
embed_files = self.get('embed_files')
if embed_files:
for ef in embed_files.split(','):
ef_parts = ef.split('=')
symbase = None
if len(ef_parts) > 1:
@@ -1057,7 +1073,7 @@ class uConf(object):
for directory, directories, files in os.walk(ef):
for f in files:
fname = "%s/%s" % (directory, f)
binary_link_cmd = "ld -r -b binary -o build/%s.o %s" % (binarize(fname), fname)
binary_link_cmd = "ld -r -b binary -o %s.o %s" % (binarize(fname), fname)
print(binary_link_cmd)
os.system(binary_link_cmd)
if symbase:
@@ -1067,7 +1083,7 @@ class uConf(object):
os.system(objcopy_cmd)
binary_list.append(binarize(fname))
else:
binary_link_cmd = "ld -r -b binary -o build/%s.o %s" % (binarize(ef), ef)
binary_link_cmd = "ld -r -b binary -o %s.o %s" % (binarize(ef), ef)
print(binary_link_cmd)
os.system(binary_link_cmd)
binary_list.append(binarize(ef))
@@ -1117,7 +1133,7 @@ class uConf(object):
report['yaml'] = 'libyaml'
if self.get('json'):
if self.get('json') == 'auto':
if self.get('json') in ('auto', 'true'):
jsonconf = spcall("pkg-config --cflags jansson")
if jsonconf:
self.cflags.append(jsonconf)
@@ -1139,6 +1155,9 @@ class uConf(object):
self.libs.append(spcall("pkg-config --libs yajl"))
self.cflags.append("-DUWSGI_JSON_YAJL")
report['json'] = 'yajl'
elif self.get('json') == 'true':
print("*** jansson and yajl headers unavailable. uWSGI build is interrupted. You have to install jansson or yajl development headers or disable JSON")
sys.exit(1)
elif self.get('json') == 'jansson':
jsonconf = spcall("pkg-config --cflags jansson")
if jsonconf:
@@ -1164,6 +1183,18 @@ class uConf(object):
self.libs.append(spcall("pkg-config --libs yajl"))
self.cflags.append("-DUWSGI_JSON_YAJL")
report['json'] = 'yajl'
elif self.has_include('yajl/yajl_tree.h'):
self.cflags.append("-DUWSGI_JSON")
self.gcc_list.append('core/json')
self.libs.append('-lyajl')
self.cflags.append("-DUWSGI_JSON_YAJL")
report['json'] = 'yajl'
elif self.has_include('yajl/yajl_parse.h'):
self.cflags.append("-DUWSGI_JSON")
self.gcc_list.append('core/json')
self.libs.append('-lyajl')
self.cflags.append("-DUWSGI_JSON_YAJL_OLD")
report['json'] = 'yajl_old'
else:
print("*** yajl headers unavailable. uWSGI build is interrupted. You have to install yajl development package or use jansson or disable JSON")
sys.exit(1)