Compare commits

...
469 Commits
Author SHA1 Message Date
roberto@quantal64 c5dc74b021 uWSGI 1.3-rc4 2012-09-22 09:45:08 +02:00
roberto@quantal64 97137488f9 improved emperor mongodb tyrant mode 2012-09-22 09:38:15 +02:00
roberto@quantal64 8cff01a1c7 report imperial monitor in emperor statistics 2012-09-22 09:21:37 +02:00
roberto@quantal64 3c8452313e added emperor_mongodb plugin 2012-09-22 09:04:47 +02:00
roberto@quantal64 322b130fc9 refactored imperial monitors api 2012-09-22 08:58:17 +02:00
roberto@quantal64 6c001c2fda fixed usage of inlining 2012-09-22 07:57:42 +02:00
roberto@quantal64 5d4050817d added --dlopen 2012-09-22 05:52:28 +02:00
roberto@quantal64 0a1147a4f6 added --rb-patch-rack-bodyproxy for older ruby/rack versions 2012-09-21 11:02:29 +02:00
roberto@quantal64 f92cb0e6a2 fixed rack compilation 2012-09-21 09:51:36 +02:00
roberto@quantal64 8b79c76261 refactored daemonize2 2012-09-20 18:08:49 +02:00
roberto@quantal64 0015b51262 fixed POST-handling reports 2012-09-20 17:49:30 +02:00
roberto@quantal64 b1dc8cd9c6 improved async cores detection 2012-09-20 17:41:13 +02:00
roberto@quantal64 3269e2d288 added support for dependancies in plugins 2012-09-20 17:16:30 +02:00
roberto@quantal64 71a9747d96 applied latest carbon patches from Łukasz Mierzwa 2012-09-20 16:43:20 +02:00
roberto@quantal64 455d041ce4 fixed http router parser 2012-09-20 16:36:08 +02:00
roberto@arch 88205f8dd1 added mongodblog plugin 2012-09-19 15:15:03 +02:00
roberto@centos6 7d9dadddf6 support for loading file for elf sections 2012-09-18 00:42:53 +02:00
roberto@centos6 57e78dd76f implemented rack.input each 2012-09-17 16:26:44 +02:00
roberto@centos6 7d0d2b33f4 improved rack.input disk buffering (second part) 2012-09-17 15:51:31 +02:00
roberto@quantal64 03c739102d reimplementing rack.input without IO wrapper 2012-09-17 13:43:43 +02:00
roberto@quantal64 392bb8d7b1 allows building with python3 and without embedded module 2012-09-17 07:41:11 +02:00
roberto@quantal64 505b35be29 do not try to remove sockets in abstract namespace 2012-09-17 06:47:07 +02:00
roberto@quantal64 fdb002ad9b added %0 - %9 magic vars for splitting paths 2012-09-17 06:33:52 +02:00
roberto@quantal64 557c46373f improved %c 2012-09-15 16:15:47 +02:00
roberto@quantal64 3cde8be505 allows building without embedded and multiple interpreters 2012-09-15 12:14:12 +02:00
roberto@quantal64 c2cf1f3a62 fixed threading + lazy 2012-09-14 15:52:23 +02:00
roberto@quantal64 956cb1f13c Added tag 1.3-rc3 for changeset 883b946db903 2012-09-13 18:47:08 +02:00
roberto@quantal64 f698b558e1 uWSGI 1.3-rc3 2012-09-13 18:46:56 +02:00
roberto@quantal64 ca832900a0 ensure master_cleanup is run by the master 2012-09-13 16:58:05 +02:00
roberto@quantal64 6a6227a8e7 added a warning for --map-socket invalid syntax 2012-09-13 14:09:55 +02:00
roberto@quantal64 8539cdb5a7 ported build system to python 3.3 2012-09-13 14:05:47 +02:00
roberto@quantal64 5cea1de1ba added master_cleanup hook and carbon flush on stop/reload 2012-09-12 19:03:22 +02:00
roberto@quantal64 e735b9e31f applied busyness_backlog.diff by Łukasz Mierzwa 2012-09-12 18:12:55 +02:00
roberto@quantal64 9ff8f8899f added --log-drain 2012-09-12 08:08:32 +02:00
roberto@quantal64 d908c4ef35 allows building without udp 2012-09-07 19:45:58 +02:00
roberto@quantal64 207f50726d oops, use classic perl syntax for push 2012-09-07 19:36:21 +02:00
roberto@quantal64 212559fcce put sleep() in each psgi cleanup hook to show its power :P 2012-09-07 19:13:34 +02:00
roberto@quantal64 cf480e499c implemented psgi cleanup handlers, and fixed a leak in rpc call 2012-09-07 19:09:22 +02:00
roberto@quantal64 f2e27f5154 improved process limit detection 2012-09-07 14:54:57 +02:00
roberto@quantal64 d932a4feae fixed typcasting 2012-09-07 14:40:06 +02:00
roberto@quantal64 da6e05072f explicit link with librt for alternatives clock 2012-09-07 06:58:26 +02:00
roberto@quantal64 13277d9d71 improved cheaper_busyness 2012-09-06 17:10:03 +02:00
roberto@quantal64 f17f8b337f fixed idle mode 2012-09-06 16:21:12 +02:00
roberto@quantal64 ffb454e414 headers must be sent before close() 2012-09-06 15:22:17 +02:00
roberto@quantal64 424f5a09e7 call close() always, even if client disconnect 2012-09-06 15:02:12 +02:00
roberto@quantal64 c29a6f6446 removed STOP/TSTP signal from gateways 2012-09-06 11:20:21 +02:00
roberto@quantal64 6f7edf0941 fixed uwsgi_buffer realloc len 2012-09-04 19:18:38 +02:00
roberto@quantal64 a4c4b7e8d2 fixed uwsgi_buffer realloc 2012-09-04 18:13:16 +02:00
roberto@quantal64 837f6f3a54 initialize spooler locks before app loading 2012-09-04 08:21:40 +02:00
roberto@quantal64 13041da6bf fixed piping 2012-09-04 08:13:02 +02:00
roberto@quantal64 046824dae7 fixed usage of mmap() 2012-09-03 14:11:42 +02:00
roberto@quantal64 269a588d9d uWSGI 1.3-rc2 2012-09-01 11:42:42 +02:00
roberto@quantal64 50ae12518a Added tag 1.3-rc2 for changeset 14524da00a8b 2012-09-01 11:42:31 +02:00
roberto@quantal64 a932937adf use new uwsgi_buffer structure for zeromq headers 2012-09-01 11:41:40 +02:00
roberto@quantal64 23bd924ace fixed remote cache_get for non existent keys 2012-09-01 11:34:44 +02:00
roberto@quantal64 e8f39685cc added the router_http plugin 2012-09-01 11:17:20 +02:00
roberto@quantal64 2122bacb33 fixed router_uwsgi in http/fastcgi and buffered modes 2012-09-01 08:18:43 +02:00
roberto@quantal64 3cb3c83442 added --if-opt/--if-not-opt 2012-09-01 07:45:28 +02:00
roberto@quantal64 d552d5257c add support for value check in if-env/if-not-env 2012-09-01 07:38:29 +02:00
roberto@quantal64 0aff486a73 added --spooler-external 2012-09-01 07:23:16 +02:00
roberto@quantal64 b887f3fc27 removed regexp-mount 2012-08-31 12:18:39 +02:00
roberto@freebsd64 b30e2c4ad8 added cpu affinity support for freebsd 2012-08-31 11:46:53 +02:00
roberto@openindiana64 040b17e5eb openindiana 64bit fixes 2012-08-31 11:08:51 +02:00
roberto@quantal64 770114a21c solaris fixes 2012-08-31 11:01:12 +02:00
roberto@quantal64 2864568f09 oops, forgot to remove debug :P 2012-08-31 10:49:13 +02:00
roberto@quantal64 56eaa88dd7 completed socket initialization refactoring 2012-08-31 10:47:33 +02:00
roberto@quantal64 bb54b90640 refactored mapped sockets and cpu affinity 2012-08-31 09:43:02 +02:00
roberto@quantal64 34502eeabe moved workers shared memory initialization to init.c 2012-08-31 09:34:01 +02:00
roberto@quantal64 ae90f29fa3 refactored mules and farms initialization 2012-08-31 09:30:33 +02:00
roberto@quantal64 1eeda4faaa moved buffer, post_buffers and hvec to shared uwsgi_core 2012-08-31 09:18:02 +02:00
roberto@quantal64 18046c976e first phase of main() refactory 2012-08-31 08:42:56 +02:00
roberto@quantal64 530bf85cf9 get rid of another series of gettimeofday 2012-08-30 20:23:32 +02:00
roberto@quantal64 5261a9fed5 report per-core requests in stats 2012-08-30 20:16:34 +02:00
roberto@quantal64 26d0d8dfdc improved clock usage in logging subsystem 2012-08-30 20:11:27 +02:00
roberto@quantal64 eddf494b07 big commit for allowing full access to workers/cores/requests data from the api/stats 2012-08-30 16:54:13 +02:00
roberto@quantal64 689a4ef6d4 added support for lua table in the WSAPI plugin, patch by Aaron B. 2012-08-30 08:54:25 +02:00
roberto@quantal64 9398304c60 fixed fastcgi support for response bigger than 64k 2012-08-28 18:31:45 +02:00
roberto@quantal64 e904f9f76e improved gevent graceful reload 2012-08-27 17:52:56 +02:00
roberto@quantal64 5df34ecfd8 fixed nanoseconds/microseconds conversion 2012-08-26 10:33:00 +02:00
roberto@quantal64 a96951880d added router_rewrite plugin 2012-08-26 09:11:42 +02:00
roberto@quantal64 c4425627ee added clock realtime plugin 2012-08-25 17:23:38 +02:00
roberto@quantal64 7033a0b5d2 added monotonic clock plugin 2012-08-25 17:15:58 +02:00
roberto@quantal64 a491be3975 added --clock and --clock-list options 2012-08-25 17:04:28 +02:00
roberto@quantal64 c664ac21bb added uwsgi pluggable clock infrastructure 2012-08-25 16:54:49 +02:00
roberto@quantal64 2205c0c33d fixed goodbye_cruel_world in gevent mode 2012-08-24 10:55:30 +02:00
roberto@quantal64 e9c54a4228 fixed emperor blacklist removal 2012-08-24 10:39:43 +02:00
roberto@quantal64 a38427944c fixed a series of typo 2012-08-23 17:06:03 +02:00
roberto@quantal64 124db58683 applied big Lukasz patch for busyness cheaper algo and improved carbon support 2012-08-23 17:02:15 +02:00
roberto@quantal64 aa075f9aaa added listing options for showing internal loaded features 2012-08-23 16:51:56 +02:00
roberto@quantal64 305f8a0667 auto-formatting of json output 2012-08-23 12:46:26 +02:00
roberto@quantal64 9d8238a2bb fixed json output 2012-08-23 11:37:15 +02:00
roberto@quantal64 3fccd4c5c0 fix early error reporting 2012-08-23 11:21:44 +02:00
roberto@quantal64 1a330e49f6 fixed reference counting in wrr 2012-08-20 20:37:02 +02:00
roberto@quantal64 7c09f294bf added content-length report on http body reading errors 2012-08-20 20:32:58 +02:00
roberto@quantal64 22c520043f improved/fixed wrr 2012-08-19 07:53:03 +02:00
roberto@quantal64 859c1eed0e try to fix subscription wrr 2012-08-18 20:40:28 +02:00
roberto@quantal64 e942668613 fixed a typo 2012-08-14 15:35:11 +02:00
roberto@quantal64 169c3a7970 added debug logging for busyness algo 2012-08-14 14:29:25 +02:00
roberto@quantal64 22892ce550 fixed carbon no_workers check 2012-08-14 14:15:35 +02:00
roberto@quantal64 2f5132c539 supports partial-write in linux sendfile 2012-08-13 19:08:17 +02:00
roberto@quantal64 d737bd0d35 applied Aarni Koskela patch for mod_uwsgi 2012-08-13 10:32:05 +02:00
roberto@quantal64 665958f1f5 fixed https write queue 2012-08-10 14:59:25 +02:00
roberto@quantal64 4bf86892ab another fix for write queue [2] 2012-08-10 13:04:26 +02:00
roberto@quantal64 bab89d1152 another fix for write queue 2012-08-10 12:49:23 +02:00
roberto@quantal64 4322c3b538 added support for better/true non-blocking write in http router 2012-08-10 11:12:59 +02:00
roberto@quantal64 9fabfd77ee added --so-keepalive 2012-08-10 09:11:01 +02:00
roberto@quantal64 94ce4187c9 added pam plugin 2012-08-09 18:21:02 +02:00
roberto@quantal64 e78388e287 added limit-nproc 2012-08-09 17:31:11 +02:00
roberto@quantal64 e3014bd0dc prepare for before_privileges_drop plugins 2012-08-09 17:25:05 +02:00
roberto@quantal64 36c79b100e improved build system reporting (by Łukasz Mierzwa) 2012-08-09 15:00:19 +02:00
roberto@quantal64 f6641aeca1 honour --add-header in php,rack and psgi plugins 2012-08-09 11:41:51 +02:00
roberto@quantal64 278187e738 added experimental 'busyness' cheaper algo 2012-08-09 11:06:45 +02:00
roberto@quantal64 668831d437 added --cheaper-initial 2012-08-09 07:36:41 +02:00
unbit 340f1e24ae Merge pull request #10 from xtfxme/defect-emperor-amqp-transient-queues
AMQP Emperor: Auto-delete transient queues
2012-07-26 22:12:55 -07:00
C Anthony Risinger 44e773f737 AMQP Emperor: Auto-delete transient queues
uWSGI requests a transient queue but does not set the `auto-delete` bit
resulting in unbounded creation of new -> abandonded queues.
2012-07-25 12:19:35 -05:00
roberto@quantal64 03aae347b0 allows ugreen with threads 2012-07-22 11:43:39 +02:00
roberto@mrspurr e393f36f0a fixed env clear in async mode 2012-07-22 11:21:08 +02:00
roberto@quantal64 b169193723 --json must be IMMEDIATE 2012-07-20 08:56:01 +02:00
roberto@quantal64 2de9b9d5c7 try to fix paste usage in python 3 2012-07-19 07:41:00 +02:00
roberto@quantal64 bde43ee7b2 added python logger 2012-07-17 11:20:16 +02:00
roberto@quantal64 4921e676d3 allows multiple loggers for the same instance 2012-07-17 10:40:39 +02:00
roberto@quantal64 b76a47231c fixed per-request chdir management 2012-07-17 10:06:38 +02:00
roberto@quantal64 2561d26b95 added --privileged-binary-patch-arg and --unprivileged-binary-patch-arg [2] 2012-07-16 12:22:28 +02:00
roberto@quantal64 4492bf517b added --privileged-binary-patch-arg and --unprivileged-binary-patch-arg 2012-07-16 12:12:47 +02:00
roberto@quantal64 c195e7e8ea added --privileged-binary-patch and --unprivileged-binary-patch, useful for running non-uwsgi apps using the Emperor 2012-07-16 11:55:40 +02:00
roberto@quantal64 667b418e28 improved IOVEC management in http router 2012-07-15 07:53:27 +02:00
roberto@quantal64 0ee7ba6aae save mountpoint,chdir and touch-reload valies of dynamic apps in shared memory 2012-07-13 21:44:16 +02:00
roberto@quantal64 8a656908e1 improved emperor stats and added emperormon.ru 2012-07-13 16:52:11 +02:00
roberto@quantal64 4f05d04c7f export blacklist in emperor stats 2012-07-13 16:18:36 +02:00
roberto@quantal64 c0fcbb7b85 fixed casting in wsgi.input (web3/pump part) 2012-07-13 13:23:30 +02:00
roberto@quantal64 fe36479d5c fixed casting in wsgi.input 2012-07-13 13:00:17 +02:00
roberto@quantal64 849829d6c0 correctly raise exception when the first iteration in a generator fails 2012-07-13 08:11:14 +02:00
roberto@quantal64 a77e9d3241 support for dir:// and glob:// in emperor configs 2012-07-12 20:44:43 +02:00
roberto@quantal64 fe26d41215 added support for vassal's heartbeat 2012-07-12 14:39:45 +02:00
roberto@quantal64 4d86712d4d if --harakiri and --py-tracebacker are both specified you will get a python traceback on harakiri 2012-07-12 05:25:24 +02:00
roberto@quantal64 006197a7c3 re-added support for emperor_amqp 2012-07-11 08:32:49 +02:00
roberto@quantal64 434aeb9761 improved emperor_pg plugin 2012-07-11 06:48:48 +02:00
roberto@quantal64 b1ca831269 fixed vassals removal 2012-07-11 06:43:45 +02:00
roberto@quantal64 8fc9b14db4 smarter config management in the emperor 2012-07-10 18:16:20 +02:00
roberto@quantal64 36cc5434fd added emperor postgresql plugin 2012-07-10 17:57:01 +02:00
roberto@quantal64 70c30a62e6 added --emperor-pidfile 2012-07-10 14:46:13 +02:00
roberto@quantal64 56827398d1 reindented the emperor and added some comment 2012-07-10 12:59:51 +02:00
roberto@quantal64 bd5cc93872 added preliminary support for vassal's heartbeat 2012-07-10 12:46:47 +02:00
roberto@quantal64 88be144a81 fixed a race condition in graceful reload 2012-07-10 12:34:57 +02:00
roberto@quantal64 8046194696 added --emperor-freq 2012-07-10 12:07:46 +02:00
roberto@quantal64 3012cb6bf9 new throttling system for the emperor 2012-07-10 11:53:34 +02:00
roberto@quantal64 cf74ccaaef new emperor infrastructure
--HG--
rename : lib/amqp.c => plugins/emperor_amqp/amqp.c
2012-07-10 09:32:50 +02:00
roberto@quantal64 8749053f30 removed websockets.py 2012-07-09 19:12:37 +02:00
roberto@quantal64 8368ce0e4c moved config files example to examples/ dir
--HG--
rename : debug.ini => examples/debug.ini
rename : fibers.yml => examples/fibers.yml
rename : heavytest.ini => examples/heavytest.ini
rename : logic.ini => examples/logic.ini
rename : mega.xml => examples/mega.xml
rename : multi.ini => examples/multi.ini
rename : multi.xml => examples/multi.xml
rename : protected.ini => examples/protected.ini
rename : sites.xml => examples/sites.xml
rename : uwsgi.xml => examples/uwsgi.xml
rename : welcome.ini => examples/welcome.ini
rename : werkzeug.yml => examples/werkzeug.yml
rename : werkzeug_strict.yml => examples/werkzeug_strict.yml
rename : zmqgevent.ini => examples/zmqgevent.ini
2012-07-09 19:10:47 +02:00
roberto@quantal64 c6c2157c1d moved all of the c files to the core directory
--HG--
rename : async.c => core/async.c
rename : cache.c => core/cache.c
rename : cluster.c => core/cluster.c
rename : event.c => core/event.c
rename : gateway.c => core/gateway.c
rename : ini.c => core/ini.c
rename : json.c => core/json.c
rename : ldap.c => core/ldap.c
rename : lock.c => core/lock.c
rename : logging.c => core/logging.c
rename : loop.c => core/loop.c
rename : mule.c => core/mule.c
rename : notify.c => core/notify.c
rename : plugins.c => core/plugins.c
rename : protocol.c => core/protocol.c
rename : queue.c => core/queue.c
rename : rb_timers.c => core/rb_timers.c
rename : regexp.c => core/regexp.c
rename : routing.c => core/routing.c
rename : rpc.c => core/rpc.c
rename : sendfile.c => core/sendfile.c
rename : setup_utils.c => core/setup_utils.c
rename : signal.c => core/signal.c
rename : skel.c => core/skel.c
rename : snmp.c => core/snmp.c
rename : socket.c => core/socket.c
rename : spooler.c => core/spooler.c
rename : sqlite3.c => core/sqlite3.c
rename : stats.c => core/stats.c
rename : subscription.c => core/subscription.c
rename : utils.c => core/utils.c
rename : xmlconf.c => core/xmlconf.c
rename : yaml.c => core/yaml.c
2012-07-09 19:08:51 +02:00
roberto@quantal64 4740c81280 updated uwsgiconfig.py 2012-07-09 19:01:13 +02:00
roberto@quantal64 f4f6e628b8 moved uwsgi.c to core
--HG--
rename : uwsgi.c => core/uwsgi.c
2012-07-09 19:00:39 +02:00
roberto@quantal64 55239207f4 started moving sources to core directory
--HG--
rename : emperor.c => core/emperor.c
rename : master.c => core/master.c
rename : master_utils.c => core/master_utils.c
2012-07-09 19:00:08 +02:00
unbit d912e951a0 Merge pull request #8 from skywave/zeromq3
Make compatible with zeroMQ-3.x
2012-07-08 22:24:16 -07:00
skywave b0c3184565 Make compatible with zeroMQ-3.x
In the 3.x versions of ZeroMQ some definitions were refactored, this
commit makes uwsgi compatible again with newer versions. Without this
patch compiliation of uwsgi will fail
2012-07-09 00:19:30 +02:00
roberto@quantal64 b3c9c5057f fixed a typo and an fd leak spotted by riccardo 2012-07-08 21:31:09 +02:00
roberto@quantal64 1c022ee01d added --lazy-apps as a more 'gentle' --lazy mode 2012-07-08 21:25:48 +02:00
roberto@quantal64 18589d86ff report system info on startup 2012-07-08 21:19:50 +02:00
roberto@quantal64 5a7b5d37b4 fix #138 2012-07-08 20:18:56 +02:00
roberto@quantal64 3e2115aa21 added proto logvar 2012-07-08 19:10:40 +02:00
roberto@quantal64 3f4a041e07 added time and ctime logvars 2012-07-08 19:03:44 +02:00
roberto@quantal64 59eb46895c first part of --logformat support 2012-07-08 18:29:51 +02:00
roberto@quantal64 2f452cc6f6 preliminary support for --worker-mount 2012-07-08 15:47:05 +02:00
roberto@quantal64 770bb1d122 reindented master.c 2012-07-08 07:20:31 +02:00
roberto@quantal64 4a036fb2ad refactored snmp and udp master support 2012-07-08 07:17:52 +02:00
roberto@quantal64 2ef72ad80f refactored master emperor manager 2012-07-08 07:06:22 +02:00
roberto@quantal64 c9088067d5 refactored master snapshot restore 2012-07-08 07:02:45 +02:00
roberto@quantal64 6f772f77c9 reindented master.c 2012-07-08 07:00:22 +02:00
roberto@quantal64 2430617427 refactored master mercy 2012-07-08 07:00:00 +02:00
roberto@quantal64 28888720bd refactored clusterbuf allocation 2012-07-08 06:52:32 +02:00
roberto@quantal64 32a1ba27ba refactored deadlock detector 2012-07-08 06:44:06 +02:00
roberto@quantal64 b750ee2aa3 fixed lazy reload + cheaper 2012-07-08 06:13:53 +02:00
roberto@quantal64 86aa5190b1 better waitpid usage 2012-07-08 05:07:07 +02:00
roberto@quantal64 55288af936 fixed async + threading support 2012-07-07 10:04:50 +02:00
roberto@quantal64 827d2e461b fixed cheap mode for routers 2012-07-01 16:56:30 +02:00
roberto@sirius 8400bcf8bc improved subscription system using a hash table 2012-07-01 14:27:15 +02:00
roberto@wuantal64 4dcfde541a added --rb-threads option and postinit_apps hook 2012-06-27 16:51:25 +02:00
roberto@quantal64 cf04a87688 preparing for ruby threads: add warnings if native threads are enabled 2012-06-27 16:24:55 +02:00
roberto@quantal64 65f88593b8 report mule pid when it cripples 2012-06-26 07:59:35 +02:00
roberto@quantal64 dbdf453724 fixed mongrel2 tnetstring JSON method 2012-06-25 13:41:33 +02:00
roberto@quantal64 e7f157b102 added an example config file for zeromq+gevent 2012-06-24 13:30:06 +02:00
roberto@quantal64 d30a5a4a50 little optimization for mongrel2 + gevent 2012-06-24 11:59:52 +02:00
roberto@quantal64 b0cfb0ca1f fixed a typo in gevent plugin 2012-06-24 08:59:58 +02:00
roberto@quantal64 c150f8c793 improved zeromq + threading 2012-06-23 19:54:11 +02:00
roberto@quantal64 46733c0673 started refactory of zeromq protocol handler 2012-06-23 16:59:17 +02:00
roberto@quantal64 772d1c8a5a refactored a bunch of initializing functions and allows zeromq+gevent 2012-06-23 10:00:43 +02:00
roberto@goyle 3f4bbdebe5 added a test for gevent+spooler 2012-06-21 10:52:36 +02:00
roberto@goyle 0394977658 allows greenlets to send jobs to the spooler 2012-06-21 10:24:28 +02:00
roberto@quantal64 33c9d01baf goodbye_cruel_world hook for gevent 2012-06-19 08:00:32 +02:00
roberto@quantal64 1367ee1e40 reporting correct python threads status 2012-06-17 19:08:17 +02:00
roberto@quantal64 8ddeed80cf the http router is now websocket friendly 2012-06-17 18:06:53 +02:00
roberto@quantal64 e796a57f14 fixed WSGI headers sending in websocket mode 2012-06-17 13:10:34 +02:00
roberto@sirius 839962370a trying to avoid OSX mess with universal binaries 2012-06-13 14:59:07 +02:00
roberto@quantal64 0a993c10e0 improved (and stabilized) auto-snapshotting 2012-06-13 12:44:36 +02:00
roberto@quantal64 aaaef51f2a be sure brained/patched mules are killed when the master dies 2012-06-13 11:04:35 +02:00
roberto@quantal64 8e10efd027 added options for setting Expires based on REQUEST_URI and PATH_INFO 2012-06-13 10:53:21 +02:00
roberto@quantal64 13c112430d fixed logfile inheritance 2012-06-13 08:04:05 +02:00
roberto@quantal64 05a40e786c fixed a typo 2012-06-12 14:36:48 +02:00
roberto@quantal64 64e05bed38 added support for graceful reloads in gevent plugin 2012-06-11 09:33:16 +02:00
roberto@quantal64 6f39909cd4 added support for multiple sockets in gevent plugin 2012-06-11 08:44:56 +02:00
roberto@mrspurr b4e41532eb dynamic modifier management for the rack plugin 2012-06-10 11:50:14 +02:00
roberto@mrspurr 4ca33d3f88 moved lib/rbtree.h to uwsgi.h 2012-06-10 11:28:32 +02:00
roberto@quantal64 b40cdfbe66 fixed spooler with chdir 2012-06-08 20:55:15 +02:00
roberto@quantal64 e775b18fd5 added http-to-https 2012-06-07 11:38:04 +02:00
roberto@quantal64 b1506712c9 added uwsgi.cache_clear api function 2012-06-07 08:02:29 +02:00
roberto@quantal64 7af2be5f1c reindenting a bunch of messy files 2012-06-06 09:32:34 +02:00
roberto@quantal64 27b1c63563 allows ipv6 socket to be inherited 2012-06-06 09:15:35 +02:00
roberto@quantal64 7b8fbf0f96 added binder.pl 2012-06-05 16:52:03 +02:00
roberto@quantal64 a748686349 added support for fd:// syntax in sockets options 2012-06-05 16:51:03 +02:00
roberto@quantal64 e2a0173d36 ready for the first 1.3 snapshot 2012-06-03 18:51:47 +02:00
roberto@quantal64 4d25e05986 fixed ruby rvm support 2012-06-03 18:32:05 +02:00
roberto@quantal64 c2091c52eb completed the python tracebacker 2012-06-03 10:58:34 +02:00
roberto@quantal64 d74928fa0f added @harakiri decorator for new uwsgi.set_user_harakiri option 2012-06-02 13:46:37 +02:00
roberto@quantal64 dc8bf75b73 implemented user defined harakiri via uwsgi.set_user_harakiri 2012-06-02 11:24:55 +02:00
roberto@quantal64 cc5ae8bf31 fixed a leak in uwsgi.workers() 2012-06-02 09:59:21 +02:00
roberto@quantal64 f62f7f9282 thread-safe wsgi env behaviour 2012-06-02 09:43:24 +02:00
roberto@quantal64 c3cbcbb0d5 added --wsgi-env-behaviour for choosing the WSGI environ allocator/destroyer policy 2012-06-02 07:37:52 +02:00
roberto@quantal64 ec2889b202 fixed python3 compilation 2012-06-01 19:57:07 +02:00
roberto@quantal64 474d04d6a1 added a security check in the http router 2012-05-31 18:53:09 +02:00
roberto@quantal64 18f535413f fixed signed subscription filenames 2012-05-31 16:25:07 +02:00
roberto@quantal64 85ca80f7ea added --extra-plugin build option for simplified plugin development 2012-05-31 15:24:07 +02:00
roberto@quantal64 097d10439d print cflags to stdout 2012-05-31 13:36:53 +02:00
roberto@quantal64 209d96131d fixed psgi post buffering in memory 2012-05-31 13:23:00 +02:00
roberto@quantal64 4baed7b7b8 added support for --cflags 2012-05-31 10:03:17 +02:00
roberto@precise64 9f02286018 fixed a typo in psgi.input 2012-05-30 14:44:56 +02:00
roberto@precise64 1b7d3b5fe9 fixed httprouter and rawrouter requests count 2012-05-29 19:02:07 +02:00
roberto@precise64 a6d7aa7da3 fixed waitpid() usage when in cheap mode 2012-05-29 16:40:45 +02:00
roberto@precise64 11fe76f26d improved --namespace-keep-mount with Lukasz ideas 2012-05-29 15:09:52 +02:00
roberto@precise64 1b6fdf6093 completed server side security of new subscription system 2012-05-29 14:37:26 +02:00
robert@mrspurr fa3badcfd0 improved security of secure subscription server 2012-05-29 14:36:04 +02:00
roberto@precise64 ce1b022025 added --namespace-keep-mount 2012-05-29 10:40:08 +02:00
roberto@precise64 6e81548daa allows building without ssl 2012-05-28 14:46:34 +02:00
roberto@precise64 bb7271ec17 another ifdef for older openssl versions 2012-05-28 14:42:58 +02:00
roberto@precise64 f6ca42a4b0 fixed locking reporting on older systems 2012-05-28 13:51:05 +02:00
roberto@precise64 bcf5d3a480 fixed yaml reporting 2012-05-28 13:46:17 +02:00
roberto@precise64 fffe26ceac added configuration report at the end of uWSGI compilation 2012-05-28 13:44:08 +02:00
roberto@centos64 fd17bdf963 fixed for older openssl versions 2012-05-28 13:08:31 +02:00
roberto@precise64 a168009382 implemented the 'secure' subscription system 2012-05-28 13:02:09 +02:00
roberto@precise64 f624f92e4d refactored keepalive support in http/https router 2012-05-27 15:25:53 +02:00
roberto@precise64 f065171aa1 export HTTPS_DN and HTTPS_CC 2012-05-27 13:28:19 +02:00
roberto@precise64 b7532abcc8 added support for SSL client certificate 2012-05-27 10:07:34 +02:00
roberto@precise64 59aa0308c7 fully disable ssl caching 2012-05-26 16:26:29 +02:00
roberto@precise64 6b5708a563 added a big WARNING for users forgetting to load plugins 2012-05-26 09:46:25 +02:00
roberto@precise64 c1a4834624 allows shared sockets to be subscribed 2012-05-26 09:05:30 +02:00
roberto@precise64 35ce3630c6 allows custom socket to be subscribed 2012-05-26 08:44:15 +02:00
roberto@precise64 c686912707 added rawrouter 2012-05-25 21:23:57 +02:00
roberto@precise64 963964afef custom options can now define commandline options too 2012-05-25 07:40:55 +02:00
roberto@precise64 53666dd289 allows multicast to be used as a subscription server 2012-05-24 20:59:15 +02:00
roberto@precise64 d8d292348e refactored snmp 2012-05-24 20:40:56 +02:00
roberto@precise64 678726859c applied Łukasz Mierzwa patch for carbon no workers 2012-05-24 20:34:10 +02:00
roberto@precise64 bedafceac3 applied riccardo's patch 2012-05-24 20:29:07 +02:00
roberto@precise64 a3635bc45f another master refactoring 2012-05-24 14:30:27 +02:00
roberto@precise64 8cc8394676 removed SCTP support 2012-05-24 12:24:29 +02:00
roberto@precise64 e5124093ff do not check for died processes if diedpid is invalid 2012-05-24 12:05:26 +02:00
roberto@precise64 6d1d5d6bf8 applied riccardo's patch for correct perror report 2012-05-23 20:39:34 +02:00
roberto@precise64 8964b45558 do not disable waitpid() calls during cheap mode 2012-05-23 20:37:13 +02:00
roberto@precise64 eb0e9e7d1a openssl session caching is a problem, no way to make non-blocking io call in callbacks... 2012-05-20 20:51:46 +02:00
roberto@precise64 17254ee863 added support for ssl session caching 2012-05-20 20:31:20 +02:00
roberto@backup 85fdfdd81f protect from SSL beast attack 2012-05-20 08:44:59 +02:00
roberto@precise64 3d194cd8cc added --declare-option 2012-05-19 10:59:40 +02:00
roberto@precise64 3cc591fd8b clang fix 2012-05-18 20:39:58 +02:00
roberto@precise64 3bb43745b8 remove HTTP_CONTENT_LENGTH and HTTP_CONTENT_TYPE from rack/psgi automatically 2012-05-18 16:08:23 +02:00
roberto@precise64 beb12b6804 better DH support based on stud 2012-05-18 11:09:49 +02:00
roberto@mrspurr 9a9cb2f8fe disable ssl2 2012-05-18 08:08:20 +02:00
roberto@centos4 6b7fed814c fixed support for centos4 2012-05-16 15:38:35 +02:00
roberto@precise64 47e26d93c0 ladies and gentleman, https support in the http router/load-balancer 2012-05-16 17:16:26 +02:00
roberto@precise64 de51c46fd8 allows graceful reloads on shared sockets 2012-05-16 11:09:25 +02:00
roberto@precise64 d342bdaf72 added --log-master-bufsize 2012-05-15 08:59:08 +02:00
roberto@precise64 7ee0150e2b force master mode in cheap/idle 2012-05-15 04:24:58 +02:00
roberto@precise64 cd5b0e7e58 ported corerouter stats to the new infrastructure 2012-05-14 21:04:29 +02:00
roberto@precise64 aebda4aced fixed a regression with http pipelined requests 2012-05-14 18:52:27 +02:00
roberto@sirius 26b7e6aabf improved wait_for_threads 2012-05-14 17:42:34 +02:00
roberto@precise64 9b16859c33 ported emperor stats to the new infrastructure 2012-05-14 16:21:16 +02:00
roberto@precise64 d662bf6064 new stats generator subsystem 2012-05-14 15:47:05 +02:00
roberto@precise64 a695a27b9c leave http-keepalive as experimental/useless/broken 2012-05-14 13:20:21 +02:00
roberto@precise64 e46077f576 httprouter keepalive preliminary support 2012-05-13 23:47:32 +02:00
roberto@precise64 6ec3b05ce5 fixed uwsgi signals in async mode 2012-05-13 19:49:00 +02:00
roberto@precise64.local f9d561993a added contrib/uwsgisubscribers.ru 2012-05-13 11:13:11 +02:00
roberto@precise64 c0b59234d0 report exceptions before stacktrace in psgi 2012-05-13 08:50:54 +02:00
roberto@precise64 f041509f15 another big merge of routers 2012-05-13 07:44:05 +02:00
roberto@precise64 06b4300d09 uwsgi.sendfile is for raw usage 2012-05-13 06:46:48 +02:00
roberto@precise64 7bf2194a08 a first series of solaris fixes 2012-05-12 19:48:12 +02:00
roberto@precise64 b6bdf37a1d merged http and fastrouter 2012-05-12 19:37:44 +02:00
roberto@precise64 4060436099 allows subscription system via unix socket 2012-05-12 18:22:44 +02:00
roberto@precise64 406b6098c5 unsubscribe/resubscribe on suspend/resume 2012-05-12 17:48:25 +02:00
roberto@precise64 a5606098aa implemented psgix.logger 2012-05-12 17:36:24 +02:00
roberto@precise64 ff9bab4b4e fixed psgi fileno() support 2012-05-12 17:02:21 +02:00
roberto@precise64 6e881293ff fixed async mode in non-linux systems 2012-05-12 11:23:37 +02:00
roberto@precise64 5fac82cfee fixed wsgi.file_wrapper 2012-05-12 10:54:35 +02:00
roberto@precise64 83da420cfc added corerouter 2012-05-12 10:50:19 +02:00
roberto@precise64 b2abccd302 fixed uwsgi.sendfile() 2012-05-12 10:47:04 +02:00
roberto@precise64 99d9e8cd67 applied atexit patch from 1.2.2 2012-05-11 21:15:58 +02:00
roberto@precise64 9fe275141f added preliminary python tracebacker 2012-05-11 20:44:56 +02:00
roberto@precise64 8c833101d8 let's start 1.3 development cycle 2012-05-10 09:58:09 +02:00
roberto@precise64 0c6f9faaf1 the installer now wants absolute binary path 2012-05-10 08:35:17 +02:00
roberto@precise64 a93ff5bf1f allows multiple start_response without leaks 2012-05-08 19:14:25 +02:00
roberto@precise64 d258c1b417 avoid WSGI status_line to be decref'ed 2012-05-08 18:47:49 +02:00
roberto@precise64 6e473a75bd added UWSGI_BIN_NAME support 2012-05-08 17:17:54 +02:00
roberto@precise64 433de267a6 added redislog plugin 2012-05-06 16:04:56 +02:00
roberto@precise64 2beca32c36 do not run cheaper algos or subscriptions on suspended instances 2012-05-06 14:04:43 +02:00
roberto@precise64 15aaddb4d3 allows embedding the psgi plugin 2012-05-05 10:23:26 +02:00
roberto@precise64 35ddb777b4 added interpolation support in build profile 2012-05-05 10:06:44 +02:00
roberto@precise64 b15a0a2d4b added --disable-write-exception 2012-05-05 09:30:43 +02:00
roberto@precise64 95bda63c40 added --exec-as-user-atexit (patch by Łukasz Mierzwa) 2012-05-05 09:11:40 +02:00
roberto@precise64 62b24fcd2a another python headers management optimization 2012-05-05 09:00:52 +02:00
roberto@precise64 df0406902e fixed static file offloading 2012-05-05 07:44:10 +02:00
roberto@precise64 71d57274e5 fixed optional pargs management 2012-05-05 07:11:35 +02:00
roberto@debian32 08c6258459 tolerate php wrong sign-compare 2012-05-04 16:26:06 +02:00
roberto@precise64 9a4e950480 added a fallback for pthread robust mutexes 2012-05-03 20:19:58 +02:00
roberto@precise64 e2dcdba5a7 fixed headers sent 2012-05-02 11:34:10 +02:00
roberto@precise64 c39cf848de better implementation of start_response() 2012-05-02 09:30:37 +02:00
roberto@precise64 5ccf2254eb added preliminary version of mod_proxy_uwsgi for apache2 2012-05-01 15:59:42 +02:00
roberto@precise64 dd291b9b71 fixed streaming in mod_uwsgi 2012-05-01 09:07:20 +02:00
roberto@precise64 0515fbb2d6 Added tag 1.2 for changeset c3cdecbf2bac 2012-04-30 11:05:16 +02:00
roberto@precise64 6692276472 uWSGI 1.2 2012-04-30 11:05:08 +02:00
roberto@mrspurr 81c09a9c9c report signum in worker's death 2012-04-29 05:04:19 +02:00
roberto@precise64 6a0a367ec3 added a test for gevent + threads 2012-04-26 15:11:52 +02:00
roberto@precise64 bdf533d62b fixed auto-reloading 2012-04-26 14:51:39 +02:00
roberto@precise64 1aba0bc26c completed --if-reload//--if-not-reload 2012-04-26 09:40:20 +02:00
roberto@precise64 aac6e9a365 fixed ruby -bash 2012-04-26 09:26:33 +02:00
roberto@precise64 9da732d96c added --if-reload/--if-not-reload and --unenv 2012-04-26 09:17:45 +02:00
roberto@precise64 328ba43ed2 fix uninitialzied structure 2012-04-25 17:55:47 +02:00
roberto@freebsd9 62d3253b02 fix kqueue() usage 2012-04-25 15:02:19 +02:00
roberto@mrspurr e5ba01e707 fixed socket in non-blocking mode 2012-04-25 14:18:40 +02:00
roberto@openbsd51 82c25f7f8c better execinfo detection 2012-04-25 11:00:25 +02:00
roberto@precise64 8791866ea0 added ebug infos for touch checks 2012-04-25 08:37:23 +02:00
roberto@opensuse12 8f10b8fece fix python version printing on freeky systems 2012-04-25 08:11:12 +02:00
roberto@opensuse12 0d28d210d4 another opensuse-related fix, build mimedict only if needed 2012-04-25 08:02:24 +02:00
roberto@precise 2368a5a050 fixed bug 121 2012-04-25 07:21:28 +02:00
roberto@precise64 74a9b1b41d added uwsgi.ready() 2012-04-24 21:50:00 +02:00
roberto@precise64 672c49e8eb refactored signal handling 2012-04-24 21:27:43 +02:00
roberto@precise64 225db32636 threading support for gevent 2012-04-24 19:23:14 +02:00
roberto@opensuse12 01541e4a50 fixed bug #120 2012-04-24 18:53:38 +02:00
roberto@precise64 357e260b45 some minor cleanup spotted by marcin deranek 2012-04-20 16:27:00 +02:00
roberto@centos32 a2513b1851 put a \0 at the end of process name 2012-04-20 16:11:16 +02:00
roberto@precise64 bbe8604054 added hack for ruby -bash 2012-04-20 14:11:08 +02:00
roberto@precise64 58a33de7f7 Added tag 1.2-rc2 for changeset 29de0fb320bc 2012-04-20 10:11:59 +02:00
roberto@precise64 ab7abc6a48 added upstart socket activation support and applied git001 patch for additional include paths 2012-04-20 09:59:59 +02:00
roberto@mrspurr 4986bdf202 added --static-map2 2012-04-20 07:04:02 +02:00
roberto@precise64 11aaddac98 fixed --static-map to a file 2012-04-19 19:44:35 +02:00
roberto@precise64 da9b2b4378 added static-expires/static-expires-mtime 2012-04-19 19:22:00 +02:00
roberto@freebsd9 9771a98bc6 fixed a typecast in rack plugin 2012-04-18 15:47:55 +02:00
roberto@precise64 033ee5f4e9 fixed a typo 2012-04-18 14:38:30 +02:00
roberto@precise64 1383163627 import dummy_threading whenever threads are in place 2012-04-18 10:14:41 +02:00
roberto@precise64 1d31b35c4f export static_offload_threads in statistics 2012-04-18 08:01:48 +02:00
roberto@precise64 7b2cc757b2 fixed SERVER_PORT in zeromq 2012-04-18 00:54:43 +02:00
roberto@precise64 68cddd1c2e fixed REMOTE_ADDR in mongrel2 when protocol is tnetstring 2012-04-17 23:41:04 +02:00
roberto@goyle b2a9fbbc5c set offload threading stacksize to 512k 2012-04-17 22:26:32 +02:00
roberto@goyle 0fcb13b9f1 implemented offload static file serving 2012-04-17 22:01:54 +02:00
roberto@goyle 938a22ce2e multiple mime file support 2012-04-17 20:04:48 +02:00
roberto@goyle 2df5dbfe52 added support for expires header 2012-04-17 19:24:13 +02:00
roberto@goyle feed0d0faa fixed get_mime_type 2012-04-15 22:33:05 +02:00
roberto@goyle c8373d20a9 added a check for strlen in the cgi plugin 2012-04-15 17:42:28 +02:00
roberto@mrspurr 170267a04a fixed mod_Ruwsgi 2012-04-15 07:11:45 +02:00
roberto@precise64 bd5969db67 fix initial messages 2012-04-15 07:06:33 +02:00
roberto@precise64 02256c013c added --carbon-no-workers 2012-04-14 13:54:41 +02:00
roberto@precise64 89be9a0d4a Added tag 1.2-rc1 for changeset 24c8fe5a26e5 2012-04-14 12:55:03 +02:00
roberto@precise64 4e57a6e145 uWSGI 1.2-rc1 2012-04-14 12:54:48 +02:00
roberto@openindiana64 784434ef3e opeinindiana fixes 2012-04-14 12:24:04 +02:00
roberto@precise64 91273b2301 py-auto-reload-ignore 2012-04-14 11:48:27 +02:00
roberto@precise64 2bcc85a99f added support for REMOTE_ADDR in mongrel2/zeromq 2012-04-14 10:08:34 +02:00
roberto@precise64 b7e6da3392 added --write-errors-tolerance and --write-errors-exception-only 2012-04-14 09:11:52 +02:00
roberto@precise64 d934270a27 merge 2012-04-14 08:22:54 +02:00
roberto@fiorenzo ed5a268e1f fix reloading of gateways 2012-04-13 19:01:05 +02:00
roberto@fiorenzo 95beaa0a86 merge 2012-04-13 17:09:22 +02:00
roberto@fiorenzo 0d3bf93c76 fixed fd leak in daemonize 2012-04-13 17:08:52 +02:00
roberto@sirius 50fb43066a ported fastcgi and zeromq to the new api 2012-04-13 16:23:55 +02:00
roberto@centos4 c33ec8ff56 ported locking to obsolete kernels 2012-04-13 14:09:03 +02:00
roberto@mrspurr e6afeec8af fixed return value in cache sweeper thread 2012-04-13 15:57:07 +02:00
roberto@sirius 57b9bdb958 better write()/writev() management 2012-04-13 11:36:43 +02:00
roberto@precise64 315bcb72c9 applied nagios patch from github 2012-04-11 07:23:00 +02:00
roberto@precise64 6b2460c02f improved syslog 2012-04-11 07:20:58 +02:00
roberto@precise64 35bc999a59 correctly set bin_name in setup.py 2012-04-09 08:41:27 +02:00
roberto@precise64 f00ad75e45 added --emperor-magic-exec 2012-04-08 09:13:07 +02:00
roberto@openbsd51 6bfe8e5b41 openBSD fixes 2012-04-08 08:24:51 +02:00
roberto@precise64 d7e8fd7d06 a couple of typo 2012-04-07 21:17:09 +02:00
roberto@precise64 949a0c35d5 improve cache reliability and performance of the sweeper 2012-04-07 21:08:42 +02:00
roberto@precise64 d193d5572f add --cache-expire-freq 2012-04-06 16:09:58 +02:00
roberto@precise64 f79f7e44a7 fixed cache and queue locking 2012-04-06 15:54:29 +02:00
roberto@mrspurr 26db55aafd fixed --pyargv 2012-04-06 11:39:48 +02:00
roberto@mrspurr 9d405c6cb2 fixed locking in uwsgi.cache_exists 2012-04-06 10:28:02 +02:00
roberto@mrspurr cceee511f2 added support for reload-on-exception on PyPy and interval-based cron syntax 2012-04-06 07:40:21 +02:00
roberto@freebsd9 e2024ed2fd merge 2012-04-05 12:28:30 +02:00
roberto@freebsd9 add7e2ee0e added execinfo support for FreeBSD 2012-04-05 12:28:10 +02:00
roberto@precise64 0458aa8eb4 use ctime_r instead of ctime 2012-04-05 12:15:04 +02:00
roberto@freebsd9 9ff6be783a use posix semaphores on freebsd9 2012-04-05 06:22:02 +02:00
roberto@mrspurr 14c558559b pypy now has PyFile_FromFile 2012-04-05 05:52:58 +02:00
roberto@centos64 92c5dcb6f2 allows robust mutexes on older linux systems 2012-04-04 22:54:56 +02:00
roberto@precise64 ae31f349f7 added robust mutexes 2012-04-04 22:53:07 +02:00
roberto@centos64 ce2846d04f first pthread robust implementation 2012-04-04 21:48:34 +02:00
roberto@mrspurr 7a6c9a5fe4 merge 2012-04-04 17:29:39 +02:00
roberto@mrspurr 43c258ad48 support for virtualenv in pypy 2012-04-04 17:29:00 +02:00
roberto@precise64 8ba032adb2 added --spooler-max-tasks 2012-04-03 17:59:37 +02:00
roberto@precise64 1a61dfd4e0 ported mod_Ruwsgi to apache 2.4 2012-04-03 09:02:00 +02:00
roberto@precise64 8e150e77a8 ported mod_uwsgi to apache 2.4 2012-04-03 08:47:09 +02:00
roberto@goyle 729fa753fa remove unneded pypy ifdef 2012-04-02 19:33:33 +02:00
roberto@longshot bf6c552189 fixed python 2.4 2012-04-02 07:55:22 +02:00
roberto@precise64 e9dc987a95 revert wsgi.url_scheme 2012-04-02 07:48:20 +02:00
roberto@precise64 35d9a39100 fixed autoload 2012-04-01 06:14:09 +02:00
roberto@mrspurr a864c8d6ed fix pypy when no app is loaded 2012-03-31 18:06:03 +02:00
roberto@precise64 c2df8a099e added --python-auto-reload 2012-03-31 17:55:09 +02:00
roberto@precise64 878e9cb9ba reports microseconds in python profilers 2012-03-31 15:48:22 +02:00
roberto@precise64 3612ea2186 fixed a deadlock in get_mime_type 2012-03-30 21:15:14 +02:00
roberto@precise64 81f0f93d96 improved module aliasing 2012-03-30 10:17:30 +02:00
roberto@precise64 c2d7b65145 better error management in pymodule-alias 2012-03-29 12:59:50 +02:00
roberto@precise64 6274e82cea fix fastrouter subscription refcnt 2012-03-29 11:26:35 +02:00
roberto@precise64 66655c9429 php append options 2012-03-28 18:28:24 +02:00
roberto@precise64 f47c8553d5 added uwsgi_expand_path() 2012-03-28 16:48:17 +02:00
roberto@precise64 f2802d3332 gevent current_req fix 2012-03-28 16:22:18 +02:00
roberto@precise64 1a173c849f minor fixes for test suite 2012-03-28 12:40:20 +02:00
roberto@precise64 57d4cd9fc9 gevent fixes 2012-03-28 11:08:04 +02:00
roberto@precise64 f6b9345716 fixed a garbage in python_call 2012-03-28 10:21:20 +02:00
roberto@freebsd64 792cd01320 fixed daemonize 2012-03-28 09:34:37 +02:00
roberto@mrspurr 03bc7d0399 close bug 85 2012-03-28 09:00:53 +02:00
roberto@mrspurr ed8f0812d7 PyPy SUPPORT 2012-03-27 13:58:27 +02:00
roberto@precise64 196dc45d0b fixed zero socket (2) 2012-03-26 14:28:18 +02:00
roberto@precise64 f8ff906d1b fixed zero socket 2012-03-26 14:20:08 +02:00
roberto@precise64 bbf1b0eda5 merged pypy 2012-03-26 13:41:50 +02:00
roberto@precise64 6f811a4899 better realpath for static docroot 2012-03-26 13:41:18 +02:00
roberto@mrspurr c66957d685 first round of pypy patches 2012-03-26 10:46:12 +02:00
roberto@goyle 282b2d5ace lua fixes 2012-03-23 21:22:17 +01:00
roberto@precise64 6a73e3ae05 fixed rack.input read 2012-03-22 16:25:27 +01:00
roberto@precise64 5856d410fd second part of zerg fixes 2012-03-22 11:14:41 +01:00
roberto@precise64 08d9de54f0 uniq zerg sockets 2012-03-22 10:05:00 +01:00
roberto@precise64 af1f98131a --perl-no-die-catch 2012-03-22 08:32:11 +01:00
roberto@precise64 9cef49ec57 fixed perl caching, added uwsgi::signal 2012-03-22 08:26:33 +01:00
roberto@precise64 d60c6d50ec fixed plugin loading by symlink 2012-03-22 07:35:27 +01:00
roberto@precise64 f3fdec2739 completed --reload-on-exception* options 2012-03-21 20:37:03 +01:00
roberto@precise64 1a20f57b73 fixed --spooler-quiet 2012-03-21 20:28:08 +01:00
roberto@precise64 0fc74dac4d better GIL usage 2012-03-21 20:21:51 +01:00
roberto@precise64 4117dd91fc ported psycopg2 example to the new api 2012-03-21 19:53:40 +01:00
roberto@precise64 508ca0df39 add realpath() for php DOCUMENT_ROOT 2012-03-21 19:28:24 +01:00
roberto@precise64 a50e356beb more verbose php debug 2012-03-21 07:50:27 +01:00
roberto@precise64 a0b7237083 added --spooler-quiet 2012-03-20 15:42:10 +01:00
roberto@precise64 08afa73e69 spooler multiprocess fixes 2012-03-20 10:58:48 +01:00
roberto@precise64 b386317921 fixed python3 reload-on-exception 2012-03-19 13:39:07 +01:00
roberto@precise64 2043127f22 fixed snmp support 2012-03-19 07:29:39 +01:00
roberto@precise64 c297a9415b started 1.2 development cycle 2012-03-18 09:03:14 +01:00
roberto@precise64 f9f9f25a01 added exception detection 2012-03-18 08:21:45 +01:00
roberto@precise64 9001af1beb better uuid detection 2012-03-17 11:01:01 +01:00
roberto@debian32 4b03f17186 python 3.x fix 2012-03-17 10:36:06 +01:00
roberto@precise64 3dbab36b91 uWSGI 1.1 2012-03-17 07:56:09 +01:00
roberto@precise64 056c890845 Added tag 1.1 for changeset e1568fd16b7b 2012-03-17 07:39:33 +01:00
roberto@precise64 4f43cd74ad env must not be immediate 2012-03-16 20:53:03 +01:00
roberto@precise64 6585b7b13d fixed pifile 2012-03-16 13:38:26 +01:00
roberto@precise64 e55048b574 fixed logdate 2012-03-16 13:07:06 +01:00
roberto@mercury 570dcde654 report listen_queue_errors 2012-03-16 06:52:48 +01:00
roberto@precise64 3cb16ee29b ready for 1.1 release 2012-03-15 20:42:41 +01:00
roberto@mailcop3 bb453da5b5 added support for SIOBKLGQ 2012-03-15 20:40:26 +01:00
roberto@precise64 1a93b68664 fixed expire_timeouts in fastrouter 2012-03-15 17:44:56 +01:00
roberto@precise64 2ce2494a50 bumped to -rc4 2012-03-15 17:36:59 +01:00
roberto@precise64 0a1e451289 Added tag 1.1-rc4 for changeset ef99144291f0 2012-03-15 17:31:05 +01:00
roberto@precise64 8ef7819080 re-included WSGI iterator close() 2012-03-15 17:29:55 +01:00
roberto@precise64 319ad13af2 allows plugin 255 to be used 2012-03-15 08:58:41 +01:00
roberto@precise4 fe28e90ae3 fixed a bug in spooler and signal plugin 2012-03-15 08:48:26 +01:00
roberto f604a0a533 bumped to 1.1-rc3 2012-03-14 18:30:19 +01:00
roberto@precise64 4ab78d42a3 Added tag 1.1-rc3 for changeset ede5c664978b 2012-03-14 18:30:02 +01:00
roberto@precise64 c631e7dae6 fixed multiple touch-reload 2012-03-14 18:29:04 +01:00
roberto@precise da8e88d638 Added tag 1.1-rc2 for changeset 901f0cb5de36 2012-03-14 12:08:58 +01:00
roberto@precise64 4707d9250d queue/cache fix 2012-03-14 11:34:51 +01:00
roberto@precise64 d719960411 fixed emperor amqp 2012-03-14 10:03:54 +01:00
roberto@precise64 734818c995 fixed shared sockets 2012-03-14 08:28:25 +01:00
roberto@precise64 a35335a820 fixed lua plugin 2012-03-12 18:54:04 +01:00
roberto@precise64 aca4dbfbe7 fixed threading rpc 2012-03-12 14:54:59 +01:00
roberto@precise64 b036029b32 another locking fix 2012-03-12 09:58:02 +01:00
roberto@freebsd64 52f3e757ed added --ftok 2012-03-12 09:40:56 +01:00
roberto@precise64 c4ce1cf7d8 appliead Riccardo's patches 2012-03-11 20:10:04 +01:00
roberto@icarus 48175d0759 various fixed for php and cgi plugins, added notfound plugin 2012-03-11 17:21:53 +00:00
roberto@precise64 2932168db7 Added tag 1.1-rc1 for changeset 1d1702789710 2012-03-10 15:23:47 +01:00
211 changed files with 19850 additions and 10262 deletions
+10
View File
@@ -44,3 +44,13 @@ a3ca2e8e27c5c12c44ba0cacb4de4cb51377f184 1.0-rc7
af490b8c30f83bc5fb6f3837a760981474647755 1.0-rc10
3c70927335856883283fe4db448e092cecc0ccdb 1.0
8fe7bb792399cb6e6a24e20551f4149409660363 1.0.1
1d1702789710ec1c20613d2490b14f70756e67ec 1.1-rc1
901f0cb5de36ea907b26d64ac9ce54605ec531d2 1.1-rc2
ede5c664978bb40e476e8d4a5789562928f28507 1.1-rc3
ef99144291f06822d026e981d5d856cbec14d867 1.1-rc4
e1568fd16b7b586cc72deb4dfccbbe64ae0b84df 1.1
24c8fe5a26e557db41cf1cee45b8964d5885e484 1.2-rc1
29de0fb320bc0a1ce84972f9f249360e315d3c10 1.2-rc2
c3cdecbf2bac591336baddd14f9ac22e18d6e200 1.2
14524da00a8b382dffb1d16a0e70cdf4a946f369 1.3-rc2
883b946db9038372cb1d76cb1d328a3093140e7b 1.3-rc3
+67
View File
@@ -1,3 +1,70 @@
*** current ***
* 1.3
- python tracebacker
- user-governed harakiri
- simplified external plugin development
- Linux namespace mountpoint improvements
- secured subscription system
- merged routers codebase (fastrouter, http, rawrouter)
- https support in the http router
- config report at the end of uWSGI build process
- support for keepalive in the http router
- improved subscription system (multicast and unix socket)
- custom options
- graceful reloads on shared sockets
- configurable log-master buffer size
- extreme-optimizations for the stats subsystem
*** april 2012 ***
* 1.2 [20120430]
- PyPy support
- Improved gevent support with threads
- Python auto-reload subsystem
- added --spooler-max-tasks
- pthread robust mutexes support in Linux and Solaris
- posix semaphores support in FreeBSD9
- thread-safe ctime() reporting
- interval support in cron subsystem
- improved syslog support
- better management of disconnected clients
- static files serving improvements
- another set of multithreading optimizations
- minor fixes in the Rack plugin
- Upstart socket-activation support
*** march 2012 ***
* 1.1 [20120317]
- new options parser subsystem
- improved php support
- multiple spooler with multiprocessing
- segmentation fault and floating point exceptions manager
- never-swap option
- zergpool plugin
- perl/psgi multiple interpreters support
- deadlock detector
- pluggable cheaper algos
- new internal routing susbsystem
- preliminary support for config logic
- log rotation infrastructure
- support for paste loggers
- threading improvements
- plugins can now mapped to specific modifiers
- <app> tag is deprecated (use mount option)
- report startup time for apps
- reintroduced expat support
- reintroduced remote spooler plugin
- various fastrouter optimizations
- added ruby rvm support
*** december 2011 ***
* 1.0 [20111230]
+29 -2
View File
@@ -160,20 +160,35 @@ static int uwsgi_map_location(request_rec *r)
return DECLINED;
}
static void log_err(const char *file, int line, request_rec *r,
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
static void log_err(const char *file, int line, int ami, request_rec *r,
apr_status_t status, const char *msg)
{
ap_log_rerror(file, line, APLOG_MODULE_INDEX, APLOG_ERR, status, r, "uwsgi: %s", msg);
#else
static void log_err(const char *file, int line, request_rec *r,
apr_status_t status, const char *msg)
{
ap_log_rerror(file, line, APLOG_ERR, status, r, "uwsgi: %s", msg);
#endif
}
static void log_debug(const char *file, int line, request_rec *r, const
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
static void log_debug(const char *file, int line, int ami, request_rec *r, const
char *msg)
{
/*
ap_log_rerror(file, line, APLOG_DEBUG, APR_SUCCESS, r, msg);
ap_log_rerror(file, line, APLOG_WARNING, APR_SUCCESS, r, "uwsgi: %s", msg);
*/
ap_log_rerror(file, line, APLOG_MODULE_INDEX, APLOG_DEBUG, APR_SUCCESS, r, "uwsgi: %s", msg);
#else
static void log_debug(const char *file, int line, request_rec *r, const
char *msg) {
ap_log_rerror(file, line, APLOG_DEBUG, APR_SUCCESS, r, "uwsgi: %s", msg);
#endif
}
/* buffered socket implementation (buckets are overkill) */
@@ -412,7 +427,11 @@ send_headers(request_rec *r, struct sockbuff *s)
apr_table_t *t;
apr_status_t rv = 0;
apr_port_t port = 0;
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
GET_PORT(port, r->useragent_addr);
#else
GET_PORT(port, r->connection->remote_addr);
#endif
uwsgi_cfg *cfg = our_dconfig(r);
log_debug(APLOG_MARK,r, "sending headers");
@@ -430,7 +449,11 @@ send_headers(request_rec *r, struct sockbuff *s)
add_header(t, "REQUEST_METHOD", (char *) r->method);
add_header(t, "QUERY_STRING", r->args ? r->args : "");
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
add_header(t, "SERVER_SOFTWARE", ap_get_server_description());
#else
add_header(t, "SERVER_SOFTWARE", ap_get_server_version());
#endif
add_header(t, "SERVER_ADMIN", r->server->server_admin);
add_header(t, "SERVER_NAME", (char *) ap_get_server_name(r));
add_header(t, "SERVER_PORT", apr_psprintf(r->pool, "%u",ap_get_server_port(r)));
@@ -438,7 +461,11 @@ send_headers(request_rec *r, struct sockbuff *s)
add_header(t, "SERVER_PROTOCOL", r->protocol);
add_header(t, "REQUEST_URI", original_uri(r));
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
add_header(t, "REMOTE_ADDR", r->useragent_ip);
#else
add_header(t, "REMOTE_ADDR", r->connection->remote_ip);
#endif
add_header(t, "REMOTE_PORT", apr_psprintf(r->pool, "%d", port));
add_header(t, "REMOTE_USER", r->user);
add_header(t, "DOCUMENT_ROOT", (char *) ap_document_root(r));
+397
View File
@@ -0,0 +1,397 @@
#define APR_WANT_MEMFUNC
#define APR_WANT_STRFUNC
#include "apr_strings.h"
#include "apr_hooks.h"
#include "apr_optional_hooks.h"
#include "apr_buckets.h"
#include "httpd.h"
#include "http_config.h"
#include "http_log.h"
#include "http_protocol.h"
#include "http_request.h"
#include "util_script.h"
#include "mod_proxy.h"
#define UWSGI_SCHEME "uwsgi"
#define UWSGI_DEFAULT_PORT 3031
module AP_MODULE_DECLARE_DATA proxy_uwsgi_module;
static int uwsgi_canon(request_rec *r, char *url)
{
char *host, sport[sizeof(":65535")];
const char *err, *path;
apr_port_t port = UWSGI_DEFAULT_PORT;
if (strncasecmp(url, UWSGI_SCHEME "://", sizeof(UWSGI_SCHEME) + 2)) {
return DECLINED;
}
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,
"error parsing URL %s: %s", url, err);
return HTTP_BAD_REQUEST;
}
apr_snprintf(sport, sizeof(sport), ":%u", port);
if (ap_strchr(host, ':')) { /* if literal IPv6 address */
host = apr_pstrcat(r->pool, "[", host, "]", NULL);
}
path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
r->proxyreq);
if (!path) {
return HTTP_BAD_REQUEST;
}
r->filename = apr_pstrcat(r->pool, "proxy:" UWSGI_SCHEME "://", host, sport, "/",
path, NULL);
return OK;
}
static int uwsgi_send(proxy_conn_rec *conn, const char *buf, apr_size_t length,
request_rec *r)
{
apr_status_t rv;
apr_size_t written;
while (length > 0) {
written = length;
if ((rv = apr_socket_send(conn->sock, buf, &written)) != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
"sending data to %s:%u failed",
conn->hostname, conn->port);
return HTTP_SERVICE_UNAVAILABLE;
}
/* count for stats */
conn->worker->s->transferred += written;
buf += written;
length -= written;
}
return OK;
}
/*
* Send uwsgi header block
*/
static int uwsgi_send_headers(request_rec *r, proxy_conn_rec *conn)
{
char *buf, *ptr;
const apr_array_header_t *env_table;
const apr_table_entry_t *env;
int j;
apr_size_t headerlen = 4;
uint16_t pktsize, keylen, vallen;
ap_add_common_vars(r);
ap_add_cgi_vars(r);
const char *script_name = apr_table_get(r->subprocess_env, "SCRIPT_NAME");
const char *path_info = apr_table_get(r->subprocess_env, "PATH_INFO");
if (script_name && path_info) {
apr_table_set(r->subprocess_env, "SCRIPT_NAME", apr_pstrndup(r->pool, script_name, strlen(script_name)-strlen(path_info)));
}
env_table = apr_table_elts(r->subprocess_env);
env = (apr_table_entry_t *)env_table->elts;
for (j = 0; j < env_table->nelts; ++j) {
headerlen += 2 + strlen(env[j].key) + 2 + strlen(env[j].val) ;
}
ptr = buf = apr_palloc(r->pool, headerlen);
ptr+=4;
for (j = 0; j < env_table->nelts; ++j) {
keylen = strlen(env[j].key);
*ptr++= (uint8_t) (keylen & 0xff);
*ptr++= (uint8_t) ((keylen >> 8) & 0xff);
memcpy(ptr, env[j].key, keylen) ; ptr+=keylen;
vallen = strlen(env[j].val);
*ptr++= (uint8_t) (vallen & 0xff);
*ptr++= (uint8_t) ((vallen >> 8) & 0xff);
memcpy(ptr, env[j].val, vallen) ; ptr+=vallen;
}
pktsize = headerlen-4;
buf[0] = 0;
buf[1] = (uint8_t) (pktsize & 0xff);
buf[2] = (uint8_t) ((pktsize >> 8) & 0xff);
buf[0] = 0;
return uwsgi_send(conn, buf, headerlen, r);
}
static int uwsgi_send_body(request_rec *r, proxy_conn_rec *conn)
{
if (ap_should_client_block(r)) {
char *buf = apr_palloc(r->pool, AP_IOBUFSIZE);
int status;
apr_size_t readlen;
readlen = ap_get_client_block(r, buf, AP_IOBUFSIZE);
while (readlen > 0) {
status = uwsgi_send(conn, buf, readlen, r);
if (status != OK) {
return HTTP_SERVICE_UNAVAILABLE;
}
readlen = ap_get_client_block(r, buf, AP_IOBUFSIZE);
}
if (readlen == -1) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"receiving request body failed");
return HTTP_INTERNAL_SERVER_ERROR;
}
}
return OK;
}
static
apr_status_t ap_proxygetline(apr_bucket_brigade *bb, char *s, int n, request_rec *r,
int fold, int *writen)
{
char *tmp_s = s;
apr_status_t rv;
apr_size_t len;
rv = ap_rgetline(&tmp_s, n, &len, r, fold, bb);
apr_brigade_cleanup(bb);
if (rv == APR_SUCCESS) {
*writen = (int) len;
} else if (rv == APR_ENOSPC) {
*writen = n;
} else {
*writen = -1;
}
return rv;
}
static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_conf *conf)
{
char buffer[HUGE_STRING_LEN];
const char *buf;
char *value, *end;
int len;
apr_status_t rc;
conn_rec *c = r->connection;
apr_off_t readbytes;
apr_status_t rv;
apr_bucket *e;
apr_read_type_e mode = APR_NONBLOCK_READ;
request_rec *rp = ap_proxy_make_fake_req(backend->connection, r);
rp->proxyreq = PROXYREQ_RESPONSE;
apr_bucket_brigade *bb = apr_brigade_create(r->pool, c->bucket_alloc);
rc = ap_proxygetline(bb, buffer, sizeof(buffer), rp, 0, &len);
if (len == 0) {
rc = ap_proxygetline(bb, buffer, sizeof(buffer), rp, 0, &len);
}
if (len <= 0) {
// oops
return HTTP_INTERNAL_SERVER_ERROR;
}
backend->worker->s->read += len;
if (!apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
// oops
return HTTP_INTERNAL_SERVER_ERROR;
}
int major, minor;
major = buffer[5] - '0';
minor = buffer[7] - '0';
/* If not an HTTP/1 message or
* if the status line was > 8192 bytes
*/
if ((major != 1) || (len >= sizeof(buffer)-1)) {
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
apr_pstrcat(r->pool, "Corrupt status line returned by remote "
"server: ", buffer, NULL));
}
char keepchar = buffer[12];
buffer[12] = '\0';
r->status = atoi(&buffer[9]);
if (keepchar != '\0') {
buffer[12] = keepchar;
} else {
/* 2616 requires the space in Status-Line; the origin
* server may have sent one but ap_rgetline_core will
* have stripped it. */
buffer[12] = ' ';
buffer[13] = '\0';
}
r->status_line = apr_pstrdup(r->pool, &buffer[9]);
// start parsing headers;
while ((len = ap_getline(buffer, sizeof(buffer), rp, 1)) > 0) {
value = strchr(buffer, ':');
// invalid header skip
if (!value) continue;
*value = '\0';
++value;
while (apr_isspace(*value)) ++value;
for (end = &value[strlen(value)-1]; end > value && apr_isspace(*end); --end) *end = '\0';
apr_table_add(r->headers_out, buffer, value);
}
if ((buf = apr_table_get(r->headers_out, "Content-Type"))) {
ap_set_content_type(r, apr_pstrdup(r->pool, buf));
}
for(;;) {
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))) {
e = apr_bucket_flush_create(c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, e);
if (ap_pass_brigade(r->output_filters, bb) || c->aborted) {
break;
}
apr_brigade_cleanup(bb);
mode = APR_BLOCK_READ;
continue;
}
else if (rv == APR_EOF) {
break;
}
else if (rv != APR_SUCCESS) {
ap_proxy_backend_broke(r, bb);
ap_pass_brigade(r->output_filters, bb);
}
mode = APR_NONBLOCK_READ;
apr_brigade_length(bb, 0, &readbytes);
backend->worker->s->read += readbytes;
ap_pass_brigade(r->output_filters, bb);
apr_brigade_cleanup(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;
}
static int uwsgi_handler(request_rec *r, proxy_worker *worker,
proxy_server_conf *conf, char *url,
const char *proxyname, apr_port_t proxyport)
{
int status;
proxy_conn_rec *backend = NULL;
apr_pool_t *p = r->pool;
apr_uri_t *uri = apr_palloc(r->pool, sizeof(*uri));
char server_portstr[32];
if (strncasecmp(url, UWSGI_SCHEME "://", sizeof(UWSGI_SCHEME) + 2)) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"declining URL %s", url);
return DECLINED;
}
// ADD PATH_INFO
apr_table_add(r->subprocess_env, "PATH_INFO", url+strlen(worker->name));
/* Create space for state information */
status = ap_proxy_acquire_connection(UWSGI_SCHEME, &backend, worker,
r->server);
if (status != OK) {
goto cleanup;
}
backend->is_ssl = 0;
/* Step One: Determine Who To Connect To */
status = ap_proxy_determine_connection(p, r, conf, worker, backend,
uri, &url, proxyname, proxyport,
server_portstr, sizeof(server_portstr));
if (status != OK) {
goto cleanup;
}
/* Step Two: Make the Connection */
if (ap_proxy_connect_backend(UWSGI_SCHEME, backend, worker, r->server)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"failed to make connection to backend: %s:%u",
backend->hostname, backend->port);
status = HTTP_SERVICE_UNAVAILABLE;
goto cleanup;
}
/* Step Three: Create conn_rec */
if (!backend->connection) {
if ((status = ap_proxy_connection_create(UWSGI_SCHEME, backend,
r->connection, r->server)) != OK)
goto cleanup;
}
/* Step Four: Process the Request */
if ( ((status = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) != OK)
|| ((status = uwsgi_send_headers(r, backend)) != OK)
|| ((status = uwsgi_send_body(r, backend)) != OK)
|| ((status = uwsgi_response(r, backend, conf)) != OK)) {
goto cleanup;
}
cleanup:
if (backend) {
backend->close = 1; /* always close the socket */
ap_proxy_release_connection(UWSGI_SCHEME, backend, r->server);
}
return status;
}
static void register_hooks(apr_pool_t *p)
{
proxy_hook_scheme_handler(uwsgi_handler, NULL, NULL, APR_HOOK_FIRST);
proxy_hook_canon_handler(uwsgi_canon, NULL, NULL, APR_HOOK_FIRST);
}
module AP_MODULE_DECLARE_DATA proxy_uwsgi_module = {
STANDARD20_MODULE_STUFF,
NULL, /* create per-directory config structure */
NULL, /* merge per-directory config structures */
NULL, /* create per-server config structure */
NULL, /* merge per-server config structures */
NULL, /* command table */
register_hooks /* register hooks */
};
+29 -3
View File
@@ -2,7 +2,7 @@
*** uWSGI/mod_uwsgi ***
Copyright 2009-2011 Unbit S.a.s. <info@unbit.it>
Copyright 2009-2012 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
@@ -37,11 +37,18 @@ LoadModule uwsgi_module <path_of_apache_modules>/mod_uwsgi.so
*/
#include <unistd.h>
#include <ctype.h>
#include "apr_strings.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "httpd.h"
#include "http_core.h"
#include "http_protocol.h"
#include "http_config.h"
#include "http_log.h"
#include "util_script.h"
#include <sys/socket.h>
#include <sys/un.h>
@@ -346,7 +353,11 @@ static int uwsgi_handler(request_rec *r) {
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "SERVER_PORT", apr_psprintf(r->pool, "%u",ap_get_server_port(r)), &pkt_size) ;
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "SERVER_PROTOCOL", r->protocol, &pkt_size) ;
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "REQUEST_URI", r->unparsed_uri, &pkt_size) ;
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "REMOTE_ADDR", r->useragent_ip, &pkt_size) ;
#else
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "REMOTE_ADDR", r->connection->remote_ip, &pkt_size) ;
#endif
//
if (r->user) {
@@ -356,7 +367,7 @@ static int uwsgi_handler(request_rec *r) {
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "REMOTE_USER", "", &pkt_size) ;
}
if (r->user) {
if (ap_auth_type(r) != NULL) {
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "AUTH_TYPE", (char *) ap_auth_type(r), &pkt_size) ;
}
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "DOCUMENT_ROOT", (char *) ap_document_root(r), &pkt_size) ;
@@ -506,7 +517,22 @@ static int uwsgi_handler(request_rec *r) {
free(uwsgi_vars);
return HTTP_INTERNAL_SERVER_ERROR;
}
apr_brigade_write(bb, NULL, NULL, buf, cnt);
if (!c->cgi_mode) {
b = apr_bucket_transient_create(buf, cnt, r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, b);
b = apr_bucket_flush_create(r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, b);
if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS) {
close(uwsgi_poll.fd);
apr_brigade_destroy(bb);
free(uwsgi_vars);
return HTTP_INTERNAL_SERVER_ERROR;
}
apr_brigade_cleanup(bb);
}
else {
apr_brigade_write(bb, NULL, NULL, buf, cnt);
}
}
else {
// EOF
+45
View File
@@ -0,0 +1,45 @@
[uwsgi]
xml = auto
ini = true
yaml = true
json = auto
sqlite3 = auto
zeromq = auto
snmp = true
spooler = true
embedded = true
ssl = auto
udp = true
multicast = true
threading = true
sendfile = true
minterpreters = true
async = true
ldap = auto
pcre = auto
routing = auto
ipv6 = false
debug = false
unbit = false
xml_implementation = libxml2
yaml_implementation = auto
malloc_implementation = libc
extras =
plugins =
bin_name = uwsgi
append_version =
plugin_dir = .
embedded_plugins = %(main_plugin)s, ping, cache, nagios, rrdtool, carbon, rpc, corerouter, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool, redislog, mongodblog, router_rewrite, router_http
as_shared_library = false
locking = auto
event = auto
timer = auto
filemonitor = auto
blacklist =
whitelist =
embed_files =
embed_config =
+3
View File
@@ -0,0 +1,3 @@
[uwsgi]
main_plugin = cgi
inherit = base
+2 -1
View File
@@ -1,3 +1,4 @@
[uwsgi]
inherit = default
main_plugin =
inherit = base
embedded_plugins = null
+2 -47
View File
@@ -1,48 +1,3 @@
[uwsgi]
xml = auto
ini = true
yaml = true
json = auto
sqlite3 = auto
zeromq = auto
snmp = true
sctp = false
spooler = true
embedded = true
udp = true
multicast = true
threading = true
sendfile = true
minterpreters = true
async = true
ldap = auto
pcre = auto
routing = auto
debug = false
unbit = false
xml_implementation = libxml2
yaml_implementation = auto
malloc_implementation = libc
extras =
plugins =
bin_name = uwsgi
append_version =
plugin_dir = .
embedded_plugins = python, ping, cache, nagios, rrdtool, carbon, rpc, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool
as_shared_library = false
locking = auto
event = auto
timer = auto
filemonitor = auto
blacklist =
whitelist =
embed_files =
embed_config =
[python]
paste = true
web3 = true
main_plugin = python
inherit = base
+2 -1
View File
@@ -1,3 +1,4 @@
[uwsgi]
inherit = default
main_plugin = python
inherit = base
embed_files = bootstrap3.py,django.zip,djapp.zip
+2 -1
View File
@@ -1,4 +1,5 @@
[uwsgi]
inherit = default
main_plugin = python
inherit = base
embed_files = embedme.py,uwsgidecorators.py
+2 -2
View File
@@ -1,3 +1,3 @@
[uwsgi]
inherit = default
embedded_plugins = +,erlang
main_plugin = erlang
inherit = base
+2 -2
View File
@@ -1,3 +1,3 @@
[uwsgi]
inherit = default
embedded_plugins = python, ping, cache, nagios, rpc, fastrouter, http, gevent
main_plugin = python,gevent
inherit = base
+1 -1
View File
@@ -1,5 +1,5 @@
[uwsgi]
inherit = default
inherit = base
bin_name = libuwsgi.so
embedded_plugins = null
as_shared_library = true
+2 -2
View File
@@ -1,3 +1,3 @@
[uwsgi]
inherit = default
embedded_plugins = lua
main_plugin = lua
inherit = base
+2 -1
View File
@@ -1,3 +1,4 @@
[uwsgi]
inherit = default
main_plugin =
inherit = base
plugins = lua
+1 -1
View File
@@ -1,5 +1,5 @@
[uwsgi]
inherit = default
inherit = base
plugins = python, ping, rack, psgi, cache, http, fastrouter
plugin_dir = plugins
embedded_plugins = null
+2 -2
View File
@@ -1,4 +1,4 @@
[uwsgi]
inherit = default
inherit = base
plugin_dir = /usr/lib/uwsgi
embedded_plugins = null
embedded_plugins =
+3
View File
@@ -0,0 +1,3 @@
[uwsgi]
main_plugin = php
inherit = base
+2 -2
View File
@@ -1,3 +1,3 @@
[uwsgi]
inherit = default
embedded_plugins = psgi
main_plugin = psgi
inherit = base
+2 -2
View File
@@ -1,3 +1,3 @@
[uwsgi]
inherit = default
embedded_plugins = +,erlang,pyerl
main_plugin = python,erlang,pyerl
inherit = base
+2 -2
View File
@@ -1,3 +1,3 @@
[uwsgi]
inherit = default
embedded_plugins = +,lua
main_plugin = python,lua
inherit = base
+2 -4
View File
@@ -1,5 +1,3 @@
[uwsgi]
inherit = default
bin_name = libuwsgi.so
embedded_plugins = symcall
as_shared_library = true
main_plugin = pypy
inherit = base
-1
View File
@@ -2,7 +2,6 @@
xml = true
ini = true
snmp = true
sctp = false
erlang = false
spooler = true
embedded = true
+2 -2
View File
@@ -1,5 +1,5 @@
[uwsgi]
inherit = default
main_plugin = pyuwsgi
inherit = base
bin_name = pyuwsgi.so
embedded_plugins = pyuwsgi,python,ping,cache,nagios,rpc,ugreen
as_shared_library = true
+2 -2
View File
@@ -1,3 +1,3 @@
[uwsgi]
inherit = default
embedded_plugins = rack, ping, cache, nagios, rpc, fastrouter, http, ugreen
main_plugin = rack
inherit = base
-1
View File
@@ -3,7 +3,6 @@ xml = true
ini = true
yaml = true
snmp = true
sctp = false
erlang = false
spooler = false
embedded = false
+4 -5
View File
@@ -2,11 +2,10 @@
xml = true
ini = true
yaml = true
json = true
json = false
sqlite3 = false
zeromq = false
snmp = false
sctp = false
spooler = true
embedded = true
udp = true
@@ -15,12 +14,12 @@ threading = true
sendfile = true
minterpreters = true
async = true
evdis = false
ldap = true
pcre = false
pcre = true
routing = true
debug = false
unbit = true
xml_implementation = libxml2
xml_implementation = expat
yaml_implementation = auto
malloc_implementation = libc
plugins =
-5
View File
@@ -6,7 +6,6 @@ json = false
sqlite3 = false
zeromq = false
snmp = false
sctp = false
spooler = true
embedded = true
udp = true
@@ -43,7 +42,3 @@ whitelist =
embed_files =
embed_config =
[python]
paste = true
web3 = true
+12
View File
@@ -0,0 +1,12 @@
use POSIX;
use IO::Socket::INET;
use IO::Socket::INET6;
my $s = IO::Socket::INET->new(LocalAddr => '127.0.0.1', LocalPort => 1717, Proto => 'tcp', Reuse => 1);
my $s2 = IO::Socket::INET->new(LocalAddr => '127.0.0.1', LocalPort => 3022, Proto => 'tcp', Reuse => 1);
my $s3 = IO::Socket::INET6->new(LocalAddr => '::', LocalPort => 3017, Proto => 'tcp', Reuse => 1);
dup2($s->fileno, 17);
dup2($s2->fileno, 22);
dup2($s3->fileno, 30);
exec './uwsgi','-M', '--socket','fd://17', '--http-socket','fd://22', '--socket','fd://30';
+114
View File
@@ -0,0 +1,114 @@
require 'sinatra'
require 'socket'
require 'json'
module EmperorStats
def self.uwsgi_get_stats(server)
parts = server.split(':')
if parts.length > 1
s = TCPSocket.open(parts[0], parts[1])
else
s = UNIXSocket.open(server)
end
return JSON.parse(s.read())
end
end
template = <<eof
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title><%=@title%></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="unbit">
<link href="http://unbit.github.com/bootstrap/css/bootstrap.css" rel="stylesheet">
<style>
body {
padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */
}
</style>
<link href="http://unbit.github.com/bootstrap/css/bootstrap-responsive.css" rel="stylesheet">
</head>
<body>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="brand" href="#"><%=@title%></a>
</div>
</div>
</div>
<div class="container">
<hr/>
<h1>Emperor: <%=@stats['emperor']%></h1>
<hr/>
<div class="row">
<div class="span8">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>name</th><th>pid</th><th>first run</th>
<th>last respawn</th>
<th>last heartbeat</th>
<th>loyal</th>
<th>respawns</th>
<% if @stats['emperor_tyrant'] == 1 %>
<th>uid</th>
<th>gid</th>
<% end %>
</tr>
</thead>
<% for vassal in @stats['vassals'] %>
<tr>
<td><%=vassal['id']%></td>
<td><%=vassal['pid']%></td>
<td><%=Time.at(vassal['first_run']).strftime("%d %b %Y %H:%M:%S")%></td>
<td><%=Time.at(vassal['last_run']).strftime("%d %b %Y %H:%M:%S")%></td>
<td><% if vassal['last_heartbeat'] > 0 %><%=Time.at(vassal['last_heartbeat']).strftime("%d %b %Y %H:%M:%S")%><% end %></td>
<td><% if vassal['loyal'] > 0 %><%=Time.at(vassal['last_loyal']).strftime("%d %b %Y %H:%M:%S")%><% end %></td>
<td><%=vassal['respawns']%></td>
<% if @stats['emperor_tyrant'] == 1 %>
<td><%=vassal['uid']%></td>
<td><%=vassal['gid']%></td>
<% end %>
</tr>
<% end %>
</table>
</div>
<div class="span4">
<h3>blacklist</h3>
<table class="table table-striped table-bordered">
<thead>
<tr><th>name</th><th>throttle</th></tr>
<% for bli in @stats['blacklist'] %>
<tr>
<td><%=bli['id']%></td>
<td><%=bli['throttle_level']%></td>
</tr>
<% end %>
</thead>
</table>
</div>
</div>
<script src="http://unbit.github.com/jquery-1.7.2.min.js" type="text/javascript"></script>
<script src="http://unbit.github.com/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
</body>
</html>
eof
get '/' do
@stats = EmperorStats::uwsgi_get_stats(ENV['EMPEROR'])
@title = 'uWSGI Emperor monitor'
erb template
end
run Sinatra::Application
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/perl
use Crypt::OpenSSL::RSA;
use IO::Socket::INET;
open PK,$ARGV[3];
my @lines = <PK>;
close PK;
$rsa_priv = Crypt::OpenSSL::RSA->new_private_key(join('',@lines));
my %items = {};
$items{'key'} = $ARGV[1];
$items{'address'} = $ARGV[2];
my $uwsgi_pkt = '';
foreach(keys %items) {
$uwsgi_pkt .= pack('v', length($_)).$_.pack('v', length($items{$_})).$items{$_};
}
my $unix_check = time();
$uwsgi_pkt .= pack('v', 4).'unix'.pack('v', length($unix_check)).$unix_check;
my $signature = $rsa_priv->sign($uwsgi_pkt);
$uwsgi_pkt .= pack('v', 4).'sign'.pack('v', length($signature)).$signature;
my $udp = new IO::Socket::INET(PeerAddr => $ARGV[0], Proto => 'udp');
$udp->send(pack('CvC', 224, length($uwsgi_pkt), 0).$uwsgi_pkt);
print ''.(length($uwsgi_pkt)+4).' bytes sent to '.$ARGV[0]."\n";
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/perl
use IO::Socket::INET;
my %items = {};
$items{'key'} = $ARGV[1];
$items{'address'} = $ARGV[2];
my $uwsgi_pkt = '';
foreach(keys %items) {
$uwsgi_pkt .= pack('v', length($_)).$_.pack('v', length($items{$_})).$items{$_};
}
my $udp = new IO::Socket::INET(PeerAddr => $ARGV[0], Proto => 'udp');
$udp->send(pack('CvC', 224, length($uwsgi_pkt), 0).$uwsgi_pkt);
print ''.(length($uwsgi_pkt)+4).' bytes sent to '.$ARGV[0]."\n";
+96
View File
@@ -0,0 +1,96 @@
require 'sinatra'
require 'socket'
require 'json'
module USubscribers
def self.uwsgi_get_stats(server)
parts = server.split(':')
if parts.length > 1
s = TCPSocket.open(parts[0], parts[1])
else
s = UNIXSocket.open(server)
end
return JSON.parse(s.read())
end
end
template = <<eof
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title><%=@title%></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="unbit">
<link href="http://unbit.github.com/bootstrap/css/bootstrap.css" rel="stylesheet">
<style>
body {
padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */
}
</style>
<link href="http://unbit.github.com/bootstrap/css/bootstrap-responsive.css" rel="stylesheet">
</head>
<body>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="brand" href="#"><%=@title%></a>
</div>
</div>
</div>
<% for server in @servers.keys %>
<div class="container">
<hr/>
<h1>SubscriptionServer: <%=server%></h1>
<hr/>
<div class="row">
<% for pool in @servers[server] %>
<div class="span6">
<h3><%=pool['key']%> (<%=pool['hits']%> hits)</h3>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>node</th><th>load</th><th>requests</th>
<th>last check</th>
<th>fail count</th>
</tr>
</thead>
<% for node in pool['nodes'] %>
<tr>
<td><%=node['name']%></td><td><%=node['load']%></td><td><%=node['requests']%></td>
<td><%=Time.at(node['last_check']).strftime("%d-%m-%Y %H:%M:%S")%></td>
<td><%=node['failcnt']%></td>
</tr>
<% end %>
</table>
</div>
<% end %>
</div>
</div>
<% end %>
<script src="http://unbit.github.com/jquery-1.7.2.min.js" type="text/javascript"></script>
<script src="http://unbit.github.com/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
</body>
</html>
eof
get '/' do
@servers = {}
for server in ENV['U_SERVERS'].split(',')
stats = USubscribers::uwsgi_get_stats(server)
if stats
@servers[server] = stats['subscriptions']
end
end
@title = 'uWSGI subscriptions viewer'
erb template
end
run Sinatra::Application
+47 -16
View File
@@ -2,6 +2,29 @@
extern struct uwsgi_server uwsgi;
void uwsgi_async_init() {
int i;
uwsgi.async_queue = event_queue_init();
if (uwsgi.async_queue < 0) {
exit(1);
}
uwsgi_add_sockets_to_queue(uwsgi.async_queue, -1);
uwsgi.rb_async_timeouts = uwsgi_init_rb_timer();
uwsgi.async_queue_unused = uwsgi_malloc(sizeof(struct wsgi_request *) * uwsgi.async);
for (i = 0; i < uwsgi.async; i++) {
uwsgi.async_queue_unused[i] = &uwsgi.workers[uwsgi.mywid].cores[i].req;
}
uwsgi.async_queue_unused_ptr = uwsgi.async - 1;
}
struct wsgi_request *find_wsgi_req_proto_by_fd(int fd) {
return uwsgi.async_proto_fd_table[fd];
}
@@ -76,7 +99,7 @@ struct wsgi_request *find_first_available_wsgi_req() {
void async_expire_timeouts() {
struct wsgi_request *wsgi_req;
time_t current_time = time(NULL);
time_t current_time = uwsgi_now();
struct uwsgi_async_fd *uaf = NULL, *current_uaf;
struct uwsgi_rb_timer *urbt;
@@ -150,7 +173,7 @@ void async_add_fd_read(struct wsgi_request *wsgi_req, int fd, int timeout) {
void async_add_timeout(struct wsgi_request *wsgi_req, int timeout) {
if (timeout > 0 && wsgi_req->async_timeout == NULL) {
wsgi_req->async_timeout = uwsgi_add_rb_timer(uwsgi.rb_async_timeouts, time(NULL)+timeout, wsgi_req);
wsgi_req->async_timeout = uwsgi_add_rb_timer(uwsgi.rb_async_timeouts, uwsgi_now()+timeout, wsgi_req);
}
}
@@ -214,6 +237,7 @@ void *async_loop(void *arg1) {
if (uwsgi.signal_socket > -1) {
event_queue_add_fd_read(uwsgi.async_queue, uwsgi.signal_socket);
event_queue_add_fd_read(uwsgi.async_queue, uwsgi.my_signal_socket);
}
// set a default request manager
@@ -230,7 +254,7 @@ void *async_loop(void *arg1) {
timeout = 0;
}
if (min_timeout) {
timeout = min_timeout->key - time(NULL);
timeout = min_timeout->key - uwsgi_now();
if (timeout <= 0) {
async_expire_timeouts();
timeout = 0;
@@ -253,6 +277,12 @@ void *async_loop(void *arg1) {
// manage events
interesting_fd = event_queue_interesting_fd(events, i);
if (uwsgi.signal_socket > -1 && (interesting_fd == uwsgi.signal_socket || interesting_fd == uwsgi.my_signal_socket)) {
uwsgi_receive_signal(interesting_fd, "worker", uwsgi.mywid);
continue;
}
is_a_new_connection = 0;
// new request coming in ?
@@ -266,12 +296,12 @@ void *async_loop(void *arg1) {
uwsgi.wsgi_req = find_first_available_wsgi_req();
if (uwsgi.wsgi_req == NULL) {
now = time(NULL);
now = uwsgi_now();
if (now > last_now) {
uwsgi_log("async queue is full !!!\n");
last_now = now;
}
break;;
break;
}
wsgi_req_setup(uwsgi.wsgi_req, uwsgi.wsgi_req->async_id, uwsgi_sock );
@@ -289,15 +319,15 @@ void *async_loop(void *arg1) {
// on linux we do not need to reset the socket to blocking state
#ifndef __linux__
if (uwsgi.numproc > 1) {
/* re-set blocking socket */
if (fcntl(uwsgi.wsgi_req->poll.fd, F_SETFL, uwsgi_sock->arg) < 0) {
uwsgi_error("fcntl()");
uwsgi.async_queue_unused_ptr++;
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
break;
}
}
/* re-set blocking socket */
int arg = uwsgi_sock->arg;
arg &= (~O_NONBLOCK);
if (fcntl(uwsgi.wsgi_req->poll.fd, F_SETFL, arg) < 0) {
uwsgi_error("fcntl()");
uwsgi.async_queue_unused_ptr++;
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
break;
}
#endif
if (wsgi_req_async_recv(uwsgi.wsgi_req)) {
@@ -336,8 +366,9 @@ void *async_loop(void *arg1) {
runqueue_push(uwsgi.wsgi_req);
continue;
}
else if (proto_parser_status == -1) {
uwsgi_log("error parsing request\n");
else if (proto_parser_status < 0) {
if (proto_parser_status == -1)
uwsgi_log("error parsing request\n");
uwsgi.async_proto_fd_table[interesting_fd] = NULL;
close(interesting_fd);
continue;
+71
View File
@@ -0,0 +1,71 @@
#include "uwsgi.h"
extern struct uwsgi_server uwsgi;
struct uwsgi_buffer *uwsgi_buffer_new(size_t len) {
struct uwsgi_buffer *ub = uwsgi_calloc(sizeof(struct uwsgi_buffer));
if (len) {
ub->buf = uwsgi_malloc(len);
ub->len = len;
}
return ub;
}
int uwsgi_buffer_append(struct uwsgi_buffer *ub, char *buf, size_t len) {
size_t remains = ub->len - ub->pos;
if (len > remains) {
size_t chunk_size = UMAX(len, (size_t) uwsgi.page_size);
char *new_buf = realloc(ub->buf, ub->len + chunk_size);
if (!new_buf) {
uwsgi_error("realloc()");
return -1;
}
ub->buf = new_buf;
ub->len += chunk_size;
}
memcpy(ub->buf + ub->pos, buf, len);
ub->pos += len;
return 0;
}
void uwsgi_buffer_destroy(struct uwsgi_buffer *ub) {
if (ub->buf) free(ub->buf);
free(ub);
}
int uwsgi_buffer_send(struct uwsgi_buffer *ub, int fd) {
size_t remains = ub->pos;
char *ptr = ub->buf;
while(remains > 0) {
int ret = uwsgi_waitfd_write(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
if (ret > 0) {
ssize_t len = write(fd, ptr, remains);
if (len > 0) {
ptr += len;
remains -= len;
}
else if (len == 0) {
return -1;
}
else {
uwsgi_error("write()");
return -1;
}
}
else if (ret == 0) {
uwsgi_log("timeout while sending buffer !!!\n");
return -1;
}
else {
return -1;
}
}
return 0;
}
+33 -8
View File
@@ -102,7 +102,7 @@ uint32_t djb33x_hash(char *key, int keylen) {
}
inline uint64_t uwsgi_cache_get_index(char *key, uint16_t keylen) {
static inline uint64_t uwsgi_cache_get_index(char *key, uint16_t keylen) {
uint32_t hash = djb33x_hash(key, keylen);
@@ -111,13 +111,14 @@ inline uint64_t uwsgi_cache_get_index(char *key, uint16_t keylen) {
uint64_t slot = uwsgi.cache_hashtable[hash_key];
struct uwsgi_cache_item *uci;
uint64_t rounds = 0;
//uwsgi_log("found slot %d for key %d\n", slot, hash_key);
uci = &uwsgi.cache_items[slot];
// first round
if (uci->djbhash != hash) goto cycle;
if (uci->djbhash != hash) return 0;
if (uci->keysize != keylen) goto cycle;
if (memcmp(uci->key, key, keylen)) goto cycle;
@@ -127,7 +128,20 @@ cycle:
while(uci->next) {
slot = uci->next;
uci = &uwsgi.cache_items[slot];
if (uci->djbhash != hash) continue;
rounds++;
if (rounds > uwsgi.cache_max_items) {
uwsgi_log("ALARM !!! cache-loop (and potential deadlock) detected slot = %llu prev = %llu next = %llu\n", uci->next, slot, uci->prev, uci->next);
// terrible case: the whole uWSGI stack can deadlock, leaving only the master alive
// if the master is avalable, trigger a brutal reload
if (uwsgi.master_process) {
kill(uwsgi.workers[0].pid, SIGTERM);
}
// otherwise kill the current worker (could be pretty useless...)
else {
exit(1);
}
}
if (uci->djbhash != hash) return 0;
if (uci->keysize != keylen) continue;
if (!memcmp(uci->key, key, keylen)) return slot;
}
@@ -154,13 +168,14 @@ char *uwsgi_cache_get(char *key, uint16_t keylen, uint64_t *valsize) {
return NULL;
}
int uwsgi_cache_del(char *key, uint16_t keylen) {
int uwsgi_cache_del(char *key, uint16_t keylen, uint64_t index) {
uint64_t index = 0;
struct uwsgi_cache_item *uci;
int ret = -1;
index = uwsgi_cache_get_index(key, keylen);
if (!index)
index = uwsgi_cache_get_index(key, keylen);
if (index) {
uci = &uwsgi.cache_items[index] ;
uci->keysize = 0;
@@ -177,9 +192,15 @@ int uwsgi_cache_del(char *key, uint16_t keylen) {
if (uci->prev) {
uwsgi.cache_items[uci->prev].next = uci->next;
}
else {
// set next as the new entry point (could be 0)
uwsgi.cache_hashtable[uci->djbhash % 0xffff] = uci->next;
}
if (uci->next) {
uwsgi.cache_items[uci->next].prev = uci->prev;
}
if (!uci->prev && !uci->next) {
// reset hashtable entry
//uwsgi_log("!!! resetted hashtable entry !!!\n");
@@ -188,6 +209,7 @@ int uwsgi_cache_del(char *key, uint16_t keylen) {
uci->djbhash = 0;
uci->prev = 0;
uci->next = 0;
uci->expires = 0;
}
return ret;
@@ -247,7 +269,7 @@ int uwsgi_cache_set(char *key, uint16_t keylen, char *val, uint64_t vallen, uint
}
}
uci = &uwsgi.cache_items[index] ;
if (expires) expires += time(NULL);
if (expires) expires += uwsgi_now();
uci->expires = expires;
uci->djbhash = djb33x_hash(key, keylen);
uci->hits = 0;
@@ -262,6 +284,9 @@ int uwsgi_cache_set(char *key, uint16_t keylen, char *val, uint64_t vallen, uint
ret = 0;
// now put the value in the 16bit hashtable
slot = uci->djbhash % 0xffff;
// reset values
uci->prev = 0;
uci->next = 0;
if (uwsgi.cache_hashtable[slot] == 0) {
uwsgi.cache_hashtable[slot] = index;
@@ -282,7 +307,7 @@ int uwsgi_cache_set(char *key, uint16_t keylen, char *val, uint64_t vallen, uint
else if (flags & UWSGI_CACHE_FLAG_UPDATE) {
uci = &uwsgi.cache_items[index] ;
if (expires) {
expires += time(NULL);
expires += uwsgi_now();
uci->expires = expires;
}
memcpy(uwsgi.cache+(index*uwsgi.cache_blocksize), val, vallen);
+46
View File
@@ -0,0 +1,46 @@
#include "uwsgi.h"
extern struct uwsgi_server uwsgi;
// in the future we will need to use the best clock source for each os/system
time_t uwsgi_now() {
return uwsgi.clock->seconds();
}
uint64_t uwsgi_micros() {
return uwsgi.clock->microseconds();
}
void uwsgi_register_clock(struct uwsgi_clock *clock) {
struct uwsgi_clock *clocks = uwsgi.clocks;
clock->next = NULL;
if (!clocks) {
uwsgi.clocks = clock;
return;
}
while(clocks) {
if (!clocks->next) {
clocks->next = clock;
return;
}
clocks = clocks->next;
}
}
void uwsgi_set_clock(char *name) {
struct uwsgi_clock *clocks = uwsgi.clocks;
while(clocks) {
if (!strcmp(name, clocks->name)) {
uwsgi.clock = clocks;
return;
}
clocks = clocks->next;
}
uwsgi_log("unable to set \"%s\" clock\n", name);
exit(1);
}
+105 -4
View File
@@ -40,7 +40,7 @@ void cluster_setup() {
// receive the packet
char clusterbuf[4096];
if (!uwsgi_hooked_parse_dict_dgram(uwsgi.cluster_fd, clusterbuf, 4096, 99, 1, cluster_manage_opt, NULL)) {
uwsgi_configure(-1);
uwsgi_configure();
goto options_parsed;
}
else {
@@ -87,7 +87,7 @@ void uwsgi_cluster_add_node(struct uwsgi_cluster_node *nucn, int type) {
if (ucn->name[0] != 0) {
if (!strcmp(ucn->name, nucn->name)) {
ucn->status = UWSGI_NODE_OK;
ucn->last_seen = time(NULL);
ucn->last_seen = uwsgi_now();
// update requests
ucn->requests = nucn->requests;
return;
@@ -122,7 +122,7 @@ void uwsgi_cluster_add_node(struct uwsgi_cluster_node *nucn, int type) {
if (type != CLUSTER_NODE_DYNAMIC && tcp_port) {
tcp_port[0] = ':';
}
ucn->last_seen = time(NULL);
ucn->last_seen = uwsgi_now();
ucn->requests = nucn->requests;
uwsgi_log("[uWSGI cluster] added node %s\n", ucn->name);
return;
@@ -324,7 +324,7 @@ char *uwsgi_cluster_best_node() {
return NULL;
}
uwsgi.shared->nodes[best_node].last_choosen = time(NULL);
uwsgi.shared->nodes[best_node].last_choosen = uwsgi_now();
return uwsgi.shared->nodes[best_node].name;
}
@@ -359,5 +359,106 @@ void manage_cluster_announce(char *key, uint16_t keylen, char *val, uint16_t val
}
}
void manage_cluster_message(char *cluster_opt_buf, int cluster_opt_size) {
struct uwsgi_cluster_node nucn;
switch (uwsgi.workers[0].cores[0].req.uh.modifier1) {
case 95:
memset(&nucn, 0, sizeof(struct uwsgi_cluster_node));
#ifdef __BIG_ENDIAN__
uwsgi.workers[0].cores[0].req.uh.pktsize = uwsgi_swap16(uwsgi.wsgi_requests[0]->uh.pktsize);
#endif
uwsgi_hooked_parse(uwsgi.workers[0].cores[0].req.buffer, uwsgi.workers[0].cores[0].req.uh.pktsize, manage_cluster_announce, &nucn);
if (nucn.name[0] != 0) {
uwsgi_cluster_add_node(&nucn, CLUSTER_NODE_DYNAMIC);
}
break;
case 96:
#ifdef __BIG_ENDIAN__
uwsgi.workers[0].cores[0].req.uh.pktsize = uwsgi_swap16(uwsgi.wsgi_requests[0]->uh.pktsize);
#endif
uwsgi_log_verbose("%.*s\n", uwsgi.workers[0].cores[0].req.uh.pktsize, uwsgi.workers[0].cores[0].req.buffer);
break;
case 98:
if (kill(getpid(), SIGHUP)) {
uwsgi_error("kill()");
}
break;
case 99:
if (uwsgi.cluster_nodes)
break;
if (uwsgi.workers[0].cores[0].req.uh.modifier2 == 0) {
uwsgi_log("requested configuration data, sending %d bytes\n", cluster_opt_size);
sendto(uwsgi.cluster_fd, cluster_opt_buf, cluster_opt_size, 0, (struct sockaddr *) &uwsgi.mc_cluster_addr, sizeof(uwsgi.mc_cluster_addr));
}
break;
case 73:
#ifdef __BIG_ENDIAN__
uwsgi.workers[0].cores[0].req.uh.pktsize = uwsgi_swap16(uwsgi.workers[0].cores[0].req.uh.pktsize);
#endif
uwsgi_log_verbose("[uWSGI cluster %s] new node available: %.*s\n", uwsgi.cluster, uwsgi.workers[0].cores[0].req.uh.pktsize, uwsgi.workers[0].cores[0].req.buffer);
break;
}
}
#endif
char *uwsgi_setup_clusterbuf(size_t *size) {
size_t cluster_opt_size = 4;
int i;
for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
//uwsgi_log("%s\n", uwsgi.exported_opts[i]->key);
cluster_opt_size += 2 + strlen(uwsgi.exported_opts[i]->key);
if (uwsgi.exported_opts[i]->value) {
cluster_opt_size += 2 + strlen(uwsgi.exported_opts[i]->value);
}
else {
cluster_opt_size += 2 + 1;
}
}
//uwsgi_log("cluster opts size: %d\n", cluster_opt_size);
char *cluster_opt_buf = uwsgi_malloc(cluster_opt_size);
struct uwsgi_header *uh = (struct uwsgi_header *) cluster_opt_buf;
uh->modifier1 = 99;
uh->pktsize = cluster_opt_size - 4;
uh->modifier2 = 1;
#ifdef __BIG_ENDIAN__
uh->pktsize = uwsgi_swap16(uh->pktsize);
#endif
char *cptrbuf = cluster_opt_buf + 4;
for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
//uwsgi_log("%s\n", uwsgi.exported_opts[i]->key);
uint16_t ustrlen = strlen(uwsgi.exported_opts[i]->key);
*cptrbuf++ = (uint8_t) (ustrlen & 0xff);
*cptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(cptrbuf, uwsgi.exported_opts[i]->key, ustrlen);
cptrbuf += ustrlen;
if (uwsgi.exported_opts[i]->value) {
ustrlen = strlen(uwsgi.exported_opts[i]->value);
*cptrbuf++ = (uint8_t) (ustrlen & 0xff);
*cptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
memcpy(cptrbuf, uwsgi.exported_opts[i]->value, ustrlen);
}
else {
ustrlen = 1;
*cptrbuf++ = (uint8_t) (ustrlen & 0xff);
*cptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
*cptrbuf = '1';
}
cptrbuf += ustrlen;
}
return cluster_opt_buf;
}
+1376
View File
File diff suppressed because it is too large Load Diff
+55 -3
View File
@@ -42,6 +42,18 @@ int event_queue_fd_write_to_read(int eq, int fd) {
}
int event_queue_fd_read_to_write(int eq, int fd) {
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLOUT, NULL)) {
uwsgi_error("port_associate");
return -1;
}
return fd;
}
int event_queue_interesting_fd_has_error(void *events, int id) {
port_event_t *pe = (port_event_t *) events;
@@ -216,6 +228,23 @@ int event_queue_fd_write_to_read(int eq, int fd) {
return fd;
}
int event_queue_fd_read_to_write(int eq, int fd) {
struct epoll_event ee;
memset(&ee, 0, sizeof(struct epoll_event));
ee.events = EPOLLOUT;
ee.data.fd = fd;
if (epoll_ctl(eq, EPOLL_CTL_MOD, fd, &ee)) {
uwsgi_error("epoll_ctl()");
return -1;
}
return fd;
}
int event_queue_del_fd(int eq, int fd, int event) {
struct epoll_event ee;
@@ -345,6 +374,28 @@ int event_queue_fd_write_to_read(int eq, int fd) {
return fd;
}
int event_queue_fd_read_to_write(int eq, int fd) {
struct kevent kev;
#ifndef __FreeBSD__
EV_SET(&kev, fd, EVFILT_READ, EV_DISABLE, 0, 0, 0);
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
uwsgi_error("kevent()");
return -1;
}
#endif
EV_SET(&kev, fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
uwsgi_error("kevent()");
return -1;
}
return fd;
}
int event_queue_del_fd(int eq, int fd, int event) {
struct kevent kev;
@@ -421,7 +472,8 @@ int event_queue_interesting_fd(void *events, int id) {
int event_queue_interesting_fd_has_error(void *events, int id) {
struct kevent *ev = (struct kevent *) events;
if ( ( (ev[id].flags == EV_ERROR) || (ev[id].flags == EV_EOF) || (ev[id].flags == (EV_EOF|EV_ERROR))) ) {
// DO NOT CHECK FOR EOF !!!
if ( ev[id].flags & EV_ERROR ) {
return 1;
}
return 0;
@@ -874,10 +926,10 @@ struct uwsgi_timer *event_queue_ack_timer(int id) {
}
#endif
inline int event_queue_read() {
int event_queue_read() {
return UWSGI_EVENT_IN;
}
inline int event_queue_write() {
int event_queue_write() {
return UWSGI_EVENT_OUT;
}
+8 -2
View File
@@ -2,7 +2,7 @@
extern struct uwsgi_server uwsgi;
struct uwsgi_gateway *register_gateway(char *name, void (*loop)(int)) {
struct uwsgi_gateway *register_gateway(char *name, void (*loop)(int, void *), void *data) {
struct uwsgi_gateway *ug;
int num=1,i;
@@ -26,6 +26,7 @@ struct uwsgi_gateway *register_gateway(char *name, void (*loop)(int)) {
ug->loop = loop;
ug->num = num;
ug->fullname = fullname;
ug->data = data;
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, ug->internal_subscription_pipe)) {
uwsgi_error("socketpair()");
@@ -70,8 +71,10 @@ void gateway_respawn(int id) {
signal(SIGUSR1, SIG_IGN);
signal(SIGUSR2, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
signal(SIGSTOP, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
ug->loop(id);
ug->loop(id, ug->data);
// never here !!! (i hope)
exit(1);
}
@@ -107,7 +110,9 @@ struct uwsgi_gateway_socket *uwsgi_new_gateway_socket(char *name, char *owner) {
memset(uwsgi_sock, 0, sizeof(struct uwsgi_gateway_socket));
uwsgi_sock->fd = -1;
uwsgi_sock->shared = 0;
uwsgi_sock->name = name;
uwsgi_sock->name_len = strlen(name);
uwsgi_sock->owner = owner;
return uwsgi_sock;
@@ -134,6 +139,7 @@ struct uwsgi_gateway_socket *uwsgi_new_gateway_socket_from_fd(int fd, char *owne
memset(uwsgi_sock, 0, sizeof(struct uwsgi_gateway_socket));
uwsgi_sock->fd = fd;
uwsgi_sock->name = uwsgi_getsockname(fd);
uwsgi_sock->name_len = strlen(uwsgi_sock->name);
uwsgi_sock->owner = owner;
return uwsgi_sock;
View File
+282
View File
@@ -0,0 +1,282 @@
#include "uwsgi.h"
extern struct uwsgi_server uwsgi;
void uwsgi_init_default() {
uwsgi.cpus = 1;
uwsgi.backtrace_depth = 64;
uwsgi.max_apps = 64;
uwsgi.master_queue = -1;
uwsgi.signal_socket = -1;
uwsgi.my_signal_socket = -1;
uwsgi.cache_server_fd = -1;
uwsgi.stats_fd = -1;
uwsgi.original_log_fd = -1;
uwsgi.emperor_fd_config = -1;
// default emperor scan frequency
uwsgi.emperor_freq = 3;
uwsgi.emperor_throttle = 1000;
uwsgi.emperor_heartbeat = 30;
// max 3 minutes throttling
uwsgi.emperor_max_throttle = 1000 * 180;
uwsgi.emperor_pid = -1;
uwsgi.subscribe_freq = 10;
uwsgi.subscription_tolerance = 17;
uwsgi.cluster_fd = -1;
uwsgi.cores = 1;
uwsgi.threads = 1;
uwsgi.default_app = -1;
uwsgi.buffer_size = 4096;
uwsgi.numproc = 1;
uwsgi.forkbomb_delay = 2;
uwsgi.async = 1;
uwsgi.listen_queue = 100;
uwsgi.cheaper_overload = 3;
uwsgi.log_master_bufsize = 8192;
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;
#ifdef UWSGI_SPOOLER
uwsgi.shared->spooler_frequency = 30;
uwsgi.shared->spooler_signal_pipe[0] = -1;
uwsgi.shared->spooler_signal_pipe[1] = -1;
#endif
uwsgi.shared->mule_signal_pipe[0] = -1;
uwsgi.shared->mule_signal_pipe[1] = -1;
uwsgi.shared->mule_queue_pipe[0] = -1;
uwsgi.shared->mule_queue_pipe[1] = -1;
uwsgi.shared->worker_log_pipe[0] = -1;
uwsgi.shared->worker_log_pipe[1] = -1;
#ifdef UWSGI_SSL
// 1 day of tolerance
uwsgi.subscriptions_sign_check_tolerance = 3600 * 24;
#endif
}
void uwsgi_setup_reload() {
char env_reload_buf[11];
char *env_reloads = getenv("UWSGI_RELOADS");
if (env_reloads) {
//convert env value to int
uwsgi.reloads = atoi(env_reloads);
uwsgi.reloads++;
//convert reloads to string
int rlen = snprintf(env_reload_buf, 10, "%u", uwsgi.reloads);
if (rlen > 0) {
env_reload_buf[rlen] = 0;
if (setenv("UWSGI_RELOADS", env_reload_buf, 1)) {
uwsgi_error("setenv()");
}
}
uwsgi.is_a_reload = 1;
}
else {
if (setenv("UWSGI_RELOADS", "0", 1)) {
uwsgi_error("setenv()");
}
}
}
void uwsgi_autoload_plugins_by_name(char *argv_zero) {
char *plugins_requested = NULL;
char *original_proc_name = getenv("UWSGI_ORIGINAL_PROC_NAME");
if (!original_proc_name) {
// here we use argv[0];
original_proc_name = argv_zero;
setenv("UWSGI_ORIGINAL_PROC_NAME", original_proc_name, 1);
}
char *p = strrchr(original_proc_name, '/');
if (p == NULL)
p = original_proc_name;
p = strstr(p, "uwsgi_");
if (p != NULL) {
plugins_requested = strtok(uwsgi_str(p + 6), "_");
while (plugins_requested) {
uwsgi_log("[uwsgi] implicit plugin requested %s\n", plugins_requested);
uwsgi_load_plugin(-1, plugins_requested, NULL);
plugins_requested = strtok(NULL, "_");
}
}
plugins_requested = getenv("UWSGI_PLUGINS");
if (plugins_requested) {
plugins_requested = uwsgi_concat2(plugins_requested, "");
char *p = strtok(plugins_requested, ",");
while (p != NULL) {
uwsgi_load_plugin(-1, p, NULL);
p = strtok(NULL, ",");
}
}
}
void uwsgi_commandline_config() {
int i;
uwsgi.option_index = -1;
char *optname;
while ((i = getopt_long(uwsgi.argc, uwsgi.argv, uwsgi.short_options, uwsgi.long_options, &uwsgi.option_index)) != -1) {
if (i == '?') {
uwsgi_log("getopt_long() error\n");
exit(1);
}
if (uwsgi.option_index > -1) {
optname = (char *) uwsgi.long_options[uwsgi.option_index].name;
}
else {
optname = uwsgi_get_optname_by_index(i);
}
if (!optname) {
uwsgi_log("unable to parse command line options\n");
exit(1);
}
uwsgi.option_index = -1;
add_exported_option(optname, optarg, 0);
}
#ifdef UWSGI_DEBUG
uwsgi_log("optind:%d argc:%d\n", optind, uwsgi.argc);
#endif
if (optind < uwsgi.argc) {
for (i = optind; i < uwsgi.argc; i++) {
char *lazy = uwsgi.argv[i];
if (lazy[0] != '[') {
uwsgi_opt_load(NULL, lazy, NULL);
// manage magic mountpoint
int magic = 0;
int j;
for (j = 0; j < uwsgi.gp_cnt; j++) {
if (uwsgi.gp[j]->magic) {
if (uwsgi.gp[j]->magic(NULL, lazy)) {
magic = 1;
break;
}
}
}
if (!magic) {
for (j = 0; j < 256; j++) {
if (uwsgi.p[j]->magic) {
if (uwsgi.p[j]->magic(NULL, lazy)) {
magic = 1;
break;
}
}
}
}
}
}
}
}
void uwsgi_setup_workers() {
int i,j;
// allocate shared memory for workers + master
uwsgi.workers = (struct uwsgi_worker *) uwsgi_calloc_shared(sizeof(struct uwsgi_worker) * (uwsgi.numproc + 1 + uwsgi.grunt));
for (i = 0; i <= uwsgi.numproc; i++) {
// allocate memory for apps
uwsgi.workers[i].apps = (struct uwsgi_app *) uwsgi_calloc_shared(sizeof(struct uwsgi_app) * uwsgi.max_apps);
// allocate memory for cores
uwsgi.workers[i].cores = (struct uwsgi_core *) uwsgi_calloc_shared(sizeof(struct uwsgi_core) * uwsgi.cores);
// this is a trick for avoiding too much memory areas
void *ts = uwsgi_calloc_shared(sizeof(void *) * uwsgi.max_apps * uwsgi.cores);
void *buffers = uwsgi_malloc_shared(uwsgi.buffer_size * uwsgi.cores);
void *hvec = uwsgi_malloc_shared(sizeof(struct iovec) * uwsgi.vec_size * uwsgi.cores);
void *post_buf = NULL;
if (uwsgi.post_buffering > 0)
post_buf = uwsgi_malloc_shared(uwsgi.post_buffering_bufsize * uwsgi.cores);
for (j = 0; j < uwsgi.cores; j++) {
// allocate shared memory for thread states (required for some language, like python)
uwsgi.workers[i].cores[j].ts = ts + ((sizeof(void *) * uwsgi.max_apps) * j);
// raw per-request buffer
uwsgi.workers[i].cores[j].buffer = buffers + (uwsgi.buffer_size * j);
// iovec for uwsgi vars
uwsgi.workers[i].cores[j].hvec = hvec + ((sizeof(struct iovec) * uwsgi.vec_size) * j);
if (post_buf)
uwsgi.workers[i].cores[j].post_buf = post_buf + (uwsgi.post_buffering_bufsize *j);
}
// master does not need to following steps...
if (i == 0) continue;
uwsgi.workers[i].signal_pipe[0] = -1;
uwsgi.workers[i].signal_pipe[1] = -1;
snprintf(uwsgi.workers[i].name, 0xff, "uWSGI worker %d", i);
snprintf(uwsgi.workers[i].snapshot_name, 0xff, "uWSGI snapshot %d", i);
}
uint64_t total_memory = (sizeof(struct uwsgi_app) * uwsgi.max_apps) + (sizeof(struct uwsgi_core) * uwsgi.cores) + (sizeof(void *) * uwsgi.max_apps * uwsgi.cores) +
(uwsgi.buffer_size * uwsgi.cores) + (sizeof(struct iovec) * uwsgi.vec_size * uwsgi.cores);
if (uwsgi.post_buffering > 0) {
total_memory += (uwsgi.post_buffering_bufsize * uwsgi.cores);
}
total_memory *= (uwsgi.numproc + uwsgi.master_process);
uwsgi_log("mapped %llu bytes (%llu KB) for %d cores\n", total_memory, total_memory / 1024, uwsgi.cores*uwsgi.numproc);
}
pid_t uwsgi_daemonize2() {
if (uwsgi.has_emperor) {
logto(uwsgi.daemonize2);
}
else {
if (!uwsgi.is_a_reload) {
uwsgi_log("*** daemonizing uWSGI ***\n");
daemonize(uwsgi.daemonize2);
}
else if (uwsgi.log_reopen) {
logto(uwsgi.daemonize2);
}
}
uwsgi.mypid = getpid();
uwsgi.workers[0].pid = uwsgi.mypid;
if (uwsgi.pidfile && !uwsgi.is_a_reload) {
uwsgi_write_pidfile(uwsgi.pidfile);
}
if (uwsgi.pidfile2 && !uwsgi.is_a_reload) {
uwsgi_write_pidfile(uwsgi.pidfile2);
}
return uwsgi.mypid;
}
View File
View File
+185 -25
View File
@@ -24,7 +24,7 @@ static struct uwsgi_lock_item *uwsgi_register_lock(char *id, int rw) {
if (!uli->next) {
uli->next = uwsgi_malloc_shared(sizeof(struct uwsgi_lock_item));
if (rw) {
uwsgi_malloc_shared(uwsgi.rwlock_size);
uli->next->lock_ptr = uwsgi_malloc_shared(uwsgi.rwlock_size);
}
else {
uli->next->lock_ptr = uwsgi_malloc_shared(uwsgi.lock_size);
@@ -45,7 +45,12 @@ static struct uwsgi_lock_item *uwsgi_register_lock(char *id, int rw) {
#ifdef UWSGI_LOCK_USE_MUTEX
#ifdef EOWNERDEAD
#define UWSGI_LOCK_ENGINE_NAME "pthread robust mutexes"
int uwsgi_pthread_robust_mutexes_enabled = 1;
#else
#define UWSGI_LOCK_ENGINE_NAME "pthread mutexes"
#endif
#define UWSGI_LOCK_SIZE sizeof(pthread_mutex_t)
@@ -62,23 +67,51 @@ struct uwsgi_lock_item *uwsgi_lock_fast_init(char *id) {
struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0);
#ifdef EOWNERDEAD
retry:
#endif
if (pthread_mutexattr_init(&attr)) {
uwsgi_log("unable to allocate mutexattr structure\n");
exit(1);
}
if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) {
uwsgi_log("unable to share mutex\n");
exit(1);
}
#ifdef EOWNERDEAD
if (uwsgi_pthread_robust_mutexes_enabled) {
if (pthread_mutexattr_setrobust_np(&attr, PTHREAD_MUTEX_ROBUST_NP)) {
uwsgi_log("unable to make the mutex 'robust'\n");
exit(1);
}
}
#endif
if (pthread_mutex_init((pthread_mutex_t *) uli->lock_ptr, &attr)) {
#ifdef EOWNERDEAD
if (uwsgi_pthread_robust_mutexes_enabled) {
uwsgi_log("!!! it looks like your kernel does not support pthread robust mutexes !!!\n");
uwsgi_log("!!! falling back to standard pthread mutexes !!!\n");
uwsgi_pthread_robust_mutexes_enabled = 0;
pthread_mutexattr_destroy(&attr);
goto retry;
}
#endif
uwsgi_log("unable to initialize mutex\n");
exit(1);
}
pthread_mutexattr_destroy(&attr);
#ifdef EOWNERDEAD
if (!uwsgi_pthread_robust_mutexes_enabled) {
uli->can_deadlock = 1;
}
#else
uli->can_deadlock = 1;
#endif
return uli;
}
@@ -105,6 +138,27 @@ pid_t uwsgi_rwlock_fast_check(struct uwsgi_lock_item *uli) {
#endif
}
void uwsgi_lock_fast(struct uwsgi_lock_item *uli) {
#ifdef EOWNERDEAD
if (pthread_mutex_lock((pthread_mutex_t *) uli->lock_ptr) == EOWNERDEAD) {
uwsgi_log("[deadlock-detector] a process holding a robust mutex died. recovering...\n");
pthread_mutex_consistent_np((pthread_mutex_t *) uli->lock_ptr);
}
#else
pthread_mutex_lock((pthread_mutex_t *) uli->lock_ptr);
#endif
uli->pid = uwsgi.mypid;
}
void uwsgi_unlock_fast(struct uwsgi_lock_item *uli) {
pthread_mutex_unlock((pthread_mutex_t *) uli->lock_ptr);
uli->pid = 0;
}
void uwsgi_rlock_fast(struct uwsgi_lock_item *uli) {
#ifdef OBSOLETE_LINUX_KERNEL
uwsgi_lock_fast(uli);
@@ -132,23 +186,10 @@ void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) {
#endif
}
void uwsgi_lock_fast(struct uwsgi_lock_item *uli) {
pthread_mutex_lock((pthread_mutex_t *) uli->lock_ptr);
uli->pid = uwsgi.mypid;
}
void uwsgi_unlock_fast(struct uwsgi_lock_item *uli) {
pthread_mutex_unlock((pthread_mutex_t *) uli->lock_ptr);
uli->pid = 0;
}
struct uwsgi_lock_item *uwsgi_rwlock_fast_init(char *id) {
#ifdef OBSOLETE_LINUX_KERNEL
return uwsgi_lock_fast_init(uli);
return uwsgi_lock_fast_init(id);
#else
pthread_rwlockattr_t attr;
@@ -159,6 +200,7 @@ struct uwsgi_lock_item *uwsgi_rwlock_fast_init(char *id) {
uwsgi_log("unable to allocate rwlock structure\n");
exit(1);
}
if (pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) {
uwsgi_log("unable to share rwlock\n");
exit(1);
@@ -224,6 +266,47 @@ pid_t uwsgi_lock_fast_check(struct uwsgi_lock_item *uli) {
pid_t uwsgi_rwlock_fast_check(struct uwsgi_lock_item *uli) { return uwsgi_lock_fast_check(uli); }
#elif defined(UWSGI_LOCK_USE_POSIX_SEM)
#define UWSGI_LOCK_SIZE sizeof(sem_t)
#define UWSGI_RWLOCK_SIZE sizeof(sem_t)
#define UWSGI_LOCK_ENGINE_NAME "POSIX semaphores"
#include <semaphore.h>
struct uwsgi_lock_item *uwsgi_lock_fast_init(char *id) {
struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0);
sem_init((sem_t*) uli->lock_ptr, 1, 1);
uli->can_deadlock = 1;
return uli;
}
struct uwsgi_lock_item *uwsgi_rwlock_fast_init(char *id) { return uwsgi_lock_fast_init(id) ;}
void uwsgi_lock_fast(struct uwsgi_lock_item *uli) {
sem_wait((sem_t *) uli->lock_ptr);
uli->pid = uwsgi.mypid;
}
void uwsgi_unlock_fast(struct uwsgi_lock_item *uli) {
sem_post((sem_t*) uli->lock_ptr);
uli->pid = 0;
}
pid_t uwsgi_lock_fast_check(struct uwsgi_lock_item *uli) {
if (sem_trywait((sem_t *) uli->lock_ptr) == 0) {
sem_post((sem_t*) uli->lock_ptr);
return 0;
}
return uli->pid;
}
pid_t uwsgi_rwlock_fast_check(struct uwsgi_lock_item *uli) { return uwsgi_lock_fast_check(uli); }
void uwsgi_rlock_fast(struct uwsgi_lock_item *uli) { uwsgi_lock_fast(uli);}
void uwsgi_wlock_fast(struct uwsgi_lock_item *uli) { uwsgi_lock_fast(uli);}
void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) { uwsgi_unlock_fast(uli); }
#elif defined(UWSGI_LOCK_USE_OSX_SPINLOCK)
#define UWSGI_LOCK_ENGINE_NAME "OSX spinlocks"
@@ -296,25 +379,38 @@ void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) { uwsgi_unlock_fast(uli);
#endif
#include <sys/ipc.h>
#include <sys/sem.h>
struct uwsgi_lock_item *uwsgi_lock_ipcsem_init(char *id) {
// used by ftok
static int counter = 1;
union semun {
int val;
struct semid_ds *buf;
ushort *array;
} semu ;
int semid;
key_t myKey;
struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0);
int semid = semget(IPC_PRIVATE, 1, IPC_CREAT|IPC_EXCL| 0600);
if (uwsgi.ftok) {
myKey = ftok(uwsgi.ftok, counter);
if (myKey < 0) {
uwsgi_error("ftok()");
exit(1);
}
counter++;
semid = semget(myKey, 1, IPC_CREAT|0666);
}
else {
semid = semget(IPC_PRIVATE, 1, IPC_CREAT|IPC_EXCL| 0666);
}
if (semid < 0) {
uwsgi_error("semget()");
exit(1);
}
// do this now, to allows triggering fo atexit hook in case of problems
// do this now, to allows triggering of atexit hook in case of problems
memcpy(uli->lock_ptr, &semid, sizeof(int));
semu.val = 1;
@@ -377,6 +473,8 @@ void uwsgi_ipcsem_clear(void) {
if (uwsgi.master_process && getpid() == uwsgi.workers[0].pid) goto clear;
if (!uwsgi.master_process && uwsgi.mywid == 1) goto clear;
return;
clear:
@@ -400,10 +498,10 @@ pid_t uwsgi_rwlock_ipcsem_check(struct uwsgi_lock_item *uli) { return uwsgi_lock
void uwsgi_setup_locking() {
// use the fastest avaikable locking
// use the fastest available locking
if (uwsgi.lock_engine) {
if (!strcmp(uwsgi.lock_engine, "ipcsem")) {
uwsgi_log("lock engine: ipcsem\n");
uwsgi_log_initial("lock engine: ipcsem\n");
atexit(uwsgi_ipcsem_clear);
uwsgi.lock_ops.lock_init = uwsgi_lock_ipcsem_init;
uwsgi.lock_ops.lock_check = uwsgi_lock_ipcsem_check;
@@ -420,7 +518,7 @@ void uwsgi_setup_locking() {
}
}
uwsgi_log("lock engine: %s\n", UWSGI_LOCK_ENGINE_NAME);
uwsgi_log_initial("lock engine: %s\n", UWSGI_LOCK_ENGINE_NAME);
#ifdef UWSGI_IPCSEM_ATEXIT
atexit(uwsgi_ipcsem_clear);
#endif
@@ -435,13 +533,48 @@ void uwsgi_setup_locking() {
uwsgi.lock_ops.rwunlock = uwsgi_rwunlock_fast;
uwsgi.lock_size = UWSGI_LOCK_SIZE;
uwsgi.rwlock_size = UWSGI_RWLOCK_SIZE;
// application generic lock
int i;
uwsgi.user_lock = uwsgi_malloc(sizeof(void *) * (uwsgi.locks + 1));
for (i = 0; i < uwsgi.locks + 1; i++) {
uwsgi.user_lock[i] = uwsgi_lock_init(uwsgi_concat2("user ", uwsgi_num2str(i)));
}
// event queue lock (mitigate same event on multiple queues)
if (uwsgi.threads > 1) {
pthread_mutex_init(&uwsgi.thunder_mutex, NULL);
}
if (uwsgi.master_process) {
// signal table lock
uwsgi.signal_table_lock = uwsgi_lock_init("signal");
// fmon table lock
uwsgi.fmon_table_lock = uwsgi_lock_init("filemon");
// timer table lock
uwsgi.timer_table_lock = uwsgi_lock_init("timer");
// probe table lock
uwsgi.probe_table_lock = uwsgi_lock_init("probe");
// rb_timer table lock
uwsgi.rb_timer_table_lock = uwsgi_lock_init("rbtimer");
// cron table lock
uwsgi.cron_table_lock = uwsgi_lock_init("cron");
}
uwsgi.rpc_table_lock = uwsgi_lock_init("rpc");
}
int uwsgi_fcntl_lock(int fd) {
struct flock fl;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_CUR;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
fl.l_pid = 0;
@@ -457,7 +590,7 @@ int uwsgi_fcntl_is_locked(int fd) {
struct flock fl;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_CUR;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
fl.l_pid = 0;
@@ -469,3 +602,30 @@ int uwsgi_fcntl_is_locked(int fd) {
return 0;
}
void uwsgi_deadlock_check(pid_t diedpid) {
struct uwsgi_lock_item *uli = uwsgi.registered_locks;
while (uli) {
if (!uli->can_deadlock)
goto nextlock;
pid_t locked_pid = 0;
if (uli->rw) {
locked_pid = uwsgi_rwlock_check(uli);
}
else {
locked_pid = uwsgi_lock_check(uli);
}
if (locked_pid == diedpid) {
uwsgi_log("[deadlock-detector] pid %d was holding lock %s (%p)\n", (int) diedpid, uli->id, uli->lock_ptr);
if (uli->rw) {
uwsgi_rwunlock(uli);
}
else {
uwsgi_unlock(uli);
}
}
nextlock:
uli = uli->next;
}
}
+1009
View File
File diff suppressed because it is too large Load Diff
+122
View File
@@ -0,0 +1,122 @@
#include "uwsgi.h"
extern struct uwsgi_server uwsgi;
struct wsgi_request *threaded_current_wsgi_req() {
return pthread_getspecific(uwsgi.tur_key);
}
struct wsgi_request *simple_current_wsgi_req() {
return uwsgi.wsgi_req;
}
void uwsgi_register_loop(char *name, void *loop) {
if (uwsgi.loops_cnt >= MAX_LOOPS) {
uwsgi_log("you can define %d loops at max\n", MAX_LOOPS);
exit(1);
}
uwsgi.loops[uwsgi.loops_cnt].name = name;
uwsgi.loops[uwsgi.loops_cnt].loop = loop;
uwsgi.loops_cnt++;
}
void *uwsgi_get_loop(char *name) {
int i;
for (i = 0; i < uwsgi.loops_cnt; i++) {
if (!strcmp(name, uwsgi.loops[i].name)) {
return uwsgi.loops[i].loop;
}
}
return NULL;
}
void *simple_loop(void *arg1) {
long core_id = (long) arg1;
struct wsgi_request *wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[core_id].req;
#ifdef UWSGI_THREADING
int i;
sigset_t smask;
if (uwsgi.threads > 1) {
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &i);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &i);
pthread_setspecific(uwsgi.tur_key, (void *) wsgi_req);
if (core_id > 0) {
// block all signals on new threads
sigfillset(&smask);
#ifdef UWSGI_DEBUG
sigdelset(&smask, SIGSEGV);
#endif
pthread_sigmask(SIG_BLOCK, &smask, NULL);
// run per-thread socket hook
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while(uwsgi_sock) {
if (uwsgi_sock->proto_thread_fixup) {
uwsgi_sock->proto_thread_fixup(uwsgi_sock, core_id);
}
uwsgi_sock = uwsgi_sock->next;
}
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->init_thread) {
uwsgi.p[i]->init_thread(core_id);
}
}
}
}
#endif
// initialize the main event queue to monitor sockets
int main_queue = event_queue_init();
uwsgi_add_sockets_to_queue(main_queue, core_id);
if (uwsgi.signal_socket > -1) {
event_queue_add_fd_read(main_queue, uwsgi.signal_socket);
event_queue_add_fd_read(main_queue, uwsgi.my_signal_socket);
}
// ok we are ready, let's start managing requests and signals
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
wsgi_req_setup(wsgi_req, core_id, NULL);
if (wsgi_req_accept(main_queue, wsgi_req)) {
continue;
}
if (wsgi_req_recv(wsgi_req)) {
uwsgi_destroy_request(wsgi_req);
continue;
}
uwsgi_close_request(wsgi_req);
}
// end of the loop
if (uwsgi.workers[uwsgi.mywid].destroy && uwsgi.workers[0].pid > 0) {
#ifdef __APPLE__
kill(uwsgi.workers[0].pid, SIGTERM);
#else
if (uwsgi.propagate_touch) {
kill(uwsgi.workers[0].pid, SIGHUP);
}
else {
gracefully_kill(0);
}
#endif
}
return NULL;
}
+520 -503
View File
File diff suppressed because it is too large Load Diff
+412 -133
View File
@@ -5,9 +5,47 @@ extern struct uwsgi_server uwsgi;
void worker_wakeup() {
}
void uwsgi_master_cleanup_hooks(void) {
int j;
// could be an inherited atexit hook
if (uwsgi.mywid > 0) return ;
uwsgi.cleaning = 1;
for (j = 0; j < uwsgi.gp_cnt; j++) {
if (uwsgi.gp[j]->master_cleanup) {
uwsgi.gp[j]->master_cleanup();
}
}
for (j = 0; j < 256; j++) {
if (uwsgi.p[j]->master_cleanup) {
uwsgi.p[j]->master_cleanup();
}
}
}
int uwsgi_calc_cheaper(void) {
int i;
static time_t last_check = 0;
int check_interval = uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL];
if (!last_check)
last_check = uwsgi_now();
time_t now = uwsgi_now();
if (!check_interval)
check_interval = 1;
if ((now - last_check) < check_interval)
return 1;
last_check = now;
int needed_workers = uwsgi.cheaper_algo();
@@ -103,7 +141,7 @@ int uwsgi_cheaper_algo_spare(void) {
overload_count++;
idle_count = 0;
healthy:
healthy:
// are we overloaded ?
if (overload_count > uwsgi.cheaper_overload) {
@@ -178,24 +216,24 @@ int uwsgi_cheaper_algo_backlog(void) {
int i;
#ifdef __linux__
int backlog = uwsgi.shared->ti.tcpi_unacked;
int backlog = uwsgi.shared->options[UWSGI_OPTION_BACKLOG_STATUS];
#else
int backlog = 0;
#endif
if (backlog > (int)uwsgi.cheaper_overload) {
if (backlog > (int) uwsgi.cheaper_overload) {
// activate the first available worker (taking step into account)
int decheaped = 0;
// search for cheaped workers
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].cheaped == 1 && uwsgi.workers[i].pid == 0) {
decheaped++;
if (decheaped >= uwsgi.cheaper_step)
break;
}
}
// return the maximum number of workers to spawn
return decheaped;
int decheaped = 0;
// search for cheaped workers
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].cheaped == 1 && uwsgi.workers[i].pid == 0) {
decheaped++;
if (decheaped >= uwsgi.cheaper_step)
break;
}
}
// return the maximum number of workers to spawn
return decheaped;
}
else if (backlog < (int) uwsgi.cheaper_overload) {
@@ -210,7 +248,7 @@ int uwsgi_cheaper_algo_backlog(void) {
return -1;
}
}
return 0;
}
@@ -226,6 +264,12 @@ void uwsgi_reload(char **argv) {
waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
}
// call master cleanup hooks
uwsgi_master_cleanup_hooks();
// call atexit user exec
uwsgi_exec_atexit();
if (uwsgi.exit_on_reload) {
uwsgi_log("uWSGI: GAME OVER (insert coin)\n");
exit(0);
@@ -238,8 +282,8 @@ void uwsgi_reload(char **argv) {
}
/* check fd table (a module can obviosly open some fd on initialization...) */
uwsgi_log("closing all non-uwsgi socket fds > 2 (max_fd = %d)...\n", (int)uwsgi.max_fd);
for (i = 3; i < (int)uwsgi.max_fd; i++) {
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++) {
int found = 0;
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
@@ -252,6 +296,17 @@ void uwsgi_reload(char **argv) {
uwsgi_sock = uwsgi_sock->next;
}
uwsgi_sock = uwsgi.shared_sockets;
while (uwsgi_sock) {
if (i == uwsgi_sock->fd) {
uwsgi_log("found fd %d mapped to shared socket %d (%s)\n", i, uwsgi_get_shared_socket_num(uwsgi_sock), uwsgi_sock->name);
found = 1;
break;
}
uwsgi_sock = uwsgi_sock->next;
}
if (!found) {
if (uwsgi.has_emperor) {
if (i == uwsgi.emperor_fd) {
@@ -278,7 +333,7 @@ void uwsgi_reload(char **argv) {
found = 1;
}
}
}
if (!found) {
@@ -371,7 +426,10 @@ void uwsgi_fixup_fds(int wid, int muleid, struct uwsgi_gateway *ug) {
ugs = ugs->next;
continue;
}
close(ugs->fd);
// do not close shared sockets !!!
if (!ugs->shared) {
close(ugs->fd);
}
ugs = ugs->next;
}
// fix the communication pipe
@@ -450,6 +508,7 @@ int uwsgi_respawn_worker(int wid) {
uwsgi.workers[uwsgi.mywid].pid = uwsgi.mypid;
uwsgi.workers[uwsgi.mywid].id = uwsgi.mywid;
uwsgi.workers[uwsgi.mywid].harakiri = 0;
uwsgi.workers[uwsgi.mywid].user_harakiri = 0;
uwsgi.workers[uwsgi.mywid].rss_size = 0;
uwsgi.workers[uwsgi.mywid].vsz_size = 0;
@@ -475,7 +534,7 @@ int uwsgi_respawn_worker(int wid) {
if (uwsgi.master_process) {
if ((uwsgi.workers[uwsgi.mywid].respawn_count || uwsgi.cheap)) {
for (i = 0; i < 0xFF; i++) {
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->master_fixup) {
uwsgi.p[i]->master_fixup(1);
}
@@ -530,20 +589,36 @@ void uwsgi_manage_signal_cron(time_t now) {
uc_month = ucron->month;
uc_week = ucron->week;
if (ucron->minute == -1)
uc_minute = uwsgi_cron_delta->tm_min;
if (ucron->hour == -1)
uc_hour = uwsgi_cron_delta->tm_hour;
if (ucron->month == -1)
uc_month = uwsgi_cron_delta->tm_mon;
if (ucron->day == -1)
uc_day = uwsgi_cron_delta->tm_mday;
if (ucron->week == -1)
uc_week = uwsgi_cron_delta->tm_wday;
// negative values as interval -1 = * , -5 = */5
if (ucron->minute < 0) {
if ((uwsgi_cron_delta->tm_min % abs(ucron->minute)) == 0) {
uc_minute = uwsgi_cron_delta->tm_min;
}
}
if (ucron->hour < 0) {
if ((uwsgi_cron_delta->tm_hour % abs(ucron->hour)) == 0) {
uc_hour = uwsgi_cron_delta->tm_hour;
}
}
if (ucron->month < 0) {
if ((uwsgi_cron_delta->tm_mon % abs(ucron->month)) == 0) {
uc_month = uwsgi_cron_delta->tm_mon;
}
}
if (ucron->day < 0) {
if ((uwsgi_cron_delta->tm_mday % abs(ucron->day)) == 0) {
uc_day = uwsgi_cron_delta->tm_mday;
}
}
if (ucron->week < 0) {
if ((uwsgi_cron_delta->tm_wday % abs(ucron->week)) == 0) {
uc_week = uwsgi_cron_delta->tm_wday;
}
}
int run_task = 0;
// mday and wday are ORed
if (ucron->day != -1 && ucron->week != -1) {
if (ucron->day >= 0 && ucron->week >= 0) {
if (uwsgi_cron_delta->tm_min == uc_minute && uwsgi_cron_delta->tm_hour == uc_hour && uwsgi_cron_delta->tm_mon == uc_month && (uwsgi_cron_delta->tm_mday == uc_day || uwsgi_cron_delta->tm_wday == uc_week)) {
run_task = 1;
}
@@ -587,8 +662,10 @@ void uwsgi_manage_command_cron(time_t now) {
return;
}
while (current_cron) {
// fix month
uwsgi_cron_delta->tm_mon++;
while (current_cron) {
uc_minute = current_cron->minute;
uc_hour = current_cron->hour;
@@ -596,20 +673,36 @@ void uwsgi_manage_command_cron(time_t now) {
uc_month = current_cron->month;
uc_week = current_cron->week;
if (current_cron->minute == -1)
uc_minute = uwsgi_cron_delta->tm_min;
if (current_cron->hour == -1)
uc_hour = uwsgi_cron_delta->tm_hour;
if (current_cron->month == -1)
uc_month = uwsgi_cron_delta->tm_mon;
if (current_cron->day == -1)
uc_day = uwsgi_cron_delta->tm_mday;
if (current_cron->week == -1)
uc_week = uwsgi_cron_delta->tm_wday;
// negative values as interval -1 = * , -5 = */5
if (current_cron->minute < 0) {
if ((uwsgi_cron_delta->tm_min % abs(current_cron->minute)) == 0) {
uc_minute = uwsgi_cron_delta->tm_min;
}
}
if (current_cron->hour < 0) {
if ((uwsgi_cron_delta->tm_hour % abs(current_cron->hour)) == 0) {
uc_hour = uwsgi_cron_delta->tm_hour;
}
}
if (current_cron->month < 0) {
if ((uwsgi_cron_delta->tm_hour % abs(current_cron->month)) == 0) {
uc_month = uwsgi_cron_delta->tm_mon;
}
}
if (current_cron->day < 0) {
if ((uwsgi_cron_delta->tm_mday % abs(current_cron->day)) == 0) {
uc_day = uwsgi_cron_delta->tm_mday;
}
}
if (current_cron->week < 0) {
if ((uwsgi_cron_delta->tm_wday % abs(current_cron->week)) == 0) {
uc_week = uwsgi_cron_delta->tm_wday;
}
}
int run_task = 0;
// mday and wday are ORed
if (current_cron->day != -1 && current_cron->week != -1) {
if (current_cron->day >= 0 && current_cron->week >= 0) {
if (uwsgi_cron_delta->tm_min == uc_minute && uwsgi_cron_delta->tm_hour == uc_hour && uwsgi_cron_delta->tm_mon == uc_month && (uwsgi_cron_delta->tm_mday == uc_day || uwsgi_cron_delta->tm_wday == uc_week)) {
run_task = 1;
}
@@ -643,184 +736,370 @@ void uwsgi_manage_command_cron(time_t now) {
}
#define stats_send_llu(x, y) fprintf(output, x, (long long unsigned int) y)
#define stats_send(x, y) fprintf(output, x, y)
void uwsgi_send_stats(int fd) {
int i, j;
struct sockaddr_un client_src;
struct uwsgi_app *ua;
socklen_t client_src_len = 0;
int client_fd = accept(fd, (struct sockaddr *) &client_src, &client_src_len);
if (client_fd < 0) {
uwsgi_error("accept()");
return;
}
FILE *output = fdopen(client_fd, "w");
if (!output) {
uwsgi_error("fdopen()");
close(client_fd);
return;
}
struct uwsgi_stats *us = uwsgi_stats_new(8192);
stats_send("{ \"version\": \"%s\",\n", UWSGI_VERSION);
if (uwsgi_stats_keyval_comma(us, "version", UWSGI_VERSION))
goto end;
#ifdef __linux__
stats_send_llu("\"listen_queue\": %llu,\n", uwsgi.shared->ti.tcpi_unacked);
if (uwsgi_stats_keylong_comma(us, "listen_queue", (unsigned long long) uwsgi.shared->options[UWSGI_OPTION_BACKLOG_STATUS]))
goto end;
if (uwsgi_stats_keylong_comma(us, "listen_queue_errors", (unsigned long long) uwsgi.shared->options[UWSGI_OPTION_BACKLOG_ERRORS]))
goto end;
#endif
stats_send_llu("\"load\": %llu,\n", uwsgi.shared->load);
fprintf(output, "\"pid\": %d,\n", (int) (getpid()));
fprintf(output, "\"uid\": %d,\n", (int) (getuid()));
fprintf(output, "\"gid\": %d,\n", (int) (getgid()));
if (uwsgi_stats_keylong_comma(us, "load", (unsigned long long) uwsgi.shared->load))
goto end;
if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) getpid()))
goto end;
if (uwsgi_stats_keylong_comma(us, "uid", (unsigned long long) getuid()))
goto end;
if (uwsgi_stats_keylong_comma(us, "gid", (unsigned long long) getgid()))
goto end;
char *cwd = uwsgi_get_cwd();
stats_send("\"cwd\": \"%s\",\n", cwd);
free(cwd);
if (uwsgi_stats_keyval_comma(us, "cwd", cwd))
goto end0;
if (uwsgi.daemons) {
fprintf(output, "\"daemons\": [\n");
if (uwsgi_stats_key(us, "daemons"))
goto end0;
if (uwsgi_stats_list_open(us))
goto end0;
struct uwsgi_daemon *ud = uwsgi.daemons;
while (ud) {
fprintf(output, "\t{ \"cmd\": \"%s\", \"pid\": %d, \"respawns\": %llu }", ud->command, (int) ud->pid, (unsigned long long) ud->respawns - 1);
if (ud->next)
fprintf(output, ",\n");
else {
fprintf(output, "\n");
if (uwsgi_stats_object_open(us))
goto end0;
if (uwsgi_stats_keyval_comma(us, "cmd", ud->command))
goto end0;
if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) ud->pid))
goto end0;
if (uwsgi_stats_keylong(us, "respawns", (unsigned long long) (ud->respawns - 1)))
goto end0;
if (uwsgi_stats_object_close(us))
goto end0;
if (ud->next) {
if (uwsgi_stats_comma(us))
goto end0;
}
ud = ud->next;
}
fprintf(output, "],\n");
if (uwsgi_stats_list_close(us))
goto end0;
if (uwsgi_stats_comma(us))
goto end0;
}
fprintf(output, "\"locks\": [\n");
if (uwsgi_stats_key(us, "locks"))
goto end0;
if (uwsgi_stats_list_open(us))
goto end0;
struct uwsgi_lock_item *uli = uwsgi.registered_locks;
while (uli) {
if (uwsgi_stats_object_open(us))
goto end0;
if (uwsgi_stats_keylong(us, uli->id, (unsigned long long) uli->pid))
goto end0;
if (uwsgi_stats_object_close(us))
goto end0;
if (uli->next) {
fprintf(output, "\t{ \"%s\": %d },\n", uli->id, (int) uli->pid);
}
else {
fprintf(output, "\t{ \"%s\": %d }\n", uli->id, (int) uli->pid);
if (uwsgi_stats_comma(us))
goto end0;
}
uli = uli->next;
}
fprintf(output, "],\n");
if (uwsgi_stats_list_close(us))
goto end0;
if (uwsgi_stats_comma(us))
goto end0;
fprintf(output, "\"workers\": [\n");
if (uwsgi_stats_key(us, "workers"))
goto end0;
if (uwsgi_stats_list_open(us))
goto end0;
for (i = 0; i < uwsgi.numproc; i++) {
fprintf(output, "\t{");
if (uwsgi_stats_object_open(us))
goto end0;
fprintf(output, "\"id\": %d, ", uwsgi.workers[i + 1].id);
fprintf(output, "\"pid\": %d, ", (int) uwsgi.workers[i + 1].pid);
stats_send_llu("\"requests\": %llu, ", uwsgi.workers[i + 1].requests);
stats_send_llu("\"delta_requests\": %llu, ", uwsgi.workers[i + 1].delta_requests);
stats_send_llu("\"exceptions\": %llu, ", uwsgi.workers[i + 1].exceptions);
stats_send_llu("\"signals\": %llu, ", uwsgi.workers[i + 1].signals);
if (uwsgi_stats_keylong_comma(us, "id", (unsigned long long) uwsgi.workers[i + 1].id))
goto end0;
if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) uwsgi.workers[i + 1].pid))
goto end0;
if (uwsgi_stats_keylong_comma(us, "requests", (unsigned long long) uwsgi.workers[i + 1].requests))
goto end0;
if (uwsgi_stats_keylong_comma(us, "delta_requests", (unsigned long long) uwsgi.workers[i + 1].delta_requests))
goto end0;
if (uwsgi_stats_keylong_comma(us, "exceptions", (unsigned long long) uwsgi.workers[i + 1].exceptions))
goto end0;
if (uwsgi_stats_keylong_comma(us, "harakiri_count", (unsigned long long) uwsgi.workers[i + 1].harakiri_count))
goto end0;
if (uwsgi_stats_keylong_comma(us, "signals", (unsigned long long) uwsgi.workers[i + 1].signals))
goto end0;
if (uwsgi_stats_keylong_comma(us, "static_offload_threads", (unsigned long long) uwsgi.workers[i + 1].static_offload_threads))
goto end0;
if (uwsgi.workers[i + 1].cheaped) {
fprintf(output, "\"status\": \"cheap\", ");
if (uwsgi_stats_keyval_comma(us, "status", "cheap"))
goto end0;
}
else if (uwsgi.workers[i + 1].suspended && !uwsgi.workers[i + 1].busy) {
fprintf(output, "\"status\": \"pause\", ");
if (uwsgi_stats_keyval_comma(us, "status", "pause"))
goto end0;
}
else {
if (uwsgi.workers[i + 1].sig) {
fprintf(output, "\"status\": \"sig%d\", ", uwsgi.workers[i + 1].signum);
if (uwsgi_stats_keyvalnum_comma(us, "status", "sig", (unsigned long long) uwsgi.workers[i + 1].signum))
goto end0;
}
else if (uwsgi.workers[i + 1].busy) {
fprintf(output, "\"status\": \"busy\", ");
if (uwsgi_stats_keyval_comma(us, "status", "busy"))
goto end0;
}
else {
fprintf(output, "\"status\": \"idle\", ");
if (uwsgi_stats_keyval_comma(us, "status", "idle"))
goto end0;
}
}
stats_send_llu("\"rss\": %llu, ", uwsgi.workers[i + 1].rss_size);
stats_send_llu("\"vsz\": %llu, ", uwsgi.workers[i + 1].vsz_size);
if (uwsgi_stats_keylong_comma(us, "rss", (unsigned long long) uwsgi.workers[i + 1].rss_size))
goto end0;
if (uwsgi_stats_keylong_comma(us, "vsz", (unsigned long long) uwsgi.workers[i + 1].vsz_size))
goto end0;
stats_send_llu("\"running_time\": %llu, ", uwsgi.workers[i + 1].running_time);
stats_send_llu("\"last_spawn\": %llu, ", uwsgi.workers[i + 1].last_spawn);
stats_send_llu("\"respawn_count\": %llu, ", uwsgi.workers[i + 1].respawn_count);
stats_send_llu("\"tx\": %llu, ", uwsgi.workers[i + 1].tx);
stats_send_llu("\"avg_rt\": %llu, ", uwsgi.workers[i + 1].avg_response_time);
if (uwsgi_stats_keylong_comma(us, "running_time", (unsigned long long) uwsgi.workers[i + 1].running_time))
goto end0;
if (uwsgi_stats_keylong_comma(us, "last_spawn", (unsigned long long) uwsgi.workers[i + 1].last_spawn))
goto end0;
if (uwsgi_stats_keylong_comma(us, "respawn_count", (unsigned long long) uwsgi.workers[i + 1].respawn_count))
goto end0;
if (uwsgi_stats_keylong_comma(us, "tx", (unsigned long long) uwsgi.workers[i + 1].tx))
goto end0;
if (uwsgi_stats_keylong_comma(us, "avg_rt", (unsigned long long) uwsgi.workers[i + 1].avg_response_time))
goto end0;
// applications list
if (uwsgi_stats_key(us, "apps"))
goto end0;
if (uwsgi_stats_list_open(us))
goto end0;
fprintf(output, "\"apps\": [\n");
for (j = 0; j < uwsgi.workers[i + 1].apps_cnt; j++) {
ua = &uwsgi.workers[i + 1].apps[j];
fprintf(output, "\t\t{ ");
fprintf(output, "\"id\": %d, ", j);
fprintf(output, "\"modifier1\": %d, ", ua->modifier1);
fprintf(output, "\"mountpoint\": \"%.*s\", ", ua->mountpoint_len, ua->mountpoint);
if (uwsgi_stats_object_open(us))
goto end0;
if (uwsgi_stats_keylong_comma(us, "id", (unsigned long long) j))
goto end0;
if (uwsgi_stats_keylong_comma(us, "modifier1", (unsigned long long) ua->modifier1))
goto end0;
if (uwsgi_stats_keyvaln_comma(us, "mountpoint", ua->mountpoint, ua->mountpoint_len))
goto end0;
if (uwsgi_stats_keylong_comma(us, "startup_time", ua->startup_time))
goto end0;
stats_send_llu("\"startup_time\": %llu, ", ua->startup_time);
stats_send_llu("\"requests\": %llu, ", ua->requests);
stats_send_llu("\"exceptions\": %llu, ", ua->exceptions);
if (uwsgi_stats_keylong_comma(us, "requests", ua->requests))
goto end0;
if (uwsgi_stats_keylong_comma(us, "exceptions", ua->exceptions))
goto end0;
if (ua->chdir) {
fprintf(output, "\"chdir\": \"%s\", ", ua->chdir);
if (uwsgi_stats_keyval(us, "chdir", ua->chdir))
goto end0;
}
else {
fprintf(output, "\"chdir\": \"\" ");
if (uwsgi_stats_keyval(us, "chdir", ""))
goto end0;
}
if (j == uwsgi.workers[i + 1].apps_cnt - 1) {
fprintf(output, "}\n");
}
else {
fprintf(output, "},\n");
if (uwsgi_stats_object_close(us))
goto end0;
if (j < uwsgi.workers[i + 1].apps_cnt - 1) {
if (uwsgi_stats_comma(us))
goto end0;
}
}
fprintf(output, "\t\t]");
if (i == uwsgi.numproc - 1) {
fprintf(output, "}\n");
if (uwsgi_stats_list_close(us))
goto end0;
if (uwsgi_stats_comma(us))
goto end0;
// cores list
if (uwsgi_stats_key(us, "cores"))
goto end0;
if (uwsgi_stats_list_open(us))
goto end0;
for (j = 0; j < uwsgi.cores; j++) {
struct uwsgi_core *uc = &uwsgi.workers[i + 1].cores[j];
if (uwsgi_stats_object_open(us))
goto end0;
if (uwsgi_stats_keylong_comma(us, "id", (unsigned long long) j))
goto end0;
if (uwsgi_stats_keylong_comma(us, "requests", (unsigned long long) uc->requests))
goto end0;
if (uwsgi_stats_keylong(us, "in_request", (unsigned long long) uc->in_request))
goto end0;
if (uwsgi_stats_object_close(us))
goto end0;
if (j < uwsgi.cores-1) {
if (uwsgi_stats_comma(us))
goto end0;
}
}
else {
fprintf(output, "},\n");
if (uwsgi_stats_list_close(us))
goto end0;
if (uwsgi_stats_object_close(us))
goto end0;
if (i < uwsgi.numproc - 1) {
if (uwsgi_stats_comma(us))
goto end0;
}
}
fprintf(output, "]}\n");
fclose(output);
if (uwsgi_stats_list_close(us))
goto end0;
if (uwsgi_stats_object_close(us))
goto end0;
size_t remains = us->pos;
off_t pos = 0;
while (remains > 0) {
ssize_t res = write(client_fd, us->base + pos, remains);
if (res <= 0) {
if (res < 0) {
uwsgi_error("write()");
}
goto end0;
}
pos += res;
remains -= res;
}
end0:
free(cwd);
end:
free(us->base);
free(us);
close(client_fd);
}
void uwsgi_register_cheaper_algo(char *name, int(*func) (void)) {
void uwsgi_register_cheaper_algo(char *name, int (*func) (void)) {
struct uwsgi_cheaper_algo *uca = uwsgi.cheaper_algos;
struct uwsgi_cheaper_algo *uca = uwsgi.cheaper_algos;
if (!uca) {
uwsgi.cheaper_algos = uwsgi_malloc(sizeof(struct uwsgi_cheaper_algo));
uca = uwsgi.cheaper_algos;
}
else {
while (uca) {
if (!uca) {
uwsgi.cheaper_algos = uwsgi_malloc(sizeof(struct uwsgi_cheaper_algo));
uca = uwsgi.cheaper_algos;
}
else {
while (uca) {
if (!uca->next) {
uca->next = uwsgi_malloc(sizeof(struct uwsgi_cheaper_algo));
uca = uca->next;
uca = uca->next;
break;
}
uca = uca->next;
}
uca = uca->next;
}
}
}
uca->name = name;
uca->func = func;
uca->next = NULL;
uca->name = name;
uca->func = func;
uca->next = NULL;
#ifdef UWSGI_DEBUG
uwsgi_log("[uwsgi-cheaper-algo] registered \"%s\"\n", uca->name);
uwsgi_log("[uwsgi-cheaper-algo] registered \"%s\"\n", uca->name);
#endif
}
void trigger_harakiri(int i) {
int j;
uwsgi_log("*** HARAKIRI ON WORKER %d (pid: %d) ***\n", i, uwsgi.workers[i].pid);
if (uwsgi.harakiri_verbose) {
#ifdef __linux__
int proc_file;
char proc_buf[4096];
char proc_name[64];
ssize_t proc_len;
if (snprintf(proc_name, 64, "/proc/%d/syscall", uwsgi.workers[i].pid) > 0) {
memset(proc_buf, 0, 4096);
proc_file = open(proc_name, O_RDONLY);
if (proc_file >= 0) {
proc_len = read(proc_file, proc_buf, 4096);
if (proc_len > 0) {
uwsgi_log("HARAKIRI: -- syscall> %s", proc_buf);
}
close(proc_file);
}
}
if (snprintf(proc_name, 64, "/proc/%d/wchan", uwsgi.workers[i].pid) > 0) {
memset(proc_buf, 0, 4096);
proc_file = open(proc_name, O_RDONLY);
if (proc_file >= 0) {
proc_len = read(proc_file, proc_buf, 4096);
if (proc_len > 0) {
uwsgi_log("HARAKIRI: -- wchan> %s\n", proc_buf);
}
close(proc_file);
}
}
#endif
}
if (uwsgi.workers[i].pid > 0) {
for (j = 0; j < uwsgi.gp_cnt; j++) {
if (uwsgi.gp[j]->harakiri) {
uwsgi.gp[j]->harakiri(i);
}
}
for (j = 0; j < 256; j++) {
if (uwsgi.p[j]->harakiri) {
uwsgi.p[j]->harakiri(i);
}
}
kill(uwsgi.workers[i].pid, SIGUSR2);
// allow SIGUSR2 to be delivered
sleep(1);
kill(uwsgi.workers[i].pid, SIGKILL);
uwsgi.workers[i].harakiri_count++;
}
// to avoid races
}
+73 -4
View File
@@ -36,6 +36,11 @@ void uwsgi_mule(int id) {
pid_t pid = uwsgi_fork(uwsgi.mules[id-1].name);
if (pid == 0) {
#ifdef __linux__
if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0,0,0)) {
uwsgi_error("prctl()");
}
#endif
uwsgi.muleid = id;
// avoid race conditions
uwsgi.mules[id-1].id = id;
@@ -48,13 +53,13 @@ void uwsgi_mule(int id) {
uwsgi_close_all_sockets();
for (i = 0; i < 0xFF; i++) {
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->master_fixup) {
uwsgi.p[i]->master_fixup(1);
}
}
for (i = 0; i < 0xFF; i++) {
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->post_fork) {
uwsgi.p[i]->post_fork();
}
@@ -62,7 +67,7 @@ void uwsgi_mule(int id) {
if (uwsgi.mules[id-1].patch) {
for (i = 0; i < 0xFF; i++) {
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->mule) {
if (uwsgi.p[i]->mule(uwsgi.mules[id-1].patch) == 1) {
// never here
@@ -184,7 +189,7 @@ void uwsgi_mule_handler() {
}
else {
int i,found = 0;
for(i=0;i<0xff;i++) {
for(i=0;i<256;i++) {
if (uwsgi.p[i]->mule_msg) {
if (uwsgi.p[i]->mule_msg(message, len)) {
found = 1;
@@ -377,3 +382,67 @@ void uwsgi_opt_add_farm(char *opt, char *value, void *foobar) {
uwsgi_string_new_list(&uwsgi.farms_list, value);
}
void uwsgi_setup_mules_and_farms() {
int i;
if (uwsgi.mules_cnt > 0) {
uwsgi.mules = (struct uwsgi_mule *) uwsgi_calloc_shared(sizeof(struct uwsgi_mule) * uwsgi.mules_cnt);
create_signal_pipe(uwsgi.shared->mule_signal_pipe);
create_signal_pipe(uwsgi.shared->mule_queue_pipe);
for (i = 0; i < uwsgi.mules_cnt; i++) {
// create the socket pipe
create_signal_pipe(uwsgi.mules[i].signal_pipe);
create_signal_pipe(uwsgi.mules[i].queue_pipe);
uwsgi.mules[i].id = i + 1;
snprintf(uwsgi.mules[i].name, 0xff, "uWSGI mule %d", i + 1);
}
}
if (uwsgi.farms_cnt > 0) {
uwsgi.farms = (struct uwsgi_farm *) uwsgi_calloc_shared(sizeof(struct uwsgi_farm) * uwsgi.farms_cnt);
struct uwsgi_string_list *farm_name = uwsgi.farms_list;
for (i = 0; i < uwsgi.farms_cnt; i++) {
char *farm_value = uwsgi_str(farm_name->value);
char *mules_list = strchr(farm_value, ':');
if (!mules_list) {
uwsgi_log("invalid farm value (%s) must be in the form name:mule[,muleN].\n", farm_value);
exit(1);
}
mules_list[0] = 0;
mules_list++;
strncpy(uwsgi.farms[i].name, farm_value, 0xff);
// create the socket pipe
create_signal_pipe(uwsgi.farms[i].signal_pipe);
create_signal_pipe(uwsgi.farms[i].queue_pipe);
char *p = strtok(mules_list, ",");
while (p != NULL) {
struct uwsgi_mule *um = get_mule_by_id(atoi(p));
if (!um) {
uwsgi_log("invalid mule id: %s\n", p);
exit(1);
}
uwsgi_mule_farm_new(&uwsgi.farms[i].mules, um);
p = strtok(NULL, ",");
}
uwsgi_log("created farm %d name: %s mules:%s\n", i + 1, uwsgi.farms[i].name, strchr(farm_name->value, ':') + 1);
farm_name = farm_name->next;
}
}
}
View File
+115 -11
View File
@@ -2,10 +2,31 @@
extern struct uwsgi_server uwsgi;
#ifdef UWSGI_ELF
static void uwsgi_plugin_parse_section(char *filename) {
size_t s_len = 0;
char *buf = uwsgi_elf_section(filename, "uwsgi", &s_len);
if (buf) {
char *p = strtok(buf, "\n");
while(p) {
char *equal = strchr(p, '=');
if (equal) {
*equal = 0;
if (!strcmp(p, "requires")) {
uwsgi_load_plugin(-1, equal+1, NULL);
}
}
p = strtok(NULL, "\n");
}
free(buf);
}
}
#endif
static int plugin_already_loaded(const char *plugin) {
int i;
for (i = 0; i < 0xFF; i++) {
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->name) {
if (!strcmp(plugin, uwsgi.p[i]->name)) {
#ifdef UWSGI_DEBUG
@@ -50,6 +71,8 @@ static int plugin_already_loaded(const char *plugin) {
void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
void *plugin_handle = NULL;
char *plugin_abs_path = NULL;
char *plugin_filename = NULL;
int need_free = 0;
char *plugin_name = plugin;
@@ -77,37 +100,54 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
// step 1: check for absolute plugin (stop if it fails)
if (strchr(plugin_name, '/')) {
#ifdef UWSGI_ELF
uwsgi_plugin_parse_section(plugin_name);
#endif
plugin_handle = dlopen(plugin_name, RTLD_NOW | RTLD_GLOBAL);
if (!plugin_handle) {
uwsgi_log( "%s\n", dlerror());
if (!has_option)
uwsgi_log( "%s\n", dlerror());
goto end;
}
plugin_symbol_name_start = uwsgi_get_last_char(plugin_name, '/');
plugin_symbol_name_start++;
plugin_abs_path = plugin_name;
goto success;
}
// step dir, check for user-supplied plugins directory
struct uwsgi_string_list *pdir = uwsgi.plugins_dir;
while(pdir) {
char *plugin_filename = uwsgi_concat3(pdir->value, "/", plugin_name);
plugin_filename = uwsgi_concat3(pdir->value, "/", plugin_name);
#ifdef UWSGI_ELF
uwsgi_plugin_parse_section(plugin_filename);
#endif
plugin_handle = dlopen(plugin_filename, RTLD_NOW | RTLD_GLOBAL);
if (plugin_handle) {
free(plugin_filename);
break;
plugin_abs_path = plugin_filename;
//free(plugin_filename);
goto success;
}
free(plugin_filename);
plugin_filename = NULL;
pdir = pdir->next;
}
// last step: search in compile-time plugin_dir
if (!plugin_handle) {
char *plugin_filename = uwsgi_concat3(UWSGI_PLUGIN_DIR, "/", plugin_name);
plugin_filename = uwsgi_concat3(UWSGI_PLUGIN_DIR, "/", plugin_name);
#ifdef UWSGI_ELF
uwsgi_plugin_parse_section(plugin_filename);
#endif
plugin_handle = dlopen(plugin_filename, RTLD_NOW | RTLD_GLOBAL);
free(plugin_filename);
plugin_abs_path = plugin_filename;
//free(plugin_filename);
}
success:
if (!plugin_handle) {
uwsgi_log( "%s\n", dlerror());
if (!has_option)
uwsgi_log( "!!! UNABLE to load uWSGI plugin: %s !!!\n", dlerror());
}
else {
char *plugin_entry_symbol = uwsgi_concat2n(plugin_symbol_name_start, strlen(plugin_symbol_name_start)-3, "", 0);
@@ -116,7 +156,7 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
// is it a link ?
memset(linkpath_buf, 0, 1024);
memset(linkpath, 0, 1024);
if ((linkpath_size = readlink(plugin_name, linkpath_buf, 1023)) > 0) {
if ((linkpath_size = readlink(plugin_abs_path, linkpath_buf, 1023)) > 0) {
do {
linkpath_buf[linkpath_size] = '\0';
strncpy(linkpath, linkpath_buf, linkpath_size+1);
@@ -145,6 +185,8 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
}
if (need_free)
free(plugin_name);
if (plugin_filename)
free(plugin_filename);
free(plugin_entry_symbol);
return NULL;
}
@@ -154,11 +196,13 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
}
if (need_free)
free(plugin_name);
if (plugin_filename)
free(plugin_filename);
free(plugin_entry_symbol);
return NULL;
}
if (has_option) {
struct uwsgi_option *op = uwsgi.options;
struct uwsgi_option *op = up->options;
int found = 0;
while (op && op->name) {
if (!strcmp(has_option, op->name)) {
@@ -173,6 +217,8 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
}
if (need_free)
free(plugin_name);
if (plugin_filename)
free(plugin_filename);
free(plugin_entry_symbol);
return NULL;
}
@@ -180,24 +226,82 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
}
if (modifier != -1) {
fill_plugin_table(modifier, up);
up->modifier1 = modifier;
}
else {
fill_plugin_table(up->modifier1, up);
}
if (need_free)
free(plugin_name);
if (plugin_filename)
free(plugin_filename);
free(plugin_entry_symbol);
if (up->on_load)
up->on_load();
return plugin_handle;
}
uwsgi_log( "%s\n", dlerror());
if (!has_option)
uwsgi_log( "%s\n", dlerror());
}
end:
if (need_free)
free(plugin_name);
if (plugin_filename)
free(plugin_filename);
return NULL;
}
int uwsgi_try_autoload(char *option) {
DIR *d;
struct dirent *dp;
// step dir, check for user-supplied plugins directory
struct uwsgi_string_list *pdir = uwsgi.plugins_dir;
while(pdir) {
d = opendir(pdir->value);
if (d) {
while ((dp = readdir(d)) != NULL) {
if (uwsgi_endswith(dp->d_name, "_plugin.so")) {
char *filename = uwsgi_concat3(pdir->value, "/", dp->d_name);
if (uwsgi_load_plugin(-1, filename, option)) {
uwsgi_log("option \"%s\" found in plugin %s\n", option, filename);
free(filename);
closedir(d);
// add new options
build_options();
return 1;
}
free(filename);
}
}
closedir(d);
}
pdir = pdir->next;
}
// last step: search in compile-time plugin_dir
d = opendir(UWSGI_PLUGIN_DIR);
if (!d) return 0;
while((dp = readdir(d)) != NULL) {
if (uwsgi_endswith(dp->d_name, "_plugin.so")) {
char *filename = uwsgi_concat3(UWSGI_PLUGIN_DIR, "/", dp->d_name);
if (uwsgi_load_plugin(-1, filename, option)) {
uwsgi_log("option \"%s\" found in plugin %s\n", option, filename);
free(filename);
closedir(d);
// add new options
build_options();
return 1;
}
free(filename);
}
}
closedir(d);
return 0;
}
+419 -122
View File
@@ -16,7 +16,8 @@ static size_t get_content_length(char *buf, uint16_t size) {
return val;
}
void set_http_date(time_t t, char *dst) {
int set_http_date(time_t t, char *header, int header_len, char *dst, int last) {
static char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
static char *months[] = {
@@ -26,12 +27,168 @@ void set_http_date(time_t t, char *dst) {
};
struct tm *hdtm = gmtime(&t);
snprintf(dst, 49, "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n\r\n",
if (last) {
return snprintf(dst, 36+header_len, "%.*s: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n\r\n",
header_len, header,
week[hdtm->tm_wday], hdtm->tm_mday,
months[hdtm->tm_mon], hdtm->tm_year+1900,
hdtm->tm_hour, hdtm->tm_min, hdtm->tm_sec);
}
return snprintf(dst, 34+header_len, "%.*s: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
header_len, header,
week[hdtm->tm_wday], hdtm->tm_mday,
months[hdtm->tm_mon], hdtm->tm_year+1900,
hdtm->tm_hour, hdtm->tm_min, hdtm->tm_sec);
}
void uwsgi_add_expires_type(struct wsgi_request *wsgi_req, char *mime_type, int mime_type_len, struct stat *st) {
struct uwsgi_dyn_dict *udd = uwsgi.static_expires_type;
time_t now = wsgi_req->start_of_request/1000000;
// Expires+34+1
char expires[42];
while(udd) {
if (!uwsgi_strncmp(udd->key, udd->keylen, mime_type, mime_type_len)) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(now+delta, "Expires", 7, expires, 0);
if (size > 0) {
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, expires, size);
wsgi_req->header_cnt++;
}
return;
}
udd = udd->next;
}
udd = uwsgi.static_expires_type_mtime;
while(udd) {
if (!uwsgi_strncmp(udd->key, udd->keylen, mime_type, mime_type_len)) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(st->st_mtime+delta, "Expires", 7, expires, 0);
if (size > 0) {
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, expires, size);
wsgi_req->header_cnt++;
}
return;
}
udd = udd->next;
}
}
#ifdef UWSGI_PCRE
void uwsgi_add_expires(struct wsgi_request *wsgi_req, char *filename, int filename_len, struct stat *st) {
struct uwsgi_dyn_dict *udd = uwsgi.static_expires;
time_t now = wsgi_req->start_of_request/1000000;
// Expires+34+1
char expires[42];
while(udd) {
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, filename, filename_len) >= 0) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(now+delta, "Expires", 7, expires, 0);
if (size > 0) {
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, expires, size);
wsgi_req->header_cnt++;
}
return;
}
udd = udd->next;
}
udd = uwsgi.static_expires_mtime;
while(udd) {
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, filename, filename_len) >= 0) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(st->st_mtime+delta, "Expires", 7, expires, 0);
if (size > 0) {
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, expires, size);
wsgi_req->header_cnt++;
}
return;
}
udd = udd->next;
}
}
void uwsgi_add_expires_path_info(struct wsgi_request *wsgi_req, struct stat *st) {
struct uwsgi_dyn_dict *udd = uwsgi.static_expires_path_info;
time_t now = wsgi_req->start_of_request/1000000;
// Expires+34+1
char expires[42];
while(udd) {
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->path_info, wsgi_req->path_info_len) >= 0) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(now+delta, "Expires", 7, expires, 0);
if (size > 0) {
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, expires, size);
wsgi_req->header_cnt++;
}
return;
}
udd = udd->next;
}
udd = uwsgi.static_expires_path_info_mtime;
while(udd) {
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->path_info, wsgi_req->path_info_len) >= 0) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(st->st_mtime+delta, "Expires", 7, expires, 0);
if (size > 0) {
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, expires, size);
wsgi_req->header_cnt++;
}
return;
}
udd = udd->next;
}
}
void uwsgi_add_expires_uri(struct wsgi_request *wsgi_req, struct stat *st) {
struct uwsgi_dyn_dict *udd = uwsgi.static_expires_uri;
time_t now = wsgi_req->start_of_request/1000000;
// Expires+34+1
char expires[42];
while(udd) {
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->uri, wsgi_req->uri_len) >= 0) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(now+delta, "Expires", 7, expires, 0);
if (size > 0) {
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, expires, size);
wsgi_req->header_cnt++;
}
return;
}
udd = udd->next;
}
udd = uwsgi.static_expires_uri_mtime;
while(udd) {
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->uri, wsgi_req->uri_len) >= 0) {
int delta = uwsgi_str_num(udd->value, udd->vallen);
int size = set_http_date(st->st_mtime+delta, "Expires", 7, expires, 0);
if (size > 0) {
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, expires, size);
wsgi_req->header_cnt++;
}
return;
}
udd = udd->next;
}
}
#endif
// only RFC 1123 is supported
time_t parse_http_date(char *date, uint16_t len) {
@@ -126,6 +283,7 @@ ssize_t send_udp_message(uint8_t modifier1, uint8_t modifier2, char *host, char
int fd;
struct sockaddr_in udp_addr;
struct sockaddr_un un_addr;
char *udp_port;
ssize_t ret;
@@ -139,23 +297,34 @@ ssize_t send_udp_message(uint8_t modifier1, uint8_t modifier2, char *host, char
}
udp_port = strchr(host, ':');
if (udp_port == NULL) {
return -1;
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;
}
udp_port[0] = 0;
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);
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);
uh->modifier1 = modifier1;
#ifdef __BIG_ENDIAN__
uh->pktsize = uwsgi_swap16(message_size);
@@ -164,14 +333,18 @@ ssize_t send_udp_message(uint8_t modifier1, uint8_t modifier2, char *host, char
#endif
uh->modifier2 = modifier2;
ret = sendto(fd, (char *) uh, message_size+4, 0, (struct sockaddr *) &udp_addr, sizeof(udp_addr));
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("sendto()");
}
close(fd);
udp_port[0] = ':';
if ((char *)uh != message) {
free(uh);
}
@@ -239,12 +412,9 @@ int uwsgi_enqueue_message(char *host, int port, uint8_t modifier1, uint8_t modif
ssize_t uwsgi_send_message(int fd, uint8_t modifier1, uint8_t modifier2, char *message, uint16_t size, int pfd, ssize_t plen, int timeout) {
struct pollfd uwsgi_mpoll;
ssize_t cnt;
struct uwsgi_header uh;
char buffer[4096];
ssize_t ret = 0;
int pret;
struct msghdr msg;
struct iovec iov [1];
union {
@@ -305,37 +475,8 @@ ssize_t uwsgi_send_message(int fd, uint8_t modifier1, uint8_t modifier2, char *m
// transfer data from one socket to another
if (pfd >= 0 && plen > 0) {
uwsgi_mpoll.fd = pfd;
uwsgi_mpoll.events = POLLIN;
while(plen > 0) {
pret = poll(&uwsgi_mpoll, 1, timeout*1000);
if (pret < 0) {
uwsgi_error("poll()");
return -1;
}
else if (pret == 0) {
uwsgi_log("timeout waiting for socket data\n");
return -1;
}
else {
cnt = read(pfd, buffer, UMIN(4096, plen));
if (cnt < 0) {
uwsgi_error("read()");
return -1;
}
else if (cnt == 0) {
return ret;
}
// send to peer
if (write(fd, buffer, cnt) != cnt) {
uwsgi_error("write()");
return -1;
}
ret += cnt;
plen -= cnt;
}
}
ret = uwsgi_pipe_sized(pfd, fd, plen, timeout);
if (ret < 0) return -1;
}
@@ -916,7 +1057,7 @@ next:
udd->vallen = strlen(udd->value);
}
if (!uwsgi_file_serve(wsgi_req, udd->value, udd->vallen, wsgi_req->path_info, wsgi_req->path_info_len)) {
if (!uwsgi_file_serve(wsgi_req, udd->value, udd->vallen, wsgi_req->path_info, wsgi_req->path_info_len, 0)) {
return -1;
}
nextcs:
@@ -944,11 +1085,11 @@ nextcs:
if (!real_docroot) goto nextsm;
udd->value = real_docroot;
udd->vallen = strlen(udd->value);
udd->status = 1;
udd->status = 1 + uwsgi_is_file(real_docroot);
}
if (!uwsgi_starts_with(wsgi_req->path_info, wsgi_req->path_info_len, udd->key, udd->keylen)) {
if (!uwsgi_file_serve(wsgi_req, udd->value, udd->vallen, wsgi_req->path_info+udd->keylen, wsgi_req->path_info_len-udd->keylen)) {
if (!uwsgi_file_serve(wsgi_req, udd->value, udd->vallen, wsgi_req->path_info+udd->keylen, wsgi_req->path_info_len-udd->keylen, udd->status-1)) {
return -1;
}
}
@@ -956,11 +1097,51 @@ nextsm:
udd = udd->next;
}
// check for static_maps in append mode
udd = uwsgi.static_maps2;
while(udd) {
#ifdef UWSGI_DEBUG
uwsgi_log("checking for %.*s <-> %.*s\n", wsgi_req->path_info_len, wsgi_req->path_info, udd->keylen, udd->key);
#endif
if (udd->status == 0) {
#ifdef UWSGI_THREADING
if (uwsgi.threads > 1) pthread_mutex_lock(&uwsgi.lock_static);
#endif
char *real_docroot = uwsgi_malloc(PATH_MAX+1);
if (!realpath(udd->value, real_docroot)) {
free(real_docroot);
udd->value = NULL;
}
#ifdef UWSGI_THREADING
if (uwsgi.threads > 1) pthread_mutex_unlock(&uwsgi.lock_static);
#endif
if (!real_docroot) goto nextsm2;
udd->value = real_docroot;
udd->vallen = strlen(udd->value);
udd->status = 1 + uwsgi_is_file(real_docroot);
}
if (!uwsgi_starts_with(wsgi_req->path_info, wsgi_req->path_info_len, udd->key, udd->keylen)) {
if (!uwsgi_file_serve(wsgi_req, udd->value, udd->vallen, wsgi_req->path_info, wsgi_req->path_info_len, udd->status-1)) {
return -1;
}
}
nextsm2:
udd = udd->next;
}
// finally check for docroot
if (uwsgi.check_static_docroot && wsgi_req->document_root_len > 0) {
if (!uwsgi_file_serve(wsgi_req, wsgi_req->document_root, wsgi_req->document_root_len, wsgi_req->path_info, wsgi_req->path_info_len)) {
char *real_docroot = uwsgi_expand_path(wsgi_req->document_root, wsgi_req->document_root_len, NULL);
if (!real_docroot) {
return -1;
}
if (!uwsgi_file_serve(wsgi_req, real_docroot, strlen(real_docroot), wsgi_req->path_info, wsgi_req->path_info_len, 0)) {
free(real_docroot);
return -1;
}
free(real_docroot);
}
return 0;
@@ -1514,31 +1695,41 @@ char *uwsgi_get_mime_type(char *name, int namelen, int *size) {
count++;
}
if (ext) {
struct uwsgi_dyn_dict *udd = uwsgi.mimetypes;
while(udd) {
if (!uwsgi_strncmp(ext, count, udd->key, udd->keylen)) {
udd->hits++;
// auto optimization
if (udd->prev) {
if (udd->hits > udd->prev->hits) {
struct uwsgi_dyn_dict *udd_parent = udd->prev->prev, *udd_prev = udd->prev;
if (udd_parent) {
udd_parent->next = udd;
}
udd_prev->prev = udd;
udd_prev->next = udd->next;
if (!ext) return NULL;
udd->prev = udd_parent;
udd->next = udd_prev;
struct uwsgi_dyn_dict *udd = uwsgi.mimetypes;
while(udd) {
if (!uwsgi_strncmp(ext, count, udd->key, udd->keylen)) {
udd->hits++;
// auto optimization
if (udd->prev) {
if (udd->hits > udd->prev->hits) {
struct uwsgi_dyn_dict *udd_parent = udd->prev->prev, *udd_prev = udd->prev;
if (udd_parent) {
udd_parent->next = udd;
}
if (udd->next) {
udd->next->prev = udd_prev;
}
udd_prev->prev = udd;
udd_prev->next = udd->next;
udd->prev = udd_parent;
udd->next = udd_prev;
if (udd->prev == NULL) {
uwsgi.mimetypes = udd;
}
}
*size = udd->vallen;
return udd->value;
}
udd = udd->next;
*size = udd->vallen;
return udd->value;
}
udd = udd->next;
}
return NULL;
}
@@ -1593,58 +1784,26 @@ int uwsgi_static_stat(char *filename, struct stat *st) {
return -1;
}
int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_t document_root_len, char *path_info, uint16_t path_info_len) {
int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, size_t real_filename_len, struct stat *st) {
struct stat st;
struct iovec headers_vec[8];
char real_filename[PATH_MAX+1];
int mime_type_size = 0;
char http_last_modified[49];
char content_length[sizeof(UMAX64_STR)+1];
size_t real_filename_len = 0;
char *filename = uwsgi_concat3n(document_root, document_root_len, "/", 1, path_info, path_info_len);
#ifdef UWSGI_DEBUG
uwsgi_log("[uwsgi-fileserve] checking for %s\n", filename);
#ifdef UWSGI_THREADING
if (uwsgi.threads > 1) pthread_mutex_lock(&uwsgi.lock_static);
#endif
if (!realpath(filename, real_filename)) {
#ifdef UWSGI_DEBUG
uwsgi_log("[uwsgi-fileserve] unable to get realpath() of the static file\n");
#endif
free(filename);
return -1;
}
free(filename);
if (uwsgi_starts_with(real_filename, strlen(real_filename), document_root, document_root_len)) {
uwsgi_log("[uwsgi-fileserve] security error: %s is not under %.*s\n", real_filename, document_root_len, document_root);
return -1;
}
if (!uwsgi_static_stat(real_filename, &st)) {
real_filename_len = strlen(real_filename);
// check for skippable ext
struct uwsgi_string_list *sse = uwsgi.static_skip_ext;
while(sse) {
if (real_filename_len >= sse->len) {
if (!uwsgi_strncmp(real_filename+(real_filename_len - sse->len), sse->len, sse->value, sse->len)) {
#ifdef UWSGI_ROUTING
if (uwsgi_apply_routes_fast(wsgi_req, real_filename, real_filename_len) == UWSGI_ROUTE_BREAK) return 0;
#endif
return -1;
}
}
sse = sse->next;
}
int mime_type_size = 0;
char http_last_modified[49];
char *mime_type = uwsgi_get_mime_type(real_filename, real_filename_len, &mime_type_size);
#ifdef UWSGI_THREADING
if (uwsgi.threads > 1) pthread_mutex_unlock(&uwsgi.lock_static);
#endif
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) {
if (st->st_mtime <= ims) {
wsgi_req->status = 304;
headers_vec[0].iov_base = wsgi_req->protocol;
headers_vec[0].iov_len = wsgi_req->protocol_len;
@@ -1691,6 +1850,12 @@ int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_
ah = ah->next;
}
#ifdef UWSGI_PCRE
uwsgi_add_expires(wsgi_req, real_filename, real_filename_len, st);
uwsgi_add_expires_path_info(wsgi_req, st);
uwsgi_add_expires_uri(wsgi_req, st);
#endif
// Content-Type (if available)
if (mime_type_size > 0 && mime_type) {
headers_vec[0].iov_base = "Content-Type: ";
@@ -1701,6 +1866,9 @@ int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_
headers_vec[2].iov_len = 2;
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, headers_vec, 3);
wsgi_req->header_cnt++;
// check for content-type related headers
uwsgi_add_expires_type(wsgi_req, mime_type, mime_type_size, st);
}
// nginx
@@ -1710,7 +1878,7 @@ int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_
headers_vec[2].iov_base = "\r\n"; headers_vec[2].iov_len = 2;
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, headers_vec, 3);
// this is the final header (\r\n added)
set_http_date(st.st_mtime, http_last_modified);
set_http_date(st->st_mtime, "Last-Modified", 13, http_last_modified, 1);
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, http_last_modified, 48);
wsgi_req->header_cnt += 2;
}
@@ -1721,7 +1889,7 @@ int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_
headers_vec[2].iov_base = "\r\n"; headers_vec[2].iov_len = 2;
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, headers_vec, 3);
// this is the final header (\r\n added)
set_http_date(st.st_mtime, http_last_modified);
set_http_date(st->st_mtime, "Last-Modified", 13, http_last_modified, 1);
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, http_last_modified, 48);
wsgi_req->header_cnt += 2;
}
@@ -1730,12 +1898,12 @@ int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_
// set Content-Length
headers_vec[0].iov_base = "Content-Length: ";
headers_vec[0].iov_len = 16;
headers_vec[1].iov_len = uwsgi_long2str2n(st.st_size, content_length, sizeof(UMAX64_STR)+1);
headers_vec[1].iov_len = uwsgi_long2str2n(st->st_size, content_length, sizeof(UMAX64_STR)+1);
headers_vec[1].iov_base = content_length;
headers_vec[2].iov_base = "\r\n";
headers_vec[2].iov_len = 2;
// this is the final header (\r\n added)
set_http_date(st.st_mtime, http_last_modified);
set_http_date(st->st_mtime, "Last-Modified", 13, http_last_modified, 1);
headers_vec[3].iov_base = http_last_modified;
headers_vec[3].iov_len = 48;
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, headers_vec, 4);
@@ -1749,6 +1917,135 @@ int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_
wsgi_req->status = 200;
return 0;
}
void *uwsgi_static_offload_thread(void *req) {
struct uwsgi_offload_request *uof_req = (struct uwsgi_offload_request *) req;
uwsgi_real_file_serve(&uof_req->wsgi_req, uof_req->real_filename, uof_req->real_filename_len, &uof_req->st);
// close the connection with the webserver
if (!uof_req->wsgi_req.fd_closed || !uof_req->wsgi_req.body_as_file) {
// NOTE, if we close the socket before receiving eventually sent data, socket layer will send a RST
uof_req->wsgi_req.socket->proto_close(&uof_req->wsgi_req);
}
// free buffer
free(uof_req->buffer);
// free hvec
free(uof_req->hvec);
free(uof_req);
pthread_mutex_lock(&uwsgi.static_offload_thread_lock);
uwsgi.workers[uwsgi.mywid].static_offload_threads--;
pthread_mutex_unlock(&uwsgi.static_offload_thread_lock);
return NULL;
}
int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_t document_root_len, char *path_info, uint16_t path_info_len, int is_a_file) {
struct stat st;
char real_filename[PATH_MAX+1];
size_t real_filename_len = 0;
char *filename = NULL;
if (!is_a_file) {
filename = uwsgi_concat3n(document_root, document_root_len, "/", 1, path_info, path_info_len);
}
else {
filename = uwsgi_concat2n(document_root, document_root_len, "", 0);
}
#ifdef UWSGI_DEBUG
uwsgi_log("[uwsgi-fileserve] checking for %s\n", filename);
#endif
if (!realpath(filename, real_filename)) {
#ifdef UWSGI_DEBUG
uwsgi_log("[uwsgi-fileserve] unable to get realpath() of the static file\n");
#endif
free(filename);
return -1;
}
free(filename);
if (uwsgi_starts_with(real_filename, strlen(real_filename), document_root, document_root_len)) {
uwsgi_log("[uwsgi-fileserve] security error: %s is not under %.*s\n", real_filename, document_root_len, document_root);
return -1;
}
if (!uwsgi_static_stat(real_filename, &st)) {
real_filename_len = strlen(real_filename);
// check for skippable ext
struct uwsgi_string_list *sse = uwsgi.static_skip_ext;
while(sse) {
if (real_filename_len >= sse->len) {
if (!uwsgi_strncmp(real_filename+(real_filename_len - sse->len), sse->len, sse->value, sse->len)) {
#ifdef UWSGI_ROUTING
if (uwsgi_apply_routes_fast(wsgi_req, real_filename, real_filename_len) == UWSGI_ROUTE_BREAK) return 0;
#endif
return -1;
}
}
sse = sse->next;
}
// Ok, the file must be served as static from uWSGI
if (uwsgi.static_offload_to_thread) {
pthread_mutex_lock(&uwsgi.static_offload_thread_lock);
uint64_t offload_thread_count = uwsgi.workers[uwsgi.mywid].static_offload_threads;
pthread_mutex_unlock(&uwsgi.static_offload_thread_lock);
if (offload_thread_count > (uint64_t) uwsgi.static_offload_to_thread) {
uwsgi_log_verbose("OVERLOAD !!! unable to offload static file serving\n");
return uwsgi_real_file_serve(wsgi_req, real_filename, real_filename_len, &st);
}
struct uwsgi_offload_request *uor = uwsgi_malloc(sizeof(struct uwsgi_offload_request));
// buffer
uor->buffer = uwsgi_malloc(uwsgi.buffer_size); memcpy(uor->buffer, wsgi_req->buffer, uwsgi.buffer_size);
// iovec
uor->hvec = uwsgi_malloc(sizeof(struct iovec) * uwsgi.vec_size); memcpy(uor->hvec, wsgi_req->hvec, sizeof(struct iovec) * uwsgi.vec_size);
// wsgi_req
memcpy(&uor->wsgi_req, wsgi_req, sizeof(struct wsgi_request));
uor->wsgi_req.buffer = uor->buffer;
uor->wsgi_req.hvec = uor->hvec;
// stat
memcpy(&uor->st, &st, sizeof(struct stat));
// filename
memcpy(uor->real_filename, real_filename, real_filename_len);
uor->real_filename_len = real_filename_len;
uor->real_filename[uor->real_filename_len] = 0;
// avoid closing the connection
wsgi_req->fd_closed = 1;
pthread_mutex_lock(&uwsgi.static_offload_thread_lock);
uwsgi.workers[uwsgi.mywid].static_offload_threads++;
pthread_mutex_unlock(&uwsgi.static_offload_thread_lock);
if (pthread_create(&uor->tid, &uwsgi.static_offload_thread_attr, uwsgi_static_offload_thread, (void *) uor)) {
uwsgi_error("pthread_create()");
// bad condition, better to exit...
exit(1);
}
wsgi_req->status = -30;
return 0;
}
else {
return uwsgi_real_file_serve(wsgi_req, real_filename, real_filename_len, &st);
}
}
return -1;
+2 -2
View File
@@ -150,7 +150,7 @@ int uwsgi_queue_push(char *message, uint64_t size) {
ptr += sizeof(struct uwsgi_queue_item);
uqi->size = size;
uqi->ts = time(NULL);
uqi->ts = uwsgi_now();
memcpy(ptr, message, size);
uwsgi.queue_header->pos++;
@@ -178,7 +178,7 @@ int uwsgi_queue_set(uint64_t pos, char *message, uint64_t size) {
ptr += sizeof(struct uwsgi_queue_item);
uqi->size = size;
uqi->ts = time(NULL);
uqi->ts = uwsgi_now();
memcpy(ptr, message, size);
return 1;
View File
View File
-1
View File
@@ -26,7 +26,6 @@ int uwsgi_apply_routes(struct wsgi_request *wsgi_req) {
return ret;
}
}
routes = routes->next;
}
View File
+17 -7
View File
@@ -89,20 +89,30 @@ ssize_t uwsgi_do_sendfile(int sockfd, int filefd, size_t filesize, size_t chunk,
#elif defined(__linux__) || defined(__sun__)
int sf_ret;
size_t written = 0;
if (async > 1) {
sf_ret = sendfile(sockfd, filefd, pos, chunk);
}
else {
sf_ret = sendfile(sockfd, filefd, pos, filesize);
if (sf_ret < 0) {
uwsgi_error("sendfile()");
return 0;
}
return sf_ret;
}
if (sf_ret < 0) {
uwsgi_error("sendfile()");
return 0;
while(written < filesize) {
sf_ret = sendfile(sockfd, filefd, pos, filesize-written);
if (sf_ret < 0) {
uwsgi_error("sendfile()");
return 0;
}
else if (sf_ret == 0) {
return 0;
}
written+= sf_ret;
}
return written;
return sf_ret;
#else
static size_t nosf_buf_size = 0;
static char *nosf_buf;
+197
View File
@@ -0,0 +1,197 @@
#include "uwsgi.h"
extern struct uwsgi_server uwsgi;
void uwsgi_setup_systemd() {
struct uwsgi_socket *uwsgi_sock = NULL;
int i;
char *listen_pid = getenv("LISTEN_PID");
if (listen_pid) {
if (atoi(listen_pid) == (int) getpid()) {
char *listen_fds = getenv("LISTEN_FDS");
if (listen_fds) {
int systemd_fds = atoi(listen_fds);
if (systemd_fds > 0) {
uwsgi_log("- SystemD socket activation detected -\n");
for (i = 3; i < 3 + systemd_fds; i++) {
uwsgi_sock = uwsgi_new_socket(NULL);
uwsgi_add_socket_from_fd(uwsgi_sock, i);
}
uwsgi.skip_zero = 1;
}
unsetenv("LISTEN_PID");
unsetenv("LISTEN_FDS");
}
}
}
}
void uwsgi_setup_upstart() {
struct uwsgi_socket *uwsgi_sock = NULL;
char *upstart_events = getenv("UPSTART_EVENTS");
if (upstart_events && !strcmp(upstart_events, "socket")) {
char *upstart_fds = getenv("UPSTART_FDS");
if (upstart_fds) {
uwsgi_log("- Upstart socket bridge detected (job: %s) -\n", getenv("UPSTART_JOB"));
uwsgi_sock = uwsgi_new_socket(NULL);
uwsgi_add_socket_from_fd(uwsgi_sock, atoi(upstart_fds));
uwsgi.skip_zero = 1;
}
unsetenv("UPSTART_EVENTS");
unsetenv("UPSTART_FDS");
}
}
void uwsgi_setup_zerg() {
struct uwsgi_socket *uwsgi_sock = NULL;
int i;
struct uwsgi_string_list *zn = uwsgi.zerg_node;
while (zn) {
if (uwsgi_zerg_attach(zn->value)) {
if (!uwsgi.zerg_fallback) {
exit(1);
}
}
zn = zn->next;
}
if (uwsgi.zerg) {
#ifdef UWSGI_DEBUG
uwsgi_log("attaching zerg sockets...\n");
#endif
int zerg_fd;
i = 0;
for (;;) {
zerg_fd = uwsgi.zerg[i];
if (zerg_fd == -1) {
break;
}
uwsgi_sock = uwsgi_new_socket(NULL);
uwsgi_add_socket_from_fd(uwsgi_sock, zerg_fd);
i++;
}
uwsgi_log("zerg sockets attached\n");
}
}
void uwsgi_setup_inherited_sockets() {
int j;
union uwsgi_sockaddr usa;
union uwsgi_sockaddr_ptr gsa;
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
//a bit overengineering
if (uwsgi_sock->name[0] != 0 && !uwsgi_sock->bound) {
for (j = 3; j < (int) uwsgi.max_fd; j++) {
uwsgi_add_socket_from_fd(uwsgi_sock, j);
}
}
uwsgi_sock = uwsgi_sock->next;
}
//now close all the unbound fd
for (j = 3; j < (int) uwsgi.max_fd; j++) {
int useless = 1;
#ifdef UWSGI_MULTICAST
if (j == uwsgi.cluster_fd)
continue;
#endif
if (uwsgi.has_emperor) {
if (j == uwsgi.emperor_fd)
continue;
}
if (uwsgi.shared->worker_log_pipe[0] > -1) {
if (j == uwsgi.shared->worker_log_pipe[0])
continue;
}
if (uwsgi.shared->worker_log_pipe[1] > -1) {
if (j == uwsgi.shared->worker_log_pipe[1])
continue;
}
if (uwsgi.original_log_fd > -1) {
if (j == uwsgi.original_log_fd)
continue;
}
if (uwsgi.cache_server && uwsgi.cache_server_fd != -1) {
if (j == uwsgi.cache_server_fd)
continue;
}
struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets;
int found = 0;
while (ugs) {
if (ugs->fd == j) {
found = 1;
break;
}
ugs = ugs->next;
}
if (found)
continue;
int y;
found = 0;
for (y = 0; y < ushared->gateways_cnt; y++) {
if (ushared->gateways[y].internal_subscription_pipe[0] == j) {
found = 1;
break;
}
if (ushared->gateways[y].internal_subscription_pipe[1] == j) {
found = 1;
break;
}
}
if (found)
continue;
socklen_t socket_type_len = sizeof(struct sockaddr_un);
gsa.sa = (struct sockaddr *) &usa;
if (!getsockname(j, gsa.sa, &socket_type_len)) {
uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
if (uwsgi_sock->fd == j && uwsgi_sock->bound) {
useless = 0;
break;
}
uwsgi_sock = uwsgi_sock->next;
}
if (useless) {
uwsgi_sock = uwsgi.shared_sockets;
while (uwsgi_sock) {
if (uwsgi_sock->fd == j && uwsgi_sock->bound) {
useless = 0;
break;
}
uwsgi_sock = uwsgi_sock->next;
}
}
}
if (useless) {
close(j);
}
}
}
+30
View File
@@ -559,3 +559,33 @@ cycle:
return received_signal;
}
void uwsgi_receive_signal(int fd, char *name, int id) {
uint8_t uwsgi_signal;
ssize_t ret = read(fd, &uwsgi_signal, 1);
if (ret == 0) {
goto destroy;
}
else if (ret < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
uwsgi_error("[uwsgi-signal] read()");
goto destroy;
}
else if (ret > 0) {
#ifdef UWSGI_DEBUG
uwsgi_log_verbose("master sent signal %d to %s %d\n", uwsgi_signal, name, id);
#endif
if (uwsgi_signal_handler(uwsgi_signal)) {
uwsgi_log_verbose("error managing signal %d on %s %d\n", uwsgi_signal, name, id);
}
}
return;
destroy:
// better to kill the whole worker...
uwsgi_log_verbose("uWSGI %s %d screams: UAAAAAAH my master disconnected: i will kill myself !!!\n", name, id);
end_me(0);
}
View File
+43 -2
View File
@@ -354,8 +354,8 @@ static int get_snmp_integer(uint8_t * ptr, uint64_t * val) {
void uwsgi_opt_snmp(char *opt, char *value, void *foobar) {
uwsgi.snmp = 1;
if (value) {
uwsgi.snmp_addr = optarg;
uwsgi.master_process = 1;
uwsgi.snmp_addr = value;
uwsgi.master_process = 1;
}
}
@@ -364,6 +364,47 @@ void uwsgi_opt_snmp_community(char *opt, char *value, void *foobar) {
uwsgi.snmp = 1;
uwsgi.snmp_community = value;
}
int uwsgi_setup_snmp(void) {
int snmp_fd = -1;
int i;
if (uwsgi.snmp) {
if (uwsgi.snmp_community) {
if (strlen(uwsgi.snmp_community) > 72) {
uwsgi_log("*** warning the supplied SNMP community string will be truncated to 72 chars ***\n");
memcpy(uwsgi.shared->snmp_community, uwsgi.snmp_community, 72);
}
else {
memcpy(uwsgi.shared->snmp_community, uwsgi.snmp_community, strlen(uwsgi.snmp_community) + 1);
}
}
uwsgi.shared->snmp_gvalue[0].type = SNMP_COUNTER64;
uwsgi.shared->snmp_gvalue[0].val = &uwsgi.workers[0].requests;
for (i = 0; i < uwsgi.numproc; i++) {
uwsgi.shared->snmp_gvalue[30 + i].type = SNMP_COUNTER64;
uwsgi.shared->snmp_gvalue[30 + i].val = &uwsgi.workers[i + 1].requests;
}
if (uwsgi.snmp_addr) {
snmp_fd = bind_to_udp(uwsgi.snmp_addr, 0, 0);
if (snmp_fd < 0) {
uwsgi_log("unable to bind to udp socket. SNMP service will be disabled.\n");
}
else {
uwsgi_log("SNMP server enabled on %s\n", uwsgi.snmp_addr);
event_queue_add_fd_read(uwsgi.master_queue, snmp_fd);
}
}
else {
uwsgi_log("SNMP agent enabled.\n");
}
}
return snmp_fd;
}
#else
#warning "*** SNMP support is disabled ***"
#endif
+1779
View File
File diff suppressed because it is too large Load Diff
+61 -40
View File
@@ -15,22 +15,25 @@ static uint64_t wakeup = 0;
// function to allow waking up the spooler if blocked in event_wait
void spooler_wakeup() { wakeup++; }
void uwsgi_opt_add_spooler(char *opt, char *directory, void *none) {
void uwsgi_opt_add_spooler(char *opt, char *directory, void *mode) {
int i;
struct uwsgi_spooler *us;
if (access(directory, R_OK | W_OK | X_OK)) {
uwsgi_error("[spooler directory] access()");
exit(1);
uwsgi_error("[spooler directory] access()");
exit(1);
}
if (uwsgi.spooler_numproc > 0) {
for(i=0;i<uwsgi.spooler_numproc;i++) {
uwsgi_new_spooler(directory);
us = uwsgi_new_spooler(directory);
if (mode) us->mode = (long) mode;
}
}
else {
uwsgi_new_spooler(directory);
us = uwsgi_new_spooler(directory);
if (mode) us->mode = (long) mode;
}
}
@@ -41,13 +44,13 @@ struct uwsgi_spooler *uwsgi_new_spooler(char *dir) {
struct uwsgi_spooler *uspool = uwsgi.spoolers;
if (!uspool) {
uwsgi.spoolers = uwsgi_malloc_shared(sizeof(struct uwsgi_spooler));
uwsgi.spoolers = uwsgi_calloc_shared(sizeof(struct uwsgi_spooler));
uspool = uwsgi.spoolers;
}
else {
while(uspool) {
if (uspool->next == NULL) {
uspool->next = uwsgi_malloc_shared(sizeof(struct uwsgi_spooler));
uspool->next = uwsgi_calloc_shared(sizeof(struct uwsgi_spooler));
uspool = uspool->next;
break;
}
@@ -101,7 +104,7 @@ pid_t spooler_start(struct uwsgi_spooler *uspool) {
uwsgi_fixup_fds(0, 0, NULL);
uwsgi_close_all_sockets();
for (i = 0; i < 0xFF; i++) {
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->post_fork) {
uwsgi.p[i]->post_fork();
}
@@ -109,7 +112,7 @@ pid_t spooler_start(struct uwsgi_spooler *uspool) {
uwsgi.signal_socket = uwsgi.shared->spooler_signal_pipe[1];
for (i = 0; i < 0xFF; i++) {
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->spooler_init) {
uwsgi.p[i]->spooler_init();
}
@@ -237,7 +240,8 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core
// here the file will be unlocked too
close(fd);
uwsgi_log("[spooler] written %d bytes to file %s\n", size + body_len + 4, filename);
if (!uwsgi.spooler_quiet)
uwsgi_log("[spooler] written %d bytes to file %s\n", size + body_len + 4, filename);
// and here waiting threads can continue
uwsgi_unlock(uspool->lock);
@@ -309,6 +313,9 @@ void spooler(struct uwsgi_spooler *uspool) {
event_queue_add_fd_read(spooler_event_queue, uwsgi.shared->spooler_signal_pipe[1]);
}
// reset the tasks counter
uspool->tasks = 0;
for (;;) {
@@ -336,19 +343,7 @@ void spooler(struct uwsgi_spooler *uspool) {
if (event_queue_wait(spooler_event_queue, timeout, &interesting_fd) > 0) {
if (uwsgi.master_process) {
if (interesting_fd == uwsgi.shared->spooler_signal_pipe[1]) {
uint8_t uwsgi_signal;
if (read(interesting_fd, &uwsgi_signal, 1) <= 0) {
uwsgi_log_verbose("uWSGI spooler screams: UAAAAAAH my master died, i will follow him...\n");
end_me(0);
}
else {
#ifdef UWSGI_DEBUG
uwsgi_log_verbose("master sent signal %d to the spooler\n", uwsgi_signal);
#endif
if (uwsgi_signal_handler(uwsgi_signal)) {
uwsgi_log_verbose("error managing signal %d on the spooler\n", uwsgi_signal);
}
}
uwsgi_receive_signal(interesting_fd, "spooler", (int) getpid());
}
}
}
@@ -360,6 +355,12 @@ void spooler(struct uwsgi_spooler *uspool) {
}
wakeup = tmp_wakeup;
// need to recycle ?
if (uwsgi.spooler_max_tasks > 0 && uspool->tasks >= (uint64_t)uwsgi.spooler_max_tasks) {
uwsgi_log("[spooler %s pid: %d] maximum number of tasks reached (%d) recycling ...\n", uspool->dir, (int) uwsgi.mypid, uwsgi.spooler_max_tasks);
end_me(0);
}
}
}
@@ -426,7 +427,7 @@ void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) {
}
// a spool request for the future
if (sf_lstat.st_mtime > time(NULL)) {
if (sf_lstat.st_mtime > uwsgi_now()) {
return;
}
@@ -453,20 +454,30 @@ void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) {
spool_fd = open(task, O_RDWR);
if (spool_fd < 0) {
uwsgi_error_open(task);
if (errno != ENOENT)
uwsgi_error_open(task);
return;
}
// check if the file is locked by anther process
// check if the file is locked by another process
if (uwsgi_fcntl_is_locked(spool_fd)) {
close(spool_fd);
uwsgi_protected_close(spool_fd);
return;
}
if (read(spool_fd, &uh, 4) != 4) {
// unlink() can destroy the lock !!!
if (access(task, R_OK | W_OK)) {
uwsgi_protected_close(spool_fd);
return;
}
ssize_t rlen = uwsgi_protected_read(spool_fd, &uh, 4);
if (rlen != 4) {
// it could be here for broken file or just opened one
uwsgi_error("read()");
close(spool_fd);
if (rlen < 0)
uwsgi_error("read()");
uwsgi_protected_close(spool_fd);
return;
}
@@ -474,10 +485,10 @@ void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) {
uh.pktsize = uwsgi_swap16(uh.pktsize);
#endif
if (read(spool_fd, spool_buf, uh.pktsize) != uh.pktsize) {
if (uwsgi_protected_read(spool_fd, spool_buf, uh.pktsize) != uh.pktsize) {
uwsgi_error("read()");
destroy_spool(dir, task);
close(spool_fd);
uwsgi_protected_close(spool_fd);
return;
}
@@ -485,19 +496,20 @@ void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) {
if (sf_lstat.st_size > (uh.pktsize+4)) {
body_len = sf_lstat.st_size - (uh.pktsize+4);
body = uwsgi_malloc(body_len);
if ((size_t)read(spool_fd, body, body_len) != body_len) {
if ((size_t)uwsgi_protected_read(spool_fd, body, body_len) != body_len) {
uwsgi_error("read()");
destroy_spool(dir, task);
close(spool_fd);
uwsgi_protected_close(spool_fd);
free(body);
return;
}
}
// not the task is running and should not be waken
// now the task is running and should not be waken up
uspool->running = 1;
uwsgi_log("[spooler %s pid: %d] managing request %s ...\n", uspool->dir, (int) uwsgi.mypid, task);
if (!uwsgi.spooler_quiet)
uwsgi_log("[spooler %s pid: %d] managing request %s ...\n", uspool->dir, (int) uwsgi.mypid, task);
// chdir before running the task (if requested)
@@ -508,9 +520,9 @@ void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) {
}
int callable_found = 0;
for(i=0;i<0xff;i++) {
for(i=0;i<256;i++) {
if (uwsgi.p[i]->spooler) {
time_t now = time(NULL);
time_t now = uwsgi_now();
if(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
set_spooler_harakiri(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI]);
}
@@ -520,8 +532,11 @@ void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) {
}
if (ret == 0) continue;
callable_found = 1;
// increase task counter
uspool->tasks++;
if (ret == -2) {
uwsgi_log("[spooler %s pid: %d] done with task %s after %d seconds\n", uspool->dir, (int) uwsgi.mypid, task, time(NULL)-now);
if (!uwsgi.spooler_quiet)
uwsgi_log("[spooler %s pid: %d] done with task %s after %d seconds\n", uspool->dir, (int) uwsgi.mypid, task, uwsgi_now()-now);
destroy_spool(dir, task);
}
// re-spool it
@@ -533,9 +548,15 @@ void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) {
free(body);
// here we free and unlock the task
close(spool_fd);
uwsgi_protected_close(spool_fd);
uspool->running = 0;
if (chdir(dir)) {
uwsgi_error("chdir()");
uwsgi_log("[spooler] something horrible happened to the spooler. Better to kill it.\n");
exit(1);
}
if (!callable_found) {
uwsgi_log("unable to find the spooler function, have you loaded it into the spooler process ?\n");
}
View File
+266
View File
@@ -0,0 +1,266 @@
#include "uwsgi.h"
/*
utility functions for fast generating json output for the stats subsystem
*/
struct uwsgi_stats *uwsgi_stats_new(size_t chunk_size) {
struct uwsgi_stats *us = uwsgi_malloc(sizeof(struct uwsgi_stats));
us->base = uwsgi_malloc(chunk_size);
us->base[0] = '{';
us->base[1] = '\n';
us->pos = 2;
us->chunk = chunk_size;
us->size = chunk_size;
us->tabs = 1;
return us;
}
int uwsgi_stats_symbol(struct uwsgi_stats *us, char sym) {
char *ptr = us->base + us->pos;
char *watermark = us->base + us->size;
if (ptr+1 > watermark) {
char *new_base = realloc(us->base, us->size + us->chunk);
if (!new_base) return -1;
us->base = new_base;
us->size += us->chunk;
ptr = us->base + us->pos;
}
*ptr = sym;
us->pos++;
return 0;
}
int uwsgi_stats_symbol_nl(struct uwsgi_stats *us, char sym) {
if (uwsgi_stats_symbol(us, sym)) {
return -1;
}
return uwsgi_stats_symbol(us, '\n');
}
int uwsgi_stats_comma(struct uwsgi_stats *us) {
return uwsgi_stats_symbol_nl(us, ',');
}
int uwsgi_stats_apply_tabs(struct uwsgi_stats *us) {
size_t i;
for(i=0;i<us->tabs;i++) {
if (uwsgi_stats_symbol(us, '\t')) return -1;
};
return 0;
}
int uwsgi_stats_object_open(struct uwsgi_stats *us) {
if (uwsgi_stats_apply_tabs(us)) return -1;
us->tabs++;
return uwsgi_stats_symbol_nl(us, '{');
}
int uwsgi_stats_object_close(struct uwsgi_stats *us) {
if (uwsgi_stats_symbol(us, '\n')) return -1;
us->tabs--;
if (uwsgi_stats_apply_tabs(us)) return -1;
return uwsgi_stats_symbol(us, '}');
}
int uwsgi_stats_list_open(struct uwsgi_stats *us) {
us->tabs++;
return uwsgi_stats_symbol_nl(us, '[');
}
int uwsgi_stats_list_close(struct uwsgi_stats *us) {
if (uwsgi_stats_symbol(us, '\n')) return -1;
us->tabs--;
if (uwsgi_stats_apply_tabs(us)) return -1;
return uwsgi_stats_symbol(us, ']');
}
int uwsgi_stats_keyval(struct uwsgi_stats *us, char *key, char *value) {
if (uwsgi_stats_apply_tabs(us)) return -1;
char *ptr = us->base + us->pos;
char *watermark = us->base + us->size;
size_t available = watermark - ptr ;
int ret = snprintf(ptr, available, "\"%s\":\"%s\"", key, value);
if (ret < 0) return -1;
while (ret >= (int) available) {
char *new_base = realloc(us->base, us->size + us->chunk);
if (!new_base) return -1;
us->base = new_base;
us->size += us->chunk;
ptr = us->base + us->pos;
watermark = us->base + us->size;
available = watermark - ptr ;
ret = snprintf(ptr, available, "\"%s\":\"%s\"", key, value);
if (ret < 0) return -1;
}
us->pos += ret;
return 0;
}
int uwsgi_stats_keyval_comma(struct uwsgi_stats *us, char *key, char *value) {
int ret = uwsgi_stats_keyval(us, key, value);
if (ret) return -1;
return uwsgi_stats_comma(us);
}
int uwsgi_stats_keyvalnum(struct uwsgi_stats *us, char *key, char *value, unsigned long long num) {
if (uwsgi_stats_apply_tabs(us)) return -1;
char *ptr = us->base + us->pos;
char *watermark = us->base + us->size;
size_t available = watermark - ptr ;
int ret = snprintf(ptr, available, "\"%s\":\"%s%llu\"", key, value, num);
if (ret < 0) return -1;
while (ret >= (int) available) {
char *new_base = realloc(us->base, us->size + us->chunk);
if (!new_base) return -1;
us->base = new_base;
us->size += us->chunk;
ptr = us->base + us->pos;
watermark = us->base + us->size;
available = watermark - ptr ;
ret = snprintf(ptr, available, "\"%s\":\"%s%llu\"", key, value, num);
if (ret < 0) return -1;
}
us->pos += ret;
return 0;
}
int uwsgi_stats_keyvalnum_comma(struct uwsgi_stats *us, char *key, char *value, unsigned long long num) {
int ret = uwsgi_stats_keyvalnum(us, key, value, num);
if (ret) return -1;
return uwsgi_stats_comma(us);
}
int uwsgi_stats_keyvaln(struct uwsgi_stats *us, char *key, char *value, int vallen) {
if (uwsgi_stats_apply_tabs(us)) return -1;
char *ptr = us->base + us->pos;
char *watermark = us->base + us->size;
size_t available = watermark - ptr ;
int ret = snprintf(ptr, available, "\"%s\":\"%.*s\"", key, vallen, value);
if (ret < 0) return -1;
while (ret >= (int) available) {
char *new_base = realloc(us->base, us->size + us->chunk);
if (!new_base) return -1;
us->base = new_base;
us->size += us->chunk;
ptr = us->base + us->pos;
watermark = us->base + us->size;
available = watermark - ptr ;
ret = snprintf(ptr, available, "\"%s\":\"%.*s\"", key, vallen, value);
if (ret < 0) return -1;
}
us->pos += ret;
return 0;
}
int uwsgi_stats_keyvaln_comma(struct uwsgi_stats *us, char *key, char *value, int vallen) {
int ret = uwsgi_stats_keyvaln(us, key, value, vallen);
if (ret) return -1;
return uwsgi_stats_comma(us);
}
int uwsgi_stats_key(struct uwsgi_stats *us, char *key) {
if (uwsgi_stats_apply_tabs(us)) return -1;
char *ptr = us->base + us->pos;
char *watermark = us->base + us->size;
size_t available = watermark - ptr ;
int ret = snprintf(ptr, available, "\"%s\":", key);
if (ret < 0) return -1;
while (ret >= (int) available) {
char *new_base = realloc(us->base, us->size + us->chunk);
if (!new_base) return -1;
us->base = new_base;
us->size += us->chunk;
ptr = us->base + us->pos;
watermark = us->base + us->size;
available = watermark - ptr ;
ret = snprintf(ptr, available, "\"%s\":", key);
if (ret < 0) return -1;
}
us->pos += ret;
return 0;
}
int uwsgi_stats_str(struct uwsgi_stats *us, char *str) {
char *ptr = us->base + us->pos;
char *watermark = us->base + us->size;
size_t available = watermark - ptr ;
int ret = snprintf(ptr, available, "\"%s\"", str);
if (ret < 0) return -1;
while (ret >= (int) available) {
char *new_base = realloc(us->base, us->size + us->chunk);
if (!new_base) return -1;
us->base = new_base;
us->size += us->chunk;
ptr = us->base + us->pos;
watermark = us->base + us->size;
available = watermark - ptr ;
ret = snprintf(ptr, available, "\"%s\"", str);
if (ret < 0) return -1;
}
us->pos += ret;
return 0;
}
int uwsgi_stats_keylong(struct uwsgi_stats *us, char *key, unsigned long long num) {
if (uwsgi_stats_apply_tabs(us)) return -1;
char *ptr = us->base + us->pos;
char *watermark = us->base + us->size;
size_t available = watermark - ptr ;
int ret = snprintf(ptr, available, "\"%s\":%llu", key, num);
if (ret < 0) return -1;
while (ret >= (int) available) {
char *new_base = realloc(us->base, us->size + us->chunk);
if (!new_base) return -1;
us->base = new_base;
us->size += us->chunk;
ptr = us->base + us->pos;
watermark = us->base + us->size;
available = watermark - ptr ;
ret = snprintf(ptr, available, "\"%s\":%llu", key, num);
if (ret < 0) return -1;
}
us->pos += ret;
return 0;
}
int uwsgi_stats_keylong_comma(struct uwsgi_stats *us, char *key, unsigned long long num) {
int ret = uwsgi_stats_keylong(us, key, num);
if (ret) return -1;
return uwsgi_stats_comma(us);
}
+257 -59
View File
@@ -18,14 +18,19 @@
*/
extern struct uwsgi_server uwsgi;
struct uwsgi_subscribe_slot *uwsgi_get_subscribe_slot(struct uwsgi_subscribe_slot **slot, char *key, uint16_t keylen, int regexp) {
struct uwsgi_subscribe_slot *current_slot = *slot;
if (keylen > 0xff) return NULL;
uint32_t hash = djb33x_hash(key, keylen);
int hash_key = hash % 0xffff;
struct uwsgi_subscribe_slot *current_slot = slot[hash_key];
#ifdef UWSGI_DEBUG
uwsgi_log("****************************\n");
while(current_slot) {
@@ -33,10 +38,9 @@ struct uwsgi_subscribe_slot *uwsgi_get_subscribe_slot(struct uwsgi_subscribe_slo
current_slot = current_slot->next;
}
uwsgi_log("****************************\n");
current_slot = slot[hash_key];
#endif
current_slot = *slot;
while(current_slot) {
#ifdef UWSGI_PCRE
if (regexp) {
@@ -55,7 +59,7 @@ struct uwsgi_subscribe_slot *uwsgi_get_subscribe_slot(struct uwsgi_subscribe_slo
slot_parent->next = current_slot;
}
else {
*slot = current_slot;
slot[hash_key] = current_slot;
}
if (current_slot->next) {
@@ -77,7 +81,7 @@ struct uwsgi_subscribe_slot *uwsgi_get_subscribe_slot(struct uwsgi_subscribe_slo
#endif
current_slot = current_slot->next;
// check for loopy optimization
if (current_slot == *slot) break;
if (current_slot == slot[hash_key]) break;
}
return NULL;
@@ -88,21 +92,21 @@ struct uwsgi_subscribe_node *uwsgi_get_subscribe_node(struct uwsgi_subscribe_slo
if (keylen > 0xff) return NULL;
struct uwsgi_subscribe_slot *current_slot = uwsgi_get_subscribe_slot(slot, key, keylen, regexp);
uint64_t rr_pos = 0;
if (current_slot) {
// node found, move up in the list increasing hits
// slot found, move up in the list increasing hits
current_slot->hits++;
time_t current = time(NULL);
time_t now = uwsgi_now();
struct uwsgi_subscribe_node *node = current_slot->nodes;
while(node) {
// is the node alive ?
if (current - node->last_check > uwsgi.subscription_tolerance) {
if (now - node->last_check > uwsgi.subscription_tolerance) {
if (node->death_mark == 0)
uwsgi_log("[uwsgi-subscription for pid %d] %.*s => marking %.*s as failed (no announce received in %d seconds)\n", (int) uwsgi.mypid, (int) keylen, key, (int) node->len, node->name, uwsgi.subscription_tolerance);
node->failcnt++;
node->death_mark = 1;
}
// is the node must be removed ?
if (node->death_mark && node->reference == 0) {
// remove the node and move to next
struct uwsgi_subscribe_node *dead_node = node;
@@ -114,38 +118,40 @@ struct uwsgi_subscribe_node *uwsgi_get_subscribe_node(struct uwsgi_subscribe_slo
continue;
}
if (node->death_mark == 0 && rr_pos == current_slot->rr && node->wrr > 0) {
if (node->death_mark == 0 && node->wrr > 0) {
node->wrr--;
if (node->wrr == 0) {
current_slot->rr++;
// if this is the last node, recalculate wrr
if (node->next == NULL) {
struct uwsgi_subscribe_node *r_node = current_slot->nodes;
while(r_node) {
r_node->wrr = r_node->weight;
r_node = r_node->next;
}
}
}
node->reference++;
return node;
}
node = node->next;
rr_pos++;
}
current_slot->rr = 1;
if (current_slot->nodes) {
if (current_slot->nodes->death_mark)
return NULL;
if (current_slot->nodes->wrr == 0) current_slot->nodes->wrr = current_slot->nodes->weight;
current_slot->nodes->wrr--;
if (current_slot->nodes->wrr > 0) {
// reset rr counter
current_slot->rr = 0;
// no wrr > 0 node found, reset them
node = current_slot->nodes;
uint64_t min_weight = 0;
while(node) {
if (!node->death_mark) {
if (min_weight == 0 || node->weight < min_weight) min_weight = node->weight;
}
current_slot->nodes->reference++;
node = node->next;
}
return current_slot->nodes;
// now set wrr
node = current_slot->nodes;
struct uwsgi_subscribe_node *choosen_node = NULL;
while(node) {
if (!node->death_mark) {
node->wrr = node->weight/min_weight;
choosen_node = node;
}
node = node->next;
}
if (choosen_node) {
choosen_node->wrr--;
choosen_node->reference++;
}
return choosen_node;
}
return NULL;
@@ -177,6 +183,8 @@ int uwsgi_remove_subscribe_node(struct uwsgi_subscribe_slot **slot, struct uwsgi
struct uwsgi_subscribe_slot *prev_slot = node_slot->prev;
struct uwsgi_subscribe_slot *next_slot = node_slot->next;
int hash_key = node_slot->hash;
// over-engineering to avoid race conditions
node->len = 0;
@@ -202,14 +210,28 @@ 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_PCRE
if (node_slot->pattern) {
pcre_free(node_slot->pattern);
}
if (node_slot->pattern_extra) {
pcre_free(node_slot->pattern_extra);
}
#endif
#ifdef UWSGI_SSL
if (uwsgi.subscriptions_sign_check_dir) {
EVP_PKEY_free(node_slot->sign_public_key);
EVP_MD_CTX_destroy(node_slot->sign_ctx);
}
#endif
free(node_slot);
*slot = NULL;
slot[hash_key] = NULL;
goto end;
}
// if i am the main entry point, set the next value
if (node_slot == *slot) {
*slot = next_slot;
if (node_slot == slot[hash_key]) {
slot[hash_key] = next_slot;
}
if (prev_slot) {
@@ -227,7 +249,12 @@ int uwsgi_remove_subscribe_node(struct uwsgi_subscribe_slot **slot, struct uwsgi
pcre_free(node_slot->pattern_extra);
}
#endif
#ifdef UWSGI_SSL
if (uwsgi.subscriptions_sign_check_dir) {
EVP_PKEY_free(node_slot->sign_public_key);
EVP_MD_CTX_destroy(node_slot->sign_ctx);
}
#endif
free(node_slot);
}
@@ -241,15 +268,33 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
struct uwsgi_subscribe_slot *current_slot = uwsgi_get_subscribe_slot(slot, usr->key, usr->keylen, 0), *old_slot = NULL, *a_slot;
struct uwsgi_subscribe_node *node, *old_node = NULL;
if (usr->address_len > 0xff) return NULL;
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
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) {
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;
}
#endif
// remove death mark and update cores and load
node->death_mark = 0;
node->last_check = time(NULL);
node->last_check = uwsgi_now();
node->cores = usr->cores;
node->load = usr->load;
node->weight = usr->weight;
@@ -260,6 +305,13 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
node = node->next;
}
#ifdef UWSGI_SSL
if (uwsgi.subscriptions_sign_check_dir && 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;
}
#endif
node = uwsgi_malloc(sizeof(struct uwsgi_subscribe_node));
node->len = usr->address_len;
node->modifier1 = usr->modifier1;
@@ -272,9 +324,10 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
node->cores = usr->cores;
node->load = usr->load;
node->weight = usr->weight;
node->unix_check = usr->unix_check;
if (!node->weight) node->weight = 1;
node->wrr = node->weight;
node->last_check = time(NULL);
node->wrr = 0;
node->last_check = uwsgi_now();
node->slot = current_slot;
memcpy(node->name, usr->address, usr->address_len);
if (old_node) {
@@ -285,13 +338,53 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
return node;
}
else {
#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;
}
#endif
current_slot = uwsgi_malloc(sizeof(struct uwsgi_subscribe_slot));
uint32_t hash = djb33x_hash(usr->key, usr->keylen);
int hash_key = hash % 0xffff;
current_slot->hash = hash_key;
#ifdef UWSGI_SSL
if (uwsgi.subscriptions_sign_check_dir) {
current_slot->sign_public_key = PEM_read_PUBKEY(kf, NULL, NULL, NULL);
fclose(kf);
if (!current_slot->sign_public_key) {
uwsgi_log("unable to load public key for %.*s\n", usr->keylen, usr->key);
free(current_slot);
return NULL;
}
current_slot->sign_ctx = EVP_MD_CTX_create();
if (!current_slot->sign_ctx) {
uwsgi_log("unable to initialize EVP context for %.*s\n", usr->keylen, usr->key);
EVP_PKEY_free(current_slot->sign_public_key);
free(current_slot);
return NULL;
}
if (!uwsgi_subscription_sign_check(current_slot, usr)) {
EVP_PKEY_free(current_slot->sign_public_key);
EVP_MD_CTX_destroy(current_slot->sign_ctx);
free(current_slot);
return NULL;
}
}
#endif
current_slot->keylen = usr->keylen;
memcpy(current_slot->key, usr->key, usr->keylen);
current_slot->key[usr->keylen] = 0;
current_slot->hits = 0;
current_slot->rr = 0;
#ifdef UWSGI_PCRE
current_slot->pattern = NULL;
@@ -317,10 +410,11 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
current_slot->nodes->cores = usr->cores;
current_slot->nodes->load = usr->load;
current_slot->nodes->weight = usr->weight;
current_slot->nodes->unix_check = usr->unix_check;
if (!current_slot->nodes->weight) current_slot->nodes->weight = 1;
current_slot->nodes->wrr = current_slot->nodes->weight;
current_slot->nodes->wrr = 0;
memcpy(current_slot->nodes->name, usr->address, usr->address_len);
current_slot->nodes->last_check = time(NULL);
current_slot->nodes->last_check = uwsgi_now();
current_slot->nodes->next = NULL;
@@ -328,7 +422,7 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
// if key is a regexp, order it by keylen
if (regexp) {
old_slot = NULL;
a_slot = *slot;
a_slot = slot[hash_key];
while(a_slot) {
if (a_slot->keylen > current_slot->keylen) {
old_slot = a_slot;
@@ -347,7 +441,7 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
current_slot->next = old_slot;
}
else {
a_slot = *slot;
a_slot = slot[hash_key];
while(a_slot) {
old_slot = a_slot;
a_slot = a_slot->next;
@@ -364,7 +458,7 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
}
else {
#endif
a_slot = *slot;
a_slot = slot[hash_key];
while(a_slot) {
old_slot = a_slot;
a_slot = a_slot->next;
@@ -382,11 +476,11 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
}
#endif
if (!*slot || current_slot->prev == NULL) {
*slot = current_slot;
if (!slot[hash_key] || current_slot->prev == NULL) {
slot[hash_key] = current_slot;
}
uwsgi_log("[uwsgi-subscription for pid %d] new pool: %.*s\n",(int) uwsgi.mypid, usr->keylen, usr->key);
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);
return current_slot->nodes;
}
@@ -394,7 +488,7 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
}
void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8_t modifier1, uint8_t modifier2, uint8_t cmd) {
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 value_cores[sizeof(UMAX64_STR)+1];
char value_load[sizeof(UMAX64_STR)+1];
@@ -418,10 +512,14 @@ void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8
int value_modifier1_size = uwsgi_long2str2n(modifier1, value_modifier1, 3);
int value_modifier2_size = uwsgi_long2str2n(modifier2, value_modifier2, 3);
if (!uwsgi.sockets) return;
if (socket_name == NULL && !uwsgi.sockets) return;
size_t ssb_size = 4 + (2 + 3) + (2 + keysize) + (2 + 7) + (2 + strlen(uwsgi.sockets->name)) + (2+9 + 2+value_modifier1_size) +
(2+9 + 2+value_modifier2_size) + (2+5 + 2+value_cores_size) + (2+4 + 2+value_load_size) + (2+5 + 2+value_weight_size);
if (!socket_name) {
socket_name = uwsgi.sockets->name;
}
size_t ssb_size = 4 + (2 + 3) + (2 + keysize) + (2 + 7) + (2 + strlen(socket_name)) + (2+9 + 2+value_modifier1_size) +
(2+9 + 2+value_modifier2_size) + (2+5 + 2+value_cores_size) + (2+4 + 2+value_load_size) + (2+6 + 2+value_weight_size);
char *subscrbuf = uwsgi_malloc(ssb_size);
// leave space for uwsgi header
@@ -447,10 +545,10 @@ void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8
memcpy(ssb, "address", ustrlen);
ssb+=ustrlen;
ustrlen = strlen(uwsgi.sockets->name);
ustrlen = strlen(socket_name);
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >>8) & 0xff);
memcpy(ssb, uwsgi.sockets->name, ustrlen);
memcpy(ssb, socket_name, ustrlen);
ssb+=ustrlen;
// modifier1 = "modifier1"
@@ -506,7 +604,7 @@ void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8
ssb+=ustrlen;
// weight
ustrlen = 5;
ustrlen = 6;
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >>8) & 0xff);
memcpy(ssb, "weight", ustrlen);
@@ -517,9 +615,109 @@ void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8
*ssb++ = (uint8_t) ((ustrlen >>8) & 0xff);
memcpy(ssb, value_weight, value_weight_size);
ssb+=ustrlen;
#ifdef UWSGI_SSL
if (sign) {
// add space for "unix" item
char unix_dst[sizeof(UMAX64_STR)+1];
if (snprintf(unix_dst, sizeof(UMAX64_STR)+1, "%lu", (unsigned long) (uwsgi_now() + (time_t)cmd)) < 1) {
uwsgi_error("unable to generate unix time for subscription !!!\n");
free(subscrbuf);
return;
}
ssb_size += 2 + 4 + 2 + strlen(unix_dst);
char *new_buf = realloc(subscrbuf, ssb_size);
if (!new_buf) {
uwsgi_error("realloc()");
free(subscrbuf);
return;
}
// fix ssb (new_buf base could be changed)
ssb = (new_buf + (ssb-subscrbuf));
subscrbuf = new_buf;
ustrlen = 4;
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >>8) & 0xff);
memcpy(ssb, "unix", ustrlen);
ssb+=ustrlen;
ustrlen = strlen(unix_dst);
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >>8) & 0xff);
memcpy(ssb, unix_dst, strlen(unix_dst));
ssb+=ustrlen;
unsigned int signature_len = 0;
char *signature = uwsgi_rsa_sign(sign, subscrbuf+4, ssb_size-4, &signature_len);
if (signature && signature_len > 0) {
// add space for "sign" item
ssb_size += 2 + 4 + 2 + signature_len;
char *new_buf = realloc(subscrbuf, ssb_size);
if (!new_buf) {
uwsgi_error("realloc()");
free(signature);
free(subscrbuf);
return;
}
// fix ssb (new_buf base could be changed)
ssb = (new_buf + (ssb-subscrbuf));
subscrbuf = new_buf;
ustrlen = 4;
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >>8) & 0xff);
memcpy(ssb, "sign", ustrlen);
ssb+=ustrlen;
ustrlen = signature_len;
*ssb++ = (uint8_t) (ustrlen & 0xff);
*ssb++ = (uint8_t) ((ustrlen >>8) & 0xff);
memcpy(ssb, signature, signature_len);
ssb+=ustrlen;
free(signature);
}
}
#endif
send_udp_message(224, cmd, udp_address, subscrbuf, ssb_size-4);
free(subscrbuf);
}
#ifdef UWSGI_SSL
int uwsgi_subscription_sign_check(struct uwsgi_subscribe_slot *slot, struct uwsgi_subscribe_req *usr) {
if (EVP_VerifyInit_ex(slot->sign_ctx, uwsgi.subscriptions_sign_check_md, NULL) == 0) {
ERR_print_errors_fp(stderr);
return 0;
}
if (EVP_VerifyUpdate(slot->sign_ctx, usr->base, usr->base_len) == 0) {
ERR_print_errors_fp(stderr);
return 0;
}
if (EVP_VerifyFinal(slot->sign_ctx, (unsigned char *)usr->sign, usr->sign_len, slot->sign_public_key) != 1) {
#ifdef UWSGI_DEBUG
ERR_print_errors_fp(stderr);
#endif
return 0;
}
return 1;
}
#endif
int uwsgi_no_subscriptions(struct uwsgi_subscribe_slot **slot) {
int i;
for(i=0;i<UMAX16;i++) {
if (slot[i]) return 0;
}
return 1;
}
+1774 -1036
View File
File diff suppressed because it is too large Load Diff
+1432 -1605
View File
File diff suppressed because it is too large Load Diff
View File
View File
-924
View File
@@ -1,924 +0,0 @@
#include "uwsgi.h"
#include <glob.h>
extern struct uwsgi_server uwsgi;
extern char **environ;
int emperor_queue;
char *emperor_absolute_dir;
void emperor_send_stats(int);
struct uwsgi_instance {
struct uwsgi_instance *ui_prev;
struct uwsgi_instance *ui_next;
char name[0xff];
pid_t pid;
int status;
time_t born;
time_t last_mod;
time_t last_loyal;
uint64_t respawns;
int use_config;
int pipe[2];
int pipe_config[2];
char *config;
uint32_t config_len;
int loyal;
int zerg;
uid_t uid;
gid_t gid;
};
struct uwsgi_instance *ui;
static void royal_death(int signum) {
if (uwsgi.vassals_stop_hook) {
struct uwsgi_instance *c_ui = ui->ui_next;
while (c_ui) {
uwsgi_log("running vassal stop-hook: %s %s\n", uwsgi.vassals_stop_hook, c_ui->name);
if (setenv("UWSGI_VASSALS_DIR", emperor_absolute_dir, 1)) {
uwsgi_error("setenv()");
}
int stop_hook_ret = uwsgi_run_command_and_wait(uwsgi.vassals_stop_hook, c_ui->name);
uwsgi_log("%s stop-hook returned %d\n", c_ui->name, stop_hook_ret);
c_ui = c_ui->ui_next;
}
}
uwsgi_notify("The Emperor is buried.");
exit(0);
}
void emperor_stats() {
struct uwsgi_instance *c_ui = ui->ui_next;
while (c_ui) {
uwsgi_log("vassal instance %s (last modified %d) status %d loyal %d zerg %d\n",c_ui->name, c_ui->last_mod, c_ui->status, c_ui->loyal, c_ui->zerg);
c_ui = c_ui->ui_next;
}
}
struct uwsgi_instance *emperor_get_by_fd(int fd) {
struct uwsgi_instance *c_ui = ui;
while (c_ui->ui_next) {
c_ui = c_ui->ui_next;
if (c_ui->pipe[0] == fd) {
return c_ui;
}
}
return NULL;
}
struct uwsgi_instance *emperor_get(char *name) {
struct uwsgi_instance *c_ui = ui;
while (c_ui->ui_next) {
c_ui = c_ui->ui_next;
if (!strcmp(c_ui->name, name)) {
return c_ui;
}
}
return NULL;
}
void emperor_del(struct uwsgi_instance *c_ui) {
struct uwsgi_instance *parent_ui = c_ui->ui_prev;
struct uwsgi_instance *child_ui = c_ui->ui_next;
parent_ui->ui_next = child_ui;
if (child_ui) {
child_ui->ui_prev = parent_ui;
}
// this will destroy the whole uWSGI instance (and workers)
close(c_ui->pipe[0]);
if (c_ui->use_config) {
close(c_ui->pipe_config[0]);
}
if (uwsgi.vassals_stop_hook) {
uwsgi_log("running vassal stop-hook: %s %s\n", uwsgi.vassals_stop_hook, c_ui->name);
if (setenv("UWSGI_VASSALS_DIR", emperor_absolute_dir, 1)) {
uwsgi_error("setenv()");
}
int stop_hook_ret = uwsgi_run_command_and_wait(uwsgi.vassals_stop_hook, c_ui->name);
uwsgi_log("%s stop-hook returned %d\n", c_ui->name, stop_hook_ret);
}
uwsgi_log("removed uwsgi instance %s\n", c_ui->name);
if (c_ui->zerg) {
uwsgi.emperor_broodlord_count--;
}
free(c_ui);
}
void emperor_stop(struct uwsgi_instance *c_ui) {
// remove uWSGI instance
if (write(c_ui->pipe[0], "\0", 1) != 1) {
uwsgi_error("write()");
}
c_ui->status = 1;
uwsgi_log("stop the uwsgi instance %s\n", c_ui->name);
}
void emperor_respawn(struct uwsgi_instance *c_ui, time_t mod) {
// reload the uWSGI instance
if (c_ui->use_config) {
if (write(c_ui->pipe[0], "\0", 1) != 1) {
uwsgi_error("write()");
}
}
else {
if (write(c_ui->pipe[0], "\1", 1) != 1) {
uwsgi_error("write()");
}
}
c_ui->respawns++;
c_ui->last_mod = mod;
uwsgi_log("[emperor] reload the uwsgi instance %s\n", c_ui->name);
}
void emperor_add(char *name, time_t born, char *config, uint32_t config_size, uid_t uid, gid_t gid) {
struct uwsgi_instance *c_ui = ui;
struct uwsgi_instance *n_ui = NULL;
pid_t pid;
char **vassal_argv;
char *uef;
char **uenvs;
int counter;
char *colon = NULL;
int i;
usleep(uwsgi.emperor_throttle*1000);
if (uwsgi.emperor_tyrant) {
if (uid == 0 || gid == 0) {
uwsgi_log("[emperor-tyrant] invalid permissions for file %s\n", name);
return;
}
}
while (c_ui->ui_next) {
c_ui = c_ui->ui_next;
}
n_ui = uwsgi_malloc(sizeof(struct uwsgi_instance));
memset(n_ui, 0, sizeof(struct uwsgi_instance));
if (config) {
n_ui->use_config = 1;
n_ui->config = config;
n_ui->config_len = config_size;
}
c_ui->ui_next = n_ui;
#ifdef UWSGI_DEBUG
uwsgi_log("c_ui->ui_next = %p\n", c_ui->ui_next);
#endif
n_ui->ui_prev = c_ui;
if (strchr(name,':')) {
n_ui->zerg = 1;
uwsgi.emperor_broodlord_count++;
}
memcpy(n_ui->name, name, strlen(name));
n_ui->born = born;
n_ui->uid = uid;
n_ui->gid = gid;
n_ui->last_mod = born;
// start without loyalty
n_ui->last_loyal = born;
n_ui->loyal = 0;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe)) {
uwsgi_error("socketpair()");
goto clear;
}
event_queue_add_fd_read(emperor_queue, n_ui->pipe[0]);
if (n_ui->use_config) {
if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe_config)) {
uwsgi_error("socketpair()");
goto clear;
}
}
// TODO pre-start hook
// a new uWSGI instance will start
pid = fork();
if (pid < 0) {
uwsgi_error("fork()")
}
else if (pid > 0) {
n_ui->pid = pid;
// close the right side of the pipe
close(n_ui->pipe[1]);
if (n_ui->use_config) {
close(n_ui->pipe_config[1]);
}
if (n_ui->use_config) {
if (write(n_ui->pipe_config[0], n_ui->config, n_ui->config_len) <= 0) {
uwsgi_error("write()");
}
close(n_ui->pipe_config[0]);
}
return;
}
else {
if (uwsgi.emperor_tyrant) {
uwsgi_log("[emperor-tyrant] dropping privileges to %d %d for instance %s\n", (int) uid, (int) gid, name);
if (setgid(gid)) {
uwsgi_error("setgid()");
exit(1);
}
if (setgroups(0, NULL)) {
uwsgi_error("setgroups()");
exit(1);
}
if (setuid(uid)) {
uwsgi_error("setuid()");
exit(1);
}
}
unsetenv("UWSGI_RELOADS");
unsetenv("NOTIFY_SOCKET");
uef = uwsgi_num2str(n_ui->pipe[1]);
if (setenv("UWSGI_EMPEROR_FD", uef, 1)) {
uwsgi_error("setenv()");
exit(1);
}
free(uef);
if (n_ui->use_config) {
uef = uwsgi_num2str(n_ui->pipe_config[1]);
if (setenv("UWSGI_EMPEROR_FD_CONFIG", uef, 1)) {
uwsgi_error("setenv()");
exit(1);
}
free(uef);
}
uenvs = environ;
while (*uenvs) {
if (!strncmp(*uenvs, "UWSGI_VASSAL_", 13)) {
char *ne = uwsgi_concat2("UWSGI_", *uenvs + 13);
char *oe = uwsgi_concat2n(*uenvs, strchr(*uenvs, '=') - *uenvs, "", 0);
if (unsetenv(oe)) {
uwsgi_error("unsetenv()");
break;
}
free(oe);
#ifdef UWSGI_DEBUG
uwsgi_log("putenv %s\n", ne);
#endif
if (putenv(ne)) {
uwsgi_error("putenv()");
}
// do not free ne as putenv will add it to the environ
uenvs = environ;
continue;
}
uenvs++;
}
// close the left side of the pipe
close(n_ui->pipe[0]);
if (n_ui->use_config) {
close(n_ui->pipe_config[0]);
}
counter = 4;
struct uwsgi_string_list *uct = uwsgi.vassals_templates;
while(uct) {
counter+=2;
uct = uct->next;
}
vassal_argv = uwsgi_malloc(sizeof(char *) * counter);
// set args
vassal_argv[0] = uwsgi.binary_path;
if (uwsgi.emperor_broodlord) {
colon = strchr(name, ':');
if (colon) {
colon[0] = 0;
}
}
if (!strcmp(name + (strlen(name) - 4), ".xml"))
vassal_argv[1] = "--xml";
if (!strcmp(name + (strlen(name) - 4), ".ini"))
vassal_argv[1] = "--ini";
if (!strcmp(name + (strlen(name) - 4), ".yml"))
vassal_argv[1] = "--yaml";
if (!strcmp(name + (strlen(name) - 5), ".yaml"))
vassal_argv[1] = "--yaml";
if (!strcmp(name + (strlen(name) - 3), ".js"))
vassal_argv[1] = "--json";
if (!strcmp(name + (strlen(name) - 5), ".json"))
vassal_argv[1] = "--json";
if (colon) {
colon[0] = ':';
}
vassal_argv[2] = name;
counter = 3;
uct = uwsgi.vassals_templates;
while(uct) {
vassal_argv[counter] = "--inherit";
vassal_argv[counter+1] = uct->value;
counter+=2;
uct = uct->next;
}
vassal_argv[counter] = NULL;
// disable stdin
int stdin_fd = open("/dev/null", O_RDONLY);
if (stdin_fd < 0) {
uwsgi_error_open("/dev/null");
exit(1);
}
if (stdin_fd != 0) {
if (dup2(stdin_fd, 0)) {
uwsgi_error("dup2()");
exit(1);
}
close(stdin_fd);
}
// close all of the unneded fd
for(i=3;i<(int)uwsgi.max_fd;i++) {
if (i != n_ui->pipe[1]) {
close(i);
}
}
if (uwsgi.vassals_start_hook) {
uwsgi_log("running vassal start-hook: %s %s\n", uwsgi.vassals_start_hook, n_ui->name);
if (setenv("UWSGI_VASSALS_DIR", emperor_absolute_dir, 1)) {
uwsgi_error("setenv()");
}
int start_hook_ret = uwsgi_run_command_and_wait(uwsgi.vassals_start_hook, n_ui->name);
uwsgi_log("%s start-hook returned %d\n", n_ui->name, start_hook_ret);
}
// start !!!
if (execvp(vassal_argv[0], vassal_argv)) {
uwsgi_error("execvp()");
}
uwsgi_log("is the uwsgi binary in your system PATH ?\n");
// never here
exit(UWSGI_EXILE_CODE);
}
clear:
free(n_ui);
c_ui->ui_next = NULL;
}
void emperor_loop() {
// monitor a directory
struct uwsgi_instance ui_base;
struct uwsgi_instance *ui_current;
struct stat st;
pid_t diedpid;
int waitpid_status;
int has_children = 0;
int i_am_alone = 0;
int simple_mode = 0;
glob_t g;
int i;
struct dirent *de;
char *amqp_port;
int amqp_fd = -1;
char *amqp_routing_key;
void *events;
int nevents;
int interesting_fd;
char notification_message[64];
struct rlimit rl;
uwsgi.emperor_stats_fd = -1;
signal(SIGPIPE, SIG_IGN);
uwsgi_unix_signal(SIGINT, royal_death);
uwsgi_unix_signal(SIGTERM, royal_death);
uwsgi_unix_signal(SIGQUIT, royal_death);
uwsgi_unix_signal(SIGUSR1, emperor_stats);
memset(&ui_base, 0, sizeof(struct uwsgi_instance));
if (getrlimit(RLIMIT_NOFILE, &rl)) {
uwsgi_error("getrlimit()");
exit(1);
}
uwsgi.max_fd = rl.rlim_cur;
emperor_queue = event_queue_init();
events = event_queue_alloc(64);
if (uwsgi.has_emperor) {
uwsgi_log("*** starting uWSGI sub-Emperor ***\n");
}
else {
uwsgi_log("*** starting uWSGI Emperor ***\n");
}
if (uwsgi.emperor_stats) {
char *tcp_port = strchr(uwsgi.emperor_stats, ':');
if (tcp_port) {
// disable deferred accept for this socket
int current_defer_accept = uwsgi.no_defer_accept;
uwsgi.no_defer_accept = 1;
uwsgi.emperor_stats_fd = bind_to_tcp(uwsgi.emperor_stats, uwsgi.listen_queue, tcp_port);
uwsgi.no_defer_accept = current_defer_accept;
}
else {
uwsgi.emperor_stats_fd = bind_to_unix(uwsgi.emperor_stats, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
}
event_queue_add_fd_read(emperor_queue, uwsgi.emperor_stats_fd);
uwsgi_log("*** Emperor stats server enabled on %s fd: %d ***\n", uwsgi.emperor_stats, uwsgi.emperor_stats_fd);
}
amqp_port = strchr(uwsgi.emperor_dir, ':');
if (amqp_port) {
if (uwsgi.emperor_amqp_vhost == NULL) uwsgi.emperor_amqp_vhost = "/";
if (uwsgi.emperor_amqp_username == NULL) uwsgi.emperor_amqp_username = "guest";
if (uwsgi.emperor_amqp_password == NULL) uwsgi.emperor_amqp_password = "guest";
reconnect:
while(amqp_fd == -1) {
uwsgi_log("connecting to AMQP server...\n");
amqp_fd = uwsgi_connect(uwsgi.emperor_dir, -1, 0);
if (amqp_fd < 0) {
sleep(1);
}
}
uwsgi_log("subscribing to queue...\n");
if (uwsgi_amqp_consume_queue(amqp_fd, uwsgi.emperor_amqp_vhost, uwsgi.emperor_amqp_username, uwsgi.emperor_amqp_password, "", "uwsgi.emperor", "fanout") < 0) {
close(amqp_fd);
amqp_fd = -1;
sleep(1);
goto reconnect;
}
event_queue_add_fd_read(emperor_queue, amqp_fd);
}
else {
if (!glob(uwsgi.emperor_dir, GLOB_MARK|GLOB_NOCHECK, NULL, &g)) {
if (g.gl_pathc == 1 && g.gl_pathv[0][strlen(g.gl_pathv[0]) - 1] == '/') {
simple_mode = 1;
if (chdir(uwsgi.emperor_dir)) {
uwsgi_error("chdir()");
exit(1);
}
}
}
else {
uwsgi_error("glob()");
exit(1);
}
globfree(&g);
emperor_absolute_dir = uwsgi_malloc(PATH_MAX+1);
if (realpath(".", emperor_absolute_dir) == NULL) {
uwsgi_error("realpath()");
exit(1);
}
}
ui = &ui_base;
int freq = 0 ;
for (;;) {
if (!i_am_alone) {
diedpid = waitpid(uwsgi.emperor_pid, &waitpid_status, WNOHANG);
if (diedpid < 0 || diedpid > 0) {
i_am_alone = 1;
}
}
nevents = event_queue_wait_multi(emperor_queue, freq, events, 64);
freq = 3;
for (i = 0; i<nevents;i++) {
interesting_fd = event_queue_interesting_fd(events, i);
if (amqp_fd > -1 && interesting_fd == amqp_fd ) {
uint64_t msgsize;
char *config = uwsgi_amqp_consume(amqp_fd, &msgsize, &amqp_routing_key);
if (!config) {
uwsgi_log("problem with RabbitMQ server, trying reconnection...\n");
event_queue_del_fd(emperor_queue, amqp_fd, event_queue_read());
close(amqp_fd);
amqp_fd = -1;
goto reconnect;
}
if (amqp_routing_key) {
uwsgi_log("AMQP routing_key = %s\n", amqp_routing_key);
char *config_file = uwsgi_concat2("emperor://", amqp_routing_key);
free(amqp_routing_key);
ui_current = emperor_get(config_file);
if (ui_current) {
// ignore event if i am not loyal
if (!ui_current->loyal) continue;
free(ui_current->config);
ui_current->config = config;
ui_current->config_len = msgsize;
if (!msgsize) {
// SAFE
emperor_del(ui_current);
}
else {
emperor_respawn(ui_current, time(NULL));
}
}
else {
if (msgsize > 0) {
emperor_add(config_file, time(NULL), config, msgsize, 0, 0);
}
}
free(config_file);
}
else {
if (msgsize) {
if (msgsize >= 0xff) { free(config); continue; }
#ifdef UWSGI_DEBUG
uwsgi_log("%.*s\n", (int)msgsize, config);
#endif
char *config_file = uwsgi_concat2n(config, msgsize, "", 0);
free(config);
if (strncmp(config_file, "http://", 7)) {
if (stat(config_file, &st)) {
free(config_file);
continue;
}
if (!S_ISREG(st.st_mode)) {
free(config_file);
continue;
}
}
ui_current = emperor_get(config_file);
if (ui_current) {
// ignore event if i am not loyal
if (!ui_current->loyal) continue;
emperor_respawn(ui_current, time(NULL));
}
else {
emperor_add(config_file, time(NULL), NULL, 0, 0, 0);
}
free(config_file);
}
}
}
else if (uwsgi.emperor_stats && uwsgi.emperor_stats_fd > -1 && interesting_fd == uwsgi.emperor_stats_fd) {
emperor_send_stats(uwsgi.emperor_stats_fd);
}
else {
ui_current = emperor_get_by_fd(interesting_fd);
if (ui_current) {
char byte;
ssize_t rlen = read(interesting_fd, &byte, 1);
if (rlen <= 0) {
// SAFE
emperor_del(ui_current);
}
else {
if (byte == 17) {
ui_current->loyal = 1;
uwsgi_log("*** vassal %s is now loyal ***\n", ui_current->name);
// TODO post-start hook
}
else if (byte == 22) {
emperor_stop(ui_current);
}
else if (byte == 30 && uwsgi.emperor_broodlord > 0 && uwsgi.emperor_broodlord_count < uwsgi.emperor_broodlord) {
uwsgi_log("[emperor] going in broodlord mode: launching zergs for %s\n", ui_current->name);
char *zerg_name = uwsgi_concat3(ui_current->name,":","zerg");
emperor_add(zerg_name, time(NULL), NULL, 0, ui_current->uid, ui_current->gid);
free(zerg_name);
}
}
}
else {
uwsgi_log("[emperor] unrecognized vassal event on fd %d\n", interesting_fd);
event_queue_del_fd(emperor_queue, interesting_fd, event_queue_read());
close(interesting_fd);
}
}
}
if (amqp_fd == -1) {
if (simple_mode) {
DIR *dir = opendir(".");
while ((de = readdir(dir)) != NULL) {
if (!strcmp(de->d_name + (strlen(de->d_name) - 4), ".xml") ||
!strcmp(de->d_name + (strlen(de->d_name) - 4), ".ini") ||
!strcmp(de->d_name + (strlen(de->d_name) - 4), ".yml") ||
!strcmp(de->d_name + (strlen(de->d_name) - 5), ".yaml") ||
!strcmp(de->d_name + (strlen(de->d_name) - 3), ".js") ||
!strcmp(de->d_name + (strlen(de->d_name) - 5), ".json")
) {
if (strlen(de->d_name) >= 0xff)
continue;
if (stat(de->d_name, &st))
continue;
if (!S_ISREG(st.st_mode))
continue;
ui_current = emperor_get(de->d_name);
if (ui_current) {
// check if uid or gid are changed, in such case, sotp the instance
if (uwsgi.emperor_tyrant) {
if (st.st_uid != ui_current->uid || st.st_gid != ui_current->gid) {
uwsgi_log("!!! permissions of file %s changed. stopping the instance... !!!\n");
emperor_stop(ui_current);
continue;
}
}
// check if mtime is changed and the uWSGI instance must be reloaded
if (st.st_mtime > ui_current->last_mod) {
emperor_respawn(ui_current, st.st_mtime);
}
}
else {
emperor_add(de->d_name, st.st_mtime, NULL, 0, st.st_uid, st.st_gid);
}
}
}
closedir(dir);
}
else {
if (glob(uwsgi.emperor_dir, GLOB_MARK|GLOB_NOCHECK, NULL, &g)) {
uwsgi_error("glob()");
continue;
}
for (i = 0; i < (int) g.gl_pathc; i++) {
if (!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 4), ".xml") ||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 4), ".ini") ||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 4), ".yml") ||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 3), ".js") ||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 5), ".json") ||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 5), ".yaml")
) {
if (strlen(g.gl_pathv[i]) >= 0xff)
continue;
if (stat(g.gl_pathv[i], &st))
continue;
if (!S_ISREG(st.st_mode))
continue;
ui_current = emperor_get(g.gl_pathv[i]);
if (ui_current) {
// check if uid or gid are changed, in such case, sotp the instance
if (uwsgi.emperor_tyrant) {
if (st.st_uid != ui_current->uid || st.st_gid != ui_current->gid) {
uwsgi_log("!!! permissions of file %s changed. stopping the instance... !!!\n");
emperor_stop(ui_current);
continue;
}
}
// check if mtime is changed and the uWSGI instance must be reloaded
if (st.st_mtime > ui_current->last_mod) {
emperor_respawn(ui_current, st.st_mtime);
}
}
else {
emperor_add(g.gl_pathv[i], st.st_mtime, NULL, 0, st.st_uid, st.st_gid);
}
}
}
globfree(&g);
}
}
// check for removed instances
ui_current = ui;
has_children = 0;
while (ui_current->ui_next) {
ui_current = ui_current->ui_next;
has_children++;
}
if (uwsgi.notify) {
if (snprintf(notification_message, 64, "The Emperor is governing %d vassals", has_children) >= 34) {
uwsgi_notify(notification_message);
}
}
if (has_children) {
diedpid = waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
}
else {
// vacuum
waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
diedpid = 0;
}
if (diedpid < 0) {
uwsgi_error("waitpid()");
}
ui_current = ui;
while (ui_current->ui_next) {
ui_current = ui_current->ui_next;
// check loyalty if not in simple/glob mode
if (amqp_fd > -1) {
if (!ui_current->loyal && (time(NULL)-ui_current->last_loyal) > 60) {
uwsgi_log("!!! no loyalty showed by instance %s !!!\n", ui_current->name);
// SAFE
emperor_del(ui_current);
break;
}
}
if (ui_current->status == 1) {
if (ui_current->config) free(ui_current->config);
// SAFE
emperor_del(ui_current);
break;
}
else if (!ui_current->use_config && strncmp(ui_current->name, "http://",7) && stat(ui_current->name, &st) && !ui_current->zerg) {
emperor_stop(ui_current);
}
else if (ui_current->pid == diedpid) {
if (ui_current->status == 0) {
// respawn an accidentally dead instance if its exit code is not UWSGI_EXILE_CODE
if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_EXILE_CODE) {
// SAFE
emperor_del(ui_current);
}
else {
// UNSAFE
emperor_add(ui_current->name, ui_current->last_mod, ui_current->config, ui_current->config_len, ui_current->uid, ui_current->gid);
emperor_del(ui_current);
}
break;
}
else if (ui_current->status == 1) {
// remove 'marked for dead' instance
if (ui_current->config) free(ui_current->config);
// SAFE
emperor_del(ui_current);
break;
}
}
}
}
}
#define stats_send_llu(x, y) fprintf(output, x, (long long unsigned int) y)
#define stats_send(x, y) fprintf(output, x, y)
void emperor_send_stats(int fd) {
struct sockaddr_un client_src;
socklen_t client_src_len = 0;
int client_fd = accept(fd, (struct sockaddr *) &client_src, &client_src_len);
if (client_fd < 0) {
uwsgi_error("accept()");
return;
}
FILE *output = fdopen(client_fd, "w");
if (!output) {
uwsgi_error("fdopen()");
close(client_fd);
return;
}
stats_send("{ \"version\": \"%s\",\n", UWSGI_VERSION);
fprintf(output,"\"pid\": %d,\n", (int)(getpid()));
fprintf(output,"\"uid\": %d,\n", (int)(getuid()));
fprintf(output,"\"gid\": %d,\n", (int)(getgid()));
char *cwd = uwsgi_get_cwd();
stats_send("\"cwd\": \"%s\",\n", cwd);
free(cwd);
stats_send("\"emperor\": \"%s\",\n", uwsgi.emperor_dir);
fprintf(output,"\"emperor_tyrant\": %d,\n", uwsgi.emperor_tyrant);
fprintf(output, "\"vassals\": [\n");
struct uwsgi_instance *c_ui = ui->ui_next;
while (c_ui) {
fprintf(output,"\t{");
stats_send("\"id\": \"%s\", ", c_ui->name);
fprintf(output,"\"pid\": %d, ", (int) c_ui->pid);
stats_send_llu( "\"born\": %llu, ", c_ui->born);
stats_send_llu( "\"last_mod\": %llu, ", c_ui->last_mod);
fprintf(output,"\"loyal\": %d, ", c_ui->loyal);
fprintf(output,"\"zerg\": %d, ", c_ui->zerg);
fprintf(output,"\"uid\": %d, ", (int)c_ui->uid);
fprintf(output,"\"gid\": %d, ", (int)c_ui->gid);
stats_send_llu( "\"respawns\": %llu ", c_ui->respawns);
c_ui = c_ui->ui_next;
if (c_ui) {
fprintf(output,"},\n");
}
else {
fprintf(output,"}\n");
}
}
fprintf(output,"]}\n");
fclose(output);
}
-22
View File
@@ -1,22 +0,0 @@
#ifdef UWSGI_EVDIS
#include "uwsgi.h"
void evdis_loop(struct uwsgi_server *uwsgi) {
// populate event list
int kfd = kqueue();
if (kfd < 0) {
uwsgi_error("kqueue()");
exit(1);
}
}
#else
#warning "*** Event Dispatcher support is disabled ***"
#endif
View File
View File
View File
View File
View File
View File
View File
View File
+10
View File
@@ -0,0 +1,10 @@
[uwsgi]
;master = true
gevent = 1000
zmq-socket = tcp://192.168.173.2:9999,tcp://192.168.173.2:9998
zmq-socket = tcp://192.168.173.19:9999,tcp://192.168.173.19:9998
http-socket = :8080
;module = tests.ugevent
-34
View File
@@ -1,34 +0,0 @@
#ifdef __linux__
#include <sys/inotify.h>
int uwsgi_file_monitor_new() {
int inotify_fd;
inotify_fd = inotify_init();
if (inotify_fd < 0) {
uwsgi_error("inotify_init()");
return -1;
}
return inotify_fd;
}
int uwsgi_file_monitor_add(int fd, char *what) {
int inotify_watch_fd;
inotify_watch_fd = inotify_add_watch(fd, what, IN_ALL_EVENTS);
if (inotify_watch_fd < 0) {
uwsgi_error("inotify_add_watch()");
return -1;
}
return inotify_watch_fd;
}
#endif
+19 -2
View File
@@ -1,7 +1,24 @@
import uwsgi
#uwsgi.cache_set('/', "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\nHello World from cache")
if uwsgi.loop == 'gevent':
import gevent
print uwsgi.version
print uwsgi.workers()
try:
uwsgi.cache_set('foo', "Hello World from cache")
except:
pass
def application(env, start_response):
print env['wsgi.input'].read()
if uwsgi.loop == 'gevent':
gevent.sleep()
start_response('200 OK', [('Content-Type', 'text/html')])
yield "foobar"
yield "foobar<br/>"
if uwsgi.loop == 'gevent':
gevent.sleep(3)
yield str(env['wsgi.input'].fileno())
yield "<h1>Hello World</h1>"
try:
yield uwsgi.cache_get('foo')
except:
pass
+19
View File
@@ -0,0 +1,19 @@
echo "*** uWSGI installer ***"
if [ $# -ne 2 ]
then
echo "Usage: install.sh <profile> <binary_path>"
exit 1
fi
if [ ${2:0:1} != "/" ]
then
echo "uWSGI binary path must be absolute !!!"
exit 1
fi
echo "downloading latest uWSGI tarball..."
curl -o uwsgi_latest_from_installer.tar.gz http://projects.unbit.it/downloads/uwsgi-latest.tar.gz
mkdir uwsgi_latest_from_installer
tar zvxC uwsgi_latest_from_installer --strip-components=1 -f uwsgi_latest_from_installer.tar.gz
cd uwsgi_latest_from_installer
UWSGI_PROFILE="$1" UWSGI_BIN_NAME="$2" make
-201
View File
@@ -1,201 +0,0 @@
/*
common functions for various routers (fastrouter, http...)
*/
static void uwsgi_corerouter_setup_sockets(char *gw_id) {
struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets;
while (ugs) {
if (!strcmp(gw_id, ugs->owner)) {
#ifdef UWSGI_SCTP
if (!ugs->subscription && !ugs->sctp) {
#else
if (!ugs->subscription) {
#endif
if (ugs->name[0] == '=') {
int shared_socket = atoi(ugs->name+1);
if (shared_socket >= 0) {
ugs->fd = uwsgi_get_shared_socket_fd_by_num(shared_socket);
if (ugs->fd == -1) {
uwsgi_log("unable to use shared socket %d\n", shared_socket);
exit(1);
}
ugs->name = uwsgi_getsockname(ugs->fd);
}
}
else if (!uwsgi_startswith("fd://", ugs->name, 5 )) {
int fd_socket = atoi(ugs->name+5);
if (fd_socket >= 0) {
ugs->fd = fd_socket;
ugs->name = uwsgi_getsockname(ugs->fd);
if (!ugs->name) {
uwsgi_log("unable to use file descriptor %d as socket\n", fd_socket);
exit(1);
}
}
}
else {
ugs->port = strchr(ugs->name, ':');
if (ugs->fd == -1) {
if (ugs->port) {
ugs->fd = bind_to_tcp(ugs->name, uwsgi.listen_queue, ugs->port);
ugs->port++;
ugs->port_len = strlen(ugs->port);
}
else {
ugs->fd = bind_to_unix(ugs->name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
}
}
}
// put socket in non-blocking mode
uwsgi_socket_nb(ugs->fd);
uwsgi_log("%s bound on %s fd %d\n", gw_id, ugs->name, ugs->fd);
}
else if (ugs->subscription) {
if (ugs->fd == -1) {
ugs->fd = bind_to_udp(ugs->name, 0, 0);
uwsgi_socket_nb(ugs->fd);
}
uwsgi_log("%s subscription server bound on %s fd %d\n", gw_id, ugs->name, ugs->fd);
}
#ifdef UWSGI_SCTP
else if (ugs->sctp) {
if (ugs->fd == -1) {
ugs->fd = bind_to_sctp(ugs->name);
}
uwsgi_log("%s SCTP server bound on %s fd %d\n", gw_id, ugs->name, ugs->fd);
}
#endif
}
ugs = ugs->next;
}
}
static void *uwsgi_corerouter_setup_event_queue(char *gw_id, int id, int nevents, int *efd, int cheap) {
*efd = event_queue_init();
struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets;
while (ugs) {
if (!strcmp(gw_id, ugs->owner)) {
if (!cheap || ugs->subscription) {
event_queue_add_fd_read(*efd, ugs->fd);
}
ugs->gateway = &ushared->gateways[id];
}
ugs = ugs->next;
}
return event_queue_alloc(nevents);
}
static void __attribute__ ((unused)) uwsgi_corerouter_manage_subscription(char *gw_id, int id, struct uwsgi_gateway_socket *ugs, int queue, struct uwsgi_subscribe_slot **subscriptions, int regexp, void (*parse_hook) (char *, uint16_t, char *, uint16_t, void *), int cheap, int *i_am_cheap) {
int i;
struct uwsgi_subscribe_req usr;
char bbuf[4096];
ssize_t len = recv(ugs->fd, bbuf, 4096, 0);
#ifdef UWSGI_EVENT_USE_PORT
event_queue_add_fd_read(queue, ugs->fd);
#endif
if (len > 0) {
memset(&usr, 0, sizeof(struct uwsgi_subscribe_req));
uwsgi_hooked_parse(bbuf + 4, len - 4, parse_hook, &usr);
// subscribe request ?
if (bbuf[3] == 0) {
if (uwsgi_add_subscribe_node(subscriptions, &usr, regexp) && *i_am_cheap) {
struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets;
while (ugs) {
if (!strcmp(ugs->owner, gw_id) && !ugs->subscription) {
event_queue_add_fd_read(queue, ugs->fd);
}
ugs = ugs->next;
}
*i_am_cheap = 0;
uwsgi_log("[%s pid %d] leaving cheap mode...\n", gw_id, (int) uwsgi.mypid);
}
}
//unsubscribe
else {
struct uwsgi_subscribe_node *node = uwsgi_get_subscribe_node_by_name(subscriptions, usr.key, usr.keylen, usr.address, usr.address_len, regexp);
if (node && node->len) {
if (node->death_mark == 0)
uwsgi_log("[%s pid %d] %.*s => marking %.*s as failed\n", gw_id, (int) uwsgi.mypid, (int) usr.keylen, usr.key, (int) usr.address_len, usr.address);
node->failcnt++;
node->death_mark = 1;
// check if i can remove the node
if (node->reference == 0) {
uwsgi_remove_subscribe_node(subscriptions, node);
}
if (*subscriptions == NULL && cheap && !*i_am_cheap) {
uwsgi_gateway_go_cheap(gw_id, queue, i_am_cheap);
}
}
}
// propagate the subscription to other nodes
for (i = 0; i < ushared->gateways_cnt; i++) {
if (i == id)
continue;
if (!strcmp(ushared->gateways[i].name, gw_id)) {
if (send(ushared->gateways[i].internal_subscription_pipe[0], bbuf, len, 0) != len) {
uwsgi_error("send()");
}
}
}
}
}
static void __attribute__ ((unused)) uwsgi_corerouter_manage_internal_subscription(char *gw_id, int queue, int fd, struct uwsgi_subscribe_slot **subscriptions, int regexp, void (*parse_hook) (char *, uint16_t, char *, uint16_t, void *), int cheap, int *i_am_cheap) {
struct uwsgi_subscribe_req usr;
char bbuf[4096];
ssize_t len = recv(fd, bbuf, 4096, 0);
#ifdef UWSGI_EVENT_USE_PORT
event_queue_add_fd_read(queue, fd);
#endif
if (len > 0) {
memset(&usr, 0, sizeof(struct uwsgi_subscribe_req));
uwsgi_hooked_parse(bbuf + 4, len - 4, parse_hook, &usr);
// subscribe request ?
if (bbuf[3] == 0) {
if (uwsgi_add_subscribe_node(subscriptions, &usr, regexp) && *i_am_cheap) {
struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets;
while (ugs) {
if (!strcmp(ugs->owner, gw_id) && !ugs->subscription) {
event_queue_add_fd_read(queue, ugs->fd);
}
ugs = ugs->next;
}
*i_am_cheap = 0;
uwsgi_log("[%s pid %d] leaving cheap mode...\n", gw_id, (int) uwsgi.mypid);
}
}
//unsubscribe
else {
struct uwsgi_subscribe_node *node = uwsgi_get_subscribe_node_by_name(subscriptions, usr.key, usr.keylen, usr.address, usr.address_len, regexp);
if (node && node->len) {
if (node->death_mark == 0)
uwsgi_log("[%s pid %d] %.*s => marking %.*s as failed\n", gw_id, (int) uwsgi.mypid, (int) usr.keylen, usr.key, (int) usr.address_len, usr.address);
node->failcnt++;
node->death_mark = 1;
// check if i can remove the node
if (node->reference == 0) {
uwsgi_remove_subscribe_node(subscriptions, node);
}
if (*subscriptions == NULL && cheap && !*i_am_cheap) {
uwsgi_gateway_go_cheap(gw_id, queue, i_am_cheap);
}
}
}
}
}
+69
View File
@@ -19,6 +19,39 @@ extern struct uwsgi_server uwsgi;
#define CLONE_NEWNET 0x40000000
#endif
int uwsgi_is_a_keep_mount(char *mp) {
struct uwsgi_string_list *usl = uwsgi.ns_keep_mount;
while(usl) {
char *colon = strchr(usl->value, ':');
if (colon) {
if (!strcmp(colon+1, mp)) {
return 1;
}
}
else {
// slip first part
if (!uwsgi_startswith(usl->value, uwsgi.ns, strlen(uwsgi.ns))) {
char *skipped = usl->value + strlen(uwsgi.ns);
if (uwsgi.ns[strlen(uwsgi.ns)-1] == '/') {
skipped--;
}
if (!strcmp(skipped, mp)) {
return 1;
}
}
else {
if (!strcmp(usl->value, mp)) {
return 1;
}
}
}
usl = usl->next;
}
return 0;
}
void linux_namespace_start(void *argv) {
for (;;) {
char stack[PTHREAD_STACK_MIN];
@@ -130,6 +163,40 @@ void linux_namespace_jail() {
uwsgi_error("mount()");
}
struct uwsgi_string_list *usl = uwsgi.ns_keep_mount;
while(usl) {
// bind mounting keep-mount items
char *keep_mountpoint = usl->value;
char *destination = strchr(usl->value, ':');
if (destination) {
keep_mountpoint = uwsgi_concat2n(usl->value, destination - usl->value, "", 0);
}
char *ks = uwsgi_concat2("/.uwsgi_ns_tmp_mountpoint", keep_mountpoint);
if (!destination) {
destination = usl->value;
// skip first part of the name if under the jail
if (!uwsgi_startswith(destination, uwsgi.ns, strlen(uwsgi.ns))) {
if (uwsgi.ns[strlen(uwsgi.ns)-1] == '/') {
destination += strlen(uwsgi.ns)-1;
}
else {
destination += strlen(uwsgi.ns);
}
}
}
else {
free(keep_mountpoint);
destination++;
}
uwsgi_log("remounting %s to %s\n", ks+25, destination);
if (mount(ks, destination, "none", MS_BIND, NULL)) {
uwsgi_error("mount()");
}
free(ks);
usl = usl->next;
}
while (unmounted) {
unmounted = 0;
@@ -139,6 +206,8 @@ void linux_namespace_jail() {
delim0++;
delim1 = strchr(delim0, ' ');
*delim1 = 0;
// and now check for keep-mounts
if (uwsgi_is_a_keep_mount(delim0)) continue;
if (!strcmp(delim0, "/") || !strcmp(delim0, "/proc"))
continue;
if (!umount(delim0)) {
-56
View File
@@ -1,56 +0,0 @@
/*
*** uWSGI, stripped down version of Linux rbtree ***
Red Black Trees
(C) 1999 Andrea Arcangeli <andrea@suse.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
struct rb_node
{
unsigned long rb_parent_color;
#define RB_RED 0
#define RB_BLACK 1
struct rb_node *rb_right;
struct rb_node *rb_left;
} __attribute__((aligned(sizeof(long))));
/* The alignment might seem pointless, but allegedly CRIS needs it */
struct rb_root
{
struct rb_node *rb_node;
};
#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3))
#define rb_color(r) ((r)->rb_parent_color & 1)
#define rb_is_red(r) (!rb_color(r))
#define rb_is_black(r) rb_color(r)
#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0)
#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0)
void rb_insert_color(struct rb_node *, struct rb_root *);
void rb_erase(struct rb_node *, struct rb_root *);
#ifdef __clang__
void rb_link_node(struct rb_node *, struct rb_node *,
struct rb_node **);
#else
inline void rb_link_node(struct rb_node *, struct rb_node *,
struct rb_node **);
#endif
-340
View File
@@ -1,340 +0,0 @@
#define _NO_UWSGI_RB
#include "uwsgi.h"
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
#include <kvm.h>
#include <sys/user.h>
#elif defined(__sun__)
/* Terrible Hack !!! */
#ifndef _LP64
#undef _FILE_OFFSET_BITS
#endif
#include <procfs.h>
#define _FILE_OFFSET_BITS 64
#endif
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
#include <sys/sysctl.h>
#endif
extern struct uwsgi_server uwsgi;
void uwsgi_check_logrotate(void) {
char message[1024];
int need_rotation = 0;
int need_reopen = 0;
if (uwsgi.log_master) {
uwsgi.shared->logsize = lseek(uwsgi.original_log_fd, 0, SEEK_CUR);
}
else {
uwsgi.shared->logsize = lseek(2, 0, SEEK_CUR);
}
if (uwsgi.log_maxsize > 0 && uwsgi.shared->logsize > uwsgi.log_maxsize) {
need_rotation = 1;
}
if (uwsgi_check_touches(uwsgi.touch_logrotate)) {
need_rotation = 1;
}
if (uwsgi_check_touches(uwsgi.touch_logreopen)) {
need_reopen = 1;
}
if (need_rotation) {
char *rot_name = uwsgi.log_backupname;
int need_free = 0;
if (rot_name == NULL) {
char *ts_str = uwsgi_num2str((int) time(NULL));
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) time(NULL), (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);
}
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);
}
else if (need_reopen) {
int ret = snprintf(message, 1024, "[%d] logsize: %llu, triggering log-reopen...\n", (int) time(NULL), (unsigned long long) uwsgi.shared->logsize);
if (ret > 0) {
if (write(uwsgi.original_log_fd, message, ret) != ret) {
// very probably this will never be printed
uwsgi_error("write()");
}
}
// reopen logfile;
close(uwsgi.original_log_fd);
uwsgi.original_log_fd = open(uwsgi.logfile, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP);
if (uwsgi.original_log_fd < 0) {
uwsgi_error_open(uwsgi.logfile);
grace_them_all(0);
}
ret = snprintf(message, 1024, "[%d] %s reopened.\n", (int) time(NULL), uwsgi.logfile);
if (ret > 0) {
if (write(uwsgi.original_log_fd, message, ret) != ret) {
// very probably this will never be printed
uwsgi_error("write()");
}
}
uwsgi.shared->logsize = lseek(uwsgi.original_log_fd, 0, SEEK_CUR);
}
}
void log_request(struct wsgi_request *wsgi_req) {
// optimize this (please)
char *time_request;
time_t microseconds, microseconds2;
int rlen;
int app_req = -1;
char *msg2 = " ";
char *via = msg2;
char mempkt[4096];
char logpkt[4096];
struct iovec logvec[4];
int logvecpos = 0;
const char *msecs = "msecs";
const char *micros = "micros";
long int rt;
char *tsize = (char *) msecs;
#ifdef UWSGI_SENDFILE
char *msg1 = " via sendfile() ";
#endif
char *msg3 = " via route() ";
struct uwsgi_app *wi;
if (wsgi_req->do_not_log)
return;
if (wsgi_req->app_id >= 0) {
wi = &uwsgi_apps[wsgi_req->app_id];
if (wi->requests > 0) {
app_req = wi->requests;
}
}
#ifdef UWSGI_SENDFILE
if (wsgi_req->sendfile_fd > -1 && wsgi_req->sendfile_obj == wsgi_req->async_result) { //wsgi_req->sendfile_fd_size > 0 ) {
via = msg1;
}
#endif
// mark route() requests
if (wsgi_req->status == -17) {
via = msg3;
}
time_request = ctime((const time_t *) &wsgi_req->start_of_request.tv_sec);
microseconds = wsgi_req->end_of_request.tv_sec * 1000000 + wsgi_req->end_of_request.tv_usec;
microseconds2 = wsgi_req->start_of_request.tv_sec * 1000000 + wsgi_req->start_of_request.tv_usec;
rt = (long int) (microseconds - microseconds2);
if (uwsgi.log_micros) {
tsize = (char *) micros;
}
else {
rt /= 1000;
}
if (uwsgi.vhost) {
logvec[logvecpos].iov_base = wsgi_req->host;
logvec[logvecpos].iov_len = wsgi_req->host_len;
logvecpos++;
logvec[logvecpos].iov_base = " ";
logvec[logvecpos].iov_len = 1;
logvecpos++;
}
if (uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG] == 1) {
#ifndef UNBIT
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);
#else
rlen = snprintf(mempkt, 4096, "{address space usage: %lld bytes/%lluMB} ", (unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size, (unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size / 1024 / 1024);
#endif
logvec[logvecpos].iov_base = mempkt;
logvec[logvecpos].iov_len = rlen;
logvecpos++;
}
rlen = snprintf(logpkt, 4096, "[pid: %d|app: %d|req: %d/%llu] %.*s (%.*s) {%d vars in %d bytes} [%.*s] %.*s %.*s => generated %llu bytes in %ld %s%s(%.*s %d) %d headers in %llu bytes (%d switches on core %d)\n", (int) uwsgi.mypid, wsgi_req->app_id, app_req, (unsigned long long) uwsgi.workers[0].requests, wsgi_req->remote_addr_len, wsgi_req->remote_addr, wsgi_req->remote_user_len, wsgi_req->remote_user, wsgi_req->var_cnt, wsgi_req->uh.pktsize, 24, time_request, wsgi_req->method_len, wsgi_req->method, wsgi_req->uri_len, wsgi_req->uri, (unsigned long long) wsgi_req->response_size, rt, tsize, via, wsgi_req->protocol_len, wsgi_req->protocol, wsgi_req->status, wsgi_req->header_cnt, (unsigned long long) wsgi_req->headers_size, wsgi_req->switches, wsgi_req->async_id);
logvec[logvecpos].iov_base = logpkt;
logvec[logvecpos].iov_len = rlen;
// do not check for errors
rlen = writev(2, logvec, logvecpos + 1);
}
void get_memusage(uint64_t * rss, uint64_t * vsz) {
#ifdef UNBIT
*vsz = syscall(356);
#elif defined(__linux__)
FILE *procfile;
int i;
procfile = fopen("/proc/self/stat", "r");
if (procfile) {
i = fscanf(procfile, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %llu %lld", (unsigned long long *) vsz, (unsigned long long *) rss);
if (i != 2) {
uwsgi_log("warning: invalid record in /proc/self/stat\n");
}
fclose(procfile);
}
*rss = *rss * uwsgi.page_size;
#elif defined (__sun__)
psinfo_t info;
int procfd;
procfd = open("/proc/self/psinfo", O_RDONLY);
if (procfd >= 0) {
if (read(procfd, (char *) &info, sizeof(info)) > 0) {
*rss = (uint64_t) info.pr_rssize * 1024;
*vsz = (uint64_t) info.pr_size * 1024;
}
close(procfd);
}
#elif defined(__APPLE__)
/* darwin documentation says that the value are in pages, but they are bytes !!! */
struct task_basic_info t_info;
mach_msg_type_number_t t_size = sizeof(struct task_basic_info);
if (task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t) & t_info, &t_size) == KERN_SUCCESS) {
*rss = t_info.resident_size;
*vsz = t_info.virtual_size;
}
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
kvm_t *kv;
int cnt;
#if defined(__FreeBSD__)
kv = kvm_open(NULL, "/dev/null", NULL, O_RDONLY, NULL);
#elif defined(__NetBSD__) || defined(__OpenBSD__)
kv = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, NULL);
#else
kv = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);
#endif
if (kv) {
#if defined(__FreeBSD__) || defined(__DragonFly__)
struct kinfo_proc *kproc;
kproc = kvm_getprocs(kv, KERN_PROC_PID, uwsgi.mypid, &cnt);
if (kproc && cnt > 0) {
*vsz = kproc->ki_size;
*rss = kproc->ki_rssize * uwsgi.page_size;
}
#elif defined(__NetBSD__) || defined(__OpenBSD__)
struct kinfo_proc2 *kproc2;
kproc2 = kvm_getproc2(kv, KERN_PROC_PID, uwsgi.mypid, sizeof(struct kinfo_proc2), &cnt);
if (kproc2 && cnt > 0) {
#ifdef __OpenBSD__
*vsz = (kproc2->p_vm_dsize + kproc2->p_vm_ssize + kproc2->p_vm_tsize) * uwsgi.page_size;
#else
*vsz = kproc2->p_vm_msize * uwsgi.page_size;
#endif
*rss = kproc2->p_vm_rssize * uwsgi.page_size;
}
#endif
kvm_close(kv);
}
#elif defined(__HAIKU__)
area_info ai;
int32 cookie;
*vsz = 0;
*rss = 0;
while (get_next_area_info(0, &cookie, &ai) == B_OK) {
*vsz += ai.ram_size;
if ((ai.protection & B_WRITE_AREA) != 0) {
*rss += ai.ram_size;
}
}
#endif
}
void uwsgi_register_logger(char *name, ssize_t(*func) (struct uwsgi_logger *, char *, size_t)) {
struct uwsgi_logger *ul = uwsgi.loggers, *old_ul;
if (!ul) {
uwsgi.loggers = uwsgi_malloc(sizeof(struct uwsgi_logger));
ul = uwsgi.loggers;
}
else {
while (ul) {
old_ul = ul;
ul = ul->next;
}
ul = uwsgi_malloc(sizeof(struct uwsgi_logger));
old_ul->next = ul;
}
ul->name = name;
ul->func = func;
ul->next = NULL;
ul->configured = 0;
ul->fd = -1;
ul->data = NULL;
#ifdef UWSGI_DEBUG
uwsgi_log("[uwsgi-logger] registered \"%s\"\n", ul->name);
#endif
}
struct uwsgi_logger *uwsgi_get_logger(char *name) {
struct uwsgi_logger *ul = uwsgi.loggers;
while (ul) {
if (!strcmp(ul->name, name)) {
return ul;
}
ul = ul->next;
}
return NULL;
}
-247
View File
@@ -1,247 +0,0 @@
#include "uwsgi.h"
extern struct uwsgi_server uwsgi;
struct wsgi_request *threaded_current_wsgi_req() {
return pthread_getspecific(uwsgi.tur_key);
}
struct wsgi_request *simple_current_wsgi_req() {
return uwsgi.wsgi_req;
}
void uwsgi_register_loop(char *name, void *loop) {
if (uwsgi.loops_cnt >= MAX_LOOPS) {
uwsgi_log("you can define %d loops at max\n", MAX_LOOPS);
exit(1);
}
uwsgi.loops[uwsgi.loops_cnt].name = name;
uwsgi.loops[uwsgi.loops_cnt].loop = loop;
uwsgi.loops_cnt++;
}
void *uwsgi_get_loop(char *name) {
int i;
for (i = 0; i < uwsgi.loops_cnt; i++) {
if (!strcmp(name, uwsgi.loops[i].name)) {
return uwsgi.loops[i].loop;
}
}
return NULL;
}
void *simple_loop(void *arg1) {
long core_id = (long) arg1;
struct wsgi_request *wsgi_req = uwsgi.wsgi_requests[core_id];
#ifdef UWSGI_THREADING
int i;
//PyThreadState *pts;
sigset_t smask;
if (uwsgi.threads > 1) {
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &i);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &i);
pthread_setspecific(uwsgi.tur_key, (void *) wsgi_req);
if (core_id > 0) {
// block all signals on new threads
sigfillset(&smask);
#ifdef UWSGI_DEBUG
sigdelset(&smask, SIGSEGV);
#endif
pthread_sigmask(SIG_BLOCK, &smask, NULL);
for (i = 0; i < 0xFF; i++) {
if (uwsgi.p[i]->init_thread) {
uwsgi.p[i]->init_thread(core_id);
}
}
}
}
#endif
// initialize the main event queue to monitor sockets
int main_queue = event_queue_init();
uwsgi_add_sockets_to_queue(main_queue);
if (uwsgi.signal_socket > -1) {
event_queue_add_fd_read(main_queue, uwsgi.signal_socket);
event_queue_add_fd_read(main_queue, uwsgi.my_signal_socket);
}
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
wsgi_req_setup(wsgi_req, core_id, NULL);
if (wsgi_req_accept(main_queue, wsgi_req)) {
continue;
}
if (wsgi_req_recv(wsgi_req)) {
uwsgi_destroy_request(wsgi_req);
continue;
}
uwsgi_close_request(wsgi_req);
}
// end of the loop
if (uwsgi.workers[uwsgi.mywid].destroy && uwsgi.workers[0].pid > 0) {
#ifdef __APPLE__
kill(uwsgi.workers[0].pid, SIGTERM);
#else
if (uwsgi.propagate_touch) {
kill(uwsgi.workers[0].pid, SIGHUP);
}
else {
gracefully_kill(0);
}
#endif
}
return NULL;
}
#ifdef UWSGI_ZEROMQ
void *zeromq_loop(void *arg1) {
sigset_t smask;
int i;
long core_id = (long) arg1;
struct wsgi_request *wsgi_req = uwsgi.wsgi_requests[core_id];
uwsgi.zeromq_recv_flag = 0;
zmq_pollitem_t zmq_poll_items[3];
char uwsgi_signal;
if (uwsgi.threads > 1) {
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &i);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &i);
pthread_setspecific(uwsgi.tur_key, (void *) wsgi_req);
if (core_id > 0) {
// block all signals on new threads
sigfillset(&smask);
#ifdef UWSGI_DEBUG
sigdelset(&smask, SIGSEGV);
#endif
pthread_sigmask(SIG_BLOCK, &smask, NULL);
for (i = 0; i < 0xFF; i++) {
if (uwsgi.p[i]->init_thread) {
uwsgi.p[i]->init_thread(core_id);
}
}
void *tmp_zmq_pull = zmq_socket(uwsgi.zmq_context, ZMQ_PULL);
if (tmp_zmq_pull == NULL) {
uwsgi_error("zmq_socket()");
exit(1);
}
if (zmq_connect(tmp_zmq_pull, uwsgi.zmq_receiver) < 0) {
uwsgi_error("zmq_connect()");
exit(1);
}
pthread_setspecific(uwsgi.zmq_pull, tmp_zmq_pull);
}
}
if (uwsgi.signal_socket > -1) {
zmq_poll_items[0].socket = pthread_getspecific(uwsgi.zmq_pull);
zmq_poll_items[0].fd = -1;
zmq_poll_items[0].events = ZMQ_POLLIN;
zmq_poll_items[1].socket = NULL;
zmq_poll_items[1].fd = uwsgi.signal_socket;
zmq_poll_items[1].events = ZMQ_POLLIN;
zmq_poll_items[2].socket = NULL;
zmq_poll_items[2].fd = uwsgi.my_signal_socket;
zmq_poll_items[2].events = ZMQ_POLLIN;
}
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
wsgi_req_setup(wsgi_req, core_id, NULL);
uwsgi.edge_triggered = 1;
wsgi_req->socket = uwsgi.zmq_socket;
if (uwsgi.signal_socket > -1) {
if (zmq_poll(zmq_poll_items, 3, -1) < 0) {
uwsgi_error("zmq_poll()");
continue;
}
if (zmq_poll_items[1].revents & ZMQ_POLLIN) {
if (read(uwsgi.signal_socket, &uwsgi_signal, 1) <= 0) {
if (uwsgi.no_orphans) {
uwsgi_log_verbose("uWSGI worker %d screams: UAAAAAAH my master died, i will follow him...\n", uwsgi.mywid);
end_me(0);
}
}
else {
#ifdef UWSGI_DEBUG
uwsgi_log_verbose("master sent signal %d to worker %d\n", uwsgi_signal, uwsgi.mywid);
#endif
if (uwsgi_signal_handler(uwsgi_signal)) {
uwsgi_log_verbose("error managing signal %d on worker %d\n", uwsgi_signal, uwsgi.mywid);
}
}
continue;
}
if (zmq_poll_items[2].revents & ZMQ_POLLIN) {
if (read(uwsgi.my_signal_socket, &uwsgi_signal, 1) <= 0) {
if (uwsgi.no_orphans) {
uwsgi_log_verbose("uWSGI worker %d screams: UAAAAAAH my master died, i will follow him...\n", uwsgi.mywid);
end_me(0);
}
}
else {
#ifdef UWSGI_DEBUG
uwsgi_log_verbose("master sent signal %d to worker %d\n", uwsgi_signal, uwsgi.mywid);
#endif
if (uwsgi_signal_handler(uwsgi_signal)) {
uwsgi_log_verbose("error managing signal %d on worker %d\n", uwsgi_signal, uwsgi.mywid);
}
}
continue;
}
if (zmq_poll_items[0].revents & ZMQ_POLLIN) {
wsgi_req->poll.fd = wsgi_req->socket->proto_accept(wsgi_req, uwsgi.zmq_socket->fd);
}
}
else {
wsgi_req->poll.fd = wsgi_req->socket->proto_accept(wsgi_req, uwsgi.zmq_socket->fd);
}
if (wsgi_req->poll.fd >= 0) {
wsgi_req_recv(wsgi_req);
}
uwsgi_close_request(wsgi_req);
}
// end of the loop
return NULL;
}
#endif
+1 -1
View File
@@ -63,7 +63,7 @@ int uwsgi_cache_request(struct wsgi_request *wsgi_req) {
case 2:
// del
if (wsgi_req->uh.pktsize > 0) {
uwsgi_cache_del(wsgi_req->buffer, wsgi_req->uh.pktsize);
uwsgi_cache_del(wsgi_req->buffer, wsgi_req->uh.pktsize, 0);
}
break;
case 3:
+231 -88
View File
@@ -2,18 +2,37 @@
extern struct uwsgi_server uwsgi;
struct carbon_server_list {
char *value; // server address
int healthy;
int errors;
struct carbon_server_list *next;
};
struct uwsgi_carbon {
struct uwsgi_string_list *servers;
struct carbon_server_list *servers_data;
int freq;
int timeout;
char *id;
int no_workers;
unsigned long long *last_busyness_values;
unsigned long long *current_busyness_values;
int need_retry;
time_t last_update;
time_t next_retry;
int max_retries;
int retry_delay;
} u_carbon;
struct uwsgi_option carbon_options[] = {
{"carbon", required_argument, 0, "push statistics to the specified carbon server", uwsgi_opt_add_string_list, &u_carbon.servers, UWSGI_OPT_MASTER},
{"carbon-timeout", required_argument, 0, "set carbon connection timeout", uwsgi_opt_set_int, &u_carbon.timeout, 0},
{"carbon-freq", required_argument, 0, "set carbon push frequency", uwsgi_opt_set_int, &u_carbon.freq, 0},
{"carbon-timeout", required_argument, 0, "set carbon connection timeout in seconds (default 3)", uwsgi_opt_set_int, &u_carbon.timeout, 0},
{"carbon-freq", required_argument, 0, "set carbon push frequency in seconds (default 60)", uwsgi_opt_set_int, &u_carbon.freq, 0},
{"carbon-id", required_argument, 0, "set carbon id", uwsgi_opt_set_str, &u_carbon.id, 0},
{"carbon-no-workers", no_argument, 0, "disable generation of single worker metrics", uwsgi_opt_true, &u_carbon.no_workers, 0},
{"carbon-max-retry", required_argument, 0, "set maximum number of retries in case of connection errors (default 1)", uwsgi_opt_set_int, &u_carbon.max_retries, 0},
{"carbon-retry-delay", required_argument, 0, "set connection retry delay in seconds (default 7)", uwsgi_opt_set_int, &u_carbon.retry_delay, 0},
{0, 0, 0, 0, 0, 0, 0},
};
@@ -27,12 +46,23 @@ void carbon_post_init() {
if (!u_carbon.servers) return;
while(usl) {
uwsgi_log("added carbon server %s\n", usl->value);
struct carbon_server_list *u_server = uwsgi_calloc(sizeof(struct carbon_server_list));
u_server->value = usl->value;
u_server->healthy = 1;
u_server->errors = 0;
if (u_carbon.servers_data) {
u_server->next = u_carbon.servers_data;
}
u_carbon.servers_data = u_server;
uwsgi_log("[carbon] added server %s\n", usl->value);
usl = usl->next;
}
if (u_carbon.freq < 1) u_carbon.freq = 60;
if (u_carbon.timeout < 1) u_carbon.timeout = 3;
if (u_carbon.max_retries <= 0) u_carbon.max_retries = 1;
if (u_carbon.retry_delay <= 0) u_carbon.retry_delay = 7;
if (!u_carbon.id) {
u_carbon.id = uwsgi_str(uwsgi.sockets->name);
@@ -41,103 +71,216 @@ void carbon_post_init() {
}
}
if (!u_carbon.last_busyness_values) {
u_carbon.last_busyness_values = uwsgi_calloc(sizeof(unsigned long long) * uwsgi.numproc);
}
if (!u_carbon.current_busyness_values) {
u_carbon.current_busyness_values = uwsgi_calloc(sizeof(unsigned long long) * uwsgi.numproc);
}
// set next update to now()+retry_delay, this way we will have first flush just after start
u_carbon.last_update = uwsgi_now() - u_carbon.freq + u_carbon.retry_delay;
uwsgi_log("[carbon] carbon plugin started, %is frequency, %is timeout, max retries %i, retry delay %is",
u_carbon.freq, u_carbon.timeout, u_carbon.max_retries, u_carbon.retry_delay);
}
int carbon_write(int *fd, char *fmt,...) {
va_list ap;
va_start(ap, fmt);
char ptr[4096];
int rlen;
rlen = vsnprintf(ptr, 4096, fmt, ap);
if (rlen < 1) return 0;
if (write(*fd, ptr, rlen) <= 0) {
uwsgi_error("write()");
return 0;
}
return 1;
}
void carbon_push_stats(int retry_cycle) {
struct carbon_server_list *usl = u_carbon.servers_data;
int i;
int fd;
int wok;
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.need_retry = 0;
while(usl) {
if (retry_cycle && usl->healthy)
// skip healthy servers during retry cycle
goto nxt;
if (retry_cycle && usl->healthy == 0)
uwsgi_log("[carbon] Retrying failed server at %s (%d)\n", usl->value, usl->errors);
if (!retry_cycle) {
usl->healthy = 1;
usl->errors = 0;
}
fd = uwsgi_connect(usl->value, u_carbon.timeout, 0);
if (fd < 0) {
uwsgi_log("[carbon] Could not connect to carbon server at %s\n", usl->value);
if (usl->errors < u_carbon.max_retries) {
u_carbon.need_retry = 1;
u_carbon.next_retry = uwsgi_now() + u_carbon.retry_delay;
} else {
uwsgi_log("[carbon] Maximum number of retries for %s (1)\n",
usl->value, u_carbon.max_retries);
usl->healthy = 0;
usl->errors = 0;
}
usl->healthy = 0;
usl->errors++;
goto nxt;
}
// put the socket in non-blocking mode
uwsgi_socket_nb(fd);
unsigned long long total_rss = 0;
unsigned long long total_vsz = 0;
unsigned long long total_tx = 0;
unsigned long long total_avg_rt = 0; // total avg_rt
unsigned long long avg_rt = 0; // per worker avg_rt reported to carbon
unsigned long long active_workers = 0; // number of workers used to calculate total avg_rt
unsigned long long total_busyness = 0;
unsigned long long total_avg_busyness = 0;
unsigned long long worker_busyness = 0;
unsigned long long total_harakiri = 0;
wok = carbon_write(&fd, "uwsgi.%s.%s.requests %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long) uwsgi.workers[0].requests, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
for(i=1;i<=uwsgi.numproc;i++) {
total_tx += uwsgi.workers[i].tx;
if (uwsgi.workers[i].cheaped) {
// also if worker is cheaped than we report its average response time as zero, sending last value might be confusing
avg_rt = 0;
worker_busyness = 0;
}
else {
// global average response time is calculated from active/idle workers, cheaped workers are excluded, otherwise it is not accurate
avg_rt = uwsgi.workers[i].avg_response_time;
active_workers++;
total_avg_rt += uwsgi.workers[i].avg_response_time;
// calculate worker busyness
worker_busyness = ((u_carbon.current_busyness_values[i-1]*100) / (u_carbon.freq*1000000));
if (worker_busyness > 100) worker_busyness = 100;
total_busyness += worker_busyness;
// only running workers are counted in total memory stats
total_rss += uwsgi.workers[i].rss_size;
total_vsz += uwsgi.workers[i].vsz_size;
total_harakiri += uwsgi.workers[i].harakiri_count/2;
}
//skip per worker metrics when disabled
if (u_carbon.no_workers) continue;
wok = carbon_write(&fd, "uwsgi.%s.%s.worker%d.requests %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long) uwsgi.workers[i].requests, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
wok = carbon_write(&fd, "uwsgi.%s.%s.worker%d.rss_size %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long) uwsgi.workers[i].rss_size, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
wok = carbon_write(&fd, "uwsgi.%s.%s.worker%d.vsz_size %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long) uwsgi.workers[i].vsz_size, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
wok = carbon_write(&fd, "uwsgi.%s.%s.worker%d.avg_rt %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long) avg_rt, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
wok = carbon_write(&fd, "uwsgi.%s.%s.worker%d.tx %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long) uwsgi.workers[i].tx, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
wok = carbon_write(&fd, "uwsgi.%s.%s.worker%d.busyness %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long) worker_busyness, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
wok = carbon_write(&fd, "uwsgi.%s.%s.worker%d.harakiri %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long) uwsgi.workers[i].harakiri_count/2, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
}
wok = carbon_write(&fd, "uwsgi.%s.%s.rss_size %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long) total_rss, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
wok = carbon_write(&fd, "uwsgi.%s.%s.vsz_size %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long) total_vsz, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
wok = carbon_write(&fd, "uwsgi.%s.%s.avg_rt %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long) (active_workers ? total_avg_rt / active_workers : 0), (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
wok = carbon_write(&fd, "uwsgi.%s.%s.tx %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long) total_tx, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
if (active_workers > 0) {
total_avg_busyness = total_busyness / active_workers;
if (total_avg_busyness > 100) total_avg_busyness = 100;
} else {
total_avg_busyness = 0;
}
wok = carbon_write(&fd, "uwsgi.%s.%s.busyness %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long) total_avg_busyness, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
wok = carbon_write(&fd, "uwsgi.%s.%s.active_workers %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long) active_workers, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
if (uwsgi.cheaper) {
wok = carbon_write(&fd, "uwsgi.%s.%s.cheaped_workers %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long) uwsgi.numproc - active_workers, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
}
wok = carbon_write(&fd, "uwsgi.%s.%s.harakiri %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long) total_harakiri, (unsigned long long) uwsgi.current_time);
if (!wok) goto clear;
usl->healthy = 1;
usl->errors = 0;
clear:
close(fd);
nxt:
usl = usl->next;
}
if (!retry_cycle) u_carbon.last_update = uwsgi_now();
if (u_carbon.need_retry)
// timeouts and retries might cause additional lags in carbon cycles, we will adjust timer to fix that
u_carbon.last_update -= u_carbon.timeout;
}
void carbon_master_cycle() {
static time_t last_update = 0;
char ptr[4096];
int rlen, i;
int fd;
struct uwsgi_string_list *usl = u_carbon.servers;
if (!u_carbon.servers) return;
if (!u_carbon.servers) return ;
if (last_update == 0) last_update = time(NULL);
// update
if (uwsgi.current_time - last_update >= u_carbon.freq) {
while(usl) {
fd = uwsgi_connect(usl->value, u_carbon.timeout, 0);
if (fd < 0) goto nxt;
// put the socket in non-blocking mode
uwsgi_socket_nb(fd);
unsigned long long total_rss = 0;
unsigned long long total_vsz = 0;
unsigned long long total_tx = 0;
unsigned long long total_avg_rt = 0; // total avg_rt
unsigned long long avg_rt = 0; // per worker avg_rt reported to carbon
unsigned long long avg_rt_workers = 0; // number of workers used to calculate total avg_rt
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.requests %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long ) uwsgi.workers[0].requests, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
for(i=1;i<=uwsgi.numproc;i++) {
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.worker%d.requests %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long ) uwsgi.workers[i].requests, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
total_rss += uwsgi.workers[i].rss_size;
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.worker%d.rss_size %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long ) uwsgi.workers[i].rss_size, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
total_vsz += uwsgi.workers[i].vsz_size;
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.worker%d.vsz_size %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long ) uwsgi.workers[i].vsz_size, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
if (uwsgi.workers[i].cheaped) {
// also if worker is cheaped than we report its average response time as zero, sending last value might be confusing
avg_rt = 0;
}
else {
// global average response time is calcucalted from active/idle workers, cheaped workers are excluded, otherwise it is not accurate
avg_rt = uwsgi.workers[i].avg_response_time;
avg_rt_workers++;
total_avg_rt += uwsgi.workers[i].avg_response_time;
}
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.worker%d.avg_rt %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long ) avg_rt, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
total_tx += uwsgi.workers[i].tx;
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.worker%d.tx %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long ) uwsgi.workers[i].tx, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
}
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.rss_size %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long ) total_rss, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.vsz_size %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long ) total_vsz, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.avg_rt %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long ) (avg_rt_workers ? total_avg_rt / avg_rt_workers : 0), (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.tx %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long ) total_tx, (unsigned long long ) uwsgi.current_time);
if (rlen < 1) goto clear;
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
clear:
close(fd);
nxt:
usl = usl->next;
}
last_update = time(NULL);
if (uwsgi.current_time - u_carbon.last_update >= u_carbon.freq || uwsgi.cleaning) {
// update
u_carbon.need_retry = 0;
carbon_push_stats(0);
} else if (u_carbon.need_retry && (uwsgi.current_time >= u_carbon.next_retry)) {
// retry failed servers
carbon_push_stats(1);
}
}
struct uwsgi_plugin carbon_plugin = {
.name = "carbon",
.master_cleanup = carbon_master_cycle,
.options = carbon_options,
.master_cycle = carbon_master_cycle,
.post_init = carbon_post_init,

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