mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-10-04 16:08:31 +00:00
Compare commits
985
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d57d5acb30 | ||
|
|
43e6664dd9 | ||
|
|
d0c6dff83e | ||
|
|
54b40f5978 | ||
|
|
1c59c03261 | ||
|
|
ce23fd38ab | ||
|
|
4818efa7de | ||
|
|
ea19e74229 | ||
|
|
fe353de5a8 | ||
|
|
1d89266f2e | ||
|
|
61d79394ca | ||
|
|
491f2828b5 | ||
|
|
431e05d4f4 | ||
|
|
ae6780a487 | ||
|
|
5707a70141 | ||
|
|
e9a7bd7da1 | ||
|
|
91e45daf6c | ||
|
|
9f69998075 | ||
|
|
4f6270976b | ||
|
|
328caa43f2 | ||
|
|
368408374a | ||
|
|
c3a90db493 | ||
|
|
5bc0320877 | ||
|
|
622ed620b9 | ||
|
|
1b859413de | ||
|
|
95432fd8e3 | ||
|
|
b3f3c5d7b3 | ||
|
|
02cef20462 | ||
|
|
3edebe34ae | ||
|
|
28c9b75fb5 | ||
|
|
a2735e10b7 | ||
|
|
e03d26fd63 | ||
|
|
7c4c346e64 | ||
|
|
67b3c0c4a8 | ||
|
|
dadca785e4 | ||
|
|
accebe5597 | ||
|
|
792965bedd | ||
|
|
1bb1bafe0c | ||
|
|
28c11324ca | ||
|
|
42d940c38e | ||
|
|
c1ea05b925 | ||
|
|
9435693865 | ||
|
|
14da582637 | ||
|
|
b2d4a795a1 | ||
|
|
493696705b | ||
|
|
d827c6f09a | ||
|
|
df000b0cb2 | ||
|
|
d9630a32c7 | ||
|
|
71cc6f61bd | ||
|
|
46eb832cc7 | ||
|
|
11b2e4b430 | ||
|
|
11775532ee | ||
|
|
f3388db8ba | ||
|
|
25ac86393f | ||
|
|
b3432a95e1 | ||
|
|
e34d169fa6 | ||
|
|
de84accb7a | ||
|
|
187577cbb5 | ||
|
|
72109b72d2 | ||
|
|
f6c01d11e9 | ||
|
|
d695ef4f57 | ||
|
|
16c6dcc573 | ||
|
|
3df19b286a | ||
|
|
6f1b08762d | ||
|
|
a4a379f9d6 | ||
|
|
3d3d0304bc | ||
|
|
26135018a3 | ||
|
|
4bd381bb99 | ||
|
|
cf08972e82 | ||
|
|
d57a58d1e7 | ||
|
|
f10789965e | ||
|
|
94145bd300 | ||
|
|
cdcb61d10d | ||
|
|
56146a34af | ||
|
|
991e818449 | ||
|
|
80083cba76 | ||
|
|
2c44fd5aa2 | ||
|
|
1561dd38fc | ||
|
|
8152648f66 | ||
|
|
c1507d0381 | ||
|
|
f0fb603af2 | ||
|
|
93e891153f | ||
|
|
26ece717b6 | ||
|
|
93767335ca | ||
|
|
7cbe751a39 | ||
|
|
c45df83f19 | ||
|
|
fabce61a58 | ||
|
|
5c9ccae598 | ||
|
|
6c9d7239f2 | ||
|
|
4b75e2577e | ||
|
|
08c9d942a4 | ||
|
|
3b59b4ad21 | ||
|
|
7682eec52a | ||
|
|
694517bbe7 | ||
|
|
7f443fdd05 | ||
|
|
01ab891c11 | ||
|
|
052aacfd36 | ||
|
|
80a6d2ccfb | ||
|
|
b4ce175bdf | ||
|
|
f6f52d32dc | ||
|
|
865b2de9bb | ||
|
|
4a8233a041 | ||
|
|
f856ad78a3 | ||
|
|
653267cbe6 | ||
|
|
8b53df27ab | ||
|
|
c4b7c2b58c | ||
|
|
66f82f364c | ||
|
|
6d269607d2 | ||
|
|
8370977e5b | ||
|
|
e2c335ff73 | ||
|
|
816b9d0343 | ||
|
|
2922e1ba35 | ||
|
|
c86f341d29 | ||
|
|
73cdd68283 | ||
|
|
81641686bc | ||
|
|
14c58c8e62 | ||
|
|
74b8f2587c | ||
|
|
bebe041061 | ||
|
|
2e5d3d2952 | ||
|
|
c2d155b8ff | ||
|
|
fda368ff08 | ||
|
|
19cf592e77 | ||
|
|
260cac6b59 | ||
|
|
673275e708 | ||
|
|
a6bc778c25 | ||
|
|
ef2f5879b6 | ||
|
|
ee725bf625 | ||
|
|
5388fa442c | ||
|
|
913493fd2e | ||
|
|
6d4a8c6619 | ||
|
|
4a57115336 | ||
|
|
1dd754a0d5 | ||
|
|
509b78d906 | ||
|
|
363366d012 | ||
|
|
26d4fd4e00 | ||
|
|
09ee97e775 | ||
|
|
1400a95cec | ||
|
|
5e96c4ca79 | ||
|
|
3c068b2a00 | ||
|
|
81fd7757c1 | ||
|
|
1db64b72ae | ||
|
|
ab1bed236c | ||
|
|
e503999392 | ||
|
|
2392eb7e0b | ||
|
|
c62b54f18d | ||
|
|
603d46c1ae | ||
|
|
c0e0ae551d | ||
|
|
a0a2507c05 | ||
|
|
6eed48b28d | ||
|
|
9c5d289098 | ||
|
|
42ab7f23d8 | ||
|
|
c9c2f4232e | ||
|
|
d4f23cc6bd | ||
|
|
b0db67d4d4 | ||
|
|
703cad6715 | ||
|
|
667d67460f | ||
|
|
35cf9ae328 | ||
|
|
c04131af4b | ||
|
|
9cc4db1a12 | ||
|
|
b326500913 | ||
|
|
a26579fcf5 | ||
|
|
a2b9c44433 | ||
|
|
c3b97da1d4 | ||
|
|
048cf0232a | ||
|
|
89c113bee6 | ||
|
|
6b9969a302 | ||
|
|
a6e7513d2a | ||
|
|
8a04f4810f | ||
|
|
1d9d443de0 | ||
|
|
00e5809a71 | ||
|
|
07ba4a040b | ||
|
|
7b319d230a | ||
|
|
641bc2daec | ||
|
|
fbaa30cc08 | ||
|
|
a0c2c9056b | ||
|
|
30ab5fd76b | ||
|
|
30beab4017 | ||
|
|
4ec1493b09 | ||
|
|
e7cbe9709e | ||
|
|
aacaeba525 | ||
|
|
6e4da5efb7 | ||
|
|
87443a4ff2 | ||
|
|
9746759c68 | ||
|
|
170ee2b98a | ||
|
|
938fb777dd | ||
|
|
33e1aafcd1 | ||
|
|
597ee90041 | ||
|
|
e87e54ea28 | ||
|
|
5c64c1ac3f | ||
|
|
c611cbc2ca | ||
|
|
9d051f4171 | ||
|
|
6aee788678 | ||
|
|
425a45caa7 | ||
|
|
0571601e02 | ||
|
|
c1992c8c7a | ||
|
|
bd913870c7 | ||
|
|
7a479dd47f | ||
|
|
7ae77aa58d | ||
|
|
97a4260d44 | ||
|
|
b90d711764 | ||
|
|
22de5b523e | ||
|
|
5798b824c0 | ||
|
|
4cbf6cfc33 | ||
|
|
8b55460156 | ||
|
|
a61d48a451 | ||
|
|
b9f4d57d67 | ||
|
|
92cd36d14d | ||
|
|
f74e61b126 | ||
|
|
c8b4ba2b5b | ||
|
|
0a15ba1c5b | ||
|
|
7ee5948233 | ||
|
|
85c8bcf9d2 | ||
|
|
67394c6664 | ||
|
|
66ef7d8229 | ||
|
|
3773bc69f2 | ||
|
|
912416b119 | ||
|
|
7dfe125013 | ||
|
|
87db34ef0b | ||
|
|
d4f75ab53c | ||
|
|
dc97e8fce5 | ||
|
|
b3965d9d67 | ||
|
|
7ee90d1e12 | ||
|
|
9d8b373e4f | ||
|
|
a068a7eb5b | ||
|
|
aa004c1893 | ||
|
|
9a9c149370 | ||
|
|
9e6e226e4b | ||
|
|
06c2aed0e0 | ||
|
|
df4f610cfc | ||
|
|
64249abae1 | ||
|
|
94f4be58bd | ||
|
|
35987d3741 | ||
|
|
be73e00dde | ||
|
|
a5f272f337 | ||
|
|
406691aa69 | ||
|
|
6827b3bf15 | ||
|
|
2055a1472f | ||
|
|
f4f9018068 | ||
|
|
3e82b5cd33 | ||
|
|
07036bce20 | ||
|
|
a4a7a75f29 | ||
|
|
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 | ||
|
|
79fa25c4e0 | ||
|
|
02050675a8 | ||
|
|
0d5857a1bc | ||
|
|
e3a51be1f9 | ||
|
|
57cb098a6e | ||
|
|
5f285eef56 | ||
|
|
7d5cf6f318 | ||
|
|
99d305c7a1 | ||
|
|
b9cc3b6a7d | ||
|
|
e1f8c69d3d | ||
|
|
67b6fbd15b | ||
|
|
50f407eb9e | ||
|
|
b127699c0a | ||
|
|
4d74fa6759 | ||
|
|
2b9d6cb7c2 | ||
|
|
e0b67bba58 | ||
|
|
3cdf17df75 | ||
|
|
43c086494b | ||
|
|
ae26e90b3a | ||
|
|
d35a7d8725 | ||
|
|
043e7ddde4 | ||
|
|
3930960159 | ||
|
|
be12175c8a | ||
|
|
02a1847539 | ||
|
|
0235535658 | ||
|
|
3af75ca64c | ||
|
|
efbe28502d | ||
|
|
47847ee471 | ||
|
|
688ffe32a9 | ||
|
|
c6bbe01f3e | ||
|
|
002af6128c | ||
|
|
5b5c92a9d7 | ||
|
|
7d31d73fc5 | ||
|
|
c5c2c83c65 | ||
|
|
174116c48b | ||
|
|
4be5830fc3 | ||
|
|
5f55357e17 | ||
|
|
8d033159b8 | ||
|
|
299fd9cf8a | ||
|
|
8caee1b15b | ||
|
|
c2d963aa0d | ||
|
|
94691b3cc3 | ||
|
|
9073a2856b | ||
|
|
4c26f34239 | ||
|
|
ad0cc774e1 | ||
|
|
d238fc50d0 | ||
|
|
dcf16c994e | ||
|
|
65cc44e611 | ||
|
|
9887177d9a | ||
|
|
6b11777bb3 | ||
|
|
604b412f4a | ||
|
|
1d9da31f18 | ||
|
|
fadf640f41 | ||
|
|
743432a53d | ||
|
|
c1956fc371 | ||
|
|
3d098358da | ||
|
|
757e908372 | ||
|
|
dd12caa6f3 | ||
|
|
0bfa5c4f46 | ||
|
|
cb252e4f0a | ||
|
|
bdab4dcf84 | ||
|
|
474860cd39 | ||
|
|
82f722b1f9 | ||
|
|
919501e92c | ||
|
|
b1f3e48b2b | ||
|
|
314df1d809 | ||
|
|
0416914951 | ||
|
|
159a5660b2 | ||
|
|
6ea9ee4ee9 | ||
|
|
c60a81db47 | ||
|
|
b71634c76b | ||
|
|
9a23c42262 | ||
|
|
680df4cff6 | ||
|
|
27fa8df9e6 | ||
|
|
2151b17aa3 | ||
|
|
b93d0cc2b0 | ||
|
|
1729275f8c | ||
|
|
9b2460f8df | ||
|
|
5451ff490c | ||
|
|
5a828aefdc | ||
|
|
6a4332ca4d | ||
|
|
7f3750b174 | ||
|
|
7b1672497e | ||
|
|
113223567a | ||
|
|
ecf23f93d1 | ||
|
|
2504af4dd1 | ||
|
|
c340e972ad | ||
|
|
e382de291f | ||
|
|
51d97fadd9 | ||
|
|
878b515e23 | ||
|
|
03bdaa50b6 | ||
|
|
34dbfc597e | ||
|
|
05efe4b7b3 | ||
|
|
a18bc5f148 | ||
|
|
9852b2fa62 | ||
|
|
9cedbb6716 | ||
|
|
96a6c5eff4 | ||
|
|
e5233f09cc | ||
|
|
2f7bf001e8 | ||
|
|
1caea3dbeb | ||
|
|
6805e5ee9f | ||
|
|
82f33591ae | ||
|
|
b3e3e2ca1d | ||
|
|
4ae0361f6d | ||
|
|
5706dd0a31 | ||
|
|
d8cd5580b7 | ||
|
|
e16c9b46ed | ||
|
|
86d28b2654 | ||
|
|
09bc058e88 | ||
|
|
0bf55fc1f9 | ||
|
|
e05edd9f82 | ||
|
|
aa9c5331d4 | ||
|
|
665511e6fa | ||
|
|
41190a5336 | ||
|
|
f2b72814a6 | ||
|
|
67d49defb6 | ||
|
|
bf1f800cf4 | ||
|
|
55a95ac4b4 | ||
|
|
820caa5364 | ||
|
|
67ce14dfa8 | ||
|
|
dc16e8eb38 | ||
|
|
fc0de78d88 | ||
|
|
1ffecc7939 | ||
|
|
2b4759e5e1 | ||
|
|
779ab3702a | ||
|
|
25fe41dd50 | ||
|
|
1c03935b76 | ||
|
|
6b10370c0a | ||
|
|
e84c3808e9 | ||
|
|
b9ff3f87d0 | ||
|
|
7a6d40c258 | ||
|
|
5c211817b7 | ||
|
|
21b2769edd | ||
|
|
baff440f18 | ||
|
|
793dcd92d2 | ||
|
|
1d203021c7 | ||
|
|
d38cc66738 | ||
|
|
603351c736 | ||
|
|
ae5b69b19c | ||
|
|
0229a9727e | ||
|
|
da571c2515 | ||
|
|
d3160c3f60 | ||
|
|
175ef65d9f | ||
|
|
8a572a642e | ||
|
|
70a51c2909 | ||
|
|
8b32564b05 | ||
|
|
c0ada5e52a | ||
|
|
0ffcb9e05e | ||
|
|
5a279bb170 | ||
|
|
757049d9da | ||
|
|
8674787692 | ||
|
|
3654016c53 | ||
|
|
4dbc15a253 | ||
|
|
3d55ab8327 | ||
|
|
f4e336026b | ||
|
|
ed90e0cf4b | ||
|
|
bed7682a3b | ||
|
|
3874d3e610 | ||
|
|
d378d42c4c | ||
|
|
4faeb852c6 | ||
|
|
27177a4df9 | ||
|
|
4ee9b36579 | ||
|
|
c06a1626ed | ||
|
|
86787b796a | ||
|
|
3bae35805b | ||
|
|
f26e79fb09 | ||
|
|
b72fc0a178 | ||
|
|
f1853568f9 | ||
|
|
2785cd3065 | ||
|
|
a8a497e431 | ||
|
|
710588fcfd | ||
|
|
a66aad02d8 | ||
|
|
651dacad3a | ||
|
|
fdeb2e26cf | ||
|
|
d5d5b87627 | ||
|
|
67c1a547af | ||
|
|
ed9c99c417 | ||
|
|
2e29b6b234 | ||
|
|
e0882ed8df | ||
|
|
a6b42af85a | ||
|
|
595e99a0c6 | ||
|
|
54f666f214 | ||
|
|
f1fad65b43 | ||
|
|
40fb6ffa91 | ||
|
|
d83a685d01 | ||
|
|
e7b346d3d9 | ||
|
|
25ec7aadc0 | ||
|
|
f7ef3161e4 | ||
|
|
2cd731f36d | ||
|
|
15a0b7fbc9 | ||
|
|
f33d16edb7 | ||
|
|
6fdb5cac37 | ||
|
|
20f7e4f0bc | ||
|
|
0c1e9080af | ||
|
|
1ceb82af59 | ||
|
|
ace76d686d | ||
|
|
a7bb9bd2bb | ||
|
|
aa39cc0eca | ||
|
|
74c88f21a9 | ||
|
|
c03e94f97e | ||
|
|
be4da2e8d9 | ||
|
|
d781a02eed | ||
|
|
fd42997e8f | ||
|
|
6be13c2e04 | ||
|
|
63f63adda6 | ||
|
|
c0904e42fc | ||
|
|
8b8f1d60ed | ||
|
|
5a6850e64b | ||
|
|
cc6e9924b8 | ||
|
|
816998155e | ||
|
|
b2ffd406e3 | ||
|
|
713ffe38b4 | ||
|
|
1810af7b2d | ||
|
|
d0fb89c783 | ||
|
|
b0c23faeeb | ||
|
|
edc4aa42c8 | ||
|
|
dda8c2ffaa | ||
|
|
7059fd8d88 | ||
|
|
dad81ce7bd | ||
|
|
277afccf64 | ||
|
|
3854d14867 | ||
|
|
e3a67a9bcd | ||
|
|
a51b19669c | ||
|
|
2707860bc5 | ||
|
|
7c69aade57 | ||
|
|
38c5d3d4b5 | ||
|
|
065b992bf9 | ||
|
|
3b93696775 | ||
|
|
62534b2490 | ||
|
|
5018c152e9 | ||
|
|
57fc6bcef0 | ||
|
|
36f26dba85 | ||
|
|
6062bf8a72 | ||
|
|
0152fb077b | ||
|
|
440d42303d | ||
|
|
72e28580a6 | ||
|
|
acf7984eb3 | ||
|
|
bda58ad5cd | ||
|
|
89258474ad | ||
|
|
dc01fc4b42 | ||
|
|
0dd5add615 |
@@ -0,0 +1,24 @@
|
||||
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
|
||||
ff4111eb8f55b958ec91c70163e10f3372a9b94d 0.9.7-rc1
|
||||
eb8aff2926230bb114fb90f67203440a2c534bf1 0.9.7-rc2
|
||||
311eef929ec8fd0a5dc8c16531afb7bb42d36d01 0.9.7-rc3
|
||||
4b50c04e414f1d9ab8b0b5910aba83d09ac21abb 0.9.7
|
||||
d9b9b540f7dce8cb05d2e61ca8b4d75f2ea25f62 0.9.7.1
|
||||
d9b9b540f7dce8cb05d2e61ca8b4d75f2ea25f62 0.9.7.1
|
||||
0000000000000000000000000000000000000000 0.9.7.1
|
||||
0000000000000000000000000000000000000000 0.9.7.1
|
||||
486e7760bcbc2191ddb9b4aee6c98dbd5fc4c754 0.9.7.1
|
||||
a5f13497b39269621f8f1e56e14d2cc141452e79 0.9.7.2
|
||||
d1e57707f6317f134fea7d12f6588d8690f74f3f 0.9.8-rc1
|
||||
e91bc724325e14c13b8f548c0b6a315c48a1c32a 0.9.8-rc2
|
||||
@@ -1,3 +1,382 @@
|
||||
*** may 2011 ***
|
||||
|
||||
* 0.9.8-rc2 [20110521]
|
||||
|
||||
- new option --die-on-term
|
||||
- fixed touch reload
|
||||
- a couple of optimizations for wsgi.input
|
||||
- systemd integration
|
||||
|
||||
* 0.9.8-rc1 [20110514]
|
||||
|
||||
- massive code cleanup and refactoring
|
||||
- added vassals loyalty concept
|
||||
- fixed virtualhosting with dynamic virtualenv
|
||||
- fixed reloading on grand-central-dispatch-enabled OSX
|
||||
- improved PSGI support with uGreen and async support
|
||||
- improved Rack support with complete fiber+async in ruby 1.9
|
||||
- support for JSON config files
|
||||
- native multi-protocol support (added fastcgi and http)
|
||||
- Mongrel2 support
|
||||
- support for templates in vassals
|
||||
- various threading fixes
|
||||
- gcc-4.6 support
|
||||
- support for logging via zeromq
|
||||
- support for configuration passed via pipe/stdin
|
||||
- pythonpath entries are now unlimited
|
||||
- socket entries are unlimited
|
||||
- pythonpath can be a glob
|
||||
- lazy mode added
|
||||
- new language-independent profiling subsystem
|
||||
- support for configuration stored in a sqlite3 db
|
||||
- allow workers to survive to syslogd death (when --log-syslog is used)
|
||||
- fix traceback in Python 3.x
|
||||
- support for uwsgi signals in threads
|
||||
- plugin autoloading
|
||||
- graceful reloading for threads
|
||||
- new wsgi.input object
|
||||
- support for alternative allocators (tcmalloc and jemalloc)
|
||||
|
||||
|
||||
*** april 2011 ***
|
||||
|
||||
* 0.9.7.2 [20110406]
|
||||
|
||||
- new option --touch-reload <file> to reload the stack on <file> modification
|
||||
--static-map <mountpoint=documentroot> allows to serve static files
|
||||
- fixed --post-limit management
|
||||
- disallow empty socket names
|
||||
- implemented exception_info WSGI support
|
||||
- new options --reload-on-as <n> and --reload-on-rss <n> allows
|
||||
to recycle workers when their memory usage is higher than <n> MB
|
||||
- fixed syslog support (use --log-syslog[=facility] to enable it)
|
||||
- improved plugin loading system
|
||||
- added support for RabbitMQ as event dispatcher for the Emperor
|
||||
- fixed FreeBSD memory report
|
||||
- PSGI plugin can be compiled without ithreads
|
||||
- various Emperor fixes
|
||||
- fixed a regression with setgroups()
|
||||
- support for shared sockets (used in jails within network namespaces)
|
||||
|
||||
*** march 2011 ***
|
||||
|
||||
* 0.9.7.1 [20110326]
|
||||
|
||||
- fixed python stackless support
|
||||
- added persistence for queue
|
||||
- forbid daemonizing in vassal mode
|
||||
- modifier1 30 is available again
|
||||
- allow python modules to be mapped/aliased via http
|
||||
- added --pidfile2 and --logfile-chown
|
||||
- added UWSGI_CACHE_GET dynamic variable
|
||||
- 304/If-Modified-Since support for --check-static
|
||||
- option --check-cache for integrated caching
|
||||
- option --map-socket to assign specific workers to socket
|
||||
- fixed unix fd passing on older OSX versions
|
||||
- fixed post-buffering without pep3333-input
|
||||
- fixed python threading without uwsgi cores
|
||||
- support for Linux network namespace
|
||||
- build with sys.abiflags if necessary
|
||||
|
||||
|
||||
* 0.9.7 [20110317]
|
||||
|
||||
- fixed psgi compilation on GNU systems
|
||||
- improved --pep3333-input
|
||||
- better error reporting on failed open/fopen
|
||||
- fixed uGreen
|
||||
- added greenlet support
|
||||
- various solaris fixes
|
||||
- new help system
|
||||
- updated async support
|
||||
- fixed uwsgi.cache_get in python
|
||||
|
||||
* 0.9.7-rc3 [20110312]
|
||||
|
||||
- added support for persistent cache (--cache-store <filename>)
|
||||
- less verbose file monitoring
|
||||
- fixed a race condition in emperor startup
|
||||
- fixed erlang empty list encoding
|
||||
- improved snmp support
|
||||
- fixed cache modifier 111 for 3 and 4
|
||||
- preliminary cpu-affinity support (Linux only)
|
||||
- fixed ldap support
|
||||
- auto-configure ldap compilation
|
||||
- added --allowed-modifiers (allow only a subset of modifiers)
|
||||
- fixed a bug with getopt_long
|
||||
|
||||
* 0.9.7-rc2 [20110309]
|
||||
|
||||
- added cron-like interface to signal framework
|
||||
- improved Linux namespaces support
|
||||
- fixed multithreading + --max-requests
|
||||
- added support for reference in configuration files
|
||||
|
||||
* 0.9.7-rc1 [20110307]
|
||||
|
||||
- export %v in emperor mode
|
||||
- fixed signal race condition in server reload
|
||||
- fixed http router post handling bug
|
||||
- added uwsgi.erlang_register_process in pyerl plugin
|
||||
- fixed unix socket inherit
|
||||
- fixed linux namespace support in recent kernel/gcc
|
||||
- ported threading to python 3.2
|
||||
- add build date to uWSGI startup info
|
||||
- do not allow clustering without defining a socket
|
||||
- kill all the gateways/daemons on startup errors
|
||||
- fixed vacuum after chdir()
|
||||
- fixed gateways reload
|
||||
- re-added support for OpenBSD and NetBSD
|
||||
- fixed post-buffering in python
|
||||
- use erlang binary for python string
|
||||
- fixed memory leak in pyerl plugin
|
||||
- removed broken log rotation (post-poned)
|
||||
- fixed no_argument options in ini and yaml parsing
|
||||
|
||||
* 0.9.7-beta1 [20110301]
|
||||
|
||||
- fully modular re-design
|
||||
- advanced build system with presets
|
||||
- threading support
|
||||
- emperor mode for massive auto-hosting
|
||||
- caching subsystem
|
||||
- message queue (even stacked) support
|
||||
- improved server reloading system
|
||||
- support for Linux Cgroups and Namespaces
|
||||
- integrated upload progress
|
||||
- Clustering infrastructure via multicast, broadcast or subscriptions
|
||||
- support for attaching/monitoring external apps to the master process
|
||||
- improved virtualhosting mode
|
||||
- extremely improved Python support with better usage of multiple interpreters
|
||||
- improved multiple apps support
|
||||
- Production ready, evented HTTP router/proxy/load-balancer
|
||||
- Production ready, evented uwsgi router/proxy/load-balancer
|
||||
- new Erlang stack
|
||||
- Internal signal subsystem
|
||||
- support for RubyOnRails and Rack apps
|
||||
- A huge series of fixes and optimizations
|
||||
|
||||
*** february 2011 ***
|
||||
|
||||
* 0.9.6.8 [20110207]
|
||||
|
||||
- fixed a bug when using --limit-as
|
||||
- fixed a erlang buffer initialization
|
||||
- added --ignore-sigpipe
|
||||
- added --master-as-root
|
||||
|
||||
*** january 2011 ***
|
||||
|
||||
* 0.9.6.7 [20110130]
|
||||
|
||||
- a huge amount of async optimizations and fixes
|
||||
- --logdate takes an optional strftime-like value
|
||||
- follow $PATH on reloading
|
||||
- uwsgi.core is exported in WSGI env
|
||||
- uwsgi.log() respect for --logdate
|
||||
- initial banner respect for --logdate
|
||||
- fixed --post-buffering
|
||||
- default listen backlog queue is now 100
|
||||
- Python 3 support is no more marked as experimental
|
||||
- Python 3.2 support
|
||||
- new option --chroot-reload will force a reload of the uWSGI stack after a chroot
|
||||
- fixed a typo in INI parsing
|
||||
|
||||
*** december 2010 ***
|
||||
|
||||
* 0.9.6.6 [20101230]
|
||||
|
||||
- support for YAML configuration files
|
||||
- backported python module aliasing from 0.9.7-dev
|
||||
- better apache2 module (support for SetEnv directive, fixed REQUEST_URI and improved connection handling)
|
||||
- uwsgi.post_fork_hook implementation (to execute function after fork()) (thanks George Kollias)
|
||||
- option --gid calls setgroups() after setgid() (thanks Jorge Cardona)
|
||||
- fixed uGreen compilation (and uGreen is now built by default)
|
||||
- fixed timeout and thundering herd problem in async modes (many thanks to Test157 for giving us a good async-test-app)
|
||||
- disable TCP_INFO in older Linux kernels (thanks Bo Shi)
|
||||
- enable TCP_INFO in FreeBSD (limited usage due to FreeBSD kernel support)
|
||||
- fixed static virtualhosting mode using xml files (thanks Guido Notari of Link I.T. spa)
|
||||
- new option --close-on-exec (thanks Jean-Baptiste Quenot)
|
||||
- use HTTP_HOST var (and fallback to SERVER_NAME) in virtual hosting mode
|
||||
- fixed a buffer overflow in automatic socket_name allocation (spotted by Riccardo Magliocchetti)
|
||||
- Official support for Nexenta
|
||||
|
||||
|
||||
*** september 2010 ***
|
||||
|
||||
* 0.9.6.5 [20100929]
|
||||
|
||||
- PEP 3333 support
|
||||
- fix --pythonpath with --wsgi-file
|
||||
- x-wsgiorg.uwsgi.version renamed to uwsgi.version
|
||||
|
||||
* 0.9.6.4 [20100925]
|
||||
|
||||
- fix a stupid bug in conditional logging backport
|
||||
|
||||
* 0.9.6.3 [20100925]
|
||||
|
||||
- fix a buffer overflow in .ini parsing (it throws a glibc error on malloc)
|
||||
- backport of conditional logging from 0.9.7-dev
|
||||
- backport of backlog queue monitor from 0.9.7-dev (only Linux)
|
||||
|
||||
* 0.9.6.2 [20100915]
|
||||
|
||||
- fix a regression in virtual hosting mode
|
||||
- fix pythonpath usage in --ini and --ini-paste
|
||||
- new uwsgi packet var: UWSGI_CHDIR
|
||||
|
||||
* 0.9.6.1 [20100912]
|
||||
|
||||
- print the request uri during SIGPIPE or HARAKIRI
|
||||
- added SIGUSR2 support (it will print the current running request, if available)
|
||||
- protocol parsing optimization
|
||||
- fixed --logto support
|
||||
- new --eval option allows inline definition of WSGI script
|
||||
- support for defining WSGI script in xml using CDATA
|
||||
- allow --pp as --pythonpath shortcut
|
||||
- various spooler optimizations and fixes
|
||||
- added -O2 optimization by default
|
||||
- added uwsgi.is_a_reload commodity function
|
||||
- .ini file support fix
|
||||
- SNMP agent fix
|
||||
- support for subprocesses generated by master
|
||||
- fix a regression in SCRIPT_NAME handling
|
||||
- Haiku official support
|
||||
- gcc 2.95 support
|
||||
- dynamic app management optimizations
|
||||
- export x-wsgiorg.uwsgi.version in WSGI env
|
||||
|
||||
*** august 2010 ***
|
||||
|
||||
* 0.9.6 [20100829]
|
||||
|
||||
- better handling of SCRIPT_NAME
|
||||
- vacuum option for deleting unix sockets and pidfiles after usage
|
||||
- advanced XML configuration
|
||||
- new configuration systems: INI files and LDAP
|
||||
- embedded HTTP server for development/testing
|
||||
- better signal handling
|
||||
- PSGI plugin improved
|
||||
- usability fixes and new commodities options for root startup
|
||||
- grunt processes (detached workers)
|
||||
- preliminary integrated virtualhosting mode
|
||||
- new option catch-exceptions can redirect python exceptions to your browser
|
||||
- logging improvements (--logto and --logdate options)
|
||||
- Full PEP 333 compliant usage of wsgi.file_wrapper
|
||||
- re-initialize random seed after every fork() [security fix]
|
||||
- fix Spooler's usage of stdin
|
||||
- export WSGI environment in uwsgi.env (for doing evil things)
|
||||
- logsize tracking (uwsgi.logsize) for future embedded log rotation
|
||||
|
||||
*** july 2010 ***
|
||||
|
||||
* 0.9.5.4 [20100706]
|
||||
|
||||
*** june 2010 ***
|
||||
|
||||
* 0.9.5.3 [20100628]
|
||||
|
||||
- fixed linux x86_64 compilation (sorry)
|
||||
|
||||
* 0.9.5.2 [20100626] *
|
||||
|
||||
- fixed a request parsing bug
|
||||
- applied debian fixes
|
||||
- fixed multiple interpreter sys.argv
|
||||
- improved --chmod-socket
|
||||
- fixed uid 0 SIGHUP
|
||||
- updated nginx and apache modules
|
||||
- updated PSGI, lua and example plugin
|
||||
- fixed --pyargv with python 3.x
|
||||
- improved plugin build system
|
||||
|
||||
*** may 2010 ***
|
||||
|
||||
* 0.9.5.1 [20100519] *
|
||||
|
||||
- fixed paste support
|
||||
- added a new modifier (22)
|
||||
- full support for configuration via environment variables
|
||||
- nginx_string option in nginx module
|
||||
- fix for harakiri without master
|
||||
- backported unladen swallow support for 0.9.6-dev
|
||||
- fixed address space limit detection via getrlimit()
|
||||
- http body buffering implementation
|
||||
- added --prio option (to set priority)
|
||||
- added --post-limit to limit the size of uploads
|
||||
- added --logto option to allow udp logging without daemonizing
|
||||
- applied Gentoo's packagers fixes for build system
|
||||
|
||||
* 0.9.5 [20100501] *
|
||||
|
||||
- hook based request/modifier management
|
||||
- plugin support via dlopen
|
||||
- on-the-fly management flag
|
||||
- integrated proxy
|
||||
- logging via udp
|
||||
- improved spooler for cron-like apps
|
||||
- async support
|
||||
- green thread platform (uGreen) on top of the async mode
|
||||
- transparent Erlang integration
|
||||
- embedded snmp agent
|
||||
- nagios mode
|
||||
- improved python 3.x support
|
||||
- improved xml configuration
|
||||
- new build system
|
||||
- address space usage limiting
|
||||
- lot of portability fixes
|
||||
- lot of optimizations and code refactoring
|
||||
|
||||
|
||||
*** april 2010 ***
|
||||
|
||||
* Fourth Maintenance release [20100427] *
|
||||
|
||||
- backported non-yielding app optimization from 0.9.5
|
||||
- backported udp logging from 0.9.5
|
||||
- backported uwsgi_error() from 0.9.5 (no more dumb perror())
|
||||
- fix a rare (but possible) segmentation fault
|
||||
- added --version
|
||||
- updated apache2 module
|
||||
|
||||
*** march 2010 ***
|
||||
|
||||
* Third Maintenance release [20100310] *
|
||||
|
||||
- fix sendfile on 64bit
|
||||
- include setup.py
|
||||
|
||||
*** february 2010 ***
|
||||
* Maintenance release *
|
||||
|
||||
- better support for NetBSD
|
||||
- threading fix for FreeBSD
|
||||
- sendfile portability fixes
|
||||
- new makefiles
|
||||
- example app for testing static file serving
|
||||
- fixes for ROCK_SOLID mode
|
||||
|
||||
*** january 2010 ***
|
||||
|
||||
- Integrated Spooler
|
||||
- better error management
|
||||
- long options
|
||||
- clustering functions
|
||||
- experimental lighttpd module
|
||||
- official support for OpenBSD and OpenSolaris
|
||||
- FastFuncs
|
||||
- new functions for embedded module
|
||||
- reliable harakiri
|
||||
- better Makefiles
|
||||
- python threads support in master process
|
||||
- proper timeout handling in apache2 module
|
||||
- endianess fixes all over the place
|
||||
- paste support
|
||||
- Django app for managing and monitoring the uWSGI server
|
||||
- options for changin uid/gid and chrooting when run by root
|
||||
- lot of bugfixes and optimizations
|
||||
|
||||
*** 20091129 Version 0.9.3 ***
|
||||
|
||||
- Nginx 0.7.x module
|
||||
|
||||
@@ -1,13 +1,2 @@
|
||||
CC=gcc
|
||||
|
||||
PYTHON_CFLAGS=`python2.5-config --cflags`
|
||||
PYTHON_LIBS=`python2.5-config --libs`
|
||||
XML_CFLAGS=`xml2-config --cflags`
|
||||
XML_LIBS=`xml2-config --libs`
|
||||
|
||||
CFLAGS=$(PYTHON_CFLAGS) $(XML_CFLAGS)
|
||||
LD_FLAGS=$(PYTHON_LIBS) $(XML_LIBS)
|
||||
|
||||
PROGRAM=uwsgi
|
||||
|
||||
include base.mk
|
||||
all:
|
||||
python uwsgiconfig.py --build
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
CC=/usr/lib/llvm/llvm/gcc-4.2/bin/llvm-gcc
|
||||
|
||||
PYTHON_CFLAGS=`python2.5-config --cflags`
|
||||
PYTHON_LIBS=`python2.5-config --libs`
|
||||
XML_CFLAGS=`xml2-config --cflags`
|
||||
XML_LIBS=`xml2-config --libs`
|
||||
|
||||
CFLAGS=$(PYTHON_CFLAGS) $(XML_CFLAGS)
|
||||
LD_FLAGS=$(PYTHON_LIBS) $(XML_LIBS)
|
||||
|
||||
PROGRAM=uwsgi
|
||||
|
||||
all: uwsgi
|
||||
|
||||
uwsgi: utils.o socket.o pymodule.o main.o
|
||||
$(CC) $(LD_FLAGS) utils.o socket.o pymodule.o main.o -o $(PROGRAM)
|
||||
|
||||
utils.o: utils.c
|
||||
$(CC) -c $(CFLAGS) utils.c
|
||||
|
||||
socket.o: socket.c
|
||||
$(CC) -c $(CFLAGS) socket.c
|
||||
|
||||
pymodule.o: uwsgi_pymodule.c
|
||||
$(CC) -c $(CFLAGS) -o pymodule.o uwsgi_pymodule.c
|
||||
|
||||
main.o: uwsgi.c
|
||||
$(CC) -c $(CFLAGS) -o main.o uwsgi.c
|
||||
|
||||
clean:
|
||||
rm -f utils.o socket.o pymodule.o main.o
|
||||
@@ -1,31 +0,0 @@
|
||||
CC=/usr/lib/llvm/llvm/gcc-4.2/bin/llvm-gcc
|
||||
|
||||
PYTHON_CFLAGS=`python2.6-config --cflags`
|
||||
PYTHON_LIBS=`python2.6-config --libs`
|
||||
XML_CFLAGS=`xml2-config --cflags`
|
||||
XML_LIBS=`xml2-config --libs`
|
||||
|
||||
CFLAGS=$(PYTHON_CFLAGS) $(XML_CFLAGS)
|
||||
LD_FLAGS=$(PYTHON_LIBS) $(XML_LIBS)
|
||||
|
||||
PROGRAM=uwsgi26
|
||||
|
||||
all: uwsgi
|
||||
|
||||
uwsgi: utils.o socket.o pymodule.o main.o
|
||||
$(CC) $(LD_FLAGS) utils.o socket.o pymodule.o main.o -o $(PROGRAM)
|
||||
|
||||
utils.o: utils.c
|
||||
$(CC) -c $(CFLAGS) utils.c
|
||||
|
||||
socket.o: socket.c
|
||||
$(CC) -c $(CFLAGS) socket.c
|
||||
|
||||
pymodule.o: uwsgi_pymodule.c
|
||||
$(CC) -c $(CFLAGS) -o pymodule.o uwsgi_pymodule.c
|
||||
|
||||
main.o: uwsgi.c
|
||||
$(CC) -c $(CFLAGS) -o main.o uwsgi.c
|
||||
|
||||
clean:
|
||||
rm -f utils.o socket.o pymodule.o main.o
|
||||
@@ -0,0 +1,2 @@
|
||||
all:
|
||||
python2.4 uwsgiconfig.py --build
|
||||
@@ -0,0 +1,2 @@
|
||||
all:
|
||||
python2.5 uwsgiconfig.py --build
|
||||
+2
-13
@@ -1,13 +1,2 @@
|
||||
CC=gcc
|
||||
|
||||
PYTHON_CFLAGS=`python2.6-config --cflags`
|
||||
PYTHON_LIBS=`python2.6-config --libs`
|
||||
XML_CFLAGS=`xml2-config --cflags`
|
||||
XML_LIBS=`xml2-config --libs`
|
||||
|
||||
CFLAGS=$(PYTHON_CFLAGS) $(XML_CFLAGS)
|
||||
LD_FLAGS=$(PYTHON_LIBS) $(XML_LIBS)
|
||||
|
||||
PROGRAM=uwsgi26
|
||||
|
||||
include base.mk
|
||||
all:
|
||||
python2.6 uwsgiconfig.py --build
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
all:
|
||||
python2.7 uwsgiconfig.py --build
|
||||
@@ -0,0 +1,2 @@
|
||||
all:
|
||||
python3.0 uwsgiconfig.py --build
|
||||
@@ -0,0 +1,2 @@
|
||||
all:
|
||||
python3.1 uwsgiconfig.py --build
|
||||
@@ -0,0 +1,2 @@
|
||||
all:
|
||||
python3.2 uwsgiconfig.py --build
|
||||
@@ -0,0 +1,2 @@
|
||||
all:
|
||||
python uwsgiconfig.py --build pylua
|
||||
@@ -1,29 +0,0 @@
|
||||
CC=gcc
|
||||
|
||||
PYTHON_CFLAGS=`python2.6-config --cflags`
|
||||
PYTHON_LIBS=`python2.6-config --libs`
|
||||
|
||||
CFLAGS=$(PYTHON_CFLAGS) -DROCK_SOLID
|
||||
LD_FLAGS=$(PYTHON_LIBS) -DROCK_SOLID
|
||||
|
||||
PROGRAM=uwsgi26_rs
|
||||
|
||||
all: uwsgi
|
||||
|
||||
uwsgi: utils.o socket.o pymodule.o main.o
|
||||
$(CC) $(LD_FLAGS) utils.o socket.o pymodule.o main.o -o $(PROGRAM)
|
||||
|
||||
utils.o: utils.c
|
||||
$(CC) -c $(CFLAGS) utils.c
|
||||
|
||||
socket.o: socket.c
|
||||
$(CC) -c $(CFLAGS) socket.c
|
||||
|
||||
pymodule.o: uwsgi_pymodule.c
|
||||
$(CC) -c $(CFLAGS) -o pymodule.o uwsgi_pymodule.c
|
||||
|
||||
main.o: uwsgi.c
|
||||
$(CC) -c $(CFLAGS) -o main.o uwsgi.c
|
||||
|
||||
clean:
|
||||
rm -f utils.o socket.o pymodule.o main.o
|
||||
@@ -1,26 +0,0 @@
|
||||
CC=gcc
|
||||
|
||||
PYTHON_CFLAGS=`python2.4-config --cflags`
|
||||
PYTHON_LIBS=`python2.4-config --libs`
|
||||
|
||||
CFLAGS=$(PYTHON_CFLAGS) -DUNBIT -D_GNU_SOURCE
|
||||
LD_FLAGS=$(PYTHON_LIBS) -DUNBIT -D_GNU_SOURCE
|
||||
|
||||
PROGRAM=/usr/share/unbit/uwsgi24
|
||||
|
||||
all: clean uwsgi
|
||||
|
||||
uwsgi: utils.o pymodule.o main.o
|
||||
$(CC) $(LD_FLAGS) main.o utils.o pymodule.o -o $(PROGRAM)
|
||||
|
||||
utils.o: utils.c
|
||||
$(CC) -c $(CFLAGS) utils.c
|
||||
|
||||
pymodule.o: uwsgi_pymodule.c
|
||||
$(CC) -c $(CFLAGS) -o pymodule.o uwsgi_pymodule.c
|
||||
|
||||
main.o: uwsgi.c
|
||||
$(CC) -c $(CFLAGS) -o main.o uwsgi.c
|
||||
|
||||
clean:
|
||||
rm -f utils.o pymodule.o main.o
|
||||
@@ -1,26 +0,0 @@
|
||||
CC=gcc
|
||||
|
||||
PYTHON_CFLAGS=`python2.5-config --cflags`
|
||||
PYTHON_LIBS=`python2.5-config --libs`
|
||||
|
||||
CFLAGS=$(PYTHON_CFLAGS) -DUNBIT -D_GNU_SOURCE
|
||||
LD_FLAGS=$(PYTHON_LIBS) -DUNBIT -D_GNU_SOURCE
|
||||
|
||||
PROGRAM=/usr/share/unbit/uwsgi
|
||||
|
||||
all: clean uwsgi
|
||||
|
||||
uwsgi: utils.o pymodule.o main.o
|
||||
$(CC) $(LD_FLAGS) main.o utils.o pymodule.o -o $(PROGRAM)
|
||||
|
||||
utils.o: utils.c
|
||||
$(CC) -c $(CFLAGS) utils.c
|
||||
|
||||
pymodule.o: uwsgi_pymodule.c
|
||||
$(CC) -c $(CFLAGS) -o pymodule.o uwsgi_pymodule.c
|
||||
|
||||
main.o: uwsgi.c
|
||||
$(CC) -c $(CFLAGS) -o main.o uwsgi.c
|
||||
|
||||
clean:
|
||||
rm -f utils.o pymodule.o main.o
|
||||
@@ -1,33 +0,0 @@
|
||||
CC=gcc
|
||||
|
||||
PYBASE=/opt/packages/python/26
|
||||
|
||||
PATH := ${PATH}:$(PYBASE)/bin
|
||||
|
||||
LD_LIBRARY_PATH= $(PYBASE)/lib
|
||||
export LD_LIBRARY_PATH
|
||||
|
||||
PYTHON_CFLAGS=`python2.6-config --cflags`
|
||||
PYTHON_LIBS=`python2.6-config --libs`
|
||||
|
||||
CFLAGS=$(PYTHON_CFLAGS) -DUNBIT -D_GNU_SOURCE
|
||||
LD_FLAGS=$(PYTHON_LIBS) -DUNBIT -D_GNU_SOURCE -L $(LD_LIBRARY_PATH)
|
||||
|
||||
PROGRAM=/usr/share/unbit/uwsgi26
|
||||
|
||||
all: clean uwsgi
|
||||
|
||||
uwsgi: utils.o pymodule.o main.o
|
||||
$(CC) $(LD_FLAGS) main.o utils.o pymodule.o -o $(PROGRAM)
|
||||
|
||||
utils.o: utils.c
|
||||
$(CC) -c $(CFLAGS) utils.c
|
||||
|
||||
pymodule.o: uwsgi_pymodule.c
|
||||
$(CC) -c $(CFLAGS) -o pymodule.o uwsgi_pymodule.c
|
||||
|
||||
main.o: uwsgi.c
|
||||
$(CC) -c $(CFLAGS) -o main.o uwsgi.c
|
||||
|
||||
clean:
|
||||
rm -f utils.o pymodule.o main.o
|
||||
@@ -1,30 +0,0 @@
|
||||
CC=gcc
|
||||
|
||||
PYBASE=/opt/packages/python/30
|
||||
|
||||
PATH := ${PATH}:$(PYBASE)/bin
|
||||
|
||||
LD_LIBRARY_PATH= $(PYBASE)/lib
|
||||
export LD_LIBRARY_PATH
|
||||
|
||||
PYTHON_CFLAGS=`python3.0-config --cflags`
|
||||
PYTHON_LIBS=`python3.0-config --libs`
|
||||
|
||||
CFLAGS=$(PYTHON_CFLAGS) -DUNBIT -D_GNU_SOURCE -DPYTHREE
|
||||
LD_FLAGS=$(PYTHON_LIBS) -DUNBIT -D_GNU_SOURCE -DPYTHREE -L $(LD_LIBRARY_PATH)
|
||||
|
||||
PROGRAM=/usr/share/unbit/uwsgi30
|
||||
|
||||
all: clean uwsgi
|
||||
|
||||
uwsgi: utils.o main.o
|
||||
$(CC) $(LD_FLAGS) main.o utils.o -o $(PROGRAM)
|
||||
|
||||
utils.o: utils.c
|
||||
$(CC) -c $(CFLAGS) utils.c
|
||||
|
||||
main.o: uwsgi.c
|
||||
$(CC) -c $(CFLAGS) -o main.o uwsgi.c
|
||||
|
||||
clean:
|
||||
rm -f utils.o main.o
|
||||
@@ -1,30 +0,0 @@
|
||||
CC=gcc
|
||||
|
||||
PYBASE=/opt/packages/python/31
|
||||
|
||||
PATH := ${PATH}:$(PYBASE)/bin
|
||||
|
||||
LD_LIBRARY_PATH= $(PYBASE)/lib
|
||||
export LD_LIBRARY_PATH
|
||||
|
||||
PYTHON_CFLAGS=`python3.1-config --cflags`
|
||||
PYTHON_LIBS=`python3.1-config --libs`
|
||||
|
||||
CFLAGS=$(PYTHON_CFLAGS) -DUNBIT -D_GNU_SOURCE -DPYTHREE
|
||||
LD_FLAGS=$(PYTHON_LIBS) -DUNBIT -D_GNU_SOURCE -DPYTHREE -L $(LD_LIBRARY_PATH)
|
||||
|
||||
PROGRAM=/usr/share/unbit/uwsgi31
|
||||
|
||||
all: clean uwsgi
|
||||
|
||||
uwsgi: utils.o main.o
|
||||
$(CC) $(LD_FLAGS) main.o utils.o -o $(PROGRAM)
|
||||
|
||||
utils.o: utils.c
|
||||
$(CC) -c $(CFLAGS) utils.c
|
||||
|
||||
main.o: uwsgi.c
|
||||
$(CC) -c $(CFLAGS) -o main.o uwsgi.c
|
||||
|
||||
clean:
|
||||
rm -f utils.o main.o
|
||||
@@ -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 */
|
||||
};
|
||||
|
||||
+169
-50
@@ -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
|
||||
@@ -24,8 +24,8 @@ To compile:
|
||||
apxs2 -i -c mod_uwsgi.c
|
||||
(OSX)
|
||||
sudo apxs -i -a -c mod_uwsgi.c
|
||||
(OSX 64bit)
|
||||
sudo apxs -i -a -c -Wc,'-arch x86_64' -Wl,'-arch x86_64' mod_uwsgi.c
|
||||
(OSX Universal binary)
|
||||
sudo apxs -i -a -c -Wc,"-arch ppc -arch i386 -arch x86_64" -Wl,"-arch ppc -arch i386 -arch x86_64" mod_uwsgi.c
|
||||
|
||||
|
||||
Configure:
|
||||
@@ -71,25 +71,73 @@ typedef struct {
|
||||
uint8_t modifier1;
|
||||
uint8_t modifier2;
|
||||
char script_name[256];
|
||||
char scheme[9];
|
||||
int cgi_mode ;
|
||||
} uwsgi_cfg;
|
||||
|
||||
module AP_MODULE_DECLARE_DATA uwsgi_module;
|
||||
|
||||
#if APR_IS_BIGENDIAN
|
||||
static uint16_t uwsgi_swap16(uint16_t x) {
|
||||
return (uint16_t) ((x & 0xff) << 8 | (x & 0xff00) >> 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int uwsgi_add_var(struct iovec *vec, int i, char *key, char *value, uint16_t *pkt_size) {
|
||||
|
||||
vec[i].iov_base = &vec[i+1].iov_len ;
|
||||
vec[i].iov_len = 2 ;
|
||||
|
||||
#if APR_IS_BIGENDIAN
|
||||
char *ptr;
|
||||
vec[i+2].iov_base = key ;
|
||||
vec[i+2].iov_len = strlen(key) ;
|
||||
#else
|
||||
vec[i+1].iov_base = key ;
|
||||
vec[i+1].iov_len = strlen(key) ;
|
||||
vec[i+2].iov_base = &vec[i+3].iov_len ;
|
||||
vec[i+2].iov_len = 2 ;
|
||||
vec[i+3].iov_base = value ;
|
||||
vec[i+3].iov_len = strlen(value) ;
|
||||
#endif
|
||||
|
||||
#if APR_IS_BIGENDIAN
|
||||
ptr = (char *) &vec[i+2].iov_len;
|
||||
vec[i].iov_base = ptr+sizeof(long)-1 ;
|
||||
vec[i].iov_len = 1 ;
|
||||
vec[i+1].iov_base = ptr+sizeof(long)-2 ;
|
||||
vec[i+1].iov_len = 1 ;
|
||||
#else
|
||||
vec[i].iov_base = &vec[i+1].iov_len ;
|
||||
vec[i].iov_len = 2 ;
|
||||
#endif
|
||||
|
||||
|
||||
#if APR_IS_BIGENDIAN
|
||||
vec[i+5].iov_base = value ;
|
||||
vec[i+5].iov_len = strlen(value) ;
|
||||
#else
|
||||
vec[i+3].iov_base = value ;
|
||||
vec[i+3].iov_len = strlen(value) ;
|
||||
#endif
|
||||
|
||||
#if APR_IS_BIGENDIAN
|
||||
ptr = (char *) &vec[i+5].iov_len;
|
||||
vec[i+3].iov_base = ptr+sizeof(long)-1 ;
|
||||
vec[i+3].iov_len = 1 ;
|
||||
vec[i+4].iov_base = ptr+sizeof(long)-2 ;
|
||||
vec[i+4].iov_len = 1 ;
|
||||
#else
|
||||
vec[i+2].iov_base = &vec[i+3].iov_len ;
|
||||
vec[i+2].iov_len = 2 ;
|
||||
#endif
|
||||
|
||||
|
||||
#if APR_IS_BIGENDIAN
|
||||
*pkt_size+= vec[i+2].iov_len + vec[i+5].iov_len + 4 ;
|
||||
#else
|
||||
*pkt_size+= vec[i+1].iov_len + vec[i+3].iov_len + 4 ;
|
||||
#endif
|
||||
|
||||
#if APR_IS_BIGENDIAN
|
||||
return i+6;
|
||||
#else
|
||||
return i+4;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void *uwsgi_server_config(apr_pool_t *p, server_rec *s) {
|
||||
@@ -195,12 +243,17 @@ static int uwsgi_handler(request_rec *r) {
|
||||
|
||||
uwsgi_cfg *c = ap_get_module_config(r->per_dir_config, &uwsgi_module);
|
||||
|
||||
#if APR_IS_BIGENDIAN
|
||||
struct iovec uwsgi_vars[(MAX_VARS*6)+1] ;
|
||||
#else
|
||||
struct iovec uwsgi_vars[(MAX_VARS*4)+1] ;
|
||||
#endif
|
||||
int vecptr = 1 ;
|
||||
char pkt_header[4];
|
||||
uint16_t pkt_size = 0;
|
||||
char buf[4096] ;
|
||||
int cnt,i ;
|
||||
int i ;
|
||||
ssize_t cnt ;
|
||||
const apr_array_header_t *headers;
|
||||
apr_table_entry_t *h;
|
||||
char *penv, *cp;
|
||||
@@ -211,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"))
|
||||
@@ -234,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);
|
||||
@@ -270,11 +321,18 @@ 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->args : "", &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "REMOTE_USER", r->user ? r->user : "", &pkt_size) ;
|
||||
if (r->user) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "AUTH_TYPE", (char *) ap_auth_type(r), &pkt_size) ;
|
||||
}
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "DOCUMENT_ROOT", (char *) ap_document_root(r), &pkt_size) ;
|
||||
|
||||
if (c->scheme[0] != 0) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "UWSGI_SCHEME", c->scheme, &pkt_size) ;
|
||||
}
|
||||
|
||||
if (c->script_name[0] == '/') {
|
||||
if (c->script_name[1] == 0) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "SCRIPT_NAME", "", &pkt_size) ;
|
||||
@@ -302,6 +360,7 @@ static int uwsgi_handler(request_rec *r) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
headers = apr_table_elts(r->headers_in);
|
||||
h = (apr_table_entry_t *) headers->elts;
|
||||
|
||||
@@ -333,13 +392,26 @@ 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;
|
||||
uwsgi_vars[0].iov_len = 4;
|
||||
|
||||
pkt_header[0] = c->modifier1 ;
|
||||
#if APR_IS_BIGENDIAN
|
||||
pkt_size = uwsgi_swap16(pkt_size);
|
||||
memcpy(pkt_header+1, &pkt_size, 2);
|
||||
pkt_size = uwsgi_swap16(pkt_size);
|
||||
#else
|
||||
memcpy(pkt_header+1, &pkt_size, 2);
|
||||
#endif
|
||||
pkt_header[3] = c->modifier2 ;
|
||||
|
||||
cnt = writev( uwsgi_poll.fd, uwsgi_vars, vecptr );
|
||||
@@ -354,6 +426,7 @@ static int uwsgi_handler(request_rec *r) {
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (ap_should_client_block(r)) {
|
||||
while ((cnt = ap_get_client_block(r, buf, 4096)) > 0) {
|
||||
@@ -366,62 +439,92 @@ static int uwsgi_handler(request_rec *r) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!c->cgi_mode) {
|
||||
r->assbackwards = 1 ;
|
||||
uwsgi_http_status[13] = 0 ;
|
||||
uwsgi_http_status[12] = 0 ;
|
||||
}
|
||||
|
||||
|
||||
bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
|
||||
|
||||
uwsgi_poll.events = POLLIN ;
|
||||
|
||||
|
||||
|
||||
for(;;) {
|
||||
/* put -1 to disable timeout on zero */
|
||||
cnt = poll(&uwsgi_poll, 1, (c->socket_timeout*1000)-1) ;
|
||||
if (cnt == 0) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: recv() timeout");
|
||||
break;
|
||||
apr_brigade_destroy(bb);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
else if (cnt > 0) {
|
||||
cnt = recv(uwsgi_poll.fd, buf, 4096, 0) ;
|
||||
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 if (cnt == 0) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: recv() %s", strerror(errno));
|
||||
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));
|
||||
break;
|
||||
close(uwsgi_poll.fd);
|
||||
apr_brigade_destroy(bb);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
close(uwsgi_poll.fd);
|
||||
|
||||
|
||||
b = apr_bucket_eos_create(r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||
|
||||
if (!c->cgi_mode) {
|
||||
if (uwsgi_http_status_read == 0) {
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
b = apr_bucket_eos_create(r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||
|
||||
if (hret = ap_scan_script_header_err_brigade(r, bb, NULL)) {
|
||||
apr_brigade_destroy(bb);
|
||||
@@ -429,7 +532,8 @@ static int uwsgi_handler(request_rec *r) {
|
||||
}
|
||||
}
|
||||
|
||||
return ap_pass_brigade(r->output_filters, bb);
|
||||
|
||||
return ap_pass_brigade(r->output_filters, bb) ;
|
||||
}
|
||||
|
||||
static const char * cmd_uwsgi_force_script_name(cmd_parms *cmd, void *cfg, const char *location) {
|
||||
@@ -446,6 +550,20 @@ static const char * cmd_uwsgi_force_script_name(cmd_parms *cmd, void *cfg, const
|
||||
|
||||
}
|
||||
|
||||
static const char * cmd_uwsgi_force_wsgi_scheme(cmd_parms *cmd, void *cfg, const char *scheme) {
|
||||
uwsgi_cfg *c = cfg;
|
||||
|
||||
if (strlen(scheme) < 9 & strlen(scheme) > 0) {
|
||||
strcpy(c->scheme, scheme);
|
||||
}
|
||||
else {
|
||||
return "ignored uWSGIforceWSGIscheme. Invalid size (max 8 chars)" ;
|
||||
}
|
||||
|
||||
return NULL ;
|
||||
|
||||
}
|
||||
|
||||
static const char * cmd_uwsgi_modifier1(cmd_parms *cmd, void *cfg, const char *value) {
|
||||
|
||||
uwsgi_cfg *c ;
|
||||
@@ -588,6 +706,7 @@ static const command_rec uwsgi_cmds[] = {
|
||||
AP_INIT_TAKE1("uWSGImodifier2", cmd_uwsgi_modifier2, NULL, RSRC_CONF|ACCESS_CONF, "Set uWSGI modifier2"),
|
||||
AP_INIT_TAKE1("uWSGIforceScriptName", cmd_uwsgi_force_script_name, NULL, ACCESS_CONF, "Fix for PATH_INFO/SCRIPT_NAME when the location has filesystem correspondence"),
|
||||
AP_INIT_TAKE1("uWSGIforceCGImode", cmd_uwsgi_force_cgi_mode, NULL, ACCESS_CONF, "Force uWSGI CGI mode for perfect integration with apache filter"),
|
||||
AP_INIT_TAKE1("uWSGIforceWSGIscheme", cmd_uwsgi_force_wsgi_scheme, NULL, ACCESS_CONF, "Force the WSGI scheme var (set by default to \"http\")"),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,426 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct wsgi_request *find_wsgi_req_proto_by_fd(int fd) {
|
||||
return uwsgi.async_proto_fd_table[fd];
|
||||
}
|
||||
|
||||
struct wsgi_request *find_wsgi_req_by_fd(int fd) {
|
||||
return uwsgi.async_waiting_fd_table[fd];
|
||||
}
|
||||
|
||||
void runqueue_remove(struct uwsgi_async_request *u_request) {
|
||||
|
||||
struct uwsgi_async_request *parent = u_request->prev;
|
||||
struct uwsgi_async_request *child = u_request->next;
|
||||
|
||||
if (parent) {
|
||||
parent->next = child;
|
||||
}
|
||||
if (child) {
|
||||
child->prev = parent;
|
||||
}
|
||||
|
||||
if (parent == NULL) {
|
||||
uwsgi.async_runqueue = child;
|
||||
}
|
||||
|
||||
if (u_request == uwsgi.async_runqueue_last) {
|
||||
uwsgi.async_runqueue_last = parent;
|
||||
}
|
||||
|
||||
free(u_request);
|
||||
|
||||
uwsgi.async_runqueue_cnt--;
|
||||
}
|
||||
|
||||
void runqueue_push(struct wsgi_request *wsgi_req) {
|
||||
|
||||
struct uwsgi_async_request *uar;
|
||||
|
||||
if (uwsgi.async_runqueue == NULL) {
|
||||
// empty runqueue, create a new one
|
||||
uwsgi.async_runqueue = uwsgi_malloc(sizeof(struct uwsgi_async_request));
|
||||
uwsgi.async_runqueue->next = NULL;
|
||||
uwsgi.async_runqueue->prev = NULL;
|
||||
uwsgi.async_runqueue->wsgi_req = wsgi_req;
|
||||
uwsgi.async_runqueue_last = uwsgi.async_runqueue;
|
||||
}
|
||||
else {
|
||||
uar = uwsgi_malloc(sizeof(struct uwsgi_async_request));
|
||||
uar->prev = uwsgi.async_runqueue_last;
|
||||
uar->next = NULL;
|
||||
uar->wsgi_req = wsgi_req;
|
||||
uwsgi.async_runqueue_last->next = uar;
|
||||
uwsgi.async_runqueue_last = uar;
|
||||
}
|
||||
|
||||
uwsgi.async_runqueue_cnt++;
|
||||
|
||||
}
|
||||
|
||||
struct wsgi_request *find_first_available_wsgi_req() {
|
||||
|
||||
struct wsgi_request *wsgi_req;
|
||||
|
||||
if (uwsgi.async_queue_unused_ptr < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wsgi_req = uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr];
|
||||
uwsgi.async_queue_unused_ptr--;
|
||||
return wsgi_req;
|
||||
}
|
||||
|
||||
void async_expire_timeouts() {
|
||||
|
||||
struct wsgi_request *wsgi_req;
|
||||
time_t current_time = time(NULL);
|
||||
struct uwsgi_async_fd *uaf = NULL, *current_uaf;
|
||||
|
||||
struct uwsgi_rb_timer *urbt;
|
||||
|
||||
for(;;) {
|
||||
|
||||
urbt = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts);
|
||||
|
||||
if (urbt == NULL) return;
|
||||
|
||||
if (urbt->key <= current_time) {
|
||||
wsgi_req = (struct wsgi_request *) urbt->data;
|
||||
// timeout expired
|
||||
wsgi_req->async_timed_out = 1;
|
||||
rb_erase(&wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts);
|
||||
free(wsgi_req->async_timeout);
|
||||
wsgi_req->async_timeout = NULL;
|
||||
uaf = wsgi_req->waiting_fds;
|
||||
// remove fds from monitoring (no problem modifying the queue here, as the function is executed only when there are no fd ready)
|
||||
while(uaf) {
|
||||
event_queue_del_fd(uwsgi.async_queue, uaf->fd, uaf->event);
|
||||
uwsgi.async_waiting_fd_table[uaf->fd] = NULL;
|
||||
current_uaf = uaf;
|
||||
uaf = current_uaf->next;
|
||||
free(current_uaf);
|
||||
}
|
||||
wsgi_req->waiting_fds = NULL;
|
||||
// put th request in the runqueue
|
||||
runqueue_push(wsgi_req);
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void async_add_fd_read(struct wsgi_request *wsgi_req, int fd, int timeout) {
|
||||
|
||||
struct uwsgi_async_fd *last_uad = NULL, *uad = wsgi_req->waiting_fds;
|
||||
|
||||
if (fd < 0) return ;
|
||||
|
||||
// find first slot
|
||||
while(uad) {
|
||||
last_uad = uad;
|
||||
uad = uad->next;
|
||||
}
|
||||
|
||||
uad = uwsgi_malloc(sizeof(struct uwsgi_async_fd));
|
||||
uad->fd = fd;
|
||||
uad->event = event_queue_read();
|
||||
uad->prev = last_uad;
|
||||
uad->next = NULL;
|
||||
|
||||
if (last_uad) {
|
||||
last_uad->next = uad;
|
||||
}
|
||||
else {
|
||||
wsgi_req->waiting_fds = uad;
|
||||
}
|
||||
|
||||
if (timeout > 0) {
|
||||
async_add_timeout(wsgi_req, timeout);
|
||||
}
|
||||
uwsgi.async_waiting_fd_table[fd] = wsgi_req;
|
||||
event_queue_add_fd_read(uwsgi.async_queue, fd);
|
||||
|
||||
}
|
||||
|
||||
void async_add_timeout(struct wsgi_request *wsgi_req, int timeout) {
|
||||
|
||||
if (timeout > 0 && wsgi_req->async_timeout == NULL) {
|
||||
wsgi_req->async_timeout = uwsgi_add_rb_timer(uwsgi.rb_async_timeouts, time(NULL)+timeout, wsgi_req);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void async_add_fd_write(struct wsgi_request *wsgi_req, int fd, int timeout) {
|
||||
|
||||
struct uwsgi_async_fd *last_uad = NULL, *uad = wsgi_req->waiting_fds;
|
||||
|
||||
if (fd < 0) return ;
|
||||
|
||||
// find first slot
|
||||
while(uad) {
|
||||
last_uad = uad;
|
||||
uad = uad->next;
|
||||
}
|
||||
|
||||
uad = uwsgi_malloc(sizeof(struct uwsgi_async_fd));
|
||||
uad->fd = fd;
|
||||
uad->event = event_queue_write();
|
||||
uad->prev = last_uad;
|
||||
uad->next = NULL;
|
||||
|
||||
if (last_uad) {
|
||||
last_uad->next = uad;
|
||||
}
|
||||
else {
|
||||
wsgi_req->waiting_fds = uad;
|
||||
}
|
||||
|
||||
if (timeout > 0) {
|
||||
async_add_timeout(wsgi_req, timeout);
|
||||
}
|
||||
|
||||
uwsgi.async_waiting_fd_table[fd] = wsgi_req;
|
||||
event_queue_add_fd_write(uwsgi.async_queue, fd);
|
||||
|
||||
}
|
||||
|
||||
void async_schedule_to_req(void) {
|
||||
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh.modifier1]->request(uwsgi.wsgi_req);
|
||||
}
|
||||
|
||||
void *async_loop(void *arg1) {
|
||||
|
||||
struct uwsgi_async_fd *tmp_uaf;
|
||||
int interesting_fd, i;
|
||||
struct uwsgi_rb_timer *min_timeout;
|
||||
int timeout;
|
||||
int is_a_new_connection;
|
||||
int proto_parser_status;
|
||||
|
||||
static struct uwsgi_async_request *current_request = NULL, *next_async_request = NULL;
|
||||
|
||||
void *events = event_queue_alloc(64);
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
|
||||
uwsgi.async_runqueue = NULL;
|
||||
uwsgi.async_runqueue_cnt = 0;
|
||||
|
||||
// set a default request manager
|
||||
if (!uwsgi.schedule_to_req) uwsgi.schedule_to_req = async_schedule_to_req;
|
||||
|
||||
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
|
||||
|
||||
if (uwsgi.async_runqueue_cnt) {
|
||||
timeout = 0;
|
||||
}
|
||||
else {
|
||||
min_timeout = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts);
|
||||
if (uwsgi.async_runqueue_cnt) {
|
||||
timeout = 0;
|
||||
}
|
||||
if (min_timeout) {
|
||||
timeout = min_timeout->key - time(NULL);
|
||||
if (timeout <= 0) {
|
||||
async_expire_timeouts();
|
||||
timeout = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
timeout = -1;
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi.async_nevents = event_queue_wait_multi(uwsgi.async_queue, timeout, events, 64);
|
||||
|
||||
// timeout ???
|
||||
if (uwsgi.async_nevents == 0) {
|
||||
async_expire_timeouts();
|
||||
}
|
||||
|
||||
|
||||
for(i=0;i<uwsgi.async_nevents;i++) {
|
||||
// manage events
|
||||
interesting_fd = event_queue_interesting_fd(events, i);
|
||||
|
||||
is_a_new_connection = 0;
|
||||
|
||||
// new request coming in ?
|
||||
|
||||
uwsgi_sock = uwsgi.sockets;
|
||||
while(uwsgi_sock) {
|
||||
|
||||
if (interesting_fd == uwsgi_sock->fd) {
|
||||
|
||||
is_a_new_connection = 1;
|
||||
|
||||
uwsgi.wsgi_req = find_first_available_wsgi_req();
|
||||
if (uwsgi.wsgi_req == NULL) {
|
||||
uwsgi_log("async queue is full !!!\n");
|
||||
break;;
|
||||
}
|
||||
|
||||
wsgi_req_setup(uwsgi.wsgi_req, uwsgi.wsgi_req->async_id, uwsgi_sock );
|
||||
if (wsgi_req_simple_accept(uwsgi.wsgi_req, interesting_fd)) {
|
||||
#ifdef UWSGI_EVENT_USE_PORT
|
||||
event_queue_add_fd_read(uwsgi.async_queue, interesting_fd);
|
||||
#endif
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
|
||||
break;
|
||||
}
|
||||
#ifdef UWSGI_EVENT_USE_PORT
|
||||
event_queue_add_fd_read(uwsgi.async_queue, interesting_fd);
|
||||
#endif
|
||||
|
||||
// on linux we do not need to reset the socket to blocking state
|
||||
#ifndef __linux__
|
||||
if (uwsgi.numproc > 1) {
|
||||
/* re-set blocking socket */
|
||||
if (fcntl(uwsgi.wsgi_req->poll.fd, F_SETFL, uwsgi_sock->arg) < 0) {
|
||||
uwsgi_error("fcntl()");
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wsgi_req_async_recv(uwsgi.wsgi_req)) {
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
|
||||
break;
|
||||
}
|
||||
|
||||
if (uwsgi.wsgi_req->do_not_add_to_async_queue) {
|
||||
runqueue_push(uwsgi.wsgi_req);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
if (!is_a_new_connection) {
|
||||
// proto event
|
||||
uwsgi.wsgi_req = find_wsgi_req_proto_by_fd(interesting_fd);
|
||||
if (uwsgi.wsgi_req) {
|
||||
proto_parser_status = uwsgi.wsgi_req->socket->proto(uwsgi.wsgi_req);
|
||||
// reset timeout
|
||||
rb_erase(&uwsgi.wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts);
|
||||
free(uwsgi.wsgi_req->async_timeout);
|
||||
uwsgi.wsgi_req->async_timeout = NULL;
|
||||
// parsing complete
|
||||
if (!proto_parser_status) {
|
||||
// remove fd from event poll and fd proto table
|
||||
event_queue_del_fd(uwsgi.async_queue, interesting_fd, event_queue_read());
|
||||
uwsgi.async_proto_fd_table[interesting_fd] = NULL;
|
||||
// put request in the runqueue
|
||||
runqueue_push(uwsgi.wsgi_req);
|
||||
continue;
|
||||
}
|
||||
else if (proto_parser_status == -1) {
|
||||
uwsgi_log("error parsing request\n");
|
||||
uwsgi.async_proto_fd_table[interesting_fd] = NULL;
|
||||
close(interesting_fd);
|
||||
continue;
|
||||
}
|
||||
// re-add timer
|
||||
async_add_timeout(uwsgi.wsgi_req, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// app event
|
||||
uwsgi.wsgi_req = find_wsgi_req_by_fd(interesting_fd);
|
||||
// unknown fd, remove it (for safety)
|
||||
if (uwsgi.wsgi_req == NULL) {
|
||||
close(interesting_fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
// remove all the fd monitors and timeout
|
||||
while(uwsgi.wsgi_req->waiting_fds) {
|
||||
#ifndef UWSGI_EVENT_USE_PORT
|
||||
event_queue_del_fd(uwsgi.async_queue, uwsgi.wsgi_req->waiting_fds->fd, uwsgi.wsgi_req->waiting_fds->event);
|
||||
#endif
|
||||
tmp_uaf = uwsgi.wsgi_req->waiting_fds;
|
||||
uwsgi.async_waiting_fd_table[tmp_uaf->fd] = NULL;
|
||||
uwsgi.wsgi_req->waiting_fds = tmp_uaf->next;
|
||||
free(tmp_uaf);
|
||||
}
|
||||
uwsgi.wsgi_req->waiting_fds = NULL;
|
||||
if (uwsgi.wsgi_req->async_timeout) {
|
||||
rb_erase(&uwsgi.wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts);
|
||||
free(uwsgi.wsgi_req->async_timeout);
|
||||
uwsgi.wsgi_req->async_timeout = NULL;
|
||||
}
|
||||
|
||||
uwsgi.wsgi_req->async_ready_fd = 1;
|
||||
uwsgi.wsgi_req->async_last_ready_fd = interesting_fd;
|
||||
|
||||
// put the request in the runqueue again
|
||||
runqueue_push(uwsgi.wsgi_req);
|
||||
}
|
||||
}
|
||||
|
||||
// event queue managed, give cpu to runqueue
|
||||
if (!current_request)
|
||||
current_request = uwsgi.async_runqueue;
|
||||
|
||||
if (uwsgi.async_runqueue_cnt) {
|
||||
|
||||
uwsgi.wsgi_req = current_request->wsgi_req;
|
||||
|
||||
uwsgi.schedule_to_req();
|
||||
uwsgi.wsgi_req->switches++;
|
||||
|
||||
next_async_request = current_request->next;
|
||||
// request ended ?
|
||||
if (uwsgi.wsgi_req->async_status <= UWSGI_OK) {
|
||||
// remove all the monitored fds and timeout
|
||||
while(uwsgi.wsgi_req->waiting_fds) {
|
||||
#ifndef UWSGI_EVENT_USE_PORT
|
||||
event_queue_del_fd(uwsgi.async_queue, uwsgi.wsgi_req->waiting_fds->fd, uwsgi.wsgi_req->waiting_fds->event);
|
||||
#endif
|
||||
tmp_uaf = uwsgi.wsgi_req->waiting_fds;
|
||||
uwsgi.async_waiting_fd_table[tmp_uaf->fd] = NULL;
|
||||
uwsgi.wsgi_req->waiting_fds = tmp_uaf->next;
|
||||
free(tmp_uaf);
|
||||
}
|
||||
uwsgi.wsgi_req->waiting_fds = NULL;
|
||||
if (uwsgi.wsgi_req->async_timeout) {
|
||||
rb_erase(&uwsgi.wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts);
|
||||
free(uwsgi.wsgi_req->async_timeout);
|
||||
uwsgi.wsgi_req->async_timeout = NULL;
|
||||
}
|
||||
|
||||
// remove from the list
|
||||
runqueue_remove(current_request);
|
||||
|
||||
uwsgi_close_request(uwsgi.wsgi_req);
|
||||
|
||||
// push wsgi_request in the unused stack
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
|
||||
|
||||
}
|
||||
else if (uwsgi.wsgi_req->waiting_fds || uwsgi.wsgi_req->async_timeout) {
|
||||
// remove this request from suspended list
|
||||
runqueue_remove(current_request);
|
||||
}
|
||||
|
||||
current_request = next_async_request;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
all: clean uwsgi
|
||||
|
||||
uwsgi: utils.o protocol.o socket.o pymodule.o spooler.o main.o
|
||||
$(CC) $(LD_FLAGS) utils.o protocol.o socket.o spooler.o pymodule.o main.o -o $(PROGRAM)
|
||||
|
||||
utils.o: utils.c
|
||||
$(CC) -c $(CFLAGS) utils.c
|
||||
|
||||
protocol.o: protocol.c
|
||||
$(CC) -c $(CFLAGS) protocol.c
|
||||
|
||||
socket.o: socket.c
|
||||
$(CC) -c $(CFLAGS) socket.c
|
||||
|
||||
spooler.o: spooler.c
|
||||
$(CC) -c $(CFLAGS) spooler.c
|
||||
|
||||
pymodule.o: uwsgi_pymodule.c
|
||||
$(CC) -c $(CFLAGS) -o pymodule.o uwsgi_pymodule.c
|
||||
|
||||
main.o: uwsgi.c
|
||||
$(CC) -c $(CFLAGS) -o main.o uwsgi.c
|
||||
|
||||
clean:
|
||||
rm -f utils.o protocol.o socket.o pymodule.o spooler.o main.o
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = null
|
||||
@@ -0,0 +1,38 @@
|
||||
[uwsgi]
|
||||
xml = true
|
||||
ini = true
|
||||
yaml = true
|
||||
json = auto
|
||||
sqlite3 = auto
|
||||
zeromq = auto
|
||||
snmp = true
|
||||
sctp = false
|
||||
spooler = true
|
||||
embedded = true
|
||||
udp = true
|
||||
multicast = true
|
||||
threading = true
|
||||
sendfile = true
|
||||
minterpreters = true
|
||||
async = true
|
||||
evdis = false
|
||||
ldap = auto
|
||||
pcre = auto
|
||||
debug = false
|
||||
unbit = false
|
||||
xml_implementation = libxml2
|
||||
yaml_implementation = auto
|
||||
malloc_implementation = libc
|
||||
plugins =
|
||||
bin_name = uwsgi
|
||||
plugin_dir = .
|
||||
embedded_plugins = python, ping, cache, nagios, rpc, fastrouter, http, ugreen
|
||||
|
||||
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,5 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
plugins = python, ping, rack, psgi, cache, http, fastrouter
|
||||
plugin_dir = plugins
|
||||
embedded_plugins = null
|
||||
@@ -0,0 +1,4 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
plugin_dir = /usr/lib/uwsgi
|
||||
embedded_plugins = null
|
||||
@@ -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,5 @@
|
||||
[uwsgi]
|
||||
inherit = unbit
|
||||
embedded_plugins = python
|
||||
bin_name = ../bin/uwsgi
|
||||
plugin_dir = ../bin/uwsgi_plugins
|
||||
@@ -0,0 +1,580 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_init_cache() {
|
||||
int i;
|
||||
|
||||
if (!uwsgi.cache_blocksize)
|
||||
uwsgi.cache_blocksize = UMAX16;
|
||||
|
||||
if (uwsgi.cache_blocksize % uwsgi.page_size != 0) {
|
||||
uwsgi_log("invalid cache blocksize %llu: must be a multiple of memory page size (%d bytes)\n", (unsigned long long) uwsgi.cache_blocksize, uwsgi.page_size);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi.cache_hashtable = (uint64_t *) mmap(NULL, sizeof(uint64_t) * UMAX16, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (!uwsgi.cache_hashtable) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(uwsgi.cache_hashtable, 0, sizeof(uint64_t) * UMAX16);
|
||||
|
||||
uwsgi.cache_unused_stack = (uint64_t *) mmap(NULL, sizeof(uint64_t) * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (!uwsgi.cache_unused_stack) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(uwsgi.cache_unused_stack, 0, sizeof(uint64_t) * uwsgi.cache_max_items);
|
||||
|
||||
// the first cache item is always zero
|
||||
uwsgi.shared->cache_first_available_item = 1;
|
||||
uwsgi.shared->cache_unused_stack_ptr = 0;
|
||||
|
||||
//uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (uwsgi.cache_store) {
|
||||
uwsgi.cache_filesize = (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items) + (uwsgi.cache_blocksize * uwsgi.cache_max_items);
|
||||
int cache_fd;
|
||||
struct stat cst;
|
||||
|
||||
if (stat(uwsgi.cache_store, &cst)) {
|
||||
uwsgi_log("creating a new cache store file: %s\n", uwsgi.cache_store);
|
||||
cache_fd = open(uwsgi.cache_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
if (cache_fd >= 0) {
|
||||
// fill the caching store
|
||||
if (ftruncate(cache_fd, uwsgi.cache_filesize)) {
|
||||
uwsgi_log("ftruncate()");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((size_t) cst.st_size != uwsgi.cache_filesize || !S_ISREG(cst.st_mode)) {
|
||||
uwsgi_log("invalid cache store file. Please remove it or fix cache blocksize/items to match its size\n");
|
||||
exit(1);
|
||||
}
|
||||
cache_fd = open(uwsgi.cache_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
uwsgi_log("recovered cache from backing store file: %s\n", uwsgi.cache_store);
|
||||
}
|
||||
|
||||
if (cache_fd < 0) {
|
||||
uwsgi_error_open(uwsgi.cache_store);
|
||||
exit(1);
|
||||
}
|
||||
uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, uwsgi.cache_filesize, PROT_READ | PROT_WRITE, MAP_SHARED, cache_fd, 0);
|
||||
uwsgi_cache_fix();
|
||||
|
||||
}
|
||||
else {
|
||||
uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items) + (uwsgi.cache_blocksize * uwsgi.cache_max_items), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
for (i = 0; i < (int) uwsgi.cache_max_items; i++) {
|
||||
memset(&uwsgi.cache_items[i], 0, sizeof(struct uwsgi_cache_item));
|
||||
}
|
||||
}
|
||||
if (!uwsgi.cache_items) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
uwsgi.cache = mmap(NULL, uwsgi.cache_blocksize * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (!uwsgi.cache) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
*/
|
||||
|
||||
uwsgi.cache = ((void *) uwsgi.cache_items) + (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items);
|
||||
|
||||
uwsgi.cache_lock = uwsgi_mmap_shared_rwlock();
|
||||
uwsgi_rwlock_init(uwsgi.cache_lock);
|
||||
|
||||
uwsgi_log("*** Cache subsystem initialized: %dMB preallocated ***\n", ((sizeof(uint64_t) * UMAX16) + (sizeof(uint64_t) * uwsgi.cache_max_items) + (uwsgi.cache_blocksize * uwsgi.cache_max_items) + (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items)) / (1024 * 1024));
|
||||
}
|
||||
|
||||
struct uwsgi_subscriber_name *uwsgi_get_subscriber(struct uwsgi_dict *udict, char *key, uint16_t keylen) {
|
||||
|
||||
uint64_t ovl;
|
||||
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;
|
||||
}
|
||||
|
||||
void uwsgi_cache_fix() {
|
||||
|
||||
uint64_t i;
|
||||
|
||||
for(i=0;i< uwsgi.cache_max_items;i++) {
|
||||
// valid record ?
|
||||
if (uwsgi.cache_items[i].keysize) {
|
||||
if (!uwsgi.cache_items[i].prev) {
|
||||
// put value in hash_table
|
||||
uwsgi.cache_hashtable[ uwsgi.cache_items[i].djbhash % 0xffff] = i;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// put this record in unused stack
|
||||
uwsgi.shared->cache_first_available_item = i;
|
||||
uwsgi.shared->cache_unused_stack_ptr++;
|
||||
uwsgi.cache_unused_stack[uwsgi.shared->cache_unused_stack_ptr] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
the uwsgi handler is included in the official Cherokee distribution
|
||||
@@ -1,92 +0,0 @@
|
||||
from Form import *
|
||||
from Table import *
|
||||
from Module import *
|
||||
from validations import *
|
||||
from consts import *
|
||||
|
||||
# For gettext
|
||||
N_ = lambda x: x
|
||||
|
||||
from ModuleCgi import *
|
||||
from ModuleBalancer import NOTE_BALANCER
|
||||
|
||||
HELPS = [
|
||||
('modules_handlers_uwsgi', "UWSGI")
|
||||
]
|
||||
|
||||
class ModuleUwsgi (ModuleCgiBase):
|
||||
PROPERTIES = ModuleCgiBase.PROPERTIES + [
|
||||
'balancer',
|
||||
'modifier1',
|
||||
'modifier2',
|
||||
'pass_wsgi_vars',
|
||||
'pass_request_body'
|
||||
]
|
||||
|
||||
def __init__ (self, cfg, prefix, submit):
|
||||
ModuleCgiBase.__init__ (self, cfg, prefix, 'uwsgi', submit)
|
||||
|
||||
self.show_script_alias = False
|
||||
self.show_change_uid = False
|
||||
self.show_document_root = True
|
||||
|
||||
def _op_render (self):
|
||||
txt = ModuleCgiBase._op_render (self)
|
||||
|
||||
txt += '<h2>%s</h2>' % (_('UWSGI specific'))
|
||||
|
||||
table = TableProps()
|
||||
|
||||
|
||||
opt = "%s!modifier1" % (self._prefix)
|
||||
self.AddPropEntry(table, _('Modifier1'), opt, 'a number between 0 and 255', size=3);
|
||||
|
||||
opt = "%s!modifier2" % (self._prefix)
|
||||
self.AddPropEntry(table, _('Modifier2'), opt, 'a number between 0 and 255', size=3);
|
||||
|
||||
opt = "%s!pass_wsgi_vars" % (self._prefix)
|
||||
self.AddPropCheck (table, _("Pass WSGI vars"), opt, True, 'pass all the wsgi vars to the application')
|
||||
|
||||
opt = "%s!pass_request_body" % (self._prefix)
|
||||
self.AddPropCheck (table, _("Pass Request body"), opt, True, 'pass the request body to the application')
|
||||
|
||||
opt = "%s!balancer" % (self._prefix)
|
||||
e = self.AddPropOptions_Reload_Module (table, _("Balancer"), opt,
|
||||
modules_available(BALANCERS), _(NOTE_BALANCER))
|
||||
|
||||
txt += self.Indent(str(table) + e)
|
||||
|
||||
return txt
|
||||
|
||||
def _op_apply_changes (self, uri, post):
|
||||
|
||||
# Apply modifier1
|
||||
opt = "%s!modifier1" % (self._prefix)
|
||||
mod1 = post.pop(opt)
|
||||
if mod1:
|
||||
self._cfg[opt] = mod1
|
||||
|
||||
# Apply modifier2
|
||||
opt = "%s!modifier2" % (self._prefix)
|
||||
mod2 = post.pop(opt)
|
||||
if mod2:
|
||||
self._cfg[opt] = mod2
|
||||
|
||||
# Apply pass_request_body and pass_wsgi_vars
|
||||
self.ApplyChangesPrefix (self._prefix, ['pass_wsgi_vars','pass_request_body'], post)
|
||||
|
||||
# Apply balancer changes
|
||||
pre = "%s!balancer" % (self._prefix)
|
||||
|
||||
new_balancer = post.pop(pre)
|
||||
if new_balancer:
|
||||
self._cfg[pre] = new_balancer
|
||||
|
||||
cfg = self._cfg[pre]
|
||||
if cfg and cfg.value:
|
||||
name = cfg.value
|
||||
props = module_obj_factory (name, self._cfg, pre, self.submit_url)
|
||||
props._op_apply_changes (uri, post)
|
||||
|
||||
# And CGI changes
|
||||
return ModuleCgiBase._op_apply_changes (self, uri, post)
|
||||
@@ -1,452 +0,0 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
|
||||
/* Cherokee
|
||||
*
|
||||
* Authors:
|
||||
* Alvaro Lopez Ortega <alvaro@alobbs.com>
|
||||
*
|
||||
* Copyright (C) 2001-2009 Alvaro Lopez Ortega
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "common-internal.h"
|
||||
#include "handler_uwsgi.h"
|
||||
|
||||
#include "connection.h"
|
||||
#include "source_interpreter.h"
|
||||
#include "thread.h"
|
||||
#include "util.h"
|
||||
#include "connection-protected.h"
|
||||
#include "bogotime.h"
|
||||
|
||||
#define ENTRIES "handler,cgi"
|
||||
|
||||
/* Plug-in initialization
|
||||
*/
|
||||
CGI_LIB_INIT (uwsgi, http_all_methods);
|
||||
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
static uint16_t uwsgi_swap16(uint16_t x) {
|
||||
return (uint16_t) ((x & 0xff) << 8 | (x & 0xff00) >> 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Methods implementation
|
||||
*/
|
||||
static ret_t
|
||||
props_free (cherokee_handler_uwsgi_props_t *props)
|
||||
{
|
||||
if (props->balancer)
|
||||
cherokee_balancer_free (props->balancer);
|
||||
|
||||
return cherokee_handler_cgi_base_props_free (PROP_CGI_BASE(props));
|
||||
}
|
||||
|
||||
ret_t
|
||||
cherokee_handler_uwsgi_configure (cherokee_config_node_t *conf, cherokee_server_t *srv, cherokee_module_props_t **_props)
|
||||
{
|
||||
ret_t ret;
|
||||
cherokee_list_t *i;
|
||||
cherokee_handler_uwsgi_props_t *props;
|
||||
|
||||
/* Instance a new property object
|
||||
*/
|
||||
if (*_props == NULL) {
|
||||
CHEROKEE_NEW_STRUCT (n, handler_uwsgi_props);
|
||||
|
||||
cherokee_handler_cgi_base_props_init_base (PROP_CGI_BASE(n),
|
||||
MODULE_PROPS_FREE(props_free));
|
||||
|
||||
n->balancer = NULL;
|
||||
n->modifier1 = 0 ;
|
||||
n->modifier2 = 0 ;
|
||||
n->pass_wsgi_vars = true;
|
||||
n->pass_request_body = true;
|
||||
|
||||
*_props = MODULE_PROPS(n);
|
||||
}
|
||||
|
||||
props = PROP_UWSGI(*_props);
|
||||
|
||||
/* Parse the configuration tree
|
||||
*/
|
||||
cherokee_config_node_foreach (i, conf) {
|
||||
cherokee_config_node_t *subconf = CONFIG_NODE(i);
|
||||
|
||||
if (equal_buf_str (&subconf->key, "balancer")) {
|
||||
ret = cherokee_balancer_instance (&subconf->val, subconf, srv, &props->balancer);
|
||||
if (ret != ret_ok) return ret;
|
||||
}
|
||||
else if (equal_buf_str (&subconf->key, "modifier1")) {
|
||||
props->modifier1 = (uint8_t) atoi(subconf->val.buf);
|
||||
}
|
||||
else if (equal_buf_str (&subconf->key, "modifier2")) {
|
||||
props->modifier2 = (uint8_t) atoi(subconf->val.buf);
|
||||
}
|
||||
else if (equal_buf_str (&subconf->key, "pass_wsgi_vars")) {
|
||||
props->pass_wsgi_vars = !! atoi (subconf->val.buf);
|
||||
}
|
||||
else if (equal_buf_str (&subconf->key, "pass_request_body")) {
|
||||
props->pass_request_body = !! atoi (subconf->val.buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* Init base class
|
||||
*/
|
||||
ret = cherokee_handler_cgi_base_configure (conf, srv, _props);
|
||||
if (ret != ret_ok) return ret;
|
||||
|
||||
/* Final checks
|
||||
*/
|
||||
if (props->balancer == NULL) {
|
||||
LOG_CRITICAL_S (CHEROKEE_ERROR_HANDLER_NO_BALANCER);
|
||||
return ret_error;
|
||||
}
|
||||
|
||||
return ret_ok;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
add_env_pair (cherokee_handler_cgi_base_t *cgi_base,
|
||||
const char *key, int key_len,
|
||||
const char *val, int val_len)
|
||||
{
|
||||
cherokee_handler_uwsgi_t *uwsgi = HDL_UWSGI(cgi_base);
|
||||
uint16_t u_key_len = (uint16_t) key_len ;
|
||||
uint16_t u_val_len = (uint16_t) val_len ;
|
||||
|
||||
|
||||
/* 2 bytes for every string (16 bit le) */
|
||||
cherokee_buffer_ensure_size (&uwsgi->header, uwsgi->header.len + key_len + val_len + 4);
|
||||
|
||||
/* force to le if cherokee is big-endian */
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
u_key_len = uwsgi_swap16(u_key_len);
|
||||
#endif
|
||||
cherokee_buffer_add (&uwsgi->header, (const char *) &u_key_len, 2);
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
u_key_len = uwsgi_swap16(u_key_len);
|
||||
#endif
|
||||
cherokee_buffer_add (&uwsgi->header, key, key_len);
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
u_val_len = uwsgi_swap16(u_val_len);
|
||||
#endif
|
||||
cherokee_buffer_add (&uwsgi->header, (const char *) &u_val_len, 2);
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
u_val_len = uwsgi_swap16(u_val_len);
|
||||
#endif
|
||||
cherokee_buffer_add (&uwsgi->header, val, val_len);
|
||||
}
|
||||
|
||||
|
||||
static ret_t
|
||||
read_from_uwsgi (cherokee_handler_cgi_base_t *cgi_base, cherokee_buffer_t *buffer)
|
||||
{
|
||||
ret_t ret;
|
||||
size_t read = 0;
|
||||
cherokee_handler_uwsgi_t *uwsgi = HDL_UWSGI(cgi_base);
|
||||
|
||||
ret = cherokee_socket_bufread (&uwsgi->socket, buffer, 4096, &read);
|
||||
|
||||
switch (ret) {
|
||||
case ret_eagain:
|
||||
cherokee_thread_deactive_to_polling (HANDLER_THREAD(cgi_base), HANDLER_CONN(cgi_base),
|
||||
uwsgi->socket.socket, 0, false);
|
||||
return ret_eagain;
|
||||
|
||||
case ret_ok:
|
||||
TRACE (ENTRIES, "%d bytes read\n", read);
|
||||
return ret_ok;
|
||||
|
||||
case ret_eof:
|
||||
case ret_error:
|
||||
cgi_base->got_eof = true;
|
||||
return ret;
|
||||
|
||||
default:
|
||||
RET_UNKNOWN(ret);
|
||||
}
|
||||
|
||||
SHOULDNT_HAPPEN;
|
||||
return ret_error;
|
||||
}
|
||||
|
||||
|
||||
ret_t
|
||||
cherokee_handler_uwsgi_new (cherokee_handler_t **hdl, void *cnt, cherokee_module_props_t *props)
|
||||
{
|
||||
CHEROKEE_NEW_STRUCT (n, handler_uwsgi);
|
||||
|
||||
/* Init the base class
|
||||
*/
|
||||
cherokee_handler_cgi_base_init (
|
||||
HDL_CGI_BASE(n), cnt,
|
||||
PLUGIN_INFO_HANDLER_PTR(uwsgi),
|
||||
HANDLER_PROPS(props),
|
||||
add_env_pair, read_from_uwsgi);
|
||||
|
||||
/* Virtual methods
|
||||
*/
|
||||
MODULE(n)->init = (handler_func_init_t) cherokee_handler_uwsgi_init;
|
||||
MODULE(n)->free = (module_func_free_t) cherokee_handler_uwsgi_free;
|
||||
|
||||
/* Virtual methods: implemented by handler_cgi_base
|
||||
*/
|
||||
HANDLER(n)->step = (handler_func_step_t) cherokee_handler_cgi_base_step;
|
||||
HANDLER(n)->add_headers = (handler_func_add_headers_t) cherokee_handler_cgi_base_add_headers;
|
||||
|
||||
/* Properties
|
||||
*/
|
||||
n->post_len = 0;
|
||||
n->src_ref = NULL;
|
||||
|
||||
cherokee_buffer_init (&n->header);
|
||||
cherokee_socket_init (&n->socket);
|
||||
|
||||
/* Return the object
|
||||
*/
|
||||
*hdl = HANDLER(n);
|
||||
return ret_ok;
|
||||
}
|
||||
|
||||
|
||||
ret_t
|
||||
cherokee_handler_uwsgi_free (cherokee_handler_uwsgi_t *hdl)
|
||||
{
|
||||
/* Free the rest of the handler CGI memory
|
||||
*/
|
||||
cherokee_handler_cgi_base_free (HDL_CGI_BASE(hdl));
|
||||
|
||||
/* UWSGI stuff
|
||||
*/
|
||||
cherokee_socket_close (&hdl->socket);
|
||||
cherokee_socket_mrproper (&hdl->socket);
|
||||
|
||||
cherokee_buffer_mrproper (&hdl->header);
|
||||
|
||||
return ret_ok;
|
||||
}
|
||||
|
||||
|
||||
static ret_t
|
||||
uwsgi_fix_packet (cherokee_buffer_t *buf, uint8_t modifier1, uint8_t modifier2)
|
||||
{
|
||||
|
||||
uwsgi_header uh;
|
||||
|
||||
uh.modifier1 = modifier1 ;
|
||||
uh.modifier2 = modifier2 ;
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
uh.env_size = uwsgi_swap16((uint16_t) buf->len) ;
|
||||
#else
|
||||
uh.env_size = (uint16_t) buf->len ;
|
||||
#endif
|
||||
|
||||
cherokee_buffer_ensure_size (buf, buf->len + 4);
|
||||
cherokee_buffer_prepend (buf, (const char * )&uh, 4);
|
||||
|
||||
return ret_ok;
|
||||
}
|
||||
|
||||
|
||||
static ret_t
|
||||
build_header (cherokee_handler_uwsgi_t *hdl)
|
||||
{
|
||||
|
||||
cherokee_handler_uwsgi_props_t *props = HANDLER_UWSGI_PROPS(hdl);
|
||||
|
||||
cuint_t len;
|
||||
char tmp[64];
|
||||
|
||||
if (props->pass_request_body == true && props->pass_wsgi_vars == true) {
|
||||
len = snprintf (tmp, sizeof(tmp), FMT_OFFSET, (CST_OFFSET)hdl->post_len);
|
||||
add_env_pair(HDL_CGI_BASE(hdl), "CONTENT_LENGTH", 14, tmp, len);
|
||||
}
|
||||
|
||||
if (props->pass_wsgi_vars == true) {
|
||||
cherokee_handler_cgi_base_build_envp (HDL_CGI_BASE(hdl), HANDLER_CONN(hdl));
|
||||
}
|
||||
|
||||
return uwsgi_fix_packet (&hdl->header, props->modifier1, props->modifier2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static ret_t
|
||||
connect_to_server (cherokee_handler_uwsgi_t *hdl)
|
||||
{
|
||||
ret_t ret;
|
||||
cherokee_connection_t *conn = HANDLER_CONN(hdl);
|
||||
cherokee_handler_uwsgi_props_t *props = HANDLER_UWSGI_PROPS(hdl);
|
||||
|
||||
/* Get a reference to the target host
|
||||
*/
|
||||
if (hdl->src_ref == NULL) {
|
||||
ret = cherokee_balancer_dispatch (props->balancer, conn, &hdl->src_ref);
|
||||
if (ret != ret_ok)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Try to connect
|
||||
*/
|
||||
if (hdl->src_ref->type == source_host) {
|
||||
ret = cherokee_source_connect_polling (hdl->src_ref, &hdl->socket, conn);
|
||||
if ((ret == ret_deny) || (ret == ret_error))
|
||||
{
|
||||
cherokee_balancer_report_fail (props->balancer, conn, hdl->src_ref);
|
||||
}
|
||||
} else {
|
||||
ret = cherokee_source_interpreter_connect_polling (SOURCE_INT(hdl->src_ref),
|
||||
&hdl->socket, conn);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static ret_t
|
||||
send_header (cherokee_handler_uwsgi_t *hdl)
|
||||
{
|
||||
ret_t ret;
|
||||
size_t written = 0;
|
||||
cherokee_connection_t *conn = HANDLER_CONN(hdl);
|
||||
|
||||
ret = cherokee_socket_bufwrite (&hdl->socket, &hdl->header, &written);
|
||||
if (ret != ret_ok) {
|
||||
conn->error_code = http_bad_gateway;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
cherokee_buffer_print_debug (&hdl->header, -1);
|
||||
#endif
|
||||
cherokee_buffer_move_to_begin (&hdl->header, written);
|
||||
|
||||
TRACE (ENTRIES, "sent remaining=%d\n", hdl->header.len);
|
||||
|
||||
if (! cherokee_buffer_is_empty (&hdl->header))
|
||||
return ret_eagain;
|
||||
|
||||
return ret_ok;
|
||||
}
|
||||
|
||||
|
||||
static ret_t
|
||||
send_post (cherokee_handler_uwsgi_t *hdl)
|
||||
{
|
||||
ret_t ret;
|
||||
int e_fd = -1;
|
||||
int mode = 0;
|
||||
cherokee_connection_t *conn = HANDLER_CONN(hdl);
|
||||
|
||||
ret = cherokee_post_walk_to_fd (&conn->post, hdl->socket.socket, &e_fd, &mode);
|
||||
|
||||
switch (ret) {
|
||||
case ret_ok:
|
||||
break;
|
||||
case ret_eagain:
|
||||
if (e_fd != -1)
|
||||
cherokee_thread_deactive_to_polling (HANDLER_THREAD(hdl), conn, e_fd, mode, false);
|
||||
return ret_eagain;
|
||||
default:
|
||||
conn->error_code = http_bad_gateway;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret_ok;
|
||||
}
|
||||
|
||||
|
||||
ret_t
|
||||
cherokee_handler_uwsgi_init (cherokee_handler_uwsgi_t *hdl)
|
||||
{
|
||||
ret_t ret;
|
||||
cherokee_connection_t *conn = HANDLER_CONN(hdl);
|
||||
cherokee_handler_uwsgi_props_t *props = HANDLER_UWSGI_PROPS(hdl);
|
||||
|
||||
switch (HDL_CGI_BASE(hdl)->init_phase) {
|
||||
case hcgi_phase_build_headers:
|
||||
TRACE (ENTRIES, "Init: %s\n", "begins");
|
||||
|
||||
/* Extracts PATH_INFO and filename from request uri
|
||||
*/
|
||||
ret = cherokee_handler_cgi_base_extract_path (HDL_CGI_BASE(hdl), false);
|
||||
if (unlikely (ret < ret_ok)) {
|
||||
conn->error_code = http_internal_error;
|
||||
return ret_error;
|
||||
}
|
||||
|
||||
/* Prepare Post
|
||||
*/
|
||||
if (! cherokee_post_is_empty (&conn->post)) {
|
||||
cherokee_post_walk_reset (&conn->post);
|
||||
cherokee_post_get_len (&conn->post, &hdl->post_len);
|
||||
}
|
||||
|
||||
/* Build the headers
|
||||
*/
|
||||
ret = build_header (hdl);
|
||||
if (unlikely (ret != ret_ok)) {
|
||||
conn->error_code = http_internal_error;
|
||||
return ret_error;
|
||||
}
|
||||
|
||||
HDL_CGI_BASE(hdl)->init_phase = hcgi_phase_connect;
|
||||
|
||||
case hcgi_phase_connect:
|
||||
TRACE (ENTRIES, "Init: %s\n", "connect");
|
||||
|
||||
/* Connect
|
||||
*/
|
||||
ret = connect_to_server (hdl);
|
||||
switch (ret) {
|
||||
case ret_ok:
|
||||
break;
|
||||
case ret_eagain:
|
||||
return ret_eagain;
|
||||
case ret_deny:
|
||||
conn->error_code = http_gateway_timeout;
|
||||
return ret_error;
|
||||
default:
|
||||
conn->error_code = http_service_unavailable;
|
||||
return ret_error;
|
||||
}
|
||||
|
||||
HDL_CGI_BASE(hdl)->init_phase = hcgi_phase_send_headers;
|
||||
|
||||
case hcgi_phase_send_headers:
|
||||
TRACE (ENTRIES, "Init: %s\n", "send_headers");
|
||||
|
||||
/* Send the header
|
||||
*/
|
||||
ret = send_header (hdl);
|
||||
if (ret != ret_ok)
|
||||
return ret;
|
||||
|
||||
HDL_CGI_BASE(hdl)->init_phase = hcgi_phase_send_post;
|
||||
|
||||
case hcgi_phase_send_post:
|
||||
/* Send the Post
|
||||
*/
|
||||
if (hdl->post_len > 0 && props->pass_request_body == true) {
|
||||
return send_post (hdl);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ret_ok;
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
|
||||
/* Cherokee
|
||||
*
|
||||
* Authors:
|
||||
* Alvaro Lopez Ortega <alvaro@alobbs.com>
|
||||
*
|
||||
* Copyright (C) 2001-2009 Alvaro Lopez Ortega
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef CHEROKEE_HANDLER_UWSGI_H
|
||||
#define CHEROKEE_HANDLER_UWSGI_H
|
||||
|
||||
#include "common-internal.h"
|
||||
|
||||
#include "handler.h"
|
||||
#include "buffer.h"
|
||||
#include "plugin_loader.h"
|
||||
#include "socket.h"
|
||||
#include "handler_cgi_base.h"
|
||||
#include "balancer.h"
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t modifier1;
|
||||
uint16_t env_size;
|
||||
uint8_t modifier2;
|
||||
} uwsgi_header ;
|
||||
|
||||
|
||||
typedef struct {
|
||||
cherokee_handler_cgi_base_t base;
|
||||
cherokee_balancer_t *balancer;
|
||||
uint8_t modifier1;
|
||||
uint8_t modifier2;
|
||||
cherokee_boolean_t pass_wsgi_vars;
|
||||
cherokee_boolean_t pass_request_body;
|
||||
} cherokee_handler_uwsgi_props_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
cherokee_handler_cgi_base_t base;
|
||||
cherokee_buffer_t header;
|
||||
cherokee_socket_t socket;
|
||||
cherokee_source_t *src_ref;
|
||||
time_t spawned;
|
||||
off_t post_len;
|
||||
} cherokee_handler_uwsgi_t;
|
||||
|
||||
#define HDL_UWSGI(x) ((cherokee_handler_uwsgi_t *)(x))
|
||||
#define PROP_UWSGI(x) ((cherokee_handler_uwsgi_props_t *)(x))
|
||||
#define HANDLER_UWSGI_PROPS(x) (PROP_UWSGI(MODULE(x)->props))
|
||||
|
||||
|
||||
/* Library init function
|
||||
*/
|
||||
void PLUGIN_INIT_NAME(uwsgi) (cherokee_plugin_loader_t *loader);
|
||||
|
||||
/* Methods
|
||||
*/
|
||||
ret_t cherokee_handler_uwsgi_new (cherokee_handler_t **hdl, void *cnt, cherokee_module_props_t *props);
|
||||
ret_t cherokee_handler_uwsgi_free (cherokee_handler_uwsgi_t *hdl);
|
||||
ret_t cherokee_handler_uwsgi_init (cherokee_handler_uwsgi_t *hdl);
|
||||
|
||||
#endif /* CHEROKEE_HANDLER_UWSGI_H */
|
||||
@@ -1 +0,0 @@
|
||||
file
|
||||
@@ -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
|
||||
@@ -0,0 +1,144 @@
|
||||
package Plack::Handler::Uwsgi;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use IO::Socket::INET;
|
||||
use HTTP::Status;
|
||||
|
||||
use Plack::Util;
|
||||
|
||||
sub new {
|
||||
my $class = shift;
|
||||
my $self = bless {@_}, $class;
|
||||
$self;
|
||||
}
|
||||
|
||||
sub run {
|
||||
my ($self, $app) = @_;
|
||||
|
||||
my $server;
|
||||
|
||||
if (exists($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);
|
||||
}
|
||||
|
||||
while ( my $client = $server->accept ) {
|
||||
|
||||
my $head = '';
|
||||
my $remains = 4;
|
||||
|
||||
while($remains) {
|
||||
$client->recv(my $buf, $remains);
|
||||
last unless $buf;
|
||||
$head.=$buf;
|
||||
$remains -= length($buf);
|
||||
}
|
||||
|
||||
if (length($head) != 4) {
|
||||
$client->close;
|
||||
next;
|
||||
}
|
||||
|
||||
my ($mod1, $envsize, $mod2) = unpack('CvC', $head);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
unless($buf) {
|
||||
$client->close;
|
||||
next;
|
||||
}
|
||||
|
||||
$envbuf.=$buf;
|
||||
$remains -= length($buf);
|
||||
}
|
||||
|
||||
if (length($envbuf) != $envsize ) {
|
||||
$client->close;
|
||||
next;
|
||||
}
|
||||
|
||||
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 $env = {
|
||||
%env,
|
||||
'psgi.version' => [1,1],
|
||||
'psgi.url_scheme' => ($env{HTTPS}||'off') =~ /^(?:on|1)$/i ? 'https' : 'http',
|
||||
'psgi.input' => $client,
|
||||
'psgi.errors' => *STDERR,
|
||||
'psgi.multithread' => Plack::Util::FALSE,
|
||||
'psgi.multiprocess' => Plack::Util::TRUE,
|
||||
'psgi.run_once' => Plack::Util::FALSE,
|
||||
'psgi.streaming' => Plack::Util::TRUE,
|
||||
'psgi.nonblocking' => Plack::Util::FALSE,
|
||||
};
|
||||
|
||||
my $res = Plack::Util::run_app $app, $env;
|
||||
|
||||
if (ref $res eq 'ARRAY') {
|
||||
$self->_handle_response($client, $env{'SERVER_PROTOCOL'}, $res);
|
||||
}
|
||||
elsif (ref $res eq 'CODE') {
|
||||
$res->(sub {
|
||||
$self->_handle_response($client, $env{'SERVER_PROTOCOL'}, $_[0]);
|
||||
});
|
||||
}
|
||||
else {
|
||||
die "Bad response $res";
|
||||
}
|
||||
|
||||
$client->close;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
sub _handle_response {
|
||||
my ($self, $client, $protocol, $res) = @_;
|
||||
|
||||
$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";
|
||||
|
||||
$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 { };
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,33 @@
|
||||
# uwsgi --master --chdir /opt/graphite/webapp/graphite --module graphite_uwsgi ...
|
||||
#
|
||||
#
|
||||
# this module will update a carbon server (used by the graphite tool: http://graphite.wikidot.com/)
|
||||
# with requests count made by a Django app (and can track graphite itself as it is a Django app ;)
|
||||
#
|
||||
#
|
||||
|
||||
import os
|
||||
import uwsgi
|
||||
import time
|
||||
from django.core.handlers.wsgi import WSGIHandler
|
||||
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
|
||||
|
||||
CARBON_SERVER = "127.0.0.1:2003"
|
||||
|
||||
def update_carbon(signum):
|
||||
# connect to the carbon server
|
||||
carbon_fd = uwsgi.connect(CARBON_SERVER)
|
||||
# send data to the carbon server
|
||||
uwsgi.send(carbon_fd, "uwsgi.%s.requests %d %d\n" % (uwsgi.hostname, uwsgi.total_requests(), int(time.time())))
|
||||
# close the connection with the carbon server
|
||||
uwsgi.close(carbon_fd)
|
||||
|
||||
# register a new uwsgi signal (signum: 17)
|
||||
uwsgi.register_signal(17, '', update_carbon)
|
||||
|
||||
# attach a timer of 10 seconds to signal 17
|
||||
uwsgi.add_timer(17, 10)
|
||||
|
||||
# the Django app
|
||||
application = WSGIHandler()
|
||||
@@ -0,0 +1,66 @@
|
||||
import django
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.conf import settings
|
||||
import os
|
||||
import sys
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Runs this project as a uWSGI application. Requires the uwsgi binary in system path."
|
||||
|
||||
http_port = '8000'
|
||||
socket_addr = None
|
||||
|
||||
def handle(self, *args, **options):
|
||||
for arg in args:
|
||||
k,v = arg.split('=')
|
||||
if k == 'http':
|
||||
if self.http_port:
|
||||
self.http_port = v
|
||||
elif k == 'socket':
|
||||
self.http_port = None
|
||||
self.socket_addr = v
|
||||
|
||||
# load http and python plugin: first the specific version, otherwise try with the generic one
|
||||
if self.http_port:
|
||||
os.environ['UWSGI_PLUGINS'] = 'http,python%d%d:python' % (sys.version_info[0], sys.version_info[1])
|
||||
else:
|
||||
os.environ['UWSGI_PLUGINS'] = 'python%d%d:python' % (sys.version_info[0], sys.version_info[1])
|
||||
|
||||
# load the Django WSGI handler
|
||||
os.environ['UWSGI_MODULE'] = 'django.core.handlers.wsgi:WSGIHandler()'
|
||||
# DJANGO settings
|
||||
if options['settings']:
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = options['settings']
|
||||
else:
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
|
||||
|
||||
# bind the http server to the default port
|
||||
if self.http_port:
|
||||
os.environ['UWSGI_HTTP'] = ':%s' % self.http_port
|
||||
elif self.socket_addr:
|
||||
os.environ['UWSGI_SOCKET'] = self.socket_addr
|
||||
|
||||
# map admin static files
|
||||
os.environ['UWSGI_STATIC_MAP'] = '%s=%s' % (settings.ADMIN_MEDIA_PREFIX, os.path.join(django.__path__[0], 'contrib', 'admin', 'media'))
|
||||
# remove sockets/pidfile at exit
|
||||
os.environ['UWSGI_VACUUM'] = '1'
|
||||
# retrieve/set the PythonHome
|
||||
os.environ['UWSGI_PYHOME'] = sys.prefix
|
||||
# increase buffer size a bit
|
||||
os.environ['UWSGI_BUFFER_SIZE'] = '8192'
|
||||
# add threads for concurrency
|
||||
os.environ['UWSGI_THREADS'] = '8'
|
||||
# enable the master process
|
||||
os.environ['UWSGI_MASTER'] = '1'
|
||||
# use uWSGI python module aliasing to fix the PYTHONPATH
|
||||
os.environ['UWSGI_PYMODULE_ALIAS'] = '%s=./' % os.path.basename(os.getcwd())
|
||||
# exec the uwsgi binary
|
||||
os.execvp('uwsgi', ('uwsgi',))
|
||||
|
||||
def usage(self, subcomand):
|
||||
return r"""
|
||||
run this project on the uWSGI server
|
||||
|
||||
http=PORT run the embedded http server on port PORT
|
||||
socket=ADDR bind the uwsgi server on address ADDR (this will disable the http server)
|
||||
"""
|
||||
@@ -0,0 +1,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
|
||||
@@ -0,0 +1,330 @@
|
||||
require 'rubygems'
|
||||
require 'socket'
|
||||
require 'rack'
|
||||
require 'rack/content_length'
|
||||
require 'rack/rewindable_input'
|
||||
require 'stringio'
|
||||
|
||||
require 'optparse'
|
||||
|
||||
options = {
|
||||
:processes => 1,
|
||||
:threads => 1,
|
||||
:master => false,
|
||||
:logging => true,
|
||||
:static => true,
|
||||
:config => nil,
|
||||
:cachehack => false
|
||||
}
|
||||
|
||||
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 }
|
||||
opts.on("-C", "--cache-hack", '') { options[:cachehack] = true }
|
||||
|
||||
opts.parse! ARGV
|
||||
end
|
||||
|
||||
if ARGV[0]
|
||||
options[:config] = ARGV[0]
|
||||
end
|
||||
|
||||
def human_round(float)
|
||||
(float * (10 ** 2)).round / (10 ** 2).to_f
|
||||
end
|
||||
|
||||
$requests = 0
|
||||
$workers = Array.new
|
||||
$mywid = 0
|
||||
|
||||
module Rack
|
||||
|
||||
class RailsCachingHack
|
||||
def initialize app
|
||||
@app = app
|
||||
end
|
||||
|
||||
def stripuri(uri)
|
||||
uri = uri.split('/')
|
||||
uri.slice!(1)
|
||||
val = uri.join('/')
|
||||
end
|
||||
def call env
|
||||
env['PATH_INFO'] = stripuri(env['PATH_INFO']) if env['PATH_INFO']
|
||||
env['REQUEST_URI'] = stripuri(env['REQUEST_URI']) if env['REQUEST_URI']
|
||||
env['REQUEST_URI'] = '/' if env['REQUEST_URI'] == ''
|
||||
@app.call env
|
||||
end
|
||||
end
|
||||
|
||||
module Handler
|
||||
class Unbit
|
||||
|
||||
def self.run(app, options={})
|
||||
server = UNIXServer.for_fd(0)
|
||||
|
||||
can_spawn = true
|
||||
if options[:master]
|
||||
$0 = 'uRack master'
|
||||
$workers[0] = Process.pid
|
||||
ulog("master process enabled (pid: #{$workers[0]})")
|
||||
$workers[1] = Process.fork
|
||||
if $workers[1].to_i > 0
|
||||
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
|
||||
|
||||
if options[:processes] > 1 and can_spawn
|
||||
for p in 2..options[:processes]
|
||||
$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]})")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# am i the master ?
|
||||
if options[:master] and Process.pid == $workers[0]
|
||||
while 1
|
||||
i_am_a_child = false
|
||||
pid = Process.waitpid
|
||||
for wid in 1..options[:processes]
|
||||
if $workers[wid] == pid
|
||||
ulog("worker #{wid} died ! (pid: #{pid})")
|
||||
$workers[wid] = Process.fork
|
||||
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]})")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
break if i_am_a_child
|
||||
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
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def self.serve(client, app, options)
|
||||
|
||||
speed = Time.now
|
||||
head, sender = client.recvfrom(4)
|
||||
|
||||
unless head
|
||||
client.close
|
||||
return
|
||||
end
|
||||
|
||||
mod1, size, mod2 = head.unpack('CvC')
|
||||
|
||||
if size == 0 or size.nil?
|
||||
client.close
|
||||
return
|
||||
end
|
||||
|
||||
vars, sender = client.recvfrom(size)
|
||||
|
||||
if vars.length != size
|
||||
client.close
|
||||
return
|
||||
end
|
||||
|
||||
env = Hash.new
|
||||
|
||||
i = 0
|
||||
while i < size
|
||||
kl = vars[i, 2].unpack('v')[0]
|
||||
i = i + 2
|
||||
key = vars[i, kl]
|
||||
i = i + kl
|
||||
vl = vars[i, 2].unpack('v')[0]
|
||||
i = i + 2
|
||||
value = vars[i, vl]
|
||||
i = i + vl
|
||||
env[key] = value
|
||||
end
|
||||
|
||||
|
||||
|
||||
env.delete "HTTP_CONTENT_LENGTH"
|
||||
env.delete "HTTP_CONTENT_TYPE"
|
||||
|
||||
env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
|
||||
env["QUERY_STRING"] ||= ""
|
||||
env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
|
||||
env["REQUEST_PATH"] ||= "/"
|
||||
env.delete "PATH_INFO" if env["PATH_INFO"] == ""
|
||||
env.delete "CONTENT_TYPE" if env["CONTENT_TYPE"] == ""
|
||||
env.delete "CONTENT_LENGTH" if env["CONTENT_LENGTH"] == ""
|
||||
|
||||
|
||||
if env["CONTENT_LENGTH"].to_i > 4096
|
||||
rack_input = Rack::RewindableInput::Tempfile.new('Rack_unbit_Input')
|
||||
rack_input.chmod(0000)
|
||||
rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
|
||||
rack_input.binmode
|
||||
rack_input.unlink
|
||||
|
||||
remains = env["CONTENT_LENGTH"].to_i
|
||||
while remains > 0
|
||||
if remains >= 4096
|
||||
buf, sender = client.recvfrom(4096)
|
||||
else
|
||||
buf, sender = client.recvfrom(remains)
|
||||
end
|
||||
|
||||
if buf.length == 0
|
||||
break
|
||||
end
|
||||
|
||||
rack_input.write( buf )
|
||||
remains -= buf.length
|
||||
end
|
||||
|
||||
elsif env["CONTENT_LENGTH"].to_i > 0
|
||||
rack_input = StringIO.new(client.recvfrom(env["CONTENT_LENGTH"].to_i)[0])
|
||||
else
|
||||
rack_input = StringIO.new('')
|
||||
end
|
||||
|
||||
rack_input.rewind
|
||||
|
||||
env.update({"rack.version" => [1,1],
|
||||
"rack.input" => rack_input,
|
||||
"rack.errors" => $stderr,
|
||||
|
||||
"rack.multithread" => false,
|
||||
"rack.multiprocess" => true,
|
||||
"rack.run_once" => false,
|
||||
|
||||
"rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http"
|
||||
})
|
||||
|
||||
app = Rack::ContentLength.new(app)
|
||||
|
||||
disconnected = false
|
||||
begin
|
||||
status, headers, body = app.call(env)
|
||||
begin
|
||||
send_headers client, env["HTTP_VERSION"] ,status, headers
|
||||
send_body client, body
|
||||
ensure
|
||||
body.close if body.respond_to? :close
|
||||
end
|
||||
rescue Errno::EPIPE, Errno::ECONNRESET
|
||||
disconnected = true
|
||||
ensure
|
||||
rack_input.close
|
||||
client.close
|
||||
end
|
||||
$requests = $requests+1
|
||||
|
||||
ulog("req: #{$requests} ip: #{env['REMOTE_ADDR']} pid: #{Process.pid} as: #{human_round(syscall(356).to_f/1024/1024)} MB => #{env['REQUEST_METHOD']} #{env['REQUEST_URI']} in #{Time.now-speed} secs [#{status}]#{' DISCONNECTED !!!' if disconnected}") if options[:logging]
|
||||
end
|
||||
|
||||
def self.send_headers(client, protocol, status, headers)
|
||||
client.print "#{protocol} #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]}\r\n"
|
||||
headers.each { |k, vs|
|
||||
vs.split("\n").each { |v|
|
||||
client.print "#{k}: #{v}\r\n"
|
||||
}
|
||||
}
|
||||
client.print "\r\n"
|
||||
client.flush
|
||||
end
|
||||
|
||||
def self.send_body(client, body)
|
||||
body.each { |part|
|
||||
client.print part
|
||||
client.flush
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def ulog(message)
|
||||
$stderr.puts "[#{Time.new}] uRack: #{message}"
|
||||
end
|
||||
|
||||
ulog("starting at #{Dir.getwd}")
|
||||
limit_as = human_round(Process.getrlimit(Process::RLIMIT_AS)[1].to_f/1024/1024)
|
||||
ulog("your process address space limit is #{limit_as} MB")
|
||||
server = Rack::Handler.get('Unbit')
|
||||
|
||||
starttime = Time.now
|
||||
|
||||
app = nil
|
||||
|
||||
if options[:config]
|
||||
cfgfile = File.read(options[:config])
|
||||
if cfgfile[/^#\\(.*)/]
|
||||
opts.parse! $1.split(/\s+/)
|
||||
end
|
||||
app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app", nil, options[:config]
|
||||
else
|
||||
# falling back to rails
|
||||
if Dir.getwd =~ /\/public\/?$/
|
||||
require '../config/environment'
|
||||
else
|
||||
require 'config/environment'
|
||||
end
|
||||
app = Rack::Builder.new {
|
||||
if options[:cachehack]
|
||||
use Rack::RailsCachingHack
|
||||
end
|
||||
if options[:static]
|
||||
use Rails::Rack::Static
|
||||
end
|
||||
if ActionController.const_defined?(:Dispatcher) && (ActionController::Dispatcher.instance_methods.include?(:call) || ActionController::Dispatcher.instance_methods.include?("call"))
|
||||
run ActionController::Dispatcher.new
|
||||
else
|
||||
require 'thin'
|
||||
run Rack::Adapter::Rails.new(:environment => ENV['RAILS_ENV'])
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
ulog("your app is ready (in #{Time.now-starttime} seconds).")
|
||||
|
||||
|
||||
server.run(app, options)
|
||||
|
||||
@@ -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, []).
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
require 'socket'
|
||||
require 'rack/content_length'
|
||||
require 'rack/rewindable_input'
|
||||
require 'stringio'
|
||||
|
||||
module Rack
|
||||
module Handler
|
||||
class Uwsgi
|
||||
|
||||
def self.run(app, options={})
|
||||
if ENV['UWSGI_FD']
|
||||
server = UNIXServer.for_fd(ENV['UWSGI_FD'].to_i)
|
||||
else
|
||||
server = TCPServer.new(options[:Host], options[:Port])
|
||||
end
|
||||
while client = server.accept
|
||||
serve client, app
|
||||
end
|
||||
end
|
||||
|
||||
def self.serve(client, app)
|
||||
|
||||
head, sender = client.recvfrom(4)
|
||||
|
||||
unless head
|
||||
client.close
|
||||
return
|
||||
end
|
||||
|
||||
mod1, size, mod2 = head.unpack('CvC')
|
||||
|
||||
if size == 0 or size.nil?
|
||||
client.close
|
||||
return
|
||||
end
|
||||
|
||||
vars, sender = client.recvfrom(size)
|
||||
|
||||
if vars.length != size
|
||||
client.close
|
||||
return
|
||||
end
|
||||
|
||||
env = Hash.new
|
||||
|
||||
i = 0
|
||||
while i < size
|
||||
kl = vars[i, 2].unpack('v')[0]
|
||||
i = i + 2
|
||||
key = vars[i, kl]
|
||||
i = i + kl
|
||||
vl = vars[i, 2].unpack('v')[0]
|
||||
i = i + 2
|
||||
value = vars[i, vl]
|
||||
i = i + vl
|
||||
env[key] = value
|
||||
end
|
||||
|
||||
|
||||
|
||||
env.delete "HTTP_CONTENT_LENGTH"
|
||||
env.delete "HTTP_CONTENT_TYPE"
|
||||
|
||||
env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
|
||||
env["QUERY_STRING"] ||= ""
|
||||
env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
|
||||
env["REQUEST_PATH"] ||= "/"
|
||||
env.delete "PATH_INFO" if env["PATH_INFO"] == ""
|
||||
env.delete "CONTENT_TYPE" if env["CONTENT_TYPE"] == ""
|
||||
env.delete "CONTENT_LENGTH" if env["CONTENT_LENGTH"] == ""
|
||||
|
||||
|
||||
if env["CONTENT_LENGTH"].to_i > 4096
|
||||
rack_input = Rack::RewindableInput::Tempfile.new('Rack_uwsgi_Input')
|
||||
rack_input.chmod(0000)
|
||||
rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
|
||||
rack_input.binmode
|
||||
if RUBY_PLATFORM !~ /(mswin|mingw|cygwin|java)/
|
||||
rack_input.unlink
|
||||
end
|
||||
|
||||
remains = env["CONTENT_LENGTH"].to_i
|
||||
while remains > 0
|
||||
if remains >= 4096
|
||||
buf, sender = client.recvfrom(4096)
|
||||
else
|
||||
buf, sender = client.recvfrom(remains)
|
||||
end
|
||||
|
||||
rack_input.write( buf )
|
||||
remains -= buf.length
|
||||
end
|
||||
|
||||
elsif env["CONTENT_LENGTH"].to_i > 0
|
||||
rack_input = StringIO.new(client.recvfrom(env["CONTENT_LENGTH"].to_i)[0])
|
||||
else
|
||||
rack_input = StringIO.new('')
|
||||
end
|
||||
|
||||
rack_input.rewind
|
||||
|
||||
env.update({"rack.version" => [1,1],
|
||||
"rack.input" => rack_input,
|
||||
"rack.errors" => $stderr,
|
||||
|
||||
"rack.multithread" => false,
|
||||
"rack.multiprocess" => true,
|
||||
"rack.run_once" => false,
|
||||
|
||||
"rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http"
|
||||
})
|
||||
|
||||
|
||||
app = Rack::ContentLength.new(app)
|
||||
|
||||
begin
|
||||
status, headers, body = app.call(env)
|
||||
begin
|
||||
send_headers client, env["HTTP_VERSION"] ,status, headers
|
||||
send_body client, body
|
||||
ensure
|
||||
body.close if body.respond_to? :close
|
||||
end
|
||||
rescue Errno::EPIPE, Errno::ECONNRESET
|
||||
ensure
|
||||
rack_input.close
|
||||
client.close
|
||||
end
|
||||
end
|
||||
|
||||
def self.send_headers(client, protocol, status, headers)
|
||||
client.print "#{protocol} #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]}\r\n"
|
||||
headers.each { |k, vs|
|
||||
vs.split("\n").each { |v|
|
||||
client.print "#{k}: #{v}\r\n"
|
||||
}
|
||||
}
|
||||
client.print "\r\n"
|
||||
client.flush
|
||||
end
|
||||
|
||||
def self.send_body(client, body)
|
||||
body.each { |part|
|
||||
client.print part
|
||||
client.flush
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
|
||||
*** uWSGI cgi client ***
|
||||
|
||||
to compile:
|
||||
gcc -Wall -o uwsgi_client.cgi uwsgi_client.c
|
||||
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#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;
|
||||
char *content_length;
|
||||
|
||||
memset(&s_addr, 0, sizeof(struct sockaddr_un));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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 (res == mptr-message) {
|
||||
while( (res = recv(uwsgi_socket, message, 4096,0)) ) {
|
||||
write(1, message, res);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
|
||||
*** uWSGI cgi client ***
|
||||
|
||||
to compile:
|
||||
gcc -Wall -o uwsgi_client.cgi uwsgi_dynamic_client.c
|
||||
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#define UWSGI_SOCK "/tmp/uwsgi.sock"
|
||||
#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;
|
||||
|
||||
memset(&s_addr, 0, sizeof(struct sockaddr_un));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
message[0] = 0;
|
||||
len = (mptr-message)-4;
|
||||
memcpy(message+1, &len, 2);
|
||||
message[3] = 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;
|
||||
|
||||
}
|
||||
|
||||
Vendored
-6
@@ -1,6 +0,0 @@
|
||||
Package: uwsgi
|
||||
Version: 0.9.2
|
||||
Maintainer: Unbit
|
||||
Description: Fast, developer-friendly wsgi server
|
||||
Architecture: i386
|
||||
Depends: python2.5, libxml2
|
||||
@@ -0,0 +1,90 @@
|
||||
{% extends "admin/base_site.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<div class="breadcrumbs">
|
||||
<a href="../">{% trans 'Home' %}</a> ›
|
||||
{% trans 'uWSGI' %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div id="content-main">
|
||||
<h1>uWSGI status</h1>
|
||||
<b>masterpid:</b> {{masterpid}}<br/>
|
||||
<b>started_on:</b> {{started_on}}<br/>
|
||||
<b>buffer size:</b> {{buffer_size}}<br/>
|
||||
<b>workers:</b> {{numproc}}<br/>
|
||||
<b>total requests:</b> {{total_requests}}<br/>
|
||||
|
||||
<br/>
|
||||
|
||||
<div class="module" style="width:860px">
|
||||
<table>
|
||||
<caption style="width:860px">workers</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="row">id</th>
|
||||
<th scope="row">pid</th>
|
||||
<th scope="row">requests</th>
|
||||
<th scope="row">running time (milliseconds)</th>
|
||||
<th scope="row">load</th>
|
||||
<th scope="row">last spawn</th>
|
||||
<th scope="row">respawn count</th>
|
||||
<th scope="row">address space (vsz)</th>
|
||||
<th scope="row">resident memory (rss)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for w in workers %}
|
||||
<tr>
|
||||
<td align="center">{{w.id}}</td>
|
||||
<td align="center">{{w.pid}}</td>
|
||||
<td align="right">{{w.requests}}</td>
|
||||
<td align="right">{{w.running_time}}</td>
|
||||
<td align="right">{{w.load|floatformat:2}} %</td>
|
||||
<td align="right">{{w.last_spawn_str}}</td>
|
||||
<td align="right">{{w.respawn_count}}</td>
|
||||
<td align="right">{{w.vsz|filesizeformat}}</td>
|
||||
<td align="right">{{w.rss|filesizeformat}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="module" style="width:860px">
|
||||
<table>
|
||||
<caption style="width:860px">spooler jobs</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="row">job filename</th>
|
||||
<th scope="row">environment</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for j in jobs %}
|
||||
<tr>
|
||||
<td align="left">{{j.file}}</td>
|
||||
<td align="left">{{j.env}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% if masterpid %}
|
||||
<br/>
|
||||
<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="reload/" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="submit" value="gracefully reload uWSGI" name="_reload"/>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from django.conf.urls.defaults import *
|
||||
|
||||
urlpatterns = patterns('uwsgi_admin.views',
|
||||
(r'^$', 'index'),
|
||||
(r'^reload/$', 'reload')
|
||||
)
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import uwsgi
|
||||
import time
|
||||
from django.shortcuts import render_to_response
|
||||
from django.template import RequestContext
|
||||
from django.contrib.admin.views.decorators import staff_member_required
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import HttpResponseRedirect
|
||||
|
||||
|
||||
def index(request):
|
||||
workers = uwsgi.workers()
|
||||
total_load = time.time() - uwsgi.started_on
|
||||
for w in workers:
|
||||
w['load'] = (100 * (w['running_time']/1000))/total_load
|
||||
w['last_spawn_str'] = time.ctime(w['last_spawn'])
|
||||
|
||||
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)
|
||||
|
||||
def reload(request):
|
||||
if uwsgi.masterpid() > 0:
|
||||
uwsgi.reload()
|
||||
request.user.message_set.create(message="uWSGI reloaded")
|
||||
else:
|
||||
request.user.message_set.create(message="The uWSGI master process is not active")
|
||||
|
||||
return HttpResponseRedirect(reverse(index))
|
||||
|
||||
reload = staff_member_required(reload)
|
||||
@@ -0,0 +1,643 @@
|
||||
#include "uwsgi.h"
|
||||
#include <glob.h>
|
||||
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
extern char **environ;
|
||||
|
||||
int emperor_queue;
|
||||
|
||||
static void royal_death(int signum) {
|
||||
uwsgi_notify("The Emperor is buried.");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
struct uwsgi_instance {
|
||||
struct uwsgi_instance *ui_prev;
|
||||
struct uwsgi_instance *ui_next;
|
||||
|
||||
char name[0xff];
|
||||
pid_t pid;
|
||||
|
||||
int status;
|
||||
time_t born;
|
||||
time_t last_mod;
|
||||
time_t last_loyal;
|
||||
|
||||
uint64_t respawns;
|
||||
int use_config;
|
||||
|
||||
int pipe[2];
|
||||
int pipe_config[2];
|
||||
|
||||
char *config;
|
||||
uint32_t config_len;
|
||||
|
||||
int loyal;
|
||||
};
|
||||
|
||||
struct uwsgi_instance *ui;
|
||||
|
||||
struct uwsgi_instance *emperor_get_by_fd(int fd) {
|
||||
|
||||
struct uwsgi_instance *c_ui = ui;
|
||||
|
||||
while (c_ui->ui_next) {
|
||||
c_ui = c_ui->ui_next;
|
||||
|
||||
if (c_ui->pipe[0] == fd) {
|
||||
return c_ui;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_instance *emperor_get(char *name) {
|
||||
|
||||
struct uwsgi_instance *c_ui = ui;
|
||||
|
||||
while (c_ui->ui_next) {
|
||||
c_ui = c_ui->ui_next;
|
||||
|
||||
if (!strcmp(c_ui->name, name)) {
|
||||
return c_ui;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void emperor_del(struct uwsgi_instance *c_ui) {
|
||||
|
||||
struct uwsgi_instance *parent_ui = c_ui->ui_prev;
|
||||
struct uwsgi_instance *child_ui = c_ui->ui_next;
|
||||
|
||||
parent_ui->ui_next = child_ui;
|
||||
if (child_ui) {
|
||||
child_ui->ui_prev = parent_ui;
|
||||
}
|
||||
|
||||
// this will destroy the whole uWSGI instance (and workers)
|
||||
close(c_ui->pipe[0]);
|
||||
|
||||
if (c_ui->use_config) {
|
||||
close(c_ui->pipe_config[0]);
|
||||
}
|
||||
|
||||
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 (c_ui->use_config) {
|
||||
if (write(c_ui->pipe[0], "\0", 1) != 1) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (write(c_ui->pipe[0], "\1", 1) != 1) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
}
|
||||
|
||||
c_ui->respawns++;
|
||||
c_ui->last_mod = mod;
|
||||
|
||||
uwsgi_log("reload the uwsgi instance %s\n", c_ui->name);
|
||||
}
|
||||
|
||||
void emperor_add(char *name, time_t born, char *config, uint32_t config_size) {
|
||||
|
||||
struct uwsgi_instance *c_ui = ui;
|
||||
struct uwsgi_instance *n_ui = NULL;
|
||||
pid_t pid;
|
||||
char **argv;
|
||||
char *uef;
|
||||
char **uenvs;
|
||||
int counter;
|
||||
|
||||
sleep(1);
|
||||
|
||||
while (c_ui->ui_next) {
|
||||
c_ui = c_ui->ui_next;
|
||||
}
|
||||
|
||||
n_ui = uwsgi_malloc(sizeof(struct uwsgi_instance));
|
||||
memset(n_ui, 0, sizeof(struct uwsgi_instance));
|
||||
|
||||
if (config) {
|
||||
n_ui->use_config = 1;
|
||||
n_ui->config = config;
|
||||
n_ui->config_len = config_size;
|
||||
}
|
||||
|
||||
c_ui->ui_next = n_ui;
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("c_ui->ui_next = %p\n", c_ui->ui_next);
|
||||
#endif
|
||||
n_ui->ui_prev = c_ui;
|
||||
memcpy(n_ui->name, name, strlen(name));
|
||||
n_ui->born = born;
|
||||
n_ui->last_mod = born;
|
||||
// start without loyalty
|
||||
n_ui->last_loyal = born;
|
||||
n_ui->loyal = 0;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe)) {
|
||||
uwsgi_error("socketpair()");
|
||||
goto clear;
|
||||
}
|
||||
|
||||
event_queue_add_fd_read(emperor_queue, n_ui->pipe[0]);
|
||||
|
||||
if (n_ui->use_config) {
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe_config)) {
|
||||
uwsgi_error("socketpair()");
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO pre-start hook
|
||||
|
||||
// a new uWSGI instance will start
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
uwsgi_error("fork()")
|
||||
}
|
||||
else if (pid > 0) {
|
||||
n_ui->pid = pid;
|
||||
// close the right side of the pipe
|
||||
close(n_ui->pipe[1]);
|
||||
if (n_ui->use_config) {
|
||||
close(n_ui->pipe_config[1]);
|
||||
}
|
||||
|
||||
if (n_ui->use_config) {
|
||||
if (write(n_ui->pipe_config[0], n_ui->config, n_ui->config_len) <= 0) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
close(n_ui->pipe_config[0]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
|
||||
unsetenv("UWSGI_RELOADS");
|
||||
unsetenv("NOTIFY_SOCKET");
|
||||
|
||||
uef = uwsgi_num2str(n_ui->pipe[1]);
|
||||
if (setenv("UWSGI_EMPEROR_FD", uef, 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
exit(1);
|
||||
}
|
||||
free(uef);
|
||||
|
||||
if (n_ui->use_config) {
|
||||
uef = uwsgi_num2str(n_ui->pipe_config[1]);
|
||||
if (setenv("UWSGI_EMPEROR_FD_CONFIG", uef, 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
exit(1);
|
||||
}
|
||||
free(uef);
|
||||
}
|
||||
|
||||
uenvs = environ;
|
||||
while (*uenvs) {
|
||||
if (!strncmp(*uenvs, "UWSGI_VASSAL_", 13)) {
|
||||
char *ne = uwsgi_concat2("UWSGI_", *uenvs + 13);
|
||||
char *oe = uwsgi_concat2n(*uenvs, strchr(*uenvs, '=') - *uenvs, "", 0);
|
||||
if (unsetenv(oe)) {
|
||||
uwsgi_error("unsetenv()");
|
||||
break;
|
||||
}
|
||||
free(oe);
|
||||
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]);
|
||||
|
||||
if (n_ui->use_config) {
|
||||
close(n_ui->pipe_config[0]);
|
||||
}
|
||||
|
||||
counter = 4;
|
||||
struct uwsgi_config_template *uct = uwsgi.vassals_templates;
|
||||
while(uct) {
|
||||
counter+=2;
|
||||
uct = uct->next;
|
||||
}
|
||||
|
||||
argv = uwsgi_malloc(sizeof(char *) * counter);
|
||||
// set args
|
||||
argv[0] = uwsgi.binary_path;
|
||||
if (!strcmp(name + (strlen(name) - 4), ".xml"))
|
||||
argv[1] = "--xml";
|
||||
if (!strcmp(name + (strlen(name) - 4), ".ini"))
|
||||
argv[1] = "--ini";
|
||||
if (!strcmp(name + (strlen(name) - 4), ".yml"))
|
||||
argv[1] = "--yaml";
|
||||
if (!strcmp(name + (strlen(name) - 5), ".yaml"))
|
||||
argv[1] = "--yaml";
|
||||
if (!strcmp(name + (strlen(name) - 3), ".js"))
|
||||
argv[1] = "--json";
|
||||
argv[2] = name;
|
||||
counter = 3;
|
||||
uct = uwsgi.vassals_templates;
|
||||
while(uct) {
|
||||
argv[counter] = "--inherit";
|
||||
argv[counter+1] = uct->filename;
|
||||
counter+=2;
|
||||
uct = uct->next;
|
||||
}
|
||||
argv[counter] = NULL;
|
||||
// start !!!
|
||||
if (execvp(argv[0], argv)) {
|
||||
uwsgi_error("execvp()");
|
||||
}
|
||||
uwsgi_log("is the uwsgi binary in your system PATH ?\n");
|
||||
// never here
|
||||
exit(UWSGI_EXILE_CODE);
|
||||
}
|
||||
|
||||
clear:
|
||||
|
||||
free(n_ui);
|
||||
c_ui->ui_next = NULL;
|
||||
|
||||
}
|
||||
|
||||
void emperor_loop() {
|
||||
|
||||
// monitor a directory
|
||||
|
||||
struct uwsgi_instance ui_base;
|
||||
struct uwsgi_instance *ui_current;
|
||||
struct stat st;
|
||||
|
||||
pid_t diedpid;
|
||||
int waitpid_status;
|
||||
int has_children = 0;
|
||||
int i_am_alone = 0;
|
||||
int simple_mode = 0;
|
||||
glob_t g;
|
||||
int i;
|
||||
struct dirent *de;
|
||||
char *amqp_port;
|
||||
int amqp_fd = -1;
|
||||
char *amqp_routing_key;
|
||||
|
||||
void *events;
|
||||
int nevents;
|
||||
int interesting_fd;
|
||||
char notification_message[64];
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
uwsgi_unix_signal(SIGINT, royal_death);
|
||||
uwsgi_unix_signal(SIGTERM, royal_death);
|
||||
|
||||
memset(&ui_base, 0, sizeof(struct uwsgi_instance));
|
||||
|
||||
|
||||
emperor_queue = event_queue_init();
|
||||
|
||||
events = event_queue_alloc(64);
|
||||
|
||||
uwsgi_log("*** starting uWSGI Emperor ***\n");
|
||||
|
||||
amqp_port = strchr(uwsgi.emperor_dir, ':');
|
||||
|
||||
if (amqp_port) {
|
||||
if (uwsgi.emperor_amqp_vhost == NULL) uwsgi.emperor_amqp_vhost = "/";
|
||||
if (uwsgi.emperor_amqp_username == NULL) uwsgi.emperor_amqp_username = "guest";
|
||||
if (uwsgi.emperor_amqp_password == NULL) uwsgi.emperor_amqp_password = "guest";
|
||||
reconnect:
|
||||
while(amqp_fd == -1) {
|
||||
uwsgi_log("connecting to AMQP server...\n");
|
||||
amqp_fd = uwsgi_connect(uwsgi.emperor_dir, -1, 0);
|
||||
if (amqp_fd < 0) {
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("subscribing to queue...\n");
|
||||
if (uwsgi_amqp_consume_queue(amqp_fd, uwsgi.emperor_amqp_vhost, uwsgi.emperor_amqp_username, uwsgi.emperor_amqp_password, "", "uwsgi.emperor", "fanout") < 0) {
|
||||
close(amqp_fd);
|
||||
amqp_fd = -1;
|
||||
sleep(1);
|
||||
goto reconnect;
|
||||
}
|
||||
|
||||
event_queue_add_fd_read(emperor_queue, amqp_fd);
|
||||
}
|
||||
else {
|
||||
if (!glob(uwsgi.emperor_dir, GLOB_MARK, 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;
|
||||
|
||||
int freq = 0 ;
|
||||
|
||||
for (;;) {
|
||||
|
||||
|
||||
if (!i_am_alone) {
|
||||
diedpid = waitpid(uwsgi.emperor_pid, &waitpid_status, WNOHANG);
|
||||
if (diedpid < 0 || diedpid > 0) {
|
||||
i_am_alone = 1;
|
||||
}
|
||||
}
|
||||
|
||||
nevents = event_queue_wait_multi(emperor_queue, freq, events, 64);
|
||||
freq = 3;
|
||||
|
||||
for (i = 0; i<nevents;i++) {
|
||||
interesting_fd = event_queue_interesting_fd(events, i);
|
||||
|
||||
if (amqp_fd > -1 && interesting_fd == amqp_fd ) {
|
||||
uint64_t msgsize;
|
||||
char *config = uwsgi_amqp_consume(amqp_fd, &msgsize, &amqp_routing_key);
|
||||
|
||||
if (!config) {
|
||||
uwsgi_log("problem with RabbitMQ server, trying reconnection...\n");
|
||||
event_queue_del_fd(emperor_queue, amqp_fd, event_queue_read());
|
||||
close(amqp_fd);
|
||||
amqp_fd = -1;
|
||||
goto reconnect;
|
||||
}
|
||||
|
||||
if (amqp_routing_key) {
|
||||
uwsgi_log("AMQP routing_key = %s\n", amqp_routing_key);
|
||||
char *config_file = uwsgi_concat2("emperor://", amqp_routing_key);
|
||||
free(amqp_routing_key);
|
||||
|
||||
ui_current = emperor_get(config_file);
|
||||
|
||||
if (ui_current) {
|
||||
// ignore event if i am not loyal
|
||||
if (!ui_current->loyal) continue;
|
||||
free(ui_current->config);
|
||||
ui_current->config = config;
|
||||
ui_current->config_len = msgsize;
|
||||
if (!msgsize) {
|
||||
emperor_del(ui_current);
|
||||
}
|
||||
else {
|
||||
emperor_respawn(ui_current, time(NULL));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (msgsize > 0) {
|
||||
emperor_add(config_file, time(NULL), config, msgsize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
free(config_file);
|
||||
}
|
||||
else {
|
||||
if (msgsize) {
|
||||
if (msgsize >= 0xff) { free(config); continue; }
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%.*s\n", (int)msgsize, config);
|
||||
#endif
|
||||
char *config_file = uwsgi_concat2n(config, msgsize, "", 0);
|
||||
free(config);
|
||||
|
||||
if (strncmp(config_file, "http://", 7)) {
|
||||
if (stat(config_file, &st)) {
|
||||
free(config_file);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!S_ISREG(st.st_mode)) {
|
||||
free(config_file);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ui_current = emperor_get(config_file);
|
||||
|
||||
if (ui_current) {
|
||||
// ignore event if i am not loyal
|
||||
if (!ui_current->loyal) continue;
|
||||
emperor_respawn(ui_current, time(NULL));
|
||||
}
|
||||
else {
|
||||
emperor_add(config_file, time(NULL), NULL, 0);
|
||||
}
|
||||
|
||||
free(config_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ui_current = emperor_get_by_fd(interesting_fd);
|
||||
if (ui_current) {
|
||||
char byte;
|
||||
ssize_t rlen = read(interesting_fd, &byte, 1);
|
||||
if (rlen <= 0) {
|
||||
emperor_del(ui_current);
|
||||
}
|
||||
else {
|
||||
if (byte == 17) {
|
||||
ui_current->loyal = 1;
|
||||
uwsgi_log("*** vassal %s is now loyal ***\n", ui_current->name);
|
||||
|
||||
// TODO post-start hook
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log("unrecognized event on fd %d\n", interesting_fd);
|
||||
event_queue_del_fd(emperor_queue, interesting_fd, event_queue_read());
|
||||
close(interesting_fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (amqp_fd == -1) {
|
||||
if (simple_mode) {
|
||||
DIR *dir = opendir(".");
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
if (!strcmp(de->d_name + (strlen(de->d_name) - 4), ".xml") ||
|
||||
!strcmp(de->d_name + (strlen(de->d_name) - 4), ".ini") ||
|
||||
!strcmp(de->d_name + (strlen(de->d_name) - 4), ".yml") ||
|
||||
!strcmp(de->d_name + (strlen(de->d_name) - 5), ".yaml") ||
|
||||
!strcmp(de->d_name + (strlen(de->d_name) - 3), ".js")
|
||||
) {
|
||||
|
||||
|
||||
if (strlen(de->d_name) >= 0xff)
|
||||
continue;
|
||||
|
||||
if (stat(de->d_name, &st))
|
||||
continue;
|
||||
|
||||
if (!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, NULL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
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]) - 3), ".js") ||
|
||||
!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, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check for removed instances
|
||||
|
||||
ui_current = ui;
|
||||
has_children = 0;
|
||||
while (ui_current->ui_next) {
|
||||
ui_current = ui_current->ui_next;
|
||||
has_children++;
|
||||
}
|
||||
|
||||
if (uwsgi.notify) {
|
||||
if (snprintf(notification_message, 64, "The Emperor is governing %d vassals", has_children) >= 34) {
|
||||
uwsgi_notify(notification_message);
|
||||
}
|
||||
}
|
||||
|
||||
if (has_children) {
|
||||
diedpid = waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
|
||||
}
|
||||
else {
|
||||
// vacuum
|
||||
waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
|
||||
diedpid = 0;
|
||||
}
|
||||
if (diedpid < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
}
|
||||
ui_current = ui;
|
||||
while (ui_current->ui_next) {
|
||||
ui_current = ui_current->ui_next;
|
||||
// check loyalty if not in simple/glob mode
|
||||
if (amqp_fd > -1) {
|
||||
if (!ui_current->loyal && (time(NULL)-ui_current->last_loyal) > 60) {
|
||||
uwsgi_log("!!! no loyalty showed by instance %s !!!\n", ui_current->name);
|
||||
emperor_del(ui_current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ui_current->status == 1) {
|
||||
if (ui_current->config) free(ui_current->config);
|
||||
emperor_del(ui_current);
|
||||
break;
|
||||
}
|
||||
else if (!ui_current->use_config && strncmp(ui_current->name, "http://",7) && stat(ui_current->name, &st)) {
|
||||
emperor_stop(ui_current);
|
||||
}
|
||||
else if (ui_current->pid == diedpid) {
|
||||
if (ui_current->status == 0) {
|
||||
// respawn an accidentally dead instance if its exit code is not UWSGI_EXILE_CODE
|
||||
if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_EXILE_CODE) {
|
||||
emperor_del(ui_current);
|
||||
}
|
||||
else {
|
||||
emperor_add(ui_current->name, ui_current->last_mod, ui_current->config, ui_current->config_len);
|
||||
emperor_del(ui_current);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (ui_current->status == 1) {
|
||||
// remove 'marked for dead' instance
|
||||
if (ui_current->config) free(ui_current->config);
|
||||
emperor_del(ui_current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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,854 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#ifdef UWSGI_EVENT_USE_PORT
|
||||
|
||||
#include <port.h>
|
||||
|
||||
#define UWSGI_EVENT_IN POLLIN
|
||||
#define UWSGI_EVENT_OUT POLLOUT
|
||||
|
||||
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, int event) {
|
||||
|
||||
if (port_dissociate(eq, PORT_SOURCE_FD, fd)) {
|
||||
uwsgi_error("port_disassociate");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int event_queue_fd_write_to_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_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 = 1;
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
else {
|
||||
*interesting_fd = (int) pe.portev_object;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef UWSGI_EVENT_USE_EPOLL
|
||||
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#define UWSGI_EVENT_IN EPOLLIN
|
||||
#define UWSGI_EVENT_OUT EPOLLOUT
|
||||
|
||||
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, int event) {
|
||||
|
||||
struct epoll_event ee;
|
||||
|
||||
memset(&ee, 0, sizeof(struct epoll_event));
|
||||
ee.data.fd = fd;
|
||||
ee.events = event;
|
||||
|
||||
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
|
||||
|
||||
#define UWSGI_EVENT_IN EVFILT_READ
|
||||
#define UWSGI_EVENT_OUT EVFILT_WRITE
|
||||
|
||||
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, int event) {
|
||||
|
||||
struct kevent kev;
|
||||
|
||||
EV_SET(&kev, fd, event, 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(filename);
|
||||
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
|
||||
|
||||
inline int event_queue_read() {
|
||||
return UWSGI_EVENT_IN;
|
||||
}
|
||||
|
||||
inline int event_queue_write() {
|
||||
return UWSGI_EVENT_OUT;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
require 'fiber'
|
||||
class SuspendingBody
|
||||
|
||||
def each
|
||||
for i in 1..3
|
||||
yield "number: #{i}\n"
|
||||
UWSGI.async_sleep(1)
|
||||
puts "sleep..."
|
||||
Fiber.yield
|
||||
end
|
||||
|
||||
fd = UWSGI.async_connect("81.174.68.52:80")
|
||||
UWSGI.wait_fd_write(fd, 3)
|
||||
Fiber.yield
|
||||
io = IO.new(fd)
|
||||
puts "connected"
|
||||
io.syswrite("GET /uwsgi/export/1081%3A362d695b2f25/plugins/fiber/fiber.c HTTP/1.0\r\n")
|
||||
io.syswrite("Host: projects.unbit.it\r\n")
|
||||
io.syswrite("\r\n")
|
||||
|
||||
UWSGI.wait_fd_read(fd, 3)
|
||||
Fiber.yield
|
||||
|
||||
puts "data available"
|
||||
|
||||
begin
|
||||
while body = io.sysread(fd)
|
||||
yield body
|
||||
Fiber.yield
|
||||
end
|
||||
rescue
|
||||
end
|
||||
|
||||
io.close
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
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
|
||||
@@ -0,0 +1,27 @@
|
||||
[uwsgi]
|
||||
|
||||
master = true
|
||||
processes = 4
|
||||
threads = 8
|
||||
|
||||
; initialize 4 sockets with 4 different protocols
|
||||
socket = :3031
|
||||
socket = :3032
|
||||
socket = :3033
|
||||
socket = :3034
|
||||
|
||||
socket-protocol = 0,uwsgi
|
||||
socket-protocol = 1,http
|
||||
socket-protocol = 2,fastcgi
|
||||
socket-protocol = 3,uwsgidump
|
||||
|
||||
|
||||
; add a cache with 1000 items of 96k
|
||||
cache = 1000
|
||||
cache-blocksize = 98304
|
||||
|
||||
|
||||
log-micros = true
|
||||
|
||||
module = heavytest
|
||||
mount = /cc=uwsgicc/__init__.py
|
||||
@@ -0,0 +1,14 @@
|
||||
import uwsgi
|
||||
import werkzeug.testapp
|
||||
|
||||
uwsgi.cache_set("/cache/get", "HTTP 1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<h1>I am the uWSGI cache</h1>")
|
||||
|
||||
def app001(env, start_response):
|
||||
start_response('200 OK', [('Content-Type', 'text/html')])
|
||||
return "PATH_INFO=%s" % env['PATH_INFO']
|
||||
|
||||
def app002(env, start_response):
|
||||
start_response('200 OK', [('Content-Type', 'text/html')])
|
||||
return "requests: %d" % uwsgi.total_requests()
|
||||
|
||||
uwsgi.applications = { '':werkzeug.testapp.test_app, '/app001':app001, '/app002':app002 }
|
||||
@@ -0,0 +1,31 @@
|
||||
import uwsgi
|
||||
import time
|
||||
import rrdtool
|
||||
|
||||
# rrdtool create test.rrd --start 1270879004 -s 10 DS:requests:COUNTER:300:U:U RRA:AVERAGE:0.5:3:105120
|
||||
|
||||
s_freq = 10
|
||||
|
||||
# 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.register_timer(0, s_freq, uwsgi.KIND_WORKER, rrdtool_updater)
|
||||
|
||||
|
||||
|
||||
def hello_world(env, start_response):
|
||||
start_response('200 Ok', [('Content-type', 'text/plain')])
|
||||
return 'Hello world !'
|
||||
|
||||
|
||||
def graph(env, start_response):
|
||||
start_response('200 Ok', [('Content-type', 'image/png')])
|
||||
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')
|
||||
# send file to client
|
||||
uwsgi.sendfile('uwsgi_graph.png')
|
||||
|
||||
uwsgi.applications = {'/': hello_world, '/graph':graph}
|
||||
@@ -0,0 +1,148 @@
|
||||
#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;
|
||||
|
||||
char *section_asked = "uwsgi";
|
||||
char *colon;
|
||||
|
||||
if (!uwsgi_startswith(file, "http://", 7)) {
|
||||
colon = uwsgi_get_last_char(file, '/');
|
||||
colon = uwsgi_get_last_char(colon, ':');
|
||||
}
|
||||
else {
|
||||
colon = uwsgi_get_last_char(file, ':');
|
||||
}
|
||||
|
||||
if (colon) {
|
||||
colon[0] = 0;
|
||||
if (colon[1] != 0) {
|
||||
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);
|
||||
add_exported_option((char *)key, val, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
len -= (ini_line - ini);
|
||||
ini += (ini_line - ini);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,107 @@
|
||||
#ifdef UWSGI_JSON
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#include <jansson.h>
|
||||
|
||||
|
||||
/*
|
||||
I really love the jansson library...
|
||||
*/
|
||||
|
||||
void uwsgi_json_config(char *file, char *magic_table[]) {
|
||||
|
||||
int len = 0;
|
||||
char *json_data;
|
||||
|
||||
|
||||
const char *key;
|
||||
|
||||
json_t *root;
|
||||
json_error_t error;
|
||||
json_t *config;
|
||||
json_t *config_value, *config_array_item;
|
||||
|
||||
void *config_iter;
|
||||
|
||||
char *object_asked = "uwsgi";
|
||||
char *colon;
|
||||
int i;
|
||||
|
||||
if (!uwsgi_startswith(file, "http://", 7)) {
|
||||
colon = uwsgi_get_last_char(file, '/');
|
||||
colon = uwsgi_get_last_char(colon, ':');
|
||||
}
|
||||
else {
|
||||
colon = uwsgi_get_last_char(file, ':');
|
||||
}
|
||||
|
||||
if (colon) {
|
||||
colon[0] = 0;
|
||||
if (colon[1] != 0) {
|
||||
object_asked = colon+1;
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("[uWSGI] getting JSON configuration from %s\n", file);
|
||||
|
||||
json_data = uwsgi_open_and_read(file, &len, 1, magic_table);
|
||||
|
||||
root = json_loads(json_data, 0, &error);
|
||||
|
||||
if (!root) {
|
||||
uwsgi_log("error parsing JSON data: line %d %s\n", error.line, error.text);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
config = json_object_get(root, object_asked);
|
||||
|
||||
if (!json_is_object(config)) {
|
||||
uwsgi_log("you must define a object named %s in your JSON data\n", object_asked);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
config_iter = json_object_iter(config);
|
||||
|
||||
while(config_iter) {
|
||||
key = json_object_iter_key(config_iter);
|
||||
config_value = json_object_iter_value(config_iter);
|
||||
|
||||
if (json_is_string(config_value)) {
|
||||
add_exported_option((char *)key, (char *) json_string_value(config_value), 0);
|
||||
}
|
||||
else if (json_is_true(config_value)) {
|
||||
add_exported_option((char *)key, (char *) "1", 0);
|
||||
}
|
||||
else if (json_is_false(config_value) || json_is_null(config_value)) {
|
||||
add_exported_option((char *)key, (char *) "0", 0);
|
||||
}
|
||||
else if (json_is_integer(config_value)) {
|
||||
add_exported_option((char *)key, uwsgi_num2str(json_integer_value(config_value)), 0);
|
||||
}
|
||||
else if (json_is_array(config_value)) {
|
||||
for(i=0;i<(int)json_array_size(config_value);i++) {
|
||||
config_array_item = json_array_get(config_value, i);
|
||||
if (json_is_string(config_array_item)) {
|
||||
add_exported_option((char *)key, (char *) json_string_value(config_array_item), 0);
|
||||
}
|
||||
else if (json_is_true(config_array_item)) {
|
||||
add_exported_option((char *)key, (char *) "1", 0);
|
||||
}
|
||||
else if (json_is_false(config_array_item) || json_is_null(config_array_item)) {
|
||||
add_exported_option((char *)key, (char *) "0", 0);
|
||||
}
|
||||
else if (json_is_integer(config_array_item)) {
|
||||
add_exported_option((char *)key, uwsgi_num2str(json_integer_value(config_array_item)), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config_iter = json_object_iter_next(config, config_iter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,393 @@
|
||||
#ifdef UWSGI_LDAP
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#include <ldap.h>
|
||||
|
||||
#ifndef LDAP_OPT_SUCCESS
|
||||
#define LDAP_OPT_SUCCESS LDAP_SUCCESS
|
||||
#endif
|
||||
|
||||
#ifndef ldap_unbind_ext_s
|
||||
#define ldap_unbind_ext_s ldap_unbind_ext
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
struct uwsgi_ldap_entry {
|
||||
int num;
|
||||
char names[1024];
|
||||
int has_arg;
|
||||
};
|
||||
|
||||
|
||||
void uwsgi_name_to_ldap(char *src, char *dst) {
|
||||
|
||||
int i;
|
||||
char *ptr = dst;
|
||||
|
||||
memset(dst, 0, 1024);
|
||||
|
||||
strcat(dst, " 'uWSGI");
|
||||
|
||||
ptr+= 7;
|
||||
|
||||
for(i=0;i< (int)strlen(src);i++) {
|
||||
if (src[i] == '-') {
|
||||
i++;
|
||||
*ptr++= toupper( (int) src[i]);
|
||||
}
|
||||
else {
|
||||
*ptr++= src[i];
|
||||
}
|
||||
}
|
||||
|
||||
strcat(dst, "'");
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_ldap_entry *get_ldap_by_num(struct uwsgi_ldap_entry *root, int num, int count) {
|
||||
|
||||
int i;
|
||||
struct uwsgi_ldap_entry *ule;
|
||||
|
||||
for(i=0;i<count;i++) {
|
||||
ule = &root[i];
|
||||
if (ule->num == num) {
|
||||
return ule;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_ldap_entry *search_ldap_cache(struct uwsgi_ldap_entry *root, char *name, int count) {
|
||||
int i;
|
||||
struct uwsgi_ldap_entry *ule;
|
||||
|
||||
for(i=0;i<count;i++) {
|
||||
ule = &root[i];
|
||||
if (uwsgi_list_has_str(ule->names, name+1)) {
|
||||
return ule;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_ldap_entry *get_ldap_names(int *count) {
|
||||
|
||||
struct option *aopt, *lopt;
|
||||
struct uwsgi_ldap_entry *ule, *entry;
|
||||
char ldap_name[1024];
|
||||
static int counter = 30000000;
|
||||
|
||||
*count = 0;
|
||||
lopt = uwsgi.long_options;
|
||||
|
||||
ule = uwsgi_malloc(sizeof(struct uwsgi_ldap_entry)*count_options(lopt));
|
||||
|
||||
while( (aopt = lopt) ) {
|
||||
if (!aopt->name)
|
||||
break;
|
||||
|
||||
uwsgi_name_to_ldap((char *)aopt->name, ldap_name);
|
||||
|
||||
entry = search_ldap_cache(ule, ldap_name, *count);
|
||||
|
||||
if (entry) goto next;
|
||||
|
||||
if (aopt->flag) {
|
||||
entry = &ule[*count] ;
|
||||
entry->num = counter;
|
||||
strcpy(entry->names, ldap_name);
|
||||
counter++;
|
||||
*count = *count+1;
|
||||
}
|
||||
else {
|
||||
entry = get_ldap_by_num(ule, aopt->val, *count);
|
||||
if (entry) {
|
||||
strcat(entry->names, ldap_name);
|
||||
}
|
||||
else {
|
||||
entry = &ule[*count] ;
|
||||
entry->num = aopt->val;
|
||||
strcpy(entry->names, ldap_name);
|
||||
*count = *count+1;
|
||||
}
|
||||
}
|
||||
|
||||
entry->has_arg = aopt->has_arg;
|
||||
|
||||
next:
|
||||
lopt++;
|
||||
}
|
||||
|
||||
return ule;
|
||||
}
|
||||
|
||||
void uwsgi_ldap_schema_dump_ldif() {
|
||||
|
||||
int i;
|
||||
int items;
|
||||
|
||||
uwsgi_log("\n");
|
||||
uwsgi_log("dn: cn=uwsgi,cn=schema,cn=config\n");
|
||||
uwsgi_log("objectClass: olcSchemaConfig\n");
|
||||
uwsgi_log("cn: uwsgi\n");
|
||||
|
||||
struct uwsgi_ldap_entry *entry, *ule = get_ldap_names(&items);
|
||||
|
||||
for(i=0;i<items;i++) {
|
||||
|
||||
entry = &ule[i];
|
||||
uwsgi_log("olcAttributeTypes: ( 1.3.6.1.4.1.35156.17.4.%d NAME (%s", entry->num, entry->names);
|
||||
|
||||
if (entry->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");
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
|
||||
uwsgi_log("olcObjectClasses: ( 1.3.6.1.4.1.35156.17.3.1 NAME 'uWSGIConfig' SUP top AUXILIARY DESC 'uWSGI configuration' MAY ( ");
|
||||
|
||||
|
||||
for(i=0;i<items;i++) {
|
||||
|
||||
entry = &ule[i];
|
||||
|
||||
char *list2 = uwsgi_concat2(entry->names+1, "");
|
||||
char *p = strtok(list2, " ");
|
||||
while (p != NULL) {
|
||||
uwsgi_log("%.*s $ ", strlen(p)-2, p+1);
|
||||
p = strtok(NULL, " ");
|
||||
}
|
||||
|
||||
free(list2);
|
||||
|
||||
}
|
||||
|
||||
uwsgi_log("uWSGInull ))\n");
|
||||
|
||||
uwsgi_log("\n");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void uwsgi_ldap_schema_dump() {
|
||||
|
||||
int i;
|
||||
int items;
|
||||
|
||||
struct uwsgi_ldap_entry *entry, *ule = get_ldap_names(&items);
|
||||
|
||||
for(i=0;i<items;i++) {
|
||||
|
||||
entry = &ule[i];
|
||||
uwsgi_log("attributetype ( 1.3.6.1.4.1.35156.17.4.%d NAME (%s", entry->num, entry->names);
|
||||
|
||||
if (entry->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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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");
|
||||
|
||||
uwsgi_log("objectclass ( 1.3.6.1.4.1.35156.17.3.1 NAME 'uWSGIConfig' SUP top AUXILIARY DESC 'uWSGI configuration' MAY ( ");
|
||||
|
||||
for(i=0;i<items;i++) {
|
||||
|
||||
entry = &ule[i];
|
||||
|
||||
char *list2 = uwsgi_concat2(entry->names+1, "");
|
||||
char *p = strtok(list2, " ");
|
||||
while (p != NULL) {
|
||||
uwsgi_log("%.*s $ ", strlen(p)-2, p+1);
|
||||
p = strtok(NULL, " ");
|
||||
}
|
||||
|
||||
free(list2);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
uwsgi_log("[uWSGI] getting LDAP configuration from %s\n", url);
|
||||
|
||||
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 LDAP_API_VERSION >= 3000
|
||||
if ( (ret = ldap_initialize( &ldp, url)) != LDAP_SUCCESS) {
|
||||
uwsgi_log("LDAP: %s\n", ldap_err2string(ret));
|
||||
exit(1);
|
||||
}
|
||||
#else
|
||||
if ( (ldp = ldap_init( ldap_url->lud_host, ldap_url->lud_port)) == NULL) {
|
||||
uwsgi_error("ldap_init()");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
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);
|
||||
|
||||
int found = 0;
|
||||
for( attr = ldap_first_attribute(ldp, entry, &ber); attr != NULL; attr = ldap_next_attribute(ldp, entry, ber)) {
|
||||
if (!strncmp(attr,"uWSGI",5)) {
|
||||
|
||||
found = 1;
|
||||
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_attr/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;
|
||||
|
||||
add_exported_option((char*) uwsgi_attr, uwsgi_val, 0);
|
||||
free(bervalues);
|
||||
}
|
||||
else {
|
||||
free(uwsgi_attr);
|
||||
}
|
||||
}
|
||||
free(attr);
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
uwsgi_log("no uWSGI LDAP entry found\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
free(ber);
|
||||
free(results);
|
||||
|
||||
ldap_unbind_ext_s(ldp, NULL, NULL);
|
||||
|
||||
}
|
||||
#endif
|
||||
+806
@@ -0,0 +1,806 @@
|
||||
#include "../uwsgi.h"
|
||||
|
||||
#define AMQP_CONNECTION_HEADER "AMQP\0\0\x09\x01"
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
#define ntohll(x) x
|
||||
#else
|
||||
#define ntohll(x) ( ( (uint64_t)(ntohl( (uint32_t)((x << 32) >> 32) )) << 32) | ntohl( ((uint32_t)(x >> 32)) ) )
|
||||
#endif
|
||||
#define htonll(x) ntohll(x)
|
||||
|
||||
#define amqp_send(a, b, c) if (send(a, b, c, 0) < 0) { uwsgi_error("send()"); return -1; }
|
||||
|
||||
struct amqp_frame_header {
|
||||
|
||||
char type;
|
||||
uint16_t channel;
|
||||
uint32_t size;
|
||||
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct amqp_frame_method {
|
||||
uint16_t class_id;
|
||||
uint16_t method_id;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
static char *amqp_simple_get_frame(int, struct amqp_frame_header *);
|
||||
static char *amqp_get_method(int, uint16_t, uint16_t, uint32_t *);
|
||||
|
||||
/*
|
||||
static char *amqp_get_longstr(char *ptr, char *watermark) {
|
||||
|
||||
uint32_t longstr_size;
|
||||
|
||||
if (ptr+4 > watermark) return NULL;
|
||||
|
||||
memcpy(&longstr_size, ptr, 4);
|
||||
longstr_size = ntohl(longstr_size);
|
||||
|
||||
if (ptr+4+longstr_size > watermark) return NULL;
|
||||
|
||||
return ptr+4+longstr_size;
|
||||
}
|
||||
*/
|
||||
|
||||
static char *amqp_get_str(char *ptr, char *watermark) {
|
||||
|
||||
uint8_t str_size;
|
||||
|
||||
// over engeneering...
|
||||
if (ptr+1 > watermark) return NULL;
|
||||
|
||||
str_size = *ptr;
|
||||
|
||||
if (ptr+1+str_size > watermark) return NULL;
|
||||
|
||||
return ptr+1+str_size;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
static char *amqp_get_table(char *ptr, char *watermark) {
|
||||
|
||||
uint32_t table_size;
|
||||
|
||||
if (ptr+4 > watermark) return NULL;
|
||||
|
||||
memcpy(&table_size, ptr, 4);
|
||||
|
||||
table_size = ntohl(table_size);
|
||||
|
||||
if (ptr+4+table_size > watermark) return NULL;
|
||||
|
||||
return ptr+4+table_size;
|
||||
}
|
||||
*/
|
||||
|
||||
static char *amqp_get_short(char *ptr, char *watermark, uint16_t *sv) {
|
||||
|
||||
uint16_t tmp_short;
|
||||
|
||||
if (ptr+2 > watermark) return NULL;
|
||||
|
||||
memcpy(&tmp_short, ptr, 2);
|
||||
|
||||
*sv = ntohs(tmp_short);
|
||||
|
||||
return ptr+2;
|
||||
}
|
||||
|
||||
static char *amqp_get_long(char *ptr, char *watermark, uint32_t *lv) {
|
||||
|
||||
uint32_t tmp_long;
|
||||
|
||||
if (ptr+4 > watermark) return NULL;
|
||||
|
||||
memcpy(&tmp_long, ptr, 4);
|
||||
|
||||
*lv = ntohl(tmp_long);
|
||||
return ptr+4;
|
||||
}
|
||||
|
||||
static char *amqp_get_longlong(char *ptr, char *watermark, uint64_t *llv) {
|
||||
|
||||
uint64_t tmp_longlong;
|
||||
|
||||
if (ptr+8 > watermark) return NULL;
|
||||
|
||||
memcpy(&tmp_longlong, ptr, 8);
|
||||
|
||||
*llv = ntohll(tmp_longlong);
|
||||
return ptr+8;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int amqp_send_ack(int fd, uint64_t delivery_tag) {
|
||||
|
||||
uint32_t size = 4 + 8 + 1;
|
||||
|
||||
size = htonl(size);
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\1", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 60 method 80
|
||||
amqp_send(fd, "\x00\x3C\x00\x50", 4);
|
||||
|
||||
// set delivery_tag
|
||||
delivery_tag = htonll(delivery_tag);
|
||||
amqp_send(fd, &delivery_tag, 8);
|
||||
|
||||
// empty bits
|
||||
amqp_send(fd, "\0", 1);
|
||||
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *uwsgi_amqp_consume(int fd, uint64_t *msgsize, char **routing_key) {
|
||||
|
||||
uint32_t size;
|
||||
struct amqp_frame_header fh;
|
||||
uint64_t delivery_tag;
|
||||
uint64_t current_size = 0;
|
||||
char *ptr;
|
||||
char *watermark;
|
||||
uint16_t sv;
|
||||
|
||||
char *frame = amqp_get_method(fd, 60, 60, &size);
|
||||
if (!frame) return NULL;
|
||||
|
||||
ptr = frame+4;
|
||||
watermark = frame+size;
|
||||
|
||||
// consumer_tag
|
||||
ptr = amqp_get_str(ptr, watermark); if (!ptr) goto clear;
|
||||
// delivery_tag (needed for ack)
|
||||
ptr = amqp_get_longlong(ptr, watermark, &delivery_tag); if (!ptr) goto clear;
|
||||
// redelivered
|
||||
if (ptr+1 > watermark) goto clear;
|
||||
ptr++;
|
||||
// exchange
|
||||
ptr = amqp_get_str(ptr, watermark); if (!ptr) goto clear;
|
||||
// routing_key
|
||||
if (ptr+1 > watermark) goto clear;
|
||||
uint8_t rk_size = (uint8_t) *ptr;
|
||||
ptr++;
|
||||
if (ptr+rk_size > watermark) goto clear;
|
||||
|
||||
if (rk_size > 0) {
|
||||
char *rkey = uwsgi_concat2n(ptr, rk_size, "", 0);
|
||||
ptr+=rk_size;
|
||||
|
||||
*routing_key = rkey;
|
||||
}
|
||||
else {
|
||||
*routing_key = NULL;
|
||||
}
|
||||
|
||||
char *header = amqp_simple_get_frame(fd, &fh);
|
||||
if (!header) goto clear;
|
||||
|
||||
if (fh.type != 2) goto clear2;
|
||||
|
||||
ptr = header;
|
||||
watermark = ptr+fh.size;
|
||||
|
||||
// header class_id
|
||||
ptr = amqp_get_short(ptr, watermark, &sv); if (!ptr) goto clear2;
|
||||
// header weight
|
||||
ptr = amqp_get_short(ptr, watermark, &sv); if (!ptr) goto clear2;
|
||||
// message size;
|
||||
ptr = amqp_get_longlong(ptr, watermark, msgsize); if (!ptr) goto clear2;
|
||||
|
||||
free(frame);
|
||||
free(header);
|
||||
|
||||
char *fullbody = uwsgi_malloc(*msgsize);
|
||||
char *message;
|
||||
|
||||
while(current_size < *msgsize) {
|
||||
message = amqp_simple_get_frame(fd, &fh);
|
||||
if (!message) goto clear;
|
||||
|
||||
if (fh.type != 3) {
|
||||
free(message);
|
||||
goto clear3;
|
||||
}
|
||||
|
||||
if (fh.size+current_size > *msgsize) {
|
||||
free(message);
|
||||
goto clear3;
|
||||
}
|
||||
|
||||
memcpy(fullbody+current_size, message, fh.size);
|
||||
current_size+=fh.size;
|
||||
free(message);
|
||||
}
|
||||
|
||||
if (amqp_send_ack(fd, delivery_tag) < 0) {
|
||||
goto clear3;
|
||||
}
|
||||
|
||||
return fullbody;
|
||||
|
||||
clear3:
|
||||
free(fullbody);
|
||||
return NULL;
|
||||
|
||||
clear2:
|
||||
free(header);
|
||||
clear:
|
||||
free(frame);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
static int amqp_send_exchange_declare( int fd, char *exchange, char *exchange_type) {
|
||||
|
||||
uint32_t size = 4 + 2 + (1 +strlen(exchange)) + (1 +strlen(exchange_type)) + 1 + 4;
|
||||
uint8_t shortsize = strlen(exchange) ;
|
||||
|
||||
size = htonl(size);
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\1", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 40 method 10
|
||||
amqp_send(fd, "\x00\x28\x00\x0A", 4);
|
||||
|
||||
// send empty reserved
|
||||
amqp_send(fd, "\0\0", 2);
|
||||
|
||||
// set exchange name
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, exchange, shortsize);
|
||||
|
||||
// set exchange type
|
||||
shortsize = strlen(exchange_type);
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, exchange_type, shortsize);
|
||||
|
||||
// empty bits
|
||||
amqp_send(fd, "\0", 1);
|
||||
// empty table
|
||||
amqp_send(fd, "\0\0\0\0", 4);
|
||||
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int amqp_send_queue_bind( int fd, char *queue, char *exchange) {
|
||||
|
||||
uint32_t size = 4 + 2 + (1 +strlen(queue)) + (1 +strlen(exchange)) + 1 + 1 + 4;
|
||||
uint8_t shortsize = strlen(queue) ;
|
||||
|
||||
size = htonl(size);
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\1", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 50 method 20
|
||||
amqp_send(fd, "\x00\x32\x00\x14", 4);
|
||||
|
||||
// send empty reserved
|
||||
amqp_send(fd, "\0\0", 2);
|
||||
|
||||
// set queue name
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, queue, shortsize);
|
||||
|
||||
// set exchange name
|
||||
shortsize = strlen(exchange);
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, exchange, shortsize);
|
||||
|
||||
// set empty routing-key
|
||||
amqp_send(fd, "\0", 1);
|
||||
|
||||
// empty bits
|
||||
amqp_send(fd, "\0", 1);
|
||||
// empty table
|
||||
amqp_send(fd, "\0\0\0\0", 4);
|
||||
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int amqp_send_queue_consume( int fd, char *queue) {
|
||||
|
||||
uint32_t size = 4 + 2 + (1 +strlen(queue)) + 1 + 1 + 4;
|
||||
uint8_t shortsize = strlen(queue) ;
|
||||
|
||||
size = htonl(size);
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\1", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 60 method 20
|
||||
amqp_send(fd, "\x00\x3C\x00\x14", 4);
|
||||
|
||||
// send empty reserved
|
||||
amqp_send(fd, "\0\0", 2);
|
||||
|
||||
// set queue name
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, queue, shortsize);
|
||||
|
||||
// set tag name
|
||||
amqp_send(fd, "\0", 1);
|
||||
|
||||
// empty bits
|
||||
amqp_send(fd, "\0", 1);
|
||||
// empty table
|
||||
amqp_send(fd, "\0\0\0\0", 4);
|
||||
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amqp_wait_connection_start(int fd) {
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 10, 10, &size);
|
||||
|
||||
if (frame) {
|
||||
free(frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int amqp_wait_exchange_declare_ok(int fd) {
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 40, 11, &size);
|
||||
|
||||
if (frame) {
|
||||
free(frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int amqp_wait_basic_consume_ok(int fd) {
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 60, 21, &size);
|
||||
|
||||
if (frame) {
|
||||
free(frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int amqp_wait_channel_open_ok(int fd) {
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 20, 11, &size);
|
||||
|
||||
if (frame) {
|
||||
free(frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int amqp_wait_queue_bind_ok(int fd) {
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 50, 21, &size);
|
||||
|
||||
if (frame) {
|
||||
free(frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static char *amqp_wait_queue_declare_ok(int fd) {
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 50, 11, &size);
|
||||
char *queue = NULL;
|
||||
char *ptr;
|
||||
char *watermark;
|
||||
|
||||
if (frame) {
|
||||
|
||||
ptr = frame+4;
|
||||
watermark = frame+size;
|
||||
|
||||
ptr = amqp_get_str(ptr, watermark); if (!ptr) { free(frame); return NULL; }
|
||||
|
||||
queue = uwsgi_concat2n(frame+5, *(frame+4), "", 0);
|
||||
|
||||
free(frame);
|
||||
return queue;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int amqp_wait_connection_open_ok(int fd) {
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 10, 41, &size);
|
||||
|
||||
if (frame) {
|
||||
free(frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int amqp_wait_connection_tune(int fd) {
|
||||
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 10, 30, &size);
|
||||
|
||||
uint16_t sv;
|
||||
uint32_t lv;
|
||||
char *watermark ;
|
||||
char *ptr;
|
||||
|
||||
|
||||
if (frame) {
|
||||
ptr = frame+4;
|
||||
watermark = frame+size;
|
||||
ptr = amqp_get_short(ptr, watermark, &sv); if (!ptr) { free(frame); return -1; }
|
||||
uwsgi_log("AMQP max channels: %d\n", sv);
|
||||
ptr = amqp_get_long(ptr, watermark, &lv); if (!ptr) { free(frame); return -1; }
|
||||
uwsgi_log("AMQP max frame size: %d\n", lv);
|
||||
ptr = amqp_get_short(ptr, watermark, &sv); if (!ptr) { free(frame); return -1; }
|
||||
uwsgi_log("AMQP heartbeath: %d\n", sv);
|
||||
|
||||
free(frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char *amqp_simple_get_frame(int fd, struct amqp_frame_header *fh) {
|
||||
|
||||
char *ptr = (char *) fh;
|
||||
size_t len = 0, rlen;
|
||||
|
||||
while(len < 7) {
|
||||
rlen = recv(fd, ptr, 7-len, 0);
|
||||
if (rlen <= 0) {
|
||||
uwsgi_error("recv()");
|
||||
return NULL;
|
||||
}
|
||||
len += rlen;
|
||||
ptr += rlen;
|
||||
}
|
||||
|
||||
fh->channel = ntohs(fh->channel);
|
||||
fh->size = ntohl(fh->size);
|
||||
|
||||
len = 0;
|
||||
|
||||
char *frame = malloc(fh->size+1);
|
||||
ptr = frame;
|
||||
|
||||
while(len < fh->size+1) {
|
||||
rlen = recv(fd, ptr, (fh->size+1)-len, 0);
|
||||
if (rlen <= 0) {
|
||||
uwsgi_error("recv()");
|
||||
return NULL;
|
||||
}
|
||||
len += rlen;
|
||||
ptr += rlen;
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
static char *amqp_get_method(int fd, uint16_t class_id, uint16_t method_id, uint32_t *size) {
|
||||
|
||||
struct amqp_frame_header fh;
|
||||
struct amqp_frame_method *fm;
|
||||
|
||||
char *frame = amqp_simple_get_frame(fd, &fh);
|
||||
if (!frame) return NULL;
|
||||
|
||||
if (fh.type != 1) goto clear;
|
||||
|
||||
fm = (struct amqp_frame_method *) frame;
|
||||
fm->class_id = ntohs(fm->class_id);
|
||||
fm->method_id = ntohs(fm->method_id);
|
||||
|
||||
if (fm->class_id != class_id) goto clear;
|
||||
if (fm->method_id != method_id) goto clear;
|
||||
|
||||
*size = fh.size;
|
||||
return frame;
|
||||
|
||||
clear:
|
||||
|
||||
free(frame);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int amqp_send_channel_open(int fd, uint16_t id) {
|
||||
|
||||
uint32_t size = 4 + 1;
|
||||
size = htonl(size);
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\1", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 20 method 10
|
||||
amqp_send(fd, "\x00\x14\x00\x0A", 4);
|
||||
|
||||
amqp_send(fd, "\0", 1);
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amqp_send_connection_open(int fd, char *vhost) {
|
||||
|
||||
uint8_t shortsize = strlen(vhost);
|
||||
uint32_t size = 4 + 1 +strlen(vhost) + 2;
|
||||
size = htonl(size);
|
||||
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\0", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 10 method 28
|
||||
amqp_send(fd, "\x00\x0A\x00\x28", 4);
|
||||
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, vhost, strlen(vhost));
|
||||
|
||||
shortsize = 0;
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int amqp_send_connection_tune_ok(int fd, uint16_t max_chan, uint32_t max_frame_size, uint16_t heartbeat) {
|
||||
|
||||
uint32_t size = 4 + 2 + 4 + 2;
|
||||
size = htonl(size);
|
||||
|
||||
max_chan = htons(max_chan);
|
||||
max_frame_size = htonl(max_frame_size);
|
||||
heartbeat = htons(heartbeat);
|
||||
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\0", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 10 method 15
|
||||
amqp_send(fd, "\x00\x0A\x00\x1F", 4);
|
||||
|
||||
amqp_send(fd, &max_chan, 2);
|
||||
amqp_send(fd, &max_frame_size, 4);
|
||||
amqp_send(fd, &heartbeat, 2);
|
||||
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int amqp_send_queue_declare(int fd, char *queue) {
|
||||
|
||||
uint32_t size = 4 + 2 + (1 +strlen(queue)) + 1 + 4;
|
||||
uint8_t shortsize = strlen(queue) ;
|
||||
|
||||
size = htonl(size);
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\1", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 50 method 10
|
||||
amqp_send(fd, "\x00\x32\x00\x0A", 4);
|
||||
|
||||
// send empty reserved
|
||||
amqp_send(fd, "\0\0", 2);
|
||||
|
||||
// set queue name
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, queue, shortsize);
|
||||
|
||||
// empty bits
|
||||
amqp_send(fd, "\0", 1);
|
||||
// empty table
|
||||
amqp_send(fd, "\0\0\0\0", 4);
|
||||
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *amqp_get_queue(int fd, char *queue) {
|
||||
|
||||
if (amqp_send_queue_declare(fd, queue) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return amqp_wait_queue_declare_ok(fd);
|
||||
}
|
||||
|
||||
|
||||
static int amqp_send_connection_start_ok(int fd, char *mech, char *sasl_response, int sasl_response_size, char *locale) {
|
||||
|
||||
uint32_t size = 4 + 4 + (1 +strlen(mech)) + (4 + sasl_response_size) + (1 + strlen(locale));
|
||||
uint8_t shortsize ;
|
||||
|
||||
size = htonl(size);
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\0", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 10 method 11
|
||||
amqp_send(fd, "\x00\x0A\x00\x0B", 4);
|
||||
|
||||
// send empty client properties
|
||||
amqp_send(fd, "\0\0\0\0", 4);
|
||||
|
||||
// send mechanism short string
|
||||
shortsize = strlen(mech);
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, mech, strlen(mech));
|
||||
|
||||
// send sasl response
|
||||
size = htonl(sasl_response_size);
|
||||
amqp_send(fd, &size, 4);
|
||||
amqp_send(fd, sasl_response, sasl_response_size);
|
||||
|
||||
// send locale
|
||||
shortsize = strlen(locale);
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, locale, strlen(locale));
|
||||
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_amqp_consume_queue(int fd, char *vhost, char *username, char *password, char *queue, char *exchange, char *exchange_type) {
|
||||
|
||||
char *auth = uwsgi_concat4n("\0",1, username, strlen(username), "\0",1, password, strlen(password));
|
||||
|
||||
if (send(fd, AMQP_CONNECTION_HEADER, 8, 0) < 0) {
|
||||
uwsgi_error("send()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (amqp_wait_connection_start(fd) < 0) {
|
||||
uwsgi_log("AMQP error waiting for Connection.start\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_log("sending Connection.start-ok\n");
|
||||
if (amqp_send_connection_start_ok(fd, "PLAIN", auth, strlen(username)+strlen(password)+2, "en_US") < 0) {
|
||||
free(auth);
|
||||
uwsgi_log("AMQP error sending Connection.start-ok\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(auth);
|
||||
|
||||
if (amqp_wait_connection_tune(fd) < 0) {
|
||||
uwsgi_log("AMQP error waiting for Connection.tune\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_log("sending Connection.tune-ok\n");
|
||||
if (amqp_send_connection_tune_ok(fd, 0, 0xffff, 0) < 0) {
|
||||
uwsgi_log("AMQP error sending Connection.tune-ok\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_log("sending Connection.open\n");
|
||||
if (amqp_send_connection_open(fd, vhost) < 0) {
|
||||
uwsgi_log("AMQP error sending Connection.open\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (amqp_wait_connection_open_ok(fd) < 0) {
|
||||
uwsgi_log("AMQP error waiting for Connection.open-ok\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_log("sending Channel.open\n");
|
||||
if (amqp_send_channel_open(fd, 1) < 0) {
|
||||
uwsgi_log("AMQP error sending Channel.open\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (amqp_wait_channel_open_ok(fd) < 0) {
|
||||
uwsgi_log("AMQP error waiting for Channel.open-ok\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
queue = amqp_get_queue(fd, queue);
|
||||
if (!queue) {
|
||||
uwsgi_log("AMQP error sending Queue.declare\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (exchange) {
|
||||
if (amqp_send_exchange_declare(fd, exchange, exchange_type) < 0) {
|
||||
uwsgi_log("AMQP error sending Exchange.declare\n");
|
||||
free(queue);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (amqp_wait_exchange_declare_ok(fd) < 0) {
|
||||
uwsgi_log("AMQP error waiting for Exchange.declare-ok\n");
|
||||
free(queue);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (amqp_send_queue_bind(fd, queue, exchange) < 0) {
|
||||
uwsgi_log("AMQP error sending Queue.bind\n");
|
||||
free(queue);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (amqp_wait_queue_bind_ok(fd) < 0) {
|
||||
uwsgi_log("AMQP error waiting for Queue.bind-ok\n");
|
||||
free(queue);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (amqp_send_queue_consume(fd, queue) < 0) {
|
||||
uwsgi_log("AMQP error sending Basic.consume\n");
|
||||
free(queue);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (amqp_wait_basic_consume_ok(fd) < 0) {
|
||||
uwsgi_log("AMQP error waiting for Basic.consume-ok\n");
|
||||
free(queue);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(queue);
|
||||
|
||||
uwsgi_log("AMQP subscription done, waiting for events...\n");
|
||||
return 0;
|
||||
}
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
#include "../uwsgi.h"
|
||||
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#ifndef CLONE_NEWUTS
|
||||
#define CLONE_NEWUTS 0x04000000
|
||||
#endif
|
||||
|
||||
#ifndef CLONE_NEWPID
|
||||
#define CLONE_NEWPID 0x20000000
|
||||
#endif
|
||||
|
||||
#ifndef CLONE_NEWIPC
|
||||
#define CLONE_NEWIPC 0x08000000
|
||||
#endif
|
||||
|
||||
#ifndef CLONE_NEWNET
|
||||
#define CLONE_NEWNET 0x40000000
|
||||
#endif
|
||||
|
||||
void linux_namespace_start(void *argv) {
|
||||
for (;;) {
|
||||
char stack[PTHREAD_STACK_MIN];
|
||||
int waitpid_status;
|
||||
uwsgi_log("*** jailing uWSGI in %s ***\n", uwsgi.ns);
|
||||
int clone_flags = SIGCHLD | CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWIPC | CLONE_NEWNS;
|
||||
if (uwsgi.ns_net) {
|
||||
clone_flags |= CLONE_NEWNET;
|
||||
}
|
||||
pid_t pid = clone(uwsgi_start, stack + PTHREAD_STACK_MIN, clone_flags, (void *) argv);
|
||||
if (pid == -1) {
|
||||
uwsgi_error("clone()");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_log("waiting for jailed master (pid: %d) death...\n", (int) pid);
|
||||
pid = waitpid(pid, &waitpid_status, 0);
|
||||
if (pid < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// in Linux this is reliable
|
||||
if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == 1) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_log("pid %d ended. Respawning...\n", (int) pid);
|
||||
}
|
||||
|
||||
// never here
|
||||
}
|
||||
|
||||
|
||||
|
||||
void linux_namespace_jail() {
|
||||
|
||||
char *ns_tmp_mountpoint = NULL, *ns_tmp_mountpoint2 = NULL;
|
||||
|
||||
if (getpid() != 1) {
|
||||
uwsgi_log("your kernel does not support linux pid namespace\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char *ns_hostname = strchr(uwsgi.ns, ':');
|
||||
if (ns_hostname) {
|
||||
ns_hostname[0] = 0;
|
||||
ns_hostname++;
|
||||
if (sethostname(ns_hostname, strlen(ns_hostname))) {
|
||||
uwsgi_error("sethostname()");
|
||||
}
|
||||
}
|
||||
|
||||
FILE *procmounts;
|
||||
char line[1024];
|
||||
int unmounted = 1;
|
||||
char *delim0, *delim1;
|
||||
|
||||
if (chdir(uwsgi.ns)) {
|
||||
uwsgi_error("chdir()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (strcmp(uwsgi.ns, "/")) {
|
||||
ns_tmp_mountpoint = uwsgi_concat2(uwsgi.ns, "/.uwsgi_ns_tmp_mountpoint");
|
||||
mkdir(ns_tmp_mountpoint, S_IRWXU);
|
||||
|
||||
ns_tmp_mountpoint2 = uwsgi_concat2(ns_tmp_mountpoint, "/.uwsgi_ns_tmp_mountpoint");
|
||||
mkdir(ns_tmp_mountpoint2, S_IRWXU);
|
||||
|
||||
if (mount(uwsgi.ns, ns_tmp_mountpoint, "none", MS_BIND, NULL)) {
|
||||
uwsgi_error("mount()");
|
||||
}
|
||||
if (chdir(ns_tmp_mountpoint)) {
|
||||
uwsgi_error("chdir()");
|
||||
}
|
||||
|
||||
if (pivot_root(".", ns_tmp_mountpoint2)) {
|
||||
uwsgi_error("pivot_root()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (chdir("/")) {
|
||||
uwsgi_error("chdir()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uwsgi_log("remounting /proc\n");
|
||||
if (mount("proc", "/proc", "proc", 0, NULL)) {
|
||||
uwsgi_error("mount()");
|
||||
}
|
||||
|
||||
while (unmounted) {
|
||||
|
||||
unmounted = 0;
|
||||
procmounts = fopen("/proc/self/mounts", "r");
|
||||
while (fgets(line, 1024, procmounts) != NULL) {
|
||||
delim0 = strchr(line, ' ');
|
||||
delim0++;
|
||||
delim1 = strchr(delim0, ' ');
|
||||
*delim1 = 0;
|
||||
if (!strcmp(delim0, "/") || !strcmp(delim0, "/proc"))
|
||||
continue;
|
||||
if (!umount(delim0)) {
|
||||
unmounted++;
|
||||
}
|
||||
}
|
||||
fclose(procmounts);
|
||||
}
|
||||
|
||||
if (rmdir("/.uwsgi_ns_tmp_mountpoint/.uwsgi_ns_tmp_mountpoint")) {
|
||||
uwsgi_error("rmdir()");
|
||||
}
|
||||
if (rmdir("/.uwsgi_ns_tmp_mountpoint")) {
|
||||
uwsgi_error("rmdir()");
|
||||
}
|
||||
|
||||
if (strcmp(uwsgi.ns, "/")) {
|
||||
free(ns_tmp_mountpoint2);
|
||||
free(ns_tmp_mountpoint);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+382
@@ -0,0 +1,382 @@
|
||||
#include "../uwsgi.h"
|
||||
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#ifdef CLONE_NEWNET
|
||||
|
||||
#define NLMSG_TAIL(nmsg) \
|
||||
((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
|
||||
|
||||
#ifndef VETH_INFO_PEER
|
||||
# define VETH_INFO_PEER 1
|
||||
#endif
|
||||
|
||||
|
||||
struct uwsgi_nl_req {
|
||||
struct nlmsghdr nlmsg;
|
||||
struct ifinfomsg ifinfomsg;
|
||||
};
|
||||
|
||||
struct uwsgi_nl_ipreq {
|
||||
struct nlmsghdr nlmsg;
|
||||
struct ifaddrmsg ifaddrmsg;
|
||||
};
|
||||
|
||||
struct uwsgi_nl_rtreq {
|
||||
struct nlmsghdr nlmsg;
|
||||
struct rtmsg rtmsg;
|
||||
};
|
||||
|
||||
int uwsgi_nl_send(struct nlmsghdr *);
|
||||
|
||||
struct nlmsghdr *uwsgi_netlink_alloc() {
|
||||
|
||||
size_t len = NLMSG_ALIGN(8192) + NLMSG_ALIGN(sizeof(struct nlmsghdr *));
|
||||
|
||||
struct nlmsghdr *nlmsg = (struct nlmsghdr *) uwsgi_malloc(len);
|
||||
|
||||
memset(nlmsg, 0, len);
|
||||
|
||||
struct uwsgi_nl_req *unr = (struct uwsgi_nl_req *)nlmsg;
|
||||
unr->ifinfomsg.ifi_family = AF_UNSPEC;
|
||||
|
||||
nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
||||
nlmsg->nlmsg_type = RTM_NEWLINK;
|
||||
nlmsg->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
|
||||
|
||||
return nlmsg;
|
||||
}
|
||||
|
||||
struct nlmsghdr *uwsgi_netlink_ip_alloc() {
|
||||
|
||||
size_t len = NLMSG_ALIGN(8192) + NLMSG_ALIGN(sizeof(struct nlmsghdr *));
|
||||
|
||||
struct nlmsghdr *nlmsg = (struct nlmsghdr *) uwsgi_malloc(len);
|
||||
|
||||
memset(nlmsg, 0, len);
|
||||
|
||||
struct uwsgi_nl_ipreq *uni = (struct uwsgi_nl_ipreq *)nlmsg;
|
||||
uni->ifaddrmsg.ifa_family = AF_INET;
|
||||
uni->ifaddrmsg.ifa_scope = 0;
|
||||
|
||||
nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
|
||||
nlmsg->nlmsg_type = RTM_NEWADDR;
|
||||
nlmsg->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_CREATE|NLM_F_EXCL;
|
||||
|
||||
|
||||
return nlmsg;
|
||||
}
|
||||
|
||||
struct nlmsghdr *uwsgi_netlink_rt_alloc() {
|
||||
|
||||
size_t len = NLMSG_ALIGN(8192) + NLMSG_ALIGN(sizeof(struct nlmsghdr *));
|
||||
|
||||
struct nlmsghdr *nlmsg = (struct nlmsghdr *) uwsgi_malloc(len);
|
||||
|
||||
memset(nlmsg, 0, len);
|
||||
|
||||
struct uwsgi_nl_rtreq *unr = (struct uwsgi_nl_rtreq *)nlmsg;
|
||||
unr->rtmsg.rtm_family = AF_INET;
|
||||
unr->rtmsg.rtm_table = RT_TABLE_MAIN;
|
||||
unr->rtmsg.rtm_protocol = RTPROT_STATIC;
|
||||
unr->rtmsg.rtm_scope = RT_SCOPE_UNIVERSE;
|
||||
unr->rtmsg.rtm_type = RTN_UNICAST;
|
||||
|
||||
|
||||
nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||
nlmsg->nlmsg_type = RTM_NEWROUTE;
|
||||
nlmsg->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_CREATE|NLM_F_EXCL;
|
||||
|
||||
|
||||
return nlmsg;
|
||||
}
|
||||
|
||||
int uwsgi_netlink_rt(char *src, char *dst, int dst_prefix, char *gw) {
|
||||
|
||||
struct nlmsghdr *nlmsg = uwsgi_netlink_rt_alloc();
|
||||
struct rtattr *rta;
|
||||
struct in_addr ia;
|
||||
struct in_addr oa;
|
||||
struct in_addr ga;
|
||||
struct uwsgi_nl_rtreq *unr = (struct uwsgi_nl_rtreq *)nlmsg;
|
||||
|
||||
if (inet_pton(AF_INET, src, &ia) <= 0) {
|
||||
uwsgi_error("inet_pton()");
|
||||
free(nlmsg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (inet_pton(AF_INET, dst, &oa) <= 0) {
|
||||
uwsgi_error("inet_pton()");
|
||||
free(nlmsg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (inet_pton(AF_INET, gw, &ga) <= 0) {
|
||||
uwsgi_error("inet_pton()");
|
||||
free(nlmsg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = RTA_PREFSRC;
|
||||
rta->rta_len = RTA_LENGTH(4);
|
||||
memcpy(RTA_DATA(rta), &ia.s_addr, 4);
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = RTA_DST;
|
||||
rta->rta_len = RTA_LENGTH(4);
|
||||
memcpy(RTA_DATA(rta), &oa.s_addr, 4);
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = RTA_GATEWAY;
|
||||
rta->rta_len = RTA_LENGTH(4);
|
||||
memcpy(RTA_DATA(rta), &ga.s_addr, 4);
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
unr->rtmsg.rtm_src_len = 0;
|
||||
unr->rtmsg.rtm_dst_len = dst_prefix;
|
||||
|
||||
return uwsgi_nl_send(nlmsg);
|
||||
}
|
||||
|
||||
int uwsgi_netlink_gw(char *iface, char *ip) {
|
||||
|
||||
struct nlmsghdr *nlmsg = uwsgi_netlink_rt_alloc();
|
||||
struct rtattr *rta;
|
||||
struct in_addr ia;
|
||||
uint32_t zero = 0;
|
||||
|
||||
int index = if_nametoindex(iface);
|
||||
if (!index) return -1;
|
||||
|
||||
if (inet_pton(AF_INET, ip, &ia) <= 0) {
|
||||
uwsgi_error("inet_pton()");
|
||||
free(nlmsg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = RTA_GATEWAY;
|
||||
rta->rta_len = RTA_LENGTH(4);
|
||||
memcpy(RTA_DATA(rta), &ia.s_addr, 4);
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = RTA_DST;
|
||||
rta->rta_len = RTA_LENGTH(4);
|
||||
memcpy(RTA_DATA(rta), &zero, 4);
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = RTA_OIF;
|
||||
rta->rta_len = RTA_LENGTH(sizeof(int));
|
||||
memcpy(RTA_DATA(rta), &index, sizeof(int));
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
return uwsgi_nl_send(nlmsg);
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_netlink_ip(char *iface, char *ip, int prefix) {
|
||||
|
||||
struct nlmsghdr *nlmsg = uwsgi_netlink_ip_alloc();
|
||||
struct uwsgi_nl_ipreq *uni = (struct uwsgi_nl_ipreq *)nlmsg;
|
||||
struct rtattr *rta;
|
||||
struct in_addr ia;
|
||||
|
||||
int index = if_nametoindex(iface);
|
||||
if (!index) return -1;
|
||||
|
||||
uni->ifaddrmsg.ifa_index = index;
|
||||
uni->ifaddrmsg.ifa_prefixlen = prefix;
|
||||
|
||||
if (inet_pton(AF_INET, ip, &ia) <= 0) {
|
||||
uwsgi_error("inet_pton()");
|
||||
free(nlmsg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = IFA_LOCAL;
|
||||
rta->rta_len = RTA_LENGTH(sizeof(struct in_addr));
|
||||
memcpy(RTA_DATA(rta), &ia, sizeof(struct in_addr));
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = IFA_ADDRESS;
|
||||
rta->rta_len = RTA_LENGTH(sizeof(struct in_addr));
|
||||
memcpy(RTA_DATA(rta), &ia, sizeof(struct in_addr));
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
return uwsgi_nl_send(nlmsg);
|
||||
}
|
||||
|
||||
int uwsgi_netlink_veth_attach(char *veth1, pid_t pid) {
|
||||
|
||||
struct nlmsghdr *nlmsg = uwsgi_netlink_alloc();
|
||||
struct uwsgi_nl_req *unr = (struct uwsgi_nl_req *)nlmsg;
|
||||
struct rtattr *rta;
|
||||
|
||||
int index = if_nametoindex(veth1);
|
||||
if (!index) return -1;
|
||||
|
||||
unr->ifinfomsg.ifi_index = index;
|
||||
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = IFLA_NET_NS_PID;
|
||||
rta->rta_len = RTA_LENGTH(sizeof(pid_t));
|
||||
memcpy(RTA_DATA(rta), &pid, sizeof(pid_t));
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
return uwsgi_nl_send(nlmsg);
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_netlink_ifup(char *iface) {
|
||||
|
||||
struct nlmsghdr *nlmsg = uwsgi_netlink_alloc();
|
||||
struct uwsgi_nl_req *unr = (struct uwsgi_nl_req *)nlmsg;
|
||||
|
||||
int index = if_nametoindex(iface);
|
||||
if (!index) return -1;
|
||||
|
||||
unr->ifinfomsg.ifi_index = index;
|
||||
unr->ifinfomsg.ifi_change |= IFF_UP;
|
||||
unr->ifinfomsg.ifi_flags |= IFF_UP;
|
||||
return uwsgi_nl_send(nlmsg);
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_netlink_del(char *iface) {
|
||||
|
||||
struct nlmsghdr *nlmsg = uwsgi_netlink_alloc();
|
||||
struct uwsgi_nl_req *unr = (struct uwsgi_nl_req *)nlmsg;
|
||||
|
||||
int index = if_nametoindex(iface);
|
||||
if (!index) return -1;
|
||||
|
||||
nlmsg->nlmsg_type = RTM_DELLINK;
|
||||
unr->ifinfomsg.ifi_index = index;
|
||||
return uwsgi_nl_send(nlmsg);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int uwsgi_netlink_veth(char *veth0, char *veth1) {
|
||||
|
||||
struct rtattr *rta, *rta0, *rta1, *rta2;
|
||||
|
||||
struct nlmsghdr *nlmsg = uwsgi_netlink_alloc();
|
||||
|
||||
nlmsg->nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
|
||||
|
||||
// IFLA_LINKINFO
|
||||
rta0 = NLMSG_TAIL(nlmsg);
|
||||
rta0->rta_type = IFLA_LINKINFO;
|
||||
rta0->rta_len = RTA_LENGTH(0);
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta0->rta_len);
|
||||
|
||||
// IFLA_INFO_KIND
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = IFLA_INFO_KIND;
|
||||
rta->rta_len = RTA_LENGTH(4);
|
||||
memcpy(RTA_DATA(rta), "veth", 4);
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
// IFLA_INFO_DATA
|
||||
rta1 = NLMSG_TAIL(nlmsg);
|
||||
rta1->rta_type = IFLA_INFO_DATA;
|
||||
rta1->rta_len = RTA_LENGTH(0);
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta1->rta_len);
|
||||
|
||||
// VETH_INFO_PEER
|
||||
rta2 = NLMSG_TAIL(nlmsg);
|
||||
rta2->rta_type = VETH_INFO_PEER;
|
||||
rta2->rta_len = RTA_LENGTH(0);
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta2->rta_len);
|
||||
|
||||
nlmsg->nlmsg_len += sizeof(struct ifinfomsg);
|
||||
|
||||
// IFLA_IFNAME
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = IFLA_IFNAME;
|
||||
rta->rta_len = RTA_LENGTH(strlen(veth1));
|
||||
memcpy(RTA_DATA(rta), veth1, strlen(veth1));
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
rta2->rta_len = (void *)NLMSG_TAIL(nlmsg) - (void *)rta2;
|
||||
rta1->rta_len = (void *)NLMSG_TAIL(nlmsg) - (void *)rta1;
|
||||
rta0->rta_len = (void *)NLMSG_TAIL(nlmsg) - (void *)rta0;
|
||||
|
||||
// IFLA_IFNAME
|
||||
rta = NLMSG_TAIL(nlmsg);
|
||||
rta->rta_type = IFLA_IFNAME;
|
||||
rta->rta_len = RTA_LENGTH(strlen(veth0));
|
||||
memcpy(RTA_DATA(rta), veth0, strlen(veth0));
|
||||
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
|
||||
|
||||
return uwsgi_nl_send(nlmsg);
|
||||
}
|
||||
|
||||
int uwsgi_nl_send(struct nlmsghdr *nlmsg) {
|
||||
|
||||
struct sockaddr_nl nladdr;
|
||||
|
||||
struct iovec iov = {
|
||||
.iov_base = (void*)nlmsg,
|
||||
.iov_len = nlmsg->nlmsg_len,
|
||||
};
|
||||
|
||||
struct msghdr msg = {
|
||||
.msg_name = &nladdr,
|
||||
.msg_namelen = sizeof(nladdr),
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
int ret;
|
||||
int nlfd;
|
||||
|
||||
memset(&nladdr, 0, sizeof(struct sockaddr_nl));
|
||||
nladdr.nl_family = AF_NETLINK;
|
||||
nladdr.nl_pid = 0;
|
||||
nladdr.nl_groups = 0;
|
||||
|
||||
nlfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
if (nlfd < 0) {
|
||||
uwsgi_error("socket()");
|
||||
free(nlmsg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = sendmsg(nlfd, &msg, 0);
|
||||
if (ret < 0) {
|
||||
uwsgi_error("sendmsg()");
|
||||
free(nlmsg);
|
||||
close(nlfd);
|
||||
return -1;
|
||||
}
|
||||
ret = recvmsg(nlfd, &msg, 0);
|
||||
if (ret < 0) {
|
||||
uwsgi_error("recvmsg()");
|
||||
free(nlmsg);
|
||||
close(nlfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (nlmsg->nlmsg_type == NLMSG_ERROR) {
|
||||
struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(nlmsg);
|
||||
ret = err->error;
|
||||
}
|
||||
|
||||
free(nlmsg);
|
||||
close(nlfd);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
+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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/* function written by Ben Taylor (found in the qemu-devel list) */
|
||||
|
||||
#include "../uwsgi.h"
|
||||
|
||||
time_t timegm(struct tm *t) {
|
||||
time_t tl, tb;
|
||||
struct tm *tg;
|
||||
|
||||
tl = mktime (t);
|
||||
if (tl == -1) {
|
||||
t->tm_hour--;
|
||||
tl = mktime (t);
|
||||
if (tl == -1)
|
||||
return -1; /* can't deal with output from strptime */
|
||||
|
||||
tl += 3600;
|
||||
}
|
||||
tg = gmtime (&tl);
|
||||
tg->tm_isdst = 0;
|
||||
tb = mktime (tg);
|
||||
if (tb == -1) {
|
||||
tg->tm_hour--;
|
||||
tb = mktime (tg);
|
||||
if (tb == -1)
|
||||
return -1; /* can't deal with output from gmtime */
|
||||
tb += 3600;
|
||||
}
|
||||
return (tl - (tb - tl));
|
||||
}
|
||||
+326
-280
@@ -35,6 +35,23 @@
|
||||
#define data_uwsgi data_fastcgi
|
||||
#define data_uwsgi_init data_fastcgi_init
|
||||
|
||||
#ifdef __linux__
|
||||
#include <endian.h>
|
||||
#elif __sun__
|
||||
#elif __APPLE__
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#else
|
||||
#include <machine/endian.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
static uint16_t uwsgi_swap16(uint16_t x) {
|
||||
return (uint16_t) ((x & 0xff) << 8 | (x & 0xff00) >> 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* the uwsgi module is based on the proxy module
|
||||
@@ -47,25 +64,17 @@ typedef struct __attribute__((packed)) {
|
||||
uint8_t modifier1;
|
||||
uint16_t pktsize;
|
||||
uint8_t modifier2;
|
||||
} uwsgi_header ;
|
||||
|
||||
typedef enum {
|
||||
UWSGI_BALANCE_UNSET,
|
||||
UWSGI_BALANCE_FAIR,
|
||||
} uwsgi_balance_t;
|
||||
} uwsgi_header;
|
||||
|
||||
typedef struct {
|
||||
array *extensions;
|
||||
unsigned short debug;
|
||||
|
||||
uwsgi_balance_t balance;
|
||||
} plugin_config;
|
||||
|
||||
typedef struct {
|
||||
PLUGIN_DATA;
|
||||
|
||||
buffer *parse_response;
|
||||
buffer *balance_buf;
|
||||
|
||||
plugin_config **config_storage;
|
||||
|
||||
@@ -121,6 +130,7 @@ static handler_ctx * handler_ctx_init() {
|
||||
hctx->fd = -1;
|
||||
hctx->fde_ndx = -1;
|
||||
|
||||
|
||||
return hctx;
|
||||
}
|
||||
|
||||
@@ -138,7 +148,6 @@ INIT_FUNC(mod_uwsgi_init) {
|
||||
p = calloc(1, sizeof(*p));
|
||||
|
||||
p->parse_response = buffer_init();
|
||||
p->balance_buf = buffer_init();
|
||||
|
||||
return p;
|
||||
}
|
||||
@@ -150,7 +159,6 @@ FREE_FUNC(mod_uwsgi_free) {
|
||||
UNUSED(srv);
|
||||
|
||||
buffer_free(p->parse_response);
|
||||
buffer_free(p->balance_buf);
|
||||
|
||||
if (p->config_storage) {
|
||||
size_t i;
|
||||
@@ -180,7 +188,6 @@ SETDEFAULTS_FUNC(mod_uwsgi_set_defaults) {
|
||||
config_values_t cv[] = {
|
||||
{ "uwsgi.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
|
||||
{ "uwsgi.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
|
||||
{ "uwsgi.balance", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
|
||||
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
|
||||
};
|
||||
|
||||
@@ -196,9 +203,7 @@ SETDEFAULTS_FUNC(mod_uwsgi_set_defaults) {
|
||||
|
||||
cv[0].destination = s->extensions;
|
||||
cv[1].destination = &(s->debug);
|
||||
cv[2].destination = p->balance_buf;
|
||||
|
||||
buffer_reset(p->balance_buf);
|
||||
|
||||
p->config_storage[i] = s;
|
||||
ca = ((data_config *)srv->config_context->data[i])->value;
|
||||
@@ -207,16 +212,6 @@ SETDEFAULTS_FUNC(mod_uwsgi_set_defaults) {
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
|
||||
if (buffer_is_empty(p->balance_buf)) {
|
||||
s->balance = UWSGI_BALANCE_FAIR;
|
||||
} else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("fair"))) {
|
||||
s->balance = UWSGI_BALANCE_FAIR;
|
||||
} else {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"uwsgi.balance has to be fair");
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
|
||||
if (NULL != (du = array_get_element(ca, "uwsgi.server"))) {
|
||||
size_t j;
|
||||
data_array *da = (data_array *)du;
|
||||
@@ -276,7 +271,7 @@ SETDEFAULTS_FUNC(mod_uwsgi_set_defaults) {
|
||||
|
||||
df = data_uwsgi_init();
|
||||
|
||||
df->port = 80;
|
||||
df->port = 3031;
|
||||
|
||||
buffer_copy_string_buffer(df->key, da_host->key);
|
||||
|
||||
@@ -396,17 +391,33 @@ static int uwsgi_establish_connection(server *srv, handler_ctx *hctx) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uwsgi_add_var(buffer *b, char * key, uint16_t keylen, char *val, uint16_t vallen) {
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
uint16_t uwlen;
|
||||
|
||||
uwlen = uwsgi_swap16(keylen);
|
||||
buffer_append_memory(b, (char *) &uwlen, 2); buffer_append_memory(b, key, keylen);
|
||||
uwlen = uwsgi_swap16(vallen);
|
||||
buffer_append_memory(b, (char *) &uwlen, 2); buffer_append_memory(b, val, vallen);
|
||||
#else
|
||||
buffer_append_memory(b, (char *) &keylen, 2); buffer_append_memory(b, key, keylen);
|
||||
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 ;
|
||||
uint16_t uwsgi_strsize;
|
||||
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;
|
||||
@@ -416,93 +427,138 @@ static int uwsgi_create_env(server *srv, handler_ctx *hctx) {
|
||||
|
||||
b = chunkqueue_get_append_buffer(hctx->wb);
|
||||
|
||||
log_error_write(srv, __FILE__, __LINE__, "s", "starting uwsgi request...");
|
||||
|
||||
/* make space for uwsgi header */
|
||||
buffer_append_memory(b, "\0\0\0\0", 4);
|
||||
|
||||
log_error_write(srv, __FILE__, __LINE__, "s", "space done...");
|
||||
|
||||
/* set WSGI vars */
|
||||
s = get_http_method_name(con->request.http_method);
|
||||
uwsgi_strsize = 14; buffer_append_memory(b, &uwsgi_strsize, 2); buffer_append_memory(b, "REQUEST_METHOD", uwsgi_strsize);
|
||||
uwsgi_strsize = strlen(s); buffer_append_memory(b, &uwsgi_strsize, 2); buffer_append_memory(b, s, uwsgi_strsize);
|
||||
uwsgi_add_var(b, "REQUEST_METHOD", 14, (char *) s, strlen(s));
|
||||
|
||||
uwsgi_strsize = 12; buffer_append_memory(b, &uwsgi_strsize, 2); buffer_append_memory(b, "QUERY_STRING", uwsgi_strsize);
|
||||
if (!buffer_is_empty(con->uri.query)) {
|
||||
uwsgi_strsize = con->uri.query->used; buffer_append_memory(b, &uwsgi_strsize, 2); buffer_append_memory(b, con->uri.query->ptr, uwsgi_strsize);
|
||||
} else {
|
||||
uwsgi_strsize = 0; buffer_append_memory(b, &uwsgi_strsize, 2);
|
||||
}
|
||||
uwsgi_add_var(b, "QUERY_STRING", 12, con->uri.query->ptr, con->uri.query->used-1);
|
||||
} else {
|
||||
uwsgi_add_var(b, "QUERY_STRING", 12, "", 0);
|
||||
}
|
||||
|
||||
s = get_http_version_name(con->request.http_version);
|
||||
uwsgi_strsize = 15; buffer_append_memory(b, &uwsgi_strsize, 2); buffer_append_memory(b, "SERVER_PROTOCOL", uwsgi_strsize);
|
||||
uwsgi_strsize = strlen(s); buffer_append_memory(b, &uwsgi_strsize, 2); buffer_append_memory(b, s, uwsgi_strsize);
|
||||
uwsgi_add_var(b, "SERVER_PROTOCOL", 15, (char *) s, strlen(s));
|
||||
|
||||
|
||||
uwsgi_strsize = 11; buffer_append_memory(b, &uwsgi_strsize, 2); buffer_append_memory(b, "SERVER_NAME", uwsgi_strsize);
|
||||
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;
|
||||
uwsgi_strsize = len ;
|
||||
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_strsize = strlen(s);
|
||||
}
|
||||
buffer_append_memory(b, &uwsgi_strsize, 2); buffer_append_memory(b, s, uwsgi_strsize);
|
||||
uwsgi_add_var(b, "SERVER_NAME", 11, (char *)s, strlen(s));
|
||||
}
|
||||
|
||||
uwsgi_strsize = 11; buffer_append_memory(b, &uwsgi_strsize, 2); buffer_append_memory(b, "SERVER_PORT", uwsgi_strsize);
|
||||
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_strsize = strlen(s); buffer_append_memory(b, &uwsgi_strsize, 2); buffer_append_memory(b, s, uwsgi_strsize);
|
||||
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);
|
||||
|
||||
uwsgi_strsize = 11; buffer_append_memory(b, &uwsgi_strsize, 2); buffer_append_memory(b, "REQUEST_URI", uwsgi_strsize);
|
||||
uwsgi_strsize = con->request.orig_uri->used; buffer_append_memory(b, &uwsgi_strsize, 2); buffer_append_memory(b, con->request.orig_uri->ptr, uwsgi_strsize);
|
||||
|
||||
uwsgi_strsize = 11; buffer_append_memory(b, &uwsgi_strsize, 2); buffer_append_memory(b, "REMOTE_PORT", uwsgi_strsize);
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
uwsgi_strsize = strlen(s); buffer_append_memory(b, &uwsgi_strsize, 2); buffer_append_memory(b, s, uwsgi_strsize);
|
||||
|
||||
uwsgi_strsize = 11; buffer_append_memory(b, &uwsgi_strsize, 2); buffer_append_memory(b, "REMOTE_ADDR", uwsgi_strsize);
|
||||
s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
|
||||
uwsgi_strsize = strlen(s); buffer_append_memory(b, &uwsgi_strsize, 2); buffer_append_memory(b, s, uwsgi_strsize);
|
||||
|
||||
|
||||
|
||||
uwsgi_add_var(b, "REMOTE_ADDR", 11, (char *)s, strlen(s));
|
||||
|
||||
|
||||
uh = (uwsgi_header *) b->ptr ;
|
||||
uh->modifier1 = 0 ;
|
||||
uh->pktsize = b->used - 4 ;
|
||||
uh->modifier2 = 0 ;
|
||||
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->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->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];
|
||||
|
||||
if (ds->value->used && ds->key->used) {
|
||||
size_t j;
|
||||
buffer_reset(srv->tmp_buf);
|
||||
if (!strcasecmp(ds->key->ptr, "CONTENT-TYPE") || !strcasecmp(ds->key->ptr, "CONTENT-LENGTH")) {
|
||||
buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
|
||||
}
|
||||
else {
|
||||
buffer_prepare_append(srv->tmp_buf, ds->key->used + 7);
|
||||
buffer_append_memory(srv->tmp_buf, "HTTP_", 5);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < con->environment->used; i++) {
|
||||
data_string *ds;
|
||||
ds = (data_string *)con->environment->data[i];
|
||||
if (ds->value->used && ds->key->used) {
|
||||
size_t j;
|
||||
buffer_reset(srv->tmp_buf);
|
||||
buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
|
||||
for (j = 0; j < ds->key->used - 1; j++) {
|
||||
srv->tmp_buf->ptr[srv->tmp_buf->used++] = light_isalnum((unsigned char)ds->key->ptr[j]) ? toupper((unsigned char)ds->key->ptr[j]) : '_';
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uh = (uwsgi_header *) b->ptr;
|
||||
uh->modifier1 = (uint8_t) 0;
|
||||
#ifdef __BIG_ENDIAN__
|
||||
uh->pktsize = uwsgi_swap16((uint16_t) b->used - 4);
|
||||
#else
|
||||
uh->pktsize = b->used - 4;
|
||||
#endif
|
||||
uh->modifier2 = (uint8_t) 0;
|
||||
|
||||
log_error_write(srv, __FILE__, __LINE__, "sd", "uwsgi_header ", b->used - 4);
|
||||
b->used++; /* fix size */
|
||||
|
||||
hctx->wb->bytes_in += b->used -1 ;
|
||||
hctx->wb->bytes_in += b->used -1;
|
||||
/* body */
|
||||
|
||||
if (con->request.content_length) {
|
||||
@@ -520,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;
|
||||
@@ -621,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) {
|
||||
@@ -681,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) {
|
||||
@@ -735,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;
|
||||
}
|
||||
|
||||
@@ -774,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;
|
||||
@@ -908,7 +964,6 @@ static int mod_uwsgi_patch_connection(server *srv, connection *con, plugin_data
|
||||
|
||||
PATCH(extensions);
|
||||
PATCH(debug);
|
||||
PATCH(balance);
|
||||
|
||||
/* skip the first, the global context */
|
||||
for (i = 1; i < srv->config_context->used; i++) {
|
||||
@@ -926,8 +981,6 @@ static int mod_uwsgi_patch_connection(server *srv, connection *con, plugin_data
|
||||
PATCH(extensions);
|
||||
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("uwsgi.debug"))) {
|
||||
PATCH(debug);
|
||||
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("uwsgi.balance"))) {
|
||||
PATCH(balance);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -953,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) {
|
||||
@@ -1000,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",
|
||||
@@ -1008,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1041,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
|
||||
@@ -1097,7 +1150,6 @@ static handler_t uwsgi_handle_fdevent(void *s, void *ctx, int revents) {
|
||||
static handler_t mod_uwsgi_check_extension(server *srv, connection *con, void *p_d) {
|
||||
plugin_data *p = p_d;
|
||||
size_t s_len;
|
||||
unsigned long last_max = ULONG_MAX;
|
||||
int max_usage = INT_MAX;
|
||||
int ndx = -1;
|
||||
size_t k;
|
||||
@@ -1143,13 +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) {
|
||||
if (s_len > ct_len + 1) {
|
||||
char *pi_offset;
|
||||
|
||||
if (0 != (pi_offset = strchr(fn->ptr + ct_len + 1, '/'))) {
|
||||
path_info_offset = pi_offset - fn->ptr;
|
||||
}
|
||||
}
|
||||
path_info_offset = ct_len;
|
||||
extension = ext;
|
||||
break;
|
||||
}
|
||||
@@ -1274,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,195 @@
|
||||
#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
|
||||
|
||||
void uwsgi_lock_init(void *lock) {
|
||||
|
||||
FILE *tf = tmpfile();
|
||||
int fd;
|
||||
|
||||
if (!tf) {
|
||||
uwsgi_error_open("temp lock file");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fd = fileno(tf);
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
#define _NO_UWSGI_RB
|
||||
#include "uwsgi.h"
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
|
||||
#include <kvm.h>
|
||||
#include <sys/user.h>
|
||||
#elif defined(__sun__)
|
||||
/* Terrible Hack !!! */
|
||||
#ifndef _LP64
|
||||
#undef _FILE_OFFSET_BITS
|
||||
#endif
|
||||
#include <procfs.h>
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void log_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
// optimize this (please)
|
||||
char *time_request;
|
||||
time_t microseconds, microseconds2;
|
||||
int rlen;
|
||||
int app_req = -1;
|
||||
char *msg2 = " ";
|
||||
char *via = msg2;
|
||||
|
||||
char mempkt[4096];
|
||||
char logpkt[4096];
|
||||
|
||||
struct iovec logvec[4];
|
||||
int logvecpos = 0;
|
||||
|
||||
const char *msecs = "msecs";
|
||||
const char *micros = "micros";
|
||||
|
||||
long int rt;
|
||||
char *tsize = (char *) msecs;
|
||||
|
||||
#ifdef UWSGI_SENDFILE
|
||||
char *msg1 = " via sendfile() ";
|
||||
#endif
|
||||
|
||||
struct uwsgi_app *wi;
|
||||
|
||||
if (wsgi_req->do_not_log) return ;
|
||||
|
||||
if (wsgi_req->app_id >= 0) {
|
||||
wi = &uwsgi.apps[wsgi_req->app_id];
|
||||
if (wi->requests > 0) {
|
||||
app_req = wi->requests;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UWSGI_SENDFILE
|
||||
if (wsgi_req->sendfile_fd > -1 && wsgi_req->sendfile_obj == wsgi_req->async_result) { //wsgi_req->sendfile_fd_size > 0 ) {
|
||||
via = msg1;
|
||||
}
|
||||
#endif
|
||||
|
||||
time_request = ctime((const time_t *) &wsgi_req->start_of_request.tv_sec);
|
||||
microseconds = wsgi_req->end_of_request.tv_sec * 1000000 + wsgi_req->end_of_request.tv_usec;
|
||||
microseconds2 = wsgi_req->start_of_request.tv_sec * 1000000 + wsgi_req->start_of_request.tv_usec;
|
||||
|
||||
rt = (long int) (microseconds - microseconds2);
|
||||
|
||||
if (uwsgi.log_micros) {
|
||||
tsize = (char *) micros;
|
||||
}
|
||||
else {
|
||||
rt /= 1000;
|
||||
}
|
||||
|
||||
if (uwsgi.vhost) {
|
||||
logvec[logvecpos].iov_base = wsgi_req->host;
|
||||
logvec[logvecpos].iov_len = wsgi_req->host_len;
|
||||
logvecpos++;
|
||||
|
||||
logvec[logvecpos].iov_base = " ";
|
||||
logvec[logvecpos].iov_len = 1;
|
||||
logvecpos++;
|
||||
}
|
||||
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG] == 1) {
|
||||
#ifndef UNBIT
|
||||
rlen = snprintf(mempkt, 4096, "{address space usage: %lld bytes/%lluMB} {rss usage: %llu bytes/%lluMB} ",
|
||||
(unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size, (unsigned long long ) uwsgi.workers[uwsgi.mywid].vsz_size / 1024 / 1024,
|
||||
(unsigned long long) uwsgi.workers[uwsgi.mywid].rss_size, (unsigned long long ) uwsgi.workers[uwsgi.mywid].rss_size / 1024 / 1024);
|
||||
#else
|
||||
rlen = snprintf(mempkt, 4096, "{address space usage: %lld bytes/%lluMB} ",
|
||||
(unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size, (unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size / 1024 / 1024);
|
||||
#endif
|
||||
|
||||
logvec[logvecpos].iov_base = mempkt;
|
||||
logvec[logvecpos].iov_len = rlen;
|
||||
logvecpos++;
|
||||
|
||||
}
|
||||
|
||||
rlen = snprintf(logpkt, 4096, "[pid: %d|app: %d|req: %d/%llu] %.*s (%.*s) {%d vars in %d bytes} [%.*s] %.*s %.*s => generated %llu bytes in %ld %s%s(%.*s %d) %d headers in %llu bytes (%d switches on core %d)\n",
|
||||
(int) uwsgi.mypid,
|
||||
wsgi_req->app_id,
|
||||
app_req,
|
||||
(unsigned long long ) uwsgi.workers[0].requests,
|
||||
wsgi_req->remote_addr_len, wsgi_req->remote_addr,
|
||||
wsgi_req->remote_user_len, wsgi_req->remote_user,
|
||||
wsgi_req->var_cnt,
|
||||
wsgi_req->uh.pktsize,
|
||||
24, time_request,
|
||||
wsgi_req->method_len, wsgi_req->method,
|
||||
wsgi_req->uri_len, wsgi_req->uri,
|
||||
(unsigned long long) wsgi_req->response_size,
|
||||
rt, tsize,
|
||||
via,
|
||||
wsgi_req->protocol_len, wsgi_req->protocol,
|
||||
wsgi_req->status,
|
||||
wsgi_req->header_cnt,
|
||||
(unsigned long long) wsgi_req->headers_size,
|
||||
wsgi_req->switches, wsgi_req->async_id);
|
||||
|
||||
logvec[logvecpos].iov_base = logpkt;
|
||||
logvec[logvecpos].iov_len = rlen;
|
||||
|
||||
// do not check for errors
|
||||
rlen = writev(2, logvec, logvecpos+1);
|
||||
}
|
||||
|
||||
void get_memusage() {
|
||||
|
||||
#ifdef UNBIT
|
||||
uwsgi.workers[uwsgi.mywid].vsz_size = syscall(356);
|
||||
#elif defined(__linux__)
|
||||
FILE *procfile;
|
||||
int i;
|
||||
procfile = fopen("/proc/self/stat", "r");
|
||||
if (procfile) {
|
||||
i = fscanf(procfile, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %llu %lld", (unsigned long long *) &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");
|
||||
}
|
||||
fclose(procfile);
|
||||
}
|
||||
uwsgi.workers[uwsgi.mywid].rss_size = uwsgi.workers[uwsgi.mywid].rss_size * uwsgi.page_size;
|
||||
#elif defined (__sun__)
|
||||
psinfo_t info;
|
||||
int procfd;
|
||||
|
||||
procfd = open("/proc/self/psinfo", O_RDONLY);
|
||||
if (procfd >= 0) {
|
||||
if ( read(procfd, (char *) &info, sizeof(info)) > 0) {
|
||||
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__)
|
||||
/* darwin documentation says that the value are in pages, but they are bytes !!! */
|
||||
struct task_basic_info t_info;
|
||||
mach_msg_type_number_t t_size = sizeof(struct task_basic_info);
|
||||
|
||||
if (task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t) & t_info, &t_size) == KERN_SUCCESS) {
|
||||
uwsgi.workers[uwsgi.mywid].rss_size = t_info.resident_size;
|
||||
uwsgi.workers[uwsgi.mywid].vsz_size = t_info.virtual_size;
|
||||
}
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
|
||||
kvm_t *kv;
|
||||
int cnt;
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
kv = kvm_open(NULL, "/dev/null", NULL, O_RDONLY, NULL);
|
||||
#else
|
||||
kv = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);
|
||||
#endif
|
||||
if (kv) {
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
|
||||
struct kinfo_proc *kproc;
|
||||
kproc = kvm_getprocs(kv, KERN_PROC_PID, uwsgi.mypid, &cnt);
|
||||
if (kproc && cnt > 0) {
|
||||
uwsgi.workers[uwsgi.mywid].vsz_size = kproc->ki_size;
|
||||
uwsgi.workers[uwsgi.mywid].rss_size = kproc->ki_rssize * uwsgi.page_size;
|
||||
}
|
||||
#elif defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
struct kinfo_proc2 *kproc2;
|
||||
|
||||
kproc2 = kvm_getproc2(kv, KERN_PROC_PID, uwsgi.mypid, sizeof(struct kinfo_proc2), &cnt);
|
||||
if (kproc2 && cnt > 0) {
|
||||
#ifdef __OpenBSD__
|
||||
uwsgi.workers[uwsgi.mywid].vsz_size = (kproc2->p_vm_dsize + kproc2->p_vm_ssize + kproc2->p_vm_tsize) * uwsgi.page_size;
|
||||
#else
|
||||
uwsgi.workers[uwsgi.mywid].vsz_size = kproc2->p_vm_msize * uwsgi.page_size;
|
||||
#endif
|
||||
uwsgi.workers[uwsgi.mywid].rss_size = kproc2->p_vm_rssize * uwsgi.page_size;
|
||||
}
|
||||
#endif
|
||||
|
||||
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
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 5.8 KiB |
@@ -0,0 +1,202 @@
|
||||
#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_setcancelstate(PTHREAD_CANCEL_ENABLE, &i);
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &i);
|
||||
pthread_setspecific(uwsgi.tur_key, (void *) wsgi_req);
|
||||
|
||||
if (core_id > 0) {
|
||||
// block all signals on new threads
|
||||
sigfillset(&smask);
|
||||
pthread_sigmask(SIG_BLOCK, &smask, NULL);
|
||||
for (i = 0; i < 0xFF; i++) {
|
||||
if (uwsgi.p[i]->init_thread) {
|
||||
uwsgi.p[i]->init_thread(core_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// initialize the main event queue to monitor sockets
|
||||
uwsgi.main_queue = event_queue_init();
|
||||
|
||||
uwsgi_add_sockets_to_queue(uwsgi.main_queue);
|
||||
|
||||
if (uwsgi.signal_socket > -1) {
|
||||
event_queue_add_fd_read(uwsgi.main_queue, uwsgi.signal_socket);
|
||||
}
|
||||
|
||||
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
|
||||
|
||||
wsgi_req_setup(wsgi_req, core_id, NULL);
|
||||
|
||||
if (wsgi_req_accept(wsgi_req)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (wsgi_req_recv(wsgi_req)) {
|
||||
uwsgi_destroy_request(wsgi_req);
|
||||
continue;
|
||||
}
|
||||
|
||||
uwsgi_close_request(wsgi_req);
|
||||
}
|
||||
|
||||
// end of the loop
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
void *zeromq_loop(void *arg1) {
|
||||
sigset_t smask;
|
||||
int i;
|
||||
|
||||
long core_id = (long) arg1;
|
||||
|
||||
struct wsgi_request *wsgi_req = uwsgi.wsgi_requests[core_id];
|
||||
uwsgi.zeromq_recv_flag = 0;
|
||||
zmq_pollitem_t zmq_poll_items[2];
|
||||
char uwsgi_signal;
|
||||
|
||||
if (uwsgi.threads > 1) {
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &i);
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &i);
|
||||
pthread_setspecific(uwsgi.tur_key, (void *) wsgi_req);
|
||||
|
||||
if (core_id > 0) {
|
||||
// block all signals on new threads
|
||||
sigfillset(&smask);
|
||||
pthread_sigmask(SIG_BLOCK, &smask, NULL);
|
||||
for (i = 0; i < 0xFF; i++) {
|
||||
if (uwsgi.p[i]->init_thread) {
|
||||
uwsgi.p[i]->init_thread(core_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void *tmp_zmq_pull = zmq_socket(uwsgi.zmq_context, ZMQ_PULL);
|
||||
if (tmp_zmq_pull == NULL) {
|
||||
uwsgi_error("zmq_socket()");
|
||||
exit(1);
|
||||
}
|
||||
if (zmq_connect(tmp_zmq_pull, uwsgi.zmq_receiver) < 0) {
|
||||
uwsgi_error("zmq_connect()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pthread_setspecific(uwsgi.zmq_pull, tmp_zmq_pull);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (uwsgi.signal_socket > -1) {
|
||||
zmq_poll_items[0].socket = pthread_getspecific(uwsgi.zmq_pull);
|
||||
zmq_poll_items[0].fd = -1;
|
||||
zmq_poll_items[0].events = ZMQ_POLLIN;
|
||||
|
||||
zmq_poll_items[1].socket = NULL;
|
||||
zmq_poll_items[1].fd = uwsgi.signal_socket;
|
||||
zmq_poll_items[1].events = ZMQ_POLLIN;
|
||||
}
|
||||
|
||||
|
||||
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
|
||||
|
||||
wsgi_req_setup(wsgi_req, core_id, NULL);
|
||||
|
||||
uwsgi.edge_triggered = 1;
|
||||
wsgi_req->socket = uwsgi.zmq_socket;
|
||||
|
||||
|
||||
if (uwsgi.signal_socket > -1) {
|
||||
if (zmq_poll(zmq_poll_items, 2, -1) < 0) {
|
||||
uwsgi_error("zmq_poll()");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (zmq_poll_items[1].revents & ZMQ_POLLIN) {
|
||||
if (read(uwsgi.signal_socket, &uwsgi_signal, 1) <= 0) {
|
||||
if (uwsgi.no_orphans) {
|
||||
uwsgi_log_verbose("uWSGI worker %d screams: UAAAAAAH my master died, i will follow him...\n", uwsgi.mywid);
|
||||
end_me(0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log_verbose("master sent signal %d to worker %d\n", uwsgi_signal, uwsgi.mywid);
|
||||
if (uwsgi_signal_handler(uwsgi_signal)) {
|
||||
uwsgi_log_verbose("error managing signal %d on worker %d\n", uwsgi_signal, uwsgi.mywid);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (zmq_poll_items[0].revents & ZMQ_POLLIN) {
|
||||
wsgi_req->poll.fd = wsgi_req->socket->proto_accept(wsgi_req, uwsgi.zmq_socket->fd);
|
||||
}
|
||||
}
|
||||
else {
|
||||
wsgi_req->poll.fd = wsgi_req->socket->proto_accept(wsgi_req, uwsgi.zmq_socket->fd);
|
||||
}
|
||||
|
||||
if (wsgi_req->poll.fd >= 0) {
|
||||
wsgi_req_recv(wsgi_req);
|
||||
}
|
||||
|
||||
uwsgi_close_request(wsgi_req);
|
||||
}
|
||||
|
||||
|
||||
// end of the loop
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,69 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void master_check_cluster_nodes() {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
struct uwsgi_cluster_node *ucn = &uwsgi.shared->nodes[i];
|
||||
|
||||
if (ucn->name[0] != 0 && ucn->type == CLUSTER_NODE_STATIC && ucn->status == UWSGI_NODE_FAILED) {
|
||||
// should i retry ?
|
||||
if (uwsgi.master_cycles % ucn->errors == 0) {
|
||||
if (!uwsgi_ping_node(i, uwsgi.wsgi_req)) {
|
||||
ucn->status = UWSGI_NODE_OK;
|
||||
uwsgi_log( "re-enabled cluster node %d/%s\n", i, ucn->name);
|
||||
}
|
||||
else {
|
||||
ucn->errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ucn->name[0] != 0 && ucn->type == CLUSTER_NODE_DYNAMIC) {
|
||||
// if the last_seen attr is higher than 30 secs ago, mark the node as dead
|
||||
if ( (uwsgi.current_time - ucn->last_seen) > 30) {
|
||||
uwsgi_log_verbose("no presence announce in the last 30 seconds by node %s, i assume it is dead.\n", ucn->name);
|
||||
ucn->name[0] = 0 ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_respawn_worker(int wid) {
|
||||
|
||||
int respawns = uwsgi.workers[wid].respawn_count;
|
||||
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid == 0) {
|
||||
uwsgi.mywid = wid;
|
||||
// fix the communication pipe
|
||||
close(uwsgi.shared->worker_signal_pipe[0]);
|
||||
uwsgi.mypid = getpid();
|
||||
uwsgi.workers[uwsgi.mywid].pid = uwsgi.mypid;
|
||||
uwsgi.workers[uwsgi.mywid].id = uwsgi.mywid;
|
||||
uwsgi.workers[uwsgi.mywid].harakiri = 0;
|
||||
uwsgi.workers[uwsgi.mywid].requests = 0;
|
||||
uwsgi.workers[uwsgi.mywid].failed_requests = 0;
|
||||
uwsgi.workers[uwsgi.mywid].respawn_count++;
|
||||
uwsgi.workers[uwsgi.mywid].last_spawn = uwsgi.current_time;
|
||||
uwsgi.workers[uwsgi.mywid].manage_next_request = 1;
|
||||
return 1;
|
||||
}
|
||||
else if (pid < 1) {
|
||||
uwsgi_error("fork()");
|
||||
}
|
||||
else {
|
||||
if (respawns > 0) {
|
||||
uwsgi_log( "Respawned uWSGI worker %d (new pid: %d)\n", uwsgi.mywid, (int) pid);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("spawned uWSGI worker %d (pid: %d, cores: %d)\n", wid, pid, uwsgi.cores);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -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,23 @@
|
||||
main = Server(
|
||||
uuid="f400bf85-4538-4f7a-8908-67e313d515c2",
|
||||
access_log="/logs/access.log",
|
||||
error_log="/logs/error.log",
|
||||
chroot="./",
|
||||
default_host="192.168.173.18",
|
||||
name="test",
|
||||
pid_file="/run/mongrel2.pid",
|
||||
port=6767,
|
||||
hosts = [
|
||||
Host(name="192.168.173.18", routes={
|
||||
'/': Handler(send_spec='tcp://192.168.173.18:9999',
|
||||
send_ident='54c6755b-9628-40a4-9a2d-cc82a816345e',
|
||||
recv_spec='tcp://192.168.173.18:9998', recv_ident='')
|
||||
})
|
||||
]
|
||||
)
|
||||
|
||||
settings = {'upload.temp_store':'tmp/mongrel2.upload.XXXXXX'}
|
||||
servers = [main]
|
||||
|
||||
|
||||
uwsgi = { 'socket':':3031', 'master':'true'}
|
||||
@@ -0,0 +1,27 @@
|
||||
[uwsgi]
|
||||
|
||||
; socket 0
|
||||
socket = :3033
|
||||
; socket 1
|
||||
socket = :3034
|
||||
; socket 2
|
||||
socket = pippo1.sock
|
||||
; socket 3
|
||||
socket = pippo2.sock
|
||||
; socket 4
|
||||
socket = 127.0.0.1:1717
|
||||
|
||||
map-socket = 0:1,2,3,4
|
||||
map-socket = 1:4
|
||||
map-socket = 2:10
|
||||
map-socket = 3:5,6,9
|
||||
map-socket = 4:7,8,9
|
||||
|
||||
|
||||
vacuum = true
|
||||
memory-report = true
|
||||
master = true
|
||||
processes = 10
|
||||
;mount = /app1=werkzeug.testapp:test_app
|
||||
;mount = /app2=config:/Users/roberta/uwsgi/my.ini
|
||||
;mount = /app3=pinaxsite/deploy/pinax.wsgi
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user