mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-10-04 16:08:31 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df0f2a549e | ||
|
|
9b7cbab37c | ||
|
|
ac46cb2371 | ||
|
|
c858c88bb3 | ||
|
|
a05f5d9860 | ||
|
|
e6914b91e1 | ||
|
|
b624bd2d35 | ||
|
|
e3c9b2c0bf | ||
|
|
576a1e7cb2 | ||
|
|
55c3ba73d3 | ||
|
|
2246d30bbe | ||
|
|
789e333736 | ||
|
|
283904107f | ||
|
|
8d92261852 | ||
|
|
e8f5d82b78 | ||
|
|
0a8643155e | ||
|
|
61793201c7 | ||
|
|
41f2982074 | ||
|
|
27b86f1b79 | ||
|
|
d69892c91e | ||
|
|
296549d1bf | ||
|
|
7d2f147172 | ||
|
|
aa56f99ee2 | ||
|
|
ca82b99f42 | ||
|
|
d204a5b844 | ||
|
|
0a98550770 | ||
|
|
0c0c2736a7 | ||
|
|
27e2d984ce | ||
|
|
14eeae09b1 | ||
|
|
16eb47070d | ||
|
|
1f69f58593 | ||
|
|
1b4421e013 | ||
|
|
f13400d592 | ||
|
|
e29f0323ea | ||
|
|
15a582d046 | ||
|
|
1e01f8be17 | ||
|
|
8cc73991a3 | ||
|
|
ecce74ade5 | ||
|
|
836efaaf70 | ||
|
|
46f8e7dc00 | ||
|
|
88cd033ca6 | ||
|
|
984df3bcdf | ||
|
|
7673cdb1aa | ||
|
|
8af700ce37 | ||
|
|
ffb8752190 | ||
|
|
71fa3ab3af | ||
|
|
09501cfa74 | ||
|
|
d84ae12733 | ||
|
|
05f292abe6 | ||
|
|
a75833d322 | ||
|
|
ca3f56de5c | ||
|
|
9d75f2c9c7 | ||
|
|
a58cbf92b0 | ||
|
|
7bac76fae5 | ||
|
|
9c71b39edd | ||
|
|
52f731c6b7 | ||
|
|
735d1cb689 | ||
|
|
5a0977f412 | ||
|
|
1da1fccbc7 | ||
|
|
ca5a528818 | ||
|
|
a9ef806a37 | ||
|
|
de112b7788 | ||
|
|
ef7baba274 | ||
|
|
3a9d13b011 | ||
|
|
5b5493aab0 | ||
|
|
5f208d8f12 | ||
|
|
47c077d066 | ||
|
|
d2ac69b6c1 | ||
|
|
8860cac7dd | ||
|
|
28bcc73c70 | ||
|
|
af20c2d8f0 | ||
|
|
44213ca510 | ||
|
|
ab21a1ac00 | ||
|
|
a67f366501 | ||
|
|
b32251e5aa | ||
|
|
16e0accb74 | ||
|
|
c6ce291cbf | ||
|
|
b7525475d8 | ||
|
|
f35a36ac02 | ||
|
|
3b53f89a24 | ||
|
|
764d94e41b | ||
|
|
0292e15497 | ||
|
|
bde4ac7b2f | ||
|
|
c71fa3abd1 | ||
|
|
d2abdb5d3a | ||
|
|
1392791837 | ||
|
|
6f7d9634d5 | ||
|
|
82b95114a8 | ||
|
|
d90e701acd | ||
|
|
42993022bb | ||
|
|
29b1e46252 | ||
|
|
260cea639f | ||
|
|
208aea8aca | ||
|
|
f164d401d3 | ||
|
|
5e1c34a08b | ||
|
|
9c7b596a0d | ||
|
|
5ff34ac6d0 | ||
|
|
e304e34929 | ||
|
|
6d7848248d | ||
|
|
dbc0da0586 | ||
|
|
fecdcf9d10 | ||
|
|
bfd0ab2301 | ||
|
|
8002777e75 | ||
|
|
d57d5acb30 | ||
|
|
43e6664dd9 | ||
|
|
d0c6dff83e | ||
|
|
54b40f5978 | ||
|
|
1c59c03261 | ||
|
|
ce23fd38ab | ||
|
|
4818efa7de | ||
|
|
ea19e74229 | ||
|
|
fe353de5a8 | ||
|
|
1d89266f2e | ||
|
|
61d79394ca | ||
|
|
491f2828b5 | ||
|
|
431e05d4f4 | ||
|
|
ae6780a487 | ||
|
|
5707a70141 | ||
|
|
e9a7bd7da1 | ||
|
|
91e45daf6c | ||
|
|
9f69998075 | ||
|
|
4f6270976b | ||
|
|
328caa43f2 | ||
|
|
368408374a | ||
|
|
c3a90db493 | ||
|
|
5bc0320877 | ||
|
|
622ed620b9 | ||
|
|
1b859413de | ||
|
|
95432fd8e3 | ||
|
|
b3f3c5d7b3 | ||
|
|
02cef20462 | ||
|
|
3edebe34ae | ||
|
|
28c9b75fb5 | ||
|
|
a2735e10b7 | ||
|
|
e03d26fd63 | ||
|
|
7c4c346e64 | ||
|
|
67b3c0c4a8 | ||
|
|
dadca785e4 | ||
|
|
accebe5597 | ||
|
|
792965bedd | ||
|
|
1bb1bafe0c | ||
|
|
28c11324ca | ||
|
|
42d940c38e | ||
|
|
c1ea05b925 | ||
|
|
9435693865 | ||
|
|
14da582637 | ||
|
|
b2d4a795a1 | ||
|
|
493696705b | ||
|
|
d827c6f09a | ||
|
|
df000b0cb2 | ||
|
|
d9630a32c7 | ||
|
|
71cc6f61bd | ||
|
|
46eb832cc7 | ||
|
|
11b2e4b430 | ||
|
|
11775532ee | ||
|
|
f3388db8ba | ||
|
|
25ac86393f | ||
|
|
b3432a95e1 | ||
|
|
e34d169fa6 | ||
|
|
de84accb7a | ||
|
|
187577cbb5 | ||
|
|
72109b72d2 | ||
|
|
f6c01d11e9 | ||
|
|
d695ef4f57 | ||
|
|
16c6dcc573 | ||
|
|
3df19b286a | ||
|
|
6f1b08762d | ||
|
|
a4a379f9d6 | ||
|
|
3d3d0304bc | ||
|
|
26135018a3 | ||
|
|
4bd381bb99 | ||
|
|
cf08972e82 | ||
|
|
d57a58d1e7 | ||
|
|
f10789965e | ||
|
|
94145bd300 | ||
|
|
cdcb61d10d | ||
|
|
56146a34af | ||
|
|
991e818449 | ||
|
|
80083cba76 | ||
|
|
2c44fd5aa2 | ||
|
|
1561dd38fc | ||
|
|
8152648f66 | ||
|
|
c1507d0381 | ||
|
|
f0fb603af2 | ||
|
|
93e891153f | ||
|
|
26ece717b6 | ||
|
|
93767335ca | ||
|
|
7cbe751a39 | ||
|
|
c45df83f19 | ||
|
|
fabce61a58 | ||
|
|
5c9ccae598 | ||
|
|
6c9d7239f2 | ||
|
|
4b75e2577e | ||
|
|
08c9d942a4 | ||
|
|
3b59b4ad21 | ||
|
|
7682eec52a | ||
|
|
694517bbe7 | ||
|
|
7f443fdd05 | ||
|
|
01ab891c11 | ||
|
|
052aacfd36 | ||
|
|
80a6d2ccfb | ||
|
|
b4ce175bdf | ||
|
|
f6f52d32dc | ||
|
|
865b2de9bb | ||
|
|
4a8233a041 | ||
|
|
f856ad78a3 | ||
|
|
653267cbe6 | ||
|
|
8b53df27ab | ||
|
|
c4b7c2b58c | ||
|
|
66f82f364c | ||
|
|
6d269607d2 | ||
|
|
8370977e5b | ||
|
|
e2c335ff73 | ||
|
|
816b9d0343 | ||
|
|
2922e1ba35 | ||
|
|
c86f341d29 | ||
|
|
73cdd68283 | ||
|
|
81641686bc | ||
|
|
14c58c8e62 | ||
|
|
74b8f2587c | ||
|
|
bebe041061 | ||
|
|
2e5d3d2952 | ||
|
|
c2d155b8ff | ||
|
|
fda368ff08 | ||
|
|
19cf592e77 | ||
|
|
260cac6b59 | ||
|
|
673275e708 | ||
|
|
a6bc778c25 | ||
|
|
ef2f5879b6 | ||
|
|
ee725bf625 | ||
|
|
5388fa442c | ||
|
|
913493fd2e | ||
|
|
6d4a8c6619 | ||
|
|
4a57115336 | ||
|
|
1dd754a0d5 | ||
|
|
509b78d906 | ||
|
|
363366d012 | ||
|
|
26d4fd4e00 | ||
|
|
09ee97e775 | ||
|
|
1400a95cec | ||
|
|
5e96c4ca79 | ||
|
|
3c068b2a00 | ||
|
|
81fd7757c1 | ||
|
|
1db64b72ae | ||
|
|
ab1bed236c | ||
|
|
e503999392 | ||
|
|
2392eb7e0b | ||
|
|
c62b54f18d | ||
|
|
603d46c1ae | ||
|
|
c0e0ae551d | ||
|
|
a0a2507c05 | ||
|
|
6eed48b28d | ||
|
|
9c5d289098 | ||
|
|
42ab7f23d8 | ||
|
|
c9c2f4232e | ||
|
|
d4f23cc6bd | ||
|
|
b0db67d4d4 | ||
|
|
703cad6715 | ||
|
|
667d67460f | ||
|
|
35cf9ae328 | ||
|
|
c04131af4b | ||
|
|
9cc4db1a12 | ||
|
|
b326500913 | ||
|
|
a26579fcf5 | ||
|
|
a2b9c44433 | ||
|
|
c3b97da1d4 | ||
|
|
048cf0232a | ||
|
|
89c113bee6 | ||
|
|
6b9969a302 | ||
|
|
a6e7513d2a | ||
|
|
8a04f4810f | ||
|
|
1d9d443de0 | ||
|
|
00e5809a71 | ||
|
|
07ba4a040b | ||
|
|
7b319d230a | ||
|
|
641bc2daec | ||
|
|
fbaa30cc08 | ||
|
|
a0c2c9056b | ||
|
|
30ab5fd76b | ||
|
|
30beab4017 | ||
|
|
4ec1493b09 | ||
|
|
e7cbe9709e | ||
|
|
aacaeba525 | ||
|
|
6e4da5efb7 | ||
|
|
87443a4ff2 | ||
|
|
9746759c68 | ||
|
|
170ee2b98a | ||
|
|
938fb777dd | ||
|
|
33e1aafcd1 | ||
|
|
597ee90041 | ||
|
|
e87e54ea28 | ||
|
|
5c64c1ac3f | ||
|
|
c611cbc2ca | ||
|
|
9d051f4171 | ||
|
|
6aee788678 | ||
|
|
425a45caa7 | ||
|
|
0571601e02 | ||
|
|
c1992c8c7a | ||
|
|
bd913870c7 | ||
|
|
7a479dd47f | ||
|
|
7ae77aa58d | ||
|
|
97a4260d44 | ||
|
|
b90d711764 | ||
|
|
22de5b523e | ||
|
|
5798b824c0 | ||
|
|
4cbf6cfc33 | ||
|
|
8b55460156 | ||
|
|
a61d48a451 | ||
|
|
b9f4d57d67 | ||
|
|
92cd36d14d |
@@ -13,3 +13,15 @@ ef31fc61ac48018c464f28ebfdf865b96bf83f18 0.9.6.2
|
||||
ff4111eb8f55b958ec91c70163e10f3372a9b94d 0.9.7-rc1
|
||||
eb8aff2926230bb114fb90f67203440a2c534bf1 0.9.7-rc2
|
||||
311eef929ec8fd0a5dc8c16531afb7bb42d36d01 0.9.7-rc3
|
||||
4b50c04e414f1d9ab8b0b5910aba83d09ac21abb 0.9.7
|
||||
d9b9b540f7dce8cb05d2e61ca8b4d75f2ea25f62 0.9.7.1
|
||||
d9b9b540f7dce8cb05d2e61ca8b4d75f2ea25f62 0.9.7.1
|
||||
0000000000000000000000000000000000000000 0.9.7.1
|
||||
0000000000000000000000000000000000000000 0.9.7.1
|
||||
486e7760bcbc2191ddb9b4aee6c98dbd5fc4c754 0.9.7.1
|
||||
a5f13497b39269621f8f1e56e14d2cc141452e79 0.9.7.2
|
||||
d1e57707f6317f134fea7d12f6588d8690f74f3f 0.9.8-rc1
|
||||
e91bc724325e14c13b8f548c0b6a315c48a1c32a 0.9.8-rc2
|
||||
4fb424d52f226a0a087fea89709f5eb540e03f25 0.9.8-rc3
|
||||
0f1f3924ee5309a9990d9af1ffc68846e3dfb31b 0.9.8-rc4
|
||||
42efe1f329005618c8b44f901979ebcecd5216fb 0.9.8
|
||||
|
||||
@@ -1,5 +1,175 @@
|
||||
*** 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>)
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
all:
|
||||
python uwsgiconfig.py --build
|
||||
|
||||
clean:
|
||||
python uwsgiconfig.py --clean
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct wsgi_request *find_wsgi_req_proto_by_fd(int fd) {
|
||||
return uwsgi.async_proto_fd_table[fd];
|
||||
}
|
||||
|
||||
struct wsgi_request *find_wsgi_req_by_fd(int fd) {
|
||||
return uwsgi.async_waiting_fd_table[fd];
|
||||
}
|
||||
@@ -195,10 +199,15 @@ void *async_loop(void *arg1) {
|
||||
int interesting_fd, i;
|
||||
struct uwsgi_rb_timer *min_timeout;
|
||||
int timeout;
|
||||
int is_a_new_connection;
|
||||
int proto_parser_status;
|
||||
|
||||
time_t now, last_now = 0;
|
||||
|
||||
static struct uwsgi_async_request *current_request = NULL, *next_async_request = NULL;
|
||||
|
||||
void *events = event_queue_alloc(64);
|
||||
struct uwsgi_socket *uwsgi_sock;
|
||||
|
||||
uwsgi.async_runqueue = NULL;
|
||||
uwsgi.async_runqueue_cnt = 0;
|
||||
@@ -235,49 +244,105 @@ void *async_loop(void *arg1) {
|
||||
async_expire_timeouts();
|
||||
}
|
||||
|
||||
|
||||
for(i=0;i<uwsgi.async_nevents;i++) {
|
||||
// manage events
|
||||
interesting_fd = event_queue_interesting_fd(events, i);
|
||||
|
||||
// new request coming in
|
||||
if (interesting_fd == uwsgi.sockets[0].fd) {
|
||||
uwsgi.wsgi_req = find_first_available_wsgi_req();
|
||||
if (uwsgi.wsgi_req == NULL) {
|
||||
uwsgi_log("async queue is full !!!\n");
|
||||
continue;
|
||||
}
|
||||
is_a_new_connection = 0;
|
||||
|
||||
wsgi_req_setup(uwsgi.wsgi_req, uwsgi.wsgi_req->async_id );
|
||||
if (wsgi_req_simple_accept(uwsgi.wsgi_req, interesting_fd)) {
|
||||
// new request coming in ?
|
||||
|
||||
uwsgi_sock = uwsgi.sockets;
|
||||
while(uwsgi_sock) {
|
||||
|
||||
if (interesting_fd == uwsgi_sock->fd) {
|
||||
|
||||
is_a_new_connection = 1;
|
||||
|
||||
uwsgi.wsgi_req = find_first_available_wsgi_req();
|
||||
if (uwsgi.wsgi_req == NULL) {
|
||||
now = time(NULL);
|
||||
if (now > last_now) {
|
||||
uwsgi_log("async queue is full !!!\n");
|
||||
last_now = now;
|
||||
}
|
||||
break;;
|
||||
}
|
||||
|
||||
wsgi_req_setup(uwsgi.wsgi_req, uwsgi.wsgi_req->async_id, uwsgi_sock );
|
||||
if (wsgi_req_simple_accept(uwsgi.wsgi_req, interesting_fd)) {
|
||||
#ifdef UWSGI_EVENT_USE_PORT
|
||||
event_queue_add_fd_read(uwsgi.async_queue, interesting_fd);
|
||||
#endif
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
|
||||
break;
|
||||
}
|
||||
#ifdef UWSGI_EVENT_USE_PORT
|
||||
event_queue_add_fd_read(uwsgi.async_queue, interesting_fd);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
#ifdef UWSGI_EVENT_USE_PORT
|
||||
event_queue_add_fd_read(uwsgi.async_queue, interesting_fd);
|
||||
#endif
|
||||
|
||||
// on linux we do not need to reset the socket to blocking state
|
||||
#ifndef __linux__
|
||||
if (uwsgi.numproc > 1) {
|
||||
/* re-set blocking socket */
|
||||
if (fcntl(uwsgi.wsgi_req->poll.fd, F_SETFL, uwsgi.sockets[0].arg) < 0) {
|
||||
uwsgi_error("fcntl()");
|
||||
continue;
|
||||
if (uwsgi.numproc > 1) {
|
||||
/* re-set blocking socket */
|
||||
if (fcntl(uwsgi.wsgi_req->poll.fd, F_SETFL, uwsgi_sock->arg) < 0) {
|
||||
uwsgi_error("fcntl()");
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wsgi_req_async_recv(uwsgi.wsgi_req)) {
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
|
||||
break;
|
||||
}
|
||||
|
||||
if (wsgi_req_simple_recv(uwsgi.wsgi_req)) {
|
||||
if (uwsgi.wsgi_req->do_not_add_to_async_queue) {
|
||||
runqueue_push(uwsgi.wsgi_req);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
if (!is_a_new_connection) {
|
||||
// proto event
|
||||
uwsgi.wsgi_req = find_wsgi_req_proto_by_fd(interesting_fd);
|
||||
if (uwsgi.wsgi_req) {
|
||||
proto_parser_status = uwsgi.wsgi_req->socket->proto(uwsgi.wsgi_req);
|
||||
// reset timeout
|
||||
rb_erase(&uwsgi.wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts);
|
||||
free(uwsgi.wsgi_req->async_timeout);
|
||||
uwsgi.wsgi_req->async_timeout = NULL;
|
||||
// parsing complete
|
||||
if (!proto_parser_status) {
|
||||
// remove fd from event poll and fd proto table
|
||||
#ifndef UWSGI_EVENT_USE_PORT
|
||||
event_queue_del_fd(uwsgi.async_queue, interesting_fd, event_queue_read());
|
||||
#endif
|
||||
uwsgi.async_proto_fd_table[interesting_fd] = NULL;
|
||||
// put request in the runqueue
|
||||
runqueue_push(uwsgi.wsgi_req);
|
||||
continue;
|
||||
}
|
||||
else if (proto_parser_status == -1) {
|
||||
uwsgi_log("error parsing request\n");
|
||||
uwsgi.async_proto_fd_table[interesting_fd] = NULL;
|
||||
close(interesting_fd);
|
||||
continue;
|
||||
}
|
||||
// re-add timer
|
||||
async_add_timeout(uwsgi.wsgi_req, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// put request in the runqueue
|
||||
runqueue_push(uwsgi.wsgi_req);
|
||||
}
|
||||
else {
|
||||
// app event
|
||||
uwsgi.wsgi_req = find_wsgi_req_by_fd(interesting_fd);
|
||||
// unknown fd, remove it (for safety)
|
||||
@@ -320,10 +385,11 @@ void *async_loop(void *arg1) {
|
||||
uwsgi.wsgi_req = current_request->wsgi_req;
|
||||
|
||||
uwsgi.schedule_to_req();
|
||||
uwsgi.wsgi_req->switches++;
|
||||
|
||||
next_async_request = current_request->next;
|
||||
// request ended ?
|
||||
if (uwsgi.wsgi_req->async_status == UWSGI_OK) {
|
||||
if (uwsgi.wsgi_req->async_status <= UWSGI_OK) {
|
||||
// remove all the monitored fds and timeout
|
||||
while(uwsgi.wsgi_req->waiting_fds) {
|
||||
#ifndef UWSGI_EVENT_USE_PORT
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
xml = true
|
||||
ini = true
|
||||
yaml = true
|
||||
json = auto
|
||||
sqlite3 = auto
|
||||
zeromq = auto
|
||||
snmp = true
|
||||
sctp = false
|
||||
spooler = true
|
||||
@@ -18,10 +21,13 @@ pcre = auto
|
||||
debug = false
|
||||
unbit = false
|
||||
xml_implementation = libxml2
|
||||
yaml_implementation = auto
|
||||
malloc_implementation = libc
|
||||
plugins =
|
||||
bin_name = uwsgi
|
||||
append_version =
|
||||
plugin_dir = .
|
||||
embedded_plugins = python, ping, nagios, rpc, fastrouter, http, ugreen
|
||||
embedded_plugins = python, ping, cache, nagios, rpc, fastrouter, http, ugreen
|
||||
|
||||
locking = auto
|
||||
event = auto
|
||||
|
||||
+4
-32
@@ -1,33 +1,5 @@
|
||||
[uwsgi]
|
||||
xml = true
|
||||
ini = true
|
||||
snmp = true
|
||||
sctp = false
|
||||
erlang = false
|
||||
spooler = false
|
||||
embedded = false
|
||||
udp = true
|
||||
multicast = false
|
||||
threading = true
|
||||
sendfile = true
|
||||
nagios = true
|
||||
proxy = true
|
||||
minterpreters = true
|
||||
async = true
|
||||
ugreen = false
|
||||
http = true
|
||||
evdis = false
|
||||
ldap = true
|
||||
routing = false
|
||||
stackless = false
|
||||
debug = false
|
||||
unbit = false
|
||||
xml_implementation = libxml2
|
||||
plugins = python, ping, rack
|
||||
bin_name = uwsgi
|
||||
plugin_dir = .
|
||||
embedded_plugins =
|
||||
|
||||
[python]
|
||||
paste = true
|
||||
web3 = true
|
||||
inherit = default
|
||||
plugins = python, ping, rack, psgi, cache, http, fastrouter
|
||||
plugin_dir = plugins
|
||||
embedded_plugins = null
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
plugin_dir = /usr/lib/uwsgi
|
||||
embedded_plugins = null
|
||||
@@ -1,4 +1,5 @@
|
||||
[uwsgi]
|
||||
inherit = unbit
|
||||
embedded_plugins = python
|
||||
bin_name = ../bin/uwsgi
|
||||
plugin_dir = ../bin/uwsgi_plugins
|
||||
|
||||
@@ -2,6 +2,98 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_init_cache() {
|
||||
int i;
|
||||
|
||||
if (!uwsgi.cache_blocksize)
|
||||
uwsgi.cache_blocksize = UMAX16;
|
||||
|
||||
if (uwsgi.cache_blocksize % uwsgi.page_size != 0) {
|
||||
uwsgi_log("invalid cache blocksize %llu: must be a multiple of memory page size (%d bytes)\n", (unsigned long long) uwsgi.cache_blocksize, uwsgi.page_size);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi.cache_hashtable = (uint64_t *) mmap(NULL, sizeof(uint64_t) * UMAX16, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (!uwsgi.cache_hashtable) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(uwsgi.cache_hashtable, 0, sizeof(uint64_t) * UMAX16);
|
||||
|
||||
uwsgi.cache_unused_stack = (uint64_t *) mmap(NULL, sizeof(uint64_t) * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (!uwsgi.cache_unused_stack) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(uwsgi.cache_unused_stack, 0, sizeof(uint64_t) * uwsgi.cache_max_items);
|
||||
|
||||
// the first cache item is always zero
|
||||
uwsgi.shared->cache_first_available_item = 1;
|
||||
uwsgi.shared->cache_unused_stack_ptr = 0;
|
||||
|
||||
//uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (uwsgi.cache_store) {
|
||||
uwsgi.cache_filesize = (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items) + (uwsgi.cache_blocksize * uwsgi.cache_max_items);
|
||||
int cache_fd;
|
||||
struct stat cst;
|
||||
|
||||
if (stat(uwsgi.cache_store, &cst)) {
|
||||
uwsgi_log("creating a new cache store file: %s\n", uwsgi.cache_store);
|
||||
cache_fd = open(uwsgi.cache_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
if (cache_fd >= 0) {
|
||||
// fill the caching store
|
||||
if (ftruncate(cache_fd, uwsgi.cache_filesize)) {
|
||||
uwsgi_log("ftruncate()");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((size_t) cst.st_size != uwsgi.cache_filesize || !S_ISREG(cst.st_mode)) {
|
||||
uwsgi_log("invalid cache store file. Please remove it or fix cache blocksize/items to match its size\n");
|
||||
exit(1);
|
||||
}
|
||||
cache_fd = open(uwsgi.cache_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
uwsgi_log("recovered cache from backing store file: %s\n", uwsgi.cache_store);
|
||||
}
|
||||
|
||||
if (cache_fd < 0) {
|
||||
uwsgi_error_open(uwsgi.cache_store);
|
||||
exit(1);
|
||||
}
|
||||
uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, uwsgi.cache_filesize, PROT_READ | PROT_WRITE, MAP_SHARED, cache_fd, 0);
|
||||
uwsgi_cache_fix();
|
||||
|
||||
}
|
||||
else {
|
||||
uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items) + (uwsgi.cache_blocksize * uwsgi.cache_max_items), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
for (i = 0; i < (int) uwsgi.cache_max_items; i++) {
|
||||
memset(&uwsgi.cache_items[i], 0, sizeof(struct uwsgi_cache_item));
|
||||
}
|
||||
}
|
||||
if (!uwsgi.cache_items) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
uwsgi.cache = mmap(NULL, uwsgi.cache_blocksize * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (!uwsgi.cache) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
*/
|
||||
|
||||
uwsgi.cache = ((void *) uwsgi.cache_items) + (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items);
|
||||
|
||||
uwsgi.cache_lock = uwsgi_mmap_shared_rwlock();
|
||||
uwsgi_rwlock_init(uwsgi.cache_lock);
|
||||
|
||||
uwsgi_log("*** Cache subsystem initialized: %dMB preallocated ***\n", ((sizeof(uint64_t) * UMAX16) + (sizeof(uint64_t) * uwsgi.cache_max_items) + (uwsgi.cache_blocksize * uwsgi.cache_max_items) + (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items)) / (1024 * 1024));
|
||||
}
|
||||
|
||||
struct uwsgi_subscriber_name *uwsgi_get_subscriber(struct uwsgi_dict *udict, char *key, uint16_t keylen) {
|
||||
|
||||
uint64_t ovl;
|
||||
@@ -39,7 +131,7 @@ struct uwsgi_subscriber_name *uwsgi_get_subscriber(struct uwsgi_dict *udict, cha
|
||||
return ret;
|
||||
}
|
||||
|
||||
void uwsgi_add_subscriber(struct uwsgi_dict *udict, char *key, uint16_t keylen, char *address, uint64_t address_len) {
|
||||
void uwsgi_add_subscriber(struct uwsgi_dict *udict, struct uwsgi_subscribe_req *usr) {
|
||||
|
||||
char *ptr;
|
||||
uint64_t vallen = 0;
|
||||
@@ -47,11 +139,11 @@ void uwsgi_add_subscriber(struct uwsgi_dict *udict, char *key, uint16_t keylen,
|
||||
int found = 0;
|
||||
int i;
|
||||
|
||||
ptr = uwsgi_dict_get(udict, key, keylen, &vallen);
|
||||
ptr = uwsgi_dict_get(udict, usr->key, usr->keylen, &vallen);
|
||||
if (ptr && vallen) {
|
||||
usub = (struct uwsgi_subscriber *) ptr;
|
||||
for(i=0;i<(int)usub->nodes;i++) {
|
||||
if (!uwsgi_strncmp(usub->names[i].name, usub->names[i].len, address, address_len)) {
|
||||
if (!uwsgi_strncmp(usub->names[i].name, usub->names[i].len, usr->address, usr->address_len)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
@@ -65,8 +157,10 @@ void uwsgi_add_subscriber(struct uwsgi_dict *udict, char *key, uint16_t keylen,
|
||||
break;
|
||||
}
|
||||
}
|
||||
usub->names[found].len = address_len;
|
||||
memcpy(usub->names[found].name, address, address_len);
|
||||
usub->names[found].len = usr->address_len;
|
||||
usub->names[found].modifier1 = usr->modifier1;
|
||||
usub->names[found].modifier2 = usr->modifier2;
|
||||
memcpy(usub->names[found].name, usr->address, usr->address_len);
|
||||
if (found == (int) usub->nodes) {
|
||||
usub->nodes++;
|
||||
}
|
||||
@@ -76,8 +170,10 @@ void uwsgi_add_subscriber(struct uwsgi_dict *udict, char *key, uint16_t keylen,
|
||||
else {
|
||||
nusub.nodes = 1;
|
||||
nusub.current = 0;
|
||||
memcpy(nusub.names[0].name, address, address_len);
|
||||
uwsgi_dict_set(udict, key, keylen, (char *) &nusub, sizeof(struct uwsgi_subscriber));
|
||||
memcpy(nusub.names[0].name, usr->address, usr->address_len);
|
||||
nusub.names[0].modifier1 = usr->modifier1;
|
||||
nusub.names[0].modifier2 = usr->modifier2;
|
||||
uwsgi_dict_set(udict, usr->key, usr->keylen, (char *) &nusub, sizeof(struct uwsgi_subscriber));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -486,103 +582,3 @@ end:
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
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)) {
|
||||
val = uwsgi_cache_get(val, vallen, &tmp_vallen);
|
||||
if (val && tmp_vallen > 0) {
|
||||
wsgi_req->response_size = write(wsgi_req->poll.fd, val, tmp_vallen);
|
||||
}
|
||||
|
||||
}
|
||||
else if (!uwsgi_strncmp(key, keylen, "get", 3)) {
|
||||
val = uwsgi_cache_get(val, vallen, &tmp_vallen);
|
||||
if (val && vallen > 0) {
|
||||
wsgi_req->response_size = write(wsgi_req->poll.fd, val, tmp_vallen);
|
||||
}
|
||||
else {
|
||||
wsgi_req->response_size = write(wsgi_req->poll.fd, "HTTP/1.0 404 Not Found\r\n\r\n<h1>Not Found</h1>", 44);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int uwsgi_cache_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
uint64_t vallen = 0;
|
||||
char *value;
|
||||
char *argv[3];
|
||||
uint8_t argc = 0;
|
||||
|
||||
switch(wsgi_req->uh.modifier2) {
|
||||
case 0:
|
||||
// get
|
||||
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 = write(wsgi_req->poll.fd, &wsgi_req->uh, 4);
|
||||
wsgi_req->response_size += write(wsgi_req->poll.fd, value, vallen);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
// set
|
||||
if (wsgi_req->uh.pktsize > 0) {
|
||||
argc = 3;
|
||||
if (!uwsgi_parse_array(wsgi_req->buffer, wsgi_req->uh.pktsize, argv, &argc)) {
|
||||
if (argc > 1) {
|
||||
uwsgi_cache_set(argv[0], strlen(argv[0]), argv[1], strlen(argv[1]), 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
// del
|
||||
if (wsgi_req->uh.pktsize > 0) {
|
||||
uwsgi_cache_del(wsgi_req->buffer, wsgi_req->uh.pktsize);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
// dict
|
||||
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_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 = write(wsgi_req->poll.fd, &wsgi_req->uh, 4);
|
||||
wsgi_req->response_size += write(wsgi_req->poll.fd, value, vallen);
|
||||
}
|
||||
else {
|
||||
wsgi_req->uh.pktsize = 0;
|
||||
wsgi_req->uh.modifier2 = 0;
|
||||
wsgi_req->response_size = write(wsgi_req->poll.fd, &wsgi_req->uh, 4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct uwsgi_plugin uwsgi_cache_plugin = {
|
||||
|
||||
.name = "cache",
|
||||
.modifier1 = 111,
|
||||
.request = uwsgi_cache_request,
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# uwsgi --master --chdir /opt/graphite/webapp/graphite --module graphite_uwsgi ...
|
||||
#
|
||||
#
|
||||
# this module will update a carbon server (used by the graphite tool: http://graphite.wikidot.com/)
|
||||
# with requests count made by a Django app (and can track graphite itself as it is a Django app ;)
|
||||
#
|
||||
#
|
||||
|
||||
import os
|
||||
import uwsgi
|
||||
import time
|
||||
from django.core.handlers.wsgi import WSGIHandler
|
||||
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
|
||||
|
||||
CARBON_SERVER = "127.0.0.1:2003"
|
||||
|
||||
def update_carbon(signum):
|
||||
# connect to the carbon server
|
||||
carbon_fd = uwsgi.connect(CARBON_SERVER)
|
||||
# send data to the carbon server
|
||||
uwsgi.send(carbon_fd, "uwsgi.%s.requests %d %d\n" % (uwsgi.hostname, uwsgi.total_requests(), int(time.time())))
|
||||
# close the connection with the carbon server
|
||||
uwsgi.close(carbon_fd)
|
||||
|
||||
# register a new uwsgi signal (signum: 17)
|
||||
uwsgi.register_signal(17, '', update_carbon)
|
||||
|
||||
# attach a timer of 10 seconds to signal 17
|
||||
uwsgi.add_timer(17, 10)
|
||||
|
||||
# the Django app
|
||||
application = WSGIHandler()
|
||||
@@ -0,0 +1,66 @@
|
||||
import django
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.conf import settings
|
||||
import os
|
||||
import sys
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Runs this project as a uWSGI application. Requires the uwsgi binary in system path."
|
||||
|
||||
http_port = '8000'
|
||||
socket_addr = None
|
||||
|
||||
def handle(self, *args, **options):
|
||||
for arg in args:
|
||||
k,v = arg.split('=')
|
||||
if k == 'http':
|
||||
if self.http_port:
|
||||
self.http_port = v
|
||||
elif k == 'socket':
|
||||
self.http_port = None
|
||||
self.socket_addr = v
|
||||
|
||||
# load http and python plugin: first the specific version, otherwise try with the generic one
|
||||
if self.http_port:
|
||||
os.environ['UWSGI_PLUGINS'] = 'http,python%d%d:python' % (sys.version_info[0], sys.version_info[1])
|
||||
else:
|
||||
os.environ['UWSGI_PLUGINS'] = 'python%d%d:python' % (sys.version_info[0], sys.version_info[1])
|
||||
|
||||
# load the Django WSGI handler
|
||||
os.environ['UWSGI_MODULE'] = 'django.core.handlers.wsgi:WSGIHandler()'
|
||||
# DJANGO settings
|
||||
if options['settings']:
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = options['settings']
|
||||
else:
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
|
||||
|
||||
# bind the http server to the default port
|
||||
if self.http_port:
|
||||
os.environ['UWSGI_HTTP'] = ':%s' % self.http_port
|
||||
elif self.socket_addr:
|
||||
os.environ['UWSGI_SOCKET'] = self.socket_addr
|
||||
|
||||
# map admin static files
|
||||
os.environ['UWSGI_STATIC_MAP'] = '%s=%s' % (settings.ADMIN_MEDIA_PREFIX, os.path.join(django.__path__[0], 'contrib', 'admin', 'media'))
|
||||
# remove sockets/pidfile at exit
|
||||
os.environ['UWSGI_VACUUM'] = '1'
|
||||
# retrieve/set the PythonHome
|
||||
os.environ['UWSGI_PYHOME'] = sys.prefix
|
||||
# increase buffer size a bit
|
||||
os.environ['UWSGI_BUFFER_SIZE'] = '8192'
|
||||
# add threads for concurrency
|
||||
os.environ['UWSGI_THREADS'] = '8'
|
||||
# enable the master process
|
||||
os.environ['UWSGI_MASTER'] = '1'
|
||||
# use uWSGI python module aliasing to fix the PYTHONPATH
|
||||
os.environ['UWSGI_PYMODULE_ALIAS'] = '%s=./' % os.path.basename(os.getcwd())
|
||||
# exec the uwsgi binary
|
||||
os.execvp('uwsgi', ('uwsgi',))
|
||||
|
||||
def usage(self, subcomand):
|
||||
return r"""
|
||||
run this project on the uWSGI server
|
||||
|
||||
http=PORT run the embedded http server on port PORT
|
||||
socket=ADDR bind the uwsgi server on address ADDR (this will disable the http server)
|
||||
"""
|
||||
@@ -0,0 +1,28 @@
|
||||
import uwsgi
|
||||
from uwsgidecorators import *
|
||||
|
||||
from uwsgicc import app as application
|
||||
|
||||
import time
|
||||
|
||||
|
||||
@rpc("helloworld")
|
||||
def hello_world():
|
||||
return "Hello World"
|
||||
|
||||
@signal(1)
|
||||
def what_time_is_it(num):
|
||||
print(time.asctime())
|
||||
|
||||
|
||||
@timer(2, 3)
|
||||
def salut(num):
|
||||
print("Salut !!! 3 seconds elapsed and signal %d raised" % num)
|
||||
|
||||
@rbtimer(3, 10)
|
||||
def tenseconds(num):
|
||||
print("red black timer !!! 10 seconds elapsed and signal %d raised" % num)
|
||||
|
||||
@filemon(4, "/tmp")
|
||||
def tmpmodified(num):
|
||||
print("/tmp has been modified")
|
||||
@@ -5,29 +5,59 @@
|
||||
extern struct uwsgi_server uwsgi;
|
||||
extern char **environ;
|
||||
|
||||
int emperor_queue;
|
||||
|
||||
static void royal_death(int signum) {
|
||||
uwsgi_notify("The Emperor is buried.");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
struct uwsgi_instance {
|
||||
struct uwsgi_instance *ui_prev;
|
||||
struct uwsgi_instance *ui_next;
|
||||
|
||||
char name[0xff];
|
||||
pid_t pid ;
|
||||
pid_t pid;
|
||||
|
||||
int status;
|
||||
time_t born;
|
||||
time_t last_mod;
|
||||
time_t last_loyal;
|
||||
|
||||
uint64_t respawns;
|
||||
int use_config;
|
||||
|
||||
int pipe[2];
|
||||
int pipe_config[2];
|
||||
|
||||
char *config;
|
||||
uint32_t config_len;
|
||||
|
||||
int loyal;
|
||||
};
|
||||
|
||||
struct uwsgi_instance *ui;
|
||||
|
||||
struct uwsgi_instance *emperor_get_by_fd(int fd) {
|
||||
|
||||
struct uwsgi_instance *c_ui = ui;
|
||||
|
||||
while (c_ui->ui_next) {
|
||||
c_ui = c_ui->ui_next;
|
||||
|
||||
if (c_ui->pipe[0] == fd) {
|
||||
return c_ui;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_instance *emperor_get(char *name) {
|
||||
|
||||
|
||||
struct uwsgi_instance *c_ui = ui;
|
||||
|
||||
while(c_ui->ui_next) {
|
||||
|
||||
while (c_ui->ui_next) {
|
||||
c_ui = c_ui->ui_next;
|
||||
|
||||
if (!strcmp(c_ui->name, name)) {
|
||||
@@ -50,6 +80,16 @@ void emperor_del(struct uwsgi_instance *c_ui) {
|
||||
// this will destroy the whole uWSGI instance (and workers)
|
||||
close(c_ui->pipe[0]);
|
||||
|
||||
if (c_ui->use_config) {
|
||||
close(c_ui->pipe_config[0]);
|
||||
}
|
||||
|
||||
if (uwsgi.vassals_stop_hook) {
|
||||
uwsgi_log("running vassal stop-hook: %s %s\n", uwsgi.vassals_stop_hook, c_ui->name);
|
||||
int stop_hook_ret = uwsgi_run_command_and_wait(uwsgi.vassals_stop_hook, c_ui->name);
|
||||
uwsgi_log("%s stop-hook returned %d\n", c_ui->name, stop_hook_ret);
|
||||
}
|
||||
|
||||
uwsgi_log("removed uwsgi instance %s\n", c_ui->name);
|
||||
|
||||
free(c_ui);
|
||||
@@ -71,44 +111,77 @@ void emperor_stop(struct uwsgi_instance *c_ui) {
|
||||
void emperor_respawn(struct uwsgi_instance *c_ui, time_t mod) {
|
||||
|
||||
// reload the uWSGI instance
|
||||
if (write(c_ui->pipe[0], "\1", 1) != 1) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
if (c_ui->use_config) {
|
||||
if (write(c_ui->pipe[0], "\0", 1) != 1) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (write(c_ui->pipe[0], "\1", 1) != 1) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
}
|
||||
|
||||
c_ui->respawns++;
|
||||
c_ui->respawns++;
|
||||
c_ui->last_mod = mod;
|
||||
|
||||
uwsgi_log("reload the uwsgi instance %s\n", c_ui->name);
|
||||
uwsgi_log("reload the uwsgi instance %s\n", c_ui->name);
|
||||
}
|
||||
|
||||
void emperor_add(char *name, time_t born) {
|
||||
void emperor_add(char *name, time_t born, char *config, uint32_t config_size) {
|
||||
|
||||
struct uwsgi_instance *c_ui = ui;
|
||||
struct uwsgi_instance *n_ui = NULL;
|
||||
pid_t pid ;
|
||||
char *argv[4];
|
||||
char *uef ;
|
||||
pid_t pid;
|
||||
char **argv;
|
||||
char *uef;
|
||||
char **uenvs;
|
||||
int counter;
|
||||
int i;
|
||||
|
||||
while(c_ui->ui_next) {
|
||||
c_ui = c_ui->ui_next;
|
||||
}
|
||||
sleep(1);
|
||||
|
||||
while (c_ui->ui_next) {
|
||||
c_ui = c_ui->ui_next;
|
||||
}
|
||||
|
||||
n_ui = uwsgi_malloc(sizeof(struct uwsgi_instance));
|
||||
memset(n_ui, 0, sizeof(struct uwsgi_instance));
|
||||
|
||||
if (config) {
|
||||
n_ui->use_config = 1;
|
||||
n_ui->config = config;
|
||||
n_ui->config_len = config_size;
|
||||
}
|
||||
|
||||
c_ui->ui_next = n_ui;
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("c_ui->ui_next = %p\n", c_ui->ui_next);
|
||||
#endif
|
||||
n_ui->ui_prev = c_ui;
|
||||
memcpy(n_ui->name, name, strlen(name));
|
||||
n_ui->born = born;
|
||||
n_ui->last_mod = born;
|
||||
// start without loyalty
|
||||
n_ui->last_loyal = born;
|
||||
n_ui->loyal = 0;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe)) {
|
||||
uwsgi_error("socketpair()");
|
||||
goto clear;
|
||||
}
|
||||
|
||||
event_queue_add_fd_read(emperor_queue, n_ui->pipe[0]);
|
||||
|
||||
if (n_ui->use_config) {
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe_config)) {
|
||||
uwsgi_error("socketpair()");
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO pre-start hook
|
||||
|
||||
// a new uWSGI instance will start
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
@@ -118,11 +191,22 @@ void emperor_add(char *name, time_t born) {
|
||||
n_ui->pid = pid;
|
||||
// close the right side of the pipe
|
||||
close(n_ui->pipe[1]);
|
||||
if (n_ui->use_config) {
|
||||
close(n_ui->pipe_config[1]);
|
||||
}
|
||||
|
||||
if (n_ui->use_config) {
|
||||
if (write(n_ui->pipe_config[0], n_ui->config, n_ui->config_len) <= 0) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
close(n_ui->pipe_config[0]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
|
||||
unsetenv("UWSGI_RELOADS");
|
||||
unsetenv("NOTIFY_SOCKET");
|
||||
|
||||
uef = uwsgi_num2str(n_ui->pipe[1]);
|
||||
if (setenv("UWSGI_EMPEROR_FD", uef, 1)) {
|
||||
@@ -131,10 +215,19 @@ void emperor_add(char *name, time_t born) {
|
||||
}
|
||||
free(uef);
|
||||
|
||||
if (n_ui->use_config) {
|
||||
uef = uwsgi_num2str(n_ui->pipe_config[1]);
|
||||
if (setenv("UWSGI_EMPEROR_FD_CONFIG", uef, 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
exit(1);
|
||||
}
|
||||
free(uef);
|
||||
}
|
||||
|
||||
uenvs = environ;
|
||||
while(*uenvs) {
|
||||
while (*uenvs) {
|
||||
if (!strncmp(*uenvs, "UWSGI_VASSAL_", 13)) {
|
||||
char *ne = uwsgi_concat2("UWSGI_", *uenvs+13);
|
||||
char *ne = uwsgi_concat2("UWSGI_", *uenvs + 13);
|
||||
char *oe = uwsgi_concat2n(*uenvs, strchr(*uenvs, '=') - *uenvs, "", 0);
|
||||
if (unsetenv(oe)) {
|
||||
uwsgi_error("unsetenv()");
|
||||
@@ -156,24 +249,64 @@ void emperor_add(char *name, time_t born) {
|
||||
// close the left side of the pipe
|
||||
close(n_ui->pipe[0]);
|
||||
|
||||
if (n_ui->use_config) {
|
||||
close(n_ui->pipe_config[0]);
|
||||
}
|
||||
|
||||
counter = 4;
|
||||
struct uwsgi_config_template *uct = uwsgi.vassals_templates;
|
||||
while(uct) {
|
||||
counter+=2;
|
||||
uct = uct->next;
|
||||
}
|
||||
|
||||
argv = uwsgi_malloc(sizeof(char *) * counter);
|
||||
// set args
|
||||
argv[0] = uwsgi.binary_path;
|
||||
if (!strcmp(name+(strlen(name)-4), ".xml")) argv[1] = "--xml";
|
||||
if (!strcmp(name+(strlen(name)-4), ".ini")) argv[1] = "--ini";
|
||||
if (!strcmp(name+(strlen(name)-4), ".yml")) argv[1] = "--yaml";
|
||||
if (!strcmp(name+(strlen(name)-5), ".yaml")) argv[1] = "--yaml";
|
||||
if (!strcmp(name + (strlen(name) - 4), ".xml"))
|
||||
argv[1] = "--xml";
|
||||
if (!strcmp(name + (strlen(name) - 4), ".ini"))
|
||||
argv[1] = "--ini";
|
||||
if (!strcmp(name + (strlen(name) - 4), ".yml"))
|
||||
argv[1] = "--yaml";
|
||||
if (!strcmp(name + (strlen(name) - 5), ".yaml"))
|
||||
argv[1] = "--yaml";
|
||||
if (!strcmp(name + (strlen(name) - 3), ".js"))
|
||||
argv[1] = "--json";
|
||||
argv[2] = name;
|
||||
argv[3] = NULL;
|
||||
counter = 3;
|
||||
uct = uwsgi.vassals_templates;
|
||||
while(uct) {
|
||||
argv[counter] = "--inherit";
|
||||
argv[counter+1] = uct->filename;
|
||||
counter+=2;
|
||||
uct = uct->next;
|
||||
}
|
||||
argv[counter] = NULL;
|
||||
|
||||
// close all of the unneded fd
|
||||
for(i=3;i<sysconf(_SC_OPEN_MAX);i++) {
|
||||
if (i != n_ui->pipe[1]) {
|
||||
close(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.vassals_start_hook) {
|
||||
uwsgi_log("running vassal start-hook: %s %s\n", uwsgi.vassals_start_hook, n_ui->name);
|
||||
int start_hook_ret = uwsgi_run_command_and_wait(uwsgi.vassals_start_hook, n_ui->name);
|
||||
uwsgi_log("%s start-hook returned %d\n", n_ui->name, start_hook_ret);
|
||||
}
|
||||
|
||||
// start !!!
|
||||
if (execvp(argv[0], argv)) {
|
||||
uwsgi_error("execvp()");
|
||||
}
|
||||
uwsgi_log("is the uwsgi binary in your system PATH ?\n");
|
||||
// never here
|
||||
exit(1);
|
||||
exit(UWSGI_EXILE_CODE);
|
||||
}
|
||||
|
||||
clear:
|
||||
clear:
|
||||
|
||||
free(n_ui);
|
||||
c_ui->ui_next = NULL;
|
||||
@@ -196,28 +329,79 @@ void emperor_loop() {
|
||||
glob_t g;
|
||||
int i;
|
||||
struct dirent *de;
|
||||
char *amqp_port;
|
||||
int amqp_fd = -1;
|
||||
char *amqp_routing_key;
|
||||
|
||||
void *events;
|
||||
int nevents;
|
||||
int interesting_fd;
|
||||
char notification_message[64];
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
uwsgi_unix_signal(SIGINT, royal_death);
|
||||
uwsgi_unix_signal(SIGTERM, royal_death);
|
||||
|
||||
memset(&ui_base, 0, sizeof(struct uwsgi_instance));
|
||||
|
||||
uwsgi_log("*** starting uWSGI Emperor ***\n");
|
||||
|
||||
if (!glob(uwsgi.emperor_dir, GLOB_MARK, NULL, &g)) {
|
||||
if (g.gl_pathc == 1 && g.gl_pathv[0][strlen(g.gl_pathv[0])-1] == '/' ) {
|
||||
simple_mode = 1;
|
||||
if (chdir(uwsgi.emperor_dir)) {
|
||||
uwsgi_error("chdir()");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
emperor_queue = event_queue_init();
|
||||
|
||||
events = event_queue_alloc(64);
|
||||
|
||||
if (uwsgi.has_emperor) {
|
||||
uwsgi_log("*** starting uWSGI sub-Emperor ***\n");
|
||||
}
|
||||
else {
|
||||
uwsgi_error("glob()");
|
||||
exit(1);
|
||||
uwsgi_log("*** starting uWSGI Emperor ***\n");
|
||||
}
|
||||
|
||||
amqp_port = strchr(uwsgi.emperor_dir, ':');
|
||||
|
||||
if (amqp_port) {
|
||||
if (uwsgi.emperor_amqp_vhost == NULL) uwsgi.emperor_amqp_vhost = "/";
|
||||
if (uwsgi.emperor_amqp_username == NULL) uwsgi.emperor_amqp_username = "guest";
|
||||
if (uwsgi.emperor_amqp_password == NULL) uwsgi.emperor_amqp_password = "guest";
|
||||
reconnect:
|
||||
while(amqp_fd == -1) {
|
||||
uwsgi_log("connecting to AMQP server...\n");
|
||||
amqp_fd = uwsgi_connect(uwsgi.emperor_dir, -1, 0);
|
||||
if (amqp_fd < 0) {
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("subscribing to queue...\n");
|
||||
if (uwsgi_amqp_consume_queue(amqp_fd, uwsgi.emperor_amqp_vhost, uwsgi.emperor_amqp_username, uwsgi.emperor_amqp_password, "", "uwsgi.emperor", "fanout") < 0) {
|
||||
close(amqp_fd);
|
||||
amqp_fd = -1;
|
||||
sleep(1);
|
||||
goto reconnect;
|
||||
}
|
||||
|
||||
event_queue_add_fd_read(emperor_queue, amqp_fd);
|
||||
}
|
||||
else {
|
||||
if (!glob(uwsgi.emperor_dir, GLOB_MARK|GLOB_NOCHECK, NULL, &g)) {
|
||||
if (g.gl_pathc == 1 && g.gl_pathv[0][strlen(g.gl_pathv[0]) - 1] == '/') {
|
||||
simple_mode = 1;
|
||||
if (chdir(uwsgi.emperor_dir)) {
|
||||
uwsgi_error("chdir()");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_error("glob()");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
ui = &ui_base;
|
||||
|
||||
for(;;) {
|
||||
int freq = 0 ;
|
||||
|
||||
for (;;) {
|
||||
|
||||
|
||||
if (!i_am_alone) {
|
||||
@@ -227,22 +411,138 @@ void emperor_loop() {
|
||||
}
|
||||
}
|
||||
|
||||
nevents = event_queue_wait_multi(emperor_queue, freq, events, 64);
|
||||
freq = 3;
|
||||
|
||||
for (i = 0; i<nevents;i++) {
|
||||
interesting_fd = event_queue_interesting_fd(events, i);
|
||||
|
||||
if (amqp_fd > -1 && interesting_fd == amqp_fd ) {
|
||||
uint64_t msgsize;
|
||||
char *config = uwsgi_amqp_consume(amqp_fd, &msgsize, &amqp_routing_key);
|
||||
|
||||
if (!config) {
|
||||
uwsgi_log("problem with RabbitMQ server, trying reconnection...\n");
|
||||
event_queue_del_fd(emperor_queue, amqp_fd, event_queue_read());
|
||||
close(amqp_fd);
|
||||
amqp_fd = -1;
|
||||
goto reconnect;
|
||||
}
|
||||
|
||||
if (amqp_routing_key) {
|
||||
uwsgi_log("AMQP routing_key = %s\n", amqp_routing_key);
|
||||
char *config_file = uwsgi_concat2("emperor://", amqp_routing_key);
|
||||
free(amqp_routing_key);
|
||||
|
||||
ui_current = emperor_get(config_file);
|
||||
|
||||
if (ui_current) {
|
||||
// ignore event if i am not loyal
|
||||
if (!ui_current->loyal) continue;
|
||||
free(ui_current->config);
|
||||
ui_current->config = config;
|
||||
ui_current->config_len = msgsize;
|
||||
if (!msgsize) {
|
||||
// SAFE
|
||||
emperor_del(ui_current);
|
||||
}
|
||||
else {
|
||||
emperor_respawn(ui_current, time(NULL));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (msgsize > 0) {
|
||||
emperor_add(config_file, time(NULL), config, msgsize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
free(config_file);
|
||||
}
|
||||
else {
|
||||
if (msgsize) {
|
||||
if (msgsize >= 0xff) { free(config); continue; }
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%.*s\n", (int)msgsize, config);
|
||||
#endif
|
||||
char *config_file = uwsgi_concat2n(config, msgsize, "", 0);
|
||||
free(config);
|
||||
|
||||
if (strncmp(config_file, "http://", 7)) {
|
||||
if (stat(config_file, &st)) {
|
||||
free(config_file);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!S_ISREG(st.st_mode)) {
|
||||
free(config_file);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ui_current = emperor_get(config_file);
|
||||
|
||||
if (ui_current) {
|
||||
// ignore event if i am not loyal
|
||||
if (!ui_current->loyal) continue;
|
||||
emperor_respawn(ui_current, time(NULL));
|
||||
}
|
||||
else {
|
||||
emperor_add(config_file, time(NULL), NULL, 0);
|
||||
}
|
||||
|
||||
free(config_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ui_current = emperor_get_by_fd(interesting_fd);
|
||||
if (ui_current) {
|
||||
char byte;
|
||||
ssize_t rlen = read(interesting_fd, &byte, 1);
|
||||
if (rlen <= 0) {
|
||||
// SAFE
|
||||
emperor_del(ui_current);
|
||||
}
|
||||
else {
|
||||
if (byte == 17) {
|
||||
ui_current->loyal = 1;
|
||||
uwsgi_log("*** vassal %s is now loyal ***\n", ui_current->name);
|
||||
|
||||
// TODO post-start hook
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log("unrecognized event on fd %d\n", interesting_fd);
|
||||
event_queue_del_fd(emperor_queue, interesting_fd, event_queue_read());
|
||||
close(interesting_fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (amqp_fd == -1) {
|
||||
if (simple_mode) {
|
||||
DIR *dir = opendir(".");
|
||||
while((de = readdir(dir)) != NULL) {
|
||||
if (!strcmp(de->d_name+(strlen(de->d_name)-4), ".xml") ||
|
||||
!strcmp(de->d_name+(strlen(de->d_name)-4), ".ini") ||
|
||||
!strcmp(de->d_name+(strlen(de->d_name)-4), ".yml") ||
|
||||
!strcmp(de->d_name+(strlen(de->d_name)-5), ".yaml")
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
if (!strcmp(de->d_name + (strlen(de->d_name) - 4), ".xml") ||
|
||||
!strcmp(de->d_name + (strlen(de->d_name) - 4), ".ini") ||
|
||||
!strcmp(de->d_name + (strlen(de->d_name) - 4), ".yml") ||
|
||||
!strcmp(de->d_name + (strlen(de->d_name) - 5), ".yaml") ||
|
||||
!strcmp(de->d_name + (strlen(de->d_name) - 3), ".js")
|
||||
) {
|
||||
|
||||
|
||||
if (strlen(de->d_name) >= 0xff) continue;
|
||||
|
||||
if (stat(de->d_name, &st)) continue;
|
||||
if (strlen(de->d_name) >= 0xff)
|
||||
continue;
|
||||
|
||||
if (stat(de->d_name, &st))
|
||||
continue;
|
||||
|
||||
if (!S_ISREG(st.st_mode))
|
||||
continue;
|
||||
|
||||
if (!S_ISREG(st.st_mode)) continue;
|
||||
|
||||
ui_current = emperor_get(de->d_name);
|
||||
|
||||
if (ui_current) {
|
||||
@@ -252,97 +552,125 @@ void emperor_loop() {
|
||||
}
|
||||
}
|
||||
else {
|
||||
emperor_add(de->d_name, st.st_mtime);
|
||||
emperor_add(de->d_name, st.st_mtime, NULL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
else {
|
||||
if (glob(uwsgi.emperor_dir, GLOB_MARK, NULL, &g)) {
|
||||
if (glob(uwsgi.emperor_dir, GLOB_MARK|GLOB_NOCHECK, NULL, &g)) {
|
||||
uwsgi_error("glob()");
|
||||
continue;
|
||||
}
|
||||
|
||||
for(i=0;i<(int)g.gl_pathc;i++) {
|
||||
if (!strcmp(g.gl_pathv[i]+(strlen(g.gl_pathv[i])-4), ".xml") ||
|
||||
!strcmp(g.gl_pathv[i]+(strlen(g.gl_pathv[i])-4), ".ini") ||
|
||||
!strcmp(g.gl_pathv[i]+(strlen(g.gl_pathv[i])-4), ".yml") ||
|
||||
!strcmp(g.gl_pathv[i]+(strlen(g.gl_pathv[i])-5), ".yaml")
|
||||
) {
|
||||
for (i = 0; i < (int) g.gl_pathc; i++) {
|
||||
if (!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 4), ".xml") ||
|
||||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 4), ".ini") ||
|
||||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 4), ".yml") ||
|
||||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 3), ".js") ||
|
||||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 5), ".yaml")
|
||||
) {
|
||||
|
||||
|
||||
if (strlen(g.gl_pathv[i]) >= 0xff) continue;
|
||||
if (strlen(g.gl_pathv[i]) >= 0xff)
|
||||
continue;
|
||||
|
||||
if (stat(g.gl_pathv[i], &st)) continue;
|
||||
if (stat(g.gl_pathv[i], &st))
|
||||
continue;
|
||||
|
||||
if (!S_ISREG(st.st_mode)) continue;
|
||||
if (!S_ISREG(st.st_mode))
|
||||
continue;
|
||||
|
||||
ui_current = emperor_get(g.gl_pathv[i]);
|
||||
ui_current = emperor_get(g.gl_pathv[i]);
|
||||
|
||||
if (ui_current) {
|
||||
// check if mtime is changed and the uWSGI instance must be reloaded
|
||||
if (st.st_mtime > ui_current->last_mod) {
|
||||
emperor_respawn(ui_current, st.st_mtime);
|
||||
}
|
||||
}
|
||||
else {
|
||||
emperor_add(g.gl_pathv[i], st.st_mtime, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (ui_current) {
|
||||
// check if mtime is changed and the uWSGI instance must be reloaded
|
||||
if (st.st_mtime > ui_current->last_mod) {
|
||||
emperor_respawn(ui_current, st.st_mtime);
|
||||
}
|
||||
}
|
||||
else {
|
||||
emperor_add(g.gl_pathv[i], st.st_mtime);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check for removed instances
|
||||
|
||||
ui_current = ui;
|
||||
has_children = 0;
|
||||
while(ui_current->ui_next) {
|
||||
ui_current = ui_current->ui_next;
|
||||
while (ui_current->ui_next) {
|
||||
ui_current = ui_current->ui_next;
|
||||
has_children++;
|
||||
}
|
||||
|
||||
if (uwsgi.notify) {
|
||||
if (snprintf(notification_message, 64, "The Emperor is governing %d vassals", has_children) >= 34) {
|
||||
uwsgi_notify(notification_message);
|
||||
}
|
||||
}
|
||||
|
||||
if (has_children) {
|
||||
diedpid = waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
|
||||
}
|
||||
else {
|
||||
// vacuum
|
||||
waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
|
||||
diedpid = 0;
|
||||
}
|
||||
if (diedpid < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
}
|
||||
ui_current = ui;
|
||||
while(ui_current->ui_next) {
|
||||
ui_current = ui_current->ui_next;
|
||||
if (ui_current->pid == diedpid) {
|
||||
if (ui_current->status == 0) {
|
||||
// respawn an accidentally dead instance
|
||||
emperor_add(ui_current->name, ui_current->last_mod);
|
||||
while (ui_current->ui_next) {
|
||||
ui_current = ui_current->ui_next;
|
||||
// check loyalty if not in simple/glob mode
|
||||
if (amqp_fd > -1) {
|
||||
if (!ui_current->loyal && (time(NULL)-ui_current->last_loyal) > 60) {
|
||||
uwsgi_log("!!! no loyalty showed by instance %s !!!\n", ui_current->name);
|
||||
// SAFE
|
||||
emperor_del(ui_current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ui_current->status == 1) {
|
||||
if (ui_current->config) free(ui_current->config);
|
||||
// SAFE
|
||||
emperor_del(ui_current);
|
||||
break;
|
||||
}
|
||||
else if (!ui_current->use_config && strncmp(ui_current->name, "http://",7) && stat(ui_current->name, &st)) {
|
||||
emperor_stop(ui_current);
|
||||
}
|
||||
else if (ui_current->pid == diedpid) {
|
||||
if (ui_current->status == 0) {
|
||||
// respawn an accidentally dead instance if its exit code is not UWSGI_EXILE_CODE
|
||||
if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_EXILE_CODE) {
|
||||
// SAFE
|
||||
emperor_del(ui_current);
|
||||
}
|
||||
else {
|
||||
// UNSAFE
|
||||
emperor_add(ui_current->name, ui_current->last_mod, ui_current->config, ui_current->config_len);
|
||||
emperor_del(ui_current);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (ui_current->status == 1) {
|
||||
// remove 'marked for dead' instance
|
||||
if (ui_current->config) free(ui_current->config);
|
||||
// SAFE
|
||||
emperor_del(ui_current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (ui_current->status == 1) {
|
||||
emperor_del(ui_current);
|
||||
break;
|
||||
}
|
||||
else if (stat(ui_current->name, &st)) {
|
||||
emperor_stop(ui_current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sleep(3);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -591,7 +591,9 @@ int event_queue_add_file_monitor(int eq, char *filename, int *id) {
|
||||
|
||||
*id = inotify_add_watch(ifd, filename, IN_ATTRIB|IN_CREATE|IN_DELETE|IN_DELETE_SELF|IN_MODIFY|IN_MOVE_SELF|IN_MOVED_FROM|IN_MOVED_TO);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("added watch %d for filename %s\n", *id, filename);
|
||||
#endif
|
||||
|
||||
if (add_to_queue) {
|
||||
return event_queue_add_fd_read(eq, ifd);
|
||||
@@ -630,7 +632,9 @@ struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
|
||||
}
|
||||
else {
|
||||
items = isize/(sizeof(struct inotify_event));
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("inotify returned %d items\n", items);
|
||||
#endif
|
||||
for(j=0;j<items;j++) {
|
||||
iie = &bie[j];
|
||||
for(i=0;i<ushared->files_monitored_cnt;i++) {
|
||||
|
||||
@@ -2,10 +2,36 @@ require 'fiber'
|
||||
class SuspendingBody
|
||||
|
||||
def each
|
||||
for i in 1..10
|
||||
for i in 1..3
|
||||
yield "number: #{i}\n"
|
||||
UWSGI.async_sleep(1)
|
||||
puts "sleep..."
|
||||
Fiber.yield
|
||||
end
|
||||
|
||||
fd = UWSGI.async_connect("81.174.68.52:80")
|
||||
UWSGI.wait_fd_write(fd, 3)
|
||||
Fiber.yield
|
||||
io = IO.new(fd)
|
||||
puts "connected"
|
||||
io.syswrite("GET /uwsgi/export/1081%3A362d695b2f25/plugins/fiber/fiber.c HTTP/1.0\r\n")
|
||||
io.syswrite("Host: projects.unbit.it\r\n")
|
||||
io.syswrite("\r\n")
|
||||
|
||||
UWSGI.wait_fd_read(fd, 3)
|
||||
Fiber.yield
|
||||
|
||||
puts "data available"
|
||||
|
||||
begin
|
||||
while body = io.sysread(fd)
|
||||
yield body
|
||||
Fiber.yield
|
||||
end
|
||||
rescue
|
||||
end
|
||||
|
||||
io.close
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
from flask import Flask, request
|
||||
app = Flask(__name__)
|
||||
app.debug = True
|
||||
|
||||
@app.route('/')
|
||||
def hello_world():
|
||||
return "<form method='POST' enctype='multipart/form-data' action='/upload'><input type='text' name='pippo'/><input type='file' name='ufile'/><input type='submit' value='upload'/></form>"
|
||||
|
||||
@app.route('/upload', methods=['GET', 'POST'])
|
||||
def upload_file():
|
||||
return str(len(request.form.get('pippo', 'boh'))) + request.form.get('pippo', 'boh')
|
||||
return request.files['ufile'].read()
|
||||
@@ -0,0 +1,27 @@
|
||||
[uwsgi]
|
||||
|
||||
master = true
|
||||
processes = 4
|
||||
threads = 8
|
||||
|
||||
; initialize 4 sockets with 4 different protocols
|
||||
socket = :3031
|
||||
socket = :3032
|
||||
socket = :3033
|
||||
socket = :3034
|
||||
|
||||
socket-protocol = 0,uwsgi
|
||||
socket-protocol = 1,http
|
||||
socket-protocol = 2,fastcgi
|
||||
socket-protocol = 3,uwsgidump
|
||||
|
||||
|
||||
; add a cache with 1000 items of 96k
|
||||
cache = 1000
|
||||
cache-blocksize = 98304
|
||||
|
||||
|
||||
log-micros = true
|
||||
|
||||
module = heavytest
|
||||
mount = /cc=uwsgicc/__init__.py
|
||||
@@ -0,0 +1,14 @@
|
||||
import uwsgi
|
||||
import werkzeug.testapp
|
||||
|
||||
uwsgi.cache_set("/cache/get", "HTTP 1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<h1>I am the uWSGI cache</h1>")
|
||||
|
||||
def app001(env, start_response):
|
||||
start_response('200 OK', [('Content-Type', 'text/html')])
|
||||
return "PATH_INFO=%s" % env['PATH_INFO']
|
||||
|
||||
def app002(env, start_response):
|
||||
start_response('200 OK', [('Content-Type', 'text/html')])
|
||||
return "requests: %d" % uwsgi.total_requests()
|
||||
|
||||
uwsgi.applications = { '':werkzeug.testapp.test_app, '/app001':app001, '/app002':app002 }
|
||||
@@ -87,7 +87,14 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
char *section_asked = "uwsgi";
|
||||
char *colon;
|
||||
|
||||
colon = uwsgi_get_last_char(file, ':');
|
||||
if (!uwsgi_startswith(file, "http://", 7)) {
|
||||
colon = uwsgi_get_last_char(file, '/');
|
||||
colon = uwsgi_get_last_char(colon, ':');
|
||||
}
|
||||
else {
|
||||
colon = uwsgi_get_last_char(file, ':');
|
||||
}
|
||||
|
||||
if (colon) {
|
||||
colon[0] = 0;
|
||||
if (colon[1] != 0) {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>it.unbit.uwsgi.emperor</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/Users/roberta/uwsgi/uwsgi</string>
|
||||
<string>--emperor</string>
|
||||
<string>/Users/*/Library/uwsgi/*.{xml,ini,yml,yaml,js}</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>it.unbit.uwsgi</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/Users/roberta/uwsgi/uwsgi</string>
|
||||
<string>--socket</string>
|
||||
<string>:3032</string>
|
||||
<string>--module</string>
|
||||
<string>welcome</string>
|
||||
<string>--master</string>
|
||||
<string>--die-on-term</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,107 @@
|
||||
#ifdef UWSGI_JSON
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#include <jansson.h>
|
||||
|
||||
|
||||
/*
|
||||
I really love the jansson library...
|
||||
*/
|
||||
|
||||
void uwsgi_json_config(char *file, char *magic_table[]) {
|
||||
|
||||
int len = 0;
|
||||
char *json_data;
|
||||
|
||||
|
||||
const char *key;
|
||||
|
||||
json_t *root;
|
||||
json_error_t error;
|
||||
json_t *config;
|
||||
json_t *config_value, *config_array_item;
|
||||
|
||||
void *config_iter;
|
||||
|
||||
char *object_asked = "uwsgi";
|
||||
char *colon;
|
||||
int i;
|
||||
|
||||
if (!uwsgi_startswith(file, "http://", 7)) {
|
||||
colon = uwsgi_get_last_char(file, '/');
|
||||
colon = uwsgi_get_last_char(colon, ':');
|
||||
}
|
||||
else {
|
||||
colon = uwsgi_get_last_char(file, ':');
|
||||
}
|
||||
|
||||
if (colon) {
|
||||
colon[0] = 0;
|
||||
if (colon[1] != 0) {
|
||||
object_asked = colon+1;
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("[uWSGI] getting JSON configuration from %s\n", file);
|
||||
|
||||
json_data = uwsgi_open_and_read(file, &len, 1, magic_table);
|
||||
|
||||
root = json_loads(json_data, 0, &error);
|
||||
|
||||
if (!root) {
|
||||
uwsgi_log("error parsing JSON data: line %d %s\n", error.line, error.text);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
config = json_object_get(root, object_asked);
|
||||
|
||||
if (!json_is_object(config)) {
|
||||
uwsgi_log("you must define a object named %s in your JSON data\n", object_asked);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
config_iter = json_object_iter(config);
|
||||
|
||||
while(config_iter) {
|
||||
key = json_object_iter_key(config_iter);
|
||||
config_value = json_object_iter_value(config_iter);
|
||||
|
||||
if (json_is_string(config_value)) {
|
||||
add_exported_option((char *)key, (char *) json_string_value(config_value), 0);
|
||||
}
|
||||
else if (json_is_true(config_value)) {
|
||||
add_exported_option((char *)key, (char *) "1", 0);
|
||||
}
|
||||
else if (json_is_false(config_value) || json_is_null(config_value)) {
|
||||
add_exported_option((char *)key, (char *) "0", 0);
|
||||
}
|
||||
else if (json_is_integer(config_value)) {
|
||||
add_exported_option((char *)key, uwsgi_num2str(json_integer_value(config_value)), 0);
|
||||
}
|
||||
else if (json_is_array(config_value)) {
|
||||
for(i=0;i<(int)json_array_size(config_value);i++) {
|
||||
config_array_item = json_array_get(config_value, i);
|
||||
if (json_is_string(config_array_item)) {
|
||||
add_exported_option((char *)key, (char *) json_string_value(config_array_item), 0);
|
||||
}
|
||||
else if (json_is_true(config_array_item)) {
|
||||
add_exported_option((char *)key, (char *) "1", 0);
|
||||
}
|
||||
else if (json_is_false(config_array_item) || json_is_null(config_array_item)) {
|
||||
add_exported_option((char *)key, (char *) "0", 0);
|
||||
}
|
||||
else if (json_is_integer(config_array_item)) {
|
||||
add_exported_option((char *)key, uwsgi_num2str(json_integer_value(config_array_item)), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config_iter = json_object_iter_next(config, config_iter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+806
@@ -0,0 +1,806 @@
|
||||
#include "../uwsgi.h"
|
||||
|
||||
#define AMQP_CONNECTION_HEADER "AMQP\0\0\x09\x01"
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
#define ntohll(x) x
|
||||
#else
|
||||
#define ntohll(x) ( ( (uint64_t)(ntohl( (uint32_t)((x << 32) >> 32) )) << 32) | ntohl( ((uint32_t)(x >> 32)) ) )
|
||||
#endif
|
||||
#define htonll(x) ntohll(x)
|
||||
|
||||
#define amqp_send(a, b, c) if (send(a, b, c, 0) < 0) { uwsgi_error("send()"); return -1; }
|
||||
|
||||
struct amqp_frame_header {
|
||||
|
||||
char type;
|
||||
uint16_t channel;
|
||||
uint32_t size;
|
||||
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct amqp_frame_method {
|
||||
uint16_t class_id;
|
||||
uint16_t method_id;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
static char *amqp_simple_get_frame(int, struct amqp_frame_header *);
|
||||
static char *amqp_get_method(int, uint16_t, uint16_t, uint32_t *);
|
||||
|
||||
/*
|
||||
static char *amqp_get_longstr(char *ptr, char *watermark) {
|
||||
|
||||
uint32_t longstr_size;
|
||||
|
||||
if (ptr+4 > watermark) return NULL;
|
||||
|
||||
memcpy(&longstr_size, ptr, 4);
|
||||
longstr_size = ntohl(longstr_size);
|
||||
|
||||
if (ptr+4+longstr_size > watermark) return NULL;
|
||||
|
||||
return ptr+4+longstr_size;
|
||||
}
|
||||
*/
|
||||
|
||||
static char *amqp_get_str(char *ptr, char *watermark) {
|
||||
|
||||
uint8_t str_size;
|
||||
|
||||
// over engeneering...
|
||||
if (ptr+1 > watermark) return NULL;
|
||||
|
||||
str_size = *ptr;
|
||||
|
||||
if (ptr+1+str_size > watermark) return NULL;
|
||||
|
||||
return ptr+1+str_size;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
static char *amqp_get_table(char *ptr, char *watermark) {
|
||||
|
||||
uint32_t table_size;
|
||||
|
||||
if (ptr+4 > watermark) return NULL;
|
||||
|
||||
memcpy(&table_size, ptr, 4);
|
||||
|
||||
table_size = ntohl(table_size);
|
||||
|
||||
if (ptr+4+table_size > watermark) return NULL;
|
||||
|
||||
return ptr+4+table_size;
|
||||
}
|
||||
*/
|
||||
|
||||
static char *amqp_get_short(char *ptr, char *watermark, uint16_t *sv) {
|
||||
|
||||
uint16_t tmp_short;
|
||||
|
||||
if (ptr+2 > watermark) return NULL;
|
||||
|
||||
memcpy(&tmp_short, ptr, 2);
|
||||
|
||||
*sv = ntohs(tmp_short);
|
||||
|
||||
return ptr+2;
|
||||
}
|
||||
|
||||
static char *amqp_get_long(char *ptr, char *watermark, uint32_t *lv) {
|
||||
|
||||
uint32_t tmp_long;
|
||||
|
||||
if (ptr+4 > watermark) return NULL;
|
||||
|
||||
memcpy(&tmp_long, ptr, 4);
|
||||
|
||||
*lv = ntohl(tmp_long);
|
||||
return ptr+4;
|
||||
}
|
||||
|
||||
static char *amqp_get_longlong(char *ptr, char *watermark, uint64_t *llv) {
|
||||
|
||||
uint64_t tmp_longlong;
|
||||
|
||||
if (ptr+8 > watermark) return NULL;
|
||||
|
||||
memcpy(&tmp_longlong, ptr, 8);
|
||||
|
||||
*llv = ntohll(tmp_longlong);
|
||||
return ptr+8;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int amqp_send_ack(int fd, uint64_t delivery_tag) {
|
||||
|
||||
uint32_t size = 4 + 8 + 1;
|
||||
|
||||
size = htonl(size);
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\1", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 60 method 80
|
||||
amqp_send(fd, "\x00\x3C\x00\x50", 4);
|
||||
|
||||
// set delivery_tag
|
||||
delivery_tag = htonll(delivery_tag);
|
||||
amqp_send(fd, &delivery_tag, 8);
|
||||
|
||||
// empty bits
|
||||
amqp_send(fd, "\0", 1);
|
||||
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *uwsgi_amqp_consume(int fd, uint64_t *msgsize, char **routing_key) {
|
||||
|
||||
uint32_t size;
|
||||
struct amqp_frame_header fh;
|
||||
uint64_t delivery_tag;
|
||||
uint64_t current_size = 0;
|
||||
char *ptr;
|
||||
char *watermark;
|
||||
uint16_t sv;
|
||||
|
||||
char *frame = amqp_get_method(fd, 60, 60, &size);
|
||||
if (!frame) return NULL;
|
||||
|
||||
ptr = frame+4;
|
||||
watermark = frame+size;
|
||||
|
||||
// consumer_tag
|
||||
ptr = amqp_get_str(ptr, watermark); if (!ptr) goto clear;
|
||||
// delivery_tag (needed for ack)
|
||||
ptr = amqp_get_longlong(ptr, watermark, &delivery_tag); if (!ptr) goto clear;
|
||||
// redelivered
|
||||
if (ptr+1 > watermark) goto clear;
|
||||
ptr++;
|
||||
// exchange
|
||||
ptr = amqp_get_str(ptr, watermark); if (!ptr) goto clear;
|
||||
// routing_key
|
||||
if (ptr+1 > watermark) goto clear;
|
||||
uint8_t rk_size = (uint8_t) *ptr;
|
||||
ptr++;
|
||||
if (ptr+rk_size > watermark) goto clear;
|
||||
|
||||
if (rk_size > 0) {
|
||||
char *rkey = uwsgi_concat2n(ptr, rk_size, "", 0);
|
||||
ptr+=rk_size;
|
||||
|
||||
*routing_key = rkey;
|
||||
}
|
||||
else {
|
||||
*routing_key = NULL;
|
||||
}
|
||||
|
||||
char *header = amqp_simple_get_frame(fd, &fh);
|
||||
if (!header) goto clear;
|
||||
|
||||
if (fh.type != 2) goto clear2;
|
||||
|
||||
ptr = header;
|
||||
watermark = ptr+fh.size;
|
||||
|
||||
// header class_id
|
||||
ptr = amqp_get_short(ptr, watermark, &sv); if (!ptr) goto clear2;
|
||||
// header weight
|
||||
ptr = amqp_get_short(ptr, watermark, &sv); if (!ptr) goto clear2;
|
||||
// message size;
|
||||
ptr = amqp_get_longlong(ptr, watermark, msgsize); if (!ptr) goto clear2;
|
||||
|
||||
free(frame);
|
||||
free(header);
|
||||
|
||||
char *fullbody = uwsgi_malloc(*msgsize);
|
||||
char *message;
|
||||
|
||||
while(current_size < *msgsize) {
|
||||
message = amqp_simple_get_frame(fd, &fh);
|
||||
if (!message) goto clear;
|
||||
|
||||
if (fh.type != 3) {
|
||||
free(message);
|
||||
goto clear3;
|
||||
}
|
||||
|
||||
if (fh.size+current_size > *msgsize) {
|
||||
free(message);
|
||||
goto clear3;
|
||||
}
|
||||
|
||||
memcpy(fullbody+current_size, message, fh.size);
|
||||
current_size+=fh.size;
|
||||
free(message);
|
||||
}
|
||||
|
||||
if (amqp_send_ack(fd, delivery_tag) < 0) {
|
||||
goto clear3;
|
||||
}
|
||||
|
||||
return fullbody;
|
||||
|
||||
clear3:
|
||||
free(fullbody);
|
||||
return NULL;
|
||||
|
||||
clear2:
|
||||
free(header);
|
||||
clear:
|
||||
free(frame);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
static int amqp_send_exchange_declare( int fd, char *exchange, char *exchange_type) {
|
||||
|
||||
uint32_t size = 4 + 2 + (1 +strlen(exchange)) + (1 +strlen(exchange_type)) + 1 + 4;
|
||||
uint8_t shortsize = strlen(exchange) ;
|
||||
|
||||
size = htonl(size);
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\1", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 40 method 10
|
||||
amqp_send(fd, "\x00\x28\x00\x0A", 4);
|
||||
|
||||
// send empty reserved
|
||||
amqp_send(fd, "\0\0", 2);
|
||||
|
||||
// set exchange name
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, exchange, shortsize);
|
||||
|
||||
// set exchange type
|
||||
shortsize = strlen(exchange_type);
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, exchange_type, shortsize);
|
||||
|
||||
// empty bits
|
||||
amqp_send(fd, "\0", 1);
|
||||
// empty table
|
||||
amqp_send(fd, "\0\0\0\0", 4);
|
||||
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int amqp_send_queue_bind( int fd, char *queue, char *exchange) {
|
||||
|
||||
uint32_t size = 4 + 2 + (1 +strlen(queue)) + (1 +strlen(exchange)) + 1 + 1 + 4;
|
||||
uint8_t shortsize = strlen(queue) ;
|
||||
|
||||
size = htonl(size);
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\1", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 50 method 20
|
||||
amqp_send(fd, "\x00\x32\x00\x14", 4);
|
||||
|
||||
// send empty reserved
|
||||
amqp_send(fd, "\0\0", 2);
|
||||
|
||||
// set queue name
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, queue, shortsize);
|
||||
|
||||
// set exchange name
|
||||
shortsize = strlen(exchange);
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, exchange, shortsize);
|
||||
|
||||
// set empty routing-key
|
||||
amqp_send(fd, "\0", 1);
|
||||
|
||||
// empty bits
|
||||
amqp_send(fd, "\0", 1);
|
||||
// empty table
|
||||
amqp_send(fd, "\0\0\0\0", 4);
|
||||
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int amqp_send_queue_consume( int fd, char *queue) {
|
||||
|
||||
uint32_t size = 4 + 2 + (1 +strlen(queue)) + 1 + 1 + 4;
|
||||
uint8_t shortsize = strlen(queue) ;
|
||||
|
||||
size = htonl(size);
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\1", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 60 method 20
|
||||
amqp_send(fd, "\x00\x3C\x00\x14", 4);
|
||||
|
||||
// send empty reserved
|
||||
amqp_send(fd, "\0\0", 2);
|
||||
|
||||
// set queue name
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, queue, shortsize);
|
||||
|
||||
// set tag name
|
||||
amqp_send(fd, "\0", 1);
|
||||
|
||||
// empty bits
|
||||
amqp_send(fd, "\0", 1);
|
||||
// empty table
|
||||
amqp_send(fd, "\0\0\0\0", 4);
|
||||
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amqp_wait_connection_start(int fd) {
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 10, 10, &size);
|
||||
|
||||
if (frame) {
|
||||
free(frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int amqp_wait_exchange_declare_ok(int fd) {
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 40, 11, &size);
|
||||
|
||||
if (frame) {
|
||||
free(frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int amqp_wait_basic_consume_ok(int fd) {
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 60, 21, &size);
|
||||
|
||||
if (frame) {
|
||||
free(frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int amqp_wait_channel_open_ok(int fd) {
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 20, 11, &size);
|
||||
|
||||
if (frame) {
|
||||
free(frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int amqp_wait_queue_bind_ok(int fd) {
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 50, 21, &size);
|
||||
|
||||
if (frame) {
|
||||
free(frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static char *amqp_wait_queue_declare_ok(int fd) {
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 50, 11, &size);
|
||||
char *queue = NULL;
|
||||
char *ptr;
|
||||
char *watermark;
|
||||
|
||||
if (frame) {
|
||||
|
||||
ptr = frame+4;
|
||||
watermark = frame+size;
|
||||
|
||||
ptr = amqp_get_str(ptr, watermark); if (!ptr) { free(frame); return NULL; }
|
||||
|
||||
queue = uwsgi_concat2n(frame+5, *(frame+4), "", 0);
|
||||
|
||||
free(frame);
|
||||
return queue;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int amqp_wait_connection_open_ok(int fd) {
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 10, 41, &size);
|
||||
|
||||
if (frame) {
|
||||
free(frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int amqp_wait_connection_tune(int fd) {
|
||||
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 10, 30, &size);
|
||||
|
||||
uint16_t sv;
|
||||
uint32_t lv;
|
||||
char *watermark ;
|
||||
char *ptr;
|
||||
|
||||
|
||||
if (frame) {
|
||||
ptr = frame+4;
|
||||
watermark = frame+size;
|
||||
ptr = amqp_get_short(ptr, watermark, &sv); if (!ptr) { free(frame); return -1; }
|
||||
uwsgi_log("AMQP max channels: %d\n", sv);
|
||||
ptr = amqp_get_long(ptr, watermark, &lv); if (!ptr) { free(frame); return -1; }
|
||||
uwsgi_log("AMQP max frame size: %d\n", lv);
|
||||
ptr = amqp_get_short(ptr, watermark, &sv); if (!ptr) { free(frame); return -1; }
|
||||
uwsgi_log("AMQP heartbeath: %d\n", sv);
|
||||
|
||||
free(frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char *amqp_simple_get_frame(int fd, struct amqp_frame_header *fh) {
|
||||
|
||||
char *ptr = (char *) fh;
|
||||
size_t len = 0, rlen;
|
||||
|
||||
while(len < 7) {
|
||||
rlen = recv(fd, ptr, 7-len, 0);
|
||||
if (rlen <= 0) {
|
||||
uwsgi_error("recv()");
|
||||
return NULL;
|
||||
}
|
||||
len += rlen;
|
||||
ptr += rlen;
|
||||
}
|
||||
|
||||
fh->channel = ntohs(fh->channel);
|
||||
fh->size = ntohl(fh->size);
|
||||
|
||||
len = 0;
|
||||
|
||||
char *frame = malloc(fh->size+1);
|
||||
ptr = frame;
|
||||
|
||||
while(len < fh->size+1) {
|
||||
rlen = recv(fd, ptr, (fh->size+1)-len, 0);
|
||||
if (rlen <= 0) {
|
||||
uwsgi_error("recv()");
|
||||
return NULL;
|
||||
}
|
||||
len += rlen;
|
||||
ptr += rlen;
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
static char *amqp_get_method(int fd, uint16_t class_id, uint16_t method_id, uint32_t *size) {
|
||||
|
||||
struct amqp_frame_header fh;
|
||||
struct amqp_frame_method *fm;
|
||||
|
||||
char *frame = amqp_simple_get_frame(fd, &fh);
|
||||
if (!frame) return NULL;
|
||||
|
||||
if (fh.type != 1) goto clear;
|
||||
|
||||
fm = (struct amqp_frame_method *) frame;
|
||||
fm->class_id = ntohs(fm->class_id);
|
||||
fm->method_id = ntohs(fm->method_id);
|
||||
|
||||
if (fm->class_id != class_id) goto clear;
|
||||
if (fm->method_id != method_id) goto clear;
|
||||
|
||||
*size = fh.size;
|
||||
return frame;
|
||||
|
||||
clear:
|
||||
|
||||
free(frame);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int amqp_send_channel_open(int fd, uint16_t id) {
|
||||
|
||||
uint32_t size = 4 + 1;
|
||||
size = htonl(size);
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\1", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 20 method 10
|
||||
amqp_send(fd, "\x00\x14\x00\x0A", 4);
|
||||
|
||||
amqp_send(fd, "\0", 1);
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amqp_send_connection_open(int fd, char *vhost) {
|
||||
|
||||
uint8_t shortsize = strlen(vhost);
|
||||
uint32_t size = 4 + 1 +strlen(vhost) + 2;
|
||||
size = htonl(size);
|
||||
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\0", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 10 method 28
|
||||
amqp_send(fd, "\x00\x0A\x00\x28", 4);
|
||||
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, vhost, strlen(vhost));
|
||||
|
||||
shortsize = 0;
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int amqp_send_connection_tune_ok(int fd, uint16_t max_chan, uint32_t max_frame_size, uint16_t heartbeat) {
|
||||
|
||||
uint32_t size = 4 + 2 + 4 + 2;
|
||||
size = htonl(size);
|
||||
|
||||
max_chan = htons(max_chan);
|
||||
max_frame_size = htonl(max_frame_size);
|
||||
heartbeat = htons(heartbeat);
|
||||
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\0", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 10 method 15
|
||||
amqp_send(fd, "\x00\x0A\x00\x1F", 4);
|
||||
|
||||
amqp_send(fd, &max_chan, 2);
|
||||
amqp_send(fd, &max_frame_size, 4);
|
||||
amqp_send(fd, &heartbeat, 2);
|
||||
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int amqp_send_queue_declare(int fd, char *queue) {
|
||||
|
||||
uint32_t size = 4 + 2 + (1 +strlen(queue)) + 1 + 4;
|
||||
uint8_t shortsize = strlen(queue) ;
|
||||
|
||||
size = htonl(size);
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\1", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 50 method 10
|
||||
amqp_send(fd, "\x00\x32\x00\x0A", 4);
|
||||
|
||||
// send empty reserved
|
||||
amqp_send(fd, "\0\0", 2);
|
||||
|
||||
// set queue name
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, queue, shortsize);
|
||||
|
||||
// empty bits
|
||||
amqp_send(fd, "\0", 1);
|
||||
// empty table
|
||||
amqp_send(fd, "\0\0\0\0", 4);
|
||||
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *amqp_get_queue(int fd, char *queue) {
|
||||
|
||||
if (amqp_send_queue_declare(fd, queue) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return amqp_wait_queue_declare_ok(fd);
|
||||
}
|
||||
|
||||
|
||||
static int amqp_send_connection_start_ok(int fd, char *mech, char *sasl_response, int sasl_response_size, char *locale) {
|
||||
|
||||
uint32_t size = 4 + 4 + (1 +strlen(mech)) + (4 + sasl_response_size) + (1 + strlen(locale));
|
||||
uint8_t shortsize ;
|
||||
|
||||
size = htonl(size);
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\0", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 10 method 11
|
||||
amqp_send(fd, "\x00\x0A\x00\x0B", 4);
|
||||
|
||||
// send empty client properties
|
||||
amqp_send(fd, "\0\0\0\0", 4);
|
||||
|
||||
// send mechanism short string
|
||||
shortsize = strlen(mech);
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, mech, strlen(mech));
|
||||
|
||||
// send sasl response
|
||||
size = htonl(sasl_response_size);
|
||||
amqp_send(fd, &size, 4);
|
||||
amqp_send(fd, sasl_response, sasl_response_size);
|
||||
|
||||
// send locale
|
||||
shortsize = strlen(locale);
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, locale, strlen(locale));
|
||||
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_amqp_consume_queue(int fd, char *vhost, char *username, char *password, char *queue, char *exchange, char *exchange_type) {
|
||||
|
||||
char *auth = uwsgi_concat4n("\0",1, username, strlen(username), "\0",1, password, strlen(password));
|
||||
|
||||
if (send(fd, AMQP_CONNECTION_HEADER, 8, 0) < 0) {
|
||||
uwsgi_error("send()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (amqp_wait_connection_start(fd) < 0) {
|
||||
uwsgi_log("AMQP error waiting for Connection.start\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_log("sending Connection.start-ok\n");
|
||||
if (amqp_send_connection_start_ok(fd, "PLAIN", auth, strlen(username)+strlen(password)+2, "en_US") < 0) {
|
||||
free(auth);
|
||||
uwsgi_log("AMQP error sending Connection.start-ok\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(auth);
|
||||
|
||||
if (amqp_wait_connection_tune(fd) < 0) {
|
||||
uwsgi_log("AMQP error waiting for Connection.tune\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_log("sending Connection.tune-ok\n");
|
||||
if (amqp_send_connection_tune_ok(fd, 0, 0xffff, 0) < 0) {
|
||||
uwsgi_log("AMQP error sending Connection.tune-ok\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_log("sending Connection.open\n");
|
||||
if (amqp_send_connection_open(fd, vhost) < 0) {
|
||||
uwsgi_log("AMQP error sending Connection.open\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (amqp_wait_connection_open_ok(fd) < 0) {
|
||||
uwsgi_log("AMQP error waiting for Connection.open-ok\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_log("sending Channel.open\n");
|
||||
if (amqp_send_channel_open(fd, 1) < 0) {
|
||||
uwsgi_log("AMQP error sending Channel.open\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (amqp_wait_channel_open_ok(fd) < 0) {
|
||||
uwsgi_log("AMQP error waiting for Channel.open-ok\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
queue = amqp_get_queue(fd, queue);
|
||||
if (!queue) {
|
||||
uwsgi_log("AMQP error sending Queue.declare\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (exchange) {
|
||||
if (amqp_send_exchange_declare(fd, exchange, exchange_type) < 0) {
|
||||
uwsgi_log("AMQP error sending Exchange.declare\n");
|
||||
free(queue);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (amqp_wait_exchange_declare_ok(fd) < 0) {
|
||||
uwsgi_log("AMQP error waiting for Exchange.declare-ok\n");
|
||||
free(queue);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (amqp_send_queue_bind(fd, queue, exchange) < 0) {
|
||||
uwsgi_log("AMQP error sending Queue.bind\n");
|
||||
free(queue);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (amqp_wait_queue_bind_ok(fd) < 0) {
|
||||
uwsgi_log("AMQP error waiting for Queue.bind-ok\n");
|
||||
free(queue);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (amqp_send_queue_consume(fd, queue) < 0) {
|
||||
uwsgi_log("AMQP error sending Basic.consume\n");
|
||||
free(queue);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (amqp_wait_basic_consume_ok(fd) < 0) {
|
||||
uwsgi_log("AMQP error waiting for Basic.consume-ok\n");
|
||||
free(queue);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(queue);
|
||||
|
||||
uwsgi_log("AMQP subscription done, waiting for events...\n");
|
||||
return 0;
|
||||
}
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
#include "../uwsgi.h"
|
||||
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#ifndef CLONE_NEWUTS
|
||||
#define CLONE_NEWUTS 0x04000000
|
||||
#endif
|
||||
|
||||
#ifndef CLONE_NEWPID
|
||||
#define CLONE_NEWPID 0x20000000
|
||||
#endif
|
||||
|
||||
#ifndef CLONE_NEWIPC
|
||||
#define CLONE_NEWIPC 0x08000000
|
||||
#endif
|
||||
|
||||
#ifndef CLONE_NEWNET
|
||||
#define CLONE_NEWNET 0x40000000
|
||||
#endif
|
||||
|
||||
void linux_namespace_start(void *argv) {
|
||||
for (;;) {
|
||||
char stack[PTHREAD_STACK_MIN];
|
||||
int waitpid_status;
|
||||
uwsgi_log("*** jailing uWSGI in %s ***\n", uwsgi.ns);
|
||||
int clone_flags = SIGCHLD | CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWIPC | CLONE_NEWNS;
|
||||
if (uwsgi.ns_net) {
|
||||
clone_flags |= CLONE_NEWNET;
|
||||
}
|
||||
pid_t pid = clone(uwsgi_start, stack + PTHREAD_STACK_MIN, clone_flags, (void *) argv);
|
||||
if (pid == -1) {
|
||||
uwsgi_error("clone()");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_log("waiting for jailed master (pid: %d) death...\n", (int) pid);
|
||||
pid = waitpid(pid, &waitpid_status, 0);
|
||||
if (pid < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// in Linux this is reliable
|
||||
if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == 1) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_log("pid %d ended. Respawning...\n", (int) pid);
|
||||
}
|
||||
|
||||
// never here
|
||||
}
|
||||
|
||||
|
||||
|
||||
void linux_namespace_jail() {
|
||||
|
||||
char *ns_tmp_mountpoint = NULL, *ns_tmp_mountpoint2 = NULL;
|
||||
|
||||
if (getpid() != 1) {
|
||||
uwsgi_log("your kernel does not support linux pid namespace\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char *ns_hostname = strchr(uwsgi.ns, ':');
|
||||
if (ns_hostname) {
|
||||
ns_hostname[0] = 0;
|
||||
ns_hostname++;
|
||||
if (sethostname(ns_hostname, strlen(ns_hostname))) {
|
||||
uwsgi_error("sethostname()");
|
||||
}
|
||||
}
|
||||
|
||||
FILE *procmounts;
|
||||
char line[1024];
|
||||
int unmounted = 1;
|
||||
char *delim0, *delim1;
|
||||
|
||||
if (chdir(uwsgi.ns)) {
|
||||
uwsgi_error("chdir()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (strcmp(uwsgi.ns, "/")) {
|
||||
ns_tmp_mountpoint = uwsgi_concat2(uwsgi.ns, "/.uwsgi_ns_tmp_mountpoint");
|
||||
mkdir(ns_tmp_mountpoint, S_IRWXU);
|
||||
|
||||
ns_tmp_mountpoint2 = uwsgi_concat2(ns_tmp_mountpoint, "/.uwsgi_ns_tmp_mountpoint");
|
||||
mkdir(ns_tmp_mountpoint2, S_IRWXU);
|
||||
|
||||
if (mount(uwsgi.ns, ns_tmp_mountpoint, "none", MS_BIND, NULL)) {
|
||||
uwsgi_error("mount()");
|
||||
}
|
||||
if (chdir(ns_tmp_mountpoint)) {
|
||||
uwsgi_error("chdir()");
|
||||
}
|
||||
|
||||
if (pivot_root(".", ns_tmp_mountpoint2)) {
|
||||
uwsgi_error("pivot_root()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (chdir("/")) {
|
||||
uwsgi_error("chdir()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uwsgi_log("remounting /proc\n");
|
||||
if (mount("proc", "/proc", "proc", 0, NULL)) {
|
||||
uwsgi_error("mount()");
|
||||
}
|
||||
|
||||
while (unmounted) {
|
||||
|
||||
unmounted = 0;
|
||||
procmounts = fopen("/proc/self/mounts", "r");
|
||||
while (fgets(line, 1024, procmounts) != NULL) {
|
||||
delim0 = strchr(line, ' ');
|
||||
delim0++;
|
||||
delim1 = strchr(delim0, ' ');
|
||||
*delim1 = 0;
|
||||
if (!strcmp(delim0, "/") || !strcmp(delim0, "/proc"))
|
||||
continue;
|
||||
if (!umount(delim0)) {
|
||||
unmounted++;
|
||||
}
|
||||
}
|
||||
fclose(procmounts);
|
||||
}
|
||||
|
||||
if (rmdir("/.uwsgi_ns_tmp_mountpoint/.uwsgi_ns_tmp_mountpoint")) {
|
||||
uwsgi_error("rmdir()");
|
||||
}
|
||||
if (rmdir("/.uwsgi_ns_tmp_mountpoint")) {
|
||||
uwsgi_error("rmdir()");
|
||||
}
|
||||
|
||||
if (strcmp(uwsgi.ns, "/")) {
|
||||
free(ns_tmp_mountpoint2);
|
||||
free(ns_tmp_mountpoint);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+382
@@ -0,0 +1,382 @@
|
||||
#include "../uwsgi.h"
|
||||
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#ifdef CLONE_NEWNET
|
||||
|
||||
#define NLMSG_TAIL(nmsg) \
|
||||
((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
|
||||
|
||||
#ifndef VETH_INFO_PEER
|
||||
# define VETH_INFO_PEER 1
|
||||
#endif
|
||||
|
||||
|
||||
struct uwsgi_nl_req {
|
||||
struct nlmsghdr nlmsg;
|
||||
struct ifinfomsg ifinfomsg;
|
||||
};
|
||||
|
||||
struct uwsgi_nl_ipreq {
|
||||
struct nlmsghdr nlmsg;
|
||||
struct ifaddrmsg ifaddrmsg;
|
||||
};
|
||||
|
||||
struct uwsgi_nl_rtreq {
|
||||
struct nlmsghdr nlmsg;
|
||||
struct rtmsg rtmsg;
|
||||
};
|
||||
|
||||
int uwsgi_nl_send(struct nlmsghdr *);
|
||||
|
||||
struct nlmsghdr *uwsgi_netlink_alloc() {
|
||||
|
||||
size_t len = NLMSG_ALIGN(8192) + NLMSG_ALIGN(sizeof(struct nlmsghdr *));
|
||||
|
||||
struct nlmsghdr *nlmsg = (struct nlmsghdr *) uwsgi_malloc(len);
|
||||
|
||||
memset(nlmsg, 0, len);
|
||||
|
||||
struct uwsgi_nl_req *unr = (struct uwsgi_nl_req *)nlmsg;
|
||||
unr->ifinfomsg.ifi_family = AF_UNSPEC;
|
||||
|
||||
nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
||||
nlmsg->nlmsg_type = RTM_NEWLINK;
|
||||
nlmsg->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
|
||||
|
||||
return nlmsg;
|
||||
}
|
||||
|
||||
struct nlmsghdr *uwsgi_netlink_ip_alloc() {
|
||||
|
||||
size_t len = NLMSG_ALIGN(8192) + NLMSG_ALIGN(sizeof(struct nlmsghdr *));
|
||||
|
||||
struct nlmsghdr *nlmsg = (struct nlmsghdr *) uwsgi_malloc(len);
|
||||
|
||||
memset(nlmsg, 0, len);
|
||||
|
||||
struct uwsgi_nl_ipreq *uni = (struct uwsgi_nl_ipreq *)nlmsg;
|
||||
uni->ifaddrmsg.ifa_family = AF_INET;
|
||||
uni->ifaddrmsg.ifa_scope = 0;
|
||||
|
||||
nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
|
||||
nlmsg->nlmsg_type = RTM_NEWADDR;
|
||||
nlmsg->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_CREATE|NLM_F_EXCL;
|
||||
|
||||
|
||||
return nlmsg;
|
||||
}
|
||||
|
||||
struct nlmsghdr *uwsgi_netlink_rt_alloc() {
|
||||
|
||||
size_t len = NLMSG_ALIGN(8192) + NLMSG_ALIGN(sizeof(struct nlmsghdr *));
|
||||
|
||||
struct nlmsghdr *nlmsg = (struct nlmsghdr *) uwsgi_malloc(len);
|
||||
|
||||
memset(nlmsg, 0, len);
|
||||
|
||||
struct uwsgi_nl_rtreq *unr = (struct uwsgi_nl_rtreq *)nlmsg;
|
||||
unr->rtmsg.rtm_family = AF_INET;
|
||||
unr->rtmsg.rtm_table = RT_TABLE_MAIN;
|
||||
unr->rtmsg.rtm_protocol = RTPROT_STATIC;
|
||||
unr->rtmsg.rtm_scope = RT_SCOPE_UNIVERSE;
|
||||
unr->rtmsg.rtm_type = RTN_UNICAST;
|
||||
|
||||
|
||||
nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||
nlmsg->nlmsg_type = RTM_NEWROUTE;
|
||||
nlmsg->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_CREATE|NLM_F_EXCL;
|
||||
|
||||
|
||||
return nlmsg;
|
||||
}
|
||||
|
||||
int uwsgi_netlink_rt(char *src, char *dst, int dst_prefix, char *gw) {
|
||||
|
||||
struct nlmsghdr *nlmsg = uwsgi_netlink_rt_alloc();
|
||||
struct rtattr *rta;
|
||||
struct in_addr ia;
|
||||
struct in_addr oa;
|
||||
struct in_addr ga;
|
||||
struct uwsgi_nl_rtreq *unr = (struct uwsgi_nl_rtreq *)nlmsg;
|
||||
|
||||
if (inet_pton(AF_INET, src, &ia) <= 0) {
|
||||
uwsgi_error("inet_pton()");
|
||||
free(nlmsg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (inet_pton(AF_INET, dst, &oa) <= 0) {
|
||||
uwsgi_error("inet_pton()");
|
||||
free(nlmsg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (inet_pton(AF_INET, gw, &ga) <= 0) {
|
||||
uwsgi_error("inet_pton()");
|
||||
free(nlmsg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = RTA_PREFSRC;
|
||||
rta->rta_len = RTA_LENGTH(4);
|
||||
memcpy(RTA_DATA(rta), &ia.s_addr, 4);
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = RTA_DST;
|
||||
rta->rta_len = RTA_LENGTH(4);
|
||||
memcpy(RTA_DATA(rta), &oa.s_addr, 4);
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = RTA_GATEWAY;
|
||||
rta->rta_len = RTA_LENGTH(4);
|
||||
memcpy(RTA_DATA(rta), &ga.s_addr, 4);
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
unr->rtmsg.rtm_src_len = 0;
|
||||
unr->rtmsg.rtm_dst_len = dst_prefix;
|
||||
|
||||
return uwsgi_nl_send(nlmsg);
|
||||
}
|
||||
|
||||
int uwsgi_netlink_gw(char *iface, char *ip) {
|
||||
|
||||
struct nlmsghdr *nlmsg = uwsgi_netlink_rt_alloc();
|
||||
struct rtattr *rta;
|
||||
struct in_addr ia;
|
||||
uint32_t zero = 0;
|
||||
|
||||
int index = if_nametoindex(iface);
|
||||
if (!index) return -1;
|
||||
|
||||
if (inet_pton(AF_INET, ip, &ia) <= 0) {
|
||||
uwsgi_error("inet_pton()");
|
||||
free(nlmsg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = RTA_GATEWAY;
|
||||
rta->rta_len = RTA_LENGTH(4);
|
||||
memcpy(RTA_DATA(rta), &ia.s_addr, 4);
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = RTA_DST;
|
||||
rta->rta_len = RTA_LENGTH(4);
|
||||
memcpy(RTA_DATA(rta), &zero, 4);
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = RTA_OIF;
|
||||
rta->rta_len = RTA_LENGTH(sizeof(int));
|
||||
memcpy(RTA_DATA(rta), &index, sizeof(int));
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
return uwsgi_nl_send(nlmsg);
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_netlink_ip(char *iface, char *ip, int prefix) {
|
||||
|
||||
struct nlmsghdr *nlmsg = uwsgi_netlink_ip_alloc();
|
||||
struct uwsgi_nl_ipreq *uni = (struct uwsgi_nl_ipreq *)nlmsg;
|
||||
struct rtattr *rta;
|
||||
struct in_addr ia;
|
||||
|
||||
int index = if_nametoindex(iface);
|
||||
if (!index) return -1;
|
||||
|
||||
uni->ifaddrmsg.ifa_index = index;
|
||||
uni->ifaddrmsg.ifa_prefixlen = prefix;
|
||||
|
||||
if (inet_pton(AF_INET, ip, &ia) <= 0) {
|
||||
uwsgi_error("inet_pton()");
|
||||
free(nlmsg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = IFA_LOCAL;
|
||||
rta->rta_len = RTA_LENGTH(sizeof(struct in_addr));
|
||||
memcpy(RTA_DATA(rta), &ia, sizeof(struct in_addr));
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = IFA_ADDRESS;
|
||||
rta->rta_len = RTA_LENGTH(sizeof(struct in_addr));
|
||||
memcpy(RTA_DATA(rta), &ia, sizeof(struct in_addr));
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
return uwsgi_nl_send(nlmsg);
|
||||
}
|
||||
|
||||
int uwsgi_netlink_veth_attach(char *veth1, pid_t pid) {
|
||||
|
||||
struct nlmsghdr *nlmsg = uwsgi_netlink_alloc();
|
||||
struct uwsgi_nl_req *unr = (struct uwsgi_nl_req *)nlmsg;
|
||||
struct rtattr *rta;
|
||||
|
||||
int index = if_nametoindex(veth1);
|
||||
if (!index) return -1;
|
||||
|
||||
unr->ifinfomsg.ifi_index = index;
|
||||
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = IFLA_NET_NS_PID;
|
||||
rta->rta_len = RTA_LENGTH(sizeof(pid_t));
|
||||
memcpy(RTA_DATA(rta), &pid, sizeof(pid_t));
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
return uwsgi_nl_send(nlmsg);
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_netlink_ifup(char *iface) {
|
||||
|
||||
struct nlmsghdr *nlmsg = uwsgi_netlink_alloc();
|
||||
struct uwsgi_nl_req *unr = (struct uwsgi_nl_req *)nlmsg;
|
||||
|
||||
int index = if_nametoindex(iface);
|
||||
if (!index) return -1;
|
||||
|
||||
unr->ifinfomsg.ifi_index = index;
|
||||
unr->ifinfomsg.ifi_change |= IFF_UP;
|
||||
unr->ifinfomsg.ifi_flags |= IFF_UP;
|
||||
return uwsgi_nl_send(nlmsg);
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_netlink_del(char *iface) {
|
||||
|
||||
struct nlmsghdr *nlmsg = uwsgi_netlink_alloc();
|
||||
struct uwsgi_nl_req *unr = (struct uwsgi_nl_req *)nlmsg;
|
||||
|
||||
int index = if_nametoindex(iface);
|
||||
if (!index) return -1;
|
||||
|
||||
nlmsg->nlmsg_type = RTM_DELLINK;
|
||||
unr->ifinfomsg.ifi_index = index;
|
||||
return uwsgi_nl_send(nlmsg);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int uwsgi_netlink_veth(char *veth0, char *veth1) {
|
||||
|
||||
struct rtattr *rta, *rta0, *rta1, *rta2;
|
||||
|
||||
struct nlmsghdr *nlmsg = uwsgi_netlink_alloc();
|
||||
|
||||
nlmsg->nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
|
||||
|
||||
// IFLA_LINKINFO
|
||||
rta0 = NLMSG_TAIL(nlmsg);
|
||||
rta0->rta_type = IFLA_LINKINFO;
|
||||
rta0->rta_len = RTA_LENGTH(0);
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta0->rta_len);
|
||||
|
||||
// IFLA_INFO_KIND
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = IFLA_INFO_KIND;
|
||||
rta->rta_len = RTA_LENGTH(4);
|
||||
memcpy(RTA_DATA(rta), "veth", 4);
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
// IFLA_INFO_DATA
|
||||
rta1 = NLMSG_TAIL(nlmsg);
|
||||
rta1->rta_type = IFLA_INFO_DATA;
|
||||
rta1->rta_len = RTA_LENGTH(0);
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta1->rta_len);
|
||||
|
||||
// VETH_INFO_PEER
|
||||
rta2 = NLMSG_TAIL(nlmsg);
|
||||
rta2->rta_type = VETH_INFO_PEER;
|
||||
rta2->rta_len = RTA_LENGTH(0);
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta2->rta_len);
|
||||
|
||||
nlmsg->nlmsg_len += sizeof(struct ifinfomsg);
|
||||
|
||||
// IFLA_IFNAME
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = IFLA_IFNAME;
|
||||
rta->rta_len = RTA_LENGTH(strlen(veth1));
|
||||
memcpy(RTA_DATA(rta), veth1, strlen(veth1));
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
rta2->rta_len = (void *)NLMSG_TAIL(nlmsg) - (void *)rta2;
|
||||
rta1->rta_len = (void *)NLMSG_TAIL(nlmsg) - (void *)rta1;
|
||||
rta0->rta_len = (void *)NLMSG_TAIL(nlmsg) - (void *)rta0;
|
||||
|
||||
// IFLA_IFNAME
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = IFLA_IFNAME;
|
||||
rta->rta_len = RTA_LENGTH(strlen(veth0));
|
||||
memcpy(RTA_DATA(rta), veth0, strlen(veth0));
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
return uwsgi_nl_send(nlmsg);
|
||||
}
|
||||
|
||||
int uwsgi_nl_send(struct nlmsghdr *nlmsg) {
|
||||
|
||||
struct sockaddr_nl nladdr;
|
||||
|
||||
struct iovec iov = {
|
||||
.iov_base = (void*)nlmsg,
|
||||
.iov_len = nlmsg->nlmsg_len,
|
||||
};
|
||||
|
||||
struct msghdr msg = {
|
||||
.msg_name = &nladdr,
|
||||
.msg_namelen = sizeof(nladdr),
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
int ret;
|
||||
int nlfd;
|
||||
|
||||
memset(&nladdr, 0, sizeof(struct sockaddr_nl));
|
||||
nladdr.nl_family = AF_NETLINK;
|
||||
nladdr.nl_pid = 0;
|
||||
nladdr.nl_groups = 0;
|
||||
|
||||
nlfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
if (nlfd < 0) {
|
||||
uwsgi_error("socket()");
|
||||
free(nlmsg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = sendmsg(nlfd, &msg, 0);
|
||||
if (ret < 0) {
|
||||
uwsgi_error("sendmsg()");
|
||||
free(nlmsg);
|
||||
close(nlfd);
|
||||
return -1;
|
||||
}
|
||||
ret = recvmsg(nlfd, &msg, 0);
|
||||
if (ret < 0) {
|
||||
uwsgi_error("recvmsg()");
|
||||
free(nlmsg);
|
||||
close(nlfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (nlmsg->nlmsg_type == NLMSG_ERROR) {
|
||||
struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(nlmsg);
|
||||
ret = err->error;
|
||||
}
|
||||
|
||||
free(nlmsg);
|
||||
close(nlfd);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
@@ -25,6 +25,16 @@
|
||||
|
||||
#include "../uwsgi.h"
|
||||
|
||||
static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
|
||||
{
|
||||
rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
|
||||
}
|
||||
static inline void rb_set_color(struct rb_node *rb, int color)
|
||||
{
|
||||
rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
|
||||
}
|
||||
|
||||
|
||||
static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
|
||||
{
|
||||
struct rb_node *right = node->rb_right;
|
||||
@@ -282,3 +292,18 @@ void rb_erase(struct rb_node *node, struct rb_root *root)
|
||||
if (color == RB_BLACK)
|
||||
__rb_erase_color(child, parent, root);
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
void rb_link_node(struct rb_node * node, struct rb_node * parent,
|
||||
struct rb_node ** rb_link)
|
||||
#else
|
||||
inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
|
||||
struct rb_node ** rb_link)
|
||||
#endif
|
||||
{
|
||||
node->rb_parent_color = (unsigned long )parent;
|
||||
node->rb_left = node->rb_right = NULL;
|
||||
|
||||
*rb_link = node;
|
||||
}
|
||||
|
||||
|
||||
+7
-19
@@ -37,7 +37,6 @@ struct rb_root
|
||||
struct rb_node *rb_node;
|
||||
};
|
||||
|
||||
|
||||
#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3))
|
||||
#define rb_color(r) ((r)->rb_parent_color & 1)
|
||||
#define rb_is_red(r) (!rb_color(r))
|
||||
@@ -45,24 +44,13 @@ struct rb_root
|
||||
#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0)
|
||||
#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0)
|
||||
|
||||
static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
|
||||
{
|
||||
rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
|
||||
}
|
||||
static inline void rb_set_color(struct rb_node *rb, int color)
|
||||
{
|
||||
rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
|
||||
}
|
||||
|
||||
void rb_insert_color(struct rb_node *, struct rb_root *);
|
||||
void rb_erase(struct rb_node *, struct rb_root *);
|
||||
|
||||
static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
|
||||
struct rb_node ** rb_link)
|
||||
{
|
||||
node->rb_parent_color = (unsigned long )parent;
|
||||
node->rb_left = node->rb_right = NULL;
|
||||
|
||||
*rb_link = node;
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
void rb_link_node(struct rb_node *, struct rb_node *,
|
||||
struct rb_node **);
|
||||
#else
|
||||
inline void rb_link_node(struct rb_node *, struct rb_node *,
|
||||
struct rb_node **);
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/* function written by Ben Taylor (found in the qemu-devel list) */
|
||||
|
||||
#include "../uwsgi.h"
|
||||
|
||||
time_t timegm(struct tm *t) {
|
||||
time_t tl, tb;
|
||||
struct tm *tg;
|
||||
|
||||
tl = mktime (t);
|
||||
if (tl == -1) {
|
||||
t->tm_hour--;
|
||||
tl = mktime (t);
|
||||
if (tl == -1)
|
||||
return -1; /* can't deal with output from strptime */
|
||||
|
||||
tl += 3600;
|
||||
}
|
||||
tg = gmtime (&tl);
|
||||
tg->tm_isdst = 0;
|
||||
tb = mktime (tg);
|
||||
if (tb == -1) {
|
||||
tg->tm_hour--;
|
||||
tb = mktime (tg);
|
||||
if (tb == -1)
|
||||
return -1; /* can't deal with output from gmtime */
|
||||
tb += 3600;
|
||||
}
|
||||
return (tl - (tb - tl));
|
||||
}
|
||||
@@ -134,21 +134,17 @@ void uwsgi_rwunlock(void *lock) { uwsgi_unlock(lock); }
|
||||
#define UWSGI_LOCK_SIZE 8
|
||||
#define UWSGI_RWLOCK_SIZE 8
|
||||
|
||||
static int lock_counter = 0;
|
||||
|
||||
void uwsgi_lock_init(void *lock) {
|
||||
|
||||
char filename[17];
|
||||
FILE *tf = tmpfile();
|
||||
int fd;
|
||||
|
||||
if (snprintf(filename, 17, ".uwsgiflock%d", lock_counter) < 0) {
|
||||
uwsgi_log("unable to create lock %d\n", lock_counter);
|
||||
}
|
||||
|
||||
int fd = open(filename, O_CREAT|O_RDWR|O_TRUNC);
|
||||
if (fd < 0) {
|
||||
uwsgi_error_open(filename);
|
||||
if (!tf) {
|
||||
uwsgi_error_open("temp lock file");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fd = fileno(tf);
|
||||
|
||||
memcpy(lock, &fd, sizeof(int));
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ void log_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
struct uwsgi_app *wi;
|
||||
|
||||
if (wsgi_req->do_not_log) return ;
|
||||
|
||||
if (wsgi_req->app_id >= 0) {
|
||||
wi = &uwsgi.apps[wsgi_req->app_id];
|
||||
if (wi->requests > 0) {
|
||||
@@ -169,7 +171,13 @@ void get_memusage() {
|
||||
kvm_t *kv;
|
||||
int cnt;
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
kv = kvm_open(NULL, "/dev/null", NULL, O_RDONLY, NULL);
|
||||
#elif defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
kv = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, NULL);
|
||||
#else
|
||||
kv = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);
|
||||
#endif
|
||||
if (kv) {
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
|
||||
|
||||
@@ -2,12 +2,16 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct wsgi_request* threaded_current_wsgi_req() { return pthread_getspecific(uwsgi.tur_key); }
|
||||
struct wsgi_request* simple_current_wsgi_req() { return uwsgi.wsgi_req; }
|
||||
struct wsgi_request *threaded_current_wsgi_req() {
|
||||
return pthread_getspecific(uwsgi.tur_key);
|
||||
}
|
||||
struct wsgi_request *simple_current_wsgi_req() {
|
||||
return uwsgi.wsgi_req;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_register_loop(char *name, void *loop) {
|
||||
|
||||
|
||||
if (uwsgi.loops_cnt >= MAX_LOOPS) {
|
||||
uwsgi_log("you can define %d loops at max\n", MAX_LOOPS);
|
||||
exit(1);
|
||||
@@ -21,8 +25,8 @@ void uwsgi_register_loop(char *name, void *loop) {
|
||||
void *uwsgi_get_loop(char *name) {
|
||||
|
||||
int i;
|
||||
|
||||
for(i=0;i<uwsgi.loops_cnt;i++) {
|
||||
|
||||
for (i = 0; i < uwsgi.loops_cnt; i++) {
|
||||
if (!strcmp(name, uwsgi.loops[i].name)) {
|
||||
return uwsgi.loops[i].loop;
|
||||
}
|
||||
@@ -44,46 +48,167 @@ void *simple_loop(void *arg1) {
|
||||
|
||||
if (uwsgi.threads > 1) {
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &i);
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &i);
|
||||
pthread_setspecific(uwsgi.tur_key, (void *) wsgi_req);
|
||||
|
||||
if (core_id > 0) {
|
||||
// block all signals on new threads
|
||||
sigfillset(&smask);
|
||||
pthread_sigmask(SIG_BLOCK, &smask, NULL);
|
||||
for(i=0;i<0xFF;i++) {
|
||||
for (i = 0; i < 0xFF; i++) {
|
||||
if (uwsgi.p[i]->init_thread) {
|
||||
uwsgi.p[i]->init_thread(core_id);
|
||||
}
|
||||
}
|
||||
/*
|
||||
pts = PyThreadState_New(uwsgi.main_thread->interp);
|
||||
pthread_setspecific(uwsgi.ut_save_key, (void *) pts);
|
||||
*/
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// initialize the main event queue to monitor sockets
|
||||
int main_queue = event_queue_init();
|
||||
|
||||
uwsgi_add_sockets_to_queue(main_queue);
|
||||
|
||||
if (uwsgi.signal_socket > -1) {
|
||||
event_queue_add_fd_read(main_queue, uwsgi.signal_socket);
|
||||
}
|
||||
|
||||
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
|
||||
|
||||
wsgi_req_setup(wsgi_req, core_id, NULL);
|
||||
|
||||
UWSGI_CLEAR_STATUS;
|
||||
|
||||
|
||||
wsgi_req_setup(wsgi_req, core_id);
|
||||
|
||||
if (wsgi_req_accept(wsgi_req)) {
|
||||
if (wsgi_req_accept(main_queue, wsgi_req)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (wsgi_req_recv(wsgi_req)) {
|
||||
uwsgi_destroy_request(wsgi_req);
|
||||
continue;
|
||||
}
|
||||
|
||||
uwsgi_close_request(wsgi_req);
|
||||
}
|
||||
|
||||
pthread_exit(NULL);
|
||||
|
||||
//never here
|
||||
// end of the loop
|
||||
if (uwsgi.workers[uwsgi.mywid].destroy && uwsgi.workers[0].pid > 0) {
|
||||
#ifdef __APPLE__
|
||||
kill(uwsgi.workers[0].pid, SIGTERM);
|
||||
#else
|
||||
if (uwsgi.propagate_touch) {
|
||||
kill(uwsgi.workers[0].pid, SIGHUP);
|
||||
}
|
||||
else {
|
||||
gracefully_kill(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
void *zeromq_loop(void *arg1) {
|
||||
sigset_t smask;
|
||||
int i;
|
||||
|
||||
long core_id = (long) arg1;
|
||||
|
||||
struct wsgi_request *wsgi_req = uwsgi.wsgi_requests[core_id];
|
||||
uwsgi.zeromq_recv_flag = 0;
|
||||
zmq_pollitem_t zmq_poll_items[2];
|
||||
char uwsgi_signal;
|
||||
|
||||
if (uwsgi.threads > 1) {
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &i);
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &i);
|
||||
pthread_setspecific(uwsgi.tur_key, (void *) wsgi_req);
|
||||
|
||||
if (core_id > 0) {
|
||||
// block all signals on new threads
|
||||
sigfillset(&smask);
|
||||
pthread_sigmask(SIG_BLOCK, &smask, NULL);
|
||||
for (i = 0; i < 0xFF; i++) {
|
||||
if (uwsgi.p[i]->init_thread) {
|
||||
uwsgi.p[i]->init_thread(core_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void *tmp_zmq_pull = zmq_socket(uwsgi.zmq_context, ZMQ_PULL);
|
||||
if (tmp_zmq_pull == NULL) {
|
||||
uwsgi_error("zmq_socket()");
|
||||
exit(1);
|
||||
}
|
||||
if (zmq_connect(tmp_zmq_pull, uwsgi.zmq_receiver) < 0) {
|
||||
uwsgi_error("zmq_connect()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pthread_setspecific(uwsgi.zmq_pull, tmp_zmq_pull);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (uwsgi.signal_socket > -1) {
|
||||
zmq_poll_items[0].socket = pthread_getspecific(uwsgi.zmq_pull);
|
||||
zmq_poll_items[0].fd = -1;
|
||||
zmq_poll_items[0].events = ZMQ_POLLIN;
|
||||
|
||||
zmq_poll_items[1].socket = NULL;
|
||||
zmq_poll_items[1].fd = uwsgi.signal_socket;
|
||||
zmq_poll_items[1].events = ZMQ_POLLIN;
|
||||
}
|
||||
|
||||
|
||||
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
|
||||
|
||||
wsgi_req_setup(wsgi_req, core_id, NULL);
|
||||
|
||||
uwsgi.edge_triggered = 1;
|
||||
wsgi_req->socket = uwsgi.zmq_socket;
|
||||
|
||||
|
||||
if (uwsgi.signal_socket > -1) {
|
||||
if (zmq_poll(zmq_poll_items, 2, -1) < 0) {
|
||||
uwsgi_error("zmq_poll()");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (zmq_poll_items[1].revents & ZMQ_POLLIN) {
|
||||
if (read(uwsgi.signal_socket, &uwsgi_signal, 1) <= 0) {
|
||||
if (uwsgi.no_orphans) {
|
||||
uwsgi_log_verbose("uWSGI worker %d screams: UAAAAAAH my master died, i will follow him...\n", uwsgi.mywid);
|
||||
end_me(0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log_verbose("master sent signal %d to worker %d\n", uwsgi_signal, uwsgi.mywid);
|
||||
if (uwsgi_signal_handler(uwsgi_signal)) {
|
||||
uwsgi_log_verbose("error managing signal %d on worker %d\n", uwsgi_signal, uwsgi.mywid);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (zmq_poll_items[0].revents & ZMQ_POLLIN) {
|
||||
wsgi_req->poll.fd = wsgi_req->socket->proto_accept(wsgi_req, uwsgi.zmq_socket->fd);
|
||||
}
|
||||
}
|
||||
else {
|
||||
wsgi_req->poll.fd = wsgi_req->socket->proto_accept(wsgi_req, uwsgi.zmq_socket->fd);
|
||||
}
|
||||
|
||||
if (wsgi_req->poll.fd >= 0) {
|
||||
wsgi_req_recv(wsgi_req);
|
||||
}
|
||||
|
||||
uwsgi_close_request(wsgi_req);
|
||||
}
|
||||
|
||||
|
||||
// end of the loop
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2,6 +2,17 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_restore_auto_snapshot(int signum) {
|
||||
|
||||
if (uwsgi.workers[1].snapshot > 0) {
|
||||
uwsgi.restore_snapshot = 1;
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[WARNING] no snapshot available\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void expire_rb_timeouts(struct rb_root *root) {
|
||||
|
||||
time_t current = time(NULL);
|
||||
@@ -31,31 +42,24 @@ void expire_rb_timeouts(struct rb_root *root) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_subscribe(char *subscription) {
|
||||
|
||||
void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, char *modifier1, size_t modifier1_len) {
|
||||
char *ssb;
|
||||
char subscrbuf[4096];
|
||||
|
||||
uint16_t ustrlen;
|
||||
|
||||
char *udp_address = strchr(subscription,':');
|
||||
if (!udp_address) return;
|
||||
ssb = subscrbuf;
|
||||
|
||||
char *subscription_key = strchr(udp_address+1, ':');
|
||||
udp_address = uwsgi_concat2n(subscription, subscription_key-subscription, "", 0);
|
||||
|
||||
ssb = subscrbuf;
|
||||
|
||||
ustrlen = 3;
|
||||
ustrlen = 3;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >>8) & 0xff);
|
||||
memcpy(ssb, "key", ustrlen);
|
||||
ssb+=ustrlen;
|
||||
|
||||
ustrlen = strlen(subscription_key+1);
|
||||
ustrlen = keysize;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >>8) & 0xff);
|
||||
memcpy(ssb, subscription_key+1, ustrlen);
|
||||
memcpy(ssb, key, ustrlen);
|
||||
ssb+=ustrlen;
|
||||
|
||||
ustrlen = 7;
|
||||
@@ -64,14 +68,112 @@ void uwsgi_subscribe(char *subscription) {
|
||||
memcpy(ssb, "address", ustrlen);
|
||||
ssb+=ustrlen;
|
||||
|
||||
ustrlen = strlen(uwsgi.sockets[0].name);
|
||||
ustrlen = strlen(uwsgi.sockets->name);
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >>8) & 0xff);
|
||||
memcpy(ssb, uwsgi.sockets[0].name, ustrlen);
|
||||
memcpy(ssb, uwsgi.sockets->name, ustrlen);
|
||||
ssb+=ustrlen;
|
||||
|
||||
if (modifier1) {
|
||||
ustrlen = 9;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >>8) & 0xff);
|
||||
memcpy(ssb, "modifier1", ustrlen);
|
||||
ssb+=ustrlen;
|
||||
|
||||
ustrlen = modifier1_len;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >>8) & 0xff);
|
||||
memcpy(ssb, modifier1, ustrlen);
|
||||
ssb+=ustrlen;
|
||||
}
|
||||
|
||||
send_udp_message(224, udp_address, subscrbuf, ssb-subscrbuf);
|
||||
free(udp_address);
|
||||
}
|
||||
|
||||
void uwsgi_subscribe(char *subscription) {
|
||||
|
||||
int subfile_size;
|
||||
int i;
|
||||
char *key = NULL;
|
||||
int keysize = 0;
|
||||
char *modifier1 = NULL;
|
||||
int modifier1_len = 0;
|
||||
|
||||
char *udp_address = strchr(subscription,':');
|
||||
if (!udp_address) return;
|
||||
|
||||
char *subscription_key = strchr(udp_address+1, ':');
|
||||
if (!subscription_key) return;
|
||||
|
||||
udp_address = uwsgi_concat2n(subscription, subscription_key-subscription, "", 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, modifier1, modifier1_len);
|
||||
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, modifier1, modifier1_len);
|
||||
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++;
|
||||
modifier1_len = strlen(modifier1);
|
||||
}
|
||||
|
||||
uwsgi_send_subscription(udp_address, subscription_key+1, strlen(subscription_key+1), modifier1, modifier1_len);
|
||||
if (modifier1)
|
||||
modifier1[-1] = ':';
|
||||
}
|
||||
|
||||
clear:
|
||||
|
||||
free(udp_address);
|
||||
|
||||
}
|
||||
|
||||
@@ -84,8 +186,11 @@ void get_linux_tcp_info(int fd) {
|
||||
if (!uwsgi.shared->ti.tcpi_sacked) {
|
||||
return;
|
||||
}
|
||||
|
||||
uwsgi.shared->options[UWSGI_OPTION_BACKLOG_STATUS] = uwsgi.shared->ti.tcpi_unacked;
|
||||
if (uwsgi.shared->ti.tcpi_unacked >= uwsgi.shared->ti.tcpi_sacked) {
|
||||
uwsgi_log_verbose("*** uWSGI listen queue of socket %d full !!! (%d/%d) ***\n", fd, uwsgi.shared->ti.tcpi_unacked, uwsgi.shared->ti.tcpi_sacked);
|
||||
uwsgi.shared->options[UWSGI_OPTION_BACKLOG_ERRORS]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,7 +200,10 @@ void manage_cluster_announce(char *key, uint16_t keylen, char *val, uint16_t val
|
||||
|
||||
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));
|
||||
@@ -120,24 +228,19 @@ void manage_cluster_announce(char *key, uint16_t keylen, char *val, uint16_t val
|
||||
|
||||
void master_loop(char **argv, char **environ) {
|
||||
|
||||
uint64_t master_cycles = 0;
|
||||
uint64_t tmp_counter;
|
||||
|
||||
char log_buf[4096];
|
||||
|
||||
time_t current_time = time(NULL);
|
||||
|
||||
struct timeval last_respawn;
|
||||
int last_respawn_rate = 0;
|
||||
|
||||
pid_t pid;
|
||||
int pid_found = 0;
|
||||
|
||||
pid_t diedpid;
|
||||
int waitpid_status;
|
||||
|
||||
int working_workers = 0;
|
||||
int blocking_workers = 0;
|
||||
|
||||
int ready_to_reload = 0;
|
||||
int ready_to_die = 0;
|
||||
|
||||
@@ -145,6 +248,9 @@ void master_loop(char **argv, char **environ) {
|
||||
|
||||
uint8_t uwsgi_signal;
|
||||
|
||||
time_t last_request_timecheck = 0;
|
||||
uint64_t last_request_count = 0;
|
||||
|
||||
#ifdef UWSGI_UDP
|
||||
struct sockaddr_in udp_client;
|
||||
socklen_t udp_len;
|
||||
@@ -167,22 +273,30 @@ void master_loop(char **argv, char **environ) {
|
||||
int snmp_fd = -1;
|
||||
#endif
|
||||
|
||||
int i=0,j;
|
||||
int i=0;
|
||||
int rlen;
|
||||
|
||||
int check_interval = 1;
|
||||
|
||||
struct uwsgi_rb_timer *min_timeout;
|
||||
struct rb_root *rb_timers = uwsgi_init_rb_timer();
|
||||
struct tm *uwsgi_cron_delta;
|
||||
|
||||
uwsgi.current_time = time(NULL);
|
||||
|
||||
uwsgi_unix_signal(SIGHUP, grace_them_all);
|
||||
uwsgi_unix_signal(SIGTERM, reap_them_all);
|
||||
if (uwsgi.die_on_term) {
|
||||
uwsgi_unix_signal(SIGTERM, kill_them_all);
|
||||
uwsgi_unix_signal(SIGQUIT, reap_them_all);
|
||||
}
|
||||
else {
|
||||
uwsgi_unix_signal(SIGTERM, reap_them_all);
|
||||
uwsgi_unix_signal(SIGQUIT, kill_them_all);
|
||||
}
|
||||
uwsgi_unix_signal(SIGINT, kill_them_all);
|
||||
uwsgi_unix_signal(SIGQUIT, kill_them_all);
|
||||
uwsgi_unix_signal(SIGUSR1, stats);
|
||||
|
||||
if (uwsgi.auto_snapshot) {
|
||||
uwsgi_unix_signal(SIGURG, uwsgi_restore_auto_snapshot);
|
||||
}
|
||||
|
||||
uwsgi.master_queue = event_queue_init();
|
||||
|
||||
@@ -205,6 +319,12 @@ void master_loop(char **argv, char **environ) {
|
||||
if (uwsgi.has_emperor) {
|
||||
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.emperor_fd);
|
||||
}
|
||||
|
||||
if (uwsgi.zerg_server) {
|
||||
uwsgi.zerg_server_fd = bind_to_unix(uwsgi.zerg_server, uwsgi.listen_queue, 0, 0);
|
||||
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.zerg_server_fd);
|
||||
uwsgi_log("*** Zerg server enabled on %s ***\n", uwsgi.zerg_server);
|
||||
}
|
||||
#ifdef UWSGI_UDP
|
||||
if (uwsgi.udp_socket) {
|
||||
udp_fd = bind_to_udp(uwsgi.udp_socket, 0, 0);
|
||||
@@ -216,6 +336,12 @@ void master_loop(char **argv, char **environ) {
|
||||
event_queue_add_fd_read(uwsgi.master_queue, udp_fd);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.cheap) {
|
||||
uwsgi_add_sockets_to_queue(uwsgi.master_queue);
|
||||
uwsgi_log("cheap mode enabled: waiting for socket connection...\n");
|
||||
}
|
||||
|
||||
#ifdef UWSGI_MULTICAST
|
||||
if (uwsgi.cluster) {
|
||||
|
||||
@@ -337,6 +463,24 @@ void master_loop(char **argv, char **environ) {
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.queue_store && uwsgi.queue_filesize) {
|
||||
if (msync(uwsgi.queue, uwsgi.queue_filesize, MS_ASYNC)) {
|
||||
uwsgi_error("msync()");
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.touch_reload) {
|
||||
struct stat tr_st;
|
||||
if (stat(uwsgi.touch_reload, &tr_st)) {
|
||||
uwsgi_error("stat()");
|
||||
uwsgi_log("unable to stat() %s, touch-reload will be disabled\n", uwsgi.touch_reload);
|
||||
uwsgi.touch_reload = NULL;
|
||||
}
|
||||
else {
|
||||
uwsgi.last_touch_reload_mtime = tr_st.st_mtime;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
//uwsgi_log("ready_to_reload %d %d\n", ready_to_reload, uwsgi.numproc);
|
||||
|
||||
@@ -360,49 +504,74 @@ void master_loop(char **argv, char **environ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ready_to_die >= uwsgi.numproc && uwsgi.to_hell) {
|
||||
#ifdef UWSGI_SPOOLER
|
||||
if (uwsgi.spool_dir && uwsgi.shared->spooler_pid > 0) {
|
||||
kill(uwsgi.shared->spooler_pid, SIGKILL);
|
||||
uwsgi_log( "killed the spooler with pid %d\n", uwsgi.shared->spooler_pid);
|
||||
if (uwsgi.respawn_workers) {
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
if (uwsgi_respawn_worker(i)) return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// TODO kill all the gateways
|
||||
uwsgi_log( "goodbye to uWSGI.\n");
|
||||
exit(0);
|
||||
uwsgi.respawn_workers = 0;
|
||||
}
|
||||
if (ready_to_reload >= uwsgi.numproc && uwsgi.to_heaven) {
|
||||
#ifdef UWSGI_SPOOLER
|
||||
if (uwsgi.spool_dir && uwsgi.shared->spooler_pid > 0) {
|
||||
kill(uwsgi.shared->spooler_pid, SIGKILL);
|
||||
uwsgi_log( "wait4() the spooler with pid %d...", uwsgi.shared->spooler_pid);
|
||||
diedpid = waitpid(uwsgi.shared->spooler_pid, &waitpid_status, 0);
|
||||
uwsgi_log( "done.");
|
||||
if (uwsgi.restore_snapshot) {
|
||||
uwsgi_log("[snapshot] restoring workers...\n");
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
if (uwsgi.workers[i].pid == 0) continue;
|
||||
kill(uwsgi.workers[i].pid, SIGKILL);
|
||||
if (waitpid(uwsgi.workers[i].pid, &waitpid_status, 0) < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
}
|
||||
if (uwsgi.auto_snapshot > 0 && i > uwsgi.auto_snapshot) {
|
||||
uwsgi.workers[i].pid = 0;
|
||||
uwsgi.workers[i].snapshot = 0;
|
||||
}
|
||||
else {
|
||||
uwsgi.workers[i].pid = uwsgi.workers[i].snapshot;
|
||||
uwsgi.workers[i].snapshot = 0;
|
||||
kill(uwsgi.workers[i].pid, SIGURG);
|
||||
uwsgi_log( "Restored uWSGI worker %d (pid: %d)\n", i, (int) uwsgi.workers[i].pid);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
uwsgi.restore_snapshot = 0;
|
||||
continue;
|
||||
}
|
||||
if ((uwsgi.cheap || ready_to_die >= uwsgi.numproc) && uwsgi.to_hell) {
|
||||
// call a series of waitpid to ensure all processes (gateways and daemons) are dead
|
||||
for(i=0;i<(uwsgi.gateways_cnt+ushared->daemons_cnt);i++) {
|
||||
diedpid = waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
|
||||
}
|
||||
|
||||
uwsgi_log( "goodbye to uWSGI.\n");
|
||||
exit(0);
|
||||
}
|
||||
if ( (uwsgi.cheap || ready_to_reload >= uwsgi.numproc) && uwsgi.to_heaven) {
|
||||
// call a series of waitpid to ensure all processes (gateways and daemons) are dead
|
||||
for(i=0;i<(uwsgi.gateways_cnt+ushared->daemons_cnt);i++) {
|
||||
diedpid = waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
|
||||
}
|
||||
|
||||
if (uwsgi.exit_on_reload) {
|
||||
uwsgi_log("uWSGI: GAME OVER (insert coin)\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
uwsgi_log( "binary reloading uWSGI...\n");
|
||||
if (chdir(uwsgi.cwd)) {
|
||||
uwsgi_error("chdir()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* check fd table (a module can obviosly open some fd on initialization...) */
|
||||
uwsgi_log( "closing all non-uwsgi socket fds > 2 (_SC_OPEN_MAX = %ld)...\n", sysconf(_SC_OPEN_MAX));
|
||||
for (i = 3; i < sysconf(_SC_OPEN_MAX); i++) {
|
||||
int found = 0;
|
||||
for(j=0;j<uwsgi.sockets_cnt;j++) {
|
||||
if (i == uwsgi.sockets[j].fd) {
|
||||
uwsgi_log("found fd %d\n", i);
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
while(uwsgi_sock) {
|
||||
if (i == uwsgi_sock->fd) {
|
||||
uwsgi_log("found fd %d mapped to socket %d (%s)\n", i, uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
@@ -413,7 +582,11 @@ void master_loop(char **argv, char **environ) {
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
#ifdef __APPLE__
|
||||
fcntl(i, F_SETFD, FD_CLOEXEC);
|
||||
#else
|
||||
close(i);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,14 +599,17 @@ void master_loop(char **argv, char **environ) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (uwsgi.numproc > 0 || uwsgi.gateways_cnt > 0 || ushared->daemons_cnt > 0) {
|
||||
master_has_children = 1;
|
||||
}
|
||||
if (!uwsgi.cheap) {
|
||||
|
||||
if (uwsgi.numproc > 0 || uwsgi.gateways_cnt > 0 || ushared->daemons_cnt > 0) {
|
||||
master_has_children = 1;
|
||||
}
|
||||
#ifdef UWSGI_SPOOLER
|
||||
if (uwsgi.spool_dir && uwsgi.shared->spooler_pid > 0) {
|
||||
master_has_children = 1;
|
||||
}
|
||||
if (uwsgi.spool_dir && uwsgi.shared->spooler_pid > 0) {
|
||||
master_has_children = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!master_has_children) {
|
||||
diedpid = 0;
|
||||
@@ -521,70 +697,11 @@ void master_loop(char **argv, char **environ) {
|
||||
|
||||
// check uwsgi-cron table
|
||||
if (ushared->cron_cnt) {
|
||||
current_time = time(NULL);
|
||||
uwsgi_cron_delta = localtime( ¤t_time );
|
||||
uwsgi_manage_signal_cron(time(NULL));
|
||||
}
|
||||
|
||||
if (uwsgi_cron_delta) {
|
||||
|
||||
// fix month
|
||||
uwsgi_cron_delta->tm_mon++;
|
||||
|
||||
uwsgi_lock(uwsgi.cron_table_lock);
|
||||
for(i=0;i<ushared->cron_cnt;i++) {
|
||||
|
||||
struct uwsgi_cron *ucron = &ushared->cron[i];
|
||||
int uc_minute, uc_hour, uc_day, uc_month, uc_week;
|
||||
|
||||
uc_minute = ucron->minute;
|
||||
uc_hour = ucron->hour;
|
||||
uc_day = ucron->day;
|
||||
uc_month = ucron->month;
|
||||
uc_week = ucron->week;
|
||||
|
||||
if (ucron->minute == -1) uc_minute = uwsgi_cron_delta->tm_min;
|
||||
if (ucron->hour == -1) uc_hour = uwsgi_cron_delta->tm_hour;
|
||||
if (ucron->month == -1) uc_month = uwsgi_cron_delta->tm_mon;
|
||||
|
||||
// mday and wday are ORed
|
||||
if (ucron->day == -1 && ucron->week == -1) {
|
||||
if (ucron->day == -1) uc_day = uwsgi_cron_delta->tm_mday;
|
||||
if (ucron->week == -1) uc_week = uwsgi_cron_delta->tm_wday;
|
||||
}
|
||||
else if (ucron->day == -1) {
|
||||
ucron->day = uwsgi_cron_delta->tm_mday;
|
||||
}
|
||||
else if (ucron->week == -1) {
|
||||
ucron->week = uwsgi_cron_delta->tm_wday;
|
||||
}
|
||||
else {
|
||||
if (ucron->day == uwsgi_cron_delta->tm_mday) {
|
||||
ucron->week = uwsgi_cron_delta->tm_wday;
|
||||
}
|
||||
else if (ucron->week == uwsgi_cron_delta->tm_wday) {
|
||||
ucron->day = uwsgi_cron_delta->tm_mday;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi_cron_delta->tm_min == uc_minute &&
|
||||
uwsgi_cron_delta->tm_hour == uc_hour &&
|
||||
uwsgi_cron_delta->tm_mon == uc_month &&
|
||||
uwsgi_cron_delta->tm_mday == uc_day &&
|
||||
uwsgi_cron_delta->tm_wday == uc_week) {
|
||||
|
||||
|
||||
// date match, signal it ?
|
||||
if (current_time - ucron->last_job > 60) {
|
||||
uwsgi_route_signal(ucron->sig);
|
||||
ucron->last_job = current_time;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
uwsgi_unlock(uwsgi.cron_table_lock);
|
||||
}
|
||||
else {
|
||||
uwsgi_error("localtime()");
|
||||
}
|
||||
if (uwsgi.crons) {
|
||||
uwsgi_manage_command_cron(time(NULL));
|
||||
}
|
||||
|
||||
if (rlen > 0) {
|
||||
@@ -596,22 +713,84 @@ void master_loop(char **argv, char **environ) {
|
||||
if (uwsgi.log_syslog) {
|
||||
syslog(LOG_INFO, "%.*s", rlen, log_buf);
|
||||
}
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
else if (uwsgi.zmq_log_socket) {
|
||||
zmq_msg_t msg;
|
||||
if (zmq_msg_init_size (&msg, rlen) == 0) {
|
||||
memcpy(zmq_msg_data(&msg), log_buf, rlen);
|
||||
zmq_send(uwsgi.zmq_log_socket, &msg, 0);
|
||||
zmq_msg_close(&msg);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (uwsgi.log_socket) {
|
||||
sendto(uwsgi.log_socket_fd, log_buf, rlen, 0, &uwsgi.log_socket_addr->sa, uwsgi.log_socket_size);
|
||||
}
|
||||
// TODO allow uwsgi.logger = func
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.zerg_server) {
|
||||
if (interesting_fd == uwsgi.zerg_server_fd) {
|
||||
struct sockaddr_un zsun;
|
||||
socklen_t zsun_len = sizeof(struct sockaddr_un);
|
||||
int zerg_client = accept(uwsgi.zerg_server_fd, (struct sockaddr *) &zsun, &zsun_len);
|
||||
if (zerg_client < 0) {
|
||||
uwsgi_error("zerg: accept()");
|
||||
continue;
|
||||
}
|
||||
|
||||
struct msghdr zerg_msg;
|
||||
void *zerg_msg_control = uwsgi_malloc(CMSG_SPACE (sizeof (int) * uwsgi_count_sockets(uwsgi.sockets)));
|
||||
struct iovec zerg_iov;
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
zerg_iov.iov_base = "uwsgi-zerg";
|
||||
zerg_iov.iov_len = 10;
|
||||
|
||||
zerg_msg.msg_name = NULL;
|
||||
zerg_msg.msg_namelen = 0;
|
||||
zerg_msg.msg_iov = &zerg_iov;
|
||||
zerg_msg.msg_iovlen = 1;
|
||||
zerg_msg.msg_flags = 0;
|
||||
zerg_msg.msg_control = zerg_msg_control;
|
||||
zerg_msg.msg_controllen = CMSG_SPACE (sizeof (int) * uwsgi_count_sockets(uwsgi.sockets));
|
||||
|
||||
cmsg = CMSG_FIRSTHDR (&zerg_msg);
|
||||
cmsg->cmsg_len = CMSG_LEN (sizeof (int) * uwsgi_count_sockets(uwsgi.sockets));
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
unsigned char *zerg_fd_ptr = CMSG_DATA(cmsg);
|
||||
while(uwsgi_sock) {
|
||||
memcpy(zerg_fd_ptr, &uwsgi_sock->fd, sizeof(int));
|
||||
zerg_fd_ptr += sizeof(int);
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
if (sendmsg(zerg_client, &zerg_msg, 0) < 0) {
|
||||
uwsgi_error("sendmsg()");
|
||||
}
|
||||
|
||||
|
||||
close(zerg_client);
|
||||
|
||||
free(zerg_msg_control);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.has_emperor) {
|
||||
if (interesting_fd == uwsgi.emperor_fd) {
|
||||
char byte;
|
||||
rlen = read(uwsgi.emperor_fd, &byte, 1);
|
||||
if (rlen > 0) {
|
||||
uwsgi_log("received message %d from emperor\n", byte);
|
||||
uwsgi_log_verbose("received message %d from emperor\n", byte);
|
||||
// remove me
|
||||
if (byte == 0) {
|
||||
close(uwsgi.emperor_fd);
|
||||
uwsgi.has_emperor = 0;
|
||||
kill_them_all(0);
|
||||
if (!uwsgi.to_hell) kill_them_all(0);
|
||||
}
|
||||
// reload me
|
||||
else if (byte == 1) {
|
||||
@@ -621,11 +800,31 @@ void master_loop(char **argv, char **environ) {
|
||||
else {
|
||||
uwsgi_log("lost connection with my emperor !!!\n");
|
||||
close(uwsgi.emperor_fd);
|
||||
uwsgi.has_emperor = 0;
|
||||
kill_them_all(0);
|
||||
if (!uwsgi.to_hell) kill_them_all(0);
|
||||
sleep(2);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (uwsgi.cheap) {
|
||||
int found = 0 ;
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
while(uwsgi_sock) {
|
||||
if (interesting_fd == uwsgi_sock->fd) {
|
||||
found = 1;
|
||||
uwsgi.cheap = 0;
|
||||
uwsgi_del_sockets_from_queue(uwsgi.master_queue);
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
if (uwsgi_respawn_worker(i)) return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
if (found) continue;
|
||||
}
|
||||
#ifdef UWSGI_SNMP
|
||||
if (uwsgi.snmp_addr && interesting_fd == snmp_fd) {
|
||||
udp_len = sizeof(udp_client);
|
||||
@@ -777,7 +976,7 @@ void master_loop(char **argv, char **environ) {
|
||||
uwsgi_error("read()");
|
||||
}
|
||||
else if (rlen > 0) {
|
||||
uwsgi_log("received uwsgi signal %d from workers\n", uwsgi_signal);
|
||||
uwsgi_log_verbose("received uwsgi signal %d from a worker\n", uwsgi_signal);
|
||||
uwsgi_route_signal(uwsgi_signal);
|
||||
}
|
||||
else {
|
||||
@@ -788,7 +987,7 @@ void master_loop(char **argv, char **environ) {
|
||||
}
|
||||
}
|
||||
|
||||
current_time = time(NULL);
|
||||
uwsgi.current_time = time(NULL);
|
||||
// checking logsize
|
||||
if (uwsgi.logfile) {
|
||||
uwsgi.shared->logsize = lseek(2, 0, SEEK_CUR);
|
||||
@@ -806,27 +1005,49 @@ void master_loop(char **argv, char **environ) {
|
||||
}
|
||||
|
||||
|
||||
master_cycles++;
|
||||
working_workers = 0;
|
||||
blocking_workers = 0;
|
||||
uwsgi.master_cycles++;
|
||||
|
||||
// recalculate requests counter on race conditions risky configurations
|
||||
// a bit of inaccuracy is better than locking;)
|
||||
|
||||
if (uwsgi.numproc > 1) {
|
||||
tmp_counter = 0;
|
||||
for(i=1;i<uwsgi.numproc+1;i++) {
|
||||
for(i=1;i<uwsgi.numproc+1;i++)
|
||||
tmp_counter += uwsgi.workers[i].requests;
|
||||
}
|
||||
uwsgi.workers[0].requests = tmp_counter;
|
||||
}
|
||||
|
||||
if (uwsgi.idle > 0 && !uwsgi.cheap) {
|
||||
uwsgi.current_time = time(NULL);
|
||||
if (!last_request_timecheck) last_request_timecheck = uwsgi.current_time;
|
||||
if (last_request_count != uwsgi.workers[0].requests) {
|
||||
last_request_timecheck = uwsgi.current_time;
|
||||
last_request_count = uwsgi.workers[0].requests;
|
||||
}
|
||||
else if (uwsgi.current_time - last_request_timecheck > uwsgi.idle) {
|
||||
uwsgi_log("workers have been inactive for more than %d seconds\n", uwsgi.idle);
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
if (uwsgi.workers[i].pid == 0) continue;
|
||||
kill(uwsgi.workers[i].pid, SIGKILL);
|
||||
if (waitpid(uwsgi.workers[i].pid, &waitpid_status, 0) < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
}
|
||||
}
|
||||
master_has_children = 0;
|
||||
uwsgi.cheap = 1;
|
||||
uwsgi_add_sockets_to_queue(uwsgi.master_queue);
|
||||
uwsgi_log("cheap mode enabled: waiting for socket connection...\n");
|
||||
last_request_timecheck = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// remove expired cache items TODO use rb_tree timeouts
|
||||
if (uwsgi.cache_max_items > 0) {
|
||||
for(i=0;i< (int)uwsgi.cache_max_items;i++) {
|
||||
uwsgi_wlock(uwsgi.cache_lock);
|
||||
if (uwsgi.cache_items[i].expires) {
|
||||
if (uwsgi.cache_items[i].expires < (uint64_t) current_time) {
|
||||
if (uwsgi.cache_items[i].expires < (uint64_t) uwsgi.current_time) {
|
||||
uwsgi_cache_del(uwsgi.cache_items[i].key, uwsgi.cache_items[i].keysize);
|
||||
}
|
||||
}
|
||||
@@ -840,16 +1061,19 @@ void master_loop(char **argv, char **environ) {
|
||||
|
||||
|
||||
#ifdef __linux__
|
||||
for(i=0;i<uwsgi.sockets_cnt;i++) {
|
||||
if (uwsgi.sockets[i].family != AF_INET) continue;
|
||||
get_linux_tcp_info(uwsgi.sockets[i].fd);
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
while(uwsgi_sock) {
|
||||
if (uwsgi_sock->family == AF_INET) {
|
||||
get_linux_tcp_info(uwsgi_sock->fd);
|
||||
}
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
/* first check for harakiri */
|
||||
if (uwsgi.workers[i].harakiri > 0) {
|
||||
if (uwsgi.workers[i].harakiri < (time_t) current_time) {
|
||||
if (uwsgi.workers[i].harakiri < (time_t) uwsgi.current_time) {
|
||||
/* first try to invoke the harakiri() custom handler */
|
||||
/* TODO */
|
||||
/* then brutally kill the worker */
|
||||
@@ -896,62 +1120,57 @@ void master_loop(char **argv, char **environ) {
|
||||
uwsgi.workers[i].harakiri = 0;
|
||||
}
|
||||
}
|
||||
/* load counters */
|
||||
if (uwsgi.workers[i].status & UWSGI_STATUS_IN_REQUEST)
|
||||
working_workers++;
|
||||
|
||||
if (uwsgi.workers[i].status & UWSGI_STATUS_BLOCKING)
|
||||
blocking_workers++;
|
||||
|
||||
uwsgi.workers[i].last_running_time = uwsgi.workers[i].running_time;
|
||||
// need to find a better way
|
||||
//uwsgi.workers[i].last_running_time = uwsgi.workers[i].running_time;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_UDP
|
||||
// check for cluster nodes
|
||||
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 (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 ( (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 ;
|
||||
}
|
||||
}
|
||||
}
|
||||
master_check_cluster_nodes();
|
||||
|
||||
// reannounce myself every 10 cycles
|
||||
if (uwsgi.cluster && uwsgi.cluster_fd >= 0 && !uwsgi.cluster_nodes && (master_cycles % 10) == 0) {
|
||||
if (uwsgi.cluster && uwsgi.cluster_fd >= 0 && !uwsgi.cluster_nodes && (uwsgi.master_cycles % 10) == 0) {
|
||||
uwsgi_cluster_add_me();
|
||||
}
|
||||
|
||||
// resubscribe every 10 cycles
|
||||
if (uwsgi.subscriptions_cnt > 0 && (master_cycles % 10) == 0) {
|
||||
if (uwsgi.subscriptions_cnt > 0 && ((uwsgi.master_cycles % 10) == 0 || uwsgi.master_cycles == 1)) {
|
||||
for(i=0;i<uwsgi.subscriptions_cnt;i++) {
|
||||
uwsgi_subscribe(uwsgi.subscriptions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.cache_store && uwsgi.cache_filesize && uwsgi.cache_store_sync && ((master_cycles % uwsgi.cache_store_sync) == 0)) {
|
||||
#endif
|
||||
|
||||
if (uwsgi.cache_store && uwsgi.cache_filesize && uwsgi.cache_store_sync && ((uwsgi.master_cycles % uwsgi.cache_store_sync) == 0)) {
|
||||
if (msync(uwsgi.cache_items, uwsgi.cache_filesize, MS_ASYNC)) {
|
||||
uwsgi_error("msync()");
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.queue_store && uwsgi.queue_filesize && uwsgi.queue_store_sync && ((uwsgi.master_cycles % uwsgi.queue_store_sync) == 0)) {
|
||||
if (msync(uwsgi.queue, uwsgi.queue_filesize, MS_ASYNC)) {
|
||||
uwsgi_error("msync()");
|
||||
}
|
||||
}
|
||||
|
||||
// check touch_reload
|
||||
if (uwsgi.touch_reload && !uwsgi.to_heaven && !uwsgi.to_hell) {
|
||||
struct stat tr_st;
|
||||
if (stat(uwsgi.touch_reload, &tr_st)) {
|
||||
uwsgi_error("stat()");
|
||||
uwsgi_log("unable to stat() %s, touch-reload will be disabled\n", uwsgi.touch_reload);
|
||||
uwsgi.touch_reload = NULL;
|
||||
}
|
||||
else {
|
||||
if (tr_st.st_mtime > uwsgi.last_touch_reload_mtime) {
|
||||
uwsgi_log("*** %s has been touched... grace them all !!! ***\n", uwsgi.touch_reload);
|
||||
grace_them_all(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// now check for lb pool
|
||||
|
||||
@@ -959,6 +1178,9 @@ void master_loop(char **argv, char **environ) {
|
||||
continue;
|
||||
|
||||
}
|
||||
// reload gateways and daemons only on normal workflow
|
||||
if (!uwsgi.to_heaven && !uwsgi.to_hell) {
|
||||
|
||||
#ifdef UWSGI_SPOOLER
|
||||
/* reload the spooler */
|
||||
if (uwsgi.spool_dir && uwsgi.shared->spooler_pid > 0) {
|
||||
@@ -970,8 +1192,6 @@ void master_loop(char **argv, char **environ) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// reload gateways and daemons only on normal workflow
|
||||
if (!uwsgi.to_heaven && !uwsgi.to_hell) {
|
||||
/* reload the gateways */
|
||||
// TODO reload_gateway(diedpid);
|
||||
pid_found = 0;
|
||||
@@ -997,6 +1217,7 @@ void master_loop(char **argv, char **environ) {
|
||||
}
|
||||
|
||||
if (pid_found) continue;
|
||||
|
||||
}
|
||||
|
||||
/* What happens here ?
|
||||
@@ -1040,12 +1261,21 @@ void master_loop(char **argv, char **environ) {
|
||||
}
|
||||
|
||||
|
||||
uwsgi_log( "DAMN ! process %d died :( trying respawn ...\n", diedpid);
|
||||
if (uwsgi.workers[uwsgi.mywid].manage_next_request) {
|
||||
uwsgi_log( "DAMN ! worker %d (pid: %d) died :( trying respawn ...\n", uwsgi.mywid, (int)diedpid);
|
||||
}
|
||||
gettimeofday(&last_respawn, NULL);
|
||||
if (last_respawn.tv_sec == uwsgi.respawn_delta) {
|
||||
uwsgi_log( "worker respawning too fast !!! i have to sleep a bit...\n");
|
||||
/* TODO, user configurable fork throttler */
|
||||
sleep(2);
|
||||
last_respawn_rate++;
|
||||
if (last_respawn_rate > uwsgi.numproc) {
|
||||
uwsgi_log( "worker respawning too fast !!! i have to sleep a bit...\n");
|
||||
/* TODO, user configurable fork throttler */
|
||||
sleep(2);
|
||||
last_respawn_rate = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
last_respawn_rate = 0;
|
||||
}
|
||||
gettimeofday(&last_respawn, NULL);
|
||||
uwsgi.respawn_delta = last_respawn.tv_sec;
|
||||
@@ -1057,46 +1287,9 @@ void master_loop(char **argv, char **environ) {
|
||||
continue;
|
||||
}
|
||||
*/
|
||||
pid = fork();
|
||||
if (pid == 0) {
|
||||
// fix the communication pipe
|
||||
close(uwsgi.shared->worker_signal_pipe[0]);
|
||||
uwsgi.mypid = getpid();
|
||||
uwsgi.workers[uwsgi.mywid].pid = uwsgi.mypid;
|
||||
uwsgi.workers[uwsgi.mywid].harakiri = 0;
|
||||
uwsgi.workers[uwsgi.mywid].requests = 0;
|
||||
uwsgi.workers[uwsgi.mywid].failed_requests = 0;
|
||||
uwsgi.workers[uwsgi.mywid].respawn_count++;
|
||||
uwsgi.workers[uwsgi.mywid].last_spawn = current_time;
|
||||
uwsgi.workers[uwsgi.mywid].manage_next_request = 1;
|
||||
break;
|
||||
}
|
||||
else if (pid < 1) {
|
||||
uwsgi_error("fork()");
|
||||
}
|
||||
else {
|
||||
uwsgi_log( "Respawned uWSGI worker (new pid: %d)\n", pid);
|
||||
//close(uwsgi.workers[uwsgi.mywid].pipe[1]);
|
||||
//event_queue_add_fd_read(uwsgi.master_queue, uwsgi.workers[uwsgi.mywid].pipe[0]);
|
||||
#ifdef UWSGI_SPOOLER
|
||||
if (uwsgi.mywid <= 0 && diedpid != uwsgi.shared->spooler_pid) {
|
||||
#else
|
||||
if (uwsgi.mywid <= 0) {
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_PROXY
|
||||
// TODO if no gateway span the error !!!
|
||||
if (diedpid != uwsgi.shared->proxy_pid) {
|
||||
#endif
|
||||
uwsgi_log( "warning the died pid was not in the workers list. Probably you hit a BUG of uWSGI\n");
|
||||
#ifdef UWSGI_PROXY
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
if (uwsgi_respawn_worker(uwsgi.mywid)) return;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+229
@@ -0,0 +1,229 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_respawn_worker(int wid) {
|
||||
|
||||
int respawns = uwsgi.workers[wid].respawn_count;
|
||||
int i;
|
||||
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid == 0) {
|
||||
uwsgi.mywid = wid;
|
||||
// fix the communication pipe
|
||||
close(uwsgi.shared->worker_signal_pipe[0]);
|
||||
uwsgi.mypid = getpid();
|
||||
uwsgi.workers[uwsgi.mywid].pid = uwsgi.mypid;
|
||||
uwsgi.workers[uwsgi.mywid].id = uwsgi.mywid;
|
||||
uwsgi.workers[uwsgi.mywid].harakiri = 0;
|
||||
uwsgi.workers[uwsgi.mywid].requests = 0;
|
||||
uwsgi.workers[uwsgi.mywid].failed_requests = 0;
|
||||
uwsgi.workers[uwsgi.mywid].respawn_count++;
|
||||
uwsgi.workers[uwsgi.mywid].last_spawn = uwsgi.current_time;
|
||||
uwsgi.workers[uwsgi.mywid].manage_next_request = 1;
|
||||
|
||||
if (uwsgi.master_process && (uwsgi.workers[uwsgi.mywid].respawn_count || uwsgi.cheap)) {
|
||||
for (i = 0; i < 0xFF; i++) {
|
||||
if (uwsgi.p[i]->master_fixup) {
|
||||
uwsgi.p[i]->master_fixup(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else if (pid < 1) {
|
||||
uwsgi_error("fork()");
|
||||
}
|
||||
else {
|
||||
if (respawns > 0) {
|
||||
uwsgi_log("Respawned uWSGI worker %d (new pid: %d)\n", wid, (int) pid);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("spawned uWSGI worker %d (pid: %d, cores: %d)\n", wid, pid, uwsgi.cores);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_manage_signal_cron(time_t now) {
|
||||
|
||||
struct tm *uwsgi_cron_delta;
|
||||
int i;
|
||||
|
||||
uwsgi.current_time = now;
|
||||
uwsgi_cron_delta = localtime(&uwsgi.current_time);
|
||||
|
||||
if (uwsgi_cron_delta) {
|
||||
|
||||
// fix month
|
||||
uwsgi_cron_delta->tm_mon++;
|
||||
|
||||
uwsgi_lock(uwsgi.cron_table_lock);
|
||||
for (i = 0; i < ushared->cron_cnt; i++) {
|
||||
|
||||
struct uwsgi_cron *ucron = &ushared->cron[i];
|
||||
int uc_minute, uc_hour, uc_day, uc_month, uc_week;
|
||||
|
||||
uc_minute = ucron->minute;
|
||||
uc_hour = ucron->hour;
|
||||
uc_day = ucron->day;
|
||||
uc_month = ucron->month;
|
||||
uc_week = ucron->week;
|
||||
|
||||
if (ucron->minute == -1)
|
||||
uc_minute = uwsgi_cron_delta->tm_min;
|
||||
if (ucron->hour == -1)
|
||||
uc_hour = uwsgi_cron_delta->tm_hour;
|
||||
if (ucron->month == -1)
|
||||
uc_month = uwsgi_cron_delta->tm_mon;
|
||||
|
||||
// mday and wday are ORed
|
||||
if (ucron->day == -1 && ucron->week == -1) {
|
||||
if (ucron->day == -1)
|
||||
uc_day = uwsgi_cron_delta->tm_mday;
|
||||
if (ucron->week == -1)
|
||||
uc_week = uwsgi_cron_delta->tm_wday;
|
||||
}
|
||||
else if (ucron->day == -1) {
|
||||
ucron->day = uwsgi_cron_delta->tm_mday;
|
||||
}
|
||||
else if (ucron->week == -1) {
|
||||
ucron->week = uwsgi_cron_delta->tm_wday;
|
||||
}
|
||||
else {
|
||||
if (ucron->day == uwsgi_cron_delta->tm_mday) {
|
||||
ucron->week = uwsgi_cron_delta->tm_wday;
|
||||
}
|
||||
else if (ucron->week == uwsgi_cron_delta->tm_wday) {
|
||||
ucron->day = uwsgi_cron_delta->tm_mday;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi_cron_delta->tm_min == uc_minute && uwsgi_cron_delta->tm_hour == uc_hour && uwsgi_cron_delta->tm_mon == uc_month && uwsgi_cron_delta->tm_mday == uc_day && uwsgi_cron_delta->tm_wday == uc_week) {
|
||||
|
||||
|
||||
// date match, signal it ?
|
||||
if (uwsgi.current_time - ucron->last_job > 60) {
|
||||
uwsgi_route_signal(ucron->sig);
|
||||
ucron->last_job = uwsgi.current_time;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
uwsgi_unlock(uwsgi.cron_table_lock);
|
||||
}
|
||||
else {
|
||||
uwsgi_error("localtime()");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_manage_command_cron(time_t now) {
|
||||
|
||||
struct tm *uwsgi_cron_delta;
|
||||
|
||||
struct uwsgi_cron *current_cron = uwsgi.crons;
|
||||
int uc_minute, uc_hour, uc_day, uc_month, uc_week;
|
||||
|
||||
uwsgi.current_time = now;
|
||||
uwsgi_cron_delta = localtime(&uwsgi.current_time);
|
||||
|
||||
|
||||
if (!uwsgi_cron_delta) {
|
||||
uwsgi_error("localtime()");
|
||||
return;
|
||||
}
|
||||
|
||||
while (current_cron) {
|
||||
|
||||
|
||||
uc_minute = current_cron->minute;
|
||||
uc_hour = current_cron->hour;
|
||||
uc_day = current_cron->day;
|
||||
uc_month = current_cron->month;
|
||||
uc_week = current_cron->week;
|
||||
|
||||
if (current_cron->minute == -1)
|
||||
uc_minute = uwsgi_cron_delta->tm_min;
|
||||
if (current_cron->hour == -1)
|
||||
uc_hour = uwsgi_cron_delta->tm_hour;
|
||||
if (current_cron->month == -1)
|
||||
uc_month = uwsgi_cron_delta->tm_mon;
|
||||
|
||||
// mday and wday are ORed
|
||||
if (current_cron->day == -1 && current_cron->week == -1) {
|
||||
if (current_cron->day == -1)
|
||||
uc_day = uwsgi_cron_delta->tm_mday;
|
||||
if (current_cron->week == -1)
|
||||
uc_week = uwsgi_cron_delta->tm_wday;
|
||||
}
|
||||
else if (current_cron->day == -1) {
|
||||
current_cron->day = uwsgi_cron_delta->tm_mday;
|
||||
}
|
||||
else if (current_cron->week == -1) {
|
||||
current_cron->week = uwsgi_cron_delta->tm_wday;
|
||||
}
|
||||
else {
|
||||
if (current_cron->day == uwsgi_cron_delta->tm_mday) {
|
||||
current_cron->week = uwsgi_cron_delta->tm_wday;
|
||||
}
|
||||
else if (current_cron->week == uwsgi_cron_delta->tm_wday) {
|
||||
current_cron->day = uwsgi_cron_delta->tm_mday;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi_cron_delta->tm_min == uc_minute && uwsgi_cron_delta->tm_hour == uc_hour && uwsgi_cron_delta->tm_mon == uc_month && uwsgi_cron_delta->tm_mday == uc_day && uwsgi_cron_delta->tm_wday == uc_week) {
|
||||
|
||||
|
||||
// date match, run command ?
|
||||
if (uwsgi.current_time - current_cron->last_job > 60) {
|
||||
//call command
|
||||
if (current_cron->command) {
|
||||
if (uwsgi_run_command(current_cron->command) >=0) {
|
||||
uwsgi_log_verbose("[uWSGI-cron] running %s\n", current_cron->command);
|
||||
}
|
||||
}
|
||||
current_cron->last_job = uwsgi.current_time;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
current_cron = current_cron->next;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
main = Server(
|
||||
uuid="f400bf85-4538-4f7a-8908-67e313d515c2",
|
||||
access_log="/logs/access.log",
|
||||
error_log="/logs/error.log",
|
||||
chroot="./",
|
||||
default_host="192.168.173.18",
|
||||
name="test",
|
||||
pid_file="/run/mongrel2.pid",
|
||||
port=6767,
|
||||
hosts = [
|
||||
Host(name="192.168.173.18", routes={
|
||||
'/': Handler(send_spec='tcp://192.168.173.18:9999',
|
||||
send_ident='54c6755b-9628-40a4-9a2d-cc82a816345e',
|
||||
recv_spec='tcp://192.168.173.18:9998', recv_ident='')
|
||||
})
|
||||
]
|
||||
)
|
||||
|
||||
settings = {'upload.temp_store':'tmp/mongrel2.upload.XXXXXX'}
|
||||
servers = [main]
|
||||
|
||||
|
||||
uwsgi = { 'socket':':3031', 'master':'true'}
|
||||
@@ -1,13 +1,27 @@
|
||||
[uwsgi]
|
||||
|
||||
; socket 0
|
||||
socket = :3033
|
||||
; socket 1
|
||||
socket = :3034
|
||||
vacuum = true
|
||||
; socket 2
|
||||
socket = pippo1.sock
|
||||
; socket 3
|
||||
socket = pippo2.sock
|
||||
; socket 4
|
||||
socket = 127.0.0.1:1717
|
||||
|
||||
map-socket = 0:1,2,3,4
|
||||
map-socket = 1:4
|
||||
map-socket = 2:10
|
||||
map-socket = 3:5,6,9
|
||||
map-socket = 4:7,8,9
|
||||
|
||||
|
||||
vacuum = true
|
||||
memory-report = true
|
||||
master = true
|
||||
processes = 10
|
||||
mount = /app1=werkzeug.testapp:test_app
|
||||
mount = /app2=config:/Users/roberta/uwsgi/my.ini
|
||||
mount = /app3=pinaxsite/deploy/pinax.wsgi
|
||||
;mount = /app1=werkzeug.testapp:test_app
|
||||
;mount = /app2=config:/Users/roberta/uwsgi/my.ini
|
||||
;mount = /app3=pinaxsite/deploy/pinax.wsgi
|
||||
|
||||
+3
-8
@@ -1,14 +1,9 @@
|
||||
import werkzeug
|
||||
|
||||
def web3_app(environ):
|
||||
status = b'200 OK'
|
||||
headers = [(b'Content-type', b'text/plain')]
|
||||
body = [b'I am a Web3 app\n']
|
||||
return body, status, headers
|
||||
import uwsgi
|
||||
|
||||
def zero_app(e,s):
|
||||
s('200 OK', [ ('Content-Type', 'text/plain') ])
|
||||
return ""
|
||||
return "0"
|
||||
|
||||
def not_found(e,s):
|
||||
s('404 Not Found', [ ('Content-Type', 'text/plain') ])
|
||||
@@ -24,4 +19,4 @@ def internal_server_error(e, s):
|
||||
s('500 Internal Server Error', [ ('Content-Type', 'text/plain') ])
|
||||
return ""
|
||||
|
||||
applications = {'':web3_app, '/wsgi':wsgi_app, '/test':werkzeug.test_app, '/zero':zero_app, '/notfound':not_found, '/ise':internal_server_error}
|
||||
uwsgi.applications = {'/wsgi':wsgi_app, '/test':werkzeug.test_app, '/zero':zero_app, '/notfound':not_found, '/ise':internal_server_error}
|
||||
|
||||
+11
-1
@@ -2,6 +2,16 @@ import uwsgi
|
||||
import struct
|
||||
import sys
|
||||
|
||||
print sys.argv
|
||||
if len(sys.argv) == 3:
|
||||
chunks = uwsgi.send_message(sys.argv[1], 10, int(sys.argv[2]), '')
|
||||
|
||||
print uwsgi.send_uwsgi_message(sys.argv[1], int(sys.argv[2]), 10, int(sys.argv[3]), struct.pack("i", int(sys.argv[4])))
|
||||
pkt = ''
|
||||
|
||||
for chunk in chunks:
|
||||
pkt += chunk
|
||||
|
||||
print "%d = %d" % (int(sys.argv[2]), struct.unpack("I", pkt)[0])
|
||||
elif len(sys.argv) == 4:
|
||||
uwsgi.send_message(sys.argv[1], 10, int(sys.argv[2]), struct.pack("I", int(sys.argv[3])))
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
|
||||
|
||||
void uwsgi_systemd_notify(char *message) {
|
||||
|
||||
struct msghdr *msghdr = (struct msghdr *) uwsgi.notification_object;
|
||||
struct iovec *iovec = msghdr->msg_iov;
|
||||
|
||||
iovec[0].iov_base = "STATUS=";
|
||||
iovec[0].iov_len = 7;
|
||||
|
||||
iovec[1].iov_base = message;
|
||||
iovec[1].iov_len = strlen(message);
|
||||
|
||||
iovec[2].iov_base = "\n";
|
||||
iovec[2].iov_len = 1;
|
||||
|
||||
msghdr->msg_iovlen = 3;
|
||||
|
||||
sendmsg(uwsgi.notification_fd, msghdr, 0);
|
||||
}
|
||||
|
||||
void uwsgi_systemd_notify_ready(void) {
|
||||
|
||||
struct msghdr *msghdr = (struct msghdr *) uwsgi.notification_object;
|
||||
struct iovec *iovec = msghdr->msg_iov;
|
||||
|
||||
iovec[0].iov_base = "STATUS=uWSGI is ready\nREADY=1\n";
|
||||
iovec[0].iov_len = 30;
|
||||
|
||||
msghdr->msg_iovlen = 1;
|
||||
|
||||
sendmsg(uwsgi.notification_fd, msghdr, 0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_systemd_init(char *systemd_socket) {
|
||||
|
||||
struct sockaddr_un *sd_sun;
|
||||
struct msghdr *msghdr;
|
||||
|
||||
uwsgi.notification_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if (uwsgi.notification_fd < 0) {
|
||||
uwsgi_error("socket()");
|
||||
return;
|
||||
}
|
||||
|
||||
sd_sun = uwsgi_malloc(sizeof(struct sockaddr_un));
|
||||
memset(sd_sun, 0, sizeof(struct sockaddr_un));
|
||||
sd_sun->sun_family = AF_UNIX;
|
||||
strncpy(sd_sun->sun_path, systemd_socket, sizeof(sd_sun->sun_path));
|
||||
if (sd_sun->sun_path[0] == '@') sd_sun->sun_path[0] = 0;
|
||||
|
||||
msghdr = uwsgi_malloc(sizeof(struct msghdr));
|
||||
memset(msghdr, 0, sizeof(struct msghdr));
|
||||
|
||||
msghdr->msg_iov = uwsgi_malloc(sizeof(struct iovec)*3);
|
||||
memset(msghdr->msg_iov, 0, sizeof(struct iovec)*3);
|
||||
|
||||
msghdr->msg_name = sd_sun;
|
||||
msghdr->msg_namelen = sizeof(struct sockaddr_un);
|
||||
|
||||
uwsgi.notification_object = msghdr;
|
||||
|
||||
uwsgi.notify = uwsgi_systemd_notify;
|
||||
uwsgi.notify_ready = uwsgi_systemd_notify_ready;
|
||||
|
||||
}
|
||||
@@ -2,63 +2,149 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void embed_plugins() {
|
||||
|
||||
#ifdef UWSGI_EMBED_PLUGIN_PSGI
|
||||
if (uwsgi.plugin_arg_psgi)
|
||||
uwsgi_load_plugin(5, "psgi_plugin.so", uwsgi.plugin_arg_psgi, 0);
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_EMBED_PLUGIN_LUA
|
||||
if (uwsgi.plugin_arg_lua)
|
||||
uwsgi_load_plugin(6, "lua_plugin.so", uwsgi.plugin_arg_lua, 0);
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_EMBED_PLUGIN_RACK
|
||||
if (uwsgi.plugin_arg_rack)
|
||||
uwsgi_load_plugin(7, "rack_plugin.so", uwsgi.plugin_arg_rack, 0);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_load_plugin(int modifier, char *plugin, char *pargs, int absolute) {
|
||||
void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option, int absolute) {
|
||||
|
||||
void *plugin_handle;
|
||||
|
||||
char *plugin_name;
|
||||
char *plugin_entry_symbol;
|
||||
struct uwsgi_plugin *up;
|
||||
char linkpath_buf[1024], linkpath[1024];
|
||||
int linkpath_size;
|
||||
int i;
|
||||
|
||||
if (absolute) {
|
||||
plugin_name = malloc(strlen(plugin) + 1);
|
||||
memcpy(plugin_name, plugin, strlen(plugin) + 1);
|
||||
char *colon = strchr(plugin, ':');
|
||||
if (colon) {
|
||||
colon[0] = 0;
|
||||
}
|
||||
|
||||
check:
|
||||
for (i = 0; i < 0xFF; i++) {
|
||||
if (uwsgi.p[i]->name) {
|
||||
if (!strcmp(plugin, uwsgi.p[i]->name)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%s plugin already available\n", plugin);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (uwsgi.p[i]->alias) {
|
||||
if (!strcmp(plugin, uwsgi.p[i]->alias)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%s plugin already available\n", plugin);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0;i<uwsgi.gp_cnt;i++) {
|
||||
|
||||
if (uwsgi.gp[i]->name) {
|
||||
if (!strcmp(plugin, uwsgi.gp[i]->name)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%s plugin already available\n", plugin);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (uwsgi.gp[i]->alias) {
|
||||
if (!strcmp(plugin, uwsgi.gp[i]->alias)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%s plugin already available\n", plugin);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (colon) {
|
||||
plugin = colon+1;
|
||||
colon[0] = ':';
|
||||
colon = NULL;
|
||||
goto check;
|
||||
}
|
||||
|
||||
if (absolute == 1) {
|
||||
plugin_name = uwsgi_concat2(plugin, "");
|
||||
// need to fix this... postpone until needed
|
||||
plugin_entry_symbol = uwsgi_concat2n(plugin, strlen(plugin)-3 ,"", 0);
|
||||
}
|
||||
else if (absolute == 2) {
|
||||
plugin_name = uwsgi_concat3(UWSGI_PLUGIN_DIR, "/", plugin);
|
||||
plugin_entry_symbol = uwsgi_concat2n(plugin, strlen(plugin)-3 ,"", 0);
|
||||
}
|
||||
else {
|
||||
plugin_name = uwsgi_concat4(UWSGI_PLUGIN_DIR, "/", plugin, "_plugin.so");
|
||||
plugin_entry_symbol = uwsgi_concat2(plugin, "_plugin");
|
||||
}
|
||||
plugin_handle = dlopen(plugin_name, RTLD_NOW | RTLD_GLOBAL);
|
||||
free(plugin_name);
|
||||
|
||||
if (!plugin_handle) {
|
||||
uwsgi_log( "%s\n", dlerror());
|
||||
}
|
||||
else {
|
||||
plugin_entry_symbol = uwsgi_concat2(plugin, "_plugin");
|
||||
up = dlsym(plugin_handle, plugin_entry_symbol);
|
||||
if (!up) {
|
||||
// is it a link ?
|
||||
memset(linkpath_buf, 0, 1024);
|
||||
memset(linkpath, 0, 1024);
|
||||
if ((linkpath_size = readlink(plugin_name, linkpath_buf, 1023)) > 0) {
|
||||
do {
|
||||
linkpath_buf[linkpath_size] = '\0';
|
||||
strcpy(linkpath, linkpath_buf);
|
||||
} while ((linkpath_size = readlink(linkpath, linkpath_buf, 1023)) > 0);
|
||||
uwsgi_log("%s\n", linkpath);
|
||||
free(plugin_entry_symbol);
|
||||
up = dlsym(plugin_handle, plugin_entry_symbol);
|
||||
char *slash = uwsgi_get_last_char(linkpath, '/');
|
||||
if (!slash) {
|
||||
slash = linkpath;
|
||||
}
|
||||
else {
|
||||
slash++;
|
||||
}
|
||||
plugin_entry_symbol = uwsgi_concat2n(slash, strlen(slash)-3, "",0);
|
||||
up = dlsym(plugin_handle, plugin_entry_symbol);
|
||||
}
|
||||
}
|
||||
if (up) {
|
||||
if (has_option) {
|
||||
struct option *lopt = up->options, *aopt;
|
||||
int found = 0;
|
||||
while ((aopt = lopt)) {
|
||||
if (!aopt->name)
|
||||
break;
|
||||
if (!strcmp(has_option, aopt->name)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
lopt++;
|
||||
}
|
||||
if (!found) {
|
||||
if (dlclose(plugin_handle)) {
|
||||
uwsgi_error("dlclose()");
|
||||
}
|
||||
free(plugin_name);
|
||||
free(plugin_entry_symbol);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
if (modifier != -1) {
|
||||
fill_plugin_table(modifier, up);
|
||||
}
|
||||
else {
|
||||
fill_plugin_table(up->modifier1, up);
|
||||
}
|
||||
return 1;
|
||||
free(plugin_name);
|
||||
free(plugin_entry_symbol);
|
||||
return plugin_handle;
|
||||
}
|
||||
uwsgi_log( "%s\n", dlerror());
|
||||
}
|
||||
|
||||
return 0;
|
||||
free(plugin_name);
|
||||
|
||||
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,28 +1,58 @@
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/* uwsgi ADMIN|10 */
|
||||
int uwsgi_request_admin(struct wsgi_request *wsgi_req) {
|
||||
|
||||
uint32_t opt_value = 0;
|
||||
int i;
|
||||
ssize_t len;
|
||||
|
||||
if (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) {
|
||||
memcpy(&opt_value, wsgi_req->buffer, 4);
|
||||
// TODO: check endianess ?
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
i = write(wsgi_req->poll.fd, wsgi_req, 4);
|
||||
if (i != 4) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
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;
|
||||
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]);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_plugin admin_plugin = {
|
||||
|
||||
.name = "admin",
|
||||
.modifier1 = 10,
|
||||
.request = uwsgi_request_admin,
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
NAME='admin'
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
|
||||
GCC_LIST = ['admin_plugin']
|
||||
Vendored
+101
@@ -0,0 +1,101 @@
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
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)) {
|
||||
val = uwsgi_cache_get(val, vallen, &tmp_vallen);
|
||||
if (val && tmp_vallen > 0) {
|
||||
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, val, tmp_vallen);
|
||||
}
|
||||
|
||||
}
|
||||
else if (!uwsgi_strncmp(key, keylen, "get", 3)) {
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_cache_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
uint64_t vallen = 0;
|
||||
char *value;
|
||||
char *argv[3];
|
||||
uint8_t argc = 0;
|
||||
|
||||
switch(wsgi_req->uh.modifier2) {
|
||||
case 0:
|
||||
// get
|
||||
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) {
|
||||
argc = 3;
|
||||
if (!uwsgi_parse_array(wsgi_req->buffer, wsgi_req->uh.pktsize, argv, &argc)) {
|
||||
if (argc > 1) {
|
||||
uwsgi_cache_set(argv[0], strlen(argv[0]), argv[1], strlen(argv[1]), 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
// del
|
||||
if (wsgi_req->uh.pktsize > 0) {
|
||||
uwsgi_cache_del(wsgi_req->buffer, wsgi_req->uh.pktsize);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
// dict
|
||||
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_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;
|
||||
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, (char *)&wsgi_req->uh, 4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct uwsgi_plugin cache_plugin = {
|
||||
|
||||
.name = "cache",
|
||||
.modifier1 = 111,
|
||||
.request = uwsgi_cache_request,
|
||||
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
NAME='proxy'
|
||||
NAME='cache'
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
|
||||
GCC_LIST = ['proxy']
|
||||
GCC_LIST = ['cache']
|
||||
@@ -5,7 +5,7 @@ extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_echo_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
wsgi_req->response_size = write(wsgi_req->poll.fd, wsgi_req->buffer, wsgi_req->uh.pktsize);
|
||||
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, wsgi_req->buffer, wsgi_req->uh.pktsize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -447,6 +447,7 @@ int erlang_opt(int i, char *optarg) {
|
||||
|
||||
struct uwsgi_plugin erlang_plugin = {
|
||||
|
||||
.name = "erlang",
|
||||
.options = erlang_options,
|
||||
.manage_opt = erlang_opt,
|
||||
.init = erlang_init,
|
||||
|
||||
@@ -11,7 +11,7 @@ int uwsgi_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
char *http = "HTTP/1.1 200 Ok\r\nContent-type: text/html\r\n\r\n<h1>Hello World</h1>";
|
||||
|
||||
wsgi_req->response_size += write(wsgi_req->poll.fd, http, strlen(http));
|
||||
wsgi_req->response_size += wsgi_req->socket_proto_write(wsgi_req, http, strlen(http));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+293
-107
@@ -12,10 +12,13 @@
|
||||
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
#define LONG_ARGS_FASTROUTER 150001
|
||||
#define LONG_ARGS_FASTROUTER_EVENTS 150002
|
||||
#define LONG_ARGS_FASTROUTER_USE_PATTERN 150003
|
||||
#define LONG_ARGS_FASTROUTER_USE_BASE 150004
|
||||
#define LONG_ARGS_FASTROUTER 150001
|
||||
#define LONG_ARGS_FASTROUTER_EVENTS 150002
|
||||
#define LONG_ARGS_FASTROUTER_USE_PATTERN 150003
|
||||
#define LONG_ARGS_FASTROUTER_USE_BASE 150004
|
||||
#define LONG_ARGS_FASTROUTER_SUBSCRIPTION_SERVER 150005
|
||||
#define LONG_ARGS_FASTROUTER_TIMEOUT 150006
|
||||
#define LONG_ARGS_FASTROUTER_SUBSCRIPTION_SLOT 150007
|
||||
|
||||
#define FASTROUTER_STATUS_FREE 0
|
||||
#define FASTROUTER_STATUS_CONNECTING 1
|
||||
@@ -23,29 +26,97 @@
|
||||
#define FASTROUTER_STATUS_RECV_VARS 3
|
||||
#define FASTROUTER_STATUS_RESPONSE 4
|
||||
|
||||
#define add_timeout(x) uwsgi_add_rb_timer(ufr.timeouts, time(NULL)+ufr.socket_timeout, x)
|
||||
#define del_timeout(x) rb_erase(&x->timeout->rbt, ufr.timeouts); free(x->timeout);
|
||||
|
||||
struct uwsgi_fastrouter_socket {
|
||||
char *name;
|
||||
int fd;
|
||||
struct uwsgi_fastrouter_socket *next;
|
||||
};
|
||||
|
||||
struct uwsgi_fastrouter {
|
||||
char *socket_name;
|
||||
int use_cache;
|
||||
int nevents;
|
||||
|
||||
char *pattern;
|
||||
int pattern_len;
|
||||
struct uwsgi_fastrouter_socket *sockets;
|
||||
|
||||
char *base;
|
||||
int base_len;
|
||||
int use_cache;
|
||||
int nevents;
|
||||
|
||||
int subscription_slot;
|
||||
|
||||
char *pattern;
|
||||
int pattern_len;
|
||||
|
||||
char *base;
|
||||
int base_len;
|
||||
|
||||
char *subscription_server;
|
||||
struct uwsgi_dict *subscription_dict;
|
||||
|
||||
int socket_timeout;
|
||||
|
||||
struct rb_root *timeouts;
|
||||
} ufr;
|
||||
|
||||
|
||||
static struct uwsgi_fastrouter_socket *uwsgi_fastrouter_new_socket(char *name) {
|
||||
|
||||
struct uwsgi_fastrouter_socket *uwsgi_sock = ufr.sockets, *old_uwsgi_sock;
|
||||
|
||||
if (!uwsgi_sock) {
|
||||
ufr.sockets = uwsgi_malloc(sizeof(struct uwsgi_fastrouter_socket));
|
||||
uwsgi_sock = ufr.sockets;
|
||||
}
|
||||
else {
|
||||
while(uwsgi_sock) {
|
||||
old_uwsgi_sock = uwsgi_sock;
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
uwsgi_sock = uwsgi_malloc(sizeof(struct uwsgi_fastrouter_socket));
|
||||
old_uwsgi_sock->next = uwsgi_sock;
|
||||
}
|
||||
|
||||
memset(uwsgi_sock, 0, sizeof(struct uwsgi_fastrouter_socket));
|
||||
uwsgi_sock->name = name;
|
||||
|
||||
return uwsgi_sock;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct option fastrouter_options[] = {
|
||||
{"fastrouter", required_argument, 0, LONG_ARGS_FASTROUTER},
|
||||
{"fastrouter-use-cache", no_argument, &ufr.use_cache, 1},
|
||||
{"fastrouter-use-pattern", required_argument, 0, LONG_ARGS_FASTROUTER_USE_PATTERN},
|
||||
{"fastrouter-use-base", required_argument, 0, LONG_ARGS_FASTROUTER_USE_BASE},
|
||||
{"fastrouter-events", required_argument, 0, LONG_ARGS_FASTROUTER_EVENTS},
|
||||
{"fastrouter-subscription-server", required_argument, 0, LONG_ARGS_FASTROUTER_SUBSCRIPTION_SERVER},
|
||||
{"fastrouter-subscription-slot", required_argument, 0, LONG_ARGS_FASTROUTER_SUBSCRIPTION_SLOT},
|
||||
{"fastrouter-timeout", required_argument, 0, LONG_ARGS_FASTROUTER_TIMEOUT},
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void fastrouter_manage_subscription(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
|
||||
|
||||
struct uwsgi_subscribe_req *usr = (struct uwsgi_subscribe_req *) data;
|
||||
|
||||
if (!uwsgi_strncmp("key", 3, key, keylen)) {
|
||||
usr->key = val;
|
||||
usr->keylen = vallen;
|
||||
}
|
||||
else if (!uwsgi_strncmp("address", 7, key, keylen)) {
|
||||
usr->address = val;
|
||||
usr->address_len = vallen;
|
||||
}
|
||||
|
||||
else if (!uwsgi_strncmp("modifier1", 9, key, keylen)) {
|
||||
usr->modifier1 = uwsgi_str_num(val, vallen);
|
||||
}
|
||||
}
|
||||
|
||||
struct fastrouter_session {
|
||||
|
||||
int fd;
|
||||
@@ -59,12 +130,60 @@ struct fastrouter_session {
|
||||
char *hostname;
|
||||
uint16_t hostname_len;
|
||||
|
||||
int has_key;
|
||||
|
||||
char *instance_address;
|
||||
uint64_t instance_address_len;
|
||||
|
||||
struct uwsgi_subscriber_name *un;
|
||||
int pass_fd;
|
||||
|
||||
struct uwsgi_rb_timer *timeout;
|
||||
int instance_failed;
|
||||
|
||||
uint8_t modifier1;
|
||||
};
|
||||
|
||||
static void close_session(struct fastrouter_session **fr_table, struct fastrouter_session *fr_session) {
|
||||
|
||||
close(fr_session->fd);
|
||||
fr_table[fr_session->fd] = NULL;
|
||||
if (fr_session->instance_fd != -1) {
|
||||
if (ufr.subscription_server && (fr_session->instance_failed || fr_session->status == FASTROUTER_STATUS_CONNECTING)) {
|
||||
uwsgi_log("marking %.*s as failed\n", (int) fr_session->instance_address_len,fr_session->instance_address);
|
||||
fr_session->un->len = 0;
|
||||
}
|
||||
close(fr_session->instance_fd);
|
||||
fr_table[fr_session->instance_fd] = NULL;
|
||||
}
|
||||
del_timeout(fr_session);
|
||||
free(fr_session);
|
||||
}
|
||||
|
||||
static struct uwsgi_rb_timer *reset_timeout(struct fastrouter_session *fr_session) {
|
||||
del_timeout(fr_session);
|
||||
return add_timeout(fr_session);
|
||||
}
|
||||
|
||||
static void expire_timeouts(struct fastrouter_session **fr_table) {
|
||||
|
||||
time_t current = time(NULL);
|
||||
struct uwsgi_rb_timer *urbt;
|
||||
|
||||
for(;;) {
|
||||
urbt = uwsgi_min_rb_timer(ufr.timeouts);
|
||||
if (urbt == NULL) return;
|
||||
|
||||
if (urbt->key <= current) {
|
||||
close_session(fr_table, (struct fastrouter_session *)urbt->data);
|
||||
uwsgi_log("timeout !!!\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void fr_get_hostname(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
|
||||
|
||||
struct fastrouter_session *fr_session = (struct fastrouter_session *) data;
|
||||
@@ -76,7 +195,14 @@ void fr_get_hostname(char *key, uint16_t keylen, char *val, uint16_t vallen, voi
|
||||
return;
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("HTTP_HOST", 9, key, keylen)) {
|
||||
if (!uwsgi_strncmp("HTTP_HOST", 9, key, keylen) && !fr_session->has_key) {
|
||||
fr_session->hostname = val;
|
||||
fr_session->hostname_len = vallen;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("UWSGI_FASTROUTER_KEY", 20, key, keylen)) {
|
||||
fr_session->has_key = 1;
|
||||
fr_session->hostname = val;
|
||||
fr_session->hostname_len = vallen;
|
||||
return;
|
||||
@@ -91,18 +217,26 @@ struct fastrouter_session *alloc_fr_session() {
|
||||
void fastrouter_loop() {
|
||||
|
||||
int fr_queue;
|
||||
int fr_server;
|
||||
int nevents;
|
||||
int interesting_fd;
|
||||
int new_connection;
|
||||
ssize_t len;
|
||||
int i;
|
||||
|
||||
time_t delta;
|
||||
char bbuf[UMAX16];
|
||||
|
||||
char *tcp_port;
|
||||
|
||||
char *tmp_socket_name;
|
||||
int tmp_socket_name_len;
|
||||
|
||||
struct uwsgi_subscribe_req usr;
|
||||
|
||||
char *magic_table[0xff];
|
||||
|
||||
struct uwsgi_rb_timer *min_timeout;
|
||||
|
||||
void *events;
|
||||
struct msghdr msg;
|
||||
union {
|
||||
@@ -123,25 +257,77 @@ void fastrouter_loop() {
|
||||
int soopt;
|
||||
socklen_t solen = sizeof(int);
|
||||
|
||||
int ufr_subserver = -1;
|
||||
|
||||
for(i=0;i<2048;i++) {
|
||||
fr_table[i] = NULL;
|
||||
}
|
||||
|
||||
fr_server = bind_to_tcp(ufr.socket_name, uwsgi.listen_queue, ufr.socket_name);
|
||||
|
||||
fr_queue = event_queue_init();
|
||||
|
||||
struct uwsgi_fastrouter_socket *ufr_sock = ufr.sockets;
|
||||
|
||||
while(ufr_sock) {
|
||||
if (ufr_sock->name[0] == '=') {
|
||||
int shared_socket = atoi(ufr_sock->name+1);
|
||||
if (shared_socket >= 0) {
|
||||
ufr_sock->fd = uwsgi_get_shared_socket_fd_by_num(shared_socket);
|
||||
if (ufr_sock->fd == -1) {
|
||||
uwsgi_log("unable to use shared socket %d\n", shared_socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
tcp_port = strchr(ufr_sock->name, ':');
|
||||
if (tcp_port) {
|
||||
ufr_sock->fd = bind_to_tcp(ufr_sock->name, uwsgi.listen_queue, tcp_port);
|
||||
}
|
||||
else {
|
||||
ufr_sock->fd = bind_to_unix(ufr_sock->name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
|
||||
}
|
||||
}
|
||||
|
||||
event_queue_add_fd_read(fr_queue, ufr_sock->fd);
|
||||
ufr_sock = ufr_sock->next;
|
||||
}
|
||||
|
||||
|
||||
events = event_queue_alloc(ufr.nevents);
|
||||
|
||||
event_queue_add_fd_read(fr_queue, fr_server);
|
||||
|
||||
if (ufr.subscription_server) {
|
||||
ufr_subserver = bind_to_udp(ufr.subscription_server, 0, 0);
|
||||
event_queue_add_fd_read(fr_queue, ufr_subserver);
|
||||
if (!ufr.subscription_slot) ufr.subscription_slot = 30;
|
||||
ufr.subscription_dict = uwsgi_dict_create(ufr.subscription_slot, 0);
|
||||
}
|
||||
|
||||
if (ufr.pattern) {
|
||||
init_magic_table(magic_table);
|
||||
}
|
||||
|
||||
ufr.timeouts = uwsgi_init_rb_timer();
|
||||
if (!ufr.socket_timeout) ufr.socket_timeout = 30;
|
||||
|
||||
for (;;) {
|
||||
|
||||
nevents = event_queue_wait_multi(fr_queue, -1, events, ufr.nevents);
|
||||
min_timeout = uwsgi_min_rb_timer(ufr.timeouts);
|
||||
if (min_timeout == NULL ) {
|
||||
delta = -1;
|
||||
}
|
||||
else {
|
||||
delta = min_timeout->key - time(NULL);
|
||||
if (delta <= 0) {
|
||||
expire_timeouts(fr_table);
|
||||
delta = 0;
|
||||
}
|
||||
}
|
||||
|
||||
nevents = event_queue_wait_multi(fr_queue, delta, events, ufr.nevents);
|
||||
|
||||
if (nevents == 0) {
|
||||
expire_timeouts(fr_table);
|
||||
}
|
||||
|
||||
for (i=0;i<nevents;i++) {
|
||||
|
||||
@@ -149,23 +335,49 @@ void fastrouter_loop() {
|
||||
interesting_fd = event_queue_interesting_fd(events, i);
|
||||
|
||||
|
||||
if (interesting_fd == fr_server) {
|
||||
new_connection = accept(fr_server, (struct sockaddr *) &fr_addr, &fr_addr_len);
|
||||
if (new_connection < 0) {
|
||||
continue;
|
||||
int taken = 0;
|
||||
struct uwsgi_fastrouter_socket *uwsgi_sock = ufr.sockets;
|
||||
while(uwsgi_sock) {
|
||||
if (interesting_fd == uwsgi_sock->fd) {
|
||||
new_connection = accept(interesting_fd, (struct sockaddr *) &fr_addr, &fr_addr_len);
|
||||
if (new_connection < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fr_table[new_connection] = alloc_fr_session();
|
||||
fr_table[new_connection]->fd = new_connection;
|
||||
fr_table[new_connection]->instance_fd = -1;
|
||||
fr_table[new_connection]->status = FASTROUTER_STATUS_RECV_HDR;
|
||||
fr_table[new_connection]->h_pos = 0;
|
||||
fr_table[new_connection]->pos = 0;
|
||||
fr_table[new_connection]->instance_failed = 0;
|
||||
fr_table[new_connection]->instance_address_len = 0;
|
||||
|
||||
fr_table[new_connection]->timeout = add_timeout(fr_table[new_connection]);
|
||||
|
||||
event_queue_add_fd_read(fr_queue, new_connection);
|
||||
taken = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
fr_table[new_connection] = alloc_fr_session();
|
||||
fr_table[new_connection]->fd = new_connection;
|
||||
fr_table[new_connection]->instance_fd = -1;
|
||||
fr_table[new_connection]->status = FASTROUTER_STATUS_RECV_HDR;
|
||||
fr_table[new_connection]->h_pos = 0;
|
||||
fr_table[new_connection]->pos = 0;
|
||||
fr_table[new_connection]->instance_address_len = 0;
|
||||
|
||||
event_queue_add_fd_read(fr_queue, new_connection);
|
||||
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
if (taken) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (interesting_fd == ufr_subserver) {
|
||||
len = recv(ufr_subserver, bbuf, 4096, 0);
|
||||
#ifdef UWSGI_EVENT_USE_PORT
|
||||
event_queue_add_fd_read(fr_queue, ufr_subserver);
|
||||
#endif
|
||||
if (len > 0) {
|
||||
memset(&usr, 0, sizeof(struct uwsgi_subscribe_req));
|
||||
uwsgi_hooked_parse(bbuf+4, len-4, fastrouter_manage_subscription, &usr);
|
||||
uwsgi_add_subscriber(ufr.subscription_dict, &usr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
fr_session = fr_table[interesting_fd];
|
||||
|
||||
@@ -173,25 +385,19 @@ void fastrouter_loop() {
|
||||
if (fr_session == NULL) continue;
|
||||
|
||||
if (event_queue_interesting_fd_has_error(events, i)) {
|
||||
close(fr_session->fd);
|
||||
fr_table[fr_session->fd] = NULL;
|
||||
if (fr_session->instance_fd != -1) {
|
||||
close(fr_session->instance_fd);
|
||||
fr_table[fr_session->instance_fd] = NULL;
|
||||
}
|
||||
free(fr_session);
|
||||
close_session(fr_table, fr_session);
|
||||
continue;
|
||||
}
|
||||
|
||||
fr_session->timeout = reset_timeout(fr_session);
|
||||
|
||||
switch(fr_session->status) {
|
||||
|
||||
case FASTROUTER_STATUS_RECV_HDR:
|
||||
len = recv(fr_session->fd, (char *)(&fr_session->uh) + fr_session->h_pos, 4-fr_session->h_pos, 0);
|
||||
if (len <= 0) {
|
||||
uwsgi_error("recv()");
|
||||
close(fr_session->fd);
|
||||
fr_table[fr_session->fd] = NULL;
|
||||
free(fr_session);
|
||||
close_session(fr_table, fr_session);
|
||||
break;
|
||||
}
|
||||
fr_session->h_pos += len;
|
||||
@@ -208,28 +414,24 @@ void fastrouter_loop() {
|
||||
len = recv(fr_session->fd, fr_session->buffer + fr_session->pos, fr_session->uh.pktsize - fr_session->pos, 0);
|
||||
if (len <= 0) {
|
||||
uwsgi_error("recv()");
|
||||
close(fr_session->fd);
|
||||
fr_table[fr_session->fd] = NULL;
|
||||
free(fr_session);
|
||||
close_session(fr_table, fr_session);
|
||||
break;
|
||||
}
|
||||
fr_session->pos += len;
|
||||
if (fr_session->pos == fr_session->uh.pktsize) {
|
||||
if (uwsgi_hooked_parse(fr_session->buffer, fr_session->uh.pktsize, fr_get_hostname, (void *) fr_session)) {
|
||||
close(fr_session->fd);
|
||||
fr_table[fr_session->fd] = NULL;
|
||||
free(fr_session);
|
||||
close_session(fr_table, fr_session);
|
||||
break;
|
||||
}
|
||||
|
||||
if (fr_session->hostname_len == 0) {
|
||||
close(fr_session->fd);
|
||||
fr_table[fr_session->fd] = NULL;
|
||||
free(fr_session);
|
||||
close_session(fr_table, fr_session);
|
||||
break;
|
||||
}
|
||||
|
||||
//uwsgi_log("requested domain %.*s\n", fr_session->hostname_len, fr_session->hostname);
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("requested domain %.*s\n", fr_session->hostname_len, fr_session->hostname);
|
||||
#endif
|
||||
if (ufr.use_cache) {
|
||||
fr_session->instance_address = uwsgi_cache_get(fr_session->hostname, fr_session->hostname_len, &fr_session->instance_address_len);
|
||||
}
|
||||
@@ -240,6 +442,14 @@ void fastrouter_loop() {
|
||||
fr_session->instance_address_len = tmp_socket_name_len;
|
||||
fr_session->instance_address = tmp_socket_name;
|
||||
}
|
||||
else if (ufr.subscription_server) {
|
||||
fr_session->un = uwsgi_get_subscriber(ufr.subscription_dict, fr_session->hostname, fr_session->hostname_len);
|
||||
if (fr_session->un && fr_session->un->len) {
|
||||
fr_session->instance_address = fr_session->un->name;
|
||||
fr_session->instance_address_len = fr_session->un->len;
|
||||
fr_session->modifier1 = fr_session->un->modifier1;
|
||||
}
|
||||
}
|
||||
else if (ufr.base) {
|
||||
tmp_socket_name = uwsgi_concat2nn(ufr.base, ufr.base_len, fr_session->hostname, fr_session->hostname_len, &tmp_socket_name_len);
|
||||
fr_session->instance_address_len = tmp_socket_name_len;
|
||||
@@ -248,9 +458,7 @@ void fastrouter_loop() {
|
||||
|
||||
// no address found
|
||||
if (!fr_session->instance_address_len) {
|
||||
close(fr_session->fd);
|
||||
fr_table[fr_session->fd] = NULL;
|
||||
free(fr_session);
|
||||
close_session(fr_table, fr_session);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -262,9 +470,11 @@ void fastrouter_loop() {
|
||||
if (tmp_socket_name) free(tmp_socket_name);
|
||||
|
||||
if (fr_session->instance_fd < 0) {
|
||||
close(fr_session->fd);
|
||||
fr_table[fr_session->fd] = NULL;
|
||||
free(fr_session);
|
||||
if (ufr.subscription_server) {
|
||||
uwsgi_log("marking %.*s as failed\n", (int) fr_session->instance_address_len,fr_session->instance_address);
|
||||
fr_session->un->len = 0;
|
||||
}
|
||||
close_session(fr_table, fr_session);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -283,31 +493,27 @@ void fastrouter_loop() {
|
||||
|
||||
if (getsockopt(fr_session->instance_fd, SOL_SOCKET, SO_ERROR, (void *) (&soopt), &solen) < 0) {
|
||||
uwsgi_error("getsockopt()");
|
||||
close(fr_session->fd);
|
||||
close(fr_session->instance_fd);
|
||||
fr_table[fr_session->fd] = NULL;
|
||||
fr_table[fr_session->instance_fd] = NULL;
|
||||
free(fr_session);
|
||||
fr_session->instance_failed = 1;
|
||||
close_session(fr_table, fr_session);
|
||||
break;
|
||||
}
|
||||
|
||||
if (soopt) {
|
||||
uwsgi_log("unable to connect() to uwsgi instance: %s\n", strerror(soopt));
|
||||
close(fr_session->fd);
|
||||
close(fr_session->instance_fd);
|
||||
fr_table[fr_session->fd] = NULL;
|
||||
fr_table[fr_session->instance_fd] = NULL;
|
||||
free(fr_session);
|
||||
fr_session->instance_failed = 1;
|
||||
close_session(fr_table, fr_session);
|
||||
break;
|
||||
}
|
||||
|
||||
fr_session->uh.modifier1 = fr_session->modifier1;
|
||||
|
||||
iov[0].iov_base = &fr_session->uh;
|
||||
iov[0].iov_len = 4;
|
||||
iov[1].iov_base = fr_session->buffer;
|
||||
iov[1].iov_len = fr_session->uh.pktsize;
|
||||
|
||||
// fd passing: PERFORMANCE EXTREME BOOST !!!
|
||||
if (fr_session->pass_fd) {
|
||||
if (fr_session->pass_fd && !uwsgi.no_fd_passing) {
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_iov = iov;
|
||||
@@ -327,21 +533,13 @@ void fastrouter_loop() {
|
||||
uwsgi_error("sendmsg()");
|
||||
}
|
||||
|
||||
close(fr_session->fd);
|
||||
close(fr_session->instance_fd);
|
||||
fr_table[fr_session->fd] = NULL;
|
||||
fr_table[fr_session->instance_fd] = NULL;
|
||||
free(fr_session);
|
||||
close_session(fr_table, fr_session);
|
||||
break;
|
||||
}
|
||||
|
||||
if (writev(fr_session->instance_fd, iov, 2) < 0) {
|
||||
uwsgi_error("writev()");
|
||||
close(fr_session->fd);
|
||||
close(fr_session->instance_fd);
|
||||
fr_table[fr_session->fd] = NULL;
|
||||
fr_table[fr_session->instance_fd] = NULL;
|
||||
free(fr_session);
|
||||
close_session(fr_table, fr_session);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -358,11 +556,7 @@ void fastrouter_loop() {
|
||||
len = recv(fr_session->instance_fd, fr_session->buffer, 0xffff, 0);
|
||||
if (len <= 0) {
|
||||
if (len < 0) uwsgi_error("recv()");
|
||||
close(fr_session->fd);
|
||||
close(fr_session->instance_fd);
|
||||
fr_table[fr_session->fd] = NULL;
|
||||
fr_table[fr_session->instance_fd] = NULL;
|
||||
free(fr_session);
|
||||
close_session(fr_table, fr_session);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -370,11 +564,7 @@ void fastrouter_loop() {
|
||||
|
||||
if (len <= 0) {
|
||||
if (len < 0) uwsgi_error("send()");
|
||||
close(fr_session->fd);
|
||||
close(fr_session->instance_fd);
|
||||
fr_table[fr_session->fd] = NULL;
|
||||
fr_table[fr_session->instance_fd] = NULL;
|
||||
free(fr_session);
|
||||
close_session(fr_table, fr_session);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -385,11 +575,7 @@ void fastrouter_loop() {
|
||||
len = recv(fr_session->fd, fr_session->buffer, 0xffff, 0);
|
||||
if (len <= 0) {
|
||||
if (len < 0) uwsgi_error("recv()");
|
||||
close(fr_session->fd);
|
||||
close(fr_session->instance_fd);
|
||||
fr_table[fr_session->fd] = NULL;
|
||||
fr_table[fr_session->instance_fd] = NULL;
|
||||
free(fr_session);
|
||||
close_session(fr_table, fr_session);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -398,11 +584,7 @@ void fastrouter_loop() {
|
||||
|
||||
if (len <= 0) {
|
||||
if (len < 0) uwsgi_error("send()");
|
||||
close(fr_session->fd);
|
||||
close(fr_session->instance_fd);
|
||||
fr_table[fr_session->fd] = NULL;
|
||||
fr_table[fr_session->instance_fd] = NULL;
|
||||
free(fr_session);
|
||||
close_session(fr_table, fr_session);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -414,13 +596,7 @@ void fastrouter_loop() {
|
||||
// fallback to destroy !!!
|
||||
default:
|
||||
uwsgi_log("default action\n");
|
||||
close(fr_session->fd);
|
||||
fr_table[fr_session->fd] = NULL;
|
||||
if (fr_session->instance_fd != -1) {
|
||||
close(fr_session->instance_fd);
|
||||
fr_table[fr_session->instance_fd] = NULL;
|
||||
}
|
||||
free(fr_session);
|
||||
close_session(fr_table, fr_session);
|
||||
break;
|
||||
|
||||
}
|
||||
@@ -432,7 +608,7 @@ void fastrouter_loop() {
|
||||
|
||||
int fastrouter_init() {
|
||||
|
||||
if (ufr.socket_name) {
|
||||
if (ufr.sockets) {
|
||||
|
||||
if (ufr.use_cache && !uwsgi.cache_max_items) {
|
||||
uwsgi_log("you need to create a uwsgi cache to use the fastrouter (add --cache <n>)\n");
|
||||
@@ -454,7 +630,10 @@ int fastrouter_opt(int i, char *optarg) {
|
||||
|
||||
switch(i) {
|
||||
case LONG_ARGS_FASTROUTER:
|
||||
ufr.socket_name = optarg;
|
||||
uwsgi_fastrouter_new_socket(generate_socket_name(optarg));
|
||||
return 1;
|
||||
case LONG_ARGS_FASTROUTER_SUBSCRIPTION_SERVER:
|
||||
ufr.subscription_server = optarg;
|
||||
return 1;
|
||||
case LONG_ARGS_FASTROUTER_EVENTS:
|
||||
ufr.nevents = atoi(optarg);
|
||||
@@ -469,6 +648,12 @@ int fastrouter_opt(int i, char *optarg) {
|
||||
// optimization
|
||||
ufr.base_len = strlen(ufr.base);
|
||||
return 1;
|
||||
case LONG_ARGS_FASTROUTER_TIMEOUT:
|
||||
ufr.socket_timeout = atoi(optarg);
|
||||
return -1;
|
||||
case LONG_ARGS_FASTROUTER_SUBSCRIPTION_SLOT:
|
||||
ufr.subscription_slot = atoi(optarg);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -476,6 +661,7 @@ int fastrouter_opt(int i, char *optarg) {
|
||||
|
||||
struct uwsgi_plugin fastrouter_plugin = {
|
||||
|
||||
.name = "fastrouter",
|
||||
.options = fastrouter_options,
|
||||
.manage_opt = fastrouter_opt,
|
||||
.init = fastrouter_init,
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
#include "../rack/uwsgi_rack.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
extern struct uwsgi_rack ur;
|
||||
|
||||
struct ufib {
|
||||
VALUE *fib;
|
||||
} ufiber;
|
||||
|
||||
struct option fiber_options[] = {
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
VALUE uwsgi_fiber_request() {
|
||||
|
||||
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh.modifier1]->request(uwsgi.wsgi_req);
|
||||
uwsgi.wsgi_req->suspended = 0;
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
inline static void fiber_schedule_to_req() {
|
||||
|
||||
int id = uwsgi.wsgi_req->async_id;
|
||||
|
||||
if (!uwsgi.wsgi_req->suspended) {
|
||||
ufiber.fib[id] = rb_fiber_new(uwsgi_fiber_request, Qnil);
|
||||
rb_gc_register_address(&ufiber.fib[id]);
|
||||
uwsgi.wsgi_req->suspended = 1;
|
||||
}
|
||||
|
||||
rb_fiber_resume(ufiber.fib[id], 0, NULL);
|
||||
|
||||
if (uwsgi.wsgi_req->suspended) {
|
||||
uwsgi.wsgi_req->async_status = UWSGI_AGAIN;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inline static void fiber_schedule_to_main(struct wsgi_request *wsgi_req) {
|
||||
|
||||
rb_fiber_yield(0, NULL);
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
}
|
||||
|
||||
VALUE protected_async_loop() {
|
||||
|
||||
async_loop(NULL);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
void fiber_loop() {
|
||||
|
||||
int error = 0;
|
||||
|
||||
ufiber.fib = uwsgi_malloc( sizeof(VALUE) * uwsgi.async );
|
||||
|
||||
uwsgi.schedule_to_main = fiber_schedule_to_main;
|
||||
uwsgi.schedule_to_req = fiber_schedule_to_req;
|
||||
|
||||
// must run all the rack/ruby plugins without protection
|
||||
ur.unprotected = 1;
|
||||
|
||||
rb_protect(protected_async_loop, 0, &error);
|
||||
|
||||
if (error) {
|
||||
uwsgi_ruby_exception();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// never here
|
||||
}
|
||||
|
||||
int fiber_init() {
|
||||
uwsgi_register_loop( (char *) "fiber", fiber_loop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_plugin fiber_plugin = {
|
||||
|
||||
.name = "fiber",
|
||||
.init = fiber_init,
|
||||
.options = fiber_options,
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
import os
|
||||
|
||||
try:
|
||||
RUBYPATH = os.environ['UWSGICONFIG_RUBYPATH']
|
||||
except:
|
||||
RUBYPATH = 'ruby'
|
||||
|
||||
NAME='fiber'
|
||||
CFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['CFLAGS']\"").read().rstrip().split()
|
||||
|
||||
CFLAGS.append('-Wno-unused-parameter')
|
||||
|
||||
includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['rubyhdrdir']\"").read().rstrip()
|
||||
if includedir == 'nil':
|
||||
includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['archdir']\"").read().rstrip()
|
||||
CFLAGS.append('-I' + includedir)
|
||||
else:
|
||||
CFLAGS.append('-I' + includedir)
|
||||
archdir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['archdir']\"").read().rstrip()
|
||||
arch = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['arch']\"").read().rstrip()
|
||||
CFLAGS.append('-I' + archdir)
|
||||
CFLAGS.append('-I' + archdir + '/' + arch)
|
||||
CFLAGS.append('-I' + includedir + '/' + arch)
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
|
||||
GCC_LIST = ['fiber']
|
||||
+26
-12
@@ -145,13 +145,13 @@ struct http_session {
|
||||
struct uwsgi_rb_timer *timeout;
|
||||
};
|
||||
|
||||
struct uwsgi_rb_timer *reset_timeout(struct http_session *uhttp_session) {
|
||||
static struct uwsgi_rb_timer *reset_timeout(struct http_session *uhttp_session) {
|
||||
|
||||
del_timeout(uhttp_session);
|
||||
return add_timeout(uhttp_session);
|
||||
}
|
||||
|
||||
void close_session(struct http_session **uhttp_table, struct http_session *uhttp_session) {
|
||||
static void close_session(struct http_session **uhttp_table, struct http_session *uhttp_session) {
|
||||
|
||||
close(uhttp_session->fd);
|
||||
uhttp_table[uhttp_session->fd] = NULL;
|
||||
@@ -170,7 +170,7 @@ void close_session(struct http_session **uhttp_table, struct http_session *uhttp
|
||||
|
||||
}
|
||||
|
||||
void expire_timeouts(struct http_session **uhttp_table) {
|
||||
static void expire_timeouts(struct http_session **uhttp_table) {
|
||||
|
||||
time_t current = time(NULL);
|
||||
struct uwsgi_rb_timer *urbt;
|
||||
@@ -429,12 +429,14 @@ void http_loop() {
|
||||
|
||||
struct uwsgi_rb_timer *min_timeout;
|
||||
void *events;
|
||||
#ifndef __sun__
|
||||
struct msghdr msg;
|
||||
union {
|
||||
struct cmsghdr cmsg;
|
||||
char control [CMSG_SPACE (sizeof (int))];
|
||||
} msg_control;
|
||||
struct cmsghdr *cmsg;
|
||||
#endif
|
||||
|
||||
union uwsgi_sockaddr uhttp_addr;
|
||||
socklen_t uhttp_addr_len = sizeof(struct sockaddr_un);
|
||||
@@ -540,7 +542,7 @@ void http_loop() {
|
||||
if (len > 0) {
|
||||
memset(&usr, 0, sizeof(struct uwsgi_subscribe_req));
|
||||
uwsgi_hooked_parse(bbuf+4, len-4, http_manage_subscription, &usr);
|
||||
uwsgi_add_subscriber(uhttp.subscription_dict, usr.key, usr.keylen, usr.address, usr.address_len);
|
||||
uwsgi_add_subscriber(uhttp.subscription_dict, &usr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -626,9 +628,9 @@ void http_loop() {
|
||||
uhttp_session->instance_address_len = uhttp_session->un->len;
|
||||
}
|
||||
}
|
||||
else if (uwsgi.sockets_cnt > 0) {
|
||||
uhttp_session->instance_address = uwsgi.sockets[0].name;
|
||||
uhttp_session->instance_address_len = strlen(uwsgi.sockets[0].name);
|
||||
else if (uwsgi.sockets) {
|
||||
uhttp_session->instance_address = uwsgi.sockets->name;
|
||||
uhttp_session->instance_address_len = strlen(uwsgi.sockets->name);
|
||||
}
|
||||
|
||||
if (!uhttp_session->instance_address_len) {
|
||||
@@ -705,8 +707,10 @@ void http_loop() {
|
||||
uhttp_session->iov_len++;
|
||||
}
|
||||
|
||||
|
||||
#ifndef __sun__
|
||||
// fd passing: PERFORMANCE EXTREME BOOST !!!
|
||||
if (uhttp_session->pass_fd && !uhttp_session->remains) {
|
||||
if (uhttp_session->pass_fd && !uhttp_session->remains && !uwsgi.no_fd_passing) {
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_iov = uhttp_session->iov;
|
||||
@@ -736,6 +740,7 @@ void http_loop() {
|
||||
break;
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef __sun__
|
||||
if (uhttp_session->iov_len > IOV_MAX) {
|
||||
int remains = uhttp_session->iov_len;
|
||||
@@ -863,10 +868,10 @@ int http_init() {
|
||||
|
||||
if (!uhttp.nevents) uhttp.nevents = 64;
|
||||
|
||||
if (!uhttp.base && !uhttp.use_cache && !uhttp.to && !uwsgi.sockets_cnt && !uhttp.subscription_server && !uhttp.use_cluster) {
|
||||
uwsgi.sockets[0].name = uwsgi_malloc(64);
|
||||
uwsgi.sockets_cnt++;
|
||||
snprintf(uwsgi.sockets[0].name, 64, "%d_%d.sock", (int) time(NULL), (int) getpid());
|
||||
if (!uhttp.base && !uhttp.use_cache && !uhttp.to && !uwsgi.sockets && !uhttp.subscription_server && !uhttp.use_cluster) {
|
||||
char *rand_name = uwsgi_malloc(64);
|
||||
snprintf(rand_name, 64, "%d_%d.sock", (int) time(NULL), (int) getpid());
|
||||
uwsgi.sockets = uwsgi_new_socket(rand_name);
|
||||
}
|
||||
|
||||
uhttp.server = bind_to_tcp(uhttp.socket_name, uwsgi.listen_queue, strchr(uhttp.socket_name,':'));
|
||||
@@ -875,10 +880,17 @@ int http_init() {
|
||||
uwsgi_log("unable to register the http gateway\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_log("HTTP router/proxy bound on %s\n", uhttp.socket_name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct uwsgi_help_item http_help[] = {
|
||||
{ "http-to <addr>", "forward http requests to uwsgi instance bound at <addr>"},
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
int http_opt(int i, char *optarg) {
|
||||
|
||||
@@ -929,8 +941,10 @@ int http_opt(int i, char *optarg) {
|
||||
|
||||
struct uwsgi_plugin http_plugin = {
|
||||
|
||||
.name = "http",
|
||||
.options = http_options,
|
||||
.manage_opt = http_opt,
|
||||
.help = http_help,
|
||||
.init = http_init,
|
||||
};
|
||||
|
||||
|
||||
@@ -16,6 +16,16 @@ NAME='jvm'
|
||||
JVM_INCPATH = "/usr/lib/jvm/java-6-sun-1.6.0.15/include/ -I/usr/lib/jvm/java-6-sun-1.6.0.15/include/linux"
|
||||
JVM_LIBPATH = "/usr/lib/jvm/java-6-sun-1.6.0.15/jre/lib/i386/server/"
|
||||
|
||||
try:
|
||||
JVM_INCPATH = os.environ['UWSGICONFIG_JVM_INCPATH']
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
JVM_LIBPATH = os.environ['UWSGICONFIG_JVM_LIBPATH']
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
JVM_INCPATH = os.environ['UWSGICONFIG_JVM_INCPATH']
|
||||
except:
|
||||
|
||||
+16
-13
@@ -16,17 +16,17 @@ struct option nagios_options[] = {
|
||||
int nagios() {
|
||||
|
||||
char *tcp_port;
|
||||
struct pollfd nagios_poll;
|
||||
struct wsgi_request nagios_req;
|
||||
// connect and send
|
||||
|
||||
if (!use_nagios) {
|
||||
return 1;
|
||||
}
|
||||
if (uwsgi.sockets[0].name == NULL) {
|
||||
if (!uwsgi.sockets) {
|
||||
fprintf(stdout, "UWSGI UNKNOWN: you have specified an invalid socket\n");
|
||||
exit(3);
|
||||
}
|
||||
tcp_port = strchr(uwsgi.sockets[0].name, ':');
|
||||
tcp_port = strchr(uwsgi.sockets->name, ':');
|
||||
if (tcp_port == NULL) {
|
||||
fprintf(stdout, "UWSGI UNKNOWN: you have specified an invalid socket\n");
|
||||
exit(3);
|
||||
@@ -34,27 +34,30 @@ int nagios() {
|
||||
|
||||
tcp_port[0] = 0;
|
||||
|
||||
nagios_poll.fd = connect_to_tcp(uwsgi.sockets[0].name, atoi(tcp_port + 1), uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], 0);
|
||||
if (nagios_poll.fd < 0) {
|
||||
int fd = connect_to_tcp(uwsgi.sockets->name, atoi(tcp_port + 1), uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], 0);
|
||||
if (fd < 0) {
|
||||
fprintf(stdout, "UWSGI CRITICAL: could not connect() to workers\n");
|
||||
exit(2);
|
||||
}
|
||||
uwsgi.wsgi_req->uh.modifier1 = UWSGI_MODIFIER_PING;
|
||||
uwsgi.wsgi_req->uh.pktsize = 0;
|
||||
uwsgi.wsgi_req->uh.modifier2 = 0;
|
||||
if (write(nagios_poll.fd, uwsgi.wsgi_req, 4) != 4) {
|
||||
nagios_req.uh.modifier1 = UWSGI_MODIFIER_PING;
|
||||
nagios_req.uh.pktsize = 0;
|
||||
nagios_req.uh.modifier2 = 0;
|
||||
if (write(fd, &nagios_req.uh, 4) != 4) {
|
||||
uwsgi_error("write()");
|
||||
fprintf(stdout, "UWSGI CRITICAL: could not send ping packet to workers\n");
|
||||
exit(2);
|
||||
}
|
||||
nagios_poll.events = POLLIN;
|
||||
if (!uwsgi_parse_response(&nagios_poll, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], (struct uwsgi_header *) uwsgi.wsgi_req, uwsgi.wsgi_req->buffer)) {
|
||||
|
||||
nagios_req.poll.fd = fd;
|
||||
nagios_req.poll.events = POLLIN;
|
||||
|
||||
if (!uwsgi_parse_packet(&nagios_req, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
|
||||
fprintf(stdout, "UWSGI CRITICAL: timed out waiting for response\n");
|
||||
exit(2);
|
||||
}
|
||||
else {
|
||||
if (uwsgi.wsgi_req->uh.pktsize > 0) {
|
||||
fprintf(stdout, "UWSGI WARNING: %.*s\n", uwsgi.wsgi_req->uh.pktsize, uwsgi.wsgi_req->buffer);
|
||||
if (nagios_req.uh.pktsize > 0) {
|
||||
fprintf(stdout, "UWSGI WARNING: %.*s\n", nagios_req.uh.pktsize, nagios_req.buffer);
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
|
||||
+18
-11
@@ -15,32 +15,38 @@ struct option uwsgi_ping_options[] = {
|
||||
|
||||
static void ping() {
|
||||
|
||||
struct uwsgi_header uh;
|
||||
struct pollfd uwsgi_poll;
|
||||
struct wsgi_request ping_req;
|
||||
char *buf = uwsgi_malloc(uwsgi.buffer_size);
|
||||
|
||||
// use a 3 secs timeout by default
|
||||
if (!uping.ping_timeout) uping.ping_timeout = 3;
|
||||
|
||||
uwsgi_log("PING uwsgi host %s (timeout: %d)\n", uping.ping, uping.ping_timeout);
|
||||
|
||||
uwsgi_poll.fd = uwsgi_connect(uping.ping, uping.ping_timeout, 0);
|
||||
if (uwsgi_poll.fd < 0) {
|
||||
int fd = uwsgi_connect(uping.ping, uping.ping_timeout, 0);
|
||||
if (fd < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uh.modifier1 = UWSGI_MODIFIER_PING;
|
||||
uh.pktsize = 0;
|
||||
uh.modifier2 = 0;
|
||||
if (write(uwsgi_poll.fd, &uh, 4) != 4) {
|
||||
memset(&ping_req, 0, sizeof(struct wsgi_request));
|
||||
ping_req.uh.modifier1 = UWSGI_MODIFIER_PING;
|
||||
ping_req.uh.pktsize = 0;
|
||||
ping_req.uh.modifier2 = 0;
|
||||
if (write(fd, &ping_req.uh, 4) != 4) {
|
||||
uwsgi_error("write()");
|
||||
exit(2);
|
||||
}
|
||||
uwsgi_poll.events = POLLIN;
|
||||
if (!uwsgi_parse_response(&uwsgi_poll, uping.ping_timeout, &uh, NULL)) {
|
||||
ping_req.poll.fd = fd;
|
||||
ping_req.poll.events = POLLIN;
|
||||
|
||||
ping_req.buffer = buf;
|
||||
|
||||
if (!uwsgi_parse_packet(&ping_req, uping.ping_timeout)) {
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
if (uh.pktsize > 0) {
|
||||
if (ping_req.uh.pktsize > 0) {
|
||||
uwsgi_log("[WARNING] node %s message: %.*s\n", uping.ping, ping_req.uh.pktsize, buf);
|
||||
exit(2);
|
||||
}
|
||||
else {
|
||||
@@ -92,6 +98,7 @@ int uwsgi_ping_manage_options(int i, char *optarg) {
|
||||
|
||||
switch(i) {
|
||||
case LONG_ARGS_PING:
|
||||
uwsgi.no_server = 1;
|
||||
uping.ping = optarg;
|
||||
return 1;
|
||||
case LONG_ARGS_PING_TIMEOUT:
|
||||
|
||||
@@ -1,490 +0,0 @@
|
||||
/*
|
||||
|
||||
uWSGI proxy
|
||||
|
||||
it needs one of this tecnology to work:
|
||||
|
||||
- epoll (linux 2.6)
|
||||
- kqueue (various BSD and Darwin)
|
||||
- /dev/poll (Solaris)
|
||||
|
||||
*/
|
||||
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
#define LONG_ARGS_PROXY_WORKERS 50000
|
||||
|
||||
struct uwsgi_proxy {
|
||||
char *socket_name;
|
||||
int add_me;
|
||||
int workers;
|
||||
int fd;
|
||||
} uproxy;
|
||||
|
||||
struct option proxy_options[] = {
|
||||
{"proxy", required_argument, 0, LONG_ARGS_PROXY},
|
||||
{"proxy-node", required_argument, 0, LONG_ARGS_PROXY_NODE},
|
||||
{"proxy-max-connections", required_argument, 0, LONG_ARGS_PROXY_MAX_CONNECTIONS},
|
||||
{"proxy-workers", required_argument, 0, LONG_ARGS_PROXY_WORKERS},
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
#define UWSGI_PROXY_CONNECTING 1
|
||||
#define UWSGI_PROXY_WAITING 2
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_proxy_connection {
|
||||
|
||||
int dest_fd;
|
||||
int status;
|
||||
int retry;
|
||||
int node;
|
||||
};
|
||||
|
||||
static void end_proxy(void) {
|
||||
exit(UWSGI_END_CODE);
|
||||
}
|
||||
|
||||
|
||||
static void reload_proxy(void) {
|
||||
exit(UWSGI_RELOAD_CODE);
|
||||
}
|
||||
|
||||
static void uwsgi_proxy_close(struct uwsgi_proxy_connection *upcs, int fd) {
|
||||
|
||||
if (upcs[fd].dest_fd >= 0) {
|
||||
close(upcs[fd].dest_fd);
|
||||
upcs[upcs[fd].dest_fd].dest_fd = -1;
|
||||
upcs[upcs[fd].dest_fd].status = 0;
|
||||
upcs[upcs[fd].dest_fd].retry = 0;
|
||||
if (upcs[upcs[fd].dest_fd].node > -1) {
|
||||
if (uwsgi.shared->nodes[upcs[upcs[fd].dest_fd].node].connections > 0)
|
||||
uwsgi.shared->nodes[upcs[upcs[fd].dest_fd].node].connections--;
|
||||
}
|
||||
}
|
||||
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
upcs[fd].dest_fd = -1;
|
||||
upcs[fd].status = 0;
|
||||
upcs[fd].retry = 0;
|
||||
if (upcs[fd].node > -1) {
|
||||
if (uwsgi.shared->nodes[upcs[fd].node].connections > 0)
|
||||
uwsgi.shared->nodes[upcs[fd].node].connections--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int uwsgi_proxy_find_next_node(int current_node) {
|
||||
int i;
|
||||
|
||||
current_node++;
|
||||
if (current_node >= MAX_CLUSTER_NODES) {
|
||||
current_node = 0;
|
||||
}
|
||||
|
||||
// is it a good node ?
|
||||
if (uwsgi.shared->nodes[current_node].name[0] != 0 && uwsgi.shared->nodes[current_node].status == UWSGI_NODE_OK) {
|
||||
if (uwsgi.shared->nodes[current_node].connections < uwsgi.shared->nodes[current_node].workers)
|
||||
return current_node;
|
||||
}
|
||||
|
||||
// try to find a better one
|
||||
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
if (uwsgi.shared->nodes[i].name[0] != 0 && uwsgi.shared->nodes[i].status == UWSGI_NODE_OK) {
|
||||
if (uwsgi.shared->nodes[i].connections < uwsgi.shared->nodes[i].workers)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// ok, it is a very loaded system, fallback to round robin
|
||||
if (uwsgi.shared->nodes[current_node].name[0] != 0 && uwsgi.shared->nodes[current_node].status == UWSGI_NODE_OK) {
|
||||
return current_node;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
if (uwsgi.shared->nodes[i].name[0] != 0 && uwsgi.shared->nodes[i].status == UWSGI_NODE_OK) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void proxy_loop() {
|
||||
|
||||
int efd;
|
||||
|
||||
#ifdef __linux__
|
||||
struct epoll_event *eevents;
|
||||
struct epoll_event ev;
|
||||
#elif defined(__sun__)
|
||||
struct pollfd *eevents;
|
||||
struct pollfd ev;
|
||||
#else
|
||||
struct kevent *eevents;
|
||||
struct kevent ev;
|
||||
#endif
|
||||
|
||||
int max_events = 64;
|
||||
int nevents, i;
|
||||
const int nonblocking = 1;
|
||||
const int blocking = 0;
|
||||
|
||||
char buffer[4096];
|
||||
ssize_t rlen;
|
||||
ssize_t wlen;
|
||||
int max_connections = sysconf(_SC_OPEN_MAX);
|
||||
|
||||
int soopt;
|
||||
socklen_t solen = sizeof(int);
|
||||
|
||||
int rc;
|
||||
|
||||
struct uwsgi_proxy_connection *upcs;
|
||||
|
||||
struct sockaddr_in upc_addr;
|
||||
socklen_t upc_len = sizeof(struct sockaddr_in);
|
||||
|
||||
int next_node = -1;
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log( "allocating space for %d concurrent proxy connections\n", max_connections);
|
||||
#endif
|
||||
|
||||
// allocate memory for connections
|
||||
upcs = malloc(sizeof(struct uwsgi_proxy_connection) * max_connections);
|
||||
if (!upcs) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
}
|
||||
memset(upcs, 0, sizeof(struct uwsgi_proxy_connection) * max_connections);
|
||||
|
||||
if (uproxy.add_me) {
|
||||
uwsgi_cluster_simple_add_node(uwsgi.sockets[0].name, 1, CLUSTER_NODE_STATIC);
|
||||
}
|
||||
|
||||
efd = async_queue_init(uproxy.fd);
|
||||
if (efd < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
eevents = malloc(sizeof(struct epoll_event) * max_events);
|
||||
memset(&ev, 0, sizeof(struct epoll_event));
|
||||
#elif defined(__sun)
|
||||
eevents = malloc(sizeof(struct pollfd) * max_events);
|
||||
memset(&ev, 0, sizeof(struct pollfd));
|
||||
#else
|
||||
eevents = malloc(sizeof(struct kevent) * max_events);
|
||||
memset(&ev, 0, sizeof(struct kevent));
|
||||
#endif
|
||||
|
||||
if (!eevents) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
signal(SIGINT, (void *) &end_proxy);
|
||||
signal(SIGTERM, (void *) &reload_proxy);
|
||||
signal(SIGHUP, (void *) &reload_proxy);
|
||||
// and welcome to the loop...
|
||||
|
||||
for (;;) {
|
||||
|
||||
nevents = async_wait(efd, eevents, max_events, -1, 0);
|
||||
if (nevents < 0) {
|
||||
uwsgi_error("epoll_wait()");
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < nevents; i++) {
|
||||
|
||||
if ( (int)eevents[i].ASYNC_FD == uproxy.fd) {
|
||||
|
||||
if (eevents[i].ASYNC_IS_IN) {
|
||||
// new connection, accept it
|
||||
ev.ASYNC_FD = accept(uproxy.fd, (struct sockaddr *) &upc_addr, &upc_len);
|
||||
if ( (int) ev.ASYNC_FD < 0) {
|
||||
uwsgi_error("accept()");
|
||||
continue;
|
||||
}
|
||||
upcs[ev.ASYNC_FD].node = -1;
|
||||
|
||||
// now connect to the first worker available
|
||||
|
||||
upcs[ev.ASYNC_FD].dest_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (upcs[ev.ASYNC_FD].dest_fd < 0) {
|
||||
uwsgi_error("socket()");
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
upcs[upcs[ev.ASYNC_FD].dest_fd].node = -1;
|
||||
|
||||
// set nonblocking
|
||||
if (ioctl(upcs[ev.ASYNC_FD].dest_fd, FIONBIO, &nonblocking)) {
|
||||
uwsgi_error("ioctl()");
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
|
||||
upcs[ev.ASYNC_FD].status = 0;
|
||||
upcs[ev.ASYNC_FD].retry = 0;
|
||||
next_node = uwsgi_proxy_find_next_node(next_node);
|
||||
if (next_node == -1) {
|
||||
uwsgi_log( "unable to find an available worker in the cluster !\n");
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
upcs[upcs[ev.ASYNC_FD].dest_fd].node = next_node;
|
||||
rc = connect(upcs[ev.ASYNC_FD].dest_fd, (struct sockaddr *) &uwsgi.shared->nodes[next_node].ucn_addr, sizeof(struct sockaddr_in));
|
||||
uwsgi.shared->nodes[next_node].connections++;
|
||||
|
||||
if (!rc) {
|
||||
// connected to worker, put it in the epoll_list
|
||||
|
||||
if (async_add(efd, ev.ASYNC_FD, ASYNC_IN)) {
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
|
||||
upcs[upcs[ev.ASYNC_FD].dest_fd].dest_fd = ev.ASYNC_FD;
|
||||
upcs[upcs[ev.ASYNC_FD].dest_fd].status = 0;
|
||||
upcs[upcs[ev.ASYNC_FD].dest_fd].retry = 0;
|
||||
|
||||
ev.ASYNC_FD = upcs[ev.ASYNC_FD].dest_fd;
|
||||
|
||||
if (async_add(efd, ev.ASYNC_FD, ASYNC_IN)) {
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
|
||||
// re-set blocking
|
||||
if (ioctl(upcs[upcs[ev.ASYNC_FD].dest_fd].dest_fd, FIONBIO, &blocking)) {
|
||||
uwsgi_error("ioctl()");
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
else if (errno == EINPROGRESS) {
|
||||
// the socket is waiting, set status to CONNECTING
|
||||
upcs[ev.ASYNC_FD].status = UWSGI_PROXY_WAITING;
|
||||
upcs[upcs[ev.ASYNC_FD].dest_fd].dest_fd = ev.ASYNC_FD;
|
||||
upcs[upcs[ev.ASYNC_FD].dest_fd].status = UWSGI_PROXY_CONNECTING;
|
||||
upcs[upcs[ev.ASYNC_FD].dest_fd].retry = 0;
|
||||
|
||||
ev.ASYNC_FD = upcs[ev.ASYNC_FD].dest_fd;
|
||||
if (async_add(efd, ev.ASYNC_FD, ASYNC_OUT)) {
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// connection failed, retry with the next node ?
|
||||
uwsgi_error("connect()");
|
||||
// close only when all node are tried
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
uwsgi_log( "!!! something horrible happened to the uWSGI proxy, reloading it !!!\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// this is for clients/workers
|
||||
if (eevents[i].ASYNC_IS_IN) {
|
||||
|
||||
// is this a connected client/worker ?
|
||||
//uwsgi_log("ready %d\n", upcs[eevents[i].data.fd].status);
|
||||
|
||||
if (!upcs[eevents[i].ASYNC_FD].status) {
|
||||
if (upcs[eevents[i].ASYNC_FD].dest_fd >= 0) {
|
||||
|
||||
rlen = read(eevents[i].ASYNC_FD, buffer, 4096);
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("read()");
|
||||
uwsgi_proxy_close(upcs, eevents[i].ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
else if (rlen == 0) {
|
||||
uwsgi_proxy_close(upcs, eevents[i].ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
wlen = write(upcs[eevents[i].ASYNC_FD].dest_fd, buffer, rlen);
|
||||
if (wlen != rlen) {
|
||||
uwsgi_error("write()");
|
||||
uwsgi_proxy_close(upcs, eevents[i].ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_proxy_close(upcs, eevents[i].ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (upcs[eevents[i].ASYNC_FD].status == UWSGI_PROXY_WAITING) {
|
||||
// disconnected node
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
uwsgi_log( "UNKNOWN STATUS %d\n", upcs[eevents[i].ASYNC_FD].status);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (eevents[i].ASYNC_IS_OUT) {
|
||||
if (upcs[eevents[i].ASYNC_FD].status == UWSGI_PROXY_CONNECTING) {
|
||||
|
||||
|
||||
#ifdef UWSGI_PROXY_USE_KQUEUE
|
||||
if (getsockopt(eevents[i].ASYNC_FD, SOL_SOCKET, SO_ERROR, (void *) (&soopt), &solen) < 0) {
|
||||
uwsgi_error("getsockopt()");
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
/* is something bad ? */
|
||||
if (soopt) {
|
||||
uwsgi_log( "connect() %s\n", strerror(soopt));
|
||||
// increase errors on node
|
||||
uwsgi_log( "*** marking cluster node %d/%s as failed ***\n", upcs[eevents[i].ASYNC_FD].node, uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].name);
|
||||
if (uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].type == CLUSTER_NODE_DYNAMIC) {
|
||||
uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].name[0] = 0 ;
|
||||
}
|
||||
else {
|
||||
uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].errors++;
|
||||
uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].status = UWSGI_NODE_FAILED;
|
||||
}
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
|
||||
// increase errors on node
|
||||
#endif
|
||||
ev.ASYNC_FD = upcs[eevents[i].ASYNC_FD].dest_fd;
|
||||
upcs[ev.ASYNC_FD].status = 0;
|
||||
if (async_add(efd, ev.ASYNC_FD, ASYNC_IN)) {
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
|
||||
ev.ASYNC_FD = upcs[ev.ASYNC_FD].dest_fd;
|
||||
upcs[ev.ASYNC_FD].status = 0;
|
||||
|
||||
if (async_mod(efd, ev.ASYNC_FD, ASYNC_IN)) {
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
// re-set blocking
|
||||
if (ioctl(ev.ASYNC_FD, FIONBIO, &blocking)) {
|
||||
uwsgi_error("ioctl()");
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log( "strange event for %d\n", (int) eevents[i].ASYNC_FD);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (upcs[eevents[i].ASYNC_FD].status == UWSGI_PROXY_CONNECTING) {
|
||||
if (getsockopt(eevents[i].ASYNC_FD, SOL_SOCKET, SO_ERROR, (void *) (&soopt), &solen) < 0) {
|
||||
uwsgi_error("getsockopt()");
|
||||
}
|
||||
/* is something bad ? */
|
||||
if (soopt) {
|
||||
uwsgi_log( "connect() %s\n", strerror(soopt));
|
||||
}
|
||||
|
||||
// increase errors on node
|
||||
uwsgi_log( "*** marking cluster node %d/%s as failed ***\n", upcs[eevents[i].ASYNC_FD].node, uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].name);
|
||||
if (uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].type == CLUSTER_NODE_DYNAMIC) {
|
||||
uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].name[0] = 0;
|
||||
}
|
||||
else {
|
||||
uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].errors++;
|
||||
uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].status = UWSGI_NODE_FAILED;
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log( "STRANGE EVENT !!! %d %d %d\n", (int) eevents[i].ASYNC_FD, (int) eevents[i].ASYNC_EV, upcs[eevents[i].ASYNC_FD].status);
|
||||
}
|
||||
uwsgi_proxy_close(upcs, eevents[i].ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int proxy_init() {
|
||||
int i;
|
||||
char *tcp_port;
|
||||
|
||||
if (!uproxy.workers) uproxy.workers = 1 ;
|
||||
|
||||
if (uproxy.socket_name) {
|
||||
|
||||
tcp_port = strchr(uproxy.socket_name, ':');
|
||||
|
||||
if (tcp_port == NULL) {
|
||||
uproxy.fd = bind_to_unix(uproxy.socket_name, UWSGI_LISTEN_QUEUE, uwsgi.chmod_socket, uwsgi.abstract_socket);
|
||||
}
|
||||
else {
|
||||
uproxy.fd = bind_to_tcp(uproxy.socket_name, UWSGI_LISTEN_QUEUE, tcp_port);
|
||||
tcp_port[0] = ':';
|
||||
}
|
||||
|
||||
if (uproxy.fd < 0) {
|
||||
uwsgi_log( "unable to create the proxy server socket.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for(i=0;i<uproxy.workers;i++) {
|
||||
if (register_gateway("proxy", proxy_loop) == NULL) {
|
||||
uwsgi_log("unable to register the proxy gateway\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int proxy_opt(int i, char *optarg) {
|
||||
|
||||
switch(i) {
|
||||
|
||||
case LONG_ARGS_PROXY_NODE:
|
||||
if (uwsgi.cluster_fd >= 0 && !strcmp(optarg, "@self")) {
|
||||
uproxy.add_me = 1;
|
||||
}
|
||||
else {
|
||||
uwsgi_cluster_simple_add_node(optarg, 1, CLUSTER_NODE_STATIC);
|
||||
}
|
||||
return 1;
|
||||
case LONG_ARGS_PROXY:
|
||||
uproxy.socket_name = optarg;
|
||||
return 1;
|
||||
case LONG_ARGS_PROXY_WORKERS:
|
||||
uproxy.workers = atoi(optarg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_plugin proxy_plugin = {
|
||||
|
||||
.options = proxy_options,
|
||||
.manage_opt = proxy_opt,
|
||||
.init = proxy_init,
|
||||
};
|
||||
|
||||
+18
-2
@@ -1,6 +1,9 @@
|
||||
#undef __USE_GNU
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define HAS_BOOL 1
|
||||
#endif
|
||||
#include <EXTERN.h>
|
||||
#include <perl.h>
|
||||
#include "XSUB.h"
|
||||
@@ -11,17 +14,30 @@ struct uwsgi_perl {
|
||||
int fd;
|
||||
char *psgibuffer;
|
||||
char *psgi;
|
||||
char *locallib;
|
||||
char *embedding[3];
|
||||
PerlInterpreter *main;
|
||||
pthread_key_t u_interpreter;
|
||||
PerlInterpreter **interp;
|
||||
SV *psgi_main;
|
||||
SV **psgi_func;
|
||||
CV *stream_responder;
|
||||
HV *streaming_stash;
|
||||
HV *input_stash;
|
||||
HV *error_stash;
|
||||
|
||||
};
|
||||
|
||||
#define LONG_ARGS_PERL_BASE 17000 + ((5 + 1) * 100)
|
||||
#define LONG_ARGS_PSGI LONG_ARGS_PERL_BASE + 1
|
||||
#define LONG_ARGS_PERL_BASE 17000 + ((5 + 1) * 1000)
|
||||
#define LONG_ARGS_PSGI LONG_ARGS_PERL_BASE + 1
|
||||
#define LONG_ARGS_PERL_LOCAL_LIB LONG_ARGS_PERL_BASE + 2
|
||||
|
||||
void init_perl_embedded_module(void);
|
||||
void uwsgi_psgi_app(void);
|
||||
int psgi_response(struct wsgi_request *, PerlInterpreter *, AV*);
|
||||
|
||||
#define psgi_xs(func) newXS("uwsgi::" #func, XS_##func, "uwsgi")
|
||||
#define psgi_check_args(x) if (items < x) Perl_croak(aTHX_ "Usage: uwsgi::%s takes %d arguments", __FUNCTION__ + 3, x)
|
||||
|
||||
SV *uwsgi_perl_obj_call(SV *, char *);
|
||||
int uwsgi_perl_obj_can(SV *, char *, size_t);
|
||||
|
||||
@@ -0,0 +1,315 @@
|
||||
#include "psgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
struct uwsgi_perl uperl;
|
||||
|
||||
|
||||
|
||||
XS(XS_input_seek) {
|
||||
|
||||
dXSARGS;
|
||||
|
||||
psgi_check_args(1);
|
||||
XSRETURN(0);
|
||||
}
|
||||
|
||||
XS(XS_error) {
|
||||
dXSARGS;
|
||||
|
||||
psgi_check_args(0);
|
||||
|
||||
ST(0) = sv_bless(newRV(sv_newmortal()), uperl.error_stash);
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_input) {
|
||||
|
||||
dXSARGS;
|
||||
psgi_check_args(0);
|
||||
|
||||
ST(0) = sv_bless(newRV(sv_newmortal()), uperl.input_stash);
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_stream)
|
||||
{
|
||||
dXSARGS;
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
psgi_check_args(1);
|
||||
|
||||
AV *response = (AV* ) SvREFCNT_inc(SvRV(ST(0))) ;
|
||||
|
||||
if (av_len(response) == 2) {
|
||||
|
||||
#ifdef my_perl
|
||||
while (psgi_response(wsgi_req, my_perl, response) != UWSGI_OK);
|
||||
#else
|
||||
while (psgi_response(wsgi_req, uperl.main, response) != UWSGI_OK);
|
||||
#endif
|
||||
}
|
||||
else if (av_len(response) == 1) {
|
||||
#ifdef my_perl
|
||||
while (psgi_response(wsgi_req, my_perl, response) != UWSGI_OK);
|
||||
#else
|
||||
while (psgi_response(wsgi_req, uperl.main, response) != UWSGI_OK);
|
||||
#endif
|
||||
SvREFCNT_dec(response);
|
||||
ST(0) = sv_bless(newRV(sv_newmortal()), uperl.streaming_stash);
|
||||
XSRETURN(1);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("invalid PSGI response: array size %d\n", av_len(response));
|
||||
}
|
||||
|
||||
SvREFCNT_dec(response);
|
||||
XSRETURN(0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
XS(XS_input_read) {
|
||||
|
||||
dXSARGS;
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
int fd = -1;
|
||||
char *tmp_buf;
|
||||
ssize_t bytes = 0, len;
|
||||
size_t remains;
|
||||
SV *read_buf;
|
||||
|
||||
psgi_check_args(3);
|
||||
|
||||
|
||||
read_buf = ST(1);
|
||||
len = SvIV(ST(2));
|
||||
|
||||
// return empty string if no post_cl or pos >= post_cl
|
||||
if (!wsgi_req->post_cl || (size_t) wsgi_req->post_pos >= wsgi_req->post_cl) {
|
||||
sv_setpvn(read_buf, "", 0);
|
||||
goto ret;
|
||||
}
|
||||
|
||||
if (wsgi_req->body_as_file) {
|
||||
fd = fileno((FILE *)wsgi_req->async_post);
|
||||
}
|
||||
else if (uwsgi.post_buffering > 0) {
|
||||
fd = -1;
|
||||
if (wsgi_req->post_cl <= (size_t) uwsgi.post_buffering) {
|
||||
fd = fileno((FILE *)wsgi_req->async_post);
|
||||
}
|
||||
}
|
||||
else {
|
||||
fd = wsgi_req->poll.fd;
|
||||
}
|
||||
// return the whole input
|
||||
if (len <= 0) {
|
||||
remains = wsgi_req->post_cl;
|
||||
}
|
||||
else {
|
||||
remains = len ;
|
||||
}
|
||||
|
||||
if (remains + wsgi_req->post_pos > wsgi_req->post_cl) {
|
||||
remains = wsgi_req->post_cl - wsgi_req->post_pos;
|
||||
}
|
||||
|
||||
if (remains <= 0) {
|
||||
sv_setpvn(read_buf, "", 0);
|
||||
goto ret;
|
||||
}
|
||||
|
||||
// data in memory ?
|
||||
if (fd == -1) {
|
||||
sv_setpvn(read_buf, wsgi_req->post_buffering_buf, remains);
|
||||
bytes = remains;
|
||||
wsgi_req->post_pos += remains;
|
||||
|
||||
}
|
||||
|
||||
tmp_buf = uwsgi_malloc(remains);
|
||||
|
||||
if (uwsgi_waitfd(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]) <= 0) {
|
||||
free(tmp_buf);
|
||||
croak("error waiting for wsgi.input data");
|
||||
goto ret;
|
||||
}
|
||||
|
||||
bytes = read(fd, tmp_buf, remains);
|
||||
if (bytes < 0) {
|
||||
free(tmp_buf);
|
||||
croak("error reading wsgi.input data");
|
||||
goto ret;
|
||||
}
|
||||
|
||||
wsgi_req->post_pos += bytes;
|
||||
sv_setpvn(read_buf, tmp_buf, bytes);
|
||||
|
||||
free(tmp_buf);
|
||||
|
||||
ret:
|
||||
XSRETURN_IV(bytes);
|
||||
}
|
||||
|
||||
|
||||
XS(XS_streaming_close) {
|
||||
|
||||
dXSARGS;
|
||||
psgi_check_args(0);
|
||||
|
||||
XSRETURN(0);
|
||||
}
|
||||
|
||||
XS(XS_streaming_write) {
|
||||
|
||||
dXSARGS;
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
STRLEN blen;
|
||||
char *body;
|
||||
|
||||
psgi_check_args(2);
|
||||
|
||||
body = SvPV(ST(1), blen);
|
||||
|
||||
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, body, blen);
|
||||
|
||||
XSRETURN(0);
|
||||
}
|
||||
|
||||
XS(XS_error_print) {
|
||||
|
||||
dXSARGS;
|
||||
STRLEN blen;
|
||||
char *body;
|
||||
|
||||
psgi_check_args(1);
|
||||
|
||||
if (items > 1) {
|
||||
body = SvPV(ST(1), blen);
|
||||
uwsgi_log("%.*s", blen, body);
|
||||
}
|
||||
|
||||
XSRETURN(0);
|
||||
}
|
||||
|
||||
/* automatically generated */
|
||||
|
||||
EXTERN_C void xs_init (pTHX);
|
||||
|
||||
EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);
|
||||
|
||||
EXTERN_C void
|
||||
xs_init(pTHX)
|
||||
{
|
||||
char *file = __FILE__;
|
||||
dXSUB_SYS;
|
||||
|
||||
/* DynaLoader is a special case */
|
||||
newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
|
||||
|
||||
newXS("uwsgi::input::new", XS_input, "uwsgi::input");
|
||||
newXS("uwsgi::input::read", XS_input_read, "uwsgi::input");
|
||||
newXS("uwsgi::input::seek", XS_input_seek, "uwsgi::input");
|
||||
|
||||
uperl.input_stash = gv_stashpv("uwsgi::input", 0);
|
||||
|
||||
newXS("uwsgi::error::new", XS_error, "uwsgi::error");
|
||||
newXS("uwsgi::error::print", XS_error_print, "uwsgi::print");
|
||||
uperl.error_stash = gv_stashpv("uwsgi::error", 0);
|
||||
|
||||
uperl.stream_responder = newXS("uwsgi::stream", XS_stream, "uwsgi");
|
||||
|
||||
newXS("uwsgi::streaming::write", XS_streaming_write, "uwsgi::streaming");
|
||||
newXS("uwsgi::streaming::close", XS_streaming_close, "uwsgi::streaming");
|
||||
|
||||
uperl.streaming_stash = gv_stashpv("uwsgi::streaming", 0);
|
||||
|
||||
#ifdef UWSGI_EMBEDDED
|
||||
init_perl_embedded_module();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* end of automagically generated part */
|
||||
|
||||
|
||||
void uwsgi_psgi_app() {
|
||||
|
||||
struct stat stat_psgi;
|
||||
|
||||
if (uperl.psgi) {
|
||||
|
||||
// two-pass loading: parse the script -> eval the script
|
||||
|
||||
|
||||
|
||||
if (uperl.locallib) {
|
||||
uwsgi_log("using %s as local::lib directory\n", uperl.locallib);
|
||||
uperl.embedding[1] = uwsgi_concat2("-Mlocal::lib=", uperl.locallib);
|
||||
uperl.embedding[2] = uperl.psgi;
|
||||
if (perl_parse(uperl.main, xs_init, 3, uperl.embedding, NULL)) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
uperl.embedding[1] = uperl.psgi;
|
||||
if (perl_parse(uperl.main, xs_init, 2, uperl.embedding, NULL)) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
perl_eval_pv("use IO::Handle;", 0);
|
||||
perl_eval_pv("use IO::File;", 0);
|
||||
|
||||
SV *dollar_zero = get_sv("0", GV_ADD);
|
||||
sv_setsv(dollar_zero, newSVpv(uperl.psgi, 0));
|
||||
|
||||
SV *dollar_slash = get_sv("/", GV_ADD);
|
||||
sv_setsv(dollar_slash, newRV_inc(newSViv(uwsgi.buffer_size)));
|
||||
|
||||
uperl.fd = open(uperl.psgi, O_RDONLY);
|
||||
if (uperl.fd < 0) {
|
||||
uwsgi_error_open(uperl.psgi);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (fstat(uperl.fd, &stat_psgi)) {
|
||||
uwsgi_error("fstat()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uperl.psgibuffer = malloc(stat_psgi.st_size + 1);
|
||||
if (!uperl.psgibuffer) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (read(uperl.fd, uperl.psgibuffer, stat_psgi.st_size) != stat_psgi.st_size) {
|
||||
uwsgi_error("read()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uperl.psgibuffer[stat_psgi.st_size] = 0;
|
||||
|
||||
if (uwsgi.threads < 2) {
|
||||
uperl.psgi_main = perl_eval_pv(uwsgi_concat4("#line 1 ", uperl.psgi, "\n", uperl.psgibuffer), 0);
|
||||
if (!uperl.psgi_main) {
|
||||
uwsgi_log("unable to find PSGI function entry point.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(SvTRUE(ERRSV)) {
|
||||
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
free(uperl.psgibuffer);
|
||||
close(uperl.fd);
|
||||
}
|
||||
|
||||
uwsgi_log("PSGI app (%s) loaded at %p\n", uperl.psgi, uperl.psgi_main);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+304
-190
@@ -8,67 +8,293 @@ struct uwsgi_perl uperl;
|
||||
struct option uwsgi_perl_options[] = {
|
||||
|
||||
{"psgi", required_argument, 0, LONG_ARGS_PSGI},
|
||||
{"perl-local-lib", required_argument, 0, LONG_ARGS_PERL_LOCAL_LIB},
|
||||
{0, 0, 0, 0},
|
||||
|
||||
};
|
||||
|
||||
extern struct http_status_codes hsc[];
|
||||
|
||||
XS(XS_stream)
|
||||
{
|
||||
dXSARGS;
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
SV *stack;
|
||||
AV *response;
|
||||
SV *uwsgi_perl_obj_new(char *class, size_t class_len) {
|
||||
|
||||
uwsgi_log("args: %d %p\n", items, wsgi_req);
|
||||
stack = ST(0);
|
||||
uwsgi_log("type %d\n", SvTYPE(stack));
|
||||
response = (AV* ) SvRV(stack) ;
|
||||
SV *newobj;
|
||||
// set current context ?
|
||||
//dTHX;
|
||||
dSP;
|
||||
|
||||
ENTER;
|
||||
SAVETMPS;
|
||||
PUSHMARK(SP);
|
||||
XPUSHs(sv_2mortal(newSVpv( class, class_len)));
|
||||
PUTBACK;
|
||||
|
||||
psgi_response(wsgi_req, my_perl, response);
|
||||
call_method( "new", G_SCALAR);
|
||||
|
||||
//mXPUSHp("x", 1);
|
||||
XSRETURN(0);
|
||||
SPAGAIN;
|
||||
|
||||
newobj = POPs;
|
||||
PUTBACK;
|
||||
FREETMPS;
|
||||
LEAVE;
|
||||
|
||||
return newobj;
|
||||
|
||||
}
|
||||
|
||||
SV *uwsgi_perl_call_stream(SV *func) {
|
||||
|
||||
SV *ret = NULL;
|
||||
// set current context ?
|
||||
//dTHX;
|
||||
dSP;
|
||||
|
||||
ENTER;
|
||||
SAVETMPS;
|
||||
PUSHMARK(SP);
|
||||
XPUSHs( sv_2mortal(newRV((SV*) uperl.stream_responder)));
|
||||
PUTBACK;
|
||||
|
||||
call_sv( func, G_SCALAR | G_EVAL);
|
||||
|
||||
SPAGAIN;
|
||||
if(SvTRUE(ERRSV)) {
|
||||
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
|
||||
}
|
||||
else {
|
||||
ret = SvREFCNT_inc(POPs);
|
||||
}
|
||||
|
||||
PUTBACK;
|
||||
FREETMPS;
|
||||
LEAVE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int uwsgi_perl_obj_can(SV *obj, char *method, size_t len) {
|
||||
|
||||
int ret;
|
||||
// set current context ? needed for threading
|
||||
//dTHX;
|
||||
dSP;
|
||||
|
||||
ENTER;
|
||||
SAVETMPS;
|
||||
PUSHMARK(SP);
|
||||
XPUSHs(obj);
|
||||
XPUSHs(sv_2mortal(newSVpv(method, len)));
|
||||
PUTBACK;
|
||||
|
||||
call_method( "can", G_SCALAR);
|
||||
|
||||
SPAGAIN;
|
||||
|
||||
ret = SvROK(POPs);
|
||||
PUTBACK;
|
||||
FREETMPS;
|
||||
LEAVE;
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* automatically generated */
|
||||
|
||||
EXTERN_C void xs_init (pTHX);
|
||||
SV *uwsgi_perl_obj_call(SV *obj, char *method) {
|
||||
|
||||
EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);
|
||||
SV *ret = NULL;
|
||||
|
||||
EXTERN_C void
|
||||
xs_init(pTHX)
|
||||
{
|
||||
char *file = __FILE__;
|
||||
dXSUB_SYS;
|
||||
dSP;
|
||||
|
||||
/* DynaLoader is a special case */
|
||||
newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
|
||||
ENTER;
|
||||
SAVETMPS;
|
||||
PUSHMARK(SP);
|
||||
|
||||
uperl.stream_responder = newXS("uwsgi::stream", XS_stream, "uwsgi");
|
||||
XPUSHs(obj);
|
||||
|
||||
#ifdef UWSGI_EMBEDDED
|
||||
init_perl_embedded_module();
|
||||
PUTBACK;
|
||||
|
||||
call_method( method, G_SCALAR | G_EVAL);
|
||||
|
||||
SPAGAIN;
|
||||
if(SvTRUE(ERRSV)) {
|
||||
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
|
||||
}
|
||||
else {
|
||||
ret = SvREFCNT_inc(POPs);
|
||||
}
|
||||
|
||||
PUTBACK;
|
||||
FREETMPS;
|
||||
LEAVE;
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
AV *psgi_call(struct wsgi_request *wsgi_req, SV *psgi_func, SV *env) {
|
||||
|
||||
AV *ret = NULL;
|
||||
|
||||
dSP;
|
||||
|
||||
ENTER;
|
||||
SAVETMPS;
|
||||
PUSHMARK(SP);
|
||||
XPUSHs(env);
|
||||
PUTBACK;
|
||||
|
||||
call_sv(psgi_func, G_SCALAR | G_EVAL);
|
||||
SPAGAIN;
|
||||
|
||||
if(SvTRUE(ERRSV)) {
|
||||
internal_server_error(wsgi_req, "exception raised");
|
||||
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
|
||||
}
|
||||
else {
|
||||
ret = (AV *) SvREFCNT_inc(SvRV(POPs));
|
||||
}
|
||||
|
||||
PUTBACK;
|
||||
FREETMPS;
|
||||
LEAVE;
|
||||
|
||||
return (AV *)ret;
|
||||
|
||||
}
|
||||
|
||||
SV *build_psgi_env(struct wsgi_request *wsgi_req) {
|
||||
int i;
|
||||
HV *env = newHV();
|
||||
|
||||
// fill perl hash
|
||||
for(i=0;i<wsgi_req->var_cnt;i++) {
|
||||
if (wsgi_req->hvec[i+1].iov_len > 0) {
|
||||
|
||||
// check for multiline header
|
||||
if (hv_exists(env, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len)) {
|
||||
SV **already_avalable_header = hv_fetch(env, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, 0);
|
||||
STRLEN hlen;
|
||||
char *old_value = SvPV(*already_avalable_header, hlen );
|
||||
char *multiline_header = uwsgi_concat3n(old_value, hlen, ", ", 2, wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len);
|
||||
if (!hv_store(env, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len,
|
||||
newSVpv(multiline_header, hlen+wsgi_req->hvec[i+1].iov_len+2), 0)) { free(multiline_header); goto clear;}
|
||||
free(multiline_header);
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
if (!hv_store(env, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len,
|
||||
newSVpv(wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len), 0)) goto clear;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!hv_store(env, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, newSVpv("", 0), 0)) goto clear;
|
||||
}
|
||||
//uwsgi_log("%.*s = %.*s\n", wsgi_req->hvec[i].iov_len, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i+1].iov_len, wsgi_req->hvec[i+1].iov_base);
|
||||
i++;
|
||||
}
|
||||
|
||||
// psgi.version
|
||||
AV *av = newAV();
|
||||
av_store( av, 0, newSViv(1));
|
||||
av_store( av, 1, newSViv(1));
|
||||
if (!hv_store(env, "psgi.version", 12, newRV_noinc((SV *)av ), 0)) goto clear;
|
||||
|
||||
if (uwsgi.numproc > 1) {
|
||||
if (!hv_store(env, "psgi.multiprocess", 17, newSViv(1), 0)) goto clear;
|
||||
}
|
||||
else {
|
||||
if (!hv_store(env, "psgi.multiprocess", 17, newSViv(0), 0)) goto clear;
|
||||
}
|
||||
|
||||
if (uwsgi.threads > 1) {
|
||||
if (!hv_store(env, "psgi.multithread", 16, newSViv(1), 0)) goto clear;
|
||||
}
|
||||
else {
|
||||
if (!hv_store(env, "psgi.multithread", 16, newSViv(0), 0)) goto clear;
|
||||
}
|
||||
|
||||
if (!hv_store(env, "psgi.run_once", 13, newSViv(0), 0)) goto clear;
|
||||
|
||||
#ifdef UWSGI_ASYNC
|
||||
if (uwsgi.async > 1) {
|
||||
if (!hv_store(env, "psgi.nonblocking", 16, newSViv(1), 0)) goto clear;
|
||||
}
|
||||
else {
|
||||
#else
|
||||
if (!hv_store(env, "psgi.nonblocking", 16, newSViv(0), 0)) goto clear;
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_ASYNC
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!hv_store(env, "psgi.streaming", 14, newSViv(1), 0)) goto clear;
|
||||
|
||||
SV *us;
|
||||
// psgi.url_scheme, honour HTTPS var or UWSGI_SCHEME
|
||||
if (wsgi_req->scheme_len > 0) {
|
||||
us = newSVpv(wsgi_req->scheme, wsgi_req->scheme_len);
|
||||
}
|
||||
else if (wsgi_req->https_len > 0) {
|
||||
if (!strncasecmp(wsgi_req->https, "on", 2) || wsgi_req->https[0] == '1') {
|
||||
us = newSVpv("https", 5);
|
||||
}
|
||||
else {
|
||||
us = newSVpv("http", 4);
|
||||
}
|
||||
}
|
||||
else {
|
||||
us = newSVpv("http", 4);
|
||||
}
|
||||
|
||||
if (!hv_store(env, "psgi.url_scheme", 15, us, 0)) goto clear;
|
||||
|
||||
|
||||
SV *pi = uwsgi_perl_obj_new("uwsgi::input", 12);
|
||||
if (!hv_store(env, "psgi.input", 10, pi, 0)) goto clear;
|
||||
|
||||
if (!hv_store(env, "psgix.input.buffered", 20, newSViv(wsgi_req->body_as_file), 0)) goto clear;
|
||||
|
||||
if (uwsgi.master_process) {
|
||||
if (!hv_store(env, "psgix.harakiri", 14, newSViv(1), 0)) goto clear;
|
||||
}
|
||||
|
||||
SV *pe = uwsgi_perl_obj_new("uwsgi::error", 12);
|
||||
if (!hv_store(env, "psgi.errors", 11, pe, 0)) goto clear;
|
||||
|
||||
return newRV_noinc((SV *)env);
|
||||
|
||||
clear:
|
||||
SvREFCNT_dec((SV *)env);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* end of automagically generated part */
|
||||
|
||||
|
||||
int uwsgi_perl_init(){
|
||||
|
||||
|
||||
struct http_status_codes *http_sc;
|
||||
|
||||
int argc = 4;
|
||||
char *embedding[] = { "", "-e", "-e", "0" };
|
||||
int argc = 3;
|
||||
uperl.embedding[0] = "";
|
||||
uperl.embedding[1] = "-e";
|
||||
uperl.embedding[2] = "0";
|
||||
|
||||
if (setenv("PLACK_ENV", "uwsgi", 0)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
|
||||
if (setenv("PLACK_SERVER", "uwsgi", 0)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
|
||||
#ifdef PERL_VERSION_STRING
|
||||
uwsgi_log("initializing Perl %s environment\n", PERL_VERSION_STRING);
|
||||
#else
|
||||
uwsgi_log("initializing Perl environment\n");
|
||||
PERL_SYS_INIT3(&argc, (char ***) &embedding, &environ);
|
||||
#endif
|
||||
PERL_SYS_INIT3(&argc, (char ***) &uperl.embedding, &environ);
|
||||
uperl.main = perl_alloc();
|
||||
if (!uperl.main) {
|
||||
uwsgi_log("unable to allocate perl interpreter\n");
|
||||
@@ -79,6 +305,7 @@ int uwsgi_perl_init(){
|
||||
PERL_SET_CONTEXT(uperl.main);
|
||||
|
||||
PL_perl_destruct_level = 2;
|
||||
PL_origalen = 1;
|
||||
perl_construct(uperl.main);
|
||||
|
||||
// filling http status codes
|
||||
@@ -87,65 +314,12 @@ int uwsgi_perl_init(){
|
||||
}
|
||||
|
||||
PL_origalen = 1;
|
||||
perl_parse(uperl.main, xs_init, 4, embedding, NULL);
|
||||
|
||||
perl_eval_pv("use IO::Handle;", 0);
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_psgi_app() {
|
||||
|
||||
struct stat stat_psgi;
|
||||
|
||||
if (uperl.psgi) {
|
||||
uperl.fd = open(uperl.psgi, O_RDONLY);
|
||||
if (uperl.fd < 0) {
|
||||
uwsgi_error_open(uperl.psgi);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (fstat(uperl.fd, &stat_psgi)) {
|
||||
uwsgi_error("fstat()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uperl.psgibuffer = malloc(stat_psgi.st_size + 1);
|
||||
if (!uperl.psgibuffer) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (read(uperl.fd, uperl.psgibuffer, stat_psgi.st_size) != stat_psgi.st_size) {
|
||||
uwsgi_error("read()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uperl.psgibuffer[stat_psgi.st_size] = 0;
|
||||
|
||||
if (uwsgi.threads < 2) {
|
||||
uperl.psgi_main = perl_eval_pv(uperl.psgibuffer, 0);
|
||||
if (!uperl.psgi_main) {
|
||||
uwsgi_log("unable to find PSGI function entry point.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(SvTRUE(ERRSV)) {
|
||||
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
free(uperl.psgibuffer);
|
||||
close(uperl.fd);
|
||||
}
|
||||
|
||||
uwsgi_log("PSGI app (%s) loaded at %p\n", uperl.psgi, uperl.psgi_main);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#ifdef my_perl
|
||||
void uwsgi_perl_enable_threads() {
|
||||
|
||||
int i;
|
||||
@@ -192,24 +366,22 @@ void uwsgi_perl_enable_threads() {
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
int uwsgi_perl_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
HV *env;
|
||||
SV **item;
|
||||
|
||||
AV *response;
|
||||
|
||||
SV *io_new, *io_err;
|
||||
int i;
|
||||
|
||||
SV **harakiri;
|
||||
SV *psgi_func = uperl.psgi_main;
|
||||
// ugly hack
|
||||
register PerlInterpreter *my_perl = uperl.main;
|
||||
dSP;
|
||||
|
||||
#ifdef UWSGI_ASYNC
|
||||
if (wsgi_req->async_status == UWSGI_AGAIN) {
|
||||
return psgi_response(wsgi_req, my_perl, wsgi_req->async_placeholder);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Standard PSGI request */
|
||||
if (!wsgi_req->uh.pktsize) {
|
||||
@@ -219,7 +391,6 @@ int uwsgi_perl_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
|
||||
if (uwsgi_parse_vars(wsgi_req)) {
|
||||
uwsgi_log("Invalid PSGI request. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -236,116 +407,48 @@ int uwsgi_perl_request(struct wsgi_request *wsgi_req) {
|
||||
SAVETMPS;
|
||||
|
||||
|
||||
env = (HV*) sv_2mortal((SV*)newHV());
|
||||
wsgi_req->async_environ = build_psgi_env(wsgi_req);
|
||||
if (!wsgi_req->async_environ) goto clear;
|
||||
|
||||
wsgi_req->async_result = psgi_call(wsgi_req, psgi_func, wsgi_req->async_environ);
|
||||
if (!wsgi_req->async_result) goto clear;
|
||||
|
||||
// fill perl hash
|
||||
for(i=0;i<wsgi_req->var_cnt;i++) {
|
||||
if (wsgi_req->hvec[i+1].iov_len > 0) {
|
||||
|
||||
item = hv_store(env, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len,
|
||||
newSVpv(wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len), 0);
|
||||
if (SvTYPE((AV *)wsgi_req->async_result) == SVt_PVCV) {
|
||||
SV *stream_result = uwsgi_perl_call_stream((SV*)wsgi_req->async_result);
|
||||
if (!stream_result) {
|
||||
internal_server_error(wsgi_req, "exception raised");
|
||||
}
|
||||
else {
|
||||
item = hv_store(env, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, newSVpv("", 0), 0);
|
||||
SvREFCNT_dec(stream_result);
|
||||
}
|
||||
//uwsgi_log("%.*s = %.*s\n", wsgi_req->hvec[i].iov_len, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i+1].iov_len, wsgi_req->hvec[i+1].iov_base);
|
||||
i++;
|
||||
goto clear2;
|
||||
}
|
||||
|
||||
|
||||
SV *us = newSVpv("http", 4);
|
||||
item = hv_store(env, "psgi.url_scheme", 15, us, 0);
|
||||
|
||||
|
||||
SV* iohandle = newSVpv( "IO::Handle", 10 );
|
||||
|
||||
|
||||
PUSHMARK(SP);
|
||||
XPUSHs( sv_2mortal(iohandle));
|
||||
PUTBACK;
|
||||
perl_call_method( "new", G_SCALAR);
|
||||
SPAGAIN;
|
||||
io_new = POPs;
|
||||
|
||||
PUSHMARK(SP);
|
||||
XPUSHs( io_new );
|
||||
XPUSHs( sv_2mortal(newSViv( wsgi_req->poll.fd)));
|
||||
XPUSHs( sv_2mortal(newSVpv( "r", 1)));
|
||||
PUTBACK;
|
||||
perl_call_method( "fdopen", G_SCALAR);
|
||||
SPAGAIN;
|
||||
|
||||
|
||||
|
||||
|
||||
SV *pi = SvREFCNT_inc(POPs);
|
||||
item = hv_store(env, "psgi.input", 10, pi, 0);
|
||||
|
||||
|
||||
PUSHMARK(SP);
|
||||
XPUSHs( newSVpv( "IO::Handle", 10 ));
|
||||
PUTBACK;
|
||||
perl_call_method( "new", G_SCALAR);
|
||||
SPAGAIN;
|
||||
io_err = POPs;
|
||||
|
||||
PUSHMARK(SP);
|
||||
XPUSHs( io_err );
|
||||
XPUSHs( sv_2mortal( newSViv( 2 )));
|
||||
XPUSHs( sv_2mortal( newSVpv( "w", 1)));
|
||||
PUTBACK;
|
||||
perl_call_method( "fdopen", G_SCALAR);
|
||||
SPAGAIN;
|
||||
|
||||
SV *pe = SvREFCNT_inc(POPs);
|
||||
item = hv_store(env, "psgi.errors", 11, pe, 0);
|
||||
|
||||
|
||||
PUSHMARK(SP);
|
||||
XPUSHs( sv_2mortal(newRV((SV *)env )) );
|
||||
PUTBACK;
|
||||
|
||||
|
||||
perl_call_sv(psgi_func, G_SCALAR);
|
||||
|
||||
|
||||
if(SvTRUE(ERRSV)) {
|
||||
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
|
||||
goto clear;
|
||||
}
|
||||
SPAGAIN;
|
||||
// no leaks to here
|
||||
|
||||
// dereference output
|
||||
response = (AV *) SvRV( POPs );
|
||||
|
||||
//uwsgi_log("response: %p %d\n", response, SvTYPE(response));
|
||||
|
||||
if (SvTYPE(response) == SVt_PVCV) {
|
||||
uwsgi_log("streaming response\n");
|
||||
|
||||
PUSHMARK(SP);
|
||||
XPUSHs( newRV((SV*) uperl.stream_responder));
|
||||
PUTBACK;
|
||||
|
||||
perl_call_sv( (SV*)response, G_SCALAR);
|
||||
|
||||
if(SvTRUE(ERRSV)) {
|
||||
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
|
||||
while (psgi_response(wsgi_req, my_perl, wsgi_req->async_result) != UWSGI_OK) {
|
||||
#ifdef UWSGI_ASYNC
|
||||
if (uwsgi.async > 1) {
|
||||
FREETMPS;
|
||||
LEAVE;
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
|
||||
goto clear;
|
||||
#endif
|
||||
}
|
||||
|
||||
psgi_response(wsgi_req, my_perl, response);
|
||||
clear2:
|
||||
// check for psgix.harakiri
|
||||
harakiri = hv_fetch((HV*)SvRV( (SV*)wsgi_req->async_environ), "psgix.harakiri.commit", 21, 0);
|
||||
if (harakiri) {
|
||||
if (SvTRUE(*harakiri)) wsgi_req->async_plagued = 1;
|
||||
}
|
||||
|
||||
SvREFCNT_dec(wsgi_req->async_environ);
|
||||
SvREFCNT_dec(wsgi_req->async_result);
|
||||
clear:
|
||||
|
||||
FREETMPS;
|
||||
LEAVE;
|
||||
|
||||
return 0;
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -353,6 +456,12 @@ void uwsgi_perl_after_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_LOGGING])
|
||||
log_request(wsgi_req);
|
||||
|
||||
if (wsgi_req->async_plagued) {
|
||||
uwsgi_log("*** psgix.harakiri.commit requested ***\n");
|
||||
goodbye_cruel_world();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_perl_init_thread(int core_id) {
|
||||
@@ -382,6 +491,9 @@ int uwsgi_perl_manage_options(int i, char *optarg) {
|
||||
case LONG_ARGS_PSGI:
|
||||
uperl.psgi = optarg;
|
||||
return 1;
|
||||
case LONG_ARGS_PERL_LOCAL_LIB:
|
||||
uperl.locallib = optarg;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -412,7 +524,9 @@ struct uwsgi_plugin psgi_plugin = {
|
||||
.init_apps = uwsgi_psgi_app,
|
||||
//.magic = uwsgi_perl_magic,
|
||||
//.help = uwsgi_perl_help,
|
||||
#ifdef my_perl
|
||||
.enable_threads = uwsgi_perl_enable_threads,
|
||||
#endif
|
||||
.manage_opt = uwsgi_perl_manage_options,
|
||||
.init_thread = uwsgi_perl_init_thread,
|
||||
.request = uwsgi_perl_request,
|
||||
|
||||
+110
-19
@@ -1,5 +1,7 @@
|
||||
#include "psgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/* statistically ordered */
|
||||
struct http_status_codes hsc[] = {
|
||||
{"200", "OK"},
|
||||
@@ -55,16 +57,61 @@ int psgi_response(struct wsgi_request *wsgi_req, PerlInterpreter *my_perl, AV *r
|
||||
struct http_status_codes *http_sc;
|
||||
int i,vi, base;
|
||||
char *chitem;
|
||||
dSP;
|
||||
SV **harakiri;
|
||||
|
||||
#ifdef UWSGI_ASYNC
|
||||
if (wsgi_req->async_status == UWSGI_AGAIN) {
|
||||
|
||||
wsgi_req->async_force_again = 0;
|
||||
|
||||
wsgi_req->switches++;
|
||||
SV *chunk = uwsgi_perl_obj_call(wsgi_req->async_placeholder, "getline");
|
||||
if (!chunk) {
|
||||
internal_server_error(wsgi_req, "exception raised");
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
if (wsgi_req->async_force_again) {
|
||||
SvREFCNT_dec(chunk);
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
|
||||
chitem = SvPV( chunk, hlen);
|
||||
|
||||
if (hlen <= 0) {
|
||||
SvREFCNT_dec(chunk);
|
||||
SV *closed = uwsgi_perl_obj_call(wsgi_req->async_placeholder, "close");
|
||||
if (closed) {
|
||||
SvREFCNT_dec(closed);
|
||||
}
|
||||
|
||||
// check for psgix.harakiri
|
||||
harakiri = hv_fetch((HV*)SvRV( (SV*)wsgi_req->async_environ), "psgix.harakiri.commit", 21, 0);
|
||||
if (harakiri) {
|
||||
if (SvTRUE(*harakiri)) wsgi_req->async_plagued = 1;
|
||||
}
|
||||
|
||||
SvREFCNT_dec(wsgi_req->async_environ);
|
||||
SvREFCNT_dec(wsgi_req->async_result);
|
||||
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, chitem, hlen);
|
||||
SvREFCNT_dec(chunk);
|
||||
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
#endif
|
||||
|
||||
status_code = av_fetch(response, 0, 0);
|
||||
if (!status_code) { uwsgi_log("invalid PSGI status code\n"); return UWSGI_OK;}
|
||||
|
||||
wsgi_req->hvec[0].iov_base = "HTTP/1.1 ";
|
||||
wsgi_req->hvec[0].iov_len = 9;
|
||||
|
||||
//uwsgi_log("setting status %d %d\n", SvTYPE(*status_code), SvIV(*status_code));
|
||||
|
||||
wsgi_req->hvec[1].iov_base = SvPV(*status_code, hlen);
|
||||
|
||||
wsgi_req->hvec[1].iov_len = 3;
|
||||
|
||||
wsgi_req->status = atoi(wsgi_req->hvec[1].iov_base);
|
||||
@@ -92,8 +139,10 @@ int psgi_response(struct wsgi_request *wsgi_req, PerlInterpreter *my_perl, AV *r
|
||||
wsgi_req->hvec[4].iov_len = 2;
|
||||
|
||||
hitem = av_fetch(response, 1, 0);
|
||||
if (!hitem) { uwsgi_log("invalid PSGI headers\n"); return UWSGI_OK;}
|
||||
|
||||
headers = (AV *) SvRV(*hitem);
|
||||
if (!headers) { uwsgi_log("invalid PSGI headers\n"); return UWSGI_OK;}
|
||||
|
||||
base = 5;
|
||||
|
||||
@@ -122,34 +171,76 @@ int psgi_response(struct wsgi_request *wsgi_req, PerlInterpreter *my_perl, AV *r
|
||||
vi = (i*2)+base;
|
||||
wsgi_req->hvec[vi].iov_base = "\r\n"; wsgi_req->hvec[vi].iov_len = 2;
|
||||
|
||||
if ( !(wsgi_req->headers_size = writev(wsgi_req->poll.fd, wsgi_req->hvec, vi+1)) ) {
|
||||
if ( !(wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, wsgi_req->hvec, vi+1)) ) {
|
||||
uwsgi_error("writev()");
|
||||
}
|
||||
|
||||
hitem = av_fetch(response, 2, 0);
|
||||
|
||||
if (SvTYPE(SvRV(*hitem)) == SVt_PVGV || SvTYPE(SvRV(*hitem)) == SVt_PVHV) {
|
||||
if (!hitem) {
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
if (!SvRV(*hitem)) { uwsgi_log("invalid PSGI response body\n") ; return UWSGI_OK; }
|
||||
|
||||
if (SvTYPE(SvRV(*hitem)) == SVt_PVGV || SvTYPE(SvRV(*hitem)) == SVt_PVHV || SvTYPE(SvRV(*hitem)) == SVt_PVMG) {
|
||||
|
||||
// respond to fileno ?
|
||||
if (uwsgi.async < 2) {
|
||||
if (uwsgi_perl_obj_can(*hitem, "fileno", 6)) {
|
||||
SV *fn = uwsgi_perl_obj_call(*hitem, "fileno");
|
||||
wsgi_req->sendfile_fd = SvIV(fn);
|
||||
SvREFCNT_dec(fn);
|
||||
wsgi_req->response_size += uwsgi_sendfile(wsgi_req);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
if (uwsgi_perl_obj_can(*hitem, "path", 4)) {
|
||||
SV *p = uwsgi_perl_obj_call(*hitem, "path");
|
||||
wsgi_req->sendfile_fd = open(SvPV_nolen(p), O_RDONLY);
|
||||
SvREFCNT_dec(p);
|
||||
wsgi_req->response_size += uwsgi_sendfile(wsgi_req);
|
||||
close(wsgi_req->sendfile_fd);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
PUSHMARK(SP);
|
||||
XPUSHs(*hitem);
|
||||
PUTBACK;
|
||||
perl_call_method("getline", G_SCALAR);
|
||||
SPAGAIN;
|
||||
|
||||
if(SvTRUE(ERRSV)) {
|
||||
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
|
||||
break;
|
||||
}
|
||||
|
||||
SV *chunk = POPs;
|
||||
wsgi_req->switches++;
|
||||
SV *chunk = uwsgi_perl_obj_call(*hitem, "getline");
|
||||
if (!chunk) {
|
||||
internal_server_error(wsgi_req, "exception raised");
|
||||
break;
|
||||
}
|
||||
chitem = SvPV( chunk, hlen);
|
||||
#ifdef UWSGI_ASYNC
|
||||
if (uwsgi.async > 1 && wsgi_req->async_force_again) {
|
||||
SvREFCNT_dec(chunk);
|
||||
wsgi_req->async_status = UWSGI_AGAIN;
|
||||
wsgi_req->async_placeholder = (SV *) *hitem;
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
#endif
|
||||
if (hlen <= 0) {
|
||||
SvREFCNT_dec(chunk);
|
||||
break;
|
||||
}
|
||||
wsgi_req->response_size = write(wsgi_req->poll.fd, chitem, hlen);
|
||||
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, chitem, hlen);
|
||||
SvREFCNT_dec(chunk);
|
||||
#ifdef UWSGI_ASYNC
|
||||
if (uwsgi.async > 1) {
|
||||
wsgi_req->async_status = UWSGI_AGAIN;
|
||||
wsgi_req->async_placeholder = (SV *) *hitem;
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SV *closed = uwsgi_perl_obj_call(*hitem, "close");
|
||||
if (closed) {
|
||||
SvREFCNT_dec(closed);
|
||||
}
|
||||
|
||||
}
|
||||
else if (SvTYPE(SvRV(*hitem)) == SVt_PVAV) {
|
||||
@@ -159,7 +250,7 @@ int psgi_response(struct wsgi_request *wsgi_req, PerlInterpreter *my_perl, AV *r
|
||||
for(i=0; i<=av_len(body); i++) {
|
||||
hitem = av_fetch(body,i,0);
|
||||
chitem = SvPV(*hitem, hlen);
|
||||
wsgi_req->response_size = write(wsgi_req->poll.fd, chitem, hlen);
|
||||
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, chitem, hlen);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -167,6 +258,6 @@ int psgi_response(struct wsgi_request *wsgi_req, PerlInterpreter *my_perl, AV *r
|
||||
uwsgi_log("unsupported response body type: %d\n", SvTYPE(SvRV(*hitem)));
|
||||
}
|
||||
|
||||
return 1;
|
||||
return UWSGI_OK;
|
||||
|
||||
}
|
||||
|
||||
@@ -2,12 +2,85 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#define psgi_xs(func) newXS("uwsgi::" #func, XS_##func, "uwsgi")
|
||||
#define psgi_check_args(x) if (items < x) Perl_croak(aTHX_ "Usage: uwsgi::%s takes %d arguments", __FUNCTION__ + 3, x)
|
||||
#ifdef UWSGI_ASYNC
|
||||
|
||||
|
||||
XS(XS_async_sleep) {
|
||||
|
||||
dXSARGS;
|
||||
int timeout ;
|
||||
|
||||
psgi_check_args(1);
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
timeout = SvIV(ST(0));
|
||||
|
||||
if (timeout >= 0) {
|
||||
async_add_timeout(wsgi_req, timeout);
|
||||
}
|
||||
|
||||
wsgi_req->async_force_again = 1;
|
||||
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
|
||||
|
||||
|
||||
XS(XS_wait_fd_read) {
|
||||
|
||||
dXSARGS;
|
||||
int fd, timeout = 0;
|
||||
|
||||
psgi_check_args(1);
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
fd = SvIV(ST(0));
|
||||
if (items > 1) {
|
||||
timeout = SvIV(ST(1));
|
||||
}
|
||||
|
||||
if (fd >= 0) {
|
||||
async_add_fd_read(wsgi_req, fd, timeout);
|
||||
}
|
||||
|
||||
wsgi_req->async_force_again = 1;
|
||||
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
|
||||
|
||||
XS(XS_wait_fd_write) {
|
||||
|
||||
dXSARGS;
|
||||
int fd, timeout = 0;
|
||||
|
||||
psgi_check_args(1);
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
fd = SvIV(ST(0));
|
||||
if (items > 1) {
|
||||
timeout = SvIV(ST(1));
|
||||
}
|
||||
|
||||
if (fd >= 0) {
|
||||
async_add_fd_read(wsgi_req, fd, timeout);
|
||||
}
|
||||
|
||||
wsgi_req->async_force_again = 1;
|
||||
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
XS(XS_reload) {
|
||||
dXSARGS;
|
||||
items = 0;
|
||||
|
||||
psgi_check_args(0);
|
||||
|
||||
uwsgi_log("SENDING HUP TO %d\n", (int) uwsgi.workers[0].pid);
|
||||
if (kill(uwsgi.workers[0].pid, SIGHUP)) {
|
||||
@@ -57,6 +130,27 @@ XS(XS_cache_get) {
|
||||
|
||||
}
|
||||
|
||||
XS(XS_log) {
|
||||
|
||||
dXSARGS;
|
||||
|
||||
psgi_check_args(1);
|
||||
|
||||
uwsgi_log("%s", SvPV_nolen(ST(0)));
|
||||
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
|
||||
XS(XS_async_connect) {
|
||||
|
||||
dXSARGS;
|
||||
psgi_check_args(1);
|
||||
|
||||
ST(0) = newSViv(uwsgi_connect(SvPV_nolen(ST(0)), 0, 1));
|
||||
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_call) {
|
||||
|
||||
dXSARGS;
|
||||
@@ -88,11 +182,30 @@ XS(XS_call) {
|
||||
}
|
||||
|
||||
|
||||
XS(XS_suspend) {
|
||||
|
||||
dXSARGS;
|
||||
psgi_check_args(0);
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
wsgi_req->async_force_again = 0;
|
||||
|
||||
if (uwsgi.schedule_to_main) uwsgi.schedule_to_main(wsgi_req);
|
||||
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
|
||||
void init_perl_embedded_module() {
|
||||
psgi_xs(reload);
|
||||
psgi_xs(cache_set);
|
||||
psgi_xs(cache_get);
|
||||
psgi_xs(call);
|
||||
psgi_xs(wait_fd_read);
|
||||
psgi_xs(wait_fd_write);
|
||||
psgi_xs(async_sleep);
|
||||
psgi_xs(log);
|
||||
psgi_xs(async_connect);
|
||||
psgi_xs(suspend);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,4 +4,4 @@ NAME='psgi'
|
||||
CFLAGS = [os.popen('perl -MExtUtils::Embed -e ccopts').read().rstrip()]
|
||||
LDFLAGS = [os.popen('perl -MExtUtils::Embed -e ldopts').read().rstrip()]
|
||||
LIBS = []
|
||||
GCC_LIST = ['uwsgi_plmodule', 'psgi_response', 'psgi_plugin']
|
||||
GCC_LIST = ['uwsgi_plmodule', 'psgi_loader', 'psgi_response', 'psgi_plugin']
|
||||
|
||||
@@ -301,11 +301,10 @@ recv:
|
||||
void pyerl_call_registered(void *func, ei_x_buff *x) {
|
||||
|
||||
PyObject *pyargs = PyTuple_New(1);
|
||||
PyObject *ret;
|
||||
|
||||
PyTuple_SetItem(pyargs, 0, erl_to_py(x));
|
||||
|
||||
ret = python_call((PyObject *) func, pyargs, 0);
|
||||
python_call((PyObject *) func, pyargs, 0);
|
||||
}
|
||||
|
||||
PyObject *pyerl_register_process(PyObject * self, PyObject * args) {
|
||||
|
||||
@@ -4,15 +4,19 @@ extern struct uwsgi_server uwsgi;
|
||||
extern struct uwsgi_python up;
|
||||
|
||||
void gil_real_get() {
|
||||
//uwsgi_log("LOCK %d\n", uwsgi.mywid);
|
||||
#ifndef PYTHREE
|
||||
PyEval_AcquireLock();
|
||||
PyThreadState_Swap((PyThreadState *) pthread_getspecific(up.upt_gil_key));
|
||||
#else
|
||||
PyEval_RestoreThread((PyThreadState *) pthread_getspecific(up.upt_gil_key));
|
||||
#endif
|
||||
|
||||
//uwsgi_log("LOCKED !!! %d\n", uwsgi.mywid);
|
||||
}
|
||||
|
||||
void gil_real_release() {
|
||||
//uwsgi_log("UNLOCK %d\n", uwsgi.mywid);
|
||||
#ifndef PYTHREE
|
||||
pthread_setspecific(up.upt_gil_key, (void *) PyThreadState_Swap(NULL));
|
||||
PyEval_ReleaseLock();
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#include "uwsgi_python.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#ifdef HAS_NOT_PyFrame_GetLineNumber
|
||||
int PyFrame_GetLineNumber(PyFrameObject *frame) {
|
||||
if (frame->f_trace) {
|
||||
return frame->f_lineno;
|
||||
}
|
||||
else {
|
||||
return PyCode_Addr2Line(frame->f_code, frame->f_lasti);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int uwsgi_python_profiler_call(PyObject *obj, PyFrameObject *frame, int what, PyObject *arg) {
|
||||
|
||||
switch(what) {
|
||||
case PyTrace_CALL:
|
||||
uwsgi_log("[uWSGI Python profiler] CALL: %s (line %d) -> %s %d args, stacksize %d\n",
|
||||
PyString_AsString(frame->f_code->co_filename),
|
||||
PyFrame_GetLineNumber(frame),
|
||||
PyString_AsString(frame->f_code->co_name), frame->f_code->co_argcount, frame->f_code->co_stacksize);
|
||||
break;
|
||||
case PyTrace_C_CALL:
|
||||
uwsgi_log("[uWSGI Python profiler] C CALL: %s (line %d) -> %s %d args, stacksize %d\n",
|
||||
PyString_AsString(frame->f_code->co_filename),
|
||||
PyFrame_GetLineNumber(frame),
|
||||
PyEval_GetFuncName(arg), frame->f_code->co_argcount, frame->f_code->co_stacksize);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
exit(1) on every malloc error: apps can be dinamically loaded so on memory problem
|
||||
it is better to let the master process manager respawn the worker.
|
||||
|
||||
TODO dynamic loading on prefork+thread looks flaky... NEED TO FIX IT
|
||||
*/
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
@@ -36,7 +38,6 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
|
||||
|
||||
struct uwsgi_app *wi;
|
||||
|
||||
|
||||
if (wsgi_req->script_name_len == 0) {
|
||||
wsgi_req->script_name = "";
|
||||
}
|
||||
@@ -48,7 +49,7 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
|
||||
}
|
||||
|
||||
|
||||
if (uwsgi.vhost && wsgi_req->host_len > 0) {
|
||||
if (uwsgi.vhost) {
|
||||
mountpoint = uwsgi_concat3n(wsgi_req->host, wsgi_req->host_len, "|", 1, wsgi_req->script_name, wsgi_req->script_name_len);
|
||||
}
|
||||
else {
|
||||
@@ -112,7 +113,6 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
|
||||
uwsgi_log("%s = %s\n", PyString_AsString(k), PyString_AsString(env_value));
|
||||
|
||||
if (PyObject_SetItem(py_environ, k, env_value)) {
|
||||
uwsgi_log("cazzo\n");
|
||||
PyErr_Print();
|
||||
}
|
||||
|
||||
@@ -125,7 +125,6 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (interpreter == NULL && id) {
|
||||
wi->interpreter = Py_NewInterpreter();
|
||||
if (!wi->interpreter) {
|
||||
@@ -149,6 +148,14 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
|
||||
wi->interpreter = up.main_thread;
|
||||
}
|
||||
|
||||
if (wsgi_req->touch_reload_len) {
|
||||
struct stat trst;
|
||||
char *touch_reload = uwsgi_strncopy(wsgi_req->touch_reload, wsgi_req->touch_reload_len);
|
||||
if (!stat(touch_reload, &trst)) {
|
||||
wi->touch_reload = touch_reload;
|
||||
wi->touch_reload_mtime = trst.st_mtime;
|
||||
}
|
||||
}
|
||||
|
||||
wi->callable = up.loaders[loader](arg1);
|
||||
|
||||
@@ -296,6 +303,7 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
|
||||
if (uwsgi.threads > 1 && id) {
|
||||
// if we have multiple threads we need to initialize a PyThreadState for each one
|
||||
for(i=0;i<uwsgi.threads;i++) {
|
||||
//uwsgi_log("%p\n", uwsgi.core[i]->ts[id]);
|
||||
uwsgi.core[i]->ts[id] = PyThreadState_New( ((PyThreadState *)wi->interpreter)->interp);
|
||||
if (!uwsgi.core[i]->ts[id]) {
|
||||
uwsgi_log("unable to allocate new PyThreadState structure for app %s", mountpoint);
|
||||
@@ -312,7 +320,7 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
|
||||
uwsgi_log( "Web3 application %d (SCRIPT_NAME=%.*s) ready on interpreter %p", id, wi->mountpoint_len, wi->mountpoint, wi->interpreter);
|
||||
}
|
||||
else {
|
||||
uwsgi_log( "WSGI application %d (SCRIPT_NAME=%.*s) ready on interpreter %p", id, wi->mountpoint_len, wi->mountpoint, wi->interpreter);
|
||||
uwsgi_log( "WSGI application %d (SCRIPT_NAME=%.*s) ready on interpreter %p pid: %d", id, wi->mountpoint_len, wi->mountpoint, wi->interpreter, (int) getpid());
|
||||
}
|
||||
|
||||
if (!wsgi_req->script_name_len) {
|
||||
@@ -431,6 +439,7 @@ PyObject *uwsgi_uwsgi_loader(void *arg1) {
|
||||
if (quick_callable[strlen(quick_callable) -2 ] == '(' && quick_callable[strlen(quick_callable) -1] ==')') {
|
||||
quick_callable[strlen(quick_callable) -2 ] = 0;
|
||||
tmp_callable = PyDict_GetItemString(wsgi_dict, quick_callable);
|
||||
quick_callable[strlen(quick_callable)] = '(';
|
||||
if (tmp_callable) {
|
||||
return python_call(tmp_callable, PyTuple_New(0), 0);
|
||||
}
|
||||
@@ -511,8 +520,14 @@ PyObject *uwsgi_file_loader(void *arg1) {
|
||||
PyObject *wsgi_file_module, *wsgi_file_dict;
|
||||
PyObject *wsgi_file_callable;
|
||||
|
||||
char *callable = up.callable;
|
||||
if (!callable) callable = "application";
|
||||
|
||||
wsgi_file_module = uwsgi_pyimport_by_filename("uwsgi_wsgi_file", filename);
|
||||
// no need to check here for module import as it is already done by uwsgi_pyimport_by_file
|
||||
if (!wsgi_file_module) {
|
||||
PyErr_Print();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
wsgi_file_dict = PyModule_GetDict(wsgi_file_module);
|
||||
if (!wsgi_file_dict) {
|
||||
@@ -520,7 +535,7 @@ PyObject *uwsgi_file_loader(void *arg1) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
wsgi_file_callable = PyDict_GetItemString(wsgi_file_dict, "application");
|
||||
wsgi_file_callable = PyDict_GetItemString(wsgi_file_dict, callable);
|
||||
if (!wsgi_file_callable) {
|
||||
PyErr_Print();
|
||||
uwsgi_log( "unable to find \"application\" callable in file %s\n", filename);
|
||||
|
||||
+184
-60
@@ -3,6 +3,8 @@
|
||||
extern struct uwsgi_server uwsgi;
|
||||
struct uwsgi_python up;
|
||||
|
||||
#include <glob.h>
|
||||
|
||||
extern PyTypeObject uwsgi_InputType;
|
||||
|
||||
struct option uwsgi_python_options[] = {
|
||||
@@ -40,6 +42,9 @@ struct uwsgi_help_item uwsgi_python_help[] = {
|
||||
{"module <module>" ,"name of python config module"},
|
||||
{"optimize <n>", "set python optimization level to <n>"},
|
||||
{"home <path>", "set python home/virtualenv"},
|
||||
{"pyhome <path>", "set python home/virtualenv"},
|
||||
{"virtualenv <path>", "set python home/virtualenv"},
|
||||
{"venv <path>", "set python home/virtualenv"},
|
||||
{"callable <callable>", "set the callable (default 'application')"},
|
||||
{"paste <config:/egg:>", "load applications using paste.deploy.loadapp()"},
|
||||
{"pythonpath <dir>", "add <dir> to PYTHONPATH"},
|
||||
@@ -82,20 +87,21 @@ int uwsgi_python_init() {
|
||||
uwsgi_log("Python version: %.*s %s\n", pyversion-Py_GetVersion(), Py_GetVersion(), Py_GetCompiler()+1);
|
||||
|
||||
if (up.home != NULL) {
|
||||
uwsgi_log("Setting PythonHome to %s...\n", up.home);
|
||||
#ifdef PYTHREE
|
||||
wchar_t *wpyhome;
|
||||
wpyhome = malloc((sizeof(wchar_t) * strlen(up.home)) + 2);
|
||||
wpyhome = malloc((sizeof(wchar_t) * strlen(up.home)) + sizeof(wchar_t) );
|
||||
if (!wpyhome) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
}
|
||||
mbstowcs(wpyhome, up.home, strlen(up.home));
|
||||
Py_SetPythonHome(wpyhome);
|
||||
free(wpyhome);
|
||||
// do not free this memory !!!
|
||||
//free(wpyhome);
|
||||
#else
|
||||
Py_SetPythonHome(up.home);
|
||||
#endif
|
||||
uwsgi_log("Set PythonHome to %s\n", up.home);
|
||||
}
|
||||
|
||||
#ifdef PYTHREE
|
||||
@@ -131,27 +137,32 @@ int uwsgi_python_init() {
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_python_post_fork() {
|
||||
void uwsgi_python_reset_random_seed() {
|
||||
|
||||
PyObject *random_module, *random_dict, *random_seed;
|
||||
|
||||
// reinitialize the random seed (thanks Jonas Borgström)
|
||||
random_module = PyImport_ImportModule("random");
|
||||
if (random_module) {
|
||||
random_dict = PyModule_GetDict(random_module);
|
||||
if (random_dict) {
|
||||
random_seed = PyDict_GetItemString(random_dict, "seed");
|
||||
if (random_seed) {
|
||||
PyObject *random_args = PyTuple_New(1);
|
||||
// pass no args
|
||||
PyTuple_SetItem(random_args, 0, Py_None);
|
||||
PyEval_CallObject(random_seed, random_args);
|
||||
if (PyErr_Occurred()) {
|
||||
PyErr_Print();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// reinitialize the random seed (thanks Jonas Borgström)
|
||||
random_module = PyImport_ImportModule("random");
|
||||
if (random_module) {
|
||||
random_dict = PyModule_GetDict(random_module);
|
||||
if (random_dict) {
|
||||
random_seed = PyDict_GetItemString(random_dict, "seed");
|
||||
if (random_seed) {
|
||||
PyObject *random_args = PyTuple_New(1);
|
||||
// pass no args
|
||||
PyTuple_SetItem(random_args, 0, Py_None);
|
||||
PyEval_CallObject(random_seed, random_args);
|
||||
if (PyErr_Occurred()) {
|
||||
PyErr_Print();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_python_post_fork() {
|
||||
|
||||
uwsgi_python_reset_random_seed();
|
||||
|
||||
#ifdef UWSGI_EMBEDDED
|
||||
// call the post_fork_hook
|
||||
@@ -179,49 +190,69 @@ PyObject *uwsgi_pyimport_by_filename(char *name, char *filename) {
|
||||
char *real_filename = filename;
|
||||
|
||||
|
||||
pyfile = fopen(filename, "r");
|
||||
if (!pyfile) {
|
||||
uwsgi_log("failed to open python file %s\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
if (strncmp(filename, "http://", 7)) {
|
||||
|
||||
if (fstat(fileno(pyfile), &pystat)) {
|
||||
uwsgi_error("fstat()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (S_ISDIR(pystat.st_mode)) {
|
||||
is_a_package = 1;
|
||||
fclose(pyfile);
|
||||
real_filename = uwsgi_concat2(filename, "/__init__.py");
|
||||
pyfile = fopen(real_filename, "r");
|
||||
pyfile = fopen(filename, "r");
|
||||
if (!pyfile) {
|
||||
uwsgi_error_open(real_filename);
|
||||
exit(1);
|
||||
uwsgi_log("failed to open python file %s\n", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fstat(fileno(pyfile), &pystat)) {
|
||||
uwsgi_error("fstat()");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (S_ISDIR(pystat.st_mode)) {
|
||||
is_a_package = 1;
|
||||
fclose(pyfile);
|
||||
real_filename = uwsgi_concat2(filename, "/__init__.py");
|
||||
pyfile = fopen(real_filename, "r");
|
||||
if (!pyfile) {
|
||||
uwsgi_error_open(real_filename);
|
||||
free(real_filename);
|
||||
fclose(pyfile);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
py_file_node = PyParser_SimpleParseFile(pyfile, real_filename, Py_file_input);
|
||||
if (!py_file_node) {
|
||||
PyErr_Print();
|
||||
uwsgi_log("failed to parse file %s\n", real_filename);
|
||||
free(real_filename);
|
||||
fclose(pyfile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fclose(pyfile);
|
||||
}
|
||||
else {
|
||||
int pycontent_size = 0;
|
||||
char *pycontent = uwsgi_open_and_read(filename, &pycontent_size, 1, NULL);
|
||||
|
||||
if (pycontent) {
|
||||
py_file_node = PyParser_SimpleParseString(pycontent, Py_file_input);
|
||||
if (!py_file_node) {
|
||||
PyErr_Print();
|
||||
uwsgi_log("failed to parse url %s\n", real_filename);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
py_file_node = PyParser_SimpleParseFile(pyfile, real_filename, Py_file_input);
|
||||
if (!py_file_node) {
|
||||
PyErr_Print();
|
||||
uwsgi_log("failed to parse file %s\n", real_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fclose(pyfile);
|
||||
|
||||
py_compiled_node = (PyObject *) PyNode_Compile(py_file_node, real_filename);
|
||||
|
||||
if (!py_compiled_node) {
|
||||
PyErr_Print();
|
||||
uwsgi_log("failed to compile python file %s\n", real_filename);
|
||||
exit(1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
py_file_module = PyImport_ExecCodeModule(name, py_compiled_node);
|
||||
if (!py_file_module) {
|
||||
PyErr_Print();
|
||||
exit(1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_DECREF(py_compiled_node);
|
||||
@@ -259,6 +290,15 @@ void init_uwsgi_vars() {
|
||||
exit(1);
|
||||
}
|
||||
pysys_dict = PyModule_GetDict(pysys);
|
||||
|
||||
#ifdef PYTHREE
|
||||
// fix stdout and stderr
|
||||
PyObject *new_stdprint = PyFile_NewStdPrinter(2);
|
||||
PyDict_SetItemString(pysys_dict, "stdout", new_stdprint);
|
||||
PyDict_SetItemString(pysys_dict, "__stdout__", new_stdprint);
|
||||
PyDict_SetItemString(pysys_dict, "stderr", new_stdprint);
|
||||
PyDict_SetItemString(pysys_dict, "__stderr__", new_stdprint);
|
||||
#endif
|
||||
pypath = PyDict_GetItemString(pysys_dict, "path");
|
||||
if (!pypath) {
|
||||
PyErr_Print();
|
||||
@@ -302,13 +342,16 @@ void init_uwsgi_vars() {
|
||||
PyErr_Print();
|
||||
}
|
||||
|
||||
for (i = 0; i < up.python_path_cnt; i++) {
|
||||
if (PyList_Insert(pypath, 0, UWSGI_PYFROMSTRING(up.python_path[i])) != 0) {
|
||||
struct uwsgi_string_list *uppp = up.python_path;
|
||||
while(uppp) {
|
||||
if (PyList_Insert(pypath, 0, UWSGI_PYFROMSTRING(uppp->value)) != 0) {
|
||||
PyErr_Print();
|
||||
}
|
||||
else {
|
||||
uwsgi_log("added %s to pythonpath.\n", up.python_path[i]);
|
||||
uwsgi_log("added %s to pythonpath.\n", uppp->value);
|
||||
}
|
||||
|
||||
uppp = uppp->next;
|
||||
}
|
||||
|
||||
for (i = 0; i < up.pymodule_alias_cnt; i++) {
|
||||
@@ -332,6 +375,10 @@ void init_uwsgi_vars() {
|
||||
else {
|
||||
// this is a filepath that need to be mapped
|
||||
tmp_module = uwsgi_pyimport_by_filename(up.pymodule_alias[i], value + 1);
|
||||
if (!tmp_module) {
|
||||
PyErr_Print();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
uwsgi_log("mapped virtual pymodule \"%s\" to real pymodule \"%s\"\n", up.pymodule_alias[i], value + 1);
|
||||
// reset original value
|
||||
@@ -395,6 +442,25 @@ void init_uwsgi_embedded_module() {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
PyObject *uwsgi_py_version_info = PyTuple_New(5);
|
||||
|
||||
PyTuple_SetItem(uwsgi_py_version_info, 0, PyInt_FromLong(UWSGI_VERSION_BASE));
|
||||
PyTuple_SetItem(uwsgi_py_version_info, 1, PyInt_FromLong(UWSGI_VERSION_MAJOR));
|
||||
PyTuple_SetItem(uwsgi_py_version_info, 2, PyInt_FromLong(UWSGI_VERSION_MINOR));
|
||||
PyTuple_SetItem(uwsgi_py_version_info, 3, PyInt_FromLong(UWSGI_VERSION_REVISION));
|
||||
PyTuple_SetItem(uwsgi_py_version_info, 4, PyString_FromString(UWSGI_VERSION_CUSTOM));
|
||||
|
||||
if (PyDict_SetItemString(up.embedded_dict, "version_info", uwsgi_py_version_info)) {
|
||||
PyErr_Print();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
if (PyDict_SetItemString(up.embedded_dict, "hostname", PyString_FromStringAndSize(uwsgi.hostname, uwsgi.hostname_len))) {
|
||||
PyErr_Print();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (uwsgi.mode) {
|
||||
if (PyDict_SetItemString(up.embedded_dict, "mode", PyString_FromString(uwsgi.mode))) {
|
||||
PyErr_Print();
|
||||
@@ -631,6 +697,9 @@ int uwsgi_python_magic(char *mountpoint, char *lazy) {
|
||||
|
||||
int uwsgi_python_manage_options(int i, char *optarg) {
|
||||
|
||||
glob_t g;
|
||||
int j;
|
||||
|
||||
switch (i) {
|
||||
case 'w':
|
||||
up.wsgi_config = optarg;
|
||||
@@ -652,12 +721,13 @@ int uwsgi_python_manage_options(int i, char *optarg) {
|
||||
}
|
||||
return 1;
|
||||
case LONG_ARGS_PYTHONPATH:
|
||||
if (up.python_path_cnt < MAX_PYTHONPATH) {
|
||||
up.python_path[up.python_path_cnt] = optarg;
|
||||
up.python_path_cnt++;
|
||||
if (glob(optarg, GLOB_MARK, NULL, &g)) {
|
||||
uwsgi_string_new_list(&up.python_path, optarg);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("you can specify at most %d --pythonpath options\n", MAX_PYTHONPATH);
|
||||
for (j = 0; j < (int) g.gl_pathc; j++) {
|
||||
uwsgi_string_new_list(&up.python_path, g.gl_pathv[j]);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
case LONG_ARGS_PYARGV:
|
||||
@@ -677,6 +747,7 @@ int uwsgi_python_manage_options(int i, char *optarg) {
|
||||
return 1;
|
||||
|
||||
|
||||
#ifdef UWSGI_INI
|
||||
case LONG_ARGS_INI_PASTE:
|
||||
uwsgi.ini = optarg;
|
||||
if (uwsgi.ini[0] != '/') {
|
||||
@@ -686,6 +757,7 @@ int uwsgi_python_manage_options(int i, char *optarg) {
|
||||
up.paste = uwsgi_concat2("config:", uwsgi.ini);
|
||||
}
|
||||
return 1;
|
||||
#endif
|
||||
case LONG_ARGS_PASTE:
|
||||
up.paste = optarg;
|
||||
return 1;
|
||||
@@ -756,6 +828,35 @@ void uwsgi_python_init_apps() {
|
||||
init_uwsgi_app(LOADER_EVAL, up.eval, uwsgi.wsgi_req, up.main_thread);
|
||||
}
|
||||
|
||||
if (uwsgi.profiler) {
|
||||
if (!strcmp(uwsgi.profiler, "pycall")) {
|
||||
PyEval_SetProfile(uwsgi_python_profiler_call, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_python_master_fixup(int step) {
|
||||
|
||||
static int master_fixed = 0;
|
||||
static int worker_fixed = 0;
|
||||
|
||||
if (!uwsgi.master_process) return;
|
||||
|
||||
if (uwsgi.has_threads) {
|
||||
if (step == 0) {
|
||||
if (!master_fixed) {
|
||||
UWSGI_RELEASE_GIL;
|
||||
master_fixed = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!worker_fixed) {
|
||||
UWSGI_GET_GIL;
|
||||
worker_fixed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_python_enable_threads() {
|
||||
@@ -777,9 +878,12 @@ void uwsgi_python_enable_threads() {
|
||||
up.gil_get = gil_real_get;
|
||||
up.gil_release = gil_real_release;
|
||||
|
||||
up.swap_ts = threaded_swap_ts;
|
||||
up.reset_ts = threaded_reset_ts;
|
||||
if (uwsgi.threads > 1) {
|
||||
up.swap_ts = threaded_swap_ts;
|
||||
up.reset_ts = threaded_reset_ts;
|
||||
}
|
||||
uwsgi_log("threads support enabled\n");
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_python_init_thread(int core_id) {
|
||||
@@ -859,13 +963,15 @@ void uwsgi_python_suspend(struct wsgi_request *wsgi_req) {
|
||||
|
||||
int uwsgi_python_signal_handler(uint8_t sig, void *handler) {
|
||||
|
||||
UWSGI_GET_GIL;
|
||||
|
||||
PyObject *args = PyTuple_New(1);
|
||||
PyObject *ret;
|
||||
|
||||
if (!args)
|
||||
return -1;
|
||||
goto clear;
|
||||
|
||||
if (!handler) return -1;
|
||||
if (!handler) goto clear;
|
||||
|
||||
|
||||
PyTuple_SetItem(args, 0, PyInt_FromLong(sig));
|
||||
@@ -873,9 +979,12 @@ int uwsgi_python_signal_handler(uint8_t sig, void *handler) {
|
||||
ret = python_call(handler, args, 0);
|
||||
|
||||
if (ret) {
|
||||
UWSGI_RELEASE_GIL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
clear:
|
||||
UWSGI_RELEASE_GIL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -925,9 +1034,15 @@ void uwsgi_python_add_item(char *key, uint16_t keylen, char *val, uint16_t valle
|
||||
|
||||
int uwsgi_python_spooler(char *buf, uint16_t len) {
|
||||
|
||||
static int random_seed_reset = 0;
|
||||
PyObject *spool_dict = PyDict_New();
|
||||
PyObject *spool_func, *pyargs, *ret;
|
||||
|
||||
if (!random_seed_reset) {
|
||||
uwsgi_python_reset_random_seed();
|
||||
random_seed_reset = 1;
|
||||
}
|
||||
|
||||
if (!up.embedded_dict) {
|
||||
// ignore
|
||||
return 0;
|
||||
@@ -979,9 +1094,15 @@ void uwsgi_python_resume(struct wsgi_request *wsgi_req) {
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_python_fixup() {
|
||||
// set hacky modifier 30
|
||||
uwsgi.p[30] = uwsgi.p[0];
|
||||
}
|
||||
|
||||
struct uwsgi_plugin python_plugin = {
|
||||
|
||||
.name = "python",
|
||||
.alias = "python",
|
||||
.modifier1 = 0,
|
||||
.init = uwsgi_python_init,
|
||||
.post_fork = uwsgi_python_post_fork,
|
||||
@@ -992,6 +1113,9 @@ struct uwsgi_plugin python_plugin = {
|
||||
.after_request = uwsgi_after_request_wsgi,
|
||||
.init_apps = uwsgi_python_init_apps,
|
||||
|
||||
.fixup = uwsgi_python_fixup,
|
||||
.master_fixup = uwsgi_python_master_fixup,
|
||||
|
||||
.mount_app = uwsgi_python_mount_app,
|
||||
|
||||
.enable_threads = uwsgi_python_enable_threads,
|
||||
|
||||
@@ -5,7 +5,6 @@ extern struct uwsgi_python up;
|
||||
|
||||
int manage_python_response(struct wsgi_request *wsgi_req) {
|
||||
// use standard WSGI response parse
|
||||
wsgi_req->switches++;
|
||||
return uwsgi_response_subhandler_wsgi(wsgi_req);
|
||||
}
|
||||
|
||||
@@ -13,8 +12,12 @@ PyObject *python_call(PyObject *callable, PyObject *args, int catch) {
|
||||
|
||||
PyObject *pyret;
|
||||
|
||||
//uwsgi_log("ready to call %p %p\n", callable, args);
|
||||
|
||||
pyret = PyEval_CallObject(callable, args);
|
||||
|
||||
//uwsgi_log("called\n");
|
||||
|
||||
if (PyErr_Occurred()) {
|
||||
if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
|
||||
uwsgi_log("Memory Error detected !!!\n");
|
||||
|
||||
+111
-46
@@ -115,6 +115,7 @@ char *uwsgi_encode_pydict(PyObject * pydict, uint16_t * size) {
|
||||
|
||||
if (!key || !val) {
|
||||
PyErr_Print();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!PyString_Check(key) || !PyString_Check(val)) {
|
||||
@@ -309,15 +310,15 @@ PyObject *py_uwsgi_rpc(PyObject * self, PyObject * args) {
|
||||
char *node, *func;
|
||||
uint16_t size = 0;
|
||||
PyObject *py_node, *py_func;
|
||||
struct uwsgi_header uh;
|
||||
struct wsgi_request rpc_req;
|
||||
int argc = PyTuple_Size(args);
|
||||
char *argv[0xff];
|
||||
int i, fd;
|
||||
uint16_t pktsize = 0, ulen;
|
||||
char *bufptr;
|
||||
int rlen;
|
||||
int rpc_args = 0;
|
||||
|
||||
struct pollfd upoll;
|
||||
|
||||
// TODO better error reporting
|
||||
if (argc < 2)
|
||||
@@ -341,10 +342,16 @@ PyObject *py_uwsgi_rpc(PyObject * self, PyObject * args) {
|
||||
|
||||
for (i = 0; i < (argc - 2); i++) {
|
||||
argv[i] = PyString_AsString(PyTuple_GetItem(args, i + 2));
|
||||
rpc_args++;
|
||||
}
|
||||
|
||||
if (node == (char *) "") {
|
||||
size = uwsgi_rpc(func, 0, NULL, buffer);
|
||||
if (!strcmp(node, "")) {
|
||||
if (!rpc_args) {
|
||||
size = uwsgi_rpc(func, 0, NULL, buffer);
|
||||
}
|
||||
else {
|
||||
size = uwsgi_rpc(func, rpc_args, argv, buffer);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -361,9 +368,11 @@ PyObject *py_uwsgi_rpc(PyObject * self, PyObject * args) {
|
||||
pktsize += 2 + strlen(argv[i]);
|
||||
}
|
||||
|
||||
uh.modifier1 = 173;
|
||||
uh.pktsize = pktsize;
|
||||
uh.modifier2 = 0;
|
||||
memset(&rpc_req, 0, sizeof(struct wsgi_request));
|
||||
|
||||
rpc_req.uh.modifier1 = 173;
|
||||
rpc_req.uh.pktsize = pktsize;
|
||||
rpc_req.uh.modifier2 = 0;
|
||||
|
||||
bufptr = buffer;
|
||||
|
||||
@@ -381,7 +390,7 @@ PyObject *py_uwsgi_rpc(PyObject * self, PyObject * args) {
|
||||
bufptr += ulen;
|
||||
}
|
||||
|
||||
if (write(fd, &uh, 4) != 4) {
|
||||
if (write(fd, &rpc_req.uh, 4) != 4) {
|
||||
uwsgi_error("write()");
|
||||
close(fd);
|
||||
goto clear;
|
||||
@@ -395,10 +404,11 @@ PyObject *py_uwsgi_rpc(PyObject * self, PyObject * args) {
|
||||
|
||||
rlen = uwsgi_waitfd(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (rlen > 0) {
|
||||
upoll.fd = fd;
|
||||
upoll.events = POLLIN;
|
||||
if (uwsgi_parse_response(&upoll, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], &uh, buffer)) {
|
||||
size = uh.pktsize;
|
||||
rpc_req.poll.fd = fd;
|
||||
rpc_req.poll.events = POLLIN;
|
||||
rpc_req.buffer = buffer;
|
||||
if (uwsgi_parse_packet(&rpc_req, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
|
||||
size = rpc_req.uh.pktsize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,8 +436,7 @@ PyObject *py_uwsgi_register_rpc(PyObject * self, PyObject * args) {
|
||||
|
||||
|
||||
if (uwsgi_register_rpc(name, 0, argc, func)) {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
return PyErr_Format(PyExc_ValueError, "unable to register rpc function");
|
||||
}
|
||||
|
||||
Py_INCREF(Py_True);
|
||||
@@ -478,9 +487,11 @@ PyObject *py_uwsgi_signal(PyObject * self, PyObject * args) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("sending %d to master\n", uwsgi_signal);
|
||||
#endif
|
||||
|
||||
rlen = write(uwsgi.shared->worker_signal_pipe[1], &uwsgi_signal, 1);
|
||||
rlen = write(uwsgi.signal_socket, &uwsgi_signal, 1);
|
||||
if (rlen != 1) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
@@ -746,6 +757,7 @@ PyObject *py_uwsgi_advanced_sendfile(PyObject * self, PyObject * args) {
|
||||
off_t pos = 0;
|
||||
size_t filesize = 0;
|
||||
struct stat stat_buf;
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
int fd = -1;
|
||||
|
||||
@@ -770,7 +782,7 @@ PyObject *py_uwsgi_advanced_sendfile(PyObject * self, PyObject * args) {
|
||||
goto clear;
|
||||
|
||||
// check for mixing file_wrapper and sendfile
|
||||
if (fd == uwsgi.wsgi_req->sendfile_fd) {
|
||||
if (fd == wsgi_req->sendfile_fd) {
|
||||
Py_INCREF(what);
|
||||
}
|
||||
}
|
||||
@@ -792,7 +804,7 @@ PyObject *py_uwsgi_advanced_sendfile(PyObject * self, PyObject * args) {
|
||||
if (!chunk)
|
||||
chunk = 4096;
|
||||
|
||||
uwsgi.wsgi_req->response_size += uwsgi_do_sendfile(uwsgi.wsgi_req->poll.fd, fd, filesize, chunk, &pos, 0);
|
||||
uwsgi.wsgi_req->response_size += uwsgi_do_sendfile(wsgi_req->poll.fd, fd, filesize, chunk, &pos, 0);
|
||||
|
||||
close(fd);
|
||||
Py_INCREF(Py_True);
|
||||
@@ -874,7 +886,6 @@ PyObject *py_uwsgi_lock(PyObject * self, PyObject * args) {
|
||||
if (uwsgi.numproc > 1 && uwsgi.mypid != uwsgi.workers[0].pid) {
|
||||
#endif
|
||||
uwsgi_lock(uwsgi.user_lock);
|
||||
UWSGI_SET_LOCKING;
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
@@ -884,7 +895,6 @@ PyObject *py_uwsgi_lock(PyObject * self, PyObject * args) {
|
||||
PyObject *py_uwsgi_unlock(PyObject * self, PyObject * args) {
|
||||
|
||||
uwsgi_unlock(uwsgi.user_lock);
|
||||
UWSGI_UNSET_LOCKING;
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
@@ -1194,8 +1204,7 @@ PyObject *py_uwsgi_send_spool(PyObject * self, PyObject * args, PyObject *kw) {
|
||||
}
|
||||
else {
|
||||
Py_DECREF(zero);
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
return PyErr_Format(PyExc_ValueError, "spooler packet cannot be more than %d bytes", uwsgi.buffer_size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1237,7 +1246,7 @@ PyObject *py_uwsgi_send_multi_message(PyObject * self, PyObject * args) {
|
||||
int managed;
|
||||
struct pollfd *multipoll;
|
||||
char *buffer;
|
||||
struct uwsgi_header uh;
|
||||
|
||||
PyObject *arg_cluster;
|
||||
|
||||
PyObject *cluster_node;
|
||||
@@ -1351,9 +1360,11 @@ PyObject *py_uwsgi_send_multi_message(PyObject * self, PyObject * args) {
|
||||
goto megamulticlear;
|
||||
}
|
||||
else {
|
||||
// TODO fix
|
||||
/*
|
||||
for (i = 0; i < clen; i++) {
|
||||
if (multipoll[i].revents & POLLIN) {
|
||||
if (!uwsgi_parse_response(&multipoll[i], PyInt_AsLong(arg_timeout), &uh, &buffer[i])) {
|
||||
if (!uwsgi_parse_packet(&multipoll[i], PyInt_AsLong(arg_timeout), &uh, &buffer[i], uwsgi_proto_uwsgi_parser)) {
|
||||
goto megamulticlear;
|
||||
}
|
||||
else {
|
||||
@@ -1366,6 +1377,7 @@ PyObject *py_uwsgi_send_multi_message(PyObject * self, PyObject * args) {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1557,7 +1569,6 @@ PyObject *uwsgi_Iter_next(PyObject * self) {
|
||||
ui->has_cl = 1;
|
||||
ui->size = uh.pktsize;
|
||||
ui->sent = 0;
|
||||
uwsgi_log("NEED TO READ %d\n", uh.pktsize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1660,8 +1671,6 @@ PyObject *py_uwsgi_async_send_message(PyObject * self, PyObject * args) {
|
||||
int modifier1 = 0;
|
||||
int modifier2 = 0;
|
||||
|
||||
ssize_t ret;
|
||||
|
||||
char *encoded;
|
||||
uint16_t esize = 0;
|
||||
|
||||
@@ -1676,14 +1685,14 @@ PyObject *py_uwsgi_async_send_message(PyObject * self, PyObject * args) {
|
||||
if (PyDict_Check(pyobj)) {
|
||||
encoded = uwsgi_encode_pydict(pyobj, &esize);
|
||||
if (esize > 0) {
|
||||
UWSGI_RELEASE_GIL ret = uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, -1, 0, 0);
|
||||
UWSGI_RELEASE_GIL uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, -1, 0, 0);
|
||||
free(encoded);
|
||||
}
|
||||
}
|
||||
else if (PyString_Check(pyobj)) {
|
||||
encoded = PyString_AsString(pyobj);
|
||||
esize = PyString_Size(pyobj);
|
||||
UWSGI_RELEASE_GIL ret = uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, -1, 0, 0);
|
||||
UWSGI_RELEASE_GIL uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, -1, 0, 0);
|
||||
}
|
||||
else {
|
||||
marshalled = PyMarshal_WriteObjectToString(pyobj, 1);
|
||||
@@ -1694,7 +1703,7 @@ PyObject *py_uwsgi_async_send_message(PyObject * self, PyObject * args) {
|
||||
|
||||
encoded = PyString_AsString(marshalled);
|
||||
esize = PyString_Size(marshalled);
|
||||
UWSGI_RELEASE_GIL ret = uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, -1, 0, 0);
|
||||
UWSGI_RELEASE_GIL uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, -1, 0, 0);
|
||||
}
|
||||
|
||||
UWSGI_GET_GIL clear:
|
||||
@@ -1804,8 +1813,6 @@ PyObject *py_uwsgi_send_message(PyObject * self, PyObject * args) {
|
||||
int fd = -1;
|
||||
int cl = 0;
|
||||
|
||||
ssize_t ret;
|
||||
|
||||
int uwsgi_fd = -1;
|
||||
char *encoded;
|
||||
uint16_t esize = 0;
|
||||
@@ -1834,14 +1841,14 @@ PyObject *py_uwsgi_send_message(PyObject * self, PyObject * args) {
|
||||
if (PyDict_Check(pyobj)) {
|
||||
encoded = uwsgi_encode_pydict(pyobj, &esize);
|
||||
if (esize > 0) {
|
||||
UWSGI_RELEASE_GIL ret = uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, fd, cl, timeout);
|
||||
UWSGI_RELEASE_GIL uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, fd, cl, timeout);
|
||||
free(encoded);
|
||||
}
|
||||
}
|
||||
else if (PyString_Check(pyobj)) {
|
||||
encoded = PyString_AsString(pyobj);
|
||||
esize = PyString_Size(pyobj);
|
||||
UWSGI_RELEASE_GIL ret = uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, fd, cl, timeout);
|
||||
UWSGI_RELEASE_GIL uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, fd, cl, timeout);
|
||||
}
|
||||
else {
|
||||
marshalled = PyMarshal_WriteObjectToString(pyobj, 1);
|
||||
@@ -1852,7 +1859,7 @@ PyObject *py_uwsgi_send_message(PyObject * self, PyObject * args) {
|
||||
|
||||
encoded = PyString_AsString(marshalled);
|
||||
esize = PyString_Size(marshalled);
|
||||
UWSGI_RELEASE_GIL ret = uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, fd, cl, timeout);
|
||||
UWSGI_RELEASE_GIL uwsgi_send_message(uwsgi_fd, (uint8_t) modifier1, (uint8_t) modifier2, encoded, esize, fd, cl, timeout);
|
||||
}
|
||||
|
||||
UWSGI_GET_GIL
|
||||
@@ -2011,7 +2018,6 @@ PyObject *py_uwsgi_reload(PyObject * self, PyObject * args) {
|
||||
PyObject *py_uwsgi_set_blocking(PyObject * self, PyObject * args) {
|
||||
|
||||
if (uwsgi.master_process) {
|
||||
uwsgi.workers[uwsgi.mywid].status |= UWSGI_STATUS_BLOCKING;
|
||||
Py_INCREF(Py_True);
|
||||
return Py_True;
|
||||
}
|
||||
@@ -2181,7 +2187,6 @@ PyObject *py_uwsgi_parse_file(PyObject * self, PyObject * args) {
|
||||
PyObject *py_uwsgi_grunt(PyObject * self, PyObject * args) {
|
||||
|
||||
pid_t grunt_pid;
|
||||
int i;
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
if (uwsgi.grunt) {
|
||||
@@ -2198,9 +2203,7 @@ PyObject *py_uwsgi_grunt(PyObject * self, PyObject * args) {
|
||||
goto clear;
|
||||
}
|
||||
else if (grunt_pid == 0) {
|
||||
for (i = 0; i < uwsgi.sockets_cnt; i++) {
|
||||
close(uwsgi.sockets[i].fd);
|
||||
}
|
||||
uwsgi_close_all_sockets();
|
||||
// create a new session
|
||||
setsid();
|
||||
// exit on SIGPIPE
|
||||
@@ -2212,6 +2215,9 @@ PyObject *py_uwsgi_grunt(PyObject * self, PyObject * args) {
|
||||
uwsgi.workers[uwsgi.mywid].id = uwsgi.mywid;
|
||||
// this field will be overwrite after each call
|
||||
uwsgi.workers[uwsgi.mywid].pid = uwsgi.mypid;
|
||||
|
||||
// reset the random seed
|
||||
uwsgi_python_reset_random_seed();
|
||||
// TODO
|
||||
// manage thread in grunt processes
|
||||
Py_INCREF(Py_True);
|
||||
@@ -2219,8 +2225,10 @@ PyObject *py_uwsgi_grunt(PyObject * self, PyObject * args) {
|
||||
}
|
||||
|
||||
// close connection on the worker
|
||||
fclose(wsgi_req->async_post);
|
||||
wsgi_req->fd_closed = 1;
|
||||
if (PyTuple_Size(args) == 0) {
|
||||
fclose(wsgi_req->async_post);
|
||||
wsgi_req->fd_closed = 1;
|
||||
}
|
||||
|
||||
clear:
|
||||
Py_INCREF(Py_None);
|
||||
@@ -2229,8 +2237,13 @@ PyObject *py_uwsgi_grunt(PyObject * self, PyObject * args) {
|
||||
|
||||
#ifdef UWSGI_SPOOLER
|
||||
static PyMethodDef uwsgi_spooler_methods[] = {
|
||||
#ifdef PYTHREE
|
||||
{"send_to_spooler", (PyCFunction) py_uwsgi_send_spool, METH_VARARGS | METH_KEYWORDS, ""},
|
||||
{"spool", (PyCFunction) py_uwsgi_send_spool, METH_VARARGS | METH_KEYWORDS, ""},
|
||||
#else
|
||||
{"send_to_spooler", (PyCFunction) py_uwsgi_send_spool, METH_KEYWORDS, ""},
|
||||
{"spool", (PyCFunction) py_uwsgi_send_spool, METH_KEYWORDS, ""},
|
||||
#endif
|
||||
{"set_spooler_frequency", py_uwsgi_spooler_freq, METH_VARARGS, ""},
|
||||
{"spooler_jobs", py_uwsgi_spooler_jobs, METH_VARARGS, ""},
|
||||
{NULL, NULL},
|
||||
@@ -2277,7 +2290,9 @@ PyObject *py_uwsgi_cluster_node_name(PyObject * self, PyObject * args) {
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
ucn = &uwsgi.shared->nodes[i];
|
||||
if (ucn->name[0] != 0) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("node_name: %s %s\n", node, ucn->name);
|
||||
#endif
|
||||
if (!strcmp(ucn->name, node)) {
|
||||
return PyString_FromString(ucn->nodename);
|
||||
}
|
||||
@@ -2348,7 +2363,6 @@ static PyMethodDef uwsgi_advanced_methods[] = {
|
||||
{"load_plugin", py_uwsgi_load_plugin, METH_VARARGS, ""},
|
||||
{"lock", py_uwsgi_lock, METH_VARARGS, ""},
|
||||
{"unlock", py_uwsgi_unlock, METH_VARARGS, ""},
|
||||
{"send", py_uwsgi_send, METH_VARARGS, ""},
|
||||
{"cl", py_uwsgi_cl, METH_VARARGS, ""},
|
||||
|
||||
{"listen_queue", py_uwsgi_listen_queue, METH_VARARGS, ""},
|
||||
@@ -2501,6 +2515,7 @@ PyObject *py_uwsgi_cache_exists(PyObject * self, PyObject * args) {
|
||||
}
|
||||
|
||||
if (remote && strlen(remote) > 0) {
|
||||
// TODO FIX THIS !!!
|
||||
uwsgi_simple_message_string(remote, 111, 0, key, keylen, buffer, &valsize, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (valsize > 0) {
|
||||
Py_INCREF(Py_True);
|
||||
@@ -2528,7 +2543,6 @@ PyObject *py_uwsgi_queue_push(PyObject * self, PyObject * args) {
|
||||
}
|
||||
|
||||
if (uwsgi.queue_size) {
|
||||
uwsgi_log("locking queue\n");
|
||||
uwsgi_wlock(uwsgi.queue_lock);
|
||||
if (uwsgi_queue_push(message, msglen)) {
|
||||
Py_INCREF(Py_True);
|
||||
@@ -2539,7 +2553,6 @@ PyObject *py_uwsgi_queue_push(PyObject * self, PyObject * args) {
|
||||
res = Py_None;
|
||||
}
|
||||
uwsgi_rwunlock(uwsgi.queue_lock);
|
||||
uwsgi_log("unlocked queue\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -2611,10 +2624,61 @@ PyObject *py_uwsgi_queue_get(PyObject * self, PyObject * args) {
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_queue_last(PyObject * self, PyObject * args) {
|
||||
|
||||
long num = 0;
|
||||
uint64_t size = 0;
|
||||
char *message;
|
||||
PyObject *res, *zero;
|
||||
uint64_t base;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "l:queue_last", &num)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (uwsgi.queue_size) {
|
||||
res = PyList_New(0);
|
||||
uwsgi_rlock(uwsgi.queue_lock);
|
||||
if (uwsgi.shared->queue_pos > 0) {
|
||||
base = uwsgi.shared->queue_pos-1;
|
||||
}
|
||||
else {
|
||||
base = uwsgi.queue_size-1;
|
||||
}
|
||||
if (num > (long)uwsgi.queue_size) num = uwsgi.queue_size;
|
||||
while(num) {
|
||||
message = uwsgi_queue_get(base, &size);
|
||||
if (message && size) {
|
||||
zero = PyString_FromStringAndSize(message, size);
|
||||
PyList_Append(res, zero);
|
||||
Py_DECREF(zero);
|
||||
}
|
||||
else {
|
||||
uwsgi_rwunlock(uwsgi.queue_lock);
|
||||
return res;
|
||||
}
|
||||
if (base > 0) {
|
||||
base--;
|
||||
}
|
||||
else {
|
||||
base = uwsgi.queue_size-1;
|
||||
}
|
||||
num--;
|
||||
}
|
||||
uwsgi_rwunlock(uwsgi.queue_lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
PyObject *py_uwsgi_cache_get(PyObject * self, PyObject * args) {
|
||||
|
||||
char *key;
|
||||
uint64_t valsize;
|
||||
uint16_t valsize16;
|
||||
Py_ssize_t keylen = 0;
|
||||
char *value = NULL;
|
||||
char *remote = NULL;
|
||||
@@ -2630,8 +2694,8 @@ PyObject *py_uwsgi_cache_get(PyObject * self, PyObject * args) {
|
||||
}
|
||||
|
||||
if (remote && strlen(remote) > 0) {
|
||||
//uwsgi_simple_message_string(remote, 111, 0, key, keylen, buffer, &valsize, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (valsize > 0) {
|
||||
uwsgi_simple_message_string(remote, 111, 0, key, keylen, buffer, &valsize16, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (valsize16 > 0) {
|
||||
value = buffer;
|
||||
}
|
||||
}
|
||||
@@ -2676,6 +2740,7 @@ static PyMethodDef uwsgi_cache_methods[] = {
|
||||
|
||||
static PyMethodDef uwsgi_queue_methods[] = {
|
||||
{"queue_get", py_uwsgi_queue_get, METH_VARARGS, ""},
|
||||
{"queue_last", py_uwsgi_queue_last, METH_VARARGS, ""},
|
||||
{"queue_push", py_uwsgi_queue_push, METH_VARARGS, ""},
|
||||
{"queue_pull", py_uwsgi_queue_pull, METH_VARARGS, ""},
|
||||
{"queue_slot", py_uwsgi_queue_slot, METH_VARARGS, ""},
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|
||||
#include <frameobject.h>
|
||||
|
||||
#define MAX_PYTHONPATH 64
|
||||
#define MAX_PYMODULE_ALIAS 64
|
||||
#define MAX_PYARGV 10
|
||||
|
||||
#define LONG_ARGS_PYTHON_BASE 17000 + ((0 + 1) * 100)
|
||||
#define LONG_ARGS_PYTHON_BASE 17000 + ((0 + 1) * 1000)
|
||||
|
||||
#define LONG_ARGS_PYTHONPATH LONG_ARGS_PYTHON_BASE + 1
|
||||
#define LONG_ARGS_PASTE LONG_ARGS_PYTHON_BASE + 2
|
||||
@@ -18,6 +18,14 @@
|
||||
#define Py_ssize_t ssize_t
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 7
|
||||
#define HAS_NOT_PyFrame_GetLineNumber
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 2
|
||||
#define HAS_NOT_PyFrame_GetLineNumber
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION > 2
|
||||
#define PYTHREE
|
||||
#endif
|
||||
@@ -90,8 +98,7 @@ struct uwsgi_python {
|
||||
|
||||
char *test_module;
|
||||
|
||||
char *python_path[MAX_PYTHONPATH];
|
||||
int python_path_cnt;
|
||||
struct uwsgi_string_list *python_path;
|
||||
|
||||
PyObject *loader_dict;
|
||||
PyObject* (*loaders[LOADER_MAX]) (void *);
|
||||
@@ -212,3 +219,7 @@ void threaded_swap_ts(struct wsgi_request *, struct uwsgi_app *);
|
||||
void simple_swap_ts(struct wsgi_request *, struct uwsgi_app *);
|
||||
void threaded_reset_ts(struct wsgi_request *, struct uwsgi_app *);
|
||||
void simple_reset_ts(struct wsgi_request *, struct uwsgi_app *);
|
||||
|
||||
int uwsgi_python_profiler_call(PyObject *, PyFrameObject *, int, PyObject *);
|
||||
|
||||
void uwsgi_python_reset_random_seed(void);
|
||||
|
||||
@@ -3,7 +3,7 @@ import os,sys
|
||||
from distutils import sysconfig
|
||||
|
||||
NAME='python'
|
||||
GCC_LIST = ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule']
|
||||
GCC_LIST = ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule', 'profiler']
|
||||
|
||||
CFLAGS = ['-I' + sysconfig.get_python_inc(), '-I' + sysconfig.get_python_inc(plat_specific=True) ]
|
||||
LDFLAGS = []
|
||||
@@ -20,10 +20,12 @@ else:
|
||||
os.environ['LD_RUN_PATH'] = "%s/lib" % sysconfig.PREFIX
|
||||
|
||||
|
||||
version = sys.version_info
|
||||
uver = "%d.%d" % (version[0], version[1])
|
||||
|
||||
LIBS.append('-lpython' + uver)
|
||||
version = sysconfig.get_config_var('VERSION')
|
||||
try:
|
||||
version = version + sys.abiflags
|
||||
except:
|
||||
pass
|
||||
LIBS.append('-lpython' + version)
|
||||
|
||||
#if str(PYLIB_PATH) != '':
|
||||
# libs.insert(0,'-L' + PYLIB_PATH)
|
||||
|
||||
+190
-115
@@ -6,18 +6,94 @@ extern struct uwsgi_python up;
|
||||
|
||||
typedef struct uwsgi_Input {
|
||||
PyObject_HEAD
|
||||
off_t pos;
|
||||
char readline[1024];
|
||||
size_t readline_size;
|
||||
size_t readline_max_size;
|
||||
size_t readline_pos;
|
||||
size_t pos;
|
||||
struct wsgi_request *wsgi_req;
|
||||
} uwsgi_Input;
|
||||
|
||||
PyObject *uwsgi_Input_iter(PyObject * self) {
|
||||
PyObject *uwsgi_Input_iter(PyObject *self) {
|
||||
Py_INCREF(self);
|
||||
return self;
|
||||
}
|
||||
|
||||
PyObject *uwsgi_Input_next(PyObject * self) {
|
||||
PyObject *uwsgi_Input_getline(uwsgi_Input *self) {
|
||||
size_t i;
|
||||
ssize_t rlen;
|
||||
struct wsgi_request *wsgi_req = self->wsgi_req;
|
||||
PyObject *res;
|
||||
|
||||
return PyErr_Format(PyExc_NotImplementedError, "wsgi.input __iter__() is not implemented");
|
||||
char *ptr = self->readline;
|
||||
|
||||
if (uwsgi.post_buffering > 0) {
|
||||
ptr = wsgi_req->post_buffering_buf;
|
||||
self->readline_size = wsgi_req->post_cl;
|
||||
if (!self->readline_pos) {
|
||||
self->pos += self->readline_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (self->readline_pos > 0 || uwsgi.post_buffering) {
|
||||
for(i=self->readline_pos;i<self->readline_size;i++) {
|
||||
if (ptr[i] == '\n') {
|
||||
res = PyString_FromStringAndSize(ptr+self->readline_pos, (i-self->readline_pos)+1);
|
||||
self->readline_pos = i+1;
|
||||
if (self->readline_pos >= self->readline_size) self->readline_pos = 0;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
res = PyString_FromStringAndSize(ptr + self->readline_pos, self->readline_size - self->readline_pos);
|
||||
self->readline_pos = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
UWSGI_RELEASE_GIL;
|
||||
if (uwsgi_waitfd(wsgi_req->poll.fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]) <= 0) {
|
||||
UWSGI_GET_GIL
|
||||
return PyErr_Format(PyExc_IOError, "error waiting for wsgi.input data");
|
||||
}
|
||||
|
||||
if (self->readline_max_size > 0 && self->readline_max_size < 1024) {
|
||||
rlen = read(wsgi_req->poll.fd, self->readline, self->readline_max_size);
|
||||
}
|
||||
else {
|
||||
rlen = read(wsgi_req->poll.fd, self->readline, 1024);
|
||||
}
|
||||
if (rlen < 0) {
|
||||
UWSGI_GET_GIL
|
||||
return PyErr_Format(PyExc_IOError, "error reading wsgi.input data");
|
||||
}
|
||||
|
||||
self->readline_size = rlen;
|
||||
self->readline_pos = 0;
|
||||
self->pos += rlen;
|
||||
|
||||
UWSGI_GET_GIL;
|
||||
|
||||
for(i=0;i<(size_t)rlen;i++) {
|
||||
if (self->readline[i] == '\n') {
|
||||
res = PyString_FromStringAndSize(self->readline, i+1);
|
||||
self->readline_pos+= i+1;
|
||||
if (self->readline_pos >= self->readline_size) self->readline_pos = 0;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
self->readline_pos = 0;
|
||||
return PyString_FromStringAndSize(self->readline, self->readline_size);
|
||||
|
||||
}
|
||||
|
||||
PyObject *uwsgi_Input_next(PyObject* self) {
|
||||
|
||||
if (!((uwsgi_Input *)self)->wsgi_req->post_cl || ((size_t) ((uwsgi_Input *)self)->pos >= ((uwsgi_Input *)self)->wsgi_req->post_cl && !((uwsgi_Input *)self)->readline_pos)) {
|
||||
PyErr_SetNone(PyExc_StopIteration);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return uwsgi_Input_getline((uwsgi_Input *)self);
|
||||
|
||||
}
|
||||
|
||||
@@ -28,10 +104,9 @@ static void uwsgi_Input_free(uwsgi_Input *self) {
|
||||
static PyObject *uwsgi_Input_read(uwsgi_Input *self, PyObject *args) {
|
||||
|
||||
long len = 0;
|
||||
size_t remains;
|
||||
size_t remains, tmp_pos = 0;
|
||||
ssize_t rlen;
|
||||
char *tmp_buf;
|
||||
int fd;
|
||||
PyObject *res;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|l:read", &len)) {
|
||||
@@ -39,57 +114,70 @@ static PyObject *uwsgi_Input_read(uwsgi_Input *self, PyObject *args) {
|
||||
}
|
||||
|
||||
// return empty string if no post_cl or pos >= post_cl
|
||||
if (!self->wsgi_req->post_cl || (size_t) self->pos >= self->wsgi_req->post_cl) {
|
||||
if ((!self->wsgi_req->post_cl || (size_t) self->pos >= self->wsgi_req->post_cl ) && !self->readline_pos) {
|
||||
return PyString_FromString("");
|
||||
}
|
||||
|
||||
if (uwsgi.post_buffering > 0) {
|
||||
fd = -1;
|
||||
if (self->wsgi_req->post_cl <= (size_t) uwsgi.post_buffering) {
|
||||
fd = fileno((FILE *)self->wsgi_req->async_post);
|
||||
// some residual data ?
|
||||
if (self->readline_pos && self->readline_size) {
|
||||
if (len > 0) {
|
||||
if ((size_t) len < (self->readline_size - self->readline_pos)) {
|
||||
res = PyString_FromStringAndSize(self->readline + self->readline_pos, len);
|
||||
self->readline_pos+=len;
|
||||
if (self->readline_pos >= self->readline_size) self->readline_pos = 0;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
self->readline_pos = 0;
|
||||
return PyString_FromStringAndSize(self->readline + self->readline_pos, self->readline_size - self->readline_pos);
|
||||
}
|
||||
else {
|
||||
fd = self->wsgi_req->poll.fd;
|
||||
}
|
||||
|
||||
// return the whole input
|
||||
if (len <= 0) {
|
||||
remains = self->wsgi_req->post_cl;
|
||||
}
|
||||
else {
|
||||
remains = len ;
|
||||
}
|
||||
if (len <= 0) {
|
||||
remains = self->wsgi_req->post_cl;
|
||||
}
|
||||
else {
|
||||
remains = len ;
|
||||
}
|
||||
|
||||
if (remains + self->pos > self->wsgi_req->post_cl) {
|
||||
remains = self->wsgi_req->post_cl - self->pos;
|
||||
}
|
||||
remains = self->wsgi_req->post_cl - self->pos;
|
||||
}
|
||||
|
||||
if (remains <= 0) {
|
||||
return PyString_FromString("");
|
||||
}
|
||||
if (remains <= 0) {
|
||||
return PyString_FromString("");
|
||||
}
|
||||
|
||||
if (fd == -1) {
|
||||
res = PyString_FromStringAndSize( self->wsgi_req->post_buffering_buf, remains);
|
||||
self->pos += remains;
|
||||
if (uwsgi.post_buffering > 0) {
|
||||
res = PyString_FromStringAndSize( self->wsgi_req->post_buffering_buf+self->pos, remains);
|
||||
self->pos += remains;
|
||||
return res;
|
||||
}
|
||||
|
||||
UWSGI_RELEASE_GIL
|
||||
|
||||
tmp_buf = uwsgi_malloc(remains);
|
||||
|
||||
if (uwsgi_waitfd(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]) <= 0) {
|
||||
free(tmp_buf);
|
||||
return PyErr_Format(PyExc_IOError, "error waiting for wsgi.input data");
|
||||
while(remains) {
|
||||
if (uwsgi_waitfd(self->wsgi_req->poll.fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]) <= 0) {
|
||||
free(tmp_buf);
|
||||
UWSGI_GET_GIL
|
||||
return PyErr_Format(PyExc_IOError, "error waiting for wsgi.input data");
|
||||
}
|
||||
|
||||
rlen = read(self->wsgi_req->poll.fd, tmp_buf+tmp_pos, remains);
|
||||
if (rlen < 0) {
|
||||
free(tmp_buf);
|
||||
UWSGI_GET_GIL
|
||||
return PyErr_Format(PyExc_IOError, "error reading wsgi.input data");
|
||||
}
|
||||
tmp_pos += rlen;
|
||||
remains -= rlen;
|
||||
}
|
||||
|
||||
rlen = read(fd, tmp_buf, remains);
|
||||
if (rlen < 0) {
|
||||
free(tmp_buf);
|
||||
return PyErr_Format(PyExc_IOError, "error reading wsgi.input data");
|
||||
}
|
||||
|
||||
self->pos += rlen;
|
||||
res = PyString_FromStringAndSize(tmp_buf, rlen);
|
||||
|
||||
UWSGI_GET_GIL
|
||||
self->pos += tmp_pos;
|
||||
res = PyString_FromStringAndSize(tmp_buf, tmp_pos);
|
||||
free(tmp_buf);
|
||||
return res;
|
||||
|
||||
@@ -97,13 +185,34 @@ static PyObject *uwsgi_Input_read(uwsgi_Input *self, PyObject *args) {
|
||||
|
||||
static PyObject *uwsgi_Input_readline(uwsgi_Input *self, PyObject *args) {
|
||||
|
||||
return PyErr_Format(PyExc_NotImplementedError, "wsgi.input readline() is not implemented");
|
||||
if (!PyArg_ParseTuple(args, "|l:readline", &((uwsgi_Input *)self)->readline_max_size)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!((uwsgi_Input *)self)->wsgi_req->post_cl || ((size_t) ((uwsgi_Input *)self)->pos >= ((uwsgi_Input *)self)->wsgi_req->post_cl && !((uwsgi_Input *)self)->readline_pos)) {
|
||||
return PyString_FromString("");
|
||||
}
|
||||
return uwsgi_Input_getline(self);
|
||||
|
||||
}
|
||||
|
||||
static PyObject *uwsgi_Input_readlines(uwsgi_Input *self, PyObject *args) {
|
||||
|
||||
return PyErr_Format(PyExc_NotImplementedError, "wsgi.input readlines() is not implemented");
|
||||
PyObject *res;
|
||||
|
||||
if (!((uwsgi_Input *)self)->wsgi_req->post_cl || ((size_t) ((uwsgi_Input *)self)->pos >= ((uwsgi_Input *)self)->wsgi_req->post_cl && !((uwsgi_Input *)self)->readline_pos)) {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
res = PyList_New(0);
|
||||
while( ((size_t) ((uwsgi_Input *)self)->pos < ((uwsgi_Input *)self)->wsgi_req->post_cl || ((uwsgi_Input *)self)->readline_pos > 0)) {
|
||||
PyObject *a_line = uwsgi_Input_getline(self);
|
||||
PyList_Append(res, a_line);
|
||||
Py_DECREF(a_line);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static PyObject *uwsgi_Input_close(uwsgi_Input *self, PyObject *args) {
|
||||
@@ -171,7 +280,7 @@ PyObject *py_uwsgi_write(PyObject * self, PyObject * args) {
|
||||
content = PyString_AsString(data);
|
||||
len = PyString_Size(data);
|
||||
UWSGI_RELEASE_GIL
|
||||
wsgi_req->response_size = write(wsgi_req->poll.fd, content, len);
|
||||
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, content, len);
|
||||
UWSGI_GET_GIL
|
||||
}
|
||||
|
||||
@@ -229,9 +338,6 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
|
||||
char *what;
|
||||
int what_len;
|
||||
|
||||
PyObject *wsgi_socket;
|
||||
|
||||
|
||||
#ifdef UWSGI_ASYNC
|
||||
if (wsgi_req->async_status == UWSGI_AGAIN) {
|
||||
// get rid of timeout
|
||||
@@ -262,19 +368,10 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
|
||||
if (uwsgi_parse_vars(wsgi_req)) {
|
||||
uwsgi_log("Invalid WSGI request. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (uwsgi.limit_post) {
|
||||
if (wsgi_req->post_cl > uwsgi.limit_post) {
|
||||
uwsgi_log("Invalid (too big) CONTENT_LENGTH. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!up.ignore_script_name) {
|
||||
|
||||
if (!wsgi_req->script_name)
|
||||
@@ -302,22 +399,22 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
|
||||
|| wsgi_req->file_len > 0
|
||||
|| wsgi_req->paste_len > 0
|
||||
) {
|
||||
// a bit of magic: 1-1 = 0 / 0-1 = -1
|
||||
// this part must be heavy locked in threaded modes
|
||||
if (uwsgi.threads > 1) {
|
||||
pthread_mutex_lock(&up.lock_pyloaders);
|
||||
}
|
||||
|
||||
UWSGI_GET_GIL
|
||||
if (uwsgi.single_interpreter) {
|
||||
wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, up.main_thread);
|
||||
}
|
||||
else {
|
||||
wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, NULL);
|
||||
}
|
||||
if (uwsgi.single_interpreter) {
|
||||
wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, up.main_thread);
|
||||
}
|
||||
else {
|
||||
wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, NULL);
|
||||
}
|
||||
UWSGI_RELEASE_GIL
|
||||
if (uwsgi.threads > 1) {
|
||||
pthread_mutex_unlock(&up.lock_pyloaders);
|
||||
}
|
||||
if (uwsgi.threads > 1) {
|
||||
pthread_mutex_unlock(&up.lock_pyloaders);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -338,7 +435,7 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
|
||||
wsgi_req->app_id = uwsgi.default_app;
|
||||
}
|
||||
else {
|
||||
internal_server_error(wsgi_req->poll.fd, "wsgi application not found");
|
||||
internal_server_error(wsgi_req, "wsgi application not found");
|
||||
goto clear2;
|
||||
}
|
||||
|
||||
@@ -360,13 +457,14 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
|
||||
|
||||
if (wsgi_req->protocol_len < 5) {
|
||||
uwsgi_log( "INVALID PROTOCOL: %.*s\n", wsgi_req->protocol_len, wsgi_req->protocol);
|
||||
internal_server_error(wsgi_req->poll.fd, "invalid HTTP protocol !!!");
|
||||
internal_server_error(wsgi_req, "invalid HTTP protocol !!!");
|
||||
goto clear;
|
||||
|
||||
}
|
||||
|
||||
if (strncmp(wsgi_req->protocol, "HTTP/", 5)) {
|
||||
uwsgi_log( "INVALID PROTOCOL: %.*s\n", wsgi_req->protocol_len, wsgi_req->protocol);
|
||||
internal_server_error(wsgi_req->poll.fd, "invalid HTTP protocol !!!");
|
||||
internal_server_error(wsgi_req, "invalid HTTP protocol !!!");
|
||||
goto clear;
|
||||
}
|
||||
|
||||
@@ -404,6 +502,7 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
|
||||
if (wsgi_req->uh.modifier1 == UWSGI_MODIFIER_MANAGE_PATH_INFO) {
|
||||
wsgi_req->uh.modifier1 = 0;
|
||||
pydictkey = PyDict_GetItemString(wsgi_req->async_environ, "SCRIPT_NAME");
|
||||
if (pydictkey) {
|
||||
if (PyString_Check(pydictkey)) {
|
||||
@@ -420,49 +519,25 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
|
||||
|
||||
|
||||
|
||||
if (uwsgi.post_buffering > 0) {
|
||||
UWSGI_RELEASE_GIL
|
||||
// read to disk if post_cl > post_buffering
|
||||
if (!up.pep3333_input) {
|
||||
if (wsgi_req->post_cl >= (size_t) uwsgi.post_buffering) {
|
||||
if (!uwsgi_read_whole_body(wsgi_req, wsgi_req->post_buffering_buf, uwsgi.post_buffering_bufsize)) {
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// read to disk if post_cl > post_buffering
|
||||
if (wsgi_req->post_cl >= (size_t) uwsgi.post_buffering) {
|
||||
if (!uwsgi_read_whole_body(wsgi_req, wsgi_req->post_buffering_buf, uwsgi.post_buffering_bufsize)) {
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
// on tiny post use memory
|
||||
else {
|
||||
if (!uwsgi_read_whole_body_in_mem(wsgi_req, wsgi_req->post_buffering_buf)) {
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
}
|
||||
UWSGI_GET_GIL
|
||||
// if async_post is mapped as a file, directly use it as wsgi.input
|
||||
if (wsgi_req->async_post) {
|
||||
#ifdef PYTHREE
|
||||
wsgi_req->async_input = PyFile_FromFd(fileno(wsgi_req->async_post), "wsgi_input", "rb", 0, NULL, NULL, NULL, 0);
|
||||
#else
|
||||
wsgi_req->async_input = PyFile_FromFile(wsgi_req->async_post, "wsgi_input", "r", NULL);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
wsgi_req->async_post = fdopen(wsgi_req->poll.fd, "r");
|
||||
// create wsgi.input custom object
|
||||
wsgi_req->async_input = (PyObject *) PyObject_New(uwsgi_Input, &uwsgi_InputType);
|
||||
((uwsgi_Input*)wsgi_req->async_input)->wsgi_req = wsgi_req;
|
||||
((uwsgi_Input*)wsgi_req->async_input)->pos = 0;
|
||||
((uwsgi_Input*)wsgi_req->async_input)->readline_pos = 0;
|
||||
((uwsgi_Input*)wsgi_req->async_input)->readline_max_size = 0;
|
||||
|
||||
}
|
||||
|
||||
if (!up.pep3333_input) {
|
||||
wsgi_socket = PyFile_FromFile(wsgi_req->async_post, "wsgi_input", "r", NULL);
|
||||
PyDict_SetItemString(wsgi_req->async_environ, "wsgi.input", wsgi_socket);
|
||||
Py_DECREF(wsgi_socket);
|
||||
}
|
||||
else {
|
||||
wsgi_socket = (PyObject *) PyObject_New(uwsgi_Input, &uwsgi_InputType);
|
||||
((uwsgi_Input*)wsgi_socket)->wsgi_req = wsgi_req;
|
||||
((uwsgi_Input*)wsgi_socket)->pos = 0;
|
||||
PyDict_SetItemString(wsgi_req->async_environ, "wsgi.input", wsgi_socket);
|
||||
}
|
||||
|
||||
|
||||
PyDict_SetItemString(wsgi_req->async_environ, "wsgi.input", wsgi_req->async_input);
|
||||
|
||||
wsgi_req->async_result = wi->request_subhandler(wsgi_req, wi);
|
||||
|
||||
@@ -472,11 +547,15 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
|
||||
|
||||
|
||||
while (wi->response_subhandler(wsgi_req) != UWSGI_OK) {
|
||||
wsgi_req->switches++;
|
||||
#ifdef UWSGI_ASYNC
|
||||
if (uwsgi.async > 1) {
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
wsgi_req->switches++;
|
||||
#ifdef UWSGI_ASYNC
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -487,9 +566,9 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
|
||||
|
||||
// LOCK THIS PART
|
||||
|
||||
wsgi_req->response_size += write(wsgi_req->poll.fd, wsgi_req->protocol, wsgi_req->protocol_len);
|
||||
wsgi_req->response_size += write(wsgi_req->poll.fd, " 500 Internal Server Error\r\n", 28 );
|
||||
wsgi_req->response_size += write(wsgi_req->poll.fd, "Content-type: text/plain\r\n\r\n", 28 );
|
||||
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, wsgi_req->protocol, wsgi_req->protocol_len);
|
||||
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, " 500 Internal Server Error\r\n", 28 );
|
||||
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, "Content-type: text/plain\r\n\r\n", 28 );
|
||||
wsgi_req->header_cnt = 1;
|
||||
|
||||
/*
|
||||
@@ -518,9 +597,6 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
|
||||
close(tmp_stderr);
|
||||
}
|
||||
|
||||
if (up.pep3333_input) {
|
||||
Py_DECREF(wsgi_socket);
|
||||
}
|
||||
clear:
|
||||
|
||||
up.reset_ts(wsgi_req, wi);
|
||||
@@ -533,7 +609,6 @@ clear2:
|
||||
|
||||
void uwsgi_after_request_wsgi(struct wsgi_request *wsgi_req) {
|
||||
|
||||
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_LOGGING] || wsgi_req->log_this) {
|
||||
log_request(wsgi_req);
|
||||
}
|
||||
|
||||
@@ -13,23 +13,36 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
|
||||
PyObject *headers, *head;
|
||||
PyObject *h_key, *h_value;
|
||||
int i, j;
|
||||
struct uwsgi_header uh;
|
||||
PyObject *exc_info = NULL;
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
int base = 0;
|
||||
int shift = 0;
|
||||
|
||||
// use writev()
|
||||
// this must be done before headers management
|
||||
if (PyTuple_Size(args) > 2) {
|
||||
exc_info = PyTuple_GetItem(args, 2);
|
||||
if (exc_info && exc_info != Py_None) {
|
||||
PyObject *exc_type = PyTuple_GetItem(exc_info, 0);
|
||||
PyObject *exc_val = PyTuple_GetItem(exc_info, 1);
|
||||
PyObject *exc_tb = PyTuple_GetItem(exc_info, 2);
|
||||
|
||||
// is a Web3 response ?
|
||||
/*
|
||||
if (PyTuple_Size(args) == 3) {
|
||||
shift = 0;
|
||||
}
|
||||
*/
|
||||
if (!exc_type || !exc_val || !exc_tb) {
|
||||
PyErr_Print();
|
||||
goto clear;
|
||||
}
|
||||
|
||||
head = PyTuple_GetItem(args, 0+shift);
|
||||
Py_INCREF(exc_type);
|
||||
Py_INCREF(exc_val);
|
||||
Py_INCREF(exc_tb);
|
||||
// in this way, error will be reported to the log
|
||||
PyErr_Restore(exc_type, exc_val, exc_tb);
|
||||
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
|
||||
head = PyTuple_GetItem(args, 0);
|
||||
if (!head) {
|
||||
goto clear;
|
||||
}
|
||||
@@ -56,10 +69,8 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
|
||||
}
|
||||
|
||||
wsgi_req->hvec[0].iov_len = wsgi_req->protocol_len;
|
||||
uh.pktsize = wsgi_req->hvec[0].iov_len;
|
||||
wsgi_req->hvec[1].iov_base = " ";
|
||||
wsgi_req->hvec[1].iov_len = 1;
|
||||
uh.pktsize += wsgi_req->hvec[1].iov_len;
|
||||
#ifdef PYTHREE
|
||||
wsgi_req->hvec[2].iov_base = PyBytes_AsString(PyUnicode_AsASCIIString(head));
|
||||
wsgi_req->hvec[2].iov_len = strlen(wsgi_req->hvec[2].iov_base);
|
||||
@@ -67,18 +78,15 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
|
||||
wsgi_req->hvec[2].iov_base = PyString_AsString(head);
|
||||
wsgi_req->hvec[2].iov_len = PyString_Size(head);
|
||||
#endif
|
||||
uh.pktsize += wsgi_req->hvec[2].iov_len;
|
||||
wsgi_req->status = atoi(wsgi_req->hvec[2].iov_base);
|
||||
wsgi_req->status = uwsgi_str3_num(wsgi_req->hvec[2].iov_base);
|
||||
wsgi_req->hvec[3].iov_base = nl;
|
||||
wsgi_req->hvec[3].iov_len = NL_SIZE;
|
||||
uh.pktsize += wsgi_req->hvec[3].iov_len;
|
||||
}
|
||||
else {
|
||||
// drop http status on cgi mode
|
||||
base = 3;
|
||||
wsgi_req->hvec[0].iov_base = "Status: ";
|
||||
wsgi_req->hvec[0].iov_len = 8;
|
||||
uh.pktsize = wsgi_req->hvec[0].iov_len;
|
||||
#ifdef PYTHREE
|
||||
wsgi_req->hvec[1].iov_base = PyBytes_AsString(PyUnicode_AsASCIIString(head));
|
||||
wsgi_req->hvec[1].iov_len = strlen(wsgi_req->hvec[1].iov_base);
|
||||
@@ -86,26 +94,21 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
|
||||
wsgi_req->hvec[1].iov_base = PyString_AsString(head);
|
||||
wsgi_req->hvec[1].iov_len = PyString_Size(head);
|
||||
#endif
|
||||
uh.pktsize += wsgi_req->hvec[1].iov_len;
|
||||
wsgi_req->status = atoi(wsgi_req->hvec[1].iov_base);
|
||||
wsgi_req->status = uwsgi_str3_num(wsgi_req->hvec[1].iov_base);
|
||||
wsgi_req->hvec[2].iov_base = nl;
|
||||
wsgi_req->hvec[2].iov_len = NL_SIZE;
|
||||
uh.pktsize += wsgi_req->hvec[2].iov_len;
|
||||
}
|
||||
|
||||
headers = PyTuple_GetItem(args, 1);
|
||||
if (!headers) goto clear;
|
||||
|
||||
|
||||
headers = PyTuple_GetItem(args, 1+shift);
|
||||
if (!headers) {
|
||||
goto clear;
|
||||
}
|
||||
if (!PyList_Check(headers)) {
|
||||
uwsgi_log( "http headers must be in a python list\n");
|
||||
goto clear;
|
||||
}
|
||||
wsgi_req->header_cnt = PyList_Size(headers);
|
||||
|
||||
|
||||
|
||||
if (wsgi_req->header_cnt > uwsgi.max_vars) {
|
||||
wsgi_req->header_cnt = uwsgi.max_vars;
|
||||
}
|
||||
@@ -135,10 +138,8 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
|
||||
wsgi_req->hvec[j].iov_base = PyString_AsString(h_key);
|
||||
wsgi_req->hvec[j].iov_len = PyString_Size(h_key);
|
||||
#endif
|
||||
uh.pktsize += wsgi_req->hvec[j].iov_len;
|
||||
wsgi_req->hvec[j + 1].iov_base = h_sep;
|
||||
wsgi_req->hvec[j + 1].iov_len = H_SEP_SIZE;
|
||||
uh.pktsize += wsgi_req->hvec[j+1].iov_len;
|
||||
#ifdef PYTHREE
|
||||
wsgi_req->hvec[j + 2].iov_base = PyBytes_AsString(PyUnicode_AsASCIIString(h_value));
|
||||
wsgi_req->hvec[j + 2].iov_len = strlen(wsgi_req->hvec[j + 2].iov_base);
|
||||
@@ -147,34 +148,67 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
|
||||
wsgi_req->hvec[j + 2].iov_len = PyString_Size(h_value);
|
||||
#endif
|
||||
|
||||
uh.pktsize += wsgi_req->hvec[j+2].iov_len;
|
||||
|
||||
wsgi_req->hvec[j + 3].iov_base = nl;
|
||||
wsgi_req->hvec[j + 3].iov_len = NL_SIZE;
|
||||
|
||||
uh.pktsize += wsgi_req->hvec[j+3].iov_len;
|
||||
//uwsgi_log( "%.*s: %.*s\n", wsgi_req->hvec[j].iov_len, (char *)wsgi_req->hvec[j].iov_base, wsgi_req->hvec[j+2].iov_len, (char *) wsgi_req->hvec[j+2].iov_base);
|
||||
}
|
||||
|
||||
j = (i * 4) + base;
|
||||
|
||||
struct uwsgi_string_list *ah = uwsgi.additional_headers;
|
||||
while(ah) {
|
||||
if (wsgi_req->header_cnt+1 <= uwsgi.max_vars) {
|
||||
wsgi_req->header_cnt++;
|
||||
wsgi_req->hvec[j].iov_base = ah->value;
|
||||
wsgi_req->hvec[j].iov_len = ah->len;
|
||||
j++;
|
||||
wsgi_req->hvec[j].iov_base = nl;
|
||||
wsgi_req->hvec[j].iov_len = NL_SIZE;
|
||||
j++;
|
||||
ah = ah->next;
|
||||
}
|
||||
else {
|
||||
uwsgi_log("no more space in iovec. consider increasing max-vars...\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// \r\n
|
||||
j = (i * 4) + base;
|
||||
wsgi_req->hvec[j].iov_base = nl;
|
||||
wsgi_req->hvec[j].iov_len = NL_SIZE;
|
||||
|
||||
uh.pktsize += wsgi_req->hvec[j].iov_len;
|
||||
|
||||
#ifdef __sun__
|
||||
int remains = j + 1;
|
||||
int iov_size;
|
||||
struct iovec* iov_ptr = wsgi_req->hvec;
|
||||
ssize_t iov_ret;
|
||||
while(remains) {
|
||||
iov_size = UMIN(remains, IOV_MAX);
|
||||
UWSGI_RELEASE_GIL
|
||||
iov_ret = wsgi_req->socket->proto_writev_header(wsgi_req, iov_ptr, iov_size);
|
||||
UWSGI_GET_GIL
|
||||
if (iov_ret < 0) {
|
||||
uwsgi_error("writev()");
|
||||
}
|
||||
wsgi_req->headers_size += iov_ret;
|
||||
iov_ptr += iov_size;
|
||||
remains -= iov_size;
|
||||
}
|
||||
#else
|
||||
UWSGI_RELEASE_GIL
|
||||
wsgi_req->headers_size = writev(wsgi_req->poll.fd, wsgi_req->hvec, j + 1);
|
||||
wsgi_req->headers_size = wsgi_req->socket->proto_writev_header(wsgi_req, wsgi_req->hvec, j + 1);
|
||||
UWSGI_GET_GIL
|
||||
if (wsgi_req->headers_size < 0) {
|
||||
uwsgi_error("writev()");
|
||||
}
|
||||
#endif
|
||||
|
||||
//uwsgi_log("%d %p\n", wsgi_req->poll.fd, up.wsgi_writeout);
|
||||
Py_INCREF(up.wsgi_writeout);
|
||||
|
||||
|
||||
return up.wsgi_writeout;
|
||||
|
||||
clear:
|
||||
|
||||
@@ -124,7 +124,7 @@ int uwsgi_response_subhandler_wsgi(struct wsgi_request *wsgi_req) {
|
||||
|
||||
// return or yield ?
|
||||
if (PyString_Check((PyObject *)wsgi_req->async_result)) {
|
||||
if ((wsize = write(wsgi_req->poll.fd, PyString_AsString(wsgi_req->async_result), PyString_Size(wsgi_req->async_result))) < 0) {
|
||||
if ((wsize = wsgi_req->socket->proto_write(wsgi_req, PyString_AsString(wsgi_req->async_result), PyString_Size(wsgi_req->async_result))) < 0) {
|
||||
uwsgi_error("write()");
|
||||
goto clear;
|
||||
}
|
||||
@@ -185,7 +185,7 @@ int uwsgi_response_subhandler_wsgi(struct wsgi_request *wsgi_req) {
|
||||
|
||||
|
||||
if (PyString_Check(pychunk)) {
|
||||
if ((wsize = write(wsgi_req->poll.fd, PyString_AsString(pychunk), PyString_Size(pychunk))) < 0) {
|
||||
if ((wsize = wsgi_req->socket->proto_write(wsgi_req, PyString_AsString(pychunk), PyString_Size(pychunk))) < 0) {
|
||||
uwsgi_error("write()");
|
||||
Py_DECREF(pychunk);
|
||||
goto clear;
|
||||
@@ -211,15 +211,12 @@ clear:
|
||||
if (wsgi_req->sendfile_fd != -1) {
|
||||
Py_DECREF((PyObject *)wsgi_req->async_sendfile);
|
||||
}
|
||||
if (wsgi_req->async_input) {
|
||||
Py_DECREF((PyObject *)wsgi_req->async_input);
|
||||
}
|
||||
if (wsgi_req->async_environ) {
|
||||
PyDict_Clear(wsgi_req->async_environ);
|
||||
}
|
||||
if (wsgi_req->async_post && !wsgi_req->fd_closed) {
|
||||
fclose(wsgi_req->async_post);
|
||||
if (!uwsgi.post_buffering || wsgi_req->post_cl <= (size_t) uwsgi.post_buffering) {
|
||||
wsgi_req->fd_closed = 1;
|
||||
}
|
||||
}
|
||||
Py_XDECREF((PyObject *)wsgi_req->async_placeholder);
|
||||
clear2:
|
||||
Py_DECREF((PyObject *)wsgi_req->async_result);
|
||||
|
||||
@@ -2,7 +2,7 @@ import os,sys
|
||||
|
||||
NAME='python24'
|
||||
|
||||
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule'])
|
||||
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule', 'profiler'])
|
||||
|
||||
CFLAGS = os.popen('python2.4-config --cflags').read().rstrip().split()
|
||||
CFLAGS.append('-Wno-unused-parameter')
|
||||
|
||||
@@ -2,7 +2,7 @@ import os,sys
|
||||
|
||||
NAME='python25'
|
||||
|
||||
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule'])
|
||||
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule', 'profiler'])
|
||||
|
||||
CFLAGS = os.popen('python2.5-config --cflags').read().rstrip().split()
|
||||
CFLAGS.append('-Wno-unused-parameter')
|
||||
|
||||
@@ -2,7 +2,7 @@ import os,sys
|
||||
|
||||
NAME='python26'
|
||||
|
||||
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule'])
|
||||
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule', 'profiler'])
|
||||
|
||||
CFLAGS = os.popen('python2.6-config --cflags').read().rstrip().split()
|
||||
CFLAGS.append('-Wno-unused-parameter')
|
||||
|
||||
@@ -2,7 +2,7 @@ import os,sys
|
||||
|
||||
NAME='python27'
|
||||
|
||||
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule'])
|
||||
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule', 'profiler'])
|
||||
|
||||
CFLAGS = os.popen('python2.7-config --cflags').read().rstrip().split()
|
||||
CFLAGS.append('-Wno-unused-parameter')
|
||||
|
||||
@@ -2,7 +2,7 @@ import os,sys
|
||||
|
||||
NAME='python30'
|
||||
|
||||
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule'])
|
||||
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule', 'profiler'])
|
||||
|
||||
CFLAGS = os.popen('python3.0-config --cflags').read().rstrip().split()
|
||||
CFLAGS.append('-Wno-unused-parameter')
|
||||
|
||||
@@ -2,7 +2,7 @@ import os,sys
|
||||
|
||||
NAME='python31'
|
||||
|
||||
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule'])
|
||||
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule', 'profiler'])
|
||||
|
||||
CFLAGS = os.popen('python3.1-config --cflags').read().rstrip().split()
|
||||
CFLAGS.append('-Wno-unused-parameter')
|
||||
|
||||
@@ -2,7 +2,7 @@ import os,sys
|
||||
|
||||
NAME='python32'
|
||||
|
||||
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule'])
|
||||
GCC_LIST = map(lambda x: '../python/' + x, ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule', 'profiler'])
|
||||
|
||||
CFLAGS = os.popen('python3.2-config --cflags').read().rstrip().split()
|
||||
CFLAGS.append('-Wno-unused-parameter')
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
#include "uwsgi_rack.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
extern struct uwsgi_rack ur;
|
||||
|
||||
VALUE fiber_list[200];
|
||||
|
||||
void uwsgi_ruby_exception(void);
|
||||
|
||||
VALUE fiber_request() {
|
||||
|
||||
struct wsgi_request *wsgi_req = uwsgi.wsgi_req;
|
||||
int async_id = wsgi_req->async_id;
|
||||
|
||||
|
||||
for(;;) {
|
||||
wsgi_req_setup(wsgi_req, async_id);
|
||||
|
||||
wsgi_req->async_status = UWSGI_ACCEPTING;
|
||||
|
||||
rb_fiber_yield(0, NULL);
|
||||
|
||||
if (wsgi_req_simple_accept(wsgi_req, uwsgi.sockets_poll[0].fd)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
wsgi_req->async_status = UWSGI_OK;
|
||||
|
||||
rb_fiber_yield(0, NULL);
|
||||
|
||||
// reinitialize switches counter
|
||||
|
||||
wsgi_req->switches = 0;
|
||||
if (wsgi_req_recv(wsgi_req)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while(wsgi_req->async_status == UWSGI_AGAIN) {
|
||||
rb_fiber_yield(0, NULL);
|
||||
wsgi_req->async_status = uwsgi.p[wsgi_req->uh.modifier1]->request(wsgi_req);
|
||||
}
|
||||
|
||||
|
||||
|
||||
rb_fiber_yield(0, NULL);
|
||||
|
||||
uwsgi_close_request(wsgi_req);
|
||||
|
||||
}
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
|
||||
VALUE protected_fiber_loop() {
|
||||
|
||||
int i, current = 0;
|
||||
|
||||
struct wsgi_request *wsgi_req;
|
||||
|
||||
// create a ruby fiber for each async core
|
||||
|
||||
uwsgi_log("create a fiber for each async core...\n");
|
||||
for(i=0;i<uwsgi.async;i++) {
|
||||
fiber_list[i] = rb_fiber_new(fiber_request, Qnil);
|
||||
rb_gc_register_address(&fiber_list[i]);
|
||||
uwsgi.wsgi_requests[i]->async_status = UWSGI_ACCEPTING;
|
||||
uwsgi.wsgi_requests[i]->async_id = i;
|
||||
uwsgi.wsgi_req = uwsgi.wsgi_requests[i];
|
||||
rb_fiber_resume(fiber_list[i], 0, NULL);
|
||||
uwsgi_log("fiber %d ready\n", i);
|
||||
}
|
||||
|
||||
|
||||
for(;;) {
|
||||
|
||||
//uwsgi.async_running = u_green_blocking();
|
||||
uwsgi.async_running = 0;
|
||||
//timeout = u_green_get_timeout();
|
||||
int timeout = 0;
|
||||
uwsgi.async_nevents = async_wait(uwsgi.async_queue, uwsgi.async_events, uwsgi.async, uwsgi.async_running, timeout);
|
||||
//u_green_expire_timeouts();
|
||||
|
||||
if (uwsgi.async_nevents < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
for(i=0; i<uwsgi.async_nevents;i++) {
|
||||
|
||||
uwsgi_log("received I/O event on fd %d\n", (int) uwsgi.async_events[i].ASYNC_FD);
|
||||
if ( (int) uwsgi.async_events[i].ASYNC_FD == uwsgi.sockets[0].fd) {
|
||||
wsgi_req = find_first_accepting_wsgi_req();
|
||||
if (!wsgi_req) goto cycle;
|
||||
uwsgi_log("request passed to fiber core %d\n", wsgi_req->async_id);
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
uwsgi.wsgi_req->switches++;
|
||||
rb_fiber_resume(fiber_list[wsgi_req->async_id], 0, NULL);
|
||||
}
|
||||
else {
|
||||
wsgi_req = find_wsgi_req_by_fd((int)uwsgi.async_events[i].ASYNC_FD, -1);
|
||||
if (wsgi_req) {
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
uwsgi.wsgi_req->switches++;
|
||||
rb_fiber_resume(fiber_list[wsgi_req->async_id], 0, NULL);
|
||||
}
|
||||
else {
|
||||
async_del(uwsgi.async_queue, (int) uwsgi.async_events[i].ASYNC_FD, uwsgi.async_events[i].ASYNC_EV);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
cycle:
|
||||
|
||||
//uwsgi_log("resuming fiber %d %p\n", current, fiber_list[current]);
|
||||
uwsgi.wsgi_req = uwsgi.wsgi_requests[current];
|
||||
uwsgi.wsgi_req->switches++;
|
||||
if (uwsgi.wsgi_req->async_status != UWSGI_ACCEPTING) {
|
||||
uwsgi_log("passing control to fiber %d\n", current);
|
||||
rb_fiber_resume(fiber_list[current], 0, NULL);
|
||||
uwsgi_log("returned to main fiber\n");
|
||||
}
|
||||
current++;
|
||||
if (current >= uwsgi.async) current = 0;
|
||||
}
|
||||
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
void fiber_loop() {
|
||||
|
||||
int error;
|
||||
|
||||
// must run all the rack/ruby plugins without protection
|
||||
ur.unprotected = 1;
|
||||
|
||||
rb_protect(protected_fiber_loop, 0, &error);
|
||||
|
||||
if (error) {
|
||||
uwsgi_ruby_exception();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// never here
|
||||
|
||||
}
|
||||
+120
-181
@@ -87,52 +87,6 @@ VALUE rb_uwsgi_io_new(VALUE class, VALUE wr) {
|
||||
Data_Get_Struct(wr, struct wsgi_request, wsgi_req);
|
||||
VALUE self = Data_Wrap_Struct(class , 0, 0, wsgi_req);
|
||||
|
||||
ssize_t len = uwsgi.post_buffering_bufsize;
|
||||
size_t post_remains = wsgi_req->post_cl;
|
||||
char *ptr;
|
||||
|
||||
/* now the fun part:
|
||||
|
||||
We will try to emulate a StringIO ruby object if http body is littler than uwsgi.post_buffering_bufsize
|
||||
otherwise we will map a *FILE object
|
||||
|
||||
*/
|
||||
|
||||
if (!wsgi_req->post_cl) {
|
||||
return self;
|
||||
}
|
||||
|
||||
if (wsgi_req->post_cl > (size_t) uwsgi.post_buffering) {
|
||||
//uwsgi_log("using file for http body storage %d\n", wsgi_req->post_cl);
|
||||
//RUBY_GVL_UNLOCK
|
||||
uwsgi_read_whole_body(wsgi_req, wsgi_req->post_buffering_buf, uwsgi.post_buffering_bufsize);
|
||||
//RUBY_GVL_LOCK
|
||||
}
|
||||
else {
|
||||
//RUBY_GVL_UNLOCK
|
||||
//uwsgi_log("using memory for http body storage %d\n", wsgi_req->post_cl);
|
||||
ptr = wsgi_req->post_buffering_buf;
|
||||
while(post_remains > 0) {
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
|
||||
inc_harakiri(uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
}
|
||||
if (post_remains > (size_t) uwsgi.post_buffering_bufsize) {
|
||||
len = read(wsgi_req->poll.fd, ptr, len);
|
||||
}
|
||||
else {
|
||||
len = read(wsgi_req->poll.fd, ptr, post_remains);
|
||||
}
|
||||
if (len < 0) {
|
||||
uwsgi_error("read()");
|
||||
return Qnil;
|
||||
}
|
||||
ptr += len;
|
||||
post_remains -= len;
|
||||
}
|
||||
wsgi_req->buf_pos = 0;
|
||||
//RUBY_GVL_LOCK
|
||||
}
|
||||
|
||||
rb_obj_call_init(self, 0, NULL);
|
||||
|
||||
return self;
|
||||
@@ -150,6 +104,8 @@ VALUE rb_uwsgi_io_gets(VALUE obj, VALUE args) {
|
||||
Data_Get_Struct(obj, struct wsgi_request, wsgi_req);
|
||||
|
||||
// return the whole body as string
|
||||
|
||||
uwsgi_log("rack.input gets is not implemented (req %p)\n", wsgi_req);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
@@ -159,6 +115,7 @@ VALUE rb_uwsgi_io_each(VALUE obj, VALUE args) {
|
||||
Data_Get_Struct(obj, struct wsgi_request, wsgi_req);
|
||||
|
||||
// yield strings chunks
|
||||
uwsgi_log("rack.input each is not implemented (req %p)\n", wsgi_req);
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
@@ -168,63 +125,28 @@ VALUE rb_uwsgi_io_read(VALUE obj, VALUE args) {
|
||||
struct wsgi_request *wsgi_req;
|
||||
Data_Get_Struct(obj, struct wsgi_request, wsgi_req);
|
||||
VALUE chunk;
|
||||
size_t len;
|
||||
int chunk_size;
|
||||
|
||||
|
||||
if (!wsgi_req->post_cl) {
|
||||
if (!wsgi_req->post_cl || wsgi_req->buf_pos >= wsgi_req->post_cl) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
if (RARRAY_LEN(args) == 0) {
|
||||
//uwsgi_log("reading the whole post data\n" ) ;
|
||||
if (wsgi_req->post_cl > (size_t) uwsgi.post_buffering) {
|
||||
char *post_body = malloc(wsgi_req->post_cl);
|
||||
if (post_body) {
|
||||
//RUBY_GVL_UNLOCK
|
||||
len = fread( post_body, wsgi_req->post_cl, 1, wsgi_req->async_post);
|
||||
//RUBY_GVL_LOCK
|
||||
chunk = rb_str_new(post_body, wsgi_req->post_cl);
|
||||
free(post_body);
|
||||
}
|
||||
else {
|
||||
uwsgi_error("malloc()");
|
||||
return Qnil;
|
||||
}
|
||||
}
|
||||
else {
|
||||
chunk = rb_str_new(wsgi_req->post_buffering_buf, wsgi_req->post_cl);
|
||||
}
|
||||
chunk = rb_str_new(wsgi_req->post_buffering_buf+wsgi_req->buf_pos, wsgi_req->post_cl-wsgi_req->buf_pos);
|
||||
return chunk;
|
||||
}
|
||||
else if (RARRAY_LEN(args) > 0) {
|
||||
chunk_size = NUM2INT(RARRAY_PTR(args)[0]);
|
||||
//uwsgi_log("chunk reading of %d bytes (post_cl: %d bufsize: %d)\n", chunk_size, wsgi_req->post_cl, uwsgi.post_buffering_bufsize ) ;
|
||||
if (wsgi_req->post_cl > (size_t) uwsgi.post_buffering) {
|
||||
char *post_body = malloc( chunk_size ) ;
|
||||
if (post_body) {
|
||||
//RUBY_GVL_UNLOCK
|
||||
len = fread( post_body, chunk_size, 1, wsgi_req->async_post );
|
||||
//uwsgi_log("read %d items\n", len);
|
||||
//RUBY_GVL_LOCK
|
||||
chunk = rb_str_new(post_body, chunk_size);
|
||||
free(post_body);
|
||||
}
|
||||
else {
|
||||
uwsgi_error("malloc()");
|
||||
return Qnil;
|
||||
}
|
||||
if (wsgi_req->buf_pos+chunk_size > wsgi_req->post_cl) {
|
||||
chunk_size = wsgi_req->post_cl-wsgi_req->buf_pos;
|
||||
}
|
||||
else {
|
||||
if (RARRAY_LEN(args) > 1) {
|
||||
rb_str_cat(RARRAY_PTR(args)[1], wsgi_req->post_buffering_buf+wsgi_req->buf_pos, chunk_size);
|
||||
}
|
||||
chunk = rb_str_new(wsgi_req->post_buffering_buf+wsgi_req->buf_pos, chunk_size);
|
||||
wsgi_req->buf_pos+=chunk_size;
|
||||
wsgi_req->buf_pos+=chunk_size;
|
||||
if (RARRAY_LEN(args) > 1) {
|
||||
rb_str_cat(RARRAY_PTR(args)[1], wsgi_req->post_buffering_buf+wsgi_req->buf_pos, chunk_size);
|
||||
return RARRAY_PTR(args)[1];
|
||||
}
|
||||
|
||||
return chunk;
|
||||
|
||||
return rb_str_new(wsgi_req->post_buffering_buf+wsgi_req->buf_pos, chunk_size);
|
||||
}
|
||||
|
||||
return Qnil;
|
||||
@@ -239,14 +161,7 @@ VALUE rb_uwsgi_io_rewind(VALUE obj, VALUE args) {
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
if (wsgi_req->post_cl > (size_t) uwsgi.post_buffering) {
|
||||
//RUBY_GVL_LOCK
|
||||
rewind(wsgi_req->async_post);
|
||||
//RUBY_GVL_UNLOCK
|
||||
}
|
||||
else {
|
||||
wsgi_req->buf_pos = 0;
|
||||
}
|
||||
wsgi_req->buf_pos = 0;
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
@@ -269,13 +184,55 @@ VALUE require_rails(VALUE arg) {
|
||||
|
||||
VALUE init_rack_app(VALUE);
|
||||
|
||||
#ifdef RUBY19
|
||||
VALUE uwsgi_ruby_fiber_yield() {
|
||||
return rb_fiber_yield(0, NULL);
|
||||
}
|
||||
#endif
|
||||
VALUE uwsgi_ruby_wait_fd_read(VALUE *class, VALUE arg1, VALUE arg2) {
|
||||
|
||||
VALUE uwsgi_ruby_suspend(VALUE *arg) {
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
int fd = NUM2INT(arg1);
|
||||
int timeout = NUM2INT(arg2);
|
||||
|
||||
if (fd >= 0) {
|
||||
async_add_fd_read(wsgi_req, fd, timeout);
|
||||
}
|
||||
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
VALUE uwsgi_ruby_wait_fd_write(VALUE *class, VALUE arg1, VALUE arg2) {
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
int fd = NUM2INT(arg1);
|
||||
int timeout = NUM2INT(arg2);
|
||||
|
||||
if (fd >= 0) {
|
||||
async_add_fd_write(wsgi_req, fd, timeout);
|
||||
}
|
||||
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
VALUE uwsgi_ruby_async_connect(VALUE *class, VALUE arg) {
|
||||
|
||||
int fd = uwsgi_connect(RSTRING_PTR(arg), 0, 1);
|
||||
|
||||
return INT2FIX(fd);
|
||||
}
|
||||
|
||||
|
||||
VALUE uwsgi_ruby_async_sleep(VALUE *class, VALUE arg) {
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
int timeout = NUM2INT(arg);
|
||||
|
||||
if (timeout >= 0) {
|
||||
async_add_timeout(wsgi_req, timeout);
|
||||
}
|
||||
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
VALUE uwsgi_ruby_suspend(VALUE *class) {
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
@@ -312,19 +269,16 @@ int uwsgi_rack_init(){
|
||||
ruby_init();
|
||||
ruby_init_loadpath();
|
||||
#endif
|
||||
ruby_show_version();
|
||||
|
||||
ruby_script("uwsgi");
|
||||
|
||||
#ifdef RUBY19
|
||||
uwsgi_register_loop( (char *) "fiber", fiber_loop);
|
||||
#endif
|
||||
|
||||
VALUE rb_uwsgi_embedded = rb_define_module("UWSGI");
|
||||
rb_define_module_function(rb_uwsgi_embedded, "suspend", uwsgi_ruby_suspend, 0);
|
||||
#ifdef RUBY19
|
||||
rb_define_module_function(rb_uwsgi_embedded, "fiber_yield", uwsgi_ruby_fiber_yield, 0);
|
||||
#endif
|
||||
|
||||
rb_define_module_function(rb_uwsgi_embedded, "async_sleep", uwsgi_ruby_async_sleep, 1);
|
||||
rb_define_module_function(rb_uwsgi_embedded, "wait_fd_read", uwsgi_ruby_wait_fd_read, 2);
|
||||
rb_define_module_function(rb_uwsgi_embedded, "wait_fd_write", uwsgi_ruby_wait_fd_write, 2);
|
||||
rb_define_module_function(rb_uwsgi_embedded, "async_connect", uwsgi_ruby_async_connect, 1);
|
||||
|
||||
if (ur.rack) {
|
||||
ur.dispatcher = rb_protect(init_rack_app, rb_str_new2(ur.rack), &error);
|
||||
@@ -376,14 +330,6 @@ int uwsgi_rack_init(){
|
||||
rb_define_method(ur.rb_uwsgi_io_class, "read", rb_uwsgi_io_read, -2);
|
||||
rb_define_method(ur.rb_uwsgi_io_class, "rewind", rb_uwsgi_io_rewind, 0);
|
||||
|
||||
#ifdef RUBY19
|
||||
#ifdef UWSGI_THREADING
|
||||
if (uwsgi.threads > 1) {
|
||||
rb_gc_disable();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
@@ -398,11 +344,10 @@ VALUE send_body(VALUE obj) {
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
ssize_t len = 0;
|
||||
int fd = wsgi_req->poll.fd;
|
||||
|
||||
//uwsgi_log("sending body\n");
|
||||
if (TYPE(obj) == T_STRING) {
|
||||
len = write( fd, RSTRING_PTR(obj), RSTRING_LEN(obj));
|
||||
len = wsgi_req->socket->proto_write( wsgi_req, RSTRING_PTR(obj), RSTRING_LEN(obj));
|
||||
}
|
||||
else {
|
||||
uwsgi_log("UNMANAGED BODY TYPE %d\n", TYPE(obj));
|
||||
@@ -428,8 +373,8 @@ VALUE send_header(VALUE obj, VALUE headers) {
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
size_t len;
|
||||
int fd = wsgi_req->poll.fd;
|
||||
VALUE hkey, hval;
|
||||
|
||||
|
||||
//uwsgi_log("HEADERS %d\n", TYPE(obj));
|
||||
if (TYPE(obj) == T_ARRAY) {
|
||||
@@ -460,9 +405,9 @@ VALUE send_header(VALUE obj, VALUE headers) {
|
||||
|
||||
//uwsgi_log("header: %.*s: %.*s\n", RSTRING_LEN(hkey), RSTRING_PTR(hkey), RSTRING_LEN(hval), RSTRING_PTR(hval));
|
||||
|
||||
len = write( fd, RSTRING_PTR(hkey), RSTRING_LEN(hkey));
|
||||
len = wsgi_req->socket->proto_write_header( wsgi_req, RSTRING_PTR(hkey), RSTRING_LEN(hkey));
|
||||
wsgi_req->headers_size += len;
|
||||
len = write( fd, ": ", 2);
|
||||
len = wsgi_req->socket->proto_write_header( wsgi_req, ": ", 2);
|
||||
wsgi_req->headers_size += len;
|
||||
|
||||
char *header_value = RSTRING_PTR(hval);
|
||||
@@ -471,17 +416,17 @@ VALUE send_header(VALUE obj, VALUE headers) {
|
||||
char *header_value_splitted = memchr(header_value, '\n', header_value_len);
|
||||
|
||||
if (!header_value_splitted) {
|
||||
len = write( fd, header_value, header_value_len);
|
||||
len = wsgi_req->socket->proto_write_header( wsgi_req, header_value, header_value_len);
|
||||
wsgi_req->headers_size += len;
|
||||
len = write( fd, "\r\n", 2);
|
||||
len = wsgi_req->socket->proto_write_header( wsgi_req, "\r\n", 2);
|
||||
wsgi_req->headers_size += len;
|
||||
wsgi_req->header_cnt++;
|
||||
}
|
||||
else {
|
||||
header_value_splitted[0] = 0;
|
||||
len = write( fd, header_value, header_value_splitted-header_value);
|
||||
len = wsgi_req->socket->proto_write_header( wsgi_req, header_value, header_value_splitted-header_value);
|
||||
wsgi_req->headers_size += len;
|
||||
len = write( fd, "\r\n", 2);
|
||||
len = wsgi_req->socket->proto_write_header( wsgi_req, "\r\n", 2);
|
||||
wsgi_req->headers_size += len;
|
||||
wsgi_req->header_cnt++;
|
||||
|
||||
@@ -491,14 +436,14 @@ VALUE send_header(VALUE obj, VALUE headers) {
|
||||
while(header_value_len && (header_value_splitted = memchr(header_value, '\n', header_value_len))) {
|
||||
header_value_splitted[0] = 0;
|
||||
|
||||
len = write( fd, RSTRING_PTR(hkey), RSTRING_LEN(hkey));
|
||||
len = wsgi_req->socket->proto_write( wsgi_req, RSTRING_PTR(hkey), RSTRING_LEN(hkey));
|
||||
wsgi_req->headers_size += len;
|
||||
len = write( fd, ": ", 2);
|
||||
len = wsgi_req->socket->proto_write( wsgi_req, ": ", 2);
|
||||
wsgi_req->headers_size += len;
|
||||
|
||||
len = write( fd, header_value, header_value_splitted-header_value);
|
||||
len = wsgi_req->socket->proto_write( wsgi_req, header_value, header_value_splitted-header_value);
|
||||
wsgi_req->headers_size += len;
|
||||
len = write( fd, "\r\n", 2);
|
||||
len = wsgi_req->socket->proto_write( wsgi_req, "\r\n", 2);
|
||||
wsgi_req->headers_size += len;
|
||||
wsgi_req->header_cnt++;
|
||||
|
||||
@@ -517,9 +462,21 @@ clear:
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE iterate_headers(VALUE headers) {
|
||||
|
||||
#ifdef RUBY19
|
||||
return rb_block_call(headers, rb_intern("each"), 0, 0, send_header, headers );
|
||||
#else
|
||||
return rb_iterate(rb_each, headers, send_header, headers);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
int error;
|
||||
int error = 0;
|
||||
int i;
|
||||
VALUE env, ret, status, headers, body;
|
||||
|
||||
@@ -532,13 +489,10 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
|
||||
if (uwsgi_parse_vars(wsgi_req)) {
|
||||
if (wsgi_req->status != 200) uwsgi_log("Invalid RACK request. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//RUBY_GVL_LOCK
|
||||
|
||||
env = rb_hash_new();
|
||||
|
||||
// fill ruby hash
|
||||
@@ -572,7 +526,13 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
|
||||
rb_hash_aset(env, rb_str_new2("rack.run_once"), Qfalse);
|
||||
|
||||
VALUE dws_wr = Data_Wrap_Struct(ur.rb_uwsgi_io_class, 0, 0, wsgi_req);
|
||||
rb_hash_aset(env, rb_str_new2("rack.input"), rb_funcall(ur.rb_uwsgi_io_class, rb_intern("new"), 1, dws_wr ));
|
||||
|
||||
if (wsgi_req->async_post) {
|
||||
rb_hash_aset(env, rb_str_new2("rack.input"), rb_funcall( rb_const_get(rb_cObject, rb_intern("IO")), rb_intern("new"), 2, INT2NUM(fileno(wsgi_req->async_post)), rb_str_new("r",1) ));
|
||||
}
|
||||
else {
|
||||
rb_hash_aset(env, rb_str_new2("rack.input"), rb_funcall(ur.rb_uwsgi_io_class, rb_intern("new"), 1, dws_wr ));
|
||||
}
|
||||
|
||||
rb_hash_aset(env, rb_str_new2("rack.errors"), rb_funcall( rb_const_get(rb_cObject, rb_intern("IO")), rb_intern("new"), 2, INT2NUM(2), rb_str_new("w",1) ));
|
||||
|
||||
@@ -627,29 +587,39 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
|
||||
wsgi_req->hvec[5].iov_base = (char *) "\r\n";
|
||||
wsgi_req->hvec[5].iov_len = 2 ;
|
||||
|
||||
//RUBY_GVL_UNLOCK
|
||||
if ( !(wsgi_req->headers_size = writev(wsgi_req->poll.fd, wsgi_req->hvec, 6)) ) {
|
||||
if ( !(wsgi_req->headers_size = wsgi_req->socket->proto_writev_header(wsgi_req, wsgi_req->hvec, 6)) ) {
|
||||
uwsgi_error("writev()");
|
||||
}
|
||||
//RUBY_GVL_LOCK
|
||||
|
||||
headers = RARRAY_PTR(ret)[1] ;
|
||||
if (rb_respond_to( headers, rb_intern("each") )) {
|
||||
rb_iterate( rb_each, headers, send_header, headers);
|
||||
if (ur.unprotected) {
|
||||
#ifdef RUBY19
|
||||
rb_block_call(headers, rb_intern("each"), 0, 0, send_header, headers);
|
||||
#else
|
||||
rb_iterate(rb_each, headers, send_header, headers);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
rb_protect( iterate_headers, headers, &error);
|
||||
if (error) {
|
||||
uwsgi_ruby_exception();
|
||||
rb_gc_unregister_address(&status);
|
||||
rb_gc_unregister_address(&headers);
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//RUBY_GVL_UNLOCK
|
||||
if (write(wsgi_req->poll.fd, "\r\n", 2) != 2) {
|
||||
if (wsgi_req->socket->proto_write(wsgi_req, "\r\n", 2) != 2) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
//RUBY_GVL_LOCK
|
||||
|
||||
body = RARRAY_PTR(ret)[2] ;
|
||||
|
||||
if (rb_respond_to( body, rb_intern("to_path") )) {
|
||||
VALUE sendfile_path = rb_funcall( body, rb_intern("to_path"), 0);
|
||||
wsgi_req->sendfile_fd = open(RSTRING_PTR(sendfile_path), O_RDONLY);
|
||||
//RUBY_GVL_UNLOCK
|
||||
wsgi_req->response_size = uwsgi_sendfile(wsgi_req);
|
||||
if (wsgi_req->response_size > 0) {
|
||||
while(wsgi_req->response_size < wsgi_req->sendfile_fd_size) {
|
||||
@@ -657,7 +627,6 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
|
||||
wsgi_req->response_size += uwsgi_sendfile(wsgi_req);
|
||||
}
|
||||
}
|
||||
//RUBY_GVL_LOCK;
|
||||
rb_gc_unregister_address(&sendfile_path);
|
||||
|
||||
}
|
||||
@@ -691,36 +660,21 @@ int uwsgi_rack_request(struct wsgi_request *wsgi_req) {
|
||||
rb_gc_unregister_address(&body);
|
||||
|
||||
}
|
||||
else {
|
||||
internal_server_error(wsgi_req, "Invalid RACK response");
|
||||
}
|
||||
|
||||
clear:
|
||||
|
||||
rb_gc_unregister_address(&ret);
|
||||
|
||||
rb_gc_unregister_address(&env);
|
||||
|
||||
if (ur.gc_freq <= 1 || ur.cycles%ur.gc_freq == 0) {
|
||||
#ifdef RUBY19
|
||||
#ifdef UWSGI_THREADING
|
||||
if (uwsgi.threads > 1) {
|
||||
if (wsgi_req->async_id == 0) {
|
||||
rb_gc_enable();
|
||||
rb_gc();
|
||||
rb_gc_disable();
|
||||
}
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
#endif
|
||||
//uwsgi_log("calling ruby GC\n");
|
||||
rb_gc();
|
||||
#ifdef RUBY19
|
||||
#ifdef UWSGI_THREADING
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
//RUBY_GVL_UNLOCK
|
||||
|
||||
ur.cycles++;
|
||||
|
||||
|
||||
@@ -761,15 +715,6 @@ void uwsgi_rack_resume(struct wsgi_request *wsgi_req) {
|
||||
uwsgi_log("RESUMING RUBY\n");
|
||||
}
|
||||
|
||||
void uwsgi_rack_enable_threads(void) {
|
||||
|
||||
pthread_mutex_init(&ur.gvl, NULL);
|
||||
}
|
||||
|
||||
void uwsgi_rack_init_thread(int core_id) {
|
||||
// thread initialization
|
||||
}
|
||||
|
||||
VALUE init_rack_app( VALUE script ) {
|
||||
|
||||
int error;
|
||||
@@ -858,11 +803,5 @@ struct uwsgi_plugin rack_plugin = {
|
||||
|
||||
.suspend = uwsgi_rack_suspend,
|
||||
.resume = uwsgi_rack_resume,
|
||||
#ifdef RUBY19
|
||||
#ifdef UWSGI_THREADING
|
||||
.enable_threads = uwsgi_rack_enable_threads,
|
||||
.init_thread = uwsgi_rack_init_thread,
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -60,3 +60,5 @@ struct uwsgi_rack {
|
||||
pthread_mutex_t gvl;
|
||||
|
||||
};
|
||||
|
||||
void uwsgi_ruby_exception(void);
|
||||
|
||||
@@ -17,7 +17,6 @@ GCC_LIST = ['rack_plugin']
|
||||
if v[0] == '1' and v[1] == '9':
|
||||
CFLAGS.append('-DRUBY19')
|
||||
CFLAGS.append('-Wno-unused-parameter')
|
||||
GCC_LIST.append('fiber')
|
||||
|
||||
includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['rubyhdrdir']\"").read().rstrip()
|
||||
if includedir == 'nil':
|
||||
|
||||
+18
-11
@@ -5,9 +5,8 @@ extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_rpc_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
char *argv[0xff];
|
||||
uint8_t argc;
|
||||
int i;
|
||||
char *argv[256];
|
||||
uint8_t argc = 0xff;
|
||||
|
||||
/* Standard RPC request */
|
||||
if (!wsgi_req->uh.pktsize) {
|
||||
@@ -15,24 +14,32 @@ int uwsgi_rpc_request(struct wsgi_request *wsgi_req) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_log("parsing array\n");
|
||||
/*
|
||||
for(argc=0;argc<wsgi_req->uh.pktsize;argc++) {
|
||||
uwsgi_log("rpc: %c\n", wsgi_req->buffer[argc]);
|
||||
}
|
||||
*/
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("RPC pktsize %d\n", wsgi_req->uh.pktsize);
|
||||
#endif
|
||||
|
||||
if (uwsgi_parse_array(wsgi_req->buffer, wsgi_req->uh.pktsize, argv, &argc)) {
|
||||
uwsgi_log("Invalid RPC request. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
uwsgi_log("done\n");
|
||||
|
||||
for(i=0;i<argc;i++) {
|
||||
uwsgi_log("arg %d %s\n", i, argv[i]);
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("RPC args %d\n", argc-1);
|
||||
#endif
|
||||
|
||||
wsgi_req->uh.pktsize = uwsgi_rpc(argv[0], argc-1, argv+1, wsgi_req->buffer);
|
||||
|
||||
if (wsgi_req->uh.modifier2 == 0) {
|
||||
wsgi_req->headers_size = write(wsgi_req->poll.fd, &wsgi_req->uh, 4);
|
||||
wsgi_req->headers_size = wsgi_req->socket->proto_write_header(wsgi_req, (char *)&wsgi_req->uh, 4);
|
||||
}
|
||||
|
||||
wsgi_req->response_size = write(wsgi_req->poll.fd, wsgi_req->buffer, wsgi_req->uh.pktsize);
|
||||
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, wsgi_req->buffer, wsgi_req->uh.pktsize);
|
||||
wsgi_req->status = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -2,8 +2,10 @@ import os,sys
|
||||
|
||||
NAME='ruby19'
|
||||
|
||||
#RUBYPATH = '/opt/ruby19/bin/ruby'
|
||||
RUBYPATH = '/Users/roberto/RUBY/bin/ruby'
|
||||
try:
|
||||
RUBYPATH = os.environ['UWSGICONFIG_RUBYPATH']
|
||||
except:
|
||||
RUBYPATH = 'ruby'
|
||||
|
||||
GCC_LIST = ['../rack/rack_plugin']
|
||||
CFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['CFLAGS']\"").read().rstrip().split()
|
||||
@@ -13,7 +15,6 @@ v = version.split('.')
|
||||
|
||||
if v[0] == '1' and v[1] == '9':
|
||||
CFLAGS.append('-DRUBY19')
|
||||
GCC_LIST.append('../rack/fiber')
|
||||
|
||||
includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['rubyhdrdir']\"").read().rstrip()
|
||||
if includedir == 'nil':
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
#include "../python/uwsgi_python.h"
|
||||
#include <stackless_api.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct ustackless {
|
||||
int enabled;
|
||||
PyObject *callable;
|
||||
PyTaskletObject **sl;
|
||||
} usl;
|
||||
|
||||
struct option stackless_options[] = {
|
||||
{"stackless", no_argument, &usl.enabled, 1},
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
PyObject *py_uwsgi_stackless_request(PyObject * self, PyObject *args) {
|
||||
|
||||
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh.modifier1]->request(uwsgi.wsgi_req);
|
||||
uwsgi.wsgi_req->suspended = 0;
|
||||
|
||||
Py_DECREF(usl.sl[uwsgi.wsgi_req->async_id]);
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyMethodDef uwsgi_stackless_request_method[] = {{"uwsgi_stackless_request", py_uwsgi_stackless_request, METH_VARARGS, ""}};
|
||||
|
||||
inline static void stackless_schedule_to_req() {
|
||||
|
||||
int id = uwsgi.wsgi_req->async_id;
|
||||
|
||||
if (!uwsgi.wsgi_req->suspended) {
|
||||
usl.sl[id] = PyTasklet_New(NULL, usl.callable);
|
||||
PyObject *args = PyTuple_New(0);
|
||||
PyTasklet_Setup(usl.sl[id], args, NULL);
|
||||
Py_DECREF(args);
|
||||
uwsgi.wsgi_req->suspended = 1;
|
||||
}
|
||||
|
||||
PyTasklet_Run(usl.sl[id]);
|
||||
|
||||
if (uwsgi.wsgi_req->suspended) {
|
||||
uwsgi.wsgi_req->async_status = UWSGI_AGAIN;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inline static void stackless_schedule_to_main(struct wsgi_request *wsgi_req) {
|
||||
|
||||
PyStackless_Schedule(Py_None, 1);
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
}
|
||||
|
||||
|
||||
int stackless_init() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void stackless_init_apps(void) {
|
||||
|
||||
if (!usl.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
usl.sl = uwsgi_malloc( sizeof(PyTaskletObject *) * uwsgi.async );
|
||||
usl.callable = PyCFunction_New(uwsgi_stackless_request_method, NULL);
|
||||
uwsgi_log("enabled stackless engine\n");
|
||||
uwsgi.schedule_to_main = stackless_schedule_to_main;
|
||||
uwsgi.schedule_to_req = stackless_schedule_to_req;
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_plugin stackless_plugin = {
|
||||
|
||||
.name = "stackless",
|
||||
.init = stackless_init,
|
||||
.init_apps = stackless_init_apps,
|
||||
.options = stackless_options,
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
from distutils import sysconfig
|
||||
|
||||
NAME='stackless'
|
||||
CFLAGS = ['-I' + sysconfig.get_python_inc(), '-I' + sysconfig.get_python_inc(plat_specific=True)]
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
|
||||
GCC_LIST = ['stackless']
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
|
||||
#include "../uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
uint16_t proto_base_add_uwsgi_header(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, char *val, uint16_t vallen) {
|
||||
|
||||
|
||||
int i;
|
||||
char *buffer = wsgi_req->buffer + wsgi_req->uh.pktsize;
|
||||
char *watermark = wsgi_req->buffer + uwsgi.buffer_size;
|
||||
char *ptr = buffer;
|
||||
|
||||
|
||||
for (i = 0; i < keylen; i++) {
|
||||
if (key[i] == '-') {
|
||||
key[i] = '_';
|
||||
}
|
||||
else {
|
||||
key[i] = toupper((int)key[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi_strncmp("CONTENT_TYPE", 12, key, keylen) && uwsgi_strncmp("CONTENT_LENGTH", 14, key, keylen)) {
|
||||
if (buffer + keylen + vallen + 2 + 2 + 5 >= watermark) {
|
||||
uwsgi_log("[WARNING] unable to add %.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, key, vallen, val);
|
||||
return 0;
|
||||
}
|
||||
*ptr++ = (uint8_t) ((keylen + 5) & 0xff);
|
||||
*ptr++ = (uint8_t) (((keylen + 5) >> 8) & 0xff);
|
||||
memcpy(ptr, "HTTP_", 5);
|
||||
ptr += 5;
|
||||
memcpy(ptr, key, keylen);
|
||||
ptr += keylen;
|
||||
keylen += 5;
|
||||
}
|
||||
else {
|
||||
if (buffer + keylen + vallen + 2 + 2 >= watermark) {
|
||||
uwsgi_log("[WARNING] unable to add %.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, key, vallen, val);
|
||||
return 0;
|
||||
}
|
||||
*ptr++ = (uint8_t) (keylen & 0xff);
|
||||
*ptr++ = (uint8_t) ((keylen >> 8) & 0xff);
|
||||
memcpy(ptr, key, keylen);
|
||||
ptr += keylen;
|
||||
}
|
||||
|
||||
*ptr++ = (uint8_t) (vallen & 0xff);
|
||||
*ptr++ = (uint8_t) ((vallen >> 8) & 0xff);
|
||||
memcpy(ptr, val, vallen);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("add uwsgi var: %.*s = %.*s\n", keylen, key, vallen, val);
|
||||
#endif
|
||||
|
||||
return keylen + vallen + 2 + 2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint16_t proto_base_add_uwsgi_var(struct wsgi_request * wsgi_req, char *key, uint16_t keylen, char *val, uint16_t vallen) {
|
||||
|
||||
|
||||
char *buffer = wsgi_req->buffer + wsgi_req->uh.pktsize;
|
||||
char *watermark = wsgi_req->buffer + uwsgi.buffer_size;
|
||||
char *ptr = buffer;
|
||||
|
||||
if (buffer + keylen + vallen + 2 + 2 >= watermark) {
|
||||
uwsgi_log("[WARNING] unable to add %.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, key, vallen, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
*ptr++ = (uint8_t) (keylen & 0xff);
|
||||
*ptr++ = (uint8_t) ((keylen >> 8) & 0xff);
|
||||
memcpy(ptr, key, keylen);
|
||||
ptr += keylen;
|
||||
|
||||
*ptr++ = (uint8_t) (vallen & 0xff);
|
||||
*ptr++ = (uint8_t) ((vallen >> 8) & 0xff);
|
||||
memcpy(ptr, val, vallen);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("add uwsgi var: %.*s = %.*s\n", keylen, key, vallen, val);
|
||||
#endif
|
||||
|
||||
return keylen + vallen + 2 + 2;
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_proto_base_accept(struct wsgi_request *wsgi_req, int fd) {
|
||||
|
||||
wsgi_req->c_len = sizeof(struct sockaddr_un);
|
||||
return accept(fd, (struct sockaddr *) &wsgi_req->c_addr, (socklen_t *) & wsgi_req->c_len);
|
||||
}
|
||||
|
||||
void uwsgi_proto_base_close(struct wsgi_request *wsgi_req) {
|
||||
|
||||
if (wsgi_req->async_post) {
|
||||
fclose(wsgi_req->async_post);
|
||||
if (wsgi_req->body_as_file) {
|
||||
close(wsgi_req->poll.fd);
|
||||
}
|
||||
}
|
||||
else {
|
||||
close(wsgi_req->poll.fd);
|
||||
}
|
||||
}
|
||||
+287
@@ -0,0 +1,287 @@
|
||||
/* async fastcgi protocol parser */
|
||||
|
||||
#include "../uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#define PROTO_STATUS_RECV_HDR 0
|
||||
#define PROTO_STATUS_RECV_BODY 1
|
||||
|
||||
|
||||
int uwsgi_proto_fastcgi_parser(struct wsgi_request *wsgi_req) {
|
||||
|
||||
ssize_t len;
|
||||
struct fcgi_record *fr;
|
||||
uint16_t rs;
|
||||
int j;
|
||||
uint8_t octet;
|
||||
uint32_t keylen, vallen;
|
||||
|
||||
// allocate space for a fastcgi record
|
||||
if (!wsgi_req->proto_parser_buf) {
|
||||
wsgi_req->proto_parser_buf = uwsgi_malloc(8 + 65536);
|
||||
}
|
||||
|
||||
if (wsgi_req->proto_parser_status == PROTO_STATUS_RECV_HDR) {
|
||||
len = read(wsgi_req->poll.fd, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos, 8 - wsgi_req->proto_parser_pos);
|
||||
if (len <= 0) {
|
||||
free(wsgi_req->proto_parser_buf);
|
||||
uwsgi_error("read()");
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->proto_parser_pos += len;
|
||||
|
||||
if (wsgi_req->proto_parser_pos >= 8) {
|
||||
fr = (struct fcgi_record *) wsgi_req->proto_parser_buf;
|
||||
rs = ntohs(fr->cl);
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("fastcgi rs %d type %d\n", rs, fr->type);
|
||||
#endif
|
||||
// empty STDIN ?
|
||||
if (fr->type == 5 && rs == 0) {
|
||||
wsgi_req->proto_parser_status = 0;
|
||||
if (wsgi_req->async_post) {
|
||||
rewind(wsgi_req->async_post);
|
||||
wsgi_req->body_as_file = 1;
|
||||
}
|
||||
free(wsgi_req->proto_parser_buf);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
wsgi_req->proto_parser_pos = 0;
|
||||
if (rs == 0) {
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
wsgi_req->proto_parser_status = PROTO_STATUS_RECV_BODY;
|
||||
}
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
else if (wsgi_req->proto_parser_status == PROTO_STATUS_RECV_BODY) {
|
||||
|
||||
fr = (struct fcgi_record *) wsgi_req->proto_parser_buf;
|
||||
rs = ntohs(fr->cl);
|
||||
|
||||
len = read(wsgi_req->poll.fd, wsgi_req->proto_parser_buf + 8 + wsgi_req->proto_parser_pos, (rs + fr->pad) - wsgi_req->proto_parser_pos);
|
||||
if (len <= 0) {
|
||||
free(wsgi_req->proto_parser_buf);
|
||||
uwsgi_error("read()");
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->proto_parser_pos += len;
|
||||
|
||||
if (wsgi_req->proto_parser_pos >= rs + fr->pad) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("record parsed = type: %d size: %d padding: %d\n", fr->type, rs, fr->pad);
|
||||
#endif
|
||||
|
||||
// params
|
||||
if (fr->type == 4) {
|
||||
for (j = 0; j < rs; j++) {
|
||||
octet = ((uint8_t *) wsgi_req->proto_parser_buf)[8 + j];
|
||||
if (octet > 127) {
|
||||
if (j + 4 >= rs) {
|
||||
free(wsgi_req->proto_parser_buf);
|
||||
return -1;
|
||||
}
|
||||
memcpy(&keylen, wsgi_req->proto_parser_buf + 8 + j, 4);
|
||||
keylen = ntohl(keylen) ^ 0x80000000;
|
||||
j += 4;
|
||||
}
|
||||
else {
|
||||
if (j + 1 >= rs) {
|
||||
free(wsgi_req->proto_parser_buf);
|
||||
return -1;
|
||||
}
|
||||
keylen = octet;
|
||||
j++;
|
||||
}
|
||||
octet = ((uint8_t *) wsgi_req->proto_parser_buf)[8 + j];
|
||||
if (octet > 127) {
|
||||
if (j + 4 > rs) {
|
||||
free(wsgi_req->proto_parser_buf);
|
||||
return -1;
|
||||
}
|
||||
memcpy(&vallen, wsgi_req->proto_parser_buf + 8 + j, 4);
|
||||
vallen = ntohl(vallen) ^ 0x80000000;
|
||||
j += 4;
|
||||
}
|
||||
else {
|
||||
if (j + 1 > rs) {
|
||||
free(wsgi_req->proto_parser_buf);
|
||||
return -1;
|
||||
}
|
||||
vallen = octet;
|
||||
j++;
|
||||
}
|
||||
|
||||
if (j + (keylen + vallen) > rs) {
|
||||
free(wsgi_req->proto_parser_buf);
|
||||
return -1;
|
||||
}
|
||||
if (keylen <= 0xffff && vallen <= 0xffff) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("keylen %d %.*s vallen %d %.*s\n", keylen, keylen, wsgi_req->proto_parser_buf + 8 + j, vallen, vallen, wsgi_req->proto_parser_buf + 8 + j + keylen);
|
||||
#endif
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, wsgi_req->proto_parser_buf + 8 + j, keylen, wsgi_req->proto_parser_buf + 8 + j + keylen, vallen);
|
||||
}
|
||||
j += (keylen + vallen) - 1;
|
||||
}
|
||||
}
|
||||
// stdin
|
||||
else if (fr->type == 5) {
|
||||
if (!wsgi_req->async_post) {
|
||||
wsgi_req->async_post = tmpfile();
|
||||
if (!wsgi_req->async_post) {
|
||||
free(wsgi_req->proto_parser_buf);
|
||||
uwsgi_error("tmpfile()");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (!fwrite(wsgi_req->proto_parser_buf + 8, rs, 1, wsgi_req->async_post)) {
|
||||
free(wsgi_req->proto_parser_buf);
|
||||
uwsgi_error("fwrite()");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
wsgi_req->proto_parser_status = PROTO_STATUS_RECV_HDR;
|
||||
wsgi_req->proto_parser_pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
|
||||
ssize_t uwsgi_proto_fastcgi_writev_header(struct wsgi_request * wsgi_req, struct iovec * iovec, size_t iov_len) {
|
||||
int i;
|
||||
ssize_t len;
|
||||
ssize_t ret = 0;
|
||||
|
||||
for (i = 0; i < (int) iov_len; i++) {
|
||||
len = uwsgi_proto_fastcgi_write(wsgi_req, iovec[i].iov_base, iovec[i].iov_len);
|
||||
if (len <= 0) {
|
||||
return len;
|
||||
}
|
||||
ret += len;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t uwsgi_proto_fastcgi_writev(struct wsgi_request * wsgi_req, struct iovec * iovec, size_t iov_len) {
|
||||
return uwsgi_proto_fastcgi_writev_header(wsgi_req, iovec, iov_len);
|
||||
}
|
||||
|
||||
ssize_t uwsgi_proto_fastcgi_write(struct wsgi_request * wsgi_req, char *buf, size_t len) {
|
||||
struct fcgi_record fr;
|
||||
ssize_t rlen;
|
||||
size_t chunk_len;
|
||||
char *ptr = buf;
|
||||
|
||||
// in fastcgi we need to not send 0 size frames
|
||||
if (!len)
|
||||
return 0;
|
||||
|
||||
fr.version = 1;
|
||||
fr.type = 6;
|
||||
fr.req1 = 0;
|
||||
fr.req0 = 1;
|
||||
fr.pad = 0;
|
||||
fr.reserved = 0;
|
||||
fr.cl = htons(len);
|
||||
|
||||
// split response in 64k chunks...
|
||||
|
||||
if (len <= 65535) {
|
||||
rlen = write(wsgi_req->poll.fd, &fr, 8);
|
||||
if (rlen <= 0) {
|
||||
return rlen;
|
||||
}
|
||||
return write(wsgi_req->poll.fd, buf, len);
|
||||
}
|
||||
else {
|
||||
while(len > 0) {
|
||||
chunk_len = UMIN(65535, len);
|
||||
fr.cl = htons(chunk_len);
|
||||
rlen = write(wsgi_req->poll.fd, &fr, 8);
|
||||
if (rlen <= 0) {
|
||||
return rlen;
|
||||
}
|
||||
rlen = write(wsgi_req->poll.fd, ptr, chunk_len);
|
||||
if (rlen <= 0) {
|
||||
return rlen;
|
||||
}
|
||||
ptr += rlen;
|
||||
len -= rlen;
|
||||
}
|
||||
return ptr-buf;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ssize_t uwsgi_proto_fastcgi_write_header(struct wsgi_request * wsgi_req, char *buf, size_t len) {
|
||||
return uwsgi_proto_fastcgi_write(wsgi_req, buf, len);
|
||||
}
|
||||
|
||||
void uwsgi_proto_fastcgi_close(struct wsgi_request *wsgi_req) {
|
||||
|
||||
if (write(wsgi_req->poll.fd, FCGI_END_REQUEST, 24) <= 0) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
|
||||
uwsgi_proto_base_close(wsgi_req);
|
||||
}
|
||||
|
||||
ssize_t uwsgi_proto_fastcgi_sendfile(struct wsgi_request *wsgi_req) {
|
||||
|
||||
ssize_t len;
|
||||
struct fcgi_record fr;
|
||||
char buf[65536];
|
||||
size_t remains = wsgi_req->sendfile_fd_size - wsgi_req->sendfile_fd_pos;
|
||||
|
||||
wsgi_req->sendfile_fd_chunk = 65536;
|
||||
|
||||
fr.version = 1;
|
||||
fr.type = 6;
|
||||
fr.req1 = 0;
|
||||
fr.req0 = 1;
|
||||
fr.pad = 0;
|
||||
fr.reserved = 0;
|
||||
|
||||
if (uwsgi.async > 1) {
|
||||
fr.cl = htons(UMIN(remains, wsgi_req->sendfile_fd_chunk));
|
||||
len = write(wsgi_req->poll.fd, &fr, 8);
|
||||
if (len != 8) {
|
||||
uwsgi_error("write()");
|
||||
return -1;
|
||||
}
|
||||
len = read(wsgi_req->sendfile_fd, buf, ntohs(fr.cl));
|
||||
if (len != (ssize_t) ntohs(fr.cl)) {
|
||||
uwsgi_error("read()");
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->sendfile_fd_pos += len;
|
||||
return write(wsgi_req->poll.fd, buf, len);
|
||||
}
|
||||
|
||||
while (remains) {
|
||||
fr.cl = htons(UMIN(remains, wsgi_req->sendfile_fd_chunk));
|
||||
len = write(wsgi_req->poll.fd, &fr, 8);
|
||||
if (len != 8) {
|
||||
uwsgi_error("write()");
|
||||
return -1;
|
||||
}
|
||||
len = read(wsgi_req->sendfile_fd, buf, ntohs(fr.cl));
|
||||
if (len != (ssize_t) ntohs(fr.cl)) {
|
||||
uwsgi_error("read()");
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->sendfile_fd_pos += len;
|
||||
if (write(wsgi_req->poll.fd, buf, len) != len) {
|
||||
uwsgi_error("write()");
|
||||
return -1;
|
||||
}
|
||||
remains = wsgi_req->sendfile_fd_size - wsgi_req->sendfile_fd_pos;
|
||||
}
|
||||
|
||||
return wsgi_req->sendfile_fd_pos;
|
||||
|
||||
}
|
||||
+308
@@ -0,0 +1,308 @@
|
||||
/* async http protocol parser */
|
||||
|
||||
#include "../uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
static uint16_t http_add_uwsgi_header(struct wsgi_request *wsgi_req, char *hh, int hhlen) {
|
||||
|
||||
char *buffer = wsgi_req->buffer + wsgi_req->uh.pktsize;
|
||||
char *watermark = wsgi_req->buffer + uwsgi.buffer_size;
|
||||
|
||||
int i;
|
||||
int status = 0;
|
||||
char *val = hh;
|
||||
uint16_t keylen = 0, vallen = 0;
|
||||
int prefix = 0;
|
||||
char *ptr = buffer;
|
||||
|
||||
for (i = 0; i < hhlen; i++) {
|
||||
if (!status) {
|
||||
hh[i] = toupper((int) hh[i]);
|
||||
if (hh[i] == '-')
|
||||
hh[i] = '_';
|
||||
if (hh[i] == ':') {
|
||||
status = 1;
|
||||
keylen = i;
|
||||
}
|
||||
}
|
||||
else if (status == 1 && hh[i] != ' ') {
|
||||
status = 2;
|
||||
val += i;
|
||||
vallen++;
|
||||
}
|
||||
else if (status == 2) {
|
||||
vallen++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!keylen)
|
||||
return 0;
|
||||
|
||||
if (uwsgi_strncmp("CONTENT_TYPE", 12, hh, keylen) && uwsgi_strncmp("CONTENT_LENGTH", 14, hh, keylen)) {
|
||||
keylen += 5;
|
||||
prefix = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp("CONTENT_LENGTH", 14, hh, keylen)) {
|
||||
wsgi_req->post_cl = uwsgi_str_num(val, vallen);
|
||||
}
|
||||
|
||||
if (buffer + keylen + vallen + 2 + 2 >= watermark) {
|
||||
if (prefix) {
|
||||
uwsgi_log("[WARNING] unable to add HTTP_%.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, hh, vallen, val);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[WARNING] unable to add %.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, hh, vallen, val);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
*ptr++ = (uint8_t) (keylen & 0xff);
|
||||
*ptr++ = (uint8_t) ((keylen >> 8) & 0xff);
|
||||
|
||||
if (prefix) {
|
||||
memcpy(ptr, "HTTP_", 5);
|
||||
ptr += 5;
|
||||
memcpy(ptr, hh, keylen - 5);
|
||||
ptr += (keylen - 5);
|
||||
}
|
||||
else {
|
||||
memcpy(ptr, hh, keylen);
|
||||
ptr += keylen;
|
||||
}
|
||||
|
||||
*ptr++ = (uint8_t) (vallen & 0xff);
|
||||
*ptr++ = (uint8_t) ((vallen >> 8) & 0xff);
|
||||
memcpy(ptr, val, vallen);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("add uwsgi var: %.*s = %.*s\n", keylen - (prefix * 5), hh, vallen, val);
|
||||
#endif
|
||||
|
||||
return 2 + keylen + 2 + vallen;
|
||||
}
|
||||
|
||||
|
||||
static int http_parse(struct wsgi_request *wsgi_req, char *watermark) {
|
||||
|
||||
char *ptr = wsgi_req->proto_parser_buf;
|
||||
char *base = ptr;
|
||||
char *query_string = NULL;
|
||||
char ip[INET_ADDRSTRLEN+1];
|
||||
struct sockaddr_in *http_sin = (struct sockaddr_in *) &wsgi_req->c_addr;
|
||||
|
||||
// REQUEST_METHOD
|
||||
while (ptr < watermark) {
|
||||
if (*ptr == ' ') {
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_METHOD", 14, base, ptr - base);
|
||||
ptr++;
|
||||
break;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
// REQUEST_URI / PATH_INFO / QUERY_STRING
|
||||
base = ptr;
|
||||
while (ptr < watermark) {
|
||||
if (*ptr == '?' && !query_string) {
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "PATH_INFO", 9, base, ptr - base);
|
||||
query_string = ptr + 1;
|
||||
}
|
||||
else if (*ptr == ' ') {
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, base, ptr - base);
|
||||
if (!query_string) {
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "PATH_INFO", 9, base, ptr - base);
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, "", 0);
|
||||
}
|
||||
else {
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, query_string, ptr - query_string);
|
||||
}
|
||||
ptr++;
|
||||
break;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
// SERVER_PROTOCOL
|
||||
base = ptr;
|
||||
while (ptr < watermark) {
|
||||
if (*ptr == '\r') {
|
||||
if (ptr + 1 >= watermark)
|
||||
return 0;
|
||||
if (*(ptr + 1) != '\n')
|
||||
return 0;
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PROTOCOL", 15, base, ptr - base);
|
||||
ptr += 2;
|
||||
break;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
// SCRIPT_NAME
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SCRIPT_NAME", 11, "", 0);
|
||||
|
||||
// SERVER_NAME
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len);
|
||||
|
||||
// SERVER_PORT
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, "3031", 4);
|
||||
|
||||
// REMOTE_ADDR
|
||||
memset(ip, 0, INET_ADDRSTRLEN+1);
|
||||
if (inet_ntop(AF_INET, (void *) &http_sin->sin_addr.s_addr, ip, INET_ADDRSTRLEN)) {
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, ip, strlen(ip));
|
||||
}
|
||||
else {
|
||||
uwsgi_error("inet_ntop()");
|
||||
}
|
||||
|
||||
//HEADERS
|
||||
base = ptr;
|
||||
|
||||
while (ptr < watermark) {
|
||||
if (*ptr == '\r') {
|
||||
if (ptr + 1 >= watermark)
|
||||
return 0;
|
||||
if (*(ptr + 1) != '\n')
|
||||
return 0;
|
||||
// multiline header ?
|
||||
if (ptr + 2 < watermark) {
|
||||
if (*(ptr + 2) == ' ' || *(ptr + 2) == '\t') {
|
||||
ptr += 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
wsgi_req->uh.pktsize += http_add_uwsgi_header(wsgi_req, base, ptr - base);
|
||||
ptr++;
|
||||
base = ptr + 1;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int uwsgi_proto_http_parser(struct wsgi_request *wsgi_req) {
|
||||
|
||||
ssize_t len;
|
||||
int j;
|
||||
char *ptr;
|
||||
ssize_t remains;
|
||||
// make this buffer configurable
|
||||
char post_buf[8192];
|
||||
|
||||
// first round ? this memory area will be freed by async_loop
|
||||
if (!wsgi_req->proto_parser_buf) {
|
||||
wsgi_req->proto_parser_buf = uwsgi_malloc(uwsgi.buffer_size);
|
||||
}
|
||||
|
||||
if (wsgi_req->post_cl) {
|
||||
remains = wsgi_req->post_cl - wsgi_req->proto_parser_pos;
|
||||
if (remains > 0) {
|
||||
remains = UMIN(remains, 8192);
|
||||
len = read(wsgi_req->poll.fd, post_buf, remains);
|
||||
if (len <= 0) {
|
||||
uwsgi_error("read()");
|
||||
fclose(wsgi_req->async_post);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!fwrite(post_buf, len, 1, wsgi_req->async_post)) {
|
||||
uwsgi_error("fwrite()");
|
||||
fclose(wsgi_req->async_post);
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->proto_parser_pos += len;
|
||||
|
||||
if (wsgi_req->proto_parser_pos < wsgi_req->post_cl)
|
||||
return UWSGI_AGAIN;
|
||||
|
||||
}
|
||||
rewind(wsgi_req->async_post);
|
||||
wsgi_req->body_as_file = 1;
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
len = read(wsgi_req->poll.fd, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos, uwsgi.buffer_size - wsgi_req->proto_parser_pos);
|
||||
if (len <= 0) {
|
||||
free(wsgi_req->proto_parser_buf);
|
||||
uwsgi_error("recv()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptr = wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos;
|
||||
|
||||
wsgi_req->proto_parser_pos += len;
|
||||
|
||||
for (j = 0; j < len; j++) {
|
||||
if (*ptr == '\r' && (wsgi_req->proto_parser_status == 0 || wsgi_req->proto_parser_status == 2)) {
|
||||
wsgi_req->proto_parser_status++;
|
||||
}
|
||||
else if (*ptr == '\r') {
|
||||
wsgi_req->proto_parser_status = 1;
|
||||
}
|
||||
else if (*ptr == '\n' && wsgi_req->proto_parser_status == 1) {
|
||||
wsgi_req->proto_parser_status = 2;
|
||||
}
|
||||
else if (*ptr == '\n' && wsgi_req->proto_parser_status == 3) {
|
||||
ptr++;
|
||||
remains = len - (j + 1);
|
||||
http_parse(wsgi_req, ptr);
|
||||
//is there a Content_Length ?
|
||||
if (wsgi_req->post_cl) {
|
||||
wsgi_req->async_post = tmpfile();
|
||||
if (!wsgi_req->async_post) {
|
||||
free(wsgi_req->proto_parser_buf);
|
||||
uwsgi_error("tmpfile()");
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->proto_parser_pos = 0;
|
||||
remains = UMIN((size_t) remains, wsgi_req->post_cl);
|
||||
if (remains) {
|
||||
if (!fwrite(ptr, remains, 1, wsgi_req->async_post)) {
|
||||
free(wsgi_req->proto_parser_buf);
|
||||
uwsgi_error("fwrite()");
|
||||
fclose(wsgi_req->async_post);
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->proto_parser_pos += remains;
|
||||
if (wsgi_req->proto_parser_pos >= wsgi_req->post_cl) {
|
||||
free(wsgi_req->proto_parser_buf);
|
||||
rewind(wsgi_req->async_post);
|
||||
wsgi_req->body_as_file = 1;
|
||||
return UWSGI_OK;
|
||||
}
|
||||
}
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
free(wsgi_req->proto_parser_buf);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
else {
|
||||
wsgi_req->proto_parser_status = 0;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
|
||||
ssize_t uwsgi_proto_http_writev_header(struct wsgi_request * wsgi_req, struct iovec * iovec, size_t iov_len) {
|
||||
return writev(wsgi_req->poll.fd, iovec, iov_len);
|
||||
}
|
||||
|
||||
ssize_t uwsgi_proto_http_writev(struct wsgi_request * wsgi_req, struct iovec * iovec, size_t iov_len) {
|
||||
return writev(wsgi_req->poll.fd, iovec, iov_len);
|
||||
}
|
||||
|
||||
ssize_t uwsgi_proto_http_write(struct wsgi_request * wsgi_req, char *buf, size_t len) {
|
||||
return write(wsgi_req->poll.fd, buf, len);
|
||||
}
|
||||
|
||||
ssize_t uwsgi_proto_http_write_header(struct wsgi_request * wsgi_req, char *buf, size_t len) {
|
||||
return write(wsgi_req->poll.fd, buf, len);
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
/* async uwsgi protocol parser */
|
||||
|
||||
#include "../uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#define PROTO_STATUS_RECV_HDR 0
|
||||
#define PROTO_STATUS_RECV_VARS 1
|
||||
|
||||
int uwsgi_proto_uwsgi_parser(struct wsgi_request *wsgi_req) {
|
||||
|
||||
uint8_t *hdr_buf = (uint8_t *) & wsgi_req->uh;
|
||||
ssize_t len;
|
||||
|
||||
struct iovec iov[1];
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
if (wsgi_req->proto_parser_status == PROTO_STATUS_RECV_HDR) {
|
||||
|
||||
|
||||
if (wsgi_req->proto_parser_pos > 0) {
|
||||
len = read(wsgi_req->poll.fd, hdr_buf + wsgi_req->proto_parser_pos, 4 - wsgi_req->proto_parser_pos);
|
||||
}
|
||||
else {
|
||||
iov[0].iov_base = hdr_buf;
|
||||
iov[0].iov_len = 4;
|
||||
|
||||
wsgi_req->msg.msg_name = NULL;
|
||||
wsgi_req->msg.msg_namelen = 0;
|
||||
wsgi_req->msg.msg_iov = iov;
|
||||
wsgi_req->msg.msg_iovlen = 1;
|
||||
wsgi_req->msg.msg_control = &wsgi_req->msg_control;
|
||||
wsgi_req->msg.msg_controllen = sizeof(wsgi_req->msg_control);
|
||||
wsgi_req->msg.msg_flags = 0;
|
||||
|
||||
len = recvmsg(wsgi_req->poll.fd, &wsgi_req->msg, 0);
|
||||
}
|
||||
|
||||
if (len <= 0) {
|
||||
uwsgi_error("read()");
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->proto_parser_pos += len;
|
||||
// header ready ?
|
||||
if (wsgi_req->proto_parser_pos == 4) {
|
||||
wsgi_req->proto_parser_status = PROTO_STATUS_RECV_VARS;
|
||||
wsgi_req->proto_parser_pos = 0;
|
||||
/* big endian ? */
|
||||
#ifdef __BIG_ENDIAN__
|
||||
wsgi_req->uh.pktsize = uwsgi_swap16(wsgi_req->uh.pktsize);
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_debug("uwsgi payload size: %d (0x%X) modifier1: %d modifier2: %d\n", wsgi_req->uh.pktsize, wsgi_req->uh.pktsize, wsgi_req->uh.modifier1, wsgi_req->uh.modifier2);
|
||||
#endif
|
||||
|
||||
/* check for max buffer size */
|
||||
if (wsgi_req->uh.pktsize > uwsgi.buffer_size) {
|
||||
uwsgi_log("invalid request block size: %d (max %d)...skip\n", wsgi_req->uh.pktsize, uwsgi.buffer_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!wsgi_req->uh.pktsize)
|
||||
return UWSGI_OK;
|
||||
|
||||
}
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
|
||||
else if (wsgi_req->proto_parser_status == PROTO_STATUS_RECV_VARS) {
|
||||
len = read(wsgi_req->poll.fd, wsgi_req->buffer + wsgi_req->proto_parser_pos, wsgi_req->uh.pktsize - wsgi_req->proto_parser_pos);
|
||||
if (len <= 0) {
|
||||
uwsgi_error("read()");
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->proto_parser_pos += len;
|
||||
|
||||
// body ready ?
|
||||
if (wsgi_req->proto_parser_pos >= wsgi_req->uh.pktsize) {
|
||||
|
||||
// older OSX versions make mess with CMSG_FIRSTHDR
|
||||
#ifdef __APPLE__
|
||||
if (!wsgi_req->msg.msg_controllen)
|
||||
return UWSGI_OK;
|
||||
#endif
|
||||
|
||||
if (uwsgi.no_fd_passing)
|
||||
return UWSGI_OK;
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&wsgi_req->msg);
|
||||
while (cmsg != NULL) {
|
||||
if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type && SCM_RIGHTS) {
|
||||
|
||||
// upgrade connection to the new socket
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("upgrading fd %d to ", wsgi_req->poll.fd);
|
||||
#endif
|
||||
close(wsgi_req->poll.fd);
|
||||
memcpy(&wsgi_req->poll.fd, CMSG_DATA(cmsg), sizeof(int));
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%d\n", wsgi_req->poll.fd);
|
||||
#endif
|
||||
}
|
||||
cmsg = CMSG_NXTHDR(&wsgi_req->msg, cmsg);
|
||||
}
|
||||
|
||||
return UWSGI_OK;
|
||||
}
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
|
||||
// never here
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t uwsgi_proto_uwsgi_writev_header(struct wsgi_request * wsgi_req, struct iovec * iovec, size_t iov_len) {
|
||||
return writev(wsgi_req->poll.fd, iovec, iov_len);
|
||||
}
|
||||
|
||||
ssize_t uwsgi_proto_uwsgi_writev(struct wsgi_request * wsgi_req, struct iovec * iovec, size_t iov_len) {
|
||||
return writev(wsgi_req->poll.fd, iovec, iov_len);
|
||||
}
|
||||
|
||||
ssize_t uwsgi_proto_uwsgi_write(struct wsgi_request * wsgi_req, char *buf, size_t len) {
|
||||
return write(wsgi_req->poll.fd, buf, len);
|
||||
}
|
||||
|
||||
ssize_t uwsgi_proto_uwsgi_write_header(struct wsgi_request * wsgi_req, char *buf, size_t len) {
|
||||
return write(wsgi_req->poll.fd, buf, len);
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/* async uwsgi protocol parser */
|
||||
|
||||
#include "../uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#define PROTO_STATUS_RECV_HDR 0
|
||||
#define PROTO_STATUS_RECV_VARS 1
|
||||
|
||||
int uwsgi_proto_uwsgi_parser(struct wsgi_request *wsgi_req) {
|
||||
|
||||
uint8_t *hdr_buf = (uint8_t *) & wsgi_req->uh;
|
||||
ssize_t len;
|
||||
|
||||
struct iovec iov[1];
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
if (wsgi_req->proto_parser_status == PROTO_STATUS_RECV_HDR) {
|
||||
|
||||
|
||||
if (wsgi_req->proto_parser_pos > 0) {
|
||||
len = read(wsgi_req->poll.fd, hdr_buf + wsgi_req->proto_parser_pos, 4 - wsgi_req->proto_parser_pos);
|
||||
}
|
||||
else {
|
||||
iov[0].iov_base = hdr_buf;
|
||||
iov[0].iov_len = 4;
|
||||
|
||||
wsgi_req->msg.msg_name = NULL;
|
||||
wsgi_req->msg.msg_namelen = 0;
|
||||
wsgi_req->msg.msg_iov = iov;
|
||||
wsgi_req->msg.msg_iovlen = 1;
|
||||
wsgi_req->msg.msg_control = &wsgi_req->msg_control;
|
||||
wsgi_req->msg.msg_controllen = sizeof(wsgi_req->msg_control);
|
||||
wsgi_req->msg.msg_flags = 0;
|
||||
|
||||
len = recvmsg(wsgi_req->poll.fd, &wsgi_req->msg, 0);
|
||||
}
|
||||
|
||||
if (len <= 0) {
|
||||
uwsgi_error("read()");
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->proto_parser_pos += len;
|
||||
// header ready ?
|
||||
if (wsgi_req->proto_parser_pos == 4) {
|
||||
wsgi_req->proto_parser_status = PROTO_STATUS_RECV_VARS;
|
||||
wsgi_req->proto_parser_pos = 0;
|
||||
/* big endian ? */
|
||||
#ifdef __BIG_ENDIAN__
|
||||
wsgi_req->uh.pktsize = uwsgi_swap16(wsgi_req->uh.pktsize);
|
||||
#endif
|
||||
|
||||
uwsgi_debug("uwsgi payload size: %d (0x%X) modifier1: %d modifier2: %d\n", wsgi_req->uh.pktsize, wsgi_req->uh.pktsize, wsgi_req->uh.modifier1, wsgi_req->uh.modifier2);
|
||||
|
||||
/* check for max buffer size */
|
||||
if (wsgi_req->uh.pktsize > uwsgi.buffer_size) {
|
||||
uwsgi_log("invalid request block size. requested %d bytes available %d bytes...skip\n", wsgi_req->uh.pktsize, uwsgi.buffer_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!wsgi_req->uh.pktsize)
|
||||
return UWSGI_OK;
|
||||
|
||||
}
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
|
||||
else if (wsgi_req->proto_parser_status == PROTO_STATUS_RECV_VARS) {
|
||||
len = read(wsgi_req->poll.fd, wsgi_req->buffer + wsgi_req->proto_parser_pos, wsgi_req->uh.pktsize - wsgi_req->proto_parser_pos);
|
||||
if (len <= 0) {
|
||||
uwsgi_error("read()");
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->proto_parser_pos += len;
|
||||
|
||||
// body ready ?
|
||||
if (wsgi_req->proto_parser_pos >= wsgi_req->uh.pktsize) {
|
||||
|
||||
// older OSX versions make mess with CMSG_FIRSTHDR
|
||||
#ifdef __APPLE__
|
||||
if (!wsgi_req->msg.msg_controllen)
|
||||
return UWSGI_OK;
|
||||
#endif
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&wsgi_req->msg);
|
||||
while (cmsg != NULL) {
|
||||
if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type && SCM_RIGHTS) {
|
||||
|
||||
// upgrade connection to the new socket
|
||||
uwsgi_log("upgrading fd %d to ", wsgi_req->poll.fd);
|
||||
|
||||
close(wsgi_req->poll.fd);
|
||||
memcpy(&wsgi_req->poll.fd, CMSG_DATA(cmsg), sizeof(int));
|
||||
|
||||
uwsgi_log("%d\n", wsgi_req->poll.fd);
|
||||
}
|
||||
cmsg = CMSG_NXTHDR(&wsgi_req->msg, cmsg);
|
||||
}
|
||||
|
||||
return UWSGI_OK;
|
||||
}
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
|
||||
// never here
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t uwsgi_proto_uwsgi_writev_header(struct wsgi_request * wsgi_req, struct iovec * iovec, size_t iov_len) {
|
||||
return writev(wsgi_req->poll.fd, iovec, iov_len);
|
||||
}
|
||||
|
||||
ssize_t uwsgi_proto_uwsgi_writev(struct wsgi_request * wsgi_req, struct iovec * iovec, size_t iov_len) {
|
||||
return writev(wsgi_req->poll.fd, iovec, iov_len);
|
||||
}
|
||||
|
||||
ssize_t uwsgi_proto_uwsgi_write(struct wsgi_request * wsgi_req, char *buf, size_t len) {
|
||||
return write(wsgi_req->poll.fd, buf, len);
|
||||
}
|
||||
|
||||
ssize_t uwsgi_proto_uwsgi_write_header(struct wsgi_request * wsgi_req, char *buf, size_t len) {
|
||||
return write(wsgi_req->poll.fd, buf, len);
|
||||
}
|
||||
+481
@@ -0,0 +1,481 @@
|
||||
#include "../uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#ifdef UWSGI_JSON
|
||||
#include <jansson.h>
|
||||
|
||||
static char *uwsgi_mongrel2_json_get_string(json_t * node, const char *json_key) {
|
||||
|
||||
json_t *json_value = json_object_get(node, json_key);
|
||||
if (json_is_string(json_value)) {
|
||||
return (char *) json_string_value(json_value);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint16_t uwsgi_mongrel2_json_add(struct wsgi_request *wsgi_req, json_t * node, const char *json_key, char *key, uint16_t keylen, char **extra, size_t * extra_len) {
|
||||
|
||||
char *json_val;
|
||||
json_t *json_value = json_object_get(node, json_key);
|
||||
if (json_is_string(json_value)) {
|
||||
json_val = (char *) json_string_value(json_value);
|
||||
// invalid value ?
|
||||
if (strlen(json_val) > 0xffff)
|
||||
return 0;
|
||||
if (extra) {
|
||||
*extra = json_val;
|
||||
*extra_len = strlen(json_val);
|
||||
}
|
||||
return proto_base_add_uwsgi_var(wsgi_req, key, keylen, json_val, strlen(json_val));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int uwsgi_mongrel2_json_parse(json_t * root, struct wsgi_request *wsgi_req) {
|
||||
|
||||
char *json_val;
|
||||
char *query_string = NULL;
|
||||
size_t query_string_len = 0;
|
||||
size_t script_name_len = 0;
|
||||
void *json_iter;
|
||||
char *json_key;
|
||||
json_t *json_value;
|
||||
|
||||
if ((json_val = uwsgi_mongrel2_json_get_string(root, "METHOD"))) {
|
||||
if (!strcmp(json_val, "JSON")) {
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_METHOD", 14, json_val, strlen(json_val));
|
||||
}
|
||||
|
||||
if ((json_val = uwsgi_mongrel2_json_get_string(root, "x-mongrel2-upload-done"))) {
|
||||
wsgi_req->async_post = fopen(json_val, "r");
|
||||
if (!wsgi_req->async_post) {
|
||||
uwsgi_error_open(json_val);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (uwsgi_mongrel2_json_get_string(root, "x-mongrel2-upload-start")) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
wsgi_req->uh.pktsize += uwsgi_mongrel2_json_add(wsgi_req, root, "VERSION", "SERVER_PROTOCOL", 15, NULL, NULL);
|
||||
wsgi_req->uh.pktsize += uwsgi_mongrel2_json_add(wsgi_req, root, "QUERY", "QUERY_STRING", 12, &query_string, &query_string_len);
|
||||
|
||||
if ((json_val = uwsgi_mongrel2_json_get_string(root, "PATTERN"))) {
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SCRIPT_NAME", 11, json_val, strlen(json_val) - 1);
|
||||
script_name_len = strlen(json_val) - 1;
|
||||
}
|
||||
|
||||
if ((json_val = uwsgi_mongrel2_json_get_string(root, "PATH"))) {
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "PATH_INFO", 9, json_val + script_name_len, strlen(json_val + script_name_len));
|
||||
if (query_string_len) {
|
||||
char *request_uri = uwsgi_concat3n(json_val, strlen(json_val), "?", 1, query_string, query_string_len);
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, request_uri, strlen(json_val) + 1 + query_string_len);
|
||||
free(request_uri);
|
||||
}
|
||||
else {
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, json_val, strlen(json_val));
|
||||
}
|
||||
}
|
||||
|
||||
if ((json_val = uwsgi_mongrel2_json_get_string(root, "host"))) {
|
||||
char *colon = strchr(json_val, ':');
|
||||
if (colon) {
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, colon + 1, strlen(colon + 1));
|
||||
}
|
||||
else {
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, "80", 2);
|
||||
}
|
||||
}
|
||||
|
||||
if ((json_val = uwsgi_mongrel2_json_get_string(root, "content-length"))) {
|
||||
wsgi_req->post_cl = atoi(json_val);
|
||||
}
|
||||
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len);
|
||||
|
||||
json_iter = json_object_iter(root);
|
||||
|
||||
while (json_iter) {
|
||||
json_key = (char *) json_object_iter_key(json_iter);
|
||||
// is it a header ?
|
||||
if (json_key[0] >= 97) {
|
||||
json_value = json_object_iter_value(json_iter);
|
||||
if (json_is_string(json_value)) {
|
||||
json_val = (char *) json_string_value(json_value);
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_header(wsgi_req, json_key, strlen(json_key), json_val, strlen(json_val));
|
||||
}
|
||||
}
|
||||
json_iter = json_object_iter_next(root, json_iter);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// dumb/fake tnetstring implementation...all is a string
|
||||
static int uwsgi_mongrel2_tnetstring_parse(struct wsgi_request *wsgi_req, char *buf, int len) {
|
||||
|
||||
char *ptr = buf;
|
||||
char *watermark = buf + len;
|
||||
char *key = NULL;
|
||||
size_t keylen = 0;
|
||||
char *val = NULL;
|
||||
size_t vallen = 0;
|
||||
uint16_t script_name_len = 0;
|
||||
char *query_string = NULL;
|
||||
uint16_t query_string_len = 0;
|
||||
int async_upload = 0;
|
||||
|
||||
while (ptr < watermark) {
|
||||
|
||||
ptr = uwsgi_netstring(ptr, len - (ptr - buf), &key, &keylen);
|
||||
if (ptr == NULL)
|
||||
break;
|
||||
// empty keys are not allowed
|
||||
if (keylen == 0)
|
||||
break;
|
||||
|
||||
if (ptr >= watermark)
|
||||
break;
|
||||
|
||||
ptr = uwsgi_netstring(ptr, len - (ptr - buf), &val, &vallen);
|
||||
if (ptr == NULL)
|
||||
break;
|
||||
|
||||
if (key[0] < 97) {
|
||||
if (!uwsgi_strncmp("METHOD", 6, key, keylen)) {
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_METHOD", 14, val, vallen);
|
||||
}
|
||||
else if (!uwsgi_strncmp("VERSION", 7, key, keylen)) {
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PROTOCOL", 15, val, vallen);
|
||||
}
|
||||
else if (!uwsgi_strncmp("QUERY", 5, key, keylen)) {
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, val, vallen);
|
||||
query_string = val;
|
||||
query_string_len = vallen;
|
||||
}
|
||||
else if (!uwsgi_strncmp("PATTERN", 7, key, keylen)) {
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SCRIPT_NAME", 11, val, vallen - 1);
|
||||
script_name_len = vallen - 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp("PATH", 4, key, keylen)) {
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "PATH_INFO", 9, val + script_name_len, vallen - script_name_len);
|
||||
if (query_string_len) {
|
||||
char *request_uri = uwsgi_concat3n(val, vallen, "?", 1, query_string, query_string_len);
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, request_uri, vallen + 1 + query_string_len);
|
||||
free(request_uri);
|
||||
}
|
||||
else {
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, val, vallen);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// add header
|
||||
if (!uwsgi_strncmp("host", 4, key, keylen)) {
|
||||
char *colon = strchr(val, ':');
|
||||
if (colon) {
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, colon + 1, (colon + 1) - val);
|
||||
}
|
||||
else {
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, "80", 2);
|
||||
}
|
||||
}
|
||||
else if (!uwsgi_strncmp("content-length", 14, key, keylen)) {
|
||||
wsgi_req->post_cl = uwsgi_str_num(val, vallen);
|
||||
}
|
||||
else if (!uwsgi_strncmp("x-mongrel2-upload-done", 22, key, keylen)) {
|
||||
char *post_filename = uwsgi_concat2n(val, vallen, "", 0);
|
||||
wsgi_req->async_post = fopen(post_filename, "r");
|
||||
if (!wsgi_req->async_post) {
|
||||
uwsgi_error_open(post_filename);
|
||||
free(post_filename);
|
||||
wsgi_req->do_not_log = 1;
|
||||
}
|
||||
async_upload += 2;
|
||||
free(post_filename);
|
||||
}
|
||||
else if (!uwsgi_strncmp("x-mongrel2-upload-start", 23, key, keylen)) {
|
||||
async_upload += 1;
|
||||
}
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_header(wsgi_req, key, keylen, val, vallen);
|
||||
}
|
||||
}
|
||||
|
||||
wsgi_req->uh.pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len);
|
||||
|
||||
// reject uncomplete upload
|
||||
if (async_upload == 1) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_proto_zeromq_parser(struct wsgi_request *wsgi_req) {
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
int uwsgi_proto_zeromq_accept(struct wsgi_request *wsgi_req, int fd) {
|
||||
|
||||
zmq_msg_t message;
|
||||
char *req_uuid = NULL;
|
||||
size_t req_uuid_len = 0;
|
||||
char *req_id = NULL;
|
||||
size_t req_id_len = 0;
|
||||
char *req_path = NULL;
|
||||
size_t req_path_len = 0;
|
||||
#ifdef UWSGI_JSON
|
||||
json_t *root;
|
||||
json_error_t error;
|
||||
#endif
|
||||
char *mongrel2_req = NULL;
|
||||
size_t mongrel2_req_size = 0;
|
||||
int resp_id_len;
|
||||
uint32_t events = 0;
|
||||
char *message_ptr;
|
||||
size_t message_size = 0;
|
||||
char *post_data;
|
||||
|
||||
|
||||
#ifdef ZMQ_EVENTS
|
||||
size_t events_len = sizeof(uint32_t);
|
||||
if (uwsgi.edge_triggered == 0) {
|
||||
if (zmq_getsockopt(pthread_getspecific(uwsgi.zmq_pull), ZMQ_EVENTS, &events, &events_len) < 0) {
|
||||
uwsgi_error("zmq_getsockopt()");
|
||||
uwsgi.edge_triggered = 0;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (events & ZMQ_POLLIN || uwsgi.edge_triggered) {
|
||||
wsgi_req->do_not_add_to_async_queue = 1;
|
||||
wsgi_req->proto_parser_status = 0;
|
||||
zmq_msg_init(&message);
|
||||
if (zmq_recv(pthread_getspecific(uwsgi.zmq_pull), &message, uwsgi.zeromq_recv_flag) < 0) {
|
||||
if (errno == EAGAIN) {
|
||||
uwsgi.edge_triggered = 0;
|
||||
}
|
||||
else {
|
||||
uwsgi_error("zmq_recv()");
|
||||
}
|
||||
zmq_msg_close(&message);
|
||||
return -1;
|
||||
}
|
||||
uwsgi.edge_triggered = 1;
|
||||
message_size = zmq_msg_size(&message);
|
||||
//uwsgi_log("%.*s\n", (int) wsgi_req->proto_parser_pos, zmq_msg_data(&message));
|
||||
if (message_size > 0xffff) {
|
||||
uwsgi_log("too much big message %d\n", message_size);
|
||||
zmq_msg_close(&message);
|
||||
wsgi_req->do_not_log = 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
message_ptr = zmq_msg_data(&message);
|
||||
|
||||
// warning mongrel2_req_size will contains a bad value, but this is not a problem...
|
||||
post_data = uwsgi_split4(message_ptr, message_size, ' ', &req_uuid, &req_uuid_len, &req_id, &req_id_len, &req_path, &req_path_len, &mongrel2_req, &mongrel2_req_size);
|
||||
if (post_data == NULL) {
|
||||
uwsgi_log("cannot parse message (split4 phase)\n");
|
||||
zmq_msg_close(&message);
|
||||
wsgi_req->do_not_log = 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// fix post_data, mongrel2_req and mongrel2_req_size
|
||||
post_data = uwsgi_netstring(mongrel2_req, message_size - (mongrel2_req - message_ptr), &mongrel2_req, &mongrel2_req_size);
|
||||
if (post_data == NULL) {
|
||||
uwsgi_log("cannot parse message (body netstring phase)\n");
|
||||
zmq_msg_close(&message);
|
||||
wsgi_req->do_not_log = 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ok ready to parse tnetstring/json data and build uwsgi request
|
||||
if (mongrel2_req[mongrel2_req_size] == '}') {
|
||||
if (uwsgi_mongrel2_tnetstring_parse(wsgi_req, mongrel2_req, mongrel2_req_size)) {
|
||||
zmq_msg_close(&message);
|
||||
wsgi_req->do_not_log = 1;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef UWSGI_JSON
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("JSON %d: %.*s\n", mongrel2_req_size, mongrel2_req_size, mongrel2_req);
|
||||
#endif
|
||||
// add a zero to the end of buf
|
||||
mongrel2_req[mongrel2_req_size] = 0;
|
||||
root = json_loads(mongrel2_req, 0, &error);
|
||||
if (!root) {
|
||||
uwsgi_log("error parsing JSON data: line %d %s\n", error.line, error.text);
|
||||
zmq_msg_close(&message);
|
||||
wsgi_req->do_not_log = 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (uwsgi_mongrel2_json_parse(root, wsgi_req)) {
|
||||
json_decref(root);
|
||||
zmq_msg_close(&message);
|
||||
wsgi_req->do_not_log = 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
json_decref(root);
|
||||
#else
|
||||
uwsgi_log("JSON support not enabled. skip request\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
// pre-build the mongrel2 response_header
|
||||
wsgi_req->proto_parser_buf = uwsgi_malloc(req_uuid_len + 1 + 11 + 1 + req_id_len + 1 + 1);
|
||||
memcpy(wsgi_req->proto_parser_buf, req_uuid, req_uuid_len);
|
||||
((char *) wsgi_req->proto_parser_buf)[req_uuid_len] = ' ';
|
||||
resp_id_len = uwsgi_num2str2(req_id_len, wsgi_req->proto_parser_buf + req_uuid_len + 1);
|
||||
((char *) wsgi_req->proto_parser_buf)[req_uuid_len + 1 + resp_id_len] = ':';
|
||||
|
||||
memcpy((char *) wsgi_req->proto_parser_buf + req_uuid_len + 1 + resp_id_len + 1, req_id, req_id_len);
|
||||
|
||||
memcpy((char *) wsgi_req->proto_parser_buf + req_uuid_len + 1 + resp_id_len + 1 + req_id_len, ", ", 2);
|
||||
wsgi_req->proto_parser_pos = (uint64_t) req_uuid_len + 1 + resp_id_len + 1 + req_id_len + 1 + 1;
|
||||
|
||||
// handle post data
|
||||
if (wsgi_req->post_cl > 0 && !wsgi_req->async_post) {
|
||||
if (uwsgi_netstring(post_data, message_size - (post_data - message_ptr), &message_ptr, &wsgi_req->post_cl)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("post_size: %d\n", wsgi_req->post_cl);
|
||||
#endif
|
||||
wsgi_req->async_post = tmpfile();
|
||||
fwrite(message_ptr, wsgi_req->post_cl, 1, wsgi_req->async_post);
|
||||
rewind(wsgi_req->async_post);
|
||||
wsgi_req->body_as_file = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
zmq_msg_close(&message);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void uwsgi_proto_zeromq_free(void *data, void *hint) {
|
||||
free(data);
|
||||
}
|
||||
|
||||
void uwsgi_proto_zeromq_close(struct wsgi_request *wsgi_req) {
|
||||
zmq_msg_t reply;
|
||||
|
||||
// check for already freed wsgi_req->proto_parser_buf/wsgi_req->proto_parser_pos
|
||||
if (!wsgi_req->proto_parser_pos)
|
||||
return;
|
||||
|
||||
zmq_msg_init_data(&reply, wsgi_req->proto_parser_buf, wsgi_req->proto_parser_pos, uwsgi_proto_zeromq_free, NULL);
|
||||
if (uwsgi.threads > 1) pthread_mutex_lock(&uwsgi.zmq_lock);
|
||||
if (zmq_send(uwsgi.zmq_pub, &reply, 0)) {
|
||||
uwsgi_error("zmq_send()");
|
||||
}
|
||||
if (uwsgi.threads > 1) pthread_mutex_unlock(&uwsgi.zmq_lock);
|
||||
zmq_msg_close(&reply);
|
||||
|
||||
if (wsgi_req->async_post && wsgi_req->body_as_file) {
|
||||
fclose(wsgi_req->async_post);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
ssize_t uwsgi_proto_zeromq_writev_header(struct wsgi_request *wsgi_req, struct iovec *iovec, size_t iov_len) {
|
||||
int i;
|
||||
ssize_t len;
|
||||
ssize_t ret = 0;
|
||||
|
||||
for (i = 0; i < (int) iov_len; i++) {
|
||||
len = uwsgi_proto_zeromq_write(wsgi_req, iovec[i].iov_base, iovec[i].iov_len);
|
||||
if (len <= 0) {
|
||||
return len;
|
||||
}
|
||||
ret += len;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t uwsgi_proto_zeromq_writev(struct wsgi_request * wsgi_req, struct iovec * iovec, size_t iov_len) {
|
||||
return uwsgi_proto_zeromq_writev_header(wsgi_req, iovec, iov_len);
|
||||
}
|
||||
|
||||
ssize_t uwsgi_proto_zeromq_write(struct wsgi_request * wsgi_req, char *buf, size_t len) {
|
||||
zmq_msg_t reply;
|
||||
char *zmq_body;
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
zmq_body = uwsgi_concat2n(wsgi_req->proto_parser_buf, (int) wsgi_req->proto_parser_pos, buf, (int) len);
|
||||
|
||||
//uwsgi_log("|%.*s|\n", (int)wsgi_req->proto_parser_pos+len, zmq_body);
|
||||
|
||||
zmq_msg_init_data(&reply, zmq_body, wsgi_req->proto_parser_pos + len, uwsgi_proto_zeromq_free, NULL);
|
||||
if (uwsgi.threads > 1) pthread_mutex_lock(&uwsgi.zmq_lock);
|
||||
if (zmq_send(uwsgi.zmq_pub, &reply, 0)) {
|
||||
uwsgi_error("zmq_send()");
|
||||
if (uwsgi.threads > 1) pthread_mutex_unlock(&uwsgi.zmq_lock);
|
||||
zmq_msg_close(&reply);
|
||||
return -1;
|
||||
}
|
||||
if (uwsgi.threads > 1) pthread_mutex_unlock(&uwsgi.zmq_lock);
|
||||
zmq_msg_close(&reply);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
ssize_t uwsgi_proto_zeromq_write_header(struct wsgi_request * wsgi_req, char *buf, size_t len) {
|
||||
return uwsgi_proto_zeromq_write(wsgi_req, buf, len);
|
||||
}
|
||||
|
||||
ssize_t uwsgi_proto_zeromq_sendfile(struct wsgi_request * wsgi_req) {
|
||||
|
||||
ssize_t len;
|
||||
char buf[65536];
|
||||
size_t remains = wsgi_req->sendfile_fd_size - wsgi_req->sendfile_fd_pos;
|
||||
|
||||
wsgi_req->sendfile_fd_chunk = 65536;
|
||||
|
||||
|
||||
if (uwsgi.async > 1) {
|
||||
len = read(wsgi_req->sendfile_fd, buf, UMIN(remains, wsgi_req->sendfile_fd_chunk));
|
||||
if (len != (int) UMIN(remains, wsgi_req->sendfile_fd_chunk)) {
|
||||
uwsgi_error("read()");
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->sendfile_fd_pos += len;
|
||||
return uwsgi_proto_zeromq_write(wsgi_req, buf, len);
|
||||
}
|
||||
|
||||
while (remains) {
|
||||
len = read(wsgi_req->sendfile_fd, buf, UMIN(remains, wsgi_req->sendfile_fd_chunk));
|
||||
if (len != (int) UMIN(remains, wsgi_req->sendfile_fd_chunk)) {
|
||||
uwsgi_error("read()");
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->sendfile_fd_pos += len;
|
||||
len = uwsgi_proto_zeromq_write(wsgi_req, buf, len);
|
||||
remains = wsgi_req->sendfile_fd_size - wsgi_req->sendfile_fd_pos;
|
||||
}
|
||||
|
||||
return wsgi_req->sendfile_fd_pos;
|
||||
|
||||
}
|
||||
+339
-151
@@ -16,6 +16,112 @@ static size_t get_content_length(char *buf, uint16_t size) {
|
||||
return val;
|
||||
}
|
||||
|
||||
void 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);
|
||||
snprintf(dst, 49, "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n\r\n",
|
||||
week[hdtm->tm_wday], hdtm->tm_mday,
|
||||
months[hdtm->tm_mon], hdtm->tm_year+1900,
|
||||
hdtm->tm_hour, hdtm->tm_min, hdtm->tm_sec);
|
||||
}
|
||||
|
||||
// only RFC 1123 is supported
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
#ifdef UWSGI_UDP
|
||||
ssize_t send_udp_message(uint8_t modifier1, char *host, char *message, uint16_t message_size) {
|
||||
|
||||
@@ -67,6 +173,8 @@ ssize_t send_udp_message(uint8_t modifier1, char *host, char *message, uint16_t
|
||||
}
|
||||
close(fd);
|
||||
|
||||
udp_port[0] = ':';
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
@@ -233,135 +341,35 @@ ssize_t uwsgi_send_message(int fd, uint8_t modifier1, uint8_t modifier2, char *m
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_parse_response(struct pollfd *upoll, int timeout, struct uwsgi_header *uh, char *buffer) {
|
||||
int rlen, i;
|
||||
struct msghdr msg;
|
||||
struct iovec iov [1];
|
||||
struct cmsghdr *cmsg;
|
||||
union {
|
||||
struct cmsghdr cmsg;
|
||||
char control [CMSG_SPACE (sizeof (int))];
|
||||
} msg_control;
|
||||
int uwsgi_parse_packet(struct wsgi_request *wsgi_req, int timeout) {
|
||||
int rlen;
|
||||
int status = UWSGI_AGAIN;
|
||||
|
||||
if (!timeout)
|
||||
timeout = 1;
|
||||
/* first 4 byte header */
|
||||
rlen = poll(upoll, 1, timeout * 1000);
|
||||
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("poll()");
|
||||
exit(1);
|
||||
}
|
||||
else if (rlen == 0) {
|
||||
uwsgi_log( "timeout. skip request\n");
|
||||
close(upoll->fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
iov [0].iov_base = uh;
|
||||
iov [0].iov_len = 4;
|
||||
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = &msg_control;
|
||||
msg.msg_controllen = sizeof (msg_control);
|
||||
msg.msg_flags = 0;
|
||||
|
||||
//rlen = read(upoll->fd, uh, 4);
|
||||
rlen = recvmsg(upoll->fd, &msg, 0);
|
||||
if (rlen > 0 && rlen < 4) {
|
||||
i = rlen;
|
||||
while (i < 4) {
|
||||
rlen = poll(upoll, 1, timeout * 1000);
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("poll()");
|
||||
exit(1);
|
||||
}
|
||||
else if (rlen == 0) {
|
||||
uwsgi_log( "timeout waiting for header. skip request.\n");
|
||||
close(upoll->fd);
|
||||
break;
|
||||
}
|
||||
rlen = read(upoll->fd, (char *) (uh) + i, 4 - i);
|
||||
if (rlen <= 0) {
|
||||
uwsgi_log( "broken header. skip request.\n");
|
||||
close(upoll->fd);
|
||||
break;
|
||||
}
|
||||
i += rlen;
|
||||
}
|
||||
if (i < 4) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (rlen <= 0) {
|
||||
uwsgi_log( "invalid request header size: %d...skip\n", rlen);
|
||||
close(upoll->fd);
|
||||
return 0;
|
||||
}
|
||||
/* big endian ? */
|
||||
#ifdef __BIG_ENDIAN__
|
||||
uh->pktsize = uwsgi_swap16(uh->pktsize);
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_debug("uwsgi payload size: %d (0x%X) modifier1: %d modifier2: %d\n", uh->pktsize, uh->pktsize, uh->modifier1, uh->modifier2);
|
||||
#endif
|
||||
|
||||
/* check for max buffer size */
|
||||
if (uh->pktsize > uwsgi.buffer_size) {
|
||||
uwsgi_log( "invalid request block size: %d...skip\n", uh->pktsize);
|
||||
close(upoll->fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//uwsgi_log("ready for reading %d bytes\n", wsgi_req.size);
|
||||
|
||||
i = 0;
|
||||
while (i < uh->pktsize) {
|
||||
rlen = poll(upoll, 1, timeout * 1000);
|
||||
while(status == UWSGI_AGAIN) {
|
||||
rlen = poll(&wsgi_req->poll, 1, timeout * 1000);
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("poll()");
|
||||
exit(1);
|
||||
}
|
||||
else if (rlen == 0) {
|
||||
uwsgi_log( "timeout. skip request. (expecting %d bytes, got %d)\n", uh->pktsize, i);
|
||||
close(upoll->fd);
|
||||
break;
|
||||
uwsgi_log( "timeout waiting for header. skip request.\n");
|
||||
//close(upoll->fd);
|
||||
return 0;
|
||||
}
|
||||
rlen = read(upoll->fd, buffer + i, uh->pktsize - i);
|
||||
if (rlen <= 0) {
|
||||
uwsgi_log( "broken vars. skip request.\n");
|
||||
close(upoll->fd);
|
||||
break;
|
||||
if (wsgi_req->socket) {
|
||||
status = wsgi_req->socket->proto(wsgi_req);
|
||||
}
|
||||
else {
|
||||
status = uwsgi_proto_uwsgi_parser(wsgi_req);
|
||||
}
|
||||
if (status < 0) {
|
||||
uwsgi_log("error parsing request\n");
|
||||
//close(upoll->fd);
|
||||
return 0;
|
||||
}
|
||||
i += rlen;
|
||||
}
|
||||
|
||||
|
||||
if (i < uh->pktsize) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
cmsg = CMSG_FIRSTHDR (&msg);
|
||||
while(cmsg != NULL) {
|
||||
if (cmsg->cmsg_len != CMSG_LEN (sizeof (int)) ||
|
||||
cmsg->cmsg_level != SOL_SOCKET ||
|
||||
cmsg->cmsg_type != SCM_RIGHTS) continue;
|
||||
|
||||
// upgrade connection to the new socket
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("upgrading fd %d to ", upoll->fd);
|
||||
#endif
|
||||
close(upoll->fd);
|
||||
memcpy(&upoll->fd, CMSG_DATA(cmsg), sizeof(int));
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%d\n", upoll->fd);
|
||||
#endif
|
||||
cmsg = CMSG_NXTHDR (&msg, cmsg);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -392,6 +400,7 @@ int uwsgi_parse_array(char *buffer, uint16_t size, char **argv, uint8_t *argc) {
|
||||
if (ptrbuf + strsize <= bufferend) {
|
||||
// item
|
||||
argv[*argc] = uwsgi_cheap_string(ptrbuf, strsize);
|
||||
uwsgi_log("arg %s\n", argv[*argc]);
|
||||
ptrbuf += strsize;
|
||||
*argc = *argc + 1;
|
||||
}
|
||||
@@ -516,6 +525,18 @@ int uwsgi_parse_vars(struct wsgi_request *wsgi_req) {
|
||||
wsgi_req->chdir = ptrbuf;
|
||||
wsgi_req->chdir_len = strsize;
|
||||
}
|
||||
else if (!uwsgi_strncmp("UWSGI_FILE", 10, wsgi_req->hvec[wsgi_req->var_cnt].iov_base, wsgi_req->hvec[wsgi_req->var_cnt].iov_len)) {
|
||||
wsgi_req->file = ptrbuf;
|
||||
wsgi_req->file_len = strsize;
|
||||
}
|
||||
else if (!uwsgi_strncmp("UWSGI_TOUCH_RELOAD", 18, wsgi_req->hvec[wsgi_req->var_cnt].iov_base, wsgi_req->hvec[wsgi_req->var_cnt].iov_len)) {
|
||||
wsgi_req->touch_reload = ptrbuf;
|
||||
wsgi_req->touch_reload_len = strsize;
|
||||
}
|
||||
else if (uwsgi.cache_max_items > 0 && !uwsgi_strncmp("UWSGI_CACHE_GET", 15, wsgi_req->hvec[wsgi_req->var_cnt].iov_base, wsgi_req->hvec[wsgi_req->var_cnt].iov_len)) {
|
||||
wsgi_req->cache_get = ptrbuf;
|
||||
wsgi_req->cache_get_len = strsize;
|
||||
}
|
||||
else if (!uwsgi_strncmp("UWSGI_SETENV", 12, wsgi_req->hvec[wsgi_req->var_cnt].iov_base, wsgi_req->hvec[wsgi_req->var_cnt].iov_len)) {
|
||||
char *env_value = memchr(ptrbuf, '=', strsize);
|
||||
if (env_value) {
|
||||
@@ -545,8 +566,19 @@ int uwsgi_parse_vars(struct wsgi_request *wsgi_req) {
|
||||
wsgi_req->https = ptrbuf;
|
||||
wsgi_req->https_len = strsize;
|
||||
}
|
||||
else if (!uwsgi_strncmp("HTTP_IF_MODIFIED_SINCE", 22, wsgi_req->hvec[wsgi_req->var_cnt].iov_base, wsgi_req->hvec[wsgi_req->var_cnt].iov_len)) {
|
||||
wsgi_req->if_modified_since = ptrbuf;
|
||||
wsgi_req->if_modified_since_len = strsize;
|
||||
}
|
||||
else if (!uwsgi_strncmp("CONTENT_LENGTH", 14, wsgi_req->hvec[wsgi_req->var_cnt].iov_base, wsgi_req->hvec[wsgi_req->var_cnt].iov_len)) {
|
||||
wsgi_req->post_cl = get_content_length(ptrbuf, strsize);
|
||||
if (uwsgi.limit_post) {
|
||||
if (wsgi_req->post_cl > uwsgi.limit_post) {
|
||||
uwsgi_log("Invalid (too big) CONTENT_LENGTH. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (wsgi_req->var_cnt < uwsgi.vec_size - (4 + 1)) {
|
||||
@@ -570,19 +602,63 @@ int uwsgi_parse_vars(struct wsgi_request *wsgi_req) {
|
||||
ptrbuf += strsize;
|
||||
}
|
||||
else {
|
||||
uwsgi_log("invalid uwsgi request (current strsize: %d). skip.\n", strsize);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log("invalid uwsgi request (current strsize: %d). skip.\n", strsize);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log("invalid uwsgi request (current strsize: %d). skip.\n", strsize);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.post_buffering > 0 && !wsgi_req->body_as_file && !wsgi_req->async_post) {
|
||||
// read to disk if post_cl > post_buffering (it will eventually do upload progress...)
|
||||
if (wsgi_req->post_cl >= (size_t) uwsgi.post_buffering) {
|
||||
if (!uwsgi_read_whole_body(wsgi_req, wsgi_req->post_buffering_buf, uwsgi.post_buffering_bufsize)) {
|
||||
wsgi_req->status = -1;
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->body_as_file = 1;
|
||||
}
|
||||
// on tiny post use memory
|
||||
else {
|
||||
if (!uwsgi_read_whole_body_in_mem(wsgi_req, wsgi_req->post_buffering_buf)) {
|
||||
wsgi_req->status = -1;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// check if data are available in the local cache
|
||||
if (wsgi_req->cache_get_len > 0) {
|
||||
uint64_t cache_value_size;
|
||||
char *cache_value = uwsgi_cache_get(wsgi_req->cache_get, wsgi_req->cache_get_len, &cache_value_size);
|
||||
if (cache_value && cache_value_size > 0) {
|
||||
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, cache_value, cache_value_size);
|
||||
wsgi_req->status = -1;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.check_cache && wsgi_req->uri_len && wsgi_req->method_len == 3 &&
|
||||
wsgi_req->method[0] == 'G' && wsgi_req->method[1] == 'E' && wsgi_req->method[2] == 'T') {
|
||||
|
||||
uint64_t cache_value_size;
|
||||
char *cache_value = uwsgi_cache_get(wsgi_req->uri, wsgi_req->uri_len, &cache_value_size);
|
||||
if (cache_value && cache_value_size > 0) {
|
||||
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, cache_value, cache_value_size);
|
||||
wsgi_req->status = -1;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.manage_script_name) {
|
||||
if (uwsgi.apps_cnt > 0 && wsgi_req->path_info_len > 1) {
|
||||
@@ -626,27 +702,26 @@ int uwsgi_parse_vars(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
}
|
||||
|
||||
// check if a file named uwsgi.check_static+env['PATH_INFO'] exists
|
||||
if (uwsgi.check_static && wsgi_req->path_info_len > 1) {
|
||||
struct stat st;
|
||||
char *filename = uwsgi_concat2n(uwsgi.check_static, uwsgi.check_static_len, wsgi_req->path_info, wsgi_req->path_info_len);
|
||||
if (!uwsgi_file_serve(wsgi_req, uwsgi.check_static, uwsgi.check_static_len, wsgi_req->path_info, wsgi_req->path_info_len, uwsgi.check_static, uwsgi.check_static_len)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// check static-map
|
||||
struct uwsgi_static_map *usm = uwsgi.static_maps;
|
||||
while(usm) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("checking for %s\n", filename);
|
||||
uwsgi_log("checking for %.*s <-> %.*s\n", wsgi_req->path_info_len, wsgi_req->path_info, usm->mountpoint_len, usm->mountpoint);
|
||||
#endif
|
||||
if (!stat(filename, &st)) {
|
||||
if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("file %s found\n", filename);
|
||||
#endif
|
||||
wsgi_req->sendfile_fd = open(filename, O_RDONLY);
|
||||
wsgi_req->response_size = write(wsgi_req->poll.fd, wsgi_req->protocol, wsgi_req->protocol_len);
|
||||
wsgi_req->response_size += write(wsgi_req->poll.fd, " 200 OK\r\n\r\n", 11);
|
||||
wsgi_req->response_size += uwsgi_sendfile(wsgi_req);
|
||||
wsgi_req->status = 200;
|
||||
free(filename);
|
||||
|
||||
if (!uwsgi_starts_with(wsgi_req->path_info, wsgi_req->path_info_len, usm->mountpoint, usm->mountpoint_len)) {
|
||||
if (!uwsgi_file_serve(wsgi_req, usm->document_root, usm->document_root_len, wsgi_req->path_info+usm->mountpoint_len, wsgi_req->path_info_len-usm->mountpoint_len, usm->orig_document_root, usm->orig_document_root_len)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
free(filename);
|
||||
usm = usm->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -687,7 +762,7 @@ int uwsgi_ping_node(int node, struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
|
||||
uwsgi_poll.events = POLLIN;
|
||||
if (!uwsgi_parse_response(&uwsgi_poll, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], (struct uwsgi_header *) wsgi_req, wsgi_req->buffer)) {
|
||||
if (!uwsgi_parse_packet(wsgi_req, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -752,7 +827,9 @@ int uwsgi_get_dgram(int fd, struct wsgi_request *wsgi_req) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_log("recevied request from %s\n", inet_ntoa(sin.sin_addr));
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("received request from %s\n", inet_ntoa(sin.sin_addr));
|
||||
#endif
|
||||
|
||||
if (rlen < 4) {
|
||||
uwsgi_log("invalid uwsgi packet\n");
|
||||
@@ -776,7 +853,9 @@ int uwsgi_get_dgram(int fd, struct wsgi_request *wsgi_req) {
|
||||
|
||||
wsgi_req->buffer = buffer+4;
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("request received %d %d\n", wsgi_req->uh.modifier1, wsgi_req->uh.modifier2);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -842,20 +921,27 @@ int uwsgi_hooked_parse_dict_dgram(int fd, char *buffer, size_t len, uint8_t modi
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_log("recevied request from %s\n", inet_ntoa(sin.sin_addr));
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("RLEN: %d\n", rlen);
|
||||
#endif
|
||||
|
||||
// check for valid dict 4(header) 2(non-zero key)+1 2(value)
|
||||
if (rlen < (4+2+1+2)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("invalid uwsgi dictionary\n");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_log("received message from %s\n", inet_ntoa(sin.sin_addr));
|
||||
|
||||
uh = (struct uwsgi_header *) buffer;
|
||||
|
||||
if (uh->modifier1 != modifier1 || uh->modifier2 != modifier2) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("invalid uwsgi dictionary received, modifier1: %d modifier2: %d\n", uh->modifier1, uh->modifier2);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -875,7 +961,9 @@ int uwsgi_hooked_parse_dict_dgram(int fd, char *buffer, size_t len, uint8_t modi
|
||||
}
|
||||
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%p %p %d\n", ptrbuf, bufferend, bufferend-ptrbuf);
|
||||
#endif
|
||||
|
||||
uwsgi_hooked_parse(ptrbuf, bufferend-ptrbuf, hook, data);
|
||||
|
||||
@@ -959,8 +1047,8 @@ ssize_t fcgi_send_param(int fd, char *key, uint16_t keylen, char *val, uint16_t
|
||||
fr.type = 4;
|
||||
fr.req1 = 0;
|
||||
fr.req0 = 1;
|
||||
fr.cl1 = (uint8_t) ((size >> 8) & 0xff);
|
||||
fr.cl0 = (uint8_t) (size &0xff);
|
||||
fr.cl8.cl1 = (uint8_t) ((size >> 8) & 0xff);
|
||||
fr.cl8.cl0 = (uint8_t) (size &0xff);
|
||||
fr.pad = 0;
|
||||
fr.reserved = 0;
|
||||
|
||||
@@ -980,8 +1068,8 @@ ssize_t fcgi_send_record(int fd, uint8_t type, uint16_t size, char *buffer) {
|
||||
fr.type = type;
|
||||
fr.req1 = 0;
|
||||
fr.req0 = 1;
|
||||
fr.cl1 = (uint8_t) ((size >> 8) & 0xff);
|
||||
fr.cl0 = (uint8_t) (size &0xff);
|
||||
fr.cl8.cl1 = (uint8_t) ((size >> 8) & 0xff);
|
||||
fr.cl8.cl0 = (uint8_t) (size &0xff);
|
||||
fr.pad = 0;
|
||||
fr.reserved = 0;
|
||||
|
||||
@@ -1001,7 +1089,6 @@ uint16_t fcgi_get_record(int fd, char *buf) {
|
||||
uint16_t remains = 8;
|
||||
char *ptr = (char *) &fr;
|
||||
ssize_t len;
|
||||
uint16_t rs;
|
||||
|
||||
while(remains) {
|
||||
uwsgi_waitfd(fd, -1);
|
||||
@@ -1011,9 +1098,7 @@ uint16_t fcgi_get_record(int fd, char *buf) {
|
||||
ptr += len;
|
||||
}
|
||||
|
||||
rs = (uint16_t) fr.cl1;
|
||||
|
||||
remains = ntohs(rs) + fr.pad;
|
||||
remains = ntohs(fr.cl) + fr.pad;
|
||||
ptr = buf;
|
||||
|
||||
while(remains) {
|
||||
@@ -1026,14 +1111,13 @@ uint16_t fcgi_get_record(int fd, char *buf) {
|
||||
|
||||
if (fr.type != 6) return 0;
|
||||
|
||||
return ntohs(rs);
|
||||
return ntohs(fr.cl);
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_simple_message_string(char *socket_name, uint8_t modifier1, uint8_t modifier2, char *what, uint16_t what_len, char *buffer, uint16_t *response_len, int timeout) {
|
||||
|
||||
struct uwsgi_header uh;
|
||||
struct pollfd upoll;
|
||||
struct wsgi_request msg_req;
|
||||
|
||||
int fd = uwsgi_connect(socket_name, timeout, 0);
|
||||
|
||||
@@ -1048,19 +1132,22 @@ char *uwsgi_simple_message_string(char *socket_name, uint8_t modifier1, uint8_t
|
||||
return NULL;
|
||||
}
|
||||
|
||||
upoll.fd = fd;
|
||||
upoll.events = POLLIN;
|
||||
memset(&msg_req, 0, sizeof(struct wsgi_request));
|
||||
msg_req.poll.fd = fd;
|
||||
msg_req.poll.events = POLLIN;
|
||||
msg_req.buffer = buffer;
|
||||
|
||||
if (buffer) {
|
||||
if (!uwsgi_parse_response(&upoll, timeout, &uh, buffer)) {
|
||||
if (!uwsgi_parse_packet(&msg_req, timeout)) {
|
||||
close(fd);
|
||||
if (response_len) *response_len = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (response_len) *response_len = msg_req.uh.pktsize;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
if (response_len) *response_len = uh.pktsize;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@@ -1149,3 +1236,104 @@ int uwsgi_simple_send_string(char *socket_name, uint8_t modifier1, uint8_t modif
|
||||
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, char *orig_document_root, uint16_t orig_document_root_len) {
|
||||
|
||||
struct stat st;
|
||||
char real_filename[PATH_MAX];
|
||||
char *filename = uwsgi_concat3n(document_root, document_root_len, "/", 1, path_info, path_info_len);
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("checking for %s\n", filename);
|
||||
#endif
|
||||
if (!realpath(filename, real_filename)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("unable to get realpath() of the static file\n");
|
||||
#endif
|
||||
free(filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(filename);
|
||||
|
||||
if (uwsgi_starts_with(real_filename, strlen(real_filename), document_root, document_root_len)) {
|
||||
uwsgi_log("security error: %s is not under %.*s\n", real_filename, document_root_len, document_root);
|
||||
return -1;
|
||||
}
|
||||
if (!stat(real_filename, &st)) {
|
||||
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) {
|
||||
wsgi_req->status = 304;
|
||||
wsgi_req->headers_size = wsgi_req->socket->proto_write_header(wsgi_req, wsgi_req->protocol, wsgi_req->protocol_len);
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, " 304 Not Modified\r\n", 19);
|
||||
|
||||
struct uwsgi_string_list *ah = uwsgi.additional_headers;
|
||||
while(ah) {
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, ah->value, ah->len);
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, "\r\n", 2);
|
||||
ah = ah->next;
|
||||
}
|
||||
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, "\r\n", 2);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
|
||||
char http_last_modified[49];
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("file %s found\n", real_filename);
|
||||
#endif
|
||||
// no need to set content-type/content-length, they will be fixed by the http server/router
|
||||
|
||||
wsgi_req->headers_size = wsgi_req->socket->proto_write_header(wsgi_req, wsgi_req->protocol, wsgi_req->protocol_len);
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, " 200 OK\r\n", 9);
|
||||
|
||||
struct uwsgi_string_list *ah = uwsgi.additional_headers;
|
||||
while(ah) {
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, ah->value, ah->len);
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, "\r\n", 2);
|
||||
ah = ah->next;
|
||||
}
|
||||
|
||||
if (uwsgi.file_serve_mode == 1) {
|
||||
wsgi_req->header_cnt = 2;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, "X-Accel-Redirect: ", 18);
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, orig_document_root, orig_document_root_len);
|
||||
if (orig_document_root[orig_document_root_len-1] != '/') {
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, "/", 1);
|
||||
}
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, path_info, path_info_len);
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, "\r\n", 2);
|
||||
set_http_date(st.st_mtime, http_last_modified);
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, http_last_modified, 48);
|
||||
}
|
||||
else if (uwsgi.file_serve_mode == 2) {
|
||||
wsgi_req->header_cnt = 2;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, "X-Sendfile: ", 12);
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, orig_document_root, orig_document_root_len);
|
||||
if (orig_document_root[orig_document_root_len-1] != '/') {
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, "/", 1);
|
||||
}
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, path_info, path_info_len);
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, "\r\n", 2);
|
||||
set_http_date(st.st_mtime, http_last_modified);
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, http_last_modified, 48);
|
||||
}
|
||||
else {
|
||||
wsgi_req->header_cnt = 1;
|
||||
set_http_date(st.st_mtime, http_last_modified);
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, http_last_modified, 48);
|
||||
wsgi_req->sendfile_fd = open(real_filename, O_RDONLY);
|
||||
wsgi_req->response_size += uwsgi_sendfile(wsgi_req);
|
||||
}
|
||||
|
||||
|
||||
wsgi_req->status = 200;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,65 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_init_queue() {
|
||||
if (!uwsgi.queue_blocksize)
|
||||
uwsgi.queue_blocksize = 8192;
|
||||
|
||||
if (uwsgi.queue_blocksize % uwsgi.page_size != 0) {
|
||||
uwsgi_log("invalid queue blocksize %llu: must be a multiple of memory page size (%d bytes)\n", (unsigned long long) uwsgi.queue_blocksize, uwsgi.page_size);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
uwsgi.shared->queue_pos = 0;
|
||||
uwsgi.shared->queue_pull_pos = 0;
|
||||
|
||||
if (uwsgi.queue_store) {
|
||||
uwsgi.queue_filesize = uwsgi.queue_blocksize * uwsgi.queue_size;
|
||||
int queue_fd;
|
||||
struct stat qst;
|
||||
|
||||
if (stat(uwsgi.queue_store, &qst)) {
|
||||
uwsgi_log("creating a new queue store file: %s\n", uwsgi.queue_store);
|
||||
queue_fd = open(uwsgi.queue_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
if (queue_fd >= 0) {
|
||||
// fill the queue store
|
||||
if (ftruncate(queue_fd, uwsgi.queue_filesize)) {
|
||||
uwsgi_log("ftruncate()");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((size_t) qst.st_size != uwsgi.queue_filesize || !S_ISREG(qst.st_mode)) {
|
||||
uwsgi_log("invalid queue store file. Please remove it or fix queue blocksize/items to match its size\n");
|
||||
exit(1);
|
||||
}
|
||||
queue_fd = open(uwsgi.queue_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
uwsgi_log("recovered queue from backing store file: %s\n", uwsgi.queue_store);
|
||||
}
|
||||
|
||||
if (queue_fd < 0) {
|
||||
uwsgi_error_open(uwsgi.queue_store);
|
||||
exit(1);
|
||||
}
|
||||
uwsgi.queue = mmap(NULL, uwsgi.queue_filesize, PROT_READ | PROT_WRITE, MAP_SHARED, queue_fd, 0);
|
||||
uwsgi_queue_fix();
|
||||
}
|
||||
else {
|
||||
uwsgi.queue = mmap(NULL, uwsgi.queue_blocksize * uwsgi.queue_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
}
|
||||
if (!uwsgi.queue) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi.queue_lock = uwsgi_mmap_shared_rwlock();
|
||||
uwsgi_rwlock_init(uwsgi.queue_lock);
|
||||
|
||||
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) {
|
||||
|
||||
struct uwsgi_queue_item *uqi;
|
||||
@@ -19,6 +78,25 @@ char *uwsgi_queue_get(uint64_t index, uint64_t *size) {
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_queue_fix() {
|
||||
|
||||
uint64_t i;
|
||||
char *value;
|
||||
uint64_t size;
|
||||
|
||||
for(i=0;i< uwsgi.queue_size;i++) {
|
||||
// valid record ?
|
||||
value = uwsgi_queue_get(i, &size);
|
||||
if (value && size) {
|
||||
uwsgi.shared->queue_pos++;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_queue_pop(uint64_t *size) {
|
||||
|
||||
struct uwsgi_queue_item *uqi;
|
||||
@@ -70,6 +148,8 @@ int uwsgi_queue_push(char *message, uint64_t size) {
|
||||
if (size > uwsgi.queue_blocksize + sizeof(struct uwsgi_queue_item))
|
||||
return 0;
|
||||
|
||||
if (!size) return 0;
|
||||
|
||||
ptr = ptr + (uwsgi.queue_blocksize*uwsgi.shared->queue_pos);
|
||||
uqi = (struct uwsgi_queue_item *) ptr;
|
||||
|
||||
|
||||
@@ -7,6 +7,11 @@ 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_log("you can register RPC functions only in the master\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_lock(uwsgi.rpc_table_lock);
|
||||
|
||||
if (uwsgi.shared->rpc_count < MAX_RPC) {
|
||||
|
||||
+9
-1
@@ -25,7 +25,13 @@ ssize_t uwsgi_sendfile(struct wsgi_request *wsgi_req) {
|
||||
if (wsgi_req->sendfile_fd_size) {
|
||||
|
||||
if (!wsgi_req->sendfile_fd_chunk) wsgi_req->sendfile_fd_chunk = 4096;
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -70,7 +76,9 @@ ssize_t uwsgi_do_sendfile(int sockfd, int filefd, size_t filesize, size_t chunk,
|
||||
}
|
||||
|
||||
if (sf_ret) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("sf_len = %d\n", sf_len);
|
||||
#endif
|
||||
uwsgi_error("sendfile()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -8,25 +8,38 @@ from setuptools.dist import Distribution
|
||||
from setuptools.command.install import install
|
||||
from setuptools.command.build_ext import build_ext
|
||||
|
||||
|
||||
def patch_bin_path(cmd, conf):
|
||||
|
||||
bin_name = conf.get('bin_name')
|
||||
|
||||
try:
|
||||
if not os.path.exists(cmd.install_scripts):
|
||||
os.makedirs(cmd.install_scripts)
|
||||
if not os.path.isabs(bin_name):
|
||||
print('Patching "bin_name" to properly install_scripts dir')
|
||||
conf.set('bin_name', os.path.join(cmd.install_scripts, conf.get('bin_name')))
|
||||
except:
|
||||
conf.set('bin_name', sys.prefix + '/bin/' + bin_name)
|
||||
|
||||
|
||||
class uWSGIBuilder(build_ext):
|
||||
|
||||
def run(self):
|
||||
conf = uc.uConf('buildconf/default.ini')
|
||||
bin_name = conf.get('bin_name')
|
||||
conf.set('bin_name', sys.prefix + '/bin/' + bin_name)
|
||||
conf = uc.uConf('buildconf/default.ini')
|
||||
patch_bin_path(self, conf)
|
||||
uc.build_uwsgi( conf )
|
||||
|
||||
|
||||
class uWSGIInstall(install):
|
||||
|
||||
def run(self):
|
||||
# hack, hack and still hack. We need to find a solution for 0.9.6
|
||||
# hack, hack and still hack. We need to find a solution...
|
||||
if self.record:
|
||||
record_file = open(self.record,'w')
|
||||
|
||||
conf = uc.uConf('buildconf/default.ini')
|
||||
bin_name = conf.get('bin_name')
|
||||
conf.set('bin_name', sys.prefix + '/bin/' + bin_name)
|
||||
conf = uc.uConf('buildconf/default.ini')
|
||||
patch_bin_path(self, conf)
|
||||
uc.build_uwsgi( conf )
|
||||
|
||||
class uWSGIDistribution(Distribution):
|
||||
@@ -38,7 +51,7 @@ class uWSGIDistribution(Distribution):
|
||||
|
||||
|
||||
setup(name='uWSGI',
|
||||
version='0.9.7-dev',
|
||||
version=uc.uwsgi_version,
|
||||
description='The uWSGI server',
|
||||
author='Unbit',
|
||||
author_email='info@unbit.it',
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user