Compare commits

...
713 Commits
Author SHA1 Message Date
Unbit 37bc47cb82 uWSGI 2.0.11.1 2015-07-19 08:17:07 +02:00
Unbit 35701f6ac6 fixed #963 2015-07-19 08:11:06 +02:00
Roberto De Ioris fb23d4a8ae Merge branch 'uwsgi-2.0' of https://github.com/unbit/uwsgi into uwsgi-2.0 2015-07-13 13:25:23 +02:00
Unbit 30c667d34f added unix signal registration hook 2015-07-06 16:11:53 +02:00
Unbit d09fd561b6 uWSGI 2.0.11 2015-07-01 08:53:41 +02:00
Roberto De Ioris ff05c16577 Merge branch 'uwsgi-2.0' of https://github.com/unbit/uwsgi into uwsgi-2.0 2015-07-01 08:51:04 +02:00
Unbit eefaa98cf3 backported pypy fixes from 2.1 2015-07-01 08:37:40 +02:00
Fabrizio Gennari 9c4d563c72 Check whether *value is indeed an SvRV before casting it 2015-07-01 06:12:54 +02:00
James Oakley ceda8a41e3 Fix version detection for gcc 5 2015-06-30 08:05:41 +02:00
Unbit 3021ba3f85 ensure the mem_collector does not receive signals 2015-06-16 18:30:19 +02:00
Roberto De Ioris 3be7312aa8 added fixpathinfo routing action 2015-06-07 19:37:48 +02:00
Roberto De Ioris 83d782051c fixed shared sockets for gateways 2015-06-03 07:23:16 +02:00
protoCall7 70996049cc Changed abs to labs because offset is declared as a long 2015-06-02 09:03:30 +02:00
Jay Oster e219e209a0 Add null terminator to uwsgi_get_dot_h() and uwsgi_config_py()
- Fixes #933
2015-06-02 09:00:01 +02:00
Unbit eb728cfe23 added sor and micros routing vars 2015-05-28 12:24:03 +02:00
unbit 7569544329 Merge pull request #929 from hulu/wait-init-thread-last
Wait for initial thread last.
2015-05-23 05:19:56 +02:00
Roberto De Ioris ee86bf593d fixed #649 2015-05-23 05:16:24 +02:00
Roberto De Ioris 27ea120325 added memory collector 2015-05-17 05:50:35 +02:00
Unbit dd21877dcb attempt to fix a bug spotted by funkybob on irc 2015-05-15 06:41:31 +02:00
Roberto De Ioris 36ca76a231 backported coverity fixes by riccardo #908 2015-05-14 06:28:52 +02:00
Unbit 0e339cf968 added bigranges sharedarea tests 2015-05-13 15:45:26 +02:00
Unbit 762200fdd6 fixed #922 2015-05-13 15:09:18 +02:00
Roberto De Ioris 688a464451 fixed #914 2015-05-12 06:28:06 +02:00
Roberto De Ioris 0dafe8aa5e backported gzip fix 2015-05-08 06:59:52 +02:00
Roberto De Ioris 5410cb4fe7 backported ssl ca management fix 2015-05-06 07:25:18 +02:00
Charlie Root 86f55a69cf fixed OpenBSD build on 2.0 2015-05-02 13:00:31 +02:00
Roberto De Ioris 6bd59ffe1c backported #848 2015-05-01 13:35:25 +02:00
Roberto De Ioris 95a139f73d backported wait-for-socket and wait_for hooks 2015-05-01 13:32:50 +02:00
Roberto De Ioris 2e71d62704 added Curtis Maloney to CONTRIBUTORS 2015-04-13 06:53:35 +02:00
Roberto De Ioris 8942e832e9 backported build fix from 2.1 2015-04-13 06:53:19 +02:00
Unbit 14b0a512e4 fixed #883 2015-04-10 15:53:42 +02:00
Unbit 0c062bbc1a fixed typo 2015-03-25 09:41:07 +01:00
Roberto De Ioris c63d94cb6e uWSGI 2.0.10 2015-03-17 08:34:34 +01:00
Unbit 4da7564c3b added support for UNIX sockets to rsyslog 2015-03-16 20:29:34 +01:00
Riccardo Magliocchetti d38edd839e Don't lower security standards with gcc 4.9
For some reason since e4d65c07ce
we started compiling -Wno-format, possibly because of plugins
dependencies not compiling.
Fedora (and Debian to some degrees) are starting to default to
-Wformat -Werror=format-security which is something sensible for
uwsgi. So let the distro handle the situation when a very recent
gcc version is encountered since they probably know better.
2015-03-11 14:04:04 +01:00
Ivan Kruglov cce041c7f0 psgi_loader: make sure that at least two params are passed to XS_input_seek() 2015-03-09 11:36:06 +01:00
Ivan Kruglov ca68d6938a psgi_loader: fix a one off bug in XS_input_seek() 2015-03-09 11:35:42 +01:00
Unbit 6d700e5a8b fixed #846 2015-02-19 06:53:21 +01:00
Unbit bad07a8520 attempt to fix #833 2015-02-11 11:32:33 +01:00
Roberto De Ioris 363b88a7b7 fixed emperor wrapper 2015-02-10 20:35:55 +01:00
Roberto De Ioris 932ed8ee29 fixed emperor wrappers logs 2015-02-10 20:31:04 +01:00
Roberto De Ioris 7b8e12911a backported --emperor-wrapper-fallback and --emperor-wraper-override 2015-02-10 20:27:02 +01:00
Roberto De Ioris c95062856b added safeexec hook 2015-02-10 20:10:19 +01:00
Unbit 6840b287d4 fixed scandir usage 2015-02-08 17:31:50 +01:00
Unbit ae9104ed91 fix return value for hv_store in uwsgi::opt 2015-02-08 17:30:29 +01:00
Roberto De Ioris 6c8d6ea15b typo 2015-01-28 07:09:48 +01:00
Roberto De Ioris 755eb3956d fixed exception handler for arguments 2015-01-28 06:50:14 +01:00
Roberto De Ioris 225dc6f7a3 fixed #806 2015-01-18 20:49:44 +01:00
Unbit 8509c41fd6 it's 2015 2015-01-05 20:29:02 +01:00
Unbit 2ae9ac8b88 another range header improvement 2015-01-05 13:53:13 +01:00
Unbit fed00ee5d6 fixed range 2015-01-04 15:02:54 +01:00
Unbit 66099275ca updated gemspec file 2014-12-29 10:07:07 +01:00
Unbit e7a40eb173 completed backporting of fastrouter post buffering 2014-12-27 13:30:16 +01:00
Riccardo Magliocchetti 8342150b78 Fix fastrouter compilation
After 6a8f18a9bb

Fix #801
2014-12-27 13:28:41 +01:00
Roberto De Ioris e2253f3693 backport of fastrouter buffering 2014-12-27 13:28:08 +01:00
Roberto De Ioris d2f07c7583 implemented uwsgi::opt in perl 2014-12-12 07:01:28 +01:00
Roberto De Ioris 1c87053a13 implemented --pull-header 2014-12-11 15:54:21 +01:00
Unbit d69e23414f another check for mod_proxy_uwsgi 2014-12-10 10:45:06 +01:00
Roberto De Ioris 3d37d272ee fixed master-fifo + cheaper 2014-12-09 09:53:45 +01:00
Riccardo Magliocchetti 9094a0f811 Fix leak on error in bind_to_unix
Spotted by cppcheck.
2014-12-09 09:44:36 +01:00
Unbit 97efcca2b7 improved mono plugin 2014-12-04 20:55:58 +01:00
Roberto De Ioris 2445fd1f61 fixed #776 2014-12-06 10:39:27 +01:00
Unbit 3234e0aae8 fixed #680 2014-12-06 09:14:17 +01:00
Unbit c5e7eb5d95 fix #785 2014-12-05 15:22:53 +01:00
Unbit e051e4fe1c another attempt at fixing mod_proxy_uwsgi 2014-12-05 15:08:47 +01:00
Unbit 5f691ec987 attempt to fix #774 2014-12-05 09:23:55 +01:00
Unbit a8e0aac9b0 fixed #787 2014-12-05 09:11:11 +01:00
Unbit bcdbab247c fix peer name in corerouters [2] 2014-11-22 13:22:21 +01:00
Roberto De Ioris 2e378dfc29 Merge branch 'uwsgi-2.0' of github.com:unbit/uwsgi into uwsgi-2.0 2014-11-22 13:19:28 +01:00
Roberto De Ioris acc270ad81 try to fix peer name in corerouter 2014-11-22 13:12:11 +01:00
Unbit b0c3ee02f9 detect modern pypy 2014-11-21 08:35:41 +01:00
Unbit 06ab5eaee5 fix #778 2014-11-21 08:34:44 +01:00
Roberto De Ioris 46de2ae0cb attempt to fix #340 2014-11-21 06:47:04 +01:00
Unbit 65fe93ac14 fixed hr_ssl_clear_errors 2014-11-20 07:35:18 +01:00
Roberto De Ioris f7cdd22f9a attempt to fix error propagation in https 2014-11-20 07:25:19 +01:00
Andjelko Horvat 3d553d2ae0 Daemon touch kill failback. 2014-11-19 10:45:59 +01:00
Unbit 582d5828aa another round of ssl fixes 2014-11-18 19:15:29 +01:00
Unbit 245a66b0e5 try to improve ssl management 2014-11-18 18:57:59 +01:00
Roberto De Ioris 596c81124e fixed destruction 2014-11-16 20:59:45 +01:00
Unbit a86a1fcc40 added active-workers signal target, aimed at improving #58 2014-11-16 18:47:33 +01:00
Unbit 34036ac8b4 Merge branch 'uwsgi-2.0' of https://github.com/unbit/uwsgi into uwsgi-2.0 2014-11-15 13:17:56 +01:00
Unbit 11cd6c34a5 fixed python3 --py-auto-reload-ignore 2014-11-15 13:17:52 +01:00
Unbit aaea6ff2e2 fixed modifiers usage in corerouters 2014-11-15 06:32:25 +01:00
Unbit 38c30bc257 bump version to 2.0.9 2014-11-15 05:26:20 +01:00
Unbit 2f3e83b78e added httpdumb router and subscribe-with-modifier 2014-11-14 15:41:42 +01:00
Roberto De Ioris 43e8c65841 support yajl brew 2014-11-14 06:03:08 +01:00
Unbit 555902a0ee less strict http generator 2014-11-13 11:56:44 +01:00
Unbit 9d4f4eb3c3 backported #772 2014-11-12 07:43:34 +01:00
Ævar Arnfjörð Bjarmason 5d338cfb3a psgi: Ensure that we call any DESTROY hooks on psgix.harakiri.commit
Before this we'd just exit(0) and let the OS clean up after us, but
e.g. with post-buffering=1 we'll end up with a temporary file in /tmp
that we won't clean up when we exit unless DESTROY is called.

This resulted in us leaking files in /tmp if we ever had a request where
the last request before a harakiri was a POST request with a body we'd
buffer to /tmp.

We'd have similar leaks in any user-defined code that required DESTROY
to run.

Aside from this I'm still not very comfortable with what this whole code
here in psgi_plugin.c and psgi_loader.c is doing when managing the
interpreter(s). It:

 * Doesn't consistently call PERL_SET_CONTEXT() as described in "perldoc
   perlembed".

 * Nothing calls PERL_SYS_TERM() either.

 * Should we be calling uwsgi_perl_free_stashes() here too?

To test this:

    UWSGI_PROFILE=psgi python uwsgiconfig.py --build
    ./uwsgi --master --http-socket localhost:1234 --psgi t/perl/test_harakiri.psgi

Then elsewhere:

    curl 'localhost:1234?0'
    curl 'localhost:1234?1'

Both of those should emit "Calling DESTROY".
2014-11-12 07:38:18 +01:00
Riccardo Magliocchetti 3406441d95 systemdlogger: fix compilation with -Werror=format-security 2014-11-06 18:53:30 +01:00
Unbit df08c7bfb5 fixed unmasked websocket 2014-11-06 09:02:21 +01:00
Unbit 75b4a3cb28 clear if sweep_on_full fails 2014-11-05 13:06:24 +01:00
Unbit c356c01f12 Merge branch 'uwsgi-2.0' of https://github.com/unbit/uwsgi into uwsgi-2.0 2014-11-02 10:51:50 +01:00
Unbit ba8aa44baa attempt to fix #766 2014-11-02 10:51:39 +01:00
Roberto De Ioris a1dc7a660c use uwsgi_buffer for send_ack in #760 2014-11-02 09:33:07 +01:00
Roberto De Ioris 3a4663844b fixed #760 2014-11-02 06:42:53 +01:00
Mattia Barbon 309f449a43 Fix latent refcounting bug
It can be reproduced by enabling the Perl debugger inside a PSGI application:

    {
        package DB;

        sub DB { }
        sub sub { &$sub }
    }

    $^P = 0x73f;

    sub { [200, ['Content-Type' => 'text/plain'], ['Hello World']] }

For every request the following warnings are emitted:

    Attempt to free unreferenced scalar: SV 0xfea6e8, Perl interpreter: 0xd534a0.
    Attempt to free unreferenced scalar: SV 0xfea718, Perl interpreter: 0xd534a0.

where the unreferenced scalars are the uwsgi::input/uwsgi::error instances
created in build_psgi_env.

The calling convention for Perl subroutines is that the values pushed on the
stack must be mortalized in the callee, and if the caller wants to retain them,
it must do a SvREFCNT_inc to undo the effect of the mortalization.

Before this patch XS_input/XS_error were not mortalizing the value, and
uwsgi_perl_obj_new was not incrementing the reference count, so the two bugs
balanced each other.

When running under debugger, Perl forwards all function/method calls to
DB::sub, which causes a mortal copy of the return value of
uwsgi::input/error::new to be pushed on the stack. The value is cleared by the
FREETMPS at the end of uwsgi_perl_obj_new, and the freed value is added to the
environment hash. The warning is emitted at the end of the request when the
environment hash is freed and Perl notices that some of the values has been
already freed.
2014-11-02 06:13:20 +01:00
Mattia Barbon f059a69312 Remove unnecessary mortalization
newRV(sv_newmortal()) is equivalent to newRV_noinc(newSV(0)): the former
creates a new SV with refcount 1, schedules a decrement "soon" (the
mortalization) and increments the refcount, the net result is a refcount of 1,
which is what the latter does.
2014-11-02 06:13:04 +01:00
Unbit 93116a1239 prepare for 2.0.8 2014-10-26 05:30:44 +01:00
unbit 5e4440443a Merge pull request #755 from aldur/manage_script_name_fix
manage_script_name fix for tricky resources
2014-10-24 17:19:50 +02:00
Unbit 373481b888 backported rtsp support 2014-10-24 17:12:52 +02:00
Unbit 105b9c69cf backported --hook-post-fork 2014-10-24 12:07:05 +02:00
Unbit 9012ead72c backported https fix for ssl shutdown 2014-10-24 11:49:18 +02:00
Roberto De Ioris 6c1d2625a8 backported support for chunked input management in the http/https router 2014-10-19 12:54:12 +02:00
Unbit c0733b5771 Merge remote-tracking branch 'origin/uwsgi-2.0-cache-lazy-expire' into uwsgi-2.0 2014-10-18 04:23:39 +02:00
Unbit f4759d7acd fixed php SCRIPT_NAME usage when --php-app is in place 2014-10-18 04:19:41 +02:00
Unbit 7082188a06 allow appendn hook without second argument 2014-10-17 13:15:30 +02:00
Unbit bcd9ed011d try to load trollius on python2 2014-10-17 13:04:46 +02:00
Nigel Heron 25c6d7a3a1 fix heap corruption in carbon plugin 2014-10-17 05:18:58 +02:00
Roberto De Ioris 675c02c7fa fixed #749 2014-10-16 20:53:47 +02:00
Roberto De Ioris 32896a1418 fixed #748 2014-10-16 08:26:13 +02:00
Unbit 548e736d84 fixed #746 2014-10-15 10:06:27 +02:00
Unbit 87575b1a22 disable SSLv3 by default and allow setting raw ssl options 2014-10-15 09:11:18 +02:00
Roberto De Ioris 1aa6eeca1b added sweep_on_full, clear_on_full and no_expire 2014-10-14 05:24:28 +02:00
Unbit f778e30d48 run the sweeper only if required 2014-10-13 13:00:07 +02:00
Unbit e071184d53 ignore lazy caches from the sweeper 2014-10-13 12:55:26 +02:00
Unbit 1d09cde778 implemented cache lazy expire 2014-10-13 12:40:40 +02:00
Greg Dahlman 70ee29becb added wait for fs and wait for mountpoint 2014-10-10 11:06:44 +02:00
Unbit 60e26333bf allows building external plugins as embedded 2014-10-10 11:00:28 +02:00
Unbit 865b9c199d improved offload api 2014-10-10 10:58:45 +02:00
Unbit 833193a1ba added UWSGI_HAS_OFFLOAD_UBUFS 2014-10-10 10:58:41 +02:00
Unbit 4eab050634 added 8 uwsgi_buffer and 8 custom fields to offload request 2014-10-10 10:57:03 +02:00
Aldur 688d1d3b75 fixed python3 support in spooler decorators 2014-10-10 10:55:18 +02:00
Unbit 349daee614 fixed uwsgidecorators spooler arguments 2014-10-10 10:49:18 +02:00
Unbit 0d272cf747 added Adriano Di Luzio to 2.0 CONTRIBUTORS 2014-10-10 10:47:19 +02:00
Unbit 46ac28efae fixed tcsetattr 2014-10-10 10:45:58 +02:00
Unbit 31b3bcc83d fixed kevent 2014-10-10 10:45:06 +02:00
Unbit f364d676fa automatically manage HTTP_X_FORWARDED_PROTO 2014-10-10 10:40:13 +02:00
Unbit c72fde1eed ensure PSGI response headers are in the right format [2] 2014-10-03 08:32:03 +02:00
Unbit a5cacfbba6 ensure PSGI response headers are in the right format 2014-10-03 08:31:52 +02:00
Unbit 921cfa5d79 backported daemons and proto http fixes from 2.1 2014-10-03 08:30:11 +02:00
Roberto De Ioris 9c676c62f5 destroy the whole instance on Emperor error 2014-10-03 08:26:57 +02:00
Roberto De Ioris 2917de3e76 exit on Emperor error 2014-10-03 08:26:43 +02:00
Unbit e836272c07 attempt to fix #732 2014-10-03 08:26:21 +02:00
Roberto De Ioris 7e25452242 set version to 2.0.7.1 2014-09-12 06:37:06 +02:00
unbit 42d42d9e4c Merge pull request #714 from xiaost/add-spooler_pids-api
python: add `spooler_pids` api for multi-spooler
2014-09-11 18:31:33 +02:00
xiaost 73c3e971e6 python: add spooler_pids api for multi-spooler
the old `spooler_pid` api only returns the first spooler pid
2014-09-11 23:34:13 +08:00
rdeioris b627edf1b8 Merge pull request #697 from xrmx/ignoreup
Update gitignore
2014-09-11 11:34:34 +02:00
Unbit 7fbc46750b attempt to fix #713 2014-09-11 08:22:19 +02:00
Unbit 1a63634359 report chdir() 2014-09-10 07:44:37 +02:00
Unbit c30e99a0df attempt to fix #611 2014-09-09 07:49:52 +02:00
Roberto De Ioris 3c53f26cbd ready for 2.0.7 2014-09-05 06:48:15 +02:00
Unbit a5c74293d8 fixed #702 2014-08-31 19:58:40 +01:00
Roberto De Ioris e5da0fc28c fix for #703, waiting for confirmation 2014-08-30 08:34:46 +02:00
Unbit 8e9bcc4758 implemented two new triggers for broodlord mode 2014-08-29 06:51:31 +02:00
Unbit bcf1f46d33 added vassal's plugin hooks 2014-08-28 18:09:02 +02:00
Unbit 8cd13f2ad9 fixed sendfile on smartos/omnios 2014-08-26 12:43:40 +02:00
Unbit 13df278cc4 attempt to fix emperor messaging on smartos/omnios 2014-08-26 12:27:36 +02:00
Unbit 56fedbd80c fixed stats vacuum 2014-08-26 09:45:00 +02:00
Unbit c4b563f260 fixed #644 2014-08-26 07:41:11 +02:00
Unbit 39706c5899 fixed #693 2014-08-26 07:25:37 +02:00
Unbit e45f710694 fix multiple python mountpoints with multiple threads in cow mode 2014-08-26 07:10:27 +02:00
unbit 0c86212aa2 Merge pull request #699 from nextsux/patch-1
Update rados.c
2014-08-24 20:28:27 +02:00
Martin Mlynář 3cfa743cb5 Update rados.c
According to http://ceph.com/docs/master/rados/api/librados/ rados_write Returns: 0 on success, negative error code on failure. When using <= comparsion, PUT method always ends with ISE 500.
2014-08-24 20:10:28 +02:00
Riccardo Magliocchetti f14cb7e02a Update gitignore
Failed patch(1) rej files, gccgo, mono and go plugins compiled
files, coverity work dir and tarball.
2014-08-20 15:55:24 +02:00
unbit 7fbc4013ca Merge pull request #679 from xrmx/logger
logfile: add support for filesize based rotation
2014-08-17 12:06:38 +02:00
Riccardo Magliocchetti 0324e5965c logfile: add support for filesize based rotation
Extends the logfile plugin sntax to accept a key value string.
Supported values are:
- logfile, the actual file name of the log file (mandatory)
- backupname, the file name of the rotated log
- maxsize, the size in bytes that triggers rotation

maxsize is mandatory if you want rotation, if you omit backupname the logfile with a
timestamp appended would be used as file name.

Example:

logger = staticlogger file:logfile=%dstatic.log,backupname=%dstatic.log.old,maxsize=1500
log-route = staticlogger app: -1|req: -1

will create a file based logger called static logger that would log
all the static requests to a file called static.log, which would be
rotated each 1500 bytes to a file named static.log.old

Fixes #542
2014-08-17 11:50:34 +02:00
unbit 2050d38f96 Merge pull request #687 from goir/uwsgi_remove_invalid_cache_file
add store_delete option to cache.
2014-08-17 11:49:11 +02:00
Goir fadce6cfe5 add store_delete option to cache. This automatically removes invalid caches files 2014-08-17 10:39:32 +02:00
Roberto De Ioris 0ac4f8f1e4 prepare for 2.0.7 2014-08-16 17:05:26 +02:00
unbit 51e81eff31 Merge pull request #688 from xrmx/coverity1608
Few coverity fixes
2014-08-16 16:58:40 +02:00
Riccardo Magliocchetti 4818a5d386 plugins/rpc: fix a couple of memory leaks
Always free response, in the worst case we are freeing NULL which
is a NOP.
Reported by Coverity as CID #1231246, #1231245
2014-08-16 16:52:59 +02:00
Riccardo Magliocchetti 4457fbefd6 core/rpc: avoid double close
Reported by coverity as CID #1231253
2014-08-16 16:31:32 +02:00
Roberto De Ioris 9780e5fc5e attempt to fix solaris/smartos events with emperor 2014-08-16 16:24:39 +02:00
Roberto De Ioris 9c18e0e12a fixed fastcgi and scgi protocols with out of buffer 2014-08-15 19:05:43 +02:00
unbit c4c146dca4 Merge pull request #685 from Ventero/mono
Fix symbol lookup error in the Mono plugin on OS X.
2014-08-15 06:03:28 +02:00
Ventero 08e1cf211c Fix symbol lookup error in the Mono plugin on OS X.
On OS X, mono libraries have to link against the Foundation framework.
2014-08-14 21:35:39 +02:00
Unbit a52a6fc1e1 fixed #683 2014-08-12 13:11:30 +02:00
Unbit 6e1c468eed fixed #669 2014-08-12 13:10:04 +02:00
Unbit 1c186db72a fix emperor destroy on mount/umount hook errors 2014-08-11 10:16:26 +02:00
Unbit 92a8d6f2c5 fixed uwsgi.rpc 2014-08-08 22:14:03 +02:00
Unbit 144ffbaa25 attempt to ignore user namespace in setns 2014-08-08 13:21:02 +02:00
Roberto De Ioris 3e910aaca2 fixed #666 2014-08-05 20:14:19 +02:00
Riccardo Magliocchetti 5b2a3c28d0 logging: reindent setup_choosen_logger 2014-08-04 16:27:14 +02:00
Riccardo Magliocchetti 01a5611159 logging: extract uwsgi_log_do_rotate from uwsgi_log_rotate
So it can be reused
2014-08-04 16:24:22 +02:00
Riccardo Magliocchetti bf692c4d18 logging: fixup uwsgi_log_rotate indentation
So one can actually read it
2014-08-04 15:39:20 +02:00
Riccardo Magliocchetti a09ee5153d Update Riccardo's entry in CONTRIBUTORS 2014-08-01 15:58:29 +02:00
Unbit bc9f5d6f88 allow calling the spooler from every cpython context 2014-08-01 12:41:55 +02:00
unbit ec25be94ba Merge pull request #675 from rectalogic/memcpy-fix
Use memmove instead of memcpy since src/dest may be overlapping.
2014-07-28 17:07:39 +02:00
Andrew Wason 7e8e113921 Use memmove instead of memcpy since src/dest may be overlapping.
Fixes #671
2014-07-28 09:21:45 -04:00
Unbit 0575859f2d attempt to fix #667 2014-07-24 09:09:15 +02:00
Unbit e9c0bf91ad fixed #668 2014-07-24 08:55:52 +02:00
rdeioris 53fb764830 Merge pull request #664 from akx/remove-compiled-java
Issue #663: Remove compiled uwsgi.class file to keep binaries out of the repo.
2014-07-21 10:13:17 +02:00
Aarni Koskela 76393e36be Remove compiled uwsgi.class file to keep binaries out of the repo. (Addresses issue #663) 2014-07-20 20:41:51 +03:00
Unbit 94a39e1755 fixed typo 2014-07-12 11:37:42 +02:00
Unbit e675b49ef8 added Mathieu Dupuy to CONTRIBUTORS 2014-07-11 08:48:18 +02:00
unbit 78b330dd96 Merge pull request #660 from andrewbevitt/master
Add cache length parameter to the PHP parameter parsing.
2014-07-09 16:34:26 +02:00
Andrew Bevitt 293ee92791 Add cache length parameter to the parameter parsing. 2014-07-10 00:11:19 +10:00
unbit dac7457927 Merge pull request #659 from CashStar/stats_pusher_statsd_counter_fix
send data as a counter, m has no meaning in statsd
2014-07-09 08:25:57 +02:00
Joshua C. Forest e1b3d8fd1a send data as a counter, m has no meaning in statsd 2014-07-08 16:19:30 -04:00
Unbit b1669d1887 2.0.6 is ready 2014-07-01 09:04:40 +02:00
Roberto De Ioris 095bd60f77 added if-hostname 2014-07-01 06:58:14 +02:00
Unbit c3d33c90a0 fixed wrongly nulled filename in rados 2014-06-30 11:57:02 +02:00
Roberto De Ioris 4905b64f2e improved buffer json escaping 2014-06-28 08:13:11 +02:00
Unbit cfe1e9de7b implemented OPTIONS in rados 2014-06-28 07:28:41 +02:00
Unbit 82dcfd338d added mkcol to rados 2014-06-28 07:02:47 +02:00
Unbit c696065d3c added uwsgi[rsize] routing var 2014-06-27 15:18:33 +02:00
Unbit 8746141afa the Rados plugin is no more based on the GlusterFS one 2014-06-27 15:03:53 +02:00
Unbit e2b2a16b8c fixed sync rados behaviour 2014-06-27 15:02:56 +02:00
Unbit 406daeb3ae first attempt in improving rados multithreading 2014-06-27 14:45:25 +02:00
Unbit acbc073c81 improved timeout 2014-06-27 14:37:23 +02:00
Unbit 2ad23e95dd implemented PUT and DELETE methods for rados 2014-06-27 14:23:43 +02:00
Unbit 807259f25b fixed rados async support 2014-06-27 13:44:53 +02:00
unbit 4b06b2391c Merge pull request #657 from johto/fifo_recreation
Remove the old FIFO socket from the event queue when recreating it
2014-06-25 07:34:29 +02:00
Marko Tiikkaja 8c0adef6e7 Remove the old FIFO socket from the event queue when recreating it
The previous code had two problems:
  1) It never removed the old fd from the event loop, which meant that
if the new fd received a different index, the old fd would keeping
waking up the master process repeatedly.
  2) If the new fd got the same index but the master loop went back to
epoll_wait() fast enough, Linux would claim that the socket is ready for
reading, but read() would return 0 again, which would cause the FIFO to
be recreated again, etc.

Fix by removing the old fd from the event queue before recreating it.
2014-06-24 13:49:20 +02:00
Unbit 52ea289283 try to fix SCRIPT_NAME and PATH_TRANSLATED in php plugin 2014-06-23 10:58:05 +02:00
Unbit bfb6e21e2a prepare for 2.0.6 2014-06-19 15:45:31 +02:00
Unbit 84d6f54ddd added fastrouter-fallback-on-no-key 2014-06-19 11:49:25 +02:00
Unbit 775afe1e86 added support for unix socket in apache mod_proxy_uwsgi 2014-06-19 05:52:26 +02:00
Unbit cabb5f3e8e another attempt at fixing mod_proxy_uwsgi for apache2.2/2.4 2014-06-19 04:37:31 +02:00
Unbit aae6413cb1 added callint scheme 2014-06-12 11:26:02 +02:00
Unbit 6666848ac3 another attempt in improving chain reloading 2014-06-11 18:32:26 +02:00
Unbit c6f1911686 fixed #649 2014-06-11 09:18:26 +02:00
Unbit ef4ee87fed fixed shortcut for ssl-socket 2014-06-08 06:36:09 +02:00
Unbit 2a2f1a9928 allow hacking the php sapi name 2014-06-08 06:21:28 +02:00
Unbit f1caa39f51 added chdir to attach-daemon2 2014-06-06 15:05:43 +02:00
Roberto De Ioris 536ffdcc79 fixed a memory leak with subscriptions 2014-06-06 04:20:39 +02:00
Unbit d3313a39b7 fixed #645 2014-06-03 18:37:00 +02:00
Unbit 89da4a97a6 another attempt for #645 2014-06-03 16:52:14 +02:00
Unbit 3e41d5927a attempt to fix #645 2014-06-03 13:16:48 +02:00
Unbit 6a32f5d49d fast fix for 2.0.5.1 2014-06-01 08:06:26 +02:00
Roberto De Ioris bf67984049 fixed #642 2014-06-02 06:53:06 +02:00
Roberto De Ioris 41b6005d30 fixed http-manage-source type 2014-06-01 06:47:31 +02:00
Roberto De Ioris 497f7efa55 prepare for 2.0.5 2014-06-01 06:18:01 +02:00
Roberto De Ioris ad7ca0b098 fixed #641 2014-05-31 07:44:05 +02:00
Roberto De Ioris 1d591c95f2 fixed #633 2014-05-31 06:41:30 +02:00
Roberto De Ioris d3daca0b16 fixed #640 2014-05-29 19:52:49 +02:00
Unbit bae1ade00a added 'resolve' option 2014-05-29 09:50:50 +02:00
Unbit fd663aedbd added setremoteaddr 2014-05-28 15:41:49 +02:00
Unbit 6b9ce2d755 added test for lru cache purge and fix for lru removal 2014-05-27 11:38:57 +02:00
Unbit bd2728b391 retry on mule_get_msg EAGAIN 2014-05-27 09:41:36 +02:00
unbit dc250fd7b5 Merge pull request #636 from prymitive/issue635
fixed log setup when both --logto and --log2, fixes unbit/uwsgi#635
2014-05-24 09:59:21 +02:00
Łukasz Mierzwa 0a9345b8d4 fixed log setup when both --logto and --log2, fixes unbit/uwsgi#635 2014-05-23 18:44:40 +02:00
unbit db509f2d38 Merge pull request #631 from btall/set-min-set-max
Add new functions 'uwsgi_metric_set_min' & 'uwsgi_metric_set_max', wh…
2014-05-22 15:22:29 +02:00
Unbit b12c39607d less invasive privileges drop when chown-socket is in place 2014-05-22 09:00:43 +02:00
Roberto De Ioris 224260ce3e postpone uwsgi_as_root() call 2014-05-22 05:43:45 +02:00
Roberto De Ioris 5f86d9522f hack for avoiding Safari iOS to make mess with keepalive 2014-05-21 21:35:54 +02:00
Unbit a0fafe7847 try to honour chmod/chown socket in fd0 mode 2014-05-21 12:35:01 +02:00
Babacar TALL daeaf1b231 Doesn't use uwsgi_metric_get for the comparison on uwsgi_metric_set_max and uwsgi_metric_set_min (it introduce a deadlock) 2014-05-20 16:46:25 +02:00
Unbit fbc0a2775f when changing metrics we need a write lock 2014-05-20 16:02:54 +02:00
Unbit d3c89a3f63 various metrics fixes for reset_after_push feature 2014-05-20 15:35:33 +02:00
unbit cd43a0d12d Merge pull request #630 from btall/reset-after-push
Implement a new metric option 'reset_after_push' which will make uWSGI.....
2014-05-20 15:31:01 +02:00
Babacar TALL f06df71bfc Use the wlock when the value is reseted 2014-05-20 14:51:14 +02:00
Babacar TALL eab2472dd0 Exposure of 'uwsgi_metric_set_min' & 'uwsgi_metric_set_max' for python interface. 2014-05-20 11:57:53 +02:00
Babacar TALL 87a2f3585c Add new functions 'uwsgi_metric_set_min' & 'uwsgi_metric_set_max', which...
push respectively a absolute value if she is less than or greater than
that the previous push.

Refactore the function uwsgi_metric_set_min
2014-05-20 11:57:42 +02:00
Babacar TALL c257a9aa98 Update all plugins so that they bear this functionality (reset_after_push) 2014-05-19 15:16:29 +02:00
Babacar TALL 43aebe2d66 Implement a new metric option 'reset_after_push' which will make uWSGI...
reset to 0 the given metric after it's been pushed to the stats backend.
This is handy when you want to automatically reset counters every 'freq'
seconds.
2014-05-19 14:36:25 +02:00
Roberto De Ioris 309115d611 allow to enable the proxy protocol management only in the http router 2014-05-17 11:52:58 +02:00
unbit 5881d41b2b Merge pull request #627 from blue-goji/proxy-protocol-for-http-module
Add ELB proxy protocol support to the HTTP module.
2014-05-16 18:31:43 +02:00
Glenn Maynard 9fe4b7b14a Add ELB proxy protocol support to the HTTP module.
Previously, this was only supported with http-socket.  If you're
using http-socket, you probably have a webserver on top of you--and if
you have that, then uWSGI isn't receiving the proxy protocol anyway.
2014-05-16 16:16:01 +00:00
Unbit 930c19210a inform user about UWSGI_GO_CHEAP_CODE 2014-05-14 15:35:06 +02:00
Unbit 5beb170cfd inform user about UWSGI_GO_CHEAP 2014-05-14 15:34:08 +02:00
Unbit a13103d851 added UWSGI_GO_CHEAP 2014-05-14 15:24:37 +02:00
Unbit bc5a86694f correctly manage 64bit sharedarea numbers on 32bit systems 2014-05-14 11:33:18 +00:00
Unbit 812685096b various sharedarea improvements 2014-05-14 10:45:49 +00:00
Unbit f70c070a0f fixed #622 2014-05-13 19:37:10 +02:00
Unbit accf622ffc fixed #623 2014-05-13 13:26:00 +02:00
Unbit 04173869ee ensure SIGPIPE is ignored in gevent mode 2014-05-13 12:49:58 +02:00
Roberto De Ioris 509a3c5cd4 fixed #620 2014-05-08 06:48:30 +02:00
Unbit 81ad3a916d allow variables in uwsgi router 2014-05-07 11:30:43 +02:00
Unbit 3f93a0b8e4 improved icecast2 management 2014-05-07 06:53:30 +02:00
Unbit 4408b655a4 implement a form of virtualhosting for http/1.0 icecast2 source requests 2014-05-07 06:47:45 +02:00
Unbit 71a6b8a304 more Emperor backports 2014-05-07 06:22:03 +02:00
Unbit 7e9069eabf reindented emperor.c 2014-05-07 06:14:48 +02:00
Roberto De Ioris 6c77dd0e38 fixed typo in SOURCE manager 2014-05-07 06:08:19 +02:00
Roberto De Ioris 27e506c72a added SOURCE management to http router 2014-05-07 06:06:14 +02:00
Roberto De Ioris bea68191e3 backported emperor fixes from 2.1 2014-05-07 06:03:54 +02:00
Unbit 9b207d8a62 added --metrics-no-cores, --stats-no-cores, --stats-no-metrics. fixed #537 2014-05-05 18:19:08 +02:00
Unbit 68d5b2de3b implements eof management in fastcgi parser 2014-05-05 17:37:55 +02:00
Unbit 3a62573005 close pipe and config file descriptors when back to on-demand mode 2014-05-04 19:43:38 +02:00
Unbit 1c6dd42318 added --emperor-no-blacklist 2014-05-04 09:15:15 +02:00
unbit 73ad0677bd Merge pull request #616 from prymitive/ignore_static_file_avg_rt
don't recalculate avg_rt for static files
2014-05-04 08:01:58 +02:00
Łukasz Mierzwa 15b2cf0712 don't recalculate avg_rt for static files 2014-05-03 21:48:41 +02:00
Unbit 0da0fa211a avoid re-calling emperor_simple_do while destroying a vassal 2014-05-03 08:55:34 +02:00
Unbit a8ecd71ffd fixed a typo in emperor mongodb 2014-05-03 08:28:37 +02:00
Unbit ea0a95a441 added error report for emperor error 2014-05-03 08:18:48 +02:00
Unbit 6ac6e58bf7 refactored return action 2014-05-02 12:00:08 +02:00
unbit f2c7addb73 Merge pull request #615 from getcwd/master
core/routing: add new "return/break-with-status" action
2014-05-02 11:43:33 +02:00
Unbit fff5fa536b allow fast moving to/from on_demand mode 2014-05-02 07:14:05 +02:00
Yu Zhao 95825c9b99 core/routing: add "return" action
The new action will allow users to write simplified "break" clause.
For example, "return:403" is equivalent to "break:403 Forbidden",
with response body "Forbidden". The response body is quite useful
for telling end users what goes wrong.
2014-05-01 15:32:08 -07:00
unbit 1e84fcf880 Merge pull request #613 from avar/more-perl-tests-and-benchmarks
More perl tests and benchmarks
2014-05-01 06:12:05 +02:00
Ævar Arnfjörð Bjarmason 0f742a72bf t/perl/hello_benchmark.pl: silly benchmark for CPU count + thunder lock
This is to test how the number of processes and using thunder-lock or
not affects response times.
2014-05-01 01:19:35 +02:00
Ævar Arnfjörð Bjarmason fd96a02576 t/perl/test_sleepy.psgi: perl test file that sleeps a bit
This is to test non-CPU bound servers that are waiting on
something (e.g. a database), expecting that we can have a lot more than
num CPU cores of these and not see performance degration.
2014-05-01 01:19:30 +02:00
unbit 77ca76428d Merge pull request #612 from avar/add-perl-hello-world-test-file
t/perl/test_hello.psgi: perl test file that does nothing but hello, worl...
2014-04-30 21:44:32 +02:00
Ævar Arnfjörð Bjarmason 9ea8f4f07c t/perl/test_hello.psgi: perl test file that does nothing but hello, world
To test a bare-minimal Perl program that does almost nothing at all.
2014-04-30 17:59:41 +00:00
Unbit 9ffc311177 fixed fastcgi parser 2014-04-30 14:40:34 +02:00
Unbit 4f89a350aa fixed json escaper 2014-04-30 07:42:11 +02:00
Unbit 8f18c77587 fixed sharedarea waiting 2014-04-29 11:19:39 +02:00
Unbit 371cafef94 do not explode on milliseconds wait 2014-04-29 07:42:11 +02:00
unbit 89c31e9280 Merge pull request #606 from getcwd/master
plugins/alarm_curl ehancement
2014-04-29 06:45:45 +02:00
Yu Zhao 418d784148 plugins/alarm_curl: option for disabling dedicated alarm threads
A new global option alarm-cheap allows users to disable creating
thread per curl-based alarm. This option can be extended to other
alarm plugins like xmpp.
2014-04-27 15:43:26 -07:00
Yu Zhao c146275e9b plugins/alarm_curl: refactor code
No need to calloc struct uwsgi_alarm_curl_config because all data
we need is populated and stored in struct uwsgi_alarm_curl.

Save some memory when there are hundreds of curl-based alarms.
2014-04-27 15:43:18 -07:00
Yu Zhao eff23382c2 plugins/{airbrake,alarm_curl,alarm_xmpp}: fix race condition
A thread may run immediately after it's created. Trying to pass
parameter to thread using uwsgi_thread->data without preventing
the thread from accessing it first is a race condition. If the
thread accesses uwsgi_thread->data first, uwsgi gets killed by
SIGSEGV.

This patch creates a new function uwsgi_thread_new_with_data()
to assign user provided data to uwsgi_thread->data before the
thread is created.
2014-04-27 14:28:59 -07:00
Yu Zhao d566469c63 plugins/alarm_curl: fix read callback function for libcurl
The read callback for libcurl shouldn't return size that is larger
than the requested size when it's too small to hold email header.
Otherwise curl will abort the operation. And we shouldn't return
1 (which is the current behavior) while there is no header at all.

The expected size of the infile set by option CURLOPT_INFILESIZE
or CURLOPT_INFILESIZE_LARGE should include both header and body
sizes. The infile size is used when server supports the optional
"SIZE" parameter of "MAIL FROM" command. libcurl hangs when wrong
size is passed in.

Since email header remains unchanged for each alarm_curl instance,
we don't have to generate it per alarm request. Based on this, the
solution is quite simple: we generate the header once during
initialization and use it for all alarms.
2014-04-27 11:38:46 -07:00
Yu Zhao e008ce5d56 plugins/alarm_curl: add SSL option to skip certificate verification
The new option ssl_insecure is equivalent to curl command line
option --insecure or -k, which is useful for posting alarms via
HTTPS to a server with self-generated certificate installed.
2014-04-27 11:25:07 -07:00
Yu Zhao 9d21c99183 plugins/alarm_curl: use CRLF instead of LF for line break in MIME
Though most programs accept LF, MIME RFC explicitly requires CRLF.
2014-04-27 11:25:03 -07:00
Yu Zhao 7e80927317 plugins/alarm_curl: free memory used during parsing args 2014-04-27 06:20:18 -07:00
Yu Zhao 6664e7120b plugins/alarm_curl: exit when requested protocol is not support
When SMTP is not supported by libcurl, or user doesn't provide
required URL for libcurl, throw an error message and then exit.
2014-04-27 06:20:18 -07:00
Yu Zhao 687aabd30b plugins/alarm_curl: turn on SMTP protocol
Compiler ignores SMTP support because enums CURLOPT_MAIL_RCPT and
CURLPROTO_SMTP are misused as macros for conditional compilation.

Replace the enums with real macro CURLPROTO_SMTP so compiler can
detect them.
2014-04-27 06:20:15 -07:00
unbit fab656c635 Merge pull request #602 from paulegan/mule-graceful-reload
Support for graceful reload of mule processes.
2014-04-26 19:28:40 +02:00
Paul Egan 72c31dab7a Support for graceful reload of mule processes.
- On reload master now signals mule with HUP instead of KILL.
- Added optional call to PyOS_AfterFork to enable cpython child
  processes to override and trap HUP signal.
- Copied cursed_at/no_mercy_at pattern used with worker processes.
- Added mule_reload_mercy option.
2014-04-26 14:12:48 +01:00
Roberto De Ioris f19a301b73 afaik only darwin misses objcopy 2014-04-26 07:18:24 +02:00
unbit 19a19a8a67 Merge pull request #604 from blablacio/master
Enabling OpenBSD support for uWSGI embedded config
2014-04-26 07:16:04 +02:00
Roberto De Ioris d9c9f41624 better manage ready/accepting vassals states 2014-04-26 07:02:41 +02:00
blablacio dc97853f9f Enabling OpenBSD support for uWSGI embedded config 2014-04-26 06:44:53 +03:00
unbit b089774c36 Merge pull request #603 from tizoc/master
Support for repeated headers in responses in the Lua plugin
2014-04-25 06:45:50 +02:00
Bruno Deferrari f8a271a027 Add a basic test app for the lua plugin 2014-04-24 21:27:16 -03:00
Bruno Deferrari ef12aaf13c Support for repeated headers in responses in the Lua plugin
This is needed for WSAPI conformance, and important for having
good support of Set-Cookie.
2014-04-24 17:30:09 -03:00
unbit a559361a30 Merge pull request #601 from getcwd/master
Add synonym "lru"  for "purge_lru" in cache config
2014-04-23 06:45:16 +02:00
Yu Zhao 6aad281441 Add synonym "lru" for "purge_lru" in cache config 2014-04-22 07:17:53 -07:00
Unbit 7604c67018 ready to release 2.0.4 2014-04-22 08:22:00 +02:00
Roberto De Ioris afc962709f fixed respawn when in on-demand mode 2014-04-21 07:49:57 +02:00
Unbit c11e0654a0 added php session support over cache 2014-04-19 18:42:52 +02:00
Unbit 6e4f47cc76 the corerouter error reporting is still wrong :( 2014-04-19 11:36:06 +02:00
Unbit 20c9f0ef40 another error report fix for the corerouter 2014-04-19 11:25:52 +02:00
Unbit ef3c8a5bd9 fixed tornado plugin 2014-04-19 11:01:14 +02:00
Unbit 76d0438fee added asyncio build profile 2014-04-19 10:58:50 +02:00
Unbit 18fd338908 fixed corerouter error reporting 2014-04-19 10:27:58 +02:00
Unbit 2b35e95706 removed some useless debug 2014-04-19 09:29:43 +02:00
Unbit 4761146599 the asyncio plugin (experimental) 2014-04-19 09:21:19 +02:00
Unbit 3924cc639e added Yu Zhao to CONTRIBUTORS 2014-04-18 06:29:29 +02:00
unbit 5f09de0469 Merge pull request #597 from getcwd/lru
Implement LRU for cache framework
2014-04-18 06:28:10 +02:00
Yu Zhao 4f0e3fb79f Implement LRU for cache framework
If "purge_lru" option is used when creating cache store, the
"expires" parameter for cache_set/cache_update will be ignored.
Instead, all items are placed on an LRU list and when the store
is full, the least recent used one will be evicted.
2014-04-17 20:26:41 -07:00
unbit 05b6baf173 Merge pull request #594 from getcwd/master
cache/sweeper ehancement
2014-04-16 07:03:53 +02:00
Yu Zhao 149823aac4 Only scan cached items when there is expired one
This is an optimization for the sweeper algorithm. By remembering
the least expiration time, we can determine whether we need to go
over all items in a cache store. If we have to, we find the new
least expiration time by examining those that are not expired yet.
2014-04-15 13:57:57 -07:00
Yu Zhao 85d86dc10e Only allocate one sweeper thread
Thread is not cheap on Linux since it involves context switch in the
kernel. And allocating multiple threads is not necessary even on SMP
since the granularity of time is second.
2014-04-15 10:58:29 -07:00
Yu Zhao e97d921909 Optimization for sweeper creation loop
cache_no_expire is a global flag, if it's set, return without further
check when trying to create sweepers.
2014-04-15 08:56:34 -07:00
unbit c5e20bf4da Merge pull request #593 from getcwd/patch-1
add ${HTTPS} to https_socket
2014-04-15 06:15:45 +02:00
getcwd a09d25ccaa add ${HTTPS} to https_socket
https plugin sets ${HTTPS} so should https_socket proto -- admins can write consistent HTTP/HTTPS routing rules for both.
2014-04-14 14:22:31 -07:00
Unbit bf01cea062 added micros() api function 2014-04-12 18:34:57 +02:00
unbit b6459be3e4 Merge pull request #591 from prymitive/ssl_opts
always generate key if (EC)DH is used
2014-04-12 12:25:29 +02:00
Łukasz Mierzwa d42788c17b always generate key if (EC)DH is used 2014-04-12 11:16:05 +02:00
Unbit 872730c116 added mongodb2 imperial monitor 2014-04-11 11:15:17 +02:00
Unbit 6fce0aee84 fixed a typo 2014-04-11 10:36:08 +02:00
Unbit e3d8a02614 add a memo for future offload improvements 2014-04-09 11:24:02 +02:00
Unbit b58696399e added support for http proxy connect in router_http 2014-04-09 10:49:17 +02:00
Unbit 519c9f58b3 Merge branch 'master' of ssh://github.com/unbit/uwsgi 2014-04-09 05:53:48 +02:00
Unbit 2c77c5c639 fixed http and uwsgi internal routers (by Guido Notari) 2014-04-09 05:53:26 +02:00
unbit fb9e5a1891 Merge pull request #587 from prymitive/lseek
check lseek return value in uwsgi_check_logrotate()
2014-04-06 20:11:20 +02:00
unbit 5aa7d1a79f Merge pull request #586 from prymitive/logto2
uwsgi_setup_log_master must always be called after logto()
2014-04-06 20:10:38 +02:00
Łukasz Mierzwa bc3442ba29 uwsgi_setup_log_master must always be called after logto(), this was not happening with --logto2 2014-04-06 15:08:03 +02:00
Łukasz Mierzwa 3061e36089 check lseek return value in uwsgi_check_logrotate() 2014-04-06 15:03:17 +02:00
Unbit 4f8c41cf61 fix headers parsing in http router 2014-04-06 10:15:24 +02:00
unbit b0065c379e Merge pull request #585 from stestagg/master
Fix uwsgi_route_var_mime
2014-04-05 15:58:06 +02:00
Steve Stagg 57f71c974d Fix some bugs introduced in c57baae477 preventing the 'mime' routing function from working with request variables, and actually return the found mimetype
The uwsgi_route_var_mime function had two errors preventing it from (afaics ever) working:
 1. Redefine the 'ret' variable inside an if block. This meant that if the uwsgi_get_mime_type function ever actually found a matching mimetype, the length of the matching value would be corectly set, but the function returns NULL (the value of the function-level ret variable)
 2. The function was looking up the request variable correctly, BUT then passing in the raw config string to uwsgi_get_mime_type NOT the resolved varible value, making the lookup just a waste of cycles.
2014-04-05 13:36:53 +01:00
Unbit b820fefbbd prepare for 2.0.4 2014-04-05 10:15:02 +02:00
Unbit 5f759f0d26 allow duplicate headers in http router 2014-04-05 10:14:11 +02:00
Unbit f7eb9ed1cd improved on_demand mode 2014-04-05 08:56:39 +02:00
Unbit 3a82732b19 advanced http timeout management 2014-04-05 07:57:01 +02:00
Unbit d74e826f71 another patch for reducing emperor race conditions 2014-04-02 09:15:05 +02:00
unbit c846a9b388 Merge pull request #582 from prymitive/cache_full_ignore
allow disabling cache warnings
2014-04-02 00:33:49 +02:00
Łukasz Mierzwa 001e4b6e39 allow disabling cache warnings in --cache2 2014-04-01 20:00:13 +02:00
Unbit a51a396f47 fixed #581 2014-04-01 12:04:31 +02:00
Unbit 17965ea870 faster restart of vassals 2014-04-01 10:52:32 +02:00
Unbit 8a032b41ec combine headers with the same name in HTTP native mode 2014-03-31 10:32:18 +02:00
Roberto De Ioris a489cfc2c1 fixed additional sources 2014-03-28 07:08:15 +01:00
unbit 3b32672ff9 Merge pull request #579 from prymitive/spdy_fix
merge duplicated headers when SPDY is enabled, fixes #572
2014-03-28 06:18:26 +01:00
Łukasz Mierzwa 858131ba57 merge duplicated headers when SPDY is enabled, fixes #572 2014-03-27 21:32:51 +01:00
Unbit 8a8d2f8675 support embedded config on FreeBSD 2014-03-26 16:54:31 +01:00
Unbit 9d37725323 added setmodifier1 and setmodifier2 2014-03-23 07:26:14 +01:00
Unbit e973492267 added no_headers option to keyval based static routers, fixes #576 2014-03-22 18:23:18 +01:00
Unbit 105a68bce9 fixed fatal hooks management 2014-03-22 13:10:00 +01:00
Unbit 0587a0ca53 fixed #557 for --lazy-apps 2014-03-22 13:01:14 +01:00
Unbit d4b259d5e0 fixed #575 2014-03-20 05:48:05 +01:00
Unbit 9e591c587f added rpc hook 2014-03-20 05:38:39 +01:00
Unbit e7cce7b785 fixed segfault for unnamed loggers 2014-03-18 16:16:12 +01:00
unbit 3285b224c2 Merge pull request #573 from prymitive/spdy_fix
Lowercase only header keys, not values.
2014-03-17 09:07:20 +01:00
Roberto De Ioris e4a4942980 prepare for 2.0.3 release 2014-03-17 06:33:04 +01:00
Roberto De Ioris 6f671936fc added uwsgi::add_var to perl 2014-03-17 06:18:15 +01:00
Roberto De Ioris 7d1d992d58 fix tnetstring support #562 2014-03-17 06:02:44 +01:00
Łukasz Mierzwa 2bba4cf15a Lowercase only header keys, not values. Fixes #572 2014-03-16 23:43:28 +01:00
unbit 930f71c562 Merge pull request #571 from avar/avar/fix-2.0.1-perl-refactoring-regression
perl: fix one-off error in 2.0-103-gf041d10 causing warnings in e.g. Pla...
2014-03-16 05:53:54 +01:00
unbit 959bb11f77 Merge pull request #570 from avar/avar/add-sanity-check-to-offset-test
perl: add sanity checks to t/perl/test_input_with_offset.pl
2014-03-16 05:52:19 +01:00
Ævar Arnfjörð Bjarmason 13d8505738 perl: fix one-off error in 2.0-103-gf041d10 causing warnings in e.g. Plack::Request
This newly added support for read() offsets started causing "Use of
uninitialized value in subroutine entry" warnings.

This is all because there was a test for the number of items on the
stack, which ignored that the first argument is always the object, so 3
arguments to read() actually yields 4 arguments on the stack, not 3.

As a result we'd be calling SvIV() on a stack item that wasn't actually
passed in.
2014-03-15 21:05:18 +00:00
Ævar Arnfjörð Bjarmason 93fe463ca8 perl: add sanity checks to t/perl/test_input_with_offset.pl 2014-03-15 20:41:54 +00:00
unbit 5c64c21745 Merge pull request #569 from avar/avar/add-generated-file-to-gitignore
.gitignore: add /core/config_py.c to ignore
2014-03-15 15:16:12 +01:00
Ævar Arnfjörð Bjarmason f825ab542d .gitignore: add /core/config_py.c to ignore
This file added in e4903ee is generated by the build system and should
be in the ignore file.
2014-03-15 14:15:35 +00:00
unbit e744aef144 Merge pull request #568 from avar/avar/perl-add-streaming-test
perl: add a trivial streaming test program
2014-03-15 15:15:23 +01:00
Ævar Arnfjörð Bjarmason 4ded485a8e perl: add a trivial streaming test program
This came out of working on this debugging session:
https://github.com/unbit/uwsgi/issues/567
2014-03-15 14:10:20 +00:00
unbit 2ce5ec3986 Merge pull request #566 from avar/avar/psgi-spelling-error-fix
perl: fix trivial spelling error in psgi_loader.c error message
2014-03-15 14:48:35 +01:00
Ævar Arnfjörð Bjarmason af95f90fb0 perl: fix trivial spelling error in psgi_loader.c error message 2014-03-15 13:47:07 +00:00
unbit 7989dc748b Update CONTRIBUTORS 2014-03-15 14:36:51 +01:00
unbit f85f3e8178 Merge pull request #565 from avar/avar/fix-perl-stacktrace
perl: fix a regression with caller() not indicating the starting *.psgi ...
2014-03-15 14:28:14 +01:00
Ævar Arnfjörð Bjarmason 97809192c8 perl: fix a regression with caller() not indicating the starting *.psgi program
In 2.0.1-41-g3480c30 I introduced a regression with how the top-level
stackframe would appear within Perl programs. Before we'd show the
filename of the *.psgi file, but after we just showed "-e".

We can retain the bugfix I added in 2.0.1-41-g3480c30 while having a
sensible stacktrace by overriding the file via the #line directive.
2014-03-15 13:10:30 +00:00
Roberto De Ioris 5f74e6d964 fixed stupid bug with python add_var 2014-03-15 12:51:15 +01:00
Roberto De Ioris ae87fdd0f7 added uwsgi.add_var 2014-03-15 12:47:59 +01:00
Roberto De Ioris 36c44c83af added disableheaders routing action 2014-03-15 12:04:01 +01:00
Roberto De Ioris 48e13bfc65 add a check for already initialized python vm 2014-03-15 08:48:07 +01:00
Unbit 16cd55637d added support for mongrel2 URL_SCHEME #562 2014-03-14 11:48:36 +01:00
Unbit 39cf2887c4 added SIGURG to the Emperor 2014-03-14 11:28:53 +01:00
Unbit 671bf8a258 try to avoid vassal pipe to have invalid fd numbers 2014-03-14 11:21:20 +01:00
Unbit 89a8ceea81 allows building plugins from git repositories 2014-03-13 14:11:12 +01:00
Roberto De Ioris 6699f4046e better error reporting on websockets errors 2014-03-13 07:35:18 +01:00
Roberto De Ioris 88474b3d96 do not wait for a whole Emperor cycle before checking for each waitpid 2014-03-13 07:03:50 +01:00
unbit 32b6463d06 Merge pull request #559 from hynek/master
Set ECDHE curve independently from DHE parameters
2014-03-13 06:19:11 +01:00
Hynek Schlawack 63cc29a61d Set ECDHE curve independently from DHE parameters 2014-03-12 21:19:52 +01:00
Unbit d58f79eeab fixed #558 2014-03-11 16:18:32 +01:00
Unbit 7b24d2f5de allows vassals to request a config chunk from the emperor 2014-03-11 07:04:23 +01:00
Unbit a93db73d0c Merge branch 'master' of github.com:unbit/uwsgi 2014-03-10 14:52:35 +01:00
Unbit c118c75bfe beter management of failed emperor kills 2014-03-10 14:52:30 +01:00
Unbit 624631d443 fixed tuntap 2014-03-08 13:57:15 +01:00
Unbit b681eab385 fixed SIGWINCH in emperor and added emperor rescan master fifo command 2014-03-08 08:13:30 +01:00
Unbit 91dfe779ff fixed typo 2014-03-08 06:38:50 +01:00
Unbit 0ad50711c0 report key in corerouters 2014-03-08 06:36:38 +01:00
Unbit df6ed26479 more debug for tuntap 2014-03-08 06:24:45 +01:00
Unbit d08778b39c removed useless tuntap debug 2014-03-08 05:59:59 +01:00
Unbit 0c8c2932cf Merge branch 'master' of https://github.com/unbit/uwsgi 2014-03-08 05:44:05 +01:00
Unbit 131bd7da2f try to improve nb tuntap gateway 2014-03-08 05:43:54 +01:00
Unbit d247424442 more useful log alarm 2014-03-07 16:09:04 +01:00
Roberto De Ioris 332fab2150 hack for avoiding libmongoclient to crash on broken cursor 2014-03-07 07:31:42 +01:00
Roberto De Ioris 62d74951db support for git-based plugins 2014-03-05 08:28:17 +01:00
Roberto De Ioris 839638a0ad report socket name on invalid zeromq syntax 2014-03-04 06:38:42 +01:00
Roberto De Ioris 536ae8d013 fixed mongrel2 post_fork hook 2014-03-04 06:32:40 +01:00
Roberto De Ioris 367c4b9bab added on_demand sockets support to mongodb Emperor plugin 2014-03-04 06:08:16 +01:00
Roberto De Ioris 3965c01880 on __APPLE__ use LOG_NOTICE for syslog plugin 2014-03-04 05:44:18 +01:00
Unbit 7e4341a7cd force on demand unix socket to 666 2014-03-02 10:14:58 +01:00
Unbit 8c118c8f62 fixed (and improved) on demand emperor socket 2014-03-02 09:36:17 +01:00
Unbit 5d76b63fac fixed #555 2014-03-01 08:25:35 +01:00
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
Unbit f3e164b397 fixed return value in hv_store 2013-12-26 18:57:52 +01:00
Unbit a60bb56b18 cygwin does not support sethostname 2013-12-26 18:00:59 +01:00
Unbit d08d08f39b exit(1) on setns propen failure 2013-12-26 17:54:05 +01:00
Unbit 4c4c2bb0fe setns-peopen does not take arguments 2013-12-26 17:53:14 +01:00
Unbit cf79ce40e4 fixed max worker lifetime 2013-12-26 17:46:19 +01:00
Unbit c153c26c18 fixed scripts/tests making use of dynamic options 2013-12-26 17:42:28 +01:00
Unbit 82f5d1f988 prepare for 2.0-rc1 2013-12-26 17:28:13 +01:00
Unbit 5de83201ea getting rid of dynami options (step 3) 2013-12-26 17:06:36 +01:00
Unbit 6d69c01651 getting rid of dynami options (step 2) 2013-12-26 17:03:27 +01:00
Unbit 61f3d162a4 getting rid og dynamic options (step 1) 2013-12-26 16:48:50 +01:00
Unbit 0a025ef93a fixed minor bug in listen queue management 2013-12-26 11:21:16 +01:00
Unbit f0951d3f41 refactored listen queue management 2013-12-26 11:14:28 +01:00
Unbit f2e4eabf42 fixed cheaper busyness check 2013-12-26 08:02:27 +01:00
Unbit 4fc99b3a3e fixed memory allocation in --attach-daemon2 2013-12-24 18:02:32 +01:00
Unbit 1efb3f4096 expose uid gid and pid in subscription nodes 2013-12-24 17:43:54 +01:00
Unbit 9c29d6899f implemented touch management for daemons 2013-12-24 17:30:23 +01:00
Unbit 9a7524b55d added --attach-daemon2 2013-12-24 17:08:36 +01:00
Unbit 04dfc3ae19 fixed hooks when exit on reload is in place 2013-12-24 07:58:06 +01:00
Unbit fc10411adb added three new emperor hooks 2013-12-24 07:08:31 +01:00
unbit 2378db4520 Merge pull request #495 from prymitive/busyness_metrics
metrics support for cheaper busyness plugin
2013-12-23 11:11:33 -08:00
Łukasz Mierzwa bdbd484db5 metrics support for cheaper busyness plugin 2013-12-23 19:07:51 +01:00
unbit a2f6dd4ee2 Merge pull request #494 from xrmx/coverity-2312-4
More Coverity fixes
2013-12-23 08:36:30 -08:00
Riccardo Magliocchetti ac001beb41 emperor: Avoid integer overflow
Reported by Coverity as CID #971237, #971238.
2013-12-23 17:12:43 +01:00
unbit 05895c40f7 Merge pull request #493 from xrmx/setns_array2
core: setns_fds is an array on stack
2013-12-23 08:09:53 -08:00
Riccardo Magliocchetti fbf9a5b27c uwsgi_app.chdir is an array
So check if it's first member is not 0 instead.

Fix Coverity CID #971000, #970998.
2013-12-23 16:53:41 +01:00
Riccardo Magliocchetti 9c84e9f6cc core: setns_fds is an array on stack
So it makes not sense to check if it's set to something. Instead
check just check setns_fds_count.

Reported by Coverity as CID #1142188, #1142187.
2013-12-23 16:45:58 +01:00
unbit 486796bdf9 Merge pull request #491 from xrmx/coverity2312-3
Coverity2312 3
2013-12-23 05:09:03 -08:00
Riccardo Magliocchetti e795cd8912 plugins/python: fix uwsgi_python_harakiri error handling
Fixes close with a negative fd.

Reported by Coverity as CID #970996.
2013-12-23 13:43:02 +01:00
Riccardo Magliocchetti 643fc3019b plugins/corerouter: check return value of bind_to_unix_dgram
Reported by Coverity as CID #1142187
2013-12-23 13:19:00 +01:00
Riccardo Magliocchetti f409e8b501 core/hooks: fix typo
which leds to coverity issues :)

Reported by Coverity as CID #1142190 and #1142186
2013-12-23 13:09:06 +01:00
Unbit 361ec8bcd4 fixed sni delete 2013-12-23 13:08:31 +01:00
Riccardo Magliocchetti ba3ac9ad09 yaml: fix memory leak
Reported by Coverity as CID #971051.
2013-12-23 13:07:43 +01:00
Riccardo Magliocchetti 419f1801cd core/ns: fix resource leak
Reported by Coverity as CID #1142191
2013-12-23 12:56:08 +01:00
unbit d3c5ccc061 Merge pull request #490 from xrmx/coverity2312-2
master: fix a couple of resource leaks
2013-12-23 03:40:15 -08:00
Riccardo Magliocchetti be6f61aa1b master: fix a couple of resource leaks
Reported by Coverity as CID #1141954
2013-12-23 12:18:26 +01:00
Roberto De Ioris eb6c35aa95 fixed #488 2013-12-23 02:56:49 +01:00
Roberto De Ioris 797b14b23e fixed #487 2013-12-23 02:24:01 +01:00
unbit 44e7be13e2 Merge pull request #485 from prymitive/typo
Few typos in cheaper plugin
2013-12-22 03:30:29 -08:00
Łukasz Mierzwa 18f6660603 typos in cheaper plugin 2013-12-22 12:23:22 +01:00
Unbit c3f64af2df implemented private hooks 2013-12-22 11:14:52 +01:00
Unbit 2278f98318 fixed writen and append 2013-12-22 08:53:29 +01:00
Unbit b4ee27b524 added chown2 hook 2013-12-22 06:20:54 +01:00
Unbit 85ee422dcb added non-tolerant chown hook 2013-12-22 06:04:20 +01:00
Unbit 15f70b2444 fix first retry in harakiri mode 2013-12-22 05:50:45 +01:00
Unbit b7b126e89f git push added append and appendn 2013-12-22 05:24:49 +01:00
Unbit 56e284e18a added writen hook 2013-12-21 09:28:25 +01:00
Unbit 0d4f4a2411 added chmod hook 2013-12-21 08:21:17 +01:00
Unbit 68049a5177 more solid log rotation 2013-12-21 08:11:35 +01:00
Unbit fc2355e5be added putenv hook 2013-12-21 07:21:34 +01:00
Unbit 49925e95d4 added mkdir hook 2013-12-20 17:39:22 +01:00
unbit bee171e5da Merge pull request #484 from xiaost-bytedance/master
fixed master fd leak when using tracebacker
2013-12-20 05:14:57 -08:00
xiaost df809c8e34 fixed master fd leak when using tracebacker 2013-12-20 21:02:31 +08:00
Unbit 3b64838324 fixed snprintf() usage all over the place 2013-12-20 08:54:27 +01:00
Unbit f1f51948eb close alarm fds on fork() 2013-12-20 08:16:36 +01:00
Unbit 906da5cb9a do not rely on unix signals to print request status during harakiri 2013-12-20 05:56:56 +01:00
Unbit dacad8d9b9 added magic vars for uid and gid 2013-12-19 17:06:49 +01:00
Unbit 39fbea6d48 added support for yajl library 2013-12-19 12:30:26 +01:00
Unbit 4796f85277 added UWSGI_PROFILE_OVERRIDE 2013-12-19 09:36:53 +01:00
Unbit 01ee66d1f6 simplify buildconf syntax for alternative implementation 2013-12-19 09:27:58 +01:00
Unbit 6c61ac9c7e added APPEND_CFLAGS support 2013-12-19 09:08:35 +01:00
Unbit 77c279b3a9 added rx and tx to subscription nodes 2013-12-18 07:31:53 +01:00
Unbit 34430ceac4 fixed gateway packet 2013-12-18 06:53:56 +01:00
Unbit fd1f79d154 fixed tuntap endianess 2013-12-17 21:31:03 +01:00
unbit 56f7d09b2b Merge pull request #483 from prymitive/sni_fix
sni support in corerouter stats requires ssl
2013-12-17 11:13:07 -08:00
unbit 479df7c2cc Merge pull request #482 from prymitive/idle_zero_mem
reset worker memory usage when --idle option kills it
2013-12-17 11:12:43 -08:00
Łukasz Mierzwa 69c41026a4 sni support in corerouter stats requires ssl 2013-12-17 20:07:02 +01:00
Łukasz Mierzwa 7a305704f1 reset worker memory usage when --idle option kills it, needed for #479 2013-12-17 20:03:53 +01:00
Unbit 8d44dff97e Merge branch 'master' of ssh://github.com/unbit/uwsgi 2013-12-17 06:51:05 +01:00
Unbit c9324c06ca implemented perl spooler and fixed a leak in the CPython one 2013-12-17 06:50:47 +01:00
unbit 3446c2d322 Merge pull request #481 from prymitive/metrics_avg_rt
2 small metrics fixes
2013-12-16 20:28:14 -08:00
Łukasz Mierzwa 6704d1a95a * add core.avg_response_time metric
* don't add worker 0 to total metrics
2013-12-16 22:33:57 +01:00
Unbit 0e539f25cd removed additional debug 2013-12-16 19:20:54 +01:00
Unbit 00eb37f724 improved credentials usage in tuntap 2013-12-16 17:47:49 +01:00
Unbit 30c6ac8cb8 allows gateway to drop privileges 2013-12-16 17:09:39 +01:00
Unbit faa13228a5 improved tuntap dynamic rules 2013-12-16 16:45:11 +01:00
Unbit e1941a49b8 added build profile for uwsgi.it 2013-12-16 15:44:14 +01:00
Unbit d32f7b997d allow unprivileged usage of setns 2013-12-16 15:23:50 +01:00
Unbit 972333941d added --jailed 2013-12-16 14:51:55 +01:00
Unbit 1691263744 added dynamic rules for tuntap devices 2013-12-16 13:52:22 +01:00
Unbit debfe5b2b9 added gateway support to tuntap router 2013-12-16 07:25:50 +01:00
Unbit d2ce28f441 added hostname hook 2013-12-15 19:28:20 +01:00
Unbit b9170b2c85 added credentials support to the tuntap router 2013-12-15 07:49:44 +01:00
Unbit 33a6195e44 improvements in SCM_CREDENTIALS subscription system 2013-12-15 06:31:33 +01:00
Unbit 933ef85cf2 SCM_CREDENTIALS are not available everywhere 2013-12-14 18:11:45 +01:00
Unbit 0b27d41712 fixed corerouter servername for sni 2013-12-14 18:00:23 +01:00
Unbit 2124b930fd subscription system can now create sni contexts 2013-12-14 17:54:19 +01:00
Unbit b5a2a89630 added api for passing credentials 2013-12-14 16:53:07 +01:00
Unbit 22bf9b33b0 added tuntaprouter stats 2013-12-14 16:16:28 +01:00
Unbit b44c2208d9 added nosuid mount support to linux 2013-12-14 14:22:02 +01:00
Unbit 44136aa572 added support for data mount option 2013-12-14 14:16:00 +01:00
Unbit 5dd62ef909 fixed #479 2013-12-14 13:37:38 +01:00
Unbit 5ea95c9e89 fixed a couple of memory leaks 2013-12-14 13:27:46 +01:00
Unbit 8095a9108c added setns() support 2013-12-14 10:43:27 +01:00
Unbit 1cbc423afc fixed 2 typos 2013-12-14 07:49:37 +01:00
Unbit 4e260fa8a1 fixed #476 and #477 2013-12-14 07:45:38 +01:00
Unbit bb4be12fda implemented more async api in lua 2013-12-13 11:51:05 +01:00
Unbit 672fb0eaa6 added --lua-gc-freq 2013-12-13 09:07:44 +01:00
Unbit def274f28c Merge branch 'master' of ssh://github.com/unbit/uwsgi 2013-12-13 07:35:48 +01:00
Unbit be9f1578cc prepare for --attach-daemon2 2013-12-13 07:35:32 +01:00
unbit 8d8f3bdc51 Merge pull request #474 from craigbruce/master
Minor typo
2013-12-12 11:28:35 -08:00
Craig Bruce 4d9720e4b5 Minor typo 2013-12-12 12:22:16 -07:00
Unbit 6e2adf9cf3 added support for async api to lua 2013-12-12 13:42:12 +01:00
Unbit 7f004c5d6d removed async_force_again from lua 2013-12-12 13:34:25 +01:00
Unbit 13e7b53c54 async_force_again 2013-12-12 13:33:37 +01:00
Unbit 1c89522519 added websocket api to lua 2013-12-12 11:16:38 +01:00
Unbit 3b4581a581 Merge branch 'master' of ssh://github.com/unbit/uwsgi 2013-12-12 03:57:30 +01:00
Unbit dfaa1d9313 1.9.21 2013-12-12 03:57:11 +01:00
unbit 795721b91e Merge pull request #473 from prymitive/stypo
fixed block check in subscriptions
2013-12-11 18:56:52 -08:00
Łukasz Mierzwa 6bd0095513 fixed block check in subscriptions 2013-12-11 20:21:09 +01:00
206 changed files with 12264 additions and 5571 deletions
+11
View File
@@ -4,10 +4,21 @@
*.jar
*~
*.so
*.gox
*.a
*.dll
*.key
*.orig
*.rej
/uwsgi
/uwsgibuild.*
/core/config_py.c
/t/ring/target
core/dot_h.c
+# coverity
+/cov-int/
+uwsgi.tar.xz
+8 -1
View File
@@ -1,7 +1,7 @@
- this is a incomplete list of all the contributors of the project -
Roberto De Ioris, Unbit, <roberto@unbit.it>
Riccardo Magliocchetti, Unbit, <riccardo@unbit.it>
Riccardo Magliocchetti
Yann Malet, Lincoln Loop
Simon Litchfield
Masahiro Honma, <hiratara@cpan.org>
@@ -25,3 +25,10 @@ Mingli Yuan
Natanael Copa
Roberto Leandrini
Ryan Petrello
Danila Shtan <danila@shtan.ru>
Ævar Arnfjörð Bjarmason
Yu Zhao (getcwd)
Mathieu Dupuy
Adriano Di Luzio (adriano@unbit.it)
Curtis Maloney
Vladimir Didenko
+81 -11
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
@@ -67,14 +67,19 @@ static int uwsgi_canon(request_rec *r, char *url)
}
url += sizeof(UWSGI_SCHEME); /* Keep slashes */
err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
if (err) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
// is it a unix socket ?
if (strlen(url) == 2) {
*sport = 0;
}
else {
err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
if (err) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"error parsing URL %s: %s", url, err);
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
}
apr_snprintf(sport, sizeof(sport), ":%u", port);
}
apr_snprintf(sport, sizeof(sport), ":%u", port);
if (ap_strchr(host, ':')) { /* if literal IPv6 address */
host = apr_pstrcat(r->pool, "[", host, "]", NULL);
@@ -253,6 +258,43 @@ static request_rec *ap_proxy_make_fake_req(conn_rec *c, request_rec *r)
return rp;
}
static apr_status_t ap_proxy_buckets_lifetime_transform(request_rec *r,
apr_bucket_brigade *from, apr_bucket_brigade *to)
{
apr_bucket *e;
apr_bucket *new;
const char *data;
apr_size_t bytes;
apr_status_t rv = APR_SUCCESS;
apr_brigade_cleanup(to);
for (e = APR_BRIGADE_FIRST(from);
e != APR_BRIGADE_SENTINEL(from);
e = APR_BUCKET_NEXT(e)) {
if (!APR_BUCKET_IS_METADATA(e)) {
apr_bucket_read(e, &data, &bytes, APR_BLOCK_READ);
new = apr_bucket_transient_create(data, bytes, r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(to, new);
}
else if (APR_BUCKET_IS_FLUSH(e)) {
new = apr_bucket_flush_create(r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(to, new);
}
else if (APR_BUCKET_IS_EOS(e)) {
new = apr_bucket_eos_create(r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(to, new);
}
else {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00964)
"Unhandled bucket type of type %s in"
" proxy_buckets_lifetime_transform", e->type->name);
apr_bucket_delete(e);
rv = APR_EGENERAL;
}
}
return rv;
}
#endif
@@ -263,6 +305,7 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_
const char *buf;
char *value, *end;
int len;
int backend_broke = 1;
apr_status_t rc;
conn_rec *c = r->connection;
apr_off_t readbytes;
@@ -274,6 +317,7 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_
rp->proxyreq = PROXYREQ_RESPONSE;
apr_bucket_brigade *bb = apr_brigade_create(r->pool, c->bucket_alloc);
apr_bucket_brigade *pass_bb = apr_brigade_create(r->pool, c->bucket_alloc);
len = ap_getline(buffer, sizeof(buffer), rp, 1);
@@ -321,12 +365,13 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_
ap_set_content_type(r, apr_pstrdup(r->pool, buf));
}
for(;;) {
int finish = 0;
while(!finish) {
rv = ap_get_brigade(rp->input_filters, bb,
AP_MODE_READBYTES, mode,
conf->io_buffer_size);
if (APR_STATUS_IS_EAGAIN(rv)
|| (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb))) {
|| (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb)) ) {
e = apr_bucket_flush_create(c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, e);
if (ap_pass_brigade(r->output_filters, bb) || c->aborted) {
@@ -342,21 +387,46 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_
else if (rv != APR_SUCCESS) {
ap_proxy_backend_broke(r, bb);
ap_pass_brigade(r->output_filters, bb);
backend_broke = 1;
break;
}
mode = APR_NONBLOCK_READ;
apr_brigade_length(bb, 0, &readbytes);
backend->worker->s->read += readbytes;
ap_pass_brigade(r->output_filters, bb);
if (APR_BRIGADE_EMPTY(bb)) {
apr_brigade_cleanup(bb);
break;
}
ap_proxy_buckets_lifetime_transform(r, bb, pass_bb);
// found the last brigade?
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) finish = 1;
// do not pass chunk if it is zero_sized
apr_brigade_length(pass_bb, 0, &readbytes);
if ((readbytes > 0 && ap_pass_brigade(r->output_filters, pass_bb) != APR_SUCCESS) || c->aborted) {
finish = 1;
}
apr_brigade_cleanup(bb);
apr_brigade_cleanup(pass_bb);
}
e = apr_bucket_eos_create(c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, e);
ap_pass_brigade(r->output_filters, bb);
apr_brigade_cleanup(bb);
return OK;
if (c->aborted || backend_broke) {
return DONE;
}
return OK;
}
static int uwsgi_handler(request_rec *r, proxy_worker *worker,
+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
-441
View File
@@ -1,441 +0,0 @@
#include "../../uwsgi.h"
#include "erlang.h"
extern struct uwsgi_server uwsgi;
struct uwsgi_erlang uerl;
struct uwsgi_option erlang_options[] = {
{"erlang", required_argument, 0, "spawn an erlang c-node", uwsgi_opt_set_str, &uerl.name, UWSGI_OPT_MASTER},
{"erlang-cookie", required_argument, 0, "set erlang cookie", uwsgi_opt_set_str, &uerl.cookie, 0},
{0, 0, 0, 0, 0, 0, 0},
};
void dump_eterm(ei_x_buff *x) {
int etype, esize, arity;
long long num;
char *atom;
int i;
char *binary;
long bin_size;
double fnum;
ei_get_type(x->buff, &x->index, &etype, &esize);
uwsgi_log("etype: %d/%c esize: %d\n", etype, etype, esize);
switch(etype) {
case ERL_SMALL_INTEGER_EXT:
case ERL_INTEGER_EXT:
case ERL_SMALL_BIG_EXT:
case ERL_LARGE_BIG_EXT:
ei_decode_longlong(x->buff, &x->index, &num);
uwsgi_log("num: %lu\n", num);
break;
case ERL_FLOAT_EXT:
ei_decode_double(x->buff, &x->index, &fnum);
uwsgi_log("float: %f\n", fnum);
break;
case ERL_STRING_EXT:
atom = uwsgi_malloc(esize+1);
ei_decode_string(x->buff, &x->index, atom);
uwsgi_log("string: %s\n", atom);
free(atom);
break;
case ERL_ATOM_EXT:
atom = uwsgi_malloc(esize+1);
ei_decode_atom(x->buff, &x->index, atom);
uwsgi_log("atom: %s\n", atom);
free(atom);
break;
case ERL_SMALL_TUPLE_EXT:
case ERL_LARGE_TUPLE_EXT:
ei_decode_tuple_header(x->buff, &x->index, &arity);
for(i=0;i<arity;i++) {
dump_eterm(x);
}
break;
case ERL_LIST_EXT:
case ERL_NIL_EXT:
ei_decode_list_header(x->buff, &x->index, &arity);
if (arity == 0) {
uwsgi_log("nil value\n");
break;
}
for(i=0;i<arity+1;i++) {
dump_eterm(x);
}
break;
case ERL_BINARY_EXT:
binary = uwsgi_malloc(esize);
ei_decode_binary(x->buff, &x->index, binary, &bin_size);
uwsgi_log("binary data of %d bytes\n", bin_size);
free(binary);
break;
default:
uwsgi_log("ignored...\n");
ei_skip_term(x->buff, &x->index);
break;
}
}
void uwsgi_erlang_rpc(int fd, erlang_pid *from, ei_x_buff *x) {
int etype, esize;
int arity;
char *gen_call;
char *module;
char *call;
char buffer[0xffff];
char *argv[256] ;
uint16_t argvs[256] ;
int argc = 0;
uint16_t ret;
ei_x_buff xr;
erlang_ref eref;
ei_get_type(x->buff, &x->index, &etype, &esize);
#ifdef UWSGI_DEBUG
uwsgi_log("%d %c %c %c\n", etype, etype, ERL_SMALL_TUPLE_EXT, ERL_LARGE_TUPLE_EXT);
#endif
if (etype != ERL_SMALL_TUPLE_EXT && etype != ERL_LARGE_TUPLE_EXT) return;
ei_decode_tuple_header(x->buff, &x->index, &arity);
#ifdef UWSGI_DEBUG
uwsgi_log("rpc arity %d\n", arity);
#endif
if (arity != 3) return ;
ei_get_type(x->buff, &x->index, &etype, &esize);
if (etype != ERL_ATOM_EXT && etype != ERL_STRING_EXT) return ;
gen_call = uwsgi_malloc(esize);
if (etype == ERL_ATOM_EXT) {
ei_decode_atom(x->buff, &x->index, gen_call);
}
else {
ei_decode_string(x->buff, &x->index, gen_call);
}
#ifdef UWSGI_DEBUG
uwsgi_log("gen call = %s\n", gen_call);
#endif
ei_get_type(x->buff, &x->index, &etype, &esize);
if (etype != ERL_SMALL_TUPLE_EXT) return ;
ei_decode_tuple_header(x->buff, &x->index, &arity);
if (arity != 2) return ;
ei_get_type(x->buff, &x->index, &etype, &esize);
ei_skip_term(x->buff, &x->index);
ei_get_type(x->buff, &x->index, &etype, &esize);
ei_decode_ref(x->buff, &x->index, &eref);
ei_get_type(x->buff, &x->index, &etype, &esize);
module = uwsgi_malloc(esize);
if (etype == ERL_ATOM_EXT) {
ei_decode_atom(x->buff, &x->index, module);
}
else {
ei_decode_string(x->buff, &x->index, module);
}
ei_get_type(x->buff, &x->index, &etype, &esize);
if (etype != ERL_SMALL_TUPLE_EXT) return ;
ei_decode_tuple_header(x->buff, &x->index, &arity);
#ifdef UWSGI_DEBUG
uwsgi_log("arity: %d\n", arity);
#endif
if (arity != 5) return ;
ei_get_type(x->buff, &x->index, &etype, &esize);
char *method = uwsgi_malloc(esize);
if (etype == ERL_ATOM_EXT) {
ei_decode_atom(x->buff, &x->index, method);
}
else {
ei_decode_string(x->buff, &x->index, method);
}
if (strcmp(method, "call")) return;
ei_get_type(x->buff, &x->index, &etype, &esize);
if (etype != ERL_ATOM_EXT && etype != ERL_STRING_EXT) return ;
module = uwsgi_malloc(esize);
if (etype == ERL_ATOM_EXT) {
ei_decode_atom(x->buff, &x->index, module);
}
else {
ei_decode_string(x->buff, &x->index, module);
}
ei_get_type(x->buff, &x->index, &etype, &esize);
if (etype != ERL_ATOM_EXT && etype != ERL_STRING_EXT) return ;
call = uwsgi_malloc(esize);
if (etype == ERL_ATOM_EXT) {
ei_decode_atom(x->buff, &x->index, call);
}
else {
ei_decode_string(x->buff, &x->index, call);
}
#ifdef UWSGI_DEBUG
uwsgi_log("RPC %s %s\n", module, call);
#endif
ei_get_type(x->buff, &x->index, &etype, &esize);
if (etype == ERL_ATOM_EXT) {
argc = 1;
argv[0] = uwsgi_malloc(esize+1);
ei_decode_atom(x->buff, &x->index, argv[0]);
argvs[1] = esize;
}
else if (etype == ERL_STRING_EXT) {
argc = 1;
argv[0] = uwsgi_malloc(esize+1);
ei_decode_string(x->buff, &x->index, argv[0]);
argvs[1] = esize;
}
ret = uwsgi_rpc(call, argc, argv, argvs, buffer);
#ifdef UWSGI_DEBUG
uwsgi_log("buffer: %.*s\n", ret, buffer);
#endif
ei_x_new_with_version(&xr);
ei_x_encode_tuple_header(&xr, 2);
//ei_x_encode_atom(&xr, "rex");
ei_x_encode_ref(&xr, &eref);
ei_x_encode_string_len(&xr, buffer, ret);
uwsgi_log("ei_send to %d %s %d %d %d: %d %d\n", fd, from->node, from->num , from->serial, from->creation, xr.index, ei_send(fd, from, xr.buff, xr.index));
//uwsgi_log("ei_send to %d %s %d %d %d: %d %d\n", fd, from->node, from->num , from->serial, from->creation, xr.index, ei_reg_send(&uerl.cnode, fd, "rex", xr.buff, xr.index));
}
void erlang_loop(int id, void *data) {
ErlConnect econn;
//ErlMessage em;
erlang_msg em;
int fd;
int eversion;
ei_x_buff x, xr;
ei_x_new(&x);
ei_x_new(&xr);
/*
int fd0 = ei_connect(&uerl.cnode, "anothernode@maverick64");
uwsgi_log("fd0: %d\n", fd0);
ei_x_encode_list_header(&x, 0);
ei_rpc_to(&uerl.cnode, fd0, "erlang", "node", x.buff, x.index);
ei_rpc_from(&uerl.cnode, fd0, 10000, &em, &xr);
uwsgi_log("From: %s To: %s RegName: %s\n", em.from.node, em.to.node, em.toname);
xr.index = 0;
ei_decode_version(xr.buff, &xr.index, &eversion);
uwsgi_log("eversion: %d\n", eversion);
dump_eterm(&xr);
*/
for(;;) {
fd = ei_accept(&uerl.cnode, uerl.fd, &econn);
if (fd >= 0) {
for (;;) {
if (ei_xreceive_msg(fd, &em, &x) == ERL_MSG) {
if (em.msgtype == ERL_TICK)
continue;
uwsgi_log("[erlang] message From: %s To (process): %s\n", em.from.node, em.toname);
x.index = 0;
ei_decode_version(x.buff, &x.index, &eversion);
#ifdef UWSGI_DEBUG
uwsgi_log("eversion: %d\n", eversion);
#endif
if (!strcmp(em.toname, "rex")) {
uwsgi_erlang_rpc(fd, &em.from, &x);
}
else {
struct uwsgi_erlang_process *uep = uerl.uep;
while(uep) {
if (!strcmp(uep->name, em.toname)) {
if (uep->plugin) {
uep->plugin(uep->func, &x);
}
break;
}
uep = uep->next;
}
if (!uep) {
uwsgi_log("!!! unregistered erlang process requested, dumping it !!!\n");
dump_eterm(&x);
}
}
/*
if (em.msgtype) {
dump_erl_obj(em.msg);
erl_free_compound(em.msg);
}
if (em.to) {
uwsgi_log("*** TO ***\n");
dump_erl_obj(em.to);
erl_free_compound(em.to);
}
if (em.from) {
uwsgi_log("*** FROM ***\n");
dump_erl_obj(em.from);
erl_free_compound(em.from);
}
*/
}
else {
break;
}
}
close(fd);
}
}
}
int erlang_init() {
char *host;
struct sockaddr_in sin;
socklen_t slen = sizeof(struct sockaddr_in);
char *ip = NULL;
char *nodename;
struct in_addr addr;
uerl.lock = uwsgi_lock_init("erlang");
if (uerl.name) {
host = strchr(uerl.name, '@');
if (!host) {
if (ei_connect_init(&uerl.cnode, uerl.name, uerl.cookie, 0) < 0) {
uwsgi_log("unable to initialize erlang connection\n");
exit(1);
}
}
else {
nodename = uwsgi_concat2n(uerl.name, host-uerl.name, "",0);
ip = uwsgi_resolve_ip(host+1);
if (ip) {
#ifdef UWSGI_DEBUG
uwsgi_log("ip: %s\n", ip);
#endif
addr.s_addr = inet_addr(ip);
if (ei_connect_xinit(&uerl.cnode, host+1, nodename, uerl.name, &addr, uerl.cookie, 0) < 0) {
uwsgi_log("unable to initialize erlang connection\n");
exit(1);
}
}
else {
if (ei_connect_init(&uerl.cnode, nodename, uerl.cookie, 0) < 0) {
uwsgi_log("unable to initialize erlang connection\n");
exit(1);
}
}
free(nodename);
}
if (ip) {
uerl.fd = bind_to_tcp(ip, uwsgi.listen_queue, NULL);
}
else {
uerl.fd = bind_to_tcp("", uwsgi.listen_queue, NULL);
}
if (uerl.fd < 0) {
exit(1);
}
if (getsockname(uerl.fd, (struct sockaddr *) &sin, &slen)) {
uwsgi_error("getsockname()");
exit(1);
}
if (ei_publish(&uerl.cnode, ntohs(sin.sin_port)) < 0) {
uwsgi_log( "*** unable to subscribe with EPMD ***\n");
exit(1);
}
uwsgi_log("Erlang C-Node %s registered on port %d\n", ei_thisnodename(&uerl.cnode), ntohs(sin.sin_port));
if (register_gateway("uWSGI erlang c-node", erlang_loop, NULL) == NULL) {
uwsgi_log("unable to register the erlang gateway\n");
exit(1);
}
}
return 0;
}
struct uwsgi_plugin erlang_plugin = {
.name = "erlang",
.options = erlang_options,
.init = erlang_init,
};
-24
View File
@@ -1,24 +0,0 @@
#include <ei.h>
struct uwsgi_erlang_process {
char name[0xff];
void (*plugin)(void *, ei_x_buff *);
void *func;
struct uwsgi_erlang_process *next;
};
struct uwsgi_erlang {
ei_cnode cnode;
char *name;
char *cookie;
int fd;
void *lock;
struct uwsgi_erlang_process *uep;
};
-15
View File
@@ -1,15 +0,0 @@
import os
NAME='erlang'
ERLANGPATH = os.environ.get('UWSGICONFIG_ERLANGPATH', 'erl')
includedir = os.popen(ERLANGPATH + " -noshell -noinput -eval \"io:format('~s~n', [code:lib_dir(erl_interface, include)])\" -s erlang halt").read().rstrip()
libpath = os.popen(ERLANGPATH + " -noshell -noinput -eval \"io:format('~s~n', [code:lib_dir(erl_interface, lib)])\" -s erlang halt").read().rstrip()
CFLAGS = [ '-I' + includedir ]
LDFLAGS = [ '-L' + libpath ]
LIBS = ['-lei']
GCC_LIST = ['erlang']
-116
View File
@@ -1,116 +0,0 @@
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
void (*uwsgi_go_helper_post_fork_c)();
void (*uwsgi_go_helper_post_init_c)();
void * (*uwsgi_go_helper_env_new_c)(struct wsgi_request *);
void (*uwsgi_go_helper_env_add_c)(void *, char *, int, char *, int);
void (*uwsgi_go_helper_request_c)(void *, struct wsgi_request *);
int (*uwsgi_go_helper_signal_handler_c)(int, void *);
void (*uwsgi_go_helper_run_core_c)(int);
char *(*uwsgi_go_helper_version_c)();
void uwsgi_go_post_fork() {
uwsgi_go_helper_post_fork_c();
}
void uwsgi_opt_setup_goroutines(char *opt, char *value, void *foobar) {
// set async mode
uwsgi_opt_set_int(opt, value, &uwsgi.async);
// set loop engine
uwsgi.loop = "goroutines";
}
struct uwsgi_option uwsgi_go_options[] = {
{"goroutines", required_argument, 0, "a shortcut setting optimal options for goroutine-based apps, takes the number of goroutines to spawn as argument", uwsgi_opt_setup_goroutines, NULL, UWSGI_OPT_THREADS},
{0, 0, 0, 0, 0, 0, 0},
};
#define uwsgi_go_get_symbol(x) x ## _c = dlsym(RTLD_DEFAULT, #x);\
if (!x ## _c) {\
uwsgi_log("[uwsgi-go] unable to load " #x " function\n"); exit(1);\
}
static int uwsgi_go_init() {
// build the functions table
uwsgi_go_get_symbol(uwsgi_go_helper_post_fork)
uwsgi_go_get_symbol(uwsgi_go_helper_post_init)
uwsgi_go_get_symbol(uwsgi_go_helper_env_new)
uwsgi_go_get_symbol(uwsgi_go_helper_env_add)
uwsgi_go_get_symbol(uwsgi_go_helper_request)
uwsgi_go_get_symbol(uwsgi_go_helper_signal_handler)
uwsgi_go_get_symbol(uwsgi_go_helper_run_core)
uwsgi_go_get_symbol(uwsgi_go_helper_version)
uwsgi_log("Go version \"%s\" initialized\n", uwsgi_go_helper_version_c());
return 0;
}
static int uwsgi_go_request(struct wsgi_request *wsgi_req) {
/* Standard GO request */
if (!wsgi_req->uh->pktsize) {
uwsgi_log("Empty GO request. skip.\n");
return -1;
}
if (uwsgi_parse_vars(wsgi_req)) {
return -1;
}
wsgi_req->async_environ = uwsgi_go_helper_env_new_c(wsgi_req);
int i;
for(i=0;i<wsgi_req->var_cnt;i++) {
uwsgi_go_helper_env_add_c(wsgi_req->async_environ, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len,
wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len);
i++;
}
uwsgi_go_helper_request_c(wsgi_req->async_environ, wsgi_req);
return UWSGI_OK;
}
static void uwsgi_go_after_request(struct wsgi_request *wsgi_req) {
log_request(wsgi_req);
}
static int uwsgi_go_signal_handler(uint8_t signum, void *handler) {
return uwsgi_go_helper_signal_handler_c((int)signum, handler);
}
static void goroutines_loop() {
int i;
for (i = 1; i < uwsgi.async; i++) {
uwsgi_go_helper_run_core_c(i);
}
simple_loop_run_int(0);
}
static void uwsgi_go_on_load() {
uwsgi_register_loop("goroutines", goroutines_loop);
}
static void uwsgi_go_call_init_hook() {
if (uwsgi_go_helper_post_init_c) {
uwsgi_go_helper_post_init_c();
}
}
struct uwsgi_plugin go_plugin = {
.name = "go",
.modifier1 = 11,
.request = uwsgi_go_request,
.after_request = uwsgi_go_after_request,
.preinit_apps = uwsgi_go_call_init_hook,
.post_fork = uwsgi_go_post_fork,
.init = uwsgi_go_init,
.signal_handler = uwsgi_go_signal_handler,
.on_load = uwsgi_go_on_load,
.options = uwsgi_go_options,
};
-420
View File
@@ -1,420 +0,0 @@
/*
uWSGI go integration package
*/
package uwsgi
/*
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
// commodity functions to simulate argc/argv
static char ** uwsgi_go_helper_create_argv(int len) {
return uwsgi_calloc(sizeof(char *) * len);
}
static void uwsgi_go_helper_set_argv(char **argv, int pos, char *item) {
argv[pos] = item;
}
*/
import "C"
import (
"os"
"net/http"
"net/http/cgi"
"unsafe"
"strings"
"strconv"
"io"
"runtime"
)
// this stores the modifier used by the go plugin (default 11)
var uwsgi_modifier1 int = -1;
// the following to objects are used to implement a sort of GC to avoid request environ and
// signal handlers to be garbage collected
var uwsgi_env_gc = make(map[*C.struct_wsgi_request](*map[string]string))
var uwsgi_signals_gc = make([]*func(int), 256)
var uwsgi_default_request_handler func(http.ResponseWriter, *http.Request) = nil
var uwsgi_default_handler http.Handler = nil
var uwsgi_post_fork_hook func() = nil
var uwsgi_post_init_hook func() = nil
/*
uWSGI api functions
*/
// raise a uWSGI signal
func Signal(signum int) {
if C.uwsgi.master_process == 0 {
return
}
C.uwsgi_signal_send(C.uwsgi.signal_socket, C.uint8_t(signum))
}
// set a user lock
func Lock(num int) {
C.uwsgi_user_lock(C.int(num));
}
// unset a user lock
func Unlock(num int) {
C.uwsgi_user_unlock(C.int(num));
}
// add a timer
func AddTimer(signum int, seconds int) bool {
if C.uwsgi.master_process == 0 {
return false
}
if int(C.uwsgi_add_timer(C.uint8_t(signum), C.int(seconds))) == 0 {
return true
}
return false
}
// add a red black timer
func AddRbTimer(signum int, seconds int) bool {
if C.uwsgi.master_process == 0 {
return false
}
if int(C.uwsgi_signal_add_rb_timer(C.uint8_t(signum), C.int(seconds), C.int(0))) == 0 {
return true
}
return false
}
// check if a signal is registered
func SignalRegistered(signum int) bool {
if C.uwsgi.master_process == 0 {
return false
}
if int(C.uwsgi_signal_registered(C.uint8_t(signum))) == 0 {
return false
}
return true
}
// register a signal
func RegisterSignal(signum int, who string, handler func(int)) bool {
if C.uwsgi.master_process == 0 {
return false
}
if uwsgi_modifier1 == -1 {
c_go := C.CString("go")
defer C.free(unsafe.Pointer(c_go))
uwsgi_modifier1 = int(C.uwsgi_plugin_modifier1(c_go))
if uwsgi_modifier1 == -1 {
return false
}
}
c_who := C.CString(who)
defer C.free(unsafe.Pointer(c_who))
if int(C.uwsgi_register_signal(C.uint8_t(signum), c_who, unsafe.Pointer(&handler), C.uint8_t(uwsgi_modifier1))) == 0 {
uwsgi_signals_gc[signum] = &handler
return true
}
return false
}
func Alarm(alarm string, msg string) {
a := C.CString(alarm)
defer C.free(unsafe.Pointer(a))
m := C.CString(msg)
defer C.free(unsafe.Pointer(m))
ml := len(msg)
C.uwsgi_alarm_trigger(a, m, C.size_t(ml))
}
// get an item from the cache
func CacheGet(key string, cache string) []byte {
k := C.CString(key)
defer C.free(unsafe.Pointer(k))
kl := len(key)
var vl C.uint64_t = C.uint64_t(0)
c := (*C.char)(nil)
if len(cache) > 0 {
c = C.CString(cache)
defer C.free(unsafe.Pointer(c))
}
var p []byte
c_value := C.uwsgi_cache_magic_get(k, C.uint16_t(kl), &vl, (*C.uint64_t)(nil), c)
if c_value != nil {
p = C.GoBytes((unsafe.Pointer)(c_value), C.int(vl))
} else {
p = nil
}
return p
}
// remove an intem from the cache
func CacheDel(key string, cache string) bool {
k := C.CString(key)
defer C.free(unsafe.Pointer(k))
kl := len(key)
c := (*C.char)(nil)
if len(cache) > 0 {
c = C.CString(cache)
defer C.free(unsafe.Pointer(c))
}
if int(C.uwsgi_cache_magic_del(k, C.uint16_t(kl), c)) < 0 {
return false;
}
return true
}
// check if an item exists in the cache
func CacheExists(key string, cache string) bool {
k := C.CString(key)
defer C.free(unsafe.Pointer(k))
kl := len(key)
c := (*C.char)(nil)
if len(cache) > 0 {
c = C.CString(cache)
defer C.free(unsafe.Pointer(c))
}
if int(C.uwsgi_cache_magic_exists(k, C.uint16_t(kl), c)) == 0 {
return false;
}
return true
}
// put an item in the cache
func CacheSetFlags(key string, p []byte, expires uint64, flags int, cache string) bool {
k := C.CString(key)
defer C.free(unsafe.Pointer(k))
kl := len(key)
v := unsafe.Pointer(&p[0])
vl := len(p)
c := (*C.char)(nil)
if len(cache) > 0 {
c = C.CString(cache)
defer C.free(unsafe.Pointer(c))
}
if int(C.uwsgi_cache_magic_set(k, C.uint16_t(kl), (*C.char)(v), C.uint64_t(vl), C.uint64_t(expires), C.uint64_t(flags), c)) < 0 {
return false;
}
return true
}
func CacheSet(key string, p []byte, expires uint64, cache string) bool {
return CacheSetFlags(key, p, expires, 0, cache);
}
func CacheUpdate(key string, p []byte, expires uint64, cache string) bool {
return CacheSetFlags(key, p, expires, 2, cache);
}
// get the current worker id
func WorkerId() int {
return int(C.uwsgi.mywid)
}
// get the current mule id
func MuleId() int {
return int(C.uwsgi.muleid)
}
// get the current logsize (if available)
func LogSize() int64 {
return int64(C.uwsgi.shared.logsize)
}
func PostFork(hook func()) {
uwsgi_post_fork_hook = hook
}
func PostInit(hook func()) {
uwsgi_post_init_hook = hook
}
func RequestHandler(hook func(http.ResponseWriter, *http.Request)) {
uwsgi_default_request_handler = hook
}
func Handler(handler http.Handler) {
uwsgi_default_handler = handler
}
/*
C -> go and go -> C bridges
*/
//export uwsgi_go_helper_post_fork
func uwsgi_go_helper_post_fork() {
if uwsgi_post_fork_hook != nil {
uwsgi_post_fork_hook()
}
}
//export uwsgi_go_helper_post_init
func uwsgi_go_helper_post_init() {
if uwsgi_post_init_hook != nil {
uwsgi_post_init_hook()
}
}
//export uwsgi_go_helper_env_new
func uwsgi_go_helper_env_new(wsgi_req *C.struct_wsgi_request) *map[string]string {
var env map[string]string
env = make(map[string]string)
// track env to avoid it being garbage collected...
uwsgi_env_gc[wsgi_req] = &env
return &env
}
//export uwsgi_go_helper_env_add
func uwsgi_go_helper_env_add(env *map[string]string, k *C.char, kl C.int, v *C.char, vl C.int) {
var mk string = C.GoStringN(k, kl)
var mv string = C.GoStringN(v, vl)
(*env)[mk] = mv
}
/*
http.* implementations
*/
type ResponseWriter struct {
r *http.Request
wsgi_req *C.struct_wsgi_request
headers http.Header
wroteHeader bool
}
func (w *ResponseWriter) Write(p []byte) (n int, err error) {
if !w.wroteHeader {
w.WriteHeader(http.StatusOK)
}
m := len(p)
C.uwsgi_response_write_body_do(w.wsgi_req, (*C.char)(unsafe.Pointer(&p[0])), C.size_t(m))
return m+n, err
}
// TODO fix it !!!
func (w *ResponseWriter) WriteHeader(status int) {
codestring := http.StatusText(status)
var tmp_buf string = strconv.Itoa(status) + " " + codestring
c_status := C.CString(tmp_buf)
defer C.free(unsafe.Pointer(c_status))
C.uwsgi_response_prepare_headers(w.wsgi_req, c_status, C.uint16_t(len(tmp_buf)) )
if w.headers.Get("Content-Type") == "" {
w.headers.Set("Content-Type", "text/html; charset=utf-8")
}
for k := range w.headers {
hk_c := C.CString(k)
defer C.free(unsafe.Pointer(hk_c))
for _, v := range w.headers[k] {
v = strings.NewReplacer("\n", " ", "\r", " ").Replace(v)
v = strings.TrimSpace(v)
hv_c := C.CString(v)
defer C.free(unsafe.Pointer(hv_c))
C.uwsgi_response_add_header(w.wsgi_req, hk_c, C.uint16_t(len(k)), hv_c, C.uint16_t(len(v)))
}
}
w.wroteHeader = true
}
func (w *ResponseWriter) Header() http.Header {
return w.headers
}
type BodyReader struct {
wsgi_req *C.struct_wsgi_request
}
// there is no close in request body
func (br *BodyReader) Close() error {
return nil
}
func (br *BodyReader) Read(p []byte) (n int, err error) {
m := len(p)
var rlen C.ssize_t = C.ssize_t(0)
c_body := C.uwsgi_request_body_read(br.wsgi_req, C.ssize_t(m), &rlen)
if (c_body == C.uwsgi.empty) {
err = io.EOF;
return 0, err
} else if (c_body != nil) {
C.memcpy(unsafe.Pointer(&p[0]), unsafe.Pointer(c_body), C.size_t(rlen))
return int(rlen), err
}
err = io.ErrUnexpectedEOF
rlen = 0
return int(rlen), err
}
//export uwsgi_go_helper_request
func uwsgi_go_helper_request(env *map[string]string, wsgi_req *C.struct_wsgi_request) {
httpReq, err := cgi.RequestFromMap(*env)
if err != nil {
} else {
httpReq.Body = &BodyReader{wsgi_req}
w := ResponseWriter{httpReq, wsgi_req,http.Header{},false}
if uwsgi_default_request_handler != nil {
uwsgi_default_request_handler(&w, httpReq)
} else if uwsgi_default_handler != nil {
uwsgi_default_handler.ServeHTTP(&w, httpReq)
} else {
http.DefaultServeMux.ServeHTTP(&w, httpReq)
}
}
}
//export uwsgi_go_helper_version
func uwsgi_go_helper_version() *C.char {
return C.CString(runtime.Version())
}
//export uwsgi_go_helper_signal_handler
func uwsgi_go_helper_signal_handler(signum int, handler *func(int)) int {
(*handler)(signum)
return 0;
}
//export uwsgi_go_helper_run_core
func uwsgi_go_helper_run_core(core_id int) {
go C.simple_loop_run_int(C.int(core_id))
}
/*
the main function, running the uWSGI server via libuwsgi.so
*/
func Run() {
argc := len(os.Args) + 1
argv := C.uwsgi_go_helper_create_argv(C.int(argc))
for i, s := range os.Args {
C.uwsgi_go_helper_set_argv(argv, C.int(i), C.CString(s))
}
C.uwsgi_init(C.int(argc-1), argv, nil)
}
-28
View File
@@ -1,28 +0,0 @@
import os
NAME='go'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['go_plugin']
def post_build(config):
os.environ['GOPATH'] = 'plugins/go'
cflags = ['-I'+os.getcwd()]
for c in config.cflags:
if not c.startswith('-DUWSGI_BUILD_DATE') and not c.startswith('-DUWSGI_CFLAGS'):
cflags.append(c)
cflags.append('-Wno-implicit-function-declaration')
cflags.append('-Wno-implicit-int')
cflags.append('-Wno-unused-function')
cflags.append('-Wno-unused-variable')
os.environ['CGO_CFLAGS'] = ' '.join(cflags).replace('\\"', '')
base = os.path.dirname(config.get('bin_name'))
if not base:
base = "."
os.environ['CGO_LDFLAGS'] = '-L' + base + ' -L'+os.getcwd() + ' -luwsgi'
if os.system("go install uwsgi") != 0:
os._exit(1)
print("*** uwsgi go module available in $GOPATH %s/plugins/go ***" % os.getcwd())
-543
View File
@@ -1,543 +0,0 @@
#include "../erlang/erlang.h"
#include "../python/uwsgi_python.h"
extern struct uwsgi_server uwsgi;
extern struct uwsgi_erlang uerl;
extern struct uwsgi_python up;
ei_cnode *pyerl_cnode;
PyObject *pyerl_close(PyObject * self, PyObject * args) {
int fd;
if (!PyArg_ParseTuple(args, "i:erlang_close", &fd)) {
return NULL;
}
if (fd >= 0)
close(fd);
Py_INCREF(Py_None);
return Py_None;
}
PyObject *pyerl_connect(PyObject * self, PyObject * args) {
char *node = NULL;
int fd;
if (!PyArg_ParseTuple(args, "s:erlang_connect", &node)) {
return NULL;
}
fd = ei_connect(pyerl_cnode, node);
if (fd < 0) {
return PyErr_Format(PyExc_ValueError, "Unable to connect to erlang node");
}
return PyInt_FromLong(fd);
}
int py_to_erl(PyObject *, ei_x_buff*);
PyObject *erl_to_py(ei_x_buff* x) {
int etype, esize, arity;
long long num;
double fnum;
char *atom, *binary;
long bin_size;
PyObject *pobj;
PyObject *zero;
erlang_pid epid;
int i;
ei_get_type(x->buff, &x->index, &etype, &esize);
switch(etype) {
case ERL_SMALL_INTEGER_EXT:
case ERL_INTEGER_EXT:
case ERL_SMALL_BIG_EXT:
case ERL_LARGE_BIG_EXT:
ei_decode_longlong(x->buff, &x->index, &num);
return PyLong_FromLong(num);
case ERL_FLOAT_EXT:
ei_decode_double(x->buff, &x->index, &fnum);
return PyFloat_FromDouble(fnum);
case ERL_STRING_EXT:
atom = uwsgi_malloc(esize+1);
ei_decode_string(x->buff, &x->index, atom);
pobj = PyString_FromString(atom);
free(atom);
Py_INCREF(pobj);
return pobj;
case ERL_ATOM_EXT:
atom = uwsgi_malloc(esize+1);
ei_decode_atom(x->buff, &x->index, atom);
#ifndef PyUnicode_FromString
zero = PyString_FromString(atom);
pobj = PyUnicode_FromObject(zero);
Py_DECREF(zero);
#else
pobj = PyUnicode_FromString(atom);
#endif
free(atom);
Py_INCREF(pobj);
return pobj;
case ERL_SMALL_TUPLE_EXT:
case ERL_LARGE_TUPLE_EXT:
ei_decode_tuple_header(x->buff, &x->index, &arity);
pobj = PyTuple_New(arity);
for(i=0;i<arity;i++) {
zero = erl_to_py(x);
PyTuple_SetItem(pobj, i, zero);
Py_DECREF(zero);
}
Py_INCREF(pobj);
return pobj;
case ERL_LIST_EXT:
case ERL_NIL_EXT:
ei_decode_list_header(x->buff, &x->index, &arity);
if (!arity) {
Py_INCREF(Py_None);
return Py_None;
}
pobj = PyList_New(0);
for(i=0;i<arity+1;i++) {
zero = erl_to_py(x);
PyList_Append(pobj, zero);
Py_DECREF(zero);
}
Py_INCREF(pobj);
return pobj;
case ERL_BINARY_EXT:
binary = uwsgi_malloc(esize);
ei_decode_binary(x->buff, &x->index, binary, &bin_size);
pobj = PyString_FromStringAndSize(binary, bin_size);
free(binary);
Py_INCREF(pobj);
return pobj;
case ERL_PID_EXT:
ei_decode_pid(x->buff, &x->index, &epid);
pobj = PyTuple_New(3);
PyTuple_SetItem(pobj, 0, PyInt_FromLong(epid.num));
PyTuple_SetItem(pobj, 1, PyInt_FromLong(epid.serial));
PyTuple_SetItem(pobj, 2, PyInt_FromLong(epid.creation));
Py_INCREF(pobj);
return pobj;
default:
ei_skip_term(x->buff, &x->index);
Py_INCREF(Py_None);
return Py_None;
}
Py_INCREF(Py_None);
return Py_None;
}
PyObject *pyerl_lock(PyObject * self, PyObject * args) {
uwsgi_lock(uerl.lock);
Py_INCREF(Py_None);
return Py_None;
}
PyObject *pyerl_unlock(PyObject * self, PyObject * args) {
uwsgi_unlock(uerl.lock);
Py_INCREF(Py_None);
return Py_None;
}
PyObject *pyerl_send(PyObject * self, PyObject * args) {
PyObject *node;
PyObject *reg;
char *cnode;
PyObject *pobj;
ei_x_buff x;
int fd;
int close_fd = 0;
erlang_pid epid;
if (!PyArg_ParseTuple(args, "OOO:erlang_send", &node, &reg, &pobj)) {
return NULL;
}
if (PyString_Check(node)) {
cnode = PyString_AsString(node);
fd = ei_connect(pyerl_cnode, cnode);
close_fd = 1;
}
else if (PyInt_Check(node)) {
fd = PyInt_AsLong(node);
}
else {
return PyErr_Format(PyExc_ValueError, "invalid erlang node/descriptor");
}
if (fd < 0) {
return PyErr_Format(PyExc_ValueError, "Unable to connect to erlang node");
}
ei_x_new_with_version(&x);
if (py_to_erl(pobj, &x) < 0) {
ei_x_free(&x);
if (close_fd) close(fd);
return PyErr_Format(PyExc_ValueError, "Unsupported object in Python->Erlang translation");
}
if (PyTuple_Check(reg) && PyTuple_Size(reg) == 3) {
epid.num = PyInt_AsLong( PyTuple_GetItem(reg, 0) );
epid.serial = PyInt_AsLong( PyTuple_GetItem(reg, 1) );
epid.creation = PyInt_AsLong( PyTuple_GetItem(reg, 2) );
ei_send(fd, &epid, x.buff, x.index);
}
else if (PyString_Check(reg)) {
ei_reg_send(pyerl_cnode, fd, PyString_AsString(reg), x.buff, x.index);
}
else {
ei_x_free(&x);
if (close_fd) close(fd);
return PyErr_Format(PyExc_ValueError, "Invalid Erlang process");
}
return PyInt_FromLong(fd);
}
PyObject *pyerl_sr(PyObject * self, PyObject * args) {
PyObject *node;
PyObject *reg;
char *cnode;
PyObject *pobj;
ei_x_buff x;
int fd;
int close_fd = 0;
erlang_msg em;
erlang_pid epid;
int eversion;
PyObject *res;
if (!PyArg_ParseTuple(args, "OOO:erlang_sr", &node, &reg, &pobj)) {
return NULL;
}
if (PyString_Check(node)) {
cnode = PyString_AsString(node);
fd = ei_connect(pyerl_cnode, cnode);
close_fd = 1;
}
else if (PyInt_Check(node)) {
fd = PyInt_AsLong(node);
}
else {
return PyErr_Format(PyExc_ValueError, "invalid erlang node/descriptor");
}
if (fd < 0) {
return PyErr_Format(PyExc_ValueError, "Unable to connect to erlang node");
}
ei_x_new_with_version(&x);
if (py_to_erl(pobj, &x) < 0) {
ei_x_free(&x);
if (close_fd) close(fd);
return PyErr_Format(PyExc_ValueError, "Unsupported object in Python->Erlang translation");
}
if (PyTuple_Check(reg) && PyTuple_Size(reg) == 3) {
epid.num = PyInt_AsLong( PyTuple_GetItem(reg, 0) );
epid.serial = PyInt_AsLong( PyTuple_GetItem(reg, 1) );
epid.creation = PyInt_AsLong( PyTuple_GetItem(reg, 2) );
ei_send(fd, &epid, x.buff, x.index);
}
else if (PyString_Check(reg)) {
ei_reg_send(pyerl_cnode, fd, PyString_AsString(reg), x.buff, x.index);
}
else {
ei_x_free(&x);
if (close_fd) close(fd);
return PyErr_Format(PyExc_ValueError, "Invalid Erlang process");
}
recv:
ei_x_free(&x);
ei_x_new(&x);
if (ei_xreceive_msg(fd, &em, &x) == ERL_MSG) {
if (em.msgtype == ERL_TICK) {
goto recv;
}
x.index = 0;
ei_decode_version(x.buff, &x.index, &eversion);
res = erl_to_py(&x);
ei_x_free(&x);
if (close_fd) close(fd);
return res;
}
ei_x_free(&x);
if (close_fd) close(fd);
Py_INCREF(Py_None);
return Py_None;
}
void pyerl_call_registered(void *func, ei_x_buff *x) {
PyObject *pyargs = PyTuple_New(1);
PyTuple_SetItem(pyargs, 0, erl_to_py(x));
python_call((PyObject *) func, pyargs, 0, NULL);
}
PyObject *pyerl_register_process(PyObject * self, PyObject * args) {
char *name;
PyObject *callable;
if (!PyArg_ParseTuple(args, "sO:erlang_register_process", &name, &callable)) {
return NULL;
}
if (strlen(name) > 0xff-1)
return PyErr_Format(PyExc_ValueError, "Invalid erlang process name");
struct uwsgi_erlang_process *uep = uerl.uep, *old_uep;
if (!uep) {
uerl.uep = uwsgi_malloc(sizeof(struct uwsgi_erlang_process));
uep = uerl.uep;
}
else {
while(uep) {
old_uep = uep;
uep = uep->next;
}
uep = uwsgi_malloc(sizeof(struct uwsgi_erlang_process));
old_uep->next = uep;
}
strcpy(uep->name, name);
uep->plugin = pyerl_call_registered;
uep->func = callable;
uep->next = NULL;
Py_INCREF(Py_None);
return Py_None;
}
PyObject *pyerl_recv(PyObject * self, PyObject * args) {
ei_x_buff x;
erlang_msg em;
PyObject *res;
int eversion;
int fd;
if (!PyArg_ParseTuple(args, "i:erlang_recv", &fd)) {
return NULL;
}
recv:
ei_x_new(&x);
if (ei_xreceive_msg(fd, &em, &x) == ERL_MSG) {
if (em.msgtype == ERL_TICK) {
ei_x_free(&x);
goto recv;
}
x.index = 0;
ei_decode_version(x.buff, &x.index, &eversion);
res = erl_to_py(&x);
ei_x_free(&x);
return res;
}
ei_x_free(&x);
Py_INCREF(Py_None);
return Py_None;
}
PyObject *pyerl_rpc(PyObject * self, PyObject * args) {
PyObject *node;
char *mod, *fun;
char *cnode;
PyObject *pobj;
ei_x_buff x;
ei_x_buff xr;
int fd;
int close_fd = 0;
int eversion;
PyObject *res;
if (!PyArg_ParseTuple(args, "OssO:erlang_rpc", &node, &mod, &fun, &pobj)) {
return NULL;
}
if (PyString_Check(node)) {
cnode = PyString_AsString(node);
fd = ei_connect(pyerl_cnode, cnode);
close_fd = 1;
}
else if (PyInt_Check(node)) {
fd = PyInt_AsLong(node);
}
else {
return PyErr_Format(PyExc_ValueError, "Invalid erlang node/descriptor");
}
if (fd < 0) {
return PyErr_Format(PyExc_ValueError, "Unable to connect to erlang node");
}
ei_x_new(&x);
if (py_to_erl(pobj, &x) < 0) {
ei_x_free(&x);
if (close_fd) close(fd);
return PyErr_Format(PyExc_ValueError, "Unsupported object in Python->Erlang translation");
}
ei_x_new(&xr);
if (ei_rpc(pyerl_cnode, fd, mod, fun, x.buff, x.index, &xr) < 0) {
if (close_fd) close(fd);
ei_x_free(&x);
ei_x_free(&xr);
return PyErr_Format(PyExc_ValueError, "Error in Erlang rpc");
}
xr.index = 0;
ei_decode_version(xr.buff, &xr.index, &eversion);
res = erl_to_py(&xr);
if (close_fd) close(fd);
ei_x_free(&x);
ei_x_free(&xr);
return res;
}
static PyMethodDef uwsgi_pyerl_methods[] = {
{"erlang_connect", pyerl_connect, METH_VARARGS, ""},
{"erlang_close", pyerl_close, METH_VARARGS, ""},
{"erlang_send_message", pyerl_send, METH_VARARGS, ""},
{"erlang_send", pyerl_send, METH_VARARGS, ""},
{"erlang_recv_message", pyerl_recv, METH_VARARGS, ""},
{"erlang_recv", pyerl_recv, METH_VARARGS, ""},
{"erlang_sr", pyerl_sr, METH_VARARGS, ""},
{"erlang_rpc", pyerl_rpc, METH_VARARGS, ""},
{"erlang_lock", pyerl_lock, METH_VARARGS, ""},
{"erlang_unlock", pyerl_unlock, METH_VARARGS, ""},
{"erlang_register_process", pyerl_register_process, METH_VARARGS, ""},
{NULL, NULL},
};
void py_erl_init_functions() {
PyMethodDef *uwsgi_function;
PyDict_SetItemString(up.embedded_dict, "erlang_node", PyString_FromString(ei_thisnodename(pyerl_cnode)));
for (uwsgi_function = uwsgi_pyerl_methods; uwsgi_function->ml_name != NULL; uwsgi_function++) {
PyObject *func = PyCFunction_New(uwsgi_function, NULL);
PyDict_SetItemString(up.embedded_dict, uwsgi_function->ml_name, func);
Py_DECREF(func);
}
}
int py_to_erl(PyObject *pobj, ei_x_buff *x) {
int i;
PyObject *pobj2;
if (pobj == NULL || pobj == Py_None) {
ei_x_encode_empty_list(x);
}
else if (PyString_Check(pobj)) {
ei_x_encode_binary(x, PyString_AsString(pobj), PyString_Size(pobj));
}
else if (PyUnicode_Check(pobj)) {
ei_x_encode_atom(x, PyString_AsString(pobj));
}
else if (PyInt_Check(pobj)) {
ei_x_encode_long(x, PyInt_AsLong(pobj));
}
else if (PyList_Check(pobj)) {
if (PyList_Size(pobj) > 0) {
ei_x_encode_list_header(x, PyList_Size(pobj));
for (i = 0; i < PyList_Size(pobj); i++) {
pobj2 = PyList_GetItem(pobj, i);
if (py_to_erl(pobj2, x) < 0) return -1;
}
}
ei_x_encode_empty_list(x);
}
else if (PyTuple_Check(pobj)) {
ei_x_encode_tuple_header(x, PyTuple_Size(pobj));
for (i = 0; i < PyTuple_Size(pobj); i++) {
pobj2 = PyTuple_GetItem(pobj, i);
if (py_to_erl(pobj2, x) < 0) return -1;
}
}
else {
return -1;
}
return x->index;
}
void pyerl_init() {
up.extension = py_erl_init_functions;
if (!uerl.name) {
pyerl_cnode = uwsgi_malloc(sizeof(ei_cnode));
memset(pyerl_cnode, 0, sizeof(ei_cnode));
if (ei_connect_init(pyerl_cnode, "uwsgi", NULL, 0) < 0) {
uwsgi_log("unable to initialize erlang connection\n");
exit(1);
}
uwsgi_log("Erlang C-Node name: %s\n",ei_thisnodename(pyerl_cnode));
}
else {
pyerl_cnode = &uerl.cnode;
}
uwsgi_log("enabled Python<->Erlang bridge\n");
}
struct uwsgi_plugin pyerl_plugin = {
.post_init = pyerl_init,
};
-16
View File
@@ -1,16 +0,0 @@
import os
from distutils import sysconfig
NAME='pyerl'
ERLANGPATH = os.environ.get('UWSGICONFIG_ERLANGPATH', 'erl')
includedir = os.popen(ERLANGPATH + " -noshell -noinput -eval \"io:format('~s~n', [code:lib_dir(erl_interface, include)])\" -s erlang halt").read().rstrip()
libpath = os.popen(ERLANGPATH + " -noshell -noinput -eval \"io:format('~s~n', [code:lib_dir(erl_interface, lib)])\" -s erlang halt").read().rstrip()
CFLAGS = [ '-I' + includedir, '-I' + sysconfig.get_python_inc(), '-I' + sysconfig.get_python_inc(plat_specific=True)]
LDFLAGS = [ '-L' + libpath ]
LIBS = ['-lei']
GCC_LIST = ['pyerl']
+1 -1
View File
@@ -1,3 +1,3 @@
[uwsgi]
main_plugin = python,gevent,psgi,lua,php,rack,jvm,jwsgi,ring,mono,transformation_toupper,coroae,v8,cgi,xslt,webdav,ssi,ldap,gccgo,rados,pypy
main_plugin = python,gevent,psgi,lua,php,rack,jvm,jwsgi,ring,mono,transformation_toupper,coroae,v8,cgi,xslt,webdav,ssi,ldap,gccgo,rados,pypy,zabbix,curl_cron,tornado,tuntap,pty,mongrel2,alarm_curl,router_radius,airbrake
inherit = base
+3
View File
@@ -0,0 +1,3 @@
[uwsgi]
main_plugin = python,asyncio,greenlet
inherit = base
-2
View File
@@ -7,8 +7,6 @@ pcre = auto
routing = auto
debug = false
unbit = false
xml_implementation = libxml2
yaml_implementation = auto
malloc_implementation = libc
extras =
plugins =
-1
View File
@@ -1,4 +1,3 @@
[uwsgi]
main_plugin = python,gevent
inherit = base
debug = false
-2
View File
@@ -7,8 +7,6 @@ pcre = false
routing = false
debug = false
unbit = false
xml_implementation = none
yaml_implementation = none
malloc_implementation = libc
extras =
plugins =
+2 -4
View File
@@ -1,14 +1,12 @@
[uwsgi]
xml = true
yaml = true
xml = libxml2
yaml = libyaml
json = true
ssl = true
pcre = true
routing = true
debug = false
unbit = false
xml_implementation = libxml2
yaml_implementation = libyaml
malloc_implementation = libc
extras =
plugins =
+2 -4
View File
@@ -1,14 +1,12 @@
[uwsgi]
xml = true
yaml = true
xml = expat
yaml = embedded
json = false
ssl = true
pcre = true
routing = true
debug = false
unbit = true
xml_implementation = expat
yaml_implementation = auto
malloc_implementation = libc
extras =
plugins =
+29
View File
@@ -0,0 +1,29 @@
[uwsgi]
xml = expat
yaml = embedded
json = true
ssl = true
pcre = true
routing = true
debug = false
unbit = false
malloc_implementation = libc
extras =
plugins =
bin_name = uwsgi
append_version =
plugin_dir = /opt/unbit/uwsgi/plugins
embedded_plugins =
as_shared_library = false
locking = auto
event = auto
timer = auto
filemonitor = auto
blacklist =
whitelist =
embed_files =
embed_config =
Binary file not shown.
+26 -27
View File
@@ -18,18 +18,18 @@ void uwsgi_alarm_init_log(struct uwsgi_alarm_instance *uai) {
void uwsgi_alarm_func_log(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
if (msg[len-1] != '\n') {
if (uai->arg && strlen(uai->arg) > 0) {
uwsgi_log_alarm("] %s %.*s\n", uai->arg, len, msg);
uwsgi_log_verbose("ALARM: %s %.*s\n", uai->arg, len, msg);
}
else {
uwsgi_log_alarm("] %.*s\n", len, msg);
uwsgi_log_verbose("ALARM: %.*s\n", len, msg);
}
}
else {
if (uai->arg && strlen(uai->arg) > 0) {
uwsgi_log_alarm("] %s %.*s", uai->arg, len, msg);
uwsgi_log_verbose("ALARM: %s %.*s", uai->arg, len, msg);
}
else {
uwsgi_log_alarm("] %.*s", len, msg);
uwsgi_log_verbose("ALARM: %.*s", len, msg);
}
}
}
@@ -363,6 +363,19 @@ void uwsgi_alarm_thread_start() {
}
}
void uwsgi_alarm_trigger_uai(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
struct iovec iov[2];
iov[0].iov_base = &uai;
iov[0].iov_len = sizeof(long);
iov[1].iov_base = msg;
iov[1].iov_len = len;
// now send the message to the alarm thread
if (writev(uwsgi.alarm_thread->pipe[0], iov, 2) != (ssize_t) (len+sizeof(long))) {
uwsgi_error("[uwsgi-alarm-error] uwsgi_alarm_trigger()/writev()");
}
}
#ifdef UWSGI_PCRE
// check if a log should raise an alarm
void uwsgi_alarm_log_check(char *msg, size_t len) {
@@ -372,7 +385,14 @@ void uwsgi_alarm_log_check(char *msg, size_t len) {
while (ual) {
if (uwsgi_regexp_match(ual->pattern, ual->pattern_extra, msg, len) >= 0) {
if (!ual->negate) {
uwsgi_alarm_log_run(ual, msg, len);
struct uwsgi_alarm_ll *uall = ual->alarms;
while (uall) {
if (uwsgi.alarm_cheap)
uwsgi_alarm_trigger_uai(uall->alarm, msg, len);
else
uwsgi_alarm_run(uall->alarm, msg, len);
uall = uall->next;
}
}
else {
break;
@@ -397,18 +417,6 @@ void uwsgi_alarm_run(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
uai->last_msg_size = len;
}
#ifdef UWSGI_PCRE
// call the alarms mapped to a log line
void uwsgi_alarm_log_run(struct uwsgi_alarm_log *ual, char *msg, size_t len) {
struct uwsgi_alarm_ll *uall = ual->alarms;
while (uall) {
uwsgi_alarm_run(uall->alarm, msg, len);
uall = uall->next;
}
}
#endif
// this is the api function workers,mules and whatever you want can call from code
void uwsgi_alarm_trigger(char *alarm_instance_name, char *msg, size_t len) {
if (!uwsgi.alarm_thread) return;
@@ -416,16 +424,7 @@ void uwsgi_alarm_trigger(char *alarm_instance_name, char *msg, size_t len) {
struct uwsgi_alarm_instance *uai = uwsgi_alarm_get_instance(alarm_instance_name);
if (!uai) return;
struct iovec iov[2];
iov[0].iov_base = &uai;
iov[0].iov_len = sizeof(long);
iov[1].iov_base = msg;
iov[1].iov_len = len;
// now send the message to the alarm thread
if (writev(uwsgi.alarm_thread->pipe[0], iov, 2) != (ssize_t) (len+sizeof(long))) {
uwsgi_error("[uwsgi-alarm-error] uwsgi_alarm_trigger()/writev()");
}
uwsgi_alarm_trigger_uai(uai, msg, len);
}
struct uwsgi_alarm_fd *uwsgi_add_alarm_fd(int fd, char *alarm, size_t buf_len, char *msg, size_t msg_len) {
+23 -3
View File
@@ -360,7 +360,8 @@ void async_schedule_to_req_green(void) {
}
#endif
for(;;) {
if (uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req) <= UWSGI_OK) {
wsgi_req->async_status = uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req);
if (wsgi_req->async_status <= UWSGI_OK) {
break;
}
wsgi_req->switches++;
@@ -368,7 +369,8 @@ void async_schedule_to_req_green(void) {
uwsgi.schedule_fix(wsgi_req);
}
// switch after each yield
uwsgi.schedule_to_main(wsgi_req);
if (uwsgi.schedule_to_main)
uwsgi.schedule_to_main(wsgi_req);
}
#ifdef UWSGI_ROUTING
@@ -386,6 +388,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) {
@@ -413,6 +432,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);
@@ -532,7 +552,7 @@ void async_loop() {
continue;
}
// re-add timer
async_add_timeout(uwsgi.wsgi_req, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
async_add_timeout(uwsgi.wsgi_req, uwsgi.socket_timeout);
continue;
}
+16 -7
View File
@@ -64,7 +64,7 @@ int uwsgi_buffer_insert_chunked(struct uwsgi_buffer *ub, size_t pos, size_t len)
// 0xFFFFFFFFFFFFFFFF\r\n\0
char chunked[19];
int ret = snprintf(chunked, 19, "%X\r\n", (unsigned int) len);
if (ret <= 0 || ret > 19) {
if (ret <= 0 || ret >= 19) {
return -1;
}
return uwsgi_buffer_insert(ub, pos, chunked, ret);
@@ -74,7 +74,7 @@ int uwsgi_buffer_append_chunked(struct uwsgi_buffer *ub, size_t len) {
// 0xFFFFFFFFFFFFFFFF\r\n\0
char chunked[19];
int ret = snprintf(chunked, 19, "%X\r\n", (unsigned int) len);
if (ret <= 0 || ret > 19) {
if (ret <= 0 || ret >= 19) {
return -1;
}
return uwsgi_buffer_append(ub, chunked, ret);
@@ -128,7 +128,16 @@ int uwsgi_buffer_append_json(struct uwsgi_buffer *ub, char *buf, size_t len) {
// need to escape \ and "
size_t i;
for(i=0;i<len;i++) {
if (buf[i] == '"') {
if (buf[i] == '\t') {
if (uwsgi_buffer_append(ub, "\\t", 2)) return -1;
}
else if (buf[i] == '\n') {
if (uwsgi_buffer_append(ub, "\\n", 2)) return -1;
}
else if (buf[i] == '\r') {
if (uwsgi_buffer_append(ub, "\\r", 2)) return -1;
}
else if (buf[i] == '"') {
if (uwsgi_buffer_append(ub, "\\\"", 2)) return -1;
}
else if (buf[i] == '\\') {
@@ -245,7 +254,7 @@ int uwsgi_buffer_append_ipv4(struct uwsgi_buffer *ub, void *addr) {
int uwsgi_buffer_num64(struct uwsgi_buffer *ub, int64_t num) {
char buf[sizeof(UMAX64_STR)+1];
int ret = snprintf(buf, sizeof(UMAX64_STR)+1, "%lld", (long long) num);
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
if (ret <= 0 || ret >= (int) (sizeof(UMAX64_STR)+1)) {
return -1;
}
return uwsgi_buffer_append(ub, buf, ret);
@@ -268,7 +277,7 @@ int uwsgi_buffer_append_keyval32(struct uwsgi_buffer *ub, char *key, uint32_t ke
int uwsgi_buffer_append_keynum(struct uwsgi_buffer *ub, char *key, uint16_t keylen, int64_t num) {
char buf[sizeof(UMAX64_STR)+1];
int ret = snprintf(buf, (sizeof(UMAX64_STR)+1), "%lld", (long long) num);
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
if (ret <= 0 || ret >= (int) (sizeof(UMAX64_STR)+1)) {
return -1;
}
if (uwsgi_buffer_u16le(ub, keylen)) return -1;
@@ -280,7 +289,7 @@ int uwsgi_buffer_append_keynum(struct uwsgi_buffer *ub, char *key, uint16_t keyl
int uwsgi_buffer_append_valnum(struct uwsgi_buffer *ub, int64_t num) {
char buf[sizeof(UMAX64_STR)+1];
int ret = snprintf(buf, (sizeof(UMAX64_STR)+1), "%lld", (long long) num);
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
if (ret <= 0 || ret >= (int) (sizeof(UMAX64_STR)+1)) {
return -1;
}
if (uwsgi_buffer_u16le(ub, ret)) return -1;
@@ -340,7 +349,7 @@ int uwsgi_buffer_send(struct uwsgi_buffer *ub, int fd) {
char *ptr = ub->buf;
while (remains > 0) {
int ret = uwsgi_waitfd_write(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
int ret = uwsgi_waitfd_write(fd, uwsgi.socket_timeout);
if (ret > 0) {
ssize_t len = write(fd, ptr, remains);
if (len > 0) {
+344 -142
View File
@@ -24,6 +24,49 @@ extern struct uwsgi_server uwsgi;
*/
static void cache_full(struct uwsgi_cache *uc) {
uint64_t i;
int force_clear = 0;
if (!uc->ignore_full) {
if (uc->purge_lru)
uwsgi_log("LRU item will be purged from cache \"%s\"\n", uc->name);
else
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
}
uc->full++;
if (uc->purge_lru && uc->lru_head)
uwsgi_cache_del2(uc, NULL, 0, uc->lru_head, UWSGI_CACHE_FLAG_LOCAL);
// we do not need locking here !
if (uc->sweep_on_full) {
uint64_t removed = 0;
uint64_t now = (uint64_t) uwsgi_now();
if (uc->next_scan <= now) {
uc->next_scan = now + uc->sweep_on_full;
for (i = 1; i < uc->max_items; i++) {
struct uwsgi_cache_item *uci = cache_item(i);
if (uci->expires > 0 && uci->expires <= now) {
if (!uwsgi_cache_del2(uc, NULL, 0, i, 0)) {
removed++;
}
}
}
if (removed == 0) {
force_clear = 1;
}
}
}
if (uc->clear_on_full || force_clear) {
for (i = 1; i < uc->max_items; i++) {
uwsgi_cache_del2(uc, NULL, 0, i, 0);
}
}
}
static uint64_t uwsgi_cache_find_free_blocks(struct uwsgi_cache *uc, uint64_t need) {
// how many blocks we need ?
uint64_t needed_blocks = need/uc->blocksize;
@@ -32,7 +75,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 +88,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 +118,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 +129,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 +151,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 +187,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 +349,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);
@@ -300,6 +374,14 @@ void uwsgi_cache_init(struct uwsgi_cache *uc) {
int cache_fd;
struct stat cst;
if (uc->store_delete && !stat(uc->store, &cst) && ((size_t) cst.st_size != uc->filesize || !S_ISREG(cst.st_mode))) {
uwsgi_log("Removing invalid cache store file: %s\n", uc->store);
if (unlink(uc->store) != 0) {
uwsgi_log("Cannot remove invalid cache store file: %s\n", uc->store);
exit(1);
}
}
if (stat(uc->store, &cst)) {
uwsgi_log("creating a new cache store file: %s\n", uc->store);
cache_fd = open(uc->store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
@@ -361,7 +443,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);
@@ -381,6 +463,17 @@ void uwsgi_cache_init(struct uwsgi_cache *uc) {
}
static uint64_t check_lazy(struct uwsgi_cache *uc, struct uwsgi_cache_item *uci, uint64_t slot) {
if (!uci->expires || !uc->lazy_expire) return slot;
uint64_t now = (uint64_t) uwsgi_now();
// expired ?
if (uci->expires <= now) {
uwsgi_cache_del2(uc, NULL, 0, slot, UWSGI_CACHE_FLAG_LOCAL);
return 0;
}
return slot;
}
static uint64_t uwsgi_cache_get_index(struct uwsgi_cache *uc, char *key, uint16_t keylen) {
uint32_t hash = uc->hash->func(key, keylen);
@@ -406,7 +499,7 @@ static uint64_t uwsgi_cache_get_index(struct uwsgi_cache *uc, char *key, uint16_
if (memcmp(uci->key, key, keylen))
goto cycle;
return slot;
return check_lazy(uc, uci, slot);
cycle:
while (uci->next) {
@@ -429,8 +522,9 @@ cycle:
continue;
if (uci->keysize != keylen)
continue;
if (!memcmp(uci->key, key, keylen))
return slot;
if (!memcmp(uci->key, key, keylen)) {
return check_lazy(uc, uci, slot);
}
}
return 0;
@@ -441,6 +535,38 @@ uint32_t uwsgi_cache_exists2(struct uwsgi_cache *uc, char *key, uint16_t keylen)
return uwsgi_cache_get_index(uc, key, keylen);
}
static void lru_remove_item(struct uwsgi_cache *uc, uint64_t index)
{
struct uwsgi_cache_item *prev, *next, *curr = cache_item(index);
if (curr->lru_next) {
next = cache_item(curr->lru_next);
next->lru_prev = curr->lru_prev;
} else
uc->lru_tail = curr->lru_prev;
if (curr->lru_prev) {
prev = cache_item(curr->lru_prev);
prev->lru_next = curr->lru_next;
} else
uc->lru_head = curr->lru_next;
}
static void lru_add_item(struct uwsgi_cache *uc, uint64_t index)
{
struct uwsgi_cache_item *prev, *curr = cache_item(index);
if (uc->lru_tail) {
prev = cache_item(uc->lru_tail);
prev->lru_next = index;
} else
uc->lru_head = index;
curr->lru_next = 0;
curr->lru_prev = uc->lru_tail;
uc->lru_tail = index;
}
char *uwsgi_cache_get2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint64_t * valsize) {
uint64_t index = uwsgi_cache_get_index(uc, key, keylen);
@@ -450,6 +576,10 @@ char *uwsgi_cache_get2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint6
if (uci->flags & UWSGI_CACHE_FLAG_UNGETTABLE)
return NULL;
*valsize = uci->valsize;
if (uc->purge_lru) {
lru_remove_item(uc, index);
lru_add_item(uc, index);
}
uci->hits++;
uc->hits++;
return uc->data + (uci->first_block * uc->blocksize);
@@ -489,6 +619,10 @@ char *uwsgi_cache_get3(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint6
*valsize = uci->valsize;
if (expires)
*expires = uci->expires;
if (uc->purge_lru) {
lru_remove_item(uc, index);
lru_add_item(uc, index);
}
uci->hits++;
uc->hits++;
return uc->data + (uci->first_block * uc->blocksize);
@@ -523,50 +657,56 @@ 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;
}
if (uc->purge_lru)
lru_remove_item(uc, index);
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 +724,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 +739,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 +755,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,56 +772,43 @@ 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) {
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++;
}
if (!uc->unused_blocks_stack_ptr) {
cache_full(uc);
if (!uc->unused_blocks_stack_ptr)
goto end;
}
index = uc->unused_blocks_stack[uc->unused_blocks_stack_ptr];
uc->unused_blocks_stack_ptr--;
uci = cache_item(index);
if (!uc->blocks_bitmap) {
uci->first_block = index;
}
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++;
cache_full(uc);
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 (uci->first_block + 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)) {
if (uc->purge_lru)
lru_add_item(uc, index);
else if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) {
now = uwsgi_now();
expires += now;
if (!uc->next_scan || uc->next_scan > expires)
uc->next_scan = expires;
}
uci->expires = expires;
uci->hash = uc->hash->func(key, keylen);
@@ -745,9 +873,16 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
}
else if (flags & UWSGI_CACHE_FLAG_UPDATE) {
uci = cache_item(index);
if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE) && !(flags & UWSGI_CACHE_FLAG_FIXEXPIRE)) {
now = uwsgi_now();
expires += now;
if (!(flags & UWSGI_CACHE_FLAG_FIXEXPIRE)) {
if (uc->purge_lru) {
lru_remove_item(uc, index);
lru_add_item(uc, index);
} else if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) {
now = uwsgi_now();
expires += now;
if (!uc->next_scan || uc->next_scan > expires)
uc->next_scan = expires;
}
uci->expires = expires;
}
if (uc->blocks_bitmap) {
@@ -755,22 +890,21 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
uint64_t old_first_block = uci->first_block;
uci->first_block = uwsgi_cache_find_free_blocks(uc, vallen);
if (uci->first_block == 0xffffffffffffffffLLU) {
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
uc->full++;
uci->first_block = old_first_block;
cache_full(uc);
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 (uci->first_block + 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);
@@ -965,39 +1099,66 @@ void *cache_udp_server_loop(void *ucache) {
return NULL;
}
static uint64_t cache_sweeper_free_items(struct uwsgi_cache *uc) {
uint64_t i;
uint64_t freed_items = 0;
if (uc->no_expire || uc->purge_lru || uc->lazy_expire)
return 0;
uwsgi_rlock(uc->lock);
if (!uc->next_scan || uc->next_scan > (uint64_t)uwsgi.current_time) {
uwsgi_rwunlock(uc->lock);
return 0;
}
uwsgi_rwunlock(uc->lock);
// skip the first slot
for (i = 1; i < uc->max_items; i++) {
struct uwsgi_cache_item *uci = cache_item(i);
uwsgi_wlock(uc->lock);
// we reset next scan time first, then we find the least
// expiration time from those that are NOT expired yet.
if (i == 1)
uc->next_scan = 0;
if (uci->expires) {
if (uci->expires <= (uint64_t)uwsgi.current_time) {
uwsgi_cache_del2(uc, NULL, 0, i, UWSGI_CACHE_FLAG_LOCAL);
freed_items++;
} else if (!uc->next_scan || uc->next_scan > uci->expires) {
uc->next_scan = uci->expires;
}
}
uwsgi_rwunlock(uc->lock);
}
return freed_items;
}
static void *cache_sweeper_loop(void *ucache) {
uint64_t i;
// block all signals
sigset_t smask;
sigfillset(&smask);
pthread_sigmask(SIG_BLOCK, &smask, NULL);
struct uwsgi_cache *uc = (struct uwsgi_cache *) ucache;
if (!uwsgi.cache_expire_freq)
uwsgi.cache_expire_freq = 3;
// remove expired cache items TODO use rb_tree timeouts
for (;;) {
struct uwsgi_cache *uc;
for (uc = (struct uwsgi_cache *)ucache; uc; uc = uc->next) {
uint64_t freed_items = cache_sweeper_free_items(uc);
if (uwsgi.cache_report_freed_items && freed_items)
uwsgi_log("freed %llu items for cache \"%s\"\n", (unsigned long long)freed_items, uc->name);
}
sleep(uwsgi.cache_expire_freq);
uint64_t freed_items = 0;
// skip the first slot
for (i = 1; i < uc->max_items; i++) {
uwsgi_wlock(uc->lock);
struct uwsgi_cache_item *uci = cache_item(i);
if (uci->expires) {
if (uci->expires < (uint64_t) uwsgi.current_time) {
uwsgi_cache_del2(uc, NULL, 0, i, UWSGI_CACHE_FLAG_LOCAL);
freed_items++;
}
}
uwsgi_rwunlock(uc->lock);
}
if (uwsgi.cache_report_freed_items && freed_items > 0) {
uwsgi_log("freed %llu items for cache \"%s\"\n", (unsigned long long) freed_items, uc->name);
}
};
}
return NULL;
}
@@ -1017,19 +1178,28 @@ void uwsgi_cache_sync_all() {
void uwsgi_cache_start_sweepers() {
struct uwsgi_cache *uc = uwsgi.caches;
if (uwsgi.cache_no_expire)
return;
int need_to_run = 0;
while(uc) {
pthread_t cache_sweeper;
if (!uwsgi.cache_no_expire && !uc->no_expire) {
if (pthread_create(&cache_sweeper, NULL, cache_sweeper_loop, (void *) uc)) {
uwsgi_error("pthread_create()");
uwsgi_log("unable to run the sweeper for cache \"%s\" !!!\n", uc->name);
}
else {
uwsgi_log("sweeper thread enabled for cache \"%s\"\n", uc->name);
}
if (!uc->no_expire && !uc->purge_lru && !uc->lazy_expire) {
need_to_run = 1;
break;
}
uc = uc->next;
}
if (!need_to_run) return;
pthread_t cache_sweeper;
if (pthread_create(&cache_sweeper, NULL, cache_sweeper_loop, uwsgi.caches)) {
uwsgi_error("uwsgi_cache_start_sweepers()/pthread_create()");
uwsgi_log("unable to run the cache sweeper!!!\n");
return;
}
uwsgi_log("cache sweeper thread enabled\n");
}
void uwsgi_cache_start_sync_servers() {
@@ -1097,12 +1267,19 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
char *c_keysize = NULL;
char *c_store = NULL;
char *c_store_sync = NULL;
char *c_store_delete = NULL;
char *c_nodes = NULL;
char *c_sync = NULL;
char *c_udp_servers = NULL;
char *c_bitmap = NULL;
char *c_use_last_modified = NULL;
char *c_math_initial = NULL;
char *c_ignore_full = NULL;
char *c_purge_lru = NULL;
char *c_lazy_expire = NULL;
char *c_sweep_on_full = NULL;
char *c_clear_on_full = NULL;
char *c_no_expire = NULL;
if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=',
"name", &c_name,
@@ -1119,6 +1296,8 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
"store", &c_store,
"store_sync", &c_store_sync,
"storesync", &c_store_sync,
"store_delete", &c_store_delete,
"storedelete", &c_store_delete,
"node", &c_nodes,
"nodes", &c_nodes,
"sync", &c_sync,
@@ -1130,6 +1309,14 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
"bitmap", &c_bitmap,
"lastmod", &c_use_last_modified,
"math_initial", &c_math_initial,
"ignore_full", &c_ignore_full,
"purge_lru", &c_purge_lru,
"lru", &c_purge_lru,
"lazy_expire", &c_lazy_expire,
"lazy", &c_lazy_expire,
"sweep_on_full", &c_sweep_on_full,
"clear_on_full", &c_clear_on_full,
"no_expire", &c_no_expire,
NULL)) {
uwsgi_log("unable to parse cache definition\n");
exit(1);
@@ -1177,9 +1364,19 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
uc->max_item_size = uc->blocksize * uc->blocks;
}
if (c_use_last_modified) uc->use_last_modified = 1;
if (c_ignore_full) uc->ignore_full = 1;
if (c_store_delete) uc->store_delete = 1;
if (c_math_initial) uc->math_initial = strtol(c_math_initial, NULL, 10);
if (c_lazy_expire) uc->lazy_expire = 1;
if (c_sweep_on_full) {
uc->sweep_on_full = uwsgi_n64(c_sweep_on_full);
}
if (c_clear_on_full) uc->clear_on_full = 1;
if (c_no_expire) uc->no_expire = 1;
uc->store_sync = uwsgi.cache_store_sync;
if (c_store_sync) { uc->store_sync = uwsgi_n64(c_store_sync); }
@@ -1211,6 +1408,8 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
}
}
if (c_purge_lru)
uc->purge_lru = 1;
}
uwsgi_cache_init(uc);
@@ -1466,7 +1665,10 @@ char *uwsgi_cache_magic_get(char *key, uint16_t keylen, uint64_t *vallen, uint64
// we have a local cache !!!
if (uc) {
uwsgi_rlock(uc->lock);
if (uc->purge_lru)
uwsgi_wlock(uc->lock);
else
uwsgi_rlock(uc->lock);
char *value = uwsgi_cache_get3(uc, key, keylen, vallen, expires);
if (!value) {
uwsgi_rwunlock(uc->lock);
@@ -1483,7 +1685,7 @@ char *uwsgi_cache_magic_get(char *key, uint16_t keylen, uint64_t *vallen, uint64
int fd = uwsgi_connect(cache_server, 0, 1);
if (fd < 0) return NULL;
int ret = uwsgi.wait_write_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
int ret = uwsgi.wait_write_hook(fd, uwsgi.socket_timeout);
if (ret <= 0) {
close(fd);
return NULL;
@@ -1495,7 +1697,7 @@ char *uwsgi_cache_magic_get(char *key, uint16_t keylen, uint64_t *vallen, uint64
return NULL;
}
if (cache_magic_send_and_manage(fd, ub, NULL, 0, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], &ucmc)) {
if (cache_magic_send_and_manage(fd, ub, NULL, 0, uwsgi.socket_timeout, &ucmc)) {
close(fd);
uwsgi_buffer_destroy(ub);
return NULL;
@@ -1526,7 +1728,7 @@ char *uwsgi_cache_magic_get(char *key, uint16_t keylen, uint64_t *vallen, uint64
}
// read the raw value from the socket
if (uwsgi_read_whole_true_nb(fd, ub->buf, ucmc.size, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
if (uwsgi_read_whole_true_nb(fd, ub->buf, ucmc.size, uwsgi.socket_timeout)) {
close(fd);
uwsgi_buffer_destroy(ub);
return NULL;
@@ -1585,7 +1787,7 @@ int uwsgi_cache_magic_exists(char *key, uint16_t keylen, char *cache) {
int fd = uwsgi_connect(cache_server, 0, 1);
if (fd < 0) return 0;
int ret = uwsgi.wait_write_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
int ret = uwsgi.wait_write_hook(fd, uwsgi.socket_timeout);
if (ret <= 0) {
close(fd);
return 0;
@@ -1597,7 +1799,7 @@ int uwsgi_cache_magic_exists(char *key, uint16_t keylen, char *cache) {
return 0;
}
if (cache_magic_send_and_manage(fd, ub, NULL, 0, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], &ucmc)) {
if (cache_magic_send_and_manage(fd, ub, NULL, 0, uwsgi.socket_timeout, &ucmc)) {
close(fd);
uwsgi_buffer_destroy(ub);
return 0;
@@ -1652,7 +1854,7 @@ int uwsgi_cache_magic_set(char *key, uint16_t keylen, char *value, uint64_t vall
int fd = uwsgi_connect(cache_server, 0, 1);
if (fd < 0) return -1;
int ret = uwsgi.wait_write_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
int ret = uwsgi.wait_write_hook(fd, uwsgi.socket_timeout);
if (ret <= 0) {
close(fd);
return -1;
@@ -1670,7 +1872,7 @@ int uwsgi_cache_magic_set(char *key, uint16_t keylen, char *value, uint64_t vall
return -1;
}
if (cache_magic_send_and_manage(fd, ub, value, vallen, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], &ucmc)) {
if (cache_magic_send_and_manage(fd, ub, value, vallen, uwsgi.socket_timeout, &ucmc)) {
close(fd);
uwsgi_buffer_destroy(ub);
return -1;
@@ -1730,7 +1932,7 @@ int uwsgi_cache_magic_del(char *key, uint16_t keylen, char *cache) {
int fd = uwsgi_connect(cache_server, 0, 1);
if (fd < 0) return -1;
int ret = uwsgi.wait_write_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
int ret = uwsgi.wait_write_hook(fd, uwsgi.socket_timeout);
if (ret <= 0) {
close(fd);
return -1;
@@ -1742,7 +1944,7 @@ int uwsgi_cache_magic_del(char *key, uint16_t keylen, char *cache) {
return -1;
}
if (cache_magic_send_and_manage(fd, ub, NULL, 0, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], &ucmc)) {
if (cache_magic_send_and_manage(fd, ub, NULL, 0, uwsgi.socket_timeout, &ucmc)) {
close(fd);
uwsgi_buffer_destroy(ub);
return -1;
@@ -1788,7 +1990,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;
@@ -1803,7 +2005,7 @@ int uwsgi_cache_magic_clear(char *cache) {
int fd = uwsgi_connect(cache_server, 0, 1);
if (fd < 0) return -1;
int ret = uwsgi.wait_write_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
int ret = uwsgi.wait_write_hook(fd, uwsgi.socket_timeout);
if (ret <= 0) {
close(fd);
return -1;
@@ -1815,7 +2017,7 @@ int uwsgi_cache_magic_clear(char *cache) {
return -1;
}
if (cache_magic_send_and_manage(fd, ub, NULL, 0, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], &ucmc)) {
if (cache_magic_send_and_manage(fd, ub, NULL, 0, uwsgi.socket_timeout, &ucmc)) {
close(fd);
uwsgi_buffer_destroy(ub);
return -1;
@@ -1859,7 +2061,7 @@ void uwsgi_cache_sync_from_nodes(struct uwsgi_cache *uc) {
goto next;
}
if (uwsgi_write_nb(fd, ub->buf, ub->pos, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
if (uwsgi_write_nb(fd, ub->buf, ub->pos, uwsgi.socket_timeout)) {
uwsgi_buffer_destroy(ub);
uwsgi_log("[cache-sync] unable to write to the cache server\n");
close(fd);
@@ -1867,7 +2069,7 @@ void uwsgi_cache_sync_from_nodes(struct uwsgi_cache *uc) {
}
size_t rlen = ub->pos;
if (uwsgi_read_with_realloc(fd, &ub->buf, &rlen, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], NULL, NULL)) {
if (uwsgi_read_with_realloc(fd, &ub->buf, &rlen, uwsgi.socket_timeout, NULL, NULL)) {
uwsgi_buffer_destroy(ub);
uwsgi_log("[cache-sync] unable to read from the cache server\n");
close(fd);
@@ -1876,7 +2078,7 @@ void uwsgi_cache_sync_from_nodes(struct uwsgi_cache *uc) {
uwsgi_hooked_parse(ub->buf, rlen, cache_sync_hook, uc);
if (uwsgi_read_nb(fd, (char *) uc->items, uc->filesize, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
if (uwsgi_read_nb(fd, (char *) uc->items, uc->filesize, uwsgi.socket_timeout)) {
uwsgi_buffer_destroy(ub);
close(fd);
uwsgi_log("[cache-sync] unable to read from the cache server\n");
+1 -1
View File
@@ -20,7 +20,7 @@ extern struct uwsgi_server uwsgi;
static ssize_t uwsgi_chunked_input_recv(struct wsgi_request *wsgi_req, int timeout, int nb) {
if (timeout == 0) timeout = uwsgi.chunked_input_timeout;
if (timeout == 0) timeout = uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT];
if (timeout == 0) timeout = uwsgi.socket_timeout;
int ret = -1;
+54 -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);
@@ -278,6 +294,26 @@ int uwsgi_logic_opt_if_not_plugin(char *key, char *value) {
return 0;
}
int uwsgi_logic_opt_if_hostname(char *key, char *value) {
if (!strcmp(uwsgi.hostname, uwsgi.logic_opt_data)) {
add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
return 1;
}
return 0;
}
int uwsgi_logic_opt_if_not_hostname(char *key, char *value) {
if (strcmp(uwsgi.hostname, uwsgi.logic_opt_data)) {
add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
return 1;
}
return 0;
}
int uwsgi_count_options(struct uwsgi_option *uopt) {
struct uwsgi_option *aopt;
@@ -384,7 +420,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);
}
@@ -799,3 +836,19 @@ char *uwsgi_manage_placeholder(char *key) {
return current_value;
}
void uwsgi_opt_resolve(char *opt, char *value, void *foo) {
char *equal = strchr(value, '=');
if (!equal) {
uwsgi_log("invalid resolve syntax, must be placeholder=domain\n");
exit(1);
}
char *ip = uwsgi_resolve_ip(equal+1);
if (!ip) {
uwsgi_log("unable to resolve name %s\n", equal+1);
uwsgi_error("uwsgi_resolve_ip()");
exit(1);
}
char *new_opt = uwsgi_concat2n(value, (equal-value)+1, ip, strlen(ip));
uwsgi_opt_set_placeholder(opt, new_opt, (void *) 1);
}
+196 -19
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, SIGTERM);
kill(-(ud->pid), ud->stop_signal);
}
else {
// pid already died
@@ -237,12 +237,17 @@ 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, SIGTERM);
if (uwsgi_instance_is_reloading && ud->reload_signal > 0) {
kill(-(ud->pid), ud->reload_signal);
}
else {
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 +258,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,9 +297,74 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
uwsgi_close_all_sockets();
uwsgi_close_all_fds();
if (ud->chdir) {
if (chdir(ud->chdir)) {
uwsgi_error("uwsgi_spawn_daemon()/chdir()");
exit(1);
}
}
#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("uwsgi_spawn_daemon()/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()");
exit(1);
}
}
if (ud->uid) {
if (setuid(ud->uid)) {
uwsgi_error("uwsgi_spawn_daemon()/setuid()");
exit(1);
}
}
if (ud->daemonize) {
/* refork... */
pid = fork();
pid_t pid = fork();
if (pid < 0) {
uwsgi_error("fork()");
exit(1);
@@ -304,7 +375,7 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
uwsgi_write_pidfile(ud->pidfile);
}
if (!uwsgi.daemons_honour_stdin) {
if (!uwsgi.daemons_honour_stdin && !ud->honour_stdin) {
// /dev/null will became stdin
uwsgi_remap_fd(0, "/dev/null");
}
@@ -315,7 +386,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()");
}
@@ -323,20 +394,17 @@ 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\"\n", ud->respawns > 0 ? "re" : "", ud->command);
uwsgi_log("[uwsgi-daemons] %sspawning \"%s\" (uid: %d gid: %d)\n", ud->respawns > 0 ? "re" : "", ud->command, (int) getuid(), (int) getgid());
uwsgi_exec_command_with_args(ud->command);
uwsgi_log("[uwsgi-daemons] unable to spawn \"%s\"\n", ud->command);
// never here;
exit(1);
}
return;
}
@@ -347,6 +415,8 @@ void uwsgi_opt_add_daemon(char *opt, char *value, void *none) {
int daemonize = 0;
int freq = 10;
char *space = NULL;
int stop_signal = SIGTERM;
int reload_signal = 0;
char *command = uwsgi_str(value);
@@ -385,7 +455,7 @@ void uwsgi_opt_add_daemon(char *opt, char *value, void *none) {
}
if (!uwsgi_ud) {
uwsgi.daemons = uwsgi_malloc(sizeof(struct uwsgi_daemon));
uwsgi.daemons = uwsgi_calloc(sizeof(struct uwsgi_daemon));
uwsgi_ud = uwsgi.daemons;
}
else {
@@ -394,7 +464,7 @@ void uwsgi_opt_add_daemon(char *opt, char *value, void *none) {
uwsgi_ud = uwsgi_ud->next;
}
uwsgi_ud = uwsgi_malloc(sizeof(struct uwsgi_daemon));
uwsgi_ud = uwsgi_calloc(sizeof(struct uwsgi_daemon));
old_ud->next = uwsgi_ud;
}
@@ -409,6 +479,8 @@ void uwsgi_opt_add_daemon(char *opt, char *value, void *none) {
uwsgi_ud->daemonize = daemonize;
uwsgi_ud->pidfile = pidfile;
uwsgi_ud->control = 0;
uwsgi_ud->stop_signal = stop_signal;
uwsgi_ud->reload_signal = reload_signal;
if (!strcmp(opt, "attach-control-daemon")) {
uwsgi_ud->control = 1;
}
@@ -419,3 +491,108 @@ void uwsgi_opt_add_daemon(char *opt, char *value, void *none) {
uwsgi.daemons_cnt++;
}
void uwsgi_opt_add_daemon2(char *opt, char *value, void *none) {
struct uwsgi_daemon *uwsgi_ud = uwsgi.daemons, *old_ud;
char *d_command = NULL;
char *d_freq = NULL;
char *d_pidfile = NULL;
char *d_control = NULL;
char *d_legion = NULL;
char *d_daemonize = NULL;
char *d_touch = NULL;
char *d_stopsignal = NULL;
char *d_reloadsignal = NULL;
char *d_stdin = NULL;
char *d_uid = NULL;
char *d_gid = NULL;
char *d_ns_pid = NULL;
char *d_chdir = NULL;
char *arg = uwsgi_str(value);
if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=',
"command", &d_command,
"cmd", &d_command,
"exec", &d_command,
"freq", &d_freq,
"pidfile", &d_pidfile,
"control", &d_control,
"daemonize", &d_daemonize,
"daemon", &d_daemonize,
"touch", &d_touch,
"stopsignal", &d_stopsignal,
"stop_signal", &d_stopsignal,
"reloadsignal", &d_reloadsignal,
"reload_signal", &d_reloadsignal,
"stdin", &d_stdin,
"uid", &d_uid,
"gid", &d_gid,
"ns_pid", &d_ns_pid,
"chdir", &d_chdir,
NULL)) {
uwsgi_log("invalid --%s keyval syntax\n", opt);
exit(1);
}
if (!d_command) {
uwsgi_log("--%s: you need to specify a 'command' key\n", opt);
exit(1);
}
#ifndef UWSGI_SSL
if (d_legion) {
uwsgi_log("legion subsystem is not supported on this uWSGI version, rebuild with ssl support\n");
exit(1);
}
#endif
if (!uwsgi_ud) {
uwsgi.daemons = uwsgi_calloc(sizeof(struct uwsgi_daemon));
uwsgi_ud = uwsgi.daemons;
}
else {
while (uwsgi_ud) {
old_ud = uwsgi_ud;
uwsgi_ud = uwsgi_ud->next;
}
uwsgi_ud = uwsgi_calloc(sizeof(struct uwsgi_daemon));
old_ud->next = uwsgi_ud;
}
uwsgi_ud->command = d_command;
uwsgi_ud->freq = d_freq ? atoi(d_freq) : 10;
uwsgi_ud->daemonize = d_daemonize ? 1 : 0;
uwsgi_ud->pidfile = d_pidfile;
uwsgi_ud->stop_signal = d_stopsignal ? atoi(d_stopsignal) : SIGTERM;
uwsgi_ud->reload_signal = d_reloadsignal ? atoi(d_reloadsignal) : 0;
uwsgi_ud->control = d_control ? 1 : 0;
uwsgi_ud->uid = d_uid ? atoi(d_uid) : 0;
uwsgi_ud->gid = d_gid ? atoi(d_gid) : 0;
uwsgi_ud->honour_stdin = d_stdin ? 1 : 0;
#ifdef UWSGI_SSL
uwsgi_ud->legion = d_legion;
#endif
uwsgi_ud->ns_pid = d_ns_pid ? 1 : 0;
uwsgi_ud->chdir = d_chdir;
if (d_touch) {
size_t i,rlen = 0;
char **argv = uwsgi_split_quoted(d_touch, strlen(d_touch), ";", &rlen);
for(i=0;i<rlen;i++) {
uwsgi_string_new_list(&uwsgi_ud->touch, argv[i]);
}
if (argv) free(argv);
}
uwsgi.daemons_cnt++;
free(arg);
}
+934 -573
View File
File diff suppressed because it is too large Load Diff
+8
View File
@@ -45,6 +45,14 @@ void uwsgi_403(struct wsgi_request *wsgi_req) {
uwsgi_response_write_body_do(wsgi_req, "Forbidden", 9);
}
void uwsgi_405(struct wsgi_request *wsgi_req) {
if (uwsgi_response_prepare_headers(wsgi_req, "405 Method Not Allowed", 22)) return;
if (uwsgi_response_add_connection_close(wsgi_req)) return;
if (error_page(wsgi_req, uwsgi.error_page_403)) return;
if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) return;
uwsgi_response_write_body_do(wsgi_req, "Method Not Allowed", 18);
}
void uwsgi_redirect_to_slash(struct wsgi_request *wsgi_req) {
char *redirect = NULL;
+7 -6
View File
@@ -414,11 +414,11 @@ int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
}
if (ret < 0) {
if (errno != ETIME) {
uwsgi_error("port_getn()");
return -1;
}
return 0;
if (errno == ETIME) return 0;
if (errno != EINTR) {
uwsgi_error("port_getn()");
}
return -1;
}
uint_t i;
@@ -452,6 +452,7 @@ int event_queue_wait(int eq, int timeout, int *interesting_fd) {
else {
ret = port_get(eq, &pe, NULL);
}
if (ret < 0) {
if (errno == ETIME) return 0;
if (errno != EINTR) {
@@ -947,7 +948,7 @@ int event_queue_wait(int eq, int timeout, int *interesting_fd) {
struct timespec ts;
struct kevent ev;
if (timeout <= 0) {
if (timeout < 0) {
ret = kevent(eq, NULL, 0, &ev, 1, NULL);
}
else {
+1 -2
View File
@@ -464,6 +464,7 @@ void uwsgi_exception_setup_handlers() {
struct uwsgi_string_list *usl = uwsgi.exception_handlers_instance;
while(usl) {
// do not free handler !!!
char *handler = uwsgi_str(usl->value);
char *colon = strchr(handler, ':');
if (colon) {
@@ -472,10 +473,8 @@ void uwsgi_exception_setup_handlers() {
struct uwsgi_exception_handler *ueh = uwsgi_exception_handler_by_name(handler);
if (!ueh) {
uwsgi_log("unable to find exception handler: %s\n", handler);
free(handler);
exit(1);
}
free(handler);
struct uwsgi_exception_handler_instance *uehi = uwsgi_calloc(sizeof(struct uwsgi_exception_handler_instance));
uehi->handler = ueh;
+11
View File
@@ -48,6 +48,14 @@ static void subscriptions_blocker() {
}
}
static void emperor_rescan() {
if (uwsgi.emperor_pid > 0) {
if (kill(uwsgi.emperor_pid, SIGWINCH)) {
uwsgi_error("emperor_rescan()/kill()");
}
}
}
/*
this is called as soon as possibile allowing plugins (or hooks) to override it
@@ -72,8 +80,10 @@ void uwsgi_master_fifo_prepare() {
uwsgi_fifo_table['-'] = uwsgi_cheaper_decrease;
uwsgi_fifo_table['+'] = uwsgi_cheaper_increase;
uwsgi_fifo_table['B'] = vassal_sos;
uwsgi_fifo_table['c'] = uwsgi_chain_reload;
uwsgi_fifo_table['C'] = uwsgi_go_cheap;
uwsgi_fifo_table['E'] = emperor_rescan;
uwsgi_fifo_table['f'] = uwsgi_refork_master;
uwsgi_fifo_table['l'] = uwsgi_log_reopen;
uwsgi_fifo_table['L'] = uwsgi_log_rotate;
@@ -122,6 +132,7 @@ int uwsgi_master_fifo_manage(int fd) {
}
// fifo destroyed, recreate it
else if (rlen == 0) {
event_queue_del_fd(uwsgi.master_queue, uwsgi.master_fifo_fd, event_queue_read());
close(fd);
uwsgi.master_fifo_fd = uwsgi_master_fifo();
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.master_fifo_fd);
+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;
}
+21 -1
View File
@@ -29,6 +29,8 @@ struct uwsgi_gateway *register_gateway(char *name, void (*loop) (int, void *), v
ug->num = num;
ug->fullname = fullname;
ug->data = data;
ug->uid = 0;
ug->gid = 0;
#if defined(SOCK_SEQPACKET) && defined(__linux__)
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, ug->internal_subscription_pipe)) {
@@ -70,7 +72,7 @@ void gateway_respawn(int id) {
if (gw_pid == 0) {
uwsgi_fixup_fds(0, 0, ug);
uwsgi_close_all_sockets();
uwsgi_close_all_unshared_sockets();
if (uwsgi.master_as_root)
uwsgi_as_root();
#ifdef __linux__
@@ -90,6 +92,24 @@ 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)) {
uwsgi_error("gateway_respawn()/setgid()");
exit(1);
}
}
if (ug->uid) {
uwsgi_log("%s %d setuid() to %d\n", ug->name, ug->num, (int) ug->uid);
if (setuid(ug->uid)) {
uwsgi_error("gateway_respawn()/setuid()");
exit(1);
}
}
ug->loop(id, ug->data);
// never here !!! (i hope)
exit(1);
+422 -4
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) {
@@ -55,6 +67,22 @@ static int uwsgi_hook_chdir(char *arg) {
return ret;
}
static int uwsgi_hook_mkdir(char *arg) {
int ret = mkdir(arg, 0777);
if (ret) {
uwsgi_error("uwsgi_hook_mkdir()");
}
return ret;
}
static int uwsgi_hook_putenv(char *arg) {
int ret = putenv(arg);
if (ret) {
uwsgi_error("uwsgi_hook_putenv()");
}
return ret;
}
static int uwsgi_hook_exec(char *arg) {
int ret = uwsgi_run_command_and_wait(NULL, arg);
if (ret != 0) {
@@ -63,6 +91,14 @@ static int uwsgi_hook_exec(char *arg) {
return ret;
}
static int uwsgi_hook_safeexec(char *arg) {
int ret = uwsgi_run_command_and_wait(NULL, arg);
if (ret != 0) {
uwsgi_log("command \"%s\" exited with non-zero code: %d\n", arg, ret);
}
return 0;
}
static int uwsgi_hook_exit(char *arg) {
int exit_code = 0;
if (strlen(arg) > 1) {
@@ -121,7 +157,7 @@ static int uwsgi_hook_write(char *arg) {
return -1;
}
*space = 0;
int fd = open(arg, O_WRONLY);
int fd = open(arg, O_WRONLY|O_CREAT|O_TRUNC, 0666);
if (fd < 0) {
uwsgi_error_open(arg);
*space = ' ';
@@ -138,6 +174,257 @@ 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) {
uwsgi_log("invalid hook append syntax, must be: <file> <string>\n");
return -1;
}
*space = 0;
int fd = open(arg, O_WRONLY|O_CREAT|O_APPEND, 0666);
if (fd < 0) {
uwsgi_error_open(arg);
*space = ' ';
return -1;
}
*space = ' ';
size_t l = strlen(space+1);
if (write(fd, space+1, l) != (ssize_t) l) {
uwsgi_error("uwsgi_hook_append()/write()");
close(fd);
return -1;
}
close(fd);
return 0;
}
static int uwsgi_hook_writen(char *arg) {
char *space = strchr(arg, ' ');
if (!space) {
uwsgi_log("invalid hook writen syntax, must be: <file> <string>\n");
return -1;
}
*space = 0;
int fd = open(arg, O_WRONLY|O_CREAT|O_TRUNC, 0666);
if (fd < 0) {
uwsgi_error_open(arg);
*space = ' ';
return -1;
}
*space = ' ';
size_t l = strlen(space+1);
char *buf = uwsgi_malloc(l + 1);
memcpy(buf, space+1, l);
buf[l] = '\n';
if (write(fd, buf, l+1) != (ssize_t) (l+1)) {
uwsgi_error("uwsgi_hook_writen()/write()");
free(buf);
close(fd);
return -1;
}
free(buf);
close(fd);
return 0;
}
static int uwsgi_hook_appendn(char *arg) {
char *space = strchr(arg, ' ');
if (space)
*space = 0;
int fd = open(arg, O_WRONLY|O_CREAT|O_APPEND, 0666);
if (fd < 0) {
uwsgi_error_open(arg);
if (space)
*space = ' ';
return -1;
}
if (!space) {
// simple newline
if (write(fd, "\n", 1) != 1) {
uwsgi_error("uwsgi_hook_appendn()/write()");
close(fd);
return -1;
}
close(fd);
return 0;
}
*space = ' ';
size_t l = strlen(space+1);
char *buf = uwsgi_malloc(l + 1);
memcpy(buf, space+1, l);
buf[l] = '\n';
if (write(fd, buf, l+1) != (ssize_t) (l+1)) {
uwsgi_error("uwsgi_hook_appendn()/write()");
free(buf);
close(fd);
return -1;
}
free(buf);
close(fd);
return 0;
}
static int uwsgi_hook_chmod(char *arg) {
char *space = strchr(arg, ' ');
if (!space) {
uwsgi_log("invalid hook chmod syntax, must be: <file> <mode>\n");
return -1;
}
*space = 0;
int error = 0;
mode_t mask = uwsgi_mode_t(space+1, &error);
if (error) {
uwsgi_log("invalid hook chmod mask: %s\n", space+1);
*space = ' ';
return -1;
}
int ret = chmod(arg, mask);
*space = ' ';
if (ret) {
uwsgi_error("uwsgi_hook_chmod()/chmod()");
}
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) {
uwsgi_log("invalid hook chown syntax, must be: <file> <uid> <gid>\n");
return -1;
}
*space = 0;
char *space2 = strchr(space+1, ' ');
if (!space2) {
*space = ' ';
uwsgi_log("invalid hook chown syntax, must be: <file> <uid> <gid>\n");
return -1;
}
*space2 = 0;
struct passwd *pw = getpwnam(space+1);
if (!pw) {
uwsgi_log("unable to find uid %s\n", space+1);
*space = ' ';
*space2 = ' ';
return -1;
}
struct group *gr = getgrnam(space2+1);
if (!gr) {
uwsgi_log("unable to find gid %s\n", space2+1);
*space = ' ';
*space2 = ' ';
return -1;
}
int ret = chown(arg, pw->pw_uid, gr->gr_gid);
*space = ' ';
*space2 = ' ';
if (ret) {
uwsgi_error("uwsgi_hook_chown()/chown)");
}
return ret;
}
static int uwsgi_hook_chown2(char *arg) {
char *space = strchr(arg, ' ');
if (!space) {
uwsgi_log("invalid hook chown2 syntax, must be: <file> <uid> <gid>\n");
return -1;
}
*space = 0;
char *space2 = strchr(space+1, ' ');
if (!space2) {
*space = ' ';
uwsgi_log("invalid hook chown2 syntax, must be: <file> <uid> <gid>\n");
return -1;
}
*space2 = 0;
if (!is_a_number(space+1)) {
uwsgi_log("invalid hook chown2 syntax, uid must be a number\n");
*space = ' ';
*space2 = ' ';
return -1;
}
if (!is_a_number(space2+1)) {
uwsgi_log("invalid hook chown2 syntax, gid must be a number\n");
*space = ' ';
*space2 = ' ';
return -1;
}
int ret = chown(arg, atoi(space+1), atoi(space2+1));
*space = ' ';
*space2 = ' ';
if (ret) {
uwsgi_error("uwsgi_hook_chown2()/chown)");
}
return ret;
}
#ifdef __sun__
extern int sethostname(char *, int);
#endif
static int uwsgi_hook_hostname(char *arg) {
#ifdef __CYGWIN__
return -1;
#else
return sethostname(arg, strlen(arg));
#endif
}
static int uwsgi_hook_unix_signal(char *arg) {
char *space = strchr(arg, ' ');
if (!space) {
uwsgi_log("invalid unix_signal syntax, must be <signum> <func>\n");
return -1;
}
*space = 0;
int signum = atoi(arg);
*space = ' ';
void (*func)(int) = dlsym(RTLD_DEFAULT, space+1);
if (!func) {
uwsgi_log("unable to find function \"%s\"\n", space+1);
return -1;
}
uwsgi_unix_signal(signum, func);
return 0;
}
static int uwsgi_hook_callint(char *arg) {
char *space = strchr(arg, ' ');
@@ -233,12 +520,99 @@ static int uwsgi_hook_callret(char *arg) {
return func();
}
static int uwsgi_hook_rpc(char *arg) {
int ret = -1;
size_t i, argc = 0;
char **rargv = uwsgi_split_quoted(arg, strlen(arg), " \t", &argc);
if (!argc) goto end;
if (argc > 256) goto destroy;
char *argv[256];
uint16_t argvs[256];
char *node = NULL;
char *func = rargv[0];
char *at = strchr(func, '@');
if (at) {
*at = 0;
node = at + 1;
}
for(i=0;i<(argc-1);i++) {
size_t a_len = strlen(rargv[i+1]);
if (a_len > 0xffff) goto destroy;
argv[i] = rargv[i+1] ;
argvs[i] = a_len;
}
uint64_t size = 0;
// response must be always freed
char *response = uwsgi_do_rpc(node, func, argc-1, argv, argvs, &size);
if (response) {
if (at) *at = '@';
uwsgi_log("[rpc result from \"%s\"] %.*s\n", rargv[0], size, response);
free(response);
ret = 0;
}
destroy:
for(i=0;i<argc;i++) {
free(rargv[i]);
}
end:
free(rargv);
return ret;
}
static int uwsgi_hook_retryrpc(char *arg) {
for(;;) {
int ret = uwsgi_hook_rpc(arg);
if (!ret) break;
sleep(2);
}
return 0;
}
static int uwsgi_hook_wait_for_fs(char *arg) {
return uwsgi_wait_for_fs(arg, 0);
}
static int uwsgi_hook_wait_for_file(char *arg) {
return uwsgi_wait_for_fs(arg, 1);
}
static int uwsgi_hook_wait_for_dir(char *arg) {
return uwsgi_wait_for_fs(arg, 2);
}
static int uwsgi_hook_wait_for_socket(char *arg) {
return uwsgi_wait_for_socket(arg);
}
void uwsgi_register_base_hooks() {
uwsgi_register_hook("cd", uwsgi_hook_chdir);
uwsgi_register_hook("chdir", uwsgi_hook_chdir);
uwsgi_register_hook("mkdir", uwsgi_hook_mkdir);
uwsgi_register_hook("putenv", uwsgi_hook_putenv);
uwsgi_register_hook("chmod", uwsgi_hook_chmod);
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("safeexec", uwsgi_hook_safeexec);
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);
uwsgi_register_hook("appendn", uwsgi_hook_appendn);
uwsgi_register_hook("writefifo", uwsgi_hook_writefifo);
uwsgi_register_hook("unlink", uwsgi_hook_unlink);
@@ -251,9 +625,25 @@ void uwsgi_register_base_hooks() {
uwsgi_register_hook("callint", uwsgi_hook_callint);
uwsgi_register_hook("callintret", uwsgi_hook_callintret);
uwsgi_register_hook("hostname", uwsgi_hook_hostname);
uwsgi_register_hook("alarm", uwsgi_hook_alarm);
uwsgi_register_hook("rpc", uwsgi_hook_rpc);
uwsgi_register_hook("retryrpc", uwsgi_hook_retryrpc);
uwsgi_register_hook("wait_for_fs", uwsgi_hook_wait_for_fs);
uwsgi_register_hook("wait_for_file", uwsgi_hook_wait_for_file);
uwsgi_register_hook("wait_for_dir", uwsgi_hook_wait_for_dir);
uwsgi_register_hook("wait_for_socket", uwsgi_hook_wait_for_socket);
uwsgi_register_hook("unix_signal", uwsgi_hook_unix_signal);
// 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) {
@@ -265,17 +655,45 @@ void uwsgi_hooks_run(struct uwsgi_string_list *l, char *phase, int fatal) {
exit(1);
}
*colon = 0;
struct uwsgi_hook *uh = uwsgi_hook_by_name(usl->value);
int private = 0;
char *action = usl->value;
// private hook ?
if (action[0] == '!') {
action++;
private = 1;
}
struct uwsgi_hook *uh = uwsgi_hook_by_name(action);
if (!uh) {
uwsgi_log("hook not found: %s\n", usl->value);
uwsgi_log("hook action not found: %s\n", action);
exit(1);
}
*colon = ':';
uwsgi_log("running \"%s\" (%s)...\n", usl->value, phase);
if (private) {
uwsgi_log("running --- PRIVATE HOOK --- (%s)...\n", phase);
}
else {
uwsgi_log("running \"%s\" (%s)...\n", usl->value, phase);
}
int ret = uh->func(colon+1);
if (fatal && ret != 0) {
uwsgi_log_verbose("FATAL hook failed, destroying instance\n");
if (uwsgi.master_process) {
if (uwsgi.workers) {
if (uwsgi.workers[0].pid == getpid()) {
kill_them_all(0);
return;
}
else {
if (kill(uwsgi.workers[0].pid, SIGINT)) {
uwsgi_error("uwsgi_hooks_run()/kill()");
exit(1);
}
return;
}
}
}
exit(1);
}
}
+20 -13
View File
@@ -3,9 +3,9 @@
extern struct uwsgi_server uwsgi;
struct http_status_codes {
const char key[3];
const char *message;
int message_size;
const char key[3];
const char *message;
int message_size;
};
/* statistically ordered */
@@ -73,7 +73,7 @@ void uwsgi_init_default() {
uwsgi.stats_pusher_default_freq = 3;
uwsgi.original_log_fd = -1;
uwsgi.original_log_fd = 2;
uwsgi.emperor_fd_config = -1;
uwsgi.emperor_fd_proxy = -1;
@@ -113,17 +113,18 @@ void uwsgi_init_default() {
uwsgi.log_master_bufsize = 8192;
uwsgi.worker_reload_mercy = 60;
uwsgi.mule_reload_mercy = 60;
uwsgi.max_vars = MAX_VARS;
uwsgi.vec_size = 4 + 1 + (4 * MAX_VARS);
uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] = 4;
uwsgi.shared->options[UWSGI_OPTION_LOGGING] = 1;
uwsgi.socket_timeout = 4;
uwsgi.logging_options.enabled = 1;
// a workers hould be running for at least 10 seconds
uwsgi.shared->options[UWSGI_OPTION_MIN_WORKER_LIFETIME] = 10;
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 +184,8 @@ void uwsgi_init_default() {
uwsgi.master_fifo_fd = -1;
uwsgi_master_fifo_prepare();
uwsgi.notify_socket_fd = -1;
}
void uwsgi_setup_reload() {
@@ -196,7 +199,7 @@ void uwsgi_setup_reload() {
uwsgi.reloads++;
//convert reloads to string
int rlen = snprintf(env_reload_buf, 10, "%u", uwsgi.reloads);
if (rlen > 0) {
if (rlen > 0 && rlen < 10) {
env_reload_buf[rlen] = 0;
if (setenv("UWSGI_RELOADS", env_reload_buf, 1)) {
uwsgi_error("setenv()");
@@ -413,7 +416,7 @@ void sanitize_args() {
uwsgi.cores = uwsgi.threads;
}
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
if (uwsgi.harakiri_options.workers > 0) {
if (!uwsgi.post_buffering) {
uwsgi_log(" *** WARNING: you have enabled harakiri without post buffering. Slow upload could be rejected on post-unbuffered webservers *** \n");
}
@@ -449,13 +452,13 @@ void sanitize_args() {
}
}
if (uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME] > 0 && uwsgi.shared->options[UWSGI_OPTION_MIN_WORKER_LIFETIME] >= uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME]) {
if (uwsgi.max_worker_lifetime > 0 && uwsgi.min_worker_lifetime >= uwsgi.max_worker_lifetime) {
uwsgi_log("invalid min-worker-lifetime value (%d), must be lower than max-worker-lifetime (%d)\n",
uwsgi.shared->options[UWSGI_OPTION_MIN_WORKER_LIFETIME], uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME]);
uwsgi.min_worker_lifetime, uwsgi.max_worker_lifetime);
exit(1);
}
if (uwsgi.cheaper_rss_limit_soft && uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG] != 1 && uwsgi.force_get_memusage != 1) {
if (uwsgi.cheaper_rss_limit_soft && uwsgi.logging_options.memory_report != 1 && uwsgi.force_get_memusage != 1) {
uwsgi_log("enabling cheaper-rss-limit-soft requires enabling also memory-report\n");
exit(1);
}
@@ -468,6 +471,10 @@ void sanitize_args() {
exit(1);
}
if (uwsgi.evil_reload_on_rss || uwsgi.evil_reload_on_as) {
if (!uwsgi.mem_collector_freq) uwsgi.mem_collector_freq = 3;
}
/* here we try to choose if thunder lock is a good thing */
#ifdef UNBIT
if (uwsgi.numproc > 1 && !uwsgi.map_socket) {
+292 -6
View File
@@ -15,7 +15,7 @@ int uwsgi_waitfd_event(int fd, int timeout, int event) {
struct pollfd upoll;
if (!timeout)
timeout = uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT];
timeout = uwsgi.socket_timeout;
timeout = timeout * 1000;
if (timeout < 0)
@@ -392,6 +392,26 @@ static char *uwsgi_scheme_call(char *url, size_t *size, int add_zero) {
return buffer;
}
static char *uwsgi_scheme_callint(char *url, size_t *size, int add_zero) {
int (*func)(void) = dlsym(RTLD_DEFAULT, url);
if (!func) {
uwsgi_log("unable to find symbol %s\n", url);
exit(1);
}
char *s = uwsgi_num2str(func());
*size = strlen(s);
if (add_zero) {
*size += 1;
}
char *buffer = uwsgi_malloc(*size);
memset(buffer, 0, *size);
memcpy(buffer, s, strlen(s));
free(s);
return buffer;
}
static char *uwsgi_scheme_sym(char *url, size_t *size, int add_zero) {
void *sym_start_ptr = NULL, *sym_end_ptr = NULL;
@@ -517,12 +537,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 +571,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;
@@ -586,11 +661,13 @@ int *uwsgi_attach_fd(int fd, int *count_ptr, char *code, size_t code_len) {
len = recvmsg(fd, &msg, 0);
if (len <= 0) {
uwsgi_error("recvmsg()");
free(msg_control);
return NULL;
}
if (code && code_len > 0) {
if (uwsgi_strncmp(id, code_len, code, code_len)) {
free(msg_control);
return NULL;
}
@@ -606,15 +683,19 @@ int *uwsgi_attach_fd(int fd, int *count_ptr, char *code, size_t code_len) {
}
cmsg = CMSG_FIRSTHDR(&msg);
if (!cmsg)
if (!cmsg) {
free(msg_control);
return NULL;
}
if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
free(msg_control);
return NULL;
}
if ((size_t) (cmsg->cmsg_len - ((char *) CMSG_DATA(cmsg) - (char *) cmsg)) > (size_t) (sizeof(int) * (count + 1))) {
uwsgi_log("not enough space for sockets data, consider increasing it\n");
free(msg_control);
return NULL;
}
@@ -906,6 +987,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;
@@ -916,8 +998,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;
@@ -1185,6 +1269,7 @@ void uwsgi_setup_schemes() {
uwsgi_register_scheme("fd", uwsgi_scheme_fd);
uwsgi_register_scheme("exec", uwsgi_scheme_exec);
uwsgi_register_scheme("call", uwsgi_scheme_call);
uwsgi_register_scheme("callint", uwsgi_scheme_callint);
}
struct uwsgi_string_list *uwsgi_check_scheme(char *file) {
@@ -1216,3 +1301,204 @@ void uwsgi_remap_fd(int fd, char *filename) {
}
}
int uwsgi_is_connected(int fd) {
int soopt;
socklen_t solen = sizeof(int);
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *) (&soopt), &solen) < 0) {
return 0;
}
/* is something bad ? */
if (soopt) return 0;
return 1;
}
int uwsgi_pass_cred(int fd, char *code, size_t code_len) {
#ifdef SCM_CREDENTIALS
struct msghdr cr_msg;
struct cmsghdr *cmsg;
struct iovec cr_iov;
void *cr_msg_control = uwsgi_calloc(CMSG_SPACE(sizeof(struct ucred)));
cr_iov.iov_base = code;
cr_iov.iov_len = code_len;
cr_msg.msg_name = NULL;
cr_msg.msg_namelen = 0;
cr_msg.msg_iov = &cr_iov;
cr_msg.msg_iovlen = 1;
cr_msg.msg_flags = 0;
cr_msg.msg_control = cr_msg_control;
cr_msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
cmsg = CMSG_FIRSTHDR(&cr_msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_CREDENTIALS;
struct ucred *u = (struct ucred*) CMSG_DATA(cmsg);
u->pid = getpid();
u->uid = getuid();
u->gid = getgid();
if (sendmsg(fd, &cr_msg, 0) < 0) {
uwsgi_error("uwsgi_pass_cred()/sendmsg()");
free(cr_msg_control);
return -1;
}
free(cr_msg_control);
return 0;
#else
return -1;
#endif
}
int uwsgi_pass_cred2(int fd, char *code, size_t code_len, struct sockaddr *addr, size_t addr_len) {
#ifdef SCM_CREDENTIALS
struct msghdr cr_msg;
struct cmsghdr *cmsg;
struct iovec cr_iov;
void *cr_msg_control = uwsgi_calloc(CMSG_SPACE(sizeof(struct ucred)));
cr_iov.iov_base = code;
cr_iov.iov_len = code_len;
cr_msg.msg_name = addr;
cr_msg.msg_namelen = addr_len;
cr_msg.msg_iov = &cr_iov;
cr_msg.msg_iovlen = 1;
cr_msg.msg_flags = 0;
cr_msg.msg_control = cr_msg_control;
cr_msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
cmsg = CMSG_FIRSTHDR(&cr_msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_CREDENTIALS;
struct ucred *u = (struct ucred*) CMSG_DATA(cmsg);
u->pid = getpid();
u->uid = getuid();
u->gid = getgid();
if (sendmsg(fd, &cr_msg, 0) < 0) {
uwsgi_error("uwsgi_pass_cred2()/sendmsg()");
free(cr_msg_control);
return -1;
}
free(cr_msg_control);
return 0;
#else
return -1;
#endif
}
int uwsgi_recv_cred(int fd, char *code, size_t code_len, pid_t *pid, uid_t *uid, gid_t *gid) {
#ifdef SCM_CREDENTIALS
struct iovec iov;
int ret = -1;
void *msg_control = uwsgi_calloc(CMSG_SPACE(sizeof(struct ucred)));
iov.iov_base = uwsgi_malloc(code_len);
iov.iov_len = code_len;
struct msghdr msg;
memset(&msg, 0, sizeof(msg));
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = msg_control;
msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
ssize_t len = recvmsg(fd, &msg, 0);
if (len <= 0) {
uwsgi_error("uwsgi_recv_cred()/recvmsg()");
goto clear;
}
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
if (!cmsg) goto clear;
if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDENTIALS) {
goto clear;
}
if (uwsgi_strncmp(code, code_len, iov.iov_base, iov.iov_len)) goto clear;
struct ucred *u = (struct ucred *) CMSG_DATA(cmsg);
*pid = u->pid;
*uid = u->uid;
*gid = u->gid;
ret = 0;
clear:
free(msg_control);
free(iov.iov_base);
return ret;
#else
return -1;
#endif
}
ssize_t uwsgi_recv_cred2(int fd, char *buf, size_t buf_len, pid_t *pid, uid_t *uid, gid_t *gid) {
#ifdef SCM_CREDENTIALS
struct iovec iov;
ssize_t ret = -1;
void *msg_control = uwsgi_calloc(CMSG_SPACE(sizeof(struct ucred)));
iov.iov_base = buf;
iov.iov_len = buf_len;
struct msghdr msg;
memset(&msg, 0, sizeof(msg));
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = msg_control;
msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
ssize_t len = recvmsg(fd, &msg, 0);
if (len <= 0) {
uwsgi_error("uwsgi_recv_cred2()/recvmsg()");
goto clear;
}
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
if (!cmsg) goto clear;
if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDENTIALS) {
goto clear;
}
struct ucred *u = (struct ucred *) CMSG_DATA(cmsg);
*pid = u->pid;
*uid = u->uid;
*gid = u->gid;
ret = len;
clear:
free(msg_control);
return ret;
#else
return -1;
#endif
}
+199 -4
View File
@@ -4,13 +4,207 @@
extern struct uwsgi_server uwsgi;
#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[]) {
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;
}
}
uwsgi_log_initial("[uWSGI] getting JSON configuration from %s\n", file);
char *json_data = uwsgi_open_and_read(file, &len, 1, magic_table);
char errbuf[1024];
yajl_val node = yajl_tree_parse((const char *)json_data, errbuf, sizeof(errbuf));
if (!node) {
uwsgi_log("error parsing JSON data: %s\n", errbuf);
exit(1);
}
const char * path[] = { object_asked, NULL };
yajl_val v = yajl_tree_get(node, path, yajl_t_any);
if (!YAJL_IS_OBJECT(v)) {
uwsgi_log("you must define a object named %s in your JSON data\n", object_asked);
exit(1);
}
size_t i;
for(i=0;i<v->u.object.len;i++) {
char *key = (char *) v->u.object.keys[i];
yajl_val o = v->u.object.values[i];
if (YAJL_IS_STRING(o)) {
add_exported_option(key, YAJL_GET_STRING(o) , 0);
}
else if (YAJL_IS_TRUE(o)) {
add_exported_option(key, strdup("1"), 0);
}
else if (YAJL_IS_FALSE(o) || YAJL_IS_NULL(o)) {
add_exported_option(key, strdup("0"), 0);
}
else if (YAJL_IS_NUMBER(o) || YAJL_IS_INTEGER(o)) {
add_exported_option(key, YAJL_GET_NUMBER(o), 0);
}
else if (YAJL_IS_ARRAY(o)) {
size_t j;
for(j=0;j<o->u.array.len;j++) {
yajl_val a_o = o->u.array.values[j];
if (YAJL_IS_STRING(a_o)) {
add_exported_option(key, YAJL_GET_STRING(a_o) , 0);
}
else if (YAJL_IS_TRUE(a_o)) {
add_exported_option(key, strdup("1"), 0);
}
else if (YAJL_IS_FALSE(a_o) || YAJL_IS_NULL(a_o)) {
add_exported_option(key, strdup("0"), 0);
}
else if (YAJL_IS_NUMBER(a_o) || YAJL_IS_INTEGER(a_o)) {
add_exported_option(key, YAJL_GET_NUMBER(a_o), 0);
}
}
}
}
}
#else
#include <jansson.h>
/*
I really love the jansson library...
*/
void uwsgi_json_config(char *file, char *magic_table[]) {
size_t len = 0;
@@ -111,3 +305,4 @@ void uwsgi_json_config(char *file, char *magic_table[]) {
}
#endif
#endif
+61 -10
View File
@@ -277,8 +277,9 @@ static void legions_check_nodes_step2() {
memcpy(best_uuid, node->uuid, 36);
}
// go on if i am not an arbiter
else if (ul->valor > 0) {
// no potential Lord is available, i will propose myself
// no potential Lord is available, i will propose myself
// but only if i am not suspended...
else if (ul->valor > 0 && uwsgi_now() > ul->suspended_til) {
best_valor = ul->valor;
memcpy(best_uuid, ul->uuid, 36);
i_am_the_best = 1;
@@ -337,13 +338,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 +364,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 +409,7 @@ static void legions_check_nodes_step2() {
}
ul->last_warning = uwsgi_now();
}
next:
ul = ul->next;
}
}
@@ -496,8 +505,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 +607,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 +666,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 +690,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 +710,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 +773,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 +812,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 +851,7 @@ int uwsgi_legion_announce(struct uwsgi_legion *ul) {
return 0;
err:
uwsgi_buffer_destroy(ub);
free(encrypted);
return -1;
}
@@ -824,6 +868,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 +1157,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 +1180,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) {
@@ -1162,6 +1210,9 @@ next:
legion = legion->next;
}
// this must be called only by the master !!!
if (!uwsgi.workers) return;
if (uwsgi.workers[0].pid != getpid()) return;
uwsgi_legion_announce_death();
}
+151 -108
View File
@@ -3,6 +3,7 @@
#endif
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
#include <sys/user.h>
#include <sys/sysctl.h>
#include <kvm.h>
#elif defined(__sun__)
/* Terrible Hack !!! */
@@ -13,10 +14,6 @@
#define _FILE_OFFSET_BITS 64
#endif
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
#include <sys/sysctl.h>
#endif
#ifdef __DragonFly__
#include <uwsgi.h>
#endif
@@ -119,6 +116,36 @@ void uwsgi_log_verbose(const char *fmt, ...) {
}
/*
commodity function mainly useful in log rotation
*/
void uwsgi_logfile_write(const char *fmt, ...) {
va_list ap;
char logpkt[4096];
struct timeval tv;
char ctime_storage[26];
gettimeofday(&tv, NULL);
#if defined(__sun__) && !defined(__clang__)
ctime_r((const time_t *) &tv.tv_sec, ctime_storage, 26);
#else
ctime_r((const time_t *) &tv.tv_sec, ctime_storage);
#endif
memcpy(logpkt, ctime_storage, 24);
memcpy(logpkt + 24, " - ", 3);
int rlen = 24 + 3;
va_start(ap, fmt);
rlen += vsnprintf(logpkt + rlen, 4096 - rlen, fmt, ap);
va_end(ap);
// do not check for errors
rlen = write(uwsgi.original_log_fd, logpkt, rlen);
}
static void fix_logpipe_buf(int *fd) {
int so_bufsize;
@@ -271,19 +298,27 @@ void logto(char *logfile) {
}
/* stdout */
if (fd != 1) {
if (dup2(fd, 1) < 0) {
// if the log-master is already active, just re-set the original_log_fd
if (uwsgi.shared->worker_log_pipe[0] == -1) {
/* stdout */
if (fd != 1) {
if (dup2(fd, 1) < 0) {
uwsgi_error("dup2()");
exit(1);
}
close(fd);
}
/* stderr */
if (dup2(1, 2) < 0) {
uwsgi_error("dup2()");
exit(1);
}
close(fd);
}
/* stderr */
if (dup2(1, 2) < 0) {
uwsgi_error("dup2()");
exit(1);
uwsgi.original_log_fd = 2;
}
else {
uwsgi.original_log_fd = fd;
}
}
@@ -316,51 +351,51 @@ void uwsgi_setup_log() {
static struct uwsgi_logger *setup_choosen_logger(struct uwsgi_string_list *usl) {
char *id = NULL;
char *name = usl->value;
char *name = usl->value;
char *space = strchr(name, ' ');
if (space) {
int is_id = 1;
int i;
for (i = 0; i < (space - name); i++) {
if (!isalnum((int)name[i])) {
is_id = 0;
break;
}
}
if (is_id) {
id = uwsgi_concat2n(name, space - name, "", 0);
name = space + 1;
}
}
char *space = strchr(name, ' ');
if (space) {
int is_id = 1;
int i;
for (i = 0; i < (space - name); i++) {
if (!isalnum((int)name[i])) {
is_id = 0;
break;
}
}
if (is_id) {
id = uwsgi_concat2n(name, space - name, "", 0);
name = space + 1;
}
}
char *colon = strchr(name, ':');
if (colon) {
*colon = 0;
}
char *colon = strchr(name, ':');
if (colon) {
*colon = 0;
}
struct uwsgi_logger *choosen_logger = uwsgi_get_logger(name);
if (!choosen_logger) {
uwsgi_log("unable to find logger %s\n", name);
exit(1);
}
struct uwsgi_logger *choosen_logger = uwsgi_get_logger(name);
if (!choosen_logger) {
uwsgi_log("unable to find logger %s\n", name);
exit(1);
}
// make a copy of the logger
struct uwsgi_logger *copy_of_choosen_logger = uwsgi_malloc(sizeof(struct uwsgi_logger));
memcpy(copy_of_choosen_logger, choosen_logger, sizeof(struct uwsgi_logger));
choosen_logger = copy_of_choosen_logger;
choosen_logger->id = id;
choosen_logger->next = NULL;
// make a copy of the logger
struct uwsgi_logger *copy_of_choosen_logger = uwsgi_malloc(sizeof(struct uwsgi_logger));
memcpy(copy_of_choosen_logger, choosen_logger, sizeof(struct uwsgi_logger));
choosen_logger = copy_of_choosen_logger;
choosen_logger->id = id;
choosen_logger->next = NULL;
if (colon) {
choosen_logger->arg = colon + 1;
// check for empty string
if (*choosen_logger->arg == 0) {
choosen_logger->arg = NULL;
}
*colon = ':';
}
return choosen_logger;
if (colon) {
choosen_logger->arg = colon + 1;
// check for empty string
if (*choosen_logger->arg == 0) {
choosen_logger->arg = NULL;
}
*colon = ':';
}
return choosen_logger;
}
void uwsgi_setup_log_master(void) {
@@ -447,13 +482,19 @@ void uwsgi_check_logrotate(void) {
int need_rotation = 0;
int need_reopen = 0;
off_t logsize;
if (uwsgi.log_master) {
uwsgi.shared->logsize = lseek(uwsgi.original_log_fd, 0, SEEK_CUR);
logsize = lseek(uwsgi.original_log_fd, 0, SEEK_CUR);
}
else {
uwsgi.shared->logsize = lseek(2, 0, SEEK_CUR);
logsize = lseek(2, 0, SEEK_CUR);
}
if (logsize < 0) {
uwsgi_error("uwsgi_check_logrotate()/lseek()");
return;
}
uwsgi.shared->logsize = logsize;
if (uwsgi.log_maxsize > 0 && (uint64_t) uwsgi.shared->logsize > uwsgi.log_maxsize) {
need_rotation = 1;
@@ -475,51 +516,53 @@ void uwsgi_check_logrotate(void) {
}
}
void uwsgi_log_do_rotate(char *logfile, char *rotatedfile, off_t logsize, int log_fd) {
int need_free = 0;
char *rot_name = rotatedfile;
if (rot_name == NULL) {
char *ts_str = uwsgi_num2str((int) uwsgi_now());
rot_name = uwsgi_concat3(logfile, ".", ts_str);
free(ts_str);
need_free = 1;
}
// this will be rawly written to the logfile
uwsgi_logfile_write("logsize: %llu, triggering rotation to %s...\n", (unsigned long long) logsize, rot_name);
if (rename(logfile, rot_name) == 0) {
// reopen logfile and dup'it, on dup2 error, exit(1)
int fd = open(logfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP);
if (fd < 0) {
// this will be written to the original file
uwsgi_error_open(logfile);
exit(1);
}
else {
if (dup2(fd, log_fd) < 0) {
// this could be lost :(
uwsgi_error("uwsgi_log_do_rotate()/dup2()");
exit(1);
}
close(fd);
}
}
else {
uwsgi_error("unable to rotate log: rename()");
}
if (need_free)
free(rot_name);
}
void uwsgi_log_rotate() {
char message[1024];
if (!uwsgi.logfile) return;
char *rot_name = uwsgi.log_backupname;
int need_free = 0;
if (rot_name == NULL) {
char *ts_str = uwsgi_num2str((int) uwsgi_now());
rot_name = uwsgi_concat3(uwsgi.logfile, ".", ts_str);
free(ts_str);
need_free = 1;
}
int ret = snprintf(message, 1024, "[%d] logsize: %llu, triggering rotation to %s...\n", (int) uwsgi_now(), (unsigned long long) uwsgi.shared->logsize, rot_name);
if (ret > 0) {
if (write(uwsgi.original_log_fd, message, ret) != ret) {
// very probably this will never be printed
uwsgi_error("write()");
}
}
if (rename(uwsgi.logfile, rot_name) == 0) {
// reopen logfile dup'it and eventually gracefully reload workers;
int fd = open(uwsgi.logfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP);
if (fd < 0) {
uwsgi_error_open(uwsgi.logfile);
grace_them_all(0);
}
else {
if (dup2(fd, uwsgi.original_log_fd) < 0) {
uwsgi_error("dup2()");
grace_them_all(0);
}
close(fd);
}
}
else {
uwsgi_error("unable to rotate log: rename()");
}
if (need_free)
free(rot_name);
if (!uwsgi.logfile)
return;
uwsgi_log_do_rotate(uwsgi.logfile, uwsgi.log_backupname, uwsgi.shared->logsize, uwsgi.original_log_fd);
}
void uwsgi_log_reopen() {
char message[1024];
if (!uwsgi.logfile) return;
int ret = snprintf(message, 1024, "[%d] logsize: %llu, triggering log-reopen...\n", (int) uwsgi_now(), (unsigned long long) uwsgi.shared->logsize);
if (ret > 0) {
if (ret > 0 && ret < 1024) {
if (write(uwsgi.original_log_fd, message, ret) != ret) {
// very probably this will never be printed
uwsgi_error("write()");
@@ -535,7 +578,7 @@ void uwsgi_log_reopen() {
return;
}
ret = snprintf(message, 1024, "[%d] %s reopened.\n", (int) uwsgi_now(), uwsgi.logfile);
if (ret > 0) {
if (ret > 0 && ret < 1024) {
if (write(uwsgi.original_log_fd, message, ret) != ret) {
// very probably this will never be printed
uwsgi_error("write()");
@@ -547,7 +590,7 @@ void uwsgi_log_reopen() {
void log_request(struct wsgi_request *wsgi_req) {
int log_it = uwsgi.shared->options[UWSGI_OPTION_LOGGING];
int log_it = uwsgi.logging_options.enabled;
if (wsgi_req->do_not_log)
return;
@@ -557,25 +600,25 @@ void log_request(struct wsgi_request *wsgi_req) {
}
/* conditional logging */
if (uwsgi.shared->options[UWSGI_OPTION_LOG_ZERO] && wsgi_req->response_size == 0) {
if (uwsgi.logging_options.zero && wsgi_req->response_size == 0) {
goto logit;
}
if (uwsgi.shared->options[UWSGI_OPTION_LOG_SLOW] && (uint32_t) wsgi_req_time >= uwsgi.shared->options[UWSGI_OPTION_LOG_SLOW]) {
if (uwsgi.logging_options.slow && (uint32_t) wsgi_req_time >= uwsgi.logging_options.slow) {
goto logit;
}
if (uwsgi.shared->options[UWSGI_OPTION_LOG_4xx] && (wsgi_req->status >= 400 && wsgi_req->status <= 499)) {
if (uwsgi.logging_options._4xx && (wsgi_req->status >= 400 && wsgi_req->status <= 499)) {
goto logit;
}
if (uwsgi.shared->options[UWSGI_OPTION_LOG_5xx] && (wsgi_req->status >= 500 && wsgi_req->status <= 599)) {
if (uwsgi.logging_options._5xx && (wsgi_req->status >= 500 && wsgi_req->status <= 599)) {
goto logit;
}
if (uwsgi.shared->options[UWSGI_OPTION_LOG_BIG] && (wsgi_req->response_size >= uwsgi.shared->options[UWSGI_OPTION_LOG_BIG])) {
if (uwsgi.logging_options.big && (wsgi_req->response_size >= uwsgi.logging_options.big)) {
goto logit;
}
if (uwsgi.shared->options[UWSGI_OPTION_LOG_SENDFILE] && wsgi_req->via == UWSGI_VIA_SENDFILE) {
if (uwsgi.logging_options.sendfile && wsgi_req->via == UWSGI_VIA_SENDFILE) {
goto logit;
}
if (uwsgi.shared->options[UWSGI_OPTION_LOG_IOERROR] && wsgi_req->read_errors > 0 && wsgi_req->write_errors > 0) {
if (uwsgi.logging_options.ioerror && wsgi_req->read_errors > 0 && wsgi_req->write_errors > 0) {
goto logit;
}
@@ -660,7 +703,7 @@ void uwsgi_logit_simple(struct wsgi_request *wsgi_req) {
logvecpos++;
}
if (uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG] == 1) {
if (uwsgi.logging_options.memory_report == 1) {
rlen = snprintf(mempkt, 4096, "{address space usage: %lld bytes/%lluMB} {rss usage: %llu bytes/%lluMB} ", (unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size, (unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size / 1024 / 1024,
(unsigned long long) uwsgi.workers[uwsgi.mywid].rss_size, (unsigned long long) uwsgi.workers[uwsgi.mywid].rss_size / 1024 / 1024);
logvec[logvecpos].iov_base = mempkt;
@@ -891,7 +934,7 @@ struct uwsgi_logger *uwsgi_get_logger_from_id(char *id) {
struct uwsgi_logger *ul = uwsgi.choosen_logger;
while (ul) {
if (!strcmp(ul->id, id)) {
if (ul->id && !strcmp(ul->id, id)) {
return ul;
}
ul = ul->next;
@@ -1090,7 +1133,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);
@@ -1813,7 +1856,7 @@ static char *uwsgi_log_encoder_json(struct uwsgi_log_encoder *ule, char *msg, si
if (!uwsgi_strncmp(usl->value, usl->len, "msg", 3)) {
size_t msg_len = len;
if (msg[len-1] == '\n') msg_len--;
char *e_json = uwsgi_malloc(msg_len * 2);
char *e_json = uwsgi_malloc((msg_len * 2)+1);
escape_json(msg, msg_len, e_json);
if (uwsgi_buffer_append(ub, e_json, strlen(e_json))){
free(e_json);
@@ -1822,7 +1865,7 @@ static char *uwsgi_log_encoder_json(struct uwsgi_log_encoder *ule, char *msg, si
free(e_json);
}
else if (!uwsgi_strncmp(usl->value, usl->len, "msgnl", 5)) {
char *e_json = uwsgi_malloc(len * 2);
char *e_json = uwsgi_malloc((len * 2)+1);
escape_json(msg, len, e_json);
if (uwsgi_buffer_append(ub, e_json, strlen(e_json))){
free(e_json);
@@ -1843,7 +1886,7 @@ static char *uwsgi_log_encoder_json(struct uwsgi_log_encoder *ule, char *msg, si
int strftime_len = strftime(sftime, 64, buf, localtime(&now));
free(buf);
if (strftime_len > 0) {
char *e_json = uwsgi_malloc(strftime_len * 2);
char *e_json = uwsgi_malloc((strftime_len * 2)+1);
escape_json(sftime, strftime_len, e_json);
if (uwsgi_buffer_append(ub, e_json, strlen(e_json))){
free(e_json);
+182 -73
View File
@@ -7,6 +7,7 @@ void uwsgi_update_load_counters() {
int i;
uint64_t busy_workers = 0;
uint64_t idle_workers = 0;
static time_t last_sos = 0;
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
@@ -21,6 +22,15 @@ void uwsgi_update_load_counters() {
if (busy_workers >= (uint64_t) uwsgi.numproc) {
ushared->overloaded++;
if (uwsgi.vassal_sos) {
if (uwsgi.current_time - last_sos > uwsgi.vassal_sos) {
uwsgi_log_verbose("asking Emperor for reinforcements (overload: %llu)...\n", (unsigned long long) ushared->overloaded);
vassal_sos();
last_sos = uwsgi.current_time;
}
}
}
ushared->busy_workers = busy_workers;
@@ -135,6 +145,15 @@ void uwsgi_master_check_mercy() {
}
}
}
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].pid > 0 && uwsgi.mules[i].cursed_at) {
if (uwsgi_now() > uwsgi.mules[i].no_mercy_at) {
uwsgi_log_verbose("mule %d (pid: %d) is taking too much time to die...NO MERCY !!!\n", i + 1, uwsgi.mules[i].pid);
uwsgi_curse_mule(i, SIGKILL);
}
}
}
}
@@ -168,53 +187,34 @@ void expire_rb_timeouts(struct uwsgi_rbtree *tree) {
}
}
int uwsgi_get_tcp_info(int fd) {
static void get_tcp_info(struct uwsgi_socket *uwsgi_sock) {
#if defined(__linux__) || defined(__FreeBSD__)
int fd = uwsgi_sock->fd;
struct tcp_info ti;
socklen_t tis = sizeof(struct tcp_info);
if (!getsockopt(fd, IPPROTO_TCP, TCP_INFO, &uwsgi.shared->ti, &tis)) {
if (!getsockopt(fd, IPPROTO_TCP, TCP_INFO, &ti, &tis)) {
// checks for older kernels
#if defined(__linux__)
if (!uwsgi.shared->ti.tcpi_sacked) {
if (!ti.tcpi_sacked) {
#elif defined(__FreeBSD__)
if (!uwsgi.shared->ti.__tcpi_sacked) {
if (!ti.__tcpi_sacked) {
#endif
return 0;
return;
}
#if defined(__linux__)
uwsgi.shared->load = (uint64_t) uwsgi.shared->ti.tcpi_unacked;
uwsgi.shared->max_load = (uint64_t) uwsgi.shared->ti.tcpi_sacked;
uwsgi_sock->queue = (uint64_t) ti.tcpi_unacked;
uwsgi_sock->max_queue = (uint64_t) ti.tcpi_sacked;
#elif defined(__FreeBSD__)
uwsgi.shared->load = (uint64_t) uwsgi.shared->ti.__tcpi_unacked;
uwsgi.shared->max_load = (uint64_t) uwsgi.shared->ti.__tcpi_sacked;
uwsgi_sock->queue = (uint64_t) ti.__tcpi_unacked;
uwsgi_sock->max_queue = (uint64_t) ti.__tcpi_sacked;
#endif
uwsgi.shared->options[UWSGI_OPTION_BACKLOG_STATUS] = uwsgi.shared->load;
if (uwsgi.vassal_sos_backlog > 0 && uwsgi.has_emperor) {
if (uwsgi.shared->load >= (uint64_t) uwsgi.vassal_sos_backlog) {
// ask emperor for help
char byte = 30;
if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
uwsgi_error("write()");
}
else {
uwsgi_log("asking emperor for reinforcements (backlog: %llu)...\n", (unsigned long long) uwsgi.shared->load);
}
}
}
if (uwsgi.shared->load >= uwsgi.shared->max_load) {
uwsgi_log_verbose("*** uWSGI listen queue of socket %d full !!! (%llu/%llu) ***\n", fd, (unsigned long long) uwsgi.shared->load, (unsigned long long) uwsgi.shared->max_load);
uwsgi.shared->options[UWSGI_OPTION_BACKLOG_ERRORS]++;
}
return uwsgi.shared->load;
}
#endif
return 0;
#endif
}
@@ -227,25 +227,78 @@ int uwsgi_get_tcp_info(int fd) {
#ifdef SIOBKLGQ
int get_linux_unbit_SIOBKLGQ(int fd) {
static void get_linux_unbit_SIOBKLGQ(struct uwsgi_socket *uwsgi_sock) {
int fd = uwsgi_sock->fd;
int queue = 0;
if (ioctl(fd, SIOBKLGQ, &queue) >= 0) {
uwsgi.shared->load = queue;
uwsgi.shared->options[UWSGI_OPTION_BACKLOG_STATUS] = queue;
if (queue >= uwsgi.listen_queue) {
uwsgi_log_verbose("*** uWSGI listen queue of socket %d full !!! (%d/%d) ***\n", fd, queue, uwsgi.listen_queue);
uwsgi.shared->options[UWSGI_OPTION_BACKLOG_ERRORS]++;
}
return queue;
uwsgi_sock->queue = (uint64_t) queue;
uwsgi_sock->max_queue = (uint64_t) uwsgi.listen_queue;
}
return 0;
}
#endif
#endif
static void master_check_listen_queue() {
uint64_t backlog = 0;
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while(uwsgi_sock) {
if (uwsgi_sock->family == AF_INET) {
get_tcp_info(uwsgi_sock);
}
#ifdef __linux__
#ifdef SIOBKLGQ
else if (uwsgi_sock->family == AF_UNIX) {
get_linux_unbit_SIOBKLGQ(uwsgi_sock);
}
#endif
#endif
if (uwsgi_sock->queue > backlog) {
backlog = uwsgi_sock->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;
}
// TODO load should be something more advanced based on different values
uwsgi.shared->load = backlog;
uwsgi.shared->backlog = backlog;
if (uwsgi.vassal_sos_backlog > 0 && uwsgi.has_emperor) {
if (uwsgi.shared->backlog >= (uint64_t) uwsgi.vassal_sos_backlog) {
// ask emperor for help
uwsgi_log_verbose("asking Emperor for reinforcements (backlog: %llu)...\n", (unsigned long long) uwsgi.shared->backlog);
vassal_sos();
}
}
}
void vassal_sos() {
if (!uwsgi.has_emperor) {
uwsgi_log("[broodlord] instance not governed by an Emperor !!!\n");
return;
}
char byte = 30;
if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
uwsgi_error("vassal_sos()/write()");
}
}
int master_loop(char **argv, char **environ) {
@@ -306,6 +359,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]);
}
@@ -358,6 +417,18 @@ int master_loop(char **argv, char **environ) {
}
}
#ifdef __linux__
if (uwsgi.setns_socket) {
uwsgi.setns_socket_fd = bind_to_unix(uwsgi.setns_socket, uwsgi.listen_queue, 0, 0);
if (uwsgi.setns_socket_fd < 0) exit(1);
if (chmod(uwsgi.setns_socket, S_IRUSR|S_IWUSR)) {
uwsgi_error("[setns-socket] chmod()");
exit(1);
}
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.setns_socket_fd);
}
#endif
if (uwsgi.zerg_server) {
uwsgi.zerg_server_fd = bind_to_unix(uwsgi.zerg_server, uwsgi.listen_queue, 0, 0);
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.zerg_server_fd);
@@ -471,6 +542,24 @@ int master_loop(char **argv, char **environ) {
usl = usl->next;
}
uwsgi_check_touches(uwsgi.touch_signal);
// daemon touches
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
if (ud->touch) {
uwsgi_check_touches(ud->touch);
}
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();
@@ -518,6 +607,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);
@@ -578,10 +668,10 @@ int master_loop(char **argv, char **environ) {
if (diedpid == 0) {
/* all processes ok, doing status scan after N seconds */
check_interval = uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL];
check_interval = uwsgi.master_interval;
if (!check_interval) {
check_interval = 1;
uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL] = 1;
uwsgi.master_interval = 1;
}
@@ -680,43 +770,25 @@ int master_loop(char **argv, char **environ) {
// check for idle
uwsgi_master_check_idle();
check_interval = uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL];
check_interval = uwsgi.master_interval;
if (!check_interval) {
check_interval = 1;
uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL] = 1;
uwsgi.master_interval = 1;
}
// get listen_queue status
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
int tmp_queue = 0;
while (uwsgi_sock) {
if (uwsgi_sock->family == AF_INET) {
uwsgi_sock->queue = uwsgi_get_tcp_info(uwsgi_sock->fd);
}
#ifdef __linux__
#ifdef SIOBKLGQ
else if (uwsgi_sock->family == AF_UNIX) {
uwsgi_sock->queue = get_linux_unbit_SIOBKLGQ(uwsgi_sock->fd);
}
#endif
#endif
if (uwsgi_sock->queue > tmp_queue) {
tmp_queue = uwsgi_sock->queue;
}
uwsgi_sock = uwsgi_sock->next;
}
// fix queue size on multiple sockets
uwsgi.shared->load = tmp_queue;
// check listen_queue status
master_check_listen_queue();
int someone_killed = 0;
// check if some worker has to die (harakiri, evil checks...)
uwsgi_master_check_workers_deadline();
if (uwsgi_master_check_workers_deadline()) someone_killed++;
if (uwsgi_master_check_gateways_deadline()) someone_killed++;
if (uwsgi_master_check_mules_deadline()) someone_killed++;
if (uwsgi_master_check_spoolers_deadline()) someone_killed++;
if (uwsgi_master_check_crons_deadline()) someone_killed++;
uwsgi_master_check_gateways_deadline();
uwsgi_master_check_mules_deadline();
uwsgi_master_check_spoolers_deadline();
uwsgi_master_check_crons_deadline();
// this could trigger a complete exit...
uwsgi_master_check_mountpoints();
#ifdef __linux__
@@ -780,8 +852,35 @@ int master_loop(char **argv, char **environ) {
uwsgi_route_signal(signum);
uwsgi_log_verbose("[uwsgi-touch-signal] raising %u\n", signum);
}
// daemon touches
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
if (ud->pid > 0 && ud->touch) {
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)) {
// killing process group failed, try to kill by process id
if (kill(ud->pid, ud->stop_signal)) {
uwsgi_error("[uwsgi-daemon/touch] kill()");
}
}
}
}
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;
if (someone_killed > 0) sleep(1);
continue;
}
@@ -836,6 +935,7 @@ int master_loop(char **argv, char **environ) {
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].pid == diedpid) {
uwsgi_log("mule %d (pid: %d) annihilated\n", i + 1, (int) diedpid);
uwsgi.mules[i].pid = 0;
goto next;
}
}
@@ -883,6 +983,11 @@ next:
if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_FAILED_APP_CODE) {
uwsgi_log("OOPS ! failed loading app in worker %d (pid %d) :( trying again...\n", thewid, (int) diedpid);
if (uwsgi.lazy_apps && uwsgi.need_app) {
uwsgi_log_verbose("need-app requested, destroying the instance...\n");
kill_them_all(0);
continue;
}
}
else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_DE_HIJACKED_CODE) {
uwsgi_log("...restoring worker %d (pid: %d)...\n", thewid, (int) diedpid);
@@ -898,6 +1003,10 @@ next:
reap_them_all(0);
continue;
}
else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_GO_CHEAP_CODE) {
uwsgi_log("worker %d asked for cheap mode (pid: %d)...\n", thewid, (int) diedpid);
uwsgi.workers[thewid].cheaped = 1;
}
else if (uwsgi.workers[thewid].manage_next_request) {
if (WIFSIGNALED(waitpid_status)) {
uwsgi_log("DAMN ! worker %d (pid: %d) died, killed by signal %d :( trying respawn ...\n", thewid, (int) diedpid, (int) WTERMSIG(waitpid_status));
+91 -27
View File
@@ -25,6 +25,11 @@ int uwsgi_master_check_reload(char **argv) {
return 0;
}
}
for(i=0;i<uwsgi.mules_cnt;i++) {
if (uwsgi.mules[i].pid > 0) {
return 0;
}
}
uwsgi_reload(argv);
// never here (unless in shared library mode)
return -1;
@@ -34,27 +39,51 @@ int uwsgi_master_check_reload(char **argv) {
// check for chain reload
void uwsgi_master_check_chain() {
static time_t last_check = 0;
if (!uwsgi.status.chain_reloading) return;
int i;
int needed_procs = 0;
for(i=1;i<=uwsgi.numproc;i++) {
if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cheaped == 0) {
needed_procs++;
}
}
if (uwsgi.status.chain_reloading > needed_procs) {
uwsgi.status.chain_reloading = 0;
uwsgi_log_verbose("chain reloading complete\n");
}
uwsgi_block_signal(SIGHUP);
for(i=1;i<=uwsgi.numproc;i++) {
// do not curse a worker until the old one is ready
if (uwsgi.workers[i].accepting == 0) break;
if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].cursed_at == 0 && i == uwsgi.status.chain_reloading) {
uwsgi_curse(i, SIGHUP);
break;
// we need to ensure the previous worker (if alive) is accepting new requests
// before going on
if (uwsgi.status.chain_reloading > 1) {
struct uwsgi_worker *previous_worker = &uwsgi.workers[uwsgi.status.chain_reloading-1];
// is the previous worker alive ?
if (previous_worker->pid > 0 && !previous_worker->cheaped) {
// the worker has been respawned but it is still not ready
if (previous_worker->accepting == 0) {
time_t now = uwsgi_now();
if (now != last_check) {
uwsgi_log_verbose("chain is still waiting for worker %d...\n", uwsgi.status.chain_reloading-1);
last_check = now;
}
return;
}
}
}
// if all the processes are recycled, the chain is over
if (uwsgi.status.chain_reloading > uwsgi.numproc) {
uwsgi.status.chain_reloading = 0;
uwsgi_log_verbose("chain reloading complete\n");
return;
}
uwsgi_block_signal(SIGHUP);
int i;
for(i=uwsgi.status.chain_reloading;i<=uwsgi.numproc;i++) {
struct uwsgi_worker *uw = &uwsgi.workers[i];
if (uw->pid > 0 && !uw->cheaped && uw->accepting) {
// the worker could have been already cursed
if (uw->cursed_at == 0) {
uwsgi_log_verbose("chain next victim is worker %d\n", i);
uwsgi_curse(i, SIGHUP);
}
break;
}
else {
uwsgi.status.chain_reloading++;
}
}
uwsgi_unblock_signal(SIGHUP);
}
@@ -115,13 +144,28 @@ void uwsgi_master_check_idle() {
uwsgi.workers[i].cheaped = 1;
if (uwsgi.workers[i].pid == 0)
continue;
// first send SIGINT
kill(uwsgi.workers[i].pid, SIGINT);
// and start waiting upto 3 seconds
int j;
for(j=0;j<3;j++) {
sleep(1);
int ret = waitpid(uwsgi.workers[i].pid, &waitpid_status, WNOHANG);
if (ret == 0) continue;
if (ret == (int) uwsgi.workers[i].pid) goto done;
// on error, directly send SIGKILL
break;
}
kill(uwsgi.workers[i].pid, SIGKILL);
if (waitpid(uwsgi.workers[i].pid, &waitpid_status, 0) < 0) {
if (errno != ECHILD)
uwsgi_error("uwsgi_master_check_idle()/waitpid()");
}
else {
done:
uwsgi.workers[i].pid = 0;
uwsgi.workers[i].rss_size = 0;
uwsgi.workers[i].vsz_size = 0;
}
}
uwsgi_add_sockets_to_queue(uwsgi.master_queue, -1);
@@ -131,19 +175,22 @@ void uwsgi_master_check_idle() {
}
void uwsgi_master_check_workers_deadline() {
int uwsgi_master_check_workers_deadline() {
int i;
int ret = 0;
for (i = 1; i <= uwsgi.numproc; i++) {
/* first check for harakiri */
if (uwsgi.workers[i].harakiri > 0) {
if (uwsgi.workers[i].harakiri < (time_t) uwsgi.current_time) {
trigger_harakiri(i);
ret = 1;
}
}
/* then user-defined harakiri */
if (uwsgi.workers[i].user_harakiri > 0) {
if (uwsgi.workers[i].user_harakiri < (time_t) uwsgi.current_time) {
trigger_harakiri(i);
ret = 1;
}
}
// then for evil memory checkers
@@ -152,6 +199,7 @@ void uwsgi_master_check_workers_deadline() {
uwsgi_log("*** EVIL RELOAD ON WORKER %d ADDRESS SPACE: %lld (pid: %d) ***\n", i, (long long) uwsgi.workers[i].vsz_size, uwsgi.workers[i].pid);
kill(uwsgi.workers[i].pid, SIGKILL);
uwsgi.workers[i].vsz_size = 0;
ret = 1;
}
}
if (uwsgi.evil_reload_on_rss) {
@@ -159,15 +207,17 @@ void uwsgi_master_check_workers_deadline() {
uwsgi_log("*** EVIL RELOAD ON WORKER %d RSS: %lld (pid: %d) ***\n", i, (long long) uwsgi.workers[i].rss_size, uwsgi.workers[i].pid);
kill(uwsgi.workers[i].pid, SIGKILL);
uwsgi.workers[i].rss_size = 0;
ret = 1;
}
}
// check if worker was running longer than allowed lifetime
if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cheaped == 0 && uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME] > 0) {
if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cheaped == 0 && uwsgi.max_worker_lifetime > 0) {
uint64_t lifetime = uwsgi_now() - uwsgi.workers[i].last_spawn;
if (lifetime > uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME] && uwsgi.workers[i].manage_next_request == 1) {
if (lifetime > uwsgi.max_worker_lifetime && uwsgi.workers[i].manage_next_request == 1) {
uwsgi_log("worker %d lifetime reached, it was running for %llu second(s)\n", i, (unsigned long long) lifetime);
uwsgi.workers[i].manage_next_request = 0;
kill(uwsgi.workers[i].pid, SIGWINCH);
ret = 1;
}
}
@@ -176,29 +226,32 @@ void uwsgi_master_check_workers_deadline() {
}
return ret;
}
void uwsgi_master_check_gateways_deadline() {
int uwsgi_master_check_gateways_deadline() {
int i;
int ret = 0;
for (i = 0; i < ushared->gateways_cnt; i++) {
if (ushared->gateways_harakiri[i] > 0) {
if (ushared->gateways_harakiri[i] < (time_t) uwsgi.current_time) {
if (ushared->gateways[i].pid > 0) {
uwsgi_log("*** HARAKIRI ON GATEWAY %s %d (pid: %d) ***\n", ushared->gateways[i].name, ushared->gateways[i].num, ushared->gateways[i].pid);
kill(ushared->gateways[i].pid, SIGKILL);
ret = 1;
}
ushared->gateways_harakiri[i] = 0;
}
}
}
return ret;
}
void uwsgi_master_check_mules_deadline() {
int uwsgi_master_check_mules_deadline() {
int i;
int ret = 0;
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].harakiri > 0) {
@@ -206,6 +259,7 @@ void uwsgi_master_check_mules_deadline() {
uwsgi_log("*** HARAKIRI ON MULE %d HANDLING SIGNAL %d (pid: %d) ***\n", i + 1, uwsgi.mules[i].signum, uwsgi.mules[i].pid);
kill(uwsgi.mules[i].pid, SIGKILL);
uwsgi.mules[i].harakiri = 0;
ret = 1;
}
}
// user harakiri
@@ -214,26 +268,32 @@ void uwsgi_master_check_mules_deadline() {
uwsgi_log("*** HARAKIRI ON MULE %d (pid: %d) ***\n", i + 1, uwsgi.mules[i].pid);
kill(uwsgi.mules[i].pid, SIGKILL);
uwsgi.mules[i].user_harakiri = 0;
ret = 1;
}
}
}
return ret;
}
void uwsgi_master_check_spoolers_deadline() {
int uwsgi_master_check_spoolers_deadline() {
int ret = 0;
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
if (uspool->harakiri > 0 && uspool->harakiri < (time_t) uwsgi.current_time) {
uwsgi_log("*** HARAKIRI ON THE SPOOLER (pid: %d) ***\n", uspool->pid);
kill(uspool->pid, SIGKILL);
uspool->harakiri = 0;
ret = 1;
}
if (uspool->user_harakiri > 0 && uspool->user_harakiri < (time_t) uwsgi.current_time) {
uwsgi_log("*** HARAKIRI ON THE SPOOLER (pid: %d) ***\n", uspool->pid);
kill(uspool->pid, SIGKILL);
uspool->user_harakiri = 0;
ret = 1;
}
uspool = uspool->next;
}
return ret;
}
@@ -294,6 +354,7 @@ int uwsgi_master_check_daemons_death(int diedpid) {
int uwsgi_worker_is_busy(int wid) {
int i;
if (uwsgi.workers[uwsgi.mywid].sig) return 1;
for(i=0;i<uwsgi.cores;i++) {
if (uwsgi.workers[wid].cores[i].in_request) {
return 1;
@@ -316,15 +377,18 @@ int uwsgi_master_check_cron_death(int diedpid) {
return 0;
}
void uwsgi_master_check_crons_deadline() {
int uwsgi_master_check_crons_deadline() {
int ret = 0;
struct uwsgi_cron *uc = uwsgi.crons;
while (uc) {
if (uc->pid >= 0 && uc->harakiri > 0 && uc->harakiri < (time_t) uwsgi.current_time) {
uwsgi_log("*** HARAKIRI ON CRON \"%s\" (pid: %d) ***\n", uc->command, uc->pid);
kill(-uc->pid, SIGKILL);
ret = 1;
}
uc = uc->next;
}
return ret;
}
void uwsgi_master_check_mountpoints() {
+10
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) {
@@ -51,6 +55,12 @@ int uwsgi_master_manage_events(int interesting_fd) {
}
}
#ifdef __linux__
if (uwsgi.setns_socket && uwsgi.setns_socket_fd > -1 && interesting_fd == uwsgi.setns_socket_fd) {
uwsgi_master_manage_setns(uwsgi.setns_socket_fd);
}
#endif
if (uwsgi_fsmon_event(interesting_fd)) {
return 0;
}
+235 -33
View File
@@ -24,6 +24,15 @@ void uwsgi_curse(int wid, int sig) {
}
}
void uwsgi_curse_mule(int mid, int sig) {
uwsgi.mules[mid].cursed_at = uwsgi_now();
uwsgi.mules[mid].no_mercy_at = uwsgi.mules[mid].cursed_at + uwsgi.mule_reload_mercy;
if (sig) {
(void) kill(uwsgi.mules[mid].pid, sig);
}
}
static void uwsgi_signal_spoolers(int signum) {
struct uwsgi_spooler *uspool = uwsgi.spoolers;
@@ -43,13 +52,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++) {
@@ -60,14 +62,25 @@ void uwsgi_destroy_processes() {
}
}
// TODO mules can be programmed to be gracefully reloaded
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].pid > 0) {
kill(uwsgi.mules[i].pid, SIGKILL);
waitpid(uwsgi.mules[i].pid, &waitpid_status, 0);
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);
}
}
@@ -101,7 +114,7 @@ int uwsgi_calc_cheaper(void) {
int i;
static time_t last_check = 0;
int check_interval = uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL];
int check_interval = uwsgi.master_interval;
if (!last_check)
last_check = uwsgi_now();
@@ -149,6 +162,7 @@ int uwsgi_calc_cheaper(void) {
ignore_algo = 1;
}
uwsgi.cheaper_fifo_delta = 0;
goto safe;
}
// if cheaper limits wants to change worker count, then skip cheaper algo
@@ -159,6 +173,7 @@ int uwsgi_calc_cheaper(void) {
needed_workers = 0;
}
safe:
if (needed_workers > 0) {
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].cheaped == 1 && uwsgi.workers[i].pid == 0) {
@@ -186,6 +201,8 @@ int uwsgi_calc_cheaper(void) {
uwsgi_log("worker %d should die...\n", oldest_worker);
#endif
uwsgi.workers[oldest_worker].cheaped = 1;
uwsgi.workers[oldest_worker].rss_size = 0;
uwsgi.workers[oldest_worker].vsz_size = 0;
uwsgi.workers[oldest_worker].manage_next_request = 0;
uwsgi_curse(oldest_worker, SIGWINCH);
}
@@ -330,7 +347,7 @@ int uwsgi_cheaper_algo_backlog(int can_spawn) {
int i;
#ifdef __linux__
int backlog = uwsgi.shared->options[UWSGI_OPTION_BACKLOG_STATUS];
int backlog = uwsgi.shared->backlog;
#else
int backlog = 0;
#endif
@@ -383,28 +400,37 @@ void uwsgi_reload(char **argv) {
// call master cleanup hooks
uwsgi_master_cleanup_hooks();
// call atexit user exec
uwsgi_exec_atexit();
if (uwsgi.exit_on_reload) {
uwsgi_log("uWSGI: GAME OVER (insert coin)\n");
exit(0);
}
// call atexit user exec
uwsgi_exec_atexit();
uwsgi_log("binary reloading uWSGI...\n");
}
else {
uwsgi_log("fork()'ing uWSGI...\n");
}
// ask for configuration (if needed)
if (uwsgi.has_emperor && uwsgi.emperor_fd_config > -1) {
char byte = 2;
if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
uwsgi_error("uwsgi_reload()/write()");
}
}
uwsgi_log("chdir() to %s\n", uwsgi.cwd);
if (chdir(uwsgi.cwd)) {
uwsgi_error("chdir()");
uwsgi_error("uwsgi_reload()/chdir()");
}
/* 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;
@@ -543,9 +569,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]);
}
@@ -584,6 +611,21 @@ 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]);
}
#endif
// fd alarms
struct uwsgi_alarm_fd *uafd = uwsgi.alarm_fds;
while(uafd) {
close(uafd->fd);
uafd = uafd->next;
}
}
@@ -713,9 +755,9 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
goto end;
#ifdef __linux__
if (uwsgi_stats_keylong_comma(us, "listen_queue", (unsigned long long) uwsgi.shared->options[UWSGI_OPTION_BACKLOG_STATUS]))
if (uwsgi_stats_keylong_comma(us, "listen_queue", (unsigned long long) uwsgi.shared->backlog))
goto end;
if (uwsgi_stats_keylong_comma(us, "listen_queue_errors", (unsigned long long) uwsgi.shared->options[UWSGI_OPTION_BACKLOG_ERRORS]))
if (uwsgi_stats_keylong_comma(us, "listen_queue_errors", (unsigned long long) uwsgi.shared->backlog_errors))
goto end;
#endif
@@ -756,7 +798,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
// allocate 2x the size of original command
// in case we need to escape all chars
char *cmd = uwsgi_malloc(strlen(ud->command)*2);
char *cmd = uwsgi_malloc((strlen(ud->command)*2)+1);
escape_json(ud->command, strlen(ud->command), cmd);
if (uwsgi_stats_keyval_comma(us, "cmd", cmd)) {
free(cmd);
@@ -873,7 +915,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
goto end;
}
if (uwsgi.has_metrics) {
if (uwsgi.has_metrics && !uwsgi.stats_no_metrics) {
if (uwsgi_stats_key(us, "metrics"))
goto end;
@@ -957,6 +999,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;
@@ -1080,7 +1125,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
if (uwsgi_stats_keylong_comma(us, "exceptions", ua->exceptions))
goto end;
if (ua->chdir) {
if (*ua->chdir) {
if (uwsgi_stats_keyval(us, "chdir", ua->chdir))
goto end;
}
@@ -1102,6 +1147,8 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
if (uwsgi_stats_list_close(us))
goto end;
if (uwsgi.stats_no_cores) goto nocores;
if (uwsgi_stats_comma(us))
goto end;
@@ -1163,9 +1210,12 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
if (uwsgi_stats_list_close(us))
goto end;
nocores:
if (uwsgi_stats_object_close(us))
goto end;
if (i < uwsgi.numproc - 1) {
if (uwsgi_stats_comma(us))
goto end;
@@ -1241,7 +1291,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
if (uwsgi_stats_keyslong_comma(us, "week", (long long) ucron->week))
goto end;
char *cmd = uwsgi_malloc(strlen(ucron->command)*2);
char *cmd = uwsgi_malloc((strlen(ucron->command)*2)+1);
escape_json(ucron->command, strlen(ucron->command), cmd);
if (uwsgi_stats_keyval_comma(us, "command", cmd)) {
free(cmd);
@@ -1453,7 +1503,7 @@ void uwsgi_register_cheaper_algo(char *name, int (*func) (int)) {
void trigger_harakiri(int i) {
int j;
uwsgi_log("*** HARAKIRI ON WORKER %d (pid: %d, try: %d) ***\n", i, uwsgi.workers[i].pid, uwsgi.workers[i].pending_harakiri + 1);
uwsgi_log_verbose("*** HARAKIRI ON WORKER %d (pid: %d, try: %d) ***\n", i, uwsgi.workers[i].pid, uwsgi.workers[i].pending_harakiri + 1);
if (uwsgi.harakiri_verbose) {
#ifdef __linux__
int proc_file;
@@ -1501,15 +1551,12 @@ void trigger_harakiri(int i) {
}
}
kill(uwsgi.workers[i].pid, SIGUSR2);
// allow SIGUSR2 to be delivered
sleep(1);
uwsgi_dump_worker(i, "HARAKIRI");
kill(uwsgi.workers[i].pid, SIGKILL);
if (!uwsgi.workers[i].pending_harakiri)
uwsgi.workers[i].harakiri_count++;
uwsgi.workers[i].pending_harakiri++;
}
// to avoid races
}
@@ -1649,6 +1696,8 @@ void uwsgi_go_cheap() {
uwsgi.status.is_cheap = 1;
for (i = 1; i <= uwsgi.numproc; i++) {
uwsgi.workers[i].cheaped = 1;
uwsgi.workers[i].rss_size = 0;
uwsgi.workers[i].vsz_size = 0;
if (uwsgi.workers[i].pid == 0)
continue;
uwsgi_log("killing worker %d (pid: %d)\n", i, (int) uwsgi.workers[i].pid);
@@ -1661,3 +1710,156 @@ void uwsgi_go_cheap() {
uwsgi_add_sockets_to_queue(uwsgi.master_queue, -1);
uwsgi_log("cheap mode enabled: waiting for socket connection...\n");
}
#ifdef __linux__
void uwsgi_setns_preopen() {
struct dirent *de;
DIR *ns = opendir("/proc/self/ns");
if (!ns) {
uwsgi_error("uwsgi_setns_preopen()/opendir()");
exit(1);
}
while ((de = readdir(ns)) != NULL) {
if (strlen(de->d_name) > 0 && de->d_name[0] == '.') continue;
if (!strcmp(de->d_name, "user")) continue;
struct uwsgi_string_list *usl = NULL;
int found = 0;
uwsgi_foreach(usl, uwsgi.setns_socket_skip) {
if (!strcmp(de->d_name, usl->value)) {
found = 1;
break;
}
}
if (found) continue;
char *filename = uwsgi_concat2("/proc/self/ns/", de->d_name);
uwsgi.setns_fds[uwsgi.setns_fds_count] = open(filename, O_RDONLY);
if (uwsgi.setns_fds[uwsgi.setns_fds_count] < 0) {
uwsgi_error_open(filename);
free(filename);
exit(1);
}
free(filename);
uwsgi.setns_fds_count++;
}
closedir(ns);
}
void uwsgi_master_manage_setns(int fd) {
struct sockaddr_un snsun;
socklen_t snsun_len = sizeof(struct sockaddr_un);
int setns_client = accept(fd, (struct sockaddr *) &snsun, &snsun_len);
if (setns_client < 0) {
uwsgi_error("uwsgi_master_manage_setns()/accept()");
return;
}
int i;
int tmp_fds[64];
int *fds = tmp_fds;
int num_fds = 0;
struct msghdr sn_msg;
void *sn_msg_control;
struct iovec sn_iov[2];
struct cmsghdr *cmsg;
DIR *ns = NULL;
if (uwsgi.setns_fds_count) {
fds = uwsgi.setns_fds;
num_fds = uwsgi.setns_fds_count;
goto send;
}
struct dirent *de;
ns = opendir("/proc/self/ns");
if (!ns) {
close(setns_client);
uwsgi_error("uwsgi_master_manage_setns()/opendir()");
return;
}
while ((de = readdir(ns)) != NULL) {
if (strlen(de->d_name) > 0 && de->d_name[0] == '.') continue;
if (!strcmp(de->d_name, "user")) continue;
struct uwsgi_string_list *usl = NULL;
int found = 0;
uwsgi_foreach(usl, uwsgi.setns_socket_skip) {
if (!strcmp(de->d_name, usl->value)) {
found = 1;
break;
}
}
if (found) continue;
char *filename = uwsgi_concat2("/proc/self/ns/", de->d_name);
fds[num_fds] = open(filename, O_RDONLY);
if (fds[num_fds] < 0) {
uwsgi_error_open(filename);
free(filename);
goto clear;
}
free(filename);
num_fds++;
}
send:
sn_msg_control = uwsgi_malloc(CMSG_SPACE(sizeof(int) * num_fds));
sn_iov[0].iov_base = "uwsgi-setns";
sn_iov[0].iov_len = 11;
sn_iov[1].iov_base = &num_fds;
sn_iov[1].iov_len = sizeof(int);
sn_msg.msg_name = NULL;
sn_msg.msg_namelen = 0;
sn_msg.msg_iov = sn_iov;
sn_msg.msg_iovlen = 2;
sn_msg.msg_flags = 0;
sn_msg.msg_control = sn_msg_control;
sn_msg.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds);
cmsg = CMSG_FIRSTHDR(&sn_msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
int *sn_fd_ptr = (int *) CMSG_DATA(cmsg);
for(i=0;i<num_fds;i++) {
sn_fd_ptr[i] = fds[i];
}
if (sendmsg(setns_client, &sn_msg, 0) < 0) {
uwsgi_error("uwsgi_master_manage_setns()/sendmsg()");
}
free(sn_msg_control);
clear:
close(setns_client);
if (ns) {
closedir(ns);
for(i=0;i<num_fds;i++) {
close(fds[i]);
}
}
}
#endif
/*
this is racey, but the worst thing would be printing garbage in the logs...
*/
void uwsgi_dump_worker(int wid, char *msg) {
int i;
uwsgi_log_verbose("%s !!! worker %d status !!!\n", msg, wid);
for(i=0;i<uwsgi.cores;i++) {
struct uwsgi_core *uc = &uwsgi.workers[wid].cores[i];
struct wsgi_request *wsgi_req = &uc->req;
if (uc->in_request) {
uwsgi_log_verbose("%s [core %d] %.*s - %.*s %.*s since %llu\n", msg, i, wsgi_req->remote_addr_len, wsgi_req->remote_addr, wsgi_req->method_len, wsgi_req->method, wsgi_req->uri_len, wsgi_req->uri, (unsigned long long) (wsgi_req->start_of_request/(1000*1000)));
}
}
uwsgi_log_verbose("%s !!! end of worker %d status !!!\n",msg, wid);
}
+43 -10
View File
@@ -321,6 +321,7 @@ struct uwsgi_metric *uwsgi_register_keyval_metric(char *arg) {
char *m_initial_value = NULL;
char *m_children = NULL;
char *m_alias = NULL;
char *m_reset_after_push = NULL;
if (!strchr(arg, '=')) {
m_name = uwsgi_str(arg);
@@ -340,6 +341,7 @@ struct uwsgi_metric *uwsgi_register_keyval_metric(char *arg) {
"arg3n", &m_arg3n,
"children", &m_children,
"alias", &m_alias,
"reset_after_push", &m_reset_after_push,
NULL)) {
uwsgi_log("invalid metric keyval syntax: %s\n", arg);
exit(1);
@@ -381,6 +383,10 @@ struct uwsgi_metric *uwsgi_register_keyval_metric(char *arg) {
struct uwsgi_metric* um = uwsgi_register_metric(m_name, m_oid, type, collector, NULL, freq, NULL);
um->initial_value = initial_value;
if (m_reset_after_push){
um->reset_after_push = 1;
}
if (m_children) {
char *p, *ctx = NULL;
uwsgi_foreach_token(m_children, ";", p, ctx) {
@@ -427,6 +433,7 @@ struct uwsgi_metric *uwsgi_register_keyval_metric(char *arg) {
if (m_initial_value) free(m_initial_value);
if (m_children) free(m_children);
if (m_alias) free(m_alias);
if (m_reset_after_push) free(m_reset_after_push);
return um;
}
@@ -465,7 +472,7 @@ static void *uwsgi_metrics_loop(void *arg) {
if (uwsgi.metrics_dir && metric->map) {
if (value != new_value) {
int ret = snprintf(metric->map, uwsgi.page_size, "%lld\n", (long long) new_value);
if (ret > 0) {
if (ret > 0 && ret < uwsgi.page_size) {
memset(metric->map+ret, 0, 4096-ret);
}
}
@@ -613,7 +620,7 @@ struct uwsgi_metric *uwsgi_metric_find_by_asn(char *asn, size_t len) {
}\
if (!um) return -1;\
if (um->collector || um->type == UWSGI_METRIC_ALIAS) return -1;\
uwsgi_rlock(uwsgi.metrics_lock)
uwsgi_wlock(uwsgi.metrics_lock)
int uwsgi_metric_set(char *name, char *oid, int64_t value) {
um_op;
@@ -694,11 +701,27 @@ int64_t uwsgi_metric_getn(char *name, size_t nlen, char *oid, size_t olen) {
return ret;
}
#define uwsgi_metric_name(f, n) if (snprintf(buf, 4096, f, n) <= 1) { uwsgi_log("unable to register metric name %s\n", f); exit(1);}
#define uwsgi_metric_name2(f, n, n2) if (snprintf(buf, 4096, f, n, n2) <= 1) { uwsgi_log("unable to register metric name %s\n", f); exit(1);}
int uwsgi_metric_set_max(char *name, char *oid, int64_t value) {
um_op;
if (value > *um->value)
*um->value = value;
uwsgi_rwunlock(uwsgi.metrics_lock);
return 0;
}
#define uwsgi_metric_oid(f, n) if (snprintf(buf2, 4096, f, n) <= 1) { uwsgi_log("unable to register metric oid %s\n", f); exit(1);}
#define uwsgi_metric_oid2(f, n, n2) if (snprintf(buf2, 4096, f, n, n2) <= 1) { uwsgi_log("unable to register metric oid %s\n", f); exit(1);}
int uwsgi_metric_set_min(char *name, char *oid, int64_t value) {
um_op;
if ((value > um->initial_value || 0) && value < *um->value)
*um->value = value;
uwsgi_rwunlock(uwsgi.metrics_lock);
return 0;
}
#define uwsgi_metric_name(f, n) ret = snprintf(buf, 4096, f, n); if (ret <= 1 || ret >= 4096) { uwsgi_log("unable to register metric name %s\n", f); exit(1);}
#define uwsgi_metric_name2(f, n, n2) ret = snprintf(buf, 4096, f, n, n2); if (ret <= 1 || ret >= 4096) { uwsgi_log("unable to register metric name %s\n", f); exit(1);}
#define uwsgi_metric_oid(f, n) ret = snprintf(buf2, 4096, f, n); if (ret <= 1 || ret >= 4096) { uwsgi_log("unable to register metric oid %s\n", f); exit(1);}
#define uwsgi_metric_oid2(f, n, n2) ret = snprintf(buf2, 4096, f, n, n2); if (ret <= 1 || ret >= 4096) { uwsgi_log("unable to register metric oid %s\n", f); exit(1);}
void uwsgi_setup_metrics() {
@@ -732,6 +755,9 @@ void uwsgi_setup_metrics() {
struct uwsgi_metric *total_tx = uwsgi_register_metric_do("core.total_tx", "5.100", UWSGI_METRIC_COUNTER, "sum", NULL, 0, NULL, 1);
struct uwsgi_metric *total_rss = uwsgi_register_metric_do("core.total_rss", "5.101", UWSGI_METRIC_GAUGE, "sum", NULL, 0, NULL, 1);
struct uwsgi_metric *total_vsz = uwsgi_register_metric_do("core.total_vsz", "5.102", UWSGI_METRIC_GAUGE, "sum", NULL, 0, NULL, 1);
struct uwsgi_metric *total_avg_rt = uwsgi_register_metric_do("core.avg_response_time", "5.103", UWSGI_METRIC_GAUGE, "avg", NULL, 0, NULL, 1);
int ret;
// create the 'worker' namespace
int i;
@@ -750,19 +776,25 @@ void uwsgi_setup_metrics() {
uwsgi_register_metric(buf, buf2, UWSGI_METRIC_COUNTER, "ptr", &uwsgi.workers[i].respawn_count, 0, NULL);
uwsgi_metric_name("worker.%d.avg_response_time", i) ; uwsgi_metric_oid("3.%d.8", i);
uwsgi_register_metric(buf, buf2, UWSGI_METRIC_GAUGE, "ptr", &uwsgi.workers[i].avg_response_time, 0, NULL);
struct uwsgi_metric *avg_rt = uwsgi_register_metric(buf, buf2, UWSGI_METRIC_GAUGE, "ptr", &uwsgi.workers[i].avg_response_time, 0, NULL);
if (i > 0) uwsgi_metric_add_child(total_avg_rt, avg_rt);
uwsgi_metric_name("worker.%d.total_tx", i) ; uwsgi_metric_oid("3.%d.9", i);
struct uwsgi_metric *tx = uwsgi_register_metric(buf, buf2, UWSGI_METRIC_COUNTER, "ptr", &uwsgi.workers[i].tx, 0, NULL);
uwsgi_metric_add_child(total_tx, tx);
if (i > 0) uwsgi_metric_add_child(total_tx, tx);
uwsgi_metric_name("worker.%d.rss_size", i) ; uwsgi_metric_oid("3.%d.11", i);
struct uwsgi_metric *rss = uwsgi_register_metric(buf, buf2, UWSGI_METRIC_GAUGE, "ptr", &uwsgi.workers[i].rss_size, 0, NULL);
uwsgi_metric_add_child(total_rss, rss);
if (i > 0) uwsgi_metric_add_child(total_rss, rss);
uwsgi_metric_name("worker.%d.vsz_size", i) ; uwsgi_metric_oid("3.%d.12", i);
struct uwsgi_metric *vsz = uwsgi_register_metric(buf, buf2, UWSGI_METRIC_GAUGE, "ptr", &uwsgi.workers[i].vsz_size, 0, NULL);
uwsgi_metric_add_child(total_vsz, vsz);
if (i > 0) uwsgi_metric_add_child(total_vsz, vsz);
// skip core metrics for worker 0
if (i == 0) continue;
if (uwsgi.metrics_no_cores) continue;
int j;
for(j=0;j<uwsgi.cores;j++) {
@@ -794,6 +826,7 @@ void uwsgi_setup_metrics() {
uwsgi_metric_append(total_tx);
uwsgi_metric_append(total_rss);
uwsgi_metric_append(total_vsz);
uwsgi_metric_append(total_avg_rt);
// sockets
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
+11 -3
View File
@@ -54,6 +54,9 @@ static struct uwsgi_mount_flag umflags[] = {
#ifdef MS_REMOUNT
{"remount", MS_REMOUNT},
#endif
#ifdef MS_NOSUID
{"nosuid", MS_NOSUID},
#endif
#ifdef MS_SYNCHRONOUS
{"sync", MS_SYNCHRONOUS},
#endif
@@ -102,7 +105,7 @@ uint64_t uwsgi_mount_flag(char *mflag) {
return 0;
}
int uwsgi_mount(char *fs, char *what, char *where, char *flags) {
int uwsgi_mount(char *fs, char *what, char *where, char *flags, char *data) {
#if defined(__FreeBSD__) || defined(__GNU_kFreeBSD__)
struct iovec iov[6];
#endif
@@ -121,7 +124,7 @@ int uwsgi_mount(char *fs, char *what, char *where, char *flags) {
free(mflags);
parsed:
#ifdef __linux__
return mount(what, where, fs, mountflags, NULL);
return mount(what, where, fs, mountflags, data);
#elif defined(__FreeBSD__) || defined(__GNU_kFreeBSD__)
iov[0].iov_base = "fstype";
iov[0].iov_len = 7;
@@ -197,6 +200,7 @@ unmountable:
}
int uwsgi_mount_hook(char *arg) {
char *data = NULL;
char *tmp_arg = uwsgi_str(arg);
char *fs = tmp_arg;
char *what = strchr(fs, ' ');
@@ -208,8 +212,12 @@ int uwsgi_mount_hook(char *arg) {
char *flags = strchr(where, ' ');
if (flags) {
*flags = 0; flags++;
data = strchr(flags, ' ');
if (data) {
*data = 0; data++;
}
}
if (uwsgi_mount(fs, what, where, flags)) {
if (uwsgi_mount(fs, what, where, flags, data)) {
uwsgi_error("uwsgi_mount()");
free(tmp_arg);
return -1;
+9 -6
View File
@@ -43,7 +43,7 @@ void uwsgi_mule(int id) {
#endif
signal(SIGALRM, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGHUP, end_me);
signal(SIGINT, end_me);
signal(SIGTERM, end_me);
signal(SIGUSR1, SIG_IGN);
@@ -329,11 +329,13 @@ next:
}
}
int ret = poll(mulepoll, count + farms_count, timeout);
if (ret <= 0) {
uwsgi_error("poll");
int ret = -1;
retry:
ret = poll(mulepoll, count + farms_count, timeout);
if (ret < 0) {
uwsgi_error("uwsgi_mule_get_msg()/poll()");
}
else {
else if (ret > 0 ) {
if (mulepoll[0].revents & POLLIN) {
len = read(uwsgi.mules[uwsgi.muleid - 1].queue_pipe[1], message, buffer_size);
}
@@ -353,7 +355,7 @@ next:
if (interesting_fd > -1) {
len = read(interesting_fd, &uwsgi_signal, 1);
if (len <= 0) {
if (len < 0 && (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)) goto clear;
if (uwsgi_is_again()) goto retry;
uwsgi_log_verbose("uWSGI mule %d braying: my master died, i will follow him...\n", uwsgi.muleid);
end_me(0);
}
@@ -380,6 +382,7 @@ next:
}
if (len < 0) {
if (uwsgi_is_again()) goto retry;
uwsgi_error("read()");
goto clear;
}
+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;
}
+46
View File
@@ -55,6 +55,9 @@ static int uwsgi_offload_enqueue(struct wsgi_request *wsgi_req, struct uwsgi_off
}
return -1;
}
#ifdef UWSGI_DEBUG
uwsgi_log("[offload] created session %p\n", uor);
#endif
return 0;
}
@@ -159,6 +162,12 @@ static int u_offload_sendfile_prepare(struct wsgi_request *wsgi_req, struct uwsg
}
static void uwsgi_offload_close(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor) {
// call the free function asap
if (uor->free) {
uor->free(uor);
}
// close the socket and the file descriptor
if (uor->takeover && uor->s > -1) {
close(uor->s);
@@ -197,12 +206,41 @@ static void uwsgi_offload_close(struct uwsgi_thread *ut, struct uwsgi_offload_re
uwsgi_buffer_destroy(uor->ubuf);
}
if (uor->ubuf1) {
uwsgi_buffer_destroy(uor->ubuf1);
}
if (uor->ubuf2) {
uwsgi_buffer_destroy(uor->ubuf2);
}
if (uor->ubuf3) {
uwsgi_buffer_destroy(uor->ubuf3);
}
if (uor->ubuf4) {
uwsgi_buffer_destroy(uor->ubuf4);
}
if (uor->ubuf5) {
uwsgi_buffer_destroy(uor->ubuf5);
}
if (uor->ubuf6) {
uwsgi_buffer_destroy(uor->ubuf6);
}
if (uor->ubuf7) {
uwsgi_buffer_destroy(uor->ubuf7);
}
if (uor->ubuf8) {
uwsgi_buffer_destroy(uor->ubuf8);
}
if (uor->pipe[0] != -1) {
close(uor->pipe[1]);
close(uor->pipe[0]);
}
free(uor);
#ifdef UWSGI_DEBUG
uwsgi_log("[offload] destroyed session %p\n", uor);
#endif
}
static void uwsgi_offload_append(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor) {
@@ -237,6 +275,7 @@ static void uwsgi_offload_loop(struct uwsgi_thread *ut) {
void *events = event_queue_alloc(uwsgi.offload_threads_events);
for (;;) {
// TODO make timeout tunable
int nevents = event_queue_wait_multi(ut->queue, -1, events, uwsgi.offload_threads_events);
for (i = 0; i < nevents; i++) {
int interesting_fd = event_queue_interesting_fd(events, i);
@@ -456,6 +495,13 @@ static int u_offload_transfer_do(struct uwsgi_thread *ut, struct uwsgi_offload_r
// write event (or just connected)
case 1:
if (fd == uor->fd) {
// maybe we want only a connection...
if (uor->ubuf->pos == 0) {
uor->status = 2;
if (event_queue_add_fd_read(ut->queue, uor->s)) return -1;
if (event_queue_fd_write_to_read(ut->queue, uor->fd)) return -1;
return 0;
}
rlen = write(uor->fd, uor->ubuf->buf + uor->written, uor->ubuf->pos-uor->written);
if (rlen > 0) {
uor->written += rlen;
+1 -1
View File
@@ -77,7 +77,7 @@ int uwsgi_upload_progress_update(struct wsgi_request *wsgi_req, int fd, size_t r
char buf[4096];
int ret = snprintf(buf, 4096, "{ \"state\" : \"uploading\", \"received\" : %llu, \"size\" : %llu }\r\n", (unsigned long long) (wsgi_req->post_cl - remains), (unsigned long long) wsgi_req->post_cl);
if (ret < 0) {
if (ret <= 0 || ret >= 4096) {
return -1;
}
+67 -96
View File
@@ -18,81 +18,6 @@ static size_t get_content_length(char *buf, uint16_t size) {
}
ssize_t send_udp_message(uint8_t modifier1, uint8_t modifier2, char *host, char *message, uint16_t message_size) {
int fd;
struct sockaddr_in udp_addr;
struct sockaddr_un un_addr;
char *udp_port;
ssize_t ret;
struct uwsgi_header *uh;
udp_port = strchr(host, ':');
if (udp_port) {
udp_port[0] = 0;
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
uwsgi_error("socket()");
return -1;
}
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("socket()");
return -1;
}
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 (message) {
uh = (struct uwsgi_header *) message;
}
else {
uh = (struct uwsgi_header *) uwsgi_malloc(4);
}
uh->modifier1 = modifier1;
#ifdef __BIG_ENDIAN__
uh->pktsize = uwsgi_swap16(message_size);
#else
uh->pktsize = message_size;
#endif
uh->modifier2 = modifier2;
if (udp_port) {
ret = sendto(fd, (char *) uh, message_size + 4, 0, (struct sockaddr *) &udp_addr, sizeof(udp_addr));
udp_port[0] = ':';
}
else {
ret = sendto(fd, (char *) uh, message_size + 4, 0, (struct sockaddr *) &un_addr, sizeof(un_addr));
}
if (ret < 0) {
uwsgi_error("send_udp_message()/sendto()");
}
close(fd);
if ((char *) uh != message) {
free(uh);
}
return ret;
}
int uwsgi_read_response(int fd, struct uwsgi_header *uh, int timeout, char **buf) {
char *ptr = (char *) uh;
@@ -412,6 +337,12 @@ static int uwsgi_proto_check_11(struct wsgi_request *wsgi_req, char *key, char *
return 0;
}
if (!uwsgi_proto_key("HTTP_ORIGIN", 11)) {
wsgi_req->http_origin = buf;
wsgi_req->http_origin_len = len;
return 0;
}
return 0;
}
@@ -563,7 +494,7 @@ static int uwsgi_proto_check_18(struct wsgi_request *wsgi_req, char *key, char *
static int uwsgi_proto_check_20(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) {
if (uwsgi.log_x_forwarded_for && !uwsgi_proto_key("HTTP_X_FORWARDED_FOR", 20)) {
if (uwsgi.logging_options.log_x_forwarded_for && !uwsgi_proto_key("HTTP_X_FORWARDED_FOR", 20)) {
wsgi_req->remote_addr = buf;
wsgi_req->remote_addr_len = len;
return 0;
@@ -589,9 +520,33 @@ static int uwsgi_proto_check_22(struct wsgi_request *wsgi_req, char *key, char *
wsgi_req->if_modified_since_len = len;
return 0;
}
if (!uwsgi_proto_key("HTTP_SEC_WEBSOCKET_KEY", 22)) {
wsgi_req->http_sec_websocket_key = buf;
wsgi_req->http_sec_websocket_key_len = len;
return 0;
}
if (!uwsgi_proto_key("HTTP_X_FORWARDED_PROTO", 22)) {
wsgi_req->scheme = buf;
wsgi_req->scheme_len = len;
}
return 0;
}
static int uwsgi_proto_check_27(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) {
if (!uwsgi_proto_key("HTTP_SEC_WEBSOCKET_PROTOCOL", 27)) {
wsgi_req->http_sec_websocket_protocol = buf;
wsgi_req->http_sec_websocket_protocol_len = len;
return 0;
}
return 0;
}
void uwsgi_proto_hooks_setup() {
int i = 0;
for(i=0;i<UWSGI_PROTO_MAX_CHECK;i++) {
@@ -609,6 +564,7 @@ void uwsgi_proto_hooks_setup() {
uwsgi.proto_hooks[18] = uwsgi_proto_check_18;
uwsgi.proto_hooks[20] = uwsgi_proto_check_20;
uwsgi.proto_hooks[22] = uwsgi_proto_check_22;
uwsgi.proto_hooks[27] = uwsgi_proto_check_27;
}
@@ -780,25 +736,40 @@ next:
}
for (i = 0; i < uwsgi_apps_cnt; i++) {
//uwsgi_log("app mountpoint = %.*s\n", uwsgi_apps[i].mountpoint_len, uwsgi_apps[i].mountpoint);
if (orig_path_info_len >= uwsgi_apps[i].mountpoint_len) {
if (!uwsgi_startswith(orig_path_info, uwsgi_apps[i].mountpoint, uwsgi_apps[i].mountpoint_len) && uwsgi_apps[i].mountpoint_len > best_found) {
best_found = uwsgi_apps[i].mountpoint_len;
wsgi_req->script_name = uwsgi_apps[i].mountpoint;
wsgi_req->script_name_len = uwsgi_apps[i].mountpoint_len;
wsgi_req->path_info = orig_path_info + wsgi_req->script_name_len;
wsgi_req->path_info_len = orig_path_info_len - wsgi_req->script_name_len;
char* mountpoint = uwsgi_apps[i].mountpoint;
int mountpoint_len = uwsgi_apps[i].mountpoint_len;
wsgi_req->hvec[wsgi_req->script_name_pos].iov_base = wsgi_req->script_name;
wsgi_req->hvec[wsgi_req->script_name_pos].iov_len = wsgi_req->script_name_len;
wsgi_req->hvec[wsgi_req->path_info_pos].iov_base = wsgi_req->path_info;
wsgi_req->hvec[wsgi_req->path_info_pos].iov_len = wsgi_req->path_info_len;
#ifdef UWSGI_DEBUG
uwsgi_log("managed SCRIPT_NAME = %.*s PATH_INFO = %.*s\n", wsgi_req->script_name_len, wsgi_req->script_name, wsgi_req->path_info_len, wsgi_req->path_info);
#endif
}
// Ignore trailing mountpoint slashes
if (mountpoint_len > 0 && mountpoint[mountpoint_len - 1] == '/') {
mountpoint_len -= 1;
}
//uwsgi_log("app mountpoint = %.*s\n", uwsgi_apps[i].mountpoint_len, uwsgi_apps[i].mountpoint);
// Check if mountpoint could be a possible candidate
if (orig_path_info_len < mountpoint_len || // it should be shorter than or equal to path_info
mountpoint_len <= best_found || // it should be better than the previous found
// should have the same prefix of path_info
uwsgi_startswith(orig_path_info, mountpoint, mountpoint_len) ||
// and should not be "misleading"
(orig_path_info_len > mountpoint_len && orig_path_info[mountpoint_len] != '/' )) {
continue;
}
best_found = mountpoint_len;
wsgi_req->script_name = uwsgi_apps[i].mountpoint;
wsgi_req->script_name_len = uwsgi_apps[i].mountpoint_len;
wsgi_req->path_info = orig_path_info + wsgi_req->script_name_len;
wsgi_req->path_info_len = orig_path_info_len - wsgi_req->script_name_len;
wsgi_req->hvec[wsgi_req->script_name_pos].iov_base = wsgi_req->script_name;
wsgi_req->hvec[wsgi_req->script_name_pos].iov_len = wsgi_req->script_name_len;
wsgi_req->hvec[wsgi_req->path_info_pos].iov_base = wsgi_req->path_info;
wsgi_req->hvec[wsgi_req->path_info_pos].iov_len = wsgi_req->path_info_len;
#ifdef UWSGI_DEBUG
uwsgi_log("managed SCRIPT_NAME = %.*s PATH_INFO = %.*s\n", wsgi_req->script_name_len, wsgi_req->script_name, wsgi_req->path_info_len, wsgi_req->path_info);
#endif
}
}
}
@@ -1100,7 +1071,7 @@ char *uwsgi_req_append(struct wsgi_request *wsgi_req, char *key, uint16_t keylen
wsgi_req->var_cnt++;
ptr += keylen;
*ptr++ = (uint8_t) (vallen & 0xff);
*ptr++ = (uint8_t) ((vallen >> 8) & 0xff);
@@ -1167,13 +1138,13 @@ int uwsgi_req_append_path_info_with_index(struct wsgi_request *wsgi_req, char *i
*ptr ++= '/';
}
memcpy(ptr, index, index_len);
wsgi_req->hvec[wsgi_req->var_cnt].iov_base = new_path_info;
wsgi_req->hvec[wsgi_req->var_cnt].iov_len = wsgi_req->path_info_len;
wsgi_req->var_cnt++;
wsgi_req->uh->pktsize += 13 + wsgi_req->path_info_len;
wsgi_req->path_info = new_path_info;
return 0;
}
+5 -5
View File
@@ -123,7 +123,7 @@ static int consume_body_for_readline(struct wsgi_request *wsgi_req) {
// allocate more memory if needed
if (wsgi_req->post_readline_size - wsgi_req->post_readline_watermark == 0) {
memcpy(wsgi_req->post_readline_buf, wsgi_req->post_readline_buf + wsgi_req->post_readline_pos, wsgi_req->post_readline_watermark - wsgi_req->post_readline_pos);
memmove(wsgi_req->post_readline_buf, wsgi_req->post_readline_buf + wsgi_req->post_readline_pos, wsgi_req->post_readline_watermark - wsgi_req->post_readline_pos);
wsgi_req->post_readline_watermark -= wsgi_req->post_readline_pos;
wsgi_req->post_readline_pos = 0;
// still something to use ?
@@ -476,8 +476,8 @@ int uwsgi_postbuffer_do_in_mem(struct wsgi_request *wsgi_req) {
char *ptr = wsgi_req->post_buffering_buf;
while (remains > 0) {
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
inc_harakiri(uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
if (uwsgi.harakiri_options.workers > 0) {
inc_harakiri(uwsgi.harakiri_options.workers);
}
ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, ptr, remains);
@@ -550,8 +550,8 @@ int uwsgi_postbuffer_do_in_disk(struct wsgi_request *wsgi_req) {
while (post_remains > 0) {
// during post buffering we need to constantly reset the harakiri
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
inc_harakiri(uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
if (uwsgi.harakiri_options.workers > 0) {
inc_harakiri(uwsgi.harakiri_options.workers);
}
// we use the already available post buffering buffer to read chunks....
+174 -3
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;
@@ -582,6 +583,39 @@ static int uwsgi_router_break(struct uwsgi_route *ur, char *arg) {
return 0;
}
static int uwsgi_router_return_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route)
{
if (route->data_len < 3)
return UWSGI_ROUTE_BREAK;
uint16_t status_msg_len = 0;
const char *status_msg = uwsgi_http_status_msg(route->data, &status_msg_len);
if (!status_msg)
return UWSGI_ROUTE_BREAK;
char *buf = uwsgi_concat3n(route->data, route->data_len, " ", 1, (char *) status_msg, status_msg_len);
if (uwsgi_response_prepare_headers(wsgi_req, buf, route->data_len + 1 + status_msg_len))
goto end;
if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10))
goto end;
if (uwsgi_response_add_content_length(wsgi_req, status_msg_len))
goto end;
uwsgi_response_write_body_do(wsgi_req, (char *) status_msg, status_msg_len);
end:
free(buf);
return UWSGI_ROUTE_BREAK;
}
static int uwsgi_router_return(struct uwsgi_route *ur, char *arg)
{
ur->func = uwsgi_router_return_func;
ur->data = arg;
ur->data_len = strlen(arg);
return 0;
}
// simple math router
static int uwsgi_router_simple_math_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
@@ -705,7 +739,7 @@ static int uwsgi_router_flush(struct uwsgi_route *ur, char *arg) {
static int transform_fixcl(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
char buf[sizeof(UMAX64_STR)+1];
int ret = snprintf(buf, sizeof(UMAX64_STR)+1, "%llu", (unsigned long long) ut->chunk->pos);
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
if (ret <= 0 || ret >= (int) (sizeof(UMAX64_STR)+1)) {
wsgi_req->write_errors++;
return -1;
}
@@ -722,6 +756,27 @@ static int uwsgi_router_fixcl(struct uwsgi_route *ur, char *arg) {
return 0;
}
// force content length
static int transform_forcecl(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
char buf[sizeof(UMAX64_STR)+1];
int ret = snprintf(buf, sizeof(UMAX64_STR)+1, "%llu", (unsigned long long) ut->chunk->pos);
if (ret <= 0 || ret >= (int) (sizeof(UMAX64_STR)+1)) {
wsgi_req->write_errors++;
return -1;
}
// do not check for errors !!!
uwsgi_response_add_header_force(wsgi_req, "Content-Length", 14, buf, ret);
return 0;
}
static int uwsgi_router_forcecl_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
uwsgi_add_transformation(wsgi_req, transform_forcecl, NULL);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_forcecl(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_forcecl_func;
return 0;
}
// log route
static int uwsgi_router_log_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
@@ -942,6 +997,20 @@ static int uwsgi_router_clearheaders(struct uwsgi_route *ur, char *arg) {
return 0;
}
// disable headers
static int uwsgi_router_disableheaders_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
wsgi_req->headers_sent = 1;
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_disableheaders(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_disableheaders_func;
ur->data = arg;
ur->data_len = strlen(arg);
return 0;
}
// signal route
static int uwsgi_router_signal_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
@@ -1071,6 +1140,32 @@ static int uwsgi_router_seturi(struct uwsgi_route *ur, char *arg) {
ur->data_len = strlen(arg);
return 0;
}
// setremoteaddr route
static int uwsgi_router_setremoteaddr_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
if (!ub) return UWSGI_ROUTE_BREAK;
char *ptr = uwsgi_req_append(wsgi_req, "REMOTE_ADDR", 11, ub->buf, ub->pos);
if (!ptr) {
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_BREAK;
}
wsgi_req->remote_addr = ptr;
wsgi_req->remote_addr_len = ub->pos;
uwsgi_buffer_destroy(ub);
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_setremoteaddr(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_setremoteaddr_func;
ur->data = arg;
ur->data_len = strlen(arg);
return 0;
}
// setdocroot route
static int uwsgi_router_setdocroot_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
@@ -1120,6 +1215,27 @@ static int uwsgi_router_setpathinfo(struct uwsgi_route *ur, char *arg) {
return 0;
}
// fixpathinfo route
static int uwsgi_router_fixpathinfo_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
if (wsgi_req->script_name_len == 0)
return UWSGI_ROUTE_NEXT;
char *ptr = uwsgi_req_append(wsgi_req, "PATH_INFO", 9, wsgi_req->path_info+wsgi_req->script_name_len, wsgi_req->path_info_len - wsgi_req->script_name_len);
if (!ptr) {
return UWSGI_ROUTE_BREAK;
}
wsgi_req->path_info = wsgi_req->path_info+wsgi_req->script_name_len;
wsgi_req->path_info_len = wsgi_req->path_info_len - wsgi_req->script_name_len;
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_fixpathinfo(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_fixpathinfo_func;
ur->data = arg;
ur->data_len = strlen(arg);
return 0;
}
// setscheme route
static int uwsgi_router_setscheme_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
@@ -1144,6 +1260,26 @@ static int uwsgi_router_setscheme(struct uwsgi_route *ur, char *arg) {
return 0;
}
// setmodifiers
static int uwsgi_router_setmodifier1_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
wsgi_req->uh->modifier1 = ur->custom;
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_setmodifier1(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_setmodifier1_func;
ur->custom = atoi(arg);
return 0;
}
static int uwsgi_router_setmodifier2_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
wsgi_req->uh->modifier2 = ur->custom;
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_setmodifier2(struct uwsgi_route *ur, char *arg) {
ur->func = uwsgi_router_setmodifier2_func;
ur->custom = atoi(arg);
return 0;
}
// setuser route
static int uwsgi_router_setuser_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
@@ -1656,7 +1792,15 @@ static char *uwsgi_route_var_uwsgi(struct wsgi_request *wsgi_req, char *key, uin
}
else if (!uwsgi_strncmp(key, keylen, "lq", 2)) {
ret = uwsgi_num2str(uwsgi.shared->load);
ret = uwsgi_num2str(uwsgi.shared->backlog);
*vallen = strlen(ret);
}
else if (!uwsgi_strncmp(key, keylen, "rsize", 5)) {
ret = uwsgi_64bit2str(wsgi_req->response_size);
*vallen = strlen(ret);
}
else if (!uwsgi_strncmp(key, keylen, "sor", 3)) {
ret = uwsgi_64bit2str(wsgi_req->start_of_request);
*vallen = strlen(ret);
}
@@ -1669,7 +1813,7 @@ static char *uwsgi_route_var_mime(struct wsgi_request *wsgi_req, char *key, uint
char *var_value = uwsgi_get_var(wsgi_req, key, keylen, &var_vallen);
if (var_value) {
size_t mime_type_len = 0;
char *ret = uwsgi_get_mime_type(key, keylen, &mime_type_len);
ret = uwsgi_get_mime_type(var_value, var_vallen, &mime_type_len);
if (ret) *vallen = mime_type_len;
}
return ret;
@@ -1695,6 +1839,10 @@ static char *uwsgi_route_var_time(struct wsgi_request *wsgi_req, char *key, uint
ret = uwsgi_num2str(uwsgi_now());
*vallen = strlen(ret);
}
else if (!uwsgi_strncmp(key, keylen, "micros", 6)) {
ret = uwsgi_64bit2str(uwsgi_micros());
*vallen = strlen(ret);
}
return ret;
}
@@ -1726,6 +1874,8 @@ void uwsgi_register_embedded_routers() {
uwsgi_register_router("continue", uwsgi_router_continue);
uwsgi_register_router("last", uwsgi_router_continue);
uwsgi_register_router("break", uwsgi_router_break);
uwsgi_register_router("return", uwsgi_router_return);
uwsgi_register_router("break-with-status", uwsgi_router_return);
uwsgi_register_router("log", uwsgi_router_log);
uwsgi_register_router("donotlog", uwsgi_router_donotlog);
uwsgi_register_router("logvar", uwsgi_router_logvar);
@@ -1736,6 +1886,7 @@ void uwsgi_register_embedded_routers() {
uwsgi_register_router("remheader", uwsgi_router_remheader);
uwsgi_register_router("clearheaders", uwsgi_router_clearheaders);
uwsgi_register_router("resetheaders", uwsgi_router_clearheaders);
uwsgi_register_router("disableheaders", uwsgi_router_disableheaders);
uwsgi_register_router("signal", uwsgi_router_signal);
uwsgi_register_router("send", uwsgi_router_send);
uwsgi_register_router("send-crnl", uwsgi_router_send_crnl);
@@ -1747,12 +1898,17 @@ void uwsgi_register_embedded_routers() {
uwsgi_register_router("setscriptname", uwsgi_router_setscriptname);
uwsgi_register_router("setmethod", uwsgi_router_setmethod);
uwsgi_register_router("seturi", uwsgi_router_seturi);
uwsgi_register_router("setremoteaddr", uwsgi_router_setremoteaddr);
uwsgi_register_router("setpathinfo", uwsgi_router_setpathinfo);
uwsgi_register_router("fixpathinfo", uwsgi_router_fixpathinfo);
uwsgi_register_router("setdocroot", uwsgi_router_setdocroot);
uwsgi_register_router("setscheme", uwsgi_router_setscheme);
uwsgi_register_router("setprocname", uwsgi_router_setprocname);
uwsgi_register_router("alarm", uwsgi_router_alarm);
uwsgi_register_router("setmodifier1", uwsgi_router_setmodifier1);
uwsgi_register_router("setmodifier2", uwsgi_router_setmodifier2);
uwsgi_register_router("+", uwsgi_router_simple_math_plus);
uwsgi_register_router("-", uwsgi_router_simple_math_minus);
uwsgi_register_router("*", uwsgi_router_simple_math_multiply);
@@ -1760,6 +1916,7 @@ void uwsgi_register_embedded_routers() {
uwsgi_register_router("flush", uwsgi_router_flush);
uwsgi_register_router("fixcl", uwsgi_router_fixcl);
uwsgi_register_router("forcecl", uwsgi_router_forcecl);
uwsgi_register_router("harakiri", uwsgi_router_harakiri);
@@ -1940,5 +2097,19 @@ next4:
usl->custom2 = strlen(space+1);
uwsgi_log("collecting header %.*s to var %s\n", usl->custom, usl->value, usl->custom_ptr);
}
uwsgi_foreach(usl, uwsgi.pull_headers) {
char *space = strchr(usl->value, ' ');
if (!space) {
uwsgi_log("invalid pull header syntax, must be <header> <var>\n");
exit(1);
}
*space = 0;
usl->custom = strlen(usl->value);
*space = ' ';
usl->custom_ptr = space+1;
usl->custom2 = strlen(space+1);
uwsgi_log("pulling header %.*s to var %s\n", usl->custom, usl->value, usl->custom_ptr);
}
}
#endif
+11 -6
View File
@@ -104,8 +104,12 @@ char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t
if (node == NULL || !strcmp(node, "")) {
// allocate the whole buffer
if (!uwsgi.rpc_table) {
uwsgi_log("local rpc subsystem is still not initialized !!!\n");
return NULL;
}
*len = uwsgi_rpc(func, argc, argv, argvs, &buffer);
if (*buffer)
if (buffer)
return buffer;
return NULL;
}
@@ -117,7 +121,7 @@ char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t
return NULL;
// wait for connection;
int ret = uwsgi.wait_write_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
int ret = uwsgi.wait_write_hook(fd, uwsgi.socket_timeout);
if (ret <= 0) {
close(fd);
return NULL;
@@ -156,14 +160,14 @@ char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t
}
// ok the request is ready, let's send it in non blocking way
if (uwsgi_write_true_nb(fd, buffer, buffer_size+4, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
if (uwsgi_write_true_nb(fd, buffer, buffer_size+4, uwsgi.socket_timeout)) {
goto error;
}
// ok time to wait for the response in non blocking way
size_t rlen = buffer_size+4;
uint8_t modifier2 = 0;
if (uwsgi_read_with_realloc(fd, &buffer, &rlen, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], NULL, &modifier2)) {
if (uwsgi_read_with_realloc(fd, &buffer, &rlen, uwsgi.socket_timeout, NULL, &modifier2)) {
goto error;
}
@@ -181,7 +185,7 @@ char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t
rlen = content_len;
// read the raw value from the socket
if (uwsgi_read_whole_true_nb(fd, buffer, rlen, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
if (uwsgi_read_whole_true_nb(fd, buffer, rlen, uwsgi.socket_timeout)) {
goto error;
}
}
@@ -189,12 +193,13 @@ char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t
close(fd);
*len = rlen;
if (*len == 0) {
goto error;
goto error2;
}
return buffer;
error:
close(fd);
error2:
free(buffer);
return NULL;
+10 -1
View File
@@ -20,9 +20,18 @@ ssize_t uwsgi_sendfile_do(int sockfd, int filefd, size_t pos, size_t len) {
int sf_ret = sendfile(filefd, sockfd, pos, &sf_len, NULL, 0);
if (sf_ret == 0 || (sf_ret == -1 && errno == EAGAIN)) return sf_len;
return -1;
#elif defined(__linux__) || defined(__sun__) || defined(__GNU_kFreeBSD__)
#elif defined(__linux__) || defined(__GNU_kFreeBSD__)
off_t off = pos;
return sendfile(sockfd, filefd, &off, len);
#elif defined(__sun__)
off_t off = pos;
ssize_t wlen = sendfile(sockfd, filefd, &off, len);
if (wlen < 0 && uwsgi_is_again()) {
if (off - pos > 0) {
return off-pos;
}
}
return wlen;
#endif
no_sendfile:
+70 -13
View File
@@ -229,8 +229,11 @@ int uwsgi_sharedarea_wait(int id, int freq, int timeout) {
uwsgi_rlock(sa->lock);
uint64_t updates = sa->updates;
uwsgi_rwunlock(sa->lock);
while(timeout == 0 || (timeout > 0 && (waiting/1000) >= timeout)) {
uwsgi.wait_milliseconds_hook(freq);
while(timeout == 0 || waiting == 0 || (timeout > 0 && waiting > 0 && (waiting/1000) < timeout)) {
if (uwsgi.wait_milliseconds_hook(freq)) {
uwsgi_rwunlock(sa->lock);
return -1;
}
waiting += freq;
// lock sa
uwsgi_rlock(sa->lock);
@@ -266,14 +269,35 @@ static struct uwsgi_sharedarea *announce_sa(struct uwsgi_sharedarea *sa) {
return sa;
}
struct uwsgi_sharedarea *uwsgi_sharedarea_init_fd(int fd, uint64_t len, off_t offset) {
int id = uwsgi_sharedarea_new_id();
uwsgi.sharedareas[id] = uwsgi_calloc_shared(sizeof(struct uwsgi_sharedarea));
uwsgi.sharedareas[id]->area = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
if (uwsgi.sharedareas[id]->area == MAP_FAILED) {
uwsgi_error("uwsgi_sharedarea_init_fd()/mmap()");
exit(1);
}
uwsgi.sharedareas[id]->id = id;
uwsgi.sharedareas[id]->fd = fd;
uwsgi.sharedareas[id]->pages = len / (size_t) uwsgi.page_size;
if (len % (size_t) uwsgi.page_size != 0) uwsgi.sharedareas[id]->pages++;
uwsgi.sharedareas[id]->max_pos = len-1;
char *id_str = uwsgi_num2str(id);
uwsgi.sharedareas[id]->lock = uwsgi_rwlock_init(uwsgi_concat2("sharedarea", id_str));
free(id_str);
return announce_sa(uwsgi.sharedareas[id]);
}
struct uwsgi_sharedarea *uwsgi_sharedarea_init(int pages) {
int id = uwsgi_sharedarea_new_id();
uwsgi.sharedareas[id] = uwsgi_calloc_shared(uwsgi.page_size * (pages + 1));
uwsgi.sharedareas[id]->area = ((char *) uwsgi.sharedareas[id]) + uwsgi.page_size;
uwsgi.sharedareas[id] = uwsgi_calloc_shared((size_t)uwsgi.page_size * (size_t)(pages + 1));
uwsgi.sharedareas[id]->area = ((char *) uwsgi.sharedareas[id]) + (size_t) uwsgi.page_size;
uwsgi.sharedareas[id]->id = id;
uwsgi.sharedareas[id]->fd = -1;
uwsgi.sharedareas[id]->pages = pages;
uwsgi.sharedareas[id]->max_pos = (uwsgi.page_size * pages) -1;
uwsgi.sharedareas[id]->max_pos = ((size_t)uwsgi.page_size * (size_t)pages) -1;
char *id_str = uwsgi_num2str(id);
uwsgi.sharedareas[id]->lock = uwsgi_rwlock_init(uwsgi_concat2("sharedarea", id_str));
free(id_str);
@@ -286,8 +310,8 @@ struct uwsgi_sharedarea *uwsgi_sharedarea_init_ptr(char *area, uint64_t len) {
uwsgi.sharedareas[id]->area = area;
uwsgi.sharedareas[id]->id = id;
uwsgi.sharedareas[id]->fd = -1;
uwsgi.sharedareas[id]->pages = len / uwsgi.page_size;
if (len % uwsgi.page_size != 0) uwsgi.sharedareas[id]->pages++;
uwsgi.sharedareas[id]->pages = len / (size_t) uwsgi.page_size;
if (len % (size_t) uwsgi.page_size != 0) uwsgi.sharedareas[id]->pages++;
uwsgi.sharedareas[id]->max_pos = len-1;
char *id_str = uwsgi_num2str(id);
uwsgi.sharedareas[id]->lock = uwsgi_rwlock_init(uwsgi_concat2("sharedarea", id_str));
@@ -301,23 +325,40 @@ struct uwsgi_sharedarea *uwsgi_sharedarea_init_keyval(char *arg) {
char *s_fd = NULL;
char *s_ptr = NULL;
char *s_size = NULL;
char *s_offset = NULL;
if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=',
"pages", &s_pages,
"file", &s_file,
"fd", &s_fd,
"ptr", &s_ptr,
"size", &s_size,
"offset", &s_offset,
NULL)) {
uwsgi_log("invalid sharedarea keyval syntax\n");
exit(1);
}
uint64_t len = 0;
off_t offset = 0;
int pages = 0;
if (s_size) {
len = uwsgi_n64(s_size);
pages = len / uwsgi.page_size;
if (len % uwsgi.page_size != 0) pages++;
if (strlen(s_size) > 2 && s_size[0] == '0' && s_size[1] == 'x') {
len = strtoul(s_size+2, NULL, 16);
}
else {
len = uwsgi_n64(s_size);
}
pages = len / (size_t) uwsgi.page_size;
if (len % (size_t) uwsgi.page_size != 0) pages++;
}
if (s_offset) {
if (strlen(s_offset) > 2 && s_offset[0] == '0' && s_offset[1] == 'x') {
offset = strtoul(s_offset+2, NULL, 16);
}
else {
offset = uwsgi_n64(s_offset);
}
}
if (s_pages) {
@@ -326,27 +367,43 @@ struct uwsgi_sharedarea *uwsgi_sharedarea_init_keyval(char *arg) {
char *area = NULL;
struct uwsgi_sharedarea *sa = NULL;
int fd = -1;
if (s_file) {
fd = open(s_file, O_RDWR|O_SYNC);
if (fd < 0) {
uwsgi_error_open(s_file);
exit(1);
}
}
else if (s_fd) {
fd = atoi(s_fd);
}
else if (s_ptr) {
}
if (pages) {
if (!area) {
sa = uwsgi_sharedarea_init(pages);
if (fd > -1) {
sa = uwsgi_sharedarea_init_fd(fd, len, offset);
}
else if (area) {
sa = uwsgi_sharedarea_init_ptr(area, len);
}
else {
uwsgi_sharedarea_init_ptr(area, len);
sa = uwsgi_sharedarea_init(pages);
}
}
else {
uwsgi_log("you need to set a size for a sharedarea !!! [%s]\n", arg);
exit(1);
}
if (s_pages) free(s_pages);
if (s_file) free(s_file);
if (s_fd) free(s_fd);
if (s_ptr) free(s_ptr);
if (s_size) free(s_size);
if (s_offset) free(s_offset);
return sa;
}
+29 -17
View File
@@ -45,21 +45,21 @@ int uwsgi_signal_handler(uint8_t sig) {
uwsgi.workers[uwsgi.mywid].sig = 1;
uwsgi.workers[uwsgi.mywid].signum = sig;
uwsgi.workers[uwsgi.mywid].signals++;
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
set_harakiri(uwsgi.shared->options[UWSGI_OPTION_HARAKIRI]);
if (uwsgi.harakiri_options.workers > 0) {
set_harakiri(uwsgi.harakiri_options.workers);
}
}
else if (uwsgi.muleid > 0) {
uwsgi.mules[uwsgi.muleid - 1].sig = 1;
uwsgi.mules[uwsgi.muleid - 1].signum = sig;
uwsgi.mules[uwsgi.muleid - 1].signals++;
if (uwsgi.shared->options[UWSGI_OPTION_MULE_HARAKIRI] > 0) {
set_mule_harakiri(uwsgi.shared->options[UWSGI_OPTION_MULE_HARAKIRI]);
if (uwsgi.harakiri_options.mules > 0) {
set_mule_harakiri(uwsgi.harakiri_options.mules);
}
}
else if (uwsgi.i_am_a_spooler && (getpid() == uwsgi.i_am_a_spooler->pid)) {
if (uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
set_spooler_harakiri(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI]);
if (uwsgi.harakiri_options.spoolers > 0) {
set_spooler_harakiri(uwsgi.harakiri_options.spoolers);
}
}
@@ -78,7 +78,7 @@ int uwsgi_signal_handler(uint8_t sig) {
}
}
else if (uwsgi.i_am_a_spooler && (getpid() == uwsgi.i_am_a_spooler->pid)) {
if (uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
if (uwsgi.harakiri_options.spoolers > 0) {
set_spooler_harakiri(0);
}
}
@@ -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.shared->options[UWSGI_OPTION_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.shared->options[UWSGI_OPTION_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;
}
@@ -329,6 +331,16 @@ void uwsgi_route_signal(uint8_t sig) {
}
}
}
// send to al lactive workers
else if (!strcmp(use->receiver, "active-workers")) {
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].pid > 0 && !uwsgi.workers[i].cheaped && !uwsgi.workers[i].suspended) {
if (uwsgi_signal_send(uwsgi.workers[i].signal_pipe[0], sig)) {
uwsgi_log("could not deliver signal %d to worker %d\n", sig, i);
}
}
}
}
// route to specific worker
else if (!strncmp(use->receiver, "worker", 6)) {
i = atoi(use->receiver + 6);
+113 -96
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,14 @@ 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);
serverfd = create_server_socket(AF_UNIX, SOCK_STREAM);
if (serverfd < 0) {
uwsgi_error("socket()");
uwsgi_nuclear_blast();
free(uws_addr);
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 +203,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 +232,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 +263,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 +307,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
@@ -554,6 +566,7 @@ char *generate_socket_name(char *socket_name) {
ifa = ifap;
while (ifa) {
memset(new_addr, 0, 16);
if (!ifa->ifa_addr) goto next;
sin = (struct sockaddr_in *) ifa->ifa_addr;
if (inet_ntop(AF_INET, (void *) &sin->sin_addr.s_addr, new_addr, 16)) {
if (!strncmp(socket_name, new_addr, strlen(socket_name))) {
@@ -566,6 +579,7 @@ char *generate_socket_name(char *socket_name) {
}
next:
ifaf = ifa;
ifa = ifaf->ifa_next;
@@ -649,7 +663,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 +680,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
@@ -750,7 +735,7 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
if (!uwsgi.no_defer_accept) {
#ifdef __linux__
if (setsockopt(serverfd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], sizeof(int))) {
if (setsockopt(serverfd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &uwsgi.socket_timeout, sizeof(int))) {
uwsgi_error("TCP_DEFER_ACCEPT setsockopt()");
}
// OSX has no SO_ACCEPTFILTER !!!
@@ -781,15 +766,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();
@@ -1273,10 +1249,20 @@ void uwsgi_add_socket_from_fd(struct uwsgi_socket *uwsgi_sock, int fd) {
}
void uwsgi_close_all_sockets() {
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
if (uwsgi_sock->bound)
close(uwsgi_sock->fd);
uwsgi_sock = uwsgi_sock->next;
}
}
void uwsgi_close_all_unshared_sockets() {
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
if (uwsgi_sock->bound)
if (uwsgi_sock->bound && !uwsgi_sock->shared)
close(uwsgi_sock->fd);
uwsgi_sock = uwsgi_sock->next;
}
@@ -1762,13 +1748,6 @@ void uwsgi_bind_sockets() {
uwsgi_sock = uwsgi_sock->next;
}
if (uwsgi.chown_socket) {
if (!uwsgi.master_as_root) {
uwsgi_as_root();
}
}
int zero_used = 0;
uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
@@ -1789,6 +1768,24 @@ void uwsgi_bind_sockets() {
uwsgi_sock->fd = 0;
uwsgi_sock->bound = 1;
uwsgi_log("uwsgi socket %d inherited UNIX address %s fd 0\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name);
if (!uwsgi.is_a_reload) {
if (uwsgi.chown_socket) {
uwsgi_chown(uwsgi_sock->name, uwsgi.chown_socket);
}
if (uwsgi.chmod_socket) {
if (uwsgi.chmod_socket_value) {
if (chmod(uwsgi_sock->name, uwsgi.chmod_socket_value) != 0) {
uwsgi_error("inherit fd0: chmod()");
}
}
else {
uwsgi_log("chmod() fd0 socket to 666 for lazy and brave users\n");
if (chmod(uwsgi_sock->name, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) != 0) {
uwsgi_error("inherit fd0: chmod()");
}
}
}
}
}
else {
uwsgi_sock = uwsgi_new_socket(uwsgi_getsockname(0));
@@ -1823,6 +1820,13 @@ void uwsgi_bind_sockets() {
stdin_done:
if (uwsgi.chown_socket) {
if (!uwsgi.master_as_root) {
uwsgi_as_root();
}
}
// check for auto_port socket
uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
@@ -1928,6 +1932,19 @@ found:
return up;
}
int uwsgi_socket_passcred(int fd) {
#ifdef SO_PASSCRED
int optval = 1;
if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) < 0) {
uwsgi_error("uwsgi_socket_passcred()/setsockopt()");
return -1;
}
return 0;
#else
return -1;
#endif
}
void uwsgi_protocols_register() {
uwsgi_register_protocol("uwsgi", uwsgi_proto_uwsgi_setup);
uwsgi_register_protocol("puwsgi", uwsgi_proto_puwsgi_setup);
+115 -34
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,125 @@ 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)) {
// at can be a float...
char *dot = memchr(value, '.', value_len);
if (dot) {
value_len = dot - value;
}
sr->at = uwsgi_str_num(value, value_len);
return;
}
}
/*
CHANGED in 2.0.7: wsgi_req is useless !
*/
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 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;
}
}
// 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, rand(),
(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,
rand(), (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 +293,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 +311,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 +323,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 +353,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 +373,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 +448,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;
}
@@ -399,7 +480,7 @@ static void spooler_scandir(struct uwsgi_spooler *uspool, char *dir) {
if (!dir)
dir = uspool->dir;
n = scandir(dir, &tasklist, 0, versionsort);
n = scandir(dir, &tasklist, NULL, versionsort);
if (n < 0) {
uwsgi_error("scandir()");
return;
@@ -552,11 +633,11 @@ void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) {
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->spooler) {
time_t now = uwsgi_now();
if (uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
set_spooler_harakiri(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI]);
if (uwsgi.harakiri_options.spoolers > 0) {
set_spooler_harakiri(uwsgi.harakiri_options.spoolers);
}
ret = uwsgi.p[i]->spooler(task, spool_buf, uh.pktsize, body, body_len);
if (uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
if (uwsgi.harakiri_options.spoolers > 0) {
set_spooler_harakiri(0);
}
if (ret == 0)
+168 -18
View File
@@ -30,7 +30,18 @@ void uwsgi_ssl_info_cb(SSL const *ssl, int where, int ret) {
}
int uwsgi_ssl_verify_callback(int ok, X509_STORE_CTX * x509_store) {
return 1;
if (!ok && uwsgi.ssl_verbose) {
char buf[256];
X509 *err_cert;
int depth;
int err;
depth = X509_STORE_CTX_get_error_depth(x509_store);
err_cert = X509_STORE_CTX_get_current_cert(x509_store);
X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
err = X509_STORE_CTX_get_error(x509_store);
uwsgi_log("[uwsgi-ssl] client certificate verify error: num=%d:%s:depth=%d:%s\n", err, X509_verify_cert_error_string(err), depth, buf);
}
return ok;
}
int uwsgi_ssl_session_new_cb(SSL *ssl, SSL_SESSION *sess) {
@@ -95,15 +106,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,13 +160,12 @@ 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);
free(sni_dir_client_ca);
SSL_set_SSL_CTX(ssl, usl->custom_ptr);
uwsgi_log("[uwsgi-sni for pid %d] added context for %s\n", (int) getpid(), servername);
return SSL_TLSEXT_ERR_OK;
}
done:
@@ -140,13 +173,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);
@@ -162,15 +221,35 @@ SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ci
ssloptions |= SSL_OP_NO_COMPRESSION;
#endif
if (!uwsgi.sslv3) {
ssloptions |= SSL_OP_NO_SSLv3;
}
// release/reuse buffers as soon as possibile
#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
@@ -179,26 +258,43 @@ SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ci
DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
BIO_free(bio);
if (dh) {
SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
SSL_CTX_set_tmp_dh(ctx, dh);
DH_free(dh);
}
}
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
#ifndef OPENSSL_NO_ECDH
#ifdef NID_X9_62_prime256v1
EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
EC_KEY_free(ecdh);
EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
if (ecdh) {
SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE);
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
EC_KEY_free(ecdh);
}
#endif
#endif
#endif
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) {
@@ -226,19 +322,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);
}
@@ -297,6 +411,11 @@ SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ci
SSL_CTX_set_timeout(ctx, uwsgi.ssl_sessions_timeout);
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.ssl_options) {
ssloptions |= atoi(usl->value);
}
SSL_CTX_set_options(ctx, ssloptions);
@@ -511,10 +630,41 @@ struct uwsgi_string_list *uwsgi_ssl_add_sni_item(char *name, char *crt, char *ke
SSL_CTX *ctx = uwsgi_ssl_new_server_context(name, crt, key, ciphers, client_ca);
if (!ctx) {
uwsgi_log("[uwsgi-ssl] DANGER unable to initialize context for \"%s\"\n", name);
free(name);
return NULL;
}
struct uwsgi_string_list *usl = uwsgi_string_new_list(&uwsgi.sni, name);
usl->custom_ptr = ctx;
// mark it as dynamic
usl->custom = 1;
uwsgi_log_verbose("[uwsgi-sni for pid %d] added SSL context for %s\n", (int) getpid(), name);
return usl;
}
void uwsgi_ssl_del_sni_item(char *name, uint16_t name_len) {
struct uwsgi_string_list *usl = NULL, *last_sni = NULL, *sni_item = NULL;
uwsgi_foreach(usl, uwsgi.sni) {
if (!uwsgi_strncmp(usl->value, usl->len, name, name_len) && usl->custom) {
sni_item = usl;
break;
}
last_sni = usl;
}
if (!sni_item) return;
if (last_sni) {
last_sni->next = sni_item->next;
}
else {
uwsgi.sni = sni_item->next;
}
// we are free to destroy it as no more clients are using it
SSL_CTX_free((SSL_CTX *) sni_item->custom_ptr);
free(sni_item->value);
free(sni_item);
uwsgi_log_verbose("[uwsgi-sni for pid %d] destroyed SSL context for %s\n",(int) getpid(), name);
}
+16 -14
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);
}
}
@@ -458,25 +459,26 @@ int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, si
uwsgi_log("[uwsgi-fileserve] file %s found\n", real_filename);
#endif
// static file - don't update avg_rt after request
wsgi_req->do_not_account_avg_rt = 1;
size_t fsize = st->st_size;
if (wsgi_req->range_to) {
fsize = wsgi_req->range_to - wsgi_req->range_from;
if (fsize > (size_t)st->st_size) {
fsize = st->st_size;
}
// security check
if (wsgi_req->range_from > fsize) {
wsgi_req->range_from = 0;
wsgi_req->range_to = 0;
}
else {
// reset in case of inconsistent size
if (wsgi_req->range_from > fsize) {
wsgi_req->range_from = 0;
fsize = 0;
}
else {
fsize -= wsgi_req->range_from;
}
fsize -= wsgi_req->range_from;
}
if (wsgi_req->range_to) {
fsize = (wsgi_req->range_to - wsgi_req->range_from)+1;
if (fsize + wsgi_req->range_from > (size_t) (st->st_size)) {
fsize = st->st_size - wsgi_req->range_from;
}
}
// HTTP status
if (fsize > 0 && (wsgi_req->range_from || wsgi_req->range_to)) {
if (uwsgi_response_prepare_headers(wsgi_req, "206 Partial Content", 19)) return -1;
+22 -31
View File
@@ -111,7 +111,7 @@ int uwsgi_stats_keyval(struct uwsgi_stats *us, char *key, char *value) {
size_t available = watermark - ptr;
int ret = snprintf(ptr, available, "\"%s\":\"%s\"", key, value);
if (ret < 0)
if (ret <= 0)
return -1;
while (ret >= (int) available) {
char *new_base = realloc(us->base, us->size + us->chunk);
@@ -123,7 +123,7 @@ int uwsgi_stats_keyval(struct uwsgi_stats *us, char *key, char *value) {
watermark = us->base + us->size;
available = watermark - ptr;
ret = snprintf(ptr, available, "\"%s\":\"%s\"", key, value);
if (ret < 0)
if (ret <= 0)
return -1;
}
@@ -149,7 +149,7 @@ int uwsgi_stats_keyvalnum(struct uwsgi_stats *us, char *key, char *value, unsign
size_t available = watermark - ptr;
int ret = snprintf(ptr, available, "\"%s\":\"%s%llu\"", key, value, num);
if (ret < 0)
if (ret <= 0)
return -1;
while (ret >= (int) available) {
char *new_base = realloc(us->base, us->size + us->chunk);
@@ -161,7 +161,7 @@ int uwsgi_stats_keyvalnum(struct uwsgi_stats *us, char *key, char *value, unsign
watermark = us->base + us->size;
available = watermark - ptr;
ret = snprintf(ptr, available, "\"%s\":\"%s%llu\"", key, value, num);
if (ret < 0)
if (ret <= 0)
return -1;
}
@@ -188,7 +188,7 @@ int uwsgi_stats_keyvaln(struct uwsgi_stats *us, char *key, char *value, int vall
size_t available = watermark - ptr;
int ret = snprintf(ptr, available, "\"%s\":\"%.*s\"", key, vallen, value);
if (ret < 0)
if (ret <= 0)
return -1;
while (ret >= (int) available) {
char *new_base = realloc(us->base, us->size + us->chunk);
@@ -200,7 +200,7 @@ int uwsgi_stats_keyvaln(struct uwsgi_stats *us, char *key, char *value, int vall
watermark = us->base + us->size;
available = watermark - ptr;
ret = snprintf(ptr, available, "\"%s\":\"%.*s\"", key, vallen, value);
if (ret < 0)
if (ret <= 0)
return -1;
}
@@ -227,7 +227,7 @@ int uwsgi_stats_key(struct uwsgi_stats *us, char *key) {
size_t available = watermark - ptr;
int ret = snprintf(ptr, available, "\"%s\":", key);
if (ret < 0)
if (ret <= 0)
return -1;
while (ret >= (int) available) {
char *new_base = realloc(us->base, us->size + us->chunk);
@@ -239,7 +239,7 @@ int uwsgi_stats_key(struct uwsgi_stats *us, char *key) {
watermark = us->base + us->size;
available = watermark - ptr;
ret = snprintf(ptr, available, "\"%s\":", key);
if (ret < 0)
if (ret <= 0)
return -1;
}
@@ -254,7 +254,7 @@ int uwsgi_stats_str(struct uwsgi_stats *us, char *str) {
size_t available = watermark - ptr;
int ret = snprintf(ptr, available, "\"%s\"", str);
if (ret < 0)
if (ret <= 0)
return -1;
while (ret >= (int) available) {
char *new_base = realloc(us->base, us->size + us->chunk);
@@ -266,7 +266,7 @@ int uwsgi_stats_str(struct uwsgi_stats *us, char *str) {
watermark = us->base + us->size;
available = watermark - ptr;
ret = snprintf(ptr, available, "\"%s\"", str);
if (ret < 0)
if (ret <= 0)
return -1;
}
@@ -287,7 +287,7 @@ int uwsgi_stats_keylong(struct uwsgi_stats *us, char *key, unsigned long long nu
size_t available = watermark - ptr;
int ret = snprintf(ptr, available, "\"%s\":%llu", key, num);
if (ret < 0)
if (ret <= 0)
return -1;
while (ret >= (int) available) {
char *new_base = realloc(us->base, us->size + us->chunk);
@@ -299,7 +299,7 @@ int uwsgi_stats_keylong(struct uwsgi_stats *us, char *key, unsigned long long nu
watermark = us->base + us->size;
available = watermark - ptr;
ret = snprintf(ptr, available, "\"%s\":%llu", key, num);
if (ret < 0)
if (ret <= 0)
return -1;
}
@@ -325,7 +325,7 @@ int uwsgi_stats_keyslong(struct uwsgi_stats *us, char *key, long long num) {
size_t available = watermark - ptr;
int ret = snprintf(ptr, available, "\"%s\":%lld", key, num);
if (ret < 0)
if (ret <= 0)
return -1;
while (ret >= (int) available) {
char *new_base = realloc(us->base, us->size + us->chunk);
@@ -337,7 +337,7 @@ int uwsgi_stats_keyslong(struct uwsgi_stats *us, char *key, long long num) {
watermark = us->base + us->size;
available = watermark - ptr;
ret = snprintf(ptr, available, "\"%s\":%lld", key, num);
if (ret < 0)
if (ret <= 0)
return -1;
}
@@ -379,7 +379,7 @@ void uwsgi_send_stats(int fd, struct uwsgi_stats *(*func) (void)) {
size_t remains = us->pos;
off_t pos = 0;
while (remains > 0) {
int ret = uwsgi_waitfd_write(client_fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
int ret = uwsgi_waitfd_write(client_fd, uwsgi.socket_timeout);
if (ret <= 0) {
goto end0;
}
@@ -551,25 +551,16 @@ struct uwsgi_stats_pusher *uwsgi_register_stats_pusher(char *name, void (*func)
static void stats_dump_var(char *k, uint16_t kl, char *v, uint16_t vl, void *data) {
struct uwsgi_stats *us = (struct uwsgi_stats *) data;
if (us->dirty) return;
uint16_t i;
// replace " with '
for(i=0;i<kl;i++) {
if (k[i] == '"') {
k[i] = '\'';
}
}
for(i=0;i<vl;i++) {
if (v[i] == '"') {
v[i] = '\'';
}
}
char *var = uwsgi_concat3n(k, kl, "=", 1, v,vl);
if (uwsgi_stats_str(us, var)) {
char *escaped_var = uwsgi_malloc(((kl+vl+1)*2)+1);
escape_json(var, strlen(var), escaped_var);
free(var);
if (uwsgi_stats_str(us, escaped_var)) {
us->dirty = 1;
free(var);
free(escaped_var);
return;
}
free(var);
free(escaped_var);
if (uwsgi_stats_comma(us)) {
us->dirty = 1;
}
@@ -578,7 +569,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;
+495 -222
View File
@@ -20,6 +20,57 @@
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);
}
}
}
#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_subscribe_slot *uwsgi_get_subscribe_slot(struct uwsgi_subscribe_slot **slot, char *key, uint16_t keylen) {
if (keylen > 0xff)
@@ -301,10 +352,16 @@ 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);
}
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
// if there is a SNI context active, destroy it
if (node_slot->sni_enabled) {
uwsgi_ssl_del_sni_item(node_slot->key, node_slot->keylen);
}
#endif
#endif
free(node_slot);
slot[hash_key] = NULL;
@@ -324,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);
}
@@ -337,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;
@@ -345,28 +407,28 @@ 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)) {
return NULL;
}
#endif
if (uwsgi.subscriptions_credentials_check_dir && !uwsgi_subscription_credentials_check(current_slot, usr)) {
return NULL;
}
node = current_slot->nodes;
while (node) {
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;
}
// eventually the packet could be upgraded to sni...
uwsgi_subscription_sni_check(current_slot, usr);
#endif
// remove death mark and update cores and load
node->death_mark = 0;
@@ -384,10 +446,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);
#endif
node = uwsgi_malloc(sizeof(struct uwsgi_subscribe_node));
@@ -396,7 +460,8 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
node->modifier2 = usr->modifier2;
node->requests = 0;
node->last_requests = 0;
node->transferred = 0;
node->tx = 0;
node->rx = 0;
node->reference = 0;
node->death_mark = 0;
node->failcnt = 0;
@@ -407,6 +472,14 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
if (!node->weight)
node->weight = 1;
node->wrr = 0;
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);
@@ -414,66 +487,51 @@ 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);
current_slot->keylen = usr->keylen;
memcpy(current_slot->key, usr->key, usr->keylen);
if (uwsgi.subscriptions_credentials_check_dir) {
if (!uwsgi_subscription_credentials_check(current_slot, usr)) {
free(current_slot);
return NULL;
}
}
#endif
current_slot->keylen = usr->keylen;
memcpy(current_slot->key, usr->key, usr->keylen);
current_slot->key[usr->keylen] = 0;
current_slot->hits = 0;
#ifdef UWSGI_SSL
current_slot->sni_enabled = 0;
uwsgi_subscription_sni_check(current_slot, usr);
#endif
current_slot->nodes = uwsgi_malloc(sizeof(struct uwsgi_subscribe_node));
current_slot->nodes->slot = current_slot;
current_slot->nodes->len = usr->address_len;
current_slot->nodes->reference = 0;
current_slot->nodes->requests = 0;
current_slot->nodes->last_requests = 0;
current_slot->nodes->transferred = 0;
current_slot->nodes->tx = 0;
current_slot->nodes->rx = 0;
current_slot->nodes->death_mark = 0;
current_slot->nodes->failcnt = 0;
current_slot->nodes->modifier1 = usr->modifier1;
@@ -485,6 +543,14 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
if (!current_slot->nodes->weight)
current_slot->nodes->weight = 1;
current_slot->nodes->wrr = 0;
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();
@@ -511,42 +577,157 @@ 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(int sfd, char *host, char *message, uint16_t message_size) {
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) {
int fd = sfd;
struct sockaddr_in udp_addr;
struct sockaddr_un un_addr;
ssize_t ret;
if (socket_name == NULL && !uwsgi.sockets)
return;
char *udp_port = strchr(host, ':');
if (!socket_name) {
socket_name = uwsgi.sockets->name;
if (fd == -1) {
if (udp_port) {
fd = socket(AF_INET, SOCK_DGRAM, 0);
}
else {
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;
}
}
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.subscribe_with_modifier1) {
modifier1 = atoi(uwsgi.subscribe_with_modifier1);
}
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);
@@ -560,15 +741,98 @@ void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8
}
#endif
// add uwsgi header
if (uwsgi_buffer_set_uh(ub, 224, cmd))
goto end;
return ub;
send_udp_message(224, cmd, udp_address, ub->buf, ub->pos - 4);
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);
@@ -610,134 +874,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);
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);
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);
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);
}
@@ -752,25 +1015,20 @@ void uwsgi_subscribe2(char *arg, uint8_t cmd) {
char *s2_modifier1 = NULL;
char *s2_modifier2 = NULL;
char *s2_check = NULL;
char *s2_sni_key = NULL;
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,
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) {
@@ -798,41 +1056,56 @@ void uwsgi_subscribe2(char *arg, uint8_t cmd) {
modifier2 = atoi(s2_modifier2);
}
uwsgi_send_subscription(s2_server, s2_key, strlen(s2_key), modifier1, modifier2, cmd, s2_addr, s2_sign);
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);
if (s2_sni_crt)
free(s2_sni_crt);
if (s2_sni_key)
free(s2_sni_key);
if (s2_sni_ca)
free(s2_sni_ca);
}
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;
}
}
+446 -235
View File
@@ -47,7 +47,7 @@ void inc_harakiri(int sec) {
uwsgi.workers[uwsgi.mywid].harakiri += sec;
}
else {
alarm(uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] + sec);
alarm(uwsgi.harakiri_options.workers + sec);
}
}
@@ -206,7 +206,8 @@ void uwsgi_set_cgroup() {
if (!uwsgi.cgroup)
return;
if (getuid()) return;
if (getuid())
return;
usl = uwsgi.cgroup;
@@ -278,41 +279,41 @@ void uwsgi_set_cgroup() {
#endif
#ifdef UWSGI_CAP
void uwsgi_apply_cap(cap_value_t *cap, int caps_count) {
cap_value_t minimal_cap_values[] = { CAP_SYS_CHROOT, CAP_SETUID, CAP_SETGID, CAP_SETPCAP };
void uwsgi_apply_cap(cap_value_t * cap, int caps_count) {
cap_value_t minimal_cap_values[] = { CAP_SYS_CHROOT, CAP_SETUID, CAP_SETGID, CAP_SETPCAP };
cap_t caps = cap_init();
cap_t caps = cap_init();
if (!caps) {
uwsgi_error("cap_init()");
exit(1);
}
cap_clear(caps);
if (!caps) {
uwsgi_error("cap_init()");
exit(1);
}
cap_clear(caps);
cap_set_flag(caps, CAP_EFFECTIVE, 4, minimal_cap_values, CAP_SET);
cap_set_flag(caps, CAP_EFFECTIVE, 4, minimal_cap_values, CAP_SET);
cap_set_flag(caps, CAP_PERMITTED, 4, minimal_cap_values, CAP_SET);
cap_set_flag(caps, CAP_PERMITTED, caps_count, cap, CAP_SET);
cap_set_flag(caps, CAP_PERMITTED, 4, minimal_cap_values, CAP_SET);
cap_set_flag(caps, CAP_PERMITTED, caps_count, cap, CAP_SET);
cap_set_flag(caps, CAP_INHERITABLE, caps_count, cap, CAP_SET);
cap_set_flag(caps, CAP_INHERITABLE, caps_count, cap, CAP_SET);
if (cap_set_proc(caps) < 0) {
uwsgi_error("cap_set_proc()");
exit(1);
}
cap_free(caps);
if (cap_set_proc(caps) < 0) {
uwsgi_error("cap_set_proc()");
exit(1);
}
cap_free(caps);
#ifdef __linux__
#ifdef SECBIT_KEEP_CAPS
if (prctl(SECBIT_KEEP_CAPS, 1, 0, 0, 0) < 0) {
uwsgi_error("prctl()");
exit(1);
}
if (prctl(SECBIT_KEEP_CAPS, 1, 0, 0, 0) < 0) {
uwsgi_error("prctl()");
exit(1);
}
#else
if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) {
uwsgi_error("prctl()");
exit(1);
}
if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) {
uwsgi_error("prctl()");
exit(1);
}
#endif
#endif
}
@@ -517,7 +518,7 @@ void uwsgi_as_root() {
#endif
#endif
if (in_jail) {
if (in_jail || uwsgi.jailed) {
uwsgi_hooks_run(uwsgi.hook_post_jail, "post-jail", 1);
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.mount_post_jail) {
@@ -587,7 +588,7 @@ void uwsgi_as_root() {
exit(1);
}
#ifdef __linux__
if (uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG]) {
if (uwsgi.logging_options.memory_report) {
uwsgi_log("*** Warning, on linux system you have to bind-mount the /proc fs in your chroot to get memory debug/report.\n");
}
#endif
@@ -603,10 +604,10 @@ void uwsgi_as_root() {
}
*space = 0;
#if defined(MS_REC) && defined(MS_PRIVATE)
if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL)) {
uwsgi_error("mount()");
exit(1);
}
if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL)) {
uwsgi_error("mount()");
exit(1);
}
#endif
if (chdir(arg)) {
uwsgi_error("pivot_root()/chdir()");
@@ -619,7 +620,7 @@ void uwsgi_as_root() {
uwsgi_error("pivot_root()");
exit(1);
}
if (uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG]) {
if (uwsgi.logging_options.memory_report) {
uwsgi_log("*** Warning, on linux system you have to bind-mount the /proc fs in your chroot to get memory debug/report.\n");
}
free(arg);
@@ -632,25 +633,25 @@ void uwsgi_as_root() {
#endif
#if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL)
if (uwsgi.unshare2 && !uwsgi.reloads) {
if (uwsgi.unshare2 && !uwsgi.reloads) {
if (unshare(uwsgi.unshare2)) {
uwsgi_error("unshare()");
exit(1);
}
else {
uwsgi_log("[linux-namespace] applied unshare() mask: %d\n", uwsgi.unshare2);
}
if (unshare(uwsgi.unshare2)) {
uwsgi_error("unshare()");
exit(1);
}
else {
uwsgi_log("[linux-namespace] applied unshare() mask: %d\n", uwsgi.unshare2);
}
#ifdef CLONE_NEWUSER
if (uwsgi.unshare2 & CLONE_NEWUSER) {
if (setuid(0)) {
uwsgi_error("uwsgi_as_root()/setuid(0)");
exit(1);
}
}
if (uwsgi.unshare2 & CLONE_NEWUSER) {
if (setuid(0)) {
uwsgi_error("uwsgi_as_root()/setuid(0)");
exit(1);
}
}
#endif
in_jail = 1;
}
in_jail = 1;
}
#endif
if (uwsgi.refork_as_root) {
@@ -698,6 +699,22 @@ void uwsgi_as_root() {
}
}
uwsgi_foreach(usl, uwsgi.wait_for_fs) {
if (uwsgi_wait_for_fs(usl->value, 0)) exit(1);
}
uwsgi_foreach(usl, uwsgi.wait_for_file) {
if (uwsgi_wait_for_fs(usl->value, 1)) exit(1);
}
uwsgi_foreach(usl, uwsgi.wait_for_dir) {
if (uwsgi_wait_for_fs(usl->value, 2)) exit(1);
}
uwsgi_foreach(usl, uwsgi.wait_for_mountpoint) {
if (uwsgi_wait_for_mountpoint(usl->value)) exit(1);
}
uwsgi_hooks_run(uwsgi.hook_as_root, "as root", 1);
uwsgi_foreach(usl, uwsgi.mount_as_root) {
@@ -753,7 +770,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);
}
@@ -977,20 +998,51 @@ 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);
}
// reset for avoiding following requests to fail on non-uwsgi protocols
// thanks Marko Tiikkaja for catching it
wsgi_req->uh->pktsize = 0;
// some plugins expected async_id to be defined before setup
int tmp_id = wsgi_req->async_id;
memset(wsgi_req, 0, sizeof(struct wsgi_request));
wsgi_req->async_id = tmp_id;
}
// finalize/close/free a request
@@ -1021,13 +1073,14 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
uint64_t end_of_request = uwsgi_micros();
wsgi_req->end_of_request = end_of_request;
tmp_rt = wsgi_req->end_of_request - wsgi_req->start_of_request;
uwsgi.workers[uwsgi.mywid].running_time += tmp_rt;
uwsgi.workers[uwsgi.mywid].avg_response_time = (uwsgi.workers[uwsgi.mywid].avg_response_time + tmp_rt) / 2;
if (!wsgi_req->do_not_account_avg_rt) {
tmp_rt = wsgi_req->end_of_request - wsgi_req->start_of_request;
uwsgi.workers[uwsgi.mywid].running_time += tmp_rt;
uwsgi.workers[uwsgi.mywid].avg_response_time = (uwsgi.workers[uwsgi.mywid].avg_response_time + tmp_rt) / 2;
}
// get memory usage
if (uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG] == 1 || uwsgi.force_get_memusage) {
if (uwsgi.logging_options.memory_report == 1 || uwsgi.force_get_memusage) {
get_memusage(&rss, &vsz);
uwsgi.workers[uwsgi.mywid].vsz_size = vsz;
uwsgi.workers[uwsgi.mywid].rss_size = rss;
@@ -1048,27 +1101,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)
@@ -1077,7 +1111,7 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
// after_request custom hooks
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.after_request_hooks) {
void (*func)(struct wsgi_request *) = (void (*)(struct wsgi_request *)) usl->custom_ptr;
void (*func) (struct wsgi_request *) = (void (*)(struct wsgi_request *)) usl->custom_ptr;
func(wsgi_req);
}
@@ -1107,7 +1141,7 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
}
// defunct process reaper
if (uwsgi.shared->options[UWSGI_OPTION_REAPER] == 1) {
if (uwsgi.reaper == 1) {
while (waitpid(WAIT_ANY, &waitpid_status, WNOHANG) > 0);
}
@@ -1154,21 +1188,21 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
wsgi_req->uh->pktsize = 0;
tmp_id = wsgi_req->async_id;
memset(wsgi_req, 0, sizeof(struct wsgi_request));
// some plugins expected async_id to be defined before setup
wsgi_req->async_id = tmp_id;
// yes, this is pretty useless but we cannot ensure all of the plugin have the same behaviour
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 0;
if (uwsgi.shared->options[UWSGI_OPTION_MAX_REQUESTS] > 0 && uwsgi.workers[uwsgi.mywid].delta_requests >= uwsgi.shared->options[UWSGI_OPTION_MAX_REQUESTS]
&& (end_of_request - (uwsgi.workers[uwsgi.mywid].last_spawn * 1000000) >= uwsgi.shared->options[UWSGI_OPTION_MIN_WORKER_LIFETIME] * 1000000)) {
if (uwsgi.max_requests > 0 && uwsgi.workers[uwsgi.mywid].delta_requests >= uwsgi.max_requests
&& (end_of_request - (uwsgi.workers[uwsgi.mywid].last_spawn * 1000000) >= uwsgi.min_worker_lifetime * 1000000)) {
goodbye_cruel_world();
}
if (uwsgi.reload_on_as && (rlim_t) vsz >= uwsgi.reload_on_as && (end_of_request - (uwsgi.workers[uwsgi.mywid].last_spawn * 1000000) >= uwsgi.shared->options[UWSGI_OPTION_MIN_WORKER_LIFETIME] * 1000000)) {
if (uwsgi.reload_on_as && (rlim_t) vsz >= uwsgi.reload_on_as && (end_of_request - (uwsgi.workers[uwsgi.mywid].last_spawn * 1000000) >= uwsgi.min_worker_lifetime * 1000000)) {
goodbye_cruel_world();
}
if (uwsgi.reload_on_rss && (rlim_t) rss >= uwsgi.reload_on_rss && (end_of_request - (uwsgi.workers[uwsgi.mywid].last_spawn * 1000000) >= uwsgi.shared->options[UWSGI_OPTION_MIN_WORKER_LIFETIME] * 1000000)) {
if (uwsgi.reload_on_rss && (rlim_t) rss >= uwsgi.reload_on_rss && (end_of_request - (uwsgi.workers[uwsgi.mywid].last_spawn * 1000000) >= uwsgi.min_worker_lifetime * 1000000)) {
goodbye_cruel_world();
}
@@ -1344,13 +1378,13 @@ int wsgi_req_async_recv(struct wsgi_request *wsgi_req) {
if (event_queue_add_fd_read(uwsgi.async_queue, wsgi_req->fd) < 0)
return -1;
async_add_timeout(wsgi_req, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
async_add_timeout(wsgi_req, uwsgi.socket_timeout);
uwsgi.async_proto_fd_table[wsgi_req->fd] = wsgi_req;
}
// enter harakiri mode
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
set_harakiri(uwsgi.shared->options[UWSGI_OPTION_HARAKIRI]);
if (uwsgi.harakiri_options.workers > 0) {
set_harakiri(uwsgi.harakiri_options.workers);
}
return 0;
@@ -1381,8 +1415,8 @@ int wsgi_req_recv(int queue, struct wsgi_request *wsgi_req) {
}
// enter harakiri mode
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
set_harakiri(uwsgi.shared->options[UWSGI_OPTION_HARAKIRI]);
if (uwsgi.harakiri_options.workers > 0) {
set_harakiri(uwsgi.harakiri_options.workers);
}
#ifdef UWSGI_ROUTING
@@ -1431,7 +1465,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()");
@@ -1455,7 +1489,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 ?
@@ -1478,7 +1520,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) {
@@ -1560,15 +1602,7 @@ void parse_sys_envs(char **envs) {
char *earg, *eq_pos;
while (*uenvs) {
if (!strncmp(*uenvs, "UWSGI_", 6) &&
strncmp(*uenvs, "UWSGI_RELOADS=", 14) &&
strncmp(*uenvs, "UWSGI_VASSALS_DIR=", 18) &&
strncmp(*uenvs, "UWSGI_EMPEROR_FD=", 17) &&
strncmp(*uenvs, "UWSGI_BROODLORD_NUM=", 20) &&
strncmp(*uenvs, "UWSGI_EMPEROR_FD_CONFIG=", 24) &&
strncmp(*uenvs, "UWSGI_EMPEROR_PROXY=", 20) &&
strncmp(*uenvs, "UWSGI_JAIL_PID=", 15) &&
strncmp(*uenvs, "UWSGI_ORIGINAL_PROC_NAME=", 25)) {
if (!strncmp(*uenvs, "UWSGI_", 6) && strncmp(*uenvs, "UWSGI_RELOADS=", 14) && strncmp(*uenvs, "UWSGI_VASSALS_DIR=", 18) && strncmp(*uenvs, "UWSGI_EMPEROR_FD=", 17) && strncmp(*uenvs, "UWSGI_BROODLORD_NUM=", 20) && strncmp(*uenvs, "UWSGI_EMPEROR_FD_CONFIG=", 24) && strncmp(*uenvs, "UWSGI_EMPEROR_PROXY=", 20) && strncmp(*uenvs, "UWSGI_JAIL_PID=", 15) && strncmp(*uenvs, "UWSGI_ORIGINAL_PROC_NAME=", 25)) {
earg = uwsgi_malloc(strlen(*uenvs + 6) + 1);
env_to_arg(*uenvs + 6, earg);
eq_pos = strchr(earg, '=');
@@ -1871,7 +1905,7 @@ int uwsgi_num2str2n(int num, char *ptr, int size) {
int uwsgi_long2str2n(unsigned long long num, char *ptr, int size) {
int ret = snprintf(ptr, size, "%llu", num);
if (ret < 0)
if (ret <= 0 || ret > size)
return 0;
return ret;
}
@@ -2779,6 +2813,7 @@ static struct uwsgi_unshare_id uwsgi_unshare_list[] = {
{"ns", CLONE_NEWNS},
{"fs", CLONE_NEWNS},
{"mount", CLONE_NEWNS},
{"mnt", CLONE_NEWNS},
#endif
#ifdef CLONE_SYSVSEM
{"sysvsem", CLONE_SYSVSEM},
@@ -2898,7 +2933,7 @@ static int uwsgi_get_cap_id(char *name) {
return -1;
}
int uwsgi_build_cap(char *what, cap_value_t **cap) {
int uwsgi_build_cap(char *what, cap_value_t ** cap) {
int cap_id;
char *caps = uwsgi_str(what);
@@ -3143,6 +3178,10 @@ void escape_json(char *src, size_t len, char *dst) {
*ptr++ = '\\';
*ptr++ = '"';
}
else if (src[i] == '\\') {
*ptr++ = '\\';
*ptr++ = '\\';
}
else {
*ptr++ = src[i];
}
@@ -3192,128 +3231,139 @@ void http_url_decode(char *buf, uint16_t * len, char *dst) {
for (i = 0; i < *len; i++) {
char c = buf[i];
if (c == '#') break;
switch(status) {
case zero:
if (c == '%') {
status = percent1;
break;
}
if (c == '/') {
status = slash;
break;
}
*ptr++ = c;
new_len++;
if (c == '#')
break;
switch (status) {
case zero:
if (c == '%') {
status = percent1;
break;
case percent1:
if (c == '%') {
*ptr++ = '%';
new_len++;
status = zero;
break;
}
value[0] = c;
status = percent2;
}
if (c == '/') {
status = slash;
break;
case percent2:
value[1] = c;
*ptr++ = hex2num(value);
}
*ptr++ = c;
new_len++;
break;
case percent1:
if (c == '%') {
*ptr++ = '%';
new_len++;
status = zero;
break;
case slash:
if (c == '.') {
status = dot;
break;
}
// we could be at the first round (in non slash)
if (i > 0 || !no_slash) {
*ptr++ = '/'; new_len++;
}
if (c == '%') {
status = percent1;
break;
}
if (c == '/') {
status = slash;
break;
}
*ptr++ = c; new_len++;
status = zero;
}
value[0] = c;
status = percent2;
break;
case percent2:
value[1] = c;
*ptr++ = hex2num(value);
new_len++;
status = zero;
break;
case slash:
if (c == '.') {
status = dot;
break;
case dot:
if (c == '.') {
status = dotdot;
break;
}
if (c == '/') {
status = slash;
break;
}
if (i > 1) {
*ptr++ = '/'; new_len++;
}
*ptr++ = '.'; new_len++;
if (c == '%') {
status = percent1;
break;
}
*ptr++ = c; new_len++;
status = zero;
}
// we could be at the first round (in non slash)
if (i > 0 || !no_slash) {
*ptr++ = '/';
new_len++;
}
if (c == '%') {
status = percent1;
break;
case dotdot:
// here we need to remove a segment
if (c == '/') {
current_new_len = new_len;
while(current_new_len) {
current_new_len--;
ptr--;
if (dst[current_new_len] == '/') {
break;
}
}
if (c == '/') {
status = slash;
break;
}
*ptr++ = c;
new_len++;
status = zero;
break;
case dot:
if (c == '.') {
status = dotdot;
break;
}
if (c == '/') {
status = slash;
break;
}
if (i > 1) {
*ptr++ = '/';
new_len++;
}
*ptr++ = '.';
new_len++;
if (c == '%') {
status = percent1;
break;
}
*ptr++ = c;
new_len++;
status = zero;
break;
case dotdot:
// here we need to remove a segment
if (c == '/') {
current_new_len = new_len;
while (current_new_len) {
current_new_len--;
ptr--;
if (dst[current_new_len] == '/') {
break;
}
new_len = current_new_len;
status = slash;
break;
}
if (i > 2) {
*ptr++ = '/'; new_len++;
}
*ptr++ = '.'; new_len++;
*ptr++ = '.'; new_len++;
if (c == '%') {
status = percent1;
break;
}
*ptr++ = c; new_len++;
status = zero;
break;
new_len = current_new_len;
status = slash;
break;
}
if (i > 2) {
*ptr++ = '/';
new_len++;
}
*ptr++ = '.';
new_len++;
*ptr++ = '.';
new_len++;
if (c == '%') {
status = percent1;
break;
}
*ptr++ = c;
new_len++;
status = zero;
break;
// over engineering
default:
*ptr++ = c;
new_len++;
break;
default:
*ptr++ = c;
new_len++;
break;
}
}
switch(status) {
case slash:
case dot:
*ptr++ = '/'; new_len++;
break;
case dotdot:
current_new_len = new_len;
while(current_new_len) {
if (dst[current_new_len-1] == '/') {
break;
}
current_new_len--;
switch (status) {
case slash:
case dot:
*ptr++ = '/';
new_len++;
break;
case dotdot:
current_new_len = new_len;
while (current_new_len) {
if (dst[current_new_len - 1] == '/') {
break;
}
new_len = current_new_len;
break;
default:
break;
current_new_len--;
}
new_len = current_new_len;
break;
default:
break;
}
*len = new_len;
@@ -3365,7 +3415,7 @@ struct uwsgi_app *uwsgi_add_app(int id, uint8_t modifier1, char *mountpoint, int
}
if (!uwsgi.no_default_app) {
if ((mountpoint_len == 0 || (mountpoint_len = -1 && mountpoint[0] == '/')) && uwsgi.default_app == -1) {
if ((mountpoint_len == 0 || (mountpoint_len == 1 && mountpoint[0] == '/')) && uwsgi.default_app == -1) {
uwsgi.default_app = id;
}
}
@@ -3464,7 +3514,7 @@ int uwsgi_tmpfd() {
tmpdir = "/tmp";
}
#ifdef O_TMPFILE
fd = open(tmpdir, O_TMPFILE | O_RDWR);
fd = open(tmpdir, O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR);
if (fd >= 0) {
return fd;
}
@@ -3573,7 +3623,7 @@ void uwsgi_set_cpu_affinity() {
base_cpu = base_cpu % uwsgi.cpus;
}
ret = snprintf(buf, 4096, "mapping worker %d to CPUs:", uwsgi.mywid);
if (ret < 25) {
if (ret < 25 || ret >= 4096) {
uwsgi_log("unable to initialize cpu affinity !!!\n");
exit(1);
}
@@ -3591,7 +3641,7 @@ void uwsgi_set_cpu_affinity() {
base_cpu = 0;
CPU_SET(base_cpu, &cpuset);
ret = snprintf(buf + pos, 4096 - pos, " %d", base_cpu);
if (ret < 2) {
if (ret < 2 || ret >= 4096) {
uwsgi_log("unable to initialize cpu affinity !!!\n");
exit(1);
}
@@ -3729,7 +3779,7 @@ static void *uwsgi_thread_run(void *arg) {
return NULL;
}
struct uwsgi_thread *uwsgi_thread_new(void (*func) (struct uwsgi_thread *)) {
struct uwsgi_thread *uwsgi_thread_new_with_data(void (*func) (struct uwsgi_thread *), void *data) {
struct uwsgi_thread *ut = uwsgi_calloc(sizeof(struct uwsgi_thread));
@@ -3746,6 +3796,7 @@ struct uwsgi_thread *uwsgi_thread_new(void (*func) (struct uwsgi_thread *)) {
uwsgi_socket_nb(ut->pipe[1]);
ut->func = func;
ut->data = data;
pthread_attr_init(&ut->tattr);
pthread_attr_setdetachstate(&ut->tattr, PTHREAD_CREATE_DETACHED);
@@ -3765,6 +3816,10 @@ error:
return NULL;
}
struct uwsgi_thread *uwsgi_thread_new(void (*func) (struct uwsgi_thread *)) {
return uwsgi_thread_new_with_data(func, NULL);
}
int uwsgi_kvlist_parse(char *src, size_t len, char list_separator, char kv_separator, ...) {
size_t i;
va_list ap;
@@ -3854,7 +3909,7 @@ int uwsgi_send_http_stats(int fd) {
char buf[4096];
int ret = uwsgi_waitfd(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
int ret = uwsgi_waitfd(fd, uwsgi.socket_timeout);
if (ret <= 0)
return -1;
@@ -3937,19 +3992,22 @@ void uwsgi_uuid(char *buf) {
uuid_generate(uuid_value);
uuid_unparse(uuid_value, buf);
#else
int i,r[11];
if (!uwsgi_file_exists("/dev/urandom")) goto fallback;
int i, r[11];
if (!uwsgi_file_exists("/dev/urandom"))
goto fallback;
int fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) goto fallback;
for(i=0;i<11;i++) {
if (fd < 0)
goto fallback;
for (i = 0; i < 11; i++) {
if (read(fd, &r[i], 4) != 4) {
close(fd); goto fallback;
close(fd);
goto fallback;
}
}
close(fd);
goto done;
fallback:
for(i=0;i<11;i++) {
for (i = 0; i < 11; i++) {
r[i] = rand();
}
done:
@@ -4174,7 +4232,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;
@@ -4339,15 +4398,167 @@ void uwsgi_exit(int status) {
}
int uwsgi_base128(struct uwsgi_buffer *ub, uint64_t l, int first) {
if( l > 127 ) {
if (uwsgi_base128(ub, l/128, 0)) return -1;
if (l > 127) {
if (uwsgi_base128(ub, l / 128, 0))
return -1;
}
l %= 128;
if(first) {
if (uwsgi_buffer_u8(ub, (uint8_t) l)) return -1;
if (first) {
if (uwsgi_buffer_u8(ub, (uint8_t) l))
return -1;
}
else {
if (uwsgi_buffer_u8(ub, 0x80 | (uint8_t) l)) return -1;
if (uwsgi_buffer_u8(ub, 0x80 | (uint8_t) l))
return -1;
}
return 0;
}
#ifdef __linux__
void uwsgi_setns(char *path) {
int (*u_setns) (int, int) = (int (*)(int, int)) dlsym(RTLD_DEFAULT, "setns");
if (!u_setns) {
uwsgi_log("your system misses setns() syscall !!!\n");
exit(1);
}
// cound be overwritten
int count = 64;
uwsgi_log("joining namespaces from %s ...\n", path);
for (;;) {
int ns_fd = uwsgi_connect(path, 30, 0);
if (ns_fd < 0) {
uwsgi_error("uwsgi_setns()/uwsgi_connect()");
sleep(1);
continue;
}
int *fds = uwsgi_attach_fd(ns_fd, &count, "uwsgi-setns", 11);
if (fds && count > 0) {
int i;
for (i = 0; i < count; i++) {
if (fds[i] > -1) {
if (u_setns(fds[i], 0) < 0) {
uwsgi_error("uwsgi_setns()/setns()");
exit(1);
}
close(fds[i]);
}
}
free(fds);
close(ns_fd);
break;
}
if (fds)
free(fds);
close(ns_fd);
sleep(1);
}
}
#endif
mode_t uwsgi_mode_t(char *value, int *error) {
mode_t mode = 0;
*error = 0;
if (strlen(value) < 3) {
*error = 1;
return mode;
}
if (strlen(value) == 3) {
mode = (mode << 3) + (value[0] - '0');
mode = (mode << 3) + (value[1] - '0');
mode = (mode << 3) + (value[2] - '0');
}
else {
mode = (mode << 3) + (value[1] - '0');
mode = (mode << 3) + (value[2] - '0');
mode = (mode << 3) + (value[3] - '0');
}
return mode;
}
int uwsgi_wait_for_mountpoint(char *mountpoint) {
if (!uwsgi.wait_for_fs_timeout) {
uwsgi.wait_for_fs_timeout = 60;
}
uwsgi_log("waiting for %s (max %d seconds) ...\n", mountpoint, uwsgi.wait_for_fs_timeout);
int counter = 0;
for (;;) {
if (counter > uwsgi.wait_for_fs_timeout) {
uwsgi_log("%s unavailable after %d seconds\n", mountpoint, counter);
return -1;
}
struct stat st0;
struct stat st1;
if (stat(mountpoint, &st0)) goto retry;
if (!S_ISDIR(st0.st_mode)) goto retry;
char *relative = uwsgi_concat2(mountpoint, "/../");
if (stat(relative, &st1)) {
free(relative);
goto retry;
}
free(relative);
// useless :P
if (!S_ISDIR(st1.st_mode)) goto retry;
if (st0.st_dev == st1.st_dev) goto retry;
uwsgi_log_verbose("%s mounted\n", mountpoint);
return 0;
retry:
sleep(1);
counter++;
}
return -1;
}
// type -> 1 file, 2 dir, 0 both
int uwsgi_wait_for_fs(char *filename, int type) {
if (!uwsgi.wait_for_fs_timeout) {
uwsgi.wait_for_fs_timeout = 60;
}
uwsgi_log("waiting for %s (max %d seconds) ...\n", filename, uwsgi.wait_for_fs_timeout);
int counter = 0;
for (;;) {
if (counter > uwsgi.wait_for_fs_timeout) {
uwsgi_log("%s unavailable after %d seconds\n", filename, counter);
return -1;
}
struct stat st;
if (stat(filename, &st)) goto retry;
if (type == 1 && !S_ISREG(st.st_mode)) goto retry;
if (type == 2 && !S_ISDIR(st.st_mode)) goto retry;
uwsgi_log_verbose("%s found\n", filename);
return 0;
retry:
sleep(1);
counter++;
}
return -1;
}
int uwsgi_wait_for_socket(char *socket_name) {
if (!uwsgi.wait_for_socket_timeout) {
uwsgi.wait_for_socket_timeout = 60;
}
uwsgi_log("waiting for %s (max %d seconds) ...\n", socket_name, uwsgi.wait_for_socket_timeout);
int counter = 0;
for (;;) {
if (counter > uwsgi.wait_for_socket_timeout) {
uwsgi_log("%s unavailable after %d seconds\n", socket_name, counter);
return -1;
}
// wait for 1 second to respect uwsgi.wait_for_fs_timeout
int fd = uwsgi_connect(socket_name, 1, 0);
if (fd < 0) goto retry;
close(fd);
uwsgi_log_verbose("%s ready\n", socket_name);
return 0;
retry:
sleep(1);
counter++;
}
return -1;
}
+341 -99
View File
@@ -2,7 +2,7 @@
*** uWSGI ***
Copyright (C) 2009-2013 Unbit S.a.s. <info@unbit.it>
Copyright (C) 2009-2015 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
@@ -39,8 +39,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"socket", required_argument, 's', "bind to the specified UNIX/TCP socket using default protocol", uwsgi_opt_add_socket, NULL, 0},
{"uwsgi-socket", required_argument, 's', "bind to the specified UNIX/TCP socket using uwsgi protocol", uwsgi_opt_add_socket, "uwsgi", 0},
#ifdef UWSGI_SSL
{"suwsgi-socket", required_argument, 's', "bind to the specified UNIX/TCP socket using uwsgi protocol over SSL", uwsgi_opt_add_ssl_socket, "suwsgi", 0},
{"ssl-socket", required_argument, 's', "bind to the specified UNIX/TCP socket using uwsgi protocol over SSL", uwsgi_opt_add_ssl_socket, "suwsgi", 0},
{"suwsgi-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using uwsgi protocol over SSL", uwsgi_opt_add_ssl_socket, "suwsgi", 0},
{"ssl-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using uwsgi protocol over SSL", uwsgi_opt_add_ssl_socket, "suwsgi", 0},
#endif
{"http-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using HTTP protocol", uwsgi_opt_add_socket, "http", 0},
@@ -71,18 +71,18 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"protocol", required_argument, 0, "force the specified protocol for default sockets", uwsgi_opt_set_str, &uwsgi.protocol, 0},
{"socket-protocol", required_argument, 0, "force the specified protocol for default sockets", uwsgi_opt_set_str, &uwsgi.protocol, 0},
{"shared-socket", required_argument, 0, "create a shared sacket for advanced jailing or ipc", uwsgi_opt_add_shared_socket, NULL, 0},
{"undeferred-shared-socket", required_argument, 0, "create a shared sacket for advanced jailing or ipc (undeferred mode)", uwsgi_opt_add_shared_socket, NULL, 0},
{"shared-socket", required_argument, 0, "create a shared socket for advanced jailing or ipc", uwsgi_opt_add_shared_socket, NULL, 0},
{"undeferred-shared-socket", required_argument, 0, "create a shared socket for advanced jailing or ipc (undeferred mode)", uwsgi_opt_add_shared_socket, NULL, 0},
{"processes", required_argument, 'p', "spawn the specified number of workers/processes", uwsgi_opt_set_int, &uwsgi.numproc, 0},
{"workers", required_argument, 'p', "spawn the specified number of workers/processes", uwsgi_opt_set_int, &uwsgi.numproc, 0},
{"thunder-lock", no_argument, 0, "serialize accept() usage (if possible)", uwsgi_opt_true, &uwsgi.use_thunder_lock, 0},
{"harakiri", required_argument, 't', "set harakiri timeout", uwsgi_opt_set_dyn, (void *) UWSGI_OPTION_HARAKIRI, 0},
{"harakiri", required_argument, 't', "set harakiri timeout", uwsgi_opt_set_int, &uwsgi.harakiri_options.workers, 0},
{"harakiri-verbose", no_argument, 0, "enable verbose mode for harakiri", uwsgi_opt_true, &uwsgi.harakiri_verbose, 0},
{"harakiri-no-arh", no_argument, 0, "do not enable harakiri during after-request-hook", uwsgi_opt_true, &uwsgi.harakiri_no_arh, 0},
{"no-harakiri-arh", no_argument, 0, "do not enable harakiri during after-request-hook", uwsgi_opt_true, &uwsgi.harakiri_no_arh, 0},
{"no-harakiri-after-req-hook", no_argument, 0, "do not enable harakiri during after-request-hook", uwsgi_opt_true, &uwsgi.harakiri_no_arh, 0},
{"backtrace-depth", required_argument, 0, "set backtrace depth", uwsgi_opt_set_int, &uwsgi.backtrace_depth, 0},
{"mule-harakiri", required_argument, 0, "set harakiri timeout for mule tasks", uwsgi_opt_set_dyn, (void *) UWSGI_OPTION_MULE_HARAKIRI, 0},
{"mule-harakiri", required_argument, 0, "set harakiri timeout for mule tasks", uwsgi_opt_set_int, &uwsgi.harakiri_options.mules, 0},
#ifdef UWSGI_XML
{"xmlconfig", required_argument, 'x', "load config from xml file", uwsgi_opt_load_xml, NULL, UWSGI_OPT_IMMEDIATE},
{"xml", required_argument, 'x', "load config from xml file", uwsgi_opt_load_xml, NULL, UWSGI_OPT_IMMEDIATE},
@@ -99,10 +99,14 @@ 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},
{"resolve", required_argument, 0, "place the result of a dns query in the specified placeholder, sytax: placeholder=name (immediate option)", uwsgi_opt_resolve, NULL, UWSGI_OPT_IMMEDIATE},
{"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},
@@ -116,6 +120,9 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"if-reload", no_argument, 0, "(opt logic) check for reload", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_reload, UWSGI_OPT_IMMEDIATE},
{"if-not-reload", no_argument, 0, "(opt logic) check for reload", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_reload, UWSGI_OPT_IMMEDIATE},
{"if-hostname", required_argument, 0, "(opt logic) check for hostname", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_hostname, UWSGI_OPT_IMMEDIATE},
{"if-not-hostname", required_argument, 0, "(opt logic) check for hostname", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_hostname, UWSGI_OPT_IMMEDIATE},
{"if-exists", required_argument, 0, "(opt logic) check for file/directory existance", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_exists, UWSGI_OPT_IMMEDIATE},
{"if-not-exists", required_argument, 0, "(opt logic) check for file/directory existance", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_exists, UWSGI_OPT_IMMEDIATE},
{"ifexists", required_argument, 0, "(opt logic) check for file/directory existance", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_exists, UWSGI_OPT_IMMEDIATE},
@@ -149,6 +156,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},
@@ -164,9 +173,9 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"max-vars", required_argument, 'v', "set the amount of internal iovec/vars structures", uwsgi_opt_max_vars, NULL, 0},
{"max-apps", required_argument, 0, "set the maximum number of per-worker applications", uwsgi_opt_set_int, &uwsgi.max_apps, 0},
{"buffer-size", required_argument, 'b', "set internal buffer size", uwsgi_opt_set_16bit, &uwsgi.buffer_size, 0},
{"memory-report", no_argument, 'm', "enable memory report", uwsgi_opt_dyn_true, (void *) UWSGI_OPTION_MEMORY_DEBUG, 0},
{"memory-report", no_argument, 'm', "enable memory report", uwsgi_opt_true, &uwsgi.logging_options.memory_report, 0},
{"profiler", required_argument, 0, "enable the specified profiler", uwsgi_opt_set_str, &uwsgi.profiler, 0},
{"cgi-mode", no_argument, 'c', "force CGI-mode for plugins supporting it", uwsgi_opt_dyn_true, (void *) UWSGI_OPTION_CGI_MODE, 0},
{"cgi-mode", no_argument, 'c', "force CGI-mode for plugins supporting it", uwsgi_opt_true, &uwsgi.cgi_mode, 0},
{"abstract-socket", no_argument, 'a', "force UNIX socket in abstract mode (Linux only)", uwsgi_opt_true, &uwsgi.abstract_socket, 0},
{"chmod-socket", optional_argument, 'C', "chmod-socket", uwsgi_opt_chmod_socket, NULL, 0},
{"chmod", optional_argument, 'C', "chmod-socket", uwsgi_opt_chmod_socket, NULL, 0},
@@ -193,6 +202,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"emperor", required_argument, 0, "run the Emperor", uwsgi_opt_add_string_list, &uwsgi.emperor, 0},
{"emperor-proxy-socket", required_argument, 0, "force the vassal to became an Emperor proxy", uwsgi_opt_set_str, &uwsgi.emperor_proxy, 0},
{"emperor-wrapper", required_argument, 0, "set a binary wrapper for vassals", uwsgi_opt_set_str, &uwsgi.emperor_wrapper, 0},
{"emperor-wrapper-override", required_argument, 0, "set a binary wrapper for vassals to try before the default one", uwsgi_opt_add_string_list, &uwsgi.emperor_wrapper_override, 0},
{"emperor-wrapper-fallback", required_argument, 0, "set a binary wrapper for vassals to try as a last resort", uwsgi_opt_add_string_list, &uwsgi.emperor_wrapper_fallback, 0},
{"emperor-nofollow", no_argument, 0, "do not follow symlinks when checking for mtime", uwsgi_opt_true, &uwsgi.emperor_nofollow, 0},
{"emperor-procname", required_argument, 0, "set the Emperor process name", uwsgi_opt_set_str, &uwsgi.emperor_procname, 0},
{"emperor-freq", required_argument, 0, "set the Emperor scan frequency (default 3 seconds)", uwsgi_opt_set_int, &uwsgi.emperor_freq, 0},
@@ -215,6 +226,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"emperor-on-demand-exec", required_argument, 0, "use the output of the specified command as on demand socket name (the vassal name is passed as the only argument)", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_exec, 0},
{"emperor-extra-extension", required_argument, 0, "allows the specified extension in the Emperor (vassal will be called with --config)", uwsgi_opt_add_string_list, &uwsgi.emperor_extra_extension, 0},
{"emperor-extra-ext", required_argument, 0, "allows the specified extension in the Emperor (vassal will be called with --config)", uwsgi_opt_add_string_list, &uwsgi.emperor_extra_extension, 0},
{"emperor-no-blacklist", no_argument, 0, "disable Emperor blacklisting subsystem", uwsgi_opt_true, &uwsgi.emperor_no_blacklist, 0},
#if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL)
{"emperor-use-clone", required_argument, 0, "use clone() instead of fork() passing the specified unshare() flags", uwsgi_opt_set_unshare, &uwsgi.emperor_clone, 0},
#endif
@@ -231,6 +243,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"vassals-include-before", required_argument, 0, "include config templates to vassals config (uses --include instead of --inherit, parses before the vassal file)", uwsgi_opt_add_string_list, &uwsgi.vassals_includes_before, 0},
{"vassals-start-hook", required_argument, 0, "run the specified command before each vassal starts", uwsgi_opt_set_str, &uwsgi.vassals_start_hook, 0},
{"vassals-stop-hook", required_argument, 0, "run the specified command after vassal's death", uwsgi_opt_set_str, &uwsgi.vassals_stop_hook, 0},
{"vassal-sos", required_argument, 0, "ask emperor for reinforcement when overloaded", uwsgi_opt_set_int, &uwsgi.vassal_sos, 0},
{"vassal-sos-backlog", required_argument, 0, "ask emperor for sos if backlog queue has more items than the value specified", uwsgi_opt_set_int, &uwsgi.vassal_sos_backlog, 0},
{"vassals-set", required_argument, 0, "automatically set the specified option (via --set) for every vassal", uwsgi_opt_add_string_list, &uwsgi.vassals_set, 0},
{"vassal-set", required_argument, 0, "automatically set the specified option (via --set) for every vassal", uwsgi_opt_add_string_list, &uwsgi.vassals_set, 0},
@@ -239,6 +252,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"reload-mercy", required_argument, 0, "set the maximum time (in seconds) we wait for workers and other processes to die during reload/shutdown", uwsgi_opt_set_int, &uwsgi.reload_mercy, 0},
{"worker-reload-mercy", required_argument, 0, "set the maximum time (in seconds) a worker can take to reload/shutdown (default is 60)", uwsgi_opt_set_int, &uwsgi.worker_reload_mercy, 0},
{"mule-reload-mercy", required_argument, 0, "set the maximum time (in seconds) a mule can take to reload/shutdown (default is 60)", uwsgi_opt_set_int, &uwsgi.mule_reload_mercy, 0},
{"exit-on-reload", no_argument, 0, "force exit even if a reload is requested", uwsgi_opt_true, &uwsgi.exit_on_reload, 0},
{"die-on-term", no_argument, 0, "exit instead of brutal reload on SIGTERM", uwsgi_opt_true, &uwsgi.die_on_term, 0},
{"force-gateway", no_argument, 0, "force the spawn of the first registered gateway without a master", uwsgi_opt_true, &uwsgi.force_gateway, 0},
@@ -248,12 +262,12 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"print-sym", required_argument, 0, "print content of the specified binary symbol", uwsgi_print_sym, NULL, UWSGI_OPT_IMMEDIATE},
{"print-symbol", required_argument, 0, "print content of the specified binary symbol", uwsgi_print_sym, NULL, UWSGI_OPT_IMMEDIATE},
{"reaper", no_argument, 'r', "call waitpid(-1,...) after each request to get rid of zombies", uwsgi_opt_dyn_true, (void *) UWSGI_OPTION_REAPER, 0},
{"max-requests", required_argument, 'R', "reload workers after the specified amount of managed requests", uwsgi_opt_set_dyn, (void *) UWSGI_OPTION_MAX_REQUESTS, 0},
{"min-worker-lifetime", required_argument, 0, "number of seconds worker must run before being reloaded (default is 60)", uwsgi_opt_set_dyn, (void *) UWSGI_OPTION_MIN_WORKER_LIFETIME, 0},
{"max-worker-lifetime", required_argument, 0, "reload workers after the specified amount of seconds (default is disabled)", uwsgi_opt_set_dyn, (void *) UWSGI_OPTION_MAX_WORKER_LIFETIME, 0},
{"reaper", no_argument, 'r', "call waitpid(-1,...) after each request to get rid of zombies", uwsgi_opt_true, &uwsgi.reaper, 0},
{"max-requests", required_argument, 'R', "reload workers after the specified amount of managed requests", uwsgi_opt_set_64bit, &uwsgi.max_requests, 0},
{"min-worker-lifetime", required_argument, 0, "number of seconds worker must run before being reloaded (default is 60)", uwsgi_opt_set_64bit, &uwsgi.min_worker_lifetime, 0},
{"max-worker-lifetime", required_argument, 0, "reload workers after the specified amount of seconds (default is disabled)", uwsgi_opt_set_64bit, &uwsgi.max_worker_lifetime, 0},
{"socket-timeout", required_argument, 'z', "set internal sockets timeout", uwsgi_opt_set_dyn, (void *) UWSGI_OPTION_SOCKET_TIMEOUT, 0},
{"socket-timeout", required_argument, 'z', "set internal sockets timeout", uwsgi_opt_set_int, &uwsgi.socket_timeout, 0},
{"no-fd-passing", no_argument, 0, "disable file descriptor passing", uwsgi_opt_true, &uwsgi.no_fd_passing, 0},
{"locks", required_argument, 0, "create the specified number of shared locks", uwsgi_opt_set_int, &uwsgi.locks, 0},
{"lock-engine", required_argument, 0, "set the lock engine", uwsgi_opt_set_str, &uwsgi.lock_engine, 0},
@@ -297,7 +311,9 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"spooler-processes", required_argument, 0, "set the number of processes for spoolers", uwsgi_opt_set_int, &uwsgi.spooler_numproc, UWSGI_OPT_IMMEDIATE},
{"spooler-quiet", no_argument, 0, "do not be verbose with spooler tasks", uwsgi_opt_true, &uwsgi.spooler_quiet, 0},
{"spooler-max-tasks", required_argument, 0, "set the maximum number of tasks to run before recycling a spooler", uwsgi_opt_set_int, &uwsgi.spooler_max_tasks, 0},
{"spooler-harakiri", required_argument, 0, "set harakiri timeout for spooler tasks", uwsgi_opt_set_dyn, (void *) UWSGI_OPTION_SPOOLER_HARAKIRI, 0},
{"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},
@@ -316,7 +332,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"rpc-max", required_argument, 0, "maximum number of rpc slots (default: 64)", uwsgi_opt_set_64bit, &uwsgi.rpc_max, 0},
{"disable-logging", no_argument, 'L', "disable request logging", uwsgi_opt_dyn_false, (void *) UWSGI_OPTION_LOGGING, 0},
{"disable-logging", no_argument, 'L', "disable request logging", uwsgi_opt_false, &uwsgi.logging_options.enabled, 0},
{"flock", required_argument, 0, "lock the specified file before starting, exit if locked", uwsgi_opt_flock, NULL, UWSGI_OPT_IMMEDIATE},
{"flock-wait", required_argument, 0, "lock the specified file before starting, wait if locked", uwsgi_opt_flock_wait, NULL, UWSGI_OPT_IMMEDIATE},
@@ -344,7 +360,13 @@ static struct uwsgi_option uwsgi_base_options[] = {
#ifdef __linux__
{"unshare", required_argument, 0, "unshare() part of the processes and put it in a new namespace", uwsgi_opt_set_unshare, &uwsgi.unshare, 0},
{"unshare2", required_argument, 0, "unshare() part of the processes and put it in a new namespace after rootfs change", uwsgi_opt_set_unshare, &uwsgi.unshare2, 0},
{"setns-socket", required_argument, 0, "expose a unix socket returning namespace fds from /proc/self/ns", uwsgi_opt_set_str, &uwsgi.setns_socket, UWSGI_OPT_MASTER},
{"setns-socket-skip", required_argument, 0, "skip the specified entry when sending setns file descriptors", uwsgi_opt_add_string_list, &uwsgi.setns_socket_skip, 0},
{"setns-skip", required_argument, 0, "skip the specified entry when sending setns file descriptors", uwsgi_opt_add_string_list, &uwsgi.setns_socket_skip, 0},
{"setns", required_argument, 0, "join a namespace created by an external uWSGI instance", uwsgi_opt_set_str, &uwsgi.setns, 0},
{"setns-preopen", no_argument, 0, "open /proc/self/ns as soon as possible and cache fds", uwsgi_opt_true, &uwsgi.setns_preopen, 0},
#endif
{"jailed", no_argument, 0, "mark the instance as jailed (force the execution of post_jail hooks)", uwsgi_opt_true, &uwsgi.jailed, 0},
#if defined(__FreeBSD__) || defined(__GNU_kFreeBSD__)
{"jail", required_argument, 0, "put the instance in a FreeBSD jail", uwsgi_opt_set_str, &uwsgi.jail, 0},
{"jail-ip4", required_argument, 0, "add an ipv4 address to the FreeBSD jail", uwsgi_opt_add_string_list, &uwsgi.jail_ip4, 0},
@@ -373,16 +395,28 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"hook-as-user-atexit", required_argument, 0, "run the specified hook before app exit and reload", uwsgi_opt_add_string_list, &uwsgi.hook_as_user_atexit, 0},
{"hook-pre-app", required_argument, 0, "run the specified hook before app loading", uwsgi_opt_add_string_list, &uwsgi.hook_pre_app, 0},
{"hook-post-app", required_argument, 0, "run the specified hook after app loading", uwsgi_opt_add_string_list, &uwsgi.hook_post_app, 0},
{"hook-post-fork", required_argument, 0, "run the specified hook after each fork", uwsgi_opt_add_string_list, &uwsgi.hook_post_fork, 0},
{"hook-accepting", required_argument, 0, "run the specified hook after each worker enter the accepting phase", uwsgi_opt_add_string_list, &uwsgi.hook_accepting, 0},
{"hook-accepting1", required_argument, 0, "run the specified hook after the first worker enters the accepting phase", uwsgi_opt_add_string_list, &uwsgi.hook_accepting1, 0},
{"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},
{"hook-as-vassal", required_argument, 0, "run the specified hook before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.hook_as_vassal, 0},
{"hook-as-emperor", required_argument, 0, "run the specified hook in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.hook_as_emperor, 0},
{"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},
@@ -429,6 +463,15 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"wait-iface", required_argument, 0, "wait for the specified network interface to come up before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_interface, 0},
{"wait-iface-timeout", required_argument, 0, "set the timeout for wait-for-interface", uwsgi_opt_set_int, &uwsgi.wait_for_interface_timeout, 0},
{"wait-for-fs", required_argument, 0, "wait for the specified filesystem item to appear before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_fs, 0},
{"wait-for-file", required_argument, 0, "wait for the specified file to appear before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_fs, 0},
{"wait-for-dir", required_argument, 0, "wait for the specified directory to appear before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_fs, 0},
{"wait-for-mountpoint", required_argument, 0, "wait for the specified mountpoint to appear before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_mountpoint, 0},
{"wait-for-fs-timeout", required_argument, 0, "set the timeout for wait-for-fs/file/dir", uwsgi_opt_set_int, &uwsgi.wait_for_fs_timeout, 0},
{"wait-for-socket", required_argument, 0, "wait for the specified socket to be ready before loading apps", uwsgi_opt_add_string_list, &uwsgi.wait_for_socket, 0},
{"wait-for-socket-timeout", required_argument, 0, "set the timeout for wait-for-socket", uwsgi_opt_set_int, &uwsgi.wait_for_socket_timeout, 0},
{"call-asap", required_argument, 0, "call the specified function as soon as possible", uwsgi_opt_add_string_list, &uwsgi.call_asap, 0},
{"call-pre-jail", required_argument, 0, "call the specified function before jailing", uwsgi_opt_add_string_list, &uwsgi.call_pre_jail, 0},
{"call-post-jail", required_argument, 0, "call the specified function after jailing", uwsgi_opt_add_string_list, &uwsgi.call_post_jail, 0},
@@ -478,6 +521,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"reload-on-rss", required_argument, 0, "reload if rss memory is higher than specified megabytes", uwsgi_opt_set_megabytes, &uwsgi.reload_on_rss, UWSGI_OPT_MEMORY},
{"evil-reload-on-as", required_argument, 0, "force the master to reload a worker if its address space is higher than specified megabytes", uwsgi_opt_set_megabytes, &uwsgi.evil_reload_on_as, UWSGI_OPT_MASTER | UWSGI_OPT_MEMORY},
{"evil-reload-on-rss", required_argument, 0, "force the master to reload a worker if its rss memory is higher than specified megabytes", uwsgi_opt_set_megabytes, &uwsgi.evil_reload_on_rss, UWSGI_OPT_MASTER | UWSGI_OPT_MEMORY},
{"mem-collector-freq", required_argument, 0, "set the memory collector frequency when evil reloads are in place", uwsgi_opt_set_int, &uwsgi.mem_collector_freq, 0},
{"reload-on-fd", required_argument, 0, "reload if the specified file descriptor is ready", uwsgi_opt_add_string_list, &uwsgi.reload_on_fd, UWSGI_OPT_MASTER},
{"brutal-reload-on-fd", required_argument, 0, "brutal reload if the specified file descriptor is ready", uwsgi_opt_add_string_list, &uwsgi.brutal_reload_on_fd, UWSGI_OPT_MASTER},
@@ -532,10 +576,12 @@ 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},
{"metric-dir-restore", no_argument, 0, "restore last value taken from the metrics dir", uwsgi_opt_true, &uwsgi.metrics_dir_restore, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
{"metrics-no-cores", no_argument, 0, "disable generation of cores-related metrics", uwsgi_opt_true, &uwsgi.metrics_no_cores, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
{"udp", required_argument, 0, "run the udp server on the specified address", uwsgi_opt_set_str, &uwsgi.udp_socket, UWSGI_OPT_MASTER},
{"stats", required_argument, 0, "enable the stats server on the specified address", uwsgi_opt_set_str, &uwsgi.stats, UWSGI_OPT_MASTER},
@@ -546,18 +592,24 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"stats-push", required_argument, 0, "push the stats json to the specified destination", uwsgi_opt_add_string_list, &uwsgi.requested_stats_pushers, UWSGI_OPT_MASTER|UWSGI_OPT_METRICS},
{"stats-pusher-default-freq", required_argument, 0, "set the default frequency of stats pushers", uwsgi_opt_set_int, &uwsgi.stats_pusher_default_freq, UWSGI_OPT_MASTER},
{"stats-pushers-default-freq", required_argument, 0, "set the default frequency of stats pushers", uwsgi_opt_set_int, &uwsgi.stats_pusher_default_freq, UWSGI_OPT_MASTER},
{"stats-no-cores", no_argument, 0, "disable generation of cores-related stats", uwsgi_opt_true, &uwsgi.stats_no_cores, UWSGI_OPT_MASTER},
{"stats-no-metrics", no_argument, 0, "do not include metrics in stats output", uwsgi_opt_true, &uwsgi.stats_no_metrics, UWSGI_OPT_MASTER},
{"multicast", required_argument, 0, "subscribe to specified multicast group", uwsgi_opt_set_str, &uwsgi.multicast_group, UWSGI_OPT_MASTER},
{"multicast-ttl", required_argument, 0, "set multicast ttl", uwsgi_opt_set_int, &uwsgi.multicast_ttl, 0},
{"multicast-loop", required_argument, 0, "set multicast loop (default 1)", uwsgi_opt_set_int, &uwsgi.multicast_loop, 0},
{"master-fifo", required_argument, 0, "enable the master fifo", uwsgi_opt_add_string_list, &uwsgi.master_fifo, UWSGI_OPT_MASTER},
{"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},
@@ -572,7 +624,10 @@ 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},
{"subscription-algo", required_argument, 0, "set load balancing algorithm for the subscription system", uwsgi_opt_ssa, NULL, 0},
{"subscription-dotsplit", no_argument, 0, "try to fallback to the next part (dot based) in subscription key", uwsgi_opt_true, &uwsgi.subscription_dotsplit, 0},
{"subscribe-to", required_argument, 0, "subscribe to the specified subscription server", uwsgi_opt_add_string_list, &uwsgi.subscriptions, UWSGI_OPT_MASTER},
@@ -582,6 +637,10 @@ 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},
{"subscribe-with-modifier1", required_argument, 0, "force the specififed modifier1 when subscribing", uwsgi_opt_set_str, &uwsgi.subscribe_with_modifier1, UWSGI_OPT_MASTER},
{"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
@@ -594,11 +653,14 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"sni", required_argument, 0, "add an SNI-governed SSL context", uwsgi_opt_sni, NULL, 0},
{"sni-dir", required_argument, 0, "check for cert/key/client_ca file in the specified directory and create a sni/ssl context on demand", uwsgi_opt_set_str, &uwsgi.sni_dir, 0},
{"sni-dir-ciphers", required_argument, 0, "set ssl ciphers for sni-dir option", uwsgi_opt_set_str, &uwsgi.sni_dir_ciphers, 0},
{"ssl-enable3", no_argument, 0, "enable SSLv3 (insecure)", uwsgi_opt_true, &uwsgi.sslv3, 0},
{"ssl-option", no_argument, 0, "set a raw ssl option (numeric value)", uwsgi_opt_add_string_list, &uwsgi.ssl_options, 0},
#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_dyn, (void *) UWSGI_OPTION_MASTER_INTERVAL, 0},
{"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},
{"binary-path", required_argument, 0, "force binary path", uwsgi_opt_set_str, &uwsgi.binary_path, 0},
{"privileged-binary-patch", required_argument, 0, "patch the uwsgi binary with a new command (before privileges drop)", uwsgi_opt_set_str, &uwsgi.privileged_binary_patch, 0},
@@ -639,10 +701,17 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"use-abort", no_argument, 0, "call abort() on segfault/fpe, could be useful for generating a core dump", uwsgi_opt_true, &uwsgi.use_abort, 0},
{"alarm", required_argument, 0, "create a new alarm, syntax: <alarm> <plugin:args>", uwsgi_opt_add_string_list, &uwsgi.alarm_list, UWSGI_OPT_MASTER},
{"alarm-freq", required_argument, 0, "tune the anti-loop alam system (default 3 seconds)", uwsgi_opt_set_int, &uwsgi.alarm_freq, 0},
{"alarm-cheap", required_argument, 0, "use main alarm thread rather than create dedicated threads for curl-based alarms", uwsgi_opt_true, &uwsgi.alarm_cheap, 0},
{"alarm-freq", required_argument, 0, "tune the anti-loop alarm system (default 3 seconds)", uwsgi_opt_set_int, &uwsgi.alarm_freq, 0},
{"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},
@@ -652,28 +721,28 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"alarm-list", no_argument, 0, "list enabled alarms", uwsgi_opt_true, &uwsgi.alarms_list, 0},
{"alarms-list", no_argument, 0, "list enabled alarms", uwsgi_opt_true, &uwsgi.alarms_list, 0},
{"alarm-msg-size", required_argument, 0, "set the max size of an alarm message (default 8192)", uwsgi_opt_set_64bit, &uwsgi.alarm_msg_size, 0},
{"log-master", no_argument, 0, "delegate logging to master process", uwsgi_opt_true, &uwsgi.log_master, UWSGI_OPT_MASTER},
{"log-master", no_argument, 0, "delegate logging to master process", uwsgi_opt_true, &uwsgi.log_master, UWSGI_OPT_MASTER|UWSGI_OPT_LOG_MASTER},
{"log-master-bufsize", required_argument, 0, "set the buffer size for the master logger. bigger log messages will be truncated", uwsgi_opt_set_64bit, &uwsgi.log_master_bufsize, 0},
{"log-master-stream", no_argument, 0, "create the master logpipe as SOCK_STREAM", uwsgi_opt_true, &uwsgi.log_master_stream, 0},
{"log-master-req-stream", no_argument, 0, "create the master requests logpipe as SOCK_STREAM", uwsgi_opt_true, &uwsgi.log_master_req_stream, 0},
{"log-reopen", no_argument, 0, "reopen log after reload", uwsgi_opt_true, &uwsgi.log_reopen, 0},
{"log-truncate", no_argument, 0, "truncate log on startup", uwsgi_opt_true, &uwsgi.log_truncate, 0},
{"log-maxsize", required_argument, 0, "set maximum logfile size", uwsgi_opt_set_64bit, &uwsgi.log_maxsize, UWSGI_OPT_LOG_MASTER},
{"log-maxsize", required_argument, 0, "set maximum logfile size", uwsgi_opt_set_64bit, &uwsgi.log_maxsize, UWSGI_OPT_MASTER|UWSGI_OPT_LOG_MASTER},
{"log-backupname", required_argument, 0, "set logfile name after rotation", uwsgi_opt_set_str, &uwsgi.log_backupname, 0},
{"logdate", optional_argument, 0, "prefix logs with date or a strftime string", uwsgi_opt_log_date, NULL, 0},
{"log-date", optional_argument, 0, "prefix logs with date or a strftime string", uwsgi_opt_log_date, NULL, 0},
{"log-prefix", optional_argument, 0, "prefix logs with a string", uwsgi_opt_log_date, NULL, 0},
{"log-zero", no_argument, 0, "log responses without body", uwsgi_opt_dyn_true, (void *) UWSGI_OPTION_LOG_ZERO, 0},
{"log-slow", required_argument, 0, "log requests slower than the specified number of milliseconds", uwsgi_opt_set_dyn, (void *) UWSGI_OPTION_LOG_SLOW, 0},
{"log-4xx", no_argument, 0, "log requests with a 4xx response", uwsgi_opt_dyn_true, (void *) UWSGI_OPTION_LOG_4xx, 0},
{"log-5xx", no_argument, 0, "log requests with a 5xx response", uwsgi_opt_dyn_true, (void *) UWSGI_OPTION_LOG_5xx, 0},
{"log-big", required_argument, 0, "log requestes bigger than the specified size", uwsgi_opt_set_dyn, (void *) UWSGI_OPTION_LOG_BIG, 0},
{"log-sendfile", required_argument, 0, "log sendfile requests", uwsgi_opt_dyn_true, (void *) UWSGI_OPTION_LOG_SENDFILE, 0},
{"log-ioerror", required_argument, 0, "log requests with io errors", uwsgi_opt_dyn_true, (void *) UWSGI_OPTION_LOG_IOERROR, 0},
{"log-zero", no_argument, 0, "log responses without body", uwsgi_opt_true, &uwsgi.logging_options.zero, 0},
{"log-slow", required_argument, 0, "log requests slower than the specified number of milliseconds", uwsgi_opt_set_int, &uwsgi.logging_options.slow, 0},
{"log-4xx", no_argument, 0, "log requests with a 4xx response", uwsgi_opt_true, &uwsgi.logging_options._4xx, 0},
{"log-5xx", no_argument, 0, "log requests with a 5xx response", uwsgi_opt_true, &uwsgi.logging_options._5xx, 0},
{"log-big", required_argument, 0, "log requestes bigger than the specified size", uwsgi_opt_set_64bit, &uwsgi.logging_options.big, 0},
{"log-sendfile", required_argument, 0, "log sendfile requests", uwsgi_opt_true, &uwsgi.logging_options.sendfile, 0},
{"log-ioerror", required_argument, 0, "log requests with io errors", uwsgi_opt_true, &uwsgi.logging_options.ioerror, 0},
{"log-micros", no_argument, 0, "report response time in microseconds instead of milliseconds", uwsgi_opt_true, &uwsgi.log_micros, 0},
{"log-x-forwarded-for", no_argument, 0, "use the ip from X-Forwarded-For header instead of REMOTE_ADDR", uwsgi_opt_true, &uwsgi.log_x_forwarded_for, 0},
{"log-x-forwarded-for", no_argument, 0, "use the ip from X-Forwarded-For header instead of REMOTE_ADDR", uwsgi_opt_true, &uwsgi.logging_options.log_x_forwarded_for, 0},
{"master-as-root", no_argument, 0, "leave master process running as root", uwsgi_opt_true, &uwsgi.master_as_root, 0},
{"drop-after-init", no_argument, 0, "run privileges drop after plugin initialization", uwsgi_opt_true, &uwsgi.drop_after_init, 0},
@@ -688,7 +757,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"cheap", no_argument, 0, "set cheap mode (spawn workers only after the first request)", uwsgi_opt_true, &uwsgi.status.is_cheap, UWSGI_OPT_MASTER},
{"cheaper", required_argument, 0, "set cheaper mode (adaptive process spawning)", uwsgi_opt_set_int, &uwsgi.cheaper_count, UWSGI_OPT_MASTER | UWSGI_OPT_CHEAPER},
{"cheaper-initial", required_argument, 0, "set the initial number of processes to spawn in cheaper mode", uwsgi_opt_set_int, &uwsgi.cheaper_initial, UWSGI_OPT_MASTER | UWSGI_OPT_CHEAPER},
{"cheaper-algo", required_argument, 0, "choose to algorithm used for adaptive process spawning)", uwsgi_opt_set_str, &uwsgi.requested_cheaper_algo, UWSGI_OPT_MASTER},
{"cheaper-algo", required_argument, 0, "choose to algorithm used for adaptive process spawning", uwsgi_opt_set_str, &uwsgi.requested_cheaper_algo, UWSGI_OPT_MASTER},
{"cheaper-step", required_argument, 0, "number of additional processes to spawn at each overload", uwsgi_opt_set_int, &uwsgi.cheaper_step, UWSGI_OPT_MASTER | UWSGI_OPT_CHEAPER},
{"cheaper-overload", required_argument, 0, "increase workers after specified overload", uwsgi_opt_set_64bit, &uwsgi.cheaper_overload, UWSGI_OPT_MASTER | UWSGI_OPT_CHEAPER},
{"cheaper-algo-list", no_argument, 0, "list enabled cheapers algorithms", uwsgi_opt_true, &uwsgi.cheaper_algo_list, 0},
@@ -799,6 +868,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"collect-header", required_argument, 0, "store the specified response header in a request var (syntax: header var)", uwsgi_opt_add_string_list, &uwsgi.collect_headers, 0},
{"response-header-collect", required_argument, 0, "store the specified response header in a request var (syntax: header var)", uwsgi_opt_add_string_list, &uwsgi.collect_headers, 0},
{"pull-header", required_argument, 0, "store the specified response header in a request var and remove it from the response (syntax: header var)", uwsgi_opt_add_string_list, &uwsgi.pull_headers, 0},
{"check-static", required_argument, 0, "check for static files in the specified directory", uwsgi_opt_check_static, NULL, UWSGI_OPT_MIME},
{"check-static-docroot", no_argument, 0, "check for static files in the requested DOCUMENT_ROOT", uwsgi_opt_true, &uwsgi.check_static_docroot, UWSGI_OPT_MIME},
{"static-check", required_argument, 0, "check for static files in the specified directory", uwsgi_opt_check_static, NULL, UWSGI_OPT_MIME},
@@ -848,7 +919,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},
@@ -901,6 +973,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"legion-smart-attach-daemon2", required_argument, 0, "same as --smart-attach-daemon2 but daemon runs only on legion lord node", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
#endif
{"daemons-honour-stdin", no_argument, 0, "do not change the stdin of external daemons to /dev/null", uwsgi_opt_true, &uwsgi.daemons_honour_stdin, UWSGI_OPT_MASTER},
{"attach-daemon2", required_argument, 0, "attach-daemon keyval variant (supports smart modes too)", uwsgi_opt_add_daemon2, NULL, UWSGI_OPT_MASTER},
{"plugins", required_argument, 0, "load uWSGI plugins", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE},
{"plugin", required_argument, 0, "load uWSGI plugins", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE},
{"need-plugins", required_argument, 0, "load uWSGI plugins (exit on error)", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE},
@@ -985,6 +1058,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);
@@ -1057,6 +1141,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;
}
@@ -1094,7 +1180,7 @@ void wait_for_threads() {
int sudden_death = 0;
pthread_mutex_lock(&uwsgi.six_feet_under_lock);
for (i = 0; i < uwsgi.threads; i++) {
for (i = 1; i < uwsgi.threads; i++) {
if (!pthread_equal(uwsgi.workers[uwsgi.mywid].cores[i].thread_id, pthread_self())) {
if (pthread_cancel(uwsgi.workers[uwsgi.mywid].cores[i].thread_id)) {
uwsgi_error("pthread_cancel()\n");
@@ -1107,7 +1193,7 @@ void wait_for_threads() {
goto end;
// wait for thread termination
for (i = 0; i < uwsgi.threads; i++) {
for (i = 1; i < uwsgi.threads; i++) {
if (!pthread_equal(uwsgi.workers[uwsgi.mywid].cores[i].thread_id, pthread_self())) {
ret = pthread_join(uwsgi.workers[uwsgi.mywid].cores[i].thread_id, NULL);
if (ret) {
@@ -1116,6 +1202,22 @@ void wait_for_threads() {
}
}
// cancel inital thread last since after pthread_cancel() and
// pthread_join() is called on it, the whole process will appear to be
// a zombie. although it won't eliminate process zombie time, but it
// should minimize it.
if (!pthread_equal(uwsgi.workers[uwsgi.mywid].cores[0].thread_id, pthread_self())) {
if (pthread_cancel(uwsgi.workers[uwsgi.mywid].cores[0].thread_id)) {
uwsgi_error("pthread_cancel() on initial thread\n");
goto end;
}
ret = pthread_join(uwsgi.workers[uwsgi.mywid].cores[0].thread_id, NULL);
if (ret) {
uwsgi_log("pthread_join() = %d on initial thread\n", ret);
}
}
end:
pthread_mutex_unlock(&uwsgi.six_feet_under_lock);
@@ -1193,6 +1295,11 @@ void kill_them_all(int signum) {
uwsgi_curse(i, SIGINT);
}
}
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].pid > 0) {
uwsgi_curse_mule(i, SIGINT);
}
}
uwsgi_destroy_processes();
}
@@ -1214,6 +1321,11 @@ void gracefully_kill_them_all(int signum) {
uwsgi_curse(i, SIGHUP);
}
}
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].pid > 0) {
uwsgi_curse_mule(i, SIGHUP);
}
}
uwsgi_destroy_processes();
}
@@ -1255,6 +1367,12 @@ void grace_them_all(int signum) {
uwsgi_curse(i, SIGHUP);
}
}
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].pid > 0) {
uwsgi_curse_mule(i, SIGHUP);
}
}
}
void uwsgi_nuclear_blast() {
@@ -1301,6 +1419,11 @@ void reap_them_all(int signum) {
if (uwsgi.workers[i].pid > 0)
uwsgi_curse(i, SIGTERM);
}
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].pid > 0) {
uwsgi_curse_mule(i, SIGTERM);
}
}
}
void harakiri() {
@@ -1362,7 +1485,7 @@ void what_i_am_doing() {
#else
ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, ctime_storage);
#endif
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0 && uwsgi.workers[uwsgi.mywid].harakiri < uwsgi_now()) {
if (uwsgi.harakiri_options.workers > 0 && uwsgi.workers[uwsgi.mywid].harakiri < uwsgi_now()) {
uwsgi_log("HARAKIRI: --- uWSGI worker %d core %d (pid: %d) WAS managing request %.*s since %.*s ---\n", (int) uwsgi.mywid, i, (int) uwsgi.mypid, wsgi_req->uri_len, wsgi_req->uri, 24, ctime_storage);
}
else {
@@ -1379,14 +1502,14 @@ void what_i_am_doing() {
#else
ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, ctime_storage);
#endif
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0 && uwsgi.workers[uwsgi.mywid].harakiri < uwsgi_now()) {
if (uwsgi.harakiri_options.workers > 0 && uwsgi.workers[uwsgi.mywid].harakiri < uwsgi_now()) {
uwsgi_log("HARAKIRI: --- uWSGI worker %d (pid: %d) WAS managing request %.*s since %.*s ---\n", (int) uwsgi.mywid, (int) uwsgi.mypid, wsgi_req->uri_len, wsgi_req->uri, 24, ctime_storage);
}
else {
uwsgi_log("SIGUSR2: --- uWSGI worker %d (pid: %d) is managing request %.*s since %.*s ---\n", (int) uwsgi.mywid, (int) uwsgi.mypid, wsgi_req->uri_len, wsgi_req->uri, 24, ctime_storage);
}
}
else if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0 && uwsgi.workers[uwsgi.mywid].harakiri < uwsgi_now() && uwsgi.workers[uwsgi.mywid].sig) {
else if (uwsgi.harakiri_options.workers > 0 && uwsgi.workers[uwsgi.mywid].harakiri < uwsgi_now() && uwsgi.workers[uwsgi.mywid].sig) {
uwsgi_log("HARAKIRI: --- uWSGI worker %d (pid: %d) WAS handling signal %d ---\n", (int) uwsgi.mywid, (int) uwsgi.mypid, uwsgi.workers[uwsgi.mywid].signum);
}
}
@@ -1447,8 +1570,10 @@ static void vacuum(void) {
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
if (uwsgi.restore_tc) {
if (tcsetattr(0, TCSANOW, &uwsgi.termios)) {
uwsgi_error("tcsetattr()");
if (getpid() == masterpid) {
if (tcsetattr(0, TCSANOW, &uwsgi.termios)) {
uwsgi_error("vacuum()/tcsetattr()");
}
}
}
@@ -1497,25 +1622,40 @@ static void vacuum(void) {
next:
uwsgi_sock = uwsgi_sock->next;
}
if (uwsgi.stats) {
// is a unix socket ?
if (!strchr(uwsgi.stats, ':') && uwsgi.stats[0] != '@') {
if (unlink(uwsgi.stats)) {
uwsgi_error("unlink()");
}
else {
uwsgi_log("VACUUM: unix socket %s (stats) removed.\n", uwsgi.stats);
}
}
}
}
}
}
void signal_pidfile(int sig, char *filename) {
int signal_pidfile(int sig, char *filename) {
int ret = 0;
size_t size = 0;
char *buffer = uwsgi_open_and_read(filename, &size, 1, NULL);
if (size > 0) {
if (kill((pid_t) atoi(buffer), sig)) {
uwsgi_error("kill()");
uwsgi_error("signal_pidfile()/kill()");
ret = -1;
}
}
else {
uwsgi_log("error: invalid pidfile\n");
ret = -1;
}
free(buffer);
return ret;
}
/*static*/ void uwsgi_command_signal(char *opt) {
@@ -1862,6 +2002,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__
@@ -2036,6 +2187,12 @@ void uwsgi_setup(int argc, char *argv[], char *envp[]) {
uwsgi.magic_table['V'] = UWSGI_VERSION;
uwsgi.magic_table['k'] = uwsgi_num2str(uwsgi.cpus);
uwsgi.magic_table['['] = "\033";
uwsgi.magic_table['u'] = uwsgi_num2str((int)getuid());
struct passwd *pw = getpwuid(getuid());
uwsgi.magic_table['U'] = pw ? pw->pw_name : uwsgi.magic_table['u'];
uwsgi.magic_table['g'] = uwsgi_num2str((int)getgid());
struct group *gr = getgrgid(getgid());
uwsgi.magic_table['G'] = gr ? gr->gr_name : uwsgi.magic_table['g'];
// you can embed a ini file in the uWSGi binary with default options
#ifdef UWSGI_EMBED_CONFIG
@@ -2053,7 +2210,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);
@@ -2268,6 +2425,16 @@ void uwsgi_setup(int argc, char *argv[], char *envp[]) {
// initialize shared sockets
uwsgi_setup_shared_sockets();
#ifdef __linux__
if (uwsgi.setns_preopen) {
uwsgi_setns_preopen();
}
// eventually join a linux namespace
if (uwsgi.setns) {
uwsgi_setns(uwsgi.setns);
}
#endif
// start the Emperor if needed
if (uwsgi.early_emperor && uwsgi.emperor) {
uwsgi_emperor_start();
@@ -2397,6 +2564,11 @@ int uwsgi_start(void *v_argv) {
uwsgi_as_root();
}
// wait for socket
uwsgi_foreach(usl, uwsgi.wait_for_socket) {
if (uwsgi_wait_for_socket(usl->value)) exit(1);
}
if (uwsgi.logto2) {
if (!uwsgi.is_a_reload || uwsgi.log_reopen) {
logto(uwsgi.logto2);
@@ -2404,6 +2576,7 @@ int uwsgi_start(void *v_argv) {
}
if (uwsgi.chdir) {
uwsgi_log("chdir() to %s\n", uwsgi.chdir);
if (chdir(uwsgi.chdir)) {
uwsgi_error("chdir()");
exit(1);
@@ -2702,7 +2875,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
@@ -2857,7 +3034,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) {
@@ -2995,15 +3172,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) {
@@ -3062,6 +3237,24 @@ next2:
}
// this lives in a worker thread and periodically scans for memory usage
// when evil reloaders are in place
void *mem_collector(void *foobar) {
// block all signals
sigset_t smask;
sigfillset(&smask);
pthread_sigmask(SIG_BLOCK, &smask, NULL);
uwsgi_log_verbose("mem-collector thread started for worker %d\n", uwsgi.mywid);
for(;;) {
sleep(uwsgi.mem_collector_freq);
uint64_t rss, vsz;
get_memusage(&rss, &vsz);
uwsgi.workers[uwsgi.mywid].rss_size = rss;
uwsgi.workers[uwsgi.mywid].vsz_size = vsz;
}
return NULL;
}
int uwsgi_run() {
// !!! from now on, we could be in the master or in a worker !!!
@@ -3079,6 +3272,21 @@ 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
if (uwsgi.evil_reload_on_rss || uwsgi.evil_reload_on_as) {
pthread_t t;
pthread_create(&t, NULL, mem_collector, NULL);
}
// eventually maps (or disable) sockets for the worker
uwsgi_map_sockets();
@@ -3140,6 +3348,8 @@ int uwsgi_run() {
}
}
uwsgi_hooks_run(uwsgi.hook_post_fork, "post-fork", 1);
if (uwsgi.worker_exec2) {
char *w_argv[2];
w_argv[0] = uwsgi.worker_exec2;
@@ -3193,7 +3403,7 @@ void uwsgi_worker_run() {
}
// setup UNIX signals for the worker
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0 && !uwsgi.master_process) {
if (uwsgi.harakiri_options.workers > 0 && !uwsgi.master_process) {
signal(SIGALRM, (void *) &harakiri);
}
uwsgi_unix_signal(SIGHUP, gracefully_kill);
@@ -3216,6 +3426,7 @@ void uwsgi_worker_run() {
}
if (uwsgi.chdir2) {
uwsgi_log("chdir() to %s\n", uwsgi.chdir2);
if (chdir(uwsgi.chdir2)) {
uwsgi_error("chdir()");
exit(1);
@@ -3289,7 +3500,10 @@ void uwsgi_ignition() {
if (uwsgi.has_emperor && uwsgi.mywid == 1) {
char byte = 5;
if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
uwsgi_error("write()");
uwsgi_error("emperor-i-am-ready-to-accept/write()");
uwsgi_log_verbose("lost communication with the Emperor, goodbye...\n");
gracefully_kill_them_all(0);
exit(1);
}
}
@@ -3570,6 +3784,13 @@ void uwsgi_init_all_apps() {
if (uwsgi.need_app) {
if (!uwsgi.lazy)
uwsgi_log("*** no app loaded. GAME OVER ***\n");
if (uwsgi.lazy_apps) {
if (uwsgi.master_process) {
if (kill(uwsgi.workers[0].pid, SIGINT)) {
uwsgi_error("kill()");
}
}
}
exit(UWSGI_FAILED_APP_CODE);
}
else {
@@ -3638,8 +3859,20 @@ void uwsgi_opt_true(char *opt, char *value, void *key) {
}
}
void uwsgi_opt_false(char *opt, char *value, void *key) {
int *ptr = (int *) key;
*ptr = 0;
if (value) {
if (!strcasecmp("false", value) || !strcasecmp("off", value) || !strcasecmp("no", value) || !strcmp("0", value)) {
*ptr = 1;
}
}
}
void uwsgi_opt_set_immediate_gid(char *opt, char *value, void *none) {
gid_t gid = atoi(value);
gid_t gid = 0;
if (is_a_number(value)) gid = atoi(value);
if (gid == 0) {
struct group *ugroup = getgrnam(value);
if (ugroup)
@@ -3668,7 +3901,8 @@ void uwsgi_opt_set_immediate_gid(char *opt, char *value, void *none) {
void uwsgi_opt_set_immediate_uid(char *opt, char *value, void *none) {
uid_t uid = atoi(value);
uid_t uid = 0;
if (is_a_number(value)) uid = atoi(value);
if (uid == 0) {
struct passwd *upasswd = getpwnam(value);
if (upasswd)
@@ -3714,6 +3948,44 @@ void uwsgi_opt_set_int(char *opt, char *value, void *key) {
}
}
void uwsgi_opt_uid(char *opt, char *value, void *key) {
uid_t uid = 0;
if (is_a_number(value)) uid = atoi(value);
if (!uid) {
struct passwd *p = getpwnam(value);
if (p) {
uid = p->pw_uid;
}
else {
uwsgi_log("unable to find user %s\n", value);
exit(1);
}
}
if (key) {
uid_t *ptr = (uid_t *) key;
*ptr = uid;
}
}
void uwsgi_opt_gid(char *opt, char *value, void *key) {
gid_t gid = 0;
if (is_a_number(value)) gid = atoi(value);
if (!gid) {
struct group *g = getgrnam(value);
if (g) {
gid = g->gr_gid;
}
else {
uwsgi_log("unable to find group %s\n", value);
exit(1);
}
}
if (key) {
gid_t *ptr = (gid_t *) key;
*ptr = gid;
}
}
void uwsgi_opt_set_rawint(char *opt, char *value, void *key) {
int *ptr = (int *) key;
if (value) {
@@ -3755,27 +4027,6 @@ void uwsgi_opt_set_megabytes(char *opt, char *value, void *key) {
*ptr = (uint64_t)strtoul(value, NULL, 10) * 1024 * 1024;
}
void uwsgi_opt_set_dyn(char *opt, char *value, void *key) {
long *fake_ptr = (long *) key;
uint8_t dyn_opt_id = (long) fake_ptr;
uwsgi.shared->options[dyn_opt_id] = atoi(value);
}
void uwsgi_opt_dyn_true(char *opt, char *value, void *key) {
long *fake_ptr = (long *) key;
uint8_t dyn_opt_id = (long) fake_ptr;
uwsgi.shared->options[dyn_opt_id] = 1;
}
void uwsgi_opt_dyn_false(char *opt, char *value, void *key) {
long *fake_ptr = (long *) key;
uint8_t dyn_opt_id = (long) fake_ptr;
uwsgi.shared->options[dyn_opt_id] = 0;
}
void uwsgi_opt_set_str(char *opt, char *value, void *key) {
char **ptr = (char **) key;
if (!value) {
@@ -3992,27 +4243,14 @@ void uwsgi_opt_scd(char *opt, char *value, void *foobar) {
#endif
void uwsgi_opt_set_umask(char *opt, char *value, void *mode) {
mode_t umask_mode = 0;
if (strlen(value) < 3) {
int error = 0;
mode_t mask = uwsgi_mode_t(value, &error);
if (error) {
uwsgi_log("invalid umask: %s\n", value);
}
umask_mode = 0;
if (strlen(value) == 3) {
umask_mode = (umask_mode << 3) + (value[0] - '0');
umask_mode = (umask_mode << 3) + (value[1] - '0');
umask_mode = (umask_mode << 3) + (value[2] - '0');
}
else {
umask_mode = (umask_mode << 3) + (value[1] - '0');
umask_mode = (umask_mode << 3) + (value[2] - '0');
umask_mode = (umask_mode << 3) + (value[3] - '0');
}
umask(umask_mode);
umask(mask);
uwsgi.do_not_change_umask = 1;
}
void uwsgi_opt_exit(char *opt, char *value, void *none) {
@@ -4032,15 +4270,13 @@ void uwsgi_opt_print(char *opt, char *value, void *str) {
}
void uwsgi_opt_set_uid(char *opt, char *value, void *none) {
uwsgi.uid = atoi(value);
if (is_a_number(value)) uwsgi.uid = atoi(value);
if (!uwsgi.uid)
uwsgi.uidname = value;
}
void uwsgi_opt_set_gid(char *opt, char *value, void *none) {
uwsgi.gid = atoi(value);
if (is_a_number(value)) uwsgi.gid = atoi(value);
if (!uwsgi.gid)
uwsgi.gidname = value;
}
@@ -4087,8 +4323,7 @@ void uwsgi_opt_pidfile_signal(char *opt, char *pidfile, void *sig) {
long *signum_fake_ptr = (long *) sig;
int signum = (long) signum_fake_ptr;
signal_pidfile(signum, pidfile);
exit(0);
exit(signal_pidfile(signum, pidfile));
}
void uwsgi_opt_load_dl(char *opt, char *value, void *none) {
@@ -4228,6 +4463,7 @@ int uwsgi_zerg_attach(char *value) {
if (zerg == NULL) {
uwsgi_log("--- invalid data received from zerg-server ---\n");
close(zerg_fd);
return -1;
}
@@ -4523,7 +4759,7 @@ extern char *uwsgi_dot_h;
char *uwsgi_get_dot_h() {
char *src = uwsgi_dot_h;
size_t len = strlen(src);
char *ptr = uwsgi_malloc(len / 2);
char *ptr = uwsgi_malloc((len / 2) + 1);
char *base = ptr;
size_t i;
unsigned int u;
@@ -4544,6 +4780,9 @@ char *uwsgi_get_dot_h() {
base = ub->buf;
ub->buf = NULL;
uwsgi_buffer_destroy(ub);
#else
// add final null byte
*ptr = '\0';
#endif
return base;
}
@@ -4556,7 +4795,7 @@ extern char *uwsgi_config_py;
char *uwsgi_get_config_py() {
char *src = uwsgi_config_py;
size_t len = strlen(src);
char *ptr = uwsgi_malloc(len / 2);
char *ptr = uwsgi_malloc((len / 2) + 1);
char *base = ptr;
size_t i;
unsigned int u;
@@ -4577,6 +4816,9 @@ char *uwsgi_get_config_py() {
base = ub->buf;
ub->buf = NULL;
uwsgi_buffer_destroy(ub);
#else
// add final null byte
*ptr = '\0';
#endif
return base;
}
+33 -9
View File
@@ -1,4 +1,4 @@
#include "uwsgi.h"
#include <uwsgi.h>
/*
@@ -10,6 +10,8 @@
extern struct uwsgi_server uwsgi;
#define REQ_DATA wsgi_req->method_len, wsgi_req->method, wsgi_req->uri_len, wsgi_req->uri, wsgi_req->remote_addr_len, wsgi_req->remote_addr
static struct uwsgi_buffer *uwsgi_websocket_message(struct wsgi_request *wsgi_req, char *msg, size_t len, uint8_t opcode) {
struct uwsgi_buffer *ub = wsgi_req->websocket_send_buf;
if (!ub) {
@@ -61,7 +63,7 @@ static int uwsgi_websockets_check_pingpong(struct wsgi_request *wsgi_req) {
// pong not received ?
if (wsgi_req->websocket_last_pong < wsgi_req->websocket_last_ping) {
if (wsgi_req->websocket_last_ping - wsgi_req->websocket_last_pong > uwsgi.websockets_pong_tolerance) {
uwsgi_log("[uwsgi-websocket] no PONG received in %d seconds !!!\n", uwsgi.websockets_pong_tolerance);
uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) no PONG received in %d seconds !!!\n", REQ_DATA, uwsgi.websockets_pong_tolerance);
return -1;
}
return 0;
@@ -189,7 +191,7 @@ static ssize_t uwsgi_websockets_recv_pkt(struct wsgi_request *wsgi_req, int nb)
}
goto wait;
}
uwsgi_error("uwsgi_websockets_recv_pkt()");
uwsgi_req_error("uwsgi_websockets_recv_pkt()");
return -1;
}
@@ -201,7 +203,7 @@ wait:
if (rlen <= 0) return -1;
}
if (ret < 0) {
uwsgi_error("uwsgi_websockets_recv_pkt()");
uwsgi_req_error("uwsgi_websockets_recv_pkt()");
return -1;
}
// send unsolicited pong
@@ -254,11 +256,11 @@ static struct uwsgi_buffer *uwsgi_websocket_recv_do(struct wsgi_request *wsgi_re
wsgi_req->websocket_size = uwsgi_be64(wsgi_req->websocket_buf->buf+2);
}
else {
uwsgi_log("[uwsgi-websocket] BUG error in websocket parser\n");
uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) BUG error in websocket parser\n", REQ_DATA);
return NULL;
}
if (wsgi_req->websocket_size > (uwsgi.websockets_max_size*1024)) {
uwsgi_log("[uwsgi-websocket] invalid packet size received: %llu, max allowed: %llu\n", wsgi_req->websocket_size, uwsgi.websockets_max_size * 1024);
uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) invalid packet size received: %llu, max allowed: %llu\n", REQ_DATA, wsgi_req->websocket_size, uwsgi.websockets_max_size * 1024);
return NULL;
}
wsgi_req->websocket_phase = 2;
@@ -271,6 +273,7 @@ static struct uwsgi_buffer *uwsgi_websocket_recv_do(struct wsgi_request *wsgi_re
}
else {
wsgi_req->websocket_need += wsgi_req->websocket_size;
wsgi_req->websocket_pktsize += wsgi_req->websocket_size;
wsgi_req->websocket_phase = 4;
}
break;
@@ -312,7 +315,7 @@ static struct uwsgi_buffer *uwsgi_websocket_recv_do(struct wsgi_request *wsgi_re
break;
// oops
default:
uwsgi_log("[uwsgi-websocket] BUG error in websocket parser\n");
uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) BUG error in websocket parser\n", REQ_DATA);
return NULL;
}
}
@@ -367,18 +370,39 @@ ssize_t uwsgi_websockets_simple_send(struct wsgi_request *wsgi_req, struct uwsgi
return len;
}
int uwsgi_websocket_handshake(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *origin, uint16_t origin_len) {
int uwsgi_websocket_handshake(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *origin, uint16_t origin_len, char *proto, uint16_t proto_len) {
#ifdef UWSGI_SSL
if (!key_len) {
key = wsgi_req->http_sec_websocket_key;
key_len = wsgi_req->http_sec_websocket_key_len;
}
if (key_len == 0) return -1;
char sha1[20];
if (uwsgi_response_prepare_headers(wsgi_req, "101 Web Socket Protocol Handshake", 33)) return -1;
if (uwsgi_response_add_header(wsgi_req, "Upgrade", 7, "WebSocket", 9)) return -1;
if (uwsgi_response_add_header(wsgi_req, "Connection", 10, "Upgrade", 7)) return -1;
if (origin_len > 0) {
// if origin was requested or proto_len is specified, send it back
if (wsgi_req->http_origin_len > 0 || origin_len > 0) {
if (!origin_len) {
origin = wsgi_req->http_origin;
origin_len = wsgi_req->http_origin_len;
}
if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Origin", 20, origin, origin_len)) return -1;
}
else {
if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Origin", 20, "*", 1)) return -1;
}
// if protocol was requested or proto_len is specified, send it back
if (wsgi_req->http_sec_websocket_protocol_len > 0 || proto_len > 0) {
if (!proto_len) {
proto = wsgi_req->http_sec_websocket_protocol;
proto_len = wsgi_req->http_sec_websocket_protocol_len;
}
if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Protocol", 22, proto, proto_len)) return -1;
}
// generate websockets sha1 and encode it to base64
if (!uwsgi_sha1_2n(key, key_len, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", 36, sha1)) return -1;
size_t b64_len = 0;
+43 -26
View File
@@ -5,7 +5,7 @@ extern struct uwsgi_server uwsgi;
int uwsgi_response_add_content_length(struct wsgi_request *wsgi_req, uint64_t cl) {
char buf[sizeof(UMAX64_STR)+1];
int ret = snprintf(buf, sizeof(UMAX64_STR)+1, "%llu", (unsigned long long) cl);
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
if (ret <= 0 || ret >= (int) (sizeof(UMAX64_STR)+1)) {
wsgi_req->write_errors++;
return -1;
}
@@ -51,7 +51,7 @@ int uwsgi_response_add_content_range(struct wsgi_request *wsgi_req, uint64_t sta
end = cl-1;
}
int ret = snprintf(buf, 6+(sizeof(UMAX64_STR)*3)+4, "bytes %llu-%llu/%llu", (unsigned long long) start, (unsigned long long) end, (unsigned long long) cl);
if (ret <= 0 || ret > (int) (6+(sizeof(UMAX64_STR)*3)+4)) {
if (ret <= 0 || ret >= (int) (6+(sizeof(UMAX64_STR)*3)+4)) {
wsgi_req->write_errors++;
return -1;
}
@@ -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;
@@ -122,9 +124,18 @@ error:
static int uwsgi_response_add_header_do(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) {
// collect the header ?
// pull/collect the header ?
struct uwsgi_string_list *usl = NULL;
uwsgi_foreach(usl, uwsgi.pull_headers) {
if (!uwsgi_strnicmp(key, key_len, usl->value, usl->custom)) {
if (!uwsgi_req_append(wsgi_req, usl->custom_ptr, usl->custom2, value, value_len)) {
wsgi_req->write_errors++ ; return -1;
}
return 0;
}
}
uwsgi_foreach(usl, uwsgi.collect_headers) {
if (!uwsgi_strnicmp(key, key_len, usl->value, usl->custom)) {
if (!uwsgi_req_append(wsgi_req, usl->custom_ptr, usl->custom2, value, value_len)) {
@@ -186,12 +197,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 +365,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 +450,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
-10
View File
@@ -42,16 +42,6 @@ def application(env, start_response):
yield '<h2>dynamic options</h2>'
yield '<b>logging</b>: ' + str(uwsgi.get_option(0)) + '<br/>'
yield '<b>max_requests</b>: ' + str(uwsgi.getoption(1)) + '<br/>'
yield '<b>socket_timeout</b>: ' + str(uwsgi.getoption(2)) + '<br/>'
yield '<b>memory_debug</b>: ' + str(uwsgi.getoption(3)) + '<br/>'
yield '<b>master_interval</b>: ' + str(uwsgi.getoption(4)) + '<br/>'
yield '<b>harakiri</b>: ' + str(uwsgi.getoption(5)) + '<br/>'
yield '<b>cgi_mode</b>: ' + str(uwsgi.get_option(6)) + '<br/>'
yield '<b>threads</b>: ' + str(uwsgi.get_option(7)) + '<br/>'
yield '<b>process_reaper</b>: ' + str(uwsgi.get_option(8)) + '<br/>'
yield '<table border="1">'
yield '<th>worker id</th><th>pid</th><th>in request</th><th>requests</th><th>running time</th><th>address space</th><th>rss</th>'
-11
View File
@@ -47,11 +47,6 @@ def serve_logo(e, sr):
uwsgi.sendfile('logo_uWSGI.png')
return ''
def serve_options(e, sr):
sr('200 OK', [('Content-Type', 'text/html')])
for opt in range(0,256):
yield "<b>%d</b> = %d<br/>" % (opt, uwsgi.get_option(opt))
def serve_config(e, sr):
sr('200 OK', [('Content-Type', 'text/html')])
for opt in uwsgi.opt.keys():
@@ -61,7 +56,6 @@ routes = {}
routes['/xsendfile'] = xsendfile
routes['/logo'] = serve_logo
routes['/config'] = serve_config
routes['/options'] = serve_options
@postfork
def setprocname():
@@ -119,11 +113,6 @@ def application(env, start_response):
Configuration<br/>
<iframe src="/config"></iframe><br/>
<br/>
Dynamic options<br/>
<iframe src="/options"></iframe><br/>
<br/>
Workers and applications<br/>
<table border="1">
-10
View File
@@ -9,12 +9,6 @@ def serve_logo(e, sr):
sr('200 OK', [('Content-Type', 'image/png')])
return uwsgi.sendfile('logo_uWSGI.png')
def serve_options(e, sr):
sr('200 OK', [('Content-Type', 'text/html')])
for opt in range(0,256):
body = "{opt} = {optvalue}<br/>".format(opt=opt, optvalue=uwsgi.get_option(opt))
yield bytes(body.encode('ascii'))
def serve_config(e, sr):
sr('200 OK', [('Content-Type', 'text/html')])
for opt in uwsgi.opt.keys():
@@ -25,7 +19,6 @@ routes = {}
routes['/xsendfile'] = xsendfile
routes['/logo'] = serve_logo
routes['/config'] = serve_config
routes['/options'] = serve_options
def application(env, start_response):
@@ -43,9 +36,6 @@ Configuration<br/>
<br/>
Dynamic options<br/>
<iframe src="/options"></iframe><br/>
""".format(version=uwsgi.version.decode('ascii'))
return bytes(body.encode('ascii'))
+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) {
-46
View File
@@ -1,46 +0,0 @@
#include "../../uwsgi.h"
extern struct uwsgi_server uwsgi;
/* uwsgi ADMIN|10 */
int uwsgi_request_admin(struct wsgi_request *wsgi_req) {
uint32_t opt_value = 0;
if (wsgi_req->uh->pktsize != 0 && wsgi_req->uh->pktsize != 4)
return UWSGI_OK;
// write request
if (wsgi_req->uh->pktsize == 4) {
memcpy(&opt_value, wsgi_req->buffer, 4);
uwsgi_log( "setting internal option %d to %d\n", wsgi_req->uh->modifier2, opt_value);
uwsgi.shared->options[wsgi_req->uh->modifier2] = opt_value;
// ACK
wsgi_req->uh->modifier1 = 255;
wsgi_req->uh->pktsize = 0;
wsgi_req->uh->modifier2 = 1;
uwsgi_response_write_body_do(wsgi_req, (char *)wsgi_req->uh , 4);
}
// get request
else {
uwsgi_log( "internal option %d = %d\n", wsgi_req->uh->modifier2, uwsgi.shared->options[wsgi_req->uh->modifier2]);
wsgi_req->uh->modifier1 = 10;
wsgi_req->uh->pktsize = 4;
uwsgi_response_write_body_do(wsgi_req, (char *)wsgi_req->uh , 4);
uwsgi_response_write_body_do(wsgi_req, (char *) &uwsgi.shared->options[wsgi_req->uh->modifier2], 4);
}
return UWSGI_OK;
}
struct uwsgi_plugin admin_plugin = {
.name = "admin",
.modifier1 = 10,
.request = uwsgi_request_admin,
};
-7
View File
@@ -1,7 +0,0 @@
NAME='admin'
CFLAGS = []
LDFLAGS = []
LIBS = []
GCC_LIST = ['admin_plugin']
+5 -6
View File
@@ -222,8 +222,8 @@ static void uwsgi_airbrake_loop(struct uwsgi_thread *ut) {
// ARGH !!!
if (!curl) return;
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, uwsgi.socket_timeout);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, uwsgi.socket_timeout);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_READDATA, ut);
curl_easy_setopt(curl, CURLOPT_POST, 1L);
@@ -271,12 +271,11 @@ static void uwsgi_airbrake_loop(struct uwsgi_thread *ut) {
}
static void uwsgi_airbrake_init(struct uwsgi_alarm_instance *uai) {
struct uwsgi_thread *ut = uwsgi_thread_new(uwsgi_airbrake_loop);
if (!ut) return;
uai->data_ptr = ut;
struct uwsgi_airbrake_config *uacc = uwsgi_calloc(sizeof(struct uwsgi_airbrake_config));
uacc->arg = uai->arg;
ut->data = uacc;
struct uwsgi_thread *ut = uwsgi_thread_new_with_data(uwsgi_airbrake_loop, uacc);
if (!ut) return;
uai->data_ptr = ut;
}
static void uwsgi_airbrake_func(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
+147 -83
View File
@@ -3,9 +3,18 @@
extern struct uwsgi_server uwsgi;
struct uwsgi_alarm_curl {
CURL *curl;
struct uwsgi_thread *ut;
int pos;
int blen;
char *body;
int hlen;
char hdr[];
};
struct uwsgi_alarm_curl_config {
int first;
char *arg;
char *url;
char *subject;
char *to;
};
@@ -17,7 +26,7 @@ struct uwsgi_alarm_curl_opt {
};
#ifdef CURLOPT_MAIL_RCPT
#ifdef CURLPROTO_SMTP
static void uwsgi_alarm_curl_to(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc) {
uacc->to = arg;
struct curl_slist *list = NULL;
@@ -29,6 +38,7 @@ static void uwsgi_alarm_curl_to(CURL *curl, CURLoption option, char *arg, struct
p = strtok_r(NULL, ",", &ctx);
}
curl_easy_setopt(curl, option, list);
free(items);
}
#endif
@@ -44,16 +54,33 @@ static void uwsgi_alarm_curl_set_subject(CURL *curl, CURLoption option, char *ar
uacc->subject = arg;
}
static struct uwsgi_alarm_curl_opt uaco[] = {
{"url", CURLOPT_URL, NULL},
#ifdef CURLOPT_MAIL_RCPT
{"mail_to", CURLOPT_MAIL_RCPT, uwsgi_alarm_curl_to },
static void uwsgi_alarm_curl_url(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc)
{
#ifndef CURLPROTO_SMTP
if (!uwsgi_strnicmp(arg, 4, "smtp", 4)) {
uwsgi_error("Please update libcurl to use SMTP protocol.\n");
exit(1);
}
#endif
#ifdef CURLOPT_MAIL_FROM
uacc->url = arg;
curl_easy_setopt(curl, option, arg);
}
static void uwsgi_alarm_curl_ssl_insecure(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc)
{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
}
static struct uwsgi_alarm_curl_opt uaco[] = {
{"url", CURLOPT_URL, uwsgi_alarm_curl_url},
#ifdef CURLPROTO_SMTP
{"mail_to", CURLOPT_MAIL_RCPT, uwsgi_alarm_curl_to},
{"mail_from", CURLOPT_MAIL_FROM, NULL},
#endif
{"subject", 0, uwsgi_alarm_curl_set_subject},
{"ssl", CURLOPT_USE_SSL, uwsgi_alarm_curl_ssl},
{"ssl_insecure", 0, uwsgi_alarm_curl_ssl_insecure},
{"auth_user", CURLOPT_USERNAME, NULL},
{"auth_pass", CURLOPT_PASSWORD, NULL},
{"method", CURLOPT_CUSTOMREQUEST, NULL},
@@ -65,14 +92,10 @@ static struct uwsgi_alarm_curl_opt uaco[] = {
static void uwsgi_alarm_curl_setopt(CURL *curl, char *opt, struct uwsgi_alarm_curl_config *uacc) {
struct uwsgi_alarm_curl_opt *o = uaco;
char *equal = strchr(opt,'=');
if (!equal) {
if (!uacc->first) {
curl_easy_setopt(curl, CURLOPT_URL, opt);
uacc->first = 1;
}
if (!equal && !uacc->url) {
uwsgi_alarm_curl_url(curl, CURLOPT_URL, opt, uacc);
return;
}
uacc->first = 1;
*equal = 0;
while(o->name) {
if (!strcmp(o->name, opt)) {
@@ -82,91 +105,137 @@ static void uwsgi_alarm_curl_setopt(CURL *curl, char *opt, struct uwsgi_alarm_cu
else {
curl_easy_setopt(curl, o->option, equal+1);
}
goto end;
break;
}
o++;
}
end:
*equal = '=';
}
static size_t uwsgi_alarm_curl_read_callback(void *ptr, size_t size, size_t nmemb, void *userp) {
struct uwsgi_thread *ut = (struct uwsgi_thread *) userp;
struct uwsgi_alarm_curl *uac = userp;
size_t full_size = size * nmemb;
size_t remains = ut->len - ut->pos;
struct uwsgi_alarm_curl_config *uacc = ut->data;
int remains = full_size;
if (remains == 0) return 0;
if (ut->custom0 == 0) {
size_t newline = 0;
size_t required = 1;
char *addr = ptr;
if (uacc->to) required += 4 + strlen(uacc->to) + 1;
if (uacc->subject) required += 9 + strlen(uacc->subject) + 1;
if (required > full_size) goto skip;
if (uacc->to) {
memcpy(addr, "To: ", 4); addr+=4;
memcpy(addr, uacc->to, strlen(uacc->to)); addr += strlen(uacc->to);
*addr ++= '\n';
newline = 1;
if (uac->pos < uac->hlen) {
if (remains > uac->hlen - uac->pos) {
memcpy(ptr, uac->hdr + uac->pos, uac->hlen - uac->pos);
ptr += uac->hlen - uac->pos;
remains -= uac->hlen - uac->pos;
uac->pos = uac->hlen;
} else {
memcpy(ptr, uac->hdr + uac->pos, remains);
uac->pos += remains;
return full_size;
}
if (uacc->subject) {
memcpy(addr, "Subject: ", 9); addr+=9;
memcpy(addr, uacc->subject, strlen(uacc->subject)); addr += strlen(uacc->subject);
*addr ++= '\n';
newline = 1;
}
skip:
if (newline > 0) {
*addr = '\n';
}
ut->custom0 = 1;
return required;
}
if (full_size < remains) {
remains = full_size;
if (remains > uac->blen + uac->hlen - uac->pos) {
memcpy(ptr, uac->body + uac->pos - uac->hlen, uac->blen + uac->hlen - uac->pos);
remains -= uac->blen + uac->hlen - uac->pos;
uac->pos = uac->blen + uac->hlen;
return full_size - remains;
}
memcpy(ptr, ut->buf + ut->pos, remains);
ut->pos += remains;
return remains;
memcpy(ptr, uac->body + uac->pos - uac->hlen, remains);
uac->pos += remains;
return full_size;
}
static void uwsgi_alarm_curl_loop(struct uwsgi_thread *ut) {
int interesting_fd;
ut->buf = uwsgi_malloc(uwsgi.log_master_bufsize);
static struct uwsgi_alarm_curl *uwsgi_alarm_curl_alloc(struct uwsgi_alarm_curl_config *uacc)
{
char *addr;
struct uwsgi_alarm_curl *uac;
size_t required = 0;
if (uacc->to) required += 4 + strlen(uacc->to) + 2;
if (uacc->subject) required += 9 + strlen(uacc->subject) + 2;
if (required)
required += 2; /* newline between MIME header and body */
uac = uwsgi_malloc(sizeof(*uac) + required);
uac->hlen = required;
addr = uac->hdr;
if (uacc->to) {
memcpy(addr, "To: ", 4); addr += 4;
memcpy(addr, uacc->to, strlen(uacc->to)); addr += strlen(uacc->to);
*addr++ = '\r';
*addr++ = '\n';
}
if (uacc->subject) {
memcpy(addr, "Subject: ", 9); addr += 9;
memcpy(addr, uacc->subject, strlen(uacc->subject)); addr += strlen(uacc->subject);
*addr++ = '\r';
*addr++ = '\n';
}
if (required) {
*addr++ = '\r';
*addr = '\n';
}
return uac;
}
static struct uwsgi_alarm_curl *uwsgi_alarm_curl_init_curl(struct uwsgi_alarm_instance *uai) {
CURL *curl = curl_easy_init();
// ARGH !!!
if (!curl) return;
if (!curl) {
uwsgi_error("Failed to initialize libcurl.\n");
exit(1);
}
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, uwsgi.socket_timeout);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, uwsgi.socket_timeout);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, uwsgi_alarm_curl_read_callback);
curl_easy_setopt(curl, CURLOPT_READDATA, ut);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(curl, CURLOPT_POST, 1L);
struct curl_slist *expect = NULL; expect = curl_slist_append(expect, "Expect:");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, expect);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
struct uwsgi_alarm_curl_config *uacc = (struct uwsgi_alarm_curl_config *) ut->data;
char *opts = uwsgi_str(uacc->arg);
struct uwsgi_alarm_curl_config uacc;
memset(&uacc, 0, sizeof(uacc));
char *opts = uwsgi_str(uai->arg);
// fill curl options
char *ctx = NULL;
char *p = strtok_r(opts, ";", &ctx);
while(p) {
uwsgi_alarm_curl_setopt(curl, uwsgi_str(p), uacc);
uwsgi_alarm_curl_setopt(curl, p, &uacc);
p = strtok_r(NULL, ";", &ctx);
}
if (!uacc.url) {
uwsgi_error("An URL is required to trigger curl-based alarm.\n");
exit(1);
}
struct uwsgi_alarm_curl *uac = uwsgi_alarm_curl_alloc(&uacc);
curl_easy_setopt(curl, CURLOPT_READDATA, uac);
free(opts);
uac->curl = curl;
uai->data_ptr = uac;
return uac;
}
static void uwsgi_alarm_curl_call_curl(struct uwsgi_alarm_curl *uac, char *msg, int len)
{
uac->pos = 0;
uac->body = msg;
uac->blen = len;
curl_easy_setopt(uac->curl, CURLOPT_INFILESIZE, uac->hlen + uac->blen);
CURLcode res = curl_easy_perform(uac->curl);
if (res != CURLE_OK)
uwsgi_log_alarm("-curl] curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
}
static void uwsgi_alarm_curl_loop(struct uwsgi_thread *ut) {
int interesting_fd;
struct uwsgi_alarm_curl *uac = uwsgi_alarm_curl_init_curl(ut->data);
uac->ut = ut;
ut->buf = uwsgi_malloc(uwsgi.log_master_bufsize);
for(;;) {
int ret = event_queue_wait(ut->queue, -1, &interesting_fd);
if (ret < 0) return;
@@ -174,31 +243,26 @@ static void uwsgi_alarm_curl_loop(struct uwsgi_thread *ut) {
if (interesting_fd != ut->pipe[1]) continue;
ssize_t rlen = read(ut->pipe[1], ut->buf, uwsgi.log_master_bufsize);
if (rlen <= 0) continue;
ut->pos = 0;
ut->len = (size_t) rlen;
ut->custom0 = 0;
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t) ut->len);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) {
uwsgi_log_alarm("-curl] curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
}
uwsgi_alarm_curl_call_curl(uac, ut->buf, rlen);
}
}
static void uwsgi_alarm_curl_init(struct uwsgi_alarm_instance *uai) {
struct uwsgi_thread *ut = uwsgi_thread_new(uwsgi_alarm_curl_loop);
if (!ut) return;
uai->data_ptr = ut;
struct uwsgi_alarm_curl_config *uacc = uwsgi_calloc(sizeof(struct uwsgi_alarm_curl_config));
uacc->arg = uai->arg;
ut->data = uacc;
if (uwsgi.alarm_cheap)
uwsgi_alarm_curl_init_curl(uai);
else
uwsgi_thread_new_with_data(uwsgi_alarm_curl_loop, uai);
}
// pipe the message into the thread;
static void uwsgi_alarm_curl_func(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
struct uwsgi_thread *ut = (struct uwsgi_thread *) uai->data_ptr;
ut->rlen = write(ut->pipe[0], msg, len);
struct uwsgi_alarm_curl *uac = uai->data_ptr;
if (uwsgi.alarm_cheap)
uwsgi_alarm_curl_call_curl(uac, msg, len);
else {
struct uwsgi_thread *ut = uac->ut;
ut->rlen = write(ut->pipe[0], msg, len);
}
}
static void uwsgi_alarm_curl_load(void) {
+1 -2
View File
@@ -4,10 +4,9 @@ void uwsgi_alarm_xmpp_loop(struct uwsgi_thread *);
static void uwsgi_alarm_xmpp_init(struct uwsgi_alarm_instance *uai) {
struct uwsgi_thread *ut = uwsgi_thread_new(uwsgi_alarm_xmpp_loop);
struct uwsgi_thread *ut = uwsgi_thread_new_with_data(uwsgi_alarm_xmpp_loop, uai->arg);
if (!ut) return;
uai->data_ptr = ut;
ut->data = uai->arg;
}
// pipe the message into the thread;
+387
View File
@@ -0,0 +1,387 @@
#include "../python/uwsgi_python.h"
/*
python >= 3.4 asyncio (PEP 3156) loop engine
EXPERIMENTAL !!!
Author: Roberto De Ioris
*/
extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
static struct uwsgi_asyncio {
PyObject *mod;
PyObject *loop;
PyObject *request;
PyObject *hook_fd;
PyObject *hook_timeout;
PyObject *hook_fix;
} uasyncio;
#define free_req_queue uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = wsgi_req
static void uwsgi_opt_setup_asyncio(char *opt, char *value, void *null) {
// set async mode
uwsgi_opt_set_int(opt, value, &uwsgi.async);
if (uwsgi.socket_timeout < 30) {
uwsgi.socket_timeout = 30;
}
// set loop engine
uwsgi.loop = "asyncio";
}
static struct uwsgi_option asyncio_options[] = {
{"asyncio", required_argument, 0, "a shortcut enabling asyncio loop engine with the specified number of async cores and optimal parameters", uwsgi_opt_setup_asyncio, NULL, UWSGI_OPT_THREADS},
{0, 0, 0, 0, 0, 0, 0},
};
static void gil_asyncio_get() {
pthread_setspecific(up.upt_gil_key, (void *) PyGILState_Ensure());
}
static void gil_asyncio_release() {
PyGILState_Release((PyGILState_STATE) pthread_getspecific(up.upt_gil_key));
}
static int uwsgi_asyncio_wait_read_hook(int fd, int timeout) {
struct wsgi_request *wsgi_req = current_wsgi_req();
if (PyObject_CallMethod(uasyncio.loop, "add_reader", "iOl", fd, uasyncio.hook_fd,(long) wsgi_req) == NULL) {
goto error;
}
PyObject *ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOl", timeout, uasyncio.hook_timeout, (long)wsgi_req);
if (!ob_timeout) {
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", fd) == NULL) PyErr_Print();
goto error;
}
// back to loop
if (uwsgi.schedule_to_main) uwsgi.schedule_to_main(wsgi_req);
// back from loop
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", fd) == NULL) PyErr_Print();
if (PyObject_CallMethod(ob_timeout, "cancel", NULL) == NULL) PyErr_Print();
Py_DECREF(ob_timeout);
if (wsgi_req->async_timed_out) return 0;
return 1;
error:
PyErr_Print();
return -1;
}
static int uwsgi_asyncio_wait_write_hook(int fd, int timeout) {
struct wsgi_request *wsgi_req = current_wsgi_req();
if (PyObject_CallMethod(uasyncio.loop, "add_writer", "iOl", fd, uasyncio.hook_fd,(long) wsgi_req) == NULL) {
goto error;
}
PyObject *ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOl", timeout, uasyncio.hook_timeout, (long)wsgi_req);
if (!ob_timeout) {
if (PyObject_CallMethod(uasyncio.loop, "remove_writer", "i", fd) == NULL) PyErr_Print();
goto error;
}
// back to loop
if (uwsgi.schedule_to_main) {
uwsgi.schedule_to_main(wsgi_req);
}
// back from loop
if (PyObject_CallMethod(uasyncio.loop, "remove_writer", "i", fd) == NULL) PyErr_Print();
if (PyObject_CallMethod(ob_timeout, "cancel", NULL) == NULL) PyErr_Print();
Py_DECREF(ob_timeout);
if (wsgi_req->async_timed_out) return 0;
return 1;
error:
PyErr_Print();
return -1;
}
static PyObject *py_uwsgi_asyncio_request(PyObject *self, PyObject *args) {
long wsgi_req_ptr = 0;
int timed_out = 0;
if (!PyArg_ParseTuple(args, "l|i:uwsgi_asyncio_request", &wsgi_req_ptr, &timed_out)) {
uwsgi_log_verbose("[BUG] invalid arguments for asyncio callback !!!\n");
exit(1);
}
struct wsgi_request *wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
uwsgi.wsgi_req = wsgi_req;
PyObject *ob_timeout = (PyObject *) wsgi_req->async_timeout;
if (PyObject_CallMethod(ob_timeout, "cancel", NULL) == NULL) PyErr_Print();
Py_DECREF(ob_timeout);
// avoid mess when closing the request
wsgi_req->async_timeout = NULL;
if (timed_out > 0) {
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) PyErr_Print();
goto end;
}
int status = wsgi_req->socket->proto(wsgi_req);
if (status > 0) {
ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOli", uwsgi.socket_timeout, uasyncio.request, wsgi_req_ptr, 1);
if (!ob_timeout) {
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) PyErr_Print();
goto end;
}
// trick for reference counting
wsgi_req->async_timeout = (struct uwsgi_rb_timer *) ob_timeout;
goto again;
}
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) {
PyErr_Print();
goto end;
}
if (status == 0) {
// we call this two time... overengineering :(
uwsgi.async_proto_fd_table[wsgi_req->fd] = NULL;
uwsgi.schedule_to_req();
goto again;
}
end:
uwsgi.async_proto_fd_table[wsgi_req->fd] = NULL;
uwsgi_close_request(uwsgi.wsgi_req);
free_req_queue;
again:
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *py_uwsgi_asyncio_accept(PyObject *self, PyObject *args) {
long uwsgi_sock_ptr = 0;
if (!PyArg_ParseTuple(args, "l:uwsgi_asyncio_accept", &uwsgi_sock_ptr)) {
return NULL;
}
struct wsgi_request *wsgi_req = find_first_available_wsgi_req();
if (wsgi_req == NULL) {
uwsgi_async_queue_is_full(uwsgi_now());
goto end;
}
uwsgi.wsgi_req = wsgi_req;
struct uwsgi_socket *uwsgi_sock = (struct uwsgi_socket *) uwsgi_sock_ptr;
// fill wsgi_request structure
wsgi_req_setup(wsgi_req, wsgi_req->async_id, uwsgi_sock );
// mark core as used
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 1;
// accept the connection (since uWSGI 1.5 all of the sockets are non-blocking)
if (wsgi_req_simple_accept(wsgi_req, uwsgi_sock->fd)) {
// in case of errors (or thundering herd, just reset it)
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 0;
free_req_queue;
goto end;
}
wsgi_req->start_of_request = uwsgi_micros();
wsgi_req->start_of_request_in_sec = wsgi_req->start_of_request/1000000;
// enter harakiri mode
if (uwsgi.harakiri_options.workers > 0) {
set_harakiri(uwsgi.harakiri_options.workers);
}
uwsgi.async_proto_fd_table[wsgi_req->fd] = wsgi_req;
// add callback for protocol
if (PyObject_CallMethod(uasyncio.loop, "add_reader", "iOl", wsgi_req->fd, uasyncio.request, (long) wsgi_req) == NULL) {
free_req_queue;
PyErr_Print();
}
// add timeout
PyObject *ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOli", uwsgi.socket_timeout, uasyncio.request, (long)wsgi_req, 1);
if (!ob_timeout) {
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) PyErr_Print();
free_req_queue;
}
else {
// trick for reference counting
wsgi_req->async_timeout = (struct uwsgi_rb_timer *) ob_timeout;
}
end:
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_asyncio_hook_fd(PyObject *self, PyObject *args) {
long wsgi_req_ptr = 0;
if (!PyArg_ParseTuple(args, "l:uwsgi_asyncio_hook_fd", &wsgi_req_ptr)) {
return NULL;
}
uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
uwsgi.schedule_to_req();
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_asyncio_hook_timeout(PyObject *self, PyObject *args) {
long wsgi_req_ptr = 0;
if (!PyArg_ParseTuple(args, "l", &wsgi_req_ptr)) {
return NULL;
}
uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
uwsgi.wsgi_req->async_timed_out = 1;
uwsgi.schedule_to_req();
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_uwsgi_asyncio_hook_fix(PyObject *self, PyObject *args) {
long wsgi_req_ptr = 0;
if (!PyArg_ParseTuple(args, "l", &wsgi_req_ptr)) {
return NULL;
}
uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
uwsgi.schedule_to_req();
Py_INCREF(Py_None);
return Py_None;
}
PyMethodDef uwsgi_asyncio_accept_def[] = { {"uwsgi_asyncio_accept", py_uwsgi_asyncio_accept, METH_VARARGS, ""} };
PyMethodDef uwsgi_asyncio_request_def[] = { {"uwsgi_asyncio_request", py_uwsgi_asyncio_request, METH_VARARGS, ""} };
PyMethodDef uwsgi_asyncio_hook_fd_def[] = { {"uwsgi_asyncio_hook_fd", py_uwsgi_asyncio_hook_fd, METH_VARARGS, ""} };
PyMethodDef uwsgi_asyncio_hook_timeout_def[] = { {"uwsgi_asyncio_hook_timeout", py_uwsgi_asyncio_hook_timeout, METH_VARARGS, ""} };
PyMethodDef uwsgi_asyncio_hook_fix_def[] = { {"uwsgi_asyncio_hook_fix", py_uwsgi_asyncio_hook_fix, METH_VARARGS, ""} };
static void uwsgi_asyncio_schedule_fix(struct wsgi_request *wsgi_req) {
PyObject *cb = PyObject_CallMethod(uasyncio.loop, "call_soon", "Ol", uasyncio.hook_fix, (long) wsgi_req);
if (!cb) goto error;
Py_DECREF(cb);
return;
error:
PyErr_Print();
}
static void asyncio_loop() {
if (!uwsgi.has_threads && uwsgi.mywid == 1) {
uwsgi_log("!!! Running asyncio without threads IS NOT recommended, enable them with --enable-threads !!!\n");
}
if (uwsgi.socket_timeout < 30) {
uwsgi_log("!!! Running asyncio with a socket-timeout lower than 30 seconds is not recommended, tune it with --socket-timeout !!!\n");
}
if (!uwsgi.async_waiting_fd_table)
uwsgi.async_waiting_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
if (!uwsgi.async_proto_fd_table)
uwsgi.async_proto_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
// get the GIL
UWSGI_GET_GIL
up.gil_get = gil_asyncio_get;
up.gil_release = gil_asyncio_release;
uwsgi.wait_write_hook = uwsgi_asyncio_wait_write_hook;
uwsgi.wait_read_hook = uwsgi_asyncio_wait_read_hook;
if (uwsgi.async < 2) {
uwsgi_log("the asyncio loop engine requires async mode (--async <n>)\n");
exit(1);
}
if (!uwsgi.schedule_to_main) {
uwsgi_log("*** DANGER *** asyncio mode without coroutine/greenthread engine loaded !!!\n");
}
if (!uwsgi.schedule_to_req) {
uwsgi.schedule_to_req = async_schedule_to_req_green;
}
else {
uwsgi.schedule_fix = uwsgi_asyncio_schedule_fix;
}
#ifndef PYTHREE
PyObject *asyncio = PyImport_ImportModule("trollius");
#else
PyObject *asyncio = PyImport_ImportModule("asyncio");
#endif
if (!asyncio) uwsgi_pyexit;
uasyncio.mod = asyncio;
uasyncio.loop = PyObject_CallMethod(asyncio, "get_event_loop", NULL);
if (!uasyncio.loop) uwsgi_pyexit;
// main greenlet waiting for connection (one greenlet per-socket)
PyObject *asyncio_accept = PyCFunction_New(uwsgi_asyncio_accept_def, NULL);
Py_INCREF(asyncio_accept);
uasyncio.request = PyCFunction_New(uwsgi_asyncio_request_def, NULL);
if (!uasyncio.request) uwsgi_pyexit;
uasyncio.hook_fd = PyCFunction_New(uwsgi_asyncio_hook_fd_def, NULL);
if (!uasyncio.hook_fd) uwsgi_pyexit;
uasyncio.hook_timeout = PyCFunction_New(uwsgi_asyncio_hook_timeout_def, NULL);
if (!uasyncio.hook_timeout) uwsgi_pyexit;
uasyncio.hook_fix = PyCFunction_New(uwsgi_asyncio_hook_fix_def, NULL);
if (!uasyncio.hook_fix) uwsgi_pyexit;
Py_INCREF(uasyncio.request);
Py_INCREF(uasyncio.hook_fd);
Py_INCREF(uasyncio.hook_timeout);
Py_INCREF(uasyncio.hook_fix);
// call add_handler on each socket
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while(uwsgi_sock) {
if (PyObject_CallMethod(uasyncio.loop, "add_reader", "iOl", uwsgi_sock->fd, asyncio_accept, (long) uwsgi_sock) == NULL) {
uwsgi_pyexit;
}
uwsgi_sock = uwsgi_sock->next;
}
if (PyObject_CallMethod(uasyncio.loop, "run_forever", NULL) == NULL) {
uwsgi_pyexit;
}
// never here ?
}
static void asyncio_init() {
uwsgi_register_loop( (char *) "asyncio", asyncio_loop);
}
struct uwsgi_plugin asyncio_plugin = {
.name = "asyncio",
.options = asyncio_options,
.on_load = asyncio_init,
};
+8
View File
@@ -0,0 +1,8 @@
from distutils import sysconfig
NAME='asyncio'
CFLAGS = ['-I' + sysconfig.get_python_inc(), '-I' + sysconfig.get_python_inc(plat_specific=True)]
LDFLAGS = []
LIBS = []
GCC_LIST = ['asyncio']
+13 -5
View File
@@ -71,7 +71,9 @@ static void carbon_post_init() {
u_server->errors = 0;
char *p, *ctx = NULL;
uwsgi_foreach_token(usl->value, ":", p, ctx) {
// make a copy to not clobber argv
char *tmp = uwsgi_str(usl->value);
uwsgi_foreach_token(tmp, ":", p, ctx) {
if (!u_server->hostname) {
u_server->hostname = uwsgi_str(p);
}
@@ -81,6 +83,7 @@ static void carbon_post_init() {
else
break;
}
free(tmp);
if (!u_server->hostname || !u_server->port) {
uwsgi_log("[carbon] invalid carbon server address (%s)\n", usl->value);
usl = usl->next;
@@ -196,7 +199,7 @@ static int carbon_push_stats(int retry_cycle, time_t now) {
for (i = 0; i < uwsgi.numproc; i++) {
u_carbon.current_busyness_values[i] = uwsgi.workers[i+1].running_time - u_carbon.last_busyness_values[i];
u_carbon.last_busyness_values[i] = uwsgi.workers[i+1].running_time;
u_carbon.was_busy[i-1] += uwsgi_worker_is_busy(i+1);
u_carbon.was_busy[i] += uwsgi_worker_is_busy(i+1);
}
needs_retry = 0;
@@ -281,7 +284,7 @@ static int carbon_push_stats(int retry_cycle, time_t now) {
total_busyness += worker_busyness;
u_carbon.was_busy[i-1] = 0;
if (uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG] == 1 || uwsgi.force_get_memusage) {
if (uwsgi.logging_options.memory_report == 1 || uwsgi.force_get_memusage) {
// only running workers are counted in total memory stats and if memory-report option is enabled
total_rss += uwsgi.workers[i].rss_size;
total_vsz += uwsgi.workers[i].vsz_size;
@@ -294,7 +297,7 @@ static int carbon_push_stats(int retry_cycle, time_t now) {
wok = carbon_write(fd, "%s%s.%s.worker%d.requests %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, i, (unsigned long long) uwsgi.workers[i].requests, (unsigned long long) now);
if (!wok) goto clear;
if (uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG] == 1 || uwsgi.force_get_memusage) {
if (uwsgi.logging_options.memory_report == 1 || uwsgi.force_get_memusage) {
wok = carbon_write(fd, "%s%s.%s.worker%d.rss_size %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, i, (unsigned long long) uwsgi.workers[i].rss_size, (unsigned long long) now);
if (!wok) goto clear;
@@ -327,7 +330,7 @@ static int carbon_push_stats(int retry_cycle, time_t now) {
}
if (uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG] == 1 || uwsgi.force_get_memusage) {
if (uwsgi.logging_options.memory_report == 1 || uwsgi.force_get_memusage) {
wok = carbon_write(fd, "%s%s.%s.rss_size %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) total_rss, (unsigned long long) now);
if (!wok) goto clear;
@@ -380,6 +383,11 @@ metrics_loop:
uwsgi_rlock(uwsgi.metrics_lock);
wok = carbon_write(fd, "%s%s.%s.%.*s %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, um->name_len, um->name, (unsigned long long) *um->value, (unsigned long long) now);
uwsgi_rwunlock(uwsgi.metrics_lock);
if (um->reset_after_push){
uwsgi_wlock(uwsgi.metrics_lock);
*um->value = um->initial_value;
uwsgi_rwunlock(uwsgi.metrics_lock);
}
if (!wok) goto clear;
um = um->next;
}
+218 -133
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;
}
}
}
}
@@ -450,9 +533,9 @@ static int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
memcpy(full_path, tmp_path, full_path_len+1);
if (uwsgi_starts_with(full_path, full_path_len, docroot, docroot_len)) {
uwsgi_log("CGI security error: %s is not under %s\n", full_path, docroot);
if (need_free)
free(docroot);
uwsgi_log("CGI security error: %s is not under %s\n", full_path, docroot);
return -1;
}
@@ -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);
}
+1 -1
View File
@@ -17,7 +17,7 @@ int cheaper_backlog2_algo(int can_spawn) {
int i;
#ifdef __linux__
int backlog = uwsgi.shared->options[UWSGI_OPTION_BACKLOG_STATUS];
int backlog = uwsgi.socket_timeout;
#else
int backlog = 0;
#endif
+85 -48
View File
@@ -13,11 +13,13 @@ struct uwsgi_cheaper_busyness_global {
uint64_t busyness_max;
uint64_t busyness_min;
uint64_t *last_values;
uint64_t *current_busyness;
uint64_t total_avg_busyness;
int *was_busy;
uint64_t tcheck;
uint64_t last_cheaped; // last time worker was cheaped due to low busyness
uint64_t next_cheap; // timestamp, we can cheap worker after it
uint64_t penalty; // penelty for respawning to fast, it will be added to multiplier
uint64_t penalty; // penalty for respawning to fast, it will be added to multiplier
uint64_t min_multi; //initial multiplier will be stored here
uint64_t cheap_multi; // current multiplier value
int last_action; // 1 - spawn workers ; 2 - cheap worker
@@ -41,7 +43,7 @@ struct uwsgi_option uwsgi_cheaper_busyness_options[] = {
uwsgi_opt_set_64bit, &uwsgi_cheaper_busyness_global.busyness_max, 0},
{"cheaper-busyness-min", required_argument, 0,
"set the cheaper busyness low percent limit, belowe that value worker is considered idle (default 25)",
"set the cheaper busyness low percent limit, below that value worker is considered idle (default 25)",
uwsgi_opt_set_64bit, &uwsgi_cheaper_busyness_global.busyness_min, 0},
{"cheaper-busyness-multiplier", required_argument, 0,
@@ -57,7 +59,7 @@ struct uwsgi_option uwsgi_cheaper_busyness_options[] = {
#ifdef __linux__
{"cheaper-busyness-backlog-alert", required_argument, 0,
"spawn emergency worker(s) if anytime listen queue is higher than this value (default 33)",
"spawn emergency worker(s) if any time listen queue is higher than this value (default 33)",
uwsgi_opt_set_int, &uwsgi_cheaper_busyness_global.backlog_alert, 0},
{"cheaper-busyness-backlog-multiplier", required_argument, 0,
"set cheaper multiplier used for emergency workers (default 3)",
@@ -148,46 +150,6 @@ int cheaper_busyness_algo(int can_spawn) {
// we use microseconds
uint64_t t = uwsgi.cheaper_overload*1000000;
// this happens on the first run, the required memory is allocated
if (!uwsgi_cheaper_busyness_global.last_values) {
uwsgi_cheaper_busyness_global.last_values = uwsgi_calloc(sizeof(uint64_t) * uwsgi.numproc);
}
if (!uwsgi_cheaper_busyness_global.was_busy) {
uwsgi_cheaper_busyness_global.was_busy = uwsgi_calloc(sizeof(int) * uwsgi.numproc);
}
// set defaults
if (!uwsgi_cheaper_busyness_global.busyness_max) uwsgi_cheaper_busyness_global.busyness_max = 50;
if (!uwsgi_cheaper_busyness_global.busyness_min) uwsgi_cheaper_busyness_global.busyness_min = 25;
if (!uwsgi_cheaper_busyness_global.cheap_multi) uwsgi_cheaper_busyness_global.cheap_multi = 10;
if (!uwsgi_cheaper_busyness_global.penalty) uwsgi_cheaper_busyness_global.penalty = 2;
#ifdef __linux__
if (!uwsgi_cheaper_busyness_global.backlog_alert) uwsgi_cheaper_busyness_global.backlog_alert = 33;
if (!uwsgi_cheaper_busyness_global.backlog_multi) uwsgi_cheaper_busyness_global.backlog_multi = 3;
if (!uwsgi_cheaper_busyness_global.backlog_step) uwsgi_cheaper_busyness_global.backlog_step = 1;
if (!uwsgi_cheaper_busyness_global.backlog_nonzero_alert) uwsgi_cheaper_busyness_global.backlog_nonzero_alert = 60;
#endif
if (!uwsgi_cheaper_busyness_global.min_multi) {
// store initial multiplier so we don't loose its initial value
uwsgi_cheaper_busyness_global.min_multi = uwsgi_cheaper_busyness_global.cheap_multi;
// since this is first run we will print current values
uwsgi_log("[busyness] settings: min=%llu%%, max=%llu%%, overload=%llu, multiplier=%llu, respawn penalty=%llu\n",
uwsgi_cheaper_busyness_global.busyness_min, uwsgi_cheaper_busyness_global.busyness_max,
uwsgi.cheaper_overload, uwsgi_cheaper_busyness_global.cheap_multi, uwsgi_cheaper_busyness_global.penalty);
#ifdef __linux__
uwsgi_log("[busyness] backlog alert is set to %d request(s), step is %d\n",
uwsgi_cheaper_busyness_global.backlog_alert, uwsgi_cheaper_busyness_global.backlog_step);
uwsgi_log("[busyness] backlog non-zero alert is set to %llu second(s)\n", uwsgi_cheaper_busyness_global.backlog_nonzero_alert);
#endif
}
// initialize with current time
if (uwsgi_cheaper_busyness_global.tcheck == 0) uwsgi_cheaper_busyness_global.tcheck = uwsgi_micros();
if (uwsgi_cheaper_busyness_global.next_cheap == 0) set_next_cheap_time();
int active_workers = 0;
uint64_t total_busyness = 0;
uint64_t avg_busyness = 0;
@@ -202,7 +164,7 @@ int cheaper_busyness_algo(int can_spawn) {
}
#ifdef __linux__
int backlog = uwsgi.shared->options[UWSGI_OPTION_BACKLOG_STATUS];
int backlog = uwsgi.shared->backlog;
#endif
uint64_t now = uwsgi_micros();
@@ -228,11 +190,23 @@ int cheaper_busyness_algo(int can_spawn) {
if (uwsgi_cheaper_busyness_global.verbose && active_workers > 1)
uwsgi_log("[busyness] worker nr %d %llus average busyness is at %llu%%\n",
i+1, uwsgi.cheaper_overload, percent);
if (uwsgi.has_metrics) {
// update metrics
uwsgi_wlock(uwsgi.metrics_lock);
uwsgi_cheaper_busyness_global.current_busyness[i] = percent;
uwsgi_rwunlock(uwsgi.metrics_lock);
}
}
uwsgi_cheaper_busyness_global.last_values[i] = uwsgi.workers[i+1].running_time;
}
avg_busyness = (active_workers ? total_busyness / active_workers : 0);
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",
(int) uwsgi.cheaper_overload, (int) active_workers, (int) avg_busyness);
@@ -261,7 +235,7 @@ int cheaper_busyness_algo(int can_spawn) {
// worker was cheaped and then spawned back in less than current multiplier*cheaper_overload seconds
// we will increase the multiplier so that next time worker will need to wait longer before being cheaped
uwsgi_cheaper_busyness_global.cheap_multi += uwsgi_cheaper_busyness_global.penalty;
uwsgi_log("[busyness] worker(s) respawned to fast, increasing chpeaper multiplier to %llu (+%llu)\n",
uwsgi_log("[busyness] worker(s) respawned to fast, increasing cheaper multiplier to %llu (+%llu)\n",
uwsgi_cheaper_busyness_global.cheap_multi, uwsgi_cheaper_busyness_global.penalty);
} else {
decrease_multi();
@@ -333,7 +307,7 @@ int cheaper_busyness_algo(int can_spawn) {
// time needed to cheap them, than a lot min<busy<max when we do not reset timer
// and then another idle cycle than would trigger cheaping
if (uwsgi_cheaper_busyness_global.verbose)
uwsgi_log("[busyness] %llus average busyness is at %llu%%, %llu non-idle cycle(s), reseting cheaper timer\n",
uwsgi_log("[busyness] %llus average busyness is at %llu%%, %llu non-idle cycle(s), resetting cheaper timer\n",
uwsgi.cheaper_overload, avg_busyness, uwsgi_cheaper_busyness_global.tolerance_counter);
set_next_cheap_time();
} else {
@@ -385,10 +359,73 @@ void uwsgi_cheaper_register_busyness(void) {
uwsgi_register_cheaper_algo("busyness", cheaper_busyness_algo);
}
static int uwsgi_cheaper_busyness_init(void) {
if (!uwsgi.requested_cheaper_algo || strcmp(uwsgi.requested_cheaper_algo, "busyness")) return 0;
// this happens on the first run, the required memory is allocated
uwsgi_cheaper_busyness_global.last_values = uwsgi_calloc(sizeof(uint64_t) * uwsgi.numproc);
uwsgi_cheaper_busyness_global.was_busy = uwsgi_calloc(sizeof(int) * uwsgi.numproc);
if (uwsgi.has_metrics) {
// allocate metrics memory
uwsgi_cheaper_busyness_global.current_busyness = uwsgi_calloc(sizeof(uint64_t) * uwsgi.numproc);
}
// set defaults
if (!uwsgi_cheaper_busyness_global.busyness_max) uwsgi_cheaper_busyness_global.busyness_max = 50;
if (!uwsgi_cheaper_busyness_global.busyness_min) uwsgi_cheaper_busyness_global.busyness_min = 25;
if (!uwsgi_cheaper_busyness_global.cheap_multi) uwsgi_cheaper_busyness_global.cheap_multi = 10;
if (!uwsgi_cheaper_busyness_global.penalty) uwsgi_cheaper_busyness_global.penalty = 2;
#ifdef __linux__
if (!uwsgi_cheaper_busyness_global.backlog_alert) uwsgi_cheaper_busyness_global.backlog_alert = 33;
if (!uwsgi_cheaper_busyness_global.backlog_multi) uwsgi_cheaper_busyness_global.backlog_multi = 3;
if (!uwsgi_cheaper_busyness_global.backlog_step) uwsgi_cheaper_busyness_global.backlog_step = 1;
if (!uwsgi_cheaper_busyness_global.backlog_nonzero_alert) uwsgi_cheaper_busyness_global.backlog_nonzero_alert = 60;
#endif
// store initial multiplier so we don't loose that value
uwsgi_cheaper_busyness_global.min_multi = uwsgi_cheaper_busyness_global.cheap_multi;
// since this is first run we will print current values
uwsgi_log("[busyness] settings: min=%llu%%, max=%llu%%, overload=%llu, multiplier=%llu, respawn penalty=%llu\n",
uwsgi_cheaper_busyness_global.busyness_min, uwsgi_cheaper_busyness_global.busyness_max,
uwsgi.cheaper_overload, uwsgi_cheaper_busyness_global.cheap_multi, uwsgi_cheaper_busyness_global.penalty);
#ifdef __linux__
uwsgi_log("[busyness] backlog alert is set to %d request(s), step is %d\n",
uwsgi_cheaper_busyness_global.backlog_alert, uwsgi_cheaper_busyness_global.backlog_step);
uwsgi_log("[busyness] backlog non-zero alert is set to %llu second(s)\n", uwsgi_cheaper_busyness_global.backlog_nonzero_alert);
#endif
// register metrics if enabled
if (uwsgi.has_metrics) {
int i;
char buf[4096];
char buf2[4096];
for (i = 0; i < uwsgi.numproc; i++) {
if (snprintf(buf, 4096, "worker.%d.plugin.cheaper_busyness.busyness", i+1) <= 0) {
uwsgi_log("[busyness] unable to register busyness metric for worker %d\n", i+1);
exit(1);
}
if (snprintf(buf2, 4096, "3.%d.100.1", i+1) <= 0) {
uwsgi_log("[busyness] unable to register busyness metric oid for worker %d\n", i+1);
exit(1);
}
uwsgi_register_metric(buf, buf2, UWSGI_METRIC_GAUGE, "ptr", &uwsgi_cheaper_busyness_global.current_busyness[i], 0, NULL);
}
uwsgi_register_metric("plugin.cheaper_busyness.total_avg_busyness", "4.100.1", UWSGI_METRIC_GAUGE, "ptr", &uwsgi_cheaper_busyness_global.total_avg_busyness, 0, NULL);
uwsgi_log("[busyness] metrics registered\n");
}
// initialize timers
uwsgi_cheaper_busyness_global.tcheck = uwsgi_micros();
set_next_cheap_time();
return 0;
}
struct uwsgi_plugin cheaper_busyness_plugin = {
.name = "cheaper_busyness",
.on_load = uwsgi_cheaper_register_busyness,
.on_load = uwsgi_cheaper_register_busyness,
.options = uwsgi_cheaper_busyness_options,
.init = uwsgi_cheaper_busyness_init
};
+59 -12
View File
@@ -41,8 +41,11 @@ 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->current_timeout = cs->corerouter->socket_timeout;
peers->timeout = cr_add_timeout(cs->corerouter, peers);
peers->prev = old_peers;
@@ -72,6 +75,12 @@ void uwsgi_cr_peer_reset(struct corerouter_peer *peer) {
peer->hook_write = NULL;
}
if (peer->is_buffering) {
if (peer->buffering_fd != -1) {
close(peer->buffering_fd);
}
}
peer->failed = 0;
peer->soopt = 0;
peer->timed_out = 0;
@@ -81,7 +90,13 @@ void uwsgi_cr_peer_reset(struct corerouter_peer *peer) {
}
// destroy a peer
void uwsgi_cr_peer_del(struct corerouter_peer *peer) {
int uwsgi_cr_peer_del(struct corerouter_peer *peer) {
// first of all check if we need to run a flush procedure
if (peer->flush && !peer->is_flushing) {
peer->is_flushing = 1;
// on success, suspend the execution
if (peer->flush(peer) > 0) return -1;
}
struct corerouter_peer *prev = peer->prev;
struct corerouter_peer *next = peer->next;
@@ -108,6 +123,7 @@ void uwsgi_cr_peer_del(struct corerouter_peer *peer) {
uwsgi_buffer_destroy(peer->out);
}
free(peer);
return 0;
}
void uwsgi_opt_corerouter(char *opt, char *value, void *cr) {
@@ -272,6 +288,22 @@ void corerouter_manage_subscription(char *key, uint16_t keylen, char *val, uint1
usr->sign = val;
usr->sign_len = vallen;
}
else if (!uwsgi_strncmp("sni_key", 7, key, keylen)) {
usr->sni_key = val;
usr->sni_key_len = vallen;
}
else if (!uwsgi_strncmp("sni_crt", 7, key, keylen)) {
usr->sni_crt = val;
usr->sni_crt_len = vallen;
}
else if (!uwsgi_strncmp("sni_ca", 6, key, keylen)) {
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) {
@@ -291,7 +323,6 @@ void corerouter_close_peer(struct uwsgi_corerouter *ucr, struct corerouter_peer
}
if (peer->failed) {
if (peer->soopt) {
if (!ucr->quiet)
uwsgi_log("[uwsgi-%s] unable to connect() to node \"%.*s\" (%d retries): %s\n", ucr->short_name, (int) peer->instance_address_len, peer->instance_address, peer->retries, strerror(peer->soopt));
@@ -365,7 +396,7 @@ void corerouter_close_peer(struct uwsgi_corerouter *ucr, struct corerouter_peer
}
end:
uwsgi_cr_peer_del(peer);
if (uwsgi_cr_peer_del(peer) < 0) return;
if (peer == cs->main_peer) {
cs->main_peer = NULL;
@@ -383,7 +414,7 @@ void corerouter_close_session(struct uwsgi_corerouter *ucr, struct corerouter_se
struct corerouter_peer *main_peer = cr_session->main_peer;
if (main_peer) {
uwsgi_cr_peer_del(main_peer);
if (uwsgi_cr_peer_del(main_peer) < 0) return;
}
// free peers
@@ -395,7 +426,7 @@ void corerouter_close_session(struct uwsgi_corerouter *ucr, struct corerouter_se
if (ucr->subscriptions && tmp_peer->un && tmp_peer->un->len) {
tmp_peer->un->reference--;
}
uwsgi_cr_peer_del(tmp_peer);
if (uwsgi_cr_peer_del(tmp_peer) < 0) return;
}
// could be used to free additional resources
@@ -550,7 +581,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;
@@ -562,8 +595,8 @@ struct corerouter_session *corerouter_alloc_session(struct uwsgi_corerouter *ucr
cs->corerouter = ucr;
cs->ugs = ugs;
// set initial timeout
peer->timeout = cr_add_timeout(ucr, ucr->cr_table[new_connection]);
// set initial timeout (could be overridden)
peer->current_timeout = ucr->socket_timeout;
ucr->active_sessions++;
@@ -602,6 +635,10 @@ struct corerouter_session *corerouter_alloc_session(struct uwsgi_corerouter *ucr
corerouter_close_session(ucr, cs);
cs = NULL;
}
else {
// truly set the timeout
peer->timeout = cr_add_timeout(ucr, ucr->cr_table[new_connection]);
}
return cs;
}
@@ -919,10 +956,13 @@ int uwsgi_corerouter_init(struct uwsgi_corerouter *ucr) {
uwsgi_log("starting %s in cheap mode\n", ucr->name);
}
for (i = 0; i < ucr->processes; i++) {
if (register_gateway(ucr->name, uwsgi_corerouter_loop, ucr) == NULL) {
struct uwsgi_gateway *ug = register_gateway(ucr->name, uwsgi_corerouter_loop, ucr);
if (ug == NULL) {
uwsgi_log("unable to register the %s gateway\n", ucr->name);
exit(1);
}
ug->uid = ucr->uid;
ug->gid = ucr->gid;
}
}
@@ -1021,6 +1061,9 @@ void corerouter_send_stats(struct uwsgi_corerouter *ucr) {
if (uwsgi_stats_keyvaln_comma(us, "key", s_slot->key, s_slot->keylen)) goto end0;
if (uwsgi_stats_keylong_comma(us, "hash", (unsigned long long) s_slot->hash)) goto end0;
if (uwsgi_stats_keylong_comma(us, "hits", (unsigned long long) s_slot->hits)) goto end0;
#ifdef UWSGI_SSL
if (uwsgi_stats_keylong_comma(us, "sni_enabled", (unsigned long long) s_slot->sni_enabled)) goto end0;
#endif
if (uwsgi_stats_key(us , "nodes")) goto end0;
if (uwsgi_stats_list_open(us)) goto end0;
@@ -1034,9 +1077,13 @@ void corerouter_send_stats(struct uwsgi_corerouter *ucr) {
if (uwsgi_stats_keylong_comma(us, "modifier1", (unsigned long long) s_node->modifier1)) goto end0;
if (uwsgi_stats_keylong_comma(us, "modifier2", (unsigned long long) s_node->modifier2)) goto end0;
if (uwsgi_stats_keylong_comma(us, "last_check", (unsigned long long) s_node->last_check)) goto end0;
if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) s_node->pid)) goto end0;
if (uwsgi_stats_keylong_comma(us, "uid", (unsigned long long) s_node->uid)) goto end0;
if (uwsgi_stats_keylong_comma(us, "gid", (unsigned long long) s_node->gid)) goto end0;
if (uwsgi_stats_keylong_comma(us, "requests", (unsigned long long) s_node->requests)) goto end0;
if (uwsgi_stats_keylong_comma(us, "last_requests", (unsigned long long) s_node->last_requests)) goto end0;
if (uwsgi_stats_keylong_comma(us, "tx", (unsigned long long) s_node->transferred)) goto end0;
if (uwsgi_stats_keylong_comma(us, "tx", (unsigned long long) s_node->tx)) goto end0;
if (uwsgi_stats_keylong_comma(us, "rx", (unsigned long long) s_node->rx)) goto end0;
if (uwsgi_stats_keylong_comma(us, "cores", (unsigned long long) s_node->cores)) goto end0;
if (uwsgi_stats_keylong_comma(us, "load", (unsigned long long) s_node->load)) goto end0;
if (uwsgi_stats_keylong_comma(us, "weight", (unsigned long long) s_node->weight)) goto end0;
@@ -1076,7 +1123,7 @@ void corerouter_send_stats(struct uwsgi_corerouter *ucr) {
size_t remains = us->pos;
off_t pos = 0;
while(remains > 0) {
int ret = uwsgi_waitfd_write(client_fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
int ret = uwsgi_waitfd_write(client_fd, uwsgi.socket_timeout);
if (ret <= 0) {
goto end0;
}
+26 -6
View File
@@ -3,12 +3,12 @@
#define COREROUTER_STATUS_RECV_HDR 2
#define COREROUTER_STATUS_RESPONSE 3
#define cr_add_timeout(u, x) uwsgi_add_rb_timer(u->timeouts, uwsgi_now()+u->socket_timeout, x)
#define cr_add_timeout_fast(u, x, t) uwsgi_add_rb_timer(u->timeouts, t+u->socket_timeout, x)
#define cr_add_timeout(u, x) uwsgi_add_rb_timer(u->timeouts, uwsgi_now()+x->current_timeout, x)
#define cr_add_timeout_fast(u, x, t) uwsgi_add_rb_timer(u->timeouts, t+x->current_timeout, x)
#define cr_del_timeout(u, x) uwsgi_del_rb_timer(u->timeouts, x->timeout); free(x->timeout);
#define uwsgi_cr_error(x, y) uwsgi_log("[uwsgi-%s client_addr: %s client_port: %s] %s: %s [%s line %d]\n", x->session->corerouter->short_name, x->session->client_address, x->session->client_port, y, strerror(errno), __FILE__, __LINE__)
#define uwsgi_cr_log(x, y, ...) uwsgi_log("[uwsgi-%s client_addr: %s client_port: %s]" y, x->session->corerouter->short_name, x->session->client_address, x->session->client_port, __VA_ARGS__)
#define uwsgi_cr_error(x, y) uwsgi_log("[uwsgi-%s key: %.*s client_addr: %s client_port: %s] %s: %s [%s line %d]\n", x->session->corerouter->short_name, (x == x->session->main_peer) ? (x->session->peers ? x->session->peers->key_len: 0) : x->key_len, (x == x->session->main_peer) ? (x->session->peers ? x->session->peers->key: "") : x->key, x->session->client_address, x->session->client_port, y, strerror(errno), __FILE__, __LINE__)
#define uwsgi_cr_log(x, y, ...) uwsgi_log("[uwsgi-%s key: %.*s client_addr: %s client_port: %s]" y, x->session->corerouter->short_name, (x == x->session->main_peer) ? (x->session->peers ? x->session->peers->key_len: 0) : x->key_len, (x == x->session->main_peer) ? (x->session->peers ? x->session->peers->key: "") : x->key, x->session->client_address, x->session->client_port, __VA_ARGS__)
#define cr_try_again if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {\
errno = EINPROGRESS;\
@@ -21,6 +21,7 @@
uwsgi_cr_error(peer, f);\
return -1;\
}\
if (peer != peer->session->main_peer && peer->un) peer->un->rx+=len;\
peer->out_pos += len;
#define cr_write_buf(peer, ubuf, f) write(peer->fd, ubuf->buf + ubuf##_pos, ubuf->pos - ubuf##_pos);\
@@ -29,6 +30,7 @@
uwsgi_cr_error(peer, f);\
return -1;\
}\
if (peer != peer->session->main_peer && peer->un) peer->un->rx+=len;\
ubuf##_pos += len;
#define cr_write_complete(peer) peer->out_pos == peer->out->pos
@@ -51,6 +53,7 @@
uwsgi_cr_error(peer, f);\
return -1;\
}\
if (peer != peer->session->main_peer && peer->un) peer->un->tx+=len;\
peer->in->pos += len;\
#define cr_read_exact(peer, l, f) read(peer->fd, peer->in->buf + peer->in->pos, (l - peer->in->pos));\
@@ -59,6 +62,7 @@
uwsgi_cr_error(peer, f);\
return -1;\
}\
if (peer != peer->session->main_peer && peer->un) peer->un->tx+=len;\
peer->in->pos += len;\
#define cr_reset_hooks(peer) if(!peer->session->main_peer->disabled) {\
@@ -176,14 +180,22 @@ struct corerouter_peer {
uint16_t retries;
// parsed key
char *key;
uint16_t key_len;
char key[0xff];
uint8_t key_len;
uint8_t modifier1;
uint8_t modifier2;
struct corerouter_peer *prev;
struct corerouter_peer *next;
int current_timeout;
ssize_t (*flush)(struct corerouter_peer *);
int is_flushing;
int is_buffering;
int buffering_fd;
};
struct uwsgi_corerouter {
@@ -258,6 +270,14 @@ struct uwsgi_corerouter {
uint64_t active_sessions;
uid_t uid;
gid_t gid;
struct uwsgi_string_list *resubscribe;
char *resubscribe_bind;
size_t buffer_size;
int fallback_on_no_key;
};
// a session is started when a client connect to the router
+58 -7
View File
@@ -4,7 +4,7 @@ common functions for various routers (fastrouter, http...)
*/
#include "../../uwsgi.h"
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
@@ -79,6 +79,9 @@ void uwsgi_corerouter_setup_sockets(struct uwsgi_corerouter *ucr) {
}
else {
ugs->fd = bind_to_unix_dgram(ugs->name);
if (ugs->fd < 1 || (uwsgi.subscriptions_use_credentials && uwsgi_socket_passcred(ugs->fd))) {
exit(1);
}
}
uwsgi_socket_nb(ugs->fd);
}
@@ -113,10 +116,17 @@ void uwsgi_corerouter_manage_subscription(struct uwsgi_corerouter *ucr, int id,
int i;
struct uwsgi_subscribe_req usr;
char bbuf[4096];
ssize_t len = -1;
ssize_t len = recv(ugs->fd, bbuf, 4096, 0);
memset(&usr, 0, sizeof(struct uwsgi_subscribe_req));
if (uwsgi.subscriptions_use_credentials) {
len = uwsgi_recv_cred2(ugs->fd, bbuf, 4096, &usr.pid, &usr.uid, &usr.gid);
}
else {
len = recv(ugs->fd, bbuf, 4096, 0);
}
if (len > 0) {
memset(&usr, 0, sizeof(struct uwsgi_subscribe_req));
uwsgi_hooked_parse(bbuf + 4, len - 4, corerouter_manage_subscription, &usr);
if (usr.sign_len > 0) {
// calc the base size
@@ -144,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;
}
@@ -177,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);
}
}
}
+6
View File
@@ -53,6 +53,7 @@ int uwsgi_cr_map_use_subscription(struct uwsgi_corerouter *ucr, struct coreroute
peer->instance_address = peer->un->name;
peer->instance_address_len = peer->un->len;
peer->modifier1 = peer->un->modifier1;
peer->modifier2 = peer->un->modifier2;
}
else if (ucr->cheap && !ucr->i_am_cheap && uwsgi_no_subscriptions(ucr->subscriptions)) {
uwsgi_gateway_go_cheap(ucr->name, ucr->queue, &ucr->i_am_cheap);
@@ -65,8 +66,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 +80,7 @@ split:
if (next) {
name_len -= next - name;
name = next;
count--;
goto split;
}
}
@@ -84,6 +89,7 @@ split:
peer->instance_address = peer->un->name;
peer->instance_address_len = peer->un->len;
peer->modifier1 = peer->un->modifier1;
peer->modifier2 = peer->un->modifier2;
}
else if (ucr->cheap && !ucr->i_am_cheap && uwsgi_no_subscriptions(ucr->subscriptions)) {
uwsgi_gateway_go_cheap(ucr->name, ucr->queue, &ucr->i_am_cheap);
+14 -44
View File
@@ -12,8 +12,8 @@ static void uwsgi_opt_setup_coroae(char *opt, char *value, void *null) {
// set async mode
uwsgi_opt_set_int(opt, value, &uwsgi.async);
if (uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] < 30) {
uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] = 30;
if (uwsgi.socket_timeout < 30) {
uwsgi.socket_timeout = 30;
}
// set loop engine
uwsgi.loop = "coroae";
@@ -66,32 +66,14 @@ SV * coroae_coro_new(CV *block) {
}
static int coroae_wait_milliseconds(int timeout) {
int ret = -1;
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(newSVnv(((double)timeout)/1000.0));
PUTBACK;
call_pv("Coro::AnyEvent::sleep", G_SCALAR|G_EVAL);
SPAGAIN;
if(SvTRUE(ERRSV)) {
uwsgi_log("[uwsgi-perl error] %s", SvPV_nolen(ERRSV));
}
else {
SV *p_ret = POPs;
if (SvTRUE(p_ret)) {
ret = 0;
}
}
PUTBACK;
FREETMPS;
LEAVE;
return ret;
char buf[256];
double d = ((double)timeout)/1000.0;
int ret = snprintf(buf, 256, "Coro::AnyEvent::sleep %f", d);
if (ret <= 0 || ret > 256) return -1;
perl_eval_pv(buf, 0);
return 0;
}
static int coroae_wait_fd_read(int fd, int timeout) {
int ret = 0;
dSP;
@@ -164,7 +146,7 @@ XS(XS_coroae_accept_request) {
}
for(;;) {
int ret = uwsgi.wait_read_hook(wsgi_req->fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
int ret = uwsgi.wait_read_hook(wsgi_req->fd, uwsgi.socket_timeout);
wsgi_req->switches++;
if (ret <= 0) {
@@ -244,8 +226,8 @@ edge:
wsgi_req->start_of_request_in_sec = wsgi_req->start_of_request/1000000;
// enter harakiri mode
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
set_harakiri(uwsgi.shared->options[UWSGI_OPTION_HARAKIRI]);
if (uwsgi.harakiri_options.workers > 0) {
set_harakiri(uwsgi.harakiri_options.workers);
}
@@ -386,21 +368,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;
+1 -1
View File
@@ -10,7 +10,7 @@ static void curl_cron_func(struct uwsgi_cron *uc, time_t now) {
curl_easy_setopt(curl, CURLOPT_URL, uc->command);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, uwsgi.socket_timeout);
// use 1 minute as the cron resolution
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60);
uwsgi_log("[uwsgi-curl-cron] requesting %s\n", uc->command);
+17 -26
View File
@@ -2,13 +2,6 @@
#define AMQP_CONNECTION_HEADER "AMQP\0\0\x09\x01"
#ifdef __BIG_ENDIAN__
#define ntohll(x) x
#else
#define ntohll(x) ( ( (uint64_t)(ntohl( (uint32_t)((x << 32) >> 32) )) << 32) | ntohl( ((uint32_t)(x >> 32)) ) )
#endif
#define htonll(x) ntohll(x)
#define amqp_send(a, b, c) if (send(a, b, c, 0) < 0) { uwsgi_error("send()"); return -1; }
struct amqp_frame_header {
@@ -69,13 +62,8 @@ static char *amqp_get_long(char *ptr, char *watermark, uint32_t *lv) {
static char *amqp_get_longlong(char *ptr, char *watermark, uint64_t *llv) {
uint64_t tmp_longlong;
if (ptr+8 > watermark) return NULL;
memcpy(&tmp_longlong, ptr, 8);
*llv = ntohll(tmp_longlong);
*llv = uwsgi_be64(ptr);
return ptr+8;
}
@@ -85,26 +73,29 @@ static int amqp_send_ack(int fd, uint64_t delivery_tag) {
uint32_t size = 4 + 8 + 1;
size = htonl(size);
struct uwsgi_buffer *ub = uwsgi_buffer_new(64);
// send type and channel
amqp_send(fd, "\1\0\1", 3);
if (uwsgi_buffer_append(ub, "\1\0\1", 3)) goto end;
// send size
amqp_send(fd, &size, 4);
// send class 60 method 80
amqp_send(fd, "\x00\x3C\x00\x50", 4);
if (uwsgi_buffer_u32be(ub, size)) goto end;
// send class 60 method 80
if (uwsgi_buffer_append(ub, "\x00\x3C\x00\x50", 4)) goto end;
// set delivery_tag
delivery_tag = htonll(delivery_tag);
amqp_send(fd, &delivery_tag, 8);
if (uwsgi_buffer_u64be(ub, delivery_tag)) goto end;
if (uwsgi_buffer_append(ub, "\0\xCE", 2)) goto end;
// empty bits
amqp_send(fd, "\0", 1);
// send buffer to socket
if (write(fd, ub->buf, ub->pos) < 0) {
uwsgi_error("amqp_send_ack()/write()");
goto end;
}
// send frame-end
amqp_send(fd, "\xCE", 1);
uwsgi_buffer_destroy(ub);
return 0;
end:
uwsgi_buffer_destroy(ub);
return -1;
}
char *uwsgi_amqp_consume(int fd, uint64_t *msgsize, char **routing_key) {
+55 -3
View File
@@ -10,6 +10,10 @@ struct uwsgi_emperor_mongodb_state {
char *address;
char *collection;
char *json;
char *database;
char *username;
char *password;
char *predigest;
};
@@ -20,18 +24,26 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
try {
// requested fields
mongo::BSONObj p = BSON( "name" << 1 << "config" << 1 << "ts" << 1 << "uid" << 1 << "gid" << 1 );
mongo::BSONObj p = BSON( "name" << 1 << "config" << 1 << "ts" << 1 << "uid" << 1 << "gid" << 1 << "socket" << 1 );
mongo::BSONObj q = mongo::fromjson(uems->json);
// the connection object (will be automatically destroyed at each cycle)
mongo::DBClientConnection c;
// set the socket timeout
c.setSoTimeout(uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
c.setSoTimeout(uwsgi.socket_timeout);
// connect
c.connect(uems->address);
if (uems->database && uems->username && uems->password) {
std::string err;
if (c.auth(uems->database, uems->username, uems->password, err, uems->predigest ? false : true) == false) {
uwsgi_log_verbose("[emperor-mongodb] unable to authenticate to db %s: %s\n", uems->database, err.c_str());
return;
}
}
// run the query
std::auto_ptr<mongo::DBClientCursor> cursor = c.query(uems->collection, q, 0, 0, &p);
while( cursor->more() ) {
while(cursor.get() && cursor->more() ) {
mongo::BSONObj p = cursor->next();
// checking for an empty string is not required, but we reduce the load
@@ -40,6 +52,7 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
if (strlen(name) == 0) continue;
const char *config = p.getStringField("config");
if (strlen(config) == 0) config = NULL;
time_t vassal_ts = 0;
// ts must be a Date object !!!
@@ -61,6 +74,7 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
}
const char *socket_name = p.getStringField("socket");
if (strlen(socket_name) == 0) socket_name = NULL;
uwsgi_emperor_simple_do(ues, (char *) name, (char *) config, vassal_ts/1000, vassal_uid, vassal_gid, (char *) socket_name);
}
@@ -76,6 +90,7 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
b.append("name", c_ui->name);
mongo::BSONObj q2 = b.obj();
cursor = c.query(uems->collection, q2, 0, 0, &p);
if (!cursor.get()) return;
#ifdef UWSGI_DEBUG
uwsgi_log("JSON: %s\n", q2.toString().c_str());
#endif
@@ -121,3 +136,40 @@ done:
uwsgi_log("[emperor] enabled emperor MongoDB monitor for %s on collection %s\n", uems->address, uems->collection);
}
// setup a new mongodb imperial monitor (keyval based)
extern "C" void uwsgi_imperial_monitor_mongodb_init2(struct uwsgi_emperor_scanner *ues) {
// allocate a new state
ues->data = uwsgi_calloc(sizeof(struct uwsgi_emperor_mongodb_state));
size_t arg_len = strlen(ues->arg);
struct uwsgi_emperor_mongodb_state *uems = (struct uwsgi_emperor_mongodb_state *) ues->data;
// parse args/ set defaults
uems->address = (char *) "127.0.0.1:27017";
uems->collection = (char *) "uwsgi.emperor.vassals";
uems->json = (char *) "";
char *args = NULL;
if (arg_len <= 11) goto done;
args = ues->arg+11;
if (uwsgi_kvlist_parse(args, strlen(args), ',', '=',
"addr", &uems->address,
"address", &uems->address,
"server", &uems->address,
"collection", &uems->collection,
"coll", &uems->collection,
"json", &uems->json,
"database", &uems->database,
"db", &uems->database,
"username", &uems->username,
"password", &uems->password,
"predigest", &uems->predigest,
NULL)) {
uwsgi_log("[emperor-mongodb] invalid keyval syntax !\n");
exit(1);
}
done:
uwsgi_log("[emperor] enabled emperor MongoDB monitor for %s on collection %s\n", uems->address, uems->collection);
}
+2
View File
@@ -2,9 +2,11 @@
void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *);
void uwsgi_imperial_monitor_mongodb_init(struct uwsgi_emperor_scanner *);
void uwsgi_imperial_monitor_mongodb_init2(struct uwsgi_emperor_scanner *);
void emperor_mongodb_init(void) {
uwsgi_register_imperial_monitor("mongodb", uwsgi_imperial_monitor_mongodb_init, uwsgi_imperial_monitor_mongodb);
uwsgi_register_imperial_monitor("mongodb2", uwsgi_imperial_monitor_mongodb_init2, uwsgi_imperial_monitor_mongodb);
}
struct uwsgi_plugin emperor_mongodb_plugin = {
+1 -1
View File
@@ -2,6 +2,6 @@
NAME='emperor_zeromq'
CFLAGS = []
LDFLAGS = []
LIBS = []
LIBS = ['-lzmq']
GCC_LIST = ['emperor_zeromq']
+135 -17
View File
@@ -16,6 +16,8 @@ extern struct uwsgi_server uwsgi;
struct fastrouter_session {
struct corerouter_session session;
int has_key;
uint64_t content_length;
uint64_t buffered;
};
static struct uwsgi_option fastrouter_options[] = {
@@ -37,17 +39,25 @@ 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},
{"fastrouter-post-buffering", required_argument, 0, "enable fastrouter post buffering", uwsgi_opt_set_64bit, &ufr.cr.post_buffering, 0},
{"fastrouter-post-buffering-dir", required_argument, 0, "put fastrouter buffered files to the specified directory", uwsgi_opt_set_str, &ufr.cr.pb_base_dir, 0},
{"fastrouter-post-buffering-dir", required_argument, 0, "put fastrouter buffered files to the specified directory (noop, use TMPDIR env)", uwsgi_opt_set_str, &ufr.cr.pb_base_dir, 0},
{"fastrouter-stats", required_argument, 0, "run the fastrouter stats server", uwsgi_opt_set_str, &ufr.cr.stats_server, 0},
{"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},
{"fastrouter-fallback-on-no-key", no_argument, 0, "move to fallback node even if a subscription key is not found", uwsgi_opt_true, &ufr.cr.fallback_on_no_key, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -58,21 +68,27 @@ static void fr_get_hostname(char *key, uint16_t keylen, char *val, uint16_t vall
//uwsgi_log("%.*s = %.*s\n", keylen, key, vallen, val);
if (!uwsgi_strncmp("SERVER_NAME", 11, key, keylen) && !peer->key_len) {
peer->key = val;
peer->key_len = vallen;
if (vallen <= 0xff) {
memcpy(peer->key, val, vallen);
peer->key_len = vallen;
}
return;
}
if (!uwsgi_strncmp("HTTP_HOST", 9, key, keylen) && !fr->has_key) {
peer->key = val;
peer->key_len = vallen;
if (vallen <= 0xff) {
memcpy(peer->key, val, vallen);
peer->key_len = vallen;
}
return;
}
if (!uwsgi_strncmp("UWSGI_FASTROUTER_KEY", 20, key, keylen)) {
fr->has_key = 1;
peer->key = val;
peer->key_len = vallen;
if (vallen <= 0xff) {
fr->has_key = 1;
memcpy(peer->key, val, vallen);
peer->key_len = vallen;
}
return;
}
@@ -89,6 +105,12 @@ static void fr_get_hostname(char *key, uint16_t keylen, char *val, uint16_t vall
}
return;
}
if (ufr.cr.post_buffering > 0) {
if (!uwsgi_strncmp("CONTENT_LENGTH", 14, key, keylen)) {
fr->content_length = uwsgi_str_num(val, vallen);
}
}
}
// writing client body to the instance
@@ -149,6 +171,23 @@ static ssize_t fr_instance_read(struct corerouter_peer *peer) {
return len;
}
static ssize_t fr_instance_sendfile(struct corerouter_peer *peer) {
struct fastrouter_session *fr = (struct fastrouter_session *) peer->session;
ssize_t len = uwsgi_sendfile_do(peer->fd, peer->session->main_peer->buffering_fd, fr->buffered, fr->content_length - fr->buffered);
if (len < 0) {
cr_try_again;
uwsgi_cr_error(peer, "fr_instance_sendfile()/sendfile()");
return -1;
}
if (len == 0) return 0;
fr->buffered += len;
if (peer != peer->session->main_peer && peer->un) peer->un->rx+=len;
if (fr->buffered >= fr->content_length) {
cr_reset_hooks(peer);
}
return len;
}
// send the uwsgi request header and vars
static ssize_t fr_instance_send_request(struct corerouter_peer *peer) {
ssize_t len = cr_write(peer, "fr_instance_send_request()");
@@ -159,9 +198,16 @@ static ssize_t fr_instance_send_request(struct corerouter_peer *peer) {
if (cr_write_complete(peer)) {
// reset the original read buffer
peer->out->pos = 0;
// start waiting for body
peer->session->main_peer->last_hook_read = fr_read_body;
cr_reset_hooks(peer);
if (!peer->session->main_peer->is_buffering) {
// start waiting for body
peer->session->main_peer->last_hook_read = fr_read_body;
cr_reset_hooks(peer);
}
else {
peer->hook_write = fr_instance_sendfile;
// stop reading from the client
peer->session->main_peer->last_hook_read = NULL;
}
}
return len;
@@ -176,8 +222,8 @@ static ssize_t fr_instance_connected(struct corerouter_peer *peer) {
peer->can_retry = 0;
// fix modifiers
peer->in->buf[0] = peer->session->main_peer->modifier1;
peer->in->buf[3] = peer->session->main_peer->modifier2;
peer->in->buf[0] = peer->modifier1;
peer->in->buf[3] = peer->modifier2;
// prepare to write the uwsgi packet
peer->out = peer->session->main_peer->in;
@@ -189,20 +235,73 @@ static ssize_t fr_instance_connected(struct corerouter_peer *peer) {
// called after receaving the uwsgi header (read vars)
static ssize_t fr_recv_uwsgi_vars(struct corerouter_peer *main_peer) {
struct fastrouter_session *fr = (struct fastrouter_session *) main_peer->session;
struct corerouter_peer *new_peer = NULL;
ssize_t len = 0;
struct uwsgi_header *uh = (struct uwsgi_header *) main_peer->in->buf;
// better to store it as the original buf address could change
uint16_t pktsize = uh->pktsize;
// are we buffering ?
if (main_peer->is_buffering) {
// memory or disk ?
if (fr->content_length <= ufr.cr.post_buffering) {
// increase buffer if needed
if (uwsgi_buffer_fix(main_peer->in, pktsize+4+fr->content_length))
return -1;
len = cr_read_exact(main_peer, pktsize+4+fr->content_length, "fr_recv_uwsgi_vars()");
if (!len) return 0;
// whole body read ?
if (main_peer->in->pos == (size_t)(pktsize+4+fr->content_length)) {
main_peer->is_buffering = 0;
goto done;
}
return len;
}
// first round ?
if (main_peer->buffering_fd == -1) {
main_peer->buffering_fd = uwsgi_tmpfd();
if (main_peer->buffering_fd < 0) return -1;
}
char buf[32768];
size_t remains = fr->content_length - fr->buffered;
ssize_t rlen = read(main_peer->fd, buf, UMIN(32768, remains));
if (rlen < 0) {
cr_try_again;
uwsgi_cr_error(main_peer, "fr_recv_uwsgi_vars()/read()");
return -1;
}
if (rlen == 0) return 0;
fr->buffered += rlen;
if (write(main_peer->buffering_fd, buf, rlen) != rlen) {
uwsgi_cr_error(main_peer, "fr_recv_uwsgi_vars()/write()");
return -1;
}
// have we done ?
if (fr->buffered >= fr->content_length) {
fr->buffered = 0;
len = rlen;
goto done;
}
return rlen;
}
// increase buffer if needed
if (uwsgi_buffer_fix(main_peer->in, pktsize+4))
return -1;
ssize_t len = cr_read_exact(main_peer, pktsize+4, "fr_recv_uwsgi_vars()");
len = cr_read_exact(main_peer, pktsize+4, "fr_recv_uwsgi_vars()");
if (!len) return 0;
// headers received, ready to choose the instance
if (main_peer->in->pos == (size_t)(pktsize+4)) {
struct uwsgi_corerouter *ucr = main_peer->session->corerouter;
struct corerouter_peer *new_peer = uwsgi_cr_peer_add(main_peer->session);
new_peer = uwsgi_cr_peer_add(main_peer->session);
new_peer->last_hook_read = fr_instance_read;
// find the hostname
@@ -219,8 +318,27 @@ static ssize_t fr_recv_uwsgi_vars(struct corerouter_peer *main_peer) {
return -1;
// check instance
if (new_peer->instance_address_len == 0)
if (new_peer->instance_address_len == 0) {
if (ufr.cr.fallback_on_no_key) {
new_peer->failed = 1;
new_peer->can_retry = 1;
corerouter_close_peer(&ufr.cr, new_peer);
return len;
}
return -1;
}
// buffering ?
if (ufr.cr.post_buffering > 0 && fr->content_length > 0) {
main_peer->is_buffering = 1;
main_peer->buffering_fd = -1;
return len;
}
done:
if (!new_peer) {
new_peer = main_peer->session->peers;
}
new_peer->can_retry = 1;
+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 = []
+3 -3
View File
@@ -264,7 +264,7 @@ static void uwsgi_gccgo_request_goroutine(void *arg) {
int ret,status;
for(;;) {
ret = uwsgi.wait_read_hook(wsgi_req->fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
ret = uwsgi.wait_read_hook(wsgi_req->fd, uwsgi.socket_timeout);
wsgi_req->switches++;
if (ret <= 0) {
@@ -388,8 +388,8 @@ retry:
wsgi_req->start_of_request_in_sec = wsgi_req->start_of_request/1000000;
// enter harakiri mode
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
set_harakiri(uwsgi.shared->options[UWSGI_OPTION_HARAKIRI]);
if (uwsgi.harakiri_options.workers > 0) {
set_harakiri(uwsgi.harakiri_options.workers);
}
// spawn the new goroutine
+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);
+51 -6
View File
@@ -8,8 +8,8 @@ static void uwsgi_opt_setup_gevent(char *opt, char *value, void *null) {
// set async mode
uwsgi_opt_set_int(opt, value, &uwsgi.async);
if (uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] < 30) {
uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] = 30;
if (uwsgi.socket_timeout < 30) {
uwsgi.socket_timeout = 30;
}
// set loop engine
uwsgi.loop = "gevent";
@@ -100,6 +100,31 @@ retry:
return Py_None;
}
PyObject *py_uwsgi_gevent_int(PyObject *self, PyObject *args) {
uwsgi_log("Brutally killing worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid);
uwsgi.workers[uwsgi.mywid].manage_next_request = 0;
uwsgi_log_verbose("stopping gevent signals watchers for worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid);
PyObject_CallMethod(ugevent.my_signal_watcher, "stop", NULL);
PyObject_CallMethod(ugevent.signal_watcher, "stop", NULL);
uwsgi_log_verbose("stopping gevent sockets watchers for worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid);
int i,count = uwsgi_count_sockets(uwsgi.sockets);
for(i=0;i<count;i++) {
PyObject_CallMethod(ugevent.watchers[i], "stop", NULL);
}
uwsgi_log_verbose("main gevent watchers stopped for worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid);
if (!ugevent.wait_for_hub) {
PyObject_CallMethod(ugevent.ctrl_gl, "kill", NULL);
}
Py_INCREF(Py_None);
return Py_None;
}
static void uwsgi_gevent_gbcw() {
// already running
@@ -210,8 +235,8 @@ edge:
wsgi_req->start_of_request_in_sec = wsgi_req->start_of_request/1000000;
// enter harakiri mode
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
set_harakiri(uwsgi.shared->options[UWSGI_OPTION_HARAKIRI]);
if (uwsgi.harakiri_options.workers > 0) {
set_harakiri(uwsgi.harakiri_options.workers);
}
// hack to easily pass wsgi_req pointer to the greenlet
@@ -257,7 +282,7 @@ PyObject *py_uwsgi_gevent_request(PyObject * self, PyObject * args) {
greenlet_switch = PyObject_GetAttrString(current_greenlet, "switch");
for(;;) {
int ret = uwsgi.wait_read_hook(wsgi_req->fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
int ret = uwsgi.wait_read_hook(wsgi_req->fd, uwsgi.socket_timeout);
wsgi_req->switches++;
if (ret <= 0) {
@@ -333,6 +358,7 @@ PyMethodDef uwsgi_gevent_signal_def[] = { {"uwsgi_gevent_signal", py_uwsgi_geven
PyMethodDef uwsgi_gevent_my_signal_def[] = { {"uwsgi_gevent_my_signal", py_uwsgi_gevent_my_signal, METH_VARARGS, ""} };
PyMethodDef uwsgi_gevent_signal_handler_def[] = { {"uwsgi_gevent_signal_handler", py_uwsgi_gevent_signal_handler, METH_VARARGS, ""} };
PyMethodDef uwsgi_gevent_unix_signal_handler_def[] = { {"uwsgi_gevent_unix_signal_handler", py_uwsgi_gevent_graceful, METH_VARARGS, ""} };
PyMethodDef uwsgi_gevent_unix_signal_int_handler_def[] = { {"uwsgi_gevent_unix_signal_int_handler", py_uwsgi_gevent_int, METH_VARARGS, ""} };
PyMethodDef uwsgi_gevent_ctrl_gl_def[] = { {"uwsgi_gevent_ctrl_gl_handler", py_uwsgi_gevent_ctrl_gl, METH_VARARGS, ""} };
static void gil_gevent_get() {
@@ -345,11 +371,14 @@ static void gil_gevent_release() {
static void gevent_loop() {
// ensure SIGPIPE is ignored
signal(SIGPIPE, SIG_IGN);
if (!uwsgi.has_threads && uwsgi.mywid == 1) {
uwsgi_log("!!! Running gevent without threads IS NOT recommended, enable them with --enable-threads !!!\n");
}
if (uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] < 30) {
if (uwsgi.socket_timeout < 30) {
uwsgi_log("!!! Running gevent with a socket-timeout lower than 30 seconds is not recommended, tune it with --socket-timeout !!!\n");
}
@@ -485,6 +514,22 @@ static void gevent_loop() {
python_call(ugevent.signal, ge_signal_tuple, 0, NULL);
// map SIGINT/SIGTERM with gevent.signal
ge_signal_tuple = PyTuple_New(2);
PyTuple_SetItem(ge_signal_tuple, 0, PyInt_FromLong(SIGINT));
PyObject *uwsgi_gevent_unix_signal_int_handler = PyCFunction_New(uwsgi_gevent_unix_signal_int_handler_def, NULL);
Py_INCREF(uwsgi_gevent_unix_signal_int_handler);
PyTuple_SetItem(ge_signal_tuple, 1, uwsgi_gevent_unix_signal_int_handler);
python_call(ugevent.signal, ge_signal_tuple, 0, NULL);
ge_signal_tuple = PyTuple_New(2);
PyTuple_SetItem(ge_signal_tuple, 0, PyInt_FromLong(SIGTERM));
PyTuple_SetItem(ge_signal_tuple, 1, uwsgi_gevent_unix_signal_int_handler);
python_call(ugevent.signal, ge_signal_tuple, 0, NULL);
PyObject *wait_for_me = ugevent.hub;
if (!ugevent.wait_for_hub) {
+1 -1
View File
@@ -200,7 +200,7 @@ static void uwsgi_glusterfs_add_mountpoint(char *arg, size_t arg_len) {
static void uwsgi_glusterfs_setup() {
if (!uglusterfs.timeout) {
uglusterfs.timeout = uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT];
uglusterfs.timeout = uwsgi.socket_timeout;
}
struct uwsgi_string_list *usl = uglusterfs.mountpoints;
+1 -1
View File
@@ -90,7 +90,7 @@ ssize_t uwsgi_graylog2_logger(struct uwsgi_logger *ul, char *message, size_t len
int rlen = snprintf(g2c.json_buf, MAX_GELF, "{ \"version\": \"1.0\", \"host\": \"%s\", \"short_message\": \"%.*s\", \"full_message\": \"%.*s\", \"timestamp\": %d, \"level\": 5, \"facility\": \"uWSGI-%s\" }",
g2c.host, truncated, g2c.escaped_buf, (int)g2c.escaped_len, g2c.escaped_buf, (int) uwsgi_now(), UWSGI_VERSION);
if (rlen > 0) {
if (rlen > 0 && rlen < MAX_GELF) {
if (compressBound((uLong) rlen) <= MAX_GELF) {
if (compress((Bytef *) ul->buf, &destLen, (Bytef *) g2c.json_buf, (uLong) rlen) == Z_OK) {
return sendto(ul->fd, ul->buf, destLen, 0, (const struct sockaddr *) &ul->addr, ul->addr_len);

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