mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-10-04 16:08:31 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02d6006b2f | ||
|
|
e8e5f11c66 | ||
|
|
e53a6fa4c0 | ||
|
|
c478b0a0c8 | ||
|
|
5f207e6978 | ||
|
|
a2b74d0afd | ||
|
|
b867b11de3 | ||
|
|
806765d1d3 | ||
|
|
62d2b97e17 | ||
|
|
c04e339034 | ||
|
|
927b495646 | ||
|
|
57b5392590 | ||
|
|
463030108f | ||
|
|
46dd754264 | ||
|
|
12d9641b66 | ||
|
|
6cb1203d26 | ||
|
|
23d0ec333e | ||
|
|
da579fd308 | ||
|
|
14152bc999 | ||
|
|
6c32e5f2e2 | ||
|
|
62f74f2b60 | ||
|
|
6ac7f6db7f | ||
|
|
388a836bbc | ||
|
|
f0187e8b0f | ||
|
|
c698b82c30 | ||
|
|
afb3e3636e | ||
|
|
774548f268 | ||
|
|
ee38901855 | ||
|
|
a07ecdb3e3 | ||
|
|
143c286f3b | ||
|
|
5f2f13c49e | ||
|
|
2c19a031c7 | ||
|
|
a10e67538a | ||
|
|
4387075930 | ||
|
|
6ec1eb5c90 | ||
|
|
6ac1cbe913 | ||
|
|
4923326bdd | ||
|
|
0f8ca18e0d | ||
|
|
7666e16072 | ||
|
|
a42f6e5d18 | ||
|
|
67b22ff796 | ||
|
|
28c14f4d8c | ||
|
|
7133069ee9 | ||
|
|
b752425223 | ||
|
|
c5367bb338 | ||
|
|
d1342241bd | ||
|
|
05be07aab4 | ||
|
|
7f4f16e96a | ||
|
|
f11664642f | ||
|
|
28b074b6ea | ||
|
|
f43161c939 | ||
|
|
d52b7111ea | ||
|
|
9331d1154e | ||
|
|
364a580090 | ||
|
|
f33fa5005a | ||
|
|
8029d01b8b | ||
|
|
69586a6134 | ||
|
|
7c9c50c6a9 | ||
|
|
97139a27d7 | ||
|
|
3b67033d65 | ||
|
|
ec08632a29 | ||
|
|
eea64e0178 | ||
|
|
78096fab30 | ||
|
|
86fcd13dd9 | ||
|
|
4badecdbbc | ||
|
|
8d1a0d6a13 | ||
|
|
b102b2979b | ||
|
|
393235fbfe | ||
|
|
183a109119 | ||
|
|
bcff6e0173 | ||
|
|
3bd2c3a573 | ||
|
|
afba91ad61 | ||
|
|
a34c0f5556 | ||
|
|
3fd41a3d2e | ||
|
|
1c5ba25437 | ||
|
|
f7ff6b5488 | ||
|
|
53ac53167b | ||
|
|
c4eccd0d93 | ||
|
|
7744285dc3 | ||
|
|
238c98c0bd | ||
|
|
f9a9ef5752 | ||
|
|
6e5e357a36 | ||
|
|
0c4004ed14 | ||
|
|
008cd13c4f | ||
|
|
7f3ba8324a | ||
|
|
e9002f2111 | ||
|
|
8f161909bb | ||
|
|
1eea49a010 | ||
|
|
e62679cc26 | ||
|
|
f8f9325cbc | ||
|
|
fa1dd3fbfd | ||
|
|
0288313524 | ||
|
|
df18d66319 | ||
|
|
e8eb86f998 | ||
|
|
534ff245f2 | ||
|
|
172654d409 | ||
|
|
4dea7cfb4b | ||
|
|
f7955858bf | ||
|
|
fb5a5ddadd | ||
|
|
2bacd79c43 | ||
|
|
6ca539497d | ||
|
|
78f3524fcb | ||
|
|
937b2de41b | ||
|
|
a07c79f7be | ||
|
|
9562c81590 | ||
|
|
0a37852c5f | ||
|
|
460b78857c | ||
|
|
ac0e0a9f9e | ||
|
|
740f16fe62 | ||
|
|
faa0995c9c | ||
|
|
dfff71a525 | ||
|
|
380d8cb3ea | ||
|
|
3f5aab2083 | ||
|
|
2af5ef9016 | ||
|
|
f82dbfd300 | ||
|
|
9cbf1c545d | ||
|
|
9ac598b9c3 | ||
|
|
07dd0c2c0b | ||
|
|
66b1cdd63c | ||
|
|
78980aab9e | ||
|
|
0ac813be79 | ||
|
|
b09513bb2e | ||
|
|
c3e906f1ff | ||
|
|
666c1fec75 | ||
|
|
5d86ed46a3 | ||
|
|
2ee1c3ac32 | ||
|
|
ef530650c4 | ||
|
|
fd1c7773ee | ||
|
|
520ff8465b | ||
|
|
170c66b000 | ||
|
|
c94206f7ba | ||
|
|
f9158b39d8 | ||
|
|
daba88f947 | ||
|
|
a7e4852621 | ||
|
|
8a8d029357 | ||
|
|
b9621b620a | ||
|
|
cc0d656b86 | ||
|
|
18080df77a | ||
|
|
059314e8f3 | ||
|
|
500e4e41fe | ||
|
|
8b21fb72b2 | ||
|
|
f8464ac733 | ||
|
|
ac05ad1ef5 | ||
|
|
ed5f501a19 | ||
|
|
515b9f2838 | ||
|
|
d57ddff924 | ||
|
|
0a2da2a2ce | ||
|
|
72f677bb0d | ||
|
|
e176af1702 | ||
|
|
6e748eafb9 | ||
|
|
e11f84193a | ||
|
|
ec4fbdff32 | ||
|
|
d3ced01b43 | ||
|
|
64468ae69e | ||
|
|
79d75e832f | ||
|
|
ae41506764 | ||
|
|
f0bb80b9b8 | ||
|
|
1955d63cad | ||
|
|
4b2fdb3d30 | ||
|
|
d586fe2fb3 | ||
|
|
924074175e | ||
|
|
a64cbea6e8 | ||
|
|
9ef571b4fa | ||
|
|
67666a1788 | ||
|
|
e1daf1d360 | ||
|
|
94f3b715e5 | ||
|
|
31892a69df | ||
|
|
a43bc93492 | ||
|
|
8dd9149624 | ||
|
|
e422f7311a | ||
|
|
bb093c7614 | ||
|
|
5186936c3a | ||
|
|
4269f0483f | ||
|
|
09f49bb5d6 | ||
|
|
a054f2b968 | ||
|
|
149cf74fe6 | ||
|
|
123b3fd4b1 | ||
|
|
2e18db2352 | ||
|
|
d7c2856041 | ||
|
|
07a87bdff3 | ||
|
|
fca3c51351 | ||
|
|
70db2befb5 | ||
|
|
057fcb0693 | ||
|
|
051dc77712 | ||
|
|
784191f127 | ||
|
|
3454279ac7 | ||
|
|
e335cf5e96 | ||
|
|
44277b38cd | ||
|
|
31bd3fa6c4 | ||
|
|
3104f915e5 | ||
|
|
860a017060 | ||
|
|
23f00ec864 | ||
|
|
69fd8aaa36 | ||
|
|
7ea77afb38 | ||
|
|
da577ef923 | ||
|
|
26cae83139 | ||
|
|
a8c4f6bffe | ||
|
|
eff66ef08f | ||
|
|
381da45196 | ||
|
|
43c347d20e | ||
|
|
fadee3242f | ||
|
|
27fda41398 | ||
|
|
f6f8dbecc0 | ||
|
|
902991daa4 | ||
|
|
245ab6d815 | ||
|
|
96700a49e3 | ||
|
|
b75ba73264 | ||
|
|
7d6f93d1cb | ||
|
|
9aaf36141e | ||
|
|
68c6dd13b8 | ||
|
|
8ac5176c4c | ||
|
|
fd49ba36eb | ||
|
|
047aac8426 | ||
|
|
103e7415f3 | ||
|
|
b64911d20e | ||
|
|
2f970ce585 | ||
|
|
47801964c4 | ||
|
|
da8eb4ad1b | ||
|
|
320a2b8a7f | ||
|
|
eab271e1e1 | ||
|
|
d161962db1 | ||
|
|
36a3b408cf | ||
|
|
10af04becc | ||
|
|
4db259900e | ||
|
|
fe4ba8130d | ||
|
|
4c4f92bad2 | ||
|
|
6f726d6370 | ||
|
|
c4f50fccfb | ||
|
|
7e2daed0e8 | ||
|
|
e4d3f79492 | ||
|
|
d128a958cf | ||
|
|
0024bf56be | ||
|
|
1d03fdee64 | ||
|
|
152fb9cde9 | ||
|
|
e6c5710657 | ||
|
|
df0b3f7eb5 | ||
|
|
f420bf3266 | ||
|
|
7a262159dc | ||
|
|
3dec2821f4 | ||
|
|
652a9c5825 | ||
|
|
79c30fed23 | ||
|
|
5ab8d800d8 | ||
|
|
0beb7108e4 | ||
|
|
356d59a38d | ||
|
|
87853d0ca3 | ||
|
|
c9056630b7 | ||
|
|
a4120efabe | ||
|
|
0bd017f722 | ||
|
|
5a738fba8a | ||
|
|
856fd8b00f | ||
|
|
d60d90afe3 | ||
|
|
0132c00f41 | ||
|
|
aebc637f2b | ||
|
|
d4c4643ddc | ||
|
|
aea66427f1 | ||
|
|
0376c804f9 | ||
|
|
4a99069a4e | ||
|
|
e3bbcc5c84 | ||
|
|
6fc40077be | ||
|
|
040d1a9d0b | ||
|
|
8a121ada9d | ||
|
|
373c45c7d4 | ||
|
|
3e7992d0ac | ||
|
|
4a4455cd16 | ||
|
|
444e8d2637 | ||
|
|
bcd6f7de32 | ||
|
|
5346ca68f9 | ||
|
|
ab83b1c7aa | ||
|
|
bc0eec51b4 | ||
|
|
187100f2bf | ||
|
|
2e4e23f63f | ||
|
|
6f1f990f69 | ||
|
|
75d2109254 | ||
|
|
cada9ed520 | ||
|
|
6f3fe261d0 | ||
|
|
c78c0a2798 | ||
|
|
6249c25411 | ||
|
|
36fc098c5d | ||
|
|
070e84125a | ||
|
|
aa50669237 | ||
|
|
32ab7e79ca | ||
|
|
8971539550 | ||
|
|
df52dfd31f | ||
|
|
61756d45a2 | ||
|
|
fe7a5eb5d3 | ||
|
|
e744d36fa0 | ||
|
|
2108c85f7e | ||
|
|
e2c405fe02 | ||
|
|
8668b9a614 | ||
|
|
87ae9d780e | ||
|
|
d0c071e759 | ||
|
|
1a6324e825 | ||
|
|
bee3ba73d8 | ||
|
|
8dde9c2984 | ||
|
|
094d4128dc | ||
|
|
da25f77326 | ||
|
|
c5073f7056 | ||
|
|
c461d2e6b3 | ||
|
|
6adca06764 | ||
|
|
746f645e6c | ||
|
|
e6ef84bb4b | ||
|
|
17975acb45 | ||
|
|
4b81ff61eb | ||
|
|
bf868ff636 | ||
|
|
c777a0f926 | ||
|
|
7a7f499f63 | ||
|
|
b22b46b153 | ||
|
|
bbd8ea51c0 | ||
|
|
e1969d92ab | ||
|
|
e8e8b6902c | ||
|
|
7041a9fa45 | ||
|
|
bfbca5bc96 | ||
|
|
be183bf07f | ||
|
|
f7aa451af4 | ||
|
|
53ccd3d4b8 | ||
|
|
aaa6033c2a | ||
|
|
345c8ed962 | ||
|
|
9e0c7a3bdc | ||
|
|
616ed04c79 | ||
|
|
441fb06129 | ||
|
|
4b92ba5cbe | ||
|
|
13932641e5 | ||
|
|
85752ccf2c | ||
|
|
6d9b753735 | ||
|
|
6b7e3a6429 | ||
|
|
6ef043c40a | ||
|
|
9704abd3e4 | ||
|
|
723acced71 | ||
|
|
ca43ad0a91 | ||
|
|
17e2dbf85b | ||
|
|
7e40c902e6 | ||
|
|
074d0b95d1 | ||
|
|
36c8a8c675 | ||
|
|
00a70c2ea2 | ||
|
|
2bf20631e1 | ||
|
|
74b9579531 | ||
|
|
5a152d1bae | ||
|
|
551152ade9 | ||
|
|
42c5b356f5 | ||
|
|
33bd68c44c | ||
|
|
46b715fcc3 | ||
|
|
b004168401 | ||
|
|
6cebf19468 | ||
|
|
fb73324d25 | ||
|
|
94624c7e52 | ||
|
|
c4033a5970 | ||
|
|
e66e56b593 | ||
|
|
b408423b03 | ||
|
|
c37a2d7842 | ||
|
|
da339bb3a9 | ||
|
|
f30be82926 | ||
|
|
f04aa843ff | ||
|
|
5c42c27cd4 | ||
|
|
fc744f5719 | ||
|
|
855c963fb3 | ||
|
|
dd932b0a78 | ||
|
|
e4e75a4d64 | ||
|
|
ef0464dba6 | ||
|
|
bc2b49c8e8 | ||
|
|
409ce34a0b | ||
|
|
89158b0509 | ||
|
|
86b90b8b16 | ||
|
|
fe4c88c1c5 | ||
|
|
f0f08728ab | ||
|
|
5259c803e8 | ||
|
|
c6e5e533fa | ||
|
|
21e4cc19c8 | ||
|
|
045001fd6c | ||
|
|
eadaf3407a | ||
|
|
7434d3113c | ||
|
|
ab9fade14d | ||
|
|
5be63b02e8 | ||
|
|
7694c38021 | ||
|
|
d13f7a45b9 | ||
|
|
44e8f01671 | ||
|
|
09a8104256 | ||
|
|
09d8ac2656 | ||
|
|
c5877df60c | ||
|
|
0f2fff31ee | ||
|
|
ebcdd294aa | ||
|
|
d663e10584 | ||
|
|
048299e1d3 | ||
|
|
96aaa9fa3f | ||
|
|
015f17192c | ||
|
|
f0ac801ecd | ||
|
|
f3b207c024 | ||
|
|
0379e200b6 | ||
|
|
abe6168bc3 | ||
|
|
a6aa2c31c6 | ||
|
|
f35ad319cf | ||
|
|
527ad44463 | ||
|
|
b245307f55 | ||
|
|
9285b403d9 | ||
|
|
58b72a4c80 | ||
|
|
73f706723e | ||
|
|
4d22f7171f | ||
|
|
b60e22b4e5 | ||
|
|
7310b73289 | ||
|
|
4fa61c225a | ||
|
|
63b41856e5 | ||
|
|
ed1e668240 | ||
|
|
e3a7e70180 | ||
|
|
9f0b20c8d2 | ||
|
|
68aff372ce | ||
|
|
38cfa72318 | ||
|
|
31047e1e10 | ||
|
|
bbb90296bb | ||
|
|
00c6aa2f65 | ||
|
|
720da09631 | ||
|
|
47f7c09b97 | ||
|
|
cb5704da10 | ||
|
|
c64356b231 | ||
|
|
2acd2f5224 | ||
|
|
ba251f8e3d | ||
|
|
48019f9044 | ||
|
|
d9a1f2448c | ||
|
|
553a947c2d | ||
|
|
736aedfa89 | ||
|
|
6184acc727 | ||
|
|
f0d96b03fa | ||
|
|
14bf840eef | ||
|
|
7ea08093c7 | ||
|
|
8eb8d07151 | ||
|
|
cdd95b434e | ||
|
|
82cbcea886 | ||
|
|
ea54a05fc3 | ||
|
|
eba39dcd67 | ||
|
|
d71ea1404d | ||
|
|
0f0d5b2a5f | ||
|
|
10a75ef848 | ||
|
|
4bd9bf8917 | ||
|
|
323da1299e | ||
|
|
75d08898b4 | ||
|
|
5e47796a02 | ||
|
|
0ade5aba0a | ||
|
|
f7b1ad8cb0 | ||
|
|
3bd147e687 | ||
|
|
66c99e257f | ||
|
|
8407a5921b | ||
|
|
5f36987827 | ||
|
|
ede1622368 | ||
|
|
a28dfb790e | ||
|
|
3711cbbd61 | ||
|
|
c9ef6281ff | ||
|
|
604ea6fd57 | ||
|
|
41dfcaa705 | ||
|
|
daa41d4a51 | ||
|
|
ded4450a70 | ||
|
|
cd0be56bbe | ||
|
|
0bf7b64b46 | ||
|
|
215d2e7055 | ||
|
|
2b5b0cf1bc | ||
|
|
67231da4a9 | ||
|
|
8c25b38470 | ||
|
|
08bbe0cd30 | ||
|
|
9f9f63fe2f | ||
|
|
997bd63cc3 | ||
|
|
6a566d9dca | ||
|
|
d2e743a800 | ||
|
|
2fedb175b4 | ||
|
|
6c5e25dbfe | ||
|
|
94fd3f0bfd | ||
|
|
ca169b05fb | ||
|
|
10ea1fee6e | ||
|
|
d7b8704165 | ||
|
|
0f774b840c | ||
|
|
81521a314b | ||
|
|
37ee7f8908 | ||
|
|
309648f68b | ||
|
|
5cfa65d04e | ||
|
|
e73c8194a0 | ||
|
|
00a3f6ae7f | ||
|
|
b7edaa68c8 | ||
|
|
2877ba54de | ||
|
|
f74a19a71a | ||
|
|
3da5238ee5 | ||
|
|
567dd36592 | ||
|
|
b48062a026 | ||
|
|
b039cb713f | ||
|
|
8e987ffa18 | ||
|
|
52502342e0 | ||
|
|
cb9e3c22f9 | ||
|
|
0c465775ad | ||
|
|
a5417f4963 | ||
|
|
b48076f6e4 | ||
|
|
c472eae332 | ||
|
|
918fc654f4 | ||
|
|
9097cbe10d | ||
|
|
e260873338 | ||
|
|
a7822742c0 | ||
|
|
f1316ef4bb | ||
|
|
4106931175 | ||
|
|
fb5ba40f0c | ||
|
|
854e51f0ad | ||
|
|
676b43f17d | ||
|
|
48b68e6a92 | ||
|
|
61f33721e1 | ||
|
|
5c3c46598f | ||
|
|
4358036f9e | ||
|
|
54d75d92ef | ||
|
|
b1ae57c932 | ||
|
|
2636baa33f | ||
|
|
926c739517 |
@@ -2,3 +2,11 @@ d3850b52334a91d005b0fe45e1e38ba0997a1fb8 no_server mode
|
||||
2d8a617299153ed2efa6ecee7920e9d36c29e0f5 0.9.5beta1
|
||||
04722a2d0121080d14a64df097c278860db5ce8a 0.9.5rc1
|
||||
820cc64ab296dc4589ef72a33a6b804c22a0430c 0.9.5rc2
|
||||
b0db39cfad5ac6d4f00bbb3f9c57cf73206e2afb 0.9.5
|
||||
9f8b98ad1dfa51b86b13fa624c65f73523075fc4 0.9.5.1
|
||||
a83e7a482e65befcfbb0e24af8cd5d15190acdd7 0.9.6-rc1
|
||||
b8f67c6cd0d62f864db9b2b265b4e260ad7d873c 0.9.6-rc2
|
||||
35918dd4b3771158b2b57410613ef029e08bbd60 0.9.6
|
||||
5f25d1f97f9dde3e391a668c1c610a52a5db8244 0.9.6.1
|
||||
ef31fc61ac48018c464f28ebfdf865b96bf83f18 0.9.6.2
|
||||
9e100c1f085034396cec586f0c76ad3f9800d1a5 0.9.7-beta1
|
||||
|
||||
@@ -1,5 +1,180 @@
|
||||
*** march 2011 ***
|
||||
|
||||
* 0.9.7-beta1 [20110301]
|
||||
|
||||
- fully modular re-design
|
||||
- advanced build system with presets
|
||||
- threading support
|
||||
- emperor mode for massive auto-hosting
|
||||
- caching subsystem
|
||||
- message queue (even stacked) support
|
||||
- improved server reloading system
|
||||
- support for Linux Cgroups and Namespaces
|
||||
- integrated upload progress
|
||||
- Clustering infrastructure via multicast, broadcast or subscriptions
|
||||
- support for attaching/monitoring external apps to the master process
|
||||
- improved virtualhosting mode
|
||||
- extremely improved Python support with better usage of multiple interpreters
|
||||
- improved multiple apps support
|
||||
- Production ready, evented HTTP router/proxy/load-balancer
|
||||
- Production ready, evented uwsgi router/proxy/load-balancer
|
||||
- new Erlang stack
|
||||
- Internal signal subsystem
|
||||
- support for RubyOnRails and Rack apps
|
||||
- A huge series of fixes and optimizations
|
||||
|
||||
*** february 2011 ***
|
||||
|
||||
* 0.9.6.8 [20110207]
|
||||
|
||||
- fixed a bug when using --limit-as
|
||||
- fixed a erlang buffer initialization
|
||||
- added --ignore-sigpipe
|
||||
- added --master-as-root
|
||||
|
||||
*** january 2011 ***
|
||||
|
||||
* 0.9.6.7 [20110130]
|
||||
|
||||
- a huge amount of async optimizations and fixes
|
||||
- --logdate takes an optional strftime-like value
|
||||
- follow $PATH on reloading
|
||||
- uwsgi.core is exported in WSGI env
|
||||
- uwsgi.log() respect for --logdate
|
||||
- initial banner respect for --logdate
|
||||
- fixed --post-buffering
|
||||
- default listen backlog queue is now 100
|
||||
- Python 3 support is no more marked as experimental
|
||||
- Python 3.2 support
|
||||
- new option --chroot-reload will force a reload of the uWSGI stack after a chroot
|
||||
- fixed a typo in INI parsing
|
||||
|
||||
*** december 2010 ***
|
||||
|
||||
* 0.9.6.6 [20101230]
|
||||
|
||||
- support for YAML configuration files
|
||||
- backported python module aliasing from 0.9.7-dev
|
||||
- better apache2 module (support for SetEnv directive, fixed REQUEST_URI and improved connection handling)
|
||||
- uwsgi.post_fork_hook implementation (to execute function after fork()) (thanks George Kollias)
|
||||
- option --gid calls setgroups() after setgid() (thanks Jorge Cardona)
|
||||
- fixed uGreen compilation (and uGreen is now built by default)
|
||||
- fixed timeout and thundering herd problem in async modes (many thanks to Test157 for giving us a good async-test-app)
|
||||
- disable TCP_INFO in older Linux kernels (thanks Bo Shi)
|
||||
- enable TCP_INFO in FreeBSD (limited usage due to FreeBSD kernel support)
|
||||
- fixed static virtualhosting mode using xml files (thanks Guido Notari of Link I.T. spa)
|
||||
- new option --close-on-exec (thanks Jean-Baptiste Quenot)
|
||||
- use HTTP_HOST var (and fallback to SERVER_NAME) in virtual hosting mode
|
||||
- fixed a buffer overflow in automatic socket_name allocation (spotted by Riccardo Magliocchetti)
|
||||
- Official support for Nexenta
|
||||
|
||||
|
||||
*** september 2010 ***
|
||||
|
||||
* 0.9.6.5 [20100929]
|
||||
|
||||
- PEP 3333 support
|
||||
- fix --pythonpath with --wsgi-file
|
||||
- x-wsgiorg.uwsgi.version renamed to uwsgi.version
|
||||
|
||||
* 0.9.6.4 [20100925]
|
||||
|
||||
- fix a stupid bug in conditional logging backport
|
||||
|
||||
* 0.9.6.3 [20100925]
|
||||
|
||||
- fix a buffer overflow in .ini parsing (it throws a glibc error on malloc)
|
||||
- backport of conditional logging from 0.9.7-dev
|
||||
- backport of backlog queue monitor from 0.9.7-dev (only Linux)
|
||||
|
||||
* 0.9.6.2 [20100915]
|
||||
|
||||
- fix a regression in virtual hosting mode
|
||||
- fix pythonpath usage in --ini and --ini-paste
|
||||
- new uwsgi packet var: UWSGI_CHDIR
|
||||
|
||||
* 0.9.6.1 [20100912]
|
||||
|
||||
- print the request uri during SIGPIPE or HARAKIRI
|
||||
- added SIGUSR2 support (it will print the current running request, if available)
|
||||
- protocol parsing optimization
|
||||
- fixed --logto support
|
||||
- new --eval option allows inline definition of WSGI script
|
||||
- support for defining WSGI script in xml using CDATA
|
||||
- allow --pp as --pythonpath shortcut
|
||||
- various spooler optimizations and fixes
|
||||
- added -O2 optimization by default
|
||||
- added uwsgi.is_a_reload commodity function
|
||||
- .ini file support fix
|
||||
- SNMP agent fix
|
||||
- support for subprocesses generated by master
|
||||
- fix a regression in SCRIPT_NAME handling
|
||||
- Haiku official support
|
||||
- gcc 2.95 support
|
||||
- dynamic app management optimizations
|
||||
- export x-wsgiorg.uwsgi.version in WSGI env
|
||||
|
||||
*** august 2010 ***
|
||||
|
||||
* 0.9.6 [20100829]
|
||||
|
||||
- better handling of SCRIPT_NAME
|
||||
- vacuum option for deleting unix sockets and pidfiles after usage
|
||||
- advanced XML configuration
|
||||
- new configuration systems: INI files and LDAP
|
||||
- embedded HTTP server for development/testing
|
||||
- better signal handling
|
||||
- PSGI plugin improved
|
||||
- usability fixes and new commodities options for root startup
|
||||
- grunt processes (detached workers)
|
||||
- preliminary integrated virtualhosting mode
|
||||
- new option catch-exceptions can redirect python exceptions to your browser
|
||||
- logging improvements (--logto and --logdate options)
|
||||
- Full PEP 333 compliant usage of wsgi.file_wrapper
|
||||
- re-initialize random seed after every fork() [security fix]
|
||||
- fix Spooler's usage of stdin
|
||||
- export WSGI environment in uwsgi.env (for doing evil things)
|
||||
- logsize tracking (uwsgi.logsize) for future embedded log rotation
|
||||
|
||||
*** july 2010 ***
|
||||
|
||||
* 0.9.5.4 [20100706]
|
||||
|
||||
*** june 2010 ***
|
||||
|
||||
* 0.9.5.3 [20100628]
|
||||
|
||||
- fixed linux x86_64 compilation (sorry)
|
||||
|
||||
* 0.9.5.2 [20100626] *
|
||||
|
||||
- fixed a request parsing bug
|
||||
- applied debian fixes
|
||||
- fixed multiple interpreter sys.argv
|
||||
- improved --chmod-socket
|
||||
- fixed uid 0 SIGHUP
|
||||
- updated nginx and apache modules
|
||||
- updated PSGI, lua and example plugin
|
||||
- fixed --pyargv with python 3.x
|
||||
- improved plugin build system
|
||||
|
||||
*** may 2010 ***
|
||||
|
||||
* 0.9.5.1 [20100519] *
|
||||
|
||||
- fixed paste support
|
||||
- added a new modifier (22)
|
||||
- full support for configuration via environment variables
|
||||
- nginx_string option in nginx module
|
||||
- fix for harakiri without master
|
||||
- backported unladen swallow support for 0.9.6-dev
|
||||
- fixed address space limit detection via getrlimit()
|
||||
- http body buffering implementation
|
||||
- added --prio option (to set priority)
|
||||
- added --post-limit to limit the size of uploads
|
||||
- added --logto option to allow udp logging without daemonizing
|
||||
- applied Gentoo's packagers fixes for build system
|
||||
|
||||
* 0.9.5 [20100501] *
|
||||
|
||||
- hook based request/modifier management
|
||||
@@ -9,7 +184,7 @@
|
||||
- logging via udp
|
||||
- improved spooler for cron-like apps
|
||||
- async support
|
||||
- green thread platform (uGreen) on top of teh async mode
|
||||
- green thread platform (uGreen) on top of the async mode
|
||||
- transparent Erlang integration
|
||||
- embedded snmp agent
|
||||
- nagios mode
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
all:
|
||||
python2.7 uwsgiconfig.py --build
|
||||
@@ -0,0 +1,2 @@
|
||||
all:
|
||||
python3.2 uwsgiconfig.py --build
|
||||
@@ -0,0 +1,2 @@
|
||||
all:
|
||||
python uwsgiconfig.py --build pylua
|
||||
@@ -0,0 +1,923 @@
|
||||
/*
|
||||
|
||||
*** uWSGI/mod_Ruwsgi ***
|
||||
|
||||
Copyright 2009-2010 Roger Florkowski <rflorkowski@mypublisher.com>
|
||||
Copyright 2009-2010 Unbit S.a.s. <info@unbit.it>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#define MOD_UWSGI_VERSION "1.0"
|
||||
|
||||
#include "ap_config.h"
|
||||
#include "apr_version.h"
|
||||
#include "apr_lib.h"
|
||||
#include "apr_strings.h"
|
||||
#include "httpd.h"
|
||||
#include "http_core.h"
|
||||
#include "http_request.h"
|
||||
#include "http_config.h"
|
||||
#include "http_log.h"
|
||||
#include "http_protocol.h"
|
||||
#include "util_script.h"
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/uio.h>
|
||||
#include <time.h>
|
||||
#include <poll.h>
|
||||
|
||||
#define DEFAULT_TIMEOUT 60 /* default socket timeout */
|
||||
#define DEFAULT_CGIMODE 0 /* not enabled */
|
||||
|
||||
#define UNSET 0
|
||||
#define ENABLED 1
|
||||
#define DISABLED 2
|
||||
|
||||
#if APR_MAJOR_VERSION == 0
|
||||
#define apr_socket_send apr_send
|
||||
#define GET_PORT(port, addr) apr_sockaddr_port_get(&(port), addr)
|
||||
#define CREATE_SOCKET(sock, family, pool) \
|
||||
apr_socket_create(sock, family, SOCK_STREAM, pool)
|
||||
#else
|
||||
#define GET_PORT(port, addr) ((port) = (addr)->port)
|
||||
#define CREATE_SOCKET(sock, family, pool) \
|
||||
apr_socket_create(sock, family, SOCK_STREAM, APR_PROTO_TCP, pool)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
char *path;
|
||||
char *addr;
|
||||
apr_port_t port;
|
||||
} mount_entry;
|
||||
|
||||
/*
|
||||
* Configuration record. Used per-directory configuration data.
|
||||
*/
|
||||
typedef struct {
|
||||
mount_entry mount;
|
||||
int enabled; /* mod_uwsgi is enabled from this directory */
|
||||
int timeout;
|
||||
int cgi_mode;
|
||||
uint8_t modifier1;
|
||||
uint8_t modifier2;
|
||||
} uwsgi_cfg;
|
||||
|
||||
/* Server level configuration */
|
||||
typedef struct {
|
||||
apr_array_header_t *mounts;
|
||||
int timeout;
|
||||
int cgi_mode;
|
||||
} uwsgi_server_cfg;
|
||||
|
||||
module AP_MODULE_DECLARE_DATA uwsgi_module;
|
||||
|
||||
/*
|
||||
* Locate our directory configuration record for the current request.
|
||||
*/
|
||||
static uwsgi_cfg *
|
||||
our_dconfig(request_rec *r)
|
||||
{
|
||||
return (uwsgi_cfg *) ap_get_module_config(r->per_dir_config, &uwsgi_module);
|
||||
}
|
||||
|
||||
static uwsgi_server_cfg *our_sconfig(server_rec *s)
|
||||
{
|
||||
return (uwsgi_server_cfg *) ap_get_module_config(s->module_config,
|
||||
&uwsgi_module);
|
||||
}
|
||||
|
||||
static int
|
||||
mount_entry_matches(const char *url, const char *prefix,
|
||||
const char **path_info)
|
||||
{
|
||||
int i;
|
||||
for (i=0; prefix[i] != '\0'; i++) {
|
||||
if (url[i] == '\0' || url[i] != prefix[i])
|
||||
return 0;
|
||||
}
|
||||
if (url[i] == '\0' || url[i] == '/') {
|
||||
*path_info = url + i;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_translate(request_rec *r)
|
||||
{
|
||||
uwsgi_cfg *cfg = our_dconfig(r);
|
||||
|
||||
if (cfg->enabled == DISABLED) {
|
||||
return DECLINED;
|
||||
}
|
||||
|
||||
if (cfg->mount.addr != UNSET) {
|
||||
ap_assert(cfg->mount.port != UNSET);
|
||||
r->handler = "uwsgi-handler";
|
||||
r->filename = r->uri;
|
||||
return OK;
|
||||
}
|
||||
else {
|
||||
int i;
|
||||
uwsgi_server_cfg *scfg = our_sconfig(r->server);
|
||||
mount_entry *entries = (mount_entry *) scfg->mounts->elts;
|
||||
for (i = 0; i < scfg->mounts->nelts; ++i) {
|
||||
const char *path_info;
|
||||
mount_entry *mount = &entries[i];
|
||||
if (mount_entry_matches(r->uri, mount->path, &path_info)) {
|
||||
r->handler = "uwsgi-handler";
|
||||
r->path_info = apr_pstrdup(r->pool, path_info);
|
||||
r->filename = r->uri;
|
||||
ap_set_module_config(r->request_config, &uwsgi_module, mount);
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
return DECLINED;
|
||||
}
|
||||
|
||||
static int uwsgi_map_location(request_rec *r)
|
||||
{
|
||||
if (r->handler && strcmp(r->handler, "uwsgi-handler") == 0) {
|
||||
return OK; /* We don't want directory walk. */
|
||||
}
|
||||
return DECLINED;
|
||||
}
|
||||
|
||||
static void log_err(const char *file, int line, request_rec *r,
|
||||
apr_status_t status, const char *msg)
|
||||
{
|
||||
ap_log_rerror(file, line, APLOG_ERR, status, r, "uwsgi: %s", msg);
|
||||
}
|
||||
|
||||
static void log_debug(const char *file, int line, request_rec *r, const
|
||||
char *msg)
|
||||
{
|
||||
/*
|
||||
ap_log_rerror(file, line, APLOG_DEBUG, APR_SUCCESS, r, msg);
|
||||
ap_log_rerror(file, line, APLOG_WARNING, APR_SUCCESS, r, "uwsgi: %s", msg);
|
||||
*/
|
||||
ap_log_rerror(file, line, APLOG_DEBUG, APR_SUCCESS, r, "uwsgi: %s", msg);
|
||||
}
|
||||
|
||||
/* buffered socket implementation (buckets are overkill) */
|
||||
|
||||
#define BUFFER_SIZE 8000
|
||||
|
||||
struct sockbuff {
|
||||
apr_socket_t *sock;
|
||||
char buf[BUFFER_SIZE];
|
||||
int used;
|
||||
};
|
||||
|
||||
static void binit(struct sockbuff *s, apr_socket_t *sock)
|
||||
{
|
||||
s->sock = sock;
|
||||
s->used = 0;
|
||||
}
|
||||
|
||||
static apr_status_t sendall(apr_socket_t *sock, char *buf, apr_size_t len)
|
||||
{
|
||||
apr_status_t rv;
|
||||
apr_size_t n;
|
||||
while (len > 0) {
|
||||
n = len;
|
||||
if ((rv = apr_socket_send(sock, buf, &n))) return rv;
|
||||
buf += n;
|
||||
len -= n;
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
static apr_status_t bflush(struct sockbuff *s)
|
||||
{
|
||||
apr_status_t rv;
|
||||
ap_assert(s->used >= 0 && s->used <= BUFFER_SIZE);
|
||||
if (s->used) {
|
||||
if ((rv = sendall(s->sock, s->buf, s->used))) return rv;
|
||||
s->used = 0;
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
static apr_status_t bwrite(struct sockbuff *s, char *buf, apr_size_t len)
|
||||
{
|
||||
apr_status_t rv;
|
||||
if (len >= BUFFER_SIZE - s->used) {
|
||||
if ((rv = bflush(s))) return rv;
|
||||
while (len >= BUFFER_SIZE) {
|
||||
if ((rv = sendall(s->sock, buf, BUFFER_SIZE))) return rv;
|
||||
buf += BUFFER_SIZE;
|
||||
len -= BUFFER_SIZE;
|
||||
}
|
||||
}
|
||||
if (len > 0) {
|
||||
ap_assert(len < BUFFER_SIZE - s->used);
|
||||
memcpy(s->buf + s->used, buf, len);
|
||||
s->used += len;
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
static apr_status_t bputs(struct sockbuff *s, char *buf)
|
||||
{
|
||||
return bwrite(s, buf, strlen(buf));
|
||||
}
|
||||
|
||||
static apr_status_t bputc(struct sockbuff *s, char c)
|
||||
{
|
||||
char buf[1];
|
||||
buf[0] = c;
|
||||
return bwrite(s, buf, 1);
|
||||
}
|
||||
|
||||
static apr_status_t bputh(struct sockbuff *s, unsigned short h)
|
||||
{
|
||||
return bwrite(s, (char *)&h, 2);
|
||||
}
|
||||
|
||||
#define CONFIG_VALUE(value, fallback) ((value) != UNSET ? (value) : (fallback))
|
||||
|
||||
static apr_status_t
|
||||
open_socket(apr_socket_t **sock, request_rec *r)
|
||||
{
|
||||
int timeout;
|
||||
int retries = 4;
|
||||
int sleeptime = 1;
|
||||
apr_status_t rv;
|
||||
apr_sockaddr_t *sockaddr;
|
||||
uwsgi_server_cfg *scfg = our_sconfig(r->server);
|
||||
uwsgi_cfg *cfg = our_dconfig(r);
|
||||
mount_entry *m = (mount_entry *) ap_get_module_config(r->request_config,
|
||||
&uwsgi_module);
|
||||
if (!m) {
|
||||
m = &cfg->mount;
|
||||
}
|
||||
|
||||
timeout = CONFIG_VALUE(cfg->timeout, CONFIG_VALUE(scfg->timeout,
|
||||
DEFAULT_TIMEOUT));
|
||||
rv = apr_sockaddr_info_get(&sockaddr,
|
||||
CONFIG_VALUE(m->addr, "localhost"),
|
||||
APR_UNSPEC,
|
||||
CONFIG_VALUE(m->port, 5000),
|
||||
0,
|
||||
r->pool);
|
||||
if (rv) {
|
||||
log_err(APLOG_MARK, r, rv, "apr_sockaddr_info_get() error");
|
||||
return rv;
|
||||
}
|
||||
|
||||
restart:
|
||||
*sock = NULL;
|
||||
rv = CREATE_SOCKET(sock, sockaddr->family, r->pool);
|
||||
if (rv) {
|
||||
log_err(APLOG_MARK, r, rv, "apr_socket_create() error");
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = apr_socket_timeout_set(*sock, apr_time_from_sec(timeout));
|
||||
if (rv) {
|
||||
log_err(APLOG_MARK, r, rv, "apr_socket_timeout_set() error");
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = apr_socket_connect(*sock, sockaddr);
|
||||
if (rv) {
|
||||
apr_socket_close(*sock);
|
||||
if ((APR_STATUS_IS_ECONNREFUSED(rv) |
|
||||
APR_STATUS_IS_EINPROGRESS(rv)) && retries > 0) {
|
||||
/* server may be temporarily down, retry */
|
||||
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, rv, r,
|
||||
"uwsgi: connection failed, retrying");
|
||||
apr_sleep(apr_time_from_sec(sleeptime));
|
||||
--retries;
|
||||
sleeptime *= 2;
|
||||
goto restart;
|
||||
}
|
||||
log_err(APLOG_MARK, r, rv, "uwsgi: can't connect to server");
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef APR_TCP_NODELAY
|
||||
/* disable Nagle, we don't send small packets */
|
||||
apr_socket_opt_set(*sock, APR_TCP_NODELAY, 1);
|
||||
#endif
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
/* This code is a duplicate of what's in util_script.c. We can't use
|
||||
* r->unparsed_uri because it gets changed if there was a redirect. */
|
||||
static char *original_uri(request_rec *r)
|
||||
{
|
||||
char *first, *last;
|
||||
|
||||
if (r->the_request == NULL) {
|
||||
return (char *) apr_pcalloc(r->pool, 1);
|
||||
}
|
||||
|
||||
first = r->the_request; /* use the request-line */
|
||||
|
||||
while (*first && !apr_isspace(*first)) {
|
||||
++first; /* skip over the method */
|
||||
}
|
||||
while (apr_isspace(*first)) {
|
||||
++first; /* and the space(s) */
|
||||
}
|
||||
|
||||
last = first;
|
||||
while (*last && !apr_isspace(*last)) {
|
||||
++last; /* end at next whitespace */
|
||||
}
|
||||
|
||||
return apr_pstrmemdup(r->pool, first, last - first);
|
||||
}
|
||||
|
||||
static char *lookup_name(apr_table_t *t, const char *name)
|
||||
{
|
||||
const apr_array_header_t *hdrs_arr = apr_table_elts(t);
|
||||
apr_table_entry_t *hdrs = (apr_table_entry_t *) hdrs_arr->elts;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < hdrs_arr->nelts; ++i) {
|
||||
if (hdrs[i].key == NULL)
|
||||
continue;
|
||||
|
||||
if (strcasecmp(hdrs[i].key, name) == 0)
|
||||
return hdrs[i].val;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *lookup_header(request_rec *r, const char *name)
|
||||
{
|
||||
return lookup_name(r->headers_in, name);
|
||||
}
|
||||
|
||||
static void add_header(apr_table_t *t, const char *name, const char *value)
|
||||
{
|
||||
if (name != NULL && value != NULL)
|
||||
apr_table_addn(t, name, value);
|
||||
}
|
||||
|
||||
static int find_path_info(const char *uri, const char *path_info)
|
||||
{
|
||||
int n;
|
||||
n = strlen(uri) - strlen(path_info);
|
||||
ap_assert(n >= 0);
|
||||
return n;
|
||||
}
|
||||
|
||||
static char *http2env(apr_pool_t *p, const char *name)
|
||||
{
|
||||
char *env_name = apr_pstrcat(p, "HTTP_", name, NULL);
|
||||
char *cp;
|
||||
|
||||
for (cp = env_name + 5; *cp != 0; cp++) {
|
||||
if (*cp == '-') {
|
||||
*cp = '_';
|
||||
}
|
||||
else {
|
||||
*cp = apr_toupper(*cp);
|
||||
}
|
||||
}
|
||||
|
||||
return env_name;
|
||||
}
|
||||
|
||||
static apr_status_t
|
||||
send_headers(request_rec *r, struct sockbuff *s)
|
||||
{
|
||||
int i;
|
||||
const apr_array_header_t *hdrs_arr, *env_arr;
|
||||
apr_table_entry_t *hdrs, *env;
|
||||
char *buf;
|
||||
unsigned short int n = 0;
|
||||
apr_table_t *t;
|
||||
apr_status_t rv = 0;
|
||||
apr_port_t port = 0;
|
||||
GET_PORT(port, r->connection->remote_addr);
|
||||
uwsgi_cfg *cfg = our_dconfig(r);
|
||||
|
||||
log_debug(APLOG_MARK,r, "sending headers");
|
||||
t = apr_table_make(r->pool, 40);
|
||||
if (!t)
|
||||
return APR_ENOMEM;
|
||||
|
||||
/* headers to send */
|
||||
|
||||
/* CONTENT_LENGTH must come first and always be present */
|
||||
buf = lookup_header(r, "Content-Length");
|
||||
if (buf == NULL)
|
||||
buf = "0";
|
||||
add_header(t, "CONTENT_LENGTH", buf);
|
||||
|
||||
add_header(t, "REQUEST_METHOD", (char *) r->method);
|
||||
add_header(t, "QUERY_STRING", r->args ? r->args : "");
|
||||
add_header(t, "SERVER_SOFTWARE", ap_get_server_version());
|
||||
add_header(t, "SERVER_ADMIN", r->server->server_admin);
|
||||
add_header(t, "SERVER_NAME", (char *) ap_get_server_name(r));
|
||||
add_header(t, "SERVER_PORT", apr_psprintf(r->pool, "%u",ap_get_server_port(r)));
|
||||
add_header(t, "SERVER_ADDR", r->connection->local_ip);
|
||||
add_header(t, "SERVER_PROTOCOL", r->protocol);
|
||||
|
||||
add_header(t, "REQUEST_URI", original_uri(r));
|
||||
add_header(t, "REMOTE_ADDR", r->connection->remote_ip);
|
||||
add_header(t, "REMOTE_PORT", apr_psprintf(r->pool, "%d", port));
|
||||
add_header(t, "REMOTE_USER", r->user);
|
||||
add_header(t, "DOCUMENT_ROOT", (char *) ap_document_root(r));
|
||||
|
||||
if (r->path_info) {
|
||||
int path_info_start = find_path_info(r->uri, r->path_info);
|
||||
add_header(t, "SCRIPT_NAME", apr_pstrndup(r->pool, r->uri,
|
||||
path_info_start));
|
||||
add_header(t, "PATH_INFO", r->path_info);
|
||||
}
|
||||
else {
|
||||
/* skip PATH_INFO, don't know it */
|
||||
add_header(t, "SCRIPT_NAME", r->uri);
|
||||
}
|
||||
|
||||
add_header(t, "CONTENT_TYPE", lookup_header(r, "Content-type"));
|
||||
|
||||
/* HTTP headers */
|
||||
hdrs_arr = apr_table_elts(r->headers_in);
|
||||
hdrs = (apr_table_entry_t *) hdrs_arr->elts;
|
||||
for (i = 0; i < hdrs_arr->nelts; ++i) {
|
||||
if (hdrs[i].key) {
|
||||
add_header(t, http2env(r->pool, hdrs[i].key), hdrs[i].val);
|
||||
}
|
||||
}
|
||||
|
||||
/* environment variables */
|
||||
env_arr = apr_table_elts(r->subprocess_env);
|
||||
env = (apr_table_entry_t*) env_arr->elts;
|
||||
for (i = 0; i < env_arr->nelts; ++i) {
|
||||
add_header(t, env[i].key, env[i].val);
|
||||
}
|
||||
|
||||
hdrs_arr = apr_table_elts(t);
|
||||
hdrs = (apr_table_entry_t*) hdrs_arr->elts;
|
||||
|
||||
/* calculate length of header data */
|
||||
for (i = 0; i < hdrs_arr->nelts; ++i) {
|
||||
n += strlen(hdrs[i].key);
|
||||
n += strlen(hdrs[i].val);
|
||||
n += 4; /* XXX */
|
||||
}
|
||||
log_debug(APLOG_MARK,r, apr_psprintf(r->pool, "pktheader size is %u", n));
|
||||
log_debug(APLOG_MARK,r, apr_psprintf(r->pool, "num headers %u", hdrs_arr->nelts));
|
||||
|
||||
/* write pkt header */
|
||||
rv = bputc(s, cfg->modifier1); /* marker */
|
||||
if (rv) return rv;
|
||||
rv = bputh(s, n); /* length of header data */
|
||||
if (rv) return rv;
|
||||
rv = bputc(s, cfg->modifier2); /* marker */
|
||||
if (rv) return rv;
|
||||
|
||||
/* write out headers */
|
||||
for (i = 0; i < hdrs_arr->nelts; ++i) {
|
||||
rv = bputh(s, strlen(hdrs[i].key)); /* length */
|
||||
if (rv) return rv;
|
||||
rv = bputs(s, hdrs[i].key); /* key */
|
||||
if (rv) return rv;
|
||||
rv = bputh(s, strlen(hdrs[i].val)); /* length */
|
||||
if (rv) return rv;
|
||||
rv = bputs(s, hdrs[i].val); /* data */
|
||||
if (rv) return rv;
|
||||
}
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
static apr_status_t send_request_body(request_rec *r, struct sockbuff *s)
|
||||
{
|
||||
if (ap_should_client_block(r)) {
|
||||
char buf[BUFFER_SIZE];
|
||||
apr_status_t rv;
|
||||
apr_off_t len;
|
||||
|
||||
while ((len = ap_get_client_block(r, buf, sizeof buf)) > 0) {
|
||||
if ((rv = bwrite(s, buf, len))) return rv;
|
||||
}
|
||||
if (len == -1)
|
||||
return HTTP_INTERNAL_SERVER_ERROR; /* what to return? */
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
static int uwsgi_handler(request_rec *r)
|
||||
{
|
||||
apr_status_t rv = 0;
|
||||
int cgi_mode, http_status = 0;
|
||||
struct sockbuff s;
|
||||
apr_socket_t *sock;
|
||||
apr_bucket_brigade *bb = NULL;
|
||||
apr_bucket *b = NULL;
|
||||
const char *location;
|
||||
uwsgi_cfg *cfg = our_dconfig(r);
|
||||
uwsgi_server_cfg *scfg = our_sconfig(r->server);
|
||||
|
||||
if (strcmp(r->handler, "uwsgi-handler"))
|
||||
return DECLINED;
|
||||
|
||||
http_status = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR);
|
||||
if (http_status != OK)
|
||||
return http_status;
|
||||
|
||||
log_debug(APLOG_MARK, r, "connecting to server");
|
||||
|
||||
rv = open_socket(&sock, r);
|
||||
if (rv) {
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
binit(&s, sock);
|
||||
|
||||
rv = send_headers(r, &s);
|
||||
if (rv) {
|
||||
log_err(APLOG_MARK, r, rv, "error sending request headers");
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
rv = send_request_body(r, &s);
|
||||
if (rv) {
|
||||
log_err(APLOG_MARK, r, rv, "error sending request body");
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
rv = bflush(&s);
|
||||
if (rv) {
|
||||
log_err(APLOG_MARK, r, rv, "error sending request");
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
|
||||
log_debug(APLOG_MARK, r, "reading response headers");
|
||||
bb = apr_brigade_create(r->connection->pool, r->connection->bucket_alloc);
|
||||
|
||||
cgi_mode = CONFIG_VALUE(cfg->cgi_mode, CONFIG_VALUE(scfg->cgi_mode, DEFAULT_CGIMODE));
|
||||
if (!cgi_mode) {
|
||||
|
||||
/* receive implemented with http-0.9 based protocol */
|
||||
apr_interval_time_t timeout;
|
||||
char buf[4096];
|
||||
apr_pollfd_t pollfd = {r->pool, APR_POLL_SOCKET, APR_POLLIN, 0, { NULL }, NULL };
|
||||
pollfd.desc.s = sock;
|
||||
timeout = CONFIG_VALUE(cfg->timeout, CONFIG_VALUE(scfg->timeout,
|
||||
DEFAULT_TIMEOUT)) * 1000 * 1000;
|
||||
r->assbackwards = 1; /* XXX */
|
||||
|
||||
for(;;) {
|
||||
apr_int32_t nsds;
|
||||
apr_size_t len;
|
||||
|
||||
if ((rv = apr_poll(&pollfd, 1, &nsds, timeout)) == APR_TIMEUP) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: recv() timeout");
|
||||
break;
|
||||
}
|
||||
if (rv != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: poll() %s", strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
len = 4096;
|
||||
rv = apr_socket_recv(sock, buf, &len);
|
||||
if (rv == APR_SUCCESS) {
|
||||
apr_brigade_write(bb, NULL, NULL, buf, len);
|
||||
}
|
||||
else if (rv == APR_EOF) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: recv() %s", strerror(errno));
|
||||
}
|
||||
|
||||
}
|
||||
log_debug(APLOG_MARK,r, "recv finished");
|
||||
b = apr_bucket_flush_create(r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||
b = apr_bucket_eos_create(r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||
|
||||
} else {
|
||||
|
||||
/* receive implemented with http-1.x based protocol */
|
||||
b = apr_bucket_socket_create(sock, r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||
b = apr_bucket_eos_create(r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||
|
||||
rv = ap_scan_script_header_err_brigade(r, bb, NULL);
|
||||
if (rv) {
|
||||
if (rv == HTTP_INTERNAL_SERVER_ERROR) {
|
||||
log_err(APLOG_MARK, r, rv, "error reading response headers");
|
||||
}
|
||||
else {
|
||||
/* Work around an Apache bug whereby the returned status is
|
||||
* ignored and status_line is used instead. This bug is
|
||||
* present at least in 2.0.54.
|
||||
*/
|
||||
r->status_line = NULL;
|
||||
}
|
||||
apr_brigade_destroy(bb);
|
||||
return rv;
|
||||
}
|
||||
|
||||
location = apr_table_get(r->headers_out, "Location");
|
||||
|
||||
if (location && location[0] == '/' &&
|
||||
((r->status == HTTP_OK) || ap_is_HTTP_REDIRECT(r->status))) {
|
||||
|
||||
apr_brigade_destroy(bb);
|
||||
|
||||
/* Internal redirect -- fake-up a pseudo-request */
|
||||
r->status = HTTP_OK;
|
||||
|
||||
/* This redirect needs to be a GET no matter what the original
|
||||
* method was.
|
||||
*/
|
||||
r->method = apr_pstrdup(r->pool, "GET");
|
||||
r->method_number = M_GET;
|
||||
|
||||
ap_internal_redirect_handler(location, r);
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
rv = ap_pass_brigade(r->output_filters, bb);
|
||||
if (rv) {
|
||||
log_err(APLOG_MARK, r, rv, "ap_pass_brigade()");
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
|
||||
server_rec *base_server)
|
||||
{
|
||||
ap_add_version_component(p, "mod_uwsgi/" MOD_UWSGI_VERSION);
|
||||
return OK;
|
||||
}
|
||||
|
||||
static void *
|
||||
uwsgi_create_dir_config(apr_pool_t *p, char *dirspec)
|
||||
{
|
||||
uwsgi_cfg *cfg = apr_pcalloc(p, sizeof(uwsgi_cfg));
|
||||
|
||||
cfg->enabled = UNSET;
|
||||
cfg->mount.addr = UNSET;
|
||||
cfg->mount.port = UNSET;
|
||||
cfg->timeout = UNSET;
|
||||
cfg->cgi_mode = UNSET;
|
||||
cfg->modifier1 = UNSET;
|
||||
cfg->modifier2 = UNSET;
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
#define MERGE(b, n, a) (n->a == UNSET ? b->a : n->a)
|
||||
|
||||
static void *
|
||||
uwsgi_merge_dir_config(apr_pool_t *p, void *basev, void *newv)
|
||||
{
|
||||
uwsgi_cfg* cfg = apr_pcalloc(p, sizeof(uwsgi_cfg));
|
||||
uwsgi_cfg* base = basev;
|
||||
uwsgi_cfg* new = newv;
|
||||
|
||||
cfg->enabled = MERGE(base, new, enabled);
|
||||
cfg->mount.addr = MERGE(base, new, mount.addr);
|
||||
cfg->mount.port = MERGE(base, new, mount.port);
|
||||
cfg->timeout = MERGE(base, new, timeout);
|
||||
cfg->cgi_mode = MERGE(base, new, cgi_mode);
|
||||
cfg->modifier1 = MERGE(base, new, modifier1);
|
||||
cfg->modifier2 = MERGE(base, new, modifier2);
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
static void *
|
||||
uwsgi_create_server_config(apr_pool_t *p, server_rec *s)
|
||||
{
|
||||
uwsgi_server_cfg *c =
|
||||
(uwsgi_server_cfg *) apr_pcalloc(p, sizeof(uwsgi_server_cfg));
|
||||
|
||||
c->mounts = apr_array_make(p, 20, sizeof(mount_entry));
|
||||
c->timeout = UNSET;
|
||||
c->cgi_mode = UNSET;
|
||||
return c;
|
||||
}
|
||||
|
||||
static void *
|
||||
uwsgi_merge_server_config(apr_pool_t *p, void *basev, void *overridesv)
|
||||
{
|
||||
uwsgi_server_cfg *c = (uwsgi_server_cfg *)
|
||||
apr_pcalloc(p, sizeof(uwsgi_server_cfg));
|
||||
uwsgi_server_cfg *base = (uwsgi_server_cfg *) basev;
|
||||
uwsgi_server_cfg *overrides = (uwsgi_server_cfg *) overridesv;
|
||||
|
||||
c->mounts = apr_array_append(p, overrides->mounts, base->mounts);
|
||||
c->timeout = MERGE(base, overrides, timeout);
|
||||
c->cgi_mode = MERGE(base, overrides, cgi_mode);
|
||||
return c;
|
||||
}
|
||||
|
||||
static const char *
|
||||
cmd_uwsgi_mount(cmd_parms *cmd, void *dummy, const char *path, const char *addr)
|
||||
{
|
||||
int n;
|
||||
apr_status_t rv;
|
||||
char *scope_id = NULL; /* A ip6 parameter - not used here. */
|
||||
uwsgi_server_cfg *scfg = our_sconfig(cmd->server);
|
||||
mount_entry *new = apr_array_push(scfg->mounts);
|
||||
n = strlen(path);
|
||||
while (n > 0 && path[n-1] == '/') {
|
||||
n--; /* strip trailing slashes */
|
||||
}
|
||||
new->path = apr_pstrndup(cmd->pool, path, n);
|
||||
rv = apr_parse_addr_port(&new->addr, &scope_id, &new->port, addr,
|
||||
cmd->pool);
|
||||
if (rv)
|
||||
return "error parsing address:port string";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
cmd_uwsgi_server(cmd_parms *cmd, void *pcfg, const char *addr_and_port)
|
||||
{
|
||||
apr_status_t rv;
|
||||
uwsgi_cfg *cfg = pcfg;
|
||||
char *scope_id = NULL; /* A ip6 parameter - not used here. */
|
||||
|
||||
if (cmd->path == NULL)
|
||||
return "not a server command";
|
||||
|
||||
rv = apr_parse_addr_port(&cfg->mount.addr, &scope_id, &cfg->mount.port,
|
||||
addr_and_port, cmd->pool);
|
||||
if (rv)
|
||||
return "error parsing address:port string";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
cmd_uwsgi_handler(cmd_parms* cmd, void* pcfg, int flag)
|
||||
{
|
||||
uwsgi_cfg *cfg = pcfg;
|
||||
|
||||
if (cmd->path == NULL) /* server command */
|
||||
return "not a server command";
|
||||
|
||||
if (flag)
|
||||
cfg->enabled = ENABLED;
|
||||
else
|
||||
cfg->enabled = DISABLED;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
cmd_uwsgi_timeout(cmd_parms *cmd, void* pcfg, const char *strtimeout)
|
||||
{
|
||||
uwsgi_cfg *dcfg = pcfg;
|
||||
int timeout = atoi(strtimeout);
|
||||
|
||||
if (cmd->path == NULL) {
|
||||
uwsgi_server_cfg *scfg = our_sconfig(cmd->server);
|
||||
scfg->timeout = timeout;
|
||||
}
|
||||
else {
|
||||
dcfg->timeout = timeout;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
cmd_uwsgi_force_cgi_mode(cmd_parms *cmd, void *pcfg, const char *value)
|
||||
{
|
||||
int cgi_mode;
|
||||
|
||||
if (!strcmp("yes", value) || !strcmp("on", value) || !strcmp("enable", value) || !strcmp("1", value)) {
|
||||
cgi_mode = 1;
|
||||
}
|
||||
else {
|
||||
cgi_mode = 0;
|
||||
}
|
||||
|
||||
if (cmd->path == NULL) {
|
||||
uwsgi_server_cfg *scfg = our_sconfig(cmd->server);
|
||||
scfg->cgi_mode = cgi_mode;
|
||||
}
|
||||
else {
|
||||
uwsgi_cfg *dcfg = pcfg;
|
||||
dcfg->cgi_mode = cgi_mode;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
cmd_uwsgi_modifier1(cmd_parms *cmd, void *pcfg, const char *value)
|
||||
{
|
||||
uwsgi_cfg *cfg = pcfg;
|
||||
int val;
|
||||
|
||||
if (cmd->path == NULL) /* server command */
|
||||
return "not a server command";
|
||||
|
||||
val = atoi(value);
|
||||
if (val < 0 || val > 255) {
|
||||
return "ignored uWSGImodifier1. Value must be between 0 and 255";
|
||||
}
|
||||
else {
|
||||
cfg->modifier1 = (uint8_t) val;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
cmd_uwsgi_modifier2(cmd_parms *cmd, void *pcfg, const char *value)
|
||||
{
|
||||
uwsgi_cfg *cfg = pcfg;
|
||||
int val;
|
||||
|
||||
if (cmd->path == NULL) /* server command */
|
||||
return "not a server command";
|
||||
|
||||
val = atoi(value);
|
||||
if (val < 0 || val > 255) {
|
||||
return "ignored uWSGImodifier2. Value must be between 0 and 255";
|
||||
}
|
||||
else {
|
||||
cfg->modifier2 = (uint8_t) val;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const command_rec uwsgi_cmds[] = {
|
||||
AP_INIT_TAKE2("uWSGImount", cmd_uwsgi_mount, NULL, RSRC_CONF,
|
||||
"path prefix and address of UWSGI server"),
|
||||
AP_INIT_TAKE1("uWSGIserver", cmd_uwsgi_server, NULL, ACCESS_CONF,
|
||||
"Address and port of an UWSGI server (e.g. localhost:4000)"),
|
||||
AP_INIT_FLAG( "uWSGIhandler", cmd_uwsgi_handler, NULL, ACCESS_CONF,
|
||||
"On or Off to enable or disable the UWSGI handler"),
|
||||
AP_INIT_TAKE1("uWSGIserverTimeout", cmd_uwsgi_timeout, NULL, ACCESS_CONF|RSRC_CONF,
|
||||
"Timeout (in seconds) for communication with the UWSGI server."),
|
||||
AP_INIT_TAKE1("uWSGIforceCGImode", cmd_uwsgi_force_cgi_mode, NULL, ACCESS_CONF|RSRC_CONF,
|
||||
"Force uWSGI CGI mode for perfect integration with apache filter"),
|
||||
AP_INIT_TAKE1("uWSGImodifier1", cmd_uwsgi_modifier1, NULL, ACCESS_CONF,
|
||||
"Set uWSGI modifier1"),
|
||||
AP_INIT_TAKE1("uWSGImodifier2", cmd_uwsgi_modifier2, NULL, ACCESS_CONF,
|
||||
"Set uWSGI modifier2"),
|
||||
/*
|
||||
AP_INIT_TAKE12("uWSGIsocket", cmd_uwsgi_socket, NULL, RSRC_CONF|ACCESS_CONF,
|
||||
"Absolute path and optional timeout in seconds of uwsgi server socket"),
|
||||
AP_INIT_TAKE1("uWSGIsocket2", cmd_uwsgi_socket2, NULL, RSRC_CONF|ACCESS_CONF,
|
||||
"Absolute path of failover uwsgi server socket"),
|
||||
AP_INIT_TAKE1("uWSGIforceScriptName", cmd_uwsgi_force_script_name, NULL, ACCESS_CONF,
|
||||
"Fix for PATH_INFO/SCRIPT_NAME when the location has filesystem correspondence"),
|
||||
*/
|
||||
{NULL}
|
||||
};
|
||||
|
||||
static void uwsgi_register_hooks(apr_pool_t *p)
|
||||
{
|
||||
ap_hook_post_config(uwsgi_init, NULL, NULL, APR_HOOK_MIDDLE);
|
||||
ap_hook_handler(uwsgi_handler, NULL, NULL, APR_HOOK_MIDDLE);
|
||||
ap_hook_translate_name(uwsgi_translate, NULL, NULL, APR_HOOK_LAST);
|
||||
ap_hook_map_to_storage(uwsgi_map_location, NULL, NULL, APR_HOOK_FIRST);
|
||||
}
|
||||
|
||||
/* Dispatch list for API hooks */
|
||||
module AP_MODULE_DECLARE_DATA uwsgi_module = {
|
||||
STANDARD20_MODULE_STUFF,
|
||||
uwsgi_create_dir_config, /* create per-dir config structs */
|
||||
uwsgi_merge_dir_config, /* merge per-dir config structs */
|
||||
uwsgi_create_server_config, /* create per-server config structs */
|
||||
uwsgi_merge_server_config, /* merge per-server config structs */
|
||||
uwsgi_cmds, /* table of config file commands */
|
||||
uwsgi_register_hooks, /* register hooks */
|
||||
};
|
||||
|
||||
+61
-37
@@ -1,18 +1,18 @@
|
||||
/*
|
||||
|
||||
*** uWSGI/mod_uwsgi ***
|
||||
*** uWSGI/mod_uwsgi ***
|
||||
|
||||
Copyright 2009 Unbit S.a.s. <info@unbit.it>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
Copyright 2009-2010 Unbit S.a.s. <info@unbit.it>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
@@ -264,7 +264,6 @@ static int uwsgi_handler(request_rec *r) {
|
||||
char uwsgi_http_status[13] ;
|
||||
int uwsgi_http_status_read = 0;
|
||||
|
||||
|
||||
apr_bucket_brigade *bb;
|
||||
|
||||
if (strcmp(r->handler, "uwsgi-handler"))
|
||||
@@ -287,7 +286,6 @@ static int uwsgi_handler(request_rec *r) {
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
|
||||
if ( (ret = timed_connect(&uwsgi_poll, (struct sockaddr *) &c->s_addr, c->addr_size, c->socket_timeout, r) ) != 0) {
|
||||
|
||||
close(uwsgi_poll.fd);
|
||||
@@ -323,7 +321,7 @@ static int uwsgi_handler(request_rec *r) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "SERVER_NAME", (char *) ap_get_server_name(r), &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "SERVER_PORT", apr_psprintf(r->pool, "%u",ap_get_server_port(r)), &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "SERVER_PROTOCOL", r->protocol, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "REQUEST_URI", r->uri, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "REQUEST_URI", r->unparsed_uri, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "REMOTE_ADDR", r->connection->remote_ip, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "REMOTE_USER", r->user ? r->user : "", &pkt_size) ;
|
||||
if (r->user) {
|
||||
@@ -394,6 +392,13 @@ static int uwsgi_handler(request_rec *r) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* environment variables */
|
||||
headers = apr_table_elts(r->subprocess_env);
|
||||
h = (apr_table_entry_t*) headers->elts;
|
||||
for (i = 0; i < headers->nelts; ++i) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, h[i].key, h[i].val, &pkt_size) ;
|
||||
}
|
||||
|
||||
|
||||
uwsgi_vars[0].iov_base = pkt_header;
|
||||
@@ -456,33 +461,52 @@ static int uwsgi_handler(request_rec *r) {
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
else if (cnt > 0) {
|
||||
cnt = recv(uwsgi_poll.fd, buf, 4096, 0) ;
|
||||
if (cnt < 0) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: recv() %s", strerror(errno));
|
||||
apr_brigade_destroy(bb);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
else if (cnt > 0) {
|
||||
if (!c->cgi_mode && uwsgi_http_status_read < 12) {
|
||||
if (uwsgi_http_status_read + cnt >= 12) {
|
||||
memcpy(uwsgi_http_status+uwsgi_http_status_read, buf, 12-uwsgi_http_status_read);
|
||||
r->status = atoi(uwsgi_http_status+8);
|
||||
uwsgi_http_status_read+=cnt;
|
||||
}
|
||||
else {
|
||||
memcpy(uwsgi_http_status+uwsgi_http_status_read, buf, cnt);
|
||||
uwsgi_http_status_read+=cnt;
|
||||
}
|
||||
}
|
||||
apr_brigade_write(bb, NULL, NULL, buf, cnt);
|
||||
|
||||
}
|
||||
else {
|
||||
break;
|
||||
if (uwsgi_poll.revents & POLLIN || uwsgi_poll.revents & POLLHUP) {
|
||||
cnt = recv(uwsgi_poll.fd, buf, 4096, 0) ;
|
||||
if (cnt < 0) {
|
||||
if (errno != ECONNRESET) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: recv() %s", strerror(errno));
|
||||
apr_brigade_destroy(bb);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (cnt > 0) {
|
||||
if (!c->cgi_mode && uwsgi_http_status_read < 12) {
|
||||
if (uwsgi_http_status_read + cnt >= 12) {
|
||||
memcpy(uwsgi_http_status+uwsgi_http_status_read, buf, 12-uwsgi_http_status_read);
|
||||
r->status = atoi(uwsgi_http_status+8);
|
||||
uwsgi_http_status_read+=cnt;
|
||||
}
|
||||
else {
|
||||
memcpy(uwsgi_http_status+uwsgi_http_status_read, buf, cnt);
|
||||
uwsgi_http_status_read+=cnt;
|
||||
}
|
||||
}
|
||||
// check for client disconnect
|
||||
if (r->connection->aborted) {
|
||||
close(uwsgi_poll.fd);
|
||||
apr_brigade_destroy(bb);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
apr_brigade_write(bb, NULL, NULL, buf, cnt);
|
||||
}
|
||||
else {
|
||||
// EOF
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// error
|
||||
if (uwsgi_poll.revents & POLLERR || uwsgi_poll.revents & POLLNVAL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: poll() %s", strerror(errno));
|
||||
close(uwsgi_poll.fd);
|
||||
apr_brigade_destroy(bb);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
@@ -1,292 +1,22 @@
|
||||
#ifdef UWSGI_ASYNC
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#ifdef __linux__
|
||||
int async_get_timeout() {
|
||||
|
||||
#include <sys/epoll.h>
|
||||
|
||||
int async_queue_init(int serverfd) {
|
||||
int epfd ;
|
||||
struct epoll_event ee;
|
||||
|
||||
epfd = epoll_create(256);
|
||||
|
||||
if (epfd < 0) {
|
||||
uwsgi_error("epoll_create()");
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
memset(&ee, 0, sizeof(struct epoll_event));
|
||||
ee.events = EPOLLIN;
|
||||
ee.data.fd = serverfd;
|
||||
|
||||
if (epoll_ctl(epfd, EPOLL_CTL_ADD, serverfd, &ee)) {
|
||||
uwsgi_error("epoll_ctl()");
|
||||
close(epfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return epfd;
|
||||
}
|
||||
|
||||
int async_wait(int queuefd, void *events, int nevents, int block, int timeout) {
|
||||
|
||||
int ret ;
|
||||
|
||||
if (timeout <= 0) {
|
||||
timeout = block;
|
||||
}
|
||||
else {
|
||||
timeout = timeout*1000;
|
||||
}
|
||||
|
||||
//uwsgi_log("waiting with timeout %d nevents %d\n", timeout, nevents);
|
||||
ret = epoll_wait(queuefd, (struct epoll_event *) events, nevents, timeout);
|
||||
if (ret < 0) {
|
||||
uwsgi_error("epoll_wait()");
|
||||
}
|
||||
return ret ;
|
||||
}
|
||||
|
||||
int async_add(int queuefd, int fd, int etype) {
|
||||
struct epoll_event ee;
|
||||
|
||||
memset(&ee, 0, sizeof(struct epoll_event));
|
||||
ee.events = etype;
|
||||
ee.data.fd = fd;
|
||||
|
||||
if (epoll_ctl(queuefd, EPOLL_CTL_ADD, fd, &ee)) {
|
||||
uwsgi_error("epoll_ctl()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int async_mod(int queuefd, int fd, int etype) {
|
||||
struct epoll_event ee;
|
||||
|
||||
memset(&ee, 0, sizeof(struct epoll_event));
|
||||
ee.events = etype;
|
||||
ee.data.fd = fd;
|
||||
|
||||
if (epoll_ctl(queuefd, EPOLL_CTL_MOD, fd, &ee)) {
|
||||
uwsgi_error("epoll_ctl()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int async_del(int queuefd, int fd, int etype) {
|
||||
struct epoll_event ee;
|
||||
|
||||
memset(&ee, 0, sizeof(struct epoll_event));
|
||||
ee.events = etype;
|
||||
ee.data.fd = fd;
|
||||
|
||||
if (epoll_ctl(queuefd, EPOLL_CTL_DEL, fd, &ee)) {
|
||||
uwsgi_error("epoll_ctl()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(__sun__)
|
||||
|
||||
int async_queue_init(int serverfd) {
|
||||
int dpfd ;
|
||||
struct pollfd dpev;
|
||||
|
||||
|
||||
dpfd = open("/dev/poll", O_RDWR);
|
||||
|
||||
if (dpfd < 0) {
|
||||
uwsgi_error("open()");
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
|
||||
dpev.fd = serverfd;
|
||||
dpev.events = POLLIN ;
|
||||
dpev.revents = 0;
|
||||
|
||||
if (write(dpfd, &dpev, sizeof(struct pollfd)) < 0) {
|
||||
uwsgi_error("write()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
return dpfd;
|
||||
}
|
||||
|
||||
int async_wait(int queuefd, void *events, int nevents, int block, int timeout) {
|
||||
|
||||
int ret ;
|
||||
struct dvpoll dv ;
|
||||
|
||||
if (timeout <= 0) {
|
||||
timeout = block;
|
||||
}
|
||||
else {
|
||||
timeout = timeout*1000;
|
||||
}
|
||||
|
||||
dv.dp_fds = (struct pollfd *) events;
|
||||
dv.dp_nfds = nevents;
|
||||
dv.dp_timeout = timeout;
|
||||
|
||||
//uwsgi_log("waiting with timeout %d nevents %d\n", timeout, nevents);
|
||||
ret = ioctl(queuefd, DP_POLL, &dv);
|
||||
if (ret < 0) {
|
||||
uwsgi_error("ioctl()");
|
||||
}
|
||||
return ret ;
|
||||
}
|
||||
|
||||
int async_add(int queuefd, int fd, int etype) {
|
||||
struct pollfd pl;
|
||||
|
||||
pl.fd = fd ;
|
||||
pl.events = etype ;
|
||||
pl.revents = 0 ;
|
||||
|
||||
if (write(queuefd, &pl, sizeof(struct pollfd)) < 0) {
|
||||
uwsgi_error("write()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int async_mod(int queuefd, int fd, int etype) {
|
||||
// using the same fd will overwrite existing rule
|
||||
return async_add(queuefd, fd, etype);
|
||||
}
|
||||
|
||||
int async_del(int queuefd, int fd, int etype) {
|
||||
// use POLLREMOVE to remove an fd
|
||||
return async_add(queuefd, fd, POLLREMOVE);
|
||||
}
|
||||
|
||||
#else
|
||||
int async_queue_init(int serverfd) {
|
||||
int kfd ;
|
||||
struct kevent kev;
|
||||
|
||||
kfd = kqueue();
|
||||
|
||||
if (kfd < 0) {
|
||||
uwsgi_error("kqueue()");
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
EV_SET(&kev, serverfd, EVFILT_READ, EV_ADD, 0, 0, 0);
|
||||
if (kevent(kfd, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return kfd;
|
||||
}
|
||||
|
||||
int async_wait(int queuefd, void *events, int nevents, int block, int timeout) {
|
||||
|
||||
int ret;
|
||||
struct timespec ts ;
|
||||
|
||||
|
||||
if (timeout <= 0) {
|
||||
if (!block) {
|
||||
memset(&ts, 0, sizeof(struct timespec));
|
||||
ts.tv_sec = timeout ;
|
||||
ret = kevent(queuefd, NULL, 0, events, nevents, &ts);
|
||||
}
|
||||
else {
|
||||
ret = kevent(queuefd, NULL, 0, events, nevents, NULL);
|
||||
}
|
||||
}
|
||||
else {
|
||||
memset(&ts, 0, sizeof(struct timespec));
|
||||
ts.tv_sec = timeout ;
|
||||
ret = kevent(queuefd, NULL, 0, events, nevents, &ts);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int async_add(int queuefd, int fd, int etype) {
|
||||
struct kevent kev;
|
||||
|
||||
|
||||
EV_SET(&kev, fd, etype, EV_ADD, 0, 0, 0);
|
||||
if (kevent(queuefd, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int async_mod(int queuefd, int fd, int etype) {
|
||||
struct kevent kev;
|
||||
|
||||
EV_SET(&kev, fd, ASYNC_OUT, EV_DISABLE, 0, 0, 0);
|
||||
if (kevent(queuefd, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
EV_SET(&kev, fd, etype, EV_ADD, 0, 0, 0);
|
||||
if (kevent(queuefd, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int async_del(int queuefd, int fd, int etype) {
|
||||
struct kevent kev;
|
||||
|
||||
EV_SET(&kev, fd, etype, EV_DELETE, 0, 0, 0);
|
||||
if (kevent(queuefd, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
inline struct wsgi_request *next_wsgi_req(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req) {
|
||||
|
||||
uint8_t *ptr = (uint8_t *) wsgi_req ;
|
||||
|
||||
ptr += sizeof(struct wsgi_request) ;
|
||||
|
||||
return (struct wsgi_request *) ptr ;
|
||||
}
|
||||
|
||||
int async_get_timeout(struct uwsgi_server *uwsgi) {
|
||||
|
||||
|
||||
struct wsgi_request* wsgi_req = uwsgi->wsgi_requests ;
|
||||
struct wsgi_request* wsgi_req ;
|
||||
int i ;
|
||||
time_t curtime, tdelta = 0 ;
|
||||
int ret = 0 ;
|
||||
|
||||
if (!uwsgi->async_running) return 0;
|
||||
// do not wait if there are cores running
|
||||
if (!uwsgi.async_running) return 0;
|
||||
|
||||
for(i=0;i<uwsgi->async;i++) {
|
||||
for(i=0;i<uwsgi.async_current_max;i++) {
|
||||
wsgi_req = uwsgi.wsgi_requests[i];
|
||||
if (wsgi_req->async_status == UWSGI_AGAIN) {
|
||||
if (wsgi_req->async_timeout_expired) {
|
||||
// do not wait if there are timeout expired
|
||||
return 0;
|
||||
}
|
||||
if (wsgi_req->async_timeout > 0) {
|
||||
@@ -295,7 +25,6 @@ int async_get_timeout(struct uwsgi_server *uwsgi) {
|
||||
}
|
||||
}
|
||||
}
|
||||
wsgi_req = next_wsgi_req(uwsgi, wsgi_req) ;
|
||||
}
|
||||
|
||||
curtime = time(NULL);
|
||||
@@ -305,72 +34,70 @@ int async_get_timeout(struct uwsgi_server *uwsgi) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void async_expire_timeouts(struct uwsgi_server *uwsgi) {
|
||||
void async_expire_timeouts() {
|
||||
|
||||
struct wsgi_request* wsgi_req = uwsgi->wsgi_requests ;
|
||||
struct wsgi_request* wsgi_req ;
|
||||
int i ;
|
||||
time_t deadline = time(NULL);
|
||||
|
||||
|
||||
for(i=0;i<uwsgi->async;i++) {
|
||||
for(i=0;i<uwsgi.async_current_max;i++) {
|
||||
wsgi_req = uwsgi.wsgi_requests[i] ;
|
||||
|
||||
if (wsgi_req->async_status == UWSGI_AGAIN && wsgi_req->async_timeout > 0) {
|
||||
if (wsgi_req->async_timeout <= deadline) {
|
||||
wsgi_req->async_timeout = 0 ;
|
||||
wsgi_req->async_timeout_expired = 1 ;
|
||||
if (wsgi_req->async_waiting_fd != -1) {
|
||||
event_queue_del_fd(uwsgi.async_queue, wsgi_req->async_waiting_fd);
|
||||
uwsgi.async_waiting_fd_table[wsgi_req->async_waiting_fd] = -1;
|
||||
wsgi_req->async_waiting_fd = -1;
|
||||
wsgi_req->async_waiting_fd_monitored = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
wsgi_req = next_wsgi_req(uwsgi, wsgi_req) ;
|
||||
}
|
||||
}
|
||||
|
||||
struct wsgi_request *find_first_available_wsgi_req(struct uwsgi_server *uwsgi) {
|
||||
struct wsgi_request *find_first_available_wsgi_req() {
|
||||
|
||||
struct wsgi_request* wsgi_req = uwsgi->wsgi_requests ;
|
||||
struct wsgi_request* wsgi_req;
|
||||
int i ;
|
||||
|
||||
for(i=0;i<uwsgi->async;i++) {
|
||||
// optimization
|
||||
if (uwsgi.async_current_max > 1) {
|
||||
if (uwsgi.wsgi_requests[uwsgi.async_current_max-1]->async_status == UWSGI_OK) {
|
||||
//uwsgi_log("decreasing current max cores\n");
|
||||
uwsgi.async_current_max--;
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0;i<uwsgi.async;i++) {
|
||||
wsgi_req = uwsgi.wsgi_requests[i] ;
|
||||
if (wsgi_req->async_status == UWSGI_OK) {
|
||||
// optimization
|
||||
if (i > uwsgi.async_current_max-1) uwsgi.async_current_max = i+1;
|
||||
wsgi_req->async_id = i;
|
||||
return wsgi_req ;
|
||||
}
|
||||
wsgi_req = next_wsgi_req(uwsgi, wsgi_req) ;
|
||||
}
|
||||
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
struct wsgi_request *find_wsgi_req_by_id(struct uwsgi_server *uwsgi, int async_id) {
|
||||
struct wsgi_request *find_wsgi_req_by_fd(int fd) {
|
||||
|
||||
uint8_t *ptr = (uint8_t *) uwsgi->wsgi_requests ;
|
||||
struct wsgi_request* wsgi_req = NULL ;
|
||||
int core_id = uwsgi.async_waiting_fd_table[fd];
|
||||
|
||||
ptr += sizeof(struct wsgi_request) * async_id ;
|
||||
if (core_id == -1) return NULL;
|
||||
|
||||
return (struct wsgi_request *) ptr ;
|
||||
}
|
||||
|
||||
struct wsgi_request *find_wsgi_req_by_fd(struct uwsgi_server *uwsgi, int fd, int etype) {
|
||||
|
||||
struct wsgi_request* wsgi_req = uwsgi->wsgi_requests ;
|
||||
int i ;
|
||||
|
||||
if (etype != -1) {
|
||||
for(i=0;i<uwsgi->async;i++) {
|
||||
if (wsgi_req->async_waiting_fd == fd && wsgi_req->async_waiting_fd_type == etype) {
|
||||
return wsgi_req ;
|
||||
}
|
||||
wsgi_req = next_wsgi_req(uwsgi, wsgi_req) ;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(i=0;i<uwsgi->async;i++) {
|
||||
if (wsgi_req->async_waiting_fd == fd) {
|
||||
return wsgi_req ;
|
||||
}
|
||||
wsgi_req = next_wsgi_req(uwsgi, wsgi_req) ;
|
||||
}
|
||||
}
|
||||
wsgi_req = uwsgi.wsgi_requests[core_id];
|
||||
//if (wsgi_req->async_waiting_fd_type == etype) return wsgi_req ;
|
||||
return wsgi_req;
|
||||
|
||||
return NULL ;
|
||||
|
||||
@@ -384,13 +111,14 @@ void async_set_timeout(struct wsgi_request *wsgi_req, time_t timeout) {
|
||||
|
||||
}
|
||||
|
||||
void async_write_all(struct uwsgi_server *uwsgi, char *data, size_t len) {
|
||||
void async_write_all(char *data, size_t len) {
|
||||
|
||||
struct wsgi_request *wsgi_req = uwsgi->wsgi_requests ;
|
||||
struct wsgi_request *wsgi_req;
|
||||
int i;
|
||||
ssize_t rlen ;
|
||||
|
||||
for(i=0;i<uwsgi->async;i++) {
|
||||
for(i=0;i<uwsgi.async_current_max;i++) {
|
||||
wsgi_req = uwsgi.wsgi_requests[i];
|
||||
if (wsgi_req->async_status == UWSGI_PAUSED) {
|
||||
rlen = write(wsgi_req->poll.fd, data, len);
|
||||
if (rlen < 0) {
|
||||
@@ -403,57 +131,71 @@ void async_write_all(struct uwsgi_server *uwsgi, char *data, size_t len) {
|
||||
}
|
||||
}
|
||||
|
||||
void async_unpause_all(struct uwsgi_server *uwsgi) {
|
||||
void async_unpause_all() {
|
||||
|
||||
struct wsgi_request *wsgi_req = uwsgi->wsgi_requests ;
|
||||
struct wsgi_request *wsgi_req ;
|
||||
int i;
|
||||
|
||||
for(i=0;i<uwsgi->async;i++) {
|
||||
for(i=0;i<uwsgi.async_current_max;i++) {
|
||||
wsgi_req = uwsgi.wsgi_requests[i];
|
||||
if (wsgi_req->async_status == UWSGI_PAUSED) {
|
||||
wsgi_req->async_status = UWSGI_AGAIN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct wsgi_request * async_loop(struct uwsgi_server *uwsgi) {
|
||||
struct wsgi_request * async_loop() {
|
||||
|
||||
struct wsgi_request *wsgi_req ;
|
||||
int i ;
|
||||
int ret;
|
||||
|
||||
uwsgi->async_running = -1 ;
|
||||
wsgi_req = uwsgi->wsgi_requests ;
|
||||
uwsgi.async_running = -1 ;
|
||||
|
||||
|
||||
for(i=0;i<uwsgi->async;i++) {
|
||||
for(i=0;i<uwsgi.async_current_max;i++) {
|
||||
wsgi_req = uwsgi.wsgi_requests[i];
|
||||
if (wsgi_req->async_status == UWSGI_AGAIN) {
|
||||
if (wsgi_req->async_waiting_fd != -1 && !wsgi_req->async_waiting_fd_monitored) {
|
||||
if (wsgi_req->sigwait) {
|
||||
uwsgi_log("waiting for signal\n");
|
||||
continue;
|
||||
}
|
||||
else if (wsgi_req->async_waiting_fd != -1 && !wsgi_req->async_waiting_fd_monitored) {
|
||||
// add fd to monitoring
|
||||
if (async_add(uwsgi->async_queue, wsgi_req->async_waiting_fd, wsgi_req->async_waiting_fd_type)) {
|
||||
ret = -1;
|
||||
if (wsgi_req->async_waiting_fd_type == ASYNC_IN) {
|
||||
ret = event_queue_add_fd_read(uwsgi.async_queue, wsgi_req->async_waiting_fd);
|
||||
}
|
||||
else if (wsgi_req->async_waiting_fd_type == ASYNC_OUT) {
|
||||
ret = event_queue_add_fd_write(uwsgi.async_queue, wsgi_req->async_waiting_fd);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
// error adding fd to the async queue, better to close it...
|
||||
close(wsgi_req->async_waiting_fd);
|
||||
wsgi_req->async_status = UWSGI_OK ;
|
||||
return wsgi_req;
|
||||
}
|
||||
uwsgi.async_waiting_fd_table[wsgi_req->async_waiting_fd] = wsgi_req->async_id;
|
||||
wsgi_req->async_waiting_fd_monitored = 1;
|
||||
wsgi_req->async_status = UWSGI_AGAIN;
|
||||
}
|
||||
else if (wsgi_req->async_waiting_fd == -1 && wsgi_req->async_timeout <= 0) {
|
||||
uwsgi->async_running = 0 ;
|
||||
// st global wsgi_req for python functions
|
||||
uwsgi->wsgi_req = wsgi_req ;
|
||||
wsgi_req->async_status = (*uwsgi->shared->hooks[wsgi_req->uh.modifier1]) (uwsgi, wsgi_req);
|
||||
uwsgi.async_running = 0 ;
|
||||
// st global wsgi_req
|
||||
uwsgi.wsgi_req = wsgi_req ;
|
||||
|
||||
wsgi_req->async_switches++;
|
||||
uwsgi_log("!!! getting new part\n");
|
||||
wsgi_req->async_status = uwsgi.p[wsgi_req->uh.modifier1]->request(wsgi_req);;
|
||||
|
||||
wsgi_req->switches++;
|
||||
|
||||
if (wsgi_req->async_status < UWSGI_AGAIN) {
|
||||
return wsgi_req;
|
||||
}
|
||||
}
|
||||
}
|
||||
wsgi_req = next_wsgi_req(uwsgi, wsgi_req) ;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = null
|
||||
@@ -0,0 +1,34 @@
|
||||
[uwsgi]
|
||||
xml = true
|
||||
ini = true
|
||||
yaml = true
|
||||
snmp = true
|
||||
sctp = false
|
||||
spooler = true
|
||||
embedded = true
|
||||
udp = true
|
||||
multicast = true
|
||||
threading = true
|
||||
sendfile = true
|
||||
minterpreters = true
|
||||
async = true
|
||||
evdis = false
|
||||
ldap = false
|
||||
pcre = auto
|
||||
stackless = false
|
||||
debug = false
|
||||
unbit = false
|
||||
xml_implementation = libxml2
|
||||
plugins =
|
||||
bin_name = uwsgi
|
||||
plugin_dir = .
|
||||
embedded_plugins = python, ping, nagios, rpc, fastrouter, http
|
||||
|
||||
locking = auto
|
||||
event = auto
|
||||
timer = auto
|
||||
filemonitor = auto
|
||||
|
||||
[python]
|
||||
paste = true
|
||||
web3 = true
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = +,erlang
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = lua
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
plugins = lua
|
||||
@@ -0,0 +1,33 @@
|
||||
[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
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = psgi
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = +,erlang,pyerl
|
||||
@@ -0,0 +1,7 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = +,lua
|
||||
|
||||
[python]
|
||||
paste = true
|
||||
web3 = true
|
||||
@@ -0,0 +1,31 @@
|
||||
[uwsgi]
|
||||
xml = true
|
||||
ini = true
|
||||
snmp = true
|
||||
sctp = false
|
||||
erlang = false
|
||||
spooler = true
|
||||
embedded = true
|
||||
udp = true
|
||||
multicast = true
|
||||
threading = true
|
||||
sendfile = true
|
||||
proxy = true
|
||||
minterpreters = true
|
||||
async = true
|
||||
http = true
|
||||
evdis = false
|
||||
ldap = false
|
||||
routing = false
|
||||
stackless = false
|
||||
debug = false
|
||||
unbit = false
|
||||
xml_implementation = libxml2
|
||||
plugins =
|
||||
bin_name = uwsgi
|
||||
plugin_dir = .
|
||||
embedded_plugins = python, ping, nagios, rack
|
||||
|
||||
[python]
|
||||
paste = true
|
||||
web3 = true
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = rack, ping, nagios, rpc
|
||||
@@ -0,0 +1,30 @@
|
||||
[uwsgi]
|
||||
xml = true
|
||||
ini = true
|
||||
yaml = 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 = false
|
||||
routing = false
|
||||
stackless = false
|
||||
debug = false
|
||||
unbit = false
|
||||
xml_implementation = libxml2
|
||||
plugins = rack
|
||||
bin_name = uwsgi
|
||||
plugin_dir = .
|
||||
embedded_plugins =
|
||||
@@ -0,0 +1,23 @@
|
||||
[uwsgi]
|
||||
xml = true
|
||||
ini = true
|
||||
yaml = true
|
||||
snmp = false
|
||||
sctp = false
|
||||
spooler = true
|
||||
embedded = true
|
||||
udp = true
|
||||
multicast = false
|
||||
threading = true
|
||||
sendfile = true
|
||||
nagios = false
|
||||
minterpreters = true
|
||||
async = true
|
||||
ldap = true
|
||||
debug = false
|
||||
unbit = true
|
||||
xml_implementation = libxml2
|
||||
plugins =
|
||||
bin_name = /opt/unbit/bin/uwsgi
|
||||
plugin_dir = /opt/unbit/uwsgi_plugins
|
||||
embedded_plugins =
|
||||
@@ -0,0 +1,4 @@
|
||||
[uwsgi]
|
||||
inherit = unbit
|
||||
bin_name = ../bin/uwsgi
|
||||
plugin_dir = ../bin/uwsgi_plugins
|
||||
@@ -0,0 +1,566 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_subscriber_name *uwsgi_get_subscriber(struct uwsgi_dict *udict, char *key, uint16_t keylen) {
|
||||
|
||||
uint64_t ovl;
|
||||
struct uwsgi_subscriber *usub;
|
||||
struct uwsgi_subscriber_name *ret = NULL;
|
||||
|
||||
usub = (struct uwsgi_subscriber *) uwsgi_dict_get(udict, key, keylen, &ovl);
|
||||
|
||||
if (usub == NULL || !ovl) return NULL;
|
||||
|
||||
if (!usub->nodes) return NULL;
|
||||
|
||||
if (usub && ovl) {
|
||||
ret = &usub->names[usub->current];
|
||||
// dead node
|
||||
if (ret->len == 0) {
|
||||
if (usub->current == usub->nodes-1) {
|
||||
usub->nodes--;
|
||||
}
|
||||
// retry with another node (if available)
|
||||
if (usub->nodes > 0) {
|
||||
usub->current++;
|
||||
if (usub->current >= usub->nodes) usub->current = 0;
|
||||
return uwsgi_get_subscriber(udict, key, keylen);
|
||||
}
|
||||
}
|
||||
|
||||
if (usub->nodes > 1) {
|
||||
usub->current++;
|
||||
if (usub->current >= usub->nodes) usub->current = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void uwsgi_add_subscriber(struct uwsgi_dict *udict, char *key, uint16_t keylen, char *address, uint64_t address_len) {
|
||||
|
||||
char *ptr;
|
||||
uint64_t vallen = 0;
|
||||
struct uwsgi_subscriber *usub, nusub;
|
||||
int found = 0;
|
||||
int i;
|
||||
|
||||
ptr = uwsgi_dict_get(udict, key, 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)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
found = usub->nodes;
|
||||
// check for unallocated slot
|
||||
for(i=0;i<(int)usub->nodes;i++) {
|
||||
if (usub->names[i].len == 0) {
|
||||
found = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
usub->names[found].len = address_len;
|
||||
memcpy(usub->names[found].name, address, address_len);
|
||||
if (found == (int) usub->nodes) {
|
||||
usub->nodes++;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_dict *uwsgi_dict_create(uint64_t items, uint64_t blocksize) {
|
||||
|
||||
int i;
|
||||
|
||||
struct uwsgi_dict *udict = (struct uwsgi_dict *) mmap(NULL, sizeof(uint64_t) * UMAX16, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (!udict) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!blocksize) blocksize = 4096;
|
||||
|
||||
if (blocksize % uwsgi.page_size != 0) {
|
||||
uwsgi_log("invalid shared dictionary blocksize %llu: must be a multiple of memory page size (%d bytes)\n", (unsigned long long) udict->blocksize, uwsgi.page_size);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
udict->blocksize = blocksize;
|
||||
udict->max_items = items;
|
||||
|
||||
udict->hashtable = (uint64_t *) mmap(NULL, sizeof(uint64_t) * UMAX16, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (!udict->hashtable) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(udict->hashtable, 0, sizeof(uint64_t) * UMAX16);
|
||||
|
||||
udict->unused_stack = (uint64_t *) mmap(NULL, sizeof(uint64_t) * udict->max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (!udict->unused_stack) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(udict->unused_stack, 0, sizeof(uint64_t) * udict->max_items);
|
||||
|
||||
udict->items = (struct uwsgi_dict_item *) mmap(NULL, sizeof(struct uwsgi_dict_item) * udict->max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (!udict->items) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
udict->data = mmap(NULL, udict->blocksize * udict->max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (!udict->data) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for(i=0;i< (int) udict->max_items;i++) {
|
||||
memset(&udict->items[i], 0, sizeof(struct uwsgi_dict_item));
|
||||
}
|
||||
|
||||
udict->first_available_item = 1;
|
||||
udict->unused_stack_ptr = 0;
|
||||
|
||||
udict->lock = uwsgi_mmap_shared_lock();
|
||||
uwsgi_lock_init(udict->lock);
|
||||
|
||||
return udict;
|
||||
}
|
||||
|
||||
uint32_t djb33x_hash(char *key, int keylen) {
|
||||
|
||||
register uint32_t hash = 5381;
|
||||
int i;
|
||||
|
||||
for(i=0;i<keylen;i++) {
|
||||
hash = ((hash << 5) + hash) ^ key[i];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
inline uint64_t uwsgi_dict_get_index(struct uwsgi_dict *udict, char *key, uint16_t keylen) {
|
||||
|
||||
uint32_t hash = djb33x_hash(key, keylen);
|
||||
|
||||
int hash_key = hash % 0xffff;
|
||||
|
||||
uint64_t slot = udict->hashtable[hash_key];
|
||||
|
||||
struct uwsgi_dict_item *udi;
|
||||
|
||||
udi = &udict->items[slot];
|
||||
|
||||
// first round
|
||||
if (udi->djbhash != hash) goto cycle;
|
||||
if (udi->keysize != keylen) goto cycle;
|
||||
if (memcmp(udi->key, key, keylen)) goto cycle;
|
||||
|
||||
return slot;
|
||||
|
||||
cycle:
|
||||
while(udi->next) {
|
||||
slot = udi->next;
|
||||
udi = &udict->items[slot];
|
||||
if (udi->djbhash != hash) continue;
|
||||
if (udi->keysize != keylen) continue;
|
||||
if (!memcmp(udi->key, key, keylen)) return slot;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *uwsgi_dict_get(struct uwsgi_dict *udict, char *key, uint16_t keylen, uint64_t *valsize) {
|
||||
|
||||
uint64_t index = uwsgi_dict_get_index(udict, key, keylen);
|
||||
|
||||
if (index) {
|
||||
*valsize = udict->items[index].valsize;
|
||||
udict->items[index].hits++;
|
||||
return udict->data+(index*udict->blocksize);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int uwsgi_dict_del(struct uwsgi_dict *udict, char *key, uint16_t keylen) {
|
||||
|
||||
uint64_t index = 0;
|
||||
struct uwsgi_dict_item *udi;
|
||||
int ret = -1;
|
||||
|
||||
index = uwsgi_dict_get_index(udict, key, keylen);
|
||||
if (index) {
|
||||
udi = &udict->items[index] ;
|
||||
udi->keysize = 0;
|
||||
udi->valsize = 0;
|
||||
udict->unused_stack_ptr++;
|
||||
udict->unused_stack[udict->unused_stack_ptr] = index;
|
||||
// try to return to initial condition...
|
||||
if (index == udict->first_available_item-1) {
|
||||
udict->first_available_item--;
|
||||
}
|
||||
ret = 0;
|
||||
// relink collisioned entry
|
||||
if (udi->prev) {
|
||||
udict->items[udi->prev].next = udi->next;
|
||||
}
|
||||
if (udi->next) {
|
||||
udict->items[udi->next].prev = udi->prev;
|
||||
}
|
||||
if (!udi->prev && !udi->next) {
|
||||
// reset hashtable entry
|
||||
udict->hashtable[udi->djbhash % 0xffff] = 0;
|
||||
}
|
||||
udi->djbhash = 0;
|
||||
udi->prev = 0;
|
||||
udi->next = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline uint64_t uwsgi_cache_get_index(char *key, uint16_t keylen) {
|
||||
|
||||
uint32_t hash = djb33x_hash(key, keylen);
|
||||
|
||||
int hash_key = hash % 0xffff;
|
||||
|
||||
uint64_t slot = uwsgi.cache_hashtable[hash_key];
|
||||
|
||||
struct uwsgi_cache_item *uci;
|
||||
|
||||
//uwsgi_log("found slot %d for key %d\n", slot, hash_key);
|
||||
|
||||
uci = &uwsgi.cache_items[slot];
|
||||
|
||||
// first round
|
||||
if (uci->djbhash != hash) goto cycle;
|
||||
if (uci->keysize != keylen) goto cycle;
|
||||
if (memcmp(uci->key, key, keylen)) goto cycle;
|
||||
|
||||
return slot;
|
||||
|
||||
cycle:
|
||||
while(uci->next) {
|
||||
slot = uci->next;
|
||||
uci = &uwsgi.cache_items[slot];
|
||||
if (uci->djbhash != hash) continue;
|
||||
if (uci->keysize != keylen) continue;
|
||||
if (!memcmp(uci->key, key, keylen)) return slot;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t uwsgi_cache_exists(char *key, uint16_t keylen) {
|
||||
|
||||
return uwsgi_cache_get_index(key, keylen);
|
||||
}
|
||||
|
||||
char *uwsgi_cache_get(char *key, uint16_t keylen, uint64_t *valsize) {
|
||||
|
||||
uint64_t index = uwsgi_cache_get_index(key, keylen);
|
||||
|
||||
if (index) {
|
||||
if (uwsgi.cache_items[index].flags & UWSGI_CACHE_FLAG_UNGETTABLE) return NULL;
|
||||
*valsize = uwsgi.cache_items[index].valsize;
|
||||
uwsgi.cache_items[index].hits++;
|
||||
return uwsgi.cache+(index*uwsgi.cache_blocksize);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int uwsgi_cache_del(char *key, uint16_t keylen) {
|
||||
|
||||
uint64_t index = 0;
|
||||
struct uwsgi_cache_item *uci;
|
||||
int ret = -1;
|
||||
|
||||
index = uwsgi_cache_get_index(key, keylen);
|
||||
if (index) {
|
||||
uci = &uwsgi.cache_items[index] ;
|
||||
uci->keysize = 0;
|
||||
uci->valsize = 0;
|
||||
uwsgi.shared->cache_unused_stack_ptr++;
|
||||
uwsgi.cache_unused_stack[uwsgi.shared->cache_unused_stack_ptr] = index;
|
||||
// try to return to initial condition...
|
||||
if (index == uwsgi.shared->cache_first_available_item-1) {
|
||||
uwsgi.shared->cache_first_available_item--;
|
||||
//uwsgi_log("FACI: %llu STACK PTR: %llu\n", (unsigned long long) uwsgi.shared->cache_first_available_item, (unsigned long long) uwsgi.shared->cache_unused_stack_ptr);
|
||||
}
|
||||
ret = 0;
|
||||
// relink collisioned entry
|
||||
if (uci->prev) {
|
||||
uwsgi.cache_items[uci->prev].next = uci->next;
|
||||
}
|
||||
if (uci->next) {
|
||||
uwsgi.cache_items[uci->next].prev = uci->prev;
|
||||
}
|
||||
if (!uci->prev && !uci->next) {
|
||||
// reset hashtable entry
|
||||
//uwsgi_log("!!! resetted hashtable entry !!!\n");
|
||||
uwsgi.cache_hashtable[uci->djbhash % 0xffff] = 0;
|
||||
}
|
||||
uci->djbhash = 0;
|
||||
uci->prev = 0;
|
||||
uci->next = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int uwsgi_cache_set(char *key, uint16_t keylen, char *val, uint64_t vallen, uint64_t expires, uint16_t flags) {
|
||||
|
||||
uint64_t index = 0, last_index = 0 ;
|
||||
|
||||
struct uwsgi_cache_item *uci, *ucii;
|
||||
|
||||
int ret = -1;
|
||||
int slot;
|
||||
|
||||
if (!keylen || !vallen) return -1;
|
||||
|
||||
if (keylen > UWSGI_CACHE_MAX_KEY_SIZE) return -1;
|
||||
|
||||
if (uwsgi.shared->cache_first_available_item >= uwsgi.cache_max_items && !uwsgi.shared->cache_unused_stack_ptr) {
|
||||
uwsgi_log("*** DANGER cache is FULL !!! ***\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
//uwsgi_log("putting cache data in key %.*s %d\n", keylen, key, vallen);
|
||||
index = uwsgi_cache_get_index(key, keylen);
|
||||
if (!index) {
|
||||
if (uwsgi.shared->cache_unused_stack_ptr) {
|
||||
//uwsgi_log("!!! REUSING CACHE SLOT !!! (faci: %llu)\n", (unsigned long long) uwsgi.shared->cache_first_available_item);
|
||||
index = uwsgi.cache_unused_stack[uwsgi.shared->cache_unused_stack_ptr];
|
||||
uwsgi.shared->cache_unused_stack_ptr--;
|
||||
}
|
||||
else {
|
||||
index = uwsgi.shared->cache_first_available_item;
|
||||
if (uwsgi.shared->cache_first_available_item < uwsgi.cache_max_items) {
|
||||
uwsgi.shared->cache_first_available_item++;
|
||||
}
|
||||
}
|
||||
uci = &uwsgi.cache_items[index] ;
|
||||
if (expires) expires += time(NULL);
|
||||
uci->expires = expires;
|
||||
uci->djbhash = djb33x_hash(key, keylen);
|
||||
uci->hits = 0;
|
||||
uci->flags = flags;
|
||||
memcpy(uci->key, key, keylen);
|
||||
memcpy(uwsgi.cache+(index*uwsgi.cache_blocksize), val, vallen);
|
||||
|
||||
// set this as late as possibile (to reduce races risk)
|
||||
|
||||
uci->valsize = vallen;
|
||||
uci->keysize = keylen;
|
||||
ret = 0;
|
||||
// now put the value in the 16bit hashtable
|
||||
slot = uci->djbhash % 0xffff;
|
||||
|
||||
if (uwsgi.cache_hashtable[slot] == 0) {
|
||||
uwsgi.cache_hashtable[slot] = index;
|
||||
}
|
||||
else {
|
||||
//uwsgi_log("HASH COLLISION !!!!\n");
|
||||
// append to first available next
|
||||
last_index = uwsgi.cache_hashtable[slot];
|
||||
ucii = &uwsgi.cache_items[ last_index ];
|
||||
while(ucii->next) {
|
||||
last_index = ucii->next;
|
||||
ucii = &uwsgi.cache_items[ last_index ];
|
||||
}
|
||||
ucii->next = index;
|
||||
uci->prev = last_index;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_dict_set(struct uwsgi_dict *udict, char *key, uint16_t keylen, char *val, uint64_t vallen) {
|
||||
|
||||
uint64_t index = 0, last_index = 0 ;
|
||||
|
||||
struct uwsgi_dict_item *udi, *udii;
|
||||
|
||||
int ret = -1;
|
||||
int slot;
|
||||
|
||||
if (!keylen || !vallen) return -1;
|
||||
|
||||
if (keylen > UWSGI_CACHE_MAX_KEY_SIZE) return -1;
|
||||
|
||||
if (udict->first_available_item >= udict->max_items && !udict->unused_stack_ptr) {
|
||||
uwsgi_log("*** DANGER dictionary %p is FULL !!! ***\n", udict);
|
||||
goto end;
|
||||
}
|
||||
|
||||
index = uwsgi_dict_get_index(udict, key, keylen);
|
||||
if (!index) {
|
||||
if (udict->unused_stack_ptr) {
|
||||
index = udict->unused_stack[udict->unused_stack_ptr];
|
||||
udict->unused_stack_ptr--;
|
||||
}
|
||||
else {
|
||||
index = udict->first_available_item;
|
||||
if (udict->first_available_item < udict->max_items) {
|
||||
udict->first_available_item++;
|
||||
}
|
||||
}
|
||||
udi = &udict->items[index] ;
|
||||
udi->djbhash = djb33x_hash(key, keylen);
|
||||
udi->hits = 0;
|
||||
memcpy(udi->key, key, keylen);
|
||||
memcpy(udict->data+(index*udict->blocksize), val, vallen);
|
||||
|
||||
// set this as late as possibile (to reduce races risk)
|
||||
|
||||
udi->valsize = vallen;
|
||||
udi->keysize = keylen;
|
||||
ret = 0;
|
||||
// now put the value in the 16bit hashtable
|
||||
slot = udi->djbhash % 0xffff;
|
||||
|
||||
if (udict->hashtable[slot] == 0) {
|
||||
udict->hashtable[slot] = index;
|
||||
}
|
||||
else {
|
||||
// append to first available next
|
||||
last_index = udict->hashtable[slot];
|
||||
udii = &udict->items[ last_index ];
|
||||
while(udii->next) {
|
||||
last_index = udii->next;
|
||||
udii = &udict->items[ last_index ];
|
||||
}
|
||||
udii->next = index;
|
||||
udi->prev = last_index;
|
||||
}
|
||||
}
|
||||
|
||||
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, 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 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,18 @@
|
||||
require 'fiber'
|
||||
require 'sinatra'
|
||||
|
||||
get '/hi' do
|
||||
|
||||
class Response
|
||||
def each
|
||||
for i in 1..10
|
||||
yield "ciao<br/>"
|
||||
Fiber.yield
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Response.new
|
||||
end
|
||||
|
||||
run Sinatra::Application
|
||||
@@ -0,0 +1,7 @@
|
||||
require 'sinatra'
|
||||
|
||||
get '/hi' do
|
||||
"Hello World"
|
||||
end
|
||||
|
||||
run Sinatra::Application
|
||||
+68
-68
@@ -17,10 +17,10 @@ sub new {
|
||||
sub run {
|
||||
my ($self, $app) = @_;
|
||||
|
||||
my $server ;
|
||||
my $server;
|
||||
|
||||
if (exists($ENV{'UWSGI_FD'})) {
|
||||
$server = IO::Socket::UNIX->new_from_fd($ENV{'UWSGI_FD'}, '+<');
|
||||
$server = IO::Socket::UNIX->new_from_fd($ENV{'UWSGI_FD'}, '+<');
|
||||
}
|
||||
else {
|
||||
$server = IO::Socket::INET->new(LocalPort => $self->{port}, LocalAddr => $self->{host}, Listen => 100, ReuseAddr => 1);
|
||||
@@ -28,62 +28,62 @@ sub run {
|
||||
|
||||
while ( my $client = $server->accept ) {
|
||||
|
||||
my $head = '';
|
||||
my $remains = 4 ;
|
||||
my $head = '';
|
||||
my $remains = 4;
|
||||
|
||||
while($remains) {
|
||||
$client->recv(my $buf, $remains);
|
||||
last unless $buf;
|
||||
$head.=$buf;
|
||||
$remains -= length($buf);
|
||||
}
|
||||
while($remains) {
|
||||
$client->recv(my $buf, $remains);
|
||||
last unless $buf;
|
||||
$head.=$buf;
|
||||
$remains -= length($buf);
|
||||
}
|
||||
|
||||
if (length($head) != 4) {
|
||||
$client->close ;
|
||||
next;
|
||||
}
|
||||
if (length($head) != 4) {
|
||||
$client->close;
|
||||
next;
|
||||
}
|
||||
|
||||
my ($mod1, $envsize, $mod2) = unpack('CvC', $head) ;
|
||||
my ($mod1, $envsize, $mod2) = unpack('CvC', $head);
|
||||
|
||||
unless ($envsize) {
|
||||
$client->close ;
|
||||
next;
|
||||
}
|
||||
unless ($envsize) {
|
||||
$client->close;
|
||||
next;
|
||||
}
|
||||
|
||||
$remains = $envsize ;
|
||||
my $envbuf = '' ;
|
||||
while($remains) {
|
||||
my $buf ;
|
||||
if ($remains >= 4096) {
|
||||
$client->recv($buf, 4096);
|
||||
}
|
||||
else {
|
||||
$client->recv($buf, $remains);
|
||||
}
|
||||
$remains = $envsize;
|
||||
my $envbuf = '';
|
||||
while($remains) {
|
||||
my $buf;
|
||||
if ($remains >= 4096) {
|
||||
$client->recv($buf, 4096);
|
||||
}
|
||||
else {
|
||||
$client->recv($buf, $remains);
|
||||
}
|
||||
|
||||
unless($buf) {
|
||||
$client->close ;
|
||||
next;
|
||||
}
|
||||
unless($buf) {
|
||||
$client->close;
|
||||
next;
|
||||
}
|
||||
|
||||
$envbuf.=$buf;
|
||||
$remains -= length($buf);
|
||||
}
|
||||
$envbuf.=$buf;
|
||||
$remains -= length($buf);
|
||||
}
|
||||
|
||||
if (length($envbuf) != $envsize ) {
|
||||
$client->close ;
|
||||
next;
|
||||
}
|
||||
if (length($envbuf) != $envsize ) {
|
||||
$client->close;
|
||||
next;
|
||||
}
|
||||
|
||||
my %env ;
|
||||
my %env;
|
||||
|
||||
my $i = 0;
|
||||
while($i < $envsize) {
|
||||
my $kl = unpack('v', substr($envbuf, $i, 2)) ; $i+=2;
|
||||
my $key = substr($envbuf, $i, $kl); $i+=$kl;
|
||||
my $vl = unpack('v', substr($envbuf, $i, 2)) ; $i+=2;
|
||||
$env{$key} = substr($envbuf, $i, $vl); $i+=$vl;
|
||||
}
|
||||
my $i = 0;
|
||||
while($i < $envsize) {
|
||||
my $kl = unpack('v', substr($envbuf, $i, 2)); $i+=2;
|
||||
my $key = substr($envbuf, $i, $kl); $i+=$kl;
|
||||
my $vl = unpack('v', substr($envbuf, $i, 2)); $i+=2;
|
||||
$env{$key} = substr($envbuf, $i, $vl); $i+=$vl;
|
||||
}
|
||||
|
||||
my $env = {
|
||||
%env,
|
||||
@@ -105,40 +105,40 @@ sub run {
|
||||
}
|
||||
elsif (ref $res eq 'CODE') {
|
||||
$res->(sub {
|
||||
$self->_handle_response($client, $env{'SERVER_PROTOCOL'}, $_[0]);
|
||||
});
|
||||
$self->_handle_response($client, $env{'SERVER_PROTOCOL'}, $_[0]);
|
||||
});
|
||||
}
|
||||
else {
|
||||
die "Bad response $res";
|
||||
}
|
||||
|
||||
$client->close ;
|
||||
$client->close;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
sub _handle_response {
|
||||
my ($self, $client, $protocol, $res) = @_;
|
||||
my ($self, $client, $protocol, $res) = @_;
|
||||
|
||||
$client->send($protocol.' '.$res->[0].' '.HTTP::Status::status_message( $res->[0] )."\r\n");
|
||||
$client->send($protocol.' '.$res->[0].' '.HTTP::Status::status_message( $res->[0] )."\r\n");
|
||||
|
||||
my $headers = $res->[1];
|
||||
my $hdrs = '';
|
||||
while (my ($k, $v) = splice @$headers, 0, 2) {
|
||||
$hdrs .= "$k: $v\r\n";
|
||||
}
|
||||
$hdrs .= "\r\n";
|
||||
my $headers = $res->[1];
|
||||
my $hdrs = '';
|
||||
while (my ($k, $v) = splice @$headers, 0, 2) {
|
||||
$hdrs .= "$k: $v\r\n";
|
||||
}
|
||||
$hdrs .= "\r\n";
|
||||
|
||||
$client->send($hdrs);
|
||||
$client->send($hdrs);
|
||||
|
||||
my $cb = sub { $client->send($_[0]) };
|
||||
my $body = $res->[2];
|
||||
if (defined $body) {
|
||||
Plack::Util::foreach($body, $cb);
|
||||
}
|
||||
else {
|
||||
return Plack::Util::inline_object write => $cb,close => sub { };
|
||||
}
|
||||
my $cb = sub { $client->send($_[0]) };
|
||||
my $body = $res->[2];
|
||||
if (defined $body) {
|
||||
Plack::Util::foreach($body, $cb);
|
||||
}
|
||||
else {
|
||||
return Plack::Util::inline_object write => $cb,close => sub { };
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# uWSGI - manage uWSGI application server
|
||||
#
|
||||
|
||||
description "uWSGI"
|
||||
|
||||
start on runlevel [2345]
|
||||
stop on runlevel [!2345]
|
||||
|
||||
respawn
|
||||
|
||||
env LOGTO=/tmp/uwsgi.log
|
||||
env BINPATH=/home/foo/uwsgi/uwsgi
|
||||
|
||||
# --no-orphans avoid workers without master
|
||||
exec $BINPATH --no-orphans --socket :3033 --uid 1001 --gid 1001 --limit-as 256 -m simple_app --logto $LOGTO -M -p 4
|
||||
+24
-1
@@ -9,6 +9,7 @@ require 'optparse'
|
||||
|
||||
options = {
|
||||
:processes => 1,
|
||||
:threads => 1,
|
||||
:master => false,
|
||||
:logging => true,
|
||||
:static => true,
|
||||
@@ -19,6 +20,7 @@ options = {
|
||||
opts = OptionParser.new do |opts|
|
||||
|
||||
opts.on("-p", "--processes=nproc", Integer, '') { |p| options[:processes] = p }
|
||||
opts.on("-t", "--threads=nthreads", Integer, '') { |t| options[:threads] = t }
|
||||
opts.on("-M", "--master", '') { options[:master] = true }
|
||||
opts.on("-L", "--no-logging", '') { options[:logging] = false }
|
||||
opts.on("-S", "--no-static", '') { options[:static] = false }
|
||||
@@ -37,6 +39,7 @@ end
|
||||
|
||||
$requests = 0
|
||||
$workers = Array.new
|
||||
$mywid = 0
|
||||
|
||||
module Rack
|
||||
|
||||
@@ -74,12 +77,14 @@ module Rack
|
||||
ulog("spawned worker 1 (pid: #{$workers[1]})")
|
||||
elsif $workers[1].to_i == 0
|
||||
$0 = "uRack worker 1"
|
||||
$mywid = 1
|
||||
can_spawn = false
|
||||
end
|
||||
else
|
||||
$0 = 'uRack worker 1'
|
||||
$workers[0] = nil
|
||||
$workers[1] = Process.pid
|
||||
$mywid = 1
|
||||
ulog("spawned worker 1 (pid: #{$workers[1]})")
|
||||
end
|
||||
|
||||
@@ -88,6 +93,7 @@ module Rack
|
||||
$workers[p] = Process.fork
|
||||
if $workers[p].to_i == 0
|
||||
$0 = "uRack worker #{p}"
|
||||
$mywid = p
|
||||
break
|
||||
elsif $workers[p].to_i > 0
|
||||
ulog("spawned worker #{p} (pid: #{$workers[p]})")
|
||||
@@ -107,6 +113,7 @@ module Rack
|
||||
if $workers[wid].to_i == 0
|
||||
$0 = "uRack worker #{wid}"
|
||||
i_am_a_child = true
|
||||
$mywid = wid
|
||||
break
|
||||
elsif $workers[wid].to_i > 0
|
||||
ulog("respawned worker #{wid} (pid: #{$workers[wid]})")
|
||||
@@ -118,9 +125,21 @@ module Rack
|
||||
end
|
||||
end
|
||||
|
||||
if options[:threads] > 2
|
||||
for t in 2..options[:threads]
|
||||
wt = Thread.new do
|
||||
ulog("spawning thread #{t} on worker #{$mywid}")
|
||||
while client = server.accept
|
||||
serve client, app, options
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
while client = server.accept
|
||||
serve client, app, options
|
||||
serve client, app, options
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def self.serve(client, app, options)
|
||||
@@ -191,6 +210,10 @@ module Rack
|
||||
buf, sender = client.recvfrom(remains)
|
||||
end
|
||||
|
||||
if buf.length == 0
|
||||
break
|
||||
end
|
||||
|
||||
rack_input.write( buf )
|
||||
remains -= buf.length
|
||||
end
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
-module(uwsgi).
|
||||
-export([encode/1,send/3]).
|
||||
|
||||
|
||||
encode(Vars) ->
|
||||
Body = lists:map(fun(X) -> Len = length(X), lists:append( binary_to_list(<<Len:16/little-unsigned-integer>>), X) end, Vars),
|
||||
lists:flatten(Body).
|
||||
|
||||
response(Sock, Output) ->
|
||||
case gen_tcp:recv(Sock,0) of
|
||||
{ ok, Data } ->
|
||||
response(Sock, lists:append(Output, binary_to_list(Data)));
|
||||
{ error, closed } ->
|
||||
gen_tcp:close(Sock),
|
||||
Output
|
||||
end.
|
||||
|
||||
send(Host, Port, Message) ->
|
||||
{ ok, Sock } = gen_tcp:connect( Host, Port, [ binary, { active, false} ]),
|
||||
|
||||
Body = encode(Message),
|
||||
|
||||
Len = length(Body),
|
||||
|
||||
ok = gen_tcp:send(Sock, << 0, Len:16/little-unsigned-integer, 0>>),
|
||||
|
||||
ok = gen_tcp:send(Sock, Body),
|
||||
|
||||
response(Sock, []).
|
||||
|
||||
+27
-28
@@ -6,7 +6,6 @@ import java.util.Enumeration;
|
||||
import org.apache.catalina.util.IOTools;
|
||||
|
||||
public class uwsgi extends HttpServlet {
|
||||
|
||||
private String mountpoint = null;
|
||||
|
||||
public void init(ServletConfig config) throws ServletException {
|
||||
@@ -22,34 +21,34 @@ public class uwsgi extends HttpServlet {
|
||||
if (getServletConfig().getInitParameter("mountpoint") != null) {
|
||||
mountpoint = getServletConfig().getInitParameter("mountpoint");
|
||||
if (mountpoint.length() <= 1) {
|
||||
mountpoint = null ;
|
||||
mountpoint = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException {
|
||||
throws IOException, ServletException {
|
||||
uWSGIHandler(request, response);
|
||||
}
|
||||
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException {
|
||||
throws IOException, ServletException {
|
||||
uWSGIHandler(request, response);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void uWSGIHandler(HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException {
|
||||
throws IOException, ServletException {
|
||||
|
||||
Socket client = new Socket("localhost",3017);
|
||||
ByteArrayOutputStream uwsgi_request = new ByteArrayOutputStream() ;
|
||||
ByteArrayOutputStream uwsgi_request = new ByteArrayOutputStream();
|
||||
DataOutputStream wos = new DataOutputStream(uwsgi_request);
|
||||
|
||||
DataOutputStream os = new DataOutputStream(client.getOutputStream());
|
||||
DataInputStream is = new DataInputStream( client.getInputStream() );
|
||||
|
||||
|
||||
|
||||
ServletOutputStream out = response.getOutputStream();
|
||||
|
||||
boolean hasBody = false;
|
||||
@@ -104,14 +103,14 @@ public class uwsgi extends HttpServlet {
|
||||
|
||||
if (mountpoint != null) {
|
||||
wos.writeShort(swapShort( (short) 11));
|
||||
wos.writeBytes("SCRIPT_NAME");
|
||||
wos.writeShort(swapShort( (short) mountpoint.length() ) ) ;
|
||||
wos.writeBytes( mountpoint ) ;
|
||||
wos.writeBytes("SCRIPT_NAME");
|
||||
wos.writeShort(swapShort( (short) mountpoint.length() ) );
|
||||
wos.writeBytes( mountpoint );
|
||||
}
|
||||
|
||||
|
||||
|
||||
wos.writeShort(swapShort( (short) 9));
|
||||
wos.writeBytes("PATH_INFO");
|
||||
wos.writeBytes("PATH_INFO");
|
||||
if (mountpoint != null) {
|
||||
wos.writeShort(swapShort( (short) (request.getRequestURI().length() - mountpoint.length()) ) );
|
||||
wos.writeBytes( request.getRequestURI().substring(mountpoint.length()) );
|
||||
@@ -149,14 +148,14 @@ public class uwsgi extends HttpServlet {
|
||||
hasBody = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// taken from CGI servlet
|
||||
|
||||
Enumeration headers = request.getHeaderNames();
|
||||
String header = null;
|
||||
while (headers.hasMoreElements()) {
|
||||
header = null;
|
||||
header = ((String) headers.nextElement()).toUpperCase();
|
||||
header = null;
|
||||
header = ((String) headers.nextElement()).toUpperCase();
|
||||
wos.writeShort(swapShort( (short) ("HTTP_" + header.replace('-', '_')).length() ));
|
||||
wos.writeBytes("HTTP_" + header.replace('-', '_'));
|
||||
wos.writeShort(swapShort( (short) request.getHeader(header).length() ));
|
||||
@@ -175,16 +174,16 @@ public class uwsgi extends HttpServlet {
|
||||
IOTools.flow(request.getInputStream(), os);
|
||||
}
|
||||
|
||||
boolean statusParsed = false ;
|
||||
boolean statusParsed = false;
|
||||
for(;;) {
|
||||
String line = byte_readline(is) ;
|
||||
String line = byte_readline(is);
|
||||
if (line == "") {
|
||||
break;
|
||||
}
|
||||
if (statusParsed == false) {
|
||||
String[] status = line.split(" ",3);
|
||||
response.setStatus( Integer.parseInt(status[1]) );
|
||||
statusParsed = true ;
|
||||
statusParsed = true;
|
||||
}
|
||||
else {
|
||||
String[] keyval = line.split(": ",2);
|
||||
@@ -200,7 +199,7 @@ public class uwsgi extends HttpServlet {
|
||||
byte cb[] = new byte[4096];
|
||||
int len = 0;
|
||||
for(;;) {
|
||||
len = is.read(cb,0,4096) ;
|
||||
len = is.read(cb,0,4096);
|
||||
if ( len > 0) {
|
||||
out.write(cb,0,len);
|
||||
}
|
||||
@@ -208,7 +207,7 @@ public class uwsgi extends HttpServlet {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -218,19 +217,19 @@ public class uwsgi extends HttpServlet {
|
||||
for(;;) {
|
||||
byte b = is.readByte();
|
||||
if (b == 10) {
|
||||
break ;
|
||||
break;
|
||||
}
|
||||
line.write(b) ;
|
||||
line.write(b);
|
||||
}
|
||||
|
||||
return line.toString("ASCII").replaceAll("\\n","").replaceAll("\\r","");
|
||||
}
|
||||
|
||||
private short swapShort(short x) {
|
||||
|
||||
short tmp1 = (short) (x>>8) ;
|
||||
short tmp2 = (short) (x<<8) ;
|
||||
return (short) (tmp1 | tmp2) ;
|
||||
|
||||
short tmp1 = (short) (x>>8);
|
||||
short tmp2 = (short) (x<<8);
|
||||
return (short) (tmp1 | tmp2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+65
-65
@@ -2,8 +2,8 @@
|
||||
|
||||
*** uWSGI cgi client ***
|
||||
|
||||
to compile:
|
||||
gcc -Wall -o uwsgi_client.cgi uwsgi_client.c
|
||||
to compile:
|
||||
gcc -Wall -o uwsgi_client.cgi uwsgi_client.c
|
||||
|
||||
*/
|
||||
|
||||
@@ -18,79 +18,79 @@ to compile:
|
||||
#define UWSGI_SOCK "/tmp/uwsgi.sock"
|
||||
|
||||
int main() {
|
||||
extern char **environ;
|
||||
char *env ;
|
||||
struct sockaddr_un s_addr ;
|
||||
int uwsgi_socket ;
|
||||
int res, cnt;
|
||||
char *place_holder;
|
||||
|
||||
unsigned short len ;
|
||||
char message[4096];
|
||||
char *mptr;
|
||||
extern char **environ;
|
||||
char *env;
|
||||
struct sockaddr_un s_addr;
|
||||
int uwsgi_socket;
|
||||
int res, cnt;
|
||||
char *place_holder;
|
||||
|
||||
unsigned short len;
|
||||
char message[4096];
|
||||
char *mptr;
|
||||
char *content_length;
|
||||
|
||||
memset(&s_addr, 0, sizeof(struct sockaddr_un)) ;
|
||||
memset(&s_addr, 0, sizeof(struct sockaddr_un));
|
||||
|
||||
s_addr.sun_family = AF_UNIX;
|
||||
strcpy(s_addr.sun_path, UWSGI_SOCK);
|
||||
s_addr.sun_family = AF_UNIX;
|
||||
strcpy(s_addr.sun_path, UWSGI_SOCK);
|
||||
|
||||
uwsgi_socket = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (uwsgi_socket < 0) {
|
||||
perror("socket()");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_socket = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (uwsgi_socket < 0) {
|
||||
perror("socket()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (connect(uwsgi_socket, (struct sockaddr *) &s_addr, strlen(UWSGI_SOCK) + ( (void *)&s_addr.sun_path - (void *)&s_addr) ) != 0) {
|
||||
perror("connect()");
|
||||
exit(1);
|
||||
}
|
||||
if (connect(uwsgi_socket, (struct sockaddr *) &s_addr, strlen(UWSGI_SOCK) + ( (void *)&s_addr.sun_path - (void *)&s_addr) ) != 0) {
|
||||
perror("connect()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(message, 0, 4096);
|
||||
memset(message, 0, 4096);
|
||||
|
||||
mptr = message+4;
|
||||
mptr = message+4;
|
||||
|
||||
if (**environ) {
|
||||
while( (env = *environ) ) {
|
||||
place_holder = strchr(env,'=');
|
||||
// key
|
||||
len = place_holder-env ;
|
||||
memcpy(mptr, &len, 2);
|
||||
mptr+=2;
|
||||
memcpy(mptr, env, len);
|
||||
mptr+=len ;
|
||||
// value
|
||||
len = (unsigned short) (env+strlen(env) - (place_holder+1)) ;
|
||||
memcpy(mptr, &len, 2);
|
||||
mptr+=2;
|
||||
memcpy(mptr, place_holder+1, len);
|
||||
mptr+= len ;
|
||||
*environ++;
|
||||
}
|
||||
}
|
||||
|
||||
message[0] = 0;
|
||||
len = (mptr-message)-4 ;
|
||||
memcpy(message+1, &len, 2) ;
|
||||
message[3] = 0 ;
|
||||
|
||||
res = send(uwsgi_socket, message, mptr-message, 0);
|
||||
|
||||
if ( (content_length = getenv("CONTENT_LENGTH")) != NULL) {
|
||||
if (atoi(content_length) > 0) {
|
||||
while( (cnt = read(0, message, 4096)) ) {
|
||||
send(uwsgi_socket, message, cnt, 0) ;
|
||||
}
|
||||
if (**environ) {
|
||||
while( (env = *environ) ) {
|
||||
place_holder = strchr(env,'=');
|
||||
// key
|
||||
len = place_holder-env;
|
||||
memcpy(mptr, &len, 2);
|
||||
mptr+=2;
|
||||
memcpy(mptr, env, len);
|
||||
mptr+=len;
|
||||
// value
|
||||
len = (unsigned short) (env+strlen(env) - (place_holder+1));
|
||||
memcpy(mptr, &len, 2);
|
||||
mptr+=2;
|
||||
memcpy(mptr, place_holder+1, len);
|
||||
mptr+= len;
|
||||
*environ++;
|
||||
}
|
||||
}
|
||||
|
||||
if (res == mptr-message) {
|
||||
while( (res = recv(uwsgi_socket, message, 4096,0)) ) {
|
||||
write(1, message, res) ;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
message[0] = 0;
|
||||
len = (mptr-message)-4;
|
||||
memcpy(message+1, &len, 2);
|
||||
message[3] = 0;
|
||||
|
||||
res = send(uwsgi_socket, message, mptr-message, 0);
|
||||
|
||||
if ( (content_length = getenv("CONTENT_LENGTH")) != NULL) {
|
||||
if (atoi(content_length) > 0) {
|
||||
while( (cnt = read(0, message, 4096)) ) {
|
||||
send(uwsgi_socket, message, cnt, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (res == mptr-message) {
|
||||
while( (res = recv(uwsgi_socket, message, 4096,0)) ) {
|
||||
write(1, message, res);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
*** uWSGI cgi client ***
|
||||
|
||||
to compile:
|
||||
gcc -Wall -o uwsgi_client.cgi uwsgi_dynamic_client.c
|
||||
to compile:
|
||||
gcc -Wall -o uwsgi_client.cgi uwsgi_dynamic_client.c
|
||||
|
||||
*/
|
||||
|
||||
@@ -19,77 +19,77 @@ to compile:
|
||||
#define UWSGI_SCRIPT "myapp_wsgi"
|
||||
|
||||
int main() {
|
||||
extern char **environ;
|
||||
char *env ;
|
||||
struct sockaddr_un s_addr ;
|
||||
int uwsgi_socket ;
|
||||
int res, cnt;
|
||||
char *place_holder;
|
||||
|
||||
unsigned short len ;
|
||||
char message[4096];
|
||||
char *mptr;
|
||||
extern char **environ;
|
||||
char *env;
|
||||
struct sockaddr_un s_addr;
|
||||
int uwsgi_socket;
|
||||
int res, cnt;
|
||||
char *place_holder;
|
||||
|
||||
memset(&s_addr, 0, sizeof(struct sockaddr_un)) ;
|
||||
unsigned short len;
|
||||
char message[4096];
|
||||
char *mptr;
|
||||
|
||||
s_addr.sun_family = AF_UNIX;
|
||||
strcpy(s_addr.sun_path, UWSGI_SOCK);
|
||||
memset(&s_addr, 0, sizeof(struct sockaddr_un));
|
||||
|
||||
uwsgi_socket = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (uwsgi_socket < 0) {
|
||||
perror("socket()");
|
||||
exit(1);
|
||||
}
|
||||
s_addr.sun_family = AF_UNIX;
|
||||
strcpy(s_addr.sun_path, UWSGI_SOCK);
|
||||
|
||||
if (connect(uwsgi_socket, (struct sockaddr *) &s_addr, strlen(UWSGI_SOCK) + ( (void *)&s_addr.sun_path - (void *)&s_addr) ) != 0) {
|
||||
perror("connect()");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_socket = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (uwsgi_socket < 0) {
|
||||
perror("socket()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(message, 0, 4096);
|
||||
if (connect(uwsgi_socket, (struct sockaddr *) &s_addr, strlen(UWSGI_SOCK) + ( (void *)&s_addr.sun_path - (void *)&s_addr) ) != 0) {
|
||||
perror("connect()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
mptr = message+4;
|
||||
if (setenv("UWSGI_SCRIPT", UWSGI_SCRIPT, 1) != 0) {
|
||||
perror("setenv()");
|
||||
exit(1);
|
||||
}
|
||||
if (**environ) {
|
||||
while( (env = *environ) ) {
|
||||
place_holder = strchr(env,'=');
|
||||
// key
|
||||
len = place_holder-env ;
|
||||
memcpy(mptr, &len, 2);
|
||||
mptr+=2;
|
||||
memcpy(mptr, env, len);
|
||||
mptr+=len ;
|
||||
// value
|
||||
len = (unsigned short) (env+strlen(env) - (place_holder+1)) ;
|
||||
memcpy(mptr, &len, 2);
|
||||
mptr+=2;
|
||||
memcpy(mptr, place_holder+1, len);
|
||||
mptr+= len ;
|
||||
*environ++;
|
||||
}
|
||||
}
|
||||
memset(message, 0, 4096);
|
||||
|
||||
message[0] = 0;
|
||||
len = (mptr-message)-4 ;
|
||||
memcpy(message+1, &len, 2) ;
|
||||
message[3] = 0 ;
|
||||
mptr = message+4;
|
||||
if (setenv("UWSGI_SCRIPT", UWSGI_SCRIPT, 1) != 0) {
|
||||
perror("setenv()");
|
||||
exit(1);
|
||||
}
|
||||
if (**environ) {
|
||||
while( (env = *environ) ) {
|
||||
place_holder = strchr(env,'=');
|
||||
// key
|
||||
len = place_holder-env;
|
||||
memcpy(mptr, &len, 2);
|
||||
mptr+=2;
|
||||
memcpy(mptr, env, len);
|
||||
mptr+=len;
|
||||
// value
|
||||
len = (unsigned short) (env+strlen(env) - (place_holder+1));
|
||||
memcpy(mptr, &len, 2);
|
||||
mptr+=2;
|
||||
memcpy(mptr, place_holder+1, len);
|
||||
mptr+= len;
|
||||
*environ++;
|
||||
}
|
||||
}
|
||||
|
||||
res = send(uwsgi_socket, message, mptr-message, 0);
|
||||
message[0] = 0;
|
||||
len = (mptr-message)-4;
|
||||
memcpy(message+1, &len, 2);
|
||||
message[3] = 0;
|
||||
|
||||
while( (cnt = read(0, message, 4096)) ) {
|
||||
send(uwsgi_socket, message, cnt, 0) ;
|
||||
}
|
||||
res = send(uwsgi_socket, message, mptr-message, 0);
|
||||
|
||||
while( (cnt = read(0, message, 4096)) ) {
|
||||
send(uwsgi_socket, message, cnt, 0);
|
||||
}
|
||||
|
||||
if (res == mptr-message) {
|
||||
while( (res = recv(uwsgi_socket, message, 4096,0)) ) {
|
||||
write(1, message, res);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
if (res == mptr-message) {
|
||||
while( (res = recv(uwsgi_socket, message, 4096,0)) ) {
|
||||
write(1, message, res) ;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Vendored
-6
@@ -1,6 +0,0 @@
|
||||
Package: uwsgi
|
||||
Version: 0.9.5
|
||||
Maintainer: Unbit
|
||||
Description: Fast, developer-friendly wsgi server
|
||||
Architecture: all
|
||||
Depends: python, libxml2
|
||||
@@ -56,9 +56,30 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="module" style="width:860px">
|
||||
<table>
|
||||
<caption style="width:860px">spooler jobs</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="row">job filename</th>
|
||||
<th scope="row">environment</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for j in jobs %}
|
||||
<tr>
|
||||
<td align="left">{{j.file}}</td>
|
||||
<td align="left">{{j.env}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% if masterpid %}
|
||||
<br/>
|
||||
<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="reload/" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="submit" value="gracefully reload uWSGI" name="_reload"/>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
@@ -14,12 +14,18 @@ def index(request):
|
||||
w['load'] = (100 * (w['running_time']/1000))/total_load
|
||||
w['last_spawn_str'] = time.ctime(w['last_spawn'])
|
||||
|
||||
spooler_jobs = uwsgi.spooler_jobs()
|
||||
jobs = []
|
||||
for j in spooler_jobs:
|
||||
jobs.append({'file': j, 'env': uwsgi.parsefile(j)})
|
||||
|
||||
return render_to_response('uwsgi.html', {'masterpid': uwsgi.masterpid(),
|
||||
'started_on': time.ctime(uwsgi.started_on),
|
||||
'buffer_size': uwsgi.buffer_size,
|
||||
'total_requests': uwsgi.total_requests(),
|
||||
'numproc': uwsgi.numproc,
|
||||
'workers': workers,
|
||||
'jobs': jobs,
|
||||
}, RequestContext(request, {}))
|
||||
index = staff_member_required(index)
|
||||
|
||||
|
||||
@@ -0,0 +1,351 @@
|
||||
#include "uwsgi.h"
|
||||
#include <glob.h>
|
||||
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
extern char **environ;
|
||||
|
||||
struct uwsgi_instance {
|
||||
struct uwsgi_instance *ui_prev;
|
||||
struct uwsgi_instance *ui_next;
|
||||
|
||||
char name[0xff];
|
||||
pid_t pid ;
|
||||
|
||||
int status;
|
||||
time_t born;
|
||||
time_t last_mod;
|
||||
|
||||
uint64_t respawns;
|
||||
|
||||
int pipe[2];
|
||||
};
|
||||
|
||||
struct uwsgi_instance *ui;
|
||||
|
||||
struct uwsgi_instance *emperor_get(char *name) {
|
||||
|
||||
struct uwsgi_instance *c_ui = ui;
|
||||
|
||||
while(c_ui->ui_next) {
|
||||
c_ui = c_ui->ui_next;
|
||||
|
||||
if (!strcmp(c_ui->name, name)) {
|
||||
return c_ui;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void emperor_del(struct uwsgi_instance *c_ui) {
|
||||
|
||||
struct uwsgi_instance *parent_ui = c_ui->ui_prev;
|
||||
struct uwsgi_instance *child_ui = c_ui->ui_next;
|
||||
|
||||
parent_ui->ui_next = child_ui;
|
||||
if (child_ui) {
|
||||
child_ui->ui_prev = parent_ui;
|
||||
}
|
||||
|
||||
// this will destroy the whole uWSGI instance (and workers)
|
||||
close(c_ui->pipe[0]);
|
||||
|
||||
uwsgi_log("removed uwsgi instance %s\n", c_ui->name);
|
||||
|
||||
free(c_ui);
|
||||
|
||||
}
|
||||
|
||||
void emperor_stop(struct uwsgi_instance *c_ui) {
|
||||
// remove uWSGI instance
|
||||
|
||||
if (write(c_ui->pipe[0], "\0", 1) != 1) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
|
||||
c_ui->status = 1;
|
||||
|
||||
uwsgi_log("stop the uwsgi instance %s\n", c_ui->name);
|
||||
}
|
||||
|
||||
void emperor_respawn(struct uwsgi_instance *c_ui, time_t mod) {
|
||||
|
||||
// reload the uWSGI instance
|
||||
if (write(c_ui->pipe[0], "\1", 1) != 1) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
|
||||
c_ui->respawns++;
|
||||
c_ui->last_mod = mod;
|
||||
|
||||
uwsgi_log("reload the uwsgi instance %s\n", c_ui->name);
|
||||
}
|
||||
|
||||
void emperor_add(char *name, time_t born) {
|
||||
|
||||
struct uwsgi_instance *c_ui = ui;
|
||||
struct uwsgi_instance *n_ui = NULL;
|
||||
pid_t pid ;
|
||||
char *argv[4];
|
||||
char *uef ;
|
||||
char **uenvs;
|
||||
|
||||
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));
|
||||
|
||||
c_ui->ui_next = n_ui;
|
||||
uwsgi_log("c_ui->ui_next = %p\n", c_ui->ui_next);
|
||||
n_ui->ui_prev = c_ui;
|
||||
memcpy(n_ui->name, name, strlen(name));
|
||||
n_ui->born = born;
|
||||
n_ui->last_mod = born;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe)) {
|
||||
uwsgi_error("socketpair()");
|
||||
goto clear;
|
||||
}
|
||||
|
||||
// a new uWSGI instance will start
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
uwsgi_error("fork()")
|
||||
}
|
||||
else if (pid > 0) {
|
||||
n_ui->pid = pid;
|
||||
// close the right side of the pipe
|
||||
close(n_ui->pipe[1]);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
|
||||
unsetenv("UWSGI_RELOADS");
|
||||
|
||||
uef = uwsgi_num2str(n_ui->pipe[1]);
|
||||
if (setenv("UWSGI_EMPEROR_FD", uef, 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
exit(1);
|
||||
}
|
||||
free(uef);
|
||||
|
||||
uenvs = environ;
|
||||
while(*uenvs) {
|
||||
if (!strncmp(*uenvs, "UWSGI_VASSAL_", 13)) {
|
||||
char *ne = uwsgi_concat2("UWSGI_", *uenvs+13);
|
||||
char *oe = uwsgi_concat2n(*uenvs, strchr(*uenvs, '=') - *uenvs, "", 0);
|
||||
if (unsetenv(oe)) {
|
||||
uwsgi_error("unsetenv()");
|
||||
break;
|
||||
}
|
||||
free(oe);
|
||||
uwsgi_log("putenv %s\n", ne);
|
||||
|
||||
if (putenv(ne)) {
|
||||
uwsgi_error("putenv()");
|
||||
}
|
||||
// do not free ne as putenv will add it to the environ
|
||||
uenvs = environ;
|
||||
continue;
|
||||
}
|
||||
uenvs++;
|
||||
}
|
||||
|
||||
// close the left side of the pipe
|
||||
close(n_ui->pipe[0]);
|
||||
|
||||
|
||||
// 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";
|
||||
argv[2] = name;
|
||||
argv[3] = NULL;
|
||||
// start !!!
|
||||
if (execvp(argv[0], argv)) {
|
||||
uwsgi_error("execvp()");
|
||||
}
|
||||
// never here
|
||||
exit(1);
|
||||
}
|
||||
|
||||
clear:
|
||||
|
||||
free(n_ui);
|
||||
c_ui->ui_next = NULL;
|
||||
|
||||
}
|
||||
|
||||
void emperor_loop() {
|
||||
|
||||
// monitor a directory
|
||||
|
||||
struct uwsgi_instance ui_base;
|
||||
struct uwsgi_instance *ui_current;
|
||||
struct stat st;
|
||||
|
||||
pid_t diedpid;
|
||||
int waitpid_status;
|
||||
int has_children = 0;
|
||||
int i_am_alone = 0;
|
||||
int simple_mode = 0;
|
||||
glob_t g;
|
||||
int i;
|
||||
struct dirent *de;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_error("glob()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ui = &ui_base;
|
||||
|
||||
for(;;) {
|
||||
|
||||
|
||||
if (!i_am_alone) {
|
||||
diedpid = waitpid(uwsgi.emperor_pid, &waitpid_status, WNOHANG);
|
||||
if (diedpid < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
}
|
||||
else if (diedpid > 0) {
|
||||
i_am_alone = 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")
|
||||
) {
|
||||
|
||||
|
||||
if (strlen(de->d_name) >= 0xff) continue;
|
||||
|
||||
if (stat(de->d_name, &st)) continue;
|
||||
|
||||
if (!S_ISREG(st.st_mode)) continue;
|
||||
|
||||
ui_current = emperor_get(de->d_name);
|
||||
|
||||
if (ui_current) {
|
||||
// check if mtime is changed and the uWSGI instance must be reloaded
|
||||
if (st.st_mtime > ui_current->last_mod) {
|
||||
emperor_respawn(ui_current, st.st_mtime);
|
||||
}
|
||||
}
|
||||
else {
|
||||
emperor_add(de->d_name, st.st_mtime);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
else {
|
||||
if (glob(uwsgi.emperor_dir, GLOB_MARK, 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")
|
||||
) {
|
||||
|
||||
|
||||
if (strlen(g.gl_pathv[i]) >= 0xff) continue;
|
||||
|
||||
if (stat(g.gl_pathv[i], &st)) continue;
|
||||
|
||||
if (!S_ISREG(st.st_mode)) continue;
|
||||
|
||||
ui_current = emperor_get(g.gl_pathv[i]);
|
||||
|
||||
if (ui_current) {
|
||||
// check if 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;
|
||||
has_children++;
|
||||
}
|
||||
|
||||
if (has_children) {
|
||||
diedpid = waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
|
||||
}
|
||||
else {
|
||||
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);
|
||||
emperor_del(ui_current);
|
||||
break;
|
||||
}
|
||||
else if (ui_current->status == 1) {
|
||||
// remove 'marked for dead' instance
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,702 +0,0 @@
|
||||
#ifdef UWSGI_ERLANG
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
static void erlang_log(void);
|
||||
|
||||
PyObject *py_erlang_connect(PyObject * self, PyObject * args) {
|
||||
|
||||
char *erlang_node;
|
||||
int fd;
|
||||
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s:erlang_connect", &erlang_node)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UWSGI_SET_BLOCKING;
|
||||
fd = erl_connect(erlang_node);
|
||||
UWSGI_UNSET_BLOCKING;
|
||||
return PyInt_FromLong(fd);
|
||||
}
|
||||
|
||||
PyObject *py_erlang_recv_message(PyObject * self, PyObject * args) {
|
||||
int erfd;
|
||||
struct pollfd erpoll;
|
||||
ErlMessage emsg;
|
||||
PyObject *pyer = NULL;
|
||||
unsigned char erlang_buffer[8192];
|
||||
int eret;
|
||||
int timeout = uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT];
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i|i:erlang_recv_message", &erfd, &timeout)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (erfd < 0) {
|
||||
goto clear;
|
||||
}
|
||||
|
||||
erpoll.fd = erfd;
|
||||
erpoll.events = POLLIN;
|
||||
cycle:
|
||||
memset(&emsg, 0, sizeof(ErlMessage));
|
||||
UWSGI_SET_BLOCKING;
|
||||
if (timeout > 0) {
|
||||
eret = poll(&erpoll, 1, timeout * 1000);
|
||||
if (eret < 0) {
|
||||
uwsgi_error("poll()");
|
||||
goto clear;
|
||||
}
|
||||
else if (eret == 0) {
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
if (erl_receive_msg(erfd, erlang_buffer, 8192, &emsg) == ERL_MSG) {
|
||||
if (emsg.type == ERL_TICK) {
|
||||
goto cycle;
|
||||
}
|
||||
if (emsg.msg) {
|
||||
pyer = eterm_to_py(emsg.msg);
|
||||
}
|
||||
if (emsg.msg) {
|
||||
erl_free_compound(emsg.msg);
|
||||
}
|
||||
if (emsg.to) {
|
||||
erl_free_compound(emsg.to);
|
||||
}
|
||||
if (emsg.from) {
|
||||
erl_free_compound(emsg.from);
|
||||
}
|
||||
if (!pyer) {
|
||||
goto clear;
|
||||
}
|
||||
UWSGI_UNSET_BLOCKING;
|
||||
return pyer;
|
||||
}
|
||||
|
||||
clear:
|
||||
UWSGI_UNSET_BLOCKING;
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
|
||||
}
|
||||
|
||||
PyObject *py_erlang_send_message(PyObject * self, PyObject * args) {
|
||||
|
||||
ETERM *pymessage;
|
||||
ETERM *pid;
|
||||
int erfd;
|
||||
PyObject *ermessage, *erdest, *zero;
|
||||
|
||||
int er_number, er_serial, er_creation;
|
||||
char *er_node;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iOO|i:erlang_send_message", &erfd, &erdest, &ermessage)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (erfd < 0) {
|
||||
goto clear;
|
||||
}
|
||||
|
||||
if (!PyString_Check(erdest) && !PyDict_Check(erdest)) {
|
||||
goto clear;
|
||||
}
|
||||
|
||||
pymessage = py_to_eterm(ermessage);
|
||||
if (!pymessage) {
|
||||
goto clear;
|
||||
}
|
||||
|
||||
|
||||
if (PyString_Check(erdest)) {
|
||||
if (!erl_reg_send(erfd, PyString_AsString(erdest), pymessage)) {
|
||||
erl_err_msg("erl_reg_send()");
|
||||
goto clear2;
|
||||
}
|
||||
}
|
||||
else if (PyDict_Check(erdest)) {
|
||||
zero = PyDict_GetItemString(erdest, "node");
|
||||
if (!zero) {
|
||||
goto clear2;
|
||||
}
|
||||
if (!PyString_Check(zero)) {
|
||||
goto clear2;
|
||||
}
|
||||
er_node = PyString_AsString(zero);
|
||||
|
||||
zero = PyDict_GetItemString(erdest, "number");
|
||||
if (!zero) {
|
||||
goto clear2;
|
||||
}
|
||||
if (!PyInt_Check(zero)) {
|
||||
goto clear2;
|
||||
}
|
||||
er_number = PyInt_AsLong(zero);
|
||||
|
||||
zero = PyDict_GetItemString(erdest, "serial");
|
||||
if (!zero) {
|
||||
goto clear2;
|
||||
}
|
||||
if (!PyInt_Check(zero)) {
|
||||
goto clear2;
|
||||
}
|
||||
er_serial = PyInt_AsLong(zero);
|
||||
|
||||
zero = PyDict_GetItemString(erdest, "creation");
|
||||
if (!zero) {
|
||||
goto clear2;
|
||||
}
|
||||
if (!PyInt_Check(zero)) {
|
||||
goto clear2;
|
||||
}
|
||||
er_creation = PyInt_AsLong(zero);
|
||||
|
||||
pid = erl_mk_pid((const char *) er_node, er_number, er_serial, er_creation);
|
||||
|
||||
if (!pid) {
|
||||
goto clear2;
|
||||
}
|
||||
|
||||
if (!erl_send(erfd, pid, pymessage)) {
|
||||
erl_err_msg("erl_send()");
|
||||
erl_free_term(pid);
|
||||
goto clear2;
|
||||
}
|
||||
|
||||
erl_free_term(pid);
|
||||
}
|
||||
else {
|
||||
goto clear;
|
||||
}
|
||||
|
||||
erl_free_compound(pymessage);
|
||||
|
||||
Py_INCREF(Py_True);
|
||||
return Py_True;
|
||||
|
||||
clear2:
|
||||
erl_free_compound(pymessage);
|
||||
clear:
|
||||
PyErr_Print();
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject *py_erlang_rpc(PyObject * self, PyObject * args) {
|
||||
|
||||
int fd, timeout = uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT];
|
||||
char *emod, *efun;
|
||||
PyObject *eargs, *pyer = NULL;
|
||||
ETERM *pyargs, *rex;
|
||||
ErlMessage emsg;
|
||||
int eret;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "issO|i:erlang_rpc", &fd, &emod, &efun, &eargs, &timeout)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fd < 0) {
|
||||
goto clear;
|
||||
}
|
||||
|
||||
pyargs = py_to_eterm(eargs);
|
||||
if (!pyargs) {
|
||||
goto clear;
|
||||
}
|
||||
|
||||
|
||||
if (erl_rpc_to(fd, emod, efun, pyargs)) {
|
||||
erl_err_msg("erl_rpc_to()");
|
||||
goto clear2;
|
||||
}
|
||||
|
||||
|
||||
cycle:
|
||||
memset(&emsg, 0, sizeof(ErlMessage));
|
||||
UWSGI_SET_BLOCKING;
|
||||
eret = erl_rpc_from(fd, timeout * 1000, &emsg);
|
||||
if (eret == ERL_TICK) {
|
||||
goto cycle;
|
||||
}
|
||||
else if (eret == ERL_MSG) {
|
||||
if (emsg.msg) {
|
||||
if (ERL_IS_TUPLE(emsg.msg)) {
|
||||
rex = erl_element(1, emsg.msg);
|
||||
if (!rex) {
|
||||
goto clear2;
|
||||
}
|
||||
if (!strncmp("rex", ERL_ATOM_PTR(rex), ERL_ATOM_SIZE(rex))) {
|
||||
erl_free_term(rex);
|
||||
rex = erl_element(2, emsg.msg);
|
||||
if (!rex) {
|
||||
goto clear2;
|
||||
}
|
||||
pyer = eterm_to_py(rex);
|
||||
erl_free_term(rex);
|
||||
}
|
||||
else {
|
||||
erl_free_term(rex);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (emsg.msg) {
|
||||
erl_free_compound(emsg.msg);
|
||||
}
|
||||
if (emsg.to) {
|
||||
erl_free_compound(emsg.to);
|
||||
}
|
||||
if (emsg.from) {
|
||||
erl_free_compound(emsg.from);
|
||||
}
|
||||
if (!pyer) {
|
||||
goto clear2;
|
||||
}
|
||||
erl_free_compound(pyargs);
|
||||
UWSGI_UNSET_BLOCKING;
|
||||
return pyer;
|
||||
}
|
||||
else {
|
||||
erl_err_msg("erl_rpc_from()");
|
||||
}
|
||||
|
||||
clear2:
|
||||
UWSGI_UNSET_BLOCKING;
|
||||
erl_free_compound(pyargs);
|
||||
|
||||
clear:
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject *py_erlang_close(PyObject * self, PyObject * args) {
|
||||
|
||||
int fd;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i:erlang_close", &fd)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if (fd >= 0) {
|
||||
erl_close_connection(fd);
|
||||
}
|
||||
|
||||
Py_INCREF(Py_True);
|
||||
return Py_True;
|
||||
}
|
||||
|
||||
static PyMethodDef uwsgi_erlang_methods[] = {
|
||||
{"erlang_connect", py_erlang_connect, METH_VARARGS, ""},
|
||||
{"erlang_send_message", py_erlang_send_message, METH_VARARGS, ""},
|
||||
{"erlang_recv_message", py_erlang_recv_message, METH_VARARGS, ""},
|
||||
{"erlang_rpc", py_erlang_rpc, METH_VARARGS, ""},
|
||||
{"erlang_close", py_erlang_close, METH_VARARGS, ""},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
|
||||
int init_erlang(char *nodename, char *cookie) {
|
||||
|
||||
struct sockaddr_in e_addr;
|
||||
|
||||
char *ip;
|
||||
char *node;
|
||||
int efd;
|
||||
int rlen;
|
||||
char *cookiefile;
|
||||
char *cookiehome;
|
||||
char cookievalue[128];
|
||||
int cookiefd;
|
||||
|
||||
PyMethodDef *uwsgi_function;
|
||||
|
||||
|
||||
ip = strchr(nodename, '@');
|
||||
|
||||
if (ip == NULL) {
|
||||
uwsgi_log( "*** invalid erlang node name ***\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cookie == NULL) {
|
||||
// get the cookie from the home
|
||||
cookiehome = getenv("HOME");
|
||||
if (!cookiehome) {
|
||||
uwsgi_log( "unable to get erlang cookie from your home.\n");
|
||||
return -1;
|
||||
}
|
||||
cookiefile = malloc(strlen(cookiehome) + 1 + strlen(".erlang.cookie") + 1);
|
||||
if (!cookiefile) {
|
||||
uwsgi_error("malloc()");
|
||||
}
|
||||
cookiefile[0] = 0;
|
||||
strcat(cookiefile, cookiehome);
|
||||
strcat(cookiefile, "/.erlang.cookie");
|
||||
|
||||
cookiefd = open(cookiefile, O_RDONLY);
|
||||
if (cookiefd < 0) {
|
||||
uwsgi_error("open()");
|
||||
free(cookiefile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(cookievalue, 0, 128);
|
||||
if (read(cookiefd, cookievalue, 127) < 1) {
|
||||
uwsgi_log( "invalid cookie found in %s\n", cookiefile);
|
||||
close(cookiefd);
|
||||
free(cookiefile);
|
||||
return -1;
|
||||
}
|
||||
cookie = cookievalue;
|
||||
close(cookiefd);
|
||||
free(cookiefile);
|
||||
}
|
||||
|
||||
node = malloc((ip - nodename) + 1);
|
||||
if (node == NULL) {
|
||||
uwsgi_error("malloc()");
|
||||
return -1;
|
||||
}
|
||||
memset(node, 0, (ip - nodename) + 1);
|
||||
memcpy(node, nodename, ip - nodename);
|
||||
|
||||
erl_init(NULL, 0);
|
||||
|
||||
if (erl_connect_xinit(ip + 1, node, nodename, NULL, cookie, 0) == -1) {
|
||||
uwsgi_log( "*** unable to initialize erlang c-node ***\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
efd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (efd < 0) {
|
||||
uwsgi_error("socket()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
memset(&e_addr, 0, sizeof(struct sockaddr_in));
|
||||
e_addr.sin_family = AF_INET;
|
||||
e_addr.sin_addr.s_addr = inet_addr(ip + 1);
|
||||
|
||||
rlen = 1;
|
||||
if (setsockopt(efd, SOL_SOCKET, SO_REUSEADDR, &rlen, sizeof(rlen))) {
|
||||
uwsgi_error("setsockopt()");
|
||||
close(efd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bind(efd, (struct sockaddr *) &e_addr, sizeof(struct sockaddr_in)) < 0) {
|
||||
uwsgi_error("bind()");
|
||||
close(efd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rlen = sizeof(struct sockaddr_in);
|
||||
if (getsockname(efd, (struct sockaddr *) &e_addr, (socklen_t *) & rlen)) {
|
||||
uwsgi_error("getsockname()");
|
||||
close(efd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(efd, uwsgi.listen_queue)) {
|
||||
uwsgi_error("listen()");
|
||||
close(efd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (erl_publish(ntohs(e_addr.sin_port)) < 0) {
|
||||
uwsgi_log( "*** unable to subscribe with EPMD ***\n");
|
||||
close(efd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_log( "Erlang C-Node initialized on port %d you can access it with name %s\n", ntohs(e_addr.sin_port), nodename);
|
||||
|
||||
for (uwsgi_function = uwsgi_erlang_methods; uwsgi_function->ml_name != NULL; uwsgi_function++) {
|
||||
PyObject *func = PyCFunction_New(uwsgi_function, NULL);
|
||||
PyDict_SetItemString(uwsgi.embedded_dict, uwsgi_function->ml_name, func);
|
||||
Py_DECREF(func);
|
||||
}
|
||||
|
||||
return efd;
|
||||
|
||||
}
|
||||
|
||||
ETERM *py_to_eterm(PyObject * pobj) {
|
||||
int i;
|
||||
int count;
|
||||
PyObject *pobj2;
|
||||
ETERM *eobj = NULL;
|
||||
ETERM *eobj2 = NULL;
|
||||
ETERM **eobj3;
|
||||
|
||||
if (pobj == NULL) {
|
||||
return erl_mk_empty_list();
|
||||
}
|
||||
|
||||
if (PyString_Check(pobj)) {
|
||||
eobj = erl_mk_atom(PyString_AsString(pobj));
|
||||
}
|
||||
else if (PyInt_Check(pobj)) {
|
||||
eobj = erl_mk_int(PyInt_AsLong(pobj));
|
||||
}
|
||||
else if (PyList_Check(pobj)) {
|
||||
eobj = erl_mk_empty_list();
|
||||
for (i = PyList_Size(pobj) - 1; i >= 0; i--) {
|
||||
pobj2 = PyList_GetItem(pobj, i);
|
||||
eobj2 = py_to_eterm(pobj2);
|
||||
eobj = erl_cons(eobj2, eobj);
|
||||
}
|
||||
}
|
||||
else if (PyDict_Check(pobj)) {
|
||||
// a pid
|
||||
char *er_node;
|
||||
int er_number, er_serial, er_creation;
|
||||
pobj2 = PyDict_GetItemString(pobj, "node");
|
||||
if (!pobj2) {
|
||||
PyErr_Print();
|
||||
goto clear;
|
||||
}
|
||||
if (!PyString_Check(pobj2)) {
|
||||
goto clear;
|
||||
}
|
||||
er_node = PyString_AsString(pobj2);
|
||||
|
||||
pobj2 = PyDict_GetItemString(pobj, "number");
|
||||
if (!pobj2) {
|
||||
PyErr_Print();
|
||||
goto clear;
|
||||
}
|
||||
if (!PyInt_Check(pobj2)) {
|
||||
goto clear;
|
||||
}
|
||||
er_number = PyInt_AsLong(pobj2);
|
||||
|
||||
pobj2 = PyDict_GetItemString(pobj, "serial");
|
||||
if (!pobj2) {
|
||||
PyErr_Print();
|
||||
goto clear;
|
||||
}
|
||||
if (!PyInt_Check(pobj2)) {
|
||||
goto clear;
|
||||
}
|
||||
er_serial = PyInt_AsLong(pobj2);
|
||||
|
||||
pobj2 = PyDict_GetItemString(pobj, "creation");
|
||||
if (!pobj2) {
|
||||
PyErr_Print();
|
||||
goto clear;
|
||||
}
|
||||
if (!PyInt_Check(pobj2)) {
|
||||
goto clear;
|
||||
}
|
||||
er_creation = PyInt_AsLong(pobj2);
|
||||
|
||||
eobj = erl_mk_pid(er_node, er_number, er_serial, er_creation);
|
||||
}
|
||||
else if (PyTuple_Check(pobj)) {
|
||||
count = PyTuple_Size(pobj);
|
||||
eobj3 = malloc(sizeof(ETERM *) * count);
|
||||
for (i = 0; i < count; i++) {
|
||||
pobj2 = PyTuple_GetItem(pobj, i);
|
||||
if (!pobj2) {
|
||||
break;
|
||||
}
|
||||
eobj3[i] = py_to_eterm(pobj2);
|
||||
}
|
||||
eobj = erl_mk_tuple(eobj3, count);
|
||||
free(eobj3);
|
||||
}
|
||||
else {
|
||||
uwsgi_log( "UNMANAGED PYTHON TYPE: %s\n", pobj->ob_type->tp_name);
|
||||
}
|
||||
|
||||
clear:
|
||||
if (eobj == NULL) {
|
||||
return erl_mk_empty_list();
|
||||
}
|
||||
|
||||
return eobj;
|
||||
}
|
||||
|
||||
PyObject *eterm_to_py(ETERM * obj) {
|
||||
int i;
|
||||
int count;
|
||||
ETERM *obj2;
|
||||
PyObject *eobj = NULL;
|
||||
|
||||
if (obj == NULL) {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
switch (ERL_TYPE(obj)) {
|
||||
|
||||
case ERL_CONS:
|
||||
case ERL_NIL:
|
||||
count = erl_length(obj);
|
||||
eobj = PyList_New(0);
|
||||
for (i = 0; i < count; i++) {
|
||||
obj2 = erl_hd(obj);
|
||||
PyList_Append(eobj, eterm_to_py(obj2));
|
||||
obj = erl_tl(obj);
|
||||
}
|
||||
break;
|
||||
case ERL_TUPLE:
|
||||
eobj = PyTuple_New(erl_size(obj));
|
||||
for (i = 1; i <= erl_size(obj); i++) {
|
||||
obj2 = erl_element(i, obj);
|
||||
PyTuple_SetItem(eobj, i - 1, eterm_to_py(obj2));
|
||||
}
|
||||
break;
|
||||
case ERL_ATOM:
|
||||
eobj = PyString_FromStringAndSize(ERL_ATOM_PTR(obj), ERL_ATOM_SIZE(obj));
|
||||
break;
|
||||
case ERL_INTEGER:
|
||||
eobj = PyInt_FromLong(ERL_INT_VALUE(obj));
|
||||
break;
|
||||
case ERL_BINARY:
|
||||
uwsgi_log( "FOUND A BINARY %.*s\n", ERL_BIN_SIZE(obj), ERL_BIN_PTR(obj));
|
||||
break;
|
||||
case ERL_PID:
|
||||
eobj = PyDict_New();
|
||||
if (PyDict_SetItemString(eobj, "node", PyString_FromString(ERL_PID_NODE(obj)))) {
|
||||
PyErr_Print();
|
||||
break;
|
||||
}
|
||||
if (PyDict_SetItemString(eobj, "number", PyInt_FromLong(ERL_PID_NUMBER(obj)))) {
|
||||
PyErr_Print();
|
||||
break;
|
||||
}
|
||||
if (PyDict_SetItemString(eobj, "serial", PyInt_FromLong(ERL_PID_SERIAL(obj)))) {
|
||||
PyErr_Print();
|
||||
break;
|
||||
}
|
||||
if (PyDict_SetItemString(eobj, "creation", PyInt_FromLong(ERL_PID_CREATION(obj)))) {
|
||||
PyErr_Print();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
uwsgi_log( "UNMANAGED ETERM TYPE: %d\n", ERL_TYPE(obj));
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (eobj == NULL) {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
return eobj;
|
||||
}
|
||||
|
||||
void erlang_loop(struct wsgi_request *wsgi_req) {
|
||||
|
||||
ErlConnect econn;
|
||||
ErlMessage em;
|
||||
ETERM *eresponse;
|
||||
|
||||
PyObject *callable = PyDict_GetItemString(uwsgi.embedded_dict, "erlang_func");
|
||||
if (!callable) {
|
||||
PyErr_Print();
|
||||
uwsgi_log( "- you have not defined a uwsgi.erlang_func callable, Erlang message manager will be disabled until you define it -\n");
|
||||
}
|
||||
|
||||
PyObject *pargs = PyTuple_New(1);
|
||||
if (!pargs) {
|
||||
PyErr_Print();
|
||||
uwsgi_log( "- error preparing arg tuple for uwsgi.erlang_func callable, Erlang message manager will be disabled -\n");
|
||||
}
|
||||
|
||||
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
|
||||
|
||||
|
||||
UWSGI_CLEAR_STATUS;
|
||||
|
||||
wsgi_req->poll.fd = erl_accept(uwsgi.erlangfd, &econn);
|
||||
|
||||
if (wsgi_req->poll.fd >= 0) {
|
||||
|
||||
UWSGI_SET_ERLANGING;
|
||||
for (;;) {
|
||||
if (erl_receive_msg(wsgi_req->poll.fd, (unsigned char *) wsgi_req->buffer, uwsgi.buffer_size, &em) == ERL_MSG) {
|
||||
if (em.type == ERL_TICK)
|
||||
continue;
|
||||
|
||||
if (!callable) {
|
||||
callable = PyDict_GetItemString(uwsgi.embedded_dict, "erlang_func");
|
||||
}
|
||||
|
||||
if (!callable) {
|
||||
uwsgi_log( "- you still have not defined a uwsgi.erlang_func callable, Erlang message rejected -\n");
|
||||
}
|
||||
|
||||
PyObject *zero = eterm_to_py(em.msg);
|
||||
if (em.msg) {
|
||||
erl_free_compound(em.msg);
|
||||
}
|
||||
if (em.to) {
|
||||
erl_free_compound(em.to);
|
||||
}
|
||||
|
||||
if (!zero) {
|
||||
PyErr_Print();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (PyTuple_SetItem(pargs, 0, zero)) {
|
||||
PyErr_Print();
|
||||
continue;
|
||||
}
|
||||
|
||||
PyObject *erlang_result = PyEval_CallObject(callable, pargs);
|
||||
|
||||
//Py_DECREF(zero);
|
||||
|
||||
if (erlang_result) {
|
||||
eresponse = py_to_eterm(erlang_result);
|
||||
if (eresponse) {
|
||||
erl_send(wsgi_req->poll.fd, em.from, eresponse);
|
||||
erl_free_compound(eresponse);
|
||||
}
|
||||
Py_DECREF(erlang_result);
|
||||
}
|
||||
|
||||
if (em.from) {
|
||||
erl_free_compound(em.from);
|
||||
}
|
||||
|
||||
uwsgi.workers[0].requests++;
|
||||
uwsgi.workers[uwsgi.mywid].requests++;
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_LOGGING])
|
||||
erlang_log();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
erl_close_connection(wsgi_req->poll.fd);
|
||||
|
||||
UWSGI_UNSET_ERLANGING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void erlang_log() {
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG]) {
|
||||
get_memusage();
|
||||
}
|
||||
else {
|
||||
uwsgi.workers[uwsgi.mywid].rss_size = 0;
|
||||
uwsgi.workers[uwsgi.mywid].vsz_size = 0;
|
||||
}
|
||||
uwsgi_log( "[Erlang worker %d pid %d] request %llu done {rss: %llu vsz: %llu}\n", uwsgi.mywid, uwsgi.mypid, uwsgi.workers[uwsgi.mywid].requests, uwsgi.workers[uwsgi.mywid].rss_size, uwsgi.workers[uwsgi.mywid].vsz_size);
|
||||
}
|
||||
|
||||
#else
|
||||
#warning "*** Erlang support is disabled ***"
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifdef UWSGI_EVDIS
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
void evdis_loop(struct uwsgi_server *uwsgi) {
|
||||
|
||||
// populate event list
|
||||
|
||||
int kfd = kqueue();
|
||||
if (kfd < 0) {
|
||||
uwsgi_error("kqueue()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#else
|
||||
#warning "*** Event Dispatcher support is disabled ***"
|
||||
#endif
|
||||
@@ -0,0 +1,833 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#ifdef UWSGI_EVENT_USE_PORT
|
||||
|
||||
#include <port.h>
|
||||
|
||||
int event_queue_init() {
|
||||
|
||||
int port = port_create();
|
||||
|
||||
if (port < 0) {
|
||||
uwsgi_error("port_create()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
int event_queue_del_fd(int eq, int fd) {
|
||||
|
||||
if (port_dissociate(eq, PORT_SOURCE_FD, fd)) {
|
||||
uwsgi_error("port_disassociate");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
int event_queue_interesting_fd_has_error(void *events, int id) {
|
||||
port_event_t *pe = (port_event_t *) events;
|
||||
if (pe[id].portev_events == POLLHUP || pe[id].portev_events == POLLERR) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int event_queue_add_fd_read(int eq, int fd) {
|
||||
|
||||
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, NULL)) {
|
||||
uwsgi_error("port_associate");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int event_queue_add_fd_write(int eq, int fd) {
|
||||
|
||||
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLOUT, NULL)) {
|
||||
uwsgi_error("port_associate");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
void *event_queue_alloc(int nevents) {
|
||||
|
||||
return uwsgi_malloc(sizeof(port_event_t) * nevents);
|
||||
}
|
||||
|
||||
int event_queue_interesting_fd(void *events, int id) {
|
||||
port_event_t *pe = (port_event_t *) events;
|
||||
if (pe[id].portev_source == PORT_SOURCE_FILE || pe[id].portev_source == PORT_SOURCE_TIMER) {
|
||||
return (int) pe[id].portev_user;
|
||||
}
|
||||
|
||||
return (int) pe[id].portev_object;
|
||||
}
|
||||
|
||||
int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
|
||||
|
||||
int ret;
|
||||
uint_t nget;
|
||||
int i;
|
||||
timespec_t ts;
|
||||
port_event_t *pe;
|
||||
|
||||
if (timeout > 0) {
|
||||
ts.tv_sec = timeout;
|
||||
ts.tv_nsec = 0;
|
||||
ret = port_getn(eq, events, nevents, &nget, &ts);
|
||||
}
|
||||
else {
|
||||
ret = port_getn(eq, events, nevents, &nget, NULL);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
if (errno != ETIME) {
|
||||
uwsgi_error("port_getn()");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
pe = (port_event_t *) events;
|
||||
for(i=0;i<nget;i++) {
|
||||
if (pe[i].portev_source == PORT_SOURCE_FD) {
|
||||
if (port_associate(eq, pe[i].portev_source, pe[i].portev_object, pe[i].portev_events, NULL)) {
|
||||
uwsgi_error("port_associate");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nget;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int event_queue_wait(int eq, int timeout, int *interesting_fd) {
|
||||
|
||||
int ret;
|
||||
port_event_t pe;
|
||||
timespec_t ts;
|
||||
|
||||
if (timeout > 0) {
|
||||
ts.tv_sec = timeout;
|
||||
ts.tv_nsec = 0;
|
||||
ret = port_get(eq, &pe, &ts);
|
||||
}
|
||||
else {
|
||||
ret = port_get(eq, &pe, NULL);
|
||||
}
|
||||
if (ret < 0) {
|
||||
if (errno != ETIME) {
|
||||
uwsgi_error("port_get()");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pe.portev_source == PORT_SOURCE_FD) {
|
||||
// event must be readded (damn Oracle/Sun why the fu*k you made such a horrible choice ???? why not adding a ONESHOT flag ???)
|
||||
if (port_associate(eq, pe.portev_source, pe.portev_object, pe.portev_events, NULL)) {
|
||||
uwsgi_error("port_associate");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (pe.portev_source == PORT_SOURCE_FILE || pe.portev_source == PORT_SOURCE_TIMER) {
|
||||
*interesting_fd = (int) pe.portev_user;
|
||||
uwsgi_log("port event interesting_fd: %d\n", *interesting_fd);
|
||||
}
|
||||
else {
|
||||
*interesting_fd = (int) pe.portev_object;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef UWSGI_EVENT_USE_EPOLL
|
||||
|
||||
#include <sys/epoll.h>
|
||||
|
||||
int event_queue_init() {
|
||||
|
||||
int epfd;
|
||||
|
||||
epfd = epoll_create(256);
|
||||
|
||||
if (epfd < 0) {
|
||||
uwsgi_error("epoll_create()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return epfd;
|
||||
}
|
||||
|
||||
|
||||
int event_queue_add_fd_read(int eq, int fd) {
|
||||
|
||||
struct epoll_event ee;
|
||||
|
||||
memset(&ee, 0, sizeof(struct epoll_event));
|
||||
ee.events = EPOLLIN;
|
||||
ee.data.fd = fd;
|
||||
|
||||
if (epoll_ctl(eq, EPOLL_CTL_ADD, fd, &ee)) {
|
||||
uwsgi_error("epoll_ctl()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int event_queue_fd_write_to_read(int eq, int fd) {
|
||||
|
||||
struct epoll_event ee;
|
||||
|
||||
memset(&ee, 0, sizeof(struct epoll_event));
|
||||
ee.events = EPOLLIN;
|
||||
ee.data.fd = fd;
|
||||
|
||||
if (epoll_ctl(eq, EPOLL_CTL_MOD, fd, &ee)) {
|
||||
uwsgi_error("epoll_ctl()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int event_queue_del_fd(int eq, int fd) {
|
||||
|
||||
struct epoll_event ee;
|
||||
|
||||
memset(&ee, 0, sizeof(struct epoll_event));
|
||||
ee.data.fd = fd;
|
||||
|
||||
if (epoll_ctl(eq, EPOLL_CTL_DEL, fd, &ee)) {
|
||||
uwsgi_error("epoll_ctl()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int event_queue_add_fd_write(int eq, int fd) {
|
||||
|
||||
struct epoll_event ee;
|
||||
|
||||
memset(&ee, 0, sizeof(struct epoll_event));
|
||||
ee.events = EPOLLOUT;
|
||||
ee.data.fd = fd;
|
||||
|
||||
if (epoll_ctl(eq, EPOLL_CTL_ADD, fd, &ee)) {
|
||||
uwsgi_error("epoll_ctl()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
void *event_queue_alloc(int nevents) {
|
||||
|
||||
return uwsgi_malloc(sizeof(struct epoll_event) * nevents);
|
||||
}
|
||||
|
||||
int event_queue_interesting_fd(void *events, int id) {
|
||||
struct epoll_event *ee = (struct epoll_event *) events;
|
||||
return ee[id].data.fd;
|
||||
}
|
||||
|
||||
int event_queue_interesting_fd_has_error(void *events, int id) {
|
||||
struct epoll_event *ee = (struct epoll_event *) events;
|
||||
if (ee[id].events == EPOLLHUP || ee[id].events == EPOLLERR || (ee[id].events == (EPOLLERR|EPOLLHUP))) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
|
||||
|
||||
int ret;
|
||||
|
||||
if (timeout > 0) {
|
||||
timeout = timeout*1000;
|
||||
}
|
||||
|
||||
ret = epoll_wait(eq, (struct epoll_event *) events, nevents, timeout);
|
||||
if (ret < 0) {
|
||||
if (errno != EINTR)
|
||||
uwsgi_error("epoll_wait()");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int event_queue_wait(int eq, int timeout, int *interesting_fd) {
|
||||
|
||||
int ret;
|
||||
struct epoll_event ee;
|
||||
|
||||
if (timeout > 0) {
|
||||
timeout = timeout*1000;
|
||||
}
|
||||
|
||||
ret = epoll_wait(eq, &ee, 1, timeout);
|
||||
if (ret < 0) {
|
||||
if (errno != EINTR)
|
||||
uwsgi_error("epoll_wait()");
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
*interesting_fd = ee.data.fd;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_EVENT_USE_KQUEUE
|
||||
int event_queue_init() {
|
||||
|
||||
int kfd = kqueue();
|
||||
|
||||
if (kfd < 0) {
|
||||
uwsgi_error("kqueue()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return kfd;
|
||||
}
|
||||
|
||||
int event_queue_fd_write_to_read(int eq, int fd) {
|
||||
|
||||
struct kevent kev;
|
||||
|
||||
EV_SET(&kev, fd, EVFILT_WRITE, EV_DISABLE, 0, 0, 0);
|
||||
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
|
||||
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int event_queue_del_fd(int eq, int fd) {
|
||||
|
||||
struct kevent kev;
|
||||
|
||||
EV_SET(&kev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
|
||||
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int event_queue_add_fd_read(int eq, int fd) {
|
||||
|
||||
struct kevent kev;
|
||||
|
||||
EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
|
||||
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int event_queue_add_fd_write(int eq, int fd) {
|
||||
|
||||
struct kevent kev;
|
||||
|
||||
EV_SET(&kev, fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
|
||||
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *event_queue_alloc(int nevents) {
|
||||
|
||||
return uwsgi_malloc(sizeof(struct kevent) * nevents);
|
||||
}
|
||||
|
||||
int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
|
||||
|
||||
int ret;
|
||||
struct timespec ts;
|
||||
|
||||
if (timeout < 0) {
|
||||
ret = kevent(eq, NULL, 0, events, nevents, NULL);
|
||||
}
|
||||
else {
|
||||
memset(&ts, 0, sizeof(struct timespec));
|
||||
ts.tv_sec = timeout;
|
||||
ret = kevent(eq, NULL, 0, (struct kevent *)events, nevents, &ts);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int event_queue_interesting_fd(void *events, int id) {
|
||||
|
||||
struct kevent *ev = (struct kevent *) events;
|
||||
return ev[id].ident;
|
||||
}
|
||||
|
||||
int event_queue_interesting_fd_has_error(void *events, int id) {
|
||||
struct kevent *ev = (struct kevent *) events;
|
||||
|
||||
if ( ( (ev[id].flags == EV_ERROR) || (ev[id].flags == EV_EOF) || (ev[id].flags == (EV_EOF|EV_ERROR))) ) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int event_queue_wait(int eq, int timeout, int *interesting_fd) {
|
||||
|
||||
int ret;
|
||||
struct timespec ts;
|
||||
struct kevent ev;
|
||||
|
||||
if (timeout <= 0) {
|
||||
ret = kevent(eq, NULL, 0, &ev, 1, NULL);
|
||||
}
|
||||
else {
|
||||
memset(&ts, 0, sizeof(struct timespec));
|
||||
ts.tv_sec = timeout;
|
||||
ret = kevent(eq, NULL, 0, &ev, 1, &ts);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
*interesting_fd = ev.ident;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_EVENT_FILEMONITOR_USE_NONE
|
||||
int event_queue_add_file_monitor(int eq, char *filename, int *id) { return -1;}
|
||||
struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {return NULL;}
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_EVENT_FILEMONITOR_USE_PORT
|
||||
int event_queue_add_file_monitor(int eq, char *filename, int *id) {
|
||||
|
||||
struct file_obj fo;
|
||||
struct stat st;
|
||||
static int fmon_id = 0xffffee00;
|
||||
|
||||
if (stat(filename, &st)) {
|
||||
uwsgi_error("stat()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fo.fo_name = filename;
|
||||
fo.fo_atime = st.st_atim;
|
||||
fo.fo_mtime = st.st_mtim;
|
||||
fo.fo_ctime = st.st_ctim;
|
||||
|
||||
fmon_id++;
|
||||
if (port_associate(eq, PORT_SOURCE_FILE, (uintptr_t) &fo, FILE_MODIFIED|FILE_ATTRIB, (void *) fmon_id)) {
|
||||
uwsgi_error("port_associate()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
*id = fmon_id;
|
||||
|
||||
uwsgi_log("added new file to monitor %s [%d]\n", filename, *id);
|
||||
|
||||
return *id;
|
||||
}
|
||||
|
||||
struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
|
||||
|
||||
int i;
|
||||
struct file_obj fo;
|
||||
struct stat st;
|
||||
|
||||
for(i=0;i<ushared->files_monitored_cnt;i++) {
|
||||
if (ushared->files_monitored[i].registered) {
|
||||
if (ushared->files_monitored[i].fd == id) {
|
||||
if (stat(ushared->files_monitored[i].filename, &st)) {
|
||||
uwsgi_error("stat()");
|
||||
return NULL;
|
||||
}
|
||||
fo.fo_name = ushared->files_monitored[i].filename;
|
||||
fo.fo_atime = st.st_atim;
|
||||
fo.fo_mtime = st.st_mtim;
|
||||
fo.fo_ctime = st.st_ctim;
|
||||
if (port_associate(eq, PORT_SOURCE_FILE, (uintptr_t) &fo, FILE_MODIFIED|FILE_ATTRIB, (void *)id)) {
|
||||
uwsgi_error("port_associate()");
|
||||
return NULL;
|
||||
}
|
||||
return &ushared->files_monitored[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef UWSGI_EVENT_FILEMONITOR_USE_KQUEUE
|
||||
int event_queue_add_file_monitor(int eq, char *filename, int *id) {
|
||||
|
||||
struct kevent kev;
|
||||
|
||||
int fd = open(filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
uwsgi_error("open()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD|EV_CLEAR, NOTE_WRITE|NOTE_DELETE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_RENAME|NOTE_REVOKE, 0, 0);
|
||||
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*id = fd;
|
||||
|
||||
uwsgi_log("added new file to monitor %s\n", filename);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
|
||||
|
||||
int i;
|
||||
|
||||
for(i=0;i<ushared->files_monitored_cnt;i++) {
|
||||
if (ushared->files_monitored[i].registered) {
|
||||
if (ushared->files_monitored[i].fd == id) {
|
||||
return &ushared->files_monitored[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_EVENT_FILEMONITOR_USE_INOTIFY
|
||||
#include <sys/inotify.h>
|
||||
|
||||
int event_queue_add_file_monitor(int eq, char *filename, int *id) {
|
||||
|
||||
int ifd = -1;
|
||||
int i;
|
||||
int add_to_queue = 0;
|
||||
|
||||
for (i=0;i<ushared->files_monitored_cnt;i++) {
|
||||
if (ushared->files_monitored[i].registered) {
|
||||
ifd = ushared->files_monitored[0].fd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ifd == -1) {
|
||||
ifd = inotify_init();
|
||||
if (ifd < 0) {
|
||||
uwsgi_error("inotify_init()");
|
||||
return -1;
|
||||
}
|
||||
add_to_queue = 1;
|
||||
}
|
||||
|
||||
*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);
|
||||
|
||||
uwsgi_log("added watch %d for filename %s\n", *id, filename);
|
||||
|
||||
if (add_to_queue) {
|
||||
return event_queue_add_fd_read(eq, ifd);
|
||||
}
|
||||
else {
|
||||
return ifd;
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
|
||||
|
||||
ssize_t rlen = 0;
|
||||
struct inotify_event ie, *bie, *iie;
|
||||
int i,j;
|
||||
int items = 0;
|
||||
|
||||
unsigned int isize = sizeof(struct inotify_event);
|
||||
struct uwsgi_fmon *uf = NULL;
|
||||
|
||||
if (ioctl(id, FIONREAD, &isize) < 0) {
|
||||
uwsgi_error("ioctl()");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (isize > sizeof(struct inotify_event)) {
|
||||
bie = uwsgi_malloc(isize);
|
||||
rlen = read(id, bie, isize);
|
||||
}
|
||||
else {
|
||||
rlen = read(id, &ie, sizeof(struct inotify_event));
|
||||
bie = &ie;
|
||||
}
|
||||
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("read()");
|
||||
}
|
||||
else {
|
||||
items = isize/(sizeof(struct inotify_event));
|
||||
uwsgi_log("inotify returned %d items\n", items);
|
||||
for(j=0;j<items;j++) {
|
||||
iie = &bie[j];
|
||||
for(i=0;i<ushared->files_monitored_cnt;i++) {
|
||||
if (ushared->files_monitored[i].registered) {
|
||||
if (ushared->files_monitored[i].fd == id && ushared->files_monitored[i].id == iie->wd) {
|
||||
uf = &ushared->files_monitored[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (items > 1) {
|
||||
free(bie);
|
||||
}
|
||||
|
||||
return uf;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_EVENT_TIMER_USE_TIMERFD
|
||||
|
||||
#ifndef UWSGI_EVENT_TIMER_USE_TIMERFD_NOINC
|
||||
#include <sys/timerfd.h>
|
||||
#endif
|
||||
|
||||
#ifndef TFD_CLOEXEC
|
||||
|
||||
// timerfd support
|
||||
|
||||
enum
|
||||
{
|
||||
TFD_CLOEXEC = 02000000,
|
||||
#define TFD_CLOEXEC TFD_CLOEXEC
|
||||
TFD_NONBLOCK = 04000
|
||||
#define TFD_NONBLOCK TFD_NONBLOCK
|
||||
};
|
||||
|
||||
|
||||
/* Bits to be set in the FLAGS parameter of `timerfd_settime'. */
|
||||
enum
|
||||
{
|
||||
TFD_TIMER_ABSTIME = 1 << 0
|
||||
#define TFD_TIMER_ABSTIME TFD_TIMER_ABSTIME
|
||||
};
|
||||
|
||||
|
||||
static int timerfd_create (clockid_t __clock_id, int __flags) {
|
||||
return syscall(322, __clock_id, __flags);
|
||||
}
|
||||
|
||||
static int timerfd_settime (int __ufd, int __flags,
|
||||
__const struct itimerspec *__utmr,
|
||||
struct itimerspec *__otmr) {
|
||||
return syscall(325, __ufd, __flags, __utmr, __otmr);
|
||||
}
|
||||
#endif
|
||||
|
||||
int event_queue_add_timer(int eq, int *id, int sec) {
|
||||
|
||||
struct itimerspec it;
|
||||
int tfd = timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC);
|
||||
|
||||
if (tfd < 0) {
|
||||
uwsgi_error("timerfd_create()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
it.it_value.tv_sec = sec;
|
||||
it.it_value.tv_nsec = 0;
|
||||
|
||||
it.it_interval.tv_sec = sec;
|
||||
it.it_interval.tv_nsec = 0;
|
||||
|
||||
if (timerfd_settime(tfd, 0, &it, NULL)) {
|
||||
uwsgi_error("timerfd_settime()");
|
||||
close(tfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*id = tfd;
|
||||
return event_queue_add_fd_read(eq, tfd);
|
||||
}
|
||||
|
||||
struct uwsgi_timer *event_queue_ack_timer(int id) {
|
||||
|
||||
int i;
|
||||
ssize_t rlen;
|
||||
uint64_t counter;
|
||||
struct uwsgi_timer *ut = NULL;
|
||||
|
||||
for(i=0;i<ushared->timers_cnt;i++) {
|
||||
if (ushared->timers[i].registered) {
|
||||
if (ushared->timers[i].id == id) {
|
||||
ut = &ushared->timers[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rlen = read(id, &counter, sizeof(uint64_t));
|
||||
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("read()");
|
||||
}
|
||||
|
||||
return ut;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_EVENT_TIMER_USE_NONE
|
||||
int event_queue_add_timer(int eq, int *id, int sec) { return -1; }
|
||||
struct uwsgi_timer *event_queue_ack_timer(int id) { return NULL;}
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_EVENT_TIMER_USE_PORT
|
||||
int event_queue_add_timer(int eq, int *id, int sec) {
|
||||
|
||||
static int timer_id = 0xffffff00;
|
||||
port_notify_t pnotif;
|
||||
struct sigevent sigev;
|
||||
itimerspec_t it;
|
||||
timer_t tid;
|
||||
|
||||
timer_id++;
|
||||
|
||||
pnotif.portnfy_port = eq;
|
||||
pnotif.portnfy_user = (void *) timer_id;
|
||||
|
||||
sigev.sigev_notify = SIGEV_PORT;
|
||||
sigev.sigev_value.sival_ptr = &pnotif;
|
||||
|
||||
if (timer_create(CLOCK_REALTIME, &sigev, &tid) < 0) {
|
||||
uwsgi_error("timer_create()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
it.it_value.tv_sec = sec;
|
||||
it.it_value.tv_nsec = 0;
|
||||
|
||||
it.it_interval.tv_sec = sec;
|
||||
it.it_interval.tv_nsec = 0;
|
||||
|
||||
if (timer_settime(tid, 0, &it, NULL) < 0) {
|
||||
uwsgi_error("timer_settime()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*id = timer_id;
|
||||
|
||||
return *id;
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_timer *event_queue_ack_timer(int id) {
|
||||
|
||||
int i;
|
||||
struct uwsgi_timer *ut = NULL;
|
||||
|
||||
for(i=0;i<uwsgi.shared->timers_cnt;i++) {
|
||||
if (uwsgi.shared->timers[i].registered) {
|
||||
if (uwsgi.shared->timers[i].id == id) {
|
||||
ut = &uwsgi.shared->timers[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ut;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef UWSGI_EVENT_TIMER_USE_KQUEUE
|
||||
int event_queue_add_timer(int eq, int *id, int sec) {
|
||||
|
||||
static int timer_id = 0xffffff00;
|
||||
struct kevent kev;
|
||||
|
||||
*id = timer_id ;
|
||||
timer_id++;
|
||||
|
||||
uwsgi_log("registering timer %d\n", sec);
|
||||
|
||||
EV_SET(&kev, *id, EVFILT_TIMER, EV_ADD, 0, sec*1000, 0);
|
||||
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return *id;
|
||||
}
|
||||
|
||||
struct uwsgi_timer *event_queue_ack_timer(int id) {
|
||||
|
||||
int i;
|
||||
struct uwsgi_timer *ut = NULL;
|
||||
|
||||
for(i=0;i<uwsgi.shared->timers_cnt;i++) {
|
||||
if (uwsgi.shared->timers[i].registered) {
|
||||
if (uwsgi.shared->timers[i].id == id) {
|
||||
ut = &uwsgi.shared->timers[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ut;
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
require 'fiber'
|
||||
class SuspendingBody
|
||||
|
||||
def each
|
||||
for i in 1..10
|
||||
yield "number: #{i}\n"
|
||||
Fiber.yield
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class RackFoo
|
||||
|
||||
def call(env)
|
||||
[200, { 'Content-Type' => 'text/plain'}, SuspendingBody.new]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
run RackFoo.new
|
||||
@@ -0,0 +1,8 @@
|
||||
uwsgi:
|
||||
plugins: rack
|
||||
socket: 127.0.0.1:3031
|
||||
rack: fibers.ru
|
||||
post-buffering: 4096
|
||||
async: 10
|
||||
loop: fiber
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifdef __linux__
|
||||
|
||||
#include <sys/inotify.h>
|
||||
|
||||
int uwsgi_file_monitor_new() {
|
||||
|
||||
int inotify_fd;
|
||||
|
||||
|
||||
inotify_fd = inotify_init();
|
||||
|
||||
if (inotify_fd < 0) {
|
||||
uwsgi_error("inotify_init()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return inotify_fd;
|
||||
}
|
||||
|
||||
int uwsgi_file_monitor_add(int fd, char *what) {
|
||||
|
||||
int inotify_watch_fd;
|
||||
|
||||
inotify_watch_fd = inotify_add_watch(fd, what, IN_ALL_EVENTS);
|
||||
|
||||
if (inotify_watch_fd < 0) {
|
||||
uwsgi_error("inotify_add_watch()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return inotify_watch_fd;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,122 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_gateway *register_fat_gateway(char *name, void (*loop)(void)) {
|
||||
|
||||
struct uwsgi_gateway *ug;
|
||||
int num=1,i;
|
||||
|
||||
if (uwsgi.gateways_cnt >= MAX_GATEWAYS) {
|
||||
uwsgi_log("you can register max %d gateways\n", MAX_GATEWAYS);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(i=0;i<uwsgi.gateways_cnt;i++) {
|
||||
if (!strcmp(name, uwsgi.gateways[i].name)) {
|
||||
num++;
|
||||
}
|
||||
}
|
||||
|
||||
ug = &uwsgi.gateways[uwsgi.gateways_cnt];
|
||||
ug->pid = 0;
|
||||
ug->name = name;
|
||||
ug->loop = loop;
|
||||
ug->num = num;
|
||||
|
||||
uwsgi.gateways_cnt++;
|
||||
|
||||
return ug;
|
||||
}
|
||||
|
||||
struct uwsgi_gateway *register_gateway(char *name, void (*loop)(void)) {
|
||||
|
||||
pid_t gw_pid;
|
||||
pid_t orig_pid = getpid();
|
||||
struct uwsgi_gateway *ug;
|
||||
int num=1,i;
|
||||
|
||||
if (uwsgi.gateways_cnt >= MAX_GATEWAYS) {
|
||||
uwsgi_log("you can register max %d gateways\n", MAX_GATEWAYS);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(i=0;i<uwsgi.gateways_cnt;i++) {
|
||||
if (!strcmp(name, uwsgi.gateways[i].name)) {
|
||||
num++;
|
||||
}
|
||||
}
|
||||
|
||||
gw_pid = fork();
|
||||
if (gw_pid < 0) {
|
||||
uwsgi_error("fork()");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!uwsgi.master_process) {
|
||||
if (gw_pid > 0) {
|
||||
#ifdef __linux__
|
||||
if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0,0,0)) {
|
||||
uwsgi_error("prctl()");
|
||||
}
|
||||
#endif
|
||||
loop();
|
||||
// never here !!! (i hope)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ug = &uwsgi.gateways[uwsgi.gateways_cnt];
|
||||
ug->pid = orig_pid;
|
||||
}
|
||||
else {
|
||||
if (gw_pid == 0) {
|
||||
if (uwsgi.master_as_root) uwsgi_as_root();
|
||||
loop();
|
||||
// never here !!! (i hope)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ug = &uwsgi.gateways[uwsgi.gateways_cnt];
|
||||
ug->pid = gw_pid;
|
||||
}
|
||||
|
||||
|
||||
ug->name = name;
|
||||
ug->loop = loop;
|
||||
ug->num = num;
|
||||
|
||||
uwsgi_log( "spawned uWSGI %s %d (pid: %d)\n", ug->name, ug->num, (int) ug->pid);
|
||||
|
||||
uwsgi.gateways_cnt++;
|
||||
|
||||
return ug;
|
||||
|
||||
}
|
||||
|
||||
void gateway_respawn(int id) {
|
||||
|
||||
pid_t gw_pid;
|
||||
struct uwsgi_gateway *ug = &uwsgi.gateways[id];
|
||||
|
||||
gw_pid = fork();
|
||||
if (gw_pid < 0) {
|
||||
uwsgi_error("fork()");
|
||||
return;
|
||||
}
|
||||
|
||||
if (gw_pid == 0) {
|
||||
if (uwsgi.master_as_root) uwsgi_as_root();
|
||||
#ifdef __linux__
|
||||
if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0,0,0)) {
|
||||
uwsgi_error("prctl()");
|
||||
}
|
||||
#endif
|
||||
ug->loop();
|
||||
// never here !!! (i hope)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ug->pid = gw_pid;
|
||||
uwsgi_log( "respawned uWSGI %s %d (pid: %d)\n", ug->name, ug->num, (int) gw_pid);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// http:3:GET / HTTP/1.1:192.168.173.10:80,192.168.173.11:80,192.168.173.12:80,192.168.173.13:80
|
||||
|
||||
/*
|
||||
write(arg1);
|
||||
|
||||
wait_for_fd()
|
||||
|
||||
get_data() == 200
|
||||
*/
|
||||
@@ -0,0 +1 @@
|
||||
// uwsgi:3::192.168.173.1:3031,192.168.173.2:3031,192.168.173.3:3031,192.168.173.4:3031
|
||||
+7
-14
@@ -6,20 +6,18 @@ import rrdtool
|
||||
|
||||
s_freq = 10
|
||||
|
||||
# this is a cron emulator done with the Spooler :)
|
||||
def rrdtool_updater(env):
|
||||
uwsgi.set_spooler_frequency(s_freq)
|
||||
rrdtool.update('../test.rrd', str(int(time.time()))+':'+str(uwsgi.total_requests()))
|
||||
uwsgi.send_to_spooler({})
|
||||
# this task will be executed every s_freq seconds
|
||||
def rrdtool_updater(sig, sec):
|
||||
rrdtool.update('test.rrd', str(int(time.time()))+':'+str(uwsgi.total_requests()))
|
||||
|
||||
|
||||
uwsgi.spooler = rrdtool_updater
|
||||
uwsgi.register_timer(0, s_freq, uwsgi.KIND_WORKER, rrdtool_updater)
|
||||
|
||||
|
||||
|
||||
def hello_world(env, start_response):
|
||||
start_response('200 Ok', [('Content-type', 'text/plain')])
|
||||
yield 'Hello world !'
|
||||
return 'Hello world !'
|
||||
|
||||
|
||||
def graph(env, start_response):
|
||||
@@ -27,12 +25,7 @@ def graph(env, start_response):
|
||||
now = int(time.time())
|
||||
graph_range = (3600*24)
|
||||
rrdtool.graph('uwsgi_graph.png', '--start', str(now - graph_range), '--end', str(now), 'DEF:urequests=test.rrd:requests:AVERAGE', 'LINE2:urequests#00FF00')
|
||||
fd = open('uwsgi_graph.png', 'r')
|
||||
# send file to browser
|
||||
return env['wsgi.file_wrapper'](fd, 4096)
|
||||
|
||||
# start the simil-cron
|
||||
uwsgi.send_to_spooler({})
|
||||
|
||||
# send file to client
|
||||
uwsgi.sendfile('uwsgi_graph.png')
|
||||
|
||||
uwsgi.applications = {'/': hello_world, '/graph':graph}
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
#ifdef UWSGI_INI
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/*
|
||||
ini file must be read ALL into memory.
|
||||
This memory must not be freed for all the server lifecycle
|
||||
*/
|
||||
|
||||
void ini_rstrip(char *line) {
|
||||
|
||||
off_t i;
|
||||
|
||||
for(i = strlen(line)-1;i>=0; i--) {
|
||||
if (line[i] == ' ' || line[i] == '\t') {
|
||||
line[i] = 0;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char *ini_lstrip(char *line) {
|
||||
|
||||
off_t i;
|
||||
char *ptr = line;
|
||||
|
||||
for(i=0;i< (int) strlen(line);i++) {
|
||||
if (line[i] == ' ' || line[i] == '\t') {
|
||||
ptr++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
char *ini_get_key(char *key) {
|
||||
|
||||
off_t i;
|
||||
char *ptr = key;
|
||||
|
||||
for(i=0;i< (int) strlen(key);i++) {
|
||||
ptr++;
|
||||
if (key[i] == '=') {
|
||||
key[i] = 0;
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
char *ini_get_line(char *ini, off_t size) {
|
||||
|
||||
off_t i;
|
||||
char *ptr = ini;
|
||||
|
||||
for(i=0;i<size;i++) {
|
||||
ptr++;
|
||||
if (ini[i] == '\n') {
|
||||
ini[i] = 0;
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
|
||||
int len = 0;
|
||||
char *ini;
|
||||
|
||||
char *ini_line;
|
||||
|
||||
char *section = "";
|
||||
char *key;
|
||||
char *val;
|
||||
|
||||
int lines = 1;
|
||||
|
||||
struct option *lopt, *aopt;
|
||||
char *section_asked = "uwsgi";
|
||||
char *colon;
|
||||
|
||||
colon = uwsgi_get_last_char(file, ':');
|
||||
if (colon) {
|
||||
colon[0] = 0;
|
||||
if (colon[1] != 0) {
|
||||
section_asked = colon+1;
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("[uWSGI] getting INI configuration from %s\n", file);
|
||||
|
||||
ini = uwsgi_open_and_read(file, &len, 1, magic_table);
|
||||
|
||||
while(len) {
|
||||
ini_line = ini_get_line(ini, len);
|
||||
if (ini_line == NULL) {
|
||||
break;
|
||||
}
|
||||
lines++;
|
||||
|
||||
// skip empty line
|
||||
key = ini_lstrip(ini);
|
||||
ini_rstrip(key);
|
||||
if (key[0] != 0) {
|
||||
if (key[0] == '[') {
|
||||
section = key+1;
|
||||
section[strlen(section)-1] = 0;
|
||||
}
|
||||
else if (key[0] == ';' || key[0] == '#') {
|
||||
// this is a comment
|
||||
}
|
||||
else {
|
||||
// val is always valid, but (obviously) can be ignored
|
||||
val = ini_get_key(key);
|
||||
|
||||
if (!strcmp(section, section_asked)) {
|
||||
ini_rstrip(key);
|
||||
val = ini_lstrip(val);
|
||||
ini_rstrip(val);
|
||||
lopt = uwsgi.long_options;
|
||||
while ((aopt = lopt)) {
|
||||
if (!aopt->name)
|
||||
break;
|
||||
if (!strcmp(key, aopt->name)) {
|
||||
if (aopt->flag) {
|
||||
*aopt->flag = aopt->val;
|
||||
add_exported_option(0, (char *)key);
|
||||
}
|
||||
else {
|
||||
if (aopt->has_arg == optional_argument) {
|
||||
if (!strcmp("true", val)) {
|
||||
val = NULL;
|
||||
}
|
||||
}
|
||||
if (aopt->has_arg == no_argument) {
|
||||
if (!strcmp("false", val) || val[0] == '0') {
|
||||
lopt++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
manage_opt(aopt->val, val);
|
||||
}
|
||||
}
|
||||
lopt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
len -= (ini_line - ini);
|
||||
ini += (ini_line - ini);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,313 @@
|
||||
#ifdef UWSGI_LDAP
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#include <ldap.h>
|
||||
|
||||
void ldap2uwsgi(char *ldapname, char *uwsginame) {
|
||||
char *ptr = uwsginame;
|
||||
|
||||
int i;
|
||||
|
||||
for(i=0;i< (int) strlen(ldapname);i++) {
|
||||
if (isupper( (int)ldapname[i])) {
|
||||
*ptr++ = '-';
|
||||
*ptr++ = tolower( (int) ldapname[i]);
|
||||
}
|
||||
else {
|
||||
*ptr++ = ldapname[i];
|
||||
}
|
||||
}
|
||||
|
||||
*ptr++= 0;
|
||||
}
|
||||
|
||||
int calc_ldap_name(char *name) {
|
||||
int i;
|
||||
int counter = 0;
|
||||
|
||||
for(i=0;i< (int)strlen(name);i++) {
|
||||
if (isupper( (int) name[i])) {
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
return strlen(name) + counter;
|
||||
}
|
||||
|
||||
void uwsgi_ldap_schema_dump_ldif() {
|
||||
struct option *aopt, *lopt;
|
||||
|
||||
lopt = uwsgi.long_options;
|
||||
int i;
|
||||
int counter = 30000;
|
||||
|
||||
uwsgi_log("\n");
|
||||
uwsgi_log("dn: cn=uwsgi,cn=schema,cn=config\n");
|
||||
uwsgi_log("objectClass: olcSchemaConfig\n");
|
||||
uwsgi_log("cn: uwsgi\n");
|
||||
|
||||
while( (aopt = lopt) ) {
|
||||
if (!aopt->name)
|
||||
break;
|
||||
|
||||
if (aopt->flag) {
|
||||
uwsgi_log("olcAttributeTypes: ( 1.3.6.1.4.1.35156.17.4.%d NAME 'uWSGI", counter);
|
||||
counter++;
|
||||
}
|
||||
else {
|
||||
uwsgi_log("olcAttributeTypes: ( 1.3.6.1.4.1.35156.17.4.%d NAME 'uWSGI", aopt->val);
|
||||
}
|
||||
for(i=0;i< (int)strlen(aopt->name);i++) {
|
||||
if (aopt->name[i] == '-') {
|
||||
i++;
|
||||
uwsgi_log("%c", toupper( (int) aopt->name[i]));
|
||||
}
|
||||
else {
|
||||
uwsgi_log("%c", aopt->name[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (aopt->has_arg) {
|
||||
uwsgi_log("' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )\n");
|
||||
}
|
||||
else {
|
||||
uwsgi_log("' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )\n");
|
||||
}
|
||||
lopt++;
|
||||
}
|
||||
|
||||
uwsgi_log("olcAttributeTypes: ( 1.3.6.1.4.1.35156.17.4.50000 NAME 'uWSGInull' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )\n");
|
||||
|
||||
lopt = uwsgi.long_options;
|
||||
|
||||
uwsgi_log("olcObjectClasses: ( 1.3.6.1.4.1.35156.17.3.1 NAME 'uWSGIConfig' SUP top AUXILIARY DESC 'uWSGI configuration' MAY ( ");
|
||||
|
||||
while( (aopt = lopt) ) {
|
||||
if (!aopt->name)
|
||||
break;
|
||||
|
||||
uwsgi_log("uWSGI");
|
||||
|
||||
for(i=0;i< (int)strlen(aopt->name);i++) {
|
||||
if (aopt->name[i] == '-') {
|
||||
i++;
|
||||
uwsgi_log("%c", toupper( (int) aopt->name[i]));
|
||||
}
|
||||
else {
|
||||
uwsgi_log("%c", aopt->name[i]);
|
||||
}
|
||||
}
|
||||
uwsgi_log(" $ ");
|
||||
lopt++;
|
||||
}
|
||||
|
||||
uwsgi_log("uWSGInull ))\n");
|
||||
|
||||
uwsgi_log("\n");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void uwsgi_ldap_schema_dump() {
|
||||
struct option *aopt, *lopt;
|
||||
|
||||
lopt = uwsgi.long_options;
|
||||
int i;
|
||||
int counter = 30000;
|
||||
|
||||
while( (aopt = lopt) ) {
|
||||
if (!aopt->name)
|
||||
break;
|
||||
|
||||
|
||||
if (aopt->flag) {
|
||||
uwsgi_log("attributetype ( 1.3.6.1.4.1.35156.17.4.%d NAME 'uWSGI", counter);
|
||||
counter++;
|
||||
}
|
||||
else {
|
||||
uwsgi_log("attributetype ( 1.3.6.1.4.1.35156.17.4.%d NAME 'uWSGI", aopt->val);
|
||||
}
|
||||
for(i=0;i< (int)strlen(aopt->name);i++) {
|
||||
if (aopt->name[i] == '-') {
|
||||
i++;
|
||||
uwsgi_log("%c", toupper( (int) aopt->name[i]));
|
||||
}
|
||||
else {
|
||||
uwsgi_log("%c", aopt->name[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (aopt->has_arg) {
|
||||
uwsgi_log("' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )\n");
|
||||
}
|
||||
else {
|
||||
uwsgi_log("' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )\n");
|
||||
}
|
||||
lopt++;
|
||||
}
|
||||
|
||||
uwsgi_log("attributetype ( 1.3.6.1.4.1.35156.17.4.50000 NAME 'uWSGInull' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )\n");
|
||||
|
||||
lopt = uwsgi.long_options;
|
||||
|
||||
uwsgi_log("objectclass ( 1.3.6.1.4.1.35156.17.3.1 NAME 'uWSGIConfig' SUP top AUXILIARY DESC 'uWSGI configuration' MAY ( ");
|
||||
|
||||
while( (aopt = lopt) ) {
|
||||
if (!aopt->name)
|
||||
break;
|
||||
|
||||
uwsgi_log("uWSGI");
|
||||
|
||||
for(i=0;i< (int)strlen(aopt->name);i++) {
|
||||
if (aopt->name[i] == '-') {
|
||||
i++;
|
||||
uwsgi_log("%c", toupper( (int) aopt->name[i]));
|
||||
}
|
||||
else {
|
||||
uwsgi_log("%c", aopt->name[i]);
|
||||
}
|
||||
}
|
||||
uwsgi_log(" $ ");
|
||||
lopt++;
|
||||
}
|
||||
|
||||
uwsgi_log("uWSGInull ))\n");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void uwsgi_ldap_config() {
|
||||
|
||||
LDAP *ldp;
|
||||
LDAPMessage *results, *entry;
|
||||
BerElement *ber;
|
||||
struct berval **bervalues;
|
||||
char *attr;
|
||||
char *uwsgi_attr;
|
||||
|
||||
char *url = "ldap:///";
|
||||
char *url_slash;
|
||||
|
||||
int desired_version = LDAP_VERSION3;
|
||||
int ret;
|
||||
|
||||
struct option *aopt, *lopt;
|
||||
|
||||
LDAPURLDesc *ldap_url;
|
||||
|
||||
if (uwsgi.ldap) {
|
||||
url = uwsgi.ldap;
|
||||
}
|
||||
|
||||
if (!ldap_is_ldap_url(url)) {
|
||||
uwsgi_log("invalid LDAP url.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (ldap_url_parse(url, &ldap_url) != LDAP_SUCCESS) {
|
||||
uwsgi_log("unable to parse LDAP url.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
url_slash = strchr(url, '/');
|
||||
url_slash = strchr(url_slash + 1, '/');
|
||||
|
||||
url_slash = strchr(url_slash + 1, '/');
|
||||
if (url_slash) {
|
||||
url_slash[0] = 0;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_debug("LDAP URL: %s\n", url);
|
||||
uwsgi_debug("LDAP BASE DN: %s\n", ldap_url->lud_dn);
|
||||
#endif
|
||||
|
||||
if ( (ret = ldap_initialize( &ldp, url)) != LDAP_SUCCESS) {
|
||||
uwsgi_log("LDAP: %s\n", ldap_err2string(ret));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
if ( (ret = ldap_set_option(ldp, LDAP_OPT_PROTOCOL_VERSION, &desired_version)) != LDAP_OPT_SUCCESS) {
|
||||
uwsgi_log("LDAP: %s\n", ldap_err2string(ret));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
if ( (ret = ldap_search_ext_s(ldp, ldap_url->lud_dn, ldap_url->lud_scope, ldap_url->lud_filter, NULL, 0, NULL, NULL, NULL, 1, &results)) != LDAP_SUCCESS) {
|
||||
uwsgi_log("LDAP: %s\n", ldap_err2string(ret));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_debug("LDAP connection initialized %p\n", ldp);
|
||||
#endif
|
||||
|
||||
free(ldap_url);
|
||||
|
||||
if (ldap_count_entries(ldp, results) < 1) {
|
||||
uwsgi_log("no LDAP entry found\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
entry = ldap_first_entry(ldp, results);
|
||||
|
||||
for( attr = ldap_first_attribute(ldp, entry, &ber); attr != NULL; attr = ldap_next_attribute(ldp, entry, ber)) {
|
||||
if (!strncmp(attr,"uWSGI",5)) {
|
||||
|
||||
uwsgi_attr = malloc( calc_ldap_name(attr) + 1 );
|
||||
if (!uwsgi_attr) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ldap2uwsgi(attr+5, uwsgi_attr);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_debug("LDAP attribute: %s = --%s\n", attr, uwsgi_attr);
|
||||
#endif
|
||||
bervalues = ldap_get_values_len(ldp, entry, attr);
|
||||
if (bervalues) {
|
||||
// do not free uwsgi_val;
|
||||
char *uwsgi_val = malloc( bervalues[0]->bv_len + 1 );
|
||||
if (!uwsgi_val) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memcpy(uwsgi_val, bervalues[0]->bv_val, bervalues[0]->bv_len);
|
||||
uwsgi_val[bervalues[0]->bv_len] = 0;
|
||||
|
||||
lopt = uwsgi.long_options;
|
||||
while ((aopt = lopt)) {
|
||||
if (!aopt->name)
|
||||
break;
|
||||
if (!strcmp(uwsgi_attr, aopt->name)) {
|
||||
if (aopt->flag) {
|
||||
*aopt->flag = aopt->val;
|
||||
add_exported_option(0, (char*) uwsgi_attr);
|
||||
}
|
||||
else {
|
||||
manage_opt(aopt->val, uwsgi_val);
|
||||
}
|
||||
}
|
||||
lopt++;
|
||||
}
|
||||
}
|
||||
|
||||
free(bervalues);
|
||||
free(uwsgi_attr);
|
||||
}
|
||||
free(attr);
|
||||
}
|
||||
|
||||
free(ber);
|
||||
free(results);
|
||||
|
||||
ldap_unbind_ext_s(ldp, NULL, NULL);
|
||||
|
||||
}
|
||||
#endif
|
||||
+284
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
|
||||
*** uWSGI, stripped down version of Linux rbtree ***
|
||||
|
||||
|
||||
Red Black Trees
|
||||
(C) 1999 Andrea Arcangeli <andrea@suse.de>
|
||||
(C) 2002 David Woodhouse <dwmw2@infradead.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "../uwsgi.h"
|
||||
|
||||
static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
|
||||
{
|
||||
struct rb_node *right = node->rb_right;
|
||||
struct rb_node *parent = rb_parent(node);
|
||||
|
||||
if ((node->rb_right = right->rb_left))
|
||||
rb_set_parent(right->rb_left, node);
|
||||
right->rb_left = node;
|
||||
|
||||
rb_set_parent(right, parent);
|
||||
|
||||
if (parent)
|
||||
{
|
||||
if (node == parent->rb_left)
|
||||
parent->rb_left = right;
|
||||
else
|
||||
parent->rb_right = right;
|
||||
}
|
||||
else
|
||||
root->rb_node = right;
|
||||
rb_set_parent(node, right);
|
||||
}
|
||||
|
||||
static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
|
||||
{
|
||||
struct rb_node *left = node->rb_left;
|
||||
struct rb_node *parent = rb_parent(node);
|
||||
|
||||
if ((node->rb_left = left->rb_right))
|
||||
rb_set_parent(left->rb_right, node);
|
||||
left->rb_right = node;
|
||||
|
||||
rb_set_parent(left, parent);
|
||||
|
||||
if (parent)
|
||||
{
|
||||
if (node == parent->rb_right)
|
||||
parent->rb_right = left;
|
||||
else
|
||||
parent->rb_left = left;
|
||||
}
|
||||
else
|
||||
root->rb_node = left;
|
||||
rb_set_parent(node, left);
|
||||
}
|
||||
|
||||
void rb_insert_color(struct rb_node *node, struct rb_root *root)
|
||||
{
|
||||
struct rb_node *parent, *gparent;
|
||||
|
||||
while ((parent = rb_parent(node)) && rb_is_red(parent))
|
||||
{
|
||||
gparent = rb_parent(parent);
|
||||
|
||||
if (parent == gparent->rb_left)
|
||||
{
|
||||
{
|
||||
register struct rb_node *uncle = gparent->rb_right;
|
||||
if (uncle && rb_is_red(uncle))
|
||||
{
|
||||
rb_set_black(uncle);
|
||||
rb_set_black(parent);
|
||||
rb_set_red(gparent);
|
||||
node = gparent;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent->rb_right == node)
|
||||
{
|
||||
register struct rb_node *tmp;
|
||||
__rb_rotate_left(parent, root);
|
||||
tmp = parent;
|
||||
parent = node;
|
||||
node = tmp;
|
||||
}
|
||||
|
||||
rb_set_black(parent);
|
||||
rb_set_red(gparent);
|
||||
__rb_rotate_right(gparent, root);
|
||||
} else {
|
||||
{
|
||||
register struct rb_node *uncle = gparent->rb_left;
|
||||
if (uncle && rb_is_red(uncle))
|
||||
{
|
||||
rb_set_black(uncle);
|
||||
rb_set_black(parent);
|
||||
rb_set_red(gparent);
|
||||
node = gparent;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent->rb_left == node)
|
||||
{
|
||||
register struct rb_node *tmp;
|
||||
__rb_rotate_right(parent, root);
|
||||
tmp = parent;
|
||||
parent = node;
|
||||
node = tmp;
|
||||
}
|
||||
|
||||
rb_set_black(parent);
|
||||
rb_set_red(gparent);
|
||||
__rb_rotate_left(gparent, root);
|
||||
}
|
||||
}
|
||||
|
||||
rb_set_black(root->rb_node);
|
||||
}
|
||||
|
||||
static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
|
||||
struct rb_root *root)
|
||||
{
|
||||
struct rb_node *other;
|
||||
|
||||
while ((!node || rb_is_black(node)) && node != root->rb_node)
|
||||
{
|
||||
if (parent->rb_left == node)
|
||||
{
|
||||
other = parent->rb_right;
|
||||
if (rb_is_red(other))
|
||||
{
|
||||
rb_set_black(other);
|
||||
rb_set_red(parent);
|
||||
__rb_rotate_left(parent, root);
|
||||
other = parent->rb_right;
|
||||
}
|
||||
if ((!other->rb_left || rb_is_black(other->rb_left)) &&
|
||||
(!other->rb_right || rb_is_black(other->rb_right)))
|
||||
{
|
||||
rb_set_red(other);
|
||||
node = parent;
|
||||
parent = rb_parent(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!other->rb_right || rb_is_black(other->rb_right))
|
||||
{
|
||||
rb_set_black(other->rb_left);
|
||||
rb_set_red(other);
|
||||
__rb_rotate_right(other, root);
|
||||
other = parent->rb_right;
|
||||
}
|
||||
rb_set_color(other, rb_color(parent));
|
||||
rb_set_black(parent);
|
||||
rb_set_black(other->rb_right);
|
||||
__rb_rotate_left(parent, root);
|
||||
node = root->rb_node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
other = parent->rb_left;
|
||||
if (rb_is_red(other))
|
||||
{
|
||||
rb_set_black(other);
|
||||
rb_set_red(parent);
|
||||
__rb_rotate_right(parent, root);
|
||||
other = parent->rb_left;
|
||||
}
|
||||
if ((!other->rb_left || rb_is_black(other->rb_left)) &&
|
||||
(!other->rb_right || rb_is_black(other->rb_right)))
|
||||
{
|
||||
rb_set_red(other);
|
||||
node = parent;
|
||||
parent = rb_parent(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!other->rb_left || rb_is_black(other->rb_left))
|
||||
{
|
||||
rb_set_black(other->rb_right);
|
||||
rb_set_red(other);
|
||||
__rb_rotate_left(other, root);
|
||||
other = parent->rb_left;
|
||||
}
|
||||
rb_set_color(other, rb_color(parent));
|
||||
rb_set_black(parent);
|
||||
rb_set_black(other->rb_left);
|
||||
__rb_rotate_right(parent, root);
|
||||
node = root->rb_node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node)
|
||||
rb_set_black(node);
|
||||
}
|
||||
|
||||
void rb_erase(struct rb_node *node, struct rb_root *root)
|
||||
{
|
||||
struct rb_node *child, *parent;
|
||||
int color;
|
||||
|
||||
if (!node->rb_left)
|
||||
child = node->rb_right;
|
||||
else if (!node->rb_right)
|
||||
child = node->rb_left;
|
||||
else
|
||||
{
|
||||
struct rb_node *old = node, *left;
|
||||
|
||||
node = node->rb_right;
|
||||
while ((left = node->rb_left) != NULL)
|
||||
node = left;
|
||||
|
||||
if (rb_parent(old)) {
|
||||
if (rb_parent(old)->rb_left == old)
|
||||
rb_parent(old)->rb_left = node;
|
||||
else
|
||||
rb_parent(old)->rb_right = node;
|
||||
} else
|
||||
root->rb_node = node;
|
||||
|
||||
child = node->rb_right;
|
||||
parent = rb_parent(node);
|
||||
color = rb_color(node);
|
||||
|
||||
if (parent == old) {
|
||||
parent = node;
|
||||
} else {
|
||||
if (child)
|
||||
rb_set_parent(child, parent);
|
||||
parent->rb_left = child;
|
||||
|
||||
node->rb_right = old->rb_right;
|
||||
rb_set_parent(old->rb_right, node);
|
||||
}
|
||||
|
||||
node->rb_parent_color = old->rb_parent_color;
|
||||
node->rb_left = old->rb_left;
|
||||
rb_set_parent(old->rb_left, node);
|
||||
|
||||
goto color;
|
||||
}
|
||||
|
||||
parent = rb_parent(node);
|
||||
color = rb_color(node);
|
||||
|
||||
if (child)
|
||||
rb_set_parent(child, parent);
|
||||
if (parent)
|
||||
{
|
||||
if (parent->rb_left == node)
|
||||
parent->rb_left = child;
|
||||
else
|
||||
parent->rb_right = child;
|
||||
}
|
||||
else
|
||||
root->rb_node = child;
|
||||
|
||||
color:
|
||||
if (color == RB_BLACK)
|
||||
__rb_erase_color(child, parent, root);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
|
||||
*** uWSGI, stripped down version of Linux rbtree ***
|
||||
|
||||
|
||||
Red Black Trees
|
||||
(C) 1999 Andrea Arcangeli <andrea@suse.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
struct rb_node
|
||||
{
|
||||
unsigned long rb_parent_color;
|
||||
#define RB_RED 0
|
||||
#define RB_BLACK 1
|
||||
struct rb_node *rb_right;
|
||||
struct rb_node *rb_left;
|
||||
} __attribute__((aligned(sizeof(long))));
|
||||
/* The alignment might seem pointless, but allegedly CRIS needs it */
|
||||
|
||||
struct rb_root
|
||||
{
|
||||
struct rb_node *rb_node;
|
||||
};
|
||||
|
||||
|
||||
#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3))
|
||||
#define rb_color(r) ((r)->rb_parent_color & 1)
|
||||
#define rb_is_red(r) (!rb_color(r))
|
||||
#define rb_is_black(r) rb_color(r)
|
||||
#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0)
|
||||
#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
+234
-228
@@ -38,7 +38,7 @@
|
||||
#ifdef __linux__
|
||||
#include <endian.h>
|
||||
#elif __sun__
|
||||
#elif __apple__
|
||||
#elif __APPLE__
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#else
|
||||
#include <machine/endian.h>
|
||||
@@ -47,7 +47,7 @@
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
static uint16_t uwsgi_swap16(uint16_t x) {
|
||||
return (uint16_t) ((x & 0xff) << 8 | (x & 0xff00) >> 8);
|
||||
return (uint16_t) ((x & 0xff) << 8 | (x & 0xff00) >> 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -64,7 +64,7 @@ typedef struct __attribute__((packed)) {
|
||||
uint8_t modifier1;
|
||||
uint16_t pktsize;
|
||||
uint8_t modifier2;
|
||||
} uwsgi_header ;
|
||||
} uwsgi_header;
|
||||
|
||||
typedef struct {
|
||||
array *extensions;
|
||||
@@ -394,7 +394,7 @@ static int uwsgi_establish_connection(server *srv, handler_ctx *hctx) {
|
||||
static void uwsgi_add_var(buffer *b, char * key, uint16_t keylen, char *val, uint16_t vallen) {
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
uint16_t uwlen ;
|
||||
uint16_t uwlen;
|
||||
|
||||
uwlen = uwsgi_swap16(keylen);
|
||||
buffer_append_memory(b, (char *) &uwlen, 2); buffer_append_memory(b, key, keylen);
|
||||
@@ -405,19 +405,19 @@ static void uwsgi_add_var(buffer *b, char * key, uint16_t keylen, char *val, uin
|
||||
buffer_append_memory(b, (char *) &vallen, 2); buffer_append_memory(b, val, vallen);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
static int uwsgi_create_env(server *srv, handler_ctx *hctx) {
|
||||
size_t i;
|
||||
|
||||
char buf[32];
|
||||
uwsgi_header *uh ;
|
||||
uwsgi_header *uh;
|
||||
const char *s;
|
||||
#ifdef HAVE_IPV6
|
||||
char b2[INET6_ADDRSTRLEN + 1];
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
connection *con = hctx->remote_conn;
|
||||
server_socket *srv_sock = con->srv_socket;
|
||||
@@ -436,53 +436,59 @@ static int uwsgi_create_env(server *srv, handler_ctx *hctx) {
|
||||
|
||||
if (!buffer_is_empty(con->uri.query)) {
|
||||
uwsgi_add_var(b, "QUERY_STRING", 12, con->uri.query->ptr, con->uri.query->used-1);
|
||||
} else {
|
||||
} else {
|
||||
uwsgi_add_var(b, "QUERY_STRING", 12, "", 0);
|
||||
}
|
||||
}
|
||||
|
||||
s = get_http_version_name(con->request.http_version);
|
||||
uwsgi_add_var(b, "SERVER_PROTOCOL", 15, (char *) s, strlen(s));
|
||||
|
||||
|
||||
if (con->server_name->used) {
|
||||
size_t len = con->server_name->used - 1;
|
||||
char *colon = strchr(con->server_name->ptr, ':');
|
||||
if (colon) len = colon - con->server_name->ptr;
|
||||
size_t len = con->server_name->used - 1;
|
||||
char *colon = strchr(con->server_name->ptr, ':');
|
||||
if (colon) len = colon - con->server_name->ptr;
|
||||
uwsgi_add_var(b, "SERVER_NAME", 11, con->server_name->ptr, len);
|
||||
|
||||
} else {
|
||||
} else {
|
||||
#ifdef HAVE_IPV6
|
||||
s = inet_ntop(srv_sock->addr.plain.sa_family,
|
||||
srv_sock->addr.plain.sa_family == AF_INET6 ?
|
||||
(const void *) &(srv_sock->addr.ipv6.sin6_addr) :
|
||||
(const void *) &(srv_sock->addr.ipv4.sin_addr),
|
||||
b2, sizeof(b2)-1);
|
||||
s = inet_ntop(srv_sock->addr.plain.sa_family,
|
||||
srv_sock->addr.plain.sa_family == AF_INET6 ?
|
||||
(const void *) &(srv_sock->addr.ipv6.sin6_addr) :
|
||||
(const void *) &(srv_sock->addr.ipv4.sin_addr),
|
||||
b2, sizeof(b2)-1);
|
||||
#else
|
||||
s = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
|
||||
s = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
|
||||
#endif
|
||||
uwsgi_add_var(b, "SERVER_NAME", 11, (char *)s, strlen(s));
|
||||
}
|
||||
}
|
||||
|
||||
LI_ltostr(buf,
|
||||
#ifdef HAVE_IPV6
|
||||
ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
|
||||
ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
|
||||
#else
|
||||
ntohs(srv_sock->addr.ipv4.sin_port)
|
||||
ntohs(srv_sock->addr.ipv4.sin_port)
|
||||
#endif
|
||||
);
|
||||
);
|
||||
|
||||
uwsgi_add_var(b, "SERVER_PORT", 11, buf, strlen(buf));
|
||||
uwsgi_add_var(b, "REQUEST_URI", 11, con->request.orig_uri->ptr, con->request.orig_uri->used-1);
|
||||
|
||||
LI_ltostr(buf,
|
||||
#ifdef HAVE_IPV6
|
||||
ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
|
||||
ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
|
||||
#else
|
||||
ntohs(con->dst_addr.ipv4.sin_port)
|
||||
ntohs(con->dst_addr.ipv4.sin_port)
|
||||
#endif
|
||||
);
|
||||
);
|
||||
uwsgi_add_var(b, "REMOTE_PORT", 11, buf, strlen(buf));
|
||||
|
||||
if (!buffer_is_empty(con->authed_user)) {
|
||||
uwsgi_add_var(b, "REMOTE_USER", 11,
|
||||
CONST_BUF_LEN(con->authed_user));
|
||||
}
|
||||
|
||||
|
||||
|
||||
s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
|
||||
uwsgi_add_var(b, "REMOTE_ADDR", 11, (char *)s, strlen(s));
|
||||
@@ -490,18 +496,18 @@ static int uwsgi_create_env(server *srv, handler_ctx *hctx) {
|
||||
if (hctx->path_info_offset > 1) {
|
||||
uwsgi_add_var(b, "SCRIPT_NAME", 11, con->uri.path->ptr, hctx->path_info_offset);
|
||||
if (strlen(con->uri.path->ptr + hctx->path_info_offset) > 0) {
|
||||
uwsgi_add_var(b, "PATH_INFO", 9, con->request.orig_uri->ptr + hctx->path_info_offset, strlen(con->request.orig_uri->ptr + hctx->path_info_offset));
|
||||
uwsgi_add_var(b, "PATH_INFO", 9, con->uri.path->ptr + hctx->path_info_offset, strlen(con->uri.path->ptr + hctx->path_info_offset));
|
||||
}
|
||||
else {
|
||||
uwsgi_add_var(b, "PATH_INFO", 9, "/", 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_add_var(b, "SCRIPT_NAME", 11, "", 0) ;
|
||||
uwsgi_add_var(b, "PATH_INFO", 9, con->request.orig_uri->ptr, con->request.orig_uri->used-1) ;
|
||||
uwsgi_add_var(b, "SCRIPT_NAME", 11, "", 0);
|
||||
uwsgi_add_var(b, "PATH_INFO", 9, con->uri.path->ptr, strlen(con->uri.path->ptr));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
for (i = 0; i < con->request.headers->used; i++) {
|
||||
data_string *ds;
|
||||
ds = (data_string *)con->request.headers->data[i];
|
||||
@@ -518,7 +524,7 @@ static int uwsgi_create_env(server *srv, handler_ctx *hctx) {
|
||||
}
|
||||
for (j = 0; j < ds->key->used - 1; j++) {
|
||||
srv->tmp_buf->ptr[srv->tmp_buf->used++] = light_isalpha(ds->key->ptr[j]) ? ds->key->ptr[j] & ~32 : '_';
|
||||
}
|
||||
}
|
||||
srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
|
||||
uwsgi_add_var(b, srv->tmp_buf->ptr, srv->tmp_buf->used-1, ds->value->ptr, ds->value->used-1);
|
||||
}
|
||||
@@ -540,19 +546,19 @@ static int uwsgi_create_env(server *srv, handler_ctx *hctx) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uh = (uwsgi_header *) b->ptr ;
|
||||
uh->modifier1 = (uint8_t) 0 ;
|
||||
|
||||
uh = (uwsgi_header *) b->ptr;
|
||||
uh->modifier1 = (uint8_t) 0;
|
||||
#ifdef __BIG_ENDIAN__
|
||||
uh->pktsize = uwsgi_swap16((uint16_t) b->used - 4) ;
|
||||
uh->pktsize = uwsgi_swap16((uint16_t) b->used - 4);
|
||||
#else
|
||||
uh->pktsize = b->used - 4 ;
|
||||
uh->pktsize = b->used - 4;
|
||||
#endif
|
||||
uh->modifier2 = (uint8_t) 0 ;
|
||||
uh->modifier2 = (uint8_t) 0;
|
||||
|
||||
b->used++; /* fix size */
|
||||
|
||||
hctx->wb->bytes_in += b->used -1 ;
|
||||
hctx->wb->bytes_in += b->used -1;
|
||||
/* body */
|
||||
|
||||
if (con->request.content_length) {
|
||||
@@ -570,37 +576,37 @@ static int uwsgi_create_env(server *srv, handler_ctx *hctx) {
|
||||
* */
|
||||
|
||||
switch (req_c->type) {
|
||||
case FILE_CHUNK:
|
||||
weHave = req_c->file.length - req_c->offset;
|
||||
case FILE_CHUNK:
|
||||
weHave = req_c->file.length - req_c->offset;
|
||||
|
||||
if (weHave > weWant) weHave = weWant;
|
||||
if (weHave > weWant) weHave = weWant;
|
||||
|
||||
chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave);
|
||||
chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave);
|
||||
|
||||
req_c->offset += weHave;
|
||||
req_cq->bytes_out += weHave;
|
||||
req_c->offset += weHave;
|
||||
req_cq->bytes_out += weHave;
|
||||
|
||||
hctx->wb->bytes_in += weHave;
|
||||
hctx->wb->bytes_in += weHave;
|
||||
|
||||
break;
|
||||
case MEM_CHUNK:
|
||||
/* append to the buffer */
|
||||
weHave = req_c->mem->used - 1 - req_c->offset;
|
||||
break;
|
||||
case MEM_CHUNK:
|
||||
/* append to the buffer */
|
||||
weHave = req_c->mem->used - 1 - req_c->offset;
|
||||
|
||||
if (weHave > weWant) weHave = weWant;
|
||||
if (weHave > weWant) weHave = weWant;
|
||||
|
||||
b = chunkqueue_get_append_buffer(hctx->wb);
|
||||
buffer_append_memory(b, req_c->mem->ptr + req_c->offset, weHave);
|
||||
b->used++; /* add virtual \0 */
|
||||
b = chunkqueue_get_append_buffer(hctx->wb);
|
||||
buffer_append_memory(b, req_c->mem->ptr + req_c->offset, weHave);
|
||||
b->used++; /* add virtual \0 */
|
||||
|
||||
req_c->offset += weHave;
|
||||
req_cq->bytes_out += weHave;
|
||||
req_c->offset += weHave;
|
||||
req_cq->bytes_out += weHave;
|
||||
|
||||
hctx->wb->bytes_in += weHave;
|
||||
hctx->wb->bytes_in += weHave;
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
offset += weHave;
|
||||
@@ -671,29 +677,29 @@ static int uwsgi_response_parse(server *srv, connection *con, plugin_data *p, bu
|
||||
copy_header = 1;
|
||||
|
||||
switch(key_len) {
|
||||
case 4:
|
||||
if (0 == strncasecmp(key, "Date", key_len)) {
|
||||
con->parsed_response |= HTTP_DATE;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if (0 == strncasecmp(key, "Location", key_len)) {
|
||||
con->parsed_response |= HTTP_LOCATION;
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
if (0 == strncasecmp(key, "Connection", key_len)) {
|
||||
copy_header = 0;
|
||||
}
|
||||
break;
|
||||
case 14:
|
||||
if (0 == strncasecmp(key, "Content-Length", key_len)) {
|
||||
con->response.content_length = strtol(value, NULL, 10);
|
||||
con->parsed_response |= HTTP_CONTENT_LENGTH;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case 4:
|
||||
if (0 == strncasecmp(key, "Date", key_len)) {
|
||||
con->parsed_response |= HTTP_DATE;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if (0 == strncasecmp(key, "Location", key_len)) {
|
||||
con->parsed_response |= HTTP_LOCATION;
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
if (0 == strncasecmp(key, "Connection", key_len)) {
|
||||
copy_header = 0;
|
||||
}
|
||||
break;
|
||||
case 14:
|
||||
if (0 == strncasecmp(key, "Content-Length", key_len)) {
|
||||
con->response.content_length = strtol(value, NULL, 10);
|
||||
con->parsed_response |= HTTP_CONTENT_LENGTH;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (copy_header) {
|
||||
@@ -731,7 +737,7 @@ static int uwsgi_demux_response(server *srv, handler_ctx *hctx) {
|
||||
|
||||
if (p->conf.debug) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sd",
|
||||
"uwsgi - have to read:", b);
|
||||
"uwsgi - have to read:", b);
|
||||
}
|
||||
|
||||
if (b > 0) {
|
||||
@@ -785,7 +791,7 @@ static int uwsgi_demux_response(server *srv, handler_ctx *hctx) {
|
||||
|
||||
/* enable chunked-transfer-encoding */
|
||||
if (con->request.http_version == HTTP_VERSION_1_1 &&
|
||||
!(con->parsed_response & HTTP_CONTENT_LENGTH)) {
|
||||
!(con->parsed_response & HTTP_CONTENT_LENGTH)) {
|
||||
con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
|
||||
}
|
||||
|
||||
@@ -824,127 +830,127 @@ static handler_t uwsgi_write_request(server *srv, handler_ctx *hctx) {
|
||||
int ret;
|
||||
|
||||
if (!host ||
|
||||
(!host->host->used || !host->port)) return -1;
|
||||
(!host->host->used || !host->port)) return -1;
|
||||
|
||||
switch(hctx->state) {
|
||||
case UWSGI_STATE_INIT:
|
||||
case UWSGI_STATE_INIT:
|
||||
#if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
|
||||
if (strstr(host->host->ptr,":")) {
|
||||
if (-1 == (hctx->fd = socket(AF_INET6, SOCK_STREAM, 0))) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
} else
|
||||
if (strstr(host->host->ptr,":")) {
|
||||
if (-1 == (hctx->fd = socket(AF_INET6, SOCK_STREAM, 0))) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
}
|
||||
hctx->fde_ndx = -1;
|
||||
{
|
||||
if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
}
|
||||
hctx->fde_ndx = -1;
|
||||
|
||||
srv->cur_fds++;
|
||||
srv->cur_fds++;
|
||||
|
||||
fdevent_register(srv->ev, hctx->fd, uwsgi_handle_fdevent, hctx);
|
||||
fdevent_register(srv->ev, hctx->fd, uwsgi_handle_fdevent, hctx);
|
||||
|
||||
if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
|
||||
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
|
||||
/* fall through */
|
||||
|
||||
case UWSGI_STATE_CONNECT:
|
||||
/* try to finish the connect() */
|
||||
if (hctx->state == UWSGI_STATE_INIT) {
|
||||
/* first round */
|
||||
switch (uwsgi_establish_connection(srv, hctx)) {
|
||||
case 1:
|
||||
uwsgi_set_state(srv, hctx, UWSGI_STATE_CONNECT);
|
||||
|
||||
/* connection is in progress, wait for an event and call getsockopt() below */
|
||||
|
||||
fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
|
||||
|
||||
return HANDLER_WAIT_FOR_EVENT;
|
||||
case -1:
|
||||
/* if ECONNREFUSED choose another connection -> FIXME */
|
||||
hctx->fde_ndx = -1;
|
||||
if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
|
||||
|
||||
return HANDLER_ERROR;
|
||||
default:
|
||||
/* everything is ok, go on */
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
int socket_error;
|
||||
socklen_t socket_error_len = sizeof(socket_error);
|
||||
|
||||
/* we don't need it anymore */
|
||||
fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
|
||||
/* fall through */
|
||||
|
||||
case UWSGI_STATE_CONNECT:
|
||||
/* try to finish the connect() */
|
||||
if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "ss",
|
||||
"getsockopt failed:", strerror(errno));
|
||||
if (hctx->state == UWSGI_STATE_INIT) {
|
||||
/* first round */
|
||||
switch (uwsgi_establish_connection(srv, hctx)) {
|
||||
case 1:
|
||||
uwsgi_set_state(srv, hctx, UWSGI_STATE_CONNECT);
|
||||
|
||||
return HANDLER_ERROR;
|
||||
/* connection is in progress, wait for an event and call getsockopt() below */
|
||||
|
||||
fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
|
||||
|
||||
return HANDLER_WAIT_FOR_EVENT;
|
||||
case -1:
|
||||
/* if ECONNREFUSED choose another connection -> FIXME */
|
||||
hctx->fde_ndx = -1;
|
||||
|
||||
return HANDLER_ERROR;
|
||||
default:
|
||||
/* everything is ok, go on */
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
int socket_error;
|
||||
socklen_t socket_error_len = sizeof(socket_error);
|
||||
|
||||
/* we don't need it anymore */
|
||||
fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
|
||||
|
||||
/* try to finish the connect() */
|
||||
if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "ss",
|
||||
"getsockopt failed:", strerror(errno));
|
||||
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
if (socket_error != 0) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "ss",
|
||||
"establishing connection failed:", strerror(socket_error),
|
||||
"port:", hctx->host->port);
|
||||
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
if (p->conf.debug) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s", "uwsgi - connect - delayed success");
|
||||
}
|
||||
}
|
||||
if (socket_error != 0) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "ss",
|
||||
"establishing connection failed:", strerror(socket_error),
|
||||
"port:", hctx->host->port);
|
||||
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
if (p->conf.debug) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s", "uwsgi - connect - delayed success");
|
||||
}
|
||||
}
|
||||
uwsgi_set_state(srv, hctx, UWSGI_STATE_PREPARE_WRITE);
|
||||
/* fall through */
|
||||
case UWSGI_STATE_PREPARE_WRITE:
|
||||
uwsgi_create_env(srv, hctx);
|
||||
|
||||
uwsgi_set_state(srv, hctx, UWSGI_STATE_PREPARE_WRITE);
|
||||
/* fall through */
|
||||
case UWSGI_STATE_PREPARE_WRITE:
|
||||
uwsgi_create_env(srv, hctx);
|
||||
uwsgi_set_state(srv, hctx, UWSGI_STATE_WRITE);
|
||||
|
||||
uwsgi_set_state(srv, hctx, UWSGI_STATE_WRITE);
|
||||
/* fall through */
|
||||
case UWSGI_STATE_WRITE:;
|
||||
ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);
|
||||
|
||||
/* fall through */
|
||||
case UWSGI_STATE_WRITE:;
|
||||
ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);
|
||||
chunkqueue_remove_finished_chunks(hctx->wb);
|
||||
|
||||
chunkqueue_remove_finished_chunks(hctx->wb);
|
||||
if (-1 == ret) { /* error on our side */
|
||||
log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
|
||||
|
||||
if (-1 == ret) { /* error on our side */
|
||||
log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
|
||||
return HANDLER_WAIT_FOR_EVENT;
|
||||
} else if (-2 == ret) { /* remote close */
|
||||
log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed, remote connection close:", strerror(errno), errno);
|
||||
|
||||
return HANDLER_WAIT_FOR_EVENT;
|
||||
} else if (-2 == ret) { /* remote close */
|
||||
log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed, remote connection close:", strerror(errno), errno);
|
||||
return HANDLER_WAIT_FOR_EVENT;
|
||||
}
|
||||
|
||||
return HANDLER_WAIT_FOR_EVENT;
|
||||
}
|
||||
if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
|
||||
uwsgi_set_state(srv, hctx, UWSGI_STATE_READ);
|
||||
|
||||
if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
|
||||
uwsgi_set_state(srv, hctx, UWSGI_STATE_READ);
|
||||
fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
|
||||
fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
|
||||
} else {
|
||||
fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
|
||||
|
||||
fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
|
||||
fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
|
||||
} else {
|
||||
fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
|
||||
return HANDLER_WAIT_FOR_EVENT;
|
||||
}
|
||||
|
||||
return HANDLER_WAIT_FOR_EVENT;
|
||||
}
|
||||
|
||||
return HANDLER_WAIT_FOR_EVENT;
|
||||
case UWSGI_STATE_READ:
|
||||
/* waiting for a response */
|
||||
return HANDLER_WAIT_FOR_EVENT;
|
||||
default:
|
||||
log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
|
||||
return HANDLER_ERROR;
|
||||
return HANDLER_WAIT_FOR_EVENT;
|
||||
case UWSGI_STATE_READ:
|
||||
/* waiting for a response */
|
||||
return HANDLER_WAIT_FOR_EVENT;
|
||||
default:
|
||||
log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
|
||||
return HANDLER_GO_ON;
|
||||
@@ -1000,36 +1006,36 @@ SUBREQUEST_FUNC(mod_uwsgi_handle_subrequest) {
|
||||
|
||||
/* ok, create the request */
|
||||
switch(uwsgi_write_request(srv, hctx)) {
|
||||
case HANDLER_ERROR:
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbdd", "uwsgi-server disabled:",
|
||||
host->host,
|
||||
host->port,
|
||||
hctx->fd);
|
||||
case HANDLER_ERROR:
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbdd", "uwsgi-server disabled:",
|
||||
host->host,
|
||||
host->port,
|
||||
hctx->fd);
|
||||
|
||||
/* disable this server */
|
||||
host->is_disabled = 1;
|
||||
host->disable_ts = srv->cur_ts;
|
||||
/* disable this server */
|
||||
host->is_disabled = 1;
|
||||
host->disable_ts = srv->cur_ts;
|
||||
|
||||
uwsgi_connection_close(srv, hctx);
|
||||
uwsgi_connection_close(srv, hctx);
|
||||
|
||||
/* reset the enviroment and restart the sub-request */
|
||||
buffer_reset(con->physical.path);
|
||||
con->mode = DIRECT;
|
||||
/* reset the enviroment and restart the sub-request */
|
||||
buffer_reset(con->physical.path);
|
||||
con->mode = DIRECT;
|
||||
|
||||
joblist_append(srv, con);
|
||||
joblist_append(srv, con);
|
||||
|
||||
/* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
|
||||
* and hope that the childs will be restarted
|
||||
*
|
||||
*/
|
||||
/* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
|
||||
* and hope that the childs will be restarted
|
||||
*
|
||||
*/
|
||||
|
||||
return HANDLER_WAIT_FOR_FD;
|
||||
case HANDLER_WAIT_FOR_EVENT:
|
||||
return HANDLER_WAIT_FOR_EVENT;
|
||||
case HANDLER_WAIT_FOR_FD:
|
||||
return HANDLER_WAIT_FOR_FD;
|
||||
default:
|
||||
break;
|
||||
return HANDLER_WAIT_FOR_FD;
|
||||
case HANDLER_WAIT_FOR_EVENT:
|
||||
return HANDLER_WAIT_FOR_EVENT;
|
||||
case HANDLER_WAIT_FOR_FD:
|
||||
return HANDLER_WAIT_FOR_FD;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (con->file_started == 1) {
|
||||
@@ -1047,7 +1053,7 @@ static handler_t uwsgi_handle_fdevent(void *s, void *ctx, int revents) {
|
||||
|
||||
|
||||
if ((revents & FDEVENT_IN) &&
|
||||
hctx->state == UWSGI_STATE_READ) {
|
||||
hctx->state == UWSGI_STATE_READ) {
|
||||
|
||||
if (p->conf.debug) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sd",
|
||||
@@ -1055,29 +1061,29 @@ static handler_t uwsgi_handle_fdevent(void *s, void *ctx, int revents) {
|
||||
}
|
||||
|
||||
switch (uwsgi_demux_response(srv, hctx)) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
hctx->host->usage--;
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
hctx->host->usage--;
|
||||
|
||||
/* we are done */
|
||||
uwsgi_connection_close(srv, hctx);
|
||||
/* we are done */
|
||||
uwsgi_connection_close(srv, hctx);
|
||||
|
||||
joblist_append(srv, con);
|
||||
return HANDLER_FINISHED;
|
||||
case -1:
|
||||
if (con->file_started == 0) {
|
||||
/* nothing has been send out yet, send a 500 */
|
||||
connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
|
||||
con->http_status = 500;
|
||||
con->mode = DIRECT;
|
||||
} else {
|
||||
/* response might have been already started, kill the connection */
|
||||
connection_set_state(srv, con, CON_STATE_ERROR);
|
||||
}
|
||||
joblist_append(srv, con);
|
||||
return HANDLER_FINISHED;
|
||||
case -1:
|
||||
if (con->file_started == 0) {
|
||||
/* nothing has been send out yet, send a 500 */
|
||||
connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
|
||||
con->http_status = 500;
|
||||
con->mode = DIRECT;
|
||||
} else {
|
||||
/* response might have been already started, kill the connection */
|
||||
connection_set_state(srv, con, CON_STATE_ERROR);
|
||||
}
|
||||
|
||||
joblist_append(srv, con);
|
||||
return HANDLER_FINISHED;
|
||||
joblist_append(srv, con);
|
||||
return HANDLER_FINISHED;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1088,7 +1094,7 @@ static handler_t uwsgi_handle_fdevent(void *s, void *ctx, int revents) {
|
||||
}
|
||||
|
||||
if (hctx->state == UWSGI_STATE_CONNECT ||
|
||||
hctx->state == UWSGI_STATE_WRITE) {
|
||||
hctx->state == UWSGI_STATE_WRITE) {
|
||||
/* we are allowed to send something out
|
||||
*
|
||||
* 1. in a unfinished connect() call
|
||||
@@ -1189,7 +1195,7 @@ static handler_t mod_uwsgi_check_extension(server *srv, connection *con, void *p
|
||||
/* check extension in the form "/uwsgi_pattern" */
|
||||
if (*(ext->key->ptr) == '/') {
|
||||
if (strncmp(fn->ptr, ext->key->ptr, ct_len) == 0) {
|
||||
path_info_offset = ct_len ;
|
||||
path_info_offset = ct_len;
|
||||
extension = ext;
|
||||
break;
|
||||
}
|
||||
@@ -1314,7 +1320,7 @@ TRIGGER_FUNC(mod_uwsgi_trigger) {
|
||||
data_uwsgi *host = (data_uwsgi *)extension->value->data[n];
|
||||
|
||||
if (!host->is_disabled ||
|
||||
srv->cur_ts - host->disable_ts < 5) continue;
|
||||
srv->cur_ts - host->disable_ts < 5) continue;
|
||||
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbd",
|
||||
"uwsgi - re-enabled:",
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
|
||||
#ifdef UWSGI_LOCK_USE_MUTEX
|
||||
|
||||
#define UWSGI_LOCK_SIZE sizeof(pthread_mutexattr_t) + sizeof(pthread_mutex_t)
|
||||
#define UWSGI_RWLOCK_SIZE sizeof(pthread_rwlockattr_t) + sizeof(pthread_rwlock_t)
|
||||
|
||||
// REMEMBER lock must contains space for both pthread_mutex_t and pthread_mutexattr_t !!!
|
||||
void uwsgi_lock_init(void *lock) {
|
||||
|
||||
if (pthread_mutexattr_init((pthread_mutexattr_t *) lock)) {
|
||||
uwsgi_log("unable to allocate mutexattr structure\n");
|
||||
exit(1);
|
||||
}
|
||||
if (pthread_mutexattr_setpshared((pthread_mutexattr_t *) lock, PTHREAD_PROCESS_SHARED)) {
|
||||
uwsgi_log("unable to share mutex\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pthread_mutex_init((pthread_mutex_t *) lock + sizeof(pthread_mutexattr_t), (pthread_mutexattr_t *) lock)) {
|
||||
uwsgi_log("unable to initialize mutex\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_rlock(void *lock) {
|
||||
pthread_rwlock_rdlock((pthread_rwlock_t *) lock + sizeof(pthread_rwlockattr_t));
|
||||
}
|
||||
|
||||
void uwsgi_wlock(void *lock) {
|
||||
pthread_rwlock_wrlock((pthread_rwlock_t *) lock + sizeof(pthread_rwlockattr_t));
|
||||
}
|
||||
|
||||
void uwsgi_rwunlock(void *lock) {
|
||||
pthread_rwlock_unlock((pthread_rwlock_t *) lock + sizeof(pthread_rwlockattr_t));
|
||||
}
|
||||
|
||||
void uwsgi_lock(void *lock) {
|
||||
|
||||
pthread_mutex_lock((pthread_mutex_t *) lock + sizeof(pthread_mutexattr_t));
|
||||
}
|
||||
|
||||
void uwsgi_unlock(void *lock) {
|
||||
|
||||
pthread_mutex_unlock((pthread_mutex_t *) lock + sizeof(pthread_mutexattr_t));
|
||||
}
|
||||
|
||||
void uwsgi_rwlock_init(void *lock) {
|
||||
|
||||
if (pthread_rwlockattr_init((pthread_rwlockattr_t *) lock)) {
|
||||
uwsgi_log("unable to allocate rwlock structure\n");
|
||||
exit(1);
|
||||
}
|
||||
if (pthread_rwlockattr_setpshared((pthread_rwlockattr_t *) lock, PTHREAD_PROCESS_SHARED)) {
|
||||
uwsgi_log("unable to share rwlock\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pthread_rwlock_init((pthread_rwlock_t *) lock + sizeof(pthread_rwlockattr_t), (pthread_rwlockattr_t *) lock)) {
|
||||
uwsgi_log("unable to initialize rwlock\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_LOCK_USE_UMTX
|
||||
|
||||
#include <machine/atomic.h>
|
||||
#include <sys/umtx.h>
|
||||
|
||||
#define UWSGI_LOCK_SIZE sizeof(struct umtx)
|
||||
#define UWSGI_RWLOCK_SIZE sizeof(struct umtx)
|
||||
|
||||
void uwsgi_rwlock_init(void *lock) { uwsgi_lock_init(lock) ;}
|
||||
void uwsgi_rlock(void *lock) { uwsgi_lock(lock);}
|
||||
void uwsgi_wlock(void *lock) { uwsgi_lock(lock);}
|
||||
void uwsgi_rwunlock(void *lock) { uwsgi_unlock(lock); }
|
||||
|
||||
void uwsgi_lock_init(void *lock) {
|
||||
umtx_init((struct umtx*) lock);
|
||||
}
|
||||
|
||||
void uwsgi_lock(void *lock) {
|
||||
umtx_lock(lock, 1);
|
||||
}
|
||||
|
||||
void uwsgi_unlock(void *lock) {
|
||||
umtx_unlock(lock, 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef UWSGI_LOCK_USE_OSX_SPINLOCK
|
||||
|
||||
#define UWSGI_LOCK_SIZE sizeof(OSSpinLock)
|
||||
#define UWSGI_RWLOCK_SIZE sizeof(OSSpinLock)
|
||||
|
||||
|
||||
void uwsgi_lock_init(void *lock) {
|
||||
|
||||
memset(lock, 0, sizeof(OSSpinLock));
|
||||
}
|
||||
|
||||
void uwsgi_lock(void *lock) {
|
||||
|
||||
OSSpinLockLock((OSSpinLock *) lock);
|
||||
}
|
||||
|
||||
void uwsgi_unlock(void *lock) {
|
||||
|
||||
OSSpinLockUnlock((OSSpinLock *) lock);
|
||||
}
|
||||
|
||||
void uwsgi_rwlock_init(void *lock) { uwsgi_lock_init(lock) ;}
|
||||
void uwsgi_rlock(void *lock) { uwsgi_lock(lock);}
|
||||
void uwsgi_wlock(void *lock) { uwsgi_lock(lock);}
|
||||
void uwsgi_rwunlock(void *lock) { uwsgi_unlock(lock); }
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef UWSGI_LOCK_USE_FLOCK
|
||||
|
||||
#define UWSGI_LOCK_SIZE 8
|
||||
#define UWSGI_RWLOCK_SIZE 8
|
||||
|
||||
static int lock_counter = 0;
|
||||
|
||||
void uwsgi_lock_init(void *lock) {
|
||||
|
||||
char filename[17];
|
||||
|
||||
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()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memcpy(lock, &fd, sizeof(int));
|
||||
}
|
||||
|
||||
void uwsgi_lock(void *lock) {
|
||||
|
||||
int fd;
|
||||
memcpy(&fd, lock, sizeof(int));
|
||||
if (flock(fd, LOCK_EX)) { uwsgi_error("flock()"); }
|
||||
}
|
||||
|
||||
void uwsgi_unlock(void *lock) {
|
||||
int fd;
|
||||
memcpy(&fd, lock, sizeof(int));
|
||||
if (flock(fd, LOCK_UN)) { uwsgi_error("flock()"); }
|
||||
}
|
||||
|
||||
void uwsgi_rwlock_init(void *lock) { uwsgi_lock_init(lock) ;}
|
||||
void uwsgi_rlock(void *lock) { uwsgi_lock(lock);}
|
||||
void uwsgi_wlock(void *lock) { uwsgi_lock(lock);}
|
||||
void uwsgi_rwunlock(void *lock) { uwsgi_unlock(lock); }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void *uwsgi_mmap_shared_lock() {
|
||||
void *addr = NULL;
|
||||
addr = mmap(NULL, UWSGI_LOCK_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
|
||||
if (addr == NULL) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
void *uwsgi_mmap_shared_rwlock() {
|
||||
void *addr = NULL;
|
||||
addr = mmap(NULL, UWSGI_RWLOCK_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
|
||||
if (addr == NULL) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
#define _NO_UWSGI_RB
|
||||
#include "uwsgi.h"
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
|
||||
@@ -31,23 +32,30 @@ void log_request(struct wsgi_request *wsgi_req) {
|
||||
char mempkt[4096];
|
||||
char logpkt[4096];
|
||||
|
||||
struct iovec logvec[2] ;
|
||||
int logvecpos = 0 ;
|
||||
struct iovec logvec[4];
|
||||
int logvecpos = 0;
|
||||
|
||||
const char *msecs = "msecs";
|
||||
const char *micros = "micros";
|
||||
|
||||
long int rt;
|
||||
char *tsize = (char *) msecs;
|
||||
|
||||
#ifdef UWSGI_SENDFILE
|
||||
char *msg1 = " via sendfile() ";
|
||||
#endif
|
||||
|
||||
struct uwsgi_app *wi;
|
||||
|
||||
if (wsgi_req->app_id >= 0) {
|
||||
wi = &uwsgi.wsgi_apps[wsgi_req->app_id];
|
||||
wi = &uwsgi.apps[wsgi_req->app_id];
|
||||
if (wi->requests > 0) {
|
||||
app_req = wi->requests;
|
||||
}
|
||||
}
|
||||
via = msg2;
|
||||
|
||||
if (wsgi_req->sendfile_fd > -1) {
|
||||
#ifdef UWSGI_SENDFILE
|
||||
if (wsgi_req->sendfile_fd > -1 && wsgi_req->sendfile_obj == wsgi_req->async_result) { //wsgi_req->sendfile_fd_size > 0 ) {
|
||||
via = msg1;
|
||||
}
|
||||
#endif
|
||||
@@ -56,52 +64,67 @@ void log_request(struct wsgi_request *wsgi_req) {
|
||||
microseconds = wsgi_req->end_of_request.tv_sec * 1000000 + wsgi_req->end_of_request.tv_usec;
|
||||
microseconds2 = wsgi_req->start_of_request.tv_sec * 1000000 + wsgi_req->start_of_request.tv_usec;
|
||||
|
||||
rt = (long int) (microseconds - microseconds2);
|
||||
|
||||
if (uwsgi.log_micros) {
|
||||
tsize = (char *) micros;
|
||||
}
|
||||
else {
|
||||
rt /= 1000;
|
||||
}
|
||||
|
||||
if (uwsgi.vhost) {
|
||||
logvec[logvecpos].iov_base = wsgi_req->host;
|
||||
logvec[logvecpos].iov_len = wsgi_req->host_len;
|
||||
logvecpos++;
|
||||
|
||||
logvec[logvecpos].iov_base = " ";
|
||||
logvec[logvecpos].iov_len = 1;
|
||||
logvecpos++;
|
||||
}
|
||||
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG] == 1) {
|
||||
#ifndef UNBIT
|
||||
rlen = snprintf(mempkt, 4096, "{address space usage: %lld bytes/%lluMB} {rss usage: %llu bytes/%lluMB} ",
|
||||
uwsgi.workers[uwsgi.mywid].vsz_size, uwsgi.workers[uwsgi.mywid].vsz_size / 1024 / 1024,
|
||||
uwsgi.workers[uwsgi.mywid].rss_size, uwsgi.workers[uwsgi.mywid].rss_size / 1024 / 1024);
|
||||
(unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size, (unsigned long long ) uwsgi.workers[uwsgi.mywid].vsz_size / 1024 / 1024,
|
||||
(unsigned long long) uwsgi.workers[uwsgi.mywid].rss_size, (unsigned long long ) uwsgi.workers[uwsgi.mywid].rss_size / 1024 / 1024);
|
||||
#else
|
||||
rlen = snprintf(mempkt, 4096, "{address space usage: %lld bytes/%lluMB} ",
|
||||
uwsgi.workers[uwsgi.mywid].vsz_size, uwsgi.workers[uwsgi.mywid].vsz_size / 1024 / 1024);
|
||||
(unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size, (unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size / 1024 / 1024);
|
||||
#endif
|
||||
|
||||
|
||||
logvec[logvecpos].iov_base = mempkt ;
|
||||
logvec[logvecpos].iov_len = rlen ;
|
||||
logvec[logvecpos].iov_base = mempkt;
|
||||
logvec[logvecpos].iov_len = rlen;
|
||||
logvecpos++;
|
||||
|
||||
|
||||
}
|
||||
|
||||
rlen = snprintf(logpkt, 4096, "[pid: %d|app: %d|req: %d/%llu] %.*s (%.*s) {%d vars in %d bytes} [%.*s] %.*s %.*s => generated %llu bytes in %ld msecs%s(%.*s %d) %d headers in %d bytes (%d async switches on async core %d)\n",
|
||||
uwsgi.mypid,
|
||||
wsgi_req->app_id,
|
||||
app_req,
|
||||
uwsgi.workers[0].requests,
|
||||
wsgi_req->remote_addr_len, wsgi_req->remote_addr,
|
||||
wsgi_req->remote_user_len, wsgi_req->remote_user,
|
||||
wsgi_req->var_cnt,
|
||||
wsgi_req->uh.pktsize,
|
||||
24, time_request,
|
||||
wsgi_req->method_len, wsgi_req->method,
|
||||
wsgi_req->uri_len, wsgi_req->uri,
|
||||
(uint64_t) wsgi_req->response_size,
|
||||
(long int) (microseconds - microseconds2) / 1000,
|
||||
via,
|
||||
wsgi_req->protocol_len, wsgi_req->protocol,
|
||||
wsgi_req->status,
|
||||
wsgi_req->header_cnt,
|
||||
wsgi_req->headers_size,
|
||||
wsgi_req->async_switches, wsgi_req->async_id);
|
||||
rlen = snprintf(logpkt, 4096, "[pid: %d|app: %d|req: %d/%llu] %.*s (%.*s) {%d vars in %d bytes} [%.*s] %.*s %.*s => generated %llu bytes in %ld %s%s(%.*s %d) %d headers in %llu bytes (%d switches on core %d)\n",
|
||||
(int) uwsgi.mypid,
|
||||
wsgi_req->app_id,
|
||||
app_req,
|
||||
(unsigned long long ) uwsgi.workers[0].requests,
|
||||
wsgi_req->remote_addr_len, wsgi_req->remote_addr,
|
||||
wsgi_req->remote_user_len, wsgi_req->remote_user,
|
||||
wsgi_req->var_cnt,
|
||||
wsgi_req->uh.pktsize,
|
||||
24, time_request,
|
||||
wsgi_req->method_len, wsgi_req->method,
|
||||
wsgi_req->uri_len, wsgi_req->uri,
|
||||
(unsigned long long) wsgi_req->response_size,
|
||||
rt, tsize,
|
||||
via,
|
||||
wsgi_req->protocol_len, wsgi_req->protocol,
|
||||
wsgi_req->status,
|
||||
wsgi_req->header_cnt,
|
||||
(unsigned long long) wsgi_req->headers_size,
|
||||
wsgi_req->switches, wsgi_req->async_id);
|
||||
|
||||
logvec[logvecpos].iov_base = logpkt ;
|
||||
logvec[logvecpos].iov_len = rlen ;
|
||||
logvec[logvecpos].iov_base = logpkt;
|
||||
logvec[logvecpos].iov_len = rlen;
|
||||
|
||||
// do not check for errors
|
||||
rlen = writev(2, logvec, logvecpos+1);
|
||||
|
||||
}
|
||||
|
||||
void get_memusage() {
|
||||
@@ -113,7 +136,7 @@ void get_memusage() {
|
||||
int i;
|
||||
procfile = fopen("/proc/self/stat", "r");
|
||||
if (procfile) {
|
||||
i = fscanf(procfile, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %llu %lld", &uwsgi.workers[uwsgi.mywid].vsz_size, &uwsgi.workers[uwsgi.mywid].rss_size);
|
||||
i = fscanf(procfile, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %llu %lld", (unsigned long long *) &uwsgi.workers[uwsgi.mywid].vsz_size, (unsigned long long *) &uwsgi.workers[uwsgi.mywid].rss_size);
|
||||
if (i != 2) {
|
||||
uwsgi_log( "warning: invalid record in /proc/self/stat\n");
|
||||
}
|
||||
@@ -122,18 +145,18 @@ void get_memusage() {
|
||||
uwsgi.workers[uwsgi.mywid].rss_size = uwsgi.workers[uwsgi.mywid].rss_size * uwsgi.page_size;
|
||||
#elif defined (__sun__)
|
||||
psinfo_t info;
|
||||
int procfd ;
|
||||
int procfd;
|
||||
|
||||
procfd = open("/proc/self/psinfo", O_RDONLY);
|
||||
if (procfd >= 0) {
|
||||
if ( read(procfd, (char *) &info, sizeof(info)) > 0) {
|
||||
uwsgi.workers[uwsgi.mywid].rss_size = (uint64_t) info.pr_rssize * 1024 ;
|
||||
uwsgi.workers[uwsgi.mywid].vsz_size = (uint64_t) info.pr_size * 1024 ;
|
||||
uwsgi.workers[uwsgi.mywid].rss_size = (uint64_t) info.pr_rssize * 1024;
|
||||
uwsgi.workers[uwsgi.mywid].vsz_size = (uint64_t) info.pr_size * 1024;
|
||||
}
|
||||
close(procfd);
|
||||
}
|
||||
|
||||
#elif defined( __APPLE__)
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
/* darwin documentation says that the value are in pages, but they are bytes !!! */
|
||||
struct task_basic_info t_info;
|
||||
mach_msg_type_number_t t_size = sizeof(struct task_basic_info);
|
||||
@@ -158,7 +181,7 @@ void get_memusage() {
|
||||
}
|
||||
#elif defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
struct kinfo_proc2 *kproc2;
|
||||
|
||||
|
||||
kproc2 = kvm_getproc2(kv, KERN_PROC_PID, uwsgi.mypid, sizeof(struct kinfo_proc2), &cnt);
|
||||
if (kproc2 && cnt > 0) {
|
||||
#ifdef __OpenBSD__
|
||||
@@ -172,6 +195,17 @@ void get_memusage() {
|
||||
|
||||
kvm_close(kv);
|
||||
}
|
||||
#elif defined(__HAIKU__)
|
||||
area_info ai;
|
||||
int32 cookie;
|
||||
|
||||
uwsgi.workers[uwsgi.mywid].vsz_size = 0;
|
||||
uwsgi.workers[uwsgi.mywid].rss_size = 0;
|
||||
while(get_next_area_info(0, &cookie, &ai) == B_OK) {
|
||||
uwsgi.workers[uwsgi.mywid].vsz_size += ai.ram_size;
|
||||
if ( (ai.protection & B_WRITE_AREA) != 0) {
|
||||
uwsgi.workers[uwsgi.mywid].rss_size += ai.ram_size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct wsgi_request* threaded_current_wsgi_req() { return pthread_getspecific(uwsgi.tur_key); }
|
||||
struct wsgi_request* simple_current_wsgi_req() { return uwsgi.wsgi_req; }
|
||||
|
||||
|
||||
void uwsgi_register_loop(char *name, void *loop) {
|
||||
|
||||
if (uwsgi.loops_cnt >= MAX_LOOPS) {
|
||||
uwsgi_log("you can define %d loops at max\n", MAX_LOOPS);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi.loops[uwsgi.loops_cnt].name = name;
|
||||
uwsgi.loops[uwsgi.loops_cnt].loop = loop;
|
||||
uwsgi.loops_cnt++;
|
||||
}
|
||||
|
||||
void *uwsgi_get_loop(char *name) {
|
||||
|
||||
int i;
|
||||
|
||||
for(i=0;i<uwsgi.loops_cnt;i++) {
|
||||
if (!strcmp(name, uwsgi.loops[i].name)) {
|
||||
return uwsgi.loops[i].loop;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *simple_loop(void *arg1) {
|
||||
|
||||
long core_id = (long) arg1;
|
||||
|
||||
struct wsgi_request *wsgi_req = uwsgi.wsgi_requests[core_id];
|
||||
int i;
|
||||
|
||||
#ifdef UWSGI_THREADING
|
||||
//PyThreadState *pts;
|
||||
sigset_t smask;
|
||||
|
||||
if (uwsgi.threads > 1) {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
/*
|
||||
pts = PyThreadState_New(uwsgi.main_thread->interp);
|
||||
pthread_setspecific(uwsgi.ut_save_key, (void *) pts);
|
||||
*/
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
|
||||
|
||||
|
||||
UWSGI_CLEAR_STATUS;
|
||||
|
||||
|
||||
wsgi_req_setup(wsgi_req, core_id);
|
||||
|
||||
if (wsgi_req_accept(wsgi_req)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (wsgi_req_recv(wsgi_req)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uwsgi_close_request(wsgi_req);
|
||||
}
|
||||
|
||||
pthread_exit(NULL);
|
||||
|
||||
//never here
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_ASYNC
|
||||
void complex_loop() {
|
||||
int current_async_timeout = 0;
|
||||
int i, j;
|
||||
int interesting_fd;
|
||||
|
||||
struct wsgi_request *wsgi_req;
|
||||
|
||||
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
|
||||
|
||||
current_async_timeout = async_get_timeout();
|
||||
|
||||
uwsgi.async_nevents = event_queue_wait_multi(uwsgi.async_queue, current_async_timeout, uwsgi.async_events, 64);
|
||||
async_expire_timeouts();
|
||||
|
||||
if (uwsgi.async_nevents < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
for(i=0; i<uwsgi.async_nevents;i++) {
|
||||
|
||||
interesting_fd = event_queue_interesting_fd(uwsgi.async_events, i);
|
||||
|
||||
if ( interesting_fd == uwsgi.sockets[0].fd) {
|
||||
|
||||
uwsgi.wsgi_req = find_first_available_wsgi_req();
|
||||
if (uwsgi.wsgi_req == NULL) {
|
||||
// async system is full !!!
|
||||
goto cycle;
|
||||
}
|
||||
|
||||
wsgi_req_setup(uwsgi.wsgi_req, uwsgi.wsgi_req->async_id );
|
||||
|
||||
if (wsgi_req_simple_accept(uwsgi.wsgi_req, interesting_fd)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wsgi_req_recv(uwsgi.wsgi_req)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uwsgi.wsgi_req->async_status == UWSGI_OK) {
|
||||
goto reqclear;
|
||||
}
|
||||
|
||||
}
|
||||
else if ( interesting_fd == uwsgi.sockets_poll[uwsgi.sockets_cnt].fd) {
|
||||
// wake up cores waiting for signal
|
||||
char byte;
|
||||
if (read(uwsgi.sockets_poll[uwsgi.sockets_cnt].fd, &byte, 1) == 1) {
|
||||
}
|
||||
else {
|
||||
uwsgi_error("read()");
|
||||
}
|
||||
for(j=0;j<uwsgi.async_current_max;j++) {
|
||||
wsgi_req = uwsgi.wsgi_requests[j] ;
|
||||
if (wsgi_req->sigwait) {
|
||||
wsgi_req->signal_received = byte;
|
||||
wsgi_req->sigwait = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi.wsgi_req = find_wsgi_req_by_fd(interesting_fd);
|
||||
if (uwsgi.wsgi_req) {
|
||||
uwsgi.wsgi_req->async_status = UWSGI_AGAIN;
|
||||
uwsgi.wsgi_req->async_waiting_fd = -1;
|
||||
uwsgi.wsgi_req->async_waiting_fd_monitored = 0;
|
||||
uwsgi.wsgi_req->async_timeout = 0;
|
||||
}
|
||||
|
||||
event_queue_del_fd(uwsgi.async_queue, interesting_fd);
|
||||
}
|
||||
}
|
||||
|
||||
cycle:
|
||||
|
||||
uwsgi.wsgi_req = async_loop();
|
||||
|
||||
if (uwsgi.wsgi_req == NULL)
|
||||
continue;
|
||||
uwsgi.wsgi_req->async_status = UWSGI_OK;
|
||||
|
||||
reqclear:
|
||||
uwsgi_close_request(uwsgi.wsgi_req);
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
<unbit>
|
||||
<pippo/>
|
||||
|
||||
<pluto>
|
||||
ciao
|
||||
ciao
|
||||
</pluto>
|
||||
|
||||
|
||||
<uwsgi id="unbit.it">
|
||||
<http>:3333</http>
|
||||
<module>trac.web.main:dispatch_request</module>
|
||||
<pluto>ciao</pluto>
|
||||
<env>TRAC_ENV=/root/uwsgi/utrac</env>
|
||||
</uwsgi>
|
||||
|
||||
<uwsgi id="projects.unbit.it">
|
||||
<http>:4444</http>
|
||||
<module>trac.web.main:dispatch_request</module>
|
||||
</uwsgi>
|
||||
|
||||
</unbit>
|
||||
@@ -0,0 +1,26 @@
|
||||
import uwsgi
|
||||
|
||||
import os
|
||||
|
||||
def application(env, start_response):
|
||||
|
||||
boundary = 'uwsgi_mjpeg_frame'
|
||||
|
||||
start_response('200 Ok', [
|
||||
|
||||
('Cache-Control', 'no-cache'),
|
||||
('Cache-Control', 'private'),
|
||||
('Pragma', 'no-cache'),
|
||||
('Content-Type', 'multipart/x-mixed-replace; boundary=' + boundary),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
yield "--%s\n" % boundary
|
||||
|
||||
while 1:
|
||||
yield "Content-Type: image/jpeg\r\n\r\n"
|
||||
uwsgi.sendfile('screenshot.jpg')
|
||||
yield "--%s\n" % boundary
|
||||
#os.system('./isightcapture -w 640 -h 480 screenshot.jpg')
|
||||
#os.system('screencapture -m -T 1 screenshot.jpg')
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
use Mojolicious::Lite;
|
||||
|
||||
# /
|
||||
get '/' => 'index';
|
||||
|
||||
# /*
|
||||
get '/:groovy' => sub {
|
||||
my $self = shift;
|
||||
$self->render_text($self->param('groovy'), layout => 'funky');
|
||||
};
|
||||
|
||||
app->start('psgi');
|
||||
__DATA__
|
||||
|
||||
@@ index.html.ep
|
||||
% layout 'funky';
|
||||
Yea baby!
|
||||
|
||||
@@ layouts/funky.html.ep
|
||||
<!doctype html><html>
|
||||
<head><title>Funky!</title></head>
|
||||
<body><%= content %></body>
|
||||
</html>
|
||||
@@ -0,0 +1,13 @@
|
||||
[uwsgi]
|
||||
socket = :3033
|
||||
socket = :3034
|
||||
vacuum = true
|
||||
socket = pippo1.sock
|
||||
socket = pippo2.sock
|
||||
socket = 127.0.0.1:1717
|
||||
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
|
||||
@@ -0,0 +1,50 @@
|
||||
<uwsgi>
|
||||
|
||||
<plugins>rack</plugins>
|
||||
|
||||
<http>:9090</http>
|
||||
|
||||
<socket>:3031</socket>
|
||||
<socket>127.0.0.1:3032</socket>
|
||||
|
||||
<manage-script-name/>
|
||||
|
||||
<master/>
|
||||
<processes>8</processes>
|
||||
|
||||
<!--
|
||||
<vhost/>
|
||||
<vhost-host/>
|
||||
-->
|
||||
|
||||
<env>TRAC_ENV=utrac</env>
|
||||
|
||||
|
||||
<app mountpoint="/">
|
||||
<module>werkzeug.testapp:test_app</module>
|
||||
</app>
|
||||
|
||||
<app mountpoint="/trac">
|
||||
<module>trac.web.main:dispatch_request</module>
|
||||
</app>
|
||||
|
||||
<app mountpoint="/trac/foo">
|
||||
<module>werkzeug.testapp:test_app</module>
|
||||
</app>
|
||||
|
||||
<app mountpoint="/bzr">
|
||||
<eval>
|
||||
from bzrlib.transport.http import wsgi
|
||||
application = wsgi.make_app("mybzr", "/bzr", readonly=False)
|
||||
</eval>
|
||||
</app>
|
||||
|
||||
<app domain="sirius002:9090">
|
||||
<module>trac.web.main:dispatch_request</module>
|
||||
</app>
|
||||
|
||||
<app domain="sirius003:9090">
|
||||
<rack>config2.ru</rack>
|
||||
</app>
|
||||
|
||||
</uwsgi>
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
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
|
||||
|
||||
def zero_app(e,s):
|
||||
s('200 OK', [ ('Content-Type', 'text/plain') ])
|
||||
return ""
|
||||
|
||||
def not_found(e,s):
|
||||
s('404 Not Found', [ ('Content-Type', 'text/plain') ])
|
||||
return ""
|
||||
|
||||
|
||||
def wsgi_app(e, s):
|
||||
s('200 OK', [ ('Content-Type', 'text/plain') ])
|
||||
yield "I am a WSGI app\n"
|
||||
|
||||
|
||||
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}
|
||||
@@ -1,51 +0,0 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
void nagios(struct uwsgi_server *uwsgi) {
|
||||
|
||||
struct pollfd nagios_poll;
|
||||
// connect and send
|
||||
if (uwsgi->socket_name == NULL) {
|
||||
fprintf(stdout, "UWSGI UNKNOWN: you have specified an invalid socket\n");
|
||||
exit(3);
|
||||
}
|
||||
char *tcp_port = strchr(uwsgi->socket_name, ':');
|
||||
if (tcp_port == NULL) {
|
||||
fprintf(stdout, "UWSGI UNKNOWN: you have specified an invalid socket\n");
|
||||
exit(3);
|
||||
}
|
||||
|
||||
tcp_port[0] = 0;
|
||||
|
||||
nagios_poll.fd = connect_to_tcp(uwsgi->socket_name, atoi(tcp_port + 1), uwsgi->shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (nagios_poll.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) {
|
||||
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)) {
|
||||
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);
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
fprintf(stdout, "UWSGI OK: armed and ready\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
// never here
|
||||
fprintf(stdout, "UWSGI UNKNOWN: probably you hit a bug of uWSGI !!!\n");
|
||||
exit(3);
|
||||
}
|
||||
+1209
-1185
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,64 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
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 *plugin_handle;
|
||||
|
||||
char *plugin_name;
|
||||
char *plugin_entry_symbol;
|
||||
struct uwsgi_plugin *up;
|
||||
|
||||
if (absolute) {
|
||||
plugin_name = malloc(strlen(plugin) + 1);
|
||||
memcpy(plugin_name, plugin, strlen(plugin) + 1);
|
||||
}
|
||||
else {
|
||||
plugin_name = uwsgi_concat4(UWSGI_PLUGIN_DIR, "/", plugin, "_plugin.so");
|
||||
}
|
||||
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) {
|
||||
if (modifier != -1) {
|
||||
fill_plugin_table(modifier, up);
|
||||
}
|
||||
else {
|
||||
fill_plugin_table(up->modifier1, up);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
uwsgi_log( "%s\n", dlerror());
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/* uwsgi ADMIN|10 */
|
||||
int uwsgi_request_admin(struct wsgi_request *wsgi_req) {
|
||||
uint32_t opt_value = 0;
|
||||
int i;
|
||||
|
||||
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()");
|
||||
}
|
||||
|
||||
|
||||
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
#include <wordexp.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
char *cgi_docroot;
|
||||
|
||||
#define LONG_ARGS_CGI_BASE 17000 + ((9 + 1) * 100)
|
||||
#define LONG_ARGS_CGI LONG_ARGS_CGI_BASE + 1
|
||||
|
||||
struct option uwsgi_cgi_options[] = {
|
||||
|
||||
{"cgi", required_argument, 0, LONG_ARGS_CGI},
|
||||
{0, 0, 0, 0},
|
||||
|
||||
};
|
||||
|
||||
int uwsgi_cgi_init(){
|
||||
|
||||
|
||||
uwsgi_log("initialized CGI engine\n");
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
int i;
|
||||
pid_t cgi_pid;
|
||||
int waitpid_status;
|
||||
char *argv[2];
|
||||
char full_path[PATH_MAX];
|
||||
|
||||
/* Standard CGI request */
|
||||
if (!wsgi_req->uh.pktsize) {
|
||||
uwsgi_log("Invalid CGI request. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (uwsgi_parse_vars(wsgi_req)) {
|
||||
uwsgi_log("Invalid CGI request. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// check for file availability (and 'runnability')
|
||||
|
||||
cgi_pid = fork();
|
||||
|
||||
if (cgi_pid < 0) {
|
||||
uwsgi_error("fork()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cgi_pid > 0) {
|
||||
// close input
|
||||
close(wsgi_req->poll.fd);
|
||||
wsgi_req->fd_closed = 1;
|
||||
|
||||
// now wait for fd
|
||||
if (waitpid(cgi_pid, &waitpid_status ,0) > 0) {
|
||||
uwsgi_log("CGI FINISHED\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// close all the fd except wsgi_req->poll.fd and 2;
|
||||
|
||||
for(i=0;i< (int)uwsgi.max_fd;i++) {
|
||||
if (i != wsgi_req->poll.fd && i != 2) {
|
||||
close(i);
|
||||
}
|
||||
}
|
||||
|
||||
// now map wsgi_req->poll.fd to 0 && 1
|
||||
if (wsgi_req->poll.fd != 0) {
|
||||
dup2(wsgi_req->poll.fd, 0);
|
||||
close(wsgi_req->poll.fd);
|
||||
}
|
||||
|
||||
dup2(0,1);
|
||||
|
||||
|
||||
// fill cgi env
|
||||
for(i=0;i<wsgi_req->var_cnt;i++) {
|
||||
// no need to free the putenv() memory
|
||||
if (putenv(uwsgi_concat3n(wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, "=", 1, wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len))) {
|
||||
uwsgi_error("putenv()");
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
char *path_info = uwsgi_concat4n(cgi_docroot, strlen(cgi_docroot), "/", 1,wsgi_req->path_info, wsgi_req->path_info_len, "", 0);
|
||||
uwsgi_log("requested %s %s\n", path_info, realpath(path_info, full_path));
|
||||
|
||||
argv[0] = full_path;
|
||||
argv[1] = NULL;
|
||||
if (execv(argv[0], argv)) {
|
||||
uwsgi_error("execv()");
|
||||
}
|
||||
|
||||
// never here
|
||||
exit(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_cgi_after_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_LOGGING])
|
||||
log_request(wsgi_req);
|
||||
}
|
||||
|
||||
int uwsgi_cgi_manage_options(int i, char *optarg) {
|
||||
|
||||
switch(i) {
|
||||
case LONG_ARGS_CGI:
|
||||
cgi_docroot = optarg;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_plugin cgi_plugin = {
|
||||
|
||||
.name = "cgi",
|
||||
.modifier1 = 9,
|
||||
.init = uwsgi_cgi_init,
|
||||
.options = uwsgi_cgi_options,
|
||||
.manage_opt = uwsgi_cgi_manage_options,
|
||||
.request = uwsgi_cgi_request,
|
||||
.after_request = uwsgi_cgi_after_request,
|
||||
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
NAME='cgi'
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
GCC_LIST = ['cgi_plugin']
|
||||
@@ -0,0 +1,19 @@
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct uwsgi_plugin echo_plugin = {
|
||||
|
||||
.name = "echo",
|
||||
.modifier1 = 101,
|
||||
|
||||
.request = uwsgi_echo_request,
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
NAME='echo'
|
||||
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
GCC_LIST = ['echo_plugin']
|
||||
@@ -0,0 +1,454 @@
|
||||
#include "../../uwsgi.h"
|
||||
#include "erlang.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
struct uwsgi_erlang uerl;
|
||||
|
||||
struct option erlang_options[] = {
|
||||
{"erlang", required_argument, 0, LONG_ARGS_ERLANG},
|
||||
{"erlang-cookie", required_argument, 0, LONG_ARGS_ERLANG_COOKIE},
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
|
||||
void dump_eterm(ei_x_buff *x) {
|
||||
|
||||
int etype, esize, arity;
|
||||
long long num;
|
||||
char *atom;
|
||||
int i;
|
||||
char *binary;
|
||||
long bin_size;
|
||||
double fnum;
|
||||
|
||||
ei_get_type(x->buff, &x->index, &etype, &esize);
|
||||
uwsgi_log("etype: %d/%c esize: %d\n", etype, etype, esize);
|
||||
|
||||
switch(etype) {
|
||||
case ERL_SMALL_INTEGER_EXT:
|
||||
case ERL_INTEGER_EXT:
|
||||
case ERL_SMALL_BIG_EXT:
|
||||
case ERL_LARGE_BIG_EXT:
|
||||
ei_decode_longlong(x->buff, &x->index, &num);
|
||||
uwsgi_log("num: %lu\n", num);
|
||||
break;
|
||||
case ERL_FLOAT_EXT:
|
||||
ei_decode_double(x->buff, &x->index, &fnum);
|
||||
uwsgi_log("float: %f\n", fnum);
|
||||
break;
|
||||
case ERL_STRING_EXT:
|
||||
atom = uwsgi_malloc(esize+1);
|
||||
ei_decode_string(x->buff, &x->index, atom);
|
||||
uwsgi_log("string: %s\n", atom);
|
||||
free(atom);
|
||||
break;
|
||||
case ERL_ATOM_EXT:
|
||||
atom = uwsgi_malloc(esize+1);
|
||||
ei_decode_atom(x->buff, &x->index, atom);
|
||||
uwsgi_log("atom: %s\n", atom);
|
||||
free(atom);
|
||||
break;
|
||||
case ERL_SMALL_TUPLE_EXT:
|
||||
case ERL_LARGE_TUPLE_EXT:
|
||||
ei_decode_tuple_header(x->buff, &x->index, &arity);
|
||||
for(i=0;i<arity;i++) {
|
||||
dump_eterm(x);
|
||||
}
|
||||
break;
|
||||
case ERL_LIST_EXT:
|
||||
case ERL_NIL_EXT:
|
||||
ei_decode_list_header(x->buff, &x->index, &arity);
|
||||
if (arity == 0) {
|
||||
uwsgi_log("nil value\n");
|
||||
break;
|
||||
}
|
||||
for(i=0;i<arity+1;i++) {
|
||||
dump_eterm(x);
|
||||
}
|
||||
break;
|
||||
case ERL_BINARY_EXT:
|
||||
binary = uwsgi_malloc(esize);
|
||||
ei_decode_binary(x->buff, &x->index, binary, &bin_size);
|
||||
uwsgi_log("binary data of %d bytes\n", bin_size);
|
||||
free(binary);
|
||||
break;
|
||||
default:
|
||||
uwsgi_log("ignored...\n");
|
||||
ei_skip_term(x->buff, &x->index);
|
||||
break;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_erlang_rpc(int fd, erlang_pid *from, ei_x_buff *x) {
|
||||
|
||||
int etype, esize;
|
||||
int arity;
|
||||
|
||||
char *gen_call;
|
||||
char *module;
|
||||
char *call;
|
||||
char buffer[0xffff];
|
||||
|
||||
char *argv[0xff] ;
|
||||
int argc;
|
||||
uint16_t ret;
|
||||
ei_x_buff xr;
|
||||
|
||||
erlang_ref eref;
|
||||
|
||||
ei_get_type(x->buff, &x->index, &etype, &esize);
|
||||
|
||||
uwsgi_log("%d %c %c %c\n", etype, etype, ERL_SMALL_TUPLE_EXT, ERL_LARGE_TUPLE_EXT);
|
||||
if (etype != ERL_SMALL_TUPLE_EXT && etype != ERL_LARGE_TUPLE_EXT) return;
|
||||
|
||||
uwsgi_log("decode tuple\n");
|
||||
ei_decode_tuple_header(x->buff, &x->index, &arity);
|
||||
|
||||
uwsgi_log("rpc arity %d\n", arity);
|
||||
if (arity != 3) return ;
|
||||
|
||||
ei_get_type(x->buff, &x->index, &etype, &esize);
|
||||
|
||||
uwsgi_log("%d %c\n", etype, etype);
|
||||
|
||||
if (etype != ERL_ATOM_EXT && etype != ERL_STRING_EXT) return ;
|
||||
|
||||
gen_call = uwsgi_malloc(esize);
|
||||
|
||||
if (etype == ERL_ATOM_EXT) {
|
||||
ei_decode_atom(x->buff, &x->index, gen_call);
|
||||
}
|
||||
else {
|
||||
ei_decode_string(x->buff, &x->index, gen_call);
|
||||
}
|
||||
|
||||
uwsgi_log("gen call = %s\n", gen_call);
|
||||
|
||||
ei_get_type(x->buff, &x->index, &etype, &esize);
|
||||
|
||||
if (etype != ERL_SMALL_TUPLE_EXT) return ;
|
||||
|
||||
ei_decode_tuple_header(x->buff, &x->index, &arity);
|
||||
if (arity != 2) return ;
|
||||
|
||||
ei_get_type(x->buff, &x->index, &etype, &esize);
|
||||
ei_skip_term(x->buff, &x->index);
|
||||
uwsgi_log("skip0 %d %c\n", etype, etype);
|
||||
ei_get_type(x->buff, &x->index, &etype, &esize);
|
||||
uwsgi_log("skip1 %d %c\n", etype, etype);
|
||||
ei_decode_ref(x->buff, &x->index, &eref);
|
||||
|
||||
ei_get_type(x->buff, &x->index, &etype, &esize);
|
||||
uwsgi_log("%d %c\n", etype, etype);
|
||||
|
||||
module = uwsgi_malloc(esize);
|
||||
|
||||
if (etype == ERL_ATOM_EXT) {
|
||||
ei_decode_atom(x->buff, &x->index, module);
|
||||
}
|
||||
else {
|
||||
ei_decode_string(x->buff, &x->index, module);
|
||||
}
|
||||
|
||||
ei_get_type(x->buff, &x->index, &etype, &esize);
|
||||
|
||||
uwsgi_log("%d %c\n", etype, etype);
|
||||
|
||||
if (etype != ERL_SMALL_TUPLE_EXT) return ;
|
||||
|
||||
ei_decode_tuple_header(x->buff, &x->index, &arity);
|
||||
|
||||
uwsgi_log("arity: %d\n", arity);
|
||||
if (arity != 5) return ;
|
||||
|
||||
ei_get_type(x->buff, &x->index, &etype, &esize);
|
||||
uwsgi_log("%d %c\n", etype, etype);
|
||||
|
||||
char *method = uwsgi_malloc(esize);
|
||||
|
||||
if (etype == ERL_ATOM_EXT) {
|
||||
ei_decode_atom(x->buff, &x->index, method);
|
||||
}
|
||||
else {
|
||||
ei_decode_string(x->buff, &x->index, method);
|
||||
}
|
||||
|
||||
if (strcmp(method, "call")) return;
|
||||
|
||||
ei_get_type(x->buff, &x->index, &etype, &esize);
|
||||
uwsgi_log("%d %c\n", etype, etype);
|
||||
|
||||
if (etype != ERL_ATOM_EXT && etype != ERL_STRING_EXT) return ;
|
||||
|
||||
module = uwsgi_malloc(esize);
|
||||
|
||||
if (etype == ERL_ATOM_EXT) {
|
||||
ei_decode_atom(x->buff, &x->index, module);
|
||||
}
|
||||
else {
|
||||
ei_decode_string(x->buff, &x->index, module);
|
||||
}
|
||||
|
||||
ei_get_type(x->buff, &x->index, &etype, &esize);
|
||||
|
||||
if (etype != ERL_ATOM_EXT && etype != ERL_STRING_EXT) return ;
|
||||
|
||||
call = uwsgi_malloc(esize);
|
||||
|
||||
if (etype == ERL_ATOM_EXT) {
|
||||
ei_decode_atom(x->buff, &x->index, call);
|
||||
}
|
||||
else {
|
||||
ei_decode_string(x->buff, &x->index, call);
|
||||
}
|
||||
|
||||
uwsgi_log("RPC %s %s\n", module, call);
|
||||
|
||||
ei_get_type(x->buff, &x->index, &etype, &esize);
|
||||
|
||||
if (etype == ERL_ATOM_EXT) {
|
||||
argc = 1;
|
||||
argv[0] = uwsgi_malloc(esize+1);
|
||||
ei_decode_atom(x->buff, &x->index, argv[0]);
|
||||
}
|
||||
else if (etype == ERL_STRING_EXT) {
|
||||
argc = 1;
|
||||
argv[0] = uwsgi_malloc(esize+1);
|
||||
ei_decode_string(x->buff, &x->index, argv[0]);
|
||||
}
|
||||
|
||||
ret = uwsgi_rpc(call, argc, argv, buffer);
|
||||
|
||||
uwsgi_log("buffer: %.*s\n", ret, buffer);
|
||||
|
||||
ei_x_new_with_version(&xr);
|
||||
|
||||
ei_x_encode_tuple_header(&xr, 2);
|
||||
//ei_x_encode_atom(&xr, "rex");
|
||||
ei_x_encode_ref(&xr, &eref);
|
||||
ei_x_encode_string_len(&xr, buffer, ret);
|
||||
|
||||
uwsgi_log("ei_send to %d %s %d %d %d: %d %d\n", fd, from->node, from->num , from->serial, from->creation, xr.index, ei_send(fd, from, xr.buff, xr.index));
|
||||
//uwsgi_log("ei_send to %d %s %d %d %d: %d %d\n", fd, from->node, from->num , from->serial, from->creation, xr.index, ei_reg_send(&uerl.cnode, fd, "rex", xr.buff, xr.index));
|
||||
|
||||
|
||||
}
|
||||
|
||||
void erlang_loop() {
|
||||
|
||||
ErlConnect econn;
|
||||
//ErlMessage em;
|
||||
erlang_msg em;
|
||||
int fd;
|
||||
|
||||
int eversion;
|
||||
int i;
|
||||
|
||||
ei_x_buff x, xr;
|
||||
|
||||
ei_x_new(&x);
|
||||
ei_x_new(&xr);
|
||||
|
||||
|
||||
/*
|
||||
int fd0 = ei_connect(&uerl.cnode, "anothernode@maverick64");
|
||||
uwsgi_log("fd0: %d\n", fd0);
|
||||
|
||||
ei_x_encode_list_header(&x, 0);
|
||||
|
||||
ei_rpc_to(&uerl.cnode, fd0, "erlang", "node", x.buff, x.index);
|
||||
|
||||
ei_rpc_from(&uerl.cnode, fd0, 10000, &em, &xr);
|
||||
|
||||
uwsgi_log("From: %s To: %s RegName: %s\n", em.from.node, em.to.node, em.toname);
|
||||
|
||||
xr.index = 0;
|
||||
ei_decode_version(xr.buff, &xr.index, &eversion);
|
||||
uwsgi_log("eversion: %d\n", eversion);
|
||||
|
||||
dump_eterm(&xr);
|
||||
*/
|
||||
|
||||
for(;;) {
|
||||
|
||||
fd = ei_accept(&uerl.cnode, uerl.fd, &econn);
|
||||
|
||||
if (fd >= 0) {
|
||||
|
||||
for (;;) {
|
||||
if (ei_xreceive_msg(fd, &em, &x) == ERL_MSG) {
|
||||
|
||||
if (em.msgtype == ERL_TICK)
|
||||
continue;
|
||||
|
||||
uwsgi_log("From: %s To: %s RegName: %s\n", em.from.node, em.to.node, em.toname);
|
||||
|
||||
|
||||
|
||||
x.index = 0;
|
||||
ei_decode_version(x.buff, &x.index, &eversion);
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("eversion: %d\n", eversion);
|
||||
#endif
|
||||
|
||||
if (!strcmp(em.toname, "rex")) {
|
||||
uwsgi_erlang_rpc(fd, &em.from, &x);
|
||||
}
|
||||
else {
|
||||
int uep = -1;
|
||||
for(i=0;i<uerl.uep_cnt;i++) {
|
||||
if (!strcmp(uerl.uep[i].name, em.toname)) {
|
||||
uep = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (uep > -1) {
|
||||
if (uerl.uep[uep].plugin) {
|
||||
uerl.uep[uep].plugin( uerl.uep[uep].func, &x );
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log("!!! unregistered erlang process requested, dumping it !!!\n");
|
||||
dump_eterm(&x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
if (em.msgtype) {
|
||||
dump_erl_obj(em.msg);
|
||||
erl_free_compound(em.msg);
|
||||
}
|
||||
if (em.to) {
|
||||
uwsgi_log("*** TO ***\n");
|
||||
dump_erl_obj(em.to);
|
||||
erl_free_compound(em.to);
|
||||
}
|
||||
|
||||
if (em.from) {
|
||||
uwsgi_log("*** FROM ***\n");
|
||||
dump_erl_obj(em.from);
|
||||
erl_free_compound(em.from);
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int erlang_init() {
|
||||
|
||||
char *host;
|
||||
struct sockaddr_in sin;
|
||||
socklen_t slen = sizeof(struct sockaddr_in);
|
||||
char *ip = NULL;
|
||||
char *nodename;
|
||||
struct in_addr addr;
|
||||
|
||||
uerl.lock = uwsgi_mmap_shared_lock();
|
||||
uwsgi_lock_init(uerl.lock);
|
||||
|
||||
if (uerl.name) {
|
||||
|
||||
uwsgi.master_process = 1;
|
||||
|
||||
host = strchr(uerl.name, '@');
|
||||
|
||||
if (!host) {
|
||||
if (ei_connect_init(&uerl.cnode, uerl.name, uerl.cookie, 0) < 0) {
|
||||
uwsgi_log("unable to initialize erlang connection\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
nodename = uwsgi_concat2n(uerl.name, host-uerl.name, "",0);
|
||||
ip = uwsgi_resolve_ip(host+1);
|
||||
if (ip) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("ip: %s\n", ip);
|
||||
#endif
|
||||
addr.s_addr = inet_addr(ip);
|
||||
if (ei_connect_xinit(&uerl.cnode, host+1, nodename, uerl.name, &addr, uerl.cookie, 0) < 0) {
|
||||
uwsgi_log("unable to initialize erlang connection\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ei_connect_init(&uerl.cnode, nodename, uerl.cookie, 0) < 0) {
|
||||
uwsgi_log("unable to initialize erlang connection\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
free(nodename);
|
||||
}
|
||||
|
||||
if (ip) {
|
||||
uerl.fd = bind_to_tcp(ip, uwsgi.listen_queue, NULL);
|
||||
}
|
||||
else {
|
||||
uerl.fd = bind_to_tcp("", uwsgi.listen_queue, NULL);
|
||||
}
|
||||
|
||||
if (uerl.fd < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (getsockname(uerl.fd, (struct sockaddr *) &sin, &slen)) {
|
||||
uwsgi_error("getsockname()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (ei_publish(&uerl.cnode, ntohs(sin.sin_port)) < 0) {
|
||||
uwsgi_log( "*** unable to subscribe with EPMD ***\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_log("Erlang C-Node %s registered on port %d\n", ei_thisnodename(&uerl.cnode), ntohs(sin.sin_port));
|
||||
|
||||
|
||||
if (register_fat_gateway("erlang", erlang_loop) == NULL) {
|
||||
uwsgi_log("unable to register the erlang gateway\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int erlang_opt(int i, char *optarg) {
|
||||
|
||||
switch(i) {
|
||||
case LONG_ARGS_ERLANG:
|
||||
uerl.name = optarg;
|
||||
return 1;
|
||||
case LONG_ARGS_ERLANG_COOKIE:
|
||||
uerl.cookie = optarg;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_plugin erlang_plugin = {
|
||||
|
||||
.options = erlang_options,
|
||||
.manage_opt = erlang_opt,
|
||||
.init = erlang_init,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
#include <ei.h>
|
||||
|
||||
#define MAX_UWSGI_ERLANG_PROCESSES 64
|
||||
|
||||
#define LONG_ARGS_ERLANG 17012
|
||||
#define LONG_ARGS_ERLANG_COOKIE 17013
|
||||
|
||||
|
||||
|
||||
struct uwsgi_erlang_process {
|
||||
|
||||
char name[0xff];
|
||||
void (*plugin)(void *, ei_x_buff *);
|
||||
void *func;
|
||||
};
|
||||
|
||||
struct uwsgi_erlang {
|
||||
|
||||
ei_cnode cnode;
|
||||
char *name;
|
||||
char *cookie;
|
||||
|
||||
int fd;
|
||||
|
||||
void *lock;
|
||||
|
||||
struct uwsgi_erlang_process uep[MAX_UWSGI_ERLANG_PROCESSES];
|
||||
int uep_cnt;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
NAME='erlang'
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = ['-lei']
|
||||
|
||||
GCC_LIST = ['erlang']
|
||||
@@ -1,13 +1,15 @@
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
int uwsgi_init(struct uwsgi_server *uwsgi, char *args){
|
||||
fprintf(stderr,"i am the example plugin initialization function with arg: %s\n", args);
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_init(char *args){
|
||||
uwsgi_log("i am the example plugin initialization function with arg: %s\n", args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req) {
|
||||
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>" ;
|
||||
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));
|
||||
|
||||
@@ -15,6 +17,6 @@ int uwsgi_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_after_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req) {
|
||||
fprintf(stderr,"i am the example plugin after request function\n");
|
||||
void uwsgi_after_request(struct wsgi_request *wsgi_req) {
|
||||
uwsgi_log("i am the example plugin after request function\n");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,484 @@
|
||||
/*
|
||||
|
||||
uWSGI fastrouter
|
||||
|
||||
requires:
|
||||
|
||||
- async
|
||||
- caching
|
||||
- pcre (optional)
|
||||
|
||||
*/
|
||||
|
||||
#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 FASTROUTER_STATUS_FREE 0
|
||||
#define FASTROUTER_STATUS_CONNECTING 1
|
||||
#define FASTROUTER_STATUS_RECV_HDR 2
|
||||
#define FASTROUTER_STATUS_RECV_VARS 3
|
||||
#define FASTROUTER_STATUS_RESPONSE 4
|
||||
|
||||
struct uwsgi_fastrouter {
|
||||
char *socket_name;
|
||||
int use_cache;
|
||||
int nevents;
|
||||
|
||||
char *pattern;
|
||||
int pattern_len;
|
||||
|
||||
char *base;
|
||||
int base_len;
|
||||
} ufr;
|
||||
|
||||
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},
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct fastrouter_session {
|
||||
|
||||
int fd;
|
||||
int instance_fd;
|
||||
int status;
|
||||
struct uwsgi_header uh;
|
||||
uint8_t h_pos;
|
||||
char buffer[0xffff];
|
||||
uint16_t pos;
|
||||
|
||||
char *hostname;
|
||||
uint16_t hostname_len;
|
||||
|
||||
char *instance_address;
|
||||
uint64_t instance_address_len;
|
||||
|
||||
int pass_fd;
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
//uwsgi_log("%.*s = %.*s\n", keylen, key, vallen, val);
|
||||
if (!uwsgi_strncmp("SERVER_NAME", 11, key, keylen) && !fr_session->hostname_len) {
|
||||
fr_session->hostname = val;
|
||||
fr_session->hostname_len = vallen;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("HTTP_HOST", 9, key, keylen)) {
|
||||
fr_session->hostname = val;
|
||||
fr_session->hostname_len = vallen;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
struct fastrouter_session *alloc_fr_session() {
|
||||
|
||||
return uwsgi_malloc(sizeof(struct fastrouter_session));
|
||||
}
|
||||
|
||||
void fastrouter_loop() {
|
||||
|
||||
int fr_queue;
|
||||
int fr_server;
|
||||
int nevents;
|
||||
int interesting_fd;
|
||||
int new_connection;
|
||||
ssize_t len;
|
||||
int i;
|
||||
|
||||
char *tmp_socket_name;
|
||||
int tmp_socket_name_len;
|
||||
|
||||
char *magic_table[0xff];
|
||||
|
||||
void *events;
|
||||
struct msghdr msg;
|
||||
union {
|
||||
struct cmsghdr cmsg;
|
||||
char control [CMSG_SPACE (sizeof (int))];
|
||||
} msg_control;
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
struct sockaddr_un fr_addr;
|
||||
socklen_t fr_addr_len = sizeof(struct sockaddr_un);
|
||||
|
||||
struct fastrouter_session *fr_session;
|
||||
|
||||
struct fastrouter_session *fr_table[2048];
|
||||
|
||||
struct iovec iov[2];
|
||||
|
||||
int soopt;
|
||||
socklen_t solen = sizeof(int);
|
||||
|
||||
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();
|
||||
|
||||
events = event_queue_alloc(ufr.nevents);
|
||||
|
||||
event_queue_add_fd_read(fr_queue, fr_server);
|
||||
|
||||
if (ufr.pattern) {
|
||||
init_magic_table(magic_table);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
|
||||
nevents = event_queue_wait_multi(fr_queue, -1, events, ufr.nevents);
|
||||
|
||||
for (i=0;i<nevents;i++) {
|
||||
|
||||
tmp_socket_name = NULL;
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
else {
|
||||
fr_session = fr_table[interesting_fd];
|
||||
|
||||
// something is going wrong...
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
|
||||
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);
|
||||
break;
|
||||
}
|
||||
fr_session->h_pos += len;
|
||||
if (fr_session->h_pos == 4) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("modifier1: %d pktsize: %d modifier2: %d\n", fr_session->uh.modifier1, fr_session->uh.pktsize, fr_session->uh.modifier2);
|
||||
#endif
|
||||
fr_session->status = FASTROUTER_STATUS_RECV_VARS;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case FASTROUTER_STATUS_RECV_VARS:
|
||||
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);
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
if (fr_session->hostname_len == 0) {
|
||||
close(fr_session->fd);
|
||||
fr_table[fr_session->fd] = NULL;
|
||||
free(fr_session);
|
||||
break;
|
||||
}
|
||||
|
||||
//uwsgi_log("requested domain %.*s\n", fr_session->hostname_len, fr_session->hostname);
|
||||
if (ufr.use_cache) {
|
||||
fr_session->instance_address = uwsgi_cache_get(fr_session->hostname, fr_session->hostname_len, &fr_session->instance_address_len);
|
||||
}
|
||||
else if (ufr.pattern) {
|
||||
magic_table['s'] = uwsgi_concat2n(fr_session->hostname, fr_session->hostname_len, "", 0);
|
||||
tmp_socket_name = magic_sub(ufr.pattern, ufr.pattern_len, &tmp_socket_name_len, magic_table);
|
||||
free(magic_table['s']);
|
||||
fr_session->instance_address_len = tmp_socket_name_len;
|
||||
fr_session->instance_address = tmp_socket_name;
|
||||
}
|
||||
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;
|
||||
fr_session->instance_address = tmp_socket_name;
|
||||
}
|
||||
|
||||
// no address found
|
||||
if (!fr_session->instance_address_len) {
|
||||
close(fr_session->fd);
|
||||
fr_table[fr_session->fd] = NULL;
|
||||
free(fr_session);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
fr_session->pass_fd = is_unix(fr_session->instance_address, fr_session->instance_address_len);
|
||||
|
||||
fr_session->instance_fd = uwsgi_connectn(fr_session->instance_address, fr_session->instance_address_len, 0, 1);
|
||||
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
fr_session->status = FASTROUTER_STATUS_CONNECTING;
|
||||
fr_table[fr_session->instance_fd] = fr_session;
|
||||
event_queue_add_fd_write(fr_queue, fr_session->instance_fd);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case FASTROUTER_STATUS_CONNECTING:
|
||||
|
||||
if (interesting_fd == fr_session->instance_fd) {
|
||||
|
||||
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);
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
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) {
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 2;
|
||||
msg.msg_flags = 0;
|
||||
msg.msg_control = &msg_control;
|
||||
msg.msg_controllen = sizeof (msg_control);
|
||||
|
||||
cmsg = CMSG_FIRSTHDR (&msg);
|
||||
cmsg->cmsg_len = CMSG_LEN (sizeof (int));
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
|
||||
memcpy(CMSG_DATA(cmsg), &fr_session->fd, sizeof(int));
|
||||
|
||||
if (sendmsg(fr_session->instance_fd, &msg, 0) < 0) {
|
||||
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);
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
event_queue_del_fd(fr_queue, fr_session->instance_fd);
|
||||
event_queue_add_fd_read(fr_queue, fr_session->instance_fd);
|
||||
fr_session->status = FASTROUTER_STATUS_RESPONSE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case FASTROUTER_STATUS_RESPONSE:
|
||||
|
||||
// data from instance
|
||||
if (interesting_fd == fr_session->instance_fd) {
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
len = send(fr_session->fd, fr_session->buffer, len, 0);
|
||||
|
||||
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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// body from client
|
||||
else if (interesting_fd == fr_session->fd) {
|
||||
|
||||
//uwsgi_log("receiving body...\n");
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
len = send(fr_session->instance_fd, fr_session->buffer, len, 0);
|
||||
|
||||
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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
||||
|
||||
// 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);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int fastrouter_init() {
|
||||
|
||||
if (ufr.socket_name) {
|
||||
|
||||
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");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!ufr.nevents) ufr.nevents = 64;
|
||||
|
||||
if (register_gateway("fastrouter", fastrouter_loop) == NULL) {
|
||||
uwsgi_log("unable to register the fastrouter gateway\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fastrouter_opt(int i, char *optarg) {
|
||||
|
||||
switch(i) {
|
||||
case LONG_ARGS_FASTROUTER:
|
||||
ufr.socket_name = optarg;
|
||||
return 1;
|
||||
case LONG_ARGS_FASTROUTER_EVENTS:
|
||||
ufr.nevents = atoi(optarg);
|
||||
return 1;
|
||||
case LONG_ARGS_FASTROUTER_USE_PATTERN:
|
||||
ufr.pattern = optarg;
|
||||
// optimization
|
||||
ufr.pattern_len = strlen(ufr.pattern);
|
||||
return 1;
|
||||
case LONG_ARGS_FASTROUTER_USE_BASE:
|
||||
ufr.base = optarg;
|
||||
// optimization
|
||||
ufr.base_len = strlen(ufr.base);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_plugin fastrouter_plugin = {
|
||||
|
||||
.options = fastrouter_options,
|
||||
.manage_opt = fastrouter_opt,
|
||||
.init = fastrouter_init,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
NAME='fastrouter'
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
|
||||
GCC_LIST = ['fastrouter']
|
||||
@@ -0,0 +1,899 @@
|
||||
/*
|
||||
|
||||
uWSGI http
|
||||
|
||||
requires:
|
||||
|
||||
- async
|
||||
- caching
|
||||
- pcre (optional)
|
||||
|
||||
*/
|
||||
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
#define MAX_HTTP_VEC 128
|
||||
#define MAX_HTTP_EXTRA_VARS 64
|
||||
|
||||
#define LONG_ARGS_HTTP_EVENTS 300001
|
||||
#define LONG_ARGS_HTTP_USE_PATTERN 300002
|
||||
#define LONG_ARGS_HTTP_USE_BASE 300003
|
||||
#define LONG_ARGS_HTTP_USE_TO 300004
|
||||
#define LONG_ARGS_HTTP_SUBSCRIPTION_SERVER 300005
|
||||
#define LONG_ARGS_HTTP_TIMEOUT 300006
|
||||
|
||||
#define HTTP_STATUS_FREE 0
|
||||
#define HTTP_STATUS_CONNECTING 1
|
||||
#define HTTP_STATUS_RECV 2
|
||||
#define HTTP_STATUS_RESPONSE 4
|
||||
|
||||
#define add_timeout(x) uwsgi_add_rb_timer(uhttp.timeouts, time(NULL)+uhttp.socket_timeout, x)
|
||||
#define del_timeout(x) rb_erase(&x->timeout->rbt, uhttp.timeouts); free(x->timeout);
|
||||
|
||||
struct uwsgi_http {
|
||||
char *socket_name;
|
||||
int use_cache;
|
||||
int use_cluster;
|
||||
int nevents;
|
||||
|
||||
int server;
|
||||
|
||||
char *subscription_server;
|
||||
|
||||
char *pattern;
|
||||
int pattern_len;
|
||||
|
||||
char *base;
|
||||
int base_len;
|
||||
|
||||
char *port;
|
||||
int port_len;
|
||||
|
||||
char *to;
|
||||
int to_len;
|
||||
|
||||
char *http_vars[MAX_HTTP_EXTRA_VARS];
|
||||
int http_vars_cnt;
|
||||
|
||||
uint8_t modifier1;
|
||||
int load;
|
||||
|
||||
int socket_timeout;
|
||||
|
||||
struct uwsgi_dict *subscription_dict;
|
||||
|
||||
struct rb_root *timeouts;
|
||||
} uhttp;
|
||||
|
||||
struct option http_options[] = {
|
||||
{"http", required_argument, 0, LONG_ARGS_HTTP},
|
||||
{"http-var", required_argument, 0, LONG_ARGS_HTTP_VAR},
|
||||
{"http-to", required_argument, 0, LONG_ARGS_HTTP_USE_TO},
|
||||
{"http-modifier1", required_argument, 0, LONG_ARGS_HTTP_MODIFIER1},
|
||||
{"http-use-cache", no_argument, &uhttp.use_cache, 1},
|
||||
{"http-use-pattern", required_argument, 0, LONG_ARGS_HTTP_USE_PATTERN},
|
||||
{"http-use-base", required_argument, 0, LONG_ARGS_HTTP_USE_BASE},
|
||||
{"http-use-cluster", no_argument, &uhttp.use_cluster, 1},
|
||||
{"http-events", required_argument, 0, LONG_ARGS_HTTP_EVENTS},
|
||||
{"http-subscription-server", required_argument, 0, LONG_ARGS_HTTP_SUBSCRIPTION_SERVER},
|
||||
{"http-timeout", required_argument, 0, LONG_ARGS_HTTP_TIMEOUT},
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
|
||||
void http_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("auth", 4, key, keylen)) {
|
||||
usr->auth = val;
|
||||
usr->auth_len = vallen;
|
||||
}
|
||||
|
||||
else if (!uwsgi_strncmp("address", 7, key, keylen)) {
|
||||
usr->address = val;
|
||||
usr->address_len = vallen;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
struct http_session {
|
||||
|
||||
int fd;
|
||||
int instance_fd;
|
||||
int status;
|
||||
struct uwsgi_header uh;
|
||||
uint8_t h_pos;
|
||||
uint16_t pos;
|
||||
uint16_t parse_pos;
|
||||
char *ptr;
|
||||
|
||||
int rnrn;
|
||||
|
||||
char *hostname;
|
||||
uint16_t hostname_len;
|
||||
|
||||
char *instance_address;
|
||||
uint64_t instance_address_len;
|
||||
|
||||
int instance_failed;
|
||||
|
||||
int pass_fd;
|
||||
|
||||
int remains;
|
||||
|
||||
struct iovec iov[MAX_HTTP_VEC];
|
||||
int iov_len;
|
||||
|
||||
char uss[MAX_HTTP_VEC*2];
|
||||
|
||||
char buffer[UMAX16];
|
||||
|
||||
struct uwsgi_subscriber_name *un;
|
||||
|
||||
in_addr_t ip_addr;
|
||||
char ip[INET_ADDRSTRLEN];
|
||||
|
||||
struct uwsgi_rb_timer *timeout;
|
||||
};
|
||||
|
||||
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) {
|
||||
|
||||
close(uhttp_session->fd);
|
||||
uhttp_table[uhttp_session->fd] = NULL;
|
||||
if (uhttp_session->instance_fd != -1) {
|
||||
if (uhttp.subscription_server && (uhttp_session->instance_failed || uhttp_session->status == HTTP_STATUS_CONNECTING)) {
|
||||
uwsgi_log("marking %.*s as failed\n", (int) uhttp_session->instance_address_len,uhttp_session->instance_address);
|
||||
uhttp_session->un->len = 0;
|
||||
}
|
||||
close(uhttp_session->instance_fd);
|
||||
uhttp_table[uhttp_session->instance_fd] = NULL;
|
||||
}
|
||||
|
||||
uhttp.load--;
|
||||
del_timeout(uhttp_session);
|
||||
free(uhttp_session);
|
||||
|
||||
}
|
||||
|
||||
void expire_timeouts(struct http_session **uhttp_table) {
|
||||
|
||||
time_t current = time(NULL);
|
||||
struct uwsgi_rb_timer *urbt;
|
||||
|
||||
for(;;) {
|
||||
|
||||
urbt = uwsgi_min_rb_timer(uhttp.timeouts);
|
||||
|
||||
if (urbt == NULL) return;
|
||||
|
||||
if (urbt->key <= current) {
|
||||
close_session(uhttp_table, (struct http_session *)urbt->data);
|
||||
uwsgi_log("timeout !!!\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct http_session *alloc_uhttp_session() {
|
||||
|
||||
return uwsgi_malloc(sizeof(struct http_session));
|
||||
}
|
||||
|
||||
uint16_t http_add_uwsgi_header(struct http_session *h_session, struct iovec *iov, char *strsize1, char *strsize2, char *hh, uint16_t hhlen, int *c) {
|
||||
|
||||
int i;
|
||||
int status = 0;
|
||||
char *val = hh;
|
||||
uint16_t keylen = 0, vallen = 0;
|
||||
int prefix = 0;
|
||||
|
||||
if (*c >= MAX_HTTP_VEC) return 0;
|
||||
|
||||
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 ((*c) + 4 >= MAX_HTTP_VEC) return 0;
|
||||
|
||||
if (!uwsgi_strncmp("HOST", 4, hh, keylen)) {
|
||||
h_session->hostname = val;
|
||||
h_session->hostname_len = vallen;
|
||||
}
|
||||
|
||||
if (uwsgi_strncmp("CONTENT_TYPE", 12, hh, keylen) && uwsgi_strncmp("CONTENT_LENGTH", 14, hh, keylen)) {
|
||||
keylen += 5;
|
||||
prefix = 1;
|
||||
if ((*c) + 5 >= MAX_HTTP_VEC) return 0;
|
||||
}
|
||||
|
||||
strsize1[0] = (uint8_t) (keylen & 0xff);
|
||||
strsize1[1] = (uint8_t) ((keylen >> 8) & 0xff);
|
||||
|
||||
iov[*c].iov_base = strsize1 ;
|
||||
iov[*c].iov_len = 2 ;
|
||||
*c+=1;
|
||||
|
||||
if (prefix) {
|
||||
iov[*c].iov_base = "HTTP_" ;
|
||||
iov[*c].iov_len = 5 ;
|
||||
*c+=1;
|
||||
}
|
||||
|
||||
iov[*c].iov_base = hh ;
|
||||
iov[*c].iov_len = keylen - (prefix*5) ;
|
||||
*c+=1;
|
||||
|
||||
strsize2[0] = (uint8_t) (vallen & 0xff);
|
||||
strsize2[1] = (uint8_t) ((vallen >> 8) & 0xff);
|
||||
|
||||
iov[*c].iov_base = strsize2 ;
|
||||
iov[*c].iov_len = 2 ;
|
||||
*c+=1;
|
||||
|
||||
iov[*c].iov_base = val ;
|
||||
iov[*c].iov_len = vallen ;
|
||||
*c+=1;
|
||||
|
||||
return 2+keylen+2+vallen;
|
||||
}
|
||||
|
||||
|
||||
uint16_t http_add_uwsgi_var(struct iovec *iov, char *strsize1, char *strsize2, char *key, uint16_t keylen, char *val, uint16_t vallen, int *c) {
|
||||
|
||||
if ((*c) + 4 >= MAX_HTTP_VEC) return 0;
|
||||
|
||||
strsize1[0] = (uint8_t) (keylen & 0xff);
|
||||
strsize1[1] = (uint8_t) ((keylen >> 8) & 0xff);
|
||||
|
||||
iov[*c].iov_base = strsize1 ;
|
||||
iov[*c].iov_len = 2 ;
|
||||
*c+=1;
|
||||
|
||||
iov[*c].iov_base = key ;
|
||||
iov[*c].iov_len = keylen ;
|
||||
*c+=1;
|
||||
|
||||
strsize2[0] = (uint8_t) (vallen & 0xff);
|
||||
strsize2[1] = (uint8_t) ((vallen >> 8) & 0xff);
|
||||
|
||||
iov[*c].iov_base = strsize2 ;
|
||||
iov[*c].iov_len = 2 ;
|
||||
*c+=1;
|
||||
|
||||
iov[*c].iov_base = val ;
|
||||
iov[*c].iov_len = vallen ;
|
||||
*c+=1;
|
||||
|
||||
return 2+keylen+2+vallen;
|
||||
}
|
||||
|
||||
int http_parse(struct http_session *h_session) {
|
||||
|
||||
char *ptr = h_session->buffer;
|
||||
char *watermark = h_session->ptr;
|
||||
char *base = ptr;
|
||||
// leave a slot for uwsgi header
|
||||
int c = 1;
|
||||
char *query_string = NULL;
|
||||
|
||||
// REQUEST_METHOD
|
||||
while(ptr < watermark) {
|
||||
if (*ptr == ' ') {
|
||||
h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "REQUEST_METHOD", 14, base, ptr-base, &c);
|
||||
ptr++;
|
||||
break;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
// REQUEST_URI / PATH_INFO / QUERY_STRING
|
||||
base = ptr;
|
||||
while(ptr < watermark) {
|
||||
if (*ptr == '?' && !query_string) {
|
||||
h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "PATH_INFO", 9, base, ptr-base, &c);
|
||||
query_string = ptr+1;
|
||||
}
|
||||
else if (*ptr == ' ') {
|
||||
h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "REQUEST_URI", 11, base, ptr-base, &c);
|
||||
if (!query_string) {
|
||||
h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "PATH_INFO", 9, base, ptr-base, &c);
|
||||
h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "QUERY_STRING", 12, "", 0, &c);
|
||||
}
|
||||
else {
|
||||
h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "QUERY_STRING", 12, query_string, ptr-query_string, &c);
|
||||
}
|
||||
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;
|
||||
h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "SERVER_PROTOCOL", 15, base, ptr-base, &c);
|
||||
ptr+=2;
|
||||
break;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
// SCRIPT_NAME
|
||||
h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "SCRIPT_NAME", 11, "", 0, &c);
|
||||
|
||||
// SERVER_NAME
|
||||
h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len, &c);
|
||||
h_session->hostname = uwsgi.hostname;
|
||||
h_session->hostname_len = uwsgi.hostname_len;
|
||||
|
||||
// SERVER_PORT
|
||||
h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "SERVER_PORT", 11, uhttp.port, uhttp.port_len, &c);
|
||||
h_session->hostname = uwsgi.hostname;
|
||||
h_session->hostname_len = uwsgi.hostname_len;
|
||||
|
||||
// UWSGI_ROUTER
|
||||
h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "UWSGI_ROUTER", 12, "http", 4, &c);
|
||||
|
||||
// REMOTE_ADDR
|
||||
if (inet_ntop(AF_INET, &h_session->ip_addr, h_session->ip, INET_ADDRSTRLEN)) {
|
||||
h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "REMOTE_ADDR", 11, h_session->ip, strlen(h_session->ip), &c);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
h_session->uh.pktsize += http_add_uwsgi_header(h_session, h_session->iov, h_session->uss+c, h_session->uss+c+2, base, ptr-base, &c);
|
||||
ptr++;
|
||||
base = ptr+1;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("vec size: %d pkt size: %d load %d\n", c, h_session->uh.pktsize, uhttp.load);
|
||||
#endif
|
||||
|
||||
return c;
|
||||
|
||||
}
|
||||
|
||||
void http_loop() {
|
||||
|
||||
int uhttp_queue;
|
||||
int uhttp_subserver = -1;
|
||||
int nevents;
|
||||
int interesting_fd;
|
||||
int new_connection;
|
||||
ssize_t len;
|
||||
int i,j;
|
||||
|
||||
char *magic_table[0xff];
|
||||
|
||||
char bbuf[UMAX16];
|
||||
|
||||
time_t delta;
|
||||
|
||||
struct uwsgi_rb_timer *min_timeout;
|
||||
void *events;
|
||||
struct msghdr msg;
|
||||
union {
|
||||
struct cmsghdr cmsg;
|
||||
char control [CMSG_SPACE (sizeof (int))];
|
||||
} msg_control;
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
union uwsgi_sockaddr uhttp_addr;
|
||||
socklen_t uhttp_addr_len = sizeof(struct sockaddr_un);
|
||||
|
||||
struct http_session *uhttp_session;
|
||||
|
||||
struct http_session *uhttp_table[2048];
|
||||
struct uwsgi_subscribe_req usr;
|
||||
|
||||
int soopt;
|
||||
socklen_t solen = sizeof(int);
|
||||
|
||||
for(i=0;i<2048;i++) {
|
||||
uhttp_table[i] = NULL;
|
||||
}
|
||||
|
||||
|
||||
uhttp.port = strchr(uhttp.socket_name,':')+1;
|
||||
uhttp.port_len = strlen(uhttp.port);
|
||||
|
||||
uhttp_queue = event_queue_init();
|
||||
|
||||
events = event_queue_alloc(uhttp.nevents);
|
||||
|
||||
event_queue_add_fd_read(uhttp_queue, uhttp.server);
|
||||
|
||||
if (uhttp.subscription_server) {
|
||||
uhttp_subserver = bind_to_udp(uhttp.subscription_server, 0, 0);
|
||||
event_queue_add_fd_read(uhttp_queue, uhttp_subserver);
|
||||
uhttp.subscription_dict = uwsgi_dict_create(100, 0);
|
||||
}
|
||||
|
||||
if (uhttp.pattern) {
|
||||
init_magic_table(magic_table);
|
||||
}
|
||||
|
||||
uhttp.timeouts = uwsgi_init_rb_timer();
|
||||
if (!uhttp.socket_timeout) uhttp.socket_timeout = 30;
|
||||
|
||||
for (;;) {
|
||||
|
||||
min_timeout = uwsgi_min_rb_timer(uhttp.timeouts);
|
||||
if (min_timeout == NULL ) {
|
||||
delta = -1;
|
||||
}
|
||||
else {
|
||||
delta = min_timeout->key - time(NULL);
|
||||
if (delta <= 0) {
|
||||
expire_timeouts(uhttp_table);
|
||||
delta = 0;
|
||||
}
|
||||
}
|
||||
nevents = event_queue_wait_multi(uhttp_queue, delta, events, uhttp.nevents);
|
||||
|
||||
if (nevents == 0) {
|
||||
// manage timeout
|
||||
expire_timeouts(uhttp_table);
|
||||
}
|
||||
|
||||
for (i=0;i<nevents;i++) {
|
||||
|
||||
interesting_fd = event_queue_interesting_fd(events, i);
|
||||
|
||||
|
||||
if (interesting_fd == uhttp.server) {
|
||||
new_connection = accept(uhttp.server, (struct sockaddr *) &uhttp_addr, &uhttp_addr_len);
|
||||
if (new_connection < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uhttp_table[new_connection] = alloc_uhttp_session();
|
||||
uhttp_table[new_connection]->fd = new_connection;
|
||||
uhttp_table[new_connection]->instance_fd = -1;
|
||||
uhttp_table[new_connection]->status = HTTP_STATUS_RECV;
|
||||
uhttp_table[new_connection]->h_pos = 0;
|
||||
uhttp_table[new_connection]->pos = 0;
|
||||
uhttp_table[new_connection]->rnrn = 0;
|
||||
uhttp_table[new_connection]->parse_pos = 0;
|
||||
uhttp_table[new_connection]->pass_fd = 0;
|
||||
uhttp_table[new_connection]->ptr = uhttp_table[new_connection]->buffer;
|
||||
uhttp_table[new_connection]->instance_address_len = 0;
|
||||
uhttp_table[new_connection]->uh.modifier1 = uhttp.modifier1;
|
||||
uhttp_table[new_connection]->uh.pktsize = 0;
|
||||
uhttp_table[new_connection]->uh.modifier2 = 0;
|
||||
uhttp_table[new_connection]->ip_addr = ((struct sockaddr_in *) &uhttp_addr)->sin_addr.s_addr;
|
||||
uhttp_table[new_connection]->instance_failed = 0;
|
||||
|
||||
uhttp_table[new_connection]->timeout = add_timeout(uhttp_table[new_connection]);
|
||||
|
||||
uhttp.load++;
|
||||
|
||||
event_queue_add_fd_read(uhttp_queue, new_connection);
|
||||
|
||||
}
|
||||
else if (interesting_fd == uhttp_subserver) {
|
||||
len = recv(uhttp_subserver, bbuf, 4096, 0);
|
||||
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);
|
||||
}
|
||||
}
|
||||
else {
|
||||
uhttp_session = uhttp_table[interesting_fd];
|
||||
|
||||
// something is going wrong...
|
||||
if (uhttp_session == NULL) continue;
|
||||
|
||||
if (event_queue_interesting_fd_has_error(events, i)) {
|
||||
close_session(uhttp_table, uhttp_session);
|
||||
continue;
|
||||
}
|
||||
|
||||
uhttp_session->timeout = reset_timeout(uhttp_session);
|
||||
|
||||
switch(uhttp_session->status) {
|
||||
|
||||
|
||||
case HTTP_STATUS_RECV:
|
||||
len = recv(uhttp_session->fd, uhttp_session->buffer + uhttp_session->h_pos, UMAX16-uhttp_session->h_pos, 0);
|
||||
if (len <= 0) {
|
||||
uwsgi_error("recv()");
|
||||
close_session(uhttp_table, uhttp_session);
|
||||
break;
|
||||
}
|
||||
|
||||
uhttp_session->h_pos += len;
|
||||
|
||||
for(j=0;j<len;j++) {
|
||||
//uwsgi_log("%d %d %d\n", j, *uhttp_session->ptr, uhttp_session->rnrn);
|
||||
if (*uhttp_session->ptr == '\r' && (uhttp_session->rnrn == 0 || uhttp_session->rnrn == 2)) {
|
||||
uhttp_session->rnrn++;
|
||||
}
|
||||
else if (*uhttp_session->ptr == '\r') {
|
||||
uhttp_session->rnrn = 1;
|
||||
}
|
||||
else if (*uhttp_session->ptr == '\n' && uhttp_session->rnrn == 1) {
|
||||
uhttp_session->rnrn = 2;
|
||||
}
|
||||
else if (*uhttp_session->ptr == '\n' && uhttp_session->rnrn == 3) {
|
||||
uhttp_session->ptr++;
|
||||
uhttp_session->remains = len-(j+1);
|
||||
uhttp_session->iov_len = http_parse(uhttp_session);
|
||||
|
||||
if (uhttp_session->iov_len == 0) {
|
||||
close_session(uhttp_table, uhttp_session);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (uhttp.use_cluster) {
|
||||
uhttp_session->instance_address = uwsgi_cluster_best_node();
|
||||
if (uhttp_session->instance_address) {
|
||||
uhttp_session->instance_address_len = strlen(uhttp_session->instance_address);
|
||||
}
|
||||
}
|
||||
else if (uhttp.use_cache) {
|
||||
uhttp_session->instance_address = uwsgi_cache_get(uhttp_session->hostname, uhttp_session->hostname_len, &uhttp_session->instance_address_len);
|
||||
}
|
||||
else if (uhttp.base) {
|
||||
uhttp_session->instance_address = uwsgi_concat2n(uhttp.base, uhttp.base_len, uhttp_session->hostname, uhttp_session->hostname_len);
|
||||
uhttp_session->instance_address_len = uhttp.base_len + uhttp_session->hostname_len;
|
||||
}
|
||||
else if (uhttp.pattern) {
|
||||
magic_table['s'] = uwsgi_concat2n(uhttp_session->hostname, uhttp_session->hostname_len, "", 0);
|
||||
int tmp_addr_len = 0;
|
||||
uhttp_session->instance_address = magic_sub(uhttp.pattern, uhttp.pattern_len, &tmp_addr_len, magic_table);
|
||||
uhttp_session->instance_address_len = tmp_addr_len;
|
||||
free(magic_table['s']);
|
||||
}
|
||||
else if (uhttp.to) {
|
||||
uhttp_session->instance_address = uhttp.to;
|
||||
uhttp_session->instance_address_len = uhttp.to_len;
|
||||
}
|
||||
else if (uhttp.subscription_server) {
|
||||
uhttp_session->un = uwsgi_get_subscriber(uhttp.subscription_dict, uhttp_session->hostname, uhttp_session->hostname_len);
|
||||
if (uhttp_session->un && uhttp_session->un->len) {
|
||||
uhttp_session->instance_address = uhttp_session->un->name;
|
||||
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);
|
||||
}
|
||||
|
||||
if (!uhttp_session->instance_address_len) {
|
||||
close_session(uhttp_table, uhttp_session);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
uhttp_session->pass_fd = is_unix(uhttp_session->instance_address, uhttp_session->instance_address_len);
|
||||
|
||||
uhttp_session->instance_fd = uwsgi_connectn(uhttp_session->instance_address, uhttp_session->instance_address_len, 0, 1);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("uwsgi backend: %.*s\n", (int) uhttp_session->instance_address_len,uhttp_session->instance_address);
|
||||
#endif
|
||||
|
||||
if (uhttp.pattern || uhttp.base ) {
|
||||
free(uhttp_session->instance_address);
|
||||
}
|
||||
|
||||
if (uhttp_session->instance_fd < 0) {
|
||||
if (uhttp.subscription_server) {
|
||||
uwsgi_log("marking %.*s as failed\n", (int) uhttp_session->instance_address_len,uhttp_session->instance_address);
|
||||
uhttp_session->un->len = 0;
|
||||
}
|
||||
close_session(uhttp_table, uhttp_session);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
uhttp_session->status = HTTP_STATUS_CONNECTING;
|
||||
uhttp_table[uhttp_session->instance_fd] = uhttp_session;
|
||||
event_queue_add_fd_write(uhttp_queue, uhttp_session->instance_fd);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
uhttp_session->rnrn = 0;
|
||||
}
|
||||
uhttp_session->ptr++;
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case HTTP_STATUS_CONNECTING:
|
||||
|
||||
if (interesting_fd == uhttp_session->instance_fd) {
|
||||
|
||||
if (getsockopt(uhttp_session->instance_fd, SOL_SOCKET, SO_ERROR, (void *) (&soopt), &solen) < 0) {
|
||||
uwsgi_error("getsockopt()");
|
||||
uhttp_session->instance_failed = 1;
|
||||
close_session(uhttp_table, uhttp_session);
|
||||
break;
|
||||
}
|
||||
|
||||
if (soopt) {
|
||||
uwsgi_log("unable to connect() to uwsgi instance: %s\n", strerror(soopt));
|
||||
uhttp_session->instance_failed = 1;
|
||||
close_session(uhttp_table, uhttp_session);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
uhttp_session->uh.pktsize = uwsgi_swap16(uhttp_session->uh.pktsize);
|
||||
#endif
|
||||
|
||||
uhttp_session->iov[0].iov_base = &uhttp_session->uh;
|
||||
uhttp_session->iov[0].iov_len = 4;
|
||||
|
||||
if (uhttp_session->remains > 0) {
|
||||
uhttp_session->iov[uhttp_session->iov_len].iov_base = uhttp_session->ptr;
|
||||
uhttp_session->iov[uhttp_session->iov_len].iov_len = uhttp_session->remains;
|
||||
uhttp_session->iov_len++;
|
||||
}
|
||||
|
||||
// fd passing: PERFORMANCE EXTREME BOOST !!!
|
||||
if (uhttp_session->pass_fd && !uhttp_session->remains) {
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_iov = uhttp_session->iov;
|
||||
msg.msg_iovlen = uhttp_session->iov_len;
|
||||
msg.msg_flags = 0;
|
||||
msg.msg_control = &msg_control;
|
||||
msg.msg_controllen = sizeof (msg_control);
|
||||
|
||||
cmsg = CMSG_FIRSTHDR (&msg);
|
||||
cmsg->cmsg_len = CMSG_LEN (sizeof (int));
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
|
||||
memcpy(CMSG_DATA(cmsg), &uhttp_session->fd, sizeof(int));
|
||||
|
||||
if (sendmsg(uhttp_session->instance_fd, &msg, 0) < 0) {
|
||||
uwsgi_error("sendmsg()");
|
||||
}
|
||||
|
||||
close(uhttp_session->fd);
|
||||
close(uhttp_session->instance_fd);
|
||||
uhttp_table[uhttp_session->fd] = NULL;
|
||||
uhttp_table[uhttp_session->instance_fd] = NULL;
|
||||
uhttp.load--;
|
||||
del_timeout(uhttp_session);
|
||||
free(uhttp_session);
|
||||
break;
|
||||
}
|
||||
|
||||
if (writev(uhttp_session->instance_fd, uhttp_session->iov, uhttp_session->iov_len) <= 0) {
|
||||
uwsgi_error("writev()");
|
||||
close_session(uhttp_table, uhttp_session);
|
||||
break;
|
||||
}
|
||||
|
||||
event_queue_fd_write_to_read(uhttp_queue, uhttp_session->instance_fd);
|
||||
uhttp_session->status = HTTP_STATUS_RESPONSE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case HTTP_STATUS_RESPONSE:
|
||||
|
||||
// data from instance
|
||||
if (interesting_fd == uhttp_session->instance_fd) {
|
||||
len = recv(uhttp_session->instance_fd, bbuf, UMAX16, 0);
|
||||
if (len <= 0) {
|
||||
if (len < 0) uwsgi_error("recv()");
|
||||
close_session(uhttp_table, uhttp_session);
|
||||
break;
|
||||
}
|
||||
|
||||
len = send(uhttp_session->fd, bbuf, len, 0);
|
||||
|
||||
if (len <= 0) {
|
||||
if (len < 0) uwsgi_error("send()");
|
||||
close(uhttp_session->fd);
|
||||
close(uhttp_session->instance_fd);
|
||||
uhttp_table[uhttp_session->fd] = NULL;
|
||||
uhttp_table[uhttp_session->instance_fd] = NULL;
|
||||
uhttp.load--;
|
||||
del_timeout(uhttp_session);
|
||||
free(uhttp_session);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// body from client
|
||||
else if (interesting_fd == uhttp_session->fd) {
|
||||
|
||||
//uwsgi_log("receiving body...\n");
|
||||
len = recv(uhttp_session->fd, bbuf, UMAX16, 0);
|
||||
if (len <= 0) {
|
||||
if (len < 0) uwsgi_error("recv()");
|
||||
close(uhttp_session->fd);
|
||||
close(uhttp_session->instance_fd);
|
||||
uhttp_table[uhttp_session->fd] = NULL;
|
||||
uhttp_table[uhttp_session->instance_fd] = NULL;
|
||||
uhttp.load--;
|
||||
del_timeout(uhttp_session);
|
||||
free(uhttp_session);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
len = send(uhttp_session->instance_fd, bbuf, len, 0);
|
||||
|
||||
if (len <= 0) {
|
||||
if (len < 0) uwsgi_error("send()");
|
||||
close_session(uhttp_table, uhttp_session);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
||||
|
||||
// fallback to destroy !!!
|
||||
default:
|
||||
uwsgi_log("default action\n");
|
||||
close(uhttp_session->fd);
|
||||
uhttp_table[uhttp_session->fd] = NULL;
|
||||
if (uhttp_session->instance_fd != -1) {
|
||||
close(uhttp_session->instance_fd);
|
||||
uhttp_table[uhttp_session->instance_fd] = NULL;
|
||||
}
|
||||
uhttp.load--;
|
||||
del_timeout(uhttp_session);
|
||||
free(uhttp_session);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int http_init() {
|
||||
|
||||
if (uhttp.socket_name) {
|
||||
|
||||
if (uhttp.use_cache && !uwsgi.cache_max_items) {
|
||||
uwsgi_log("you need to create a uwsgi cache to use the http (add --cache <n>)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
uhttp.server = bind_to_tcp(uhttp.socket_name, uwsgi.listen_queue, strchr(uhttp.socket_name,':'));
|
||||
|
||||
if (register_gateway("http", http_loop) == NULL) {
|
||||
uwsgi_log("unable to register the http gateway\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int http_opt(int i, char *optarg) {
|
||||
|
||||
switch(i) {
|
||||
case LONG_ARGS_HTTP:
|
||||
uhttp.socket_name = optarg;
|
||||
return 1;
|
||||
case LONG_ARGS_HTTP_SUBSCRIPTION_SERVER:
|
||||
uhttp.subscription_server = optarg;
|
||||
return 1;
|
||||
case LONG_ARGS_HTTP_EVENTS:
|
||||
uhttp.nevents = atoi(optarg);
|
||||
return 1;
|
||||
case LONG_ARGS_HTTP_USE_PATTERN:
|
||||
uhttp.pattern = optarg;
|
||||
// optimization
|
||||
uhttp.pattern_len = strlen(uhttp.pattern);
|
||||
return 1;
|
||||
case LONG_ARGS_HTTP_USE_BASE:
|
||||
uhttp.base = optarg;
|
||||
// optimization
|
||||
uhttp.base_len = strlen(uhttp.base);
|
||||
return 1;
|
||||
case LONG_ARGS_HTTP_USE_TO:
|
||||
uhttp.to = optarg;
|
||||
// optimization
|
||||
uhttp.to_len = strlen(uhttp.to);
|
||||
return 1;
|
||||
case LONG_ARGS_HTTP_VAR:
|
||||
if (uhttp.http_vars_cnt < MAX_HTTP_EXTRA_VARS) {
|
||||
uhttp.http_vars[uhttp.http_vars_cnt] = optarg;
|
||||
uhttp.http_vars_cnt++;
|
||||
} else {
|
||||
uwsgi_log("you can specify at most 64 --http-var options\n");
|
||||
}
|
||||
return 1;
|
||||
case LONG_ARGS_HTTP_MODIFIER1:
|
||||
uhttp.modifier1 = (uint8_t) atoi(optarg);
|
||||
return 1;
|
||||
case LONG_ARGS_HTTP_TIMEOUT:
|
||||
uhttp.socket_timeout = atoi(optarg);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct uwsgi_plugin http_plugin = {
|
||||
|
||||
.options = http_options,
|
||||
.manage_opt = http_opt,
|
||||
.init = http_init,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
NAME='http'
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
|
||||
GCC_LIST = ['http']
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "../../uwsgi.h"
|
||||
#include <jni.h>
|
||||
|
||||
#define MAX_CLASSPATH 64
|
||||
|
||||
#define LONG_ARGS_JVM_BASE 17000 + (300 * 100)
|
||||
#define LONG_ARGS_JVM_CLASS LONG_ARGS_JVM_BASE + 1
|
||||
#define LONG_ARGS_JVM_CLASSPATH LONG_ARGS_JVM_BASE + 2
|
||||
|
||||
struct uwsgi_jvm {
|
||||
|
||||
char *classpath[MAX_CLASSPATH];
|
||||
int classpath_cnt;
|
||||
|
||||
JNIEnv *env;
|
||||
char *class;
|
||||
jclass main_class;
|
||||
|
||||
jclass str_class;
|
||||
jclass ht_class;
|
||||
jclass fd_class;
|
||||
};
|
||||
|
||||
|
||||
jmethodID uwsgi_jvm_get_method_id(jclass, char *, char *);
|
||||
jmethodID uwsgi_jvm_get_static_method_id(jclass, char *, char *);
|
||||
jclass uwsgi_jvm_get_class(char *);
|
||||
jclass uwsgi_jvm_get_object_class(jobject);
|
||||
int uwsgi_jvm_exception(void);
|
||||
|
||||
jobject uwsgi_jvm_str_new(char *, int );
|
||||
jobject uwsgi_jvm_str(char *);
|
||||
|
||||
jobject uwsgi_jvm_array_get(jobject , int );
|
||||
jobject uwsgi_jvm_ht_new(void);
|
||||
jobject uwsgi_jvm_ht_put(jobject, jobject, jobject);
|
||||
|
||||
jobject uwsgi_jvm_fd(int);
|
||||
|
||||
char *uwsgi_jvm_str2c(jobject);
|
||||
int uwsgi_jvm_strlen2c(jobject);
|
||||
@@ -0,0 +1,230 @@
|
||||
#include "jvm.h"
|
||||
|
||||
/*
|
||||
|
||||
with javap -s -p <class>
|
||||
you can get method signatures
|
||||
|
||||
*/
|
||||
|
||||
struct uwsgi_jvm ujvm;
|
||||
|
||||
struct option uwsgi_jvm_options[] = {
|
||||
{"jvm-main-class", required_argument, 0, LONG_ARGS_JVM_CLASS},
|
||||
{"jvm-classpath", required_argument, 0, LONG_ARGS_JVM_CLASSPATH},
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
int uwsgi_jvm_exception(void) {
|
||||
|
||||
if ((*ujvm.env)->ExceptionOccurred(ujvm.env)) {
|
||||
(*ujvm.env)->ExceptionDescribe(ujvm.env);
|
||||
(*ujvm.env)->ExceptionClear(ujvm.env);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
jclass uwsgi_jvm_get_object_class(jobject obj) {
|
||||
return (*ujvm.env)->GetObjectClass(ujvm.env, obj);
|
||||
}
|
||||
|
||||
jclass uwsgi_jvm_get_class(char *name) {
|
||||
|
||||
jclass my_class = (*ujvm.env)->FindClass(ujvm.env, name);
|
||||
|
||||
if (uwsgi_jvm_exception()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return my_class;
|
||||
}
|
||||
|
||||
jmethodID uwsgi_jvm_get_method_id(jclass cls, char *name, char *signature) {
|
||||
|
||||
jmethodID mid;
|
||||
|
||||
mid = (*ujvm.env)->GetMethodID(ujvm.env, cls, name, signature);
|
||||
|
||||
return mid;
|
||||
}
|
||||
|
||||
jmethodID uwsgi_jvm_get_static_method_id(jclass cls, char *name, char *signature) {
|
||||
|
||||
jmethodID mid;
|
||||
|
||||
mid = (*ujvm.env)->GetStaticMethodID(ujvm.env, cls, name, signature);
|
||||
|
||||
return mid;
|
||||
}
|
||||
|
||||
jobject uwsgi_jvm_str_new(char *str, int len) {
|
||||
|
||||
jbyteArray ba;
|
||||
static jmethodID str_new_mid = 0;
|
||||
|
||||
if (!str_new_mid) {
|
||||
str_new_mid = uwsgi_jvm_get_method_id(ujvm.str_class, "<init>", "([BLjava/lang/String;)V");
|
||||
}
|
||||
|
||||
ba = (*ujvm.env)->NewByteArray(ujvm.env, len);
|
||||
(*ujvm.env)->SetByteArrayRegion(ujvm.env, ba, 0, len, (jbyte *) str);
|
||||
return (*ujvm.env)->NewObject(ujvm.env, ujvm.str_class, str_new_mid, ba,
|
||||
(*ujvm.env)->NewStringUTF(ujvm.env, "UTF-8"));
|
||||
}
|
||||
|
||||
jobject uwsgi_jvm_str(char *str) {
|
||||
return (*ujvm.env)->NewStringUTF(ujvm.env, str);
|
||||
}
|
||||
|
||||
|
||||
int jvm_init(void) {
|
||||
|
||||
jint res;
|
||||
JavaVM *jvm;
|
||||
JavaVMInitArgs vm_args;
|
||||
JavaVMOption options[1];
|
||||
jmethodID mmid;
|
||||
|
||||
int i;
|
||||
char *old_cp = NULL ;
|
||||
|
||||
|
||||
vm_args.version = JNI_VERSION_1_2;
|
||||
|
||||
JNI_GetDefaultJavaVMInitArgs(&vm_args);
|
||||
|
||||
options[0].optionString = "-Djava.class.path=.";
|
||||
|
||||
if (ujvm.classpath_cnt > 0) {
|
||||
for(i=0;i<ujvm.classpath_cnt;i++) {
|
||||
if (old_cp) {
|
||||
options[0].optionString = uwsgi_concat3(old_cp, ":", ujvm.classpath[i]);
|
||||
free(old_cp);
|
||||
}
|
||||
else {
|
||||
options[0].optionString = uwsgi_concat3(options[0].optionString, ":", ujvm.classpath[i]);
|
||||
}
|
||||
old_cp = options[0].optionString ;
|
||||
}
|
||||
}
|
||||
|
||||
vm_args.options = options;
|
||||
vm_args.nOptions = 1;
|
||||
|
||||
res = JNI_CreateJavaVM(&jvm, (void **) &ujvm.env, &vm_args);
|
||||
|
||||
if (res) {
|
||||
uwsgi_log("unable to initialize JVM\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_log("JVM initialized\n");
|
||||
|
||||
if (ujvm.class) {
|
||||
ujvm.main_class = uwsgi_jvm_get_class(ujvm.class);
|
||||
if (!ujvm.main_class) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
mmid = uwsgi_jvm_get_static_method_id(ujvm.main_class, "main", "([Ljava/lang/String;)V");
|
||||
if (mmid) {
|
||||
(*ujvm.env)->CallStaticVoidMethod(ujvm.env, ujvm.main_class, mmid);
|
||||
uwsgi_jvm_exception();
|
||||
}
|
||||
}
|
||||
|
||||
ujvm.str_class = uwsgi_jvm_get_class("java/lang/String");
|
||||
ujvm.ht_class = uwsgi_jvm_get_class("java/util/Hashtable");
|
||||
ujvm.fd_class = uwsgi_jvm_get_class("java/io/FileDescriptor");
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
jobject uwsgi_jvm_array_get(jobject obj, int index) {
|
||||
return (*ujvm.env)->GetObjectArrayElement(ujvm.env, obj, index);
|
||||
}
|
||||
|
||||
jobject uwsgi_jvm_ht_new() {
|
||||
static jmethodID htimid = 0;
|
||||
|
||||
if (!htimid) {
|
||||
htimid = uwsgi_jvm_get_method_id(ujvm.ht_class, "<init>", "()V");
|
||||
}
|
||||
|
||||
return (*ujvm.env)->NewObject(ujvm.env, ujvm.ht_class, htimid);
|
||||
}
|
||||
|
||||
jobject uwsgi_jvm_ht_put(jobject obj, jobject key, jobject val) {
|
||||
|
||||
static jmethodID htpmid = 0 ;
|
||||
|
||||
if (!htpmid) {
|
||||
htpmid = uwsgi_jvm_get_method_id(ujvm.ht_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
}
|
||||
|
||||
return (*ujvm.env)->CallObjectMethod(ujvm.env, obj, htpmid, key, val);
|
||||
}
|
||||
|
||||
jobject uwsgi_jvm_fd(int fd) {
|
||||
|
||||
jobject fd_obj;
|
||||
static jmethodID fd_mid = 0;
|
||||
static jfieldID fd_field = 0 ;
|
||||
|
||||
if (!fd_mid) {
|
||||
fd_mid = uwsgi_jvm_get_method_id( ujvm.fd_class, "<init>", "()V");
|
||||
}
|
||||
|
||||
fd_obj = (*ujvm.env)->NewObject(ujvm.env, ujvm.fd_class, fd_mid);
|
||||
|
||||
if (!fd_field) {
|
||||
fd_field = (*ujvm.env)->GetFieldID(ujvm.env, ujvm.fd_class, "fd", "I");
|
||||
}
|
||||
|
||||
(*ujvm.env)->SetIntField(ujvm.env, fd_obj, fd_field, fd);
|
||||
|
||||
return fd_obj;
|
||||
}
|
||||
|
||||
char *uwsgi_jvm_str2c(jobject obj) {
|
||||
|
||||
return (char *) (*ujvm.env)->GetStringUTFChars(ujvm.env, obj, NULL);
|
||||
}
|
||||
|
||||
int uwsgi_jvm_strlen2c(jobject obj) {
|
||||
|
||||
return (*ujvm.env)->GetStringUTFLength(ujvm.env, obj);
|
||||
}
|
||||
|
||||
int uwsgi_jvm_manage_opt(int i, char *optarg) {
|
||||
|
||||
switch(i) {
|
||||
case LONG_ARGS_JVM_CLASS:
|
||||
ujvm.class = optarg;
|
||||
return 1;
|
||||
case LONG_ARGS_JVM_CLASSPATH:
|
||||
if (ujvm.classpath_cnt < MAX_CLASSPATH) {
|
||||
ujvm.classpath[ujvm.classpath_cnt] = optarg;
|
||||
ujvm.classpath_cnt++;
|
||||
}
|
||||
else {
|
||||
uwsgi_log( "you can specify at most %d --jvm-classpath options\n", MAX_CLASSPATH);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct uwsgi_plugin jvm_plugin = {
|
||||
|
||||
.name = "jvm",
|
||||
.init = jvm_init,
|
||||
.options = uwsgi_jvm_options,
|
||||
.manage_opt = uwsgi_jvm_manage_opt,
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import os,sys
|
||||
|
||||
NAME='jvm'
|
||||
|
||||
# Snow Leopard
|
||||
#JVM_INCPATH = "/Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Headers/"
|
||||
#JVM_LIBPATH = "/Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Libraries/ -framework JavaVM"
|
||||
|
||||
# FreeBSD openjdk7 example
|
||||
# env UWSGICONFIG_JVM_INCPATH="/usr/local/openjdk7/include -I/usr/local/openjdk7/include/freebsd/" UWSGICONFIG_JVM_LIBPATH="/usr/local/openjdk7/jre/lib/amd64/server" python uwsgiconfig.py --plugin plugins/jvm
|
||||
|
||||
# NexentaOS example
|
||||
# UWSGICONFIG_JVM_INCPATH="/usr/java/include -I /usr/java/include/solaris" UWSGICONFIG_JVM_LIBPATH="/usr/java/jre/lib/i386/" python uwsgiconfig.py --plugin plugins/jvm
|
||||
|
||||
# Ubuntu
|
||||
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
|
||||
|
||||
CFLAGS = ['-I' + JVM_INCPATH]
|
||||
LDFLAGS = ['-L' + JVM_LIBPATH]
|
||||
LIBS = ['-ljvm']
|
||||
GCC_LIST = ['jvm_plugin']
|
||||
|
||||
if os.environ.has_key('LD_RUN_PATH'):
|
||||
os.environ['LD_RUN_PATH'] += ':' + JVM_LIBPATH
|
||||
else:
|
||||
os.environ['LD_RUN_PATH'] = JVM_LIBPATH
|
||||
@@ -0,0 +1,117 @@
|
||||
#include "../jvm/jvm.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
extern struct uwsgi_jvm ujvm;
|
||||
|
||||
void uwsgi_jwsgi_init(void) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_jwsgi_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
jmethodID jmid;
|
||||
int i;
|
||||
jobject env;
|
||||
jobject hkey, hval;
|
||||
jobject response;
|
||||
|
||||
jobject status;
|
||||
jobject headers, header;
|
||||
jobject body;
|
||||
|
||||
jclass hc;
|
||||
|
||||
jmethodID hh_size, hh_get;
|
||||
int hlen;
|
||||
|
||||
if (!wsgi_req->uh.pktsize) {
|
||||
uwsgi_log("Invalid JWSGI request. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (uwsgi_parse_vars(wsgi_req)) {
|
||||
uwsgi_log("Invalid JWSGI request. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
jmid = uwsgi_jvm_get_static_method_id(ujvm.main_class, "jwsgi", "(Ljava/util/Hashtable;)[Ljava/lang/Object;");
|
||||
|
||||
uwsgi_log("jwsgi method id = %d\n", jmid);
|
||||
|
||||
env = uwsgi_jvm_ht_new();
|
||||
uwsgi_jvm_exception();
|
||||
|
||||
for(i=0;i<wsgi_req->var_cnt;i++) {
|
||||
|
||||
uwsgi_jvm_ht_put(env,
|
||||
uwsgi_jvm_str_new(wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len),
|
||||
uwsgi_jvm_str_new(wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len)
|
||||
);
|
||||
|
||||
// check if something is going wrong during hashtable fill
|
||||
uwsgi_jvm_exception();
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
uwsgi_log("env created\n");
|
||||
|
||||
uwsgi_jvm_ht_put(env, uwsgi_jvm_str("jwsgi.input"), uwsgi_jvm_fd(wsgi_req->poll.fd));
|
||||
|
||||
uwsgi_log("jwsgi.input created\n");
|
||||
|
||||
response = (*ujvm.env)->CallObjectMethod(ujvm.env, ujvm.main_class, jmid, env);
|
||||
uwsgi_jvm_exception();
|
||||
|
||||
uwsgi_log("RESPONSE SIZE %d\n", (*ujvm.env)->GetArrayLength(ujvm.env, response));
|
||||
|
||||
status = uwsgi_jvm_array_get(response, 0);
|
||||
uwsgi_jvm_exception();
|
||||
|
||||
wsgi_req->headers_size += write(wsgi_req->poll.fd, wsgi_req->protocol, wsgi_req->protocol_len);
|
||||
wsgi_req->headers_size += write(wsgi_req->poll.fd, " ", 1);
|
||||
wsgi_req->headers_size += write(wsgi_req->poll.fd, uwsgi_jvm_str2c(status), uwsgi_jvm_strlen2c(status));
|
||||
wsgi_req->headers_size += write(wsgi_req->poll.fd, "\r\n", 2);
|
||||
|
||||
|
||||
headers = uwsgi_jvm_array_get(response, 1);
|
||||
hc = uwsgi_jvm_get_object_class(headers);
|
||||
hh_size = uwsgi_jvm_get_method_id(hc, "size","()I");
|
||||
hh_get = uwsgi_jvm_get_method_id(hc, "get","(I)Ljava/lang/Object;");
|
||||
|
||||
hlen = (*ujvm.env)->CallIntMethod(ujvm.env, headers, hh_size);
|
||||
|
||||
for(i=0;i<hlen;i++) {
|
||||
header = (*ujvm.env)->CallObjectMethod(ujvm.env, headers, hh_get, i);
|
||||
hkey = uwsgi_jvm_array_get(header, 0);
|
||||
hval = uwsgi_jvm_array_get(header, 1);
|
||||
|
||||
wsgi_req->headers_size += write(wsgi_req->poll.fd, uwsgi_jvm_str2c(hkey), uwsgi_jvm_strlen2c(hkey));
|
||||
wsgi_req->headers_size += write(wsgi_req->poll.fd, ": ", 2);
|
||||
wsgi_req->headers_size += write(wsgi_req->poll.fd, uwsgi_jvm_str2c(hval), uwsgi_jvm_strlen2c(hval));
|
||||
wsgi_req->headers_size += write(wsgi_req->poll.fd, "\r\n", 2);
|
||||
}
|
||||
|
||||
wsgi_req->headers_size += write(wsgi_req->poll.fd, "\r\n", 2);
|
||||
|
||||
body = uwsgi_jvm_array_get(response, 2);
|
||||
|
||||
wsgi_req->response_size = write(wsgi_req->poll.fd, (*ujvm.env)->GetStringUTFChars(ujvm.env, body, NULL), (*ujvm.env)->GetStringUTFLength(ujvm.env, body));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void uwsgi_jwsgi_after_request(struct wsgi_request *wsgi_req) {
|
||||
log_request(wsgi_req);
|
||||
}
|
||||
|
||||
struct uwsgi_plugin jwsgi_plugin = {
|
||||
|
||||
.name = "jwsgi",
|
||||
.modifier1 = 8,
|
||||
.request = uwsgi_jwsgi_request,
|
||||
.after_request = uwsgi_jwsgi_after_request,
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
import os,sys
|
||||
|
||||
NAME='jwsgi'
|
||||
|
||||
# Snow Leopard
|
||||
#JVM_INCPATH = "/Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Headers/"
|
||||
#JVM_LIBPATH = "/Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Libraries/ -framework JavaVM"
|
||||
|
||||
# Ubuntu
|
||||
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/"
|
||||
|
||||
|
||||
CFLAGS = ['-I' + JVM_INCPATH]
|
||||
LDFLAGS = ['-L' + JVM_LIBPATH]
|
||||
LIBS = ['-ljvm']
|
||||
GCC_LIST = ['jwsgi_plugin']
|
||||
|
||||
if os.environ.has_key('LD_RUN_PATH'):
|
||||
os.environ['LD_RUN_PATH'] += ':' + JVM_LIBPATH
|
||||
else:
|
||||
os.environ['LD_RUN_PATH'] = JVM_LIBPATH
|
||||
+574
-118
@@ -1,214 +1,670 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
/* gcc -fPIC -shared -o lua_plugin.so `python2.5-config --cflags` -I /usr/include/lua5.1 -llua5.1 lua_plugin.c */
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
#include <lua.h>
|
||||
#include <lualib.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
static struct uwsgi_lua {
|
||||
struct lua_State *L ;
|
||||
struct uwsgi_server *uwsgi;
|
||||
struct uwsgi_lua {
|
||||
struct lua_State **L;
|
||||
|
||||
char *filename;
|
||||
} ulua;
|
||||
|
||||
static void *uwsgi_lua_alloc(void *ud, void *ptr, size_t osize, size_t nsize) {
|
||||
if(nsize == 0) {
|
||||
free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
#define LONG_ARGS_LUA_BASE 17000 + (6 * 100)
|
||||
#define LONG_ARGS_LUA LONG_ARGS_LUA_BASE + 1
|
||||
|
||||
return realloc(ptr, nsize);
|
||||
#define lca(L, n) ulua_check_args(L, __FUNCTION__, n)
|
||||
|
||||
struct option uwsgi_lua_options[] = {
|
||||
|
||||
{"lua", required_argument, 0, LONG_ARGS_LUA},
|
||||
|
||||
{0, 0, 0, 0},
|
||||
|
||||
};
|
||||
|
||||
static void ulua_check_args(lua_State *L, const char *func, int n) {
|
||||
int args = lua_gettop(L);
|
||||
char error[4096];
|
||||
if (args != n) {
|
||||
if (n == 1) {
|
||||
snprintf(error, 4096, "uwsgi.%s takes 1 parameter", func+10);
|
||||
}
|
||||
else {
|
||||
snprintf(error, 4096, "uwsgi.%s takes %d parameters", func+10, n);
|
||||
}
|
||||
lua_pushstring(L, error);
|
||||
lua_error(L);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *uwsgi_read_lua(lua_State *L, void *data, size_t *size) {
|
||||
|
||||
int fd = *(int *)data;
|
||||
static char buf[4096];
|
||||
|
||||
*size = read(fd, buf, 4096);
|
||||
static int uwsgi_api_log(lua_State *L) {
|
||||
|
||||
if (size == 0) {
|
||||
return NULL;
|
||||
const char *logline ;
|
||||
|
||||
lca(L, 1);
|
||||
|
||||
if (lua_isstring(L, 1)) {
|
||||
logline = lua_tolstring(L, 1, NULL);
|
||||
uwsgi_log( "%s\n", logline);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_api_register_rpc(lua_State *L) {
|
||||
|
||||
uint8_t argc = lua_gettop(L);
|
||||
const char *name;
|
||||
// a hack for 64bit;
|
||||
int func;
|
||||
long lfunc;
|
||||
|
||||
if (argc < 2) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
name = lua_tolstring(L, 1, NULL);
|
||||
|
||||
lua_pushvalue(L, 2);
|
||||
func = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
|
||||
uwsgi_log("registered function %d in global table\n", func);
|
||||
lfunc = func;
|
||||
|
||||
if (uwsgi_register_rpc((char *)name, 6, 0, (void *) lfunc)) {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
else {
|
||||
lua_pushboolean(L, 1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static char *encode_lua_table(lua_State *L, int index, uint16_t *size) {
|
||||
|
||||
char *buf, *ptrbuf;
|
||||
char *key;
|
||||
char *value;
|
||||
size_t keylen;
|
||||
size_t vallen;
|
||||
|
||||
*size = 0;
|
||||
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, index) != 0) {
|
||||
if (lua_isstring(L, -2) && lua_isstring(L, -1)) {
|
||||
key = (char *) lua_tolstring(L, -2, &keylen);
|
||||
value = (char *) lua_tolstring(L, -1, &vallen);
|
||||
if (keylen > 0xffff || vallen > 0xffff) continue;
|
||||
*size += (2+keylen+2+vallen);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
buf = malloc(*size);
|
||||
if (!buf) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ptrbuf = buf;
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, index) != 0) {
|
||||
if (lua_isstring(L, -2) && lua_isstring(L, -1)) {
|
||||
key = (char *) lua_tolstring(L, -2, &keylen);
|
||||
value = (char *) lua_tolstring(L, -1, &vallen);
|
||||
|
||||
if (keylen > 0xffff || vallen > 0xffff) continue;
|
||||
|
||||
*ptrbuf++ = (uint8_t) (keylen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((keylen >>8) & 0xff);
|
||||
memcpy(ptrbuf, key, keylen); ptrbuf += keylen;
|
||||
*ptrbuf++ = (uint8_t) (vallen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((vallen >>8) & 0xff);
|
||||
memcpy(ptrbuf, value, vallen); ptrbuf += vallen;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int uwsgi_lua_input(lua_State *L) {
|
||||
static int uwsgi_api_cache_set(lua_State *L) {
|
||||
|
||||
int n = lua_gettop(L);
|
||||
int args = lua_gettop(L);
|
||||
const char *key ;
|
||||
const char *value ;
|
||||
uint64_t expires = 0;
|
||||
size_t vallen;
|
||||
|
||||
static char *buf = "" ;
|
||||
|
||||
fprintf(stderr,"richiesti %d bytes\n", n);
|
||||
if (args > 1) {
|
||||
|
||||
//sum = read(ulua.uwsgi->poll.fd,);
|
||||
key = lua_tolstring(L, 1, NULL);
|
||||
value = lua_tolstring(L, 2, &vallen);
|
||||
if (args > 2) {
|
||||
expires = lua_tonumber(L, 3);
|
||||
}
|
||||
|
||||
lua_pushlstring(L, buf, 0);
|
||||
uwsgi_cache_set((char *)key, strlen(key), (char *)value, (uint16_t) vallen, expires, 0);
|
||||
|
||||
}
|
||||
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
static int uwsgi_api_register_signal(lua_State *L) {
|
||||
|
||||
int args = lua_gettop(L);
|
||||
uint8_t sig;
|
||||
long lhandler;
|
||||
const char *who;
|
||||
|
||||
if (args >= 3) {
|
||||
|
||||
sig = lua_tonumber(L, 1);
|
||||
who = lua_tostring(L, 2);
|
||||
lua_pushvalue(L, 3);
|
||||
lhandler = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
|
||||
uwsgi_register_signal(sig, (char *)who, (void *) lhandler, 6);
|
||||
}
|
||||
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int uwsgi_init(struct uwsgi_server *uwsgi, char *args){
|
||||
|
||||
int fd, i;
|
||||
static int uwsgi_api_cache_get(lua_State *L) {
|
||||
|
||||
fprintf(stderr,"Initializing Lua environment...\n");
|
||||
char *value ;
|
||||
uint64_t valsize;
|
||||
const char *key ;
|
||||
|
||||
|
||||
|
||||
lca(L, 1);
|
||||
|
||||
ulua.L = lua_newstate(uwsgi_lua_alloc, NULL);
|
||||
if (lua_isstring(L, 1)) {
|
||||
|
||||
luaL_openlibs(ulua.L);
|
||||
key = lua_tolstring(L, 1, NULL);
|
||||
value = uwsgi_cache_get((char *)key, strlen(key), &valsize);
|
||||
|
||||
if (value) {
|
||||
lua_pushlstring(L, value, valsize);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
fd = open(args, O_RDONLY) ;
|
||||
if (fd < 0) {
|
||||
perror("open()");
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
|
||||
i = lua_load(ulua.L, uwsgi_read_lua, &fd, "uwsgi");
|
||||
|
||||
fprintf(stderr,"lua_load: %d\n" ,i);
|
||||
lua_pushnil(L);
|
||||
|
||||
// use a pcall
|
||||
lua_call(ulua.L, 0, 1);
|
||||
return 1;
|
||||
|
||||
fprintf(stderr,"%s\n", lua_typename(ulua.L, lua_type(ulua.L, -1)));
|
||||
|
||||
// ok the lua engine is ready
|
||||
return 0 ;
|
||||
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req) {
|
||||
|
||||
static int uwsgi_api_send_message(lua_State *L) {
|
||||
|
||||
int args = lua_gettop(L);
|
||||
const char *host;
|
||||
int uwsgi_fd;
|
||||
uint8_t modifier1, modifier2;
|
||||
char *pkt = NULL;
|
||||
uint16_t pktsize = 0 ;
|
||||
char buf[4096];
|
||||
int rlen;
|
||||
int items = 0;
|
||||
int input_fd = -1, timeout = -1, input_size = 0;
|
||||
|
||||
// is this an fd ?
|
||||
if (lua_isnumber(L, 1)) {
|
||||
args = 1;
|
||||
}
|
||||
else if (lua_isstring(L, 1)) {
|
||||
host = lua_tolstring(L, 1, NULL);
|
||||
uwsgi_fd = uwsgi_connect((char *)host, timeout, 0);
|
||||
modifier1 = lua_tonumber(L, 2);
|
||||
modifier2 = lua_tonumber(L, 3);
|
||||
if (args > 4) {
|
||||
timeout = lua_tonumber(L, 5);
|
||||
if (args == 7) {
|
||||
input_fd = lua_tonumber(L, 6);
|
||||
input_size = lua_tonumber(L, 7);
|
||||
}
|
||||
}
|
||||
if (lua_istable(L,4)) {
|
||||
// passed a table
|
||||
pkt = encode_lua_table(L, 4, &pktsize);
|
||||
}
|
||||
if (uwsgi_send_message(uwsgi_fd, modifier1, modifier2, pkt, pktsize, input_fd, input_size, timeout) == -1) {
|
||||
free(pkt);
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
free(pkt);
|
||||
|
||||
for(;;) {
|
||||
rlen = uwsgi_waitfd(uwsgi_fd, timeout);
|
||||
if (rlen > 0) {
|
||||
rlen = read(uwsgi_fd, buf, 4096);
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("read()");
|
||||
break;
|
||||
}
|
||||
else if (rlen > 0) {
|
||||
lua_pushlstring(L, buf, rlen);
|
||||
items++;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (rlen == 0) {
|
||||
uwsgi_log("uwsgi request timed out waiting for response\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
close(uwsgi_fd);
|
||||
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
static int uwsgi_api_cl(lua_State *L) {
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
lua_pushnumber(L, wsgi_req->post_cl);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int uwsgi_api_req_fd(lua_State *L) {
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
lua_pushnumber(L, wsgi_req->poll.fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_reg uwsgi_api[] = {
|
||||
{"log", uwsgi_api_log},
|
||||
{"cl", uwsgi_api_cl},
|
||||
{"req_fd", uwsgi_api_req_fd},
|
||||
{"send_message", uwsgi_api_send_message},
|
||||
{"cache_get", uwsgi_api_cache_get},
|
||||
{"cache_set", uwsgi_api_cache_set},
|
||||
{"register_signal", uwsgi_api_register_signal},
|
||||
{"register_rpc", uwsgi_api_register_rpc},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
|
||||
static int uwsgi_lua_input(lua_State *L) {
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
ssize_t sum, len, total;
|
||||
char *buf, *ptr;
|
||||
|
||||
int n = lua_gettop(L);
|
||||
|
||||
if (!wsgi_req->post_cl) {
|
||||
lua_pushlstring(L, "", 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sum = lua_tonumber(L, 2);
|
||||
|
||||
if (n > 1) {
|
||||
uwsgi_log("requested %d bytes\n", sum);
|
||||
}
|
||||
|
||||
buf = malloc(sum);
|
||||
if (!buf) {
|
||||
uwsgi_error("malloc()");
|
||||
}
|
||||
|
||||
total = sum;
|
||||
|
||||
ptr = buf;
|
||||
while(total) {
|
||||
len = read(wsgi_req->poll.fd, ptr, total);
|
||||
ptr += len;
|
||||
total -= len;
|
||||
}
|
||||
|
||||
lua_pushlstring(L, buf, sum);
|
||||
free(buf);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int uwsgi_lua_init(){
|
||||
|
||||
uwsgi_log("Initializing Lua environment... (%d cores)\n", uwsgi.cores);
|
||||
|
||||
ulua.L = malloc( sizeof(lua_State*) * uwsgi.cores );
|
||||
if (!ulua.L) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// ok the lua engine is ready
|
||||
return 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_lua_app() {
|
||||
int i;
|
||||
|
||||
if (ulua.filename) {
|
||||
for(i=0;i<uwsgi.cores;i++) {
|
||||
ulua.L[i] = luaL_newstate();
|
||||
luaL_openlibs(ulua.L[i]);
|
||||
luaL_register(ulua.L[i], "uwsgi", uwsgi_api);
|
||||
if (luaL_loadfile(ulua.L[i], ulua.filename)) {
|
||||
uwsgi_log("unable to load file %s\n", ulua.filename);
|
||||
exit(1);
|
||||
}
|
||||
// use a pcall
|
||||
//lua_call(ulua.L[i], 0, 1);
|
||||
if (lua_pcall(ulua.L[i], 0, 1, 0) != 0) {
|
||||
uwsgi_log("%s\n", lua_tostring(ulua.L[i], -1));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int uwsgi_lua_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
int i;
|
||||
const char *http ;
|
||||
size_t slen ;
|
||||
int raw;
|
||||
const char *http;
|
||||
size_t slen;
|
||||
ssize_t rlen;
|
||||
char *ptrbuf;
|
||||
lua_State *L = ulua.L[wsgi_req->async_id];
|
||||
|
||||
#ifdef UWSGI_ASYNC
|
||||
if (wsgi_req->async_status == UWSGI_AGAIN) {
|
||||
if ((i = lua_pcall(L, 0, 1, 0)) == 0) {
|
||||
if (lua_type(L, -1) == LUA_TSTRING) {
|
||||
http = lua_tolstring(L, -1, &slen);
|
||||
if ( (rlen = write(wsgi_req->poll.fd, http, slen)) != (ssize_t) slen) {
|
||||
perror("write()");
|
||||
return UWSGI_OK;
|
||||
}
|
||||
wsgi_req->response_size += rlen;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
lua_pushvalue(L, -1);
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
goto clear;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Standard WSAPI request */
|
||||
if (!wsgi_req->uh.pktsize) {
|
||||
fprintf (stderr, "Invalid WSAPI request. skip.\n");
|
||||
return -1;
|
||||
uwsgi_log( "Invalid WSAPI request. skip.\n");
|
||||
goto clear;
|
||||
}
|
||||
|
||||
if (uwsgi_parse_vars(uwsgi, wsgi_req)) {
|
||||
fprintf(stderr,"Invalid WSAPI request. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
if (uwsgi_parse_vars(wsgi_req)) {
|
||||
uwsgi_log("Invalid WSAPI request. skip.\n");
|
||||
goto clear;
|
||||
}
|
||||
|
||||
// put function in the stack
|
||||
lua_pushvalue(ulua.L, -1);
|
||||
lua_getfield(ulua.L, -1, "run");
|
||||
//lua_getfield(L, LUA_GLOBALSINDEX, "run");
|
||||
lua_pushvalue(L, -1);
|
||||
|
||||
// put cgi vars in the stack
|
||||
lua_newtable(ulua.L);
|
||||
lua_pushstring(ulua.L, "");
|
||||
lua_setfield(ulua.L, -2, "CONTENT_TYPE");
|
||||
|
||||
lua_newtable(L);
|
||||
lua_pushstring(L, "");
|
||||
lua_setfield(L, -2, "CONTENT_TYPE");
|
||||
for(i=0;i<wsgi_req->var_cnt;i++) {
|
||||
lua_pushlstring(ulua.L, (char *)wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len);
|
||||
lua_pushlstring(L, (char *)wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len);
|
||||
// transform it in a valid c string TODO this is ugly
|
||||
ptrbuf = wsgi_req->hvec[i].iov_base+wsgi_req->hvec[i].iov_len ;
|
||||
*ptrbuf = 0 ;
|
||||
lua_setfield(ulua.L, -2, (char *)wsgi_req->hvec[i].iov_base);
|
||||
ptrbuf = wsgi_req->hvec[i].iov_base+wsgi_req->hvec[i].iov_len;
|
||||
*ptrbuf = 0;
|
||||
lua_setfield(L, -2, (char *)wsgi_req->hvec[i].iov_base);
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
// put "input" table
|
||||
lua_newtable(ulua.L);
|
||||
lua_pushcfunction(ulua.L, uwsgi_lua_input);
|
||||
lua_setfield(ulua.L, -2, "read");
|
||||
lua_setfield(ulua.L, -2, "input");
|
||||
lua_newtable(L);
|
||||
lua_pushcfunction(L, uwsgi_lua_input);
|
||||
lua_setfield(L, -2, "read");
|
||||
lua_setfield(L, -2, "input");
|
||||
|
||||
|
||||
// call function
|
||||
i = lua_pcall(ulua.L, 1, 3, 0);
|
||||
i = lua_pcall(L, 1, 3, 0);
|
||||
if (i != 0) {
|
||||
fprintf(stderr,"%s\n", lua_tostring(ulua.L, -1));
|
||||
lua_pop(ulua.L, 1);
|
||||
return -1 ;
|
||||
uwsgi_log("%s\n", lua_tostring(L, -1));
|
||||
lua_pop(L, 1);
|
||||
goto clear;
|
||||
}
|
||||
|
||||
fprintf(stderr,"%d %s %s %s\n",i,lua_typename(ulua.L, lua_type(ulua.L, -3)), lua_typename(ulua.L, lua_type(ulua.L, -2)) , lua_typename(ulua.L, lua_type(ulua.L, -1)));
|
||||
//uwsgi_log("%d %s %s %s\n",i,lua_typename(L, lua_type(L, -3)), lua_typename(L, lua_type(L, -2)) , lua_typename(L, lua_type(L, -1)));
|
||||
|
||||
raw = 0;
|
||||
// send status
|
||||
if (lua_type(ulua.L, -3) == LUA_TSTRING || lua_type(ulua.L, -3) == LUA_TNUMBER) {
|
||||
http = lua_tolstring(ulua.L, -3, &slen);
|
||||
if (write(wsgi_req->poll.fd, "HTTP/1.1 ", 9) != 9) {
|
||||
if (lua_type(L, -3) == LUA_TSTRING || lua_type(L, -3) == LUA_TNUMBER) {
|
||||
http = lua_tolstring(L, -3, &slen);
|
||||
if (write(wsgi_req->poll.fd, wsgi_req->protocol, wsgi_req->protocol_len) != wsgi_req->protocol_len) {
|
||||
perror("write()");
|
||||
return -1 ;
|
||||
goto clear;
|
||||
}
|
||||
if (write(wsgi_req->poll.fd, http, slen) != slen) {
|
||||
if (write(wsgi_req->poll.fd, " ", 1) != 1) {
|
||||
perror("write()");
|
||||
return -1 ;
|
||||
goto clear;
|
||||
}
|
||||
if (write(wsgi_req->poll.fd, http, slen) != (ssize_t) slen) {
|
||||
perror("write()");
|
||||
goto clear;
|
||||
}
|
||||
// a performance hack
|
||||
ptrbuf = (char *) http;
|
||||
ptrbuf[3] = 0;
|
||||
wsgi_req->status = atoi(ptrbuf);
|
||||
if (write(wsgi_req->poll.fd, "\r\n", 2) != 2) {
|
||||
perror("write()");
|
||||
return -1 ;
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
raw = 1;
|
||||
wsgi_req->status = -1;
|
||||
}
|
||||
|
||||
// send headers
|
||||
|
||||
lua_pushnil(ulua.L);
|
||||
while(lua_next(ulua.L, -3) != 0) {
|
||||
http = lua_tolstring(ulua.L, -2, &slen);
|
||||
if (write(wsgi_req->poll.fd, http, slen) != slen) {
|
||||
lua_pushnil(L);
|
||||
while(lua_next(L, -3) != 0) {
|
||||
http = lua_tolstring(L, -2, &slen);
|
||||
if (write(wsgi_req->poll.fd, http, slen) != (ssize_t) slen) {
|
||||
perror("write()");
|
||||
return -1 ;
|
||||
goto clear;
|
||||
}
|
||||
if (write(wsgi_req->poll.fd, ": ", 2) != 2) {
|
||||
perror("write()");
|
||||
return -1 ;
|
||||
goto clear;
|
||||
}
|
||||
http = lua_tolstring(ulua.L, -1, &slen);
|
||||
if (write(wsgi_req->poll.fd, http, slen) != slen) {
|
||||
http = lua_tolstring(L, -1, &slen);
|
||||
if (write(wsgi_req->poll.fd, http, slen) != (ssize_t) slen) {
|
||||
perror("write()");
|
||||
return -1 ;
|
||||
goto clear;
|
||||
}
|
||||
if (write(wsgi_req->poll.fd, "\r\n", 2) != 2) {
|
||||
perror("write()");
|
||||
return -1 ;
|
||||
goto clear;
|
||||
}
|
||||
lua_pop(ulua.L, 1);
|
||||
}
|
||||
|
||||
if (write(wsgi_req->poll.fd, "\r\n", 2) != 2) {
|
||||
perror("write()");
|
||||
return -1 ;
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
|
||||
if (!raw) {
|
||||
if (write(wsgi_req->poll.fd, "\r\n", 2) != 2) {
|
||||
perror("write()");
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
|
||||
// send body with coroutine
|
||||
lua_pushvalue(ulua.L, -1);
|
||||
lua_pushvalue(L, -1);
|
||||
|
||||
while ( (i = lua_pcall(ulua.L, 0, 1, 0)) == 0) {
|
||||
if (lua_type(ulua.L, -1) == LUA_TSTRING) {
|
||||
http = lua_tolstring(ulua.L, -1, &slen);
|
||||
if (write(wsgi_req->poll.fd, http, slen) != slen) {
|
||||
while ( (i = lua_pcall(L, 0, 1, 0)) == 0) {
|
||||
if (lua_type(L, -1) == LUA_TSTRING) {
|
||||
http = lua_tolstring(L, -1, &slen);
|
||||
if ( (rlen = write(wsgi_req->poll.fd, http, slen)) != (ssize_t) slen) {
|
||||
perror("write()");
|
||||
return -1 ;
|
||||
goto clear;
|
||||
}
|
||||
//fprintf(stderr,"%.*s\n", slen, http);
|
||||
}
|
||||
lua_pop(ulua.L, 1);
|
||||
lua_pushvalue(ulua.L, -1);
|
||||
}
|
||||
wsgi_req->response_size += rlen;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
lua_pushvalue(L, -1);
|
||||
#ifdef UWSGI_ASYNC
|
||||
if (uwsgi.async > 1) {
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
lua_pop(ulua.L, 4);
|
||||
clear:
|
||||
|
||||
lua_pop(L, 4);
|
||||
|
||||
// set frequency
|
||||
lua_gc(L, LUA_GCCOLLECT, 0);
|
||||
|
||||
return UWSGI_OK;
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_lua_after_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_LOGGING])
|
||||
log_request(wsgi_req);
|
||||
}
|
||||
|
||||
int uwsgi_lua_manage_options(int i, char *optarg) {
|
||||
|
||||
switch(i) {
|
||||
case LONG_ARGS_LUA:
|
||||
ulua.filename = optarg;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_lua_magic(char *mountpoint, char *lazy) {
|
||||
|
||||
if (!strcmp(lazy+strlen(lazy)-4, ".lua")) {
|
||||
ulua.filename = lazy;
|
||||
return 1;
|
||||
}
|
||||
else if (!strcmp(lazy+strlen(lazy)-3, ".ws")) {
|
||||
ulua.filename = lazy;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_lua_signal_handler(uint8_t sig, void *handler) {
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
lua_State *L = ulua.L[wsgi_req->async_id];
|
||||
|
||||
uwsgi_log("managing signal handler on core %d\n", wsgi_req->async_id);
|
||||
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, (long) handler);
|
||||
|
||||
lua_pushnumber(L, sig);
|
||||
|
||||
if (lua_pcall(L, 1, 1, 0) != 0) {
|
||||
uwsgi_log("error running function `f': %s",
|
||||
lua_tostring(L, -1));
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
uint16_t uwsgi_lua_rpc(void * func, uint8_t argc, char **argv, char *buffer) {
|
||||
|
||||
uint8_t i;
|
||||
const char *sv;
|
||||
size_t sl;
|
||||
long lfunc = (long) func;
|
||||
int ifunc = lfunc;
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
lua_State *L = ulua.L[wsgi_req->async_id];
|
||||
|
||||
uwsgi_log("get function %d\n", ifunc);
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ifunc);
|
||||
|
||||
for(i=0;i<argc;i++) {
|
||||
lua_pushstring(L, argv[i]);
|
||||
}
|
||||
|
||||
if (lua_pcall(L, argc, 1, 0) != 0) {
|
||||
uwsgi_log("error running function `f': %s", lua_tostring(L, -1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
sv = lua_tolstring(L, -1, &sl);
|
||||
|
||||
uwsgi_log("sv = %s sl = %d\n", sv, sl);
|
||||
if (sl <= 0xffff) {
|
||||
memcpy(buffer, sv, sl);
|
||||
return sl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_after_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req) {
|
||||
|
||||
if (uwsgi->shared->options[UWSGI_OPTION_LOGGING])
|
||||
log_request(wsgi_req);
|
||||
}
|
||||
struct uwsgi_plugin lua_plugin = {
|
||||
|
||||
.name = "lua",
|
||||
.modifier1 = 6,
|
||||
.init = uwsgi_lua_init,
|
||||
.options = uwsgi_lua_options,
|
||||
.manage_opt = uwsgi_lua_manage_options,
|
||||
.request = uwsgi_lua_request,
|
||||
.after_request = uwsgi_lua_after_request,
|
||||
.init_apps = uwsgi_lua_app,
|
||||
.magic = uwsgi_lua_magic,
|
||||
.signal_handler = uwsgi_lua_signal_handler,
|
||||
.rpc = uwsgi_lua_rpc,
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
import os,sys
|
||||
|
||||
try:
|
||||
LUALIB = os.environ['UWSGICONFIG_LUALIB']
|
||||
except:
|
||||
LUALIB = 'lua'
|
||||
|
||||
try:
|
||||
LUAINC = os.environ['UWSGICONFIG_LUAINC']
|
||||
except:
|
||||
LUAINC = '/usr/include/lua5.1'
|
||||
|
||||
try:
|
||||
LUALIBPATH = os.environ['UWSGICONFIG_LUALIBPATH']
|
||||
except:
|
||||
LUALIBPATH = '/usr/lib/lua5.1'
|
||||
|
||||
NAME='lua'
|
||||
CFLAGS = '-I /usr/include/lua5.1'
|
||||
LDFLAGS = '-llua5.1'
|
||||
CFLAGS = ['-I%s' % LUAINC]
|
||||
LDFLAGS = ['-L%s' % LUALIBPATH]
|
||||
GCC_LIST = ['lua_plugin']
|
||||
LIBS = ['-l%s' % LUALIB]
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
struct uwsgi_mono {
|
||||
|
||||
char *assembly_name ;
|
||||
|
||||
} um;
|
||||
|
||||
int uwsgi_mono_init() {
|
||||
|
||||
|
||||
MonoDomain *domain;
|
||||
|
||||
MonoAssembly *assembly;
|
||||
MonoImage *image, *corlib;
|
||||
|
||||
domain = mono_jit_init("uwsgi");
|
||||
|
||||
corlib = mono_get_corlib();
|
||||
if (!corlib) {
|
||||
uwsgi_log("unable to initialize MONO engine\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
image = mono_assembly_get_image(assembly);
|
||||
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_plugin mono_plugin = {
|
||||
|
||||
.name = "mono",
|
||||
.init = uwsgi_mono_init,
|
||||
};
|
||||
@@ -0,0 +1,88 @@
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
int use_nagios = 0;
|
||||
|
||||
#define LONG_ARGS_NAGIOS 40000
|
||||
|
||||
struct option nagios_options[] = {
|
||||
|
||||
{"nagios", no_argument, 0, LONG_ARGS_NAGIOS},
|
||||
{0, 0, 0, 0},
|
||||
|
||||
};
|
||||
|
||||
|
||||
int nagios() {
|
||||
|
||||
char *tcp_port;
|
||||
struct pollfd nagios_poll;
|
||||
// connect and send
|
||||
|
||||
if (!use_nagios) {
|
||||
return 1;
|
||||
}
|
||||
if (uwsgi.sockets[0].name == NULL) {
|
||||
fprintf(stdout, "UWSGI UNKNOWN: you have specified an invalid socket\n");
|
||||
exit(3);
|
||||
}
|
||||
tcp_port = strchr(uwsgi.sockets[0].name, ':');
|
||||
if (tcp_port == NULL) {
|
||||
fprintf(stdout, "UWSGI UNKNOWN: you have specified an invalid socket\n");
|
||||
exit(3);
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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)) {
|
||||
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);
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
fprintf(stdout, "UWSGI OK: armed and ready\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
// never here
|
||||
fprintf(stdout, "UWSGI UNKNOWN: probably you hit a bug of uWSGI !!!\n");
|
||||
exit(3);
|
||||
}
|
||||
|
||||
int nagios_opt(int i, char *optarg) {
|
||||
|
||||
switch(i) {
|
||||
case LONG_ARGS_NAGIOS:
|
||||
uwsgi.no_initial_output = 1;
|
||||
use_nagios = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct uwsgi_plugin nagios_plugin = {
|
||||
|
||||
.options = nagios_options,
|
||||
.manage_opt = nagios_opt,
|
||||
.init = nagios,
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
NAME='nagios'
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
|
||||
GCC_LIST = ['nagios']
|
||||
@@ -0,0 +1,113 @@
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_ping {
|
||||
char *ping;
|
||||
int ping_timeout;
|
||||
} uping;
|
||||
|
||||
struct option uwsgi_ping_options[] = {
|
||||
{"ping", required_argument, 0, LONG_ARGS_PING},
|
||||
{"ping-timeout", required_argument, 0, LONG_ARGS_PING_TIMEOUT},
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
static void ping() {
|
||||
|
||||
struct uwsgi_header uh;
|
||||
struct pollfd uwsgi_poll;
|
||||
|
||||
// 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) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uh.modifier1 = UWSGI_MODIFIER_PING;
|
||||
uh.pktsize = 0;
|
||||
uh.modifier2 = 0;
|
||||
if (write(uwsgi_poll.fd, &uh, 4) != 4) {
|
||||
uwsgi_error("write()");
|
||||
exit(2);
|
||||
}
|
||||
uwsgi_poll.events = POLLIN;
|
||||
if (!uwsgi_parse_response(&uwsgi_poll, uping.ping_timeout, &uh, NULL)) {
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
if (uh.pktsize > 0) {
|
||||
exit(2);
|
||||
}
|
||||
else {
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int ping_init() {
|
||||
|
||||
if (uping.ping) {
|
||||
ping();
|
||||
//never here
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* uwsgi PING|100 */
|
||||
int uwsgi_request_ping(struct wsgi_request *wsgi_req) {
|
||||
char len;
|
||||
|
||||
uwsgi_log( "PING\n");
|
||||
wsgi_req->uh.modifier2 = 1;
|
||||
wsgi_req->uh.pktsize = 0;
|
||||
|
||||
len = strlen(uwsgi.shared->warning_message);
|
||||
if (len > 0) {
|
||||
// TODO: check endianess ?
|
||||
wsgi_req->uh.pktsize = len;
|
||||
}
|
||||
if (write(wsgi_req->poll.fd, wsgi_req, 4) != 4) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
if (write(wsgi_req->poll.fd, uwsgi.shared->warning_message, len)
|
||||
!= len) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
}
|
||||
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
int uwsgi_ping_manage_options(int i, char *optarg) {
|
||||
|
||||
switch(i) {
|
||||
case LONG_ARGS_PING:
|
||||
uping.ping = optarg;
|
||||
return 1;
|
||||
case LONG_ARGS_PING_TIMEOUT:
|
||||
uping.ping_timeout = atoi(optarg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct uwsgi_plugin ping_plugin = {
|
||||
|
||||
.name = "ping",
|
||||
.modifier1 = 100,
|
||||
.options = uwsgi_ping_options,
|
||||
.manage_opt = uwsgi_ping_manage_options,
|
||||
.request = uwsgi_request_ping,
|
||||
.init = ping_init,
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
NAME='ping'
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
GCC_LIST = ['ping_plugin']
|
||||
+116
-32
@@ -1,18 +1,33 @@
|
||||
#ifdef UWSGI_PROXY
|
||||
/*
|
||||
|
||||
/*
|
||||
uWSGI proxy
|
||||
|
||||
uWSGI proxy
|
||||
it needs one of this tecnology to work:
|
||||
|
||||
it needs one of this tecnology to work:
|
||||
|
||||
- epoll (linux 2.6)
|
||||
- kqueue (various BSD and Darwin)
|
||||
- /dev/poll (Solaris)
|
||||
- epoll (linux 2.6)
|
||||
- kqueue (various BSD and Darwin)
|
||||
- /dev/poll (Solaris)
|
||||
|
||||
*/
|
||||
|
||||
#include "uwsgi.h"
|
||||
#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
|
||||
@@ -38,7 +53,6 @@ static void reload_proxy(void) {
|
||||
|
||||
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;
|
||||
@@ -60,11 +74,9 @@ static void uwsgi_proxy_close(struct uwsgi_proxy_connection *upcs, int fd) {
|
||||
uwsgi.shared->nodes[upcs[fd].node].connections--;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int uwsgi_proxy_find_next_node(int current_node) {
|
||||
|
||||
int i;
|
||||
|
||||
current_node++;
|
||||
@@ -99,12 +111,11 @@ static int uwsgi_proxy_find_next_node(int current_node) {
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_proxy(int proxyfd) {
|
||||
void proxy_loop() {
|
||||
|
||||
int efd ;
|
||||
int efd;
|
||||
|
||||
#ifdef __linux__
|
||||
struct epoll_event *eevents;
|
||||
@@ -139,9 +150,9 @@ void uwsgi_proxy(int proxyfd) {
|
||||
|
||||
int next_node = -1;
|
||||
|
||||
uwsgi_log( "spawned uWSGI proxy (pid: %d)\n", getpid());
|
||||
|
||||
#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);
|
||||
@@ -151,21 +162,24 @@ void uwsgi_proxy(int proxyfd) {
|
||||
}
|
||||
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(proxyfd);
|
||||
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));
|
||||
memset(&ev, 0, sizeof(struct epoll_event));
|
||||
#elif defined(__sun)
|
||||
eevents = malloc(sizeof(struct pollfd) * max_events);
|
||||
memset(&ev, 0, sizeof(struct pollfd));
|
||||
memset(&ev, 0, sizeof(struct pollfd));
|
||||
#else
|
||||
eevents = malloc(sizeof(struct kevent) * max_events);
|
||||
memset(&ev, 0, sizeof(struct kevent));
|
||||
memset(&ev, 0, sizeof(struct kevent));
|
||||
#endif
|
||||
|
||||
if (!eevents) {
|
||||
@@ -188,13 +202,12 @@ void uwsgi_proxy(int proxyfd) {
|
||||
|
||||
for (i = 0; i < nevents; i++) {
|
||||
|
||||
|
||||
if (eevents[i].ASYNC_FD == proxyfd) {
|
||||
if ( (int)eevents[i].ASYNC_FD == uproxy.fd) {
|
||||
|
||||
if (eevents[i].ASYNC_IS_IN) {
|
||||
// new connection, accept it
|
||||
ev.ASYNC_FD = accept(proxyfd, (struct sockaddr *) &upc_addr, &upc_len);
|
||||
if (ev.ASYNC_FD < 0) {
|
||||
ev.ASYNC_FD = accept(uproxy.fd, (struct sockaddr *) &upc_addr, &upc_len);
|
||||
if ( (int) ev.ASYNC_FD < 0) {
|
||||
uwsgi_error("accept()");
|
||||
continue;
|
||||
}
|
||||
@@ -342,8 +355,13 @@ void uwsgi_proxy(int proxyfd) {
|
||||
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);
|
||||
uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].errors++;
|
||||
uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].status = UWSGI_NODE_FAILED;
|
||||
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;
|
||||
}
|
||||
@@ -387,8 +405,13 @@ void uwsgi_proxy(int proxyfd) {
|
||||
|
||||
// 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);
|
||||
uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].errors++;
|
||||
uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].status = UWSGI_NODE_FAILED;
|
||||
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);
|
||||
@@ -401,6 +424,67 @@ void uwsgi_proxy(int proxyfd) {
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#warning "*** PROXY support is disabled ***"
|
||||
#endif
|
||||
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,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
NAME='proxy'
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
|
||||
GCC_LIST = ['proxy']
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
#include <EXTERN.h>
|
||||
#include <perl.h>
|
||||
#include "XSUB.h"
|
||||
|
||||
|
||||
struct uwsgi_perl {
|
||||
|
||||
int fd;
|
||||
char *psgibuffer;
|
||||
char *psgi;
|
||||
PerlInterpreter *main;
|
||||
pthread_key_t u_interpreter;
|
||||
PerlInterpreter **interp;
|
||||
SV *psgi_main;
|
||||
SV **psgi_func;
|
||||
CV *stream_responder;
|
||||
|
||||
};
|
||||
|
||||
#define LONG_ARGS_PERL_BASE 17000 + ((5 + 1) * 100)
|
||||
#define LONG_ARGS_PSGI LONG_ARGS_PERL_BASE + 1
|
||||
|
||||
void init_perl_embedded_module(void);
|
||||
int psgi_response(struct wsgi_request *, PerlInterpreter *, AV*);
|
||||
+297
-250
@@ -1,59 +1,38 @@
|
||||
#include <uwsgi.h>
|
||||
#include "psgi.h"
|
||||
|
||||
#include <EXTERN.h>
|
||||
#include <perl.h>
|
||||
extern char **environ;
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
static PerlInterpreter *my_perl;
|
||||
static SV *psgi_func ;
|
||||
struct uwsgi_perl uperl;
|
||||
|
||||
/* statistically ordered */
|
||||
static struct http_status_codes hsc[] = {
|
||||
struct option uwsgi_perl_options[] = {
|
||||
|
||||
{"200", "OK"},
|
||||
{"302", "Found"},
|
||||
{"404", "Not Found"},
|
||||
{"500", "Internal Server Error"},
|
||||
{"301", "Moved Permanently"},
|
||||
{"304", "Not Modified"},
|
||||
{"303", "See Other"},
|
||||
{"403", "Forbidden"},
|
||||
{"307", "Temporary Redirect"},
|
||||
{"401", "Unauthorized"},
|
||||
{"400", "Bad Request"},
|
||||
{"405", "Method Not Allowed"},
|
||||
{"408", "Request Timeout"},
|
||||
{"psgi", required_argument, 0, LONG_ARGS_PSGI},
|
||||
{0, 0, 0, 0},
|
||||
|
||||
{"100", "Continue"},
|
||||
{"101", "Switching Protocols"},
|
||||
{"201", "Created"},
|
||||
{"202", "Accepted"},
|
||||
{"203", "Non-Authoritative Information"},
|
||||
{"204", "No Content"},
|
||||
{"205", "Reset Content"},
|
||||
{"206", "Partial Content"},
|
||||
{"300", "Multiple Choices"},
|
||||
{"305", "Use Proxy"},
|
||||
{"402", "Payment Required"},
|
||||
{"406", "Not Acceptable"},
|
||||
{"407", "Proxy Authentication Required"},
|
||||
{"409", "Conflict"},
|
||||
{"410", "Gone"},
|
||||
{"411", "Length Required"},
|
||||
{"412", "Precondition Failed"},
|
||||
{"413", "Request Entity Too Large"},
|
||||
{"414", "Request-URI Too Long"},
|
||||
{"415", "Unsupported Media Type"},
|
||||
{"416", "Requested Range Not Satisfiable"},
|
||||
{"417", "Expectation Failed"},
|
||||
{"501", "Not Implemented"},
|
||||
{"502", "Bad Gateway"},
|
||||
{"503", "Service Unavailable"},
|
||||
{"504", "Gateway Timeout"},
|
||||
{"505", "HTTP Version Not Supported"},
|
||||
{ "", NULL },
|
||||
};
|
||||
|
||||
extern struct http_status_codes hsc[];
|
||||
|
||||
XS(XS_stream)
|
||||
{
|
||||
dXSARGS;
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
SV *stack;
|
||||
AV *response;
|
||||
|
||||
uwsgi_log("args: %d %p\n", items, wsgi_req);
|
||||
stack = ST(0);
|
||||
uwsgi_log("type %d\n", SvTYPE(stack));
|
||||
response = (AV* ) SvRV(stack) ;
|
||||
|
||||
|
||||
psgi_response(wsgi_req, my_perl, response);
|
||||
|
||||
//mXPUSHp("x", 1);
|
||||
XSRETURN(0);
|
||||
|
||||
}
|
||||
|
||||
/* automatically generated */
|
||||
|
||||
@@ -61,191 +40,266 @@ EXTERN_C void xs_init (pTHX);
|
||||
|
||||
EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);
|
||||
|
||||
EXTERN_C void
|
||||
EXTERN_C void
|
||||
xs_init(pTHX)
|
||||
{
|
||||
char *file = __FILE__;
|
||||
dXSUB_SYS;
|
||||
char *file = __FILE__;
|
||||
dXSUB_SYS;
|
||||
|
||||
/* DynaLoader is a special case */
|
||||
newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
|
||||
/* DynaLoader is a special case */
|
||||
newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
|
||||
|
||||
uperl.stream_responder = newXS("uwsgi::stream", XS_stream, "uwsgi");
|
||||
|
||||
#ifdef UWSGI_EMBEDDED
|
||||
init_perl_embedded_module();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* end of automagically generated part */
|
||||
|
||||
|
||||
int uwsgi_init(struct uwsgi_server *uwsgi, char *args){
|
||||
|
||||
char *pargs[2] ;
|
||||
char *psgibuffer ;
|
||||
int fd ;
|
||||
|
||||
struct stat stat_psgi;
|
||||
|
||||
struct http_status_codes *http_sc ;
|
||||
|
||||
char *embedding[] = { "", "-e", "0" };
|
||||
int uwsgi_perl_init(){
|
||||
|
||||
|
||||
fprintf(stderr,"initializing Perl environment: %s\n", args);
|
||||
struct http_status_codes *http_sc;
|
||||
|
||||
my_perl = perl_alloc();
|
||||
if (!my_perl) {
|
||||
fprintf(stderr,"unable to allocate perl interpreter\n");
|
||||
int argc = 4;
|
||||
char *embedding[] = { "", "-e", "-e", "0" };
|
||||
|
||||
uwsgi_log("initializing Perl environment\n");
|
||||
PERL_SYS_INIT3(&argc, (char ***) &embedding, &environ);
|
||||
uperl.main = perl_alloc();
|
||||
if (!uperl.main) {
|
||||
uwsgi_log("unable to allocate perl interpreter\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pargs[0] = "" ;
|
||||
pargs[1] = args ;
|
||||
dTHXa(uperl.main);
|
||||
PERL_SET_CONTEXT(uperl.main);
|
||||
|
||||
perl_construct(my_perl);
|
||||
PL_perl_destruct_level = 2;
|
||||
perl_construct(uperl.main);
|
||||
|
||||
// filling http status codes
|
||||
for (http_sc = hsc; http_sc->message != NULL; http_sc++) {
|
||||
http_sc->message_size = strlen(http_sc->message);
|
||||
}
|
||||
|
||||
|
||||
perl_parse(my_perl, xs_init, 3, embedding, NULL);
|
||||
PL_origalen = 1;
|
||||
perl_parse(uperl.main, xs_init, 4, embedding, NULL);
|
||||
|
||||
perl_eval_pv("use IO::Handle;", 0);
|
||||
|
||||
fd = open(args, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("open()");
|
||||
goto clear ;
|
||||
}
|
||||
|
||||
if (fstat(fd, &stat_psgi)) {
|
||||
perror("fstat()");
|
||||
close(fd);
|
||||
goto clear;
|
||||
}
|
||||
|
||||
psgibuffer = malloc(stat_psgi.st_size);
|
||||
if (!psgibuffer) {
|
||||
perror("malloc()");
|
||||
close(fd);
|
||||
goto clear;
|
||||
}
|
||||
|
||||
if (read(fd, psgibuffer, stat_psgi.st_size) != stat_psgi.st_size) {
|
||||
perror("read()");
|
||||
close(fd);
|
||||
free(psgibuffer);
|
||||
goto clear;
|
||||
}
|
||||
|
||||
psgibuffer[stat_psgi.st_size] = 0 ;
|
||||
|
||||
psgi_func = perl_eval_pv(psgibuffer, 0);
|
||||
if (!psgi_func) {
|
||||
fprintf(stderr,"unable to find PSGI function entry point.\n");
|
||||
close(fd);
|
||||
free(psgibuffer);
|
||||
goto clear;
|
||||
}
|
||||
|
||||
free(psgibuffer);
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
|
||||
clear:
|
||||
perl_destruct(my_perl);
|
||||
perl_free(my_perl);
|
||||
return -1;
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req) {
|
||||
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()");
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_perl_enable_threads() {
|
||||
|
||||
HV *env ;
|
||||
SV **item ;
|
||||
int i;
|
||||
|
||||
if (pthread_key_create(&uperl.u_interpreter, NULL)) {
|
||||
uwsgi_error("pthread_key_create()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uperl.interp = malloc( sizeof(PerlInterpreter*) * uwsgi.threads );
|
||||
if (!uperl.interp) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for(i=1;i<uwsgi.threads;i++) {
|
||||
uperl.interp[i] = perl_clone(uperl.main, CLONEf_KEEP_PTR_TABLE);
|
||||
if (!uperl.interp[i]) {
|
||||
uwsgi_log("unable to create new perl interpreter\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
uperl.psgi_func = malloc( sizeof(SV*) * uwsgi.threads );
|
||||
if (!uperl.psgi_func) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
AV *response, *headers, *body ;
|
||||
|
||||
SV **status_code, **hitem, *io_new, *io_err, *io, *chunk;
|
||||
char *chitem ;
|
||||
STRLEN hlen ;
|
||||
dTHXa(uperl.main);
|
||||
PERL_SET_CONTEXT(uperl.main);
|
||||
|
||||
struct http_status_codes *http_sc;
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int uwsgi_perl_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
HV *env;
|
||||
SV **item;
|
||||
|
||||
AV *response;
|
||||
|
||||
SV *io_new, *io_err;
|
||||
int i;
|
||||
|
||||
SV *psgi_func = uperl.psgi_main;
|
||||
// ugly hack
|
||||
register PerlInterpreter *my_perl = uperl.main;
|
||||
dSP;
|
||||
|
||||
int i,vi, base ;
|
||||
|
||||
/* Standard PSGI request */
|
||||
if (!wsgi_req->uh.pktsize) {
|
||||
fprintf (stderr, "Invalid PSGI request. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (uwsgi_parse_vars(uwsgi, wsgi_req)) {
|
||||
fprintf(stderr,"Invalid PSGI request. skip.\n");
|
||||
if (!wsgi_req->uh.pktsize) {
|
||||
uwsgi_log("Invalid PSGI request. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
dSP;
|
||||
if (uwsgi_parse_vars(wsgi_req)) {
|
||||
uwsgi_log("Invalid PSGI request. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef UWSGI_THREADING
|
||||
if (uwsgi.threads > 1 && wsgi_req->async_id > 0) {
|
||||
psgi_func = uperl.psgi_func[wsgi_req->async_id];
|
||||
my_perl = pthread_getspecific(uperl.u_interpreter);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
ENTER;
|
||||
SAVETMPS;
|
||||
|
||||
|
||||
env = (HV*)sv_2mortal((SV*)newHV());
|
||||
env = (HV*) sv_2mortal((SV*)newHV());
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
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);
|
||||
}
|
||||
else {
|
||||
item = hv_store(env, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, newSVpv("", 0), 0);
|
||||
}
|
||||
//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++;
|
||||
}
|
||||
|
||||
item = hv_store(env, "psgi.url_scheme", 15, newSVpv("http", 4), 0);
|
||||
|
||||
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( newSVpv( "IO::Handle", 10 )));
|
||||
XPUSHs( sv_2mortal(iohandle));
|
||||
PUTBACK;
|
||||
perl_call_method( "new", G_SCALAR);
|
||||
SPAGAIN;
|
||||
io_new = newSVsv(POPs);
|
||||
|
||||
io_new = POPs;
|
||||
|
||||
PUSHMARK(SP);
|
||||
XPUSHs( sv_2mortal(io_new) );
|
||||
XPUSHs( sv_2mortal( newSViv( wsgi_req->poll.fd)));
|
||||
XPUSHs( sv_2mortal( newSVpv( "r", 1)));
|
||||
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;
|
||||
|
||||
|
||||
item = hv_store(env, "psgi.input", 10, newSVsv(POPs), 0);
|
||||
|
||||
|
||||
SV *pi = SvREFCNT_inc(POPs);
|
||||
item = hv_store(env, "psgi.input", 10, pi, 0);
|
||||
|
||||
|
||||
PUSHMARK(SP);
|
||||
XPUSHs( sv_2mortal( newSVpv( "IO::Handle", 10 )));
|
||||
XPUSHs( newSVpv( "IO::Handle", 10 ));
|
||||
PUTBACK;
|
||||
perl_call_method( "new", G_SCALAR);
|
||||
SPAGAIN;
|
||||
io_err = newSVsv(POPs);
|
||||
io_err = POPs;
|
||||
|
||||
PUSHMARK(SP);
|
||||
XPUSHs( sv_2mortal(io_err) );
|
||||
XPUSHs( io_err );
|
||||
XPUSHs( sv_2mortal( newSViv( 2 )));
|
||||
XPUSHs( sv_2mortal( newSVpv( "w", 1)));
|
||||
PUTBACK;
|
||||
perl_call_method( "fdopen", G_SCALAR);
|
||||
SPAGAIN;
|
||||
|
||||
|
||||
item = hv_store(env, "psgi.errors", 11, newSVsv(POPs), 0);
|
||||
SV *pe = SvREFCNT_inc(POPs);
|
||||
item = hv_store(env, "psgi.errors", 11, pe, 0);
|
||||
|
||||
|
||||
PUSHMARK(SP);
|
||||
@@ -254,113 +308,40 @@ int uwsgi_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req) {
|
||||
|
||||
|
||||
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( sv_2mortal(newSVsv(POPs)) ) ;
|
||||
response = (AV *) SvRV( POPs );
|
||||
|
||||
//uwsgi_log("response: %p %d\n", response, SvTYPE(response));
|
||||
|
||||
status_code = av_fetch(response, 0, 0);
|
||||
if (SvTYPE(response) == SVt_PVCV) {
|
||||
uwsgi_log("streaming response\n");
|
||||
|
||||
PUSHMARK(SP);
|
||||
XPUSHs( newRV((SV*) uperl.stream_responder));
|
||||
PUTBACK;
|
||||
|
||||
wsgi_req->hvec[0].iov_base = "HTTP/1.1 ";
|
||||
wsgi_req->hvec[0].iov_len = 9 ;
|
||||
perl_call_sv( (SV*)response, G_SCALAR);
|
||||
|
||||
wsgi_req->hvec[1].iov_base = SvPV(*status_code, hlen);
|
||||
wsgi_req->hvec[1].iov_len = 3 ;
|
||||
|
||||
wsgi_req->hvec[2].iov_base = " ";
|
||||
wsgi_req->hvec[2].iov_len = 1 ;
|
||||
|
||||
wsgi_req->hvec[3].iov_len = 0 ;
|
||||
|
||||
// get the status code
|
||||
for (http_sc = hsc; http_sc->message != NULL; http_sc++) {
|
||||
if (!strncmp(http_sc->key, wsgi_req->hvec[1].iov_base, 3)) {
|
||||
wsgi_req->hvec[3].iov_base = http_sc->message ;
|
||||
wsgi_req->hvec[3].iov_len = http_sc->message_size ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (wsgi_req->hvec[3].iov_len == 0) {
|
||||
wsgi_req->hvec[3].iov_base = "Unknown" ;
|
||||
wsgi_req->hvec[3].iov_len = 7;
|
||||
}
|
||||
|
||||
wsgi_req->hvec[4].iov_base = "\r\n";
|
||||
wsgi_req->hvec[4].iov_len = 2 ;
|
||||
|
||||
hitem = av_fetch(response, 1, 0) ;
|
||||
|
||||
headers = (AV *) SvRV(*hitem);
|
||||
|
||||
base = 5 ;
|
||||
|
||||
// put them in hvec
|
||||
for(i=0; i<=av_len(headers); i++) {
|
||||
|
||||
vi = (i*2)+base ;
|
||||
hitem = av_fetch(headers,i,0);
|
||||
chitem = SvPV(*hitem, hlen);
|
||||
wsgi_req->hvec[vi].iov_base = chitem ; wsgi_req->hvec[vi].iov_len = hlen ;
|
||||
|
||||
wsgi_req->hvec[vi+1].iov_base = ": " ; wsgi_req->hvec[vi+1].iov_len = 2 ;
|
||||
|
||||
hitem = av_fetch(headers,i+1,0);
|
||||
chitem = SvPV(*hitem, hlen);
|
||||
wsgi_req->hvec[vi+2].iov_base = chitem ; wsgi_req->hvec[vi+2].iov_len = hlen ;
|
||||
|
||||
wsgi_req->hvec[vi+3].iov_base = "\r\n" ; wsgi_req->hvec[vi+3].iov_len = 2 ;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
vi = (i*2)+base ;
|
||||
wsgi_req->hvec[vi].iov_base = "\r\n" ; wsgi_req->hvec[vi].iov_len = 2 ;
|
||||
|
||||
|
||||
if ( (wsgi_req->response_size = writev(wsgi_req->poll.fd, wsgi_req->hvec, vi+1)) < 0) {
|
||||
perror("writev()");
|
||||
}
|
||||
|
||||
|
||||
hitem = av_fetch(response, 2, 0) ;
|
||||
|
||||
io = *hitem;
|
||||
|
||||
|
||||
if (SvTYPE(SvRV(io)) == SVt_PVGV) {
|
||||
|
||||
for(;;) {
|
||||
|
||||
PUSHMARK(SP);
|
||||
XPUSHs(io) ;
|
||||
PUTBACK;
|
||||
perl_call_method("getline", G_SCALAR);
|
||||
SPAGAIN;
|
||||
chunk = sv_2mortal(newSVsv(POPs));
|
||||
|
||||
chitem = SvPV(chunk, hlen);
|
||||
if (hlen <= 0) {
|
||||
break;
|
||||
}
|
||||
wsgi_req->response_size += write(wsgi_req->poll.fd, chitem, hlen);
|
||||
if(SvTRUE(ERRSV)) {
|
||||
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
|
||||
}
|
||||
|
||||
|
||||
goto clear;
|
||||
}
|
||||
else if (SvTYPE(SvRV(io)) == SVt_PVAV) {
|
||||
|
||||
body = (AV *) SvRV(io);
|
||||
psgi_response(wsgi_req, my_perl, response);
|
||||
|
||||
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);
|
||||
}
|
||||
clear:
|
||||
|
||||
}
|
||||
|
||||
FREETMPS;
|
||||
LEAVE;
|
||||
|
||||
@@ -368,8 +349,74 @@ int uwsgi_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_after_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req) {
|
||||
void uwsgi_perl_after_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
if (uwsgi->shared->options[UWSGI_OPTION_LOGGING])
|
||||
log_request(wsgi_req);
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_LOGGING])
|
||||
log_request(wsgi_req);
|
||||
}
|
||||
|
||||
void uwsgi_perl_init_thread(int core_id) {
|
||||
|
||||
|
||||
pthread_setspecific(uperl.u_interpreter, uperl.interp[core_id]);
|
||||
dTHXa(uperl.interp[core_id]);
|
||||
PERL_SET_CONTEXT(uperl.interp[core_id]);
|
||||
|
||||
uperl.psgi_func[core_id] = perl_eval_pv(uperl.psgibuffer, 0);
|
||||
if (!uperl.psgi_func[core_id]) {
|
||||
uwsgi_log("unable to find PSGI function entry point.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(SvTRUE(ERRSV)) {
|
||||
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_perl_manage_options(int i, char *optarg) {
|
||||
|
||||
switch(i) {
|
||||
case LONG_ARGS_PSGI:
|
||||
uperl.psgi = optarg;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_perl_magic(char *mountpoint, char *lazy) {
|
||||
|
||||
if (!strcmp(lazy+strlen(lazy)-5, ".psgi")) {
|
||||
uperl.psgi = lazy;
|
||||
return 1;
|
||||
}
|
||||
else if (!strcmp(lazy+strlen(lazy)-3, ".pl")) {
|
||||
uperl.psgi = lazy;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_plugin psgi_plugin = {
|
||||
|
||||
.name = "psgi",
|
||||
.modifier1 = 5,
|
||||
.init = uwsgi_perl_init,
|
||||
.options = uwsgi_perl_options,
|
||||
.init_apps = uwsgi_psgi_app,
|
||||
//.magic = uwsgi_perl_magic,
|
||||
//.help = uwsgi_perl_help,
|
||||
.enable_threads = uwsgi_perl_enable_threads,
|
||||
.manage_opt = uwsgi_perl_manage_options,
|
||||
.init_thread = uwsgi_perl_init_thread,
|
||||
.request = uwsgi_perl_request,
|
||||
.after_request = uwsgi_perl_after_request,
|
||||
|
||||
.magic = uwsgi_perl_magic,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
#include "psgi.h"
|
||||
|
||||
/* statistically ordered */
|
||||
struct http_status_codes hsc[] = {
|
||||
{"200", "OK"},
|
||||
{"302", "Found"},
|
||||
{"404", "Not Found"},
|
||||
{"500", "Internal Server Error"},
|
||||
{"301", "Moved Permanently"},
|
||||
{"304", "Not Modified"},
|
||||
{"303", "See Other"},
|
||||
{"403", "Forbidden"},
|
||||
{"307", "Temporary Redirect"},
|
||||
{"401", "Unauthorized"},
|
||||
{"400", "Bad Request"},
|
||||
{"405", "Method Not Allowed"},
|
||||
{"408", "Request Timeout"},
|
||||
|
||||
{"100", "Continue"},
|
||||
{"101", "Switching Protocols"},
|
||||
{"201", "Created"},
|
||||
{"202", "Accepted"},
|
||||
{"203", "Non-Authoritative Information"},
|
||||
{"204", "No Content"},
|
||||
{"205", "Reset Content"},
|
||||
{"206", "Partial Content"},
|
||||
{"300", "Multiple Choices"},
|
||||
{"305", "Use Proxy"},
|
||||
{"402", "Payment Required"},
|
||||
{"406", "Not Acceptable"},
|
||||
{"407", "Proxy Authentication Required"},
|
||||
{"409", "Conflict"},
|
||||
{"410", "Gone"},
|
||||
{"411", "Length Required"},
|
||||
{"412", "Precondition Failed"},
|
||||
{"413", "Request Entity Too Large"},
|
||||
{"414", "Request-URI Too Long"},
|
||||
{"415", "Unsupported Media Type"},
|
||||
{"416", "Requested Range Not Satisfiable"},
|
||||
{"417", "Expectation Failed"},
|
||||
{"501", "Not Implemented"},
|
||||
{"502", "Bad Gateway"},
|
||||
{"503", "Service Unavailable"},
|
||||
{"504", "Gateway Timeout"},
|
||||
{"505", "HTTP Version Not Supported"},
|
||||
{ "", NULL },
|
||||
};
|
||||
|
||||
|
||||
int psgi_response(struct wsgi_request *wsgi_req, PerlInterpreter *my_perl, AV *response) {
|
||||
|
||||
SV **status_code, **hitem ;
|
||||
AV *headers, *body =NULL;
|
||||
STRLEN hlen;
|
||||
struct http_status_codes *http_sc;
|
||||
int i,vi, base;
|
||||
char *chitem;
|
||||
dSP;
|
||||
|
||||
status_code = av_fetch(response, 0, 0);
|
||||
|
||||
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);
|
||||
|
||||
wsgi_req->hvec[2].iov_base = " ";
|
||||
wsgi_req->hvec[2].iov_len = 1;
|
||||
|
||||
wsgi_req->hvec[3].iov_len = 0;
|
||||
|
||||
// get the status code
|
||||
for (http_sc = hsc; http_sc->message != NULL; http_sc++) {
|
||||
if (!strncmp(http_sc->key, wsgi_req->hvec[1].iov_base, 3)) {
|
||||
wsgi_req->hvec[3].iov_base = (char *) http_sc->message;
|
||||
wsgi_req->hvec[3].iov_len = http_sc->message_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (wsgi_req->hvec[3].iov_len == 0) {
|
||||
wsgi_req->hvec[3].iov_base = "Unknown";
|
||||
wsgi_req->hvec[3].iov_len = 7;
|
||||
}
|
||||
|
||||
wsgi_req->hvec[4].iov_base = "\r\n";
|
||||
wsgi_req->hvec[4].iov_len = 2;
|
||||
|
||||
hitem = av_fetch(response, 1, 0);
|
||||
|
||||
headers = (AV *) SvRV(*hitem);
|
||||
|
||||
base = 5;
|
||||
|
||||
|
||||
// put them in hvec
|
||||
for(i=0; i<=av_len(headers); i++) {
|
||||
|
||||
vi = (i*2)+base;
|
||||
hitem = av_fetch(headers,i,0);
|
||||
chitem = SvPV(*hitem, hlen);
|
||||
wsgi_req->hvec[vi].iov_base = chitem; wsgi_req->hvec[vi].iov_len = hlen;
|
||||
|
||||
wsgi_req->hvec[vi+1].iov_base = ": "; wsgi_req->hvec[vi+1].iov_len = 2;
|
||||
|
||||
hitem = av_fetch(headers,i+1,0);
|
||||
chitem = SvPV(*hitem, hlen);
|
||||
wsgi_req->hvec[vi+2].iov_base = chitem; wsgi_req->hvec[vi+2].iov_len = hlen;
|
||||
|
||||
wsgi_req->hvec[vi+3].iov_base = "\r\n"; wsgi_req->hvec[vi+3].iov_len = 2;
|
||||
|
||||
wsgi_req->header_cnt++;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
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)) ) {
|
||||
uwsgi_error("writev()");
|
||||
}
|
||||
|
||||
hitem = av_fetch(response, 2, 0);
|
||||
|
||||
if (SvTYPE(SvRV(*hitem)) == SVt_PVGV || SvTYPE(SvRV(*hitem)) == SVt_PVHV) {
|
||||
|
||||
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;
|
||||
chitem = SvPV( chunk, hlen);
|
||||
if (hlen <= 0) {
|
||||
break;
|
||||
}
|
||||
wsgi_req->response_size = write(wsgi_req->poll.fd, chitem, hlen);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else if (SvTYPE(SvRV(*hitem)) == SVt_PVAV) {
|
||||
|
||||
body = (AV *) SvRV(*hitem);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
uwsgi_log("unsupported response body type: %d\n", SvTYPE(SvRV(*hitem)));
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
#include "psgi.h"
|
||||
|
||||
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)
|
||||
|
||||
XS(XS_reload) {
|
||||
dXSARGS;
|
||||
items = 0;
|
||||
|
||||
uwsgi_log("SENDING HUP TO %d\n", (int) uwsgi.workers[0].pid);
|
||||
if (kill(uwsgi.workers[0].pid, SIGHUP)) {
|
||||
uwsgi_error("kill()");
|
||||
XSRETURN_NO;
|
||||
}
|
||||
XSRETURN_YES;
|
||||
}
|
||||
|
||||
XS(XS_cache_set) {
|
||||
dXSARGS;
|
||||
|
||||
char *key, *val;
|
||||
STRLEN keylen;
|
||||
STRLEN vallen;
|
||||
|
||||
psgi_check_args(2);
|
||||
|
||||
key = SvPV(ST(0), keylen);
|
||||
val = SvPV(ST(1), vallen);
|
||||
|
||||
uwsgi_cache_set(key, (uint16_t) keylen, val, (uint64_t) vallen, 0, 0);
|
||||
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
|
||||
XS(XS_cache_get) {
|
||||
dXSARGS;
|
||||
|
||||
char *key, *val;
|
||||
STRLEN keylen;
|
||||
uint64_t vallen;
|
||||
|
||||
psgi_check_args(1);
|
||||
|
||||
key = SvPV(ST(0), keylen);
|
||||
|
||||
val = uwsgi_cache_get(key, (uint16_t) keylen, &vallen);
|
||||
|
||||
if (!val)
|
||||
XSRETURN_UNDEF;
|
||||
|
||||
ST(0) = newSVpv(val, vallen);
|
||||
sv_2mortal(ST(0));
|
||||
|
||||
XSRETURN(1);
|
||||
|
||||
}
|
||||
|
||||
XS(XS_call) {
|
||||
|
||||
dXSARGS;
|
||||
|
||||
char buffer[0xffff];
|
||||
char *func;
|
||||
uint16_t size = 0;
|
||||
int i;
|
||||
char *argv[0xff];
|
||||
|
||||
psgi_check_args(1);
|
||||
|
||||
func = SvPV_nolen(ST(0));
|
||||
|
||||
for(i=0;i<(items-1);i++) {
|
||||
argv[i] = SvPV_nolen(ST(i+1));
|
||||
}
|
||||
|
||||
size = uwsgi_rpc(func, items-1, argv, buffer);
|
||||
|
||||
if (size > 0) {
|
||||
ST(0) = newSVpv(buffer, size);
|
||||
sv_2mortal(ST(0));
|
||||
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void init_perl_embedded_module() {
|
||||
psgi_xs(reload);
|
||||
psgi_xs(cache_set);
|
||||
psgi_xs(cache_get);
|
||||
psgi_xs(call);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import os,sys
|
||||
|
||||
NAME='psgi'
|
||||
CFLAGS = os.popen('perl -MExtUtils::Embed -e ccopts').read().rstrip()
|
||||
LDFLAGS = os.popen('perl -MExtUtils::Embed -e ldopts').read().rstrip()
|
||||
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']
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user