mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-10-04 16:08:31 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d6086c84a | ||
|
|
a45be4f7a9 | ||
|
|
dd63bef92e | ||
|
|
621a05d879 | ||
|
|
b857690caf | ||
|
|
edb0a72dfd | ||
|
|
da4af442ad | ||
|
|
04ff580075 | ||
|
|
5925db13cf | ||
|
|
d283fd1aae | ||
|
|
345b22d8f0 | ||
|
|
b8fc89166d | ||
|
|
50ffb9d258 | ||
|
|
9ae1b26d52 | ||
|
|
f281d21a1b | ||
|
|
b9a2b92005 | ||
|
|
92a26d4ff6 | ||
|
|
51360416a7 | ||
|
|
c7bc98a50c | ||
|
|
b4b5c0175a | ||
|
|
7ed3eb36ee | ||
|
|
05c475f597 | ||
|
|
c750dfc1e3 | ||
|
|
01b14f4395 | ||
|
|
46d7d4bf1d | ||
|
|
02d76f12e0 | ||
|
|
719860a349 | ||
|
|
5cce0935fd | ||
|
|
24ef2a838f | ||
|
|
8aa739b4b2 | ||
|
|
9221e1953e | ||
|
|
18592fb2bd | ||
|
|
fc80eeb581 | ||
|
|
bc19b58681 | ||
|
|
8f2202eab5 | ||
|
|
aa2ecf14df | ||
|
|
43f5792826 | ||
|
|
36ff37e12c | ||
|
|
6dd6f961e8 | ||
|
|
5dd5d92ffb | ||
|
|
64f1b844bd | ||
|
|
e562c4691d | ||
|
|
1cbab74f0e | ||
|
|
3053fdb25a | ||
|
|
f11f542242 | ||
|
|
32ddf10cfa | ||
|
|
1b54be396c | ||
|
|
f81a4f9736 | ||
|
|
048b339593 | ||
|
|
081a6b90bf | ||
|
|
97f1b6d649 | ||
|
|
593aba2b19 | ||
|
|
47c9e5e3f0 | ||
|
|
bca8bc0c4d | ||
|
|
a67dfdd542 | ||
|
|
d1bbe7e3f9 | ||
|
|
442c982aff | ||
|
|
a2f50ccf2e | ||
|
|
b1c5fef0dc | ||
|
|
f6d8ac52f4 | ||
|
|
94e4fcbfe1 | ||
|
|
c9e7b0f48e | ||
|
|
2f932d8ca0 | ||
|
|
c517320f7a | ||
|
|
b0dae66264 | ||
|
|
0d87ed7298 | ||
|
|
fd3291b11f | ||
|
|
e5ac5d6352 | ||
|
|
403bd604e2 | ||
|
|
045d8947ae | ||
|
|
a9f2c71863 | ||
|
|
b504a1ebe8 | ||
|
|
f05ce0d2fc | ||
|
|
a2f3c716b1 | ||
|
|
2d7ca36f60 | ||
|
|
5370e535dd | ||
|
|
092767c29f | ||
|
|
4e119e6838 | ||
|
|
87ef444ea6 | ||
|
|
714be76f9b | ||
|
|
af0f0da8c2 | ||
|
|
8407372801 | ||
|
|
d19c4e84fc | ||
|
|
3342852a9a | ||
|
|
586a02d849 | ||
|
|
188dad744a | ||
|
|
6cf3bbea69 | ||
|
|
04736d371e | ||
|
|
cc9151f89e |
@@ -1,9 +1,5 @@
|
||||
*.o
|
||||
*.py[co]
|
||||
*.class
|
||||
*.jar
|
||||
|
||||
/uwsgi
|
||||
/uwsgibuild.*
|
||||
|
||||
/t/ring/target
|
||||
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
language: c
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
|
||||
script:
|
||||
- echo -e "\n\n>>> Building uWSGI binary"
|
||||
- /usr/bin/python uwsgiconfig.py --build travis
|
||||
- echo -e "\n\n>>> Building python26 plugin"
|
||||
- /usr/bin/python2.6 -V
|
||||
- /usr/bin/python2.6 uwsgiconfig.py --plugin plugins/python base python26
|
||||
- echo -e "\n\n>>> Building python27 plugin"
|
||||
- /usr/bin/python2.7 -V
|
||||
- /usr/bin/python2.7 uwsgiconfig.py --plugin plugins/python base python27
|
||||
- echo -e "\n\n>>> Building python31 plugin"
|
||||
- /usr/bin/python3.1 -V
|
||||
- /usr/bin/python3.1 uwsgiconfig.py --plugin plugins/python base python31
|
||||
- echo -e "\n\n>>> Building python32 plugin"
|
||||
- /usr/bin/python3.2 -V
|
||||
- /usr/bin/python3.2 uwsgiconfig.py --plugin plugins/python base python32
|
||||
- echo -e "\n\n>>> Building python33 plugin"
|
||||
- /usr/bin/python3.3 -V
|
||||
- /usr/bin/python3.3 uwsgiconfig.py --plugin plugins/python base python33
|
||||
- echo -e "\n\n>>> Building rack 1.8.7 plugin"
|
||||
- /usr/bin/ruby1.8 -v
|
||||
- UWSGICONFIG_RUBYPATH=/usr/bin/ruby1.8 /usr/bin/python uwsgiconfig.py --plugin plugins/rack base rack187
|
||||
- echo -e "\n\n>>> Building rack 1.9.1 plugin"
|
||||
- /usr/bin/ruby1.9.1 -v
|
||||
- UWSGICONFIG_RUBYPATH=/usr/bin/ruby1.9.1 /usr/bin/python uwsgiconfig.py --plugin plugins/rack base rack191
|
||||
- echo -e "\n\n>>> Building cgi plugin"
|
||||
- /usr/bin/python uwsgiconfig.py --plugin plugins/cgi base
|
||||
- echo -e "\n\n>>> Building dummy plugin"
|
||||
- /usr/bin/python uwsgiconfig.py --plugin plugins/dummy base
|
||||
- echo -e "\n\n>>> Building done, starting tests"
|
||||
- ./tests/travis.sh
|
||||
|
||||
before_install:
|
||||
- sudo add-apt-repository -y ppa:fkrull/deadsnakes
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qqyf python2.6-dev python2.7-dev python3.1-dev python3.2-dev python3.3-dev rubygems1.8 ruby1.8-dev ruby1.9.1-dev
|
||||
- sudo apt-get install -qqyf libxml2-dev libpcre3-dev libcap2-dev
|
||||
- sudo apt-get install -qqyf curl
|
||||
|
||||
@@ -21,4 +21,3 @@ Roy Marples
|
||||
Aarni Koskela
|
||||
C Anthony Risinger
|
||||
Stephen Pierce
|
||||
Mingli Yuan
|
||||
|
||||
@@ -0,0 +1,679 @@
|
||||
*** current ***
|
||||
|
||||
* 1.4.1
|
||||
|
||||
- fixed typos in corerouter plugins
|
||||
- fixed offloading when the number of threads is higher than 1
|
||||
- fixed static_maps for non-existent paths
|
||||
- fixed uwsgi_connect() on modern Linux systems to reset the socket to blocking mode
|
||||
|
||||
*** november 2012 ***
|
||||
|
||||
* 1.4
|
||||
|
||||
- gevent improvements
|
||||
- improved http/https router and fastrouter
|
||||
- Go official support
|
||||
- a new set of infos are exported to the stats system
|
||||
- improved systemd support
|
||||
- log filtering and routing
|
||||
- improved tracebacker
|
||||
- offload transfer for static files, and network transfers
|
||||
- matheval support
|
||||
- plugins can be written in Obj-C
|
||||
- smart attach daemon
|
||||
- added support for PEP 405 virtualenvs
|
||||
- rawrouter with xclient support
|
||||
- internal routing plugin for cache
|
||||
|
||||
*** semptember 2012 ***
|
||||
|
||||
* 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
|
||||
- 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
|
||||
- redislog and mongodblog plugins
|
||||
- added python logger
|
||||
- mongodb and postgres imperial monitors
|
||||
- implemented psgix.logger and psgix.cleanup
|
||||
- full rack spec compliance
|
||||
- preliminary ipv6 support
|
||||
- gevent graceful reloads
|
||||
- support for multiple loggers and logformat
|
||||
- lazy-apps to load apps after fork() but without changing reloading subsystem
|
||||
- emperor heartbeat subsystem
|
||||
- cheaper busyness plugin
|
||||
- pluggable clock sources
|
||||
- added router_rewrite and router_http plugins
|
||||
- external spoolers
|
||||
- support for section:// and fd:// loaders
|
||||
- alarm subsystem (with curl and xmpp plugins)
|
||||
|
||||
|
||||
*** 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]
|
||||
|
||||
- adaptive process spawning (--cheaper option)
|
||||
- new control options --stop, --reload, --suspend, --resume, --pause
|
||||
- stats framework
|
||||
- new subscription system
|
||||
- support for mime types in static file serving
|
||||
- posix capablities support
|
||||
- uWSGI mules and farms
|
||||
- support for multiple --touch-reload options
|
||||
- new logging subsystem
|
||||
- new custom locking subsystem
|
||||
- process name handling
|
||||
- better (and faster) HTTP parser
|
||||
- perl and python threading improvements
|
||||
- new plugins: rrdtool, carbon, cgi, php
|
||||
- various improvements in the Rack/ruby plugin
|
||||
- Linux KSM support
|
||||
- refactored ping and nagios plugins
|
||||
- support for signals in lazy mode
|
||||
- optimized static-file serving
|
||||
- support for linux unshare()
|
||||
|
||||
*** august 2011 ***
|
||||
|
||||
* 0.9.9 [20110829]
|
||||
|
||||
- various spooler improvements
|
||||
- upload progress optimizations and fixes
|
||||
- new emperor mode: Tyrant
|
||||
- allows multiple --ini options
|
||||
- better binary path detection
|
||||
- gevent loop engine support
|
||||
- resolve domain names in socket logging
|
||||
- snmp fixes and reintroduction of the snmp-api
|
||||
- fixed grunt mode
|
||||
- you can specify build profile via env var UWSGI_PROFILE
|
||||
- reintroduction of string-based multiapp
|
||||
- new option --emperor-throttle
|
||||
- improved queue and sharedarea subsystems
|
||||
- uWSGI can now be built as a shared library
|
||||
- new api attribute: uwsgi.magic_table
|
||||
- improved apache2 module
|
||||
- new option --pyshell
|
||||
- allow threads in gateways
|
||||
- fastrouter improvements
|
||||
- the application list is now shared and exported to the api
|
||||
- allows setting the thread stack size
|
||||
- UWSGI_APPID for better multiapp hosting
|
||||
- better reloading in lazy mode
|
||||
- native pump support
|
||||
- various rack fixes
|
||||
- support for attaching binary data in the executable
|
||||
- new option --set
|
||||
- extreme-optimized http protocol parser
|
||||
- WSGI handler optimizations
|
||||
|
||||
*** july 2011 ***
|
||||
|
||||
* 0.9.8.3 [20110723]
|
||||
|
||||
- implemented uwsgi.SymZipImporter to load embedded zip files
|
||||
- OSX Lion is officially supported
|
||||
- fixed xinetd support (example file added in contrib)
|
||||
- suppot for systemd socket activation
|
||||
- added --freebind option (Linux only)
|
||||
|
||||
* 0.9.8.2 [20110719]
|
||||
|
||||
- fixed an ini and yaml parsing bug spotted by Raffaele Colace
|
||||
- spooler has been extremely improved
|
||||
- new option --chown-socket
|
||||
- added uwsgidecorators for elegant uwsgi api access from python
|
||||
- the rack plugin is now stable
|
||||
- support for embedding config and generic files in the server binary
|
||||
- high-performance cache-server
|
||||
- accept() is now locked on all threads in the same workers
|
||||
- preliminary implementation of hooks in emperor
|
||||
- support for C++ in server core
|
||||
- tcp port auto-bind
|
||||
- implemented workers, workerN and spooler signal target
|
||||
- prefork/multithread uwsgi.signal_wait() implementation
|
||||
- export uwsgi.node in WSGI vars
|
||||
- new option --import (python plugin)
|
||||
- support for unlimited number of Linux cgroups
|
||||
- broodlord mode
|
||||
|
||||
*** june 2011 ***
|
||||
|
||||
* 0.9.8.1 [20110625]
|
||||
|
||||
- the build system has been improved
|
||||
- various threading fixes
|
||||
- fix python GIL status after reload
|
||||
- new option --propagate-touch
|
||||
- fixed uwsgi.sendfile
|
||||
- fixed readline() support in wsgi.input
|
||||
- fixed dynamic touch reload
|
||||
- new option --logto2
|
||||
- export %c in config files
|
||||
- fixed libyaml support
|
||||
- support passing modifiers in subscription system
|
||||
- reset random seed in spooler
|
||||
- subscribe from a list in a text file
|
||||
- allow binding on port 0 (auto-assignment)
|
||||
- reset random seed on grunt
|
||||
- fix vhost mode for empty hostname
|
||||
- fixed python3+virtualenv support
|
||||
- tasks are now allowed to chdir() in spooler
|
||||
- better zeromq+clustering support
|
||||
- clustering has been refactored
|
||||
- fixed rpc
|
||||
- report correct worker id in cheap mode
|
||||
- fixed a fd-leak in attach-daemon
|
||||
- use setsid() in attach-daemon
|
||||
- zerg mode
|
||||
- added psgix.harakiri
|
||||
- allows magic vars in sqlite3 config db
|
||||
- added UWSGI_FASTROUTER_KEY var
|
||||
- slowdown async-queue-is-full messages
|
||||
- new option --cron
|
||||
- --vassals-start-hook and --vassals-stop-hook
|
||||
- the proxy plugin has been removed
|
||||
|
||||
* 0.9.8 [20110605]
|
||||
|
||||
- support for --callable in virtualhosting mode
|
||||
- a NetBSD fix
|
||||
- abstract unix socket can be prefixed with \0 (nginx-style)
|
||||
- add /lib to the linker in sun-like systems
|
||||
- a mercy mode of 5 seconds is enabled by default on SIGINT/SIGQUIT
|
||||
|
||||
* 0.9.8-rc4 [20110602]
|
||||
|
||||
- fixed REMOTE_ADDR when --protocol=http
|
||||
- official support for OpenIndiana
|
||||
- added a welcome.py test script
|
||||
- new api attribute uwsgi.version_info
|
||||
- improved the admin plugin
|
||||
- two new management flag for backlog queue monitoring
|
||||
- fixed uwsgi_log for bigger loglines
|
||||
- new option --early-emperor to allows out-of-jail emperors
|
||||
- emperor can now spawn other emperors (sub-emperors)
|
||||
- fixed idle mode in single-process
|
||||
- fixed solaris iovec
|
||||
|
||||
*** may 2011 ***
|
||||
|
||||
* 0.9.8-rc3 [20110530]
|
||||
|
||||
- snapshotting support
|
||||
- fixed python 3.x spooler
|
||||
- improvements for grunt processes
|
||||
- better abstract unix socket
|
||||
- --log-socket allows logging to generic DGRAM sockets
|
||||
- a bunch of solaris fixes
|
||||
- new option --no-fd-passing for fastrouter
|
||||
- --fastrouter-subscription-slot to set the number of slot in subscription server
|
||||
- unlimited shared sockets
|
||||
- fixed netlink compilation
|
||||
- auto-reconnect on emperor+amqp server disconnection
|
||||
- various emperor fixes
|
||||
- unlimited fastrouter sockets
|
||||
- better cgroup support
|
||||
- --add-header option allow adding of custom HTTP response headers
|
||||
- cheap and idle operational modes
|
||||
|
||||
|
||||
* 0.9.8-rc2 [20110521]
|
||||
|
||||
- new option --die-on-term
|
||||
- fixed touch reload
|
||||
- a couple of optimizations for wsgi.input
|
||||
- systemd integration
|
||||
|
||||
* 0.9.8-rc1 [20110514]
|
||||
|
||||
- massive code cleanup and refactoring
|
||||
- added vassals loyalty concept
|
||||
- fixed virtualhosting with dynamic virtualenv
|
||||
- fixed reloading on grand-central-dispatch-enabled OSX
|
||||
- improved PSGI support with uGreen and async support
|
||||
- improved Rack support with complete fiber+async in ruby 1.9
|
||||
- support for JSON config files
|
||||
- native multi-protocol support (added fastcgi and http)
|
||||
- Mongrel2 support
|
||||
- support for templates in vassals
|
||||
- various threading fixes
|
||||
- gcc-4.6 support
|
||||
- support for logging via zeromq
|
||||
- support for configuration passed via pipe/stdin
|
||||
- pythonpath entries are now unlimited
|
||||
- socket entries are unlimited
|
||||
- pythonpath can be a glob
|
||||
- lazy mode added
|
||||
- new language-independent profiling subsystem
|
||||
- support for configuration stored in a sqlite3 db
|
||||
- allow workers to survive to syslogd death (when --log-syslog is used)
|
||||
- fix traceback in Python 3.x
|
||||
- support for uwsgi signals in threads
|
||||
- plugin autoloading
|
||||
- graceful reloading for threads
|
||||
- new wsgi.input object
|
||||
- support for alternative allocators (tcmalloc and jemalloc)
|
||||
|
||||
|
||||
*** april 2011 ***
|
||||
|
||||
* 0.9.7.2 [20110406]
|
||||
|
||||
- new option --touch-reload <file> to reload the stack on <file> modification
|
||||
--static-map <mountpoint=documentroot> allows to serve static files
|
||||
- fixed --post-limit management
|
||||
- disallow empty socket names
|
||||
- implemented exception_info WSGI support
|
||||
- new options --reload-on-as <n> and --reload-on-rss <n> allows
|
||||
to recycle workers when their memory usage is higher than <n> MB
|
||||
- fixed syslog support (use --log-syslog[=facility] to enable it)
|
||||
- improved plugin loading system
|
||||
- added support for RabbitMQ as event dispatcher for the Emperor
|
||||
- fixed FreeBSD memory report
|
||||
- PSGI plugin can be compiled without ithreads
|
||||
- various Emperor fixes
|
||||
- fixed a regression with setgroups()
|
||||
- support for shared sockets (used in jails within network namespaces)
|
||||
|
||||
*** march 2011 ***
|
||||
|
||||
* 0.9.7.1 [20110326]
|
||||
|
||||
- fixed python stackless support
|
||||
- added persistence for queue
|
||||
- forbid daemonizing in vassal mode
|
||||
- modifier1 30 is available again
|
||||
- allow python modules to be mapped/aliased via http
|
||||
- added --pidfile2 and --logfile-chown
|
||||
- added UWSGI_CACHE_GET dynamic variable
|
||||
- 304/If-Modified-Since support for --check-static
|
||||
- option --check-cache for integrated caching
|
||||
- option --map-socket to assign specific workers to socket
|
||||
- fixed unix fd passing on older OSX versions
|
||||
- fixed post-buffering without pep3333-input
|
||||
- fixed python threading without uwsgi cores
|
||||
- support for Linux network namespace
|
||||
- build with sys.abiflags if necessary
|
||||
|
||||
|
||||
* 0.9.7 [20110317]
|
||||
|
||||
- fixed psgi compilation on GNU systems
|
||||
- improved --pep3333-input
|
||||
- better error reporting on failed open/fopen
|
||||
- fixed uGreen
|
||||
- added greenlet support
|
||||
- various solaris fixes
|
||||
- new help system
|
||||
- updated async support
|
||||
- fixed uwsgi.cache_get in python
|
||||
|
||||
* 0.9.7-rc3 [20110312]
|
||||
|
||||
- added support for persistent cache (--cache-store <filename>)
|
||||
- less verbose file monitoring
|
||||
- fixed a race condition in emperor startup
|
||||
- fixed erlang empty list encoding
|
||||
- improved snmp support
|
||||
- fixed cache modifier 111 for 3 and 4
|
||||
- preliminary cpu-affinity support (Linux only)
|
||||
- fixed ldap support
|
||||
- auto-configure ldap compilation
|
||||
- added --allowed-modifiers (allow only a subset of modifiers)
|
||||
- fixed a bug with getopt_long
|
||||
|
||||
* 0.9.7-rc2 [20110309]
|
||||
|
||||
- added cron-like interface to signal framework
|
||||
- improved Linux namespaces support
|
||||
- fixed multithreading + --max-requests
|
||||
- added support for reference in configuration files
|
||||
|
||||
* 0.9.7-rc1 [20110307]
|
||||
|
||||
- export %v in emperor mode
|
||||
- fixed signal race condition in server reload
|
||||
- fixed http router post handling bug
|
||||
- added uwsgi.erlang_register_process in pyerl plugin
|
||||
- fixed unix socket inherit
|
||||
- fixed linux namespace support in recent kernel/gcc
|
||||
- ported threading to python 3.2
|
||||
- add build date to uWSGI startup info
|
||||
- do not allow clustering without defining a socket
|
||||
- kill all the gateways/daemons on startup errors
|
||||
- fixed vacuum after chdir()
|
||||
- fixed gateways reload
|
||||
- re-added support for OpenBSD and NetBSD
|
||||
- fixed post-buffering in python
|
||||
- use erlang binary for python string
|
||||
- fixed memory leak in pyerl plugin
|
||||
- removed broken log rotation (post-poned)
|
||||
- fixed no_argument options in ini and yaml parsing
|
||||
|
||||
* 0.9.7-beta1 [20110301]
|
||||
|
||||
- fully modular re-design
|
||||
- advanced build system with presets
|
||||
- threading support
|
||||
- emperor mode for massive auto-hosting
|
||||
- caching subsystem
|
||||
- message queue (even stacked) support
|
||||
- improved server reloading system
|
||||
- support for Linux Cgroups and Namespaces
|
||||
- integrated upload progress
|
||||
- Clustering infrastructure via multicast, broadcast or subscriptions
|
||||
- support for attaching/monitoring external apps to the master process
|
||||
- improved virtualhosting mode
|
||||
- extremely improved Python support with better usage of multiple interpreters
|
||||
- improved multiple apps support
|
||||
- Production ready, evented HTTP router/proxy/load-balancer
|
||||
- Production ready, evented uwsgi router/proxy/load-balancer
|
||||
- new Erlang stack
|
||||
- Internal signal subsystem
|
||||
- support for RubyOnRails and Rack apps
|
||||
- A huge series of fixes and optimizations
|
||||
|
||||
*** february 2011 ***
|
||||
|
||||
* 0.9.6.8 [20110207]
|
||||
|
||||
- fixed a bug when using --limit-as
|
||||
- fixed a erlang buffer initialization
|
||||
- added --ignore-sigpipe
|
||||
- added --master-as-root
|
||||
|
||||
*** january 2011 ***
|
||||
|
||||
* 0.9.6.7 [20110130]
|
||||
|
||||
- a huge amount of async optimizations and fixes
|
||||
- --logdate takes an optional strftime-like value
|
||||
- follow $PATH on reloading
|
||||
- uwsgi.core is exported in WSGI env
|
||||
- uwsgi.log() respect for --logdate
|
||||
- initial banner respect for --logdate
|
||||
- fixed --post-buffering
|
||||
- default listen backlog queue is now 100
|
||||
- Python 3 support is no more marked as experimental
|
||||
- Python 3.2 support
|
||||
- new option --chroot-reload will force a reload of the uWSGI stack after a chroot
|
||||
- fixed a typo in INI parsing
|
||||
|
||||
*** december 2010 ***
|
||||
|
||||
* 0.9.6.6 [20101230]
|
||||
|
||||
- support for YAML configuration files
|
||||
- backported python module aliasing from 0.9.7-dev
|
||||
- better apache2 module (support for SetEnv directive, fixed REQUEST_URI and improved connection handling)
|
||||
- uwsgi.post_fork_hook implementation (to execute function after fork()) (thanks George Kollias)
|
||||
- option --gid calls setgroups() after setgid() (thanks Jorge Cardona)
|
||||
- fixed uGreen compilation (and uGreen is now built by default)
|
||||
- fixed timeout and thundering herd problem in async modes (many thanks to Test157 for giving us a good async-test-app)
|
||||
- disable TCP_INFO in older Linux kernels (thanks Bo Shi)
|
||||
- enable TCP_INFO in FreeBSD (limited usage due to FreeBSD kernel support)
|
||||
- fixed static virtualhosting mode using xml files (thanks Guido Notari of Link I.T. spa)
|
||||
- new option --close-on-exec (thanks Jean-Baptiste Quenot)
|
||||
- use HTTP_HOST var (and fallback to SERVER_NAME) in virtual hosting mode
|
||||
- fixed a buffer overflow in automatic socket_name allocation (spotted by Riccardo Magliocchetti)
|
||||
- Official support for Nexenta
|
||||
|
||||
|
||||
*** september 2010 ***
|
||||
|
||||
* 0.9.6.5 [20100929]
|
||||
|
||||
- PEP 3333 support
|
||||
- fix --pythonpath with --wsgi-file
|
||||
- x-wsgiorg.uwsgi.version renamed to uwsgi.version
|
||||
|
||||
* 0.9.6.4 [20100925]
|
||||
|
||||
- fix a stupid bug in conditional logging backport
|
||||
|
||||
* 0.9.6.3 [20100925]
|
||||
|
||||
- fix a buffer overflow in .ini parsing (it throws a glibc error on malloc)
|
||||
- backport of conditional logging from 0.9.7-dev
|
||||
- backport of backlog queue monitor from 0.9.7-dev (only Linux)
|
||||
|
||||
* 0.9.6.2 [20100915]
|
||||
|
||||
- fix a regression in virtual hosting mode
|
||||
- fix pythonpath usage in --ini and --ini-paste
|
||||
- new uwsgi packet var: UWSGI_CHDIR
|
||||
|
||||
* 0.9.6.1 [20100912]
|
||||
|
||||
- print the request uri during SIGPIPE or HARAKIRI
|
||||
- added SIGUSR2 support (it will print the current running request, if available)
|
||||
- protocol parsing optimization
|
||||
- fixed --logto support
|
||||
- new --eval option allows inline definition of WSGI script
|
||||
- support for defining WSGI script in xml using CDATA
|
||||
- allow --pp as --pythonpath shortcut
|
||||
- various spooler optimizations and fixes
|
||||
- added -O2 optimization by default
|
||||
- added uwsgi.is_a_reload commodity function
|
||||
- .ini file support fix
|
||||
- SNMP agent fix
|
||||
- support for subprocesses generated by master
|
||||
- fix a regression in SCRIPT_NAME handling
|
||||
- Haiku official support
|
||||
- gcc 2.95 support
|
||||
- dynamic app management optimizations
|
||||
- export x-wsgiorg.uwsgi.version in WSGI env
|
||||
|
||||
*** august 2010 ***
|
||||
|
||||
* 0.9.6 [20100829]
|
||||
|
||||
- better handling of SCRIPT_NAME
|
||||
- vacuum option for deleting unix sockets and pidfiles after usage
|
||||
- advanced XML configuration
|
||||
- new configuration systems: INI files and LDAP
|
||||
- embedded HTTP server for development/testing
|
||||
- better signal handling
|
||||
- PSGI plugin improved
|
||||
- usability fixes and new commodities options for root startup
|
||||
- grunt processes (detached workers)
|
||||
- preliminary integrated virtualhosting mode
|
||||
- new option catch-exceptions can redirect python exceptions to your browser
|
||||
- logging improvements (--logto and --logdate options)
|
||||
- Full PEP 333 compliant usage of wsgi.file_wrapper
|
||||
- re-initialize random seed after every fork() [security fix]
|
||||
- fix Spooler's usage of stdin
|
||||
- export WSGI environment in uwsgi.env (for doing evil things)
|
||||
- logsize tracking (uwsgi.logsize) for future embedded log rotation
|
||||
|
||||
*** july 2010 ***
|
||||
|
||||
* 0.9.5.4 [20100706]
|
||||
|
||||
*** june 2010 ***
|
||||
|
||||
* 0.9.5.3 [20100628]
|
||||
|
||||
- fixed linux x86_64 compilation (sorry)
|
||||
|
||||
* 0.9.5.2 [20100626] *
|
||||
|
||||
- fixed a request parsing bug
|
||||
- applied debian fixes
|
||||
- fixed multiple interpreter sys.argv
|
||||
- improved --chmod-socket
|
||||
- fixed uid 0 SIGHUP
|
||||
- updated nginx and apache modules
|
||||
- updated PSGI, lua and example plugin
|
||||
- fixed --pyargv with python 3.x
|
||||
- improved plugin build system
|
||||
|
||||
*** may 2010 ***
|
||||
|
||||
* 0.9.5.1 [20100519] *
|
||||
|
||||
- fixed paste support
|
||||
- added a new modifier (22)
|
||||
- full support for configuration via environment variables
|
||||
- nginx_string option in nginx module
|
||||
- fix for harakiri without master
|
||||
- backported unladen swallow support for 0.9.6-dev
|
||||
- fixed address space limit detection via getrlimit()
|
||||
- http body buffering implementation
|
||||
- added --prio option (to set priority)
|
||||
- added --post-limit to limit the size of uploads
|
||||
- added --logto option to allow udp logging without daemonizing
|
||||
- applied Gentoo's packagers fixes for build system
|
||||
|
||||
* 0.9.5 [20100501] *
|
||||
|
||||
- hook based request/modifier management
|
||||
- plugin support via dlopen
|
||||
- on-the-fly management flag
|
||||
- integrated proxy
|
||||
- logging via udp
|
||||
- improved spooler for cron-like apps
|
||||
- async support
|
||||
- green thread platform (uGreen) on top of the async mode
|
||||
- transparent Erlang integration
|
||||
- embedded snmp agent
|
||||
- nagios mode
|
||||
- improved python 3.x support
|
||||
- improved xml configuration
|
||||
- new build system
|
||||
- address space usage limiting
|
||||
- lot of portability fixes
|
||||
- lot of optimizations and code refactoring
|
||||
|
||||
|
||||
*** april 2010 ***
|
||||
|
||||
* Fourth Maintenance release [20100427] *
|
||||
|
||||
- backported non-yielding app optimization from 0.9.5
|
||||
- backported udp logging from 0.9.5
|
||||
- backported uwsgi_error() from 0.9.5 (no more dumb perror())
|
||||
- fix a rare (but possible) segmentation fault
|
||||
- added --version
|
||||
- updated apache2 module
|
||||
|
||||
*** march 2010 ***
|
||||
|
||||
* Third Maintenance release [20100310] *
|
||||
|
||||
- fix sendfile on 64bit
|
||||
- include setup.py
|
||||
|
||||
*** february 2010 ***
|
||||
* Maintenance release *
|
||||
|
||||
- better support for NetBSD
|
||||
- threading fix for FreeBSD
|
||||
- sendfile portability fixes
|
||||
- new makefiles
|
||||
- example app for testing static file serving
|
||||
- fixes for ROCK_SOLID mode
|
||||
|
||||
*** january 2010 ***
|
||||
|
||||
- Integrated Spooler
|
||||
- better error management
|
||||
- long options
|
||||
- clustering functions
|
||||
- experimental lighttpd module
|
||||
- official support for OpenBSD and OpenSolaris
|
||||
- FastFuncs
|
||||
- new functions for embedded module
|
||||
- reliable harakiri
|
||||
- better Makefiles
|
||||
- python threads support in master process
|
||||
- proper timeout handling in apache2 module
|
||||
- endianess fixes all over the place
|
||||
- paste support
|
||||
- Django app for managing and monitoring the uWSGI server
|
||||
- options for changin uid/gid and chrooting when run by root
|
||||
- lot of bugfixes and optimizations
|
||||
|
||||
*** 20091129 Version 0.9.3 ***
|
||||
|
||||
- Nginx 0.7.x module
|
||||
- configuration via python module
|
||||
- support (non-standard) for Python 3.x
|
||||
- Twisted client resource adapter
|
||||
- graceful restart of worker processes and hot-plug substitution/upgrade of the uWSGI server
|
||||
- shared memory area to share data between workers/processes
|
||||
- Tomcat handler
|
||||
- support for virtualenv
|
||||
- tons of bugfixes and optimizations
|
||||
|
||||
*** 20090829 Version 0.9.2 ***
|
||||
|
||||
- TCP support
|
||||
- configurable internal timeout (socket/poll)
|
||||
- Cherokee handler
|
||||
- code refactoring
|
||||
- Makefiles
|
||||
- customizable harakiri handler (put an harakiri(environ, start_response) function in your wsgi script)
|
||||
- limit requests per worker
|
||||
- a lot of bugfix and optimizations
|
||||
@@ -1,3 +1,3 @@
|
||||
surprise i am empty !
|
||||
|
||||
Look in the online documentation on https://uwsgi-docs.readthedocs.org/en/latest/
|
||||
Look in the online documentation on http://projects.unbit.it/uwsgi/
|
||||
|
||||
+43
-40
@@ -1,36 +1,6 @@
|
||||
/*
|
||||
|
||||
*** mod_proxy_uwsgi ***
|
||||
|
||||
Copyright 2009-2013 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
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
|
||||
To build:
|
||||
|
||||
apxs2 -i -c mod_proxy_uwsgi.c
|
||||
|
||||
To use:
|
||||
|
||||
LoadModule proxy_uwsgi_module /usr/lib/apache2/modules/mod_proxy_uwsgi.so
|
||||
ProxyPass / uwsgi://127.0.0.1:3031/
|
||||
|
||||
Docs:
|
||||
|
||||
http://uwsgi-docs.readthedocs.org/en/latest/Apache.html#mod-proxy-uwsgi
|
||||
apxs2 -i -c mod_proxy_uwsgi.c
|
||||
|
||||
*/
|
||||
#define APR_WANT_MEMFUNC
|
||||
@@ -217,6 +187,28 @@ static int uwsgi_send_body(request_rec *r, proxy_conn_rec *conn)
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -236,7 +228,11 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_
|
||||
|
||||
apr_bucket_brigade *bb = apr_brigade_create(r->pool, c->bucket_alloc);
|
||||
|
||||
len = ap_getline(buffer, sizeof(buffer), rp, 1);
|
||||
|
||||
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
|
||||
@@ -245,11 +241,25 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_
|
||||
|
||||
backend->worker->s->read += len;
|
||||
|
||||
if (!apr_date_checkmask(buffer, "HTTP/#.# ###*") || len >= sizeof(buffer)-1) {
|
||||
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]);
|
||||
@@ -343,13 +353,6 @@ static int uwsgi_handler(request_rec *r, proxy_worker *worker,
|
||||
if (u_path_info[0] != '/') {
|
||||
delta = 1;
|
||||
}
|
||||
int decode_status = ap_unescape_url(url+w_len-delta);
|
||||
if (decode_status) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
"unable to decode uri: %s",
|
||||
url+w_len-delta);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
apr_table_add(r->subprocess_env, "PATH_INFO", url+w_len-delta);
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
*** uWSGI/mod_uwsgi ***
|
||||
|
||||
Copyright 2009-2013 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
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
cmd = File.expand_path "#{File.dirname(__FILE__)}/../ext/uwsgi/uwsgi.ruby"
|
||||
|
||||
exec(cmd, *ARGV)
|
||||
@@ -0,0 +1 @@
|
||||
object file for embedded files will be put here
|
||||
+7
-1
@@ -6,7 +6,13 @@ json = auto
|
||||
sqlite3 = auto
|
||||
zeromq = auto
|
||||
snmp = true
|
||||
spooler = true
|
||||
embedded = true
|
||||
ssl = auto
|
||||
udp = true
|
||||
multicast = true
|
||||
threading = true
|
||||
minterpreters = true
|
||||
async = true
|
||||
ldap = auto
|
||||
pcre = auto
|
||||
@@ -23,7 +29,7 @@ plugins =
|
||||
bin_name = uwsgi
|
||||
append_version =
|
||||
plugin_dir = .
|
||||
embedded_plugins = %(main_plugin)s, ping, cache, nagios, rrdtool, carbon, rpc, corerouter, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool, redislog, mongodblog, router_rewrite, router_http, logfile, router_cache, rawrouter, router_static, sslrouter
|
||||
embedded_plugins = %(main_plugin)s, ping, cache, nagios, rrdtool, carbon, rpc, corerouter, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool, redislog, mongodblog, router_rewrite, router_http, logfile, router_cache, rawrouter
|
||||
as_shared_library = false
|
||||
|
||||
locking = auto
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
[uwsgi]
|
||||
# pypy,jvm,ring,jwsgi
|
||||
main_plugin = erlang,psgi,rack,lua,python,gevent,php,cgi,mono,pyerl,go
|
||||
inherit = base
|
||||
@@ -1,3 +0,0 @@
|
||||
[uwsgi]
|
||||
main_plugin = jvm,jwsgi
|
||||
inherit = base
|
||||
@@ -1,3 +0,0 @@
|
||||
[uwsgi]
|
||||
main_plugin = mono
|
||||
inherit = base
|
||||
@@ -1,3 +0,0 @@
|
||||
[uwsgi]
|
||||
main_plugin = jvm,ring
|
||||
inherit = base
|
||||
@@ -1,3 +0,0 @@
|
||||
[uwsgi]
|
||||
main_plugin =
|
||||
inherit = base
|
||||
@@ -5,6 +5,14 @@ yaml = true
|
||||
json = false
|
||||
sqlite3 = false
|
||||
zeromq = false
|
||||
snmp = false
|
||||
spooler = true
|
||||
embedded = true
|
||||
udp = true
|
||||
multicast = false
|
||||
threading = true
|
||||
minterpreters = true
|
||||
async = true
|
||||
ldap = true
|
||||
pcre = true
|
||||
routing = true
|
||||
|
||||
+1
-4
@@ -1,15 +1,12 @@
|
||||
use POSIX;
|
||||
use IO::Socket::INET;
|
||||
use IO::Socket::INET6;
|
||||
use IO::Socket::UNIX;
|
||||
|
||||
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);
|
||||
my $s4 = IO::Socket::UNIX->new(Local => '/tmp/u.sock', Listen => 1);
|
||||
|
||||
dup2($s->fileno, 17);
|
||||
dup2($s2->fileno, 22);
|
||||
dup2($s3->fileno, 30);
|
||||
dup2($s4->fileno, 0);
|
||||
exec './uwsgi','-M', '--socket','fd://17', '--http-socket','fd://22', '--socket','fd://30','--stats',':5001';
|
||||
exec './uwsgi','-M', '--socket','fd://17', '--http-socket','fd://22', '--socket','fd://30';
|
||||
|
||||
+4
-77
@@ -136,8 +136,7 @@ static struct uwsgi_alarm_instance *uwsgi_alarm_get_instance(char *name) {
|
||||
}
|
||||
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
static int uwsgi_alarm_log_add(char *alarms, char *regexp, int negate) {
|
||||
static int uwsgi_alarm_log_add(char *alarms, char *regexp) {
|
||||
|
||||
struct uwsgi_alarm_log *old_ual = NULL, *ual = uwsgi.alarm_logs;
|
||||
while (ual) {
|
||||
@@ -149,7 +148,6 @@ static int uwsgi_alarm_log_add(char *alarms, char *regexp, int negate) {
|
||||
if (uwsgi_regexp_build(regexp, &ual->pattern, &ual->pattern_extra)) {
|
||||
return -1;
|
||||
}
|
||||
ual->negate = negate;
|
||||
|
||||
if (old_ual) {
|
||||
old_ual->next = ual;
|
||||
@@ -163,10 +161,8 @@ static int uwsgi_alarm_log_add(char *alarms, char *regexp, int negate) {
|
||||
char *p = strtok(list, ",");
|
||||
while (p) {
|
||||
struct uwsgi_alarm_instance *uai = uwsgi_alarm_get_instance(p);
|
||||
if (!uai) {
|
||||
free(list);
|
||||
if (!uai)
|
||||
return -1;
|
||||
}
|
||||
struct uwsgi_alarm_ll *old_uall = NULL, *uall = ual->alarms;
|
||||
while (uall) {
|
||||
old_uall = uall;
|
||||
@@ -183,38 +179,12 @@ static int uwsgi_alarm_log_add(char *alarms, char *regexp, int negate) {
|
||||
}
|
||||
p = strtok(NULL, ",");
|
||||
}
|
||||
free(list);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void uwsgi_alarm_thread_loop(struct uwsgi_thread *ut) {
|
||||
char *buf = uwsgi_malloc(uwsgi.alarm_msg_size + sizeof(long));
|
||||
for (;;) {
|
||||
int interesting_fd = -1;
|
||||
int ret = event_queue_wait(ut->queue, -1, &interesting_fd);
|
||||
if (ret > 0) {
|
||||
ssize_t len = read(ut->pipe[1], buf, uwsgi.alarm_msg_size + sizeof(long));
|
||||
if (len > (ssize_t)(sizeof(long) + 1)) {
|
||||
size_t msg_size = len - sizeof(long);
|
||||
char *msg = buf + sizeof(long);
|
||||
long ptr = 0;
|
||||
memcpy(&ptr, buf, sizeof(long));
|
||||
struct uwsgi_alarm_instance *uai = (struct uwsgi_alarm_instance *) ptr;
|
||||
if (!uai)
|
||||
break;
|
||||
uwsgi_alarm_run(uai, msg, msg_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
|
||||
// initialize alarms, instances and log regexps
|
||||
void uwsgi_alarms_init() {
|
||||
|
||||
if (!uwsgi.master_process) return;
|
||||
|
||||
// first of all, create instance of alarms
|
||||
struct uwsgi_string_list *usl = uwsgi.alarm_list;
|
||||
while (usl) {
|
||||
@@ -241,9 +211,6 @@ void uwsgi_alarms_init() {
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
if (!uwsgi.alarm_instances) return;
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
// then map log-alarm
|
||||
usl = uwsgi.alarm_logs_list;
|
||||
while (usl) {
|
||||
@@ -256,27 +223,15 @@ void uwsgi_alarms_init() {
|
||||
*space = 0;
|
||||
char *regexp = space + 1;
|
||||
// here the log-alarm is created
|
||||
if (uwsgi_alarm_log_add(line, regexp, usl->custom)) {
|
||||
if (uwsgi_alarm_log_add(line, regexp)) {
|
||||
uwsgi_log("invalid log-alarm: %s\n", usl->value);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
usl = usl->next;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void uwsgi_alarm_thread_start() {
|
||||
if (!uwsgi.alarm_instances) return;
|
||||
// start the alarm_thread
|
||||
uwsgi.alarm_thread = uwsgi_thread_new(uwsgi_alarm_thread_loop);
|
||||
if (!uwsgi.alarm_thread) {
|
||||
uwsgi_log("unable to spawn alarm thread\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
// check if a log should raise an alarm
|
||||
void uwsgi_alarm_log_check(char *msg, size_t len) {
|
||||
if (!uwsgi_strncmp(msg, len, "[uwsgi-alarm", 12))
|
||||
@@ -284,17 +239,11 @@ void uwsgi_alarm_log_check(char *msg, size_t len) {
|
||||
struct uwsgi_alarm_log *ual = uwsgi.alarm_logs;
|
||||
while (ual) {
|
||||
if (uwsgi_regexp_match(ual->pattern, ual->pattern_extra, msg, len) >= 0) {
|
||||
if (!ual->negate) {
|
||||
uwsgi_alarm_log_run(ual, msg, len);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
uwsgi_alarm_log_run(ual, msg, len);
|
||||
}
|
||||
ual = ual->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// call the alarm func
|
||||
void uwsgi_alarm_run(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
|
||||
@@ -310,7 +259,6 @@ void uwsgi_alarm_run(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
|
||||
uai->last_msg_size = len;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
// call the alarms mapped to a log line
|
||||
void uwsgi_alarm_log_run(struct uwsgi_alarm_log *ual, char *msg, size_t len) {
|
||||
struct uwsgi_alarm_ll *uall = ual->alarms;
|
||||
@@ -319,24 +267,3 @@ void uwsgi_alarm_log_run(struct uwsgi_alarm_log *ual, char *msg, size_t len) {
|
||||
uall = uall->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// this is the api function workers,mules and whatever you want can call from code
|
||||
void uwsgi_alarm_trigger(char *alarm_instance_name, char *msg, size_t len) {
|
||||
if (!uwsgi.alarm_thread) return;
|
||||
if (len > uwsgi.alarm_msg_size) return;
|
||||
struct uwsgi_alarm_instance *uai = uwsgi_alarm_get_instance(alarm_instance_name);
|
||||
if (!uai) return;
|
||||
|
||||
struct iovec iov[2];
|
||||
iov[0].iov_base = &uai;
|
||||
iov[0].iov_len = sizeof(long);
|
||||
iov[1].iov_base = msg;
|
||||
iov[1].iov_len = len;
|
||||
|
||||
// now send the message to the alarm thread
|
||||
if (writev(uwsgi.alarm_thread->pipe[0], iov, 2) != (ssize_t) (len+sizeof(long))) {
|
||||
uwsgi_error("[uwsgi-alarm-error] uwsgi_alarm_trigger()/writev()");
|
||||
}
|
||||
}
|
||||
|
||||
+37
-64
@@ -1,14 +1,7 @@
|
||||
#include <uwsgi.h>
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_async_queue_is_full(time_t now) {
|
||||
if (now > uwsgi.async_queue_is_full) {
|
||||
uwsgi_log_verbose("[DANGER] async queue is full !!!\n");
|
||||
uwsgi.async_queue_is_full = now;
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_async_init() {
|
||||
int i;
|
||||
|
||||
@@ -40,7 +33,7 @@ struct wsgi_request *find_wsgi_req_by_fd(int fd) {
|
||||
return uwsgi.async_waiting_fd_table[fd];
|
||||
}
|
||||
|
||||
static void runqueue_remove(struct uwsgi_async_request *u_request) {
|
||||
void runqueue_remove(struct uwsgi_async_request *u_request) {
|
||||
|
||||
struct uwsgi_async_request *parent = u_request->prev;
|
||||
struct uwsgi_async_request *child = u_request->next;
|
||||
@@ -65,7 +58,7 @@ static void runqueue_remove(struct uwsgi_async_request *u_request) {
|
||||
uwsgi.async_runqueue_cnt--;
|
||||
}
|
||||
|
||||
static void runqueue_push(struct wsgi_request *wsgi_req) {
|
||||
void runqueue_push(struct wsgi_request *wsgi_req) {
|
||||
|
||||
struct uwsgi_async_request *uar;
|
||||
|
||||
@@ -103,9 +96,10 @@ struct wsgi_request *find_first_available_wsgi_req() {
|
||||
return wsgi_req;
|
||||
}
|
||||
|
||||
static void async_expire_timeouts(uint64_t now) {
|
||||
void async_expire_timeouts() {
|
||||
|
||||
struct wsgi_request *wsgi_req;
|
||||
uint64_t current_time = (uint64_t) uwsgi_now();
|
||||
struct uwsgi_async_fd *uaf = NULL, *current_uaf;
|
||||
|
||||
struct uwsgi_rb_timer *urbt;
|
||||
@@ -117,7 +111,7 @@ static void async_expire_timeouts(uint64_t now) {
|
||||
if (urbt == NULL)
|
||||
return;
|
||||
|
||||
if (urbt->value <= now) {
|
||||
if (urbt->value <= current_time) {
|
||||
wsgi_req = (struct wsgi_request *) urbt->data;
|
||||
// timeout expired
|
||||
wsgi_req->async_timed_out = 1;
|
||||
@@ -144,12 +138,12 @@ static void async_expire_timeouts(uint64_t now) {
|
||||
|
||||
}
|
||||
|
||||
int async_add_fd_read(struct wsgi_request *wsgi_req, int fd, int timeout) {
|
||||
void async_add_fd_read(struct wsgi_request *wsgi_req, int fd, int timeout) {
|
||||
|
||||
struct uwsgi_async_fd *last_uad = NULL, *uad = wsgi_req->waiting_fds;
|
||||
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
return;
|
||||
|
||||
// find first slot
|
||||
while (uad) {
|
||||
@@ -174,23 +168,8 @@ int async_add_fd_read(struct wsgi_request *wsgi_req, int fd, int timeout) {
|
||||
async_add_timeout(wsgi_req, timeout);
|
||||
}
|
||||
uwsgi.async_waiting_fd_table[fd] = wsgi_req;
|
||||
wsgi_req->async_force_again = 1;
|
||||
return event_queue_add_fd_read(uwsgi.async_queue, fd);
|
||||
}
|
||||
event_queue_add_fd_read(uwsgi.async_queue, fd);
|
||||
|
||||
static int async_wait_fd_read(int fd, int timeout) {
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
if (async_add_fd_read(wsgi_req, fd, timeout)) {
|
||||
return -1;
|
||||
}
|
||||
if (uwsgi.schedule_to_main) {
|
||||
uwsgi.schedule_to_main(wsgi_req);
|
||||
}
|
||||
if (wsgi_req->async_timed_out) {
|
||||
wsgi_req->async_timed_out = 0;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void async_add_timeout(struct wsgi_request *wsgi_req, int timeout) {
|
||||
@@ -201,12 +180,12 @@ void async_add_timeout(struct wsgi_request *wsgi_req, int timeout) {
|
||||
|
||||
}
|
||||
|
||||
int async_add_fd_write(struct wsgi_request *wsgi_req, int fd, int timeout) {
|
||||
void async_add_fd_write(struct wsgi_request *wsgi_req, int fd, int timeout) {
|
||||
|
||||
struct uwsgi_async_fd *last_uad = NULL, *uad = wsgi_req->waiting_fds;
|
||||
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
return;
|
||||
|
||||
// find first slot
|
||||
while (uad) {
|
||||
@@ -232,27 +211,12 @@ int async_add_fd_write(struct wsgi_request *wsgi_req, int fd, int timeout) {
|
||||
}
|
||||
|
||||
uwsgi.async_waiting_fd_table[fd] = wsgi_req;
|
||||
wsgi_req->async_force_again = 1;
|
||||
return event_queue_add_fd_write(uwsgi.async_queue, fd);
|
||||
}
|
||||
event_queue_add_fd_write(uwsgi.async_queue, fd);
|
||||
|
||||
static int async_wait_fd_write(int fd, int timeout) {
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
if (async_add_fd_write(wsgi_req, fd, timeout)) {
|
||||
return -1;
|
||||
}
|
||||
if (uwsgi.schedule_to_main) {
|
||||
uwsgi.schedule_to_main(wsgi_req);
|
||||
}
|
||||
if (wsgi_req->async_timed_out) {
|
||||
wsgi_req->async_timed_out = 0;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void async_schedule_to_req(void) {
|
||||
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req);
|
||||
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh.modifier1]->request(uwsgi.wsgi_req);
|
||||
}
|
||||
|
||||
void async_loop() {
|
||||
@@ -269,7 +233,7 @@ void async_loop() {
|
||||
int is_a_new_connection;
|
||||
int proto_parser_status;
|
||||
|
||||
uint64_t now;
|
||||
time_t now, last_now = 0;
|
||||
|
||||
static struct uwsgi_async_request *current_request = NULL, *next_async_request = NULL;
|
||||
|
||||
@@ -279,9 +243,6 @@ void async_loop() {
|
||||
uwsgi.async_runqueue = NULL;
|
||||
uwsgi.async_runqueue_cnt = 0;
|
||||
|
||||
uwsgi.wait_write_hook = async_wait_fd_write;
|
||||
uwsgi.wait_read_hook = async_wait_fd_read;
|
||||
|
||||
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);
|
||||
@@ -291,22 +252,20 @@ void async_loop() {
|
||||
if (!uwsgi.schedule_to_req)
|
||||
uwsgi.schedule_to_req = async_schedule_to_req;
|
||||
|
||||
if (!uwsgi.schedule_to_main) {
|
||||
uwsgi_log("*** WARNING *** async mode without coroutine/greenthread engine loaded !!!\n");
|
||||
}
|
||||
|
||||
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
|
||||
|
||||
now = (uint64_t) uwsgi_now();
|
||||
if (uwsgi.async_runqueue_cnt) {
|
||||
timeout = 0;
|
||||
}
|
||||
else {
|
||||
min_timeout = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts, NULL);
|
||||
if (uwsgi.async_runqueue_cnt) {
|
||||
timeout = 0;
|
||||
}
|
||||
if (min_timeout) {
|
||||
timeout = min_timeout->value - now;
|
||||
timeout = min_timeout->value - uwsgi_now();
|
||||
if (timeout <= 0) {
|
||||
async_expire_timeouts(now);
|
||||
async_expire_timeouts();
|
||||
timeout = 0;
|
||||
}
|
||||
}
|
||||
@@ -317,10 +276,9 @@ void async_loop() {
|
||||
|
||||
uwsgi.async_nevents = event_queue_wait_multi(uwsgi.async_queue, timeout, events, 64);
|
||||
|
||||
now = (uint64_t) uwsgi_now();
|
||||
// timeout ???
|
||||
if (uwsgi.async_nevents == 0) {
|
||||
async_expire_timeouts(now);
|
||||
async_expire_timeouts();
|
||||
}
|
||||
|
||||
|
||||
@@ -347,7 +305,11 @@ void async_loop() {
|
||||
|
||||
uwsgi.wsgi_req = find_first_available_wsgi_req();
|
||||
if (uwsgi.wsgi_req == NULL) {
|
||||
uwsgi_async_queue_is_full((time_t)now);
|
||||
now = uwsgi_now();
|
||||
if (now > last_now) {
|
||||
uwsgi_log("async queue is full !!!\n");
|
||||
last_now = now;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -357,6 +319,18 @@ void async_loop() {
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
|
||||
break;
|
||||
}
|
||||
// on linux we do not need to reset the socket to blocking state
|
||||
#ifndef __linux__
|
||||
/* 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)) {
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
@@ -432,7 +406,6 @@ void async_loop() {
|
||||
|
||||
// put the request in the runqueue again
|
||||
runqueue_push(uwsgi.wsgi_req);
|
||||
// avoid managing other enqueued events...
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+8
-212
@@ -48,50 +48,6 @@ int uwsgi_buffer_ensure(struct uwsgi_buffer *ub, size_t len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_insert(struct uwsgi_buffer *ub, size_t pos, char *buf, size_t len) {
|
||||
size_t to_move = (ub->pos-pos);
|
||||
if (uwsgi_buffer_ensure(ub, len)) return -1;
|
||||
memmove(ub->buf+pos+len, ub->buf+pos, to_move);
|
||||
memcpy(ub->buf+pos, buf, len);
|
||||
ub->pos += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_insert_chunked(struct uwsgi_buffer *ub, size_t pos, size_t len) {
|
||||
// 0xFFFFFFFFFFFFFFFF\r\n\0
|
||||
char chunked[19];
|
||||
int ret = snprintf(chunked, 19, "%X\r\n", (unsigned int) len);
|
||||
if (ret <= 0 || ret > 19) {
|
||||
return -1;
|
||||
}
|
||||
return uwsgi_buffer_insert(ub, pos, chunked, ret);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append_chunked(struct uwsgi_buffer *ub, size_t len) {
|
||||
// 0xFFFFFFFFFFFFFFFF\r\n\0
|
||||
char chunked[19];
|
||||
int ret = snprintf(chunked, 19, "%X\r\n", (unsigned int) len);
|
||||
if (ret <= 0 || ret > 19) {
|
||||
return -1;
|
||||
}
|
||||
return uwsgi_buffer_append(ub, chunked, ret);
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_buffer_decapitate(struct uwsgi_buffer *ub, size_t len) {
|
||||
if (len > ub->pos) return -1;
|
||||
memmove(ub->buf, ub->buf + len, ub->pos-len);
|
||||
ub->pos = ub->pos-len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_byte(struct uwsgi_buffer *ub, char byte) {
|
||||
return uwsgi_buffer_append(ub, &byte, 1);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u8(struct uwsgi_buffer *ub, uint8_t u8) {
|
||||
return uwsgi_buffer_append(ub, (char *) &u8, 1);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append(struct uwsgi_buffer *ub, char *buf, size_t len) {
|
||||
|
||||
@@ -121,173 +77,12 @@ int uwsgi_buffer_append(struct uwsgi_buffer *ub, char *buf, size_t len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append_json(struct uwsgi_buffer *ub, char *buf, size_t len) {
|
||||
// need to escape \ and "
|
||||
size_t i;
|
||||
for(i=0;i<len;i++) {
|
||||
if (buf[i] == '"') {
|
||||
if (uwsgi_buffer_append(ub, "\\\"", 2)) return -1;
|
||||
}
|
||||
else if (buf[i] == '\\') {
|
||||
if (uwsgi_buffer_append(ub, "\\\\", 2)) return -1;
|
||||
}
|
||||
else {
|
||||
if (uwsgi_buffer_append(ub, buf+i, 1)) return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u16le(struct uwsgi_buffer *ub, uint16_t num) {
|
||||
uint8_t buf[2];
|
||||
buf[0] = (uint8_t) (num & 0xff);
|
||||
buf[1] = (uint8_t) ((num >> 8) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 2);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u16be(struct uwsgi_buffer *ub, uint16_t num) {
|
||||
uint8_t buf[2];
|
||||
buf[1] = (uint8_t) (num & 0xff);
|
||||
buf[0] = (uint8_t) ((num >> 8) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 2);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u24be(struct uwsgi_buffer *ub, uint32_t num) {
|
||||
uint8_t buf[3];
|
||||
buf[2] = (uint8_t) (num & 0xff);
|
||||
buf[1] = (uint8_t) ((num >> 8) & 0xff);
|
||||
buf[0] = (uint8_t) ((num >> 16) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 3);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u32be(struct uwsgi_buffer *ub, uint32_t num) {
|
||||
uint8_t buf[4];
|
||||
buf[3] = (uint8_t) (num & 0xff);
|
||||
buf[2] = (uint8_t) ((num >> 8) & 0xff);
|
||||
buf[1] = (uint8_t) ((num >> 16) & 0xff);
|
||||
buf[0] = (uint8_t) ((num >> 24) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 4);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u32le(struct uwsgi_buffer *ub, uint32_t num) {
|
||||
uint8_t buf[4];
|
||||
buf[0] = (uint8_t) (num & 0xff);
|
||||
buf[1] = (uint8_t) ((num >> 8) & 0xff);
|
||||
buf[2] = (uint8_t) ((num >> 16) & 0xff);
|
||||
buf[3] = (uint8_t) ((num >> 24) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 4);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u64be(struct uwsgi_buffer *ub, uint64_t num) {
|
||||
uint8_t buf[8];
|
||||
buf[7] = (uint8_t) (num & 0xff);
|
||||
buf[6] = (uint8_t) ((num >> 8) & 0xff);
|
||||
buf[5] = (uint8_t) ((num >> 16) & 0xff);
|
||||
buf[4] = (uint8_t) ((num >> 24) & 0xff);
|
||||
buf[3] = (uint8_t) ((num >> 32) & 0xff);
|
||||
buf[2] = (uint8_t) ((num >> 40) & 0xff);
|
||||
buf[1] = (uint8_t) ((num >> 48) & 0xff);
|
||||
buf[0] = (uint8_t) ((num >> 56) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 8);
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_buffer_append_ipv4(struct uwsgi_buffer *ub, void *addr) {
|
||||
char ip[INET_ADDRSTRLEN];
|
||||
if (!inet_ntop(AF_INET, addr, ip, INET_ADDRSTRLEN)) {
|
||||
uwsgi_error("uwsgi_buffer_append_ipv4() -> inet_ntop()");
|
||||
return -1;
|
||||
}
|
||||
return uwsgi_buffer_append(ub, ip, strlen(ip));
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_buffer_num64(struct uwsgi_buffer *ub, int64_t num) {
|
||||
char buf[sizeof(UMAX64_STR)+1];
|
||||
int ret = snprintf(buf, sizeof(UMAX64_STR)+1, "%lld", (long long) num);
|
||||
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
|
||||
return -1;
|
||||
}
|
||||
return uwsgi_buffer_append(ub, buf, ret);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append_keyval(struct uwsgi_buffer *ub, char *key, uint16_t keylen, char *val, uint16_t vallen) {
|
||||
if (uwsgi_buffer_u16le(ub, keylen)) return -1;
|
||||
if (uwsgi_buffer_append(ub, key, keylen)) return -1;
|
||||
if (uwsgi_buffer_u16le(ub, vallen)) return -1;
|
||||
return uwsgi_buffer_append(ub, val, vallen);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append_keyval32(struct uwsgi_buffer *ub, char *key, uint32_t keylen, char *val, uint32_t vallen) {
|
||||
if (uwsgi_buffer_u32be(ub, keylen)) return -1;
|
||||
if (uwsgi_buffer_append(ub, key, keylen)) return -1;
|
||||
if (uwsgi_buffer_u32be(ub, vallen)) return -1;
|
||||
return uwsgi_buffer_append(ub, val, vallen);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append_keynum(struct uwsgi_buffer *ub, char *key, uint16_t keylen, int64_t num) {
|
||||
char buf[sizeof(UMAX64_STR)+1];
|
||||
int ret = snprintf(buf, (sizeof(UMAX64_STR)+1), "%lld", (long long) num);
|
||||
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
|
||||
return -1;
|
||||
}
|
||||
if (uwsgi_buffer_u16le(ub, keylen)) return -1;
|
||||
if (uwsgi_buffer_append(ub, key, keylen)) return -1;
|
||||
if (uwsgi_buffer_u16le(ub, ret)) return -1;
|
||||
return uwsgi_buffer_append(ub, buf, ret);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append_valnum(struct uwsgi_buffer *ub, int64_t num) {
|
||||
char buf[sizeof(UMAX64_STR)+1];
|
||||
int ret = snprintf(buf, (sizeof(UMAX64_STR)+1), "%lld", (long long) num);
|
||||
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
|
||||
return -1;
|
||||
}
|
||||
if (uwsgi_buffer_u16le(ub, ret)) return -1;
|
||||
return uwsgi_buffer_append(ub, buf, ret);
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_buffer_append_keyipv4(struct uwsgi_buffer *ub, char *key, uint16_t keylen, void *addr) {
|
||||
if (uwsgi_buffer_u16le(ub, keylen)) return -1;
|
||||
if (uwsgi_buffer_append(ub, key, keylen)) return -1;
|
||||
if (uwsgi_buffer_u16le(ub, 15)) return -1;
|
||||
char *ptr = ub->buf + (ub->pos - 2);
|
||||
if (uwsgi_buffer_append_ipv4(ub, addr)) return -1;
|
||||
// fix the size
|
||||
*ptr = ((ub->buf+ub->pos) - (ptr+2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append_base64(struct uwsgi_buffer *ub, char *s, size_t len) {
|
||||
size_t b64_len = 0;
|
||||
char *b64 = uwsgi_base64_encode(s, len, &b64_len);
|
||||
if (!b64) return -1;
|
||||
int ret = uwsgi_buffer_append(ub, b64, b64_len);
|
||||
free(b64);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_buffer_destroy(struct uwsgi_buffer *ub) {
|
||||
if (ub->buf)
|
||||
free(ub->buf);
|
||||
free(ub);
|
||||
}
|
||||
|
||||
ssize_t uwsgi_buffer_write_simple(struct wsgi_request *wsgi_req, struct uwsgi_buffer *ub) {
|
||||
size_t remains = ub->pos;
|
||||
while(remains) {
|
||||
ssize_t len = write(wsgi_req->fd, ub->buf + (ub->pos - remains), remains);
|
||||
if (len <= 0) {
|
||||
return len;
|
||||
}
|
||||
remains -= len;
|
||||
}
|
||||
|
||||
return ub->pos;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_send(struct uwsgi_buffer *ub, int fd) {
|
||||
size_t remains = ub->pos;
|
||||
char *ptr = ub->buf;
|
||||
@@ -320,11 +115,12 @@ int uwsgi_buffer_send(struct uwsgi_buffer *ub, int fd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_set_uh(struct uwsgi_buffer *ub, uint8_t modifier1, uint8_t modifier2) {
|
||||
if (ub->pos < 4) return -1;
|
||||
ub->buf[0] = modifier1;
|
||||
ub->buf[1] = (uint8_t) ((ub->pos - 4) & 0xff);
|
||||
ub->buf[2] = (uint8_t) (((ub->pos - 4) >> 8) & 0xff);
|
||||
ub->buf[3] = modifier2;
|
||||
return 0;
|
||||
int uwsgi_buffer_num64(struct uwsgi_buffer *ub, int64_t num) {
|
||||
char buf[sizeof(UMAX64_STR)+1];
|
||||
int ret = snprintf(buf, sizeof(UMAX64_STR)+1, "%lld", (long long) num);
|
||||
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
|
||||
return -1;
|
||||
}
|
||||
return uwsgi_buffer_append(ub, buf, ret);
|
||||
}
|
||||
|
||||
|
||||
+231
-1455
File diff suppressed because it is too large
Load Diff
+464
@@ -0,0 +1,464 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
|
||||
#ifdef UWSGI_UDP
|
||||
|
||||
static void cluster_manage_opt(char *key, uint16_t keylen, char *value, uint16_t vallen, void *foobar) {
|
||||
|
||||
add_exported_option(uwsgi_concat2n(key, keylen, "", 0), uwsgi_concat2n(value, vallen, "", 0), 0);
|
||||
|
||||
}
|
||||
|
||||
void cluster_setup() {
|
||||
|
||||
int rlen;
|
||||
// get cluster configuration
|
||||
if (uwsgi.cluster != NULL) {
|
||||
// get multicast socket
|
||||
|
||||
uwsgi.cluster_fd = uwsgi_cluster_join(uwsgi.cluster);
|
||||
|
||||
uwsgi_log("JOINED CLUSTER: %s\n", uwsgi.cluster);
|
||||
|
||||
// ask for cluster options only if bot pre-existent options are set
|
||||
if (uwsgi.exported_opts_cnt == 1 && !uwsgi.cluster_nodes) {
|
||||
// now wait max 60 seconds and resend multicast request every 10 seconds
|
||||
for (;;) {
|
||||
uwsgi_log("asking \"%s\" uWSGI cluster for configuration data:\n", uwsgi.cluster);
|
||||
if (uwsgi_send_empty_pkt(uwsgi.cluster_fd, uwsgi.cluster, 99, 0) < 0) {
|
||||
uwsgi_log("unable to send multicast message to %s\n", uwsgi.cluster);
|
||||
continue;
|
||||
}
|
||||
waitfd:
|
||||
rlen = uwsgi_waitfd(uwsgi.cluster_fd, 10);
|
||||
if (rlen < 0) {
|
||||
break;
|
||||
}
|
||||
else if (rlen > 0) {
|
||||
// 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();
|
||||
goto options_parsed;
|
||||
}
|
||||
else {
|
||||
goto waitfd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
options_parsed:
|
||||
|
||||
if (!uwsgi.cluster_nodes)
|
||||
uwsgi_cluster_add_me();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void uwsgi_cluster_add_node(struct uwsgi_cluster_node *nucn, int type) {
|
||||
|
||||
int i;
|
||||
struct uwsgi_cluster_node *ucn;
|
||||
char *tcp_port;
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("adding node\n");
|
||||
#endif
|
||||
|
||||
tcp_port = strchr(nucn->name, ':');
|
||||
#ifndef UWSGI_ZEROMQ
|
||||
if (tcp_port == NULL) {
|
||||
#else
|
||||
char *zmq_dash = strchr(nucn->name, '-');
|
||||
if (tcp_port == NULL && zmq_dash == NULL) {
|
||||
#endif
|
||||
|
||||
fprintf(stdout, "invalid cluster node name %s\n", nucn->name);
|
||||
return;
|
||||
}
|
||||
|
||||
// first check for already present node
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
ucn = &uwsgi.shared->nodes[i];
|
||||
if (ucn->name[0] != 0) {
|
||||
if (!strcmp(ucn->name, nucn->name)) {
|
||||
ucn->status = UWSGI_NODE_OK;
|
||||
ucn->last_seen = uwsgi_now();
|
||||
// update requests
|
||||
ucn->requests = nucn->requests;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
ucn = &uwsgi.shared->nodes[i];
|
||||
|
||||
if (ucn->name[0] == 0) {
|
||||
memcpy(ucn->name, nucn->name, strlen(nucn->name) + 1);
|
||||
memcpy(ucn->nodename, nucn->nodename, strlen(nucn->nodename) + 1);
|
||||
ucn->workers = nucn->workers;
|
||||
ucn->ucn_addr.sin_family = AF_INET;
|
||||
if (tcp_port) {
|
||||
ucn->ucn_addr.sin_port = htons(atoi(tcp_port + 1));
|
||||
tcp_port[0] = 0;
|
||||
}
|
||||
if (nucn->name[0] == 0) {
|
||||
ucn->ucn_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
}
|
||||
else {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%s\n", nucn->name);
|
||||
#endif
|
||||
ucn->ucn_addr.sin_addr.s_addr = inet_addr(nucn->name);
|
||||
}
|
||||
|
||||
ucn->type = type;
|
||||
// here memory can be freed, as it is allocated by uwsgi_concat2n
|
||||
if (type != CLUSTER_NODE_DYNAMIC && tcp_port) {
|
||||
tcp_port[0] = ':';
|
||||
}
|
||||
ucn->last_seen = uwsgi_now();
|
||||
ucn->requests = nucn->requests;
|
||||
uwsgi_log("[uWSGI cluster] added node %s\n", ucn->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("unable to add node %s\n", nucn->name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int uwsgi_cluster_add_me() {
|
||||
|
||||
const char *key1 = "hostname";
|
||||
const char *key2 = "address";
|
||||
const char *key3 = "workers";
|
||||
const char *key4 = "requests";
|
||||
|
||||
char *ptrbuf;
|
||||
uint16_t ustrlen;
|
||||
char numproc[6];
|
||||
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
char uuid_zmq_str[37];
|
||||
uuid_t uuid_zmq;
|
||||
if (!uwsgi.sockets && !uwsgi.zeromq) {
|
||||
#else
|
||||
if (!uwsgi.sockets) {
|
||||
#endif
|
||||
uwsgi_log("you need to specify at least a socket to start a uWSGI cluster\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
snprintf(numproc, 6, "%d", uwsgi.numproc);
|
||||
|
||||
size_t len;
|
||||
|
||||
if (uwsgi.sockets) {
|
||||
len = 2 + strlen(key1) + 2 + strlen(uwsgi.hostname) + 2 + strlen(key2) + 2 + strlen(uwsgi.sockets->name) + 2 + strlen(key3) + 2 + strlen(numproc) + 2 + strlen(key4) + 2 + 1;
|
||||
}
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
else if (uwsgi.zeromq) {
|
||||
uuid_generate(uuid_zmq);
|
||||
uuid_unparse(uuid_zmq, uuid_zmq_str);
|
||||
len = 2 + strlen(key1) + 2 + strlen(uwsgi.hostname) + 2 + strlen(key2) + 2 + strlen(uuid_zmq_str) + 2 + strlen(key3) + 2 + strlen(numproc) + 2 + strlen(key4) + 2 + 1;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
len = 2 + strlen(key1) + 2 + strlen(uwsgi.hostname) + 2 + strlen(key3) + 2 + strlen(numproc) + 2 + strlen(key4) + 2 + 1;
|
||||
}
|
||||
char *buf = uwsgi_malloc(len);
|
||||
|
||||
ptrbuf = buf;
|
||||
|
||||
ustrlen = strlen(key1);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key1, strlen(key1));
|
||||
ptrbuf += strlen(key1);
|
||||
|
||||
ustrlen = strlen(uwsgi.hostname);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, uwsgi.hostname, strlen(uwsgi.hostname));
|
||||
ptrbuf += strlen(uwsgi.hostname);
|
||||
|
||||
|
||||
if (uwsgi.sockets && uwsgi.sockets->name) {
|
||||
ustrlen = strlen(key2);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key2, strlen(key2));
|
||||
ptrbuf += strlen(key2);
|
||||
|
||||
ustrlen = strlen(uwsgi.sockets->name);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, uwsgi.sockets->name, strlen(uwsgi.sockets->name));
|
||||
ptrbuf += strlen(uwsgi.sockets->name);
|
||||
}
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
else if (uwsgi.zeromq) {
|
||||
ustrlen = strlen(key2);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key2, strlen(key2));
|
||||
ptrbuf += strlen(key2);
|
||||
|
||||
ustrlen = strlen(uuid_zmq_str);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, uuid_zmq_str, strlen(uuid_zmq_str));
|
||||
ptrbuf += strlen(uuid_zmq_str);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
ustrlen = strlen(key3);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key3, strlen(key3));
|
||||
ptrbuf += strlen(key3);
|
||||
|
||||
ustrlen = strlen(numproc);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, numproc, strlen(numproc));
|
||||
ptrbuf += strlen(numproc);
|
||||
|
||||
ustrlen = strlen(key4);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key4, strlen(key4));
|
||||
ptrbuf += strlen(key4);
|
||||
|
||||
ustrlen = 1;
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, "0", 1);
|
||||
ptrbuf += 1;
|
||||
|
||||
|
||||
uwsgi_string_sendto(uwsgi.cluster_fd, 95, 0, (struct sockaddr *) &uwsgi.mc_cluster_addr, sizeof(uwsgi.mc_cluster_addr), buf, len);
|
||||
|
||||
free(buf);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("add_me() successfull\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_cluster_join(char *name) {
|
||||
|
||||
int fd;
|
||||
char *cp;
|
||||
int broadcast = 0;
|
||||
|
||||
|
||||
|
||||
if (name[0] == ':') {
|
||||
fd = bind_to_udp(name, 0, 1);
|
||||
broadcast = 1;
|
||||
}
|
||||
else {
|
||||
fd = bind_to_udp(name, 1, 0);
|
||||
}
|
||||
|
||||
if (fd >= 0) {
|
||||
cp = strchr(name, ':');
|
||||
cp[0] = 0;
|
||||
uwsgi.mc_cluster_addr.sin_family = AF_INET;
|
||||
if (broadcast) {
|
||||
uwsgi.mc_cluster_addr.sin_addr.s_addr = INADDR_BROADCAST;
|
||||
}
|
||||
else {
|
||||
uwsgi.mc_cluster_addr.sin_addr.s_addr = inet_addr(name);
|
||||
}
|
||||
uwsgi.mc_cluster_addr.sin_port = htons(atoi(cp + 1));
|
||||
cp[0] = ':';
|
||||
|
||||
|
||||
// announce my presence to all the nodes
|
||||
uwsgi_string_sendto(fd, 73, 0, (struct sockaddr *) &uwsgi.mc_cluster_addr, sizeof(uwsgi.mc_cluster_addr), uwsgi.hostname, strlen(uwsgi.hostname));
|
||||
}
|
||||
else {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
return fd;
|
||||
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_cluster_best_node() {
|
||||
|
||||
int i;
|
||||
int best_node = -1;
|
||||
struct uwsgi_cluster_node *ucn;
|
||||
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
ucn = &uwsgi.shared->nodes[i];
|
||||
if (ucn->name[0] != 0 && ucn->status == UWSGI_NODE_OK) {
|
||||
if (best_node == -1) {
|
||||
best_node = i;
|
||||
}
|
||||
else {
|
||||
if (ucn->last_choosen < uwsgi.shared->nodes[best_node].last_choosen) {
|
||||
best_node = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (best_node == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uwsgi.shared->nodes[best_node].last_choosen = uwsgi_now();
|
||||
return uwsgi.shared->nodes[best_node].name;
|
||||
}
|
||||
|
||||
|
||||
void manage_cluster_announce(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
|
||||
|
||||
char *tmpstr;
|
||||
struct uwsgi_cluster_node *ucn = (struct uwsgi_cluster_node *) data;
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%.*s = %.*s\n", keylen, key, vallen, val);
|
||||
#endif
|
||||
|
||||
if (!uwsgi_strncmp("hostname", 8, key, keylen)) {
|
||||
strncpy(ucn->nodename, val, UMIN(vallen, 255));
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("address", 7, key, keylen)) {
|
||||
strncpy(ucn->name, val, UMIN(vallen, 100));
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("workers", 7, key, keylen)) {
|
||||
tmpstr = uwsgi_concat2n(val, vallen, "", 0);
|
||||
ucn->workers = atoi(tmpstr);
|
||||
free(tmpstr);
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("requests", 8, key, keylen)) {
|
||||
tmpstr = uwsgi_concat2n(val, vallen, "", 0);
|
||||
ucn->requests = strtoul(tmpstr, NULL, 0);
|
||||
free(tmpstr);
|
||||
}
|
||||
}
|
||||
|
||||
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.workers[0].cores[0].req.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.workers[0].cores[0].req.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;
|
||||
}
|
||||
+30
-103
@@ -6,6 +6,7 @@ a supervisor for multiple uWSGI instances
|
||||
|
||||
*/
|
||||
#include "uwsgi.h"
|
||||
#include <glob.h>
|
||||
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
@@ -87,7 +88,7 @@ void uwsgi_emperor_blacklist_add(char *id) {
|
||||
}
|
||||
}
|
||||
|
||||
strncpy(uebi->id, id, 0xff);
|
||||
strcpy(uebi->id, id);
|
||||
gettimeofday(&uebi->first_attempt, NULL);
|
||||
memcpy(&uebi->last_attempt, &uebi->first_attempt, sizeof(struct timeval));
|
||||
uebi->throttle_level = uwsgi.emperor_throttle;
|
||||
@@ -185,24 +186,8 @@ void uwsgi_imperial_monitor_directory(struct uwsgi_emperor_scanner *ues) {
|
||||
|
||||
while (c_ui) {
|
||||
if (c_ui->scanner == ues) {
|
||||
if (c_ui->zerg) {
|
||||
char *colon = strrchr(c_ui->name, ':');
|
||||
if (!colon) {
|
||||
emperor_stop(c_ui);
|
||||
}
|
||||
else {
|
||||
char *filename = uwsgi_calloc(0xff);
|
||||
memcpy(filename, c_ui->name, colon - c_ui->name);
|
||||
if (stat(filename, &st)) {
|
||||
emperor_stop(c_ui);
|
||||
}
|
||||
free(filename);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (stat(c_ui->name, &st)) {
|
||||
emperor_stop(c_ui);
|
||||
}
|
||||
if (stat(c_ui->name, &st)) {
|
||||
emperor_stop(c_ui);
|
||||
}
|
||||
}
|
||||
c_ui = c_ui->ui_next;
|
||||
@@ -261,25 +246,9 @@ void uwsgi_imperial_monitor_glob(struct uwsgi_emperor_scanner *ues) {
|
||||
|
||||
while (c_ui) {
|
||||
if (c_ui->scanner == ues) {
|
||||
if (c_ui->zerg) {
|
||||
char *colon = strrchr(c_ui->name, ':');
|
||||
if (!colon) {
|
||||
emperor_stop(c_ui);
|
||||
}
|
||||
else {
|
||||
char *filename = uwsgi_calloc(0xff);
|
||||
memcpy(filename, c_ui->name, colon - c_ui->name);
|
||||
if (stat(filename, &st)) {
|
||||
emperor_stop(c_ui);
|
||||
}
|
||||
free(filename);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (stat(c_ui->name, &st)) {
|
||||
emperor_stop(c_ui);
|
||||
}
|
||||
}
|
||||
if (stat(c_ui->name, &st)) {
|
||||
emperor_stop(c_ui);
|
||||
}
|
||||
}
|
||||
c_ui = c_ui->ui_next;
|
||||
}
|
||||
@@ -356,7 +325,7 @@ static void emperor_stats() {
|
||||
|
||||
while (c_ui) {
|
||||
|
||||
uwsgi_log("vassal instance %s (last modified %lld) status %d loyal %d zerg %d\n", c_ui->name, (long long) c_ui->last_mod, c_ui->status, c_ui->loyal, c_ui->zerg);
|
||||
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;
|
||||
}
|
||||
@@ -448,28 +417,17 @@ void emperor_stop(struct uwsgi_instance *c_ui) {
|
||||
|
||||
void emperor_respawn(struct uwsgi_instance *c_ui, time_t mod) {
|
||||
|
||||
struct uwsgi_header uh;
|
||||
|
||||
// reload the uWSGI instance
|
||||
if (write(c_ui->pipe[0], "\1", 1) != 1) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
|
||||
// push the config to the config pipe (if needed)
|
||||
if (c_ui->use_config) {
|
||||
uh.modifier1 = 115;
|
||||
uh.pktsize = c_ui->config_len;
|
||||
uh.modifier2 = 0;
|
||||
if (write(c_ui->pipe_config[0], &uh, 4) != 4) {
|
||||
uwsgi_error("[uwsgi-emperor] write() header config");
|
||||
if (write(c_ui->pipe[0], "\0", 1) != 1) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
else {
|
||||
if (write(c_ui->pipe_config[0], c_ui->config, c_ui->config_len) != (long) c_ui->config_len) {
|
||||
uwsgi_error("[uwsgi-emperor] write() config");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (write(c_ui->pipe[0], "\1", 1) != 1) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
c_ui->respawns++;
|
||||
c_ui->last_mod = mod;
|
||||
@@ -496,7 +454,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
|
||||
#endif
|
||||
|
||||
if (strlen(name) > (0xff - 1)) {
|
||||
uwsgi_log("[emperor] invalid vassal name: %s\n", name);
|
||||
uwsgi_log("[emperor] invalid vassal name\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -591,10 +549,6 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
|
||||
}
|
||||
}
|
||||
|
||||
if (n_ui->zerg) {
|
||||
uwsgi.emperor_broodlord_num++;
|
||||
}
|
||||
|
||||
// TODO pre-start hook
|
||||
|
||||
// a new uWSGI instance will start
|
||||
@@ -611,19 +565,10 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
|
||||
}
|
||||
|
||||
if (n_ui->use_config) {
|
||||
struct uwsgi_header uh;
|
||||
uh.modifier1 = 115;
|
||||
uh.pktsize = n_ui->config_len;
|
||||
uh.modifier2 = 0;
|
||||
if (write(n_ui->pipe_config[0], &uh, 4) != 4) {
|
||||
uwsgi_error("[uwsgi-emperor] write() header config");
|
||||
}
|
||||
else {
|
||||
if (write(n_ui->pipe_config[0], n_ui->config, n_ui->config_len) != (long) n_ui->config_len) {
|
||||
uwsgi_error("[uwsgi-emperor] write() 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;
|
||||
}
|
||||
@@ -657,16 +602,6 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
|
||||
}
|
||||
free(uef);
|
||||
|
||||
// add UWSGI_BROODLORD_NUM
|
||||
if (n_ui->zerg) {
|
||||
uef = uwsgi_num2str(uwsgi.emperor_broodlord_num);
|
||||
if (setenv("UWSGI_BROODLORD_NUM", 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)) {
|
||||
@@ -683,7 +618,6 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
|
||||
char *oe = uwsgi_concat2n(*uenvs, strchr(*uenvs, '=') - *uenvs, "", 0);
|
||||
if (unsetenv(oe)) {
|
||||
uwsgi_error("unsetenv()");
|
||||
free(oe);
|
||||
break;
|
||||
}
|
||||
free(oe);
|
||||
@@ -1056,9 +990,9 @@ void emperor_loop() {
|
||||
}
|
||||
|
||||
// check if a monitor is mapped to that file descriptor
|
||||
if (uwsgi_emperor_scanner_event(interesting_fd)) {
|
||||
if (uwsgi_emperor_scanner_event(interesting_fd))
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
ui_current = emperor_get_by_fd(interesting_fd);
|
||||
if (ui_current) {
|
||||
@@ -1066,7 +1000,9 @@ void emperor_loop() {
|
||||
ssize_t rlen = read(interesting_fd, &byte, 1);
|
||||
if (rlen <= 0) {
|
||||
// SAFE
|
||||
emperor_del(ui_current);
|
||||
if (!ui_current->config_len) {
|
||||
emperor_del(ui_current);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (byte == 17) {
|
||||
@@ -1454,25 +1390,16 @@ void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *ues, char *name, char
|
||||
}
|
||||
// check if mtime is changed and the uWSGI instance must be reloaded
|
||||
if (ts > ui_current->last_mod) {
|
||||
// make a new config (free the old one) if needed
|
||||
if (config) {
|
||||
if (ui_current->config)
|
||||
free(ui_current->config);
|
||||
ui_current->config = uwsgi_str(config);
|
||||
ui_current->config_len = strlen(ui_current->config);
|
||||
}
|
||||
// reload the instance
|
||||
// make a new config (free the old one)
|
||||
free(ui_current->config);
|
||||
ui_current->config = config;
|
||||
ui_current->config_len = strlen(config);
|
||||
// always respawn (no need for amqp-style rules)
|
||||
emperor_respawn(ui_current, ts);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// make a copy of the config as it will be freed
|
||||
char *new_config = NULL;
|
||||
size_t new_config_len = 0;
|
||||
if (config) {
|
||||
new_config = uwsgi_str(config);
|
||||
new_config_len = strlen(new_config);
|
||||
}
|
||||
emperor_add(ues, name, ts, new_config, new_config_len, uid, gid);
|
||||
emperor_add(ues, name, ts, uwsgi_str(config), strlen((const char *) config), uid, gid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
// generate internal server error message
|
||||
void uwsgi_500(struct wsgi_request *wsgi_req) {
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "500 Internal Server Error", 25)) return;
|
||||
if (uwsgi_response_add_connection_close(wsgi_req)) return;
|
||||
uwsgi_response_write_body_do(wsgi_req, "Internal Server Error", 21);
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_404(struct wsgi_request *wsgi_req) {
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "404 Not Found", 13)) return;
|
||||
if (uwsgi_response_add_connection_close(wsgi_req)) return;
|
||||
if (uwsgi_response_add_header(wsgi_req, "Content-Type", 12, "text/plain", 10)) return;
|
||||
uwsgi_response_write_body_do(wsgi_req, "Not Found", 9);
|
||||
}
|
||||
|
||||
void uwsgi_403(struct wsgi_request *wsgi_req) {
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "403 Forbidden", 13)) return;
|
||||
if (uwsgi_response_add_connection_close(wsgi_req)) return;
|
||||
if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) return;
|
||||
uwsgi_response_write_body_do(wsgi_req, "Forbidden", 9);
|
||||
}
|
||||
|
||||
void uwsgi_redirect_to_slash(struct wsgi_request *wsgi_req) {
|
||||
|
||||
char *redirect = NULL;
|
||||
size_t redirect_len = 0;
|
||||
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "301 Moved Permanently", 21)) return;
|
||||
if (uwsgi_response_add_connection_close(wsgi_req)) return;
|
||||
|
||||
if (wsgi_req->query_string_len == 0) {
|
||||
redirect = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "/", 1);
|
||||
redirect_len = wsgi_req->path_info_len + 1;
|
||||
}
|
||||
else {
|
||||
redirect = uwsgi_concat3n(wsgi_req->path_info, wsgi_req->path_info_len, "/?", 2, wsgi_req->query_string, wsgi_req->query_string_len);
|
||||
redirect_len = wsgi_req->path_info_len + 2 + wsgi_req->query_string_len;
|
||||
}
|
||||
uwsgi_response_add_header(wsgi_req, "Location", 8, redirect, redirect_len);
|
||||
free(redirect);
|
||||
return;
|
||||
}
|
||||
|
||||
+2
-242
@@ -2,233 +2,6 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#ifdef UWSGI_EVENT_USE_POLL
|
||||
#define UWSGI_EVENT_IN POLLIN
|
||||
#define UWSGI_EVENT_OUT POLLOUT
|
||||
|
||||
int uwsgi_poll_event_queue_max = 0;
|
||||
struct uwsgi_poll_event {
|
||||
int nevents;
|
||||
int max_events;
|
||||
pthread_mutex_t lock;
|
||||
struct pollfd *poll;
|
||||
};
|
||||
|
||||
struct uwsgi_poll_event **uwsgi_poll_event_queue;
|
||||
|
||||
// all of the public functions must be heavy locked
|
||||
|
||||
static int uwsgi_poll_fd_is_registered(struct uwsgi_poll_event *upe, int fd) {
|
||||
int i;
|
||||
for(i=0;i<upe->nevents;i++) {
|
||||
if (upe->poll[i].fd == fd) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_poll_fd_add(struct uwsgi_poll_event *upe, int fd, int event) {
|
||||
int pos = upe->nevents;
|
||||
if (pos > upe->max_events) return -1;
|
||||
upe->poll[pos].fd = fd;
|
||||
upe->poll[pos].events = event;
|
||||
upe->nevents++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_poll_fd_del(struct uwsgi_poll_event *upe, int fd) {
|
||||
int i;
|
||||
for(i=0;i<upe->nevents;i++) {
|
||||
if (upe->poll[i].fd == fd) {
|
||||
if (i < upe->nevents-1) {
|
||||
memcpy(&upe->poll[i], &upe->poll[i+1], sizeof(struct uwsgi_poll_event) * (upe->nevents - (i+1)));
|
||||
}
|
||||
upe->nevents--;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void uwsgi_poll_queue_rebuild(struct uwsgi_poll_event *upe) {
|
||||
// we need to check if some file descriptor is no more valid
|
||||
int i;
|
||||
for(i=0;i<upe->nevents;i++) {
|
||||
if (!uwsgi_valid_fd(upe->poll[i].fd)) {
|
||||
uwsgi_poll_fd_del(upe, upe->poll[i].fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int event_queue_wait(int eq, int timeout, int *interesting_fd) {
|
||||
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
|
||||
pthread_mutex_lock(&upe->lock);
|
||||
uwsgi_poll_queue_rebuild(upe);
|
||||
int ret = poll(upe->poll, upe->nevents, timeout * 1000);
|
||||
if (ret > 0) {
|
||||
int i;
|
||||
for(i=0;i<upe->nevents;i++) {
|
||||
if (upe->poll[i].revents) {
|
||||
*interesting_fd = upe->poll[i].fd;
|
||||
pthread_mutex_unlock(&upe->lock);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&upe->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int event_queue_init() {
|
||||
if (!uwsgi_poll_event_queue) {
|
||||
uwsgi_poll_event_queue = uwsgi_calloc(sizeof(struct uwsgi_poll_event *) * uwsgi.max_fd);
|
||||
}
|
||||
int eq = uwsgi_poll_event_queue_max;
|
||||
uwsgi_poll_event_queue[eq] = uwsgi_calloc(sizeof(struct uwsgi_poll_event));
|
||||
uwsgi_poll_event_queue_max++;
|
||||
uwsgi_poll_event_queue[eq]->poll = uwsgi_malloc(sizeof(struct pollfd) * uwsgi.max_fd);
|
||||
uwsgi_poll_event_queue[eq]->max_events = uwsgi.max_fd;
|
||||
pthread_mutex_init(&uwsgi_poll_event_queue[eq]->lock, NULL);
|
||||
return eq;
|
||||
}
|
||||
|
||||
void *event_queue_alloc(int nevents) {
|
||||
return uwsgi_calloc(sizeof(struct pollfd) * nevents);
|
||||
}
|
||||
|
||||
int event_queue_interesting_fd_is_read(void *events, int id) {
|
||||
struct pollfd *pevents = (struct pollfd *)events;
|
||||
struct pollfd *upoll = &pevents[id];
|
||||
if (upoll->revents & POLLIN) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int event_queue_fd_write_to_readwrite(int eq, int fd) {
|
||||
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
|
||||
pthread_mutex_lock(&upe->lock);
|
||||
int i;
|
||||
for(i=0;i<upe->nevents;i++) {
|
||||
if (upe->poll[i].fd == fd) {
|
||||
upe->poll[i].events = POLLIN|POLLOUT;
|
||||
pthread_mutex_unlock(&upe->lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&upe->lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int event_queue_fd_read_to_readwrite(int eq, int fd) {
|
||||
return event_queue_fd_write_to_readwrite(eq, fd);
|
||||
}
|
||||
|
||||
int event_queue_interesting_fd_is_write(void *events, int id) {
|
||||
struct pollfd *pevents = (struct pollfd *)events;
|
||||
struct pollfd *upoll = &pevents[id];
|
||||
if (upoll->revents & POLLOUT) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int event_queue_add_fd_read(int eq, int fd) {
|
||||
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
|
||||
pthread_mutex_lock(&upe->lock);
|
||||
if (uwsgi_poll_fd_is_registered(upe, fd)) {
|
||||
pthread_mutex_unlock(&upe->lock);
|
||||
return 0;
|
||||
}
|
||||
int ret = uwsgi_poll_fd_add(upe, fd, POLLIN);
|
||||
pthread_mutex_unlock(&upe->lock);
|
||||
return ret;
|
||||
}
|
||||
int event_queue_add_fd_write(int eq, int fd) {
|
||||
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
|
||||
pthread_mutex_lock(&upe->lock);
|
||||
if (uwsgi_poll_fd_is_registered(upe, fd)) {
|
||||
pthread_mutex_unlock(&upe->lock);
|
||||
return 0;
|
||||
}
|
||||
int ret = uwsgi_poll_fd_add(upe, fd, POLLOUT);
|
||||
pthread_mutex_unlock(&upe->lock);
|
||||
return ret;
|
||||
}
|
||||
int event_queue_del_fd(int eq, int fd, int event) {
|
||||
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
|
||||
pthread_mutex_lock(&upe->lock);
|
||||
int ret = uwsgi_poll_fd_del(upe, fd);
|
||||
pthread_mutex_unlock(&upe->lock);
|
||||
return ret;
|
||||
}
|
||||
int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
|
||||
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
|
||||
pthread_mutex_lock(&upe->lock);
|
||||
uwsgi_poll_queue_rebuild(upe);
|
||||
int ret = poll(upe->poll, upe->nevents, timeout * 1000);
|
||||
int cnt = 0;
|
||||
if (ret > 0) {
|
||||
int i;
|
||||
for(i=0;i<upe->nevents;i++) {
|
||||
if (upe->poll[i].revents) {
|
||||
struct pollfd *pevents = (struct pollfd *)events;
|
||||
struct pollfd *upoll = &pevents[cnt];
|
||||
upoll->fd = upe->poll[i].fd;
|
||||
upoll->revents = upe->poll[i].revents;
|
||||
upoll->events = upe->poll[i].events;
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&upe->lock);
|
||||
if (ret <= 0) return ret;
|
||||
return cnt;
|
||||
}
|
||||
int event_queue_interesting_fd_has_error(void *events, int id) {
|
||||
struct pollfd *pevents = (struct pollfd *)events;
|
||||
struct pollfd *upoll = &pevents[id];
|
||||
if (upoll->revents & POLLERR || upoll->revents & POLLHUP || upoll->revents & POLLNVAL) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int event_queue_interesting_fd(void *events, int id) {
|
||||
struct pollfd *pevents = (struct pollfd *)events;
|
||||
struct pollfd *upoll = &pevents[id];
|
||||
return upoll->fd;
|
||||
}
|
||||
int event_queue_fd_write_to_read(int eq, int fd) {
|
||||
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
|
||||
pthread_mutex_lock(&upe->lock);
|
||||
int i;
|
||||
for(i=0;i<upe->nevents;i++) {
|
||||
if (upe->poll[i].fd == fd) {
|
||||
upe->poll[i].events = POLLIN;
|
||||
pthread_mutex_unlock(&upe->lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&upe->lock);
|
||||
return -1;
|
||||
}
|
||||
int event_queue_fd_read_to_write(int eq, int fd) {
|
||||
struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
|
||||
pthread_mutex_lock(&upe->lock);
|
||||
int i;
|
||||
for(i=0;i<upe->nevents;i++) {
|
||||
if (upe->poll[i].fd == fd) {
|
||||
upe->poll[i].events = POLLOUT;
|
||||
pthread_mutex_unlock(&upe->lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&upe->lock);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_EVENT_USE_PORT
|
||||
|
||||
#include <port.h>
|
||||
@@ -335,7 +108,7 @@ int event_queue_interesting_fd_has_error(void *events, int id) {
|
||||
|
||||
int event_queue_interesting_fd_is_read(void *events, int id) {
|
||||
port_event_t *pe = (port_event_t *) events;
|
||||
if (pe[id].portev_events == POLLIN) {
|
||||
if (pe[id].portev_events = POLLIN) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -351,7 +124,7 @@ int event_queue_interesting_fd_is_write(void *events, int id) {
|
||||
|
||||
int event_queue_add_fd_read(int eq, int fd) {
|
||||
|
||||
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, NULL)) {
|
||||
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, (void *) eq)) {
|
||||
uwsgi_error("port_associate");
|
||||
return -1;
|
||||
}
|
||||
@@ -398,7 +171,6 @@ int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
|
||||
int ret;
|
||||
uint_t nget = 1;
|
||||
timespec_t ts;
|
||||
|
||||
|
||||
if (timeout >= 0) {
|
||||
ts.tv_sec = timeout;
|
||||
@@ -417,18 +189,6 @@ int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint_t i;
|
||||
port_event_t *pe = (port_event_t *) events;
|
||||
for(i=0;i<nget;i++) {
|
||||
port_event_t *pe_i = &pe[i];
|
||||
if (pe_i->portev_source == PORT_SOURCE_FD) {
|
||||
// event must be readded (damn Oracle/Sun why the fu*k you made such a horrible choice ???? why not adding a ONESHOT flag ???)
|
||||
if (port_associate(eq, pe_i->portev_source, pe_i->portev_object, pe_i->portev_events, NULL)) {
|
||||
uwsgi_error("port_associate");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nget;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,499 +0,0 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/*
|
||||
|
||||
Exceptions management
|
||||
|
||||
generally exceptions are printed in the logs, but if you enable
|
||||
an exception manager they will be stored in a (relatively big) uwsgi packet
|
||||
with the following structure.
|
||||
|
||||
"vars" -> keyval of request vars
|
||||
"backtrace" -> list of backtrace lines. Each line is a list of 5 elements filename,line,function,text,custom
|
||||
"unix" -> seconds since the epoch
|
||||
"class" -> the exception class
|
||||
"msg" -> a text message mapped to the extension
|
||||
"repr" -> a text message mapped to the extension in language-specific gergo
|
||||
"wid" -> worker id
|
||||
"core" -> the core generating the exception
|
||||
"pid" -> pid of the worker
|
||||
"node" -> hostname
|
||||
|
||||
Other vars can be added, but you cannot be sure they will be used by exceptions handler.
|
||||
|
||||
The exception-uwsgi packet is passed "as is" to the exception handler
|
||||
|
||||
Exceptions hooks:
|
||||
|
||||
a request plugin can export that hooks:
|
||||
|
||||
struct uwsgi_buffer *backtrace(struct wsgi_request *);
|
||||
struct uwsgi_buffer *exception_class(struct wsgi_request *);
|
||||
struct uwsgi_buffer *exception_msg(struct wsgi_request *);
|
||||
struct uwsgi_buffer *exception_repr(struct wsgi_request *);
|
||||
void exception_log(struct wsgi_request *);
|
||||
|
||||
Remember to reset the exception status (if possibile) after each call
|
||||
|
||||
Exceptions catcher:
|
||||
|
||||
This is a special development-mode in which exceptions are printed
|
||||
to the HTTP client.
|
||||
|
||||
*/
|
||||
|
||||
struct uwsgi_buffer *uwsgi_exception_handler_object(struct wsgi_request *wsgi_req) {
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(4096);
|
||||
if (uwsgi_buffer_append_keyval(ub, "vars", 4, wsgi_req->buffer,wsgi_req->uh->pktsize)) goto error;
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->backtrace) {
|
||||
struct uwsgi_buffer *bt = uwsgi.p[wsgi_req->uh->modifier1]->backtrace(wsgi_req);
|
||||
if (bt) {
|
||||
if (uwsgi_buffer_append_keyval(ub, "backtrace", 9, bt->buf, bt->pos)) {
|
||||
uwsgi_buffer_destroy(bt);
|
||||
goto error;
|
||||
}
|
||||
uwsgi_buffer_destroy(bt);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->exception_class) {
|
||||
struct uwsgi_buffer *ec = uwsgi.p[wsgi_req->uh->modifier1]->exception_class(wsgi_req);
|
||||
if (ec) {
|
||||
if (uwsgi_buffer_append_keyval(ub, "class", 5, ec->buf, ec->pos)) {
|
||||
uwsgi_buffer_destroy(ec);
|
||||
goto error;
|
||||
}
|
||||
uwsgi_buffer_destroy(ec);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->exception_msg) {
|
||||
struct uwsgi_buffer *em = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req);
|
||||
if (em) {
|
||||
if (uwsgi_buffer_append_keyval(ub, "msg", 3, em->buf, em->pos)) {
|
||||
uwsgi_buffer_destroy(em);
|
||||
goto error;
|
||||
}
|
||||
uwsgi_buffer_destroy(em);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->exception_repr) {
|
||||
struct uwsgi_buffer *er = uwsgi.p[wsgi_req->uh->modifier1]->exception_repr(wsgi_req);
|
||||
if (er) {
|
||||
if (uwsgi_buffer_append_keyval(ub, "repr", 4, er->buf, er->pos)) {
|
||||
uwsgi_buffer_destroy(er);
|
||||
goto error;
|
||||
}
|
||||
uwsgi_buffer_destroy(er);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi_buffer_append_keynum(ub, "unix", 4, uwsgi_now())) goto error;
|
||||
if (uwsgi_buffer_append_keynum(ub, "wid", 3, uwsgi.mywid)) goto error;
|
||||
if (uwsgi_buffer_append_keynum(ub, "pid", 3, uwsgi.mypid)) goto error;
|
||||
if (uwsgi_buffer_append_keynum(ub, "core", 4, wsgi_req->async_id)) goto error;
|
||||
if (uwsgi_buffer_append_keyval(ub, "node", 4, uwsgi.hostname, uwsgi.hostname_len)) goto error;
|
||||
|
||||
return ub;
|
||||
|
||||
error:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void append_vars_to_ubuf(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
|
||||
struct uwsgi_buffer *ub = (struct uwsgi_buffer *) data;
|
||||
|
||||
if (uwsgi_buffer_append(ub, key, keylen)) return;
|
||||
if (uwsgi_buffer_append(ub, " = ", 3)) return;
|
||||
if (uwsgi_buffer_append(ub, val, vallen)) return;
|
||||
if (uwsgi_buffer_append(ub, "\n", 1)) return;
|
||||
}
|
||||
|
||||
static void append_backtrace_to_ubuf(uint16_t pos, char *value, uint16_t len, void *data) {
|
||||
struct uwsgi_buffer *ub = (struct uwsgi_buffer *) data;
|
||||
|
||||
uint16_t item = 0;
|
||||
if (pos > 0) {
|
||||
item = pos % 5;
|
||||
}
|
||||
|
||||
switch(item) {
|
||||
// filename
|
||||
case 0:
|
||||
if (uwsgi_buffer_append(ub, "filename: \"", 11)) return;
|
||||
if (uwsgi_buffer_append(ub, value, len)) return;
|
||||
if (uwsgi_buffer_append(ub, "\" ", 2)) return;
|
||||
break;
|
||||
// lineno
|
||||
case 1:
|
||||
if (uwsgi_buffer_append(ub, "line: ", 6)) return;
|
||||
if (uwsgi_buffer_append(ub, value, len)) return;
|
||||
if (uwsgi_buffer_append(ub, " ", 1)) return;
|
||||
break;
|
||||
// function
|
||||
case 2:
|
||||
if (uwsgi_buffer_append(ub, "function: \"", 11)) return;
|
||||
if (uwsgi_buffer_append(ub, value, len)) return;
|
||||
if (uwsgi_buffer_append(ub, "\" ", 2)) return;
|
||||
break;
|
||||
// text
|
||||
case 3:
|
||||
if (len > 0) {
|
||||
if (uwsgi_buffer_append(ub, "text/code: \"", 12)) return;
|
||||
if (uwsgi_buffer_append(ub, value, len)) return;
|
||||
if (uwsgi_buffer_append(ub, "\" ", 2)) return;
|
||||
}
|
||||
break;
|
||||
// custom
|
||||
case 4:
|
||||
if (len > 0) {
|
||||
if (uwsgi_buffer_append(ub, "custom: \"", 9)) return;
|
||||
if (uwsgi_buffer_append(ub, value, len)) return;
|
||||
if (uwsgi_buffer_append(ub, "\" ", 2)) return;
|
||||
}
|
||||
if (uwsgi_buffer_append(ub, "\n", 1)) return;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_exceptions_catch(struct wsgi_request *wsgi_req) {
|
||||
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "500 Internal Server Error", 25)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(4096);
|
||||
if (uwsgi_buffer_append(ub, "uWSGI exceptions catcher for \"", 30)) goto error;
|
||||
if (uwsgi_buffer_append(ub, wsgi_req->method, wsgi_req->method_len)) goto error;
|
||||
if (uwsgi_buffer_append(ub, " ", 1)) goto error;
|
||||
if (uwsgi_buffer_append(ub, wsgi_req->uri, wsgi_req->uri_len)) goto error;
|
||||
if (uwsgi_buffer_append(ub, "\" (request plugin: \"", 20)) goto error;
|
||||
if (uwsgi_buffer_append(ub, (char *) uwsgi.p[wsgi_req->uh->modifier1]->name, strlen(uwsgi.p[wsgi_req->uh->modifier1]->name))) goto error;
|
||||
if (uwsgi_buffer_append(ub, "\", modifier1: ", 14 )) goto error;
|
||||
if (uwsgi_buffer_num64(ub, wsgi_req->uh->modifier1)) goto error;
|
||||
if (uwsgi_buffer_append(ub, ")\n\n", 3)) goto error;
|
||||
|
||||
if (uwsgi_buffer_append(ub, "Exception: ", 11)) goto error;
|
||||
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->exception_repr) {
|
||||
struct uwsgi_buffer *ub_exc_repr = uwsgi.p[wsgi_req->uh->modifier1]->exception_repr(wsgi_req);
|
||||
if (ub_exc_repr) {
|
||||
if (uwsgi_buffer_append(ub, ub_exc_repr->buf, ub_exc_repr->pos)) {
|
||||
uwsgi_buffer_destroy(ub_exc_repr);
|
||||
goto error;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub_exc_repr);
|
||||
}
|
||||
else {
|
||||
goto notavail3;
|
||||
}
|
||||
}
|
||||
else {
|
||||
notavail3:
|
||||
if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error;
|
||||
}
|
||||
|
||||
if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error;
|
||||
|
||||
if (uwsgi_buffer_append(ub, "Exception class: ", 17)) goto error;
|
||||
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->exception_class) {
|
||||
struct uwsgi_buffer *ub_exc_class = uwsgi.p[wsgi_req->uh->modifier1]->exception_class(wsgi_req);
|
||||
if (ub_exc_class) {
|
||||
if (uwsgi_buffer_append(ub, ub_exc_class->buf, ub_exc_class->pos)) {
|
||||
uwsgi_buffer_destroy(ub_exc_class);
|
||||
goto error;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub_exc_class);
|
||||
}
|
||||
else {
|
||||
goto notavail;
|
||||
}
|
||||
}
|
||||
else {
|
||||
notavail:
|
||||
if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error;
|
||||
}
|
||||
|
||||
if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error;
|
||||
|
||||
if (uwsgi_buffer_append(ub, "Exception message: ", 19)) goto error;
|
||||
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->exception_msg) {
|
||||
struct uwsgi_buffer *ub_exc_msg = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req);
|
||||
if (ub_exc_msg) {
|
||||
if (uwsgi_buffer_append(ub, ub_exc_msg->buf, ub_exc_msg->pos)) {
|
||||
uwsgi_buffer_destroy(ub_exc_msg);
|
||||
goto error;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub_exc_msg);
|
||||
}
|
||||
else {
|
||||
goto notavail2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
notavail2:
|
||||
if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error;
|
||||
}
|
||||
|
||||
if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error;
|
||||
|
||||
if (uwsgi_buffer_append(ub, "Backtrace:\n", 11)) goto error;
|
||||
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->backtrace) {
|
||||
struct uwsgi_buffer *ub_exc_bt = uwsgi.p[wsgi_req->uh->modifier1]->backtrace(wsgi_req);
|
||||
if (ub_exc_bt) {
|
||||
struct uwsgi_buffer *parsed_bt = uwsgi_buffer_new(4096);
|
||||
if (uwsgi_hooked_parse_array(ub_exc_bt->buf, ub_exc_bt->pos, append_backtrace_to_ubuf, parsed_bt)) {
|
||||
uwsgi_buffer_destroy(ub_exc_bt);
|
||||
uwsgi_buffer_destroy(parsed_bt);
|
||||
goto error;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub_exc_bt);
|
||||
if (uwsgi_buffer_append(ub, parsed_bt->buf, parsed_bt->pos)) {
|
||||
uwsgi_buffer_destroy(parsed_bt);
|
||||
goto error;
|
||||
}
|
||||
uwsgi_buffer_destroy(parsed_bt);
|
||||
}
|
||||
else {
|
||||
goto notavail4;
|
||||
}
|
||||
}
|
||||
else {
|
||||
notavail4:
|
||||
if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error;
|
||||
}
|
||||
|
||||
if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error;
|
||||
|
||||
if (uwsgi_hooked_parse(wsgi_req->buffer, wsgi_req->uh->pktsize, append_vars_to_ubuf, ub)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
static void uwsgi_exception_run_handlers(struct uwsgi_buffer *ub) {
|
||||
struct uwsgi_string_list *usl = uwsgi.exception_handlers_instance;
|
||||
struct iovec iov[2];
|
||||
iov[1].iov_base = ub->buf;
|
||||
iov[1].iov_len = ub->pos;
|
||||
while(usl) {
|
||||
struct uwsgi_exception_handler_instance *uehi = (struct uwsgi_exception_handler_instance *) usl->custom_ptr;
|
||||
iov[0].iov_base = &uehi;
|
||||
iov[0].iov_len = sizeof(long);
|
||||
// now send the message to the exception handler thread
|
||||
if (writev(uwsgi.exception_handler_thread->pipe[0], iov, 2) != (ssize_t) (ub->pos+sizeof(long))) {
|
||||
uwsgi_error("[uwsgi-exception-handler-error] uwsgi_exception_run_handlers()/writev()");
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_manage_exception(struct wsgi_request *wsgi_req,int catch) {
|
||||
|
||||
int do_exit = uwsgi.reload_on_exception;
|
||||
|
||||
if (!wsgi_req) goto log2;
|
||||
|
||||
if (do_exit) goto check_catch;
|
||||
|
||||
if (wsgi_req && uwsgi.exception_handlers_instance) {
|
||||
struct uwsgi_buffer *ehi = uwsgi_exception_handler_object(wsgi_req);
|
||||
if (ehi) {
|
||||
uwsgi_exception_run_handlers(ehi);
|
||||
uwsgi_buffer_destroy(ehi);
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].exceptions++;
|
||||
uwsgi_apps[wsgi_req->app_id].exceptions++;
|
||||
|
||||
if (uwsgi.reload_on_exception_type && uwsgi.p[wsgi_req->uh->modifier1]->exception_class) {
|
||||
struct uwsgi_buffer *ub = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req);
|
||||
if (ub) {
|
||||
struct uwsgi_string_list *usl = uwsgi.reload_on_exception_type;
|
||||
while (usl) {
|
||||
if (!uwsgi_strncmp(usl->value, usl->len, ub->buf, ub->len)) {
|
||||
do_exit = 1;
|
||||
uwsgi_buffer_destroy(ub);
|
||||
goto check_catch;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.reload_on_exception_value && uwsgi.p[wsgi_req->uh->modifier1]->exception_msg) {
|
||||
struct uwsgi_buffer *ub = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req);
|
||||
if (ub) {
|
||||
struct uwsgi_string_list *usl = uwsgi.reload_on_exception_value;
|
||||
while (usl) {
|
||||
if (!uwsgi_strncmp(usl->value, usl->len, ub->buf, ub->len)) {
|
||||
do_exit = 1;
|
||||
uwsgi_buffer_destroy(ub);
|
||||
goto check_catch;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.reload_on_exception_repr && uwsgi.p[wsgi_req->uh->modifier1]->exception_repr) {
|
||||
struct uwsgi_buffer *ub = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req);
|
||||
if (ub) {
|
||||
struct uwsgi_string_list *usl = uwsgi.reload_on_exception_repr;
|
||||
while (usl) {
|
||||
if (!uwsgi_strncmp(usl->value, usl->len, ub->buf, ub->len)) {
|
||||
do_exit = 1;
|
||||
uwsgi_buffer_destroy(ub);
|
||||
goto check_catch;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
}
|
||||
}
|
||||
|
||||
check_catch:
|
||||
if (catch && wsgi_req) {
|
||||
if (uwsgi_exceptions_catch(wsgi_req)) {
|
||||
// for now, just goto, new features could be added
|
||||
goto log;
|
||||
}
|
||||
}
|
||||
|
||||
log:
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->exception_log) {
|
||||
uwsgi.p[wsgi_req->uh->modifier1]->exception_log(wsgi_req);
|
||||
}
|
||||
|
||||
log2:
|
||||
if (do_exit) {
|
||||
exit(UWSGI_EXCEPTION_CODE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_exception_handler *uwsgi_register_exception_handler(char *name, int (*func)(struct uwsgi_exception_handler_instance *, char *, size_t)) {
|
||||
struct uwsgi_exception_handler *old_ueh = NULL, *ueh = uwsgi.exception_handlers;
|
||||
while(ueh) {
|
||||
if (!strcmp(name, ueh->name)) {
|
||||
return NULL;
|
||||
}
|
||||
old_ueh = ueh;
|
||||
ueh = ueh->next;
|
||||
}
|
||||
|
||||
ueh = uwsgi_calloc(sizeof(struct uwsgi_exception_handler));
|
||||
ueh->name = name;
|
||||
ueh->func = func;
|
||||
|
||||
if (old_ueh) {
|
||||
old_ueh->next = ueh;
|
||||
}
|
||||
else {
|
||||
uwsgi.exception_handlers = ueh;
|
||||
}
|
||||
|
||||
return ueh;
|
||||
}
|
||||
|
||||
struct uwsgi_exception_handler *uwsgi_exception_handler_by_name(char *name) {
|
||||
struct uwsgi_exception_handler *ueh = uwsgi.exception_handlers;
|
||||
while(ueh) {
|
||||
if (!strcmp(name, ueh->name)) {
|
||||
return ueh;
|
||||
}
|
||||
ueh = ueh->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void uwsgi_exception_handler_thread_loop(struct uwsgi_thread *ut) {
|
||||
char *buf = uwsgi_malloc(uwsgi.exception_handler_msg_size + sizeof(long));
|
||||
for (;;) {
|
||||
int interesting_fd = -1;
|
||||
int ret = event_queue_wait(ut->queue, -1, &interesting_fd);
|
||||
if (ret > 0) {
|
||||
ssize_t len = read(ut->pipe[1], buf, uwsgi.alarm_msg_size + sizeof(long));
|
||||
if (len > (ssize_t)(sizeof(long) + 1)) {
|
||||
size_t msg_size = len - sizeof(long);
|
||||
char *msg = buf + sizeof(long);
|
||||
long ptr = 0;
|
||||
memcpy(&ptr, buf, sizeof(long));
|
||||
struct uwsgi_exception_handler_instance *uehi = (struct uwsgi_exception_handler_instance *) ptr;
|
||||
if (!uehi)
|
||||
break;
|
||||
if (uehi->handler->func(uehi, msg, msg_size)) {
|
||||
uwsgi_log("[uwsgi-exception] error running the handler \"%s\" args: \"%s\"\n", uehi->handler->name, uehi->arg ? uehi->arg : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void uwsgi_exception_setup_handlers() {
|
||||
|
||||
struct uwsgi_string_list *usl = uwsgi.exception_handlers_instance;
|
||||
while(usl) {
|
||||
char *handler = uwsgi_str(usl->value);
|
||||
char *colon = strchr(handler, ':');
|
||||
if (colon) {
|
||||
*colon = 0;
|
||||
}
|
||||
struct uwsgi_exception_handler *ueh = uwsgi_exception_handler_by_name(handler);
|
||||
if (!ueh) {
|
||||
uwsgi_log("unable to find exception handler: %s\n", handler);
|
||||
free(handler);
|
||||
exit(1);
|
||||
}
|
||||
free(handler);
|
||||
|
||||
struct uwsgi_exception_handler_instance *uehi = uwsgi_calloc(sizeof(struct uwsgi_exception_handler_instance));
|
||||
uehi->handler = ueh;
|
||||
if (colon) {
|
||||
uehi->arg = colon+1;
|
||||
}
|
||||
usl->custom_ptr = uehi;
|
||||
usl = usl->next;
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_exceptions_handler_thread_start() {
|
||||
|
||||
// start the exception_handler_thread
|
||||
uwsgi.exception_handler_thread = uwsgi_thread_new(uwsgi_exception_handler_thread_loop);
|
||||
if (!uwsgi.exception_handler_thread) {
|
||||
uwsgi_log("unable to spawn exception handler thread\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -41,10 +41,6 @@ struct uwsgi_gateway *register_gateway(char *name, void (*loop) (int, void *), v
|
||||
return ug;
|
||||
}
|
||||
|
||||
static void gateway_brutal_end() {
|
||||
_exit(UWSGI_END_CODE);
|
||||
}
|
||||
|
||||
void gateway_respawn(int id) {
|
||||
|
||||
pid_t gw_pid;
|
||||
@@ -69,7 +65,6 @@ void gateway_respawn(int id) {
|
||||
}
|
||||
#endif
|
||||
uwsgi.mypid = getpid();
|
||||
atexit(gateway_brutal_end);
|
||||
signal(SIGALRM, SIG_IGN);
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
signal(SIGINT, end_me);
|
||||
|
||||
-93
@@ -1,93 +0,0 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
// Bernstein classic hash (this is not static as it is used by other areas)
|
||||
uint32_t djb33x_hash(char *key, uint64_t keylen) {
|
||||
|
||||
register uint32_t hash = 5381;
|
||||
uint64_t i;
|
||||
|
||||
for (i = 0; i < keylen; i++) {
|
||||
hash = ((hash << 5) + hash) ^ key[i];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
// Murmur2 hash Copyright (C) Austin Appleby
|
||||
// adapted from nginx
|
||||
uint32_t murmur2_hash(char *key, uint64_t keylen) {
|
||||
|
||||
uint32_t h, k;
|
||||
uint8_t *ukey = (uint8_t *) key;
|
||||
h = 0 ^ keylen;
|
||||
while (keylen >= 4) {
|
||||
k = ukey[0];
|
||||
k |= ukey[1] << 8;
|
||||
k |= ukey[2] << 16;
|
||||
k |= ukey[3] << 24;
|
||||
|
||||
k *= 0x5bd1e995;
|
||||
k ^= k >> 24;
|
||||
k *= 0x5bd1e995;
|
||||
|
||||
h *= 0x5bd1e995;
|
||||
h ^= k;
|
||||
|
||||
ukey += 4;
|
||||
keylen -= 4;
|
||||
}
|
||||
|
||||
switch (keylen) {
|
||||
case 3:
|
||||
h ^= key[2] << 16;
|
||||
case 2:
|
||||
h ^= key[1] << 8;
|
||||
case 1:
|
||||
h ^= key[0];
|
||||
h *= 0x5bd1e995;
|
||||
}
|
||||
|
||||
h ^= h >> 13;
|
||||
h *= 0x5bd1e995;
|
||||
h ^= h >> 15;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_hash_algo *uwsgi_hash_algo_get(char *name) {
|
||||
struct uwsgi_hash_algo *uha = uwsgi.hash_algos;
|
||||
while(uha) {
|
||||
if (!strcmp(name, uha->name)) {
|
||||
return uha;
|
||||
}
|
||||
uha = uha->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
void uwsgi_hash_algo_register(char *name, uint32_t (*func)(char *, uint64_t)) {
|
||||
|
||||
struct uwsgi_hash_algo *old_uha = NULL, *uha = uwsgi.hash_algos;
|
||||
while(uha) {
|
||||
if (!strcmp(uha->name, name)) return;
|
||||
old_uha = uha;
|
||||
uha = uha->next;
|
||||
}
|
||||
|
||||
uha = uwsgi_calloc(sizeof(struct uwsgi_hash_algo));
|
||||
uha->name = name;
|
||||
uha->func = func;
|
||||
if (old_uha) {
|
||||
old_uha->next = uha;
|
||||
}
|
||||
else {
|
||||
uwsgi.hash_algos = uha;
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_hash_algo_register_all() {
|
||||
uwsgi_hash_algo_register("djb33x", djb33x_hash);
|
||||
uwsgi_hash_algo_register("murmur2", murmur2_hash);
|
||||
}
|
||||
+4
-4
@@ -54,9 +54,9 @@ char *ini_get_key(char *key) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
char *ini_get_line(char *ini, size_t size) {
|
||||
char *ini_get_line(char *ini, off_t size) {
|
||||
|
||||
size_t i;
|
||||
off_t i;
|
||||
char *ptr = ini;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
@@ -78,7 +78,7 @@ char *ini_get_line(char *ini, size_t size) {
|
||||
|
||||
void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
|
||||
size_t len = 0;
|
||||
int len = 0;
|
||||
char *ini;
|
||||
|
||||
char *ini_line;
|
||||
@@ -109,7 +109,7 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
}
|
||||
|
||||
if (file[0] != 0) {
|
||||
uwsgi_log_initial("[uWSGI] getting INI configuration from %s\n", file);
|
||||
uwsgi_log("[uWSGI] getting INI configuration from %s\n", file);
|
||||
}
|
||||
|
||||
ini = uwsgi_open_and_read(file, &len, 1, magic_table);
|
||||
|
||||
+13
-168
@@ -2,61 +2,6 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct http_status_codes {
|
||||
const char key[3];
|
||||
const char *message;
|
||||
int message_size;
|
||||
};
|
||||
|
||||
/* statistically ordered */
|
||||
struct http_status_codes hsc[] = {
|
||||
{"200", "OK"},
|
||||
{"302", "Found"},
|
||||
{"404", "Not Found"},
|
||||
{"500", "Internal Server Error"},
|
||||
{"301", "Moved Permanently"},
|
||||
{"304", "Not Modified"},
|
||||
{"303", "See Other"},
|
||||
{"403", "Forbidden"},
|
||||
{"307", "Temporary Redirect"},
|
||||
{"401", "Unauthorized"},
|
||||
{"400", "Bad Request"},
|
||||
{"405", "Method Not Allowed"},
|
||||
{"408", "Request Timeout"},
|
||||
|
||||
{"100", "Continue"},
|
||||
{"101", "Switching Protocols"},
|
||||
{"201", "Created"},
|
||||
{"202", "Accepted"},
|
||||
{"203", "Non-Authoritative Information"},
|
||||
{"204", "No Content"},
|
||||
{"205", "Reset Content"},
|
||||
{"206", "Partial Content"},
|
||||
{"300", "Multiple Choices"},
|
||||
{"305", "Use Proxy"},
|
||||
{"402", "Payment Required"},
|
||||
{"406", "Not Acceptable"},
|
||||
{"407", "Proxy Authentication Required"},
|
||||
{"409", "Conflict"},
|
||||
{"410", "Gone"},
|
||||
{"411", "Length Required"},
|
||||
{"412", "Precondition Failed"},
|
||||
{"413", "Request Entity Too Large"},
|
||||
{"414", "Request-URI Too Long"},
|
||||
{"415", "Unsupported Media Type"},
|
||||
{"416", "Requested Range Not Satisfiable"},
|
||||
{"417", "Expectation Failed"},
|
||||
{"501", "Not Implemented"},
|
||||
{"502", "Bad Gateway"},
|
||||
{"503", "Service Unavailable"},
|
||||
{"504", "Gateway Timeout"},
|
||||
{"505", "HTTP Version Not Supported"},
|
||||
{"", NULL},
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
void uwsgi_init_default() {
|
||||
|
||||
uwsgi.cpus = 1;
|
||||
@@ -68,6 +13,7 @@ void uwsgi_init_default() {
|
||||
|
||||
uwsgi.signal_socket = -1;
|
||||
uwsgi.my_signal_socket = -1;
|
||||
uwsgi.cache_server_fd = -1;
|
||||
uwsgi.stats_fd = -1;
|
||||
|
||||
uwsgi.stats_pusher_default_freq = 3;
|
||||
@@ -86,18 +32,15 @@ void uwsgi_init_default() {
|
||||
uwsgi.subscribe_freq = 10;
|
||||
uwsgi.subscription_tolerance = 17;
|
||||
|
||||
uwsgi.cluster_fd = -1;
|
||||
uwsgi.cores = 1;
|
||||
uwsgi.threads = 1;
|
||||
|
||||
// default max number of rpc slot
|
||||
uwsgi.rpc_max = 64;
|
||||
|
||||
uwsgi.offload_threads_events = 64;
|
||||
|
||||
uwsgi.default_app = -1;
|
||||
|
||||
uwsgi.buffer_size = 4096;
|
||||
uwsgi.body_read_warning = 8;
|
||||
uwsgi.numproc = 1;
|
||||
|
||||
uwsgi.forkbomb_delay = 2;
|
||||
@@ -109,22 +52,18 @@ void uwsgi_init_default() {
|
||||
|
||||
uwsgi.log_master_bufsize = 8192;
|
||||
|
||||
uwsgi.worker_reload_mercy = 60;
|
||||
|
||||
uwsgi.max_vars = MAX_VARS;
|
||||
uwsgi.vec_size = 4 + 1 + (4 * MAX_VARS);
|
||||
|
||||
uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] = 4;
|
||||
uwsgi.shared->options[UWSGI_OPTION_LOGGING] = 1;
|
||||
|
||||
// a workers hould be running for at least 10 seconds
|
||||
uwsgi.shared->options[UWSGI_OPTION_MIN_WORKER_LIFETIME] = 10;
|
||||
|
||||
#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;
|
||||
|
||||
@@ -134,37 +73,20 @@ void uwsgi_init_default() {
|
||||
uwsgi.shared->worker_log_pipe[0] = -1;
|
||||
uwsgi.shared->worker_log_pipe[1] = -1;
|
||||
|
||||
uwsgi.shared->worker_req_log_pipe[0] = -1;
|
||||
uwsgi.shared->worker_req_log_pipe[1] = -1;
|
||||
|
||||
uwsgi.req_log_fd = 2;
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
// 1 day of tolerance
|
||||
uwsgi.subscriptions_sign_check_tolerance = 3600 * 24;
|
||||
uwsgi.ssl_sessions_timeout = 300;
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_ALARM
|
||||
uwsgi.alarm_freq = 3;
|
||||
uwsgi.alarm_msg_size = 8192;
|
||||
#endif
|
||||
|
||||
uwsgi.exception_handler_msg_size = 65536;
|
||||
|
||||
#ifdef UWSGI_MULTICAST
|
||||
uwsgi.multicast_ttl = 1;
|
||||
uwsgi.multicast_loop = 1;
|
||||
#endif
|
||||
|
||||
// filling http status codes
|
||||
struct http_status_codes *http_sc;
|
||||
for (http_sc = hsc; http_sc->message != NULL; http_sc++) {
|
||||
http_sc->message_size = strlen(http_sc->message);
|
||||
}
|
||||
|
||||
uwsgi.empty = "";
|
||||
|
||||
uwsgi.wait_read_hook = uwsgi_simple_wait_read_hook;
|
||||
uwsgi.wait_write_hook = uwsgi_simple_wait_write_hook;
|
||||
|
||||
uwsgi_websockets_init();
|
||||
}
|
||||
|
||||
void uwsgi_setup_reload() {
|
||||
@@ -296,7 +218,7 @@ void uwsgi_commandline_config() {
|
||||
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.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
|
||||
@@ -307,8 +229,7 @@ void uwsgi_setup_workers() {
|
||||
|
||||
// this is a trick for avoiding too much memory areas
|
||||
void *ts = uwsgi_calloc_shared(sizeof(void *) * uwsgi.max_apps * uwsgi.cores);
|
||||
// add 4 bytes for uwsgi header
|
||||
void *buffers = uwsgi_malloc_shared((uwsgi.buffer_size+4) * 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)
|
||||
@@ -318,8 +239,8 @@ void uwsgi_setup_workers() {
|
||||
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 (+4 bytes for uwsgi header)
|
||||
uwsgi.workers[i].cores[j].buffer = buffers + ((uwsgi.buffer_size+4) * 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)
|
||||
@@ -341,11 +262,7 @@ void uwsgi_setup_workers() {
|
||||
}
|
||||
|
||||
total_memory *= (uwsgi.numproc + uwsgi.master_process);
|
||||
if (uwsgi.numproc > 0)
|
||||
uwsgi_log("mapped %llu bytes (%llu KB) for %d cores\n", (unsigned long long) total_memory, (unsigned long long) (total_memory / 1024), uwsgi.cores * uwsgi.numproc);
|
||||
|
||||
// allocate signal table
|
||||
uwsgi.shared->signal_table = uwsgi_calloc_shared(sizeof(struct uwsgi_signal_entry) * 256 * (uwsgi.numproc + 1));
|
||||
uwsgi_log("mapped %llu bytes (%llu KB) for %d cores\n", total_memory, total_memory / 1024, uwsgi.cores * uwsgi.numproc);
|
||||
|
||||
}
|
||||
|
||||
@@ -376,75 +293,3 @@ pid_t uwsgi_daemonize2() {
|
||||
|
||||
return uwsgi.mypid;
|
||||
}
|
||||
|
||||
// fix/check related options
|
||||
void sanitize_args() {
|
||||
|
||||
if (uwsgi.async > 1) {
|
||||
uwsgi.cores = uwsgi.async;
|
||||
}
|
||||
|
||||
if (uwsgi.threads > 1) {
|
||||
uwsgi.has_threads = 1;
|
||||
uwsgi.cores = uwsgi.threads;
|
||||
}
|
||||
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
|
||||
if (!uwsgi.post_buffering) {
|
||||
uwsgi_log(" *** WARNING: you have enabled harakiri without post buffering. Slow upload could be rejected on post-unbuffered webservers *** \n");
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.write_errors_exception_only) {
|
||||
uwsgi.ignore_sigpipe = 1;
|
||||
uwsgi.ignore_write_errors = 1;
|
||||
}
|
||||
|
||||
if (uwsgi.cheaper_count == 0) uwsgi.cheaper = 0;
|
||||
|
||||
if (uwsgi.cheaper_count > 0 && uwsgi.cheaper_count >= uwsgi.numproc) {
|
||||
uwsgi_log("invalid cheaper value: must be lower than processes\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (uwsgi.cheaper && uwsgi.cheaper_count) {
|
||||
if (uwsgi.cheaper_initial) {
|
||||
if (uwsgi.cheaper_initial < uwsgi.cheaper_count) {
|
||||
uwsgi_log("warning: invalid cheaper-initial value (%d), must be equal or higher than cheaper (%d), using %d as initial number of workers\n",
|
||||
uwsgi.cheaper_initial, uwsgi.cheaper_count, uwsgi.cheaper_count);
|
||||
uwsgi.cheaper_initial = uwsgi.cheaper_count;
|
||||
}
|
||||
else if (uwsgi.cheaper_initial > uwsgi.numproc) {
|
||||
uwsgi_log("warning: invalid cheaper-initial value (%d), must be lower or equal than worker count (%d), using %d as initial number of workers\n",
|
||||
uwsgi.cheaper_initial, uwsgi.numproc, uwsgi.numproc);
|
||||
uwsgi.cheaper_initial = uwsgi.numproc;
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi.cheaper_initial = uwsgi.cheaper_count;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.auto_snapshot > 0 && uwsgi.auto_snapshot > uwsgi.numproc) {
|
||||
uwsgi_log("invalid auto-snapshot value: must be <= than processes\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME] > 0 && uwsgi.shared->options[UWSGI_OPTION_MIN_WORKER_LIFETIME] >= uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME]) {
|
||||
uwsgi_log("invalid min-worker-lifetime value (%d), must be lower than max-worker-lifetime (%d)\n",
|
||||
uwsgi.shared->options[UWSGI_OPTION_MIN_WORKER_LIFETIME], uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const char *uwsgi_http_status_msg(char *status, uint16_t *len) {
|
||||
struct http_status_codes *http_sc;
|
||||
for (http_sc = hsc; http_sc->message != NULL; http_sc++) {
|
||||
if (!strncmp(http_sc->key, status, 3)) {
|
||||
*len = http_sc->message_size;
|
||||
return http_sc->message;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+2
-2
@@ -13,7 +13,7 @@ extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_json_config(char *file, char *magic_table[]) {
|
||||
|
||||
size_t len = 0;
|
||||
int len = 0;
|
||||
char *json_data;
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ void uwsgi_json_config(char *file, char *magic_table[]) {
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log_initial("[uWSGI] getting JSON configuration from %s\n", file);
|
||||
uwsgi_log("[uWSGI] getting JSON configuration from %s\n", file);
|
||||
|
||||
json_data = uwsgi_open_and_read(file, &len, 1, magic_table);
|
||||
|
||||
|
||||
-1022
File diff suppressed because it is too large
Load Diff
+4
-76
@@ -91,6 +91,7 @@ retry:
|
||||
}
|
||||
|
||||
#ifdef EOWNERDEAD
|
||||
|
||||
#ifndef PTHREAD_MUTEX_ROBUST
|
||||
#define PTHREAD_MUTEX_ROBUST PTHREAD_MUTEX_ROBUST_NP
|
||||
#endif
|
||||
@@ -401,60 +402,6 @@ void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_unlock_fast(uli);
|
||||
}
|
||||
|
||||
#elif defined(UWSGI_LOCK_USE_WINDOWS_MUTEX)
|
||||
|
||||
#define UWSGI_LOCK_ENGINE_NAME "windows mutexes"
|
||||
#define UWSGI_LOCK_SIZE sizeof(HANDLE)
|
||||
#define UWSGI_RWLOCK_SIZE sizeof(HANDLE)
|
||||
|
||||
|
||||
struct uwsgi_lock_item *uwsgi_lock_fast_init(char *id) {
|
||||
|
||||
struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0);
|
||||
struct _SECURITY_ATTRIBUTES sa;
|
||||
memset(&sa, 0, sizeof(struct _SECURITY_ATTRIBUTES));
|
||||
sa.bInheritHandle = 1;
|
||||
uli->lock_ptr = CreateMutex(&sa, FALSE, NULL);
|
||||
return uli;
|
||||
}
|
||||
|
||||
void uwsgi_lock_fast(struct uwsgi_lock_item *uli) {
|
||||
WaitForSingleObject(uli->lock_ptr, INFINITE);
|
||||
uli->pid = uwsgi.mypid;
|
||||
}
|
||||
|
||||
void uwsgi_unlock_fast(struct uwsgi_lock_item *uli) {
|
||||
ReleaseMutex(uli->lock_ptr);
|
||||
uli->pid = 0;
|
||||
}
|
||||
|
||||
pid_t uwsgi_lock_fast_check(struct uwsgi_lock_item *uli) {
|
||||
if (WaitForSingleObject(uli->lock_ptr, 0) == WAIT_TIMEOUT) {
|
||||
return 0;
|
||||
}
|
||||
return uli->pid;
|
||||
}
|
||||
|
||||
struct uwsgi_lock_item *uwsgi_rwlock_fast_init(char *id) {
|
||||
return uwsgi_lock_fast_init(id);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
pid_t uwsgi_rwlock_fast_check(struct uwsgi_lock_item *uli) {
|
||||
return uwsgi_lock_fast_check(uli);
|
||||
}
|
||||
|
||||
void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_unlock_fast(uli);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#define uwsgi_lock_fast_init uwsgi_lock_ipcsem_init
|
||||
@@ -531,9 +478,7 @@ void uwsgi_lock_ipcsem(struct uwsgi_lock_item *uli) {
|
||||
|
||||
memcpy(&semid, uli->lock_ptr, sizeof(int));
|
||||
|
||||
retry:
|
||||
if (semop(semid, &sb, 1)) {
|
||||
if (errno == EINTR) goto retry;
|
||||
uwsgi_error("semop()");
|
||||
}
|
||||
}
|
||||
@@ -548,9 +493,7 @@ void uwsgi_unlock_ipcsem(struct uwsgi_lock_item *uli) {
|
||||
|
||||
memcpy(&semid, uli->lock_ptr, sizeof(int));
|
||||
|
||||
retry:
|
||||
if (semop(semid, &sb, 1)) {
|
||||
if (errno == EINTR) goto retry;
|
||||
uwsgi_error("semop()");
|
||||
}
|
||||
|
||||
@@ -615,10 +558,6 @@ pid_t uwsgi_rwlock_ipcsem_check(struct uwsgi_lock_item *uli) {
|
||||
|
||||
void uwsgi_setup_locking() {
|
||||
|
||||
int i;
|
||||
|
||||
if (uwsgi.locking_setup) return;
|
||||
|
||||
// use the fastest available locking
|
||||
if (uwsgi.lock_engine) {
|
||||
if (!strcmp(uwsgi.lock_engine, "ipcsem")) {
|
||||
@@ -635,10 +574,8 @@ void uwsgi_setup_locking() {
|
||||
uwsgi.lock_ops.rwunlock = uwsgi_rwunlock_ipcsem;
|
||||
uwsgi.lock_size = 8;
|
||||
uwsgi.rwlock_size = 8;
|
||||
goto ready;
|
||||
return;
|
||||
}
|
||||
uwsgi_log("unable to find lock engine \"%s\"\n", uwsgi.lock_engine);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_log_initial("lock engine: %s\n", UWSGI_LOCK_ENGINE_NAME);
|
||||
@@ -657,8 +594,8 @@ void uwsgi_setup_locking() {
|
||||
uwsgi.lock_size = UWSGI_LOCK_SIZE;
|
||||
uwsgi.rwlock_size = UWSGI_RWLOCK_SIZE;
|
||||
|
||||
ready:
|
||||
// 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)));
|
||||
@@ -691,20 +628,11 @@ ready:
|
||||
|
||||
if (uwsgi.use_thunder_lock) {
|
||||
// process shared thunder lock
|
||||
uwsgi.the_thunder_lock = uwsgi_lock_init("thunder");
|
||||
uwsgi.the_thunder_lock = uwsgi_lock_init("thunder");
|
||||
}
|
||||
|
||||
uwsgi.rpc_table_lock = uwsgi_lock_init("rpc");
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
// register locking for legions
|
||||
struct uwsgi_legion *ul = uwsgi.legions;
|
||||
while(ul) {
|
||||
ul->lock = uwsgi_lock_init(uwsgi_concat2("legion_", ul->legion));
|
||||
ul = ul->next;
|
||||
}
|
||||
#endif
|
||||
uwsgi.locking_setup = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+130
-367
@@ -1,9 +1,9 @@
|
||||
#ifndef __DragonFly__
|
||||
#include <uwsgi.h>
|
||||
#endif
|
||||
#define _NO_UWSGI_RB
|
||||
#include "uwsgi.h"
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
|
||||
#include <sys/user.h>
|
||||
#include <kvm.h>
|
||||
#include <sys/user.h>
|
||||
#elif defined(__sun__)
|
||||
/* Terrible Hack !!! */
|
||||
#ifndef _LP64
|
||||
@@ -17,10 +17,6 @@
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef __DragonFly__
|
||||
#include <uwsgi.h>
|
||||
#endif
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
//use this instead of fprintf to avoid buffering mess with udp logging
|
||||
@@ -148,21 +144,6 @@ void create_logpipe(void) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (uwsgi.req_log_master) {
|
||||
#if defined(SOCK_SEQPACKET) && defined(__linux__)
|
||||
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, uwsgi.shared->worker_req_log_pipe)) {
|
||||
#else
|
||||
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, uwsgi.shared->worker_req_log_pipe)) {
|
||||
#endif
|
||||
uwsgi_error("socketpair()\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_socket_nb(uwsgi.shared->worker_req_log_pipe[0]);
|
||||
uwsgi_socket_nb(uwsgi.shared->worker_req_log_pipe[1]);
|
||||
uwsgi.req_log_fd = uwsgi.shared->worker_req_log_pipe[1];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
@@ -213,6 +194,7 @@ void logto(char *logfile) {
|
||||
|
||||
int fd;
|
||||
|
||||
#ifdef UWSGI_UDP
|
||||
char *udp_port;
|
||||
struct sockaddr_in udp_addr;
|
||||
|
||||
@@ -248,6 +230,7 @@ void logto(char *logfile) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
if (uwsgi.log_truncate) {
|
||||
fd = open(logfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP);
|
||||
}
|
||||
@@ -265,7 +248,9 @@ void logto(char *logfile) {
|
||||
uwsgi_error("chmod()");
|
||||
}
|
||||
}
|
||||
#ifdef UWSGI_UDP
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* stdout */
|
||||
@@ -309,70 +294,61 @@ void uwsgi_setup_log() {
|
||||
|
||||
}
|
||||
|
||||
static struct uwsgi_logger *setup_choosen_logger(struct uwsgi_string_list *usl) {
|
||||
char *id = NULL;
|
||||
char *name = usl->value;
|
||||
|
||||
char *space = strchr(name, ' ');
|
||||
if (space) {
|
||||
int is_id = 1;
|
||||
int i;
|
||||
for (i = 0; i < (space - name); i++) {
|
||||
if (!isalnum((int)name[i])) {
|
||||
is_id = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_id) {
|
||||
id = uwsgi_concat2n(name, space - name, "", 0);
|
||||
name = space + 1;
|
||||
}
|
||||
}
|
||||
|
||||
char *colon = strchr(name, ':');
|
||||
if (colon) {
|
||||
*colon = 0;
|
||||
}
|
||||
|
||||
struct uwsgi_logger *choosen_logger = uwsgi_get_logger(name);
|
||||
if (!choosen_logger) {
|
||||
uwsgi_log("unable to find logger %s\n", name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// make a copy of the logger
|
||||
struct uwsgi_logger *copy_of_choosen_logger = uwsgi_malloc(sizeof(struct uwsgi_logger));
|
||||
memcpy(copy_of_choosen_logger, choosen_logger, sizeof(struct uwsgi_logger));
|
||||
choosen_logger = copy_of_choosen_logger;
|
||||
choosen_logger->id = id;
|
||||
choosen_logger->next = NULL;
|
||||
|
||||
if (colon) {
|
||||
choosen_logger->arg = colon + 1;
|
||||
// check for empty string
|
||||
if (*choosen_logger->arg == 0) {
|
||||
choosen_logger->arg = NULL;
|
||||
}
|
||||
*colon = ':';
|
||||
}
|
||||
return choosen_logger;
|
||||
}
|
||||
|
||||
void uwsgi_setup_log_master(void) {
|
||||
|
||||
struct uwsgi_string_list *usl = uwsgi.requested_logger;
|
||||
while (usl) {
|
||||
struct uwsgi_logger *choosen_logger = setup_choosen_logger(usl);
|
||||
uwsgi_append_logger(choosen_logger);
|
||||
usl = usl->next;
|
||||
}
|
||||
char *id = NULL;
|
||||
char *name = usl->value;
|
||||
|
||||
usl = uwsgi.requested_req_logger;
|
||||
while (usl) {
|
||||
struct uwsgi_logger *choosen_logger = setup_choosen_logger(usl);
|
||||
uwsgi_append_req_logger(choosen_logger);
|
||||
usl = usl->next;
|
||||
}
|
||||
char *space = strchr(name, ' ');
|
||||
if (space) {
|
||||
int is_id = 1;
|
||||
int i;
|
||||
for (i = 0; i < (space - name); i++) {
|
||||
if (!isalnum(name[i])) {
|
||||
is_id = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_id) {
|
||||
id = uwsgi_concat2n(name, space - name, "", 0);
|
||||
name = space + 1;
|
||||
}
|
||||
}
|
||||
|
||||
char *colon = strchr(name, ':');
|
||||
if (colon) {
|
||||
*colon = 0;
|
||||
}
|
||||
|
||||
struct uwsgi_logger *choosen_logger = uwsgi_get_logger(name);
|
||||
if (!choosen_logger) {
|
||||
uwsgi_log("unable to find logger %s\n", name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// make a copy of the logger
|
||||
struct uwsgi_logger *copy_of_choosen_logger = uwsgi_malloc(sizeof(struct uwsgi_logger));
|
||||
memcpy(copy_of_choosen_logger, choosen_logger, sizeof(struct uwsgi_logger));
|
||||
choosen_logger = copy_of_choosen_logger;
|
||||
choosen_logger->id = id;
|
||||
choosen_logger->next = NULL;
|
||||
|
||||
if (colon) {
|
||||
choosen_logger->arg = colon + 1;
|
||||
// check for empty string
|
||||
if (*choosen_logger->arg == 0) {
|
||||
choosen_logger->arg = NULL;
|
||||
}
|
||||
*colon = ':';
|
||||
}
|
||||
|
||||
uwsgi_append_logger(choosen_logger);
|
||||
|
||||
usl = usl->next;
|
||||
|
||||
}
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
// set logger by its id
|
||||
@@ -381,11 +357,6 @@ void uwsgi_setup_log_master(void) {
|
||||
url->custom_ptr = uwsgi_get_logger_from_id(url->custom_str);
|
||||
url = url->next;
|
||||
}
|
||||
url = uwsgi.log_req_route;
|
||||
while (url) {
|
||||
url->custom_ptr = uwsgi_get_logger_from_id(url->custom_str);
|
||||
url = url->next;
|
||||
}
|
||||
#endif
|
||||
|
||||
uwsgi.original_log_fd = dup(1);
|
||||
@@ -487,13 +458,13 @@ void uwsgi_check_logrotate(void) {
|
||||
uwsgi_error_open(uwsgi.logfile);
|
||||
grace_them_all(0);
|
||||
}
|
||||
else {
|
||||
if (dup2(fd, uwsgi.original_log_fd) < 0) {
|
||||
uwsgi_error("dup2()");
|
||||
grace_them_all(0);
|
||||
}
|
||||
close(fd);
|
||||
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()");
|
||||
@@ -556,7 +527,7 @@ void log_request(struct wsgi_request *wsgi_req) {
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_LOG_BIG] && (wsgi_req->response_size >= uwsgi.shared->options[UWSGI_OPTION_LOG_BIG])) {
|
||||
goto logit;
|
||||
}
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_LOG_SENDFILE] && wsgi_req->via == UWSGI_VIA_SENDFILE) {
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_LOG_SENDFILE] && (wsgi_req->sendfile_fd > -1 && wsgi_req->sendfile_obj == wsgi_req->async_result)) {
|
||||
goto logit;
|
||||
}
|
||||
|
||||
@@ -601,19 +572,16 @@ void uwsgi_logit_simple(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
}
|
||||
|
||||
// mark requests via (sendfile, route, offload...)
|
||||
switch(wsgi_req->via) {
|
||||
case UWSGI_VIA_SENDFILE:
|
||||
via = msg1;
|
||||
break;
|
||||
case UWSGI_VIA_ROUTE:
|
||||
via = msg3;
|
||||
break;
|
||||
case UWSGI_VIA_OFFLOAD:
|
||||
via = msg4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (wsgi_req->sendfile_fd > -1 && wsgi_req->sendfile_obj == wsgi_req->async_result) { //wsgi_req->sendfile_fd_size > 0 ) {
|
||||
via = msg1;
|
||||
}
|
||||
|
||||
// mark route() requests
|
||||
if (wsgi_req->status == -17) {
|
||||
via = msg3;
|
||||
}
|
||||
else if (wsgi_req->status == -30) {
|
||||
via = msg4;
|
||||
}
|
||||
|
||||
#ifdef __sun__
|
||||
@@ -654,13 +622,11 @@ void uwsgi_logit_simple(struct wsgi_request *wsgi_req) {
|
||||
|
||||
}
|
||||
|
||||
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 %llu %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, (unsigned long long) 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);
|
||||
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 %llu %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, (unsigned long long) 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);
|
||||
|
||||
// not enough space for logging the request, just log a (safe) minimal message
|
||||
if (rlen > 4096) {
|
||||
rlen = snprintf(logpkt, 4096, "[pid: %d|app: %d|req: %d/%llu] 0.0.0.0 () {%d vars in %d bytes} [%.*s] - - => generated %llu bytes in %llu %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->var_cnt, wsgi_req->uh->pktsize,
|
||||
24, time_request, (unsigned long long) wsgi_req->response_size, (unsigned long long) rt, tsize, via, wsgi_req->status, wsgi_req->header_cnt, (unsigned long long) wsgi_req->headers_size, wsgi_req->switches, wsgi_req->async_id);
|
||||
rlen = snprintf(logpkt, 4096, "[pid: %d|app: %d|req: %d/%llu] 0.0.0.0 () {%d vars in %d bytes} [%.*s] - - => generated %llu bytes in %llu %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->var_cnt, wsgi_req->uh.pktsize, 24, time_request, (unsigned long long) wsgi_req->response_size, (unsigned long long) rt, tsize, via, wsgi_req->status, wsgi_req->header_cnt, (unsigned long long) wsgi_req->headers_size, wsgi_req->switches, wsgi_req->async_id);
|
||||
// argh, last resort, truncate it
|
||||
if (rlen > 4096) {
|
||||
rlen = 4096;
|
||||
@@ -671,7 +637,7 @@ void uwsgi_logit_simple(struct wsgi_request *wsgi_req) {
|
||||
logvec[logvecpos].iov_len = rlen;
|
||||
|
||||
// do not check for errors
|
||||
rlen = writev(uwsgi.req_log_fd, logvec, logvecpos + 1);
|
||||
rlen = writev(2, logvec, logvecpos + 1);
|
||||
}
|
||||
|
||||
void get_memusage(uint64_t * rss, uint64_t * vsz) {
|
||||
@@ -690,18 +656,6 @@ void get_memusage(uint64_t * rss, uint64_t * vsz) {
|
||||
fclose(procfile);
|
||||
}
|
||||
*rss = *rss * uwsgi.page_size;
|
||||
#elif defined(__CYGWIN__)
|
||||
// same as Linux but rss is not in pages...
|
||||
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 %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);
|
||||
}
|
||||
#elif defined (__sun__)
|
||||
psinfo_t info;
|
||||
int procfd;
|
||||
@@ -741,13 +695,8 @@ void get_memusage(uint64_t * rss, uint64_t * vsz) {
|
||||
struct kinfo_proc *kproc;
|
||||
kproc = kvm_getprocs(kv, KERN_PROC_PID, uwsgi.mypid, &cnt);
|
||||
if (kproc && cnt > 0) {
|
||||
#if defined(__FreeBSD__)
|
||||
*vsz = kproc->ki_size;
|
||||
*rss = kproc->ki_rssize * uwsgi.page_size;
|
||||
#elif defined(__DragonFly__)
|
||||
*vsz = kproc->kp_vm_map_size;
|
||||
*rss = kproc->kp_vm_rssize * uwsgi.page_size;
|
||||
#endif
|
||||
}
|
||||
#elif defined(UWSGI_NEW_OPENBSD)
|
||||
struct kinfo_proc *kproc;
|
||||
@@ -812,7 +761,6 @@ void uwsgi_register_logger(char *name, ssize_t(*func) (struct uwsgi_logger *, ch
|
||||
ul->configured = 0;
|
||||
ul->fd = -1;
|
||||
ul->data = NULL;
|
||||
ul->buf = NULL;
|
||||
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
@@ -837,24 +785,6 @@ void uwsgi_append_logger(struct uwsgi_logger *ul) {
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_append_req_logger(struct uwsgi_logger *ul) {
|
||||
|
||||
if (!uwsgi.choosen_req_logger) {
|
||||
uwsgi.choosen_req_logger = ul;
|
||||
return;
|
||||
}
|
||||
|
||||
struct uwsgi_logger *ucl = uwsgi.choosen_req_logger;
|
||||
while (ucl) {
|
||||
if (!ucl->next) {
|
||||
ucl->next = ul;
|
||||
return;
|
||||
}
|
||||
ucl = ucl->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_logger *uwsgi_get_logger(char *name) {
|
||||
struct uwsgi_logger *ul = uwsgi.loggers;
|
||||
|
||||
@@ -925,13 +855,13 @@ void uwsgi_logit_lf(struct wsgi_request *wsgi_req) {
|
||||
|
||||
if (uwsgi.logvectors[wsgi_req->async_id][pos].iov_len == 0 && logchunk->type != 0) {
|
||||
uwsgi.logvectors[wsgi_req->async_id][pos].iov_base = (char *) empty_var;
|
||||
uwsgi.logvectors[wsgi_req->async_id][pos].iov_len = 1;
|
||||
uwsgi.logvectors[wsgi_req->async_id][pos].iov_len = 1;
|
||||
}
|
||||
logchunk = logchunk->next;
|
||||
}
|
||||
|
||||
// do not check for errors
|
||||
rlen = writev(uwsgi.req_log_fd, uwsgi.logvectors[wsgi_req->async_id], uwsgi.logformat_vectors);
|
||||
rlen = writev(2, uwsgi.logvectors[wsgi_req->async_id], uwsgi.logformat_vectors);
|
||||
|
||||
// free allocated memory
|
||||
logchunk = uwsgi.logchunks;
|
||||
@@ -1006,25 +936,24 @@ static ssize_t uwsgi_lf_status(struct wsgi_request *wsgi_req, char **buf) {
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uwsgi_lf_rsize(struct wsgi_request *wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(wsgi_req->response_size);
|
||||
return strlen(*buf);
|
||||
*buf = uwsgi_num2str(wsgi_req->response_size);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_hsize(struct wsgi_request *wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(wsgi_req->headers_size);
|
||||
return strlen(*buf);
|
||||
*buf = uwsgi_num2str(wsgi_req->headers_size);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_size(struct wsgi_request *wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(wsgi_req->headers_size+wsgi_req->response_size);
|
||||
return strlen(*buf);
|
||||
*buf = uwsgi_num2str(wsgi_req->headers_size+wsgi_req->response_size);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_cl(struct wsgi_request *wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(wsgi_req->post_cl);
|
||||
return strlen(*buf);
|
||||
*buf = uwsgi_num2str(wsgi_req->post_cl);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
|
||||
@@ -1048,19 +977,19 @@ static ssize_t uwsgi_lf_time(struct wsgi_request * wsgi_req, char **buf) {
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uwsgi_lf_ltime(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_malloc(64);
|
||||
time_t now = wsgi_req->start_of_request / 1000000;
|
||||
size_t ret = strftime(*buf, 64, "%d/%b/%Y:%H:%M:%S %z", localtime(&now));
|
||||
if (ret == 0) {
|
||||
*buf[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
*buf = uwsgi_malloc(64);
|
||||
time_t now = wsgi_req->start_of_request / 1000000;
|
||||
size_t ret = strftime(*buf, 64, "%d/%b/%Y:%H:%M:%S %z", localtime(&now));
|
||||
if (ret == 0) {
|
||||
*buf[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static ssize_t uwsgi_lf_micros(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(wsgi_req->end_of_request - wsgi_req->start_of_request);
|
||||
return strlen(*buf);
|
||||
@@ -1117,17 +1046,17 @@ static ssize_t uwsgi_lf_rssM(struct wsgi_request * wsgi_req, char **buf) {
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_pktsize(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(wsgi_req->uh->pktsize);
|
||||
*buf = uwsgi_num2str(wsgi_req->uh.pktsize);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_modifier1(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(wsgi_req->uh->modifier1);
|
||||
*buf = uwsgi_num2str(wsgi_req->uh.modifier1);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_modifier2(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(wsgi_req->uh->modifier2);
|
||||
*buf = uwsgi_num2str(wsgi_req->uh.modifier2);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
@@ -1194,38 +1123,38 @@ void uwsgi_add_logchunk(int variable, int pos, char *ptr, size_t len) {
|
||||
logchunk->pos_len = offsetof(struct wsgi_request, protocol_len);
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "uagent", 6)) {
|
||||
logchunk->pos = offsetof(struct wsgi_request, user_agent);
|
||||
logchunk->pos_len = offsetof(struct wsgi_request, user_agent_len);
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "referer", 7)) {
|
||||
logchunk->pos = offsetof(struct wsgi_request, referer);
|
||||
logchunk->pos_len = offsetof(struct wsgi_request, referer_len);
|
||||
}
|
||||
logchunk->pos = offsetof(struct wsgi_request, user_agent);
|
||||
logchunk->pos_len = offsetof(struct wsgi_request, user_agent_len);
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "referer", 7)) {
|
||||
logchunk->pos = offsetof(struct wsgi_request, referer);
|
||||
logchunk->pos_len = offsetof(struct wsgi_request, referer_len);
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "status", 6)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_status;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "rsize", 5)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_rsize;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "hsize", 5)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_hsize;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "size", 4)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_size;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "cl", 2)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_cl;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_rsize;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "hsize", 5)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_hsize;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "size", 4)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_size;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "cl", 2)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_cl;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "micros", 6)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_micros;
|
||||
@@ -1242,10 +1171,10 @@ void uwsgi_add_logchunk(int variable, int pos, char *ptr, size_t len) {
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "ltime", 5)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_ltime;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_ltime;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "ctime", 5)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_ctime;
|
||||
@@ -1327,169 +1256,3 @@ void uwsgi_add_logchunk(int variable, int pos, char *ptr, size_t len) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int uwsgi_master_log(void) {
|
||||
|
||||
ssize_t rlen = read(uwsgi.shared->worker_log_pipe[0], uwsgi.log_master_buf, uwsgi.log_master_bufsize);
|
||||
if (rlen > 0) {
|
||||
#ifdef UWSGI_PCRE
|
||||
uwsgi_alarm_log_check(uwsgi.log_master_buf, rlen);
|
||||
struct uwsgi_regexp_list *url = uwsgi.log_drain_rules;
|
||||
while (url) {
|
||||
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, uwsgi.log_master_buf, rlen) >= 0) {
|
||||
return 0;
|
||||
}
|
||||
url = url->next;
|
||||
}
|
||||
if (uwsgi.log_filter_rules) {
|
||||
int show = 0;
|
||||
url = uwsgi.log_filter_rules;
|
||||
while (url) {
|
||||
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, uwsgi.log_master_buf, rlen) >= 0) {
|
||||
show = 1;
|
||||
break;
|
||||
}
|
||||
url = url->next;
|
||||
}
|
||||
if (!show)
|
||||
return 0;
|
||||
}
|
||||
|
||||
url = uwsgi.log_route;
|
||||
int finish = 0;
|
||||
while (url) {
|
||||
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, uwsgi.log_master_buf, rlen) >= 0) {
|
||||
struct uwsgi_logger *ul_route = (struct uwsgi_logger *) url->custom_ptr;
|
||||
if (ul_route) {
|
||||
ul_route->func(ul_route, uwsgi.log_master_buf, rlen);
|
||||
finish = 1;
|
||||
}
|
||||
}
|
||||
url = url->next;
|
||||
}
|
||||
if (finish)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
int raw_log = 1;
|
||||
|
||||
struct uwsgi_logger *ul = uwsgi.choosen_logger;
|
||||
while (ul) {
|
||||
// check for named logger
|
||||
if (ul->id) {
|
||||
goto next;
|
||||
}
|
||||
ul->func(ul, uwsgi.log_master_buf, rlen);
|
||||
raw_log = 0;
|
||||
next:
|
||||
ul = ul->next;
|
||||
}
|
||||
|
||||
if (raw_log) {
|
||||
rlen = write(uwsgi.original_log_fd, uwsgi.log_master_buf, rlen);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int uwsgi_master_req_log(void) {
|
||||
|
||||
ssize_t rlen = read(uwsgi.shared->worker_req_log_pipe[0], uwsgi.log_master_buf, uwsgi.log_master_bufsize);
|
||||
if (rlen > 0) {
|
||||
#ifdef UWSGI_PCRE
|
||||
struct uwsgi_regexp_list *url = uwsgi.log_req_route;
|
||||
int finish = 0;
|
||||
while (url) {
|
||||
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, uwsgi.log_master_buf, rlen) >= 0) {
|
||||
struct uwsgi_logger *ul_route = (struct uwsgi_logger *) url->custom_ptr;
|
||||
if (ul_route) {
|
||||
ul_route->func(ul_route, uwsgi.log_master_buf, rlen);
|
||||
finish = 1;
|
||||
}
|
||||
}
|
||||
url = url->next;
|
||||
}
|
||||
if (finish)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
int raw_log = 1;
|
||||
|
||||
struct uwsgi_logger *ul = uwsgi.choosen_req_logger;
|
||||
while (ul) {
|
||||
// check for named logger
|
||||
if (ul->id) {
|
||||
goto next;
|
||||
}
|
||||
ul->func(ul, uwsgi.log_master_buf, rlen);
|
||||
raw_log = 0;
|
||||
next:
|
||||
ul = ul->next;
|
||||
}
|
||||
|
||||
if (raw_log) {
|
||||
rlen = write(uwsgi.original_log_fd, uwsgi.log_master_buf, rlen);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void *logger_thread_loop(void *noarg) {
|
||||
struct pollfd logpoll[2];
|
||||
|
||||
// block all signals
|
||||
sigset_t smask;
|
||||
sigfillset(&smask);
|
||||
pthread_sigmask(SIG_BLOCK, &smask, NULL);
|
||||
|
||||
logpoll[0].events = POLLIN;
|
||||
logpoll[0].fd = uwsgi.shared->worker_log_pipe[0];
|
||||
|
||||
int logpolls = 1;
|
||||
|
||||
if (uwsgi.req_log_master) {
|
||||
logpoll[1].events = POLLIN;
|
||||
logpoll[1].fd = uwsgi.shared->worker_req_log_pipe[0];
|
||||
}
|
||||
|
||||
|
||||
for (;;) {
|
||||
int ret = poll(logpoll, logpolls, -1);
|
||||
if (ret > 0) {
|
||||
if (logpoll[0].revents & POLLIN) {
|
||||
pthread_mutex_lock(&uwsgi.threaded_logger_lock);
|
||||
uwsgi_master_log();
|
||||
pthread_mutex_unlock(&uwsgi.threaded_logger_lock);
|
||||
}
|
||||
else if (logpolls > 1 && logpoll[1].revents & POLLIN) {
|
||||
pthread_mutex_lock(&uwsgi.threaded_logger_lock);
|
||||
uwsgi_master_req_log();
|
||||
pthread_mutex_unlock(&uwsgi.threaded_logger_lock);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void uwsgi_threaded_logger_spawn() {
|
||||
pthread_t logger_thread;
|
||||
|
||||
if (pthread_create(&logger_thread, NULL, logger_thread_loop, NULL)) {
|
||||
uwsgi_error("pthread_create()");
|
||||
uwsgi_log("falling back to non-threaded logger...\n");
|
||||
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_log_pipe[0]);
|
||||
if (uwsgi.req_log_master) {
|
||||
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_req_log_pipe[0]);
|
||||
}
|
||||
uwsgi.threaded_logger = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -64,10 +64,12 @@ void simple_loop() {
|
||||
|
||||
void uwsgi_loop_cores_run(void *(*func) (void *)) {
|
||||
int i;
|
||||
#ifdef UWSGI_THREADING
|
||||
for (i = 1; i < uwsgi.threads; i++) {
|
||||
long j = i;
|
||||
pthread_create(&uwsgi.workers[uwsgi.mywid].cores[i].thread_id, &uwsgi.threads_attr, func, (void *) j);
|
||||
}
|
||||
#endif
|
||||
long y = 0;
|
||||
func((void *) y);
|
||||
}
|
||||
@@ -118,9 +120,12 @@ void *simple_loop_run(void *arg1) {
|
||||
|
||||
struct wsgi_request *wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[core_id].req;
|
||||
|
||||
#ifdef UWSGI_THREADING
|
||||
if (uwsgi.threads > 1) {
|
||||
uwsgi_setup_thread_req(core_id, wsgi_req);
|
||||
}
|
||||
#endif
|
||||
|
||||
// initialize the main event queue to monitor sockets
|
||||
int main_queue = event_queue_init();
|
||||
|
||||
@@ -141,7 +146,7 @@ void *simple_loop_run(void *arg1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (wsgi_req_recv(main_queue, wsgi_req)) {
|
||||
if (wsgi_req_recv(wsgi_req)) {
|
||||
uwsgi_destroy_request(wsgi_req);
|
||||
continue;
|
||||
}
|
||||
|
||||
+873
-157
File diff suppressed because it is too large
Load Diff
@@ -1,278 +0,0 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
// check if all of the workers are dead and exit uWSGI
|
||||
void uwsgi_master_check_death() {
|
||||
if (uwsgi_instance_is_dying) {
|
||||
int i;
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
if (uwsgi.workers[i].pid > 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
uwsgi_log("goodbye to uWSGI.\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
// check if all of the workers are dead, and trigger a reload
|
||||
int uwsgi_master_check_reload(char **argv) {
|
||||
if (uwsgi_instance_is_reloading) {
|
||||
int i;
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
if (uwsgi.workers[i].pid > 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
uwsgi_reload(argv);
|
||||
// never here (unless in shared library mode)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check for chain reload
|
||||
void uwsgi_master_check_chain() {
|
||||
if (!uwsgi.status.chain_reloading) return;
|
||||
if (uwsgi.status.chain_reloading > uwsgi.numproc) {
|
||||
uwsgi.status.chain_reloading = 0;
|
||||
uwsgi_log_verbose("chain reloading complete\n");
|
||||
}
|
||||
int i;
|
||||
uwsgi_block_signal(SIGHUP);
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].cursed_at == 0 && i == uwsgi.status.chain_reloading) {
|
||||
uwsgi_curse(i, SIGHUP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
uwsgi_unblock_signal(SIGHUP);
|
||||
}
|
||||
|
||||
|
||||
// special function for assuming all of the workers are dead
|
||||
void uwsgi_master_commit_status() {
|
||||
int i;
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
uwsgi.workers[i].pid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_master_check_idle() {
|
||||
|
||||
static time_t last_request_timecheck = 0;
|
||||
static uint64_t last_request_count = 0;
|
||||
int i;
|
||||
int waitpid_status;
|
||||
|
||||
if (!uwsgi.idle || uwsgi.status.is_cheap)
|
||||
return;
|
||||
|
||||
uwsgi.current_time = uwsgi_now();
|
||||
if (!last_request_timecheck)
|
||||
last_request_timecheck = uwsgi.current_time;
|
||||
|
||||
// security check, stop the check if there are busy workers
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
|
||||
if (uwsgi_worker_is_busy(i)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (last_request_count != uwsgi.workers[0].requests) {
|
||||
last_request_timecheck = uwsgi.current_time;
|
||||
last_request_count = uwsgi.workers[0].requests;
|
||||
}
|
||||
// a bit of over-engeneering to avoid clock skews
|
||||
else if (last_request_timecheck < uwsgi.current_time && (uwsgi.current_time - last_request_timecheck > uwsgi.idle)) {
|
||||
uwsgi_log("workers have been inactive for more than %d seconds (%llu-%llu)\n", uwsgi.idle, (unsigned long long) uwsgi.current_time, (unsigned long long) last_request_timecheck);
|
||||
uwsgi.status.is_cheap = 1;
|
||||
if (uwsgi.die_on_idle) {
|
||||
if (uwsgi.has_emperor) {
|
||||
char byte = 22;
|
||||
if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
|
||||
uwsgi_error("write()");
|
||||
kill_them_all(0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
kill_them_all(0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
uwsgi.workers[i].cheaped = 1;
|
||||
if (uwsgi.workers[i].pid == 0)
|
||||
continue;
|
||||
kill(uwsgi.workers[i].pid, SIGKILL);
|
||||
if (waitpid(uwsgi.workers[i].pid, &waitpid_status, 0) < 0) {
|
||||
if (errno != ECHILD)
|
||||
uwsgi_error("uwsgi_master_check_idle()/waitpid()");
|
||||
}
|
||||
}
|
||||
uwsgi_add_sockets_to_queue(uwsgi.master_queue, -1);
|
||||
uwsgi_log("cheap mode enabled: waiting for socket connection...\n");
|
||||
last_request_timecheck = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_master_check_workers_deadline() {
|
||||
int i;
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
/* first check for harakiri */
|
||||
if (uwsgi.workers[i].harakiri > 0) {
|
||||
if (uwsgi.workers[i].harakiri < (time_t) uwsgi.current_time) {
|
||||
trigger_harakiri(i);
|
||||
}
|
||||
}
|
||||
/* then user-defined harakiri */
|
||||
if (uwsgi.workers[i].user_harakiri > 0) {
|
||||
if (uwsgi.workers[i].user_harakiri < (time_t) uwsgi.current_time) {
|
||||
trigger_harakiri(i);
|
||||
}
|
||||
}
|
||||
// then for evil memory checkers
|
||||
if (uwsgi.evil_reload_on_as) {
|
||||
if ((rlim_t) uwsgi.workers[i].vsz_size >= uwsgi.evil_reload_on_as) {
|
||||
uwsgi_log("*** EVIL RELOAD ON WORKER %d ADDRESS SPACE: %lld (pid: %d) ***\n", i, (long long) uwsgi.workers[i].vsz_size, uwsgi.workers[i].pid);
|
||||
kill(uwsgi.workers[i].pid, SIGKILL);
|
||||
uwsgi.workers[i].vsz_size = 0;
|
||||
}
|
||||
}
|
||||
if (uwsgi.evil_reload_on_rss) {
|
||||
if ((rlim_t) uwsgi.workers[i].rss_size >= uwsgi.evil_reload_on_rss) {
|
||||
uwsgi_log("*** EVIL RELOAD ON WORKER %d RSS: %lld (pid: %d) ***\n", i, (long long) uwsgi.workers[i].rss_size, uwsgi.workers[i].pid);
|
||||
kill(uwsgi.workers[i].pid, SIGKILL);
|
||||
uwsgi.workers[i].rss_size = 0;
|
||||
}
|
||||
}
|
||||
// check if worker was running longer than allowed lifetime
|
||||
if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cheaped == 0 && uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME] > 0) {
|
||||
uint64_t lifetime = uwsgi_now() - uwsgi.workers[i].last_spawn;
|
||||
if (lifetime > uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME] && uwsgi.workers[i].manage_next_request == 1) {
|
||||
uwsgi_log("worker %d lifetime reached, it was running for %llu second(s)\n", i, (unsigned long long) lifetime);
|
||||
uwsgi.workers[i].manage_next_request = 0;
|
||||
kill(uwsgi.workers[i].pid, SIGWINCH);
|
||||
}
|
||||
}
|
||||
|
||||
// need to find a better way
|
||||
//uwsgi.workers[i].last_running_time = uwsgi.workers[i].running_time;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_master_check_gateways_deadline() {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ushared->gateways_cnt; i++) {
|
||||
if (ushared->gateways_harakiri[i] > 0) {
|
||||
if (ushared->gateways_harakiri[i] < (time_t) uwsgi.current_time) {
|
||||
if (ushared->gateways[i].pid > 0) {
|
||||
kill(ushared->gateways[i].pid, SIGKILL);
|
||||
}
|
||||
ushared->gateways_harakiri[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_master_check_mules_deadline() {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
if (uwsgi.mules[i].harakiri > 0) {
|
||||
if (uwsgi.mules[i].harakiri < (time_t) uwsgi.current_time) {
|
||||
uwsgi_log("*** HARAKIRI ON MULE %d HANDLING SIGNAL %d (pid: %d) ***\n", i + 1, uwsgi.mules[i].signum, uwsgi.mules[i].pid);
|
||||
kill(uwsgi.mules[i].pid, SIGKILL);
|
||||
uwsgi.mules[i].harakiri = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_master_check_spoolers_deadline() {
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
while (uspool) {
|
||||
if (uspool->harakiri > 0 && uspool->harakiri < (time_t) uwsgi.current_time) {
|
||||
uwsgi_log("*** HARAKIRI ON THE SPOOLER (pid: %d) ***\n", uspool->pid);
|
||||
kill(uspool->pid, SIGKILL);
|
||||
uspool->harakiri = 0;
|
||||
}
|
||||
uspool = uspool->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_master_check_spoolers_death(int diedpid) {
|
||||
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
while (uspool) {
|
||||
if (uspool->pid > 0 && diedpid == uspool->pid) {
|
||||
uwsgi_log("OOOPS the spooler is no more...trying respawn...\n");
|
||||
uspool->respawned++;
|
||||
uspool->pid = spooler_start(uspool);
|
||||
return -1;
|
||||
}
|
||||
uspool = uspool->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_master_check_emperor_death(int diedpid) {
|
||||
if (uwsgi.emperor_pid >= 0 && diedpid == uwsgi.emperor_pid) {
|
||||
uwsgi_log_verbose("!!! Emperor died !!!\n");
|
||||
uwsgi_emperor_start();
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_master_check_mules_death(int diedpid) {
|
||||
int i;
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
if (uwsgi.mules[i].pid == diedpid) {
|
||||
uwsgi_log("OOOPS mule %d (pid: %d) crippled...trying respawn...\n", i + 1, uwsgi.mules[i].pid);
|
||||
uwsgi_mule(i + 1);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_master_check_gateways_death(int diedpid) {
|
||||
int i;
|
||||
for (i = 0; i < ushared->gateways_cnt; i++) {
|
||||
if (ushared->gateways[i].pid == diedpid) {
|
||||
gateway_respawn(i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_master_check_daemons_death(int diedpid) {
|
||||
/* reload the daemons */
|
||||
if (uwsgi_daemon_check_pid_reload(diedpid)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_worker_is_busy(int wid) {
|
||||
int i;
|
||||
for(i=0;i<uwsgi.cores;i++) {
|
||||
if (uwsgi.workers[wid].cores[i].in_request) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_master_manage_events(int interesting_fd) {
|
||||
|
||||
// is a logline ?
|
||||
if (uwsgi.log_master && !uwsgi.threaded_logger) {
|
||||
// stderr log ?
|
||||
if (interesting_fd == uwsgi.shared->worker_log_pipe[0]) {
|
||||
uwsgi_master_log();
|
||||
return 0;
|
||||
}
|
||||
// req log ?
|
||||
if (uwsgi.req_log_master && interesting_fd == uwsgi.shared->worker_req_log_pipe[0]) {
|
||||
uwsgi_master_req_log();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// stats server ?
|
||||
if (uwsgi.stats && uwsgi.stats_fd > -1) {
|
||||
if (interesting_fd == uwsgi.stats_fd) {
|
||||
uwsgi_send_stats(uwsgi.stats_fd, uwsgi_master_generate_stats);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// a zerg connection ?
|
||||
if (uwsgi.zerg_server) {
|
||||
if (interesting_fd == uwsgi.zerg_server_fd) {
|
||||
uwsgi_manage_zerg(uwsgi.zerg_server_fd, 0, NULL);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// emperor event ?
|
||||
if (uwsgi.has_emperor) {
|
||||
if (interesting_fd == uwsgi.emperor_fd) {
|
||||
uwsgi_master_manage_emperor();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// wakeup from cheap mode ?
|
||||
if (uwsgi.status.is_cheap) {
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
while (uwsgi_sock) {
|
||||
if (interesting_fd == uwsgi_sock->fd) {
|
||||
uwsgi.status.is_cheap = 0;
|
||||
uwsgi_del_sockets_from_queue(uwsgi.master_queue);
|
||||
// how many worker we need to respawn ?
|
||||
int needed = uwsgi.numproc;
|
||||
// if in cheaper mode, just respawn the minimal amount
|
||||
if (uwsgi.cheaper) {
|
||||
needed = uwsgi.cheaper_count;
|
||||
}
|
||||
int i;
|
||||
for (i = 1; i <= needed; i++) {
|
||||
if (uwsgi_respawn_worker(i))
|
||||
return -1;
|
||||
}
|
||||
// here we continue instead of returning
|
||||
break;
|
||||
}
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// an SNMP request ?
|
||||
if (uwsgi.snmp_addr && interesting_fd == uwsgi.snmp_fd) {
|
||||
uwsgi_master_manage_snmp(uwsgi.snmp_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// a UDP request ?
|
||||
if (uwsgi.udp_socket && interesting_fd == uwsgi.udp_fd) {
|
||||
uwsgi_master_manage_udp(uwsgi.udp_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// check if some file monitor is ready
|
||||
// no need to lock as we are only getting registered items (and only the master can register them)
|
||||
int i;
|
||||
for (i = 0; i < ushared->files_monitored_cnt; i++) {
|
||||
if (ushared->files_monitored[i].registered) {
|
||||
if (interesting_fd == ushared->files_monitored[i].fd) {
|
||||
struct uwsgi_fmon *uf = event_queue_ack_file_monitor(uwsgi.master_queue, interesting_fd);
|
||||
// now call the file_monitor handler
|
||||
if (uf)
|
||||
uwsgi_route_signal(uf->sig);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if some timer elapsed
|
||||
// no need to lock again
|
||||
for (i = 0; i < ushared->timers_cnt; i++) {
|
||||
if (ushared->timers[i].registered) {
|
||||
if (interesting_fd == ushared->timers[i].fd) {
|
||||
struct uwsgi_timer *ut = event_queue_ack_timer(interesting_fd);
|
||||
// now call the timer handler
|
||||
if (ut)
|
||||
uwsgi_route_signal(ut->sig);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t uwsgi_signal;
|
||||
// check for worker signal
|
||||
if (interesting_fd == uwsgi.shared->worker_signal_pipe[0]) {
|
||||
ssize_t rlen = read(interesting_fd, &uwsgi_signal, 1);
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("uwsgi_master_manage_events()/read()");
|
||||
}
|
||||
else if (rlen > 0) {
|
||||
uwsgi_route_signal(uwsgi_signal);
|
||||
}
|
||||
else {
|
||||
// TODO restart workers here
|
||||
uwsgi_log_verbose("lost connection with workers !!!\n");
|
||||
close(interesting_fd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check for spooler signal
|
||||
if (uwsgi.spoolers) {
|
||||
if (interesting_fd == uwsgi.shared->spooler_signal_pipe[0]) {
|
||||
ssize_t rlen = read(interesting_fd, &uwsgi_signal, 1);
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("uwsgi_master_manage_events()/read()");
|
||||
}
|
||||
else if (rlen > 0) {
|
||||
uwsgi_route_signal(uwsgi_signal);
|
||||
}
|
||||
else {
|
||||
// TODO restart spoolers here
|
||||
uwsgi_log_verbose("lost connection with spoolers\n");
|
||||
close(interesting_fd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// check for mules signal
|
||||
if (uwsgi.mules_cnt > 0) {
|
||||
if (interesting_fd == uwsgi.shared->mule_signal_pipe[0]) {
|
||||
ssize_t rlen = read(interesting_fd, &uwsgi_signal, 1);
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("uwsgi_master_manage_events()/read()");
|
||||
}
|
||||
else if (rlen > 0) {
|
||||
uwsgi_route_signal(uwsgi_signal);
|
||||
}
|
||||
else {
|
||||
// TODO respawn mules here
|
||||
uwsgi_log_verbose("lost connection with mules\n");
|
||||
close(interesting_fd);
|
||||
}
|
||||
// return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
+66
-325
@@ -5,82 +5,15 @@ extern struct uwsgi_server uwsgi;
|
||||
void worker_wakeup() {
|
||||
}
|
||||
|
||||
uint64_t uwsgi_worker_exceptions(int wid) {
|
||||
uint64_t total = 0;
|
||||
int i;
|
||||
for(i=0;i<uwsgi.cores;i++) {
|
||||
total += uwsgi.workers[wid].cores[i].exceptions;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
void uwsgi_curse(int wid, int sig) {
|
||||
uwsgi.workers[wid].cursed_at = uwsgi_now();
|
||||
uwsgi.workers[wid].no_mercy_at = uwsgi.workers[wid].cursed_at + uwsgi.worker_reload_mercy;
|
||||
|
||||
if (sig) {
|
||||
(void) kill(uwsgi.workers[wid].pid, sig);
|
||||
}
|
||||
}
|
||||
|
||||
static void uwsgi_signal_spoolers(int signum) {
|
||||
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
while (uspool) {
|
||||
if (uspool->pid > 0) {
|
||||
kill(uspool->pid, signum);
|
||||
uwsgi_log("killing the spooler with pid %d\n", uspool->pid);
|
||||
}
|
||||
uspool = uspool->next;
|
||||
}
|
||||
|
||||
}
|
||||
void uwsgi_destroy_processes() {
|
||||
|
||||
int i;
|
||||
int waitpid_status;
|
||||
|
||||
uwsgi_signal_spoolers(SIGKILL);
|
||||
|
||||
if (uwsgi.emperor_pid >= 0) {
|
||||
kill(uwsgi.emperor_pid, SIGKILL);
|
||||
waitpid(uwsgi.emperor_pid, &waitpid_status, 0);
|
||||
uwsgi_log("The Emperor has been buried (pid: %d)\n", (int) uwsgi.emperor_pid);
|
||||
}
|
||||
|
||||
|
||||
uwsgi_detach_daemons();
|
||||
|
||||
for (i = 0; i < ushared->gateways_cnt; i++) {
|
||||
if (ushared->gateways[i].pid > 0) {
|
||||
kill(ushared->gateways[i].pid, SIGKILL);
|
||||
waitpid(ushared->gateways[i].pid, &waitpid_status, 0);
|
||||
uwsgi_log("gateway \"%s %d\" has been buried (pid: %d)\n", ushared->gateways[i].name, ushared->gateways[i].num, (int) ushared->gateways[i].pid);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO mules can be programmed to be gracefully reloaded
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
if (uwsgi.mules[i].pid > 0) {
|
||||
kill(uwsgi.mules[i].pid, SIGKILL);
|
||||
waitpid(uwsgi.mules[i].pid, &waitpid_status, 0);
|
||||
uwsgi_log("mule %d has been buried (pid: %d)\n", i, (int) uwsgi.mules[i].pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void uwsgi_master_cleanup_hooks(void) {
|
||||
|
||||
int j;
|
||||
|
||||
// could be an inherited atexit hook
|
||||
if (uwsgi.mypid != uwsgi.workers[0].pid)
|
||||
if (uwsgi.mywid > 0)
|
||||
return;
|
||||
|
||||
uwsgi.status.is_cleaning = 1;
|
||||
uwsgi.cleaning = 1;
|
||||
|
||||
for (j = 0; j < uwsgi.gp_cnt; j++) {
|
||||
if (uwsgi.gp[j]->master_cleanup) {
|
||||
@@ -145,7 +78,8 @@ int uwsgi_calc_cheaper(void) {
|
||||
#endif
|
||||
uwsgi.workers[oldest_worker].cheaped = 1;
|
||||
uwsgi.workers[oldest_worker].manage_next_request = 0;
|
||||
uwsgi_curse(oldest_worker, SIGWINCH);
|
||||
// wakeup task in case of wait
|
||||
(void) kill(uwsgi.workers[oldest_worker].pid, SIGWINCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,7 +131,7 @@ int uwsgi_cheaper_algo_spare(void) {
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
|
||||
// if a non-busy worker is found, the overload_count is decremented and stop the cycle
|
||||
if (uwsgi_worker_is_busy(i) == 0) {
|
||||
if (uwsgi.workers[i].busy == 0) {
|
||||
if (overload_count > 0)
|
||||
overload_count--;
|
||||
goto healthy;
|
||||
@@ -240,7 +174,7 @@ healthy:
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
|
||||
active_workers++;
|
||||
if (uwsgi_worker_is_busy(i) == 1)
|
||||
if (uwsgi.workers[i].busy == 1)
|
||||
busy_workers++;
|
||||
}
|
||||
}
|
||||
@@ -373,44 +307,43 @@ void uwsgi_reload(char **argv) {
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
if (found) continue;
|
||||
|
||||
if (uwsgi.has_emperor) {
|
||||
if (i == uwsgi.emperor_fd) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == uwsgi.emperor_fd_config) {
|
||||
continue;
|
||||
if (!found) {
|
||||
if (uwsgi.has_emperor) {
|
||||
if (i == uwsgi.emperor_fd) {
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.log_master) {
|
||||
if (uwsgi.original_log_fd > -1) {
|
||||
if (i == uwsgi.original_log_fd) {
|
||||
continue;
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.shared->worker_log_pipe[0] > -1) {
|
||||
if (i == uwsgi.shared->worker_log_pipe[0]) {
|
||||
continue;
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.shared->worker_log_pipe[1] > -1) {
|
||||
if (i == uwsgi.shared->worker_log_pipe[1]) {
|
||||
continue;
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
#ifdef __APPLE__
|
||||
fcntl(i, F_SETFD, FD_CLOEXEC);
|
||||
fcntl(i, F_SETFD, FD_CLOEXEC);
|
||||
#else
|
||||
close(i);
|
||||
close(i);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UWSGI_AS_SHARED_LIBRARY
|
||||
@@ -440,10 +373,44 @@ void uwsgi_reload(char **argv) {
|
||||
|
||||
}
|
||||
|
||||
void master_check_cluster_nodes() {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
struct uwsgi_cluster_node *ucn = &uwsgi.shared->nodes[i];
|
||||
|
||||
if (ucn->name[0] != 0 && ucn->type == CLUSTER_NODE_STATIC && ucn->status == UWSGI_NODE_FAILED) {
|
||||
// should i retry ?
|
||||
if (uwsgi.master_cycles % ucn->errors == 0) {
|
||||
if (!uwsgi_ping_node(i, uwsgi.wsgi_req)) {
|
||||
ucn->status = UWSGI_NODE_OK;
|
||||
uwsgi_log("re-enabled cluster node %d/%s\n", i, ucn->name);
|
||||
}
|
||||
else {
|
||||
ucn->errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ucn->name[0] != 0 && ucn->type == CLUSTER_NODE_DYNAMIC) {
|
||||
// if the last_seen attr is higher than 30 secs ago, mark the node as dead
|
||||
if ((uwsgi.current_time - ucn->last_seen) > 30) {
|
||||
uwsgi_log_verbose("no presence announce in the last 30 seconds by node %s, i assume it is dead.\n", ucn->name);
|
||||
ucn->name[0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_fixup_fds(int wid, int muleid, struct uwsgi_gateway *ug) {
|
||||
|
||||
int i;
|
||||
|
||||
// close the cache server
|
||||
if (uwsgi.cache_server_fd != -1) {
|
||||
close(uwsgi.cache_server_fd);
|
||||
}
|
||||
|
||||
if (uwsgi.master_process) {
|
||||
if (uwsgi.master_queue > -1)
|
||||
close(uwsgi.master_queue);
|
||||
@@ -476,13 +443,14 @@ void uwsgi_fixup_fds(int wid, int muleid, struct uwsgi_gateway *ug) {
|
||||
close(uwsgi.workers[i].signal_pipe[1]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UWSGI_SPOOLER
|
||||
if (uwsgi.i_am_a_spooler && uwsgi.i_am_a_spooler->pid != getpid()) {
|
||||
if (uwsgi.shared->spooler_signal_pipe[0] != -1)
|
||||
close(uwsgi.shared->spooler_signal_pipe[0]);
|
||||
if (uwsgi.shared->spooler_signal_pipe[1] != -1)
|
||||
close(uwsgi.shared->spooler_signal_pipe[1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (uwsgi.shared->mule_signal_pipe[0] != -1)
|
||||
close(uwsgi.shared->mule_signal_pipe[0]);
|
||||
@@ -535,13 +503,11 @@ int uwsgi_respawn_worker(int wid) {
|
||||
uwsgi.workers[wid].pending_harakiri = 0;
|
||||
uwsgi.workers[wid].rss_size = 0;
|
||||
uwsgi.workers[wid].vsz_size = 0;
|
||||
// ... reset stopped_at
|
||||
uwsgi.workers[wid].cursed_at = 0;
|
||||
uwsgi.workers[wid].no_mercy_at = 0;
|
||||
|
||||
// internal statuses should be reset too
|
||||
|
||||
uwsgi.workers[wid].cheaped = 0;
|
||||
uwsgi.workers[wid].busy = 0;
|
||||
// SUSPENSION is managed by the user, not the master...
|
||||
//uwsgi.workers[wid].suspended = 0;
|
||||
uwsgi.workers[wid].sig = 0;
|
||||
@@ -582,6 +548,7 @@ int uwsgi_respawn_worker(int wid) {
|
||||
uwsgi.workers[uwsgi.mywid].manage_next_request = 1;
|
||||
/*
|
||||
uwsgi.workers[uwsgi.mywid].cheaped = 0;
|
||||
uwsgi.workers[uwsgi.mywid].busy = 0;
|
||||
uwsgi.workers[uwsgi.mywid].suspended = 0;
|
||||
uwsgi.workers[uwsgi.mywid].sig = 0;
|
||||
*/
|
||||
@@ -590,17 +557,16 @@ int uwsgi_respawn_worker(int wid) {
|
||||
uwsgi.workers[uwsgi.mywid].apps_cnt = uwsgi.workers[0].apps_cnt;
|
||||
|
||||
// reset wsgi_request structures
|
||||
for(i=0;i<uwsgi.cores;i++) {
|
||||
uwsgi.workers[uwsgi.mywid].cores[i].in_request = 0;
|
||||
memset(&uwsgi.workers[uwsgi.mywid].cores[i].req, 0, sizeof(struct wsgi_request));
|
||||
}
|
||||
for(i=0;i<uwsgi.cores;i++) {
|
||||
memset(&uwsgi.workers[uwsgi.mywid].cores[i].req, 0, sizeof(struct wsgi_request));
|
||||
}
|
||||
|
||||
uwsgi_fixup_fds(wid, 0, NULL);
|
||||
|
||||
uwsgi.my_signal_socket = uwsgi.workers[wid].signal_pipe[1];
|
||||
|
||||
if (uwsgi.master_process) {
|
||||
if ((uwsgi.workers[uwsgi.mywid].respawn_count || uwsgi.status.is_cheap)) {
|
||||
if ((uwsgi.workers[uwsgi.mywid].respawn_count || uwsgi.cheap)) {
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->master_fixup) {
|
||||
uwsgi.p[i]->master_fixup(1);
|
||||
@@ -755,7 +721,7 @@ void uwsgi_manage_command_cron(time_t now) {
|
||||
}
|
||||
}
|
||||
if (current_cron->month < 0) {
|
||||
if ((uwsgi_cron_delta->tm_mon % abs(current_cron->month)) == 0) {
|
||||
if ((uwsgi_cron_delta->tm_hour % abs(current_cron->month)) == 0) {
|
||||
uc_month = uwsgi_cron_delta->tm_mon;
|
||||
}
|
||||
}
|
||||
@@ -901,66 +867,6 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
if (uwsgi_stats_comma(us))
|
||||
goto end;
|
||||
|
||||
if (uwsgi.caches) {
|
||||
|
||||
|
||||
if (uwsgi_stats_key(us, "caches"))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_list_open(us)) goto end;
|
||||
|
||||
struct uwsgi_cache *uc = uwsgi.caches;
|
||||
while(uc) {
|
||||
if (uwsgi_stats_object_open(us))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keyval_comma(us, "name", uc->name ? uc->name : "default"))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keyval_comma(us, "hash", uc->hash->name))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "hashsize", (unsigned long long) uc->hashsize))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "keysize", (unsigned long long) uc->keysize))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "max_items", (unsigned long long) uc->max_items))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "blocks", (unsigned long long) uc->blocks))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "blocksize", (unsigned long long) uc->blocksize))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "items", (unsigned long long) uc->n_items))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "hits", (unsigned long long) uc->hits))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "miss", (unsigned long long) uc->miss))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong(us, "full", (unsigned long long) uc->full))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_object_close(us))
|
||||
goto end;
|
||||
|
||||
if (uc->next) {
|
||||
if (uwsgi_stats_comma(us))
|
||||
goto end;
|
||||
}
|
||||
uc = uc->next;
|
||||
}
|
||||
|
||||
if (uwsgi_stats_comma(us))
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (uwsgi_stats_key(us, "sockets"))
|
||||
goto end;
|
||||
|
||||
@@ -1020,7 +926,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
goto end;
|
||||
if (uwsgi_stats_keylong_comma(us, "delta_requests", (unsigned long long) uwsgi.workers[i + 1].delta_requests))
|
||||
goto end;
|
||||
if (uwsgi_stats_keylong_comma(us, "exceptions", (unsigned long long) uwsgi_worker_exceptions(i + 1)))
|
||||
if (uwsgi_stats_keylong_comma(us, "exceptions", (unsigned long long) uwsgi.workers[i + 1].exceptions))
|
||||
goto end;
|
||||
if (uwsgi_stats_keylong_comma(us, "harakiri_count", (unsigned long long) uwsgi.workers[i + 1].harakiri_count))
|
||||
goto end;
|
||||
@@ -1038,7 +944,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
if (uwsgi_stats_keyval_comma(us, "status", "cheap"))
|
||||
goto end;
|
||||
}
|
||||
else if (uwsgi.workers[i + 1].suspended && !uwsgi_worker_is_busy(i+1)) {
|
||||
else if (uwsgi.workers[i + 1].suspended && !uwsgi.workers[i + 1].busy) {
|
||||
if (uwsgi_stats_keyval_comma(us, "status", "pause"))
|
||||
goto end;
|
||||
}
|
||||
@@ -1047,7 +953,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
if (uwsgi_stats_keyvalnum_comma(us, "status", "sig", (unsigned long long) uwsgi.workers[i + 1].signum))
|
||||
goto end;
|
||||
}
|
||||
else if (uwsgi_worker_is_busy(i+1)) {
|
||||
else if (uwsgi.workers[i + 1].busy) {
|
||||
if (uwsgi_stats_keyval_comma(us, "status", "busy"))
|
||||
goto end;
|
||||
}
|
||||
@@ -1152,21 +1058,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
if (uwsgi_stats_keylong_comma(us, "offloaded_requests", (unsigned long long) uc->offloaded_requests))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "write_errors", (unsigned long long) uc->write_errors))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "in_request", (unsigned long long) uc->in_request))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_key(us, "vars"))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_list_open(us))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_dump_vars(us, uc)) goto end;
|
||||
|
||||
if (uwsgi_stats_list_close(us))
|
||||
if (uwsgi_stats_keylong(us, "in_request", (unsigned long long) uc->in_request))
|
||||
goto end;
|
||||
|
||||
|
||||
@@ -1194,6 +1086,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
if (uwsgi_stats_list_close(us))
|
||||
goto end;
|
||||
|
||||
#ifdef UWSGI_SPOOLER
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
if (uspool) {
|
||||
if (uwsgi_stats_comma(us))
|
||||
@@ -1232,147 +1125,12 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
if (uwsgi_stats_list_close(us))
|
||||
goto end;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
struct uwsgi_legion *legion = NULL;
|
||||
if (uwsgi.legions) {
|
||||
|
||||
if (uwsgi_stats_comma(us))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_key(us, "legions"))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_list_open(us))
|
||||
goto end;
|
||||
|
||||
legion = uwsgi.legions;
|
||||
while (legion) {
|
||||
if (uwsgi_stats_object_open(us))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keyval_comma(us, "legion", legion->legion))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keyval_comma(us, "addr", legion->addr))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keyval_comma(us, "uuid", legion->uuid))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "valor", (unsigned long long) legion->valor))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "checksum", (unsigned long long) legion->checksum))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "quorum", (unsigned long long) legion->quorum))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "i_am_the_lord", (unsigned long long) legion->i_am_the_lord))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "lord_valor", (unsigned long long) legion->lord_valor))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keyvaln_comma(us, "lord_uuid", legion->lord_uuid, 36))
|
||||
goto end;
|
||||
|
||||
// legion nodes start
|
||||
if (uwsgi_stats_key(us, "nodes"))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_list_open(us))
|
||||
goto end;
|
||||
|
||||
struct uwsgi_string_list *nodes = legion->nodes;
|
||||
while (nodes) {
|
||||
|
||||
if (uwsgi_stats_str(us, nodes->value))
|
||||
goto end;
|
||||
|
||||
nodes = nodes->next;
|
||||
if (nodes) {
|
||||
if (uwsgi_stats_comma(us))
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi_stats_list_close(us))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_comma(us))
|
||||
goto end;
|
||||
|
||||
|
||||
// legion members start
|
||||
if (uwsgi_stats_key(us, "members"))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_list_open(us))
|
||||
goto end;
|
||||
|
||||
uwsgi_rlock(legion->lock);
|
||||
struct uwsgi_legion_node *node = legion->nodes_head;
|
||||
while (node) {
|
||||
if (uwsgi_stats_object_open(us))
|
||||
goto unlock_legion_mutex;
|
||||
|
||||
if (uwsgi_stats_keyvaln_comma(us, "name", node->name, node->name_len))
|
||||
goto unlock_legion_mutex;
|
||||
|
||||
if (uwsgi_stats_keyval_comma(us, "uuid", node->uuid))
|
||||
goto unlock_legion_mutex;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "valor", (unsigned long long) node->valor))
|
||||
goto unlock_legion_mutex;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "checksum", (unsigned long long) node->checksum))
|
||||
goto unlock_legion_mutex;
|
||||
|
||||
if (uwsgi_stats_keylong(us, "last_seen", (unsigned long long) node->last_seen))
|
||||
goto unlock_legion_mutex;
|
||||
|
||||
if (uwsgi_stats_object_close(us))
|
||||
goto unlock_legion_mutex;
|
||||
|
||||
node = node->next;
|
||||
if (node) {
|
||||
if (uwsgi_stats_comma(us))
|
||||
goto unlock_legion_mutex;
|
||||
}
|
||||
}
|
||||
uwsgi_rwunlock(legion->lock);
|
||||
|
||||
if (uwsgi_stats_list_close(us))
|
||||
goto end;
|
||||
// legion nodes end
|
||||
|
||||
if (uwsgi_stats_object_close(us))
|
||||
goto end;
|
||||
|
||||
legion = legion->next;
|
||||
if (legion) {
|
||||
if (uwsgi_stats_comma(us))
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi_stats_list_close(us))
|
||||
goto end;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
if (uwsgi_stats_object_close(us))
|
||||
goto end;
|
||||
|
||||
return us;
|
||||
#ifdef UWSGI_SSL
|
||||
unlock_legion_mutex:
|
||||
if (legion)
|
||||
uwsgi_rwunlock(legion->lock);
|
||||
#endif
|
||||
end:
|
||||
free(us->base);
|
||||
free(us);
|
||||
@@ -1469,20 +1227,3 @@ void trigger_harakiri(int i) {
|
||||
// to avoid races
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_master_fix_request_counters() {
|
||||
int i;
|
||||
uint64_t total_counter = 0;
|
||||
for (i = 1; i <= uwsgi.numproc;i++) {
|
||||
uint64_t tmp_counter = 0;
|
||||
int j;
|
||||
for(j=0;j<uwsgi.cores;j++) {
|
||||
tmp_counter += uwsgi.workers[i].cores[j].requests;
|
||||
}
|
||||
uwsgi.workers[i].requests = tmp_counter;
|
||||
total_counter += tmp_counter;
|
||||
}
|
||||
|
||||
uwsgi.workers[0].requests = total_counter;
|
||||
}
|
||||
|
||||
|
||||
+2
-4
@@ -56,7 +56,6 @@ void uwsgi_mule(int id) {
|
||||
// avoid race conditions
|
||||
uwsgi.mules[id - 1].id = id;
|
||||
uwsgi.mules[id - 1].pid = getpid();
|
||||
uwsgi.mypid = uwsgi.mules[id - 1].pid;
|
||||
|
||||
uwsgi_fixup_fds(0, id, NULL);
|
||||
|
||||
@@ -82,7 +81,7 @@ void uwsgi_mule(int id) {
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->mule) {
|
||||
if (uwsgi.p[i]->mule(uwsgi.mules[id - 1].patch) == 1) {
|
||||
// never here ?
|
||||
// never here
|
||||
end_me(1);
|
||||
}
|
||||
}
|
||||
@@ -210,7 +209,7 @@ void uwsgi_mule_handler() {
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
uwsgi_log("*** mule %d received a %ld bytes message ***\n", uwsgi.muleid, (long) len);
|
||||
uwsgi_log("*** mule %d received a %d bytes message ***\n", uwsgi.muleid, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -437,7 +436,6 @@ void uwsgi_setup_mules_and_farms() {
|
||||
mules_list++;
|
||||
|
||||
strncpy(uwsgi.farms[i].name, farm_value, 0xff);
|
||||
free(farm_value);
|
||||
|
||||
// create the socket pipe
|
||||
create_signal_pipe(uwsgi.farms[i].signal_pipe);
|
||||
|
||||
+3
-6
@@ -20,9 +20,7 @@ void uwsgi_systemd_notify(char *message) {
|
||||
|
||||
msghdr->msg_iovlen = 3;
|
||||
|
||||
if (sendmsg(uwsgi.notification_fd, msghdr, 0) < 0) {
|
||||
uwsgi_error("sendmsg()");
|
||||
}
|
||||
sendmsg(uwsgi.notification_fd, msghdr, 0);
|
||||
}
|
||||
|
||||
void uwsgi_systemd_notify_ready(void) {
|
||||
@@ -35,9 +33,8 @@ void uwsgi_systemd_notify_ready(void) {
|
||||
|
||||
msghdr->msg_iovlen = 1;
|
||||
|
||||
if (sendmsg(uwsgi.notification_fd, msghdr, 0) < 0) {
|
||||
uwsgi_error("sendmsg()");
|
||||
}
|
||||
sendmsg(uwsgi.notification_fd, msghdr, 0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
+73
-193
@@ -4,17 +4,6 @@
|
||||
|
||||
uWSGI offloading subsystem
|
||||
|
||||
steps to offload a task
|
||||
|
||||
1) allocate a uwsgi_offload_request structure (could be on stack)
|
||||
struct uwsgi_offload_request uor;
|
||||
2) prepare it for a specific engine (last argument is the takeover flag)
|
||||
uwsgi_offload_setup(my_engine, &uor, 1)
|
||||
3) run it (last argument is the waiter)
|
||||
int uwsgi_offload_run(wsgi_req, &uor, NULL);
|
||||
|
||||
between 2 and 3 you can set specific values
|
||||
|
||||
*/
|
||||
|
||||
|
||||
@@ -24,20 +13,19 @@ extern struct uwsgi_server uwsgi;
|
||||
#define uwsgi_offload_0r_1w(x, y) if (event_queue_del_fd(ut->queue, x, event_queue_read())) return -1;\
|
||||
if (event_queue_fd_read_to_write(ut->queue, y)) return -1;
|
||||
|
||||
void uwsgi_offload_setup(struct uwsgi_offload_engine *uoe, struct uwsgi_offload_request *uor, struct wsgi_request *wsgi_req, uint8_t takeover) {
|
||||
static int uwsgi_offload_net_transfer(struct uwsgi_thread *, struct uwsgi_offload_request *, int);
|
||||
static int uwsgi_offload_sendfile_transfer(struct uwsgi_thread *, struct uwsgi_offload_request *, int);
|
||||
|
||||
static void uwsgi_offload_setup(struct uwsgi_offload_request *uor, struct wsgi_request *wsgi_req,
|
||||
int (*func)(struct uwsgi_thread *, struct uwsgi_offload_request *, int)) {
|
||||
|
||||
wsgi_req->fd_closed = 1;
|
||||
memset(uor, 0, sizeof(struct uwsgi_offload_request));
|
||||
|
||||
uor->engine = uoe;
|
||||
|
||||
uor->s = wsgi_req->fd;
|
||||
uor->fd = -1;
|
||||
uor->fd2 = -1;
|
||||
// an engine could changes behaviour based on pipe anf takeover values
|
||||
uor->pipe[0] = -1;
|
||||
uor->pipe[1] = -1;
|
||||
uor->takeover = takeover;
|
||||
|
||||
uor->s = wsgi_req->poll.fd;
|
||||
uor->func = func;
|
||||
// put socket in non-blocking mode
|
||||
uwsgi_socket_nb(uor->s);
|
||||
|
||||
}
|
||||
|
||||
static int uwsgi_offload_enqueue(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) {
|
||||
@@ -50,92 +38,79 @@ static int uwsgi_offload_enqueue(struct wsgi_request *wsgi_req, struct uwsgi_off
|
||||
struct uwsgi_thread *ut = uwsgi.offload_thread[uc->offload_rr];
|
||||
uc->offload_rr++;
|
||||
if (write(ut->pipe[0], uor, sizeof(struct uwsgi_offload_request)) != sizeof(struct uwsgi_offload_request)) {
|
||||
if (uor->takeover) {
|
||||
wsgi_req->fd_closed = 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
int uwsgi_offload_request_net_do(struct wsgi_request *wsgi_req, char *socket, struct uwsgi_buffer *ubuf) {
|
||||
|
||||
transfer offload engine:
|
||||
name -> socket name
|
||||
ubuf -> data to send
|
||||
// fill offload request
|
||||
struct uwsgi_offload_request uor;
|
||||
uwsgi_offload_setup(&uor, wsgi_req, uwsgi_offload_net_transfer);
|
||||
|
||||
*/
|
||||
|
||||
int u_offload_transfer_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) {
|
||||
|
||||
if (!uor->name) {
|
||||
return -1;
|
||||
uor.fd = uwsgi_connect(socket, 0, 1);
|
||||
if (uor.fd < 0) {
|
||||
uwsgi_error("uwsgi_offload_request_net_do() -> connect()");
|
||||
goto error;
|
||||
}
|
||||
|
||||
uor->fd = uwsgi_connect(uor->ubuf->buf, 0, 1);
|
||||
if (uor->fd < 0) {
|
||||
uwsgi_error("u_offload_transfer_prepare()/connect()");
|
||||
return -1;
|
||||
uor.ubuf = ubuf;
|
||||
|
||||
if (uwsgi_offload_enqueue(wsgi_req, &uor)) {
|
||||
goto error2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error2:
|
||||
close(uor.fd);
|
||||
error:
|
||||
wsgi_req->fd_closed = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
int uwsgi_offload_request_sendfile_do(struct wsgi_request *wsgi_req, char *filename, size_t len) {
|
||||
|
||||
sendfile offload engine:
|
||||
name -> filename to transfer
|
||||
fd -> file descriptor of file to transfer
|
||||
fd2 -> sendfile destination (default wsgi_req->fd)
|
||||
len -> size of the file or amount of data to transfer
|
||||
pos -> position in the file
|
||||
// fill offload request
|
||||
struct uwsgi_offload_request uor;
|
||||
uwsgi_offload_setup(&uor, wsgi_req, uwsgi_offload_sendfile_transfer);
|
||||
|
||||
*/
|
||||
|
||||
static int u_offload_sendfile_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) {
|
||||
|
||||
if (!uor->name && uor->fd == -1) return -1;
|
||||
|
||||
if (uor->name) {
|
||||
uor->fd = open(uor->name, O_RDONLY | O_NONBLOCK);
|
||||
if (uor->fd < 0) {
|
||||
uwsgi_error_open(uor->name);
|
||||
return -1;
|
||||
}
|
||||
uor.fd = open(filename, O_RDONLY | O_NONBLOCK);
|
||||
if (uor.fd < 0) {
|
||||
uwsgi_error_open(filename);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// make a fstat to get the file size
|
||||
if (!uor->len) {
|
||||
if (!len) {
|
||||
struct stat st;
|
||||
if (fstat(uor->fd, &st)) {
|
||||
uwsgi_error("u_offload_sendfile_prepare()/fstat()");
|
||||
if (uor->name) {
|
||||
close(uor->fd);
|
||||
}
|
||||
return -1;
|
||||
if (fstat(uor.fd, &st)) {
|
||||
uwsgi_error("fstat()");
|
||||
goto error2;
|
||||
}
|
||||
uor->len = st.st_size;
|
||||
len = st.st_size;
|
||||
}
|
||||
|
||||
if (uor->fd2 == -1) {
|
||||
uor->fd2 = uor->s;
|
||||
uor.len = len;
|
||||
|
||||
if (uwsgi_offload_enqueue(wsgi_req, &uor)) {
|
||||
goto error2;
|
||||
}
|
||||
uor->s = -1;
|
||||
|
||||
return 0;
|
||||
|
||||
error2:
|
||||
close(uor.fd);
|
||||
error:
|
||||
wsgi_req->fd_closed = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void uwsgi_offload_close(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor) {
|
||||
// close the socket and the file descriptor
|
||||
if (uor->takeover && uor->s > -1) {
|
||||
close(uor->s);
|
||||
}
|
||||
if (uor->fd != -1) {
|
||||
close(uor->fd);
|
||||
}
|
||||
if (uor->fd2 != -1) {
|
||||
close(uor->fd2);
|
||||
}
|
||||
close(uor->s);
|
||||
close(uor->fd);
|
||||
// remove the structure from the linked list;
|
||||
struct uwsgi_offload_request *prev = uor->prev;
|
||||
struct uwsgi_offload_request *next = uor->next;
|
||||
@@ -164,11 +139,6 @@ static void uwsgi_offload_close(struct uwsgi_thread *ut, struct uwsgi_offload_re
|
||||
uwsgi_buffer_destroy(uor->ubuf);
|
||||
}
|
||||
|
||||
if (uor->pipe[0] != -1) {
|
||||
close(uor->pipe[1]);
|
||||
close(uor->pipe[0]);
|
||||
}
|
||||
|
||||
free(uor);
|
||||
}
|
||||
|
||||
@@ -189,7 +159,7 @@ static void uwsgi_offload_append(struct uwsgi_thread *ut, struct uwsgi_offload_r
|
||||
static struct uwsgi_offload_request *uwsgi_offload_get_by_fd(struct uwsgi_thread *ut, int s) {
|
||||
struct uwsgi_offload_request *uor = ut->offload_requests_head;
|
||||
while (uor) {
|
||||
if (uor->s == s || uor->fd == s || uor->fd2 == s) {
|
||||
if (uor->s == s || uor->fd == s) {
|
||||
return uor;
|
||||
}
|
||||
uor = uor->next;
|
||||
@@ -215,8 +185,8 @@ static void uwsgi_offload_loop(struct uwsgi_thread *ut) {
|
||||
free(uor);
|
||||
continue;
|
||||
}
|
||||
// cal the event function for the first time
|
||||
if (uor->engine->event_func(ut, uor, -1)) {
|
||||
// start monitoring socket for write
|
||||
if (uor->func(ut, uor, -1)) {
|
||||
uwsgi_offload_close(ut, uor);
|
||||
continue;
|
||||
}
|
||||
@@ -229,7 +199,7 @@ static void uwsgi_offload_loop(struct uwsgi_thread *ut) {
|
||||
if (!uor)
|
||||
continue;
|
||||
// run the hook
|
||||
if (uor->engine->event_func(ut, uor, interesting_fd)) {
|
||||
if (uor->func(ut, uor, interesting_fd)) {
|
||||
uwsgi_offload_close(ut, uor);
|
||||
}
|
||||
}
|
||||
@@ -251,14 +221,14 @@ the offload task starts after having acquired the file fd
|
||||
|
||||
*/
|
||||
|
||||
static int u_offload_sendfile_do(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) {
|
||||
static int uwsgi_offload_sendfile_transfer(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) {
|
||||
|
||||
if (fd == -1) {
|
||||
if (event_queue_add_fd_write(ut->queue, uor->fd2)) return -1;
|
||||
if (event_queue_add_fd_write(ut->queue, uor->s)) return -1;
|
||||
return 0;
|
||||
}
|
||||
#if defined(__linux__) || defined(__sun__)
|
||||
ssize_t len = sendfile(uor->fd2, uor->fd, &uor->pos, 128 * 1024);
|
||||
ssize_t len = sendfile(uor->s, uor->fd, &uor->pos, 128 * 1024);
|
||||
if (len > 0) {
|
||||
uor->written += len;
|
||||
if (uor->written >= uor->len) {
|
||||
@@ -268,25 +238,25 @@ static int u_offload_sendfile_do(struct uwsgi_thread *ut, struct uwsgi_offload_r
|
||||
}
|
||||
else if (len < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_sendfile_do()");
|
||||
uwsgi_error("sendfile()");
|
||||
}
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
off_t sbytes = 0;
|
||||
int ret = sendfile(uor->fd, uor->fd2, uor->pos, 0, NULL, &sbytes, 0);
|
||||
int ret = sendfile(uor->fd, uor->s, uor->pos, 0, NULL, &sbytes, 0);
|
||||
// transfer finished
|
||||
if (ret == -1) {
|
||||
uor->pos += sbytes;
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_sendfile_do()");
|
||||
uwsgi_error("sendfile()");
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
off_t len = 0;
|
||||
int ret = sendfile(uor->fd, uor->fd2, uor->pos, &len, NULL, 0);
|
||||
int ret = sendfile(uor->fd, uor->s, uor->pos, &len, NULL, 0);
|
||||
// transfer finished
|
||||
if (ret == -1) {
|
||||
uor->pos += len;
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_sendfile_do()");
|
||||
uwsgi_error("sendfile()");
|
||||
}
|
||||
#endif
|
||||
return -1;
|
||||
@@ -303,7 +273,7 @@ the offload task starts soon after the call to connect()
|
||||
3 -> write to s
|
||||
4 -> write to fd
|
||||
*/
|
||||
static int u_offload_transfer_do(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) {
|
||||
static int uwsgi_offload_net_transfer(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) {
|
||||
|
||||
ssize_t rlen;
|
||||
|
||||
@@ -319,7 +289,7 @@ static int u_offload_transfer_do(struct uwsgi_thread *ut, struct uwsgi_offload_r
|
||||
if (fd == uor->fd) {
|
||||
uor->status = 1;
|
||||
// ok try to send the request right now...
|
||||
return u_offload_transfer_do(ut, uor, fd);
|
||||
return uwsgi_offload_net_transfer(ut, uor, fd);
|
||||
}
|
||||
return -1;
|
||||
// write event (or just connected)
|
||||
@@ -337,7 +307,7 @@ static int u_offload_transfer_do(struct uwsgi_thread *ut, struct uwsgi_offload_r
|
||||
}
|
||||
else if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_transfer_do() -> write()");
|
||||
uwsgi_error("uwsgi_offload_net_transfer() -> write()");
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
@@ -357,7 +327,7 @@ static int u_offload_transfer_do(struct uwsgi_thread *ut, struct uwsgi_offload_r
|
||||
}
|
||||
if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_transfer_do() -> read()/fd");
|
||||
uwsgi_error("uwsgi_offload_net_transfer() -> read()/fd");
|
||||
}
|
||||
}
|
||||
else if (fd == uor->s) {
|
||||
@@ -371,7 +341,7 @@ static int u_offload_transfer_do(struct uwsgi_thread *ut, struct uwsgi_offload_r
|
||||
}
|
||||
if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_transfer_do() -> read()/s");
|
||||
uwsgi_error("uwsgi_offload_net_transfer() -> read()/s");
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
@@ -390,7 +360,7 @@ static int u_offload_transfer_do(struct uwsgi_thread *ut, struct uwsgi_offload_r
|
||||
}
|
||||
else if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_transfer_do() -> write()/s");
|
||||
uwsgi_error("uwsgi_offload_net_transfer() -> write()/s");
|
||||
}
|
||||
return -1;
|
||||
// write event on fd
|
||||
@@ -408,7 +378,7 @@ static int u_offload_transfer_do(struct uwsgi_thread *ut, struct uwsgi_offload_r
|
||||
}
|
||||
else if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_transfer_do() -> write()/fd");
|
||||
uwsgi_error("uwsgi_offload_net_transfer() -> write()/fd");
|
||||
}
|
||||
return -1;
|
||||
default:
|
||||
@@ -417,93 +387,3 @@ static int u_offload_transfer_do(struct uwsgi_thread *ut, struct uwsgi_offload_r
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int uwsgi_offload_run(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor, int *wait) {
|
||||
|
||||
if (uor->engine->prepare_func(wsgi_req, uor)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wait) {
|
||||
if (pipe(uor->pipe)) {
|
||||
uwsgi_error("uwsgi_offload_setup()/pipe()");
|
||||
return -1;
|
||||
}
|
||||
*wait = uor->pipe[0];
|
||||
uwsgi_socket_nb(uor->pipe[0]);
|
||||
uwsgi_socket_nb(uor->pipe[1]);
|
||||
}
|
||||
|
||||
if (uor->takeover) {
|
||||
wsgi_req->fd_closed = 1;
|
||||
}
|
||||
|
||||
if (uwsgi_offload_enqueue(wsgi_req, uor)) {
|
||||
close(uor->pipe[0]);
|
||||
close(uor->pipe[1]);
|
||||
if (uor->takeover) {
|
||||
wsgi_req->fd_closed = 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
};
|
||||
|
||||
struct uwsgi_offload_engine *uwsgi_offload_engine_by_name(char *name) {
|
||||
struct uwsgi_offload_engine *uoe = uwsgi.offload_engines;
|
||||
while(uoe) {
|
||||
if (!strcmp(name, uoe->name)) {
|
||||
return uoe;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_offload_engine *uwsgi_offload_register_engine(char *name, int (*prepare_func)(struct wsgi_request *, struct uwsgi_offload_request *), int (*event_func) (struct uwsgi_thread *, struct uwsgi_offload_request *, int)) {
|
||||
|
||||
struct uwsgi_offload_engine *old_engine=NULL,*engine=uwsgi.offload_engines;
|
||||
while(engine) {
|
||||
if (!strcmp(engine->name, name)) {
|
||||
return engine;
|
||||
}
|
||||
old_engine = engine;
|
||||
engine = engine->next;
|
||||
}
|
||||
|
||||
engine = uwsgi_calloc(sizeof(struct uwsgi_offload_engine));
|
||||
engine->name = name;
|
||||
engine->prepare_func = prepare_func;
|
||||
engine->event_func = event_func;
|
||||
|
||||
if (old_engine) {
|
||||
old_engine->next = engine;
|
||||
}
|
||||
else {
|
||||
uwsgi.offload_engines = engine;
|
||||
}
|
||||
|
||||
return engine;
|
||||
}
|
||||
|
||||
void uwsgi_offload_engines_register_all() {
|
||||
uwsgi.offload_engine_sendfile = uwsgi_offload_register_engine("sendfile", u_offload_sendfile_prepare, u_offload_sendfile_do);
|
||||
uwsgi.offload_engine_transfer = uwsgi_offload_register_engine("transfer", u_offload_transfer_prepare, u_offload_transfer_do);
|
||||
}
|
||||
|
||||
int uwsgi_offload_request_sendfile_do(struct wsgi_request *wsgi_req, int fd, size_t len) {
|
||||
struct uwsgi_offload_request uor;
|
||||
uwsgi_offload_setup(uwsgi.offload_engine_sendfile, &uor, wsgi_req, 1);
|
||||
uor.fd = fd;
|
||||
uor.len = len;
|
||||
return uwsgi_offload_run(wsgi_req, &uor, NULL);
|
||||
}
|
||||
|
||||
int uwsgi_offload_request_net_do(struct wsgi_request *wsgi_req, char *socketname, struct uwsgi_buffer *ubuf) {
|
||||
struct uwsgi_offload_request uor;
|
||||
uwsgi_offload_setup(uwsgi.offload_engine_transfer, &uor, wsgi_req, 1);
|
||||
uor.name = socketname;
|
||||
uor.ubuf = ubuf;
|
||||
return uwsgi_offload_run(wsgi_req, &uor, NULL);
|
||||
}
|
||||
|
||||
+4
-3
@@ -24,7 +24,7 @@ static void uwsgi_plugin_parse_section(char *filename) {
|
||||
}
|
||||
#endif
|
||||
|
||||
int plugin_already_loaded(const char *plugin) {
|
||||
static int plugin_already_loaded(const char *plugin) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
@@ -76,8 +76,8 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
|
||||
char *plugin_filename = NULL;
|
||||
|
||||
int need_free = 0;
|
||||
char *plugin_name = uwsgi_strip(uwsgi_str(plugin));
|
||||
char *plugin_symbol_name_start = plugin_name;
|
||||
char *plugin_name = plugin;
|
||||
char *plugin_symbol_name_start = plugin;
|
||||
|
||||
struct uwsgi_plugin *up;
|
||||
char linkpath_buf[1024], linkpath[1024];
|
||||
@@ -165,6 +165,7 @@ success:
|
||||
uwsgi_log("%s\n", linkpath);
|
||||
#endif
|
||||
free(plugin_entry_symbol);
|
||||
up = dlsym(plugin_handle, plugin_entry_symbol);
|
||||
char *slash = uwsgi_get_last_char(linkpath, '/');
|
||||
if (!slash) {
|
||||
slash = linkpath;
|
||||
|
||||
-107
@@ -1,107 +0,0 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
|
||||
upload progress facilities
|
||||
|
||||
*/
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
char *uwsgi_upload_progress_create(struct wsgi_request *wsgi_req, int *fd) {
|
||||
const char *x_progress_id = "X-Progress-ID=";
|
||||
char *xpi_ptr = (char *) x_progress_id;
|
||||
uint16_t i;
|
||||
char *upload_progress_filename = NULL;
|
||||
|
||||
if (wsgi_req->uri_len <= 51)
|
||||
return NULL;
|
||||
|
||||
|
||||
for (i = 0; i < wsgi_req->uri_len; i++) {
|
||||
if (wsgi_req->uri[i] == xpi_ptr[0]) {
|
||||
if (xpi_ptr[0] == '=') {
|
||||
if (wsgi_req->uri + i + 36 <= wsgi_req->uri + wsgi_req->uri_len) {
|
||||
upload_progress_filename = wsgi_req->uri + i + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
xpi_ptr++;
|
||||
}
|
||||
else {
|
||||
xpi_ptr = (char *) x_progress_id;
|
||||
}
|
||||
}
|
||||
|
||||
// now check for valid uuid (from spec available at http://en.wikipedia.org/wiki/Universally_unique_identifier)
|
||||
if (!upload_progress_filename)
|
||||
return NULL;
|
||||
|
||||
uwsgi_log("upload progress uuid = %.*s\n", 36, upload_progress_filename);
|
||||
if (!check_hex(upload_progress_filename, 8))
|
||||
return NULL;
|
||||
if (upload_progress_filename[8] != '-')
|
||||
return NULL;
|
||||
|
||||
if (!check_hex(upload_progress_filename + 9, 4))
|
||||
return NULL;
|
||||
if (upload_progress_filename[13] != '-')
|
||||
return NULL;
|
||||
|
||||
if (!check_hex(upload_progress_filename + 14, 4))
|
||||
return NULL;
|
||||
if (upload_progress_filename[18] != '-')
|
||||
return NULL;
|
||||
|
||||
if (!check_hex(upload_progress_filename + 19, 4))
|
||||
return NULL;
|
||||
if (upload_progress_filename[23] != '-')
|
||||
return NULL;
|
||||
|
||||
if (!check_hex(upload_progress_filename + 24, 12))
|
||||
return NULL;
|
||||
|
||||
upload_progress_filename = uwsgi_concat4n(uwsgi.upload_progress, strlen(uwsgi.upload_progress), "/", 1, upload_progress_filename, 36, ".js", 3);
|
||||
// here we use O_EXCL to avoid eventual application bug in uuid generation/using
|
||||
*fd = open(upload_progress_filename, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP);
|
||||
if (*fd < 0) {
|
||||
uwsgi_error_open(upload_progress_filename);
|
||||
free(upload_progress_filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return upload_progress_filename;
|
||||
}
|
||||
|
||||
int uwsgi_upload_progress_update(struct wsgi_request *wsgi_req, int fd, size_t remains) {
|
||||
char buf[4096];
|
||||
|
||||
int ret = snprintf(buf, 4096, "{ \"state\" : \"uploading\", \"received\" : %llu, \"size\" : %llu }\r\n", (unsigned long long) (wsgi_req->post_cl - remains), (unsigned long long) wsgi_req->post_cl);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lseek(fd, 0, SEEK_SET)) {
|
||||
uwsgi_error("uwsgi_upload_progress_update()/lseek()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (write(fd, buf, ret) != ret) {
|
||||
uwsgi_error("uwsgi_upload_progress_update()/write()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fsync(fd)) {
|
||||
uwsgi_error("uwsgi_upload_progress_update()/fsync()");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uwsgi_upload_progress_destroy(char *filename, int fd) {
|
||||
close(fd);
|
||||
if (unlink(filename)) {
|
||||
uwsgi_error("uwsgi_upload_progress_destroy()/unlink()");
|
||||
}
|
||||
free(filename);
|
||||
}
|
||||
+1421
-430
File diff suppressed because it is too large
Load Diff
+1
-2
@@ -47,7 +47,6 @@ void uwsgi_init_queue() {
|
||||
// fix header
|
||||
uwsgi.queue_header = uwsgi.queue;
|
||||
uwsgi.queue += 16;
|
||||
close(queue_fd);
|
||||
}
|
||||
else {
|
||||
uwsgi.queue = mmap(NULL, (uwsgi.queue_blocksize * uwsgi.queue_size) + 16, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
@@ -66,7 +65,7 @@ void uwsgi_init_queue() {
|
||||
|
||||
uwsgi.queue_lock = uwsgi_rwlock_init("queue");
|
||||
|
||||
uwsgi_log("*** Queue subsystem initialized: %luMB preallocated ***\n", (uwsgi.queue_blocksize * uwsgi.queue_size) / (1024 * 1024));
|
||||
uwsgi_log("*** Queue subsystem initialized: %dMB preallocated ***\n", (uwsgi.queue_blocksize * uwsgi.queue_size) / (1024 * 1024));
|
||||
}
|
||||
|
||||
char *uwsgi_queue_get(uint64_t index, uint64_t * size) {
|
||||
|
||||
-572
@@ -1,572 +0,0 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_simple_wait_read_hook(int fd, int timeout) {
|
||||
struct pollfd upoll;
|
||||
timeout = timeout * 1000;
|
||||
|
||||
upoll.fd = fd;
|
||||
upoll.events = POLLIN;
|
||||
upoll.revents = 0;
|
||||
int ret = poll(&upoll, 1, timeout);
|
||||
|
||||
if (ret > 0) {
|
||||
if (upoll.revents & POLLIN) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (ret < 0) {
|
||||
uwsgi_error("uwsgi_simple_wait_read_hook()/poll()");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
seek()/rewind() language-independent implementations.
|
||||
*/
|
||||
|
||||
void uwsgi_request_body_seek(struct wsgi_request *wsgi_req, off_t pos) {
|
||||
if (wsgi_req->post_file) {
|
||||
if (pos < 0) {
|
||||
if (fseek(wsgi_req->post_file, pos, SEEK_CUR)) {
|
||||
uwsgi_error("uwsgi_request_body_seek()/fseek()");
|
||||
}
|
||||
wsgi_req->post_pos = ftell(wsgi_req->post_file);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fseek(wsgi_req->post_file, pos, SEEK_SET)) {
|
||||
uwsgi_error("uwsgi_request_body_seek()/fseek()");
|
||||
}
|
||||
wsgi_req->post_pos = ftell(wsgi_req->post_file);
|
||||
return;
|
||||
}
|
||||
|
||||
if (uwsgi.post_buffering) {
|
||||
if (pos < 0) {
|
||||
if (pos > (off_t) wsgi_req->post_pos) {
|
||||
wsgi_req->post_pos = 0;
|
||||
return;
|
||||
}
|
||||
wsgi_req->post_pos -= pos;
|
||||
return;
|
||||
}
|
||||
if (pos >= (off_t) uwsgi.post_buffering) {
|
||||
pos = uwsgi.post_buffering - 1;
|
||||
}
|
||||
wsgi_req->post_pos = pos;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
read() and readline() language-independent implementations.
|
||||
|
||||
*/
|
||||
|
||||
#define uwsgi_read_error0(x) uwsgi_log("[uwsgi-body-read] Error reading %llu bytes. Content-Length: %llu consumed: %llu left: %llu message: Client closed connection\n",\
|
||||
(unsigned long long) x,\
|
||||
(unsigned long long) wsgi_req->post_cl, (unsigned long long) wsgi_req->post_pos, (unsigned long long) wsgi_req->post_cl-wsgi_req->post_pos);
|
||||
|
||||
#define uwsgi_read_error(x) uwsgi_log("[uwsgi-body-read] Error reading %llu bytes. Content-Length: %llu consumed: %llu left: %llu message: %s\n",\
|
||||
(unsigned long long) x,\
|
||||
(unsigned long long) wsgi_req->post_cl, (unsigned long long) wsgi_req->post_pos, (unsigned long long) wsgi_req->post_cl-wsgi_req->post_pos,\
|
||||
strerror(errno));
|
||||
|
||||
#define uwsgi_read_timeout(x) uwsgi_log("[uwsgi-body-read] Timeout reading %llu bytes. Content-Length: %llu consumed: %llu left: %llu\n",\
|
||||
(unsigned long long) x,\
|
||||
(unsigned long long) wsgi_req->post_cl, (unsigned long long) wsgi_req->post_pos, (unsigned long long) wsgi_req->post_cl-wsgi_req->post_pos);
|
||||
|
||||
static int consume_body_for_readline(struct wsgi_request *wsgi_req) {
|
||||
|
||||
size_t remains = UMIN(uwsgi.buffer_size, wsgi_req->post_cl - wsgi_req->post_pos);
|
||||
|
||||
int ret;
|
||||
|
||||
// allocate more memory if needed
|
||||
if (wsgi_req->post_readline_size - wsgi_req->post_readline_watermark == 0) {
|
||||
memcpy(wsgi_req->post_readline_buf, wsgi_req->post_readline_buf + wsgi_req->post_readline_pos, wsgi_req->post_readline_watermark - wsgi_req->post_readline_pos);
|
||||
wsgi_req->post_readline_watermark -= wsgi_req->post_readline_pos;
|
||||
wsgi_req->post_readline_pos = 0;
|
||||
// still something to use ?
|
||||
if (wsgi_req->post_readline_size - wsgi_req->post_readline_watermark < remains) {
|
||||
char *tmp_buf = realloc(wsgi_req->post_readline_buf, wsgi_req->post_readline_size + remains);
|
||||
if (!tmp_buf) {
|
||||
uwsgi_error("consume_body_for_readline()/realloc()");
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->post_readline_buf = tmp_buf;
|
||||
wsgi_req->post_readline_size += remains;
|
||||
// INFORM THE USER HIS readline() USAGE IS FOOLISH
|
||||
if (!wsgi_req->post_warning && wsgi_req->post_readline_size > (uwsgi.body_read_warning * 1024*1024)) {
|
||||
uwsgi_log("[uwsgi-warning] you are using readline() on request body allocating over than %llu MB, that is really bad and can be avoided...\n", (unsigned long long) (wsgi_req->post_readline_size/(1024*1024)));
|
||||
wsgi_req->post_warning = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// read from a file
|
||||
if (wsgi_req->post_file) {
|
||||
size_t ret = fread(wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark, wsgi_req->post_readline_size - wsgi_req->post_readline_watermark, 1, wsgi_req->post_file);
|
||||
if (ret == 0) {
|
||||
uwsgi_error("consume_body_for_readline()/fread()");
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->post_pos += wsgi_req->post_readline_size - wsgi_req->post_readline_watermark;
|
||||
wsgi_req->post_readline_watermark += wsgi_req->post_readline_size - wsgi_req->post_readline_watermark;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// read from post_buffering memory
|
||||
if (uwsgi.post_buffering) {
|
||||
wsgi_req->post_pos += wsgi_req->post_readline_size - wsgi_req->post_readline_watermark;
|
||||
memcpy(wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark, wsgi_req->post_buffering_buf + wsgi_req->post_pos, wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
|
||||
wsgi_req->post_readline_watermark += wsgi_req->post_readline_size - wsgi_req->post_readline_watermark;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// read from socket
|
||||
ssize_t len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark , wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
|
||||
if (len > 0) {
|
||||
wsgi_req->post_pos += len;
|
||||
wsgi_req->post_readline_watermark += len;
|
||||
return 0;
|
||||
}
|
||||
if (len == 0) {
|
||||
uwsgi_read_error(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
|
||||
return -1;
|
||||
}
|
||||
if (len < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
goto wait;
|
||||
}
|
||||
uwsgi_read_error(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
|
||||
return -1;
|
||||
}
|
||||
wait:
|
||||
ret = uwsgi_wait_read_req(wsgi_req);
|
||||
if (ret > 0) {
|
||||
len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark , wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
|
||||
if (len > 0) {
|
||||
wsgi_req->post_pos += len;
|
||||
wsgi_req->post_readline_watermark += len;
|
||||
return 0;
|
||||
}
|
||||
uwsgi_read_error(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
|
||||
return -1;
|
||||
}
|
||||
// 0 means timeout
|
||||
else if (ret == 0) {
|
||||
uwsgi_read_timeout(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
|
||||
return -1;
|
||||
}
|
||||
uwsgi_read_error(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO take hint into account
|
||||
// readline_buf is allocated when needed and freed at the end of the request
|
||||
char *uwsgi_request_body_readline(struct wsgi_request *wsgi_req, ssize_t hint, ssize_t *rlen) {
|
||||
|
||||
// return 0 if no post_cl or pos >= post_cl and no residual data
|
||||
if ((!wsgi_req->post_cl || wsgi_req->post_pos >= wsgi_req->post_cl ) && !wsgi_req->post_readline_pos) {
|
||||
return uwsgi.empty;
|
||||
}
|
||||
|
||||
// some residual data ?
|
||||
if (wsgi_req->post_readline_pos > 0) {
|
||||
size_t i;
|
||||
for(i=wsgi_req->post_readline_pos;i<wsgi_req->post_readline_watermark;i++) {
|
||||
// found a newline
|
||||
if (wsgi_req->post_readline_buf[i] == '\n') {
|
||||
*rlen = (i+1)-wsgi_req->post_readline_pos;
|
||||
char *buf = wsgi_req->post_readline_buf + wsgi_req->post_readline_pos;
|
||||
wsgi_req->post_readline_pos += *rlen;
|
||||
// all the readline buffer has been consumed
|
||||
if (wsgi_req->post_readline_pos >= wsgi_req->post_readline_watermark) {
|
||||
wsgi_req->post_readline_pos = 0;
|
||||
wsgi_req->post_readline_watermark = 0;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
// ok, no newline found, continue below
|
||||
}
|
||||
|
||||
// allocate memory on the first round
|
||||
if (!wsgi_req->post_readline_buf) {
|
||||
size_t amount = UMIN(uwsgi.buffer_size, wsgi_req->post_cl);
|
||||
wsgi_req->post_readline_buf = malloc(amount);
|
||||
if (!wsgi_req->post_readline_buf) {
|
||||
uwsgi_error("uwsgi_request_body_readline()/malloc()");
|
||||
*rlen = -1;
|
||||
return NULL;
|
||||
}
|
||||
wsgi_req->post_readline_size = amount;
|
||||
}
|
||||
|
||||
// ok, no newline found, consume a bit more of memory and retry
|
||||
for(;;) {
|
||||
// no more data to consume
|
||||
if (wsgi_req->post_pos >= wsgi_req->post_cl) break;
|
||||
|
||||
if (consume_body_for_readline(wsgi_req)) {
|
||||
*rlen = -1;
|
||||
return NULL;
|
||||
}
|
||||
size_t i;
|
||||
for(i=wsgi_req->post_readline_pos;i<wsgi_req->post_readline_watermark;i++) {
|
||||
if (wsgi_req->post_readline_buf[i] == '\n') {
|
||||
*rlen = (i+1)-wsgi_req->post_readline_pos;
|
||||
char *buf = wsgi_req->post_readline_buf + wsgi_req->post_readline_pos;
|
||||
wsgi_req->post_readline_pos += *rlen;
|
||||
if (wsgi_req->post_readline_pos >= wsgi_req->post_readline_watermark) {
|
||||
wsgi_req->post_readline_pos = 0;
|
||||
wsgi_req->post_readline_watermark = 0;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no line found, let's return all
|
||||
*rlen = wsgi_req->post_readline_size - wsgi_req->post_readline_pos;
|
||||
char *buf = wsgi_req->post_readline_buf + wsgi_req->post_readline_pos;
|
||||
wsgi_req->post_readline_pos = 0;
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_request_body_read(struct wsgi_request *wsgi_req, ssize_t hint, ssize_t *rlen) {
|
||||
|
||||
int ret = -1;
|
||||
size_t remains = hint;
|
||||
|
||||
// return empty if no post_cl or pos >= post_cl and no residual data
|
||||
if ((!wsgi_req->post_cl || wsgi_req->post_pos >= wsgi_req->post_cl ) && !wsgi_req->post_readline_pos) {
|
||||
return uwsgi.empty;
|
||||
}
|
||||
|
||||
// return the whole input
|
||||
if (remains <= 0) {
|
||||
remains = wsgi_req->post_cl;
|
||||
}
|
||||
|
||||
// some residual data ?
|
||||
if (wsgi_req->post_readline_pos > 0) {
|
||||
if (remains <= (wsgi_req->post_readline_watermark - wsgi_req->post_readline_pos)) {
|
||||
*rlen = remains;
|
||||
char *buf = wsgi_req->post_readline_buf + wsgi_req->post_readline_pos;
|
||||
wsgi_req->post_readline_pos += remains;
|
||||
return buf;
|
||||
}
|
||||
// the hint is higher than residual data, let's copy it to read() memory and go on
|
||||
size_t avail = wsgi_req->post_readline_watermark - wsgi_req->post_readline_pos;
|
||||
// check if we have enough memory...
|
||||
if (avail > wsgi_req->post_read_buf_size) {
|
||||
char *tmp_buf = realloc(wsgi_req->post_read_buf, avail);
|
||||
if (!tmp_buf) {
|
||||
uwsgi_error("uwsgi_request_body_read()/realloc()");
|
||||
*rlen = -1;
|
||||
return NULL;
|
||||
}
|
||||
wsgi_req->post_read_buf = tmp_buf;
|
||||
wsgi_req->post_read_buf_size = avail;
|
||||
if (!wsgi_req->post_warning && wsgi_req->post_read_buf_size > (uwsgi.body_read_warning * 1024*1024)) {
|
||||
uwsgi_log("[uwsgi-warning] you are using read() on request body allocating over than %llu MB, that is really bad and can be avoided...\n", (unsigned long long) (wsgi_req->post_read_buf_size/(1024*1024)));
|
||||
wsgi_req->post_warning = 1;
|
||||
}
|
||||
}
|
||||
// fix remains...
|
||||
if (remains > 0) {
|
||||
remains -= avail;
|
||||
}
|
||||
*rlen += avail;
|
||||
memcpy(wsgi_req->post_read_buf, wsgi_req->post_readline_buf + wsgi_req->post_readline_pos, avail);
|
||||
wsgi_req->post_readline_pos = 0;
|
||||
wsgi_req->post_readline_watermark = 0;
|
||||
}
|
||||
|
||||
if (remains + wsgi_req->post_pos > wsgi_req->post_cl) {
|
||||
remains = wsgi_req->post_cl - wsgi_req->post_pos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (remains == 0) {
|
||||
if (*rlen > 0) {
|
||||
return wsgi_req->post_read_buf;
|
||||
}
|
||||
else {
|
||||
return uwsgi.empty;
|
||||
}
|
||||
}
|
||||
|
||||
// read from post buffering memory
|
||||
if (uwsgi.post_buffering > 0 && !wsgi_req->post_file) {
|
||||
*rlen += remains;
|
||||
char *buf = wsgi_req->post_buffering_buf+wsgi_req->post_pos;
|
||||
wsgi_req->post_pos += remains;
|
||||
return buf;
|
||||
}
|
||||
|
||||
// ok we need to check if we need to allocate memory
|
||||
if (!wsgi_req->post_read_buf) {
|
||||
wsgi_req->post_read_buf = malloc(remains);
|
||||
if (!wsgi_req->post_read_buf) {
|
||||
uwsgi_error("uwsgi_request_body_read()/malloc()");
|
||||
*rlen = -1;
|
||||
return NULL;
|
||||
}
|
||||
wsgi_req->post_read_buf_size = remains;
|
||||
}
|
||||
// need to realloc ?
|
||||
else {
|
||||
if ((remains+*rlen) > wsgi_req->post_read_buf_size) {
|
||||
char *tmp_buf = realloc(wsgi_req->post_read_buf, (remains+*rlen));
|
||||
if (!tmp_buf) {
|
||||
uwsgi_error("uwsgi_request_body_read()/realloc()");
|
||||
*rlen = -1;
|
||||
return NULL;
|
||||
}
|
||||
wsgi_req->post_read_buf = tmp_buf;
|
||||
wsgi_req->post_read_buf_size = (remains+*rlen);
|
||||
if (!wsgi_req->post_warning && wsgi_req->post_read_buf_size > (uwsgi.body_read_warning * 1024*1024)) {
|
||||
uwsgi_log("[uwsgi-warning] you are using read() on request body allocating over than %llu MB, that is really bad and can be avoided...\n", (unsigned long long) (wsgi_req->post_read_buf_size/(1024*1024)));
|
||||
wsgi_req->post_warning = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check for disk buffered body first (they are all read in one shot)
|
||||
if (wsgi_req->post_file) {
|
||||
if (fread(wsgi_req->post_read_buf + *rlen, remains, 1, wsgi_req->post_file) != 1) {
|
||||
*rlen = -1;
|
||||
uwsgi_log("%llu\n", remains);
|
||||
uwsgi_error("uwsgi_request_body_read()/fread()");
|
||||
return NULL;
|
||||
}
|
||||
*rlen += remains;
|
||||
wsgi_req->post_pos+= remains;
|
||||
return wsgi_req->post_read_buf;
|
||||
}
|
||||
|
||||
// ok read all the required bytes...
|
||||
while(remains > 0) {
|
||||
// here we first try to read (as data could be already available)
|
||||
ssize_t len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_read_buf + *rlen , remains);
|
||||
if (len > 0) {
|
||||
wsgi_req->post_pos+=len;
|
||||
remains -= len;
|
||||
*rlen += len;
|
||||
continue;
|
||||
}
|
||||
// client closed connection...
|
||||
if (len == 0) {
|
||||
*rlen = -1;
|
||||
uwsgi_read_error0(remains);
|
||||
return NULL;
|
||||
}
|
||||
if (len < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
goto wait;
|
||||
}
|
||||
*rlen = -1;
|
||||
uwsgi_read_error(remains);
|
||||
return NULL;
|
||||
}
|
||||
wait:
|
||||
ret = uwsgi_wait_read_req(wsgi_req);
|
||||
if (ret > 0) {
|
||||
len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_read_buf + *rlen, remains);
|
||||
if (len > 0) {
|
||||
wsgi_req->post_pos+=len;
|
||||
remains -= len;
|
||||
*rlen += len;
|
||||
continue;
|
||||
}
|
||||
*rlen = -1;
|
||||
if (len == 0) {
|
||||
uwsgi_read_error0(remains);
|
||||
}
|
||||
else {
|
||||
uwsgi_read_error(remains);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
// 0 means timeout
|
||||
else if (ret == 0) {
|
||||
*rlen = 0;
|
||||
uwsgi_read_timeout(remains);
|
||||
return NULL;
|
||||
}
|
||||
*rlen = -1;
|
||||
uwsgi_read_error(remains);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return wsgi_req->post_read_buf;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
post buffering
|
||||
|
||||
*/
|
||||
|
||||
int uwsgi_postbuffer_do_in_mem(struct wsgi_request *wsgi_req) {
|
||||
|
||||
size_t remains = wsgi_req->post_cl;
|
||||
int ret;
|
||||
char *ptr = wsgi_req->post_buffering_buf;
|
||||
|
||||
while (remains > 0) {
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
|
||||
inc_harakiri(uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
}
|
||||
|
||||
ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, ptr, remains);
|
||||
if (rlen > 0) {
|
||||
remains -= rlen;
|
||||
ptr += rlen;
|
||||
continue;
|
||||
}
|
||||
if (rlen == 0) {
|
||||
uwsgi_read_error0(remains);
|
||||
return -1;
|
||||
}
|
||||
if (rlen < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
goto wait;
|
||||
}
|
||||
uwsgi_read_error(remains);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wait:
|
||||
ret = uwsgi_wait_read_req(wsgi_req);
|
||||
if (ret > 0) {
|
||||
rlen = wsgi_req->socket->proto_read_body(wsgi_req, ptr, remains);
|
||||
if (rlen > 0) {
|
||||
remains -= rlen;
|
||||
ptr += rlen;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
uwsgi_read_error(remains);
|
||||
return -1;
|
||||
}
|
||||
uwsgi_read_timeout(remains);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_postbuffer_do_in_disk(struct wsgi_request *wsgi_req) {
|
||||
|
||||
size_t post_remains = wsgi_req->post_cl;
|
||||
int ret;
|
||||
int upload_progress_fd = -1;
|
||||
char *upload_progress_filename = NULL;
|
||||
|
||||
wsgi_req->post_file = tmpfile();
|
||||
if (!wsgi_req->post_file) {
|
||||
uwsgi_error("uwsgi_postbuffer_do_in_disk()/tmpfile()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (uwsgi.upload_progress) {
|
||||
// first check for X-Progress-ID size
|
||||
// separator + 'X-Progress-ID' + '=' + uuid
|
||||
upload_progress_filename = uwsgi_upload_progress_create(wsgi_req, &upload_progress_fd);
|
||||
if (!upload_progress_filename) {
|
||||
uwsgi_log("invalid X-Progress-ID value: must be a UUID\n");
|
||||
}
|
||||
}
|
||||
|
||||
// manage buffered data and upload progress
|
||||
while (post_remains > 0) {
|
||||
|
||||
// during post buffering we need to constantly reset the harakiri
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
|
||||
inc_harakiri(uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
}
|
||||
|
||||
// we use the already available post buffering buffer to read chunks....
|
||||
size_t remains = UMIN(post_remains, uwsgi.post_buffering);
|
||||
|
||||
// first try to read data (there could be something already available
|
||||
ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_buffering_buf, remains);
|
||||
if (rlen > 0) goto write;
|
||||
if (rlen == 0) {
|
||||
uwsgi_read_error0(remains);
|
||||
goto end;
|
||||
}
|
||||
if (rlen < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
goto wait;
|
||||
}
|
||||
uwsgi_read_error(remains);
|
||||
goto end;
|
||||
}
|
||||
|
||||
wait:
|
||||
ret = uwsgi_wait_read_req(wsgi_req);
|
||||
if (ret > 0) {
|
||||
rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_buffering_buf, remains);
|
||||
if (rlen > 0) goto write;
|
||||
if (rlen == 0) {
|
||||
uwsgi_read_error0(remains);
|
||||
}
|
||||
else {
|
||||
uwsgi_read_error(remains);
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
if (ret < 0) {
|
||||
uwsgi_read_error(remains);
|
||||
goto end;
|
||||
}
|
||||
uwsgi_read_timeout(remains);
|
||||
goto end;
|
||||
|
||||
write:
|
||||
if (fwrite(wsgi_req->post_buffering_buf, rlen, 1, wsgi_req->post_file) != 1) {
|
||||
uwsgi_error("uwsgi_postbuffer_do_in_disk()/fwrite()");
|
||||
goto end;
|
||||
}
|
||||
|
||||
post_remains -= rlen;
|
||||
|
||||
if (upload_progress_filename) {
|
||||
// stop updating it on errors
|
||||
if (uwsgi_upload_progress_update(wsgi_req, upload_progress_fd, post_remains)) {
|
||||
uwsgi_upload_progress_destroy(upload_progress_filename, upload_progress_fd);
|
||||
upload_progress_filename = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
rewind(wsgi_req->post_file);
|
||||
|
||||
if (upload_progress_filename) {
|
||||
uwsgi_upload_progress_destroy(upload_progress_filename, upload_progress_fd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
end:
|
||||
if (upload_progress_filename) {
|
||||
uwsgi_upload_progress_destroy(upload_progress_filename, upload_progress_fd);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
+38
-38
@@ -62,49 +62,49 @@ int uwsgi_regexp_ovector(pcre * pattern, pcre_extra * pattern_extra) {
|
||||
|
||||
char *uwsgi_regexp_apply_ovec(char *src, int src_n, char *dst, int dst_n, int *ovector, int n) {
|
||||
|
||||
int i;
|
||||
int dollar = 0;
|
||||
int i;
|
||||
int dollar = 0;
|
||||
|
||||
size_t dollars = n;
|
||||
|
||||
for(i=0;i<dst_n;i++) {
|
||||
if (dst[i] == '$') {
|
||||
dollars++;
|
||||
}
|
||||
}
|
||||
size_t dollars = n;
|
||||
|
||||
char *res = uwsgi_malloc(dst_n + (src_n * dollars) + 1);
|
||||
char *ptr = res;
|
||||
for(i=0;i<dst_n;i++) {
|
||||
if (dst[i] == '$') {
|
||||
dollars++;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < dst_n; i++) {
|
||||
if (dollar) {
|
||||
if (isdigit((int) dst[i])) {
|
||||
int pos = (dst[i] - 48);
|
||||
if (pos <= n) {
|
||||
pos = pos * 2;
|
||||
memcpy(ptr, src + ovector[pos], ovector[pos + 1] - ovector[pos]);
|
||||
ptr += ovector[pos + 1] - ovector[pos];
|
||||
}
|
||||
}
|
||||
else {
|
||||
*ptr++ = '$';
|
||||
*ptr++ = dst[i];
|
||||
}
|
||||
dollar = 0;
|
||||
}
|
||||
else {
|
||||
if (dst[i] == '$') {
|
||||
dollar = 1;
|
||||
}
|
||||
else {
|
||||
*ptr++ = dst[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
char *res = uwsgi_malloc(dst_n + (src_n * dollars) + 1);
|
||||
char *ptr = res;
|
||||
|
||||
*ptr++ = 0;
|
||||
for (i = 0; i < dst_n; i++) {
|
||||
if (dollar) {
|
||||
if (isdigit((int) dst[i])) {
|
||||
int pos = (dst[i] - 48);
|
||||
if (pos <= n) {
|
||||
pos = pos * 2;
|
||||
memcpy(ptr, src + ovector[pos], ovector[pos + 1] - ovector[pos]);
|
||||
ptr += ovector[pos + 1] - ovector[pos];
|
||||
}
|
||||
}
|
||||
else {
|
||||
*ptr++ = '$';
|
||||
*ptr++ = dst[i];
|
||||
}
|
||||
dollar = 0;
|
||||
}
|
||||
else {
|
||||
if (dst[i] == '$') {
|
||||
dollar = 1;
|
||||
}
|
||||
else {
|
||||
*ptr++ = dst[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
*ptr++ = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+63
-644
@@ -1,226 +1,65 @@
|
||||
#ifdef UWSGI_ROUTING
|
||||
#include <uwsgi.h>
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_buffer *uwsgi_routing_translate(struct wsgi_request *wsgi_req, struct uwsgi_route *ur, char *subject, uint16_t subject_len, char *data, size_t data_len) {
|
||||
|
||||
char *pass1 = data;
|
||||
size_t pass1_len = data_len;
|
||||
|
||||
// cannot fail
|
||||
if (subject) {
|
||||
pass1 = uwsgi_regexp_apply_ovec(subject, subject_len, data, data_len, ur->ovector, ur->ovn);
|
||||
pass1_len = strlen(pass1);
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(pass1_len);
|
||||
size_t i;
|
||||
int status = 0;
|
||||
char *key = NULL;
|
||||
size_t keylen = 0;
|
||||
for(i=0;i<pass1_len;i++) {
|
||||
switch(status) {
|
||||
case 0:
|
||||
if (pass1[i] == '$') {
|
||||
status = 1;
|
||||
break;
|
||||
}
|
||||
if (uwsgi_buffer_append(ub, pass1 + i, 1)) goto error;
|
||||
break;
|
||||
case 1:
|
||||
if (pass1[i] == '{') {
|
||||
status = 2;
|
||||
key = pass1+i+1;
|
||||
keylen = 0;
|
||||
break;
|
||||
}
|
||||
status = 0;
|
||||
key = NULL;
|
||||
keylen = 0;
|
||||
if (uwsgi_buffer_append(ub, "$", 1)) goto error;
|
||||
if (uwsgi_buffer_append(ub, pass1 + i, 1)) goto error;
|
||||
break;
|
||||
case 2:
|
||||
if (pass1[i] == '}') {
|
||||
uint16_t vallen = 0;
|
||||
char *value = uwsgi_get_var(wsgi_req, key, keylen, &vallen);
|
||||
if (value) {
|
||||
if (uwsgi_buffer_append(ub, value, vallen)) goto error;
|
||||
}
|
||||
status = 0;
|
||||
key = NULL;
|
||||
keylen = 0;
|
||||
break;
|
||||
}
|
||||
keylen++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// fix the buffer
|
||||
if (status == 1) {
|
||||
if (uwsgi_buffer_append(ub, "$", 1)) goto error;
|
||||
}
|
||||
else if (status == 2) {
|
||||
if (uwsgi_buffer_append(ub, "${", 2)) goto error;
|
||||
if (keylen > 0) {
|
||||
if (uwsgi_buffer_append(ub, key, keylen)) goto error;
|
||||
}
|
||||
}
|
||||
|
||||
// add the final NULL byte (to simplify plugin work)
|
||||
if (uwsgi_buffer_append(ub, "\0", 1)) goto error;
|
||||
// .. but came back of 1 position to avoid accounting it
|
||||
ub->pos--;
|
||||
|
||||
if (pass1 != data) {
|
||||
free(pass1);
|
||||
}
|
||||
return ub;
|
||||
|
||||
error:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int uwsgi_apply_routes_do(struct wsgi_request *wsgi_req, char *subject, uint16_t subject_len) {
|
||||
|
||||
struct uwsgi_route *routes = uwsgi.routes;
|
||||
void *goon_func = NULL;
|
||||
int n = -1;
|
||||
|
||||
char *orig_subject = subject;
|
||||
uint16_t orig_subject_len = subject_len;
|
||||
|
||||
while (routes) {
|
||||
|
||||
if (wsgi_req->route_goto > 0 && wsgi_req->route_pc < wsgi_req->route_goto) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (goon_func && goon_func == routes->func) {
|
||||
goto next;
|
||||
}
|
||||
goon_func = NULL;
|
||||
wsgi_req->route_goto = 0;
|
||||
|
||||
if (!routes->if_func) {
|
||||
if (!subject) {
|
||||
char **subject2 = (char **) (((char *) (wsgi_req)) + routes->subject);
|
||||
uint16_t *subject_len2 = (uint16_t *) (((char *) (wsgi_req)) + routes->subject_len);
|
||||
subject = *subject2 ;
|
||||
subject_len = *subject_len2;
|
||||
}
|
||||
n = uwsgi_regexp_match_ovec(routes->pattern, routes->pattern_extra, subject, subject_len, routes->ovector, routes->ovn);
|
||||
}
|
||||
else {
|
||||
int ret = routes->if_func(wsgi_req, routes);
|
||||
// error
|
||||
if (ret < 0) {
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
// true
|
||||
if (!routes->if_negate) {
|
||||
if (ret == 0) {
|
||||
goto next;
|
||||
}
|
||||
n = ret;
|
||||
}
|
||||
else {
|
||||
if (ret > 0) {
|
||||
goto next;
|
||||
}
|
||||
n = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (n >= 0) {
|
||||
wsgi_req->is_routing = 1;
|
||||
int ret = routes->func(wsgi_req, routes);
|
||||
wsgi_req->is_routing = 0;
|
||||
if (ret == UWSGI_ROUTE_BREAK) {
|
||||
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].routed_requests++;
|
||||
return ret;
|
||||
}
|
||||
if (ret == UWSGI_ROUTE_CONTINUE) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret == UWSGI_ROUTE_GOON) {
|
||||
goon_func = routes->func;
|
||||
}
|
||||
}
|
||||
next:
|
||||
subject = orig_subject;
|
||||
subject_len = orig_subject_len;
|
||||
routes = routes->next;
|
||||
if (routes) wsgi_req->route_pc++;
|
||||
}
|
||||
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
}
|
||||
|
||||
int uwsgi_apply_routes(struct wsgi_request *wsgi_req) {
|
||||
|
||||
if (!uwsgi.routes)
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
struct uwsgi_route *routes = uwsgi.routes;
|
||||
|
||||
// avoid loops
|
||||
if (wsgi_req->is_routing)
|
||||
if (!routes)
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
|
||||
if (uwsgi_parse_vars(wsgi_req)) {
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
|
||||
// in case of static files serving previous rules could be applied
|
||||
if (wsgi_req->routes_applied) {
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
}
|
||||
|
||||
return uwsgi_apply_routes_do(wsgi_req, NULL, 0);
|
||||
}
|
||||
|
||||
static void *uwsgi_route_get_condition_func(char *name) {
|
||||
struct uwsgi_route_condition *urc = uwsgi.route_conditions;
|
||||
while(urc) {
|
||||
if (!strcmp(urc->name, name)) {
|
||||
return urc->func;
|
||||
while (routes) {
|
||||
char **subject = (char **) (((char *) (wsgi_req)) + routes->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *) (wsgi_req)) + routes->subject_len);
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("route subject = %.*s\n", *subject_len, *subject);
|
||||
#endif
|
||||
int n = uwsgi_regexp_match_ovec(routes->pattern, routes->pattern_extra, *subject, *subject_len, routes->ovector, routes->ovn);
|
||||
if (n >= 0) {
|
||||
int ret = routes->func(wsgi_req, routes);
|
||||
if (ret == UWSGI_ROUTE_BREAK) uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].routed_requests++;
|
||||
if (ret != UWSGI_ROUTE_NEXT) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
urc = urc->next;
|
||||
routes = routes->next;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
}
|
||||
|
||||
int uwsgi_apply_routes_fast(struct wsgi_request *wsgi_req, char *uri, int len) {
|
||||
|
||||
struct uwsgi_route *routes = uwsgi.routes;
|
||||
|
||||
if (!routes)
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
|
||||
while (routes) {
|
||||
int n = uwsgi_regexp_match_ovec(routes->pattern, routes->pattern_extra, uri, len, routes->ovector, routes->ovn);
|
||||
if (n >= 0) {
|
||||
int ret = routes->func(wsgi_req, routes);
|
||||
if (ret == UWSGI_ROUTE_BREAK) uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].routed_requests++;
|
||||
if (ret != UWSGI_ROUTE_NEXT) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
routes = routes->next;
|
||||
}
|
||||
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
|
||||
|
||||
struct uwsgi_route *old_ur = NULL,*ur = uwsgi.routes;
|
||||
uint64_t pos = 0;
|
||||
while(ur) {
|
||||
old_ur = ur;
|
||||
ur = ur->next;
|
||||
pos++;
|
||||
}
|
||||
ur = uwsgi_calloc(sizeof(struct uwsgi_route));
|
||||
if (old_ur) {
|
||||
old_ur->next = ur;
|
||||
}
|
||||
else {
|
||||
uwsgi.routes = ur;
|
||||
}
|
||||
|
||||
ur->pos = pos;
|
||||
|
||||
// is it a label ?
|
||||
if (foobar == NULL) {
|
||||
ur->label = value;
|
||||
ur->label_len = strlen(value);
|
||||
return;
|
||||
}
|
||||
|
||||
char *route = uwsgi_str(value);
|
||||
|
||||
char *space = strchr(route, ' ');
|
||||
@@ -231,27 +70,23 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
|
||||
|
||||
*space = 0;
|
||||
|
||||
if (!strcmp(foobar, "if") || !strcmp(foobar, "if-not")) {
|
||||
char *colon = strchr(route, ':');
|
||||
if (!colon) {
|
||||
uwsgi_log("invalid route condition syntax\n");
|
||||
exit(1);
|
||||
}
|
||||
*colon = 0;
|
||||
|
||||
if (!strcmp(foobar, "if-not")) {
|
||||
ur->if_negate = 1;
|
||||
}
|
||||
|
||||
foobar = colon+1;
|
||||
ur->if_func = uwsgi_route_get_condition_func(route);
|
||||
if (!ur->if_func) {
|
||||
uwsgi_log("unable to find \"%s\" route condition\n", route);
|
||||
exit(1);
|
||||
struct uwsgi_route *ur = uwsgi.routes;
|
||||
if (!ur) {
|
||||
uwsgi.routes = uwsgi_calloc(sizeof(struct uwsgi_route));
|
||||
ur = uwsgi.routes;
|
||||
}
|
||||
else {
|
||||
while (ur) {
|
||||
if (!ur->next) {
|
||||
ur->next = uwsgi_calloc(sizeof(struct uwsgi_route));
|
||||
ur = ur->next;
|
||||
break;
|
||||
}
|
||||
ur = ur->next;
|
||||
}
|
||||
}
|
||||
|
||||
else if (!strcmp(foobar, "http_host")) {
|
||||
if (!strcmp(foobar, "http_host")) {
|
||||
ur->subject = offsetof(struct wsgi_request, host);
|
||||
ur->subject_len = offsetof(struct wsgi_request, host_len);
|
||||
}
|
||||
@@ -263,44 +98,21 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
|
||||
ur->subject = offsetof(struct wsgi_request, query_string);
|
||||
ur->subject_len = offsetof(struct wsgi_request, query_string_len);
|
||||
}
|
||||
else if (!strcmp(foobar, "remote_addr")) {
|
||||
ur->subject = offsetof(struct wsgi_request, remote_addr);
|
||||
ur->subject_len = offsetof(struct wsgi_request, remote_addr_len);
|
||||
}
|
||||
else if (!strcmp(foobar, "user_agent")) {
|
||||
ur->subject = offsetof(struct wsgi_request, user_agent);
|
||||
ur->subject_len = offsetof(struct wsgi_request, user_agent_len);
|
||||
}
|
||||
else if (!strcmp(foobar, "referer")) {
|
||||
ur->subject = offsetof(struct wsgi_request, referer);
|
||||
ur->subject_len = offsetof(struct wsgi_request, referer_len);
|
||||
}
|
||||
else if (!strcmp(foobar, "remote_user")) {
|
||||
ur->subject = offsetof(struct wsgi_request, remote_user);
|
||||
ur->subject_len = offsetof(struct wsgi_request, remote_user_len);
|
||||
}
|
||||
else {
|
||||
ur->subject = offsetof(struct wsgi_request, path_info);
|
||||
ur->subject_len = offsetof(struct wsgi_request, path_info_len);
|
||||
}
|
||||
|
||||
ur->subject_str = foobar;
|
||||
ur->subject_str_len = strlen(ur->subject_str);
|
||||
ur->regexp = route;
|
||||
if (uwsgi_regexp_build(route, &ur->pattern, &ur->pattern_extra)) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (ur->subject && ur->subject_len) {
|
||||
if (uwsgi_regexp_build(route, &ur->pattern, &ur->pattern_extra)) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ur->ovn = uwsgi_regexp_ovector(ur->pattern, ur->pattern_extra);
|
||||
if (ur->ovn > 0) {
|
||||
ur->ovector = uwsgi_calloc(sizeof(int) * (3 * (ur->ovn + 1)));
|
||||
}
|
||||
ur->ovn = uwsgi_regexp_ovector(ur->pattern, ur->pattern_extra);
|
||||
if (ur->ovn > 0) {
|
||||
ur->ovector = uwsgi_calloc(sizeof(int) * (3 * (ur->ovn + 1)));
|
||||
}
|
||||
|
||||
char *command = space + 1;
|
||||
ur->action = uwsgi_str(command);
|
||||
|
||||
char *colon = strchr(command, ':');
|
||||
if (!colon) {
|
||||
@@ -326,7 +138,6 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
|
||||
last_ur->is_last = 1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
r = r->next;
|
||||
}
|
||||
@@ -335,358 +146,6 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int uwsgi_route_api_func(struct wsgi_request *wsgi_req, char *router, char *args) {
|
||||
struct uwsgi_route *ur = NULL;
|
||||
struct uwsgi_router *r = uwsgi.routers;
|
||||
while(r) {
|
||||
if (!strcmp(router, r->name)) {
|
||||
goto found;
|
||||
}
|
||||
r = r->next;
|
||||
}
|
||||
free(args);
|
||||
return -1;
|
||||
found:
|
||||
ur = uwsgi_calloc(sizeof(struct uwsgi_route));
|
||||
// initialize the virtual route
|
||||
if (r->func(ur, args)) {
|
||||
free(ur);
|
||||
free(args);
|
||||
return -1;
|
||||
}
|
||||
// call it
|
||||
int ret = ur->func(wsgi_req, ur);
|
||||
if (ur->free) {
|
||||
ur->free(ur);
|
||||
}
|
||||
free(ur);
|
||||
free(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// continue/last route
|
||||
|
||||
static int uwsgi_router_continue_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
}
|
||||
|
||||
static int uwsgi_router_continue(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_continue_func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// break route
|
||||
|
||||
static int uwsgi_router_break_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
|
||||
if (route->data_len >= 3) {
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, route->data, route->data_len)) goto end;
|
||||
if (uwsgi_response_add_connection_close(wsgi_req)) goto end;
|
||||
if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) goto end;
|
||||
// no need to check for return value
|
||||
uwsgi_response_write_headers_do(wsgi_req);
|
||||
}
|
||||
end:
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
|
||||
static int uwsgi_router_break(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_break_func;
|
||||
ur->data = arg;
|
||||
ur->data_len = strlen(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// goon route
|
||||
static int uwsgi_router_goon_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
|
||||
return UWSGI_ROUTE_GOON;
|
||||
}
|
||||
static int uwsgi_router_goon(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_goon_func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// log route
|
||||
static int uwsgi_router_log_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
|
||||
uwsgi_log("%.*s\n", ub->pos, ub->buf);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
static int uwsgi_router_log(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_log_func;
|
||||
ur->data = arg;
|
||||
ur->data_len = strlen(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// logvar route
|
||||
static int uwsgi_router_logvar_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data2, ur->data2_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
uwsgi_logvar_add(wsgi_req, ur->data, ur->data_len, ub->buf, ub->pos);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
static int uwsgi_router_logvar(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_logvar_func;
|
||||
char *equal = strchr(arg, '=');
|
||||
if (!equal) {
|
||||
uwsgi_log("invalid logvar syntax, must be key=value\n");
|
||||
exit(1);
|
||||
}
|
||||
ur->data = arg;
|
||||
ur->data_len = equal-arg;
|
||||
ur->data2 = equal+1;
|
||||
ur->data2_len = strlen(ur->data2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// goto route
|
||||
|
||||
static int uwsgi_router_goto_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
// build the label (if needed)
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
|
||||
// find the label
|
||||
struct uwsgi_route *routes = uwsgi.routes;
|
||||
while(routes) {
|
||||
if (!routes->label) goto next;
|
||||
if (!uwsgi_strncmp(routes->label, routes->label_len, ub->buf, ub->pos)) {
|
||||
wsgi_req->route_goto = routes->pos;
|
||||
goto found;
|
||||
}
|
||||
next:
|
||||
routes = routes->next;
|
||||
}
|
||||
|
||||
wsgi_req->route_goto = ur->custom;
|
||||
|
||||
found:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
if (wsgi_req->route_goto <= wsgi_req->route_pc) {
|
||||
wsgi_req->route_goto = 0;
|
||||
uwsgi_log("[uwsgi-route] ERROR \"goto\" instruction can only jump forward (check your label !!!)\n");
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
static int uwsgi_router_goto(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_goto_func;
|
||||
ur->data = arg;
|
||||
ur->data_len = strlen(arg);
|
||||
ur->custom = atoi(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// addvar route
|
||||
static int uwsgi_router_addvar_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data2, ur->data2_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
|
||||
if (!uwsgi_req_append(wsgi_req, ur->data, ur->data_len, ub->buf, ub->pos)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_router_addvar(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_addvar_func;
|
||||
char *equal = strchr(arg, '=');
|
||||
if (!equal) {
|
||||
uwsgi_log("[uwsgi-route] invalid addvar syntax, must be KEY=VAL\n");
|
||||
exit(1);
|
||||
}
|
||||
ur->data = arg;
|
||||
ur->data_len = equal-arg;
|
||||
ur->data2 = equal+1;
|
||||
ur->data2_len = strlen(ur->data2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// addheader route
|
||||
static int uwsgi_router_addheader_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
uwsgi_additional_header_add(wsgi_req, ub->buf, ub->pos);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_router_addheader(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_addheader_func;
|
||||
ur->data = arg;
|
||||
ur->data_len = strlen(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// remheader route
|
||||
static int uwsgi_router_remheader_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
uwsgi_remove_header(wsgi_req, ub->buf, ub->pos);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_router_remheader(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_remheader_func;
|
||||
ur->data = arg;
|
||||
ur->data_len = strlen(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// signal route
|
||||
static int uwsgi_router_signal_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
|
||||
uwsgi_signal_send(uwsgi.signal_socket, route->custom);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
static int uwsgi_router_signal(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_signal_func;
|
||||
ur->custom = atoi(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// send route
|
||||
static int uwsgi_router_send_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
|
||||
uwsgi_response_write_body_do(wsgi_req, route->data, route->data_len);
|
||||
if (route->custom) {
|
||||
uwsgi_response_write_body_do(wsgi_req, "\r\n", 2);
|
||||
}
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
static int uwsgi_router_send(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_send_func;
|
||||
ur->data = arg;
|
||||
ur->data_len = strlen(arg);
|
||||
return 0;
|
||||
}
|
||||
static int uwsgi_router_send_crnl(struct uwsgi_route *ur, char *arg) {
|
||||
uwsgi_router_send(ur, arg);
|
||||
ur->custom = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_route_condition_exists(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len);
|
||||
if (!ub) return -1;
|
||||
if (uwsgi_file_exists(ub->buf)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 1;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_route_condition_isfile(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len);
|
||||
if (!ub) return -1;
|
||||
if (uwsgi_is_file(ub->buf)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 1;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_route_condition_isdir(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len);
|
||||
if (!ub) return -1;
|
||||
if (uwsgi_is_dir(ub->buf)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 1;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_route_condition_islink(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len);
|
||||
if (!ub) return -1;
|
||||
if (uwsgi_is_link(ub->buf)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 1;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_route_condition_isexec(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len);
|
||||
if (!ub) return -1;
|
||||
if (!access(ub->buf, X_OK)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 1;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// register embedded routers
|
||||
void uwsgi_register_embedded_routers() {
|
||||
uwsgi_register_router("continue", uwsgi_router_continue);
|
||||
uwsgi_register_router("last", uwsgi_router_continue);
|
||||
uwsgi_register_router("break", uwsgi_router_break);
|
||||
uwsgi_register_router("goon", uwsgi_router_goon);
|
||||
uwsgi_register_router("log", uwsgi_router_log);
|
||||
uwsgi_register_router("logvar", uwsgi_router_logvar);
|
||||
uwsgi_register_router("goto", uwsgi_router_goto);
|
||||
uwsgi_register_router("addvar", uwsgi_router_addvar);
|
||||
uwsgi_register_router("addheader", uwsgi_router_addheader);
|
||||
uwsgi_register_router("delheader", uwsgi_router_remheader);
|
||||
uwsgi_register_router("remheader", uwsgi_router_remheader);
|
||||
uwsgi_register_router("signal", uwsgi_router_signal);
|
||||
uwsgi_register_router("send", uwsgi_router_send);
|
||||
uwsgi_register_router("send-crnl", uwsgi_router_send_crnl);
|
||||
|
||||
uwsgi_register_route_condition("exists", uwsgi_route_condition_exists);
|
||||
uwsgi_register_route_condition("isfile", uwsgi_route_condition_isfile);
|
||||
uwsgi_register_route_condition("isdir", uwsgi_route_condition_isdir);
|
||||
uwsgi_register_route_condition("islink", uwsgi_route_condition_islink);
|
||||
uwsgi_register_route_condition("isexec", uwsgi_route_condition_isexec);
|
||||
}
|
||||
|
||||
struct uwsgi_router *uwsgi_register_router(char *name, int (*func) (struct uwsgi_route *, char *)) {
|
||||
|
||||
struct uwsgi_router *ur = uwsgi.routers;
|
||||
@@ -710,44 +169,4 @@ struct uwsgi_router *uwsgi_register_router(char *name, int (*func) (struct uwsgi
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_route_condition *uwsgi_register_route_condition(char *name, int (*func) (struct wsgi_request *, struct uwsgi_route *)) {
|
||||
struct uwsgi_route_condition *old_urc = NULL,*urc = uwsgi.route_conditions;
|
||||
while(urc) {
|
||||
if (!strcmp(urc->name, name)) {
|
||||
return urc;
|
||||
}
|
||||
old_urc = urc;
|
||||
urc = urc->next;
|
||||
}
|
||||
|
||||
urc = uwsgi_calloc(sizeof(struct uwsgi_route_condition));
|
||||
urc->name = name;
|
||||
urc->func = func;
|
||||
|
||||
if (old_urc) {
|
||||
old_urc->next = urc;
|
||||
}
|
||||
else {
|
||||
uwsgi.route_conditions = urc;
|
||||
}
|
||||
|
||||
return urc;
|
||||
}
|
||||
|
||||
void uwsgi_routing_dump() {
|
||||
struct uwsgi_route *routes = uwsgi.routes;
|
||||
if (!routes) return;
|
||||
uwsgi_log("*** dumping internal routing table ***\n");
|
||||
while(routes) {
|
||||
if (routes->label) {
|
||||
uwsgi_log("[rule: %llu] label: %s\n", (unsigned long long ) routes->pos, routes->label);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[rule: %llu] subject: %s %s: %s%s action: %s\n", (unsigned long long ) routes->pos, routes->subject_str, routes->if_func ? "func" : "regexp", routes->if_negate ? "!" : "", routes->regexp, routes->action);
|
||||
}
|
||||
routes = routes->next;
|
||||
}
|
||||
uwsgi_log("*** end of the internal routing table ***\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
+42
-78
@@ -7,51 +7,25 @@ int uwsgi_register_rpc(char *name, uint8_t modifier1, uint8_t args, void *func)
|
||||
struct uwsgi_rpc *urpc;
|
||||
int ret = -1;
|
||||
|
||||
if (uwsgi.mywid == 0 && uwsgi.workers[0].pid != uwsgi.mypid) {
|
||||
uwsgi_log("only the master and the workers can register RPC functions\n");
|
||||
if (uwsgi.mywid != 0) {
|
||||
uwsgi_log("you can register RPC functions only in the master\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_lock(uwsgi.rpc_table_lock);
|
||||
|
||||
// first check if a function is already registered
|
||||
size_t i;
|
||||
for(i=0;i<uwsgi.shared->rpc_count[uwsgi.mywid];i++) {
|
||||
int pos = (uwsgi.mywid * uwsgi.rpc_max) + i;
|
||||
urpc = &uwsgi.rpc_table[pos];
|
||||
if (!strcmp(name, urpc->name)) {
|
||||
goto already;
|
||||
}
|
||||
}
|
||||
if (uwsgi.shared->rpc_count < MAX_RPC) {
|
||||
urpc = &uwsgi.shared->rpc_table[uwsgi.shared->rpc_count];
|
||||
|
||||
if (uwsgi.shared->rpc_count[uwsgi.mywid] < uwsgi.rpc_max) {
|
||||
int pos = (uwsgi.mywid * uwsgi.rpc_max) + uwsgi.shared->rpc_count[uwsgi.mywid];
|
||||
urpc = &uwsgi.rpc_table[pos];
|
||||
uwsgi.shared->rpc_count[uwsgi.mywid]++;
|
||||
already:
|
||||
memcpy(urpc->name, name, strlen(name));
|
||||
urpc->modifier1 = modifier1;
|
||||
urpc->args = args;
|
||||
urpc->func = func;
|
||||
urpc->shared = uwsgi.mywid == 0 ? 1 : 0;
|
||||
|
||||
uwsgi.shared->rpc_count++;
|
||||
|
||||
ret = 0;
|
||||
if (uwsgi.mywid == 0) {
|
||||
uwsgi_log("registered shared/inherited RPC function \"%s\"\n", name);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("registered RPC function \"%s\" on worker %d\n", name, uwsgi.mywid);
|
||||
}
|
||||
}
|
||||
|
||||
// implement cow
|
||||
if (uwsgi.mywid == 0) {
|
||||
int i;
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
uwsgi.shared->rpc_count[i] = uwsgi.shared->rpc_count[0];
|
||||
int pos = (i * uwsgi.rpc_max);
|
||||
memcpy(&uwsgi.rpc_table[pos], uwsgi.rpc_table, sizeof(struct uwsgi_rpc) * uwsgi.rpc_max);
|
||||
}
|
||||
uwsgi_log("registered RPC function %s\n", name);
|
||||
}
|
||||
|
||||
uwsgi_unlock(uwsgi.rpc_table_lock);
|
||||
@@ -62,15 +36,13 @@ already:
|
||||
uint16_t uwsgi_rpc(char *name, uint8_t argc, char *argv[], uint16_t argvs[], char *output) {
|
||||
|
||||
struct uwsgi_rpc *urpc = NULL;
|
||||
uint64_t i;
|
||||
int i;
|
||||
uint16_t ret = 0;
|
||||
|
||||
int pos = (uwsgi.mywid * uwsgi.rpc_max);
|
||||
|
||||
for (i = 0; i < uwsgi.shared->rpc_count[uwsgi.mywid]; i++) {
|
||||
if (uwsgi.rpc_table[pos + i].name[0] != 0) {
|
||||
if (!strcmp(uwsgi.rpc_table[pos + i].name, name)) {
|
||||
urpc = &uwsgi.rpc_table[pos + i];
|
||||
for (i = 0; i < uwsgi.shared->rpc_count; i++) {
|
||||
if (uwsgi.shared->rpc_table[i].name[0] != 0) {
|
||||
if (!strcmp(uwsgi.shared->rpc_table[i].name, name)) {
|
||||
urpc = &uwsgi.shared->rpc_table[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -90,31 +62,25 @@ char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t
|
||||
|
||||
uint8_t i;
|
||||
uint16_t ulen;
|
||||
struct uwsgi_header *uh = NULL;
|
||||
struct uwsgi_header uh;
|
||||
char *buffer = NULL;
|
||||
|
||||
*len = 0;
|
||||
|
||||
if (node == NULL || !strcmp(node, "")) {
|
||||
// allocate the whole buffer
|
||||
buffer = uwsgi_malloc(UMAX16);
|
||||
buffer = uwsgi_malloc(65536);
|
||||
*len = uwsgi_rpc(func, argc, argv, argvs, buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
// connect to node (async way)
|
||||
int fd = uwsgi_connect(node, 0, 1);
|
||||
// connect to node
|
||||
int fd = uwsgi_connect(node, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], 0);
|
||||
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
// wait for connection;
|
||||
int ret = uwsgi.wait_write_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (ret <= 0) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// prepare a uwsgi array
|
||||
uint16_t buffer_size = 2 + strlen(func);
|
||||
|
||||
@@ -123,16 +89,14 @@ char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t
|
||||
}
|
||||
|
||||
// allocate the whole buffer
|
||||
buffer = uwsgi_malloc(4+buffer_size);
|
||||
buffer = uwsgi_malloc(65536);
|
||||
|
||||
// set the uwsgi header
|
||||
uh = (struct uwsgi_header *) buffer;
|
||||
uh->modifier1 = 173;
|
||||
uh->pktsize = buffer_size;
|
||||
uh->modifier2 = 0;
|
||||
uh.modifier1 = 173;
|
||||
uh.pktsize = buffer_size;
|
||||
uh.modifier2 = 0;
|
||||
|
||||
// add func to the array
|
||||
char *bufptr = buffer + 4;
|
||||
char *bufptr = buffer;
|
||||
ulen = strlen(func);
|
||||
*bufptr++ = (uint8_t) (ulen & 0xff);
|
||||
*bufptr++ = (uint8_t) ((ulen >> 8) & 0xff);
|
||||
@@ -147,33 +111,33 @@ char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t
|
||||
bufptr += ulen;
|
||||
}
|
||||
|
||||
// ok the reuqest is ready, let's send it in non blocking way
|
||||
if (uwsgi_write_true_nb(fd, buffer, buffer_size+4, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
|
||||
goto error;
|
||||
if (write(fd, &uh, 4) != 4) {
|
||||
uwsgi_error("write()");
|
||||
close(fd);
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// ok time to wait for the response in non blocking way
|
||||
size_t rlen = buffer_size+4;
|
||||
if (uwsgi_read_with_realloc(fd, &buffer, &rlen, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
|
||||
goto error;
|
||||
if (write(fd, buffer, buffer_size) != buffer_size) {
|
||||
uwsgi_error("write()");
|
||||
close(fd);
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (uwsgi_read_response(fd, &uh, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], &buffer) < 0) {
|
||||
close(fd);
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
*len = rlen;
|
||||
|
||||
*len = uh.pktsize;
|
||||
if (*len == 0) {
|
||||
goto error;
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
return buffer;
|
||||
|
||||
error:
|
||||
close(fd);
|
||||
free(buffer);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_rpc_init() {
|
||||
uwsgi.rpc_table = uwsgi_calloc_shared((sizeof(struct uwsgi_rpc) * uwsgi.rpc_max) * (uwsgi.numproc+1));
|
||||
uwsgi.shared->rpc_count = uwsgi_calloc_shared(sizeof(uint64_t) * (uwsgi.numproc+1));
|
||||
}
|
||||
|
||||
+163
-28
@@ -2,38 +2,173 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
// sendfile() abstraction
|
||||
ssize_t uwsgi_sendfile_do(int sockfd, int filefd, size_t pos, size_t len) {
|
||||
ssize_t uwsgi_sendfile(struct wsgi_request * wsgi_req) {
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
off_t sf_len = len;
|
||||
int sf_ret = sendfile(filefd, sockfd, pos, len, NULL, &sf_len, 0);
|
||||
if (sf_ret == 0 || (sf_ret == -1 && errno == EAGAIN)) return sf_len;
|
||||
return -1;
|
||||
#elif defined(__APPLE__)
|
||||
off_t sf_len = len;
|
||||
int sf_ret = sendfile(filefd, sockfd, pos, &sf_len, NULL, 0);
|
||||
if (sf_ret == 0 || (sf_ret == -1 && errno == EAGAIN)) return sf_len;
|
||||
return -1;
|
||||
#elif defined(__linux__) || defined(__sun__)
|
||||
off_t off = pos;
|
||||
return sendfile(sockfd, filefd, &off, len);
|
||||
#else
|
||||
// for platform not supporting sendfile we need to rely on boring read/write
|
||||
// generally that platforms have very low memory, so use a 8k buffer
|
||||
char buf[8192];
|
||||
if (pos > 0) {
|
||||
if (lseek(filefd, pos, SEEK_SET)) {
|
||||
uwsgi_error("uwsgi_sendfile_do()/seek()");
|
||||
return -1;
|
||||
int fd = wsgi_req->sendfile_fd;
|
||||
int sockfd = wsgi_req->poll.fd;
|
||||
struct stat stat_buf;
|
||||
ssize_t sst = 0;
|
||||
|
||||
if (!wsgi_req->sendfile_fd_size) {
|
||||
|
||||
if (fstat(fd, &stat_buf)) {
|
||||
uwsgi_error("fstat()");
|
||||
goto end;
|
||||
}
|
||||
else {
|
||||
wsgi_req->sendfile_fd_size = stat_buf.st_size;
|
||||
}
|
||||
}
|
||||
ssize_t rlen = read(filefd, buf, UMIN(len, 8192));
|
||||
if (rlen <= 0) {
|
||||
uwsgi_error("uwsgi_sendfile_do()/read()");
|
||||
return -1;
|
||||
|
||||
if (wsgi_req->sendfile_fd_size) {
|
||||
|
||||
if (!wsgi_req->sendfile_fd_chunk)
|
||||
wsgi_req->sendfile_fd_chunk = 4096;
|
||||
|
||||
if (wsgi_req->socket->proto_sendfile) {
|
||||
sst = wsgi_req->socket->proto_sendfile(wsgi_req);
|
||||
}
|
||||
else {
|
||||
sst = uwsgi_do_sendfile(sockfd, wsgi_req->sendfile_fd, wsgi_req->sendfile_fd_size, wsgi_req->sendfile_fd_chunk, &wsgi_req->sendfile_fd_pos, uwsgi.async);
|
||||
}
|
||||
|
||||
}
|
||||
return write(sockfd, buf, rlen);
|
||||
|
||||
end:
|
||||
return sst;
|
||||
}
|
||||
|
||||
ssize_t uwsgi_do_sendfile(int sockfd, int filefd, size_t filesize, size_t chunk, off_t * pos, int async) {
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
|
||||
int sf_ret;
|
||||
|
||||
off_t sf_len = filesize;
|
||||
|
||||
if (async > 1) {
|
||||
sf_len = chunk;
|
||||
sf_ret = sendfile(filefd, sockfd, *pos, 0, NULL, &sf_len, 0);
|
||||
*pos += sf_len;
|
||||
}
|
||||
else {
|
||||
sf_ret = sendfile(filefd, sockfd, 0, 0, NULL, &sf_len, 0);
|
||||
}
|
||||
|
||||
if (sf_ret < 0) {
|
||||
if (errno != EAGAIN) {
|
||||
uwsgi_error("sendfile()");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return sf_len;
|
||||
#elif defined(__APPLE__)
|
||||
int sf_ret;
|
||||
off_t sf_len = filesize;
|
||||
|
||||
if (async > 1) {
|
||||
sf_len = chunk;
|
||||
sf_ret = sendfile(filefd, sockfd, *pos, &sf_len, NULL, 0);
|
||||
*pos += sf_len;
|
||||
}
|
||||
else {
|
||||
sf_ret = sendfile(filefd, sockfd, 0, &sf_len, NULL, 0);
|
||||
}
|
||||
|
||||
if (sf_ret) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("sf_len = %d\n", sf_len);
|
||||
#endif
|
||||
uwsgi_error("sendfile()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sf_len;
|
||||
|
||||
#elif defined(__linux__) || defined(__sun__)
|
||||
int sf_ret;
|
||||
size_t written = 0;
|
||||
|
||||
if (async > 1) {
|
||||
sf_ret = sendfile(sockfd, filefd, pos, chunk);
|
||||
if (sf_ret < 0) {
|
||||
uwsgi_error("sendfile()");
|
||||
return 0;
|
||||
}
|
||||
return sf_ret;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
#else
|
||||
static size_t nosf_buf_size = 0;
|
||||
static char *nosf_buf;
|
||||
char *nosf_buf2;
|
||||
|
||||
ssize_t jlen = 0;
|
||||
ssize_t rlen = 0;
|
||||
ssize_t i = 0;
|
||||
|
||||
if (!nosf_buf) {
|
||||
nosf_buf = malloc(chunk);
|
||||
}
|
||||
else if (chunk != nosf_buf_size) {
|
||||
nosf_buf2 = realloc(nosf_buf, chunk);
|
||||
if (!nosf_buf2) {
|
||||
free(nosf_buf);
|
||||
}
|
||||
nosf_buf = nosf_buf2;
|
||||
}
|
||||
|
||||
if (!nosf_buf) {
|
||||
uwsgi_error("sendfile malloc()/realloc()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
nosf_buf_size = chunk;
|
||||
|
||||
if (async > 1) {
|
||||
jlen = read(filefd, nosf_buf, chunk);
|
||||
if (jlen <= 0) {
|
||||
uwsgi_error("read()");
|
||||
return 0;
|
||||
}
|
||||
jlen = write(sockfd, nosf_buf, jlen);
|
||||
if (jlen <= 0) {
|
||||
uwsgi_error("write()");
|
||||
return 0;
|
||||
}
|
||||
return jlen;
|
||||
}
|
||||
|
||||
while (i < (int) filesize) {
|
||||
jlen = read(filefd, nosf_buf, chunk);
|
||||
if (jlen <= 0) {
|
||||
uwsgi_error("read()");
|
||||
break;
|
||||
}
|
||||
i += jlen;
|
||||
jlen = write(sockfd, nosf_buf, jlen);
|
||||
if (jlen <= 0) {
|
||||
uwsgi_error("write()");
|
||||
break;
|
||||
}
|
||||
rlen += jlen;
|
||||
}
|
||||
|
||||
return rlen;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
+9
-2
@@ -106,11 +106,13 @@ void uwsgi_setup_inherited_sockets() {
|
||||
//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 (j == uwsgi.emperor_fd_config)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uwsgi.shared->worker_log_pipe[0] > -1) {
|
||||
@@ -128,6 +130,11 @@ void uwsgi_setup_inherited_sockets() {
|
||||
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) {
|
||||
|
||||
+12
-27
@@ -6,9 +6,7 @@ int uwsgi_signal_handler(uint8_t sig) {
|
||||
|
||||
struct uwsgi_signal_entry *use = NULL;
|
||||
|
||||
int pos = (uwsgi.mywid * 256) + sig;
|
||||
|
||||
use = &uwsgi.shared->signal_table[pos];
|
||||
use = &uwsgi.shared->signal_table[sig];
|
||||
|
||||
if (!use->handler)
|
||||
return -1;
|
||||
@@ -57,11 +55,13 @@ int uwsgi_signal_handler(uint8_t sig) {
|
||||
set_mule_harakiri(uwsgi.shared->options[UWSGI_OPTION_MULE_HARAKIRI]);
|
||||
}
|
||||
}
|
||||
#ifdef UWSGI_SPOOLER
|
||||
else if (uwsgi.i_am_a_spooler && (getpid() == uwsgi.i_am_a_spooler->pid)) {
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
|
||||
set_spooler_harakiri(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int ret = uwsgi.p[use->modifier1]->signal_handler(sig, use->handler);
|
||||
|
||||
@@ -77,19 +77,20 @@ int uwsgi_signal_handler(uint8_t sig) {
|
||||
set_mule_harakiri(0);
|
||||
}
|
||||
}
|
||||
#ifdef UWSGI_SPOOLER
|
||||
else if (uwsgi.i_am_a_spooler && (getpid() == uwsgi.i_am_a_spooler->pid)) {
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
|
||||
set_spooler_harakiri(0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int uwsgi_signal_registered(uint8_t sig) {
|
||||
|
||||
int pos = (uwsgi.mywid * 256) + sig;
|
||||
if (uwsgi.shared->signal_table[pos].handler != NULL)
|
||||
if (uwsgi.shared->signal_table[sig].handler != NULL)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@@ -99,23 +100,15 @@ int uwsgi_register_signal(uint8_t sig, char *receiver, void *handler, uint8_t mo
|
||||
|
||||
struct uwsgi_signal_entry *use = NULL;
|
||||
|
||||
if (!uwsgi.master_process) return -1;
|
||||
|
||||
if (uwsgi.mywid == 0 && uwsgi.workers[0].pid != uwsgi.mypid) {
|
||||
uwsgi_log("only the master and the workers can register signal handlers\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strlen(receiver) > 63)
|
||||
return -1;
|
||||
|
||||
uwsgi_lock(uwsgi.signal_table_lock);
|
||||
|
||||
int pos = (uwsgi.mywid * 256) + sig;
|
||||
use = &uwsgi.shared->signal_table[pos];
|
||||
use = &uwsgi.shared->signal_table[sig];
|
||||
|
||||
if (use->handler && uwsgi.mywid == 0) {
|
||||
uwsgi_log("[uwsgi-signal] you cannot re-register a signal as the master !!!\n");
|
||||
if (use->handler) {
|
||||
uwsgi_log("[uwsgi-signal] you cannot re-register a signal !!!\n");
|
||||
uwsgi_unlock(uwsgi.signal_table_lock);
|
||||
return -1;
|
||||
}
|
||||
@@ -132,15 +125,6 @@ int uwsgi_register_signal(uint8_t sig, char *receiver, void *handler, uint8_t mo
|
||||
uwsgi_log("[uwsgi-signal] signum %d registered (wid: %d modifier1: %d target: %s)\n", sig, uwsgi.mywid, modifier1, receiver);
|
||||
}
|
||||
|
||||
// check for cow
|
||||
if (uwsgi.mywid == 0) {
|
||||
int i;
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
int pos = (i * 256);
|
||||
memcpy(&uwsgi.shared->signal_table[pos], use, sizeof(struct uwsgi_signal_entry) * 256);
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_unlock(uwsgi.signal_table_lock);
|
||||
|
||||
return 0;
|
||||
@@ -442,8 +426,7 @@ int uwsgi_signal_send(int fd, uint8_t sig) {
|
||||
|
||||
void uwsgi_route_signal(uint8_t sig) {
|
||||
|
||||
int pos = (uwsgi.mywid * 256) + sig;
|
||||
struct uwsgi_signal_entry *use = &ushared->signal_table[pos];
|
||||
struct uwsgi_signal_entry *use = &ushared->signal_table[sig];
|
||||
int i;
|
||||
|
||||
// send to first available worker
|
||||
@@ -474,6 +457,7 @@ void uwsgi_route_signal(uint8_t sig) {
|
||||
else if (!strcmp(use->receiver, "subscribed")) {
|
||||
}
|
||||
// route to spooler
|
||||
#ifdef UWSGI_SPOOLER
|
||||
else if (!strcmp(use->receiver, "spooler")) {
|
||||
if (ushared->worker_signal_pipe[0] != -1) {
|
||||
if (uwsgi_signal_send(ushared->spooler_signal_pipe[0], sig)) {
|
||||
@@ -481,6 +465,7 @@ void uwsgi_route_signal(uint8_t sig) {
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (!strcmp(use->receiver, "mules")) {
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
if (uwsgi_signal_send(uwsgi.mules[i].signal_pipe[0], sig)) {
|
||||
|
||||
+6
-15
@@ -1,4 +1,6 @@
|
||||
#include <uwsgi.h>
|
||||
#ifdef UWSGI_SNMP
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
@@ -406,17 +408,6 @@ int uwsgi_setup_snmp(void) {
|
||||
|
||||
return snmp_fd;
|
||||
}
|
||||
|
||||
void uwsgi_master_manage_snmp(int snmp_fd) {
|
||||
struct sockaddr_in udp_client;
|
||||
socklen_t udp_len = sizeof(udp_client);
|
||||
ssize_t rlen = recvfrom(snmp_fd, uwsgi.wsgi_req->buffer, uwsgi.buffer_size, 0, (struct sockaddr *) &udp_client, &udp_len);
|
||||
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("recvfrom()");
|
||||
}
|
||||
else if (rlen > 0) {
|
||||
manage_snmp(snmp_fd, (uint8_t *) uwsgi.wsgi_req->buffer, rlen, &udp_client);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#warning "*** SNMP support is disabled ***"
|
||||
#endif
|
||||
|
||||
+133
-152
@@ -2,23 +2,6 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
static int uwsgi_socket_strcmp(char *sock1, char *sock2) {
|
||||
size_t sock1_len = strlen(sock1);
|
||||
size_t sock2_len = strlen(sock2);
|
||||
|
||||
if (!uwsgi_starts_with(sock1, sock1_len, "0.0.0.0:", 8)) {
|
||||
sock1 += 7;
|
||||
sock1_len = strlen(sock1);
|
||||
}
|
||||
|
||||
if (!uwsgi_starts_with(sock2, sock2_len, "0.0.0.0:", 8)) {
|
||||
sock2 += 7;
|
||||
sock2_len = strlen(sock2);
|
||||
}
|
||||
|
||||
return uwsgi_strncmp(sock1, sock1_len, sock2, sock2_len);
|
||||
}
|
||||
|
||||
char *uwsgi_getsockname(int fd) {
|
||||
|
||||
socklen_t socket_type_len = sizeof(struct sockaddr_un);
|
||||
@@ -185,6 +168,7 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst
|
||||
return serverfd;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_UDP
|
||||
int bind_to_udp(char *socket_name, int multicast, int broadcast) {
|
||||
int serverfd;
|
||||
struct sockaddr_in uws_addr;
|
||||
@@ -192,7 +176,10 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
|
||||
int bcast = 1;
|
||||
int reuse = 1;
|
||||
|
||||
#ifdef UWSGI_MULTICAST
|
||||
struct ip_mreq mc;
|
||||
uint8_t loop = 1;
|
||||
#endif
|
||||
|
||||
udp_port = strchr(socket_name, ':');
|
||||
if (udp_port == NULL) {
|
||||
@@ -209,6 +196,7 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
|
||||
uws_addr.sin_family = AF_INET;
|
||||
uws_addr.sin_port = htons(atoi(udp_port + 1));
|
||||
|
||||
#ifdef UWSGI_MULTICAST
|
||||
if (!broadcast && !multicast) {
|
||||
char quad[4];
|
||||
char *first_part = strchr(socket_name, '.');
|
||||
@@ -219,6 +207,9 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
|
||||
multicast = 1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (!broadcast) {
|
||||
#endif
|
||||
if (!strcmp(socket_name, "255.255.255.255")) {
|
||||
broadcast = 1;
|
||||
}
|
||||
@@ -245,12 +236,14 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
|
||||
uwsgi_error("setsockopt()");
|
||||
}
|
||||
|
||||
#ifdef UWSGI_MULTICAST
|
||||
if (multicast) {
|
||||
// if multicast is enabled remember to bind to INADDR_ANY
|
||||
uws_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
mc.imr_multiaddr.s_addr = inet_addr(socket_name);
|
||||
mc.imr_interface.s_addr = INADDR_ANY;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (broadcast) {
|
||||
if (setsockopt(serverfd, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast))) {
|
||||
@@ -266,9 +259,10 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_MULTICAST
|
||||
if (multicast) {
|
||||
uwsgi_log("[uwsgi-mcast] joining multicast group: %s:%d\n", socket_name, ntohs(uws_addr.sin_port));
|
||||
if (setsockopt(serverfd, IPPROTO_IP, IP_MULTICAST_LOOP, &uwsgi.multicast_loop, sizeof(uwsgi.multicast_loop))) {
|
||||
uwsgi_log("[uWSGI] joining multicast group: %s:%d\n", socket_name, ntohs(uws_addr.sin_port));
|
||||
if (setsockopt(serverfd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop))) {
|
||||
uwsgi_error("setsockopt()");
|
||||
}
|
||||
|
||||
@@ -281,11 +275,13 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
udp_port[0] = ':';
|
||||
return serverfd;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
int uwsgi_connectn(char *socket_name, uint16_t len, int timeout, int async) {
|
||||
|
||||
@@ -478,7 +474,7 @@ char *generate_socket_name(char *socket_name) {
|
||||
|
||||
}
|
||||
|
||||
uwsgi_log("unable to find a valid socket address\n");
|
||||
uwsgi_log("unable to find avalid socket address\n");
|
||||
#endif
|
||||
uwsgi_nuclear_blast();
|
||||
}
|
||||
@@ -551,30 +547,12 @@ socklen_t socket_to_in_addr(char *socket_name, char *port, int portn, struct soc
|
||||
int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
|
||||
|
||||
int serverfd;
|
||||
#ifdef AF_INET6
|
||||
struct sockaddr_in6 uws_addr;
|
||||
#else
|
||||
struct sockaddr_in uws_addr;
|
||||
#endif
|
||||
int reuse = 1;
|
||||
int family = AF_INET;
|
||||
socklen_t addr_len = sizeof(struct sockaddr_in);
|
||||
|
||||
#ifdef AF_INET6
|
||||
if (socket_name[0] == '[' && tcp_port[-1] == ']') {
|
||||
family = AF_INET6;
|
||||
socket_to_in_addr6(socket_name, tcp_port, 0, &uws_addr);
|
||||
addr_len = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
socket_to_in_addr(socket_name, tcp_port, 0, (struct sockaddr_in *) &uws_addr);
|
||||
#ifdef AF_INET6
|
||||
}
|
||||
#endif
|
||||
socket_to_in_addr(socket_name, tcp_port, 0, &uws_addr);
|
||||
|
||||
|
||||
serverfd = socket(family, SOCK_STREAM, 0);
|
||||
serverfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (serverfd < 0) {
|
||||
uwsgi_error("socket()");
|
||||
uwsgi_nuclear_blast();
|
||||
@@ -608,19 +586,6 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
|
||||
#endif
|
||||
}
|
||||
|
||||
if (uwsgi.tcp_fast_open) {
|
||||
#ifdef TCP_FASTOPEN
|
||||
if (setsockopt(serverfd, SOL_TCP, TCP_FASTOPEN, (const void *) &uwsgi.tcp_fast_open, sizeof(int)) < 0) {
|
||||
uwsgi_error("TCP_FASTOPEN setsockopt()");
|
||||
}
|
||||
else {
|
||||
uwsgi_log("TCP_FASTOPEN enabled on %s\n", socket_name);
|
||||
}
|
||||
#else
|
||||
uwsgi_log("!!! your system does not support TCP_FASTOPEN !!!\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (uwsgi.so_send_timeout) {
|
||||
struct timeval tv;
|
||||
tv.tv_sec = uwsgi.so_send_timeout;
|
||||
@@ -656,7 +621,7 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
|
||||
}
|
||||
|
||||
|
||||
if (bind(serverfd, (struct sockaddr *) &uws_addr, addr_len) != 0) {
|
||||
if (bind(serverfd, (struct sockaddr *) &uws_addr, sizeof(uws_addr)) != 0) {
|
||||
if (errno == EADDRINUSE) {
|
||||
uwsgi_log("probably another instance of uWSGI is running on the same address (%s).\n", socket_name);
|
||||
}
|
||||
@@ -667,7 +632,7 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
|
||||
#ifdef __linux__
|
||||
long somaxconn = uwsgi_num_from_file("/proc/sys/net/core/somaxconn", 1);
|
||||
if (somaxconn > 0 && uwsgi.listen_queue > somaxconn) {
|
||||
uwsgi_log("Listen queue size is greater than the system max net.core.somaxconn (%li).\n", somaxconn);
|
||||
uwsgi_log("Listen queue size is greater than the system max net.core.somaxconn (%i).\n", somaxconn);
|
||||
uwsgi_nuclear_blast();
|
||||
}
|
||||
#endif
|
||||
@@ -742,16 +707,7 @@ int timed_connect(struct pollfd *fdpoll, const struct sockaddr *addr, int addr_s
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MSG_FASTOPEN
|
||||
if (addr->sa_family == AF_INET && uwsgi.tcp_fast_open_client) {
|
||||
ret = sendto(fdpoll->fd, "", 0, MSG_FASTOPEN, addr, addr_size);
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
ret = connect(fdpoll->fd, addr, addr_size);
|
||||
#ifdef MSG_FASTOPEN
|
||||
}
|
||||
#endif
|
||||
ret = connect(fdpoll->fd, addr, addr_size);
|
||||
|
||||
if (async) {
|
||||
if (ret < 0 && errno != EINPROGRESS) {
|
||||
@@ -967,7 +923,6 @@ struct uwsgi_socket *uwsgi_new_socket(char *name) {
|
||||
char *auto_port = uwsgi_num2str(ntohs(sin.sin_port));
|
||||
char *auto_ip = inet_ntoa(sin.sin_addr);
|
||||
uwsgi_sock->name = uwsgi_concat3n(auto_ip, strlen(auto_ip), ":", 1, auto_port, strlen(auto_port));
|
||||
free(auto_port);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1087,7 +1042,7 @@ void uwsgi_add_socket_from_fd(struct uwsgi_socket *uwsgi_sock, int fd) {
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef AF_INET6
|
||||
#ifdef UWSGI_IPV6
|
||||
else if (gsa.sa->sa_family == AF_INET6) {
|
||||
char *computed_addr;
|
||||
char computed_port[6];
|
||||
@@ -1403,7 +1358,87 @@ nextsock:
|
||||
}
|
||||
|
||||
|
||||
#ifdef AF_INET6
|
||||
#ifdef UWSGI_IPV6
|
||||
int bind_to_tcp6(char *socket_name, int listen_queue, char *tcp_port) {
|
||||
|
||||
int serverfd;
|
||||
struct sockaddr_in6 uws_addr;
|
||||
int reuse = 1;
|
||||
|
||||
socket_to_in_addr6(socket_name, tcp_port, 0, &uws_addr);
|
||||
|
||||
serverfd = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
if (serverfd < 0) {
|
||||
uwsgi_error("socket()");
|
||||
uwsgi_nuclear_blast();
|
||||
}
|
||||
|
||||
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) {
|
||||
uwsgi_error("setsockopt()");
|
||||
uwsgi_nuclear_blast();
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
#ifdef IP_FREEBIND
|
||||
if (uwsgi.freebind) {
|
||||
if (setsockopt(serverfd, SOL_IP, IP_FREEBIND, (const void *) &uwsgi.freebind, sizeof(int)) < 0) {
|
||||
uwsgi_error("setsockopt()");
|
||||
uwsgi_nuclear_blast();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (uwsgi.reuse_port) {
|
||||
#ifdef SO_REUSEPORT
|
||||
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEPORT, (const void *) &uwsgi.reuse_port, sizeof(int)) < 0) {
|
||||
uwsgi_error("setsockopt()");
|
||||
uwsgi_nuclear_blast();
|
||||
}
|
||||
#else
|
||||
uwsgi_log("!!! your system does not support SO_REUSEPORT !!!\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!uwsgi.no_defer_accept) {
|
||||
|
||||
#ifdef __linux__
|
||||
if (setsockopt(serverfd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], sizeof(int))) {
|
||||
uwsgi_error("setsockopt()");
|
||||
}
|
||||
// OSX has no SO_ACCEPTFILTER !!!
|
||||
#elif defined(__freebsd__)
|
||||
struct accept_filter_arg afa;
|
||||
strcpy(afa.af_name, "dataready");
|
||||
afa.af_arg[0] = 0;
|
||||
if (setsockopt(serverfd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(struct accept_filter_arg))) {
|
||||
uwsgi_error("setsockopt()");
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (bind(serverfd, (struct sockaddr *) &uws_addr, sizeof(uws_addr)) != 0) {
|
||||
if (errno == EADDRINUSE) {
|
||||
uwsgi_log("probably another instance of uWSGI is running on the same address.\n");
|
||||
}
|
||||
uwsgi_error("bind()");
|
||||
uwsgi_nuclear_blast();
|
||||
}
|
||||
|
||||
if (listen(serverfd, listen_queue) != 0) {
|
||||
uwsgi_error("listen()");
|
||||
uwsgi_nuclear_blast();
|
||||
}
|
||||
|
||||
|
||||
if (tcp_port)
|
||||
tcp_port[0] = ':';
|
||||
|
||||
return serverfd;
|
||||
}
|
||||
|
||||
socklen_t socket_to_in_addr6(char *socket_name, char *port, int portn, struct sockaddr_in6 * sin_addr) {
|
||||
|
||||
memset(sin_addr, 0, sizeof(struct sockaddr_in6));
|
||||
@@ -1459,9 +1494,9 @@ void uwsgi_setup_shared_sockets() {
|
||||
uwsgi_log("uwsgi shared socket %d bound to UNIX address %s fd %d\n", uwsgi_get_shared_socket_num(shared_sock), shared_sock->name, shared_sock->fd);
|
||||
}
|
||||
else {
|
||||
#ifdef AF_INET6
|
||||
#ifdef UWSGI_IPV6
|
||||
if (shared_sock->name[0] == '[' && tcp_port[-1] == ']') {
|
||||
shared_sock->fd = bind_to_tcp(shared_sock->name, uwsgi.listen_queue, tcp_port);
|
||||
shared_sock->fd = bind_to_tcp6(shared_sock->name, uwsgi.listen_queue, tcp_port);
|
||||
shared_sock->family = AF_INET6;
|
||||
// fix socket name
|
||||
shared_sock->name = uwsgi_getsockname(shared_sock->fd);
|
||||
@@ -1474,7 +1509,7 @@ void uwsgi_setup_shared_sockets() {
|
||||
// fix socket name
|
||||
shared_sock->name = uwsgi_getsockname(shared_sock->fd);
|
||||
uwsgi_log("uwsgi shared socket %d bound to TCP address %s fd %d\n", uwsgi_get_shared_socket_num(shared_sock), shared_sock->name, shared_sock->fd);
|
||||
#ifdef AF_INET6
|
||||
#ifdef UWSGI_IPV6
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1493,7 +1528,7 @@ void uwsgi_setup_shared_sockets() {
|
||||
for (i = 3; i < (int) uwsgi.max_fd; i++) {
|
||||
char *sock = uwsgi_getsockname(i);
|
||||
if (sock) {
|
||||
if (!uwsgi_socket_strcmp(sock, shared_sock->name)) {
|
||||
if (!strcmp(sock, shared_sock->name)) {
|
||||
if (strchr(sock, ':')) {
|
||||
uwsgi_log("uwsgi shared socket %d inherited TCP address %s fd %d\n", uwsgi_get_shared_socket_num(shared_sock), sock, i);
|
||||
shared_sock->family = AF_INET;
|
||||
@@ -1504,7 +1539,9 @@ void uwsgi_setup_shared_sockets() {
|
||||
}
|
||||
shared_sock->fd = i;
|
||||
}
|
||||
free(sock);
|
||||
else {
|
||||
free(sock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1618,9 +1655,9 @@ void uwsgi_bind_sockets() {
|
||||
uwsgi_log("uwsgi socket %d bound to UNIX address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd);
|
||||
}
|
||||
else {
|
||||
#ifdef AF_INET6
|
||||
#ifdef UWSGI_IPV6
|
||||
if (uwsgi_sock->name[0] == '[' && tcp_port[-1] == ']') {
|
||||
uwsgi_sock->fd = bind_to_tcp(uwsgi_sock->name, uwsgi.listen_queue, tcp_port);
|
||||
uwsgi_sock->fd = bind_to_tcp6(uwsgi_sock->name, uwsgi.listen_queue, tcp_port);
|
||||
uwsgi_log("uwsgi socket %d bound to TCP6 address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd);
|
||||
uwsgi_sock->family = AF_INET6;
|
||||
}
|
||||
@@ -1629,7 +1666,7 @@ void uwsgi_bind_sockets() {
|
||||
uwsgi_sock->fd = bind_to_tcp(uwsgi_sock->name, uwsgi.listen_queue, tcp_port);
|
||||
uwsgi_log("uwsgi socket %d bound to TCP address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd);
|
||||
uwsgi_sock->family = AF_INET;
|
||||
#ifdef AF_INET6
|
||||
#ifdef UWSGI_IPV6
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1705,14 +1742,14 @@ void uwsgi_bind_sockets() {
|
||||
uwsgi_sock = uwsgi.sockets;
|
||||
while (uwsgi_sock) {
|
||||
if (uwsgi_sock->auto_port) {
|
||||
#ifdef AF_INET6
|
||||
#ifdef UWSGI_IPV6
|
||||
if (uwsgi_sock->family == AF_INET6) {
|
||||
uwsgi_log("uwsgi socket %d bound to TCP6 address %s (port auto-assigned) fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd);
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
uwsgi_log("uwsgi socket %d bound to TCP address %s (port auto-assigned) fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd);
|
||||
#ifdef AF_INET6
|
||||
#ifdef UWSGI_IPV6
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1723,7 +1760,6 @@ void uwsgi_bind_sockets() {
|
||||
}
|
||||
|
||||
void uwsgi_set_sockets_protocols() {
|
||||
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
while (uwsgi_sock) {
|
||||
char *requested_protocol = uwsgi_sock->proto_name;
|
||||
@@ -1745,7 +1781,6 @@ void uwsgi_set_sockets_protocols() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
setup_proto:
|
||||
if (!requested_protocol) {
|
||||
requested_protocol = uwsgi.protocol;
|
||||
@@ -1754,70 +1789,28 @@ setup_proto:
|
||||
if (requested_protocol && !strcmp("http", requested_protocol)) {
|
||||
uwsgi_sock->proto = uwsgi_proto_http_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_uwsgi_write;
|
||||
uwsgi_sock->proto_writev = uwsgi_proto_uwsgi_writev;
|
||||
uwsgi_sock->proto_write_header = uwsgi_proto_uwsgi_write_header;
|
||||
uwsgi_sock->proto_writev_header = uwsgi_proto_uwsgi_writev_header;
|
||||
uwsgi_sock->proto_sendfile = NULL;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_base_close;
|
||||
if (uwsgi.offload_threads > 0)
|
||||
uwsgi_sock->can_offload = 1;
|
||||
}
|
||||
|
||||
else if (requested_protocol && (!strcmp("fastcgi", requested_protocol) || !strcmp("fcgi", requested_protocol))) {
|
||||
if (uwsgi.protocol && (!strcmp(uwsgi.protocol, "fastcgi") || !strcmp(uwsgi.protocol, "fcgi"))) {
|
||||
uwsgi.shared->options[UWSGI_OPTION_CGI_MODE] = 1;
|
||||
}
|
||||
uwsgi_sock->proto = uwsgi_proto_fastcgi_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_cgi_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_fastcgi_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_writev = uwsgi_proto_fastcgi_writev;
|
||||
uwsgi_sock->proto_write_header = uwsgi_proto_fastcgi_write_header;
|
||||
uwsgi_sock->proto_writev_header = uwsgi_proto_fastcgi_writev_header;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_fastcgi_close;
|
||||
}
|
||||
else if (requested_protocol && (!strcmp("fastcgi-nph", requested_protocol) || !strcmp("fcgi-nph", requested_protocol))) {
|
||||
uwsgi_sock->proto = uwsgi_proto_fastcgi_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_fastcgi_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_fastcgi_close;
|
||||
}
|
||||
|
||||
else if (requested_protocol && (!strcmp("scgi", requested_protocol) || !strcmp("scgi", requested_protocol))) {
|
||||
uwsgi_sock->proto = uwsgi_proto_scgi_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_cgi_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_base_close;
|
||||
}
|
||||
|
||||
else if (requested_protocol && (!strcmp("scgi-nph", requested_protocol) || !strcmp("scgi-nph", requested_protocol))) {
|
||||
uwsgi_sock->proto = uwsgi_proto_scgi_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_base_close;
|
||||
}
|
||||
|
||||
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
else if (requested_protocol && !strcmp("zmq", requested_protocol)) {
|
||||
uwsgi.zeromq = 1;
|
||||
@@ -1826,13 +1819,11 @@ setup_proto:
|
||||
else {
|
||||
uwsgi_sock->proto = uwsgi_proto_uwsgi_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_uwsgi_write;
|
||||
uwsgi_sock->proto_writev = uwsgi_proto_uwsgi_writev;
|
||||
uwsgi_sock->proto_write_header = uwsgi_proto_uwsgi_write_header;
|
||||
uwsgi_sock->proto_writev_header = uwsgi_proto_uwsgi_writev_header;
|
||||
uwsgi_sock->proto_sendfile = NULL;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_base_close;
|
||||
if (uwsgi.offload_threads > 0)
|
||||
uwsgi_sock->can_offload = 1;
|
||||
@@ -1843,13 +1834,3 @@ nextsock:
|
||||
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_tcp_nodelay(int fd) {
|
||||
#ifdef TCP_NODELAY
|
||||
int flag = 1;
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int))) {
|
||||
uwsgi_error("uwsgi_tcp_nodelay()/setsockopt()");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+7
-2
@@ -1,3 +1,4 @@
|
||||
#ifdef UWSGI_SPOOLER
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
@@ -254,7 +255,7 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core
|
||||
close(fd);
|
||||
|
||||
if (!uwsgi.spooler_quiet)
|
||||
uwsgi_log("[spooler] written %lu bytes to file %s\n", (unsigned long) size + body_len + 4, filename);
|
||||
uwsgi_log("[spooler] written %d bytes to file %s\n", size + body_len + 4, filename);
|
||||
|
||||
// and here waiting threads can continue
|
||||
uwsgi_unlock(uspool->lock);
|
||||
@@ -547,7 +548,7 @@ void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) {
|
||||
uspool->tasks++;
|
||||
if (ret == -2) {
|
||||
if (!uwsgi.spooler_quiet)
|
||||
uwsgi_log("[spooler %s pid: %d] done with task %s after %lld seconds\n", uspool->dir, (int) uwsgi.mypid, task, (long long) uwsgi_now() - now);
|
||||
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
|
||||
@@ -583,3 +584,7 @@ void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#warning "*** Spooler support is disabled ***"
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ extern struct uwsgi_server uwsgi;
|
||||
static int uwsgi_sqlite3_config_callback(void *magic_table, int field_count, char **fields, char **col) {
|
||||
// make a copy of the string
|
||||
if (field_count >= 2) {
|
||||
size_t value_len = strlen(fields[1]) + 1;
|
||||
int value_len = strlen(fields[1]) + 1;
|
||||
char *value = magic_sub(fields[1], value_len, &value_len, (char **) magic_table);
|
||||
add_exported_option(uwsgi_strncopy(fields[0], strlen(fields[0])), value, 0);
|
||||
}
|
||||
|
||||
-499
@@ -1,499 +0,0 @@
|
||||
#include "../uwsgi.h"
|
||||
#include <openssl/rand.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
/*
|
||||
|
||||
ssl additional datas are retrieved via indexes.
|
||||
|
||||
You can create an index with SSL_CTX_get_ex_new_index and
|
||||
set data in it with SSL_CTX_set_ex_data
|
||||
|
||||
*/
|
||||
|
||||
void uwsgi_ssl_init(void) {
|
||||
OPENSSL_config(NULL);
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
OpenSSL_add_all_algorithms();
|
||||
uwsgi.ssl_initialized = 1;
|
||||
}
|
||||
|
||||
void uwsgi_ssl_info_cb(SSL const *ssl, int where, int ret) {
|
||||
if (where & SSL_CB_HANDSHAKE_DONE) {
|
||||
if (ssl->s3) {
|
||||
ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int uwsgi_ssl_verify_callback(int ok, X509_STORE_CTX * x509_store) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int uwsgi_ssl_session_new_cb(SSL *ssl, SSL_SESSION *sess) {
|
||||
char session_blob[4096];
|
||||
int len = i2d_SSL_SESSION(sess, NULL);
|
||||
if (len > 4096) {
|
||||
if (uwsgi.ssl_verbose) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to store session of size %d\n", len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char *p = (unsigned char *) session_blob;
|
||||
i2d_SSL_SESSION(sess, &p);
|
||||
|
||||
// ok let's write the value to the cache
|
||||
uwsgi_wlock(uwsgi.ssl_sessions_cache->lock);
|
||||
if (uwsgi_cache_set2(uwsgi.ssl_sessions_cache, (char *) sess->session_id, sess->session_id_length, session_blob, len, uwsgi.ssl_sessions_timeout, 0)) {
|
||||
if (uwsgi.ssl_verbose) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to store session of size %d in the cache\n", len);
|
||||
}
|
||||
}
|
||||
uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SSL_SESSION *uwsgi_ssl_session_get_cb(SSL *ssl, unsigned char *key, int keylen, int *copy) {
|
||||
|
||||
uint64_t valsize = 0;
|
||||
|
||||
*copy = 0;
|
||||
uwsgi_rlock(uwsgi.ssl_sessions_cache->lock);
|
||||
char *value = uwsgi_cache_get2(uwsgi.ssl_sessions_cache, (char *)key, keylen, &valsize);
|
||||
if (!value) {
|
||||
uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock);
|
||||
if (uwsgi.ssl_verbose) {
|
||||
uwsgi_log("[uwsgi-ssl] cache miss\n");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
SSL_SESSION *sess = d2i_SSL_SESSION(NULL, (const unsigned char **)&value, valsize);
|
||||
uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock);
|
||||
return sess;
|
||||
}
|
||||
|
||||
void uwsgi_ssl_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess) {
|
||||
uwsgi_wlock(uwsgi.ssl_sessions_cache->lock);
|
||||
if (uwsgi_cache_del2(uwsgi.ssl_sessions_cache, (char *) sess->session_id, sess->session_id_length, 0, 0)) {
|
||||
if (uwsgi.ssl_verbose) {
|
||||
uwsgi_log("[uwsgi-ssl] error removing cache item\n");
|
||||
}
|
||||
}
|
||||
uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock);
|
||||
}
|
||||
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
static int uwsgi_sni_cb(SSL *ssl, int *ad, void *arg) {
|
||||
const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
|
||||
if (!servername) return SSL_TLSEXT_ERR_NOACK;
|
||||
size_t servername_len = strlen(servername);
|
||||
|
||||
struct uwsgi_string_list *usl = uwsgi.sni;
|
||||
while(usl) {
|
||||
if (!uwsgi_strncmp(usl->value, usl->len, (char *)servername, servername_len)) {
|
||||
SSL_set_SSL_CTX(ssl, usl->custom_ptr);
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
struct uwsgi_regexp_list *url = uwsgi.sni_regexp;
|
||||
while(url) {
|
||||
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, (char *)servername, servername_len) >= 0) {
|
||||
SSL_set_SSL_CTX(ssl, url->custom_ptr);
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
url = url->next;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (uwsgi.sni_dir) {
|
||||
size_t sni_dir_len = strlen(uwsgi.sni_dir);
|
||||
char *sni_dir_cert = uwsgi_concat4n(uwsgi.sni_dir, sni_dir_len, "/", 1, (char *) servername, servername_len, ".crt", 4);
|
||||
char *sni_dir_key = uwsgi_concat4n(uwsgi.sni_dir, sni_dir_len, "/", 1, (char *) servername, servername_len, ".key", 4);
|
||||
char *sni_dir_client_ca = uwsgi_concat4n(uwsgi.sni_dir, sni_dir_len, "/", 1, (char *) servername, servername_len, ".ca", 3);
|
||||
if (uwsgi_file_exists(sni_dir_cert) && uwsgi_file_exists(sni_dir_key)) {
|
||||
char *client_ca = NULL;
|
||||
if (uwsgi_file_exists(sni_dir_client_ca)) {
|
||||
client_ca = sni_dir_client_ca;
|
||||
}
|
||||
usl = uwsgi_ssl_add_sni_item(uwsgi_str((char *)servername), sni_dir_cert, sni_dir_key, uwsgi.sni_dir_ciphers, client_ca);
|
||||
if (!usl) goto done;
|
||||
free(sni_dir_cert);
|
||||
free(sni_dir_key);
|
||||
free(sni_dir_client_ca);
|
||||
SSL_set_SSL_CTX(ssl, usl->custom_ptr);
|
||||
uwsgi_log("[uwsgi-sni for pid %d] added context for %s\n", (int) getpid(), servername);
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
done:
|
||||
free(sni_dir_cert);
|
||||
free(sni_dir_key);
|
||||
free(sni_dir_client_ca);
|
||||
}
|
||||
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
#endif
|
||||
|
||||
SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ciphers, char *client_ca) {
|
||||
|
||||
SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
|
||||
if (!ctx) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to initialize context \"%s\"\n", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// this part is taken from nginx and stud, removing unneeded functionality
|
||||
// stud (for me) has made the best choice on choosing DH approach
|
||||
|
||||
long ssloptions = SSL_OP_NO_SSLv2 | SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION;
|
||||
// disable compression (if possibile)
|
||||
#ifdef SSL_OP_NO_COMPRESSION
|
||||
ssloptions |= SSL_OP_NO_COMPRESSION;
|
||||
#endif
|
||||
|
||||
// release/reuse buffers as soon as possibile
|
||||
#ifdef SSL_MODE_RELEASE_BUFFERS
|
||||
SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
|
||||
#endif
|
||||
|
||||
if (SSL_CTX_use_certificate_chain_file(ctx, crt) <= 0) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to assign certificate %s for context \"%s\"\n", crt, name);
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// this part is based from stud
|
||||
BIO *bio = BIO_new_file(crt, "r");
|
||||
if (bio) {
|
||||
DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
|
||||
BIO_free(bio);
|
||||
if (dh) {
|
||||
SSL_CTX_set_tmp_dh(ctx, dh);
|
||||
DH_free(dh);
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
|
||||
#ifndef OPENSSL_NO_ECDH
|
||||
#ifdef NID_X9_62_prime256v1
|
||||
EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||||
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
|
||||
EC_KEY_free(ecdh);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) <= 0) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to assign key %s for context \"%s\"\n", key, name);
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// if ciphers are specified, prefer server ciphers
|
||||
if (ciphers && strlen(ciphers) > 0) {
|
||||
if (SSL_CTX_set_cipher_list(ctx, ciphers) == 0) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to set requested ciphers (%s) for context \"%s\"\n", ciphers, name);
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssloptions |= SSL_OP_CIPHER_SERVER_PREFERENCE;
|
||||
}
|
||||
|
||||
// set session context (if possibile), this is required for client certificate authentication
|
||||
if (name) {
|
||||
SSL_CTX_set_session_id_context(ctx, (unsigned char *) name, strlen(name));
|
||||
}
|
||||
|
||||
if (client_ca) {
|
||||
if (client_ca[0] == '!') {
|
||||
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, uwsgi_ssl_verify_callback);
|
||||
client_ca++;
|
||||
}
|
||||
else {
|
||||
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, uwsgi_ssl_verify_callback);
|
||||
}
|
||||
// in the future we should allow to set the verify depth
|
||||
SSL_CTX_set_verify_depth(ctx, 1);
|
||||
if (SSL_CTX_load_verify_locations(ctx, client_ca, NULL) == 0) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to set ssl verify locations (%s) for context \"%s\"\n", client_ca, name);
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
STACK_OF(X509_NAME) * list = SSL_load_client_CA_file(client_ca);
|
||||
if (!list) {
|
||||
uwsgi_log("unable to load client CA certificate (%s) for context \"%s\"\n", client_ca, name);
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SSL_CTX_set_client_CA_list(ctx, list);
|
||||
}
|
||||
|
||||
|
||||
SSL_CTX_set_info_callback(ctx, uwsgi_ssl_info_cb);
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
SSL_CTX_set_tlsext_servername_callback(ctx, uwsgi_sni_cb);
|
||||
#endif
|
||||
|
||||
// disable session caching by default
|
||||
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
|
||||
|
||||
if (uwsgi.ssl_sessions_use_cache) {
|
||||
|
||||
// we need to early initialize locking and caching
|
||||
uwsgi_setup_locking();
|
||||
uwsgi_cache_create_all();
|
||||
|
||||
uwsgi.ssl_sessions_cache = uwsgi_cache_by_name(uwsgi.ssl_sessions_use_cache);
|
||||
if (!uwsgi.ssl_sessions_cache) {
|
||||
uwsgi_log("unable to find cache \"%s\"\n", uwsgi.ssl_sessions_use_cache ? uwsgi.ssl_sessions_use_cache : "default");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!uwsgi.ssl_sessions_cache->max_items) {
|
||||
uwsgi_log("you have to enable uWSGI cache to use it as SSL session store !!!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (uwsgi.ssl_sessions_cache->blocksize < 4096) {
|
||||
uwsgi_log("cache blocksize for SSL session store must be at least 4096 bytes\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER|
|
||||
SSL_SESS_CACHE_NO_INTERNAL|
|
||||
SSL_SESS_CACHE_NO_AUTO_CLEAR);
|
||||
|
||||
#ifdef SSL_OP_NO_TICKET
|
||||
ssloptions |= SSL_OP_NO_TICKET;
|
||||
#endif
|
||||
|
||||
// just for fun
|
||||
SSL_CTX_sess_set_cache_size(ctx, 0);
|
||||
|
||||
// set the callback for ssl sessions
|
||||
SSL_CTX_sess_set_new_cb(ctx, uwsgi_ssl_session_new_cb);
|
||||
SSL_CTX_sess_set_get_cb(ctx, uwsgi_ssl_session_get_cb);
|
||||
SSL_CTX_sess_set_remove_cb(ctx, uwsgi_ssl_session_remove_cb);
|
||||
}
|
||||
|
||||
SSL_CTX_set_timeout(ctx, uwsgi.ssl_sessions_timeout);
|
||||
|
||||
SSL_CTX_set_options(ctx, ssloptions);
|
||||
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_rsa_sign(char *algo_key, char *message, size_t message_len, unsigned int *s_len) {
|
||||
|
||||
// openssl could not be initialized
|
||||
if (!uwsgi.ssl_initialized) {
|
||||
uwsgi_ssl_init();
|
||||
}
|
||||
|
||||
*s_len = 0;
|
||||
EVP_PKEY *pk = NULL;
|
||||
|
||||
char *algo = uwsgi_str(algo_key);
|
||||
char *colon = strchr(algo, ':');
|
||||
if (!colon) {
|
||||
uwsgi_log("invalid RSA signature syntax, must be: <digest>:<pemfile>\n");
|
||||
free(algo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*colon = 0;
|
||||
char *keyfile = colon + 1;
|
||||
char *signature = NULL;
|
||||
|
||||
FILE *kf = fopen(keyfile, "r");
|
||||
if (!kf) {
|
||||
uwsgi_error_open(keyfile);
|
||||
free(algo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (PEM_read_PrivateKey(kf, &pk, NULL, NULL) == 0) {
|
||||
uwsgi_log("unable to load private key: %s\n", keyfile);
|
||||
free(algo);
|
||||
fclose(kf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fclose(kf);
|
||||
|
||||
EVP_MD_CTX *ctx = EVP_MD_CTX_create();
|
||||
if (!ctx) {
|
||||
free(algo);
|
||||
EVP_PKEY_free(pk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const EVP_MD *md = EVP_get_digestbyname(algo);
|
||||
if (!md) {
|
||||
uwsgi_log("unknown digest algo: %s\n", algo);
|
||||
free(algo);
|
||||
EVP_PKEY_free(pk);
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*s_len = EVP_PKEY_size(pk);
|
||||
signature = uwsgi_malloc(*s_len);
|
||||
|
||||
if (EVP_SignInit_ex(ctx, md, NULL) == 0) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
free(signature);
|
||||
signature = NULL;
|
||||
*s_len = 0;
|
||||
goto clear;
|
||||
}
|
||||
|
||||
if (EVP_SignUpdate(ctx, message, message_len) == 0) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
free(signature);
|
||||
signature = NULL;
|
||||
*s_len = 0;
|
||||
goto clear;
|
||||
}
|
||||
|
||||
|
||||
if (EVP_SignFinal(ctx, (unsigned char *) signature, s_len, pk) == 0) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
free(signature);
|
||||
signature = NULL;
|
||||
*s_len = 0;
|
||||
goto clear;
|
||||
}
|
||||
|
||||
clear:
|
||||
free(algo);
|
||||
EVP_PKEY_free(pk);
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
return signature;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_sanitize_cert_filename(char *base, char *key, uint16_t keylen) {
|
||||
uint16_t i;
|
||||
char *filename = uwsgi_concat4n(base, strlen(base), "/", 1, key, keylen, ".pem\0", 5);
|
||||
|
||||
for (i = strlen(base) + 1; i < (strlen(base) + 1) + keylen; i++) {
|
||||
if (filename[i] >= '0' && filename[i] <= '9')
|
||||
continue;
|
||||
if (filename[i] >= 'A' && filename[i] <= 'Z')
|
||||
continue;
|
||||
if (filename[i] >= 'a' && filename[i] <= 'z')
|
||||
continue;
|
||||
if (filename[i] == '.')
|
||||
continue;
|
||||
if (filename[i] == '-')
|
||||
continue;
|
||||
if (filename[i] == '_')
|
||||
continue;
|
||||
filename[i] = '_';
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
char *uwsgi_ssl_rand(size_t len) {
|
||||
unsigned char *buf = uwsgi_calloc(len+1);
|
||||
if (RAND_bytes(buf, len) <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
return (char *) buf;
|
||||
}
|
||||
|
||||
char *uwsgi_sha1(char *src, size_t len, char *dst) {
|
||||
SHA_CTX sha;
|
||||
SHA1_Init(&sha);
|
||||
SHA1_Update(&sha, src, len);
|
||||
SHA1_Final((unsigned char *)dst, &sha);
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *uwsgi_sha1_2n(char *s1, size_t len1, char *s2, size_t len2, char *dst) {
|
||||
SHA_CTX sha;
|
||||
SHA1_Init(&sha);
|
||||
SHA1_Update(&sha, s1, len1);
|
||||
SHA1_Update(&sha, s2, len2);
|
||||
SHA1_Final((unsigned char *)dst, &sha);
|
||||
return dst;
|
||||
}
|
||||
|
||||
void uwsgi_opt_sni(char *opt, char *value, void *foobar) {
|
||||
char *client_ca = NULL;
|
||||
char *v = uwsgi_str(value);
|
||||
|
||||
char *space = strchr(v, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid %s syntax, must be sni_key<space>crt,key[,ciphers,client_ca]\n", opt);
|
||||
exit(1);
|
||||
}
|
||||
*space = 0;
|
||||
char *crt = space+1;
|
||||
char *key = strchr(crt, ',');
|
||||
if (!key) {
|
||||
uwsgi_log("invalid %s syntax, must be sni_key<space>crt,key[,ciphers,client_ca]\n", opt);
|
||||
exit(1);
|
||||
}
|
||||
*key = '\0'; key++;
|
||||
|
||||
char *ciphers = strchr(key, ',');
|
||||
if (ciphers) {
|
||||
*ciphers = '\0'; ciphers++;
|
||||
client_ca = strchr(ciphers, ',');
|
||||
if (client_ca) {
|
||||
*client_ca = '\0'; client_ca++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!uwsgi.ssl_initialized) {
|
||||
uwsgi_ssl_init();
|
||||
}
|
||||
|
||||
SSL_CTX *ctx = uwsgi_ssl_new_server_context(v, crt, key, ciphers, client_ca);
|
||||
if (!ctx) {
|
||||
uwsgi_log("[uwsgi-ssl] DANGER unable to initialize context for \"%s\"\n", v);
|
||||
free(v);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
if (!strcmp(opt, "sni-regexp")) {
|
||||
struct uwsgi_regexp_list *url = uwsgi_regexp_new_list(&uwsgi.sni_regexp, v);
|
||||
url->custom_ptr = ctx;
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
struct uwsgi_string_list *usl = uwsgi_string_new_list(&uwsgi.sni, v);
|
||||
usl->custom_ptr = ctx;
|
||||
#ifdef UWSGI_PCRE
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_string_list *uwsgi_ssl_add_sni_item(char *name, char *crt, char *key, char *ciphers, char *client_ca) {
|
||||
if (!uwsgi.ssl_initialized) {
|
||||
uwsgi_ssl_init();
|
||||
}
|
||||
SSL_CTX *ctx = uwsgi_ssl_new_server_context(name, crt, key, ciphers, client_ca);
|
||||
if (!ctx) {
|
||||
uwsgi_log("[uwsgi-ssl] DANGER unable to initialize context for \"%s\"\n", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_string_list *usl = uwsgi_string_new_list(&uwsgi.sni, name);
|
||||
usl->custom_ptr = ctx;
|
||||
return usl;
|
||||
}
|
||||
-623
@@ -1,623 +0,0 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_static_want_gzip(struct wsgi_request *wsgi_req, char *filename, size_t filename_len, struct stat *st) {
|
||||
// check for filename size
|
||||
if (filename_len + 4 > PATH_MAX) return 0;
|
||||
// check for supported encodings
|
||||
if (!uwsgi_contains_n(wsgi_req->encoding, wsgi_req->encoding_len, "gzip", 4) ) return 0;
|
||||
|
||||
// check for 'all'
|
||||
if (uwsgi.static_gzip_all) goto gzip;
|
||||
|
||||
// check for dirs/prefix
|
||||
struct uwsgi_string_list *usl = uwsgi.static_gzip_dir;
|
||||
while(usl) {
|
||||
if (!uwsgi_starts_with(filename, filename_len, usl->value, usl->len)) {
|
||||
goto gzip;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
// check for ext/suffix
|
||||
usl = uwsgi.static_gzip_ext;
|
||||
while(usl) {
|
||||
if (!uwsgi_strncmp(filename + (filename_len - usl->len), usl->len, usl->value, usl->len)) {
|
||||
goto gzip;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
// check for regexp
|
||||
struct uwsgi_regexp_list *url = uwsgi.static_gzip;
|
||||
while(url) {
|
||||
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, filename, filename_len) >= 0) {
|
||||
goto gzip;
|
||||
}
|
||||
url = url->next;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
gzip:
|
||||
|
||||
memcpy(filename + filename_len, ".gz\0", 4);
|
||||
filename_len += 3;
|
||||
|
||||
if (stat(filename, st)) {
|
||||
filename_len -= 3;
|
||||
filename[filename_len] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int set_http_date(time_t t, char *dst) {
|
||||
|
||||
static char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
|
||||
static char *months[] = {
|
||||
"Jan", "Feb", "Mar", "Apr",
|
||||
"May", "Jun", "Jul", "Aug",
|
||||
"Sep", "Oct", "Nov", "Dec"
|
||||
};
|
||||
|
||||
struct tm *hdtm = gmtime(&t);
|
||||
|
||||
int ret = snprintf(dst, 31, "%s, %02d %s %4d %02d:%02d:%02d GMT",
|
||||
week[hdtm->tm_wday], hdtm->tm_mday, months[hdtm->tm_mon], hdtm->tm_year + 1900, hdtm->tm_hour, hdtm->tm_min, hdtm->tm_sec);
|
||||
if (ret <= 0 || ret > 31) {
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// only RFC 1123 is supported
|
||||
static time_t parse_http_date(char *date, uint16_t len) {
|
||||
|
||||
struct tm hdtm;
|
||||
|
||||
if (len != 29 && date[3] != ',')
|
||||
return 0;
|
||||
|
||||
hdtm.tm_mday = uwsgi_str2_num(date + 5);
|
||||
|
||||
switch (date[8]) {
|
||||
case 'J':
|
||||
if (date[9] == 'a') {
|
||||
hdtm.tm_mon = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (date[9] == 'u') {
|
||||
if (date[10] == 'n') {
|
||||
hdtm.tm_mon = 5;
|
||||
break;
|
||||
}
|
||||
|
||||
if (date[10] == 'l') {
|
||||
hdtm.tm_mon = 6;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
case 'F':
|
||||
hdtm.tm_mon = 1;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
if (date[9] != 'a')
|
||||
return 0;
|
||||
|
||||
if (date[10] == 'r') {
|
||||
hdtm.tm_mon = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (date[10] == 'y') {
|
||||
hdtm.tm_mon = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
case 'A':
|
||||
if (date[10] == 'r') {
|
||||
hdtm.tm_mon = 3;
|
||||
break;
|
||||
}
|
||||
if (date[10] == 'g') {
|
||||
hdtm.tm_mon = 7;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case 'S':
|
||||
hdtm.tm_mon = 8;
|
||||
break;
|
||||
|
||||
case 'O':
|
||||
hdtm.tm_mon = 9;
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
hdtm.tm_mon = 10;
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
hdtm.tm_mon = 11;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
hdtm.tm_year = uwsgi_str4_num(date + 12) - 1900;
|
||||
|
||||
hdtm.tm_hour = uwsgi_str2_num(date + 17);
|
||||
hdtm.tm_min = uwsgi_str2_num(date + 20);
|
||||
hdtm.tm_sec = uwsgi_str2_num(date + 23);
|
||||
|
||||
return timegm(&hdtm);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int 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;
|
||||
// 30+1
|
||||
char expires[31];
|
||||
|
||||
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);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
int 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;
|
||||
// 30+1
|
||||
char expires[31];
|
||||
|
||||
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);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int 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;
|
||||
// 30+1
|
||||
char expires[31];
|
||||
|
||||
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);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int 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;
|
||||
// 30+1
|
||||
char expires[31];
|
||||
|
||||
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);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
char *uwsgi_get_mime_type(char *name, int namelen, int *size) {
|
||||
|
||||
int i;
|
||||
int count = 0;
|
||||
char *ext = NULL;
|
||||
for (i = namelen - 1; i >= 0; i--) {
|
||||
if (!isalnum((int) name[i])) {
|
||||
if (name[i] == '.') {
|
||||
ext = name + (namelen - count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!ext)
|
||||
return NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssize_t uwsgi_append_static_path(char *dir, size_t dir_len, char *file, size_t file_len) {
|
||||
|
||||
|
||||
size_t len = dir_len;
|
||||
|
||||
if (len + 1 + file_len > PATH_MAX) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dir[len - 1] == '/') {
|
||||
memcpy(dir + len, file, file_len);
|
||||
dir[len + file_len] = 0;
|
||||
len += file_len;
|
||||
}
|
||||
else {
|
||||
dir[len] = '/';
|
||||
memcpy(dir + len + 1, file, file_len);
|
||||
dir[len + 1 + file_len] = 0;
|
||||
len += 1 + file_len;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int uwsgi_static_stat(struct wsgi_request *wsgi_req, char *filename, size_t *filename_len, struct stat *st, struct uwsgi_string_list **index) {
|
||||
|
||||
int ret = stat(filename, st);
|
||||
// if non-existant return -1
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
if (S_ISREG(st->st_mode))
|
||||
return 0;
|
||||
|
||||
// check for index
|
||||
if (S_ISDIR(st->st_mode)) {
|
||||
struct uwsgi_string_list *usl = uwsgi.static_index;
|
||||
while (usl) {
|
||||
ssize_t new_len = uwsgi_append_static_path(filename, *filename_len, usl->value, usl->len);
|
||||
if (new_len >= 0) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("checking for %s\n", filename);
|
||||
#endif
|
||||
if (uwsgi_is_file2(filename, st)) {
|
||||
*index = usl;
|
||||
*filename_len = new_len;
|
||||
return 0;
|
||||
}
|
||||
// reset to original name
|
||||
filename[*filename_len] = 0;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, size_t real_filename_len, struct stat *st) {
|
||||
|
||||
int mime_type_size = 0;
|
||||
char http_last_modified[49];
|
||||
|
||||
if (uwsgi.threads > 1)
|
||||
pthread_mutex_lock(&uwsgi.lock_static);
|
||||
|
||||
char *mime_type = uwsgi_get_mime_type(real_filename, real_filename_len, &mime_type_size);
|
||||
|
||||
if (uwsgi.threads > 1)
|
||||
pthread_mutex_unlock(&uwsgi.lock_static);
|
||||
|
||||
if (wsgi_req->if_modified_since_len) {
|
||||
time_t ims = parse_http_date(wsgi_req->if_modified_since, wsgi_req->if_modified_since_len);
|
||||
if (st->st_mtime <= ims) {
|
||||
uwsgi_response_prepare_headers(wsgi_req, "304 Not Modified", 16);
|
||||
return uwsgi_response_write_headers_do(wsgi_req);
|
||||
}
|
||||
}
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("[uwsgi-fileserve] file %s found\n", real_filename);
|
||||
#endif
|
||||
|
||||
// HTTP status
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1;
|
||||
|
||||
#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) {
|
||||
if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_size)) return -1;
|
||||
// check for content-type related headers
|
||||
uwsgi_add_expires_type(wsgi_req, mime_type, mime_type_size, st);
|
||||
}
|
||||
|
||||
// increase static requests counter
|
||||
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].static_requests++;
|
||||
|
||||
// nginx
|
||||
if (uwsgi.file_serve_mode == 1) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "X-Accel-Redirect", 16, real_filename, real_filename_len)) return -1;
|
||||
// this is the final header (\r\n added)
|
||||
int size = set_http_date(st->st_mtime, http_last_modified);
|
||||
if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
|
||||
}
|
||||
// apache
|
||||
else if (uwsgi.file_serve_mode == 2) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "X-Sendfile", 10, real_filename, real_filename_len)) return -1;
|
||||
// this is the final header (\r\n added)
|
||||
int size = set_http_date(st->st_mtime, http_last_modified);
|
||||
if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
|
||||
}
|
||||
// raw
|
||||
else {
|
||||
// here we need to choose if we want the gzip variant;
|
||||
if (uwsgi_static_want_gzip(wsgi_req, real_filename, real_filename_len, st)) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "gzip", 4)) return -1;
|
||||
}
|
||||
// set Content-Length
|
||||
if (uwsgi_response_add_content_length(wsgi_req, st->st_size)) return -1;
|
||||
int size = set_http_date(st->st_mtime, http_last_modified);
|
||||
if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
|
||||
|
||||
// if it is a HEAD request just skip transfer
|
||||
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) {
|
||||
wsgi_req->status = 200;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Ok, the file must be transferred from uWSGI
|
||||
// offloading will be automatically managed
|
||||
int fd = open(real_filename, O_RDONLY);
|
||||
if (fd < 0) return -1;
|
||||
// fd will be closed in the following function
|
||||
uwsgi_response_sendfile_do(wsgi_req, fd, 0, st->st_size);
|
||||
}
|
||||
|
||||
wsgi_req->status = 200;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
size_t filename_len = 0;
|
||||
|
||||
struct uwsgi_string_list *index = NULL;
|
||||
|
||||
if (!is_a_file) {
|
||||
filename = uwsgi_concat3n(document_root, document_root_len, "/", 1, path_info, path_info_len);
|
||||
filename_len = document_root_len + 1 + path_info_len;
|
||||
}
|
||||
else {
|
||||
filename = uwsgi_concat2n(document_root, document_root_len, "", 0);
|
||||
filename_len = document_root_len;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("[uwsgi-fileserve] checking for %s\n", filename);
|
||||
#endif
|
||||
|
||||
if (uwsgi.static_cache_paths) {
|
||||
uwsgi_rlock(uwsgi.static_cache_paths->lock);
|
||||
uint64_t item_len;
|
||||
char *item = uwsgi_cache_get2(uwsgi.static_cache_paths, filename, filename_len, &item_len);
|
||||
if (item && item_len > 0 && item_len <= PATH_MAX) {
|
||||
memcpy(real_filename, item, item_len);
|
||||
real_filename_len = item_len;
|
||||
uwsgi_rwunlock(uwsgi.static_cache_paths->lock);
|
||||
goto found;
|
||||
}
|
||||
uwsgi_rwunlock(uwsgi.static_cache_paths->lock);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
real_filename_len = strlen(real_filename);
|
||||
|
||||
if (uwsgi.static_cache_paths) {
|
||||
uwsgi_wlock(uwsgi.static_cache_paths->lock);
|
||||
uwsgi_cache_set2(uwsgi.static_cache_paths, filename, filename_len, real_filename, real_filename_len, uwsgi.use_static_cache_paths, UWSGI_CACHE_FLAG_UPDATE);
|
||||
uwsgi_rwunlock(uwsgi.static_cache_paths->lock);
|
||||
}
|
||||
|
||||
found:
|
||||
free(filename);
|
||||
|
||||
if (uwsgi_starts_with(real_filename, real_filename_len, document_root, document_root_len)) {
|
||||
struct uwsgi_string_list *safe = uwsgi.static_safe;
|
||||
while(safe) {
|
||||
if (!uwsgi_starts_with(real_filename, real_filename_len, safe->value, safe->len)) {
|
||||
goto safe;
|
||||
}
|
||||
safe = safe->next;
|
||||
}
|
||||
uwsgi_log("[uwsgi-fileserve] security error: %s is not under %.*s or a safe path\n", real_filename, document_root_len, document_root);
|
||||
return -1;
|
||||
}
|
||||
|
||||
safe:
|
||||
|
||||
if (!uwsgi_static_stat(wsgi_req, real_filename, &real_filename_len, &st, &index)) {
|
||||
|
||||
if (index) {
|
||||
// if we are here the PATH_INFO need to be changed
|
||||
if (uwsgi_req_append_path_info_with_index(wsgi_req, index->value, index->len)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// skip methods other than GET and HEAD
|
||||
if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "GET", 3) && uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 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)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
sse = sse->next;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
// before sending the file, we need to check if some rule applies
|
||||
if (!wsgi_req->is_routing && uwsgi_apply_routes_do(wsgi_req, NULL, 0) == UWSGI_ROUTE_BREAK) {
|
||||
return 0;
|
||||
}
|
||||
wsgi_req->routes_applied = 1;
|
||||
#endif
|
||||
|
||||
return uwsgi_real_file_serve(wsgi_req, real_filename, real_filename_len, &st);
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
+9
-69
@@ -13,7 +13,6 @@ struct uwsgi_stats *uwsgi_stats_new(size_t chunk_size) {
|
||||
us->chunk = chunk_size;
|
||||
us->size = chunk_size;
|
||||
us->tabs = 1;
|
||||
us->dirty = 0;
|
||||
us->minified = uwsgi.stats_minified;
|
||||
if (!us->minified) {
|
||||
us->base[1] = '\n';
|
||||
@@ -374,7 +373,7 @@ struct uwsgi_stats_pusher *uwsgi_stats_pusher_get(char *name) {
|
||||
return usp;
|
||||
}
|
||||
|
||||
struct uwsgi_stats_pusher_instance *uwsgi_stats_pusher_add(struct uwsgi_stats_pusher *pusher, char *arg) {
|
||||
void uwsgi_stats_pusher_add(struct uwsgi_stats_pusher *pusher, char *arg) {
|
||||
struct uwsgi_stats_pusher_instance *old_uspi = NULL, *uspi = uwsgi.stats_pusher_instances;
|
||||
while (uspi) {
|
||||
old_uspi = uspi;
|
||||
@@ -383,16 +382,13 @@ struct uwsgi_stats_pusher_instance *uwsgi_stats_pusher_add(struct uwsgi_stats_pu
|
||||
|
||||
uspi = uwsgi_calloc(sizeof(struct uwsgi_stats_pusher_instance));
|
||||
uspi->pusher = pusher;
|
||||
uspi->arg = uwsgi_str(arg);
|
||||
uspi->raw = pusher->raw;
|
||||
uspi->arg = arg;
|
||||
if (old_uspi) {
|
||||
old_uspi->next = uspi;
|
||||
}
|
||||
else {
|
||||
uwsgi.stats_pusher_instances = uspi;
|
||||
}
|
||||
|
||||
return uspi;
|
||||
}
|
||||
|
||||
void uwsgi_stats_pusher_loop(struct uwsgi_thread *ut) {
|
||||
@@ -417,17 +413,12 @@ void uwsgi_stats_pusher_loop(struct uwsgi_thread *ut) {
|
||||
while (uspi) {
|
||||
int delta = uspi->freq ? uspi->freq : uwsgi.stats_pusher_default_freq;
|
||||
if ((uspi->last_run + delta) <= now) {
|
||||
if (uspi->raw) {
|
||||
uspi->pusher->func(uspi, now, NULL, 0);
|
||||
}
|
||||
else {
|
||||
if (!us) {
|
||||
us = uwsgi_master_generate_stats();
|
||||
if (!us)
|
||||
goto next;
|
||||
}
|
||||
uspi->pusher->func(uspi, now, us->base, us->pos);
|
||||
if (!us) {
|
||||
us = uwsgi_master_generate_stats();
|
||||
if (!us)
|
||||
goto next;
|
||||
}
|
||||
uspi->pusher->func(uspi, us->base, us->pos);
|
||||
uspi->last_run = now;
|
||||
}
|
||||
next:
|
||||
@@ -453,7 +444,6 @@ void uwsgi_stats_pusher_setup() {
|
||||
pusher = uwsgi_stats_pusher_get(ssp);
|
||||
if (!pusher) {
|
||||
uwsgi_log("unable to find \"%s\" stats_pusher\n", ssp);
|
||||
free(ssp);
|
||||
exit(1);
|
||||
}
|
||||
char *arg = NULL;
|
||||
@@ -463,11 +453,10 @@ void uwsgi_stats_pusher_setup() {
|
||||
}
|
||||
uwsgi_stats_pusher_add(pusher, arg);
|
||||
usl = usl->next;
|
||||
free(ssp);
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_stats_pusher *uwsgi_register_stats_pusher(char *name, void (*func) (struct uwsgi_stats_pusher_instance *, time_t, char *, size_t)) {
|
||||
void uwsgi_register_stats_pusher(char *name, void (*func) (struct uwsgi_stats_pusher_instance *, char *, size_t)) {
|
||||
|
||||
struct uwsgi_stats_pusher *pusher = uwsgi.stats_pushers, *old_pusher = NULL;
|
||||
|
||||
@@ -486,8 +475,6 @@ struct uwsgi_stats_pusher *uwsgi_register_stats_pusher(char *name, void (*func)
|
||||
else {
|
||||
uwsgi.stats_pushers = pusher;
|
||||
}
|
||||
|
||||
return pusher;
|
||||
}
|
||||
|
||||
struct uwsgi_stats_pusher_file_conf {
|
||||
@@ -496,7 +483,7 @@ struct uwsgi_stats_pusher_file_conf {
|
||||
char *separator;
|
||||
};
|
||||
|
||||
void uwsgi_stats_pusher_file(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) {
|
||||
void uwsgi_stats_pusher_file(struct uwsgi_stats_pusher_instance *uspi, char *json, size_t json_len) {
|
||||
struct uwsgi_stats_pusher_file_conf *uspic = (struct uwsgi_stats_pusher_file_conf *) uspi->data;
|
||||
if (!uspi->configured) {
|
||||
uspic = uwsgi_calloc(sizeof(struct uwsgi_stats_pusher_file_conf));
|
||||
@@ -533,50 +520,3 @@ void uwsgi_stats_pusher_file(struct uwsgi_stats_pusher_instance *uspi, time_t no
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void stats_dump_var(char *k, uint16_t kl, char *v, uint16_t vl, void *data) {
|
||||
struct uwsgi_stats *us = (struct uwsgi_stats *) data;
|
||||
if (us->dirty) return;
|
||||
uint16_t i;
|
||||
// replace " with '
|
||||
for(i=0;i<kl;i++) {
|
||||
if (k[i] == '"') {
|
||||
k[i] = '\'';
|
||||
}
|
||||
}
|
||||
for(i=0;i<vl;i++) {
|
||||
if (v[i] == '"') {
|
||||
v[i] = '\'';
|
||||
}
|
||||
}
|
||||
char *var = uwsgi_concat3n(k, kl, "=", 1, v,vl);
|
||||
if (uwsgi_stats_str(us, var)) {
|
||||
us->dirty = 1;
|
||||
free(var);
|
||||
return;
|
||||
}
|
||||
free(var);
|
||||
if (uwsgi_stats_comma(us)) {
|
||||
us->dirty = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int uwsgi_stats_dump_vars(struct uwsgi_stats *us, struct uwsgi_core *uc) {
|
||||
if (!uc->in_request) return 0;
|
||||
struct uwsgi_header *uh = (struct uwsgi_header *) uwsgi.workers[0].cores[0].buffer;
|
||||
uint16_t pktsize = uh->pktsize;
|
||||
if (!pktsize) return 0;
|
||||
char *dst = uwsgi.workers[0].cores[0].buffer;
|
||||
memcpy(dst, uc->buffer+4, uwsgi.buffer_size);
|
||||
// ok now check if something changed...
|
||||
if (!uc->in_request) return 0;
|
||||
if (uh->pktsize != pktsize) return 0;
|
||||
if (memcmp(dst, uc->buffer+4, uwsgi.buffer_size)) return 0;
|
||||
// nothing changed let's dump vars
|
||||
int ret = uwsgi_hooked_parse(dst, pktsize, stats_dump_var, us);
|
||||
if (ret) return -1;
|
||||
if (us->dirty) return -1;
|
||||
if (uwsgi_stats_str(us, "")) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
#include "../uwsgi.h"
|
||||
|
||||
/*
|
||||
|
||||
Storage subsystem: filesystem-like abstraction
|
||||
|
||||
struct uwsgi_storage_engine {
|
||||
char *name;
|
||||
uint16_t name_len;
|
||||
int64_t (*get)(char *, uint16_t, char *, uint64_t, uint64_t, uint64_t);
|
||||
int64_t (*set)(char *, uint16_t, char *, uint64_t, uint64_t, uint64_t);
|
||||
};
|
||||
|
||||
struct uwsgi_storage {
|
||||
char *name;
|
||||
uint16_t name_len;
|
||||
struct uwsgi_storage_engine *engine;
|
||||
};
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
struct uwsgi_storage* uwsgi_storage_by_name(char *name, uint16_t name_len) {
|
||||
if (!name_len) {
|
||||
name_len = strlen(name);
|
||||
}
|
||||
struct uwsgi_storage *s = uwsgi.virtualdisks;
|
||||
while(s) {
|
||||
if (!uwsgi_strncmp(s->name, s->name_len, name, name_len)) {
|
||||
return s;
|
||||
}
|
||||
s = s->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int64_t uwsgi_storage_get(struct uwsgi_storage *storage, char *key, uint16_t key_len, char *out_buf, uint64_t pos, uint64_t size, uint64_t flags) {
|
||||
if (!storage->get) return -1;
|
||||
return storage->get(key, key_len, out_buf, pos, size, flags);
|
||||
}
|
||||
|
||||
int64_t uwsgi_storage_set(struct uwsgi_storage *storage, char *key, uint16_t key_len, char *in_buf, uint64_t pos, uint64_t size, uint64_t flags) {
|
||||
if (!storage->set) return -1;
|
||||
return storage->set(key, key_len, out_buf, pos, size, flags);
|
||||
}
|
||||
-340
@@ -1,340 +0,0 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
// check if a string_list contains an item
|
||||
struct uwsgi_string_list *uwsgi_string_list_has_item(struct uwsgi_string_list *list, char *key, size_t keylen) {
|
||||
struct uwsgi_string_list *usl = list;
|
||||
while (usl) {
|
||||
if (keylen == usl->len) {
|
||||
if (!memcmp(key, usl->value, keylen)) {
|
||||
return usl;
|
||||
}
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// lower a string
|
||||
char *uwsgi_lower(char *str, size_t size) {
|
||||
size_t i;
|
||||
for (i = 0; i < size; i++) {
|
||||
str[i] = tolower((int) str[i]);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
// check if a string is contained in another one
|
||||
char *uwsgi_str_contains(char *str, int slen, char what) {
|
||||
|
||||
int i;
|
||||
for (i = 0; i < slen; i++) {
|
||||
if (str[i] == what) {
|
||||
return str + i;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int uwsgi_contains_n(char *s1, size_t s1_len, char *s2, size_t s2_len) {
|
||||
size_t i;
|
||||
char *ptr = s2;
|
||||
for (i = 0; i < s1_len; i++) {
|
||||
if (s1[i] == *ptr) {
|
||||
ptr++;
|
||||
if (ptr == s2 + s2_len) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ptr = s2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// fast compare 2 sized strings
|
||||
int uwsgi_strncmp(char *src, int slen, char *dst, int dlen) {
|
||||
|
||||
if (slen != dlen)
|
||||
return 1;
|
||||
|
||||
return memcmp(src, dst, dlen);
|
||||
|
||||
}
|
||||
|
||||
// fast compare 2 sized strings (case insensitive)
|
||||
int uwsgi_strnicmp(char *src, int slen, char *dst, int dlen) {
|
||||
|
||||
if (slen != dlen)
|
||||
return 1;
|
||||
|
||||
return strncasecmp(src, dst, dlen);
|
||||
|
||||
}
|
||||
|
||||
// fast sized check of initial part of a string
|
||||
int uwsgi_starts_with(char *src, int slen, char *dst, int dlen) {
|
||||
|
||||
if (slen < dlen)
|
||||
return -1;
|
||||
|
||||
return memcmp(src, dst, dlen);
|
||||
}
|
||||
|
||||
|
||||
// unsized check
|
||||
int uwsgi_startswith(char *src, char *what, int wlen) {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < wlen; i++) {
|
||||
if (src[i] != what[i])
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// concatenate strings
|
||||
char *uwsgi_concatn(int c, ...) {
|
||||
|
||||
va_list s;
|
||||
char *item;
|
||||
int j = c;
|
||||
char *buf;
|
||||
size_t len = 1;
|
||||
size_t tlen = 1;
|
||||
|
||||
va_start(s, c);
|
||||
while (j > 0) {
|
||||
item = va_arg(s, char *);
|
||||
if (item == NULL) {
|
||||
break;
|
||||
}
|
||||
len += va_arg(s, int);
|
||||
j--;
|
||||
}
|
||||
va_end(s);
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
memset(buf, 0, len);
|
||||
|
||||
j = c;
|
||||
|
||||
len = 0;
|
||||
|
||||
va_start(s, c);
|
||||
while (j > 0) {
|
||||
item = va_arg(s, char *);
|
||||
if (item == NULL) {
|
||||
break;
|
||||
}
|
||||
tlen = va_arg(s, int);
|
||||
memcpy(buf + len, item, tlen);
|
||||
len += tlen;
|
||||
j--;
|
||||
}
|
||||
va_end(s);
|
||||
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_concat2(char *one, char *two) {
|
||||
|
||||
char *buf;
|
||||
size_t len = strlen(one) + strlen(two) + 1;
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
buf[len - 1] = 0;
|
||||
|
||||
memcpy(buf, one, strlen(one));
|
||||
memcpy(buf + strlen(one), two, strlen(two));
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_concat4(char *one, char *two, char *three, char *four) {
|
||||
|
||||
char *buf;
|
||||
size_t len = strlen(one) + strlen(two) + strlen(three) + strlen(four) + 1;
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
buf[len - 1] = 0;
|
||||
|
||||
memcpy(buf, one, strlen(one));
|
||||
memcpy(buf + strlen(one), two, strlen(two));
|
||||
memcpy(buf + strlen(one) + strlen(two), three, strlen(three));
|
||||
memcpy(buf + strlen(one) + strlen(two) + strlen(three), four, strlen(four));
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_concat3(char *one, char *two, char *three) {
|
||||
|
||||
char *buf;
|
||||
size_t len = strlen(one) + strlen(two) + strlen(three) + 1;
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
buf[len - 1] = 0;
|
||||
|
||||
memcpy(buf, one, strlen(one));
|
||||
memcpy(buf + strlen(one), two, strlen(two));
|
||||
memcpy(buf + strlen(one) + strlen(two), three, strlen(three));
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_concat2n(char *one, int s1, char *two, int s2) {
|
||||
|
||||
char *buf;
|
||||
size_t len = s1 + s2 + 1;
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
buf[len - 1] = 0;
|
||||
|
||||
memcpy(buf, one, s1);
|
||||
memcpy(buf + s1, two, s2);
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_concat2nn(char *one, int s1, char *two, int s2, int *len) {
|
||||
|
||||
char *buf;
|
||||
*len = s1 + s2 + 1;
|
||||
|
||||
|
||||
buf = uwsgi_malloc(*len);
|
||||
buf[*len - 1] = 0;
|
||||
|
||||
memcpy(buf, one, s1);
|
||||
memcpy(buf + s1, two, s2);
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_concat3n(char *one, int s1, char *two, int s2, char *three, int s3) {
|
||||
|
||||
char *buf;
|
||||
size_t len = s1 + s2 + s3 + 1;
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
buf[len - 1] = 0;
|
||||
|
||||
memcpy(buf, one, s1);
|
||||
memcpy(buf + s1, two, s2);
|
||||
memcpy(buf + s1 + s2, three, s3);
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_concat4n(char *one, int s1, char *two, int s2, char *three, int s3, char *four, int s4) {
|
||||
|
||||
char *buf;
|
||||
size_t len = s1 + s2 + s3 + s4 + 1;
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
buf[len - 1] = 0;
|
||||
|
||||
memcpy(buf, one, s1);
|
||||
memcpy(buf + s1, two, s2);
|
||||
memcpy(buf + s1 + s2, three, s3);
|
||||
memcpy(buf + s1 + s2 + s3, four, s4);
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
// concat unsized strings
|
||||
char *uwsgi_concat(int c, ...) {
|
||||
|
||||
va_list s;
|
||||
char *item;
|
||||
size_t len = 1;
|
||||
int j = c;
|
||||
char *buf;
|
||||
|
||||
va_start(s, c);
|
||||
while (j > 0) {
|
||||
item = va_arg(s, char *);
|
||||
if (item == NULL) {
|
||||
break;
|
||||
}
|
||||
len += (int) strlen(item);
|
||||
j--;
|
||||
}
|
||||
va_end(s);
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
memset(buf, 0, len);
|
||||
|
||||
j = c;
|
||||
|
||||
len = 0;
|
||||
|
||||
va_start(s, c);
|
||||
while (j > 0) {
|
||||
item = va_arg(s, char *);
|
||||
if (item == NULL) {
|
||||
break;
|
||||
}
|
||||
memcpy(buf + len, item, strlen(item));
|
||||
len += strlen(item);
|
||||
j--;
|
||||
}
|
||||
va_end(s);
|
||||
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_strncopy(char *s, int len) {
|
||||
|
||||
char *buf;
|
||||
|
||||
buf = uwsgi_malloc(len + 1);
|
||||
buf[len] = 0;
|
||||
|
||||
memcpy(buf, s, len);
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
// this move a string back of one char and put a 0 at the end (used in uwsgi parsers for buffer reusing)
|
||||
char *uwsgi_cheap_string(char *buf, int len) {
|
||||
|
||||
int i;
|
||||
char *cheap_buf = buf - 1;
|
||||
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
*cheap_buf++ = buf[i];
|
||||
}
|
||||
|
||||
|
||||
buf[len - 1] = 0;
|
||||
|
||||
return buf - 1;
|
||||
}
|
||||
|
||||
+176
-254
@@ -91,7 +91,7 @@ static struct uwsgi_subscribe_node *uwsgi_subscription_algo_lrc(struct uwsgi_sub
|
||||
if (min_rc == 0 || node->reference < min_rc) {
|
||||
min_rc = node->reference;
|
||||
choosen_node = node;
|
||||
if (min_rc == 0 && !(node->next && node->next->reference <= node->reference && node->next->last_requests <= node->last_requests))
|
||||
if (min_rc == 0 && !(node->next && node->next->reference <= node->reference && node->next->requests <= node->requests))
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -125,7 +125,7 @@ static struct uwsgi_subscribe_node *uwsgi_subscription_algo_wlrc(struct uwsgi_su
|
||||
if (min_rc == 0 || ref < min_rc) {
|
||||
min_rc = ref;
|
||||
choosen_node = node;
|
||||
if (min_rc == 0 && !(node->next && next_node_ref <= ref && node->next->last_requests <= node->last_requests))
|
||||
if (min_rc == 0 && !(node->next && next_node_ref <= ref && node->next->requests <= node->requests))
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -376,7 +376,6 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
|
||||
node->weight = usr->weight;
|
||||
if (!node->weight)
|
||||
node->weight = 1;
|
||||
node->last_requests = 0;
|
||||
return node;
|
||||
}
|
||||
old_node = node;
|
||||
@@ -395,7 +394,6 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
|
||||
node->modifier1 = usr->modifier1;
|
||||
node->modifier2 = usr->modifier2;
|
||||
node->requests = 0;
|
||||
node->last_requests = 0;
|
||||
node->transferred = 0;
|
||||
node->reference = 0;
|
||||
node->death_mark = 0;
|
||||
@@ -472,7 +470,6 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
|
||||
current_slot->nodes->len = usr->address_len;
|
||||
current_slot->nodes->reference = 0;
|
||||
current_slot->nodes->requests = 0;
|
||||
current_slot->nodes->last_requests = 0;
|
||||
current_slot->nodes->transferred = 0;
|
||||
current_slot->nodes->death_mark = 0;
|
||||
current_slot->nodes->failcnt = 0;
|
||||
@@ -517,8 +514,31 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
|
||||
}
|
||||
|
||||
|
||||
// TODO rewrite it using uwsgi buffers
|
||||
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];
|
||||
char value_weight[sizeof(UMAX64_STR) + 1];
|
||||
|
||||
|
||||
int value_cores_size = uwsgi_long2str2n(uwsgi.numproc * uwsgi.cores, value_cores, sizeof(UMAX64_STR));
|
||||
int value_load_size = uwsgi_long2str2n(uwsgi.shared->load, value_load, sizeof(UMAX64_STR));
|
||||
|
||||
int value_weight_size = 0;
|
||||
|
||||
if (uwsgi.auto_weight) {
|
||||
value_weight_size = uwsgi_long2str2n(uwsgi.numproc * uwsgi.cores, value_weight, sizeof(UMAX64_STR));
|
||||
}
|
||||
else {
|
||||
value_weight_size = uwsgi_long2str2n(uwsgi.weight, value_weight, sizeof(UMAX64_STR));
|
||||
}
|
||||
|
||||
char value_modifier1[4];
|
||||
char value_modifier2[4];
|
||||
int value_modifier1_size = uwsgi_long2str2n(modifier1, value_modifier1, 3);
|
||||
int value_modifier2_size = uwsgi_long2str2n(modifier2, value_modifier2, 3);
|
||||
|
||||
if (socket_name == NULL && !uwsgi.sockets)
|
||||
return;
|
||||
|
||||
@@ -526,44 +546,173 @@ void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8
|
||||
socket_name = uwsgi.sockets->name;
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(4096);
|
||||
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);
|
||||
|
||||
// make space for uwsgi header
|
||||
ub->pos = 4;
|
||||
char *subscrbuf = uwsgi_malloc(ssb_size);
|
||||
// leave space for uwsgi header
|
||||
char *ssb = subscrbuf + 4;
|
||||
|
||||
if (uwsgi_buffer_append_keyval(ub, "key", 3, key, keysize)) goto end;
|
||||
if (uwsgi_buffer_append_keyval(ub, "address", 7, socket_name, strlen(socket_name))) goto end;
|
||||
if (uwsgi_buffer_append_keynum(ub, "modifier1", 9, modifier1)) goto end;
|
||||
if (uwsgi_buffer_append_keynum(ub, "modifier2", 9, modifier2)) goto end;
|
||||
if (uwsgi_buffer_append_keynum(ub, "cores", 5, uwsgi.numproc * uwsgi.cores)) goto end;
|
||||
if (uwsgi_buffer_append_keynum(ub, "load", 4, uwsgi.shared->load)) goto end;
|
||||
if (uwsgi.auto_weight) {
|
||||
if (uwsgi_buffer_append_keynum(ub, "weight", 6, uwsgi.numproc * uwsgi.cores )) goto end;
|
||||
}
|
||||
else {
|
||||
if (uwsgi_buffer_append_keynum(ub, "weight", 6, uwsgi.weight )) goto end;
|
||||
}
|
||||
// key = "domain"
|
||||
uint16_t ustrlen = 3;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, "key", ustrlen);
|
||||
ssb += ustrlen;
|
||||
|
||||
ustrlen = keysize;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, key, ustrlen);
|
||||
ssb += ustrlen;
|
||||
|
||||
// address = "first uwsgi socket"
|
||||
ustrlen = 7;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, "address", ustrlen);
|
||||
ssb += ustrlen;
|
||||
|
||||
ustrlen = strlen(socket_name);
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, socket_name, ustrlen);
|
||||
ssb += ustrlen;
|
||||
|
||||
// modifier1 = "modifier1"
|
||||
ustrlen = 9;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, "modifier1", ustrlen);
|
||||
ssb += ustrlen;
|
||||
|
||||
ustrlen = value_modifier1_size;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, value_modifier1, value_modifier1_size);
|
||||
ssb += ustrlen;
|
||||
|
||||
// modifier2 = "modifier2"
|
||||
ustrlen = 9;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, "modifier2", ustrlen);
|
||||
ssb += ustrlen;
|
||||
|
||||
ustrlen = value_modifier2_size;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, value_modifier2, value_modifier2_size);
|
||||
ssb += ustrlen;
|
||||
|
||||
// cores = uwsgi.numproc * uwsgi.cores
|
||||
ustrlen = 5;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, "cores", ustrlen);
|
||||
ssb += ustrlen;
|
||||
|
||||
ustrlen = value_cores_size;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, value_cores, value_cores_size);
|
||||
ssb += ustrlen;
|
||||
|
||||
// load
|
||||
ustrlen = 4;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, "load", ustrlen);
|
||||
ssb += ustrlen;
|
||||
|
||||
ustrlen = value_load_size;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, value_load, value_load_size);
|
||||
ssb += ustrlen;
|
||||
|
||||
// weight
|
||||
ustrlen = 6;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, "weight", ustrlen);
|
||||
ssb += ustrlen;
|
||||
|
||||
ustrlen = value_weight_size;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, value_weight, value_weight_size);
|
||||
ssb += ustrlen;
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
if (sign) {
|
||||
if (uwsgi_buffer_append_keynum(ub, "unix", 4, (uwsgi_now() + (time_t) cmd) )) goto end;
|
||||
// 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, ub->buf + 4, ub->pos - 4, &signature_len);
|
||||
char *signature = uwsgi_rsa_sign(sign, subscrbuf + 4, ssb_size - 4, &signature_len);
|
||||
if (signature && signature_len > 0) {
|
||||
if (uwsgi_buffer_append_keyval(ub, "sign", 4, signature, signature_len)) {
|
||||
// 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);
|
||||
goto end;
|
||||
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, ub->buf, ub->pos - 4);
|
||||
end:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
send_udp_message(224, cmd, udp_address, subscrbuf, ssb_size - 4);
|
||||
free(subscrbuf);
|
||||
}
|
||||
|
||||
|
||||
@@ -607,230 +756,3 @@ struct uwsgi_subscribe_slot **uwsgi_subscription_init_ht() {
|
||||
}
|
||||
return uwsgi_calloc(sizeof(struct uwsgi_subscription_slot *) * UMAX16);
|
||||
}
|
||||
|
||||
void uwsgi_subscribe(char *subscription, uint8_t cmd) {
|
||||
|
||||
size_t subfile_size;
|
||||
size_t i;
|
||||
char *key = NULL;
|
||||
int keysize = 0;
|
||||
char *modifier1 = NULL;
|
||||
int modifier1_len = 0;
|
||||
char *socket_name = NULL;
|
||||
char *udp_address = subscription;
|
||||
char *udp_port = NULL;
|
||||
char *subscription_key = NULL;
|
||||
char *sign = NULL;
|
||||
|
||||
// check for explicit socket_name
|
||||
char *equal = strchr(subscription, '=');
|
||||
if (equal) {
|
||||
socket_name = subscription;
|
||||
if (socket_name[0] == '=') {
|
||||
equal = strchr(socket_name + 1, '=');
|
||||
if (!equal)
|
||||
return;
|
||||
*equal = '\0';
|
||||
struct uwsgi_socket *us = uwsgi_get_shared_socket_by_num(atoi(socket_name + 1));
|
||||
if (!us)
|
||||
return;
|
||||
socket_name = us->name;
|
||||
}
|
||||
*equal = '\0';
|
||||
udp_address = equal + 1;
|
||||
}
|
||||
|
||||
// check for unix socket
|
||||
if (udp_address[0] != '/') {
|
||||
udp_port = strchr(udp_address, ':');
|
||||
if (!udp_port) {
|
||||
if (equal)
|
||||
*equal = '=';
|
||||
return;
|
||||
}
|
||||
subscription_key = strchr(udp_port + 1, ':');
|
||||
}
|
||||
else {
|
||||
subscription_key = strchr(udp_address + 1, ':');
|
||||
}
|
||||
|
||||
if (!subscription_key) {
|
||||
if (equal)
|
||||
*equal = '=';
|
||||
return;
|
||||
}
|
||||
|
||||
udp_address = uwsgi_concat2n(udp_address, subscription_key - udp_address, "", 0);
|
||||
|
||||
if (subscription_key[1] == '@') {
|
||||
if (!uwsgi_file_exists(subscription_key + 2))
|
||||
goto clear;
|
||||
char *lines = uwsgi_open_and_read(subscription_key + 2, &subfile_size, 1, NULL);
|
||||
if (subfile_size > 0) {
|
||||
key = lines;
|
||||
for (i = 0; i < subfile_size; i++) {
|
||||
if (lines[i] == 0) {
|
||||
if (keysize > 0) {
|
||||
if (key[0] != '#' && key[0] != '\n') {
|
||||
modifier1 = strchr(key, ',');
|
||||
if (modifier1) {
|
||||
modifier1[0] = 0;
|
||||
modifier1++;
|
||||
modifier1_len = strlen(modifier1);
|
||||
keysize = strlen(key);
|
||||
}
|
||||
uwsgi_send_subscription(udp_address, key, keysize, uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign);
|
||||
modifier1 = NULL;
|
||||
modifier1_len = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (lines[i] == '\n') {
|
||||
if (keysize > 0) {
|
||||
if (key[0] != '#' && key[0] != '\n') {
|
||||
lines[i] = 0;
|
||||
modifier1 = strchr(key, ',');
|
||||
if (modifier1) {
|
||||
modifier1[0] = 0;
|
||||
modifier1++;
|
||||
modifier1_len = strlen(modifier1);
|
||||
keysize = strlen(key);
|
||||
}
|
||||
uwsgi_send_subscription(udp_address, key, keysize, uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign);
|
||||
modifier1 = NULL;
|
||||
modifier1_len = 0;
|
||||
lines[i] = '\n';
|
||||
}
|
||||
}
|
||||
key = lines + i + 1;
|
||||
keysize = 0;
|
||||
continue;
|
||||
}
|
||||
keysize++;
|
||||
}
|
||||
|
||||
free(lines);
|
||||
}
|
||||
}
|
||||
else {
|
||||
modifier1 = strchr(subscription_key + 1, ',');
|
||||
if (modifier1) {
|
||||
modifier1[0] = 0;
|
||||
modifier1++;
|
||||
|
||||
sign = strchr(modifier1 + 1, ',');
|
||||
if (sign) {
|
||||
*sign = 0;
|
||||
sign++;
|
||||
}
|
||||
modifier1_len = strlen(modifier1);
|
||||
}
|
||||
|
||||
uwsgi_send_subscription(udp_address, subscription_key + 1, strlen(subscription_key + 1), uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign);
|
||||
if (modifier1)
|
||||
modifier1[-1] = ',';
|
||||
if (sign)
|
||||
sign[-1] = ',';
|
||||
}
|
||||
|
||||
clear:
|
||||
if (equal)
|
||||
*equal = '=';
|
||||
free(udp_address);
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_subscribe2(char *arg, uint8_t cmd) {
|
||||
|
||||
char *s2_server = NULL;
|
||||
char *s2_key = NULL;
|
||||
char *s2_socket = NULL;
|
||||
char *s2_addr = NULL;
|
||||
char *s2_weight = NULL;
|
||||
char *s2_sign = NULL;
|
||||
char *s2_modifier1 = NULL;
|
||||
char *s2_modifier2 = NULL;
|
||||
char *s2_check = NULL;
|
||||
|
||||
if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=',
|
||||
"server", &s2_server,
|
||||
"key", &s2_key,
|
||||
"socket", &s2_socket,
|
||||
"addr", &s2_addr,
|
||||
"weight", &s2_weight,
|
||||
"modifier1", &s2_modifier1,
|
||||
"modifier2", &s2_modifier2,
|
||||
"sign", &s2_sign,
|
||||
"check", &s2_check,
|
||||
NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s2_server || !s2_key) goto end;
|
||||
|
||||
if (s2_check) {
|
||||
if (uwsgi_file_exists(s2_check)) goto end;
|
||||
}
|
||||
|
||||
if (s2_weight) {
|
||||
uwsgi.weight = atoi(s2_weight);
|
||||
}
|
||||
|
||||
if (s2_socket) {
|
||||
struct uwsgi_socket *us = uwsgi_get_socket_by_num(atoi(s2_socket));
|
||||
if (us) {
|
||||
if (s2_addr) {
|
||||
free(s2_addr);
|
||||
}
|
||||
s2_addr = uwsgi_str(us->name);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t modifier1 = 0;
|
||||
uint8_t modifier2 = 0;
|
||||
|
||||
if (s2_modifier1) {
|
||||
modifier1 = atoi(s2_modifier1);
|
||||
}
|
||||
|
||||
if (s2_modifier2) {
|
||||
modifier2 = atoi(s2_modifier2);
|
||||
}
|
||||
|
||||
uwsgi_send_subscription(s2_server, s2_key, strlen(s2_key), modifier1, modifier2, cmd, s2_addr, s2_sign);
|
||||
end:
|
||||
if (s2_server) free(s2_server);
|
||||
if (s2_key) free(s2_key);
|
||||
if (s2_socket) free(s2_socket);
|
||||
if (s2_addr) free(s2_addr);
|
||||
if (s2_weight) free(s2_weight);
|
||||
if (s2_modifier1) free(s2_modifier1);
|
||||
if (s2_modifier2) free(s2_modifier2);
|
||||
if (s2_sign) free(s2_sign);
|
||||
if (s2_check) free(s2_check);
|
||||
}
|
||||
|
||||
void uwsgi_subscribe_all(uint8_t cmd, int verbose) {
|
||||
// -- subscribe
|
||||
struct uwsgi_string_list *subscriptions = uwsgi.subscriptions;
|
||||
while (subscriptions) {
|
||||
if (verbose) {
|
||||
uwsgi_log("%s %s\n", cmd ? "unsubscribing from" : "subscribing to", subscriptions->value);
|
||||
}
|
||||
uwsgi_subscribe(subscriptions->value, cmd);
|
||||
subscriptions = subscriptions->next;
|
||||
}
|
||||
|
||||
// --subscribe2
|
||||
subscriptions = uwsgi.subscriptions2;
|
||||
while (subscriptions) {
|
||||
if (verbose) {
|
||||
uwsgi_log("%s %s\n", cmd ? "unsubscribing from" : "subscribing to", subscriptions->value);
|
||||
}
|
||||
uwsgi_subscribe2(subscriptions->value, cmd);
|
||||
subscriptions = subscriptions->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
|
||||
uWSGI timebomb
|
||||
|
||||
this is a simple thread waiting for a timeout and calling exit
|
||||
with the specified value.
|
||||
|
||||
You can use it as a last resort in async apps that could block
|
||||
normal uWSGI behaviours
|
||||
|
||||
*/
|
||||
|
||||
struct time_bomb {
|
||||
int timeout;
|
||||
int exit_code;
|
||||
};
|
||||
|
||||
static void *time_bomb(void *arg) {
|
||||
|
||||
// block all signals
|
||||
sigset_t smask;
|
||||
sigfillset(&smask);
|
||||
pthread_sigmask(SIG_BLOCK, &smask, NULL);
|
||||
|
||||
struct time_bomb *tb = (struct time_bomb *) arg;
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = tb->timeout;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
uwsgi_log_verbose("*** BOOOOOOM ***\n");
|
||||
exit(tb->exit_code);
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_time_bomb(int timeout, int exit_code) {
|
||||
|
||||
pthread_t time_bomb_thread;
|
||||
|
||||
struct time_bomb *tb = uwsgi_malloc(sizeof(struct time_bomb));
|
||||
tb->timeout = timeout;
|
||||
tb->exit_code = exit_code;
|
||||
|
||||
if (pthread_create(&time_bomb_thread, NULL, time_bomb, (void *) tb)) {
|
||||
uwsgi_error("pthread_create()");
|
||||
uwsgi_log("unable to setup the time bomb, goodbye\n");
|
||||
exit(exit_code);
|
||||
}
|
||||
else {
|
||||
uwsgi_log_verbose("Fire in the hole !!! (%d seconds to detonation)\n", timeout);
|
||||
}
|
||||
|
||||
}
|
||||
+1801
-491
File diff suppressed because it is too large
Load Diff
+342
-333
File diff suppressed because it is too large
Load Diff
@@ -1,359 +0,0 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
/*
|
||||
|
||||
uWSGI websockets functions
|
||||
|
||||
sponsored by 20Tab S.r.l. <info@20tab.com>
|
||||
|
||||
*/
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
static struct uwsgi_buffer *uwsgi_websocket_message(char *msg, size_t len) {
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(10 + len);
|
||||
if (uwsgi_buffer_u8(ub, 0x81)) goto error;
|
||||
if (len < 126) {
|
||||
if (uwsgi_buffer_u8(ub, len)) goto error;
|
||||
}
|
||||
else if (len <= (uint16_t) 0xffff) {
|
||||
if (uwsgi_buffer_u8(ub, 126)) goto error;
|
||||
if (uwsgi_buffer_u16be(ub, len)) goto error;
|
||||
}
|
||||
else {
|
||||
if (uwsgi_buffer_u8(ub, 127)) goto error;
|
||||
if (uwsgi_buffer_u64be(ub, len)) goto error;
|
||||
}
|
||||
|
||||
if (uwsgi_buffer_append(ub, msg, len)) goto error;
|
||||
return ub;
|
||||
|
||||
error:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int uwsgi_websockets_ping(struct wsgi_request *wsgi_req) {
|
||||
if (uwsgi_response_write_body_do(wsgi_req, uwsgi.websockets_ping->buf, uwsgi.websockets_ping->pos)) {
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->websocket_last_ping = uwsgi_now();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_websockets_pong(struct wsgi_request *wsgi_req) {
|
||||
return uwsgi_response_write_body_do(wsgi_req, uwsgi.websockets_pong->buf, uwsgi.websockets_pong->pos);
|
||||
}
|
||||
|
||||
static int uwsgi_websockets_check_pingpong(struct wsgi_request *wsgi_req) {
|
||||
time_t now = uwsgi_now();
|
||||
// first round
|
||||
if (wsgi_req->websocket_last_ping == 0) {
|
||||
return uwsgi_websockets_ping(wsgi_req);
|
||||
}
|
||||
// pong not received ?
|
||||
if (wsgi_req->websocket_last_pong < wsgi_req->websocket_last_ping) {
|
||||
if (wsgi_req->websocket_last_ping - wsgi_req->websocket_last_pong > uwsgi.websockets_pong_tolerance) {
|
||||
uwsgi_log("[uwsgi-websocket] no PONG received in %d seconds !!!\n", uwsgi.websockets_pong_tolerance);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// pong received, send anther ping
|
||||
if (now - wsgi_req->websocket_last_ping >= uwsgi.websockets_ping_freq) {
|
||||
return uwsgi_websockets_ping(wsgi_req);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_websocket_send_do(struct wsgi_request *wsgi_req, char *msg, size_t len) {
|
||||
struct uwsgi_buffer *ub = uwsgi_websocket_message(msg, len);
|
||||
if (!ub) return -1;
|
||||
|
||||
ssize_t ret = uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_websocket_send(struct wsgi_request *wsgi_req, char *msg, size_t len) {
|
||||
if (wsgi_req->websocket_closed) {
|
||||
return -1;
|
||||
}
|
||||
ssize_t ret = uwsgi_websocket_send_do(wsgi_req, msg, len);
|
||||
if (ret < 0) {
|
||||
wsgi_req->websocket_closed = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void uwsgi_websocket_parse_header(struct wsgi_request *wsgi_req) {
|
||||
uint8_t byte1 = wsgi_req->websocket_buf->buf[0];
|
||||
uint8_t byte2 = wsgi_req->websocket_buf->buf[1];
|
||||
wsgi_req->websocket_opcode = byte1 & 0xf;
|
||||
wsgi_req->websocket_has_mask = byte2 >> 7;
|
||||
wsgi_req->websocket_size = byte2 & 0x7f;
|
||||
}
|
||||
|
||||
static struct uwsgi_buffer *uwsgi_websockets_parse(struct wsgi_request *wsgi_req) {
|
||||
// de-mask buffer
|
||||
uint8_t *ptr = (uint8_t *) (wsgi_req->websocket_buf->buf + (wsgi_req->websocket_pktsize - wsgi_req->websocket_size));
|
||||
size_t i;
|
||||
|
||||
if (wsgi_req->websocket_has_mask) {
|
||||
uint8_t *mask = ptr-4;
|
||||
for(i=0;i<wsgi_req->websocket_size;i++) {
|
||||
ptr[i] = ptr[i] ^ mask[i%4];
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(wsgi_req->websocket_size);
|
||||
if (uwsgi_buffer_append(ub, (char *) ptr, wsgi_req->websocket_size)) goto error;
|
||||
if (uwsgi_buffer_decapitate(wsgi_req->websocket_buf, wsgi_req->websocket_pktsize)) goto error;
|
||||
wsgi_req->websocket_phase = 0;
|
||||
wsgi_req->websocket_need = 2;
|
||||
return ub;
|
||||
error:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uwsgi_websockets_recv_pkt(struct wsgi_request *wsgi_req, int nb) {
|
||||
|
||||
int ret = -1;
|
||||
|
||||
for(;;) {
|
||||
ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->websocket_buf->buf + wsgi_req->websocket_buf->pos, wsgi_req->websocket_buf->len - wsgi_req->websocket_buf->pos);
|
||||
if (rlen > 0) return rlen;
|
||||
if (rlen == 0) return -1;
|
||||
if (rlen < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
if (nb) {
|
||||
if (uwsgi_websockets_check_pingpong(wsgi_req)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
goto wait;
|
||||
}
|
||||
uwsgi_error("uwsgi_websockets_recv_pkt()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wait:
|
||||
ret = uwsgi.wait_read_hook(wsgi_req->fd, uwsgi.websockets_ping_freq);
|
||||
if (ret > 0) {
|
||||
rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->websocket_buf->buf + wsgi_req->websocket_buf->pos, wsgi_req->websocket_buf->len - wsgi_req->websocket_buf->pos);
|
||||
if (rlen > 0) return rlen;
|
||||
if (rlen <= 0) return -1;
|
||||
}
|
||||
if (ret < 0) {
|
||||
uwsgi_error("uwsgi_websockets_recv_pkt()");
|
||||
return -1;
|
||||
}
|
||||
// send unsolicited pong
|
||||
if (uwsgi_websockets_check_pingpong(wsgi_req)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static struct uwsgi_buffer *uwsgi_websocket_recv_do(struct wsgi_request *wsgi_req, int nb) {
|
||||
if (!wsgi_req->websocket_buf) {
|
||||
// this buffer will be destroyed on connection close
|
||||
wsgi_req->websocket_buf = uwsgi_buffer_new(uwsgi.page_size);
|
||||
// need 2 byte header
|
||||
wsgi_req->websocket_need = 2;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
size_t remains = wsgi_req->websocket_buf->pos;
|
||||
// i have data;
|
||||
if (remains >= wsgi_req->websocket_need) {
|
||||
switch(wsgi_req->websocket_phase) {
|
||||
// header
|
||||
case 0:
|
||||
uwsgi_websocket_parse_header(wsgi_req);
|
||||
wsgi_req->websocket_pktsize = 2 + (wsgi_req->websocket_has_mask*4);
|
||||
if (wsgi_req->websocket_size == 126) {
|
||||
wsgi_req->websocket_need += 2;
|
||||
wsgi_req->websocket_phase = 1;
|
||||
wsgi_req->websocket_pktsize += 2;
|
||||
}
|
||||
else if (wsgi_req->websocket_size == 127) {
|
||||
wsgi_req->websocket_need += 8;
|
||||
wsgi_req->websocket_phase = 1;
|
||||
wsgi_req->websocket_pktsize += 8;
|
||||
}
|
||||
else {
|
||||
wsgi_req->websocket_phase = 2;
|
||||
}
|
||||
break;
|
||||
// size
|
||||
case 1:
|
||||
if (wsgi_req->websocket_size == 126) {
|
||||
wsgi_req->websocket_size = uwsgi_be16(wsgi_req->websocket_buf->buf+2);
|
||||
}
|
||||
else if (wsgi_req->websocket_size == 127) {
|
||||
wsgi_req->websocket_size = uwsgi_be64(wsgi_req->websocket_buf->buf+2);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[uwsgi-websocket] BUG error in websocket parser\n");
|
||||
return NULL;
|
||||
}
|
||||
if (wsgi_req->websocket_size > (uwsgi.websockets_max_size*1024)) {
|
||||
uwsgi_log("[uwsgi-websocket] invalid packet size received: %llu, max allowed: %llu\n", wsgi_req->websocket_size, uwsgi.websockets_max_size * 1024);
|
||||
return NULL;
|
||||
}
|
||||
wsgi_req->websocket_phase = 2;
|
||||
break;
|
||||
// mask check
|
||||
case 2:
|
||||
if (wsgi_req->websocket_has_mask) {
|
||||
wsgi_req->websocket_need += 4;
|
||||
wsgi_req->websocket_phase = 3;
|
||||
}
|
||||
else {
|
||||
wsgi_req->websocket_need += wsgi_req->websocket_size;
|
||||
wsgi_req->websocket_phase = 4;
|
||||
}
|
||||
break;
|
||||
// mask
|
||||
case 3:
|
||||
wsgi_req->websocket_pktsize += wsgi_req->websocket_size;
|
||||
wsgi_req->websocket_need += wsgi_req->websocket_size;
|
||||
wsgi_req->websocket_phase = 4;
|
||||
break;
|
||||
// message
|
||||
case 4:
|
||||
switch (wsgi_req->websocket_opcode) {
|
||||
// message
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
return uwsgi_websockets_parse(wsgi_req);
|
||||
// close
|
||||
case 0x8:
|
||||
return NULL;
|
||||
// ping
|
||||
case 0x9:
|
||||
if (uwsgi_websockets_pong(wsgi_req)) {
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
// pong
|
||||
case 0xA:
|
||||
wsgi_req->websocket_last_pong = uwsgi_now();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// reset the status
|
||||
wsgi_req->websocket_phase = 0;
|
||||
wsgi_req->websocket_need = 2;
|
||||
// decapitate the buffer
|
||||
if (uwsgi_buffer_decapitate(wsgi_req->websocket_buf, wsgi_req->websocket_pktsize)) return NULL;
|
||||
break;
|
||||
// oops
|
||||
default:
|
||||
uwsgi_log("[uwsgi-websocket] BUG error in websocket parser\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
// need more data
|
||||
else {
|
||||
if (uwsgi_buffer_ensure(wsgi_req->websocket_buf, uwsgi.page_size)) return NULL;
|
||||
ssize_t len = uwsgi_websockets_recv_pkt(wsgi_req, nb);
|
||||
if (len <= 0) {
|
||||
if (nb == 1 && len == 0) {
|
||||
// return an empty buffer to signal blocking event
|
||||
return uwsgi_buffer_new(0);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
// update buffer size
|
||||
wsgi_req->websocket_buf->pos+=len;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *uwsgi_websocket_recv(struct wsgi_request *wsgi_req) {
|
||||
if (wsgi_req->websocket_closed) {
|
||||
return NULL;
|
||||
}
|
||||
struct uwsgi_buffer *ub = uwsgi_websocket_recv_do(wsgi_req, 0);
|
||||
if (!ub) {
|
||||
wsgi_req->websocket_closed = 1;
|
||||
}
|
||||
return ub;
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *uwsgi_websocket_recv_nb(struct wsgi_request *wsgi_req) {
|
||||
if (wsgi_req->websocket_closed) {
|
||||
return NULL;
|
||||
}
|
||||
struct uwsgi_buffer *ub = uwsgi_websocket_recv_do(wsgi_req, 1);
|
||||
if (!ub) {
|
||||
wsgi_req->websocket_closed = 1;
|
||||
}
|
||||
return ub;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ssize_t uwsgi_websockets_simple_send(struct wsgi_request *wsgi_req, struct uwsgi_buffer *ub) {
|
||||
ssize_t len = wsgi_req->socket->proto_write(wsgi_req, ub->buf, ub->pos);
|
||||
if (wsgi_req->write_errors > 0) {
|
||||
return -1;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int uwsgi_websocket_handshake(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *origin, uint16_t origin_len) {
|
||||
#ifdef UWSGI_SSL
|
||||
char sha1[20];
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "101 Web Socket Protocol Handshake", 33)) return -1;
|
||||
if (uwsgi_response_add_header(wsgi_req, "Upgrade", 7, "WebSocket", 9)) return -1;
|
||||
if (uwsgi_response_add_header(wsgi_req, "Connection", 10, "Upgrade", 7)) return -1;
|
||||
if (origin_len > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Origin", 20, origin, origin_len)) return -1;
|
||||
}
|
||||
else {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Origin", 20, "*", 1)) return -1;
|
||||
}
|
||||
// generate websockets sha1 and encode it to base64
|
||||
if (!uwsgi_sha1_2n(key, key_len, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", 36, sha1)) return -1;
|
||||
size_t b64_len = 0;
|
||||
char *b64 = uwsgi_base64_encode(sha1, 20, &b64_len);
|
||||
if (!b64) return -1;
|
||||
|
||||
if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Accept", 20, b64, b64_len)) {
|
||||
free(b64);
|
||||
return -1;
|
||||
}
|
||||
free(b64);
|
||||
|
||||
wsgi_req->websocket_last_pong = uwsgi_now();
|
||||
|
||||
return uwsgi_response_write_headers_do(wsgi_req);
|
||||
#else
|
||||
uwsgi_log("you need to build uWSGI with SSL support to use the websocket handshake api function !!!\n");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void uwsgi_websockets_init() {
|
||||
uwsgi.websockets_pong = uwsgi_buffer_new(2);
|
||||
uwsgi_buffer_append(uwsgi.websockets_pong, "\x8A\0", 2);
|
||||
uwsgi.websockets_ping = uwsgi_buffer_new(2);
|
||||
uwsgi_buffer_append(uwsgi.websockets_ping, "\x89\0", 2);
|
||||
uwsgi.websockets_ping_freq = 30;
|
||||
uwsgi.websockets_pong_tolerance = 3;
|
||||
uwsgi.websockets_max_size = 1024;
|
||||
}
|
||||
-299
@@ -1,299 +0,0 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_response_add_content_length(struct wsgi_request *wsgi_req, uint64_t cl) {
|
||||
char buf[sizeof(UMAX64_STR)+1];
|
||||
int ret = snprintf(buf, sizeof(UMAX64_STR)+1, "%llu", (unsigned long long) cl);
|
||||
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
return uwsgi_response_add_header(wsgi_req, "Content-Length", 14, buf, ret);
|
||||
}
|
||||
|
||||
// status could be NNN or NNN message
|
||||
int uwsgi_response_prepare_headers(struct wsgi_request *wsgi_req, char *status, uint16_t status_len) {
|
||||
|
||||
if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || status_len < 3 || wsgi_req->write_errors) return -1;
|
||||
|
||||
if (!wsgi_req->headers) {
|
||||
wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size);
|
||||
wsgi_req->headers->limit = UMAX16;
|
||||
}
|
||||
|
||||
// reset the buffer (could be useful for rollbacks...)
|
||||
wsgi_req->headers->pos = 0;
|
||||
struct uwsgi_buffer *hh = NULL;
|
||||
if (status_len <= 4) {
|
||||
char *new_sc = NULL;
|
||||
size_t new_sc_len = 0;
|
||||
uint16_t sc_len = 0;
|
||||
const char *sc = uwsgi_http_status_msg(status, &sc_len);
|
||||
if (sc) {
|
||||
new_sc = uwsgi_concat3n(status, 3, " ", 1, (char *)sc, sc_len);
|
||||
new_sc_len = 4+sc_len;
|
||||
}
|
||||
else {
|
||||
new_sc = uwsgi_concat2n(status, 3, " Unknown", 8);
|
||||
new_sc_len = 11;
|
||||
}
|
||||
hh = wsgi_req->socket->proto_prepare_headers(wsgi_req, new_sc, new_sc_len);
|
||||
free(new_sc);
|
||||
}
|
||||
else {
|
||||
hh = wsgi_req->socket->proto_prepare_headers(wsgi_req, status, status_len);
|
||||
}
|
||||
if (!hh) {wsgi_req->write_errors++; return -1;}
|
||||
if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error;
|
||||
uwsgi_buffer_destroy(hh);
|
||||
wsgi_req->status = uwsgi_str3_num(status);
|
||||
return 0;
|
||||
error:
|
||||
uwsgi_buffer_destroy(hh);
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
//each protocol has its header generator
|
||||
int uwsgi_response_add_header(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) {
|
||||
|
||||
if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || wsgi_req->write_errors) return -1;
|
||||
|
||||
struct uwsgi_string_list *rh = uwsgi.remove_headers;
|
||||
while(rh) {
|
||||
if (!uwsgi_strnicmp(key, key_len, rh->value, rh->len)) {
|
||||
return 0;
|
||||
}
|
||||
rh = rh->next;
|
||||
}
|
||||
rh = wsgi_req->remove_headers;
|
||||
while(rh) {
|
||||
if (!uwsgi_strnicmp(key, key_len, rh->value, rh->len)) {
|
||||
return 0;
|
||||
}
|
||||
rh = rh->next;
|
||||
}
|
||||
|
||||
if (!wsgi_req->headers) {
|
||||
wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size);
|
||||
wsgi_req->headers->limit = UMAX16;
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *hh = wsgi_req->socket->proto_add_header(wsgi_req, key, key_len, value, value_len);
|
||||
if (!hh) { wsgi_req->write_errors++ ; return -1;}
|
||||
if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error;
|
||||
wsgi_req->header_cnt++;
|
||||
uwsgi_buffer_destroy(hh);
|
||||
return 0;
|
||||
error:
|
||||
uwsgi_buffer_destroy(hh);
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int uwsgi_response_write_headers_do(struct wsgi_request *wsgi_req) {
|
||||
if (wsgi_req->headers_sent || !wsgi_req->headers || wsgi_req->response_size || wsgi_req->write_errors) {
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
struct uwsgi_string_list *ah = uwsgi.additional_headers;
|
||||
while(ah) {
|
||||
if (uwsgi_response_add_header(wsgi_req, NULL, 0, ah->value, ah->len)) return -1;
|
||||
ah = ah->next;
|
||||
}
|
||||
|
||||
ah = wsgi_req->additional_headers;
|
||||
while(ah) {
|
||||
if (uwsgi_response_add_header(wsgi_req, NULL, 0, ah->value, ah->len)) return -1;
|
||||
ah = ah->next;
|
||||
}
|
||||
|
||||
|
||||
if (wsgi_req->socket->proto_fix_headers(wsgi_req)) { wsgi_req->write_errors++ ; return -1;}
|
||||
|
||||
for(;;) {
|
||||
int ret = wsgi_req->socket->proto_write_headers(wsgi_req, wsgi_req->headers->buf, wsgi_req->headers->pos);
|
||||
if (ret < 0) {
|
||||
if (!uwsgi.ignore_write_errors) {
|
||||
uwsgi_error("uwsgi_response_write_headers_do()");
|
||||
}
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
if (ret == UWSGI_OK) {
|
||||
break;
|
||||
}
|
||||
ret = uwsgi_wait_write_req(wsgi_req);
|
||||
if (ret < 0) { wsgi_req->write_errors++; return -1;}
|
||||
if (ret == 0) {
|
||||
uwsgi_log("uwsgi_response_write_headers_do() TIMEOUT !!!\n");
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
wsgi_req->headers_size += wsgi_req->write_pos;
|
||||
// reset for the next write
|
||||
wsgi_req->write_pos = 0;
|
||||
wsgi_req->headers_sent = 1;
|
||||
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
|
||||
if (wsgi_req->write_errors) return -1;
|
||||
|
||||
if (!wsgi_req->headers_sent) {
|
||||
int ret = uwsgi_response_write_headers_do(wsgi_req);
|
||||
if (ret == UWSGI_OK) goto sendbody;
|
||||
if (ret == UWSGI_AGAIN) return UWSGI_AGAIN;
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
sendbody:
|
||||
|
||||
if (len == 0) return UWSGI_OK;
|
||||
|
||||
for(;;) {
|
||||
int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len);
|
||||
if (ret < 0) {
|
||||
if (!uwsgi.ignore_write_errors) {
|
||||
uwsgi_error("uwsgi_response_write_body_do()");
|
||||
}
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
if (ret == UWSGI_OK) {
|
||||
break;
|
||||
}
|
||||
ret = uwsgi_wait_write_req(wsgi_req);
|
||||
if (ret < 0) { wsgi_req->write_errors++; return -1;}
|
||||
if (ret == 0) {
|
||||
uwsgi_log("uwsgi_response_write_body_do() TIMEOUT !!!\n");
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
wsgi_req->response_size += wsgi_req->write_pos;
|
||||
// reset for the next write
|
||||
wsgi_req->write_pos = 0;
|
||||
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
int uwsgi_response_sendfile_do(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) {
|
||||
|
||||
int can_close = 1;
|
||||
|
||||
if (fd == wsgi_req->sendfile_fd) can_close = 0;
|
||||
|
||||
if (wsgi_req->write_errors) return -1;
|
||||
|
||||
if (!wsgi_req->headers_sent) {
|
||||
int ret = uwsgi_response_write_headers_do(wsgi_req);
|
||||
if (ret == UWSGI_OK) goto sendfile;
|
||||
if (ret == UWSGI_AGAIN) return UWSGI_AGAIN;
|
||||
wsgi_req->write_errors++;
|
||||
if (can_close) close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sendfile:
|
||||
|
||||
if (len == 0) {
|
||||
struct stat st;
|
||||
if (fstat(fd, &st)) {
|
||||
uwsgi_error("fstat()");
|
||||
wsgi_req->write_errors++;
|
||||
if (can_close) close(fd);
|
||||
return -1;
|
||||
}
|
||||
len = st.st_size;
|
||||
}
|
||||
|
||||
if (wsgi_req->socket->can_offload) {
|
||||
// of we cannot close the socket (before the app will close it later)
|
||||
// let's dup it
|
||||
if (!can_close) {
|
||||
int tmp_fd = dup(fd);
|
||||
if (tmp_fd < 0) {
|
||||
uwsgi_error("uwsgi_response_sendfile_do()/dup()");
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
fd = tmp_fd;
|
||||
can_close = 1;
|
||||
}
|
||||
if (!uwsgi_offload_request_sendfile_do(wsgi_req, fd, len)) {
|
||||
wsgi_req->via = UWSGI_VIA_OFFLOAD;
|
||||
wsgi_req->response_size += len;
|
||||
return 0;
|
||||
}
|
||||
wsgi_req->write_errors++;
|
||||
if (can_close) close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
wsgi_req->via = UWSGI_VIA_SENDFILE;
|
||||
|
||||
for(;;) {
|
||||
int ret = wsgi_req->socket->proto_sendfile(wsgi_req, fd, pos, len);
|
||||
if (ret < 0) {
|
||||
if (!uwsgi.ignore_write_errors) {
|
||||
uwsgi_error("uwsgi_response_sendfile_do()");
|
||||
}
|
||||
wsgi_req->write_errors++;
|
||||
if (can_close) close(fd);
|
||||
return -1;
|
||||
}
|
||||
if (ret == UWSGI_OK) {
|
||||
break;
|
||||
}
|
||||
ret = uwsgi_wait_write_req(wsgi_req);
|
||||
if (ret < 0) {
|
||||
wsgi_req->write_errors++;
|
||||
if (can_close) close(fd);
|
||||
return -1;
|
||||
}
|
||||
if (ret == 0) {
|
||||
uwsgi_log("uwsgi_response_sendfile_do() TIMEOUT !!!\n");
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
wsgi_req->response_size += wsgi_req->write_pos;
|
||||
// reset for the next write
|
||||
wsgi_req->write_pos = 0;
|
||||
// close the file descriptor
|
||||
if (can_close) close(fd);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_simple_wait_write_hook(int fd, int timeout) {
|
||||
struct pollfd upoll;
|
||||
timeout = timeout * 1000;
|
||||
|
||||
upoll.fd = fd;
|
||||
upoll.events = POLLOUT;
|
||||
upoll.revents = 0;
|
||||
int ret = poll(&upoll, 1, timeout);
|
||||
|
||||
if (ret > 0) {
|
||||
if (upoll.revents & POLLOUT) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (ret < 0) {
|
||||
uwsgi_error("uwsgi_simple_wait_write_hook()/poll()");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
+3
-3
@@ -20,7 +20,7 @@ void uwsgi_xml_config(char *filename, struct wsgi_request *wsgi_req, char *magic
|
||||
|
||||
char *xml_id;
|
||||
char *xml_content;
|
||||
size_t xml_size = 0;
|
||||
int xml_size = 0;
|
||||
|
||||
if (uwsgi_check_scheme(filename)) {
|
||||
colon = uwsgi_get_last_char(filename, '/');
|
||||
@@ -47,7 +47,7 @@ void uwsgi_xml_config(char *filename, struct wsgi_request *wsgi_req, char *magic
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_log_initial("[uWSGI] parsing config file %s\n", filename);
|
||||
uwsgi_log("[uWSGI] parsing config file %s\n", filename);
|
||||
|
||||
element = xmlDocGetRootElement(doc);
|
||||
if (element == NULL) {
|
||||
@@ -221,7 +221,7 @@ void uwsgi_xml_config(char *filename, struct wsgi_request *wsgi_req, char *magic
|
||||
char *colon;
|
||||
|
||||
char *xml_content;
|
||||
size_t xml_size = 0;
|
||||
int xml_size = 0;
|
||||
int done = 0;
|
||||
|
||||
if (uwsgi_check_scheme(filename)) {
|
||||
|
||||
+4
-4
@@ -61,9 +61,9 @@ int yaml_get_depth(char *line) {
|
||||
return depth;
|
||||
}
|
||||
|
||||
char *yaml_get_line(char *yaml, size_t size) {
|
||||
char *yaml_get_line(char *yaml, off_t size) {
|
||||
|
||||
size_t i;
|
||||
off_t i;
|
||||
char *ptr = yaml;
|
||||
int comment = 0;
|
||||
|
||||
@@ -96,7 +96,7 @@ char *yaml_get_line(char *yaml, size_t size) {
|
||||
|
||||
void uwsgi_yaml_config(char *file, char *magic_table[]) {
|
||||
|
||||
size_t len = 0;
|
||||
int len = 0;
|
||||
char *yaml;
|
||||
|
||||
int in_uwsgi_section = 0;
|
||||
@@ -122,7 +122,7 @@ void uwsgi_yaml_config(char *file, char *magic_table[]) {
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log_initial("[uWSGI] getting YAML configuration from %s\n", file);
|
||||
uwsgi_log("[uWSGI] getting YAML configuration from %s\n", file);
|
||||
|
||||
yaml = uwsgi_open_and_read(file, &len, 1, magic_table);
|
||||
|
||||
|
||||
-55
@@ -1,55 +0,0 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
|
||||
int uwsgi_deflate_init(z_stream *z, char *dict, size_t dict_len) {
|
||||
z->zalloc = Z_NULL;
|
||||
z->zfree = Z_NULL;
|
||||
z->opaque = Z_NULL;
|
||||
if (deflateInit2(z, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 9, Z_DEFAULT_STRATEGY) != Z_OK) {
|
||||
//if (deflateInit(z, Z_DEFAULT_COMPRESSION)) {
|
||||
return -1;
|
||||
}
|
||||
if (dict && dict_len) {
|
||||
if (deflateSetDictionary(z, (Bytef *) dict, dict_len) != Z_OK) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_deflate(z_stream *z, char *buf, size_t len, size_t *dlen) {
|
||||
|
||||
// calculate the amount of bytes needed for output (+30 should be enough)
|
||||
Bytef *dbuf = uwsgi_malloc(len+30);
|
||||
z->avail_in = len;
|
||||
z->next_in = (Bytef *) buf;
|
||||
z->avail_out = len+30;
|
||||
z->next_out = dbuf;
|
||||
|
||||
if (len > 0) {
|
||||
if (deflate(z, Z_SYNC_FLUSH) != Z_OK) {
|
||||
free(dbuf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (deflate(z, Z_FINISH) != Z_STREAM_END) {
|
||||
free(dbuf);
|
||||
return NULL;
|
||||
}
|
||||
deflateEnd(z);
|
||||
}
|
||||
|
||||
*dlen = (z->next_out - dbuf);
|
||||
return (char *) dbuf;
|
||||
}
|
||||
|
||||
void uwsgi_crc32(uint32_t *ctx, char *buf, size_t len) {
|
||||
if (!buf) {
|
||||
*ctx = crc32(*ctx, Z_NULL, 0);
|
||||
}
|
||||
else {
|
||||
*ctx = crc32(*ctx, (const Bytef *) buf, len);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
{% extends "admin/base_site.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<div class="breadcrumbs">
|
||||
<a href="../">{% trans 'Home' %}</a> ›
|
||||
{% trans 'uWSGI' %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div id="content-main">
|
||||
<h1>uWSGI status</h1>
|
||||
<b>masterpid:</b> {{masterpid}}<br/>
|
||||
<b>started_on:</b> {{started_on}}<br/>
|
||||
<b>buffer size:</b> {{buffer_size}}<br/>
|
||||
<b>workers:</b> {{numproc}}<br/>
|
||||
<b>total requests:</b> {{total_requests}}<br/>
|
||||
|
||||
<br/>
|
||||
|
||||
<div class="module" style="width:860px">
|
||||
<table>
|
||||
<caption style="width:860px">workers</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="row">id</th>
|
||||
<th scope="row">pid</th>
|
||||
<th scope="row">requests</th>
|
||||
<th scope="row">running time (milliseconds)</th>
|
||||
<th scope="row">load</th>
|
||||
<th scope="row">last spawn</th>
|
||||
<th scope="row">respawn count</th>
|
||||
<th scope="row">address space (vsz)</th>
|
||||
<th scope="row">resident memory (rss)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for w in workers %}
|
||||
<tr>
|
||||
<td align="center">{{w.id}}</td>
|
||||
<td align="center">{{w.pid}}</td>
|
||||
<td align="right">{{w.requests}}</td>
|
||||
<td align="right">{{w.running_time}}</td>
|
||||
<td align="right">{{w.load|floatformat:2}} %</td>
|
||||
<td align="right">{{w.last_spawn_str}}</td>
|
||||
<td align="right">{{w.respawn_count}}</td>
|
||||
<td align="right">{{w.vsz|filesizeformat}}</td>
|
||||
<td align="right">{{w.rss|filesizeformat}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="module" style="width:860px">
|
||||
<table>
|
||||
<caption style="width:860px">spooler jobs</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="row">job filename</th>
|
||||
<th scope="row">environment</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for j in jobs %}
|
||||
<tr>
|
||||
<td align="left">{{j.file}}</td>
|
||||
<td align="left">{{j.env}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% if masterpid %}
|
||||
<br/>
|
||||
<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="reload/" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="submit" value="gracefully reload uWSGI" name="_reload"/>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from django.conf.urls.defaults import *
|
||||
|
||||
urlpatterns = patterns('uwsgi_admin.views',
|
||||
(r'^$', 'index'),
|
||||
(r'^reload/$', 'reload')
|
||||
)
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import uwsgi
|
||||
import time
|
||||
from django.shortcuts import render_to_response
|
||||
from django.template import RequestContext
|
||||
from django.contrib.admin.views.decorators import staff_member_required
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import HttpResponseRedirect
|
||||
|
||||
|
||||
def index(request):
|
||||
workers = uwsgi.workers()
|
||||
total_load = time.time() - uwsgi.started_on
|
||||
for w in workers:
|
||||
w['load'] = (100 * (w['running_time']/1000))/total_load
|
||||
w['last_spawn_str'] = time.ctime(w['last_spawn'])
|
||||
|
||||
jobs = []
|
||||
if 'spooler' in uwsgi.opt:
|
||||
spooler_jobs = uwsgi.spooler_jobs()
|
||||
for j in spooler_jobs:
|
||||
jobs.append({'file': j, 'env': uwsgi.parsefile(j)})
|
||||
|
||||
return render_to_response('uwsgi.html', {'masterpid': uwsgi.masterpid(),
|
||||
'started_on': time.ctime(uwsgi.started_on),
|
||||
'buffer_size': uwsgi.buffer_size,
|
||||
'total_requests': uwsgi.total_requests(),
|
||||
'numproc': uwsgi.numproc,
|
||||
'workers': workers,
|
||||
'jobs': jobs,
|
||||
}, RequestContext(request, {}))
|
||||
index = staff_member_required(index)
|
||||
|
||||
def reload(request):
|
||||
if uwsgi.masterpid() > 0:
|
||||
uwsgi.reload()
|
||||
request.user.message_set.create(message="uWSGI reloaded")
|
||||
else:
|
||||
request.user.message_set.create(message="The uWSGI master process is not active")
|
||||
|
||||
return HttpResponseRedirect(reverse(index))
|
||||
|
||||
reload = staff_member_required(reload)
|
||||
@@ -0,0 +1,29 @@
|
||||
from django.template.base import TemplateDoesNotExist
|
||||
from django.template.loader import BaseLoader
|
||||
from django.conf import settings
|
||||
|
||||
try:
|
||||
import uwsgi
|
||||
on_uwsgi = True
|
||||
except:
|
||||
on_uwsgi = False
|
||||
|
||||
|
||||
|
||||
|
||||
class Loader(BaseLoader):
|
||||
|
||||
is_usable = on_uwsgi
|
||||
|
||||
def symbolize(self, name):
|
||||
return name.replace('.','_').replace('/','_').replace('-','_')
|
||||
|
||||
def load_template_source(self, template_name, template_dirs=None):
|
||||
filename = 'templates_' + self.symbolize(template_name)
|
||||
for app in settings.INSTALLED_APPS:
|
||||
try:
|
||||
symbol = "%s_%s" % (self.symbolize(app), filename)
|
||||
return (uwsgi.embedded_data(symbol), "sym://%s" % symbol)
|
||||
except:
|
||||
pass
|
||||
raise TemplateDoesNotExist(template_name)
|
||||
@@ -1,77 +0,0 @@
|
||||
# to run the server
|
||||
# uwsgi --plugin psgi,coroae --http-socket :9090 --http-socket-modifier1 5 --coroae 8 --psgi examples/corostream.pl --master
|
||||
# to test it
|
||||
# curl -D /dev/stdout -N --raw http://localhost:9090/
|
||||
|
||||
use Coro::AnyEvent;
|
||||
use AnyEvent::HTTP;
|
||||
|
||||
my $signal_handler = sub {
|
||||
my $signum = shift;
|
||||
print "i am the signal ".$signum."\n" ;
|
||||
};
|
||||
|
||||
my $signal_timer = sub {
|
||||
my $signum = shift;
|
||||
print "2 seconds elapsed\n";
|
||||
};
|
||||
|
||||
uwsgi::register_signal(17, '', $signal_handler);
|
||||
uwsgi::register_signal(30, '', $signal_timer);
|
||||
|
||||
# raise the signal 30 every 2 seconds
|
||||
uwsgi::add_timer(30, 2);
|
||||
|
||||
sub streamer {
|
||||
$responder = shift;
|
||||
# generate the headers and start streaming the response
|
||||
my $writer = $responder->( [200, ['Content-Type' => 'text/plain']]);
|
||||
|
||||
$writer->write("Hello, the streaming is starting...\n");
|
||||
|
||||
for(my $i=0;$i<5;$i++) {
|
||||
Coro::AnyEvent::sleep 1;
|
||||
$writer->write("[".$i."] one seconds elapsed...\n");
|
||||
}
|
||||
|
||||
$writer->write("let me show you the coroae plugin source taken from github\n\n");
|
||||
|
||||
# this condvar will allow us to wait for the github response
|
||||
my $w = AnyEvent->condvar;
|
||||
|
||||
my $uwsgi_coroae_src = '';
|
||||
|
||||
http_get 'https://raw.github.com/unbit/uwsgi/master/plugins/coroae/coroae.c', sub { $uwsgi_coroae_src = $_[0] ; $w->send;};
|
||||
|
||||
$w->recv;
|
||||
|
||||
$writer->write($uwsgi_coroae_src);
|
||||
|
||||
Coro::AnyEvent::sleep 1;
|
||||
|
||||
$writer->write("now let's raise a uwsgi signal...\n");
|
||||
|
||||
uwsgi::signal(17);
|
||||
|
||||
Coro::AnyEvent::sleep 1;
|
||||
|
||||
$writer->write("another one second elapsed, time to finish.\n");
|
||||
|
||||
Coro::AnyEvent::sleep 1;
|
||||
|
||||
$writer->write("Goodbye\n");
|
||||
|
||||
$writer->close;
|
||||
|
||||
print "the request ended, but we are still here\n";
|
||||
|
||||
Coro::AnyEvent::sleep 1;
|
||||
|
||||
print "another second elapsed, time to end (really)\n";
|
||||
}
|
||||
|
||||
# our PSGI app
|
||||
my $app = sub {
|
||||
my $env = shift;
|
||||
return \&streamer;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
require 'net/http'
|
||||
|
||||
Net::HTTP.start("uwsgi.it") do |http|
|
||||
resp = http.get("/install")
|
||||
open("install.sh", "wb") do |file|
|
||||
file.write(resp.body)
|
||||
end
|
||||
end
|
||||
|
||||
system("bash install.sh rack #{Dir.pwd}/uwsgi.ruby")
|
||||
|
||||
open("Makefile", "w") do |file|
|
||||
file.write("all:\n")
|
||||
file.write("\t\n")
|
||||
end
|
||||
+1
-2
@@ -15,11 +15,10 @@ rpc result:<br/>
|
||||
|
||||
<?
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
echo uwsgi_cache_update('foobar', $_POST['cache_val']);
|
||||
uwsgi_cache_update('foobar', $_POST['cache_val']);
|
||||
}
|
||||
|
||||
?>
|
||||
cache value: <?= uwsgi_cache_get('foobar') ?><br/>
|
||||
<form method="POST">
|
||||
<input type="text" name="cache_val" value="<?=uwsgi_cache_get('foobar')?>"/>
|
||||
<input type="submit" value="cache set" />
|
||||
|
||||
+2
-14
@@ -132,16 +132,10 @@ void linux_namespace_jail() {
|
||||
|
||||
if (strcmp(uwsgi.ns, "/")) {
|
||||
ns_tmp_mountpoint = uwsgi_concat2(uwsgi.ns, "/.uwsgi_ns_tmp_mountpoint");
|
||||
if (mkdir(ns_tmp_mountpoint, S_IRWXU) < 0) {
|
||||
uwsgi_error("mkdir() ns_tmp_mountpoint");
|
||||
exit(1);
|
||||
}
|
||||
mkdir(ns_tmp_mountpoint, S_IRWXU);
|
||||
|
||||
ns_tmp_mountpoint2 = uwsgi_concat2(ns_tmp_mountpoint, "/.uwsgi_ns_tmp_mountpoint");
|
||||
if (mkdir(ns_tmp_mountpoint2, S_IRWXU) < 0) {
|
||||
uwsgi_error("mkdir() ns_tmp_mountpoint2");
|
||||
exit(1);
|
||||
}
|
||||
mkdir(ns_tmp_mountpoint2, S_IRWXU);
|
||||
|
||||
if (mount(uwsgi.ns, ns_tmp_mountpoint, "none", MS_BIND, NULL)) {
|
||||
uwsgi_error("mount()");
|
||||
@@ -207,16 +201,10 @@ void linux_namespace_jail() {
|
||||
|
||||
unmounted = 0;
|
||||
procmounts = fopen("/proc/self/mounts", "r");
|
||||
if (!procmounts)
|
||||
break;
|
||||
while (fgets(line, 1024, procmounts) != NULL) {
|
||||
delim0 = strchr(line, ' ');
|
||||
if (!delim0)
|
||||
continue;
|
||||
delim0++;
|
||||
delim1 = strchr(delim0, ' ');
|
||||
if (!delim1)
|
||||
continue;
|
||||
*delim1 = 0;
|
||||
// and now check for keep-mounts
|
||||
if (uwsgi_is_a_keep_mount(delim0)) continue;
|
||||
|
||||
@@ -6,30 +6,42 @@ extern struct uwsgi_server uwsgi;
|
||||
int uwsgi_request_admin(struct wsgi_request *wsgi_req) {
|
||||
|
||||
uint32_t opt_value = 0;
|
||||
ssize_t len;
|
||||
|
||||
if (wsgi_req->uh->pktsize != 0 && wsgi_req->uh->pktsize != 4)
|
||||
if (wsgi_req->uh.pktsize != 0 && wsgi_req->uh.pktsize != 4)
|
||||
return UWSGI_OK;
|
||||
|
||||
// write request
|
||||
if (wsgi_req->uh->pktsize == 4) {
|
||||
if (wsgi_req->uh.pktsize == 4) {
|
||||
memcpy(&opt_value, wsgi_req->buffer, 4);
|
||||
uwsgi_log( "setting internal option %d to %d\n", wsgi_req->uh->modifier2, opt_value);
|
||||
uwsgi.shared->options[wsgi_req->uh->modifier2] = opt_value;
|
||||
uwsgi_log( "setting internal option %d to %d\n", wsgi_req->uh.modifier2, opt_value);
|
||||
uwsgi.shared->options[wsgi_req->uh.modifier2] = opt_value;
|
||||
|
||||
// ACK
|
||||
wsgi_req->uh->modifier1 = 255;
|
||||
wsgi_req->uh->pktsize = 0;
|
||||
wsgi_req->uh->modifier2 = 1;
|
||||
uwsgi_response_write_body_do(wsgi_req, (char *)wsgi_req->uh , 4);
|
||||
wsgi_req->uh.modifier1 = 255;
|
||||
wsgi_req->uh.pktsize = 0;
|
||||
wsgi_req->uh.modifier2 = 1;
|
||||
len = write(wsgi_req->poll.fd, wsgi_req, 4);
|
||||
if (len != 4) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
}
|
||||
// get request
|
||||
else {
|
||||
uwsgi_log( "internal option %d = %d\n", wsgi_req->uh->modifier2, uwsgi.shared->options[wsgi_req->uh->modifier2]);
|
||||
uwsgi_log( "internal option %d = %d\n", wsgi_req->uh.modifier2, uwsgi.shared->options[wsgi_req->uh.modifier2]);
|
||||
|
||||
wsgi_req->uh->modifier1 = 10;
|
||||
wsgi_req->uh->pktsize = 4;
|
||||
uwsgi_response_write_body_do(wsgi_req, (char *)wsgi_req->uh , 4);
|
||||
uwsgi_response_write_body_do(wsgi_req, (char *) &uwsgi.shared->options[wsgi_req->uh->modifier2], 4);
|
||||
wsgi_req->uh.modifier1 = 10;
|
||||
wsgi_req->uh.pktsize = 4;
|
||||
len = write(wsgi_req->poll.fd, wsgi_req, 4);
|
||||
if (len != 4) {
|
||||
uwsgi_error("write()");
|
||||
return UWSGI_OK;
|
||||
}
|
||||
len = write(wsgi_req->poll.fd, (char *) &uwsgi.shared->options[wsgi_req->uh.modifier2], 4);
|
||||
if (len != 4) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return UWSGI_OK;
|
||||
|
||||
@@ -17,7 +17,6 @@ struct uwsgi_alarm_curl_opt {
|
||||
};
|
||||
|
||||
|
||||
#ifdef CURLOPT_MAIL_RCPT
|
||||
static void uwsgi_alarm_curl_to(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc) {
|
||||
uacc->to = arg;
|
||||
struct curl_slist *list = NULL;
|
||||
@@ -30,7 +29,6 @@ static void uwsgi_alarm_curl_to(CURL *curl, CURLoption option, char *arg, struct
|
||||
}
|
||||
curl_easy_setopt(curl, option, list);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void uwsgi_alarm_curl_ssl(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc) {
|
||||
curl_easy_setopt(curl, option, (long)CURLUSESSL_ALL);
|
||||
@@ -46,12 +44,8 @@ static void uwsgi_alarm_curl_set_subject(CURL *curl, CURLoption option, char *ar
|
||||
|
||||
static struct uwsgi_alarm_curl_opt uaco[] = {
|
||||
{"url", CURLOPT_URL, NULL},
|
||||
#ifdef CURLOPT_MAIL_RCPT
|
||||
{"mail_to", CURLOPT_MAIL_RCPT, uwsgi_alarm_curl_to },
|
||||
#endif
|
||||
#ifdef CURLOPT_MAIL_FROM
|
||||
{"mail_from", CURLOPT_MAIL_FROM, NULL},
|
||||
#endif
|
||||
{"subject", 0, uwsgi_alarm_curl_set_subject},
|
||||
{"ssl", CURLOPT_USE_SSL, uwsgi_alarm_curl_ssl},
|
||||
{"auth_user", CURLOPT_USERNAME, NULL},
|
||||
|
||||
@@ -25,8 +25,6 @@ class Jabbo : public ConnectionListener{
|
||||
p = strtok_r(NULL, ",", &ctx);
|
||||
}
|
||||
|
||||
full_jid = jab_username;
|
||||
|
||||
JID jid(jab_username);
|
||||
client = new Client( jid, jab_password );
|
||||
client->registerConnectionListener(this);
|
||||
@@ -54,11 +52,11 @@ class Jabbo : public ConnectionListener{
|
||||
event_queue_add_fd_read(u_thread->queue, fd);
|
||||
event_queue_add_fd_read(u_thread->queue, u_thread->pipe[1]);
|
||||
u_connected = 1;
|
||||
uwsgi_log_alarm("-xmpp] (%s) connected to the XMPP server\n", full_jid);
|
||||
uwsgi_log("[uwsgi-xmpp] connected to the XMPP server\n");
|
||||
}
|
||||
|
||||
virtual void onDisconnect(ConnectionError e) {
|
||||
uwsgi_log_alarm("-xmpp] (%s) trying reconnect to the XMPP server...\n", full_jid);
|
||||
uwsgi_log("[uwsgi-xmpp] trying reconnect to the XMPP server...\n");
|
||||
if (u_connected) {
|
||||
// no need to remove it as it is already closed...
|
||||
//event_queue_del_fd(u_thread->queue, fd, event_queue_read());
|
||||
@@ -71,12 +69,12 @@ class Jabbo : public ConnectionListener{
|
||||
}
|
||||
|
||||
virtual void onResourceBindError(const Error *error) {
|
||||
uwsgi_log_alarm("-xmpp] (%s) onResourceBindError(): %s\n", full_jid, error->text().c_str());
|
||||
uwsgi_log("[uwsgi-xmpp] onResourceBindError(): %s\n", error->text().c_str());
|
||||
client->disconnect();
|
||||
}
|
||||
|
||||
virtual void onSessionCreateError(const Error *error) {
|
||||
uwsgi_log_alarm("-xmpp] (%s) onSessionCreateError(): %s\n", full_jid, error->text().c_str());
|
||||
uwsgi_log("[uwsgi-xmpp] onSessionCreateError(): %s\n", error->text().c_str());
|
||||
client->disconnect();
|
||||
}
|
||||
|
||||
@@ -85,7 +83,6 @@ class Jabbo : public ConnectionListener{
|
||||
}
|
||||
|
||||
Client* client;
|
||||
char *full_jid;
|
||||
int fd;
|
||||
int u_connected;
|
||||
struct uwsgi_thread *u_thread;
|
||||
|
||||
Vendored
+39
-253
@@ -1,195 +1,35 @@
|
||||
#include <uwsgi.h>
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
/*
|
||||
|
||||
Plugin for remote access to the uWSGI cache
|
||||
|
||||
For request generating a response containing cache data, we need to make
|
||||
a copy to avoid holding the lock too much in case of blocking/slow writes
|
||||
|
||||
we use 1.9 cache magic functions to be DRY
|
||||
|
||||
the modifier2 is the command to run. Some command is extremely raw, and generally it is mean
|
||||
for internal uWSGI usage.
|
||||
|
||||
commands:
|
||||
|
||||
0 -> simple cache get for values not bigger than 64k, the request is [111, keysize, 0] + key / response is [111, vallen, 0] + value
|
||||
|
||||
1 -> simple cache set for values not bigger than 64k, the request is [111, pktsize, 1] + (key, value) / response is connection closed
|
||||
|
||||
2 -> simple cache del, the request is [111, keysize, 2] + key / response is connection closed
|
||||
|
||||
3/4 -> simple dict based get command -> [111, pktsize ,3/4] + (key|get) / response is value for "key and get", but if "get" and no key is found an HTTP 404 is returned
|
||||
|
||||
5 -> get and stream -> [111, keysize, 5] + key response is a stream of the value til the whole object is transferred
|
||||
|
||||
6 -> dump the whole cache
|
||||
|
||||
17 -> magic interface for plugins remote access { "cmd": "get|set|update|del|exists", "key": "cache key", "expires": "seconds", "cache": "the cache name"}
|
||||
returns: {"status":"ok|notfound|error", "size": "size of the following body, if present"} + stream
|
||||
|
||||
*/
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
static void cache_simple_command(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
|
||||
void cache_command(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
|
||||
|
||||
struct wsgi_request *wsgi_req = (struct wsgi_request *) data;
|
||||
uint64_t tmp_vallen = 0;
|
||||
|
||||
if (vallen > 0) {
|
||||
if (!uwsgi_strncmp(key, keylen, "key", 3)) {
|
||||
uint64_t vallen = 0;
|
||||
char *value = uwsgi_cache_magic_get(val, vallen, &vallen, NULL);
|
||||
if (value) {
|
||||
uwsgi_response_write_body_do(wsgi_req, value, vallen);
|
||||
free(value);
|
||||
val = uwsgi_cache_get(val, vallen, &tmp_vallen);
|
||||
if (val && tmp_vallen > 0) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("cache value size: %llu\n", tmp_vallen);
|
||||
#endif
|
||||
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, val, tmp_vallen);
|
||||
}
|
||||
|
||||
}
|
||||
else if (!uwsgi_strncmp(key, keylen, "get", 3)) {
|
||||
uint64_t vallen = 0;
|
||||
char *value = uwsgi_cache_magic_get(val, vallen, &vallen, NULL);
|
||||
if (value) {
|
||||
uwsgi_response_write_body_do(wsgi_req, value, vallen);
|
||||
free(value);
|
||||
val = uwsgi_cache_get(val, vallen, &tmp_vallen);
|
||||
if (val && vallen > 0) {
|
||||
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, val, tmp_vallen);
|
||||
}
|
||||
else {
|
||||
uwsgi_404(wsgi_req);
|
||||
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, "HTTP/1.0 404 Not Found\r\n\r\n<h1>Not Found</h1>", 44);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this function does not use the magic api internally to avoid too much copy
|
||||
static void manage_magic_context(struct wsgi_request *wsgi_req, struct uwsgi_cache_magic_context *ucmc) {
|
||||
|
||||
struct uwsgi_buffer *ub = NULL;
|
||||
struct uwsgi_cache *uc = uwsgi.caches;
|
||||
|
||||
if (ucmc->cache_len > 0) {
|
||||
uc = uwsgi_cache_by_namelen(ucmc->cache, ucmc->cache_len);
|
||||
if (!uc) return;
|
||||
}
|
||||
|
||||
if (!uc) return;
|
||||
|
||||
// cache get
|
||||
if (!uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "get", 3)) {
|
||||
uint64_t vallen = 0;
|
||||
uwsgi_rlock(uc->lock);
|
||||
char *value = uwsgi_cache_get2(uc, ucmc->key, ucmc->key_len, &vallen);
|
||||
if (!value) {
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
return;
|
||||
}
|
||||
// we are still locked !!!
|
||||
ub = uwsgi_buffer_new(uwsgi.page_size);
|
||||
ub->pos = 4;
|
||||
if (uwsgi_buffer_append_keyval(ub, "status", 6, "ok", 2)) goto error;
|
||||
if (uwsgi_buffer_append_keynum(ub, "size", 4, vallen)) goto error;
|
||||
if (uwsgi_buffer_set_uh(ub, 111, 17)) goto error;
|
||||
if (uwsgi_buffer_append(ub, value, vallen)) goto error;
|
||||
// unlock !!!
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return;
|
||||
}
|
||||
|
||||
// cache exists
|
||||
if (!uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "exists", 6)) {
|
||||
uwsgi_rlock(uc->lock);
|
||||
if (!uwsgi_cache_exists2(uc, ucmc->key, ucmc->key_len)) {
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
return;
|
||||
}
|
||||
// we are still locked !!!
|
||||
ub = uwsgi_buffer_new(uwsgi.page_size);
|
||||
ub->pos = 4;
|
||||
if (uwsgi_buffer_append_keyval(ub, "status", 6, "ok", 2)) goto error;
|
||||
if (uwsgi_buffer_set_uh(ub, 111, 17)) goto error;
|
||||
// unlock !!!
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return;
|
||||
}
|
||||
|
||||
// cache del
|
||||
if (!uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "del", 3)) {
|
||||
uwsgi_wlock(uc->lock);
|
||||
if (uwsgi_cache_del2(uc, ucmc->key, ucmc->key_len, 0, 0)) {
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
return;
|
||||
}
|
||||
// we are still locked !!!
|
||||
ub = uwsgi_buffer_new(uwsgi.page_size);
|
||||
ub->pos = 4;
|
||||
if (uwsgi_buffer_append_keyval(ub, "status", 6, "ok", 2)) goto error;
|
||||
if (uwsgi_buffer_set_uh(ub, 111, 17)) goto error;
|
||||
// unlock !!!
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return;
|
||||
}
|
||||
|
||||
// cache clear
|
||||
if (!uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "clear", 5)) {
|
||||
uint64_t i;
|
||||
uwsgi_wlock(uc->lock);
|
||||
for (i = 1; i < uwsgi.caches->max_items; i++) {
|
||||
if (uwsgi_cache_del2(uc, NULL, 0, i, 0)) {
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// we are still locked !!!
|
||||
ub = uwsgi_buffer_new(uwsgi.page_size);
|
||||
ub->pos = 4;
|
||||
if (uwsgi_buffer_append_keyval(ub, "status", 6, "ok", 2)) goto error;
|
||||
if (uwsgi_buffer_set_uh(ub, 111, 17)) goto error;
|
||||
// unlock !!!
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return;
|
||||
}
|
||||
|
||||
// cache set
|
||||
if (!uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "set", 3) || !uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "update", 6)) {
|
||||
if (ucmc->size == 0 || ucmc->size > uc->max_item_size) return;
|
||||
wsgi_req->post_cl = ucmc->size;
|
||||
// read the value
|
||||
ssize_t rlen = 0;
|
||||
char *value = uwsgi_request_body_read(wsgi_req, ucmc->size, &rlen);
|
||||
if (rlen != (ssize_t) ucmc->size) return;
|
||||
// ok let's lock
|
||||
uwsgi_wlock(uc->lock);
|
||||
if (uwsgi_cache_set2(uc, ucmc->key, ucmc->key_len, value, ucmc->size, ucmc->expires, ucmc->cmd_len > 3 ? UWSGI_CACHE_FLAG_UPDATE : 0)) {
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
return;
|
||||
}
|
||||
// we are still locked !!!
|
||||
ub = uwsgi_buffer_new(uwsgi.page_size);
|
||||
ub->pos = 4;
|
||||
if (uwsgi_buffer_append_keyval(ub, "status", 6, "ok", 2)) goto error;
|
||||
if (uwsgi_buffer_set_uh(ub, 111, 17)) goto error;
|
||||
// unlock !!!
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
error:
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
}
|
||||
|
||||
static int uwsgi_cache_request(struct wsgi_request *wsgi_req) {
|
||||
int uwsgi_cache_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
uint64_t vallen = 0;
|
||||
char *value;
|
||||
@@ -197,116 +37,62 @@ static int uwsgi_cache_request(struct wsgi_request *wsgi_req) {
|
||||
uint16_t argvs[3];
|
||||
uint8_t argc = 0;
|
||||
|
||||
// used for modifier2 17
|
||||
struct uwsgi_cache_magic_context ucmc;
|
||||
struct uwsgi_cache *uc = NULL;
|
||||
|
||||
switch(wsgi_req->uh->modifier2) {
|
||||
switch(wsgi_req->uh.modifier2) {
|
||||
case 0:
|
||||
// get
|
||||
if (wsgi_req->uh->pktsize > 0) {
|
||||
value = uwsgi_cache_magic_get(wsgi_req->buffer, wsgi_req->uh->pktsize, &vallen, NULL);
|
||||
if (value) {
|
||||
wsgi_req->uh->pktsize = vallen;
|
||||
if (uwsgi_response_write_body_do(wsgi_req, (char *)&wsgi_req->uh, 4)) { free(value) ; return -1;}
|
||||
uwsgi_response_write_body_do(wsgi_req, value, vallen);
|
||||
free(value);
|
||||
if (wsgi_req->uh.pktsize > 0) {
|
||||
value = uwsgi_cache_get(wsgi_req->buffer, wsgi_req->uh.pktsize, &vallen);
|
||||
if (value && vallen > 0) {
|
||||
wsgi_req->uh.pktsize = vallen;
|
||||
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, (char *)&wsgi_req->uh, 4);
|
||||
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, value, vallen);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
// set
|
||||
if (wsgi_req->uh->pktsize > 0) {
|
||||
// max 3 items
|
||||
if (wsgi_req->uh.pktsize > 0) {
|
||||
argc = 3;
|
||||
if (!uwsgi_parse_array(wsgi_req->buffer, wsgi_req->uh->pktsize, argv, argvs, &argc)) {
|
||||
if (!uwsgi_parse_array(wsgi_req->buffer, wsgi_req->uh.pktsize, argv, argvs, &argc)) {
|
||||
if (argc > 1) {
|
||||
uwsgi_cache_magic_set(argv[0], argvs[0], argv[1], argvs[1], 0, 0, NULL);
|
||||
uwsgi_cache_set(argv[0], argvs[0], argv[1], argvs[1], 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
// del
|
||||
if (wsgi_req->uh->pktsize > 0) {
|
||||
uwsgi_cache_magic_del(wsgi_req->buffer, wsgi_req->uh->pktsize, NULL);
|
||||
if (wsgi_req->uh.pktsize > 0) {
|
||||
uwsgi_cache_del(wsgi_req->buffer, wsgi_req->uh.pktsize, 0);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
// dict
|
||||
if (wsgi_req->uh->pktsize > 0) {
|
||||
uwsgi_hooked_parse(wsgi_req->buffer, wsgi_req->uh->pktsize, cache_simple_command, (void *) wsgi_req);
|
||||
if (wsgi_req->uh.pktsize > 0) {
|
||||
uwsgi_hooked_parse(wsgi_req->buffer, wsgi_req->uh.pktsize, cache_command, (void *) wsgi_req);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
// get (uwsgi + stream)
|
||||
if (wsgi_req->uh->pktsize > 0) {
|
||||
value = uwsgi_cache_magic_get(wsgi_req->buffer, wsgi_req->uh->pktsize, &vallen, NULL);
|
||||
if (value) {
|
||||
wsgi_req->uh->pktsize = 0;
|
||||
wsgi_req->uh->modifier2 = 1;
|
||||
if (uwsgi_response_write_body_do(wsgi_req, (char *)&wsgi_req->uh, 4)) { free(value) ;return -1;}
|
||||
uwsgi_response_write_body_do(wsgi_req, value, vallen);
|
||||
free(value);
|
||||
if (wsgi_req->uh.pktsize > 0) {
|
||||
value = uwsgi_cache_get(wsgi_req->buffer, wsgi_req->uh.pktsize, &vallen);
|
||||
if (value && vallen > 0) {
|
||||
wsgi_req->uh.pktsize = 0;
|
||||
wsgi_req->uh.modifier2 = 1;
|
||||
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, (char *)&wsgi_req->uh, 4);
|
||||
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, value, vallen);
|
||||
}
|
||||
else {
|
||||
wsgi_req->uh->pktsize = 0;
|
||||
wsgi_req->uh->modifier2 = 0;
|
||||
uwsgi_response_write_body_do(wsgi_req, (char *)&wsgi_req->uh, 4);
|
||||
free(value);
|
||||
wsgi_req->uh.pktsize = 0;
|
||||
wsgi_req->uh.modifier2 = 0;
|
||||
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, (char *)&wsgi_req->uh, 4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
// dump
|
||||
uc = uwsgi.caches;
|
||||
if (wsgi_req->uh->pktsize > 0) {
|
||||
uc = uwsgi_cache_by_namelen(wsgi_req->buffer, wsgi_req->uh->pktsize);
|
||||
}
|
||||
|
||||
if (!uc) break;
|
||||
|
||||
uwsgi_wlock(uc->lock);
|
||||
struct uwsgi_buffer *cache_dump = uwsgi_buffer_new(uwsgi.page_size + uc->filesize);
|
||||
cache_dump->pos = 4;
|
||||
if (uwsgi_buffer_append_keynum(cache_dump, "items", 5, uc->max_items)) {
|
||||
uwsgi_buffer_destroy(cache_dump);
|
||||
break;
|
||||
}
|
||||
if (uwsgi_buffer_append_keynum(cache_dump, "blocksize", 9, uc->blocksize)) {
|
||||
uwsgi_buffer_destroy(cache_dump);
|
||||
break;
|
||||
}
|
||||
|
||||
if (uwsgi_buffer_set_uh(cache_dump, 111, 7)) {
|
||||
uwsgi_buffer_destroy(cache_dump);
|
||||
break;
|
||||
}
|
||||
|
||||
if (uwsgi_buffer_append(cache_dump, (char *)uc->items, uc->filesize)) {
|
||||
uwsgi_buffer_destroy(cache_dump);
|
||||
break;
|
||||
}
|
||||
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
|
||||
uwsgi_response_write_body_do(wsgi_req, cache_dump->buf, cache_dump->pos);
|
||||
uwsgi_buffer_destroy(cache_dump);
|
||||
break;
|
||||
case 17:
|
||||
if (wsgi_req->uh->pktsize == 0) break;
|
||||
memset(&ucmc, 0, sizeof(struct uwsgi_cache_magic_context));
|
||||
if (uwsgi_hooked_parse(wsgi_req->buffer, wsgi_req->uh->pktsize, uwsgi_cache_magic_context_hook, &ucmc)) {
|
||||
break;
|
||||
}
|
||||
manage_magic_context(wsgi_req, &ucmc);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return UWSGI_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct uwsgi_plugin cache_plugin = {
|
||||
|
||||
+50
-104
@@ -1,10 +1,4 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
|
||||
Author: Łukasz Mierzwa
|
||||
|
||||
*/
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
@@ -24,19 +18,14 @@ struct uwsgi_carbon {
|
||||
int no_workers;
|
||||
unsigned long long *last_busyness_values;
|
||||
unsigned long long *current_busyness_values;
|
||||
int *was_busy;
|
||||
int need_retry;
|
||||
time_t last_update;
|
||||
time_t next_retry;
|
||||
int max_retries;
|
||||
int retry_delay;
|
||||
char *root_node;
|
||||
char *hostname_dot_replacement;
|
||||
char *hostname;
|
||||
struct uwsgi_stats_pusher *pusher;
|
||||
} u_carbon;
|
||||
|
||||
static struct uwsgi_option carbon_options[] = {
|
||||
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 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},
|
||||
@@ -44,13 +33,12 @@ static struct uwsgi_option carbon_options[] = {
|
||||
{"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},
|
||||
{"carbon-root", required_argument, 0, "set carbon metrics root node (default 'uwsgi')", uwsgi_opt_set_str, &u_carbon.root_node, 0},
|
||||
{"carbon-hostname-dots", required_argument, 0, "set char to use as a replacement for dots in hostname (dots are not replaced by default)", uwsgi_opt_set_str, &u_carbon.hostname_dot_replacement, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
|
||||
};
|
||||
|
||||
static void carbon_post_init() {
|
||||
|
||||
void carbon_post_init() {
|
||||
|
||||
int i;
|
||||
struct uwsgi_string_list *usl = u_carbon.servers;
|
||||
@@ -71,11 +59,6 @@ static void carbon_post_init() {
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
if (!u_carbon.root_node) u_carbon.root_node = "uwsgi.";
|
||||
if (strlen(u_carbon.root_node) && !uwsgi_endswith(u_carbon.root_node, ".")) {
|
||||
u_carbon.root_node = uwsgi_concat2(u_carbon.root_node, ".");
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -88,13 +71,6 @@ static void carbon_post_init() {
|
||||
}
|
||||
}
|
||||
|
||||
u_carbon.hostname = uwsgi_str(uwsgi.hostname);
|
||||
if (u_carbon.hostname_dot_replacement) {
|
||||
for(i=0;i<(int)strlen(u_carbon.hostname);i++) {
|
||||
if (u_carbon.hostname[i] == '.') u_carbon.hostname[i] = u_carbon.hostname_dot_replacement[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (!u_carbon.last_busyness_values) {
|
||||
u_carbon.last_busyness_values = uwsgi_calloc(sizeof(unsigned long long) * uwsgi.numproc);
|
||||
}
|
||||
@@ -103,23 +79,14 @@ static void carbon_post_init() {
|
||||
u_carbon.current_busyness_values = uwsgi_calloc(sizeof(unsigned long long) * uwsgi.numproc);
|
||||
}
|
||||
|
||||
if (!u_carbon.was_busy) {
|
||||
u_carbon.was_busy = uwsgi_calloc(sizeof(int) * uwsgi.numproc);
|
||||
}
|
||||
|
||||
// set next update to now()+retry_delay, this way we will have first flush just after start
|
||||
u_carbon.last_update = uwsgi_now() - u_carbon.freq + u_carbon.retry_delay;
|
||||
|
||||
uwsgi_log("[carbon] carbon plugin started, %is frequency, %is timeout, max retries %i, retry delay %is\n",
|
||||
u_carbon.freq, u_carbon.timeout, u_carbon.max_retries, u_carbon.retry_delay);
|
||||
|
||||
struct uwsgi_stats_pusher_instance *uspi = uwsgi_stats_pusher_add(u_carbon.pusher, NULL);
|
||||
uspi->freq = u_carbon.freq;
|
||||
// no need to generate the json
|
||||
uspi->raw=1;
|
||||
}
|
||||
|
||||
static int carbon_write(int fd, char *fmt,...) {
|
||||
int carbon_write(int *fd, char *fmt,...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
@@ -127,21 +94,19 @@ static int carbon_write(int fd, char *fmt,...) {
|
||||
int rlen;
|
||||
|
||||
rlen = vsnprintf(ptr, 4096, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (rlen < 1) return 0;
|
||||
|
||||
if (uwsgi_write_nb(fd, ptr, rlen, u_carbon.timeout)) {
|
||||
uwsgi_error("carbon_write()");
|
||||
if (write(*fd, ptr, rlen) <= 0) {
|
||||
uwsgi_error("write()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void carbon_push_stats(int retry_cycle, time_t now) {
|
||||
void carbon_push_stats(int retry_cycle) {
|
||||
struct carbon_server_list *usl = u_carbon.servers_data;
|
||||
if (!u_carbon.servers_data) return;
|
||||
int i;
|
||||
int fd;
|
||||
int wok;
|
||||
@@ -149,7 +114,6 @@ static void carbon_push_stats(int retry_cycle, time_t now) {
|
||||
for (i = 0; i < uwsgi.numproc; i++) {
|
||||
u_carbon.current_busyness_values[i] = uwsgi.workers[i+1].running_time - u_carbon.last_busyness_values[i];
|
||||
u_carbon.last_busyness_values[i] = uwsgi.workers[i+1].running_time;
|
||||
u_carbon.was_busy[i-1] += uwsgi_worker_is_busy(i+1);
|
||||
}
|
||||
|
||||
u_carbon.need_retry = 0;
|
||||
@@ -173,7 +137,7 @@ static void carbon_push_stats(int retry_cycle, time_t now) {
|
||||
u_carbon.need_retry = 1;
|
||||
u_carbon.next_retry = uwsgi_now() + u_carbon.retry_delay;
|
||||
} else {
|
||||
uwsgi_log("[carbon] Maximum number of retries for %s (%d)\n",
|
||||
uwsgi_log("[carbon] Maximum number of retries for %s (1)\n",
|
||||
usl->value, u_carbon.max_retries);
|
||||
usl->healthy = 0;
|
||||
usl->errors = 0;
|
||||
@@ -196,13 +160,11 @@ static void carbon_push_stats(int retry_cycle, time_t now) {
|
||||
unsigned long long worker_busyness = 0;
|
||||
unsigned long long total_harakiri = 0;
|
||||
|
||||
wok = carbon_write(fd, "%s%s.%s.requests %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) uwsgi.workers[0].requests, (unsigned long long) now);
|
||||
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;
|
||||
total_harakiri += uwsgi.workers[i].harakiri_count;
|
||||
|
||||
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;
|
||||
@@ -215,63 +177,53 @@ static void carbon_push_stats(int retry_cycle, time_t now) {
|
||||
total_avg_rt += uwsgi.workers[i].avg_response_time;
|
||||
|
||||
// calculate worker busyness
|
||||
if (u_carbon.current_busyness_values[i-1] == 0 && u_carbon.was_busy[i-1]) {
|
||||
worker_busyness = 100;
|
||||
}
|
||||
else {
|
||||
worker_busyness = ((u_carbon.current_busyness_values[i-1]*100) / (u_carbon.freq*1000000));
|
||||
if (worker_busyness > 100) worker_busyness = 100;
|
||||
}
|
||||
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;
|
||||
u_carbon.was_busy[i-1] = 0;
|
||||
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG] == 1 || uwsgi.force_get_memusage) {
|
||||
// only running workers are counted in total memory stats and if memory-report option is enabled
|
||||
total_rss += uwsgi.workers[i].rss_size;
|
||||
total_vsz += uwsgi.workers[i].vsz_size;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
//skip per worker metrics when disabled
|
||||
if (u_carbon.no_workers) continue;
|
||||
|
||||
wok = carbon_write(fd, "%s%s.%s.worker%d.requests %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, i, (unsigned long long) uwsgi.workers[i].requests, (unsigned long long) now);
|
||||
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;
|
||||
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG] == 1 || uwsgi.force_get_memusage) {
|
||||
wok = carbon_write(fd, "%s%s.%s.worker%d.rss_size %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, i, (unsigned long long) uwsgi.workers[i].rss_size, (unsigned long long) now);
|
||||
if (!wok) goto clear;
|
||||
|
||||
wok = carbon_write(fd, "%s%s.%s.worker%d.vsz_size %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, i, (unsigned long long) uwsgi.workers[i].vsz_size, (unsigned long long) now);
|
||||
if (!wok) goto clear;
|
||||
}
|
||||
|
||||
wok = carbon_write(fd, "%s%s.%s.worker%d.avg_rt %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, i, (unsigned long long) avg_rt, (unsigned long long) now);
|
||||
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, "%s%s.%s.worker%d.tx %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, i, (unsigned long long) uwsgi.workers[i].tx, (unsigned long long) now);
|
||||
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, "%s%s.%s.worker%d.busyness %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, i, (unsigned long long) worker_busyness, (unsigned long long) now);
|
||||
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, "%s%s.%s.worker%d.harakiri %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, i, (unsigned long long) uwsgi.workers[i].harakiri_count, (unsigned long long) now);
|
||||
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, (unsigned long long) uwsgi.current_time);
|
||||
if (!wok) goto clear;
|
||||
|
||||
}
|
||||
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG] == 1 || uwsgi.force_get_memusage) {
|
||||
wok = carbon_write(fd, "%s%s.%s.rss_size %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) total_rss, (unsigned long long) now);
|
||||
if (!wok) goto clear;
|
||||
|
||||
wok = carbon_write(fd, "%s%s.%s.vsz_size %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) total_vsz, (unsigned long long) now);
|
||||
if (!wok) goto clear;
|
||||
}
|
||||
|
||||
wok = carbon_write(fd, "%s%s.%s.avg_rt %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) (active_workers ? total_avg_rt / active_workers : 0), (unsigned long long) now);
|
||||
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, "%s%s.%s.tx %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) total_tx, (unsigned long long) now);
|
||||
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) {
|
||||
@@ -280,18 +232,18 @@ static void carbon_push_stats(int retry_cycle, time_t now) {
|
||||
} else {
|
||||
total_avg_busyness = 0;
|
||||
}
|
||||
wok = carbon_write(fd, "%s%s.%s.busyness %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) total_avg_busyness, (unsigned long long) now);
|
||||
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, "%s%s.%s.active_workers %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) active_workers, (unsigned long long) now);
|
||||
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, "%s%s.%s.cheaped_workers %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) uwsgi.numproc - active_workers, (unsigned long long) now);
|
||||
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, "%s%s.%s.harakiri %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) total_harakiri, (unsigned long long) now);
|
||||
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;
|
||||
@@ -308,34 +260,28 @@ nxt:
|
||||
u_carbon.last_update -= u_carbon.timeout;
|
||||
}
|
||||
|
||||
static void carbon_push(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) {
|
||||
void carbon_master_cycle() {
|
||||
|
||||
if (u_carbon.need_retry && now >= u_carbon.next_retry) {
|
||||
carbon_push_stats(1, now);
|
||||
}
|
||||
else {
|
||||
if (!u_carbon.servers) return;
|
||||
|
||||
if (uwsgi.current_time - u_carbon.last_update >= u_carbon.freq || uwsgi.cleaning) {
|
||||
// update
|
||||
u_carbon.need_retry = 0;
|
||||
carbon_push_stats(0, now);
|
||||
|
||||
carbon_push_stats(0);
|
||||
} else if (u_carbon.need_retry && (uwsgi.current_time >= u_carbon.next_retry)) {
|
||||
// retry failed servers
|
||||
carbon_push_stats(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void carbon_cleanup() {
|
||||
carbon_push_stats(0, uwsgi_now());
|
||||
}
|
||||
|
||||
static void carbon_register() {
|
||||
u_carbon.pusher = uwsgi_register_stats_pusher("carbon", carbon_push);
|
||||
}
|
||||
|
||||
struct uwsgi_plugin carbon_plugin = {
|
||||
|
||||
.name = "carbon",
|
||||
|
||||
.master_cleanup = carbon_cleanup,
|
||||
.master_cleanup = carbon_master_cycle,
|
||||
|
||||
.options = carbon_options,
|
||||
.on_load = carbon_register,
|
||||
.master_cycle = carbon_master_cycle,
|
||||
.post_init = carbon_post_init,
|
||||
};
|
||||
|
||||
+155
-58
@@ -1,4 +1,4 @@
|
||||
#include <uwsgi.h>
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
@@ -66,6 +66,55 @@ struct uwsgi_option uwsgi_cgi_options[] = {
|
||||
|
||||
};
|
||||
|
||||
void uwsgi_cgi_404(struct wsgi_request *wsgi_req) {
|
||||
|
||||
wsgi_req->status = 404;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write(wsgi_req, "HTTP/1.0 404 Not Found\r\nContent-Type: text/plain\r\n\r\nNot Found", 61);
|
||||
}
|
||||
|
||||
void uwsgi_cgi_403(struct wsgi_request *wsgi_req) {
|
||||
|
||||
wsgi_req->status = 403;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write(wsgi_req, "HTTP/1.0 403 Forbidden\r\nContent-Type: text/plain\r\n\r\nForbidden", 61);
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_cgi_redirect_to_slash(struct wsgi_request *wsgi_req) {
|
||||
|
||||
struct iovec iov[6];
|
||||
|
||||
wsgi_req->status = 301;
|
||||
iov[0].iov_base = wsgi_req->protocol;
|
||||
iov[0].iov_len = wsgi_req->protocol_len;
|
||||
iov[1].iov_base = " 301 Moved Permanently\r\n";
|
||||
iov[1].iov_len = 24;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 2);
|
||||
|
||||
iov[0].iov_base = "Location: ";
|
||||
iov[0].iov_len = 10;
|
||||
iov[1].iov_base = wsgi_req->path_info;
|
||||
iov[1].iov_len = wsgi_req->path_info_len;
|
||||
iov[2].iov_base = "/";
|
||||
iov[2].iov_len = 1;
|
||||
|
||||
if (wsgi_req->query_string_len > 0) {
|
||||
iov[3].iov_base = "?";
|
||||
iov[3].iov_len = 1;
|
||||
iov[4].iov_base = wsgi_req->query_string;
|
||||
iov[4].iov_len = wsgi_req->query_string_len;
|
||||
iov[5].iov_base = "\r\n\r\n";
|
||||
iov[5].iov_len = 4;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 6);
|
||||
wsgi_req->header_cnt++;
|
||||
}
|
||||
else {
|
||||
iov[3].iov_base = "\r\n\r\n";
|
||||
iov[3].iov_len = 4;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 4);
|
||||
wsgi_req->header_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_cgi_apps() {
|
||||
|
||||
struct uwsgi_dyn_dict *udd = uc.mountpoint;
|
||||
@@ -186,6 +235,10 @@ int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
size_t header_size = 0;
|
||||
int status_sent = 0;
|
||||
|
||||
struct uwsgi_string_list *ah = uwsgi.additional_headers;
|
||||
|
||||
struct iovec iov[4];
|
||||
|
||||
for(i=0;i<len;i++) {
|
||||
// end of a line
|
||||
if (buf[i] == '\n') {
|
||||
@@ -214,7 +267,16 @@ int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
// "Status: NNN"
|
||||
if (header_size >= 11) {
|
||||
if (!strncasecmp("Status: ", key, 8)) {
|
||||
uwsgi_response_prepare_headers(wsgi_req, key+8, header_size - 8);
|
||||
wsgi_req->status = uwsgi_str3_num(key+8);
|
||||
iov[0].iov_base = wsgi_req->protocol;
|
||||
iov[0].iov_len = wsgi_req->protocol_len;
|
||||
iov[1].iov_base = " ";
|
||||
iov[1].iov_len = 1;
|
||||
iov[2].iov_base = key+8;
|
||||
iov[2].iov_len = header_size - 8;
|
||||
iov[3].iov_base = "\r\n";
|
||||
iov[3].iov_len = 2;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 4);
|
||||
status_sent = 1;
|
||||
key = NULL;
|
||||
value = NULL;
|
||||
@@ -229,18 +291,34 @@ int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
// Location: X
|
||||
if (header_size >= 11) {
|
||||
if (!strncasecmp("Location: ", key, 10)) {
|
||||
uwsgi_response_prepare_headers(wsgi_req, "302 Found", 9);
|
||||
|
||||
wsgi_req->status = 302;
|
||||
iov[0].iov_base = wsgi_req->protocol;
|
||||
iov[0].iov_len = wsgi_req->protocol_len;
|
||||
iov[1].iov_base = " 302 Found\r\n";
|
||||
iov[1].iov_len = 12;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 2);
|
||||
status_sent = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (status_sent == 0) {
|
||||
uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6);
|
||||
wsgi_req->status = 200;
|
||||
iov[0].iov_base = wsgi_req->protocol;
|
||||
iov[0].iov_len = wsgi_req->protocol_len;
|
||||
iov[1].iov_base = " 200 OK\r\n";
|
||||
iov[1].iov_len = 9;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 2);
|
||||
status_sent = 1;
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_response_add_header(wsgi_req, NULL, 0, key, header_size);
|
||||
iov[0].iov_base = key;
|
||||
iov[0].iov_len = header_size;
|
||||
iov[1].iov_base = "\r\n";
|
||||
iov[1].iov_len = 2;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 2);
|
||||
wsgi_req->header_cnt++;
|
||||
|
||||
key = NULL;
|
||||
value = NULL;
|
||||
@@ -259,8 +337,19 @@ int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
|
||||
send_body:
|
||||
|
||||
while(ah) {
|
||||
iov[0].iov_base = ah->value;
|
||||
iov[0].iov_len = ah->len;
|
||||
iov[1].iov_base = "\r\n";
|
||||
iov[1].iov_len = 2;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 2);
|
||||
wsgi_req->header_cnt++;
|
||||
ah = ah->next;
|
||||
}
|
||||
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, "\r\n", 2);
|
||||
if (len-i > 0) {
|
||||
uwsgi_response_write_body_do(wsgi_req, buf+i, len-i);
|
||||
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, buf+i, len-i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -343,7 +432,7 @@ int uwsgi_cgi_walk(struct wsgi_request *wsgi_req, char *full_path, char *docroot
|
||||
*(dst+part_size-1) = 0;
|
||||
|
||||
if (stat(full_path, &st)) {
|
||||
uwsgi_404(wsgi_req);
|
||||
uwsgi_cgi_404(wsgi_req);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -404,8 +493,8 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
|
||||
char *script_name = NULL;
|
||||
|
||||
/* Standard CGI request */
|
||||
if (!wsgi_req->uh->pktsize) {
|
||||
uwsgi_log("Empty CGI request. skip.\n");
|
||||
if (!wsgi_req->uh.pktsize) {
|
||||
uwsgi_log("Invalid CGI request. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -428,7 +517,7 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
|
||||
if (docroot == NULL || docroot_len == 0) {
|
||||
uwsgi_404(wsgi_req);
|
||||
uwsgi_cgi_404(wsgi_req);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
@@ -448,7 +537,7 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
|
||||
if (realpath(full_path, tmp_path) == NULL) {
|
||||
if (need_free)
|
||||
free(docroot);
|
||||
uwsgi_404(wsgi_req);
|
||||
uwsgi_cgi_404(wsgi_req);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
@@ -470,7 +559,7 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
|
||||
if (stat(full_path, &cgi_stat)) {
|
||||
uwsgi_404(wsgi_req);
|
||||
uwsgi_cgi_404(wsgi_req);
|
||||
if (need_free)
|
||||
free(docroot);
|
||||
return UWSGI_OK;
|
||||
@@ -480,7 +569,7 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
// add / to directories
|
||||
if (wsgi_req->path_info_len == 0 || (wsgi_req->path_info_len > 0 && wsgi_req->path_info[wsgi_req->path_info_len-1] != '/')) {
|
||||
uwsgi_redirect_to_slash(wsgi_req);
|
||||
uwsgi_cgi_redirect_to_slash(wsgi_req);
|
||||
if (need_free)
|
||||
free(docroot);
|
||||
return UWSGI_OK;
|
||||
@@ -503,7 +592,7 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
uwsgi_404(wsgi_req);
|
||||
uwsgi_cgi_404(wsgi_req);
|
||||
if (need_free)
|
||||
free(docroot);
|
||||
return UWSGI_OK;
|
||||
@@ -527,7 +616,7 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
|
||||
if (!cgi_allowed) {
|
||||
uwsgi_403(wsgi_req);
|
||||
uwsgi_cgi_403(wsgi_req);
|
||||
if (need_free)
|
||||
free(docroot);
|
||||
return UWSGI_OK;
|
||||
@@ -543,7 +632,7 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
|
||||
if (helper == NULL) {
|
||||
if (access(full_path, X_OK)) {
|
||||
uwsgi_error("access()");
|
||||
uwsgi_403(wsgi_req);
|
||||
uwsgi_cgi_403(wsgi_req);
|
||||
if (need_free)
|
||||
free(docroot);
|
||||
return UWSGI_OK;
|
||||
@@ -558,13 +647,17 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
if (pipe(post_pipe)) {
|
||||
if (need_free)
|
||||
free(docroot);
|
||||
close(cgi_pipe[0]);
|
||||
close(cgi_pipe[1]);
|
||||
uwsgi_error("pipe()");
|
||||
return UWSGI_OK;
|
||||
int send_post_data = 0;
|
||||
if (uwsgi.post_buffering > 0 && wsgi_req->post_cl && !wsgi_req->async_post) {
|
||||
send_post_data = 1;
|
||||
if (pipe(post_pipe)) {
|
||||
if (need_free)
|
||||
free(docroot);
|
||||
close(cgi_pipe[0]);
|
||||
close(cgi_pipe[1]);
|
||||
uwsgi_error("pipe()");
|
||||
return UWSGI_OK;
|
||||
}
|
||||
}
|
||||
|
||||
cgi_pid = fork();
|
||||
@@ -575,8 +668,10 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
|
||||
free(docroot);
|
||||
close(cgi_pipe[0]);
|
||||
close(cgi_pipe[1]);
|
||||
close(post_pipe[0]);
|
||||
close(post_pipe[1]);
|
||||
if (send_post_data) {
|
||||
close(post_pipe[0]);
|
||||
close(post_pipe[1]);
|
||||
}
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
@@ -586,34 +681,23 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
|
||||
free(docroot);
|
||||
|
||||
close(cgi_pipe[1]);
|
||||
close(post_pipe[0]);
|
||||
|
||||
// ok start sending post data...
|
||||
size_t remains = wsgi_req->post_cl;
|
||||
while(remains > 0) {
|
||||
ssize_t rlen = 0;
|
||||
char *buf = uwsgi_request_body_read(wsgi_req, 8192, &rlen);
|
||||
if (!buf) {
|
||||
if (send_post_data) {
|
||||
close(post_pipe[0]);
|
||||
if (write(post_pipe[1], wsgi_req->post_buffering_buf, wsgi_req->post_cl) != (ssize_t) wsgi_req->post_cl) {
|
||||
uwsgi_error("write()");
|
||||
close(post_pipe[1]);
|
||||
goto clear2;
|
||||
}
|
||||
if (buf == uwsgi.empty) break;
|
||||
// write data to the node
|
||||
if (uwsgi_write_true_nb(post_pipe[1], buf, rlen, uc.timeout)) {
|
||||
close(post_pipe[1]);
|
||||
goto clear2;
|
||||
}
|
||||
remains -= rlen;
|
||||
}
|
||||
|
||||
close(post_pipe[1]);
|
||||
goto clear2;
|
||||
}
|
||||
close(post_pipe[1]);
|
||||
}
|
||||
// wait for data
|
||||
char *headers_buf = uwsgi_malloc(uc.buffer_size);
|
||||
char *ptr = headers_buf;
|
||||
remains = uc.buffer_size;
|
||||
size_t remains = uc.buffer_size;
|
||||
int completed = 0;
|
||||
while(remains > 0) {
|
||||
int ret = uwsgi.wait_read_hook(cgi_pipe[0], uc.timeout);
|
||||
int ret = uwsgi_waitfd(cgi_pipe[0], uc.timeout);
|
||||
if (ret > 0) {
|
||||
len = read(cgi_pipe[0], ptr, remains);
|
||||
if (len > 0) {
|
||||
@@ -643,11 +727,11 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
|
||||
while (!completed) {
|
||||
int ret = uwsgi.wait_read_hook(cgi_pipe[0], uc.timeout);
|
||||
int ret = uwsgi_waitfd(cgi_pipe[0], uc.timeout);
|
||||
if (ret > 0) {
|
||||
len = read(cgi_pipe[0], headers_buf, uc.buffer_size);
|
||||
if (len > 0) {
|
||||
uwsgi_response_write_body_do(wsgi_req, headers_buf, len);
|
||||
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, headers_buf, len);
|
||||
}
|
||||
// end of output
|
||||
else if (len == 0) {
|
||||
@@ -670,7 +754,6 @@ clear:
|
||||
free(headers_buf);
|
||||
clear2:
|
||||
close(cgi_pipe[0]);
|
||||
close(post_pipe[1]);
|
||||
|
||||
// now wait for process exit/death
|
||||
if (waitpid(cgi_pid, &waitpid_status, 0) < 0) {
|
||||
@@ -683,23 +766,37 @@ clear2:
|
||||
// close all the fd except wsgi_req->poll.fd and 2;
|
||||
|
||||
for(i=0;i< (int)uwsgi.max_fd;i++) {
|
||||
if (post_pipe[0] == i) {
|
||||
continue;
|
||||
}
|
||||
if (wsgi_req->post_file) {
|
||||
if (fileno(wsgi_req->post_file) == i) {
|
||||
if (send_post_data) {
|
||||
if (post_pipe[0] == i) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (i != wsgi_req->fd && i != 2 && i != cgi_pipe[1]) {
|
||||
if (wsgi_req->async_post) {
|
||||
if (fileno((FILE*)wsgi_req->async_post) == i) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (i != wsgi_req->poll.fd && i != 2 && i != cgi_pipe[1]) {
|
||||
close(i);
|
||||
}
|
||||
}
|
||||
|
||||
// now map wsgi_req->poll.fd (or async_post) to 0 & cgi_pipe[1] to 1
|
||||
if (post_pipe[0] != 0) {
|
||||
dup2(post_pipe[0], 0);
|
||||
close(post_pipe[0]);
|
||||
if (send_post_data) {
|
||||
if (post_pipe[0] != 0) {
|
||||
dup2(post_pipe[0], 0);
|
||||
close(post_pipe[0]);
|
||||
}
|
||||
}
|
||||
else if (wsgi_req->async_post) {
|
||||
if (fileno((FILE*)wsgi_req->async_post) != 0) {
|
||||
dup2(fileno((FILE*)wsgi_req->async_post), 0);
|
||||
fclose(wsgi_req->async_post);
|
||||
}
|
||||
}
|
||||
else if (wsgi_req->poll.fd != 0) {
|
||||
dup2(wsgi_req->poll.fd, 0);
|
||||
close(wsgi_req->poll.fd);
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <uwsgi.h>
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
/*
|
||||
|
||||
@@ -13,7 +13,6 @@ struct uwsgi_cheaper_busyness_global {
|
||||
uint64_t busyness_max;
|
||||
uint64_t busyness_min;
|
||||
uint64_t *last_values;
|
||||
int *was_busy;
|
||||
uint64_t tcheck;
|
||||
uint64_t last_cheaped; // last time worker was cheaped due to low busyness
|
||||
uint64_t next_cheap; // timestamp, we can cheap worker after it
|
||||
@@ -28,9 +27,6 @@ struct uwsgi_cheaper_busyness_global {
|
||||
int backlog_alert;
|
||||
int backlog_step;
|
||||
uint64_t backlog_multi; // multiplier used to cheap emergency workers
|
||||
uint64_t backlog_nonzero_alert;
|
||||
int backlog_is_nonzero;
|
||||
uint64_t backlog_nonzero_since; // since when backlog is > 0
|
||||
#endif
|
||||
} uwsgi_cheaper_busyness_global;
|
||||
|
||||
@@ -57,7 +53,7 @@ struct uwsgi_option uwsgi_cheaper_busyness_options[] = {
|
||||
|
||||
#ifdef __linux__
|
||||
{"cheaper-busyness-backlog-alert", required_argument, 0,
|
||||
"spawn emergency worker(s) if anytime listen queue is higher than this value (default 33)",
|
||||
"spawn emergency worker if anytime listen queue is higher than this value (default 33)",
|
||||
uwsgi_opt_set_int, &uwsgi_cheaper_busyness_global.backlog_alert, 0},
|
||||
{"cheaper-busyness-backlog-multiplier", required_argument, 0,
|
||||
"set cheaper multiplier used for emergency workers (default 3)",
|
||||
@@ -65,9 +61,6 @@ struct uwsgi_option uwsgi_cheaper_busyness_options[] = {
|
||||
{"cheaper-busyness-backlog-step", required_argument, 0,
|
||||
"number of emergency workers to spawn at a time (default 1)",
|
||||
uwsgi_opt_set_int, &uwsgi_cheaper_busyness_global.backlog_step, 0},
|
||||
{"cheaper-busyness-backlog-nonzero", required_argument, 0,
|
||||
"spawn emergency worker(s) if backlog is > 0 for more then N seconds (default 60)",
|
||||
uwsgi_opt_set_64bit, &uwsgi_cheaper_busyness_global.backlog_nonzero_alert, 0},
|
||||
#endif
|
||||
|
||||
{0, 0, 0, 0, 0, 0 ,0},
|
||||
@@ -125,17 +118,12 @@ int spawn_emergency_worker(int backlog) {
|
||||
}
|
||||
}
|
||||
|
||||
// reset cheap timer, so that we need to start counting idle cycles from zero
|
||||
uwsgi_cheaper_busyness_global.emergency_workers += decheaped;
|
||||
|
||||
set_next_cheap_time();
|
||||
|
||||
if (decheaped > 0) {
|
||||
uwsgi_cheaper_busyness_global.emergency_workers += decheaped;
|
||||
uwsgi_log("[busyness] %d requests in listen queue, spawning %d emergency worker(s) (%d)!\n",
|
||||
backlog, decheaped, uwsgi_cheaper_busyness_global.emergency_workers);
|
||||
} else {
|
||||
uwsgi_log("[busyness] %d requests in listen queue but we are already started maximum number of workers (%d)\n",
|
||||
backlog, uwsgi.numproc);
|
||||
}
|
||||
uwsgi_log("[busyness] %d requests in listen queue, spawning %d emergency worker(s) (%d)!\n",
|
||||
backlog, decheaped, uwsgi_cheaper_busyness_global.emergency_workers);
|
||||
|
||||
return decheaped;
|
||||
}
|
||||
@@ -152,9 +140,6 @@ int cheaper_busyness_algo(void) {
|
||||
if (!uwsgi_cheaper_busyness_global.last_values) {
|
||||
uwsgi_cheaper_busyness_global.last_values = uwsgi_calloc(sizeof(uint64_t) * uwsgi.numproc);
|
||||
}
|
||||
if (!uwsgi_cheaper_busyness_global.was_busy) {
|
||||
uwsgi_cheaper_busyness_global.was_busy = uwsgi_calloc(sizeof(int) * uwsgi.numproc);
|
||||
}
|
||||
|
||||
// set defaults
|
||||
if (!uwsgi_cheaper_busyness_global.busyness_max) uwsgi_cheaper_busyness_global.busyness_max = 50;
|
||||
@@ -166,7 +151,6 @@ int cheaper_busyness_algo(void) {
|
||||
if (!uwsgi_cheaper_busyness_global.backlog_alert) uwsgi_cheaper_busyness_global.backlog_alert = 33;
|
||||
if (!uwsgi_cheaper_busyness_global.backlog_multi) uwsgi_cheaper_busyness_global.backlog_multi = 3;
|
||||
if (!uwsgi_cheaper_busyness_global.backlog_step) uwsgi_cheaper_busyness_global.backlog_step = 1;
|
||||
if (!uwsgi_cheaper_busyness_global.backlog_nonzero_alert) uwsgi_cheaper_busyness_global.backlog_nonzero_alert = 60;
|
||||
#endif
|
||||
|
||||
if (!uwsgi_cheaper_busyness_global.min_multi) {
|
||||
@@ -179,7 +163,6 @@ int cheaper_busyness_algo(void) {
|
||||
#ifdef __linux__
|
||||
uwsgi_log("[busyness] backlog alert is set to %d request(s), step is %d\n",
|
||||
uwsgi_cheaper_busyness_global.backlog_alert, uwsgi_cheaper_busyness_global.backlog_step);
|
||||
uwsgi_log("[busyness] backlog non-zero alert is set to %llu second(s)\n", uwsgi_cheaper_busyness_global.backlog_nonzero_alert);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -193,11 +176,9 @@ int cheaper_busyness_algo(void) {
|
||||
uint64_t avg_busyness = 0;
|
||||
|
||||
for (i = 0; i < uwsgi.numproc; i++) {
|
||||
|
||||
if (uwsgi.workers[i+1].cheaped == 0 && uwsgi.workers[i+1].pid > 0) {
|
||||
active_workers++;
|
||||
uwsgi_cheaper_busyness_global.was_busy[i] += uwsgi_worker_is_busy(i+1);
|
||||
} else {
|
||||
uwsgi_cheaper_busyness_global.was_busy[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,19 +192,7 @@ int cheaper_busyness_algo(void) {
|
||||
for (i = 0; i < uwsgi.numproc; i++) {
|
||||
if (uwsgi.workers[i+1].cheaped == 0 && uwsgi.workers[i+1].pid > 0) {
|
||||
uint64_t percent = (( (uwsgi.workers[i+1].running_time-uwsgi_cheaper_busyness_global.last_values[i])*100)/t);
|
||||
if (percent > 100) {
|
||||
percent = 100;
|
||||
}
|
||||
else if (uwsgi.workers[i+1].running_time-uwsgi_cheaper_busyness_global.last_values[i] == 0 && percent == 0 && uwsgi_cheaper_busyness_global.was_busy[i] > 0) {
|
||||
// running_time did not change but workers were busy
|
||||
// this means that workers had response times > busyness check interval
|
||||
if (uwsgi_cheaper_busyness_global.verbose) {
|
||||
uwsgi_log("[busyness] worker %d was busy %d time(s) in last cycle but no request was completed during this time, marking as 100%% busy\n",
|
||||
i+1, uwsgi_cheaper_busyness_global.was_busy[i]);
|
||||
}
|
||||
percent = 100;
|
||||
}
|
||||
uwsgi_cheaper_busyness_global.was_busy[i] = 0;
|
||||
if (percent > 100) percent = 100;
|
||||
total_busyness += percent;
|
||||
if (uwsgi_cheaper_busyness_global.verbose && active_workers > 1)
|
||||
uwsgi_log("[busyness] worker nr %d %llus average busyness is at %llu%%\n",
|
||||
@@ -344,36 +313,13 @@ int cheaper_busyness_algo(void) {
|
||||
uwsgi_cheaper_busyness_global.next_cheap += uwsgi.cheaper_overload*1000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
else if (backlog > uwsgi_cheaper_busyness_global.backlog_alert && active_workers < uwsgi.numproc) {
|
||||
} else if (backlog > uwsgi_cheaper_busyness_global.backlog_alert && active_workers < uwsgi.numproc) {
|
||||
// we check for backlog overload every cycle
|
||||
return spawn_emergency_worker(backlog);
|
||||
}
|
||||
else if (backlog > 0) {
|
||||
if (uwsgi_cheaper_busyness_global.backlog_is_nonzero) {
|
||||
// backlog was > 0 last time, check timestamp and spawn workers if needed
|
||||
if ((now - uwsgi_cheaper_busyness_global.backlog_nonzero_since)/1000000 >= uwsgi_cheaper_busyness_global.backlog_nonzero_alert) {
|
||||
uwsgi_log("[busyness] backlog was non-zero for %llu second(s), spawning new worker(s)\n", (now - uwsgi_cheaper_busyness_global.backlog_nonzero_since)/1000000);
|
||||
uwsgi_cheaper_busyness_global.backlog_nonzero_since = now;
|
||||
return spawn_emergency_worker(backlog);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// this is first > 0 pass, setup timer
|
||||
if (uwsgi_cheaper_busyness_global.verbose)
|
||||
uwsgi_log("[busyness] backlog is starting to fill (%d)\n", backlog);
|
||||
uwsgi_cheaper_busyness_global.backlog_is_nonzero = 1;
|
||||
uwsgi_cheaper_busyness_global.backlog_nonzero_since = now;
|
||||
}
|
||||
}
|
||||
else if (uwsgi_cheaper_busyness_global.backlog_is_nonzero) {
|
||||
if (uwsgi_cheaper_busyness_global.verbose)
|
||||
uwsgi_log("[busyness] backlog is now empty\n");
|
||||
uwsgi_cheaper_busyness_global.backlog_is_nonzero = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+392
-395
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user