mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-10-04 16:08:31 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a8850ffe5 | ||
|
|
e640f812ba | ||
|
|
75ea170472 | ||
|
|
1b14b1926e | ||
|
|
edaed7ab01 | ||
|
|
6cceece3d7 | ||
|
|
2add03edb8 | ||
|
|
7aab9bae51 | ||
|
|
46c2c1d885 | ||
|
|
544e97fac0 | ||
|
|
265a700498 | ||
|
|
a657b4b0aa | ||
|
|
ac97c8cf34 | ||
|
|
545f3ee608 | ||
|
|
fcd1a36420 | ||
|
|
47a8ab3da9 | ||
|
|
c4375a8e7a | ||
|
|
a6c5bd3bb3 | ||
|
|
d53127e8cf | ||
|
|
851dd987ab | ||
|
|
cf582af970 | ||
|
|
d0ec331b6b | ||
|
|
cc75f5f7b3 | ||
|
|
3d08b7fdd0 | ||
|
|
7a92449fc3 | ||
|
|
4b3c34469d | ||
|
|
55bf34561e | ||
|
|
7e79dc0405 | ||
|
|
d3053523ab | ||
|
|
e32185cc14 | ||
|
|
8e3e3cf27b | ||
|
|
e2cea376e8 | ||
|
|
2a27b66d96 | ||
|
|
522717ca99 | ||
|
|
5ee106170b | ||
|
|
d62f04a5a6 | ||
|
|
eefe5048b2 | ||
|
|
8f792fde2d | ||
|
|
d8ef2d8300 | ||
|
|
e69dd5cb6a | ||
|
|
8acd57d87e | ||
|
|
a42aa1a273 | ||
|
|
4b2b7ccf82 | ||
|
|
e0fa180a23 | ||
|
|
06ea1fcd1b | ||
|
|
567bcc582d | ||
|
|
844f8c71fa | ||
|
|
bddbbb93cd | ||
|
|
310cc83d36 | ||
|
|
23dcdc5863 | ||
|
|
1286e1835c | ||
|
|
613f2ed939 | ||
|
|
46108f8d0c | ||
|
|
28dcfa4131 | ||
|
|
b48597d3c3 | ||
|
|
fe4c6ba13e | ||
|
|
4049493ffd | ||
|
|
0c9b6e98f7 | ||
|
|
ce33d0be5a | ||
|
|
4f0fb90bff | ||
|
|
66eff0107a | ||
|
|
82f83e610f | ||
|
|
cf7df391ad | ||
|
|
244c9f8204 | ||
|
|
26dc19df7d | ||
|
|
7b8bff1a08 | ||
|
|
0b010124ef | ||
|
|
c7bde15f39 | ||
|
|
b941e4f2f0 | ||
|
|
536c6e7e29 | ||
|
|
dfe4abec35 | ||
|
|
693b80d7d3 | ||
|
|
c9e6475ef4 | ||
|
|
b745132ebd | ||
|
|
19686cb19f | ||
|
|
e0c0593b5b | ||
|
|
415a8af363 | ||
|
|
d44777b1b4 | ||
|
|
e3ff3037b4 | ||
|
|
7add30fd31 | ||
|
|
501cd0349b | ||
|
|
7b4e3f6601 | ||
|
|
8622c2780c | ||
|
|
13de7b6d5b | ||
|
|
53cb864f9c | ||
|
|
72f693f02a | ||
|
|
fb80e32682 | ||
|
|
1db3426ee1 | ||
|
|
a44879e384 | ||
|
|
c0075c817d | ||
|
|
177dc3322b | ||
|
|
21ef4fc89b | ||
|
|
f467643f6f | ||
|
|
3db41e7e05 | ||
|
|
73151729c6 | ||
|
|
5d9c415028 | ||
|
|
b92ed4da4e | ||
|
|
2d1a9a03d2 | ||
|
|
5d6edd2321 | ||
|
|
365f4ba83f | ||
|
|
66e30ae293 | ||
|
|
728425de19 | ||
|
|
b0af1f800b | ||
|
|
543271e856 | ||
|
|
a1564a44fa | ||
|
|
571029cfd3 | ||
|
|
579eaa630a | ||
|
|
9530c8ffe0 | ||
|
|
0d8690091b | ||
|
|
5b5e3a1ec1 | ||
|
|
869ae5e3ed | ||
|
|
d6dc8d86f8 | ||
|
|
758745be68 | ||
|
|
2adfa56d6a | ||
|
|
a4c728f5df | ||
|
|
5c06341b7f | ||
|
|
6f57902a9b | ||
|
|
a3e118893d | ||
|
|
ff2d3c29d6 | ||
|
|
59a8df85f2 | ||
|
|
e303bd182a | ||
|
|
dcef9a497c | ||
|
|
8d4fd66aaf | ||
|
|
471bd23acf | ||
|
|
ffcef81dd0 | ||
|
|
317df5d06b | ||
|
|
ad7b5efd6f | ||
|
|
891f770724 | ||
|
|
0b6d715982 | ||
|
|
76c2415516 | ||
|
|
3260faca17 | ||
|
|
feb493158c | ||
|
|
a5c1556cb7 | ||
|
|
89e640bdd9 | ||
|
|
3ade8daff8 | ||
|
|
049ea3fbed | ||
|
|
715d26beed | ||
|
|
1f5064094c | ||
|
|
7ed522dc29 | ||
|
|
2086500405 | ||
|
|
8f79409ed1 | ||
|
|
c2a3cd1476 | ||
|
|
e195a5d72c | ||
|
|
c86b757904 | ||
|
|
6800d2ac95 | ||
|
|
90fda2b4bb | ||
|
|
bf7ded9058 | ||
|
|
6615dc3a62 | ||
|
|
c35054085c | ||
|
|
fdf2bd7f96 | ||
|
|
1c10b9dfe1 | ||
|
|
6854394e5c | ||
|
|
78a0d5f432 | ||
|
|
5fe5aa70a4 | ||
|
|
e9c0c6bd0b | ||
|
|
5d12b3dc9c | ||
|
|
169a4b66db | ||
|
|
fbd6329db9 | ||
|
|
69c2e56857 | ||
|
|
18f7d1edd3 | ||
|
|
3f7cd5ff92 | ||
|
|
785e1dbf83 | ||
|
|
bc6acf8d14 | ||
|
|
3a099d0b2e | ||
|
|
f9ad5e4144 | ||
|
|
ce9f6650a0 | ||
|
|
fdeef04343 | ||
|
|
fe72ec82e1 | ||
|
|
fd0f308273 | ||
|
|
f4e9ab43cb | ||
|
|
3a141b523c | ||
|
|
2d731532be | ||
|
|
d545cd5be0 | ||
|
|
261d05d67e | ||
|
|
639995785a | ||
|
|
817e076cae | ||
|
|
713370f343 | ||
|
|
5594503a56 | ||
|
|
d57e5d46fb | ||
|
|
ee2db5fabd | ||
|
|
0c4cd6f378 | ||
|
|
8c32b9665c | ||
|
|
7405a01654 | ||
|
|
5d27691b4b | ||
|
|
19bbcfbf4c | ||
|
|
fa1064db87 | ||
|
|
850ac69ca1 | ||
|
|
943edeb30c | ||
|
|
01815a354b | ||
|
|
2f4412aca1 | ||
|
|
2782bb7594 | ||
|
|
074c1298d5 | ||
|
|
55a7911611 | ||
|
|
013ad3044d | ||
|
|
dcf4217b9d | ||
|
|
876dfc31a9 | ||
|
|
fd03bdbe00 | ||
|
|
83612649d5 | ||
|
|
3c4db7e97e | ||
|
|
088c70efdc | ||
|
|
2b19029dd0 | ||
|
|
4fb5a84378 | ||
|
|
b3107d9a25 | ||
|
|
bf32988f3e | ||
|
|
1bf3dd7bf4 | ||
|
|
07fd84f89f | ||
|
|
3a8db4a97a | ||
|
|
aea30a26f5 | ||
|
|
8f5d1cdae7 | ||
|
|
53913357e0 | ||
|
|
098416f444 | ||
|
|
c98cb09c7c | ||
|
|
bb1ef28d69 | ||
|
|
1d5b05265d | ||
|
|
d9fef3c30e | ||
|
|
e5dfb9efc3 | ||
|
|
02bab15e86 | ||
|
|
6f4ddead09 | ||
|
|
b361248ff6 | ||
|
|
e9c42ceaa5 | ||
|
|
5d7029744a | ||
|
|
1084a3afa8 | ||
|
|
ed254bffee | ||
|
|
733784d7dd | ||
|
|
cb5b26bcb4 | ||
|
|
0065152bb1 | ||
|
|
03266203fd | ||
|
|
4a5f68f9d8 | ||
|
|
83e31a1c27 | ||
|
|
0efed5ef9c | ||
|
|
cdfef1281d | ||
|
|
e00907e142 | ||
|
|
6dcbcf39e3 | ||
|
|
044579a8e0 | ||
|
|
d2b52b4663 | ||
|
|
7f75b2c02c | ||
|
|
24a3f671e5 | ||
|
|
875100e3c8 | ||
|
|
34bc7c0cfd | ||
|
|
b39a10ff7c | ||
|
|
02331904de | ||
|
|
d1a4ae694e | ||
|
|
7a5ffc1124 | ||
|
|
19c5bfb42c | ||
|
|
893bf3686b | ||
|
|
e54fa9bcd4 | ||
|
|
c1eb5ab0fe | ||
|
|
461914dde4 | ||
|
|
85662578e4 | ||
|
|
a59c0ae795 | ||
|
|
3a860155ee | ||
|
|
27553c2967 | ||
|
|
9a8ac9af3c | ||
|
|
2f5daffe99 | ||
|
|
75cd31dce4 | ||
|
|
f7150d1b41 | ||
|
|
d6a6b65338 | ||
|
|
979f6027b4 | ||
|
|
7dc059c75b | ||
|
|
b639b5974f | ||
|
|
0de08c553c | ||
|
|
80788ac695 | ||
|
|
1494c621c1 | ||
|
|
605e5b5173 | ||
|
|
4cf2213051 | ||
|
|
3aa36668e5 | ||
|
|
1c0b5b42e9 | ||
|
|
702dc44fad | ||
|
|
2cae07aa52 | ||
|
|
b5616ff25c | ||
|
|
b7b7521975 | ||
|
|
dce3263ee3 | ||
|
|
9796e05ca1 | ||
|
|
5cc0d459ec | ||
|
|
531a850a71 | ||
|
|
4c36280287 | ||
|
|
70be8eb55e | ||
|
|
f8b757b21e | ||
|
|
3a63d352bb | ||
|
|
60467705c5 | ||
|
|
eada0c09e0 | ||
|
|
8e851aa6a1 | ||
|
|
eaf7bb967d | ||
|
|
7be45c77b1 | ||
|
|
5e2b460dc8 | ||
|
|
16143e698f | ||
|
|
4259946e3b | ||
|
|
0a750d76ee | ||
|
|
e4a9f5f0dd | ||
|
|
d5b7698f89 | ||
|
|
a481e8508e | ||
|
|
a53b57497b | ||
|
|
d871357b2d | ||
|
|
2d57db55f4 | ||
|
|
bae45ce03a | ||
|
|
44cc4336f1 | ||
|
|
44f6e214fd | ||
|
|
3e46f81d2b | ||
|
|
e4532b9a50 | ||
|
|
2694be562c | ||
|
|
fadb9edd7f | ||
|
|
d85e0790de | ||
|
|
bc46c4d704 | ||
|
|
a73a010188 | ||
|
|
4e8c8ef317 | ||
|
|
e402e7805d | ||
|
|
302b8f026b | ||
|
|
630054b72a | ||
|
|
a05f459b2b | ||
|
|
207979580a | ||
|
|
f69526f8bf | ||
|
|
e249d567a1 | ||
|
|
a23ba653da | ||
|
|
0644d53572 | ||
|
|
f58f51294d | ||
|
|
86194eb93e | ||
|
|
0a89f375e6 | ||
|
|
6282178b3c | ||
|
|
8e14d68022 | ||
|
|
e86bd0c070 | ||
|
|
bf991f8892 | ||
|
|
b341678d20 | ||
|
|
5f59365d88 | ||
|
|
5130a7bb33 | ||
|
|
cc84a596d6 | ||
|
|
e67bed431a | ||
|
|
72613a9f48 | ||
|
|
c048ea0615 | ||
|
|
957ca1b7ed | ||
|
|
d80a6df039 | ||
|
|
94f9bd9d91 | ||
|
|
b480efe672 | ||
|
|
4fc306d979 | ||
|
|
56abccbdeb | ||
|
|
f218af0735 | ||
|
|
9b69c62780 | ||
|
|
eb5d67e07f | ||
|
|
e7391987b1 | ||
|
|
02cbe15575 | ||
|
|
a5a657f0d4 | ||
|
|
67567c86e0 | ||
|
|
445d02da45 | ||
|
|
4a05df41ce | ||
|
|
5c0c2f6b45 | ||
|
|
0ab55fef46 | ||
|
|
dd344bfe38 | ||
|
|
e92a889bcc | ||
|
|
419d656a83 | ||
|
|
3c3d58bfe9 | ||
|
|
1989099cc5 | ||
|
|
1446e3f0a9 | ||
|
|
00fc31289d | ||
|
|
2c463ad6af | ||
|
|
e641ae05c4 | ||
|
|
a13e0075ee | ||
|
|
e617a7b88e | ||
|
|
cbdeb4caad | ||
|
|
59314d692f | ||
|
|
3dfa56b279 | ||
|
|
920d5d7416 | ||
|
|
dcb654d7fb | ||
|
|
a563da1223 | ||
|
|
1e26cda615 | ||
|
|
97133b27ce | ||
|
|
b428bd3b87 | ||
|
|
05136e74b4 | ||
|
|
9f28a8bdf1 | ||
|
|
d9361f1fee | ||
|
|
835230b1a4 | ||
|
|
f88f51c553 | ||
|
|
1996305eb1 | ||
|
|
c7ad50e950 | ||
|
|
0ec0c29d67 | ||
|
|
75af117e8a | ||
|
|
2b04cefe4e | ||
|
|
0e41c4111a | ||
|
|
5f5d382c64 | ||
|
|
3e867fe401 | ||
|
|
153142b8b0 | ||
|
|
5562c0c047 | ||
|
|
f4a1f800ba | ||
|
|
bdbc5e5605 | ||
|
|
4104f825ff | ||
|
|
efa01ea404 | ||
|
|
982559ae66 | ||
|
|
60002e8de8 | ||
|
|
25d671e0f6 | ||
|
|
5a58281a3f | ||
|
|
c422231806 | ||
|
|
4979883fe5 | ||
|
|
8158a624d3 | ||
|
|
06403b5fce | ||
|
|
bc482652fc | ||
|
|
58aa5755e0 | ||
|
|
bca835c58a | ||
|
|
4b0f68a57a | ||
|
|
b693d73ebe | ||
|
|
dfab80447b | ||
|
|
bbde0c866a | ||
|
|
7b3514f757 | ||
|
|
6d5fb3b252 | ||
|
|
87e8f118d3 | ||
|
|
3ae78cc0a8 | ||
|
|
7ef921356f | ||
|
|
378185d997 | ||
|
|
c4b15a8509 | ||
|
|
96ef9d155b | ||
|
|
d5e6412b20 | ||
|
|
eebe757c16 | ||
|
|
43a21d32cb | ||
|
|
9f9eb5ef17 | ||
|
|
0116c62980 | ||
|
|
fae446e495 | ||
|
|
6f7054df18 | ||
|
|
0f31c21f4a | ||
|
|
bd3e234703 | ||
|
|
71bfd63623 | ||
|
|
98b89dc83c | ||
|
|
97ec789bbe | ||
|
|
14b403c046 | ||
|
|
bc01d25068 | ||
|
|
69808c34a8 | ||
|
|
273181daf5 | ||
|
|
8d2394eba1 | ||
|
|
6f5b468b11 | ||
|
|
c9e759bc14 | ||
|
|
e6d064f5c1 | ||
|
|
8f7ed02475 | ||
|
|
f7edcebbdc | ||
|
|
a19b392ba6 | ||
|
|
287df9ef86 | ||
|
|
de7be379c4 | ||
|
|
1e4d41795c | ||
|
|
e2e973a20e | ||
|
|
5d993fbfc0 | ||
|
|
a94a8ea287 | ||
|
|
55d8677a46 | ||
|
|
4004aeb54e | ||
|
|
2de2898d86 | ||
|
|
8c1b48a88d | ||
|
|
9bd3022a5e | ||
|
|
eb0ce609f0 | ||
|
|
5353eba35b | ||
|
|
4f94ceed5e | ||
|
|
cd29998b40 | ||
|
|
9aad6be26a | ||
|
|
19edee88bc | ||
|
|
42e6a7d024 | ||
|
|
1890290d05 | ||
|
|
c85231be96 | ||
|
|
0ca89771d6 | ||
|
|
d203b12464 | ||
|
|
b64690bdd6 | ||
|
|
e76c696678 | ||
|
|
f1ad2090fc | ||
|
|
f0be3c3966 | ||
|
|
8b7abc956f | ||
|
|
25a8af392b | ||
|
|
ebe1b3497e | ||
|
|
6a7246fe5a | ||
|
|
1d64e46fcd | ||
|
|
6d5e089e4e | ||
|
|
845bc1d41b | ||
|
|
007cd73ac5 | ||
|
|
651a7e4078 | ||
|
|
c3423370ec | ||
|
|
500f1e37f6 | ||
|
|
699a9bfa8e | ||
|
|
90aa7f0d0e | ||
|
|
527819703e | ||
|
|
47adc8fe48 | ||
|
|
865ad5d631 | ||
|
|
877b99c1d5 | ||
|
|
45bb124200 | ||
|
|
147af04342 | ||
|
|
b30e54bdc1 | ||
|
|
1b7484cf22 | ||
|
|
c04513f8bd | ||
|
|
c29db6ee6f | ||
|
|
0d60b001fb | ||
|
|
ea7d428c1b | ||
|
|
55ac61dbb0 | ||
|
|
048878b197 | ||
|
|
1e479de839 | ||
|
|
5b34f6c515 | ||
|
|
8fcf83769c | ||
|
|
d1ca55da55 | ||
|
|
375328623b | ||
|
|
be15137a49 | ||
|
|
43d89b2eaf | ||
|
|
d590a189ed | ||
|
|
c26861bff6 | ||
|
|
b4923deae2 | ||
|
|
20e7a65d92 | ||
|
|
fc895d105e | ||
|
|
e0e8dbe6b6 | ||
|
|
8e5834dcbb | ||
|
|
668c173969 | ||
|
|
4c19a941eb | ||
|
|
9761153ab0 | ||
|
|
140a1b1587 | ||
|
|
e5f5f40f3c | ||
|
|
2e13622ecc | ||
|
|
a4fb281859 | ||
|
|
75ba4e2220 | ||
|
|
24b17da2ea | ||
|
|
c4664fe6e3 | ||
|
|
a1ab298609 | ||
|
|
533f9f8323 | ||
|
|
6d5912f307 | ||
|
|
3d2b7c136a | ||
|
|
f25d147908 | ||
|
|
e119c8cc53 | ||
|
|
73e94350df | ||
|
|
9d8ee5aec8 | ||
|
|
c3bbd5f54f | ||
|
|
e17be93cb6 | ||
|
|
1013ca340a | ||
|
|
b87e7c0af8 | ||
|
|
615348c5a1 | ||
|
|
cae0f9bc2e | ||
|
|
93b23e3de0 | ||
|
|
eebb00d2b3 | ||
|
|
11f9b04fd1 | ||
|
|
bde996de75 | ||
|
|
552163a3bd | ||
|
|
2e6af966a9 | ||
|
|
c1775967c8 | ||
|
|
034a0a594d | ||
|
|
63a66ea82a | ||
|
|
6f155ebf17 | ||
|
|
f39d8cc5fb | ||
|
|
aecba7e710 | ||
|
|
c365eeec76 | ||
|
|
5bd06402de | ||
|
|
ec899a45d5 | ||
|
|
513c9cee3d | ||
|
|
850f2abd5c | ||
|
|
8d7940ebee | ||
|
|
195e9c398e | ||
|
|
c998d6bd1b | ||
|
|
34be14ece1 | ||
|
|
c0d6f33d54 | ||
|
|
d5210283ca | ||
|
|
545784d7af | ||
|
|
e9726b1e75 | ||
|
|
e08b2cccf9 | ||
|
|
0ba1b982d1 | ||
|
|
374c02c46e | ||
|
|
5ed59690a0 | ||
|
|
2de489f301 | ||
|
|
40a722294f | ||
|
|
9598c525cf | ||
|
|
3ed6c5e943 | ||
|
|
0f178c17ee | ||
|
|
1c963b72a3 | ||
|
|
bd1b3b8b12 | ||
|
|
f9a843dfd5 | ||
|
|
9df8f4ae2b | ||
|
|
87f649b71b | ||
|
|
3585bb0a6e | ||
|
|
750bbd64b2 | ||
|
|
19c567cef3 | ||
|
|
5024368854 | ||
|
|
3200f88363 | ||
|
|
650c77d0d1 | ||
|
|
3fa29515f2 | ||
|
|
012435747e | ||
|
|
733077a437 | ||
|
|
6b3fa74800 | ||
|
|
d673627c79 | ||
|
|
8b423d00e9 | ||
|
|
201086c854 | ||
|
|
2441cf36b3 | ||
|
|
df0f2a549e | ||
|
|
9b7cbab37c | ||
|
|
ac46cb2371 | ||
|
|
c858c88bb3 | ||
|
|
a05f5d9860 | ||
|
|
e6914b91e1 | ||
|
|
b624bd2d35 | ||
|
|
e3c9b2c0bf | ||
|
|
576a1e7cb2 | ||
|
|
55c3ba73d3 | ||
|
|
2246d30bbe | ||
|
|
789e333736 | ||
|
|
283904107f | ||
|
|
8d92261852 | ||
|
|
e8f5d82b78 | ||
|
|
0a8643155e | ||
|
|
61793201c7 | ||
|
|
41f2982074 | ||
|
|
27b86f1b79 | ||
|
|
d69892c91e | ||
|
|
296549d1bf | ||
|
|
7d2f147172 | ||
|
|
aa56f99ee2 | ||
|
|
ca82b99f42 | ||
|
|
d204a5b844 | ||
|
|
0a98550770 | ||
|
|
0c0c2736a7 | ||
|
|
27e2d984ce | ||
|
|
14eeae09b1 | ||
|
|
16eb47070d | ||
|
|
1f69f58593 | ||
|
|
1b4421e013 | ||
|
|
f13400d592 | ||
|
|
e29f0323ea | ||
|
|
15a582d046 | ||
|
|
1e01f8be17 | ||
|
|
8cc73991a3 | ||
|
|
ecce74ade5 | ||
|
|
836efaaf70 | ||
|
|
46f8e7dc00 | ||
|
|
88cd033ca6 | ||
|
|
984df3bcdf | ||
|
|
7673cdb1aa | ||
|
|
8af700ce37 | ||
|
|
ffb8752190 | ||
|
|
71fa3ab3af | ||
|
|
09501cfa74 | ||
|
|
d84ae12733 | ||
|
|
05f292abe6 | ||
|
|
a75833d322 | ||
|
|
ca3f56de5c | ||
|
|
9d75f2c9c7 | ||
|
|
a58cbf92b0 | ||
|
|
7bac76fae5 | ||
|
|
9c71b39edd | ||
|
|
52f731c6b7 | ||
|
|
735d1cb689 | ||
|
|
5a0977f412 | ||
|
|
1da1fccbc7 | ||
|
|
ca5a528818 | ||
|
|
a9ef806a37 | ||
|
|
de112b7788 | ||
|
|
ef7baba274 | ||
|
|
3a9d13b011 | ||
|
|
5b5493aab0 | ||
|
|
5f208d8f12 | ||
|
|
47c077d066 | ||
|
|
d2ac69b6c1 | ||
|
|
8860cac7dd | ||
|
|
28bcc73c70 | ||
|
|
af20c2d8f0 | ||
|
|
44213ca510 | ||
|
|
ab21a1ac00 | ||
|
|
a67f366501 | ||
|
|
b32251e5aa | ||
|
|
16e0accb74 | ||
|
|
c6ce291cbf | ||
|
|
b7525475d8 | ||
|
|
f35a36ac02 | ||
|
|
3b53f89a24 | ||
|
|
764d94e41b | ||
|
|
0292e15497 | ||
|
|
bde4ac7b2f | ||
|
|
c71fa3abd1 |
@@ -23,3 +23,22 @@ a5f13497b39269621f8f1e56e14d2cc141452e79 0.9.7.2
|
||||
d1e57707f6317f134fea7d12f6588d8690f74f3f 0.9.8-rc1
|
||||
e91bc724325e14c13b8f548c0b6a315c48a1c32a 0.9.8-rc2
|
||||
4fb424d52f226a0a087fea89709f5eb540e03f25 0.9.8-rc3
|
||||
0f1f3924ee5309a9990d9af1ffc68846e3dfb31b 0.9.8-rc4
|
||||
42efe1f329005618c8b44f901979ebcecd5216fb 0.9.8
|
||||
fd8477b6348faf16588106055ca59df1c488f76a 0.9.8.1
|
||||
7169ef1d68d3dab4737bcc3f9e082839e5a06cc1 0.9.8.2
|
||||
f4d3c4dcd7a63e21fcc9d8d567374c69935178bd 0.9.8.3
|
||||
6945ee03c7ea95eb19217ef1e1fb17d9ae26adbc 0.9.9-beta1
|
||||
fb168b0b86169219aa9b8e40f0caa6297cf34dbc 0.9.9-rc1
|
||||
6aa667612019fcff8e68af9469f73aff6fa378a8 0.9.9-rc2
|
||||
376ffd8f190623e5e2521fe9fa64bf03c31e71be 0.9.9
|
||||
7048ae11cfc8453c6bb599af3c0dfacd7ebae43c 1.0-rc1
|
||||
7a4e021ea7ba2953e474326612c3bb82d6817f0e 1.0-rc2
|
||||
4e4e781ef89ac33e71a7e92741d54549240ed156 1.0-rc3
|
||||
24f7e260ea345c2cd73e2fd8191dddbd1b039062 1.0-rc4
|
||||
043ba93dd69cf6924e98db3cb9a8759cce997367 1.0-rc5
|
||||
a2b8f25fd17ed7424d1470a287d0b3144d2a12c8 1.0-rc6
|
||||
a3ca2e8e27c5c12c44ba0cacb4de4cb51377f184 1.0-rc7
|
||||
365e2514cc19f0366365318f12a1d63113b02924 1.0-rc8
|
||||
5da6fe43a8c29056bc9442c684615e11a3699795 1.0-rc9
|
||||
af490b8c30f83bc5fb6f3837a760981474647755 1.0-rc10
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
- this is a incomplete list of all the contributors of the project -
|
||||
|
||||
Roberto De Ioris, Unbit, <roberto@unbit.it>
|
||||
Riccardo Magliocchetti, Unbit, <riccardo@unbit.it>
|
||||
Yann Malet, Lincoln Loop
|
||||
Simon Litchfield
|
||||
Masahiro Honma, <hiratara@cpan.org>
|
||||
Łukasz Wróblewski <admin@nri.pl>
|
||||
Giacomo Bagnoli, Asidev
|
||||
Guido Notari, Link I.T. S.p.a.
|
||||
Marco Beri, Link I.T. S.p.a.
|
||||
Leonid Borisenko
|
||||
Cal Leeming, Simplicity Media Ltd
|
||||
Luigi Scarso
|
||||
Corey Farwell
|
||||
Charles Duffy
|
||||
Lukas Lalinsky
|
||||
Steven Fernandez
|
||||
Łukasz Mierzwa
|
||||
@@ -1,3 +1,151 @@
|
||||
*** december 2011 ***
|
||||
|
||||
* 1.0 [20111230]
|
||||
|
||||
- adaptive process spawning (--cheaper option)
|
||||
- new control options --stop, --reload, --suspend, --resume, --pause
|
||||
- stats framework
|
||||
- new subscription system
|
||||
- support for mime types in static file serving
|
||||
- posix capablities support
|
||||
- uWSGI mules and farms
|
||||
- support for multiple --touch-reload options
|
||||
- new logging subsystem
|
||||
- new custom locking subsystem
|
||||
- process name handling
|
||||
- better (and faster) HTTP parser
|
||||
- perl and python threading improvements
|
||||
- new plugins: rrdtool, carbon, cgi, php
|
||||
- various improvements in the Rack/ruby plugin
|
||||
- Linux KSM support
|
||||
- refactored ping and nagios plugins
|
||||
- support for signals in lazy mode
|
||||
- optimized static-file serving
|
||||
- support for linux unshare()
|
||||
|
||||
*** august 2011 ***
|
||||
|
||||
* 0.9.9 [20110829]
|
||||
|
||||
- various spooler improvements
|
||||
- upload progress optimizations and fixes
|
||||
- new emperor mode: Tyrant
|
||||
- allows multiple --ini options
|
||||
- better binary path detection
|
||||
- gevent loop engine support
|
||||
- resolve domain names in socket logging
|
||||
- snmp fixes and reintroduction of the snmp-api
|
||||
- fixed grunt mode
|
||||
- you can specify build profile via env var UWSGI_PROFILE
|
||||
- reintroduction of string-based multiapp
|
||||
- new option --emperor-throttle
|
||||
- improved queue and sharedarea subsystems
|
||||
- uWSGI can now be built as a shared library
|
||||
- new api attribute: uwsgi.magic_table
|
||||
- improved apache2 module
|
||||
- new option --pyshell
|
||||
- allow threads in gateways
|
||||
- fastrouter improvements
|
||||
- the application list is now shared and exported to the api
|
||||
- allows setting the thread stack size
|
||||
- UWSGI_APPID for better multiapp hosting
|
||||
- better reloading in lazy mode
|
||||
- native pump support
|
||||
- various rack fixes
|
||||
- support for attaching binary data in the executable
|
||||
- new option --set
|
||||
- extreme-optimized http protocol parser
|
||||
- WSGI handler optimizations
|
||||
|
||||
*** july 2011 ***
|
||||
|
||||
* 0.9.8.3 [20110723]
|
||||
|
||||
- implemented uwsgi.SymZipImporter to load embedded zip files
|
||||
- OSX Lion is officially supported
|
||||
- fixed xinetd support (example file added in contrib)
|
||||
- suppot for systemd socket activation
|
||||
- added --freebind option (Linux only)
|
||||
|
||||
* 0.9.8.2 [20110719]
|
||||
|
||||
- fixed an ini and yaml parsing bug spotted by Raffaele Colace
|
||||
- spooler has been extremely improved
|
||||
- new option --chown-socket
|
||||
- added uwsgidecorators for elegant uwsgi api access from python
|
||||
- the rack plugin is now stable
|
||||
- support for embedding config and generic files in the server binary
|
||||
- high-performance cache-server
|
||||
- accept() is now locked on all threads in the same workers
|
||||
- preliminary implementation of hooks in emperor
|
||||
- support for C++ in server core
|
||||
- tcp port auto-bind
|
||||
- implemented workers, workerN and spooler signal target
|
||||
- prefork/multithread uwsgi.signal_wait() implementation
|
||||
- export uwsgi.node in WSGI vars
|
||||
- new option --import (python plugin)
|
||||
- support for unlimited number of Linux cgroups
|
||||
- broodlord mode
|
||||
|
||||
*** june 2011 ***
|
||||
|
||||
* 0.9.8.1 [20110625]
|
||||
|
||||
- the build system has been improved
|
||||
- various threading fixes
|
||||
- fix python GIL status after reload
|
||||
- new option --propagate-touch
|
||||
- fixed uwsgi.sendfile
|
||||
- fixed readline() support in wsgi.input
|
||||
- fixed dynamic touch reload
|
||||
- new option --logto2
|
||||
- export %c in config files
|
||||
- fixed libyaml support
|
||||
- support passing modifiers in subscription system
|
||||
- reset random seed in spooler
|
||||
- subscribe from a list in a text file
|
||||
- allow binding on port 0 (auto-assignment)
|
||||
- reset random seed on grunt
|
||||
- fix vhost mode for empty hostname
|
||||
- fixed python3+virtualenv support
|
||||
- tasks are now allowed to chdir() in spooler
|
||||
- better zeromq+clustering support
|
||||
- clustering has been refactored
|
||||
- fixed rpc
|
||||
- report correct worker id in cheap mode
|
||||
- fixed a fd-leak in attach-daemon
|
||||
- use setsid() in attach-daemon
|
||||
- zerg mode
|
||||
- added psgix.harakiri
|
||||
- allows magic vars in sqlite3 config db
|
||||
- added UWSGI_FASTROUTER_KEY var
|
||||
- slowdown async-queue-is-full messages
|
||||
- new option --cron
|
||||
- --vassals-start-hook and --vassals-stop-hook
|
||||
- the proxy plugin has been removed
|
||||
|
||||
* 0.9.8 [20110605]
|
||||
|
||||
- support for --callable in virtualhosting mode
|
||||
- a NetBSD fix
|
||||
- abstract unix socket can be prefixed with \0 (nginx-style)
|
||||
- add /lib to the linker in sun-like systems
|
||||
- a mercy mode of 5 seconds is enabled by default on SIGINT/SIGQUIT
|
||||
|
||||
* 0.9.8-rc4 [20110602]
|
||||
|
||||
- fixed REMOTE_ADDR when --protocol=http
|
||||
- official support for OpenIndiana
|
||||
- added a welcome.py test script
|
||||
- new api attribute uwsgi.version_info
|
||||
- improved the admin plugin
|
||||
- two new management flag for backlog queue monitoring
|
||||
- fixed uwsgi_log for bigger loglines
|
||||
- new option --early-emperor to allows out-of-jail emperors
|
||||
- emperor can now spawn other emperors (sub-emperors)
|
||||
- fixed idle mode in single-process
|
||||
- fixed solaris iovec
|
||||
|
||||
*** may 2011 ***
|
||||
|
||||
* 0.9.8-rc3 [20110530]
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
all:
|
||||
python uwsgiconfig.py --build
|
||||
|
||||
clean:
|
||||
python uwsgiconfig.py --clean
|
||||
|
||||
+113
-54
@@ -2,7 +2,7 @@
|
||||
|
||||
*** uWSGI/mod_uwsgi ***
|
||||
|
||||
Copyright 2009-2010 Unbit S.a.s. <info@unbit.it>
|
||||
Copyright 2009-2011 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
|
||||
@@ -51,7 +51,6 @@ LoadModule uwsgi_module <path_of_apache_modules>/mod_uwsgi.so
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
#define MAX_VARS 64
|
||||
#define DEFAULT_SOCK "/tmp/uwsgi.sock"
|
||||
|
||||
typedef struct {
|
||||
@@ -73,6 +72,8 @@ typedef struct {
|
||||
char script_name[256];
|
||||
char scheme[9];
|
||||
int cgi_mode ;
|
||||
int max_vars;
|
||||
int empty_remote_user;
|
||||
} uwsgi_cfg;
|
||||
|
||||
module AP_MODULE_DECLARE_DATA uwsgi_module;
|
||||
@@ -83,8 +84,18 @@ static uint16_t uwsgi_swap16(uint16_t x) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static int uwsgi_add_var(struct iovec *vec, int i, char *key, char *value, uint16_t *pkt_size) {
|
||||
static int uwsgi_add_var(struct iovec *vec, int i, request_rec *r, char *key, char *value, uint16_t *pkt_size) {
|
||||
|
||||
uwsgi_cfg *c = ap_get_module_config(r->per_dir_config, &uwsgi_module);
|
||||
|
||||
#if APR_IS_BIGENDIAN
|
||||
if (i+6 > c->max_vars) {
|
||||
#else
|
||||
if (i+4 > c->max_vars) {
|
||||
#endif
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: max number of uwsgi variables reached. consider increasing it with uWSGImaxVars directive");
|
||||
return i;
|
||||
}
|
||||
|
||||
#if APR_IS_BIGENDIAN
|
||||
char *ptr;
|
||||
@@ -150,6 +161,9 @@ static void *uwsgi_server_config(apr_pool_t *p, server_rec *s) {
|
||||
c->modifier1 = 0 ;
|
||||
c->modifier2 = 0 ;
|
||||
c->cgi_mode = 0 ;
|
||||
c->max_vars = 128;
|
||||
c->script_name[0] = 0;
|
||||
c->empty_remote_user = 1;
|
||||
|
||||
return c;
|
||||
}
|
||||
@@ -164,6 +178,14 @@ static void *uwsgi_dir_config(apr_pool_t *p, char *dir) {
|
||||
c->modifier1 = 0 ;
|
||||
c->modifier2 = 0 ;
|
||||
c->cgi_mode = 0 ;
|
||||
c->max_vars = 128;
|
||||
c->empty_remote_user = 1;
|
||||
c->script_name[0] = 0;
|
||||
if (dir) {
|
||||
if (strcmp(dir, "/")) {
|
||||
strncpy(c->script_name, dir, 255);
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
@@ -243,11 +265,8 @@ 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
|
||||
struct iovec *uwsgi_vars;
|
||||
|
||||
int vecptr = 1 ;
|
||||
char pkt_header[4];
|
||||
uint16_t pkt_size = 0;
|
||||
@@ -315,68 +334,58 @@ static int uwsgi_handler(request_rec *r) {
|
||||
}
|
||||
|
||||
|
||||
#if APR_IS_BIGENDIAN
|
||||
uwsgi_vars = malloc(sizeof(struct iovec) * (c->max_vars*6)+1);
|
||||
#else
|
||||
uwsgi_vars = malloc(sizeof(struct iovec) * (c->max_vars*4)+1);
|
||||
#endif
|
||||
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "REQUEST_METHOD", (char *) r->method, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "QUERY_STRING", r->args ? r->args : "", &pkt_size) ;
|
||||
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->unparsed_uri, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "REMOTE_ADDR", r->connection->remote_ip, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "REMOTE_USER", r->user ? r->user : "", &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "REQUEST_METHOD", (char *) r->method, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "QUERY_STRING", r->args ? r->args : "", &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "SERVER_NAME", (char *) ap_get_server_name(r), &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "SERVER_PORT", apr_psprintf(r->pool, "%u",ap_get_server_port(r)), &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "SERVER_PROTOCOL", r->protocol, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "REQUEST_URI", r->unparsed_uri, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "REMOTE_ADDR", r->connection->remote_ip, &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, r, "REMOTE_USER", r->user, &pkt_size) ;
|
||||
}
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "DOCUMENT_ROOT", (char *) ap_document_root(r), &pkt_size) ;
|
||||
else if (c->empty_remote_user) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "REMOTE_USER", "", &pkt_size) ;
|
||||
}
|
||||
|
||||
if (r->user) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "AUTH_TYPE", (char *) ap_auth_type(r), &pkt_size) ;
|
||||
}
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "DOCUMENT_ROOT", (char *) ap_document_root(r), &pkt_size) ;
|
||||
|
||||
if (c->scheme[0] != 0) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "UWSGI_SCHEME", c->scheme, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "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) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "PATH_INFO", r->uri, &pkt_size) ;
|
||||
}
|
||||
else {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "SCRIPT_NAME", c->script_name, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "PATH_INFO", r->uri+strlen(c->script_name), &pkt_size) ;
|
||||
}
|
||||
// SCRIPT_NAME = "/" is like SCRIPT_NAME = ""
|
||||
if (c->script_name[0] != 0 && !(c->script_name[0] == '/' && c->script_name[1] == 0)) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "SCRIPT_NAME", c->script_name, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "PATH_INFO", r->uri+strlen(c->script_name), &pkt_size) ;
|
||||
}
|
||||
else {
|
||||
if (r->path_info) {
|
||||
if (strlen(r->path_info) <= 0) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "SCRIPT_NAME", "", &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "PATH_INFO", r->uri, &pkt_size) ;
|
||||
}
|
||||
else {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "SCRIPT_NAME", apr_pstrndup(r->pool, r->uri, (strlen(r->uri) - strlen(r->path_info) )) , &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "PATH_INFO", r->path_info, &pkt_size) ;
|
||||
}
|
||||
}
|
||||
else {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "SCRIPT_NAME", "", &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "PATH_INFO", r->uri, &pkt_size) ;
|
||||
}
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "SCRIPT_NAME", "", &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "PATH_INFO", r->uri, &pkt_size) ;
|
||||
}
|
||||
|
||||
|
||||
headers = apr_table_elts(r->headers_in);
|
||||
h = (apr_table_entry_t *) headers->elts;
|
||||
|
||||
// check for max vars (a bit ugly)
|
||||
cnt = headers->nelts ;
|
||||
if (cnt + 11 > MAX_VARS) {
|
||||
cnt = MAX_VARS -11;
|
||||
}
|
||||
|
||||
for(i=0;i< cnt;i++) {
|
||||
for(i=0;i< headers->nelts;i++) {
|
||||
if (h[i].key){
|
||||
if (!strcasecmp(h[i].key, "Content-Type")) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "CONTENT_TYPE", h[i].val, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "CONTENT_TYPE", h[i].val, &pkt_size) ;
|
||||
}
|
||||
else if (!strcasecmp(h[i].key, "Content-Length")) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "CONTENT_LENGTH", h[i].val, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "CONTENT_LENGTH", h[i].val, &pkt_size) ;
|
||||
}
|
||||
else {
|
||||
penv = apr_pstrcat(r->pool, "HTTP_", h[i].key, NULL);
|
||||
@@ -388,7 +397,7 @@ static int uwsgi_handler(request_rec *r) {
|
||||
*cp = toupper(*cp);
|
||||
}
|
||||
}
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, penv, h[i].val, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, penv, h[i].val, &pkt_size) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -397,7 +406,7 @@ static int uwsgi_handler(request_rec *r) {
|
||||
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) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, h[i].key, h[i].val, &pkt_size) ;
|
||||
}
|
||||
|
||||
|
||||
@@ -418,11 +427,13 @@ static int uwsgi_handler(request_rec *r) {
|
||||
if (cnt < 0) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: writev() %s", strerror(errno));
|
||||
close(uwsgi_poll.fd);
|
||||
free(uwsgi_vars);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
else if (cnt != pkt_size+4) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: writev() returned wrong size");
|
||||
close(uwsgi_poll.fd);
|
||||
free(uwsgi_vars);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
@@ -434,6 +445,7 @@ static int uwsgi_handler(request_rec *r) {
|
||||
if (cnt < 0) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: read() client block failed !");
|
||||
close(uwsgi_poll.fd);
|
||||
free(uwsgi_vars);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -458,6 +470,7 @@ static int uwsgi_handler(request_rec *r) {
|
||||
if (cnt == 0) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: recv() timeout");
|
||||
apr_brigade_destroy(bb);
|
||||
free(uwsgi_vars);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
else if (cnt > 0) {
|
||||
@@ -467,6 +480,7 @@ static int uwsgi_handler(request_rec *r) {
|
||||
if (errno != ECONNRESET) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: recv() %s", strerror(errno));
|
||||
apr_brigade_destroy(bb);
|
||||
free(uwsgi_vars);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
else {
|
||||
@@ -489,6 +503,7 @@ static int uwsgi_handler(request_rec *r) {
|
||||
if (r->connection->aborted) {
|
||||
close(uwsgi_poll.fd);
|
||||
apr_brigade_destroy(bb);
|
||||
free(uwsgi_vars);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
apr_brigade_write(bb, NULL, NULL, buf, cnt);
|
||||
@@ -508,6 +523,7 @@ static int uwsgi_handler(request_rec *r) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: poll() %s", strerror(errno));
|
||||
close(uwsgi_poll.fd);
|
||||
apr_brigade_destroy(bb);
|
||||
free(uwsgi_vars);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -521,6 +537,7 @@ static int uwsgi_handler(request_rec *r) {
|
||||
|
||||
if (!c->cgi_mode) {
|
||||
if (uwsgi_http_status_read == 0) {
|
||||
free(uwsgi_vars);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -528,11 +545,13 @@ static int uwsgi_handler(request_rec *r) {
|
||||
|
||||
if (hret = ap_scan_script_header_err_brigade(r, bb, NULL)) {
|
||||
apr_brigade_destroy(bb);
|
||||
free(uwsgi_vars);
|
||||
return hret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
free(uwsgi_vars);
|
||||
return ap_pass_brigade(r->output_filters, bb) ;
|
||||
}
|
||||
|
||||
@@ -564,6 +583,22 @@ static const char * cmd_uwsgi_force_wsgi_scheme(cmd_parms *cmd, void *cfg, const
|
||||
|
||||
}
|
||||
|
||||
static const char *cmd_uwsgi_max_vars(cmd_parms *cmd, void *cfg, const char *value) {
|
||||
uwsgi_cfg *c ;
|
||||
int val ;
|
||||
|
||||
if (cfg) {
|
||||
c = cfg ;
|
||||
}
|
||||
else {
|
||||
c = ap_get_module_config(cmd->server->module_config, &uwsgi_module);
|
||||
}
|
||||
|
||||
c->max_vars = atoi(value);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char * cmd_uwsgi_modifier1(cmd_parms *cmd, void *cfg, const char *value) {
|
||||
|
||||
uwsgi_cfg *c ;
|
||||
@@ -598,7 +633,7 @@ static const char * cmd_uwsgi_force_cgi_mode(cmd_parms *cmd, void *cfg, const ch
|
||||
c = ap_get_module_config(cmd->server->module_config, &uwsgi_module);
|
||||
}
|
||||
|
||||
if (!strcmp("yes", value) || !strcmp("on", value) || !strcmp("enable", value) || !strcmp("1", value)) {
|
||||
if (!strcmp("yes", value) || !strcmp("on", value) || !strcmp("enable", value) || !strcmp("1", value) || !strcmp("true", value)) {
|
||||
c->cgi_mode = 1 ;
|
||||
}
|
||||
|
||||
@@ -699,6 +734,28 @@ static const char * cmd_uwsgi_socket(cmd_parms *cmd, void *cfg, const char *path
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
static const char * cmd_uwsgi_empty_remote_user(cmd_parms *cmd, void *cfg, const char *value) {
|
||||
|
||||
uwsgi_cfg *c ;
|
||||
|
||||
if (cfg) {
|
||||
c = cfg ;
|
||||
}
|
||||
else {
|
||||
c = ap_get_module_config(cmd->server->module_config, &uwsgi_module);
|
||||
}
|
||||
|
||||
if (!strcmp("yes", value) || !strcmp("on", value) || !strcmp("enable", value) || !strcmp("1", value) || !strcmp("true", value)) {
|
||||
c->empty_remote_user = 1;
|
||||
}
|
||||
else {
|
||||
c->empty_remote_user = 0;
|
||||
}
|
||||
|
||||
return NULL ;
|
||||
|
||||
}
|
||||
|
||||
static const command_rec uwsgi_cmds[] = {
|
||||
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"),
|
||||
@@ -707,6 +764,8 @@ static const command_rec uwsgi_cmds[] = {
|
||||
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\")"),
|
||||
AP_INIT_TAKE1("uWSGIemptyRemoteUser", cmd_uwsgi_empty_remote_user, NULL, ACCESS_CONF, "Always include REMOTE_USER in the environment, even with an empty value (default true)"),
|
||||
AP_INIT_TAKE1("uWSGImaxVars", cmd_uwsgi_max_vars, NULL, ACCESS_CONF, "Set the maximum allowed number of uwsgi variables (default 128)"),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
||||
@@ -202,14 +202,20 @@ void *async_loop(void *arg1) {
|
||||
int is_a_new_connection;
|
||||
int proto_parser_status;
|
||||
|
||||
time_t now, last_now = 0;
|
||||
|
||||
static struct uwsgi_async_request *current_request = NULL, *next_async_request = NULL;
|
||||
|
||||
void *events = event_queue_alloc(64);
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
struct uwsgi_socket *uwsgi_sock;
|
||||
|
||||
uwsgi.async_runqueue = NULL;
|
||||
uwsgi.async_runqueue_cnt = 0;
|
||||
|
||||
if (uwsgi.signal_socket > -1) {
|
||||
event_queue_add_fd_read(uwsgi.async_queue, uwsgi.signal_socket);
|
||||
}
|
||||
|
||||
// set a default request manager
|
||||
if (!uwsgi.schedule_to_req) uwsgi.schedule_to_req = async_schedule_to_req;
|
||||
|
||||
@@ -260,7 +266,11 @@ void *async_loop(void *arg1) {
|
||||
|
||||
uwsgi.wsgi_req = find_first_available_wsgi_req();
|
||||
if (uwsgi.wsgi_req == NULL) {
|
||||
uwsgi_log("async queue is full !!!\n");
|
||||
now = time(NULL);
|
||||
if (now > last_now) {
|
||||
uwsgi_log("async queue is full !!!\n");
|
||||
last_now = now;
|
||||
}
|
||||
break;;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import struct
|
||||
import sys
|
||||
import os
|
||||
|
||||
filename = sys.argv[1]
|
||||
|
||||
size = os.path.getsize(filename)
|
||||
|
||||
f = open(filename, 'r')
|
||||
print(f.read())
|
||||
f.close()
|
||||
|
||||
print(struct.pack("<Q", size))
|
||||
@@ -0,0 +1,5 @@
|
||||
import sys
|
||||
import uwsgi
|
||||
|
||||
print("i am the bootstrap for uwsgi.SymbolsImporter")
|
||||
sys.meta_path.insert(0, uwsgi.SymbolsImporter())
|
||||
@@ -0,0 +1,4 @@
|
||||
import sys
|
||||
import uwsgi
|
||||
|
||||
sys.meta_path.insert(0, uwsgi.SymbolsZipImporter("pygments_zip"))
|
||||
@@ -0,0 +1,5 @@
|
||||
import sys
|
||||
import uwsgi
|
||||
|
||||
sys.meta_path.insert(0, uwsgi.SymbolsZipImporter("django_zip:djenv/lib/python2.6/site-packages"))
|
||||
sys.meta_path.insert(0, uwsgi.SymbolsZipImporter("djapp_zip"))
|
||||
@@ -0,0 +1,4 @@
|
||||
import sys
|
||||
import uwsgi
|
||||
|
||||
sys.meta_path.insert(0, uwsgi.ZipImporter("data://0"))
|
||||
@@ -0,0 +1,3 @@
|
||||
import uwsgi
|
||||
|
||||
print uwsgi.extract("data://0")
|
||||
@@ -0,0 +1 @@
|
||||
object file for embedded files will be put here
|
||||
@@ -27,13 +27,18 @@ plugins =
|
||||
bin_name = uwsgi
|
||||
append_version =
|
||||
plugin_dir = .
|
||||
embedded_plugins = python, ping, cache, nagios, rpc, fastrouter, http, ugreen
|
||||
embedded_plugins = python, ping, cache, nagios, rrdtool, carbon, rpc, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket
|
||||
as_shared_library = false
|
||||
|
||||
locking = auto
|
||||
event = auto
|
||||
timer = auto
|
||||
filemonitor = auto
|
||||
|
||||
embed_files =
|
||||
|
||||
embed_config =
|
||||
|
||||
[python]
|
||||
paste = true
|
||||
web3 = true
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embed_files = bootstrap3.py,django.zip,djapp.zip
|
||||
@@ -0,0 +1,4 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
|
||||
embed_files = embedme.py,uwsgidecorators.py
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = python, ping, cache, nagios, rpc, fastrouter, http, gevent
|
||||
@@ -0,0 +1,5 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
bin_name = libuwsgi.so
|
||||
embedded_plugins = null
|
||||
as_shared_library = true
|
||||
@@ -1,7 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = +,lua
|
||||
|
||||
[python]
|
||||
paste = true
|
||||
web3 = true
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
bin_name = libuwsgi.so
|
||||
embedded_plugins = symcall
|
||||
as_shared_library = true
|
||||
@@ -0,0 +1,5 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
bin_name = pyuwsgi.so
|
||||
embedded_plugins = pyuwsgi,python,ping,cache,nagios,rpc,ugreen
|
||||
as_shared_library = true
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = rack, ping, nagios, rpc
|
||||
embedded_plugins = rack, ping, cache, nagios, rpc, fastrouter, http, ugreen
|
||||
|
||||
+13
-1
@@ -2,6 +2,9 @@
|
||||
xml = true
|
||||
ini = true
|
||||
yaml = true
|
||||
json = true
|
||||
sqlite3 = false
|
||||
zeromq = false
|
||||
snmp = false
|
||||
sctp = false
|
||||
spooler = true
|
||||
@@ -10,14 +13,23 @@ udp = true
|
||||
multicast = false
|
||||
threading = true
|
||||
sendfile = true
|
||||
nagios = false
|
||||
minterpreters = true
|
||||
async = true
|
||||
evdis = false
|
||||
ldap = true
|
||||
pcre = false
|
||||
debug = false
|
||||
unbit = true
|
||||
xml_implementation = libxml2
|
||||
yaml_implementation = auto
|
||||
malloc_implementation = libc
|
||||
plugins =
|
||||
bin_name = /opt/unbit/bin/uwsgi
|
||||
append_version = unbit
|
||||
plugin_dir = /opt/unbit/uwsgi_plugins
|
||||
embedded_plugins =
|
||||
|
||||
locking = auto
|
||||
event = auto
|
||||
timer = auto
|
||||
filemonitor = auto
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
[uwsgi]
|
||||
inherit = unbit
|
||||
json = false
|
||||
embedded_plugins = python
|
||||
bin_name = ../bin/uwsgi
|
||||
plugin_dir = ../bin/uwsgi_plugins
|
||||
|
||||
@@ -6,12 +6,7 @@ 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_blocksize = UMAX16;
|
||||
|
||||
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) {
|
||||
@@ -91,148 +86,8 @@ void uwsgi_init_cache() {
|
||||
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;
|
||||
uwsgi_log("*** Cache subsystem initialized: %dMB (key: %llu bytes, keys: %llu bytes, data: %llu bytes) preallocated ***\n", ((uwsgi.cache_blocksize * uwsgi.cache_max_items) + (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items)) / (1024 * 1024),
|
||||
(unsigned long long) sizeof(struct uwsgi_cache_item), (unsigned long long) sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items, (unsigned long long) uwsgi.cache_blocksize * uwsgi.cache_max_items);
|
||||
}
|
||||
|
||||
uint32_t djb33x_hash(char *key, int keylen) {
|
||||
@@ -248,89 +103,6 @@ uint32_t djb33x_hash(char *key, int keylen) {
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
@@ -508,73 +280,140 @@ int uwsgi_cache_set(char *key, uint16_t keylen, char *val, uint64_t vallen, uint
|
||||
uci->prev = last_index;
|
||||
}
|
||||
}
|
||||
else if (flags & UWSGI_CACHE_FLAG_UPDATE) {
|
||||
uci = &uwsgi.cache_items[index] ;
|
||||
if (expires) {
|
||||
expires += time(NULL);
|
||||
uci->expires = expires;
|
||||
}
|
||||
memcpy(uwsgi.cache+(index*uwsgi.cache_blocksize), val, vallen);
|
||||
uci->valsize = vallen;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
end:
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_dict_set(struct uwsgi_dict *udict, char *key, uint16_t keylen, char *val, uint64_t vallen) {
|
||||
/* THIS PART IS HEAVILY OPTIMIZED: PERFORMANCE NOT ELEGANCE !!! */
|
||||
|
||||
uint64_t index = 0, last_index = 0 ;
|
||||
void *cache_thread_loop(void *fd_ptr) {
|
||||
|
||||
struct uwsgi_dict_item *udi, *udii;
|
||||
int *fd_tmp = (int *) fd_ptr;
|
||||
int fd = *fd_tmp;
|
||||
int i;
|
||||
ssize_t len;
|
||||
char uwsgi_packet[UMAX16+4];
|
||||
struct uwsgi_header *uh = (struct uwsgi_header *) uwsgi_packet;
|
||||
char *val;
|
||||
uint64_t vallen;
|
||||
char *key;
|
||||
uint16_t keylen;
|
||||
struct pollfd ctl_poll;
|
||||
char *watermark;
|
||||
struct sockaddr_un ctl_sun;
|
||||
socklen_t ctl_sun_len;
|
||||
|
||||
int ret = -1;
|
||||
int slot;
|
||||
ctl_poll.events = POLLIN;
|
||||
|
||||
if (!keylen || !vallen) return -1;
|
||||
for(;;) {
|
||||
ctl_sun_len = sizeof(struct sockaddr_un);
|
||||
pthread_mutex_lock(&uwsgi.cache_server_lock);
|
||||
|
||||
if (keylen > UWSGI_CACHE_MAX_KEY_SIZE) return -1;
|
||||
ctl_poll.fd = accept(fd, (struct sockaddr *) &ctl_sun, &ctl_sun_len);
|
||||
|
||||
if (udict->first_available_item >= udict->max_items && !udict->unused_stack_ptr) {
|
||||
uwsgi_log("*** DANGER dictionary %p is FULL !!! ***\n", udict);
|
||||
goto end;
|
||||
}
|
||||
pthread_mutex_unlock(&uwsgi.cache_server_lock);
|
||||
|
||||
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);
|
||||
if (ctl_poll.fd < 0) {
|
||||
uwsgi_error("cache accept()");
|
||||
continue;
|
||||
}
|
||||
i = 0;
|
||||
while(i < 4) {
|
||||
len = poll(&ctl_poll, 1, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (len <= 0) {
|
||||
uwsgi_error("cache poll()");
|
||||
goto clear;
|
||||
}
|
||||
len = read(ctl_poll.fd, uwsgi_packet+i, 4-i);
|
||||
if (len < 0) {
|
||||
uwsgi_error("cache read()");
|
||||
goto clear;
|
||||
}
|
||||
i+=len;
|
||||
}
|
||||
|
||||
// set this as late as possibile (to reduce races risk)
|
||||
if (uh->pktsize == 0) goto clear;
|
||||
|
||||
udi->valsize = vallen;
|
||||
udi->keysize = keylen;
|
||||
ret = 0;
|
||||
// now put the value in the 16bit hashtable
|
||||
slot = udi->djbhash % 0xffff;
|
||||
while(i < 4+uh->pktsize) {
|
||||
len = poll(&ctl_poll, 1, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (len <= 0) {
|
||||
uwsgi_error("cache poll()");
|
||||
goto clear;
|
||||
}
|
||||
len = read(ctl_poll.fd, uwsgi_packet+i, (4+uh->pktsize)-i);
|
||||
if (len < 0) {
|
||||
uwsgi_error("cache read()");
|
||||
goto clear;
|
||||
}
|
||||
i+=len;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
watermark = uwsgi_packet+4+uh->pktsize;
|
||||
|
||||
end:
|
||||
return ret;
|
||||
// get first parameter
|
||||
memcpy(&keylen, uwsgi_packet+4, 2);
|
||||
#ifdef __BIG_ENDIAN__
|
||||
keylen = uwsgi_swap16(keylen);
|
||||
#endif
|
||||
if (uwsgi_packet+6+keylen > watermark) goto clear;
|
||||
key = uwsgi_packet+6+keylen+2;
|
||||
memcpy(&keylen, key-2, 2);
|
||||
#ifdef __BIG_ENDIAN__
|
||||
keylen = uwsgi_swap16(keylen);
|
||||
#endif
|
||||
|
||||
if (key+keylen > watermark) goto clear;
|
||||
|
||||
val = uwsgi_cache_get(key, keylen, &vallen);
|
||||
if (val && vallen > 0) {
|
||||
if (write(ctl_poll.fd, val, vallen) < 0) {
|
||||
uwsgi_error("cache write()");
|
||||
}
|
||||
}
|
||||
|
||||
clear:
|
||||
close(ctl_poll.fd);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int uwsgi_cache_server(char *socket, int threads) {
|
||||
|
||||
int *fd = uwsgi_malloc(sizeof(int));
|
||||
|
||||
int i;
|
||||
pthread_t thread_id;
|
||||
char *tcp_port = strchr(socket, ':');
|
||||
if (tcp_port) {
|
||||
*fd = bind_to_tcp(socket, uwsgi.listen_queue, tcp_port);
|
||||
}
|
||||
else {
|
||||
*fd = bind_to_unix(socket, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
|
||||
}
|
||||
|
||||
pthread_mutex_init(&uwsgi.cache_server_lock, NULL);
|
||||
|
||||
if (threads < 1) threads = 1;
|
||||
|
||||
uwsgi_log("*** cache-optimized server enabled on fd %d (%d threads) ***\n", *fd, threads);
|
||||
|
||||
for(i=0;i<threads;i++) {
|
||||
pthread_create(&thread_id, NULL, cache_thread_loop, (void *) fd);
|
||||
}
|
||||
|
||||
return *fd;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,355 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#ifdef UWSGI_UDP
|
||||
void cluster_setup() {
|
||||
|
||||
int rlen;
|
||||
// get cluster configuration
|
||||
if (uwsgi.cluster != NULL) {
|
||||
// get multicast socket
|
||||
|
||||
uwsgi.cluster_fd = uwsgi_cluster_join(uwsgi.cluster);
|
||||
|
||||
uwsgi_log("JOINED CLUSTER: %s\n", uwsgi.cluster);
|
||||
|
||||
// ask for cluster options only if bot pre-existent options are set
|
||||
if (uwsgi.exported_opts_cnt == 1 && !uwsgi.cluster_nodes) {
|
||||
// now wait max 60 seconds and resend multicast request every 10 seconds
|
||||
for (;;) {
|
||||
uwsgi_log("asking \"%s\" uWSGI cluster for configuration data:\n", uwsgi.cluster);
|
||||
if (uwsgi_send_empty_pkt(uwsgi.cluster_fd, uwsgi.cluster, 99, 0) < 0) {
|
||||
uwsgi_log("unable to send multicast message to %s\n", uwsgi.cluster);
|
||||
continue;
|
||||
}
|
||||
waitfd:
|
||||
rlen = uwsgi_waitfd(uwsgi.cluster_fd, 10);
|
||||
if (rlen < 0) {
|
||||
break;
|
||||
}
|
||||
else if (rlen > 0) {
|
||||
// receive the packet
|
||||
char clusterbuf[4096];
|
||||
if (!uwsgi_hooked_parse_dict_dgram(uwsgi.cluster_fd, clusterbuf, 4096, 99, 1, manage_string_opt, NULL)) {
|
||||
uwsgi_configure();
|
||||
goto options_parsed;
|
||||
}
|
||||
else {
|
||||
goto waitfd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
options_parsed:
|
||||
|
||||
if (!uwsgi.cluster_nodes)
|
||||
uwsgi_cluster_add_me();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void uwsgi_cluster_add_node(struct uwsgi_cluster_node *nucn, int type) {
|
||||
|
||||
int i;
|
||||
struct uwsgi_cluster_node *ucn;
|
||||
char *tcp_port;
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("adding node\n");
|
||||
#endif
|
||||
|
||||
tcp_port = strchr(nucn->name, ':');
|
||||
#ifndef UWSGI_ZEROMQ
|
||||
if (tcp_port == NULL) {
|
||||
#else
|
||||
char *zmq_dash = strchr(nucn->name, '-');
|
||||
if (tcp_port == NULL && zmq_dash == NULL) {
|
||||
#endif
|
||||
|
||||
fprintf(stdout, "invalid cluster node name %s\n", nucn->name);
|
||||
return;
|
||||
}
|
||||
|
||||
// first check for already present node
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
ucn = &uwsgi.shared->nodes[i];
|
||||
if (ucn->name[0] != 0) {
|
||||
if (!strcmp(ucn->name, nucn->name)) {
|
||||
ucn->status = UWSGI_NODE_OK;
|
||||
ucn->last_seen = time(NULL);
|
||||
// update requests
|
||||
ucn->requests = nucn->requests;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
ucn = &uwsgi.shared->nodes[i];
|
||||
|
||||
if (ucn->name[0] == 0) {
|
||||
memcpy(ucn->name, nucn->name, strlen(nucn->name) + 1);
|
||||
memcpy(ucn->nodename, nucn->nodename, strlen(nucn->nodename) + 1);
|
||||
ucn->workers = nucn->workers;
|
||||
ucn->ucn_addr.sin_family = AF_INET;
|
||||
if (tcp_port) {
|
||||
ucn->ucn_addr.sin_port = htons(atoi(tcp_port + 1));
|
||||
tcp_port[0] = 0;
|
||||
}
|
||||
if (nucn->name[0] == 0) {
|
||||
ucn->ucn_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
}
|
||||
else {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%s\n", nucn->name);
|
||||
#endif
|
||||
ucn->ucn_addr.sin_addr.s_addr = inet_addr(nucn->name);
|
||||
}
|
||||
|
||||
ucn->type = type;
|
||||
// here memory can be freed, as it is allocated by uwsgi_concat2n
|
||||
if (type != CLUSTER_NODE_DYNAMIC && tcp_port) {
|
||||
tcp_port[0] = ':';
|
||||
}
|
||||
ucn->last_seen = time(NULL);
|
||||
ucn->requests = nucn->requests;
|
||||
uwsgi_log("[uWSGI cluster] added node %s\n", ucn->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("unable to add node %s\n", nucn->name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int uwsgi_cluster_add_me() {
|
||||
|
||||
const char *key1 = "hostname";
|
||||
const char *key2 = "address";
|
||||
const char *key3 = "workers";
|
||||
const char *key4 = "requests";
|
||||
|
||||
char *ptrbuf;
|
||||
uint16_t ustrlen;
|
||||
char numproc[6];
|
||||
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
char uuid_zmq_str[37];
|
||||
uuid_t uuid_zmq;
|
||||
if (!uwsgi.sockets && !uwsgi.zeromq) {
|
||||
#else
|
||||
if (!uwsgi.sockets) {
|
||||
#endif
|
||||
uwsgi_log("you need to specify at least a socket to start a uWSGI cluster\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
snprintf(numproc, 6, "%d", uwsgi.numproc);
|
||||
|
||||
size_t len;
|
||||
|
||||
if (uwsgi.sockets) {
|
||||
len = 2 + strlen(key1) + 2 + strlen(uwsgi.hostname) + 2 + strlen(key2) + 2 + strlen(uwsgi.sockets->name) + 2 + strlen(key3) + 2 + strlen(numproc) + 2 + strlen(key4) + 2 + 1;
|
||||
}
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
else if (uwsgi.zeromq) {
|
||||
uuid_generate(uuid_zmq);
|
||||
uuid_unparse(uuid_zmq, uuid_zmq_str);
|
||||
len = 2 + strlen(key1) + 2 + strlen(uwsgi.hostname) + 2 + strlen(key2) + 2 + strlen(uuid_zmq_str) + 2 + strlen(key3) + 2 + strlen(numproc) + 2 + strlen(key4) + 2 + 1;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
len = 2 + strlen(key1) + 2 + strlen(uwsgi.hostname) + 2 + strlen(key3) + 2 + strlen(numproc) + 2 + strlen(key4) + 2 + 1;
|
||||
}
|
||||
char *buf = uwsgi_malloc(len);
|
||||
|
||||
ptrbuf = buf;
|
||||
|
||||
ustrlen = strlen(key1);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key1, strlen(key1));
|
||||
ptrbuf += strlen(key1);
|
||||
|
||||
ustrlen = strlen(uwsgi.hostname);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, uwsgi.hostname, strlen(uwsgi.hostname));
|
||||
ptrbuf += strlen(uwsgi.hostname);
|
||||
|
||||
|
||||
if (uwsgi.sockets && uwsgi.sockets->name) {
|
||||
ustrlen = strlen(key2);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key2, strlen(key2));
|
||||
ptrbuf += strlen(key2);
|
||||
|
||||
ustrlen = strlen(uwsgi.sockets->name);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, uwsgi.sockets->name, strlen(uwsgi.sockets->name));
|
||||
ptrbuf += strlen(uwsgi.sockets->name);
|
||||
}
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
else if (uwsgi.zeromq) {
|
||||
ustrlen = strlen(key2);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key2, strlen(key2));
|
||||
ptrbuf += strlen(key2);
|
||||
|
||||
ustrlen = strlen(uuid_zmq_str);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, uuid_zmq_str, strlen(uuid_zmq_str));
|
||||
ptrbuf += strlen(uuid_zmq_str);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
ustrlen = strlen(key3);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key3, strlen(key3));
|
||||
ptrbuf += strlen(key3);
|
||||
|
||||
ustrlen = strlen(numproc);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, numproc, strlen(numproc));
|
||||
ptrbuf += strlen(numproc);
|
||||
|
||||
ustrlen = strlen(key4);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key4, strlen(key4));
|
||||
ptrbuf += strlen(key4);
|
||||
|
||||
ustrlen = 1;
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, "0", 1);
|
||||
ptrbuf += 1;
|
||||
|
||||
|
||||
uwsgi_string_sendto(uwsgi.cluster_fd, 95, 0, (struct sockaddr *) &uwsgi.mc_cluster_addr, sizeof(uwsgi.mc_cluster_addr), buf, len);
|
||||
|
||||
free(buf);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("add_me() successfull\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_cluster_join(char *name) {
|
||||
|
||||
int fd;
|
||||
char *cp;
|
||||
int broadcast = 0;
|
||||
|
||||
|
||||
|
||||
if (name[0] == ':') {
|
||||
fd = bind_to_udp(name, 0, 1);
|
||||
broadcast = 1;
|
||||
}
|
||||
else {
|
||||
fd = bind_to_udp(name, 1, 0);
|
||||
}
|
||||
|
||||
if (fd >= 0) {
|
||||
cp = strchr(name, ':');
|
||||
cp[0] = 0;
|
||||
uwsgi.mc_cluster_addr.sin_family = AF_INET;
|
||||
if (broadcast) {
|
||||
uwsgi.mc_cluster_addr.sin_addr.s_addr = INADDR_BROADCAST;
|
||||
}
|
||||
else {
|
||||
uwsgi.mc_cluster_addr.sin_addr.s_addr = inet_addr(name);
|
||||
}
|
||||
uwsgi.mc_cluster_addr.sin_port = htons(atoi(cp + 1));
|
||||
cp[0] = ':';
|
||||
|
||||
|
||||
// announce my presence to all the nodes
|
||||
uwsgi_string_sendto(fd, 73, 0, (struct sockaddr *) &uwsgi.mc_cluster_addr, sizeof(uwsgi.mc_cluster_addr), uwsgi.hostname, strlen(uwsgi.hostname));
|
||||
}
|
||||
else {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
return fd;
|
||||
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_cluster_best_node() {
|
||||
|
||||
int i;
|
||||
int best_node = -1;
|
||||
struct uwsgi_cluster_node *ucn;
|
||||
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
ucn = &uwsgi.shared->nodes[i];
|
||||
if (ucn->name[0] != 0 && ucn->status == UWSGI_NODE_OK) {
|
||||
if (best_node == -1) {
|
||||
best_node = i;
|
||||
}
|
||||
else {
|
||||
if (ucn->last_choosen < uwsgi.shared->nodes[best_node].last_choosen) {
|
||||
best_node = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (best_node == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uwsgi.shared->nodes[best_node].last_choosen = time(NULL);
|
||||
return uwsgi.shared->nodes[best_node].name;
|
||||
}
|
||||
|
||||
|
||||
void manage_cluster_announce(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
|
||||
|
||||
char *tmpstr;
|
||||
struct uwsgi_cluster_node *ucn = (struct uwsgi_cluster_node *) data;
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%.*s = %.*s\n", keylen, key, vallen, val);
|
||||
#endif
|
||||
|
||||
if (!uwsgi_strncmp("hostname", 8, key, keylen)) {
|
||||
strncpy(ucn->nodename, val, UMIN(vallen, 255));
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("address", 7, key, keylen)) {
|
||||
strncpy(ucn->name, val, UMIN(vallen, 100));
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("workers", 7, key, keylen)) {
|
||||
tmpstr = uwsgi_concat2n(val, vallen, "", 0);
|
||||
ucn->workers = atoi(tmpstr);
|
||||
free(tmpstr);
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("requests", 8, key, keylen)) {
|
||||
tmpstr = uwsgi_concat2n(val, vallen, "", 0);
|
||||
ucn->requests = strtoul(tmpstr, NULL, 0);
|
||||
free(tmpstr);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
require 'stringio'
|
||||
|
||||
hello = proc do |signum|
|
||||
puts "Hello i am signal #{signum}"
|
||||
end
|
||||
|
||||
file_changed = proc do |signum|
|
||||
puts "/tmp has been modified"
|
||||
end
|
||||
|
||||
UWSGI.register_signal(17, '', hello)
|
||||
UWSGI.register_signal(30, '', file_changed)
|
||||
|
||||
UWSGI.add_rb_timer(17 , 2)
|
||||
UWSGI.add_timer(17 , 1)
|
||||
UWSGI.add_file_monitor(30 , '/tmp')
|
||||
|
||||
puts UWSGI.signal_registered(1)
|
||||
puts UWSGI.signal_registered(17)
|
||||
|
||||
run lambda { |env|
|
||||
puts env.inspect
|
||||
UWSGI.signal(17)
|
||||
[200, {'Content-Type'=>'text/plain'}, StringIO.new("Hello World!\n")]
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
require 'stringio'
|
||||
require 'uwsgidsl'
|
||||
|
||||
|
||||
|
||||
signal 17,'mule5' do |signum|
|
||||
end
|
||||
|
||||
puts UWSGI::VERSION
|
||||
puts UWSGI::NUMPROC
|
||||
puts UWSGI::HOSTNAME
|
||||
|
||||
puts UWSGI::OPT.inspect
|
||||
|
||||
timer 2 do |signum|
|
||||
puts "ciao sono un dsl ruby: #{signum} #{UWSGI::OPT.inspect}"
|
||||
end
|
||||
|
||||
timer 1,'mule1' do |signum|
|
||||
puts "1 second elapsed (signum #{signum})"
|
||||
end
|
||||
|
||||
filemon '/tmp' do |signum|
|
||||
puts "/tmp has been modified"
|
||||
end
|
||||
|
||||
cron 5,-1,-1,-1,-1 do |signum|
|
||||
puts "cron ready #{signum}"
|
||||
end
|
||||
|
||||
cron 58,-1,-1,-1,-1 do |signum|
|
||||
puts "cron ready #{signum}"
|
||||
end
|
||||
|
||||
postfork do
|
||||
puts "fork() called"
|
||||
end
|
||||
|
||||
rpc 'pippo' do
|
||||
"i am an rpc function"
|
||||
end
|
||||
|
||||
rpc 'pluto' do |x,y|
|
||||
"i am another rpc function #{x} #{y}"
|
||||
end
|
||||
|
||||
begin
|
||||
foo_func
|
||||
rescue
|
||||
end
|
||||
|
||||
puts UWSGI.cache_exists('nilkey')
|
||||
puts UWSGI.cache_exists?('nilkey')
|
||||
|
||||
UWSGI.cache_set!('foobar_key?a=1', UWSGI::OPT.inspect)
|
||||
begin
|
||||
puts UWSGI.cache_get(nil)
|
||||
rescue
|
||||
end
|
||||
puts UWSGI.cache_get('foobar_key?a=1')
|
||||
|
||||
|
||||
run lambda { |env|
|
||||
puts env.inspect
|
||||
UWSGI.setprocname("i am the uWSGI rack plugin")
|
||||
UWSGI.signal(17)
|
||||
[200, {'Content-Type'=>'text/plain'}, StringIO.new("Hello World! #{UWSGI.mem.inspect}\n")]
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
#!/bin/bash
|
||||
|
||||
# uwsgi - Use uwsgi to run python and wsgi web apps.
|
||||
#
|
||||
# chkconfig: - 85 15
|
||||
# description: Use uwsgi to run python and wsgi web apps.
|
||||
# processname: uwsgi
|
||||
|
||||
# author: Roman Vasilyev
|
||||
|
||||
# Source function library.
|
||||
. /etc/rc.d/init.d/functions
|
||||
|
||||
PATH=/opt/uwsgi:/sbin:/bin:/usr/sbin:/usr/bin
|
||||
prog=/usr/sbin/uwsgi
|
||||
|
||||
OWNER=nginx
|
||||
|
||||
NAME=uwsgi
|
||||
DESC=uwsgi
|
||||
|
||||
#DAEMON_OPTS="-s 127.0.0.1:9001 -M 4 -t 30 -A 4 -p 4 -d /var/log/uwsgi.log --pidfile /var/run/$NAME.pid --pythonpath $PYTHONPATH --module $MODULE"
|
||||
DAEMON_OPTS="-s 127.0.0.1:9001 -M 4 -t 30 -A 4 -p 16 -b 32768 -d /var/log/$NAME.log --pidfile /var/run/$NAME.pid --uid $OWNER"
|
||||
|
||||
[ -f /etc/sysconfig/uwsgi ] && . /etc/sysconfig/uwsgi
|
||||
|
||||
lockfile=/var/lock/subsys/uwsgi
|
||||
|
||||
start () {
|
||||
echo -n "Starting $DESC: "
|
||||
daemon $prog $DAEMON_OPTS
|
||||
retval=$?
|
||||
echo
|
||||
[ $retval -eq 0 ] && touch $lockfile
|
||||
return $retval
|
||||
}
|
||||
|
||||
stop () {
|
||||
echo -n "Stopping $DESC: "
|
||||
killproc $prog
|
||||
retval=$?
|
||||
echo
|
||||
[ $retval -eq 0 ] && rm -f $lockfile
|
||||
return $retval
|
||||
}
|
||||
|
||||
reload () {
|
||||
echo "Reloading $NAME"
|
||||
killproc $prog -HUP
|
||||
RETVAL=$?
|
||||
echo
|
||||
}
|
||||
|
||||
force-reload () {
|
||||
echo "Reloading $NAME"
|
||||
killproc $prog -TERM
|
||||
RETVAL=$?
|
||||
echo
|
||||
}
|
||||
|
||||
restart () {
|
||||
stop
|
||||
start
|
||||
}
|
||||
|
||||
rh_status () {
|
||||
status $prog
|
||||
}
|
||||
|
||||
rh_status_q() {
|
||||
rh_status >/dev/null 2>&1
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
rh_status_q && exit 0
|
||||
$1
|
||||
;;
|
||||
stop)
|
||||
rh_status_q || exit 0
|
||||
$1
|
||||
;;
|
||||
restart|force-reload)
|
||||
$1
|
||||
;;
|
||||
reload)
|
||||
rh_status_q || exit 7
|
||||
$1
|
||||
;;
|
||||
status)
|
||||
rh_status
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart|reload|force-reload|status}" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
exit 0
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#include <Python.h>
|
||||
|
||||
void uwsgi_cgi_load_python() {
|
||||
|
||||
Py_Initialize();
|
||||
}
|
||||
|
||||
void uwsgi_cgi_run_python(char *filename) {
|
||||
|
||||
char **e, *p;
|
||||
PyObject *k, *env_value;
|
||||
|
||||
FILE *fp = fopen(filename, "r");
|
||||
|
||||
PySys_SetArgv(1, &filename);
|
||||
|
||||
PyObject *os_module = PyImport_ImportModule("os");
|
||||
if (os_module) {
|
||||
PyObject *os_module_dict = PyModule_GetDict(os_module);
|
||||
PyObject *py_environ = PyDict_GetItemString(os_module_dict, "environ");
|
||||
if (py_environ) {
|
||||
for (e = environ; *e != NULL; e++) {
|
||||
p = strchr(*e, '=');
|
||||
if (p == NULL) continue;
|
||||
|
||||
k = PyString_FromStringAndSize(*e, (int)(p-*e));
|
||||
if (k == NULL) {
|
||||
PyErr_Print();
|
||||
continue;
|
||||
}
|
||||
|
||||
env_value = PyString_FromString(p+1);
|
||||
if (env_value == NULL) {
|
||||
PyErr_Print();
|
||||
Py_DECREF(k);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (PyObject_SetItem(py_environ, k, env_value)) {
|
||||
PyErr_Print();
|
||||
}
|
||||
|
||||
Py_DECREF(k);
|
||||
Py_DECREF(env_value);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PyRun_AnyFileEx(fp, filename, 1);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
from tasksconsumer import enqueue
|
||||
|
||||
def application(env, sr):
|
||||
|
||||
sr('200 OK', [('Content-Type','text/html')])
|
||||
|
||||
enqueue(queue='fast', pippo='pluto')
|
||||
|
||||
return "Task enqueued"
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
from tasksconsumer import *
|
||||
|
||||
@queueconsumer('fast', 4)
|
||||
def fast_queue(arguments):
|
||||
print "fast", arguments
|
||||
|
||||
@queueconsumer('slow')
|
||||
def slow_queue(arguments):
|
||||
print "foobar", arguments
|
||||
@@ -0,0 +1,44 @@
|
||||
from uwsgidecorators import *
|
||||
import Queue
|
||||
from threading import Thread
|
||||
|
||||
queues = {}
|
||||
|
||||
class queueconsumer(object):
|
||||
|
||||
def __init__(self, name, num=1, **kwargs):
|
||||
self.name = name
|
||||
self.num = num
|
||||
self.queue = Queue.Queue()
|
||||
self.threads = []
|
||||
self.func = None
|
||||
queues[self.name] = self
|
||||
|
||||
|
||||
@staticmethod
|
||||
def consumer(self):
|
||||
while True:
|
||||
req = self.queue.get()
|
||||
print req
|
||||
self.func(req)
|
||||
self.queue.task_done()
|
||||
|
||||
def __call__(self, f):
|
||||
self.func = f
|
||||
for i in range(self.num):
|
||||
t = Thread(target=self.consumer,args=(self,))
|
||||
self.threads.append(t)
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
@spool
|
||||
def spooler_enqueuer(arguments):
|
||||
if 'queue' in arguments:
|
||||
queue = arguments['queue']
|
||||
queues[queue].queue.put(arguments)
|
||||
else:
|
||||
raise Exception("You have to specify a queue name")
|
||||
|
||||
|
||||
def enqueue(*args, **kwargs):
|
||||
return spooler_enqueuer.spool(*args, **kwargs)
|
||||
@@ -12,4 +12,6 @@ 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
|
||||
# --die-on-term could be a good idea
|
||||
exec $BINPATH --no-orphans --socket :3033 --uid 1001 --gid 1001 --limit-as 256 -w simple_app --logto $LOGTO -M -p 4
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
require 'rubygems'
|
||||
require 'socket'
|
||||
begin
|
||||
require 'bundler/setup'
|
||||
rescue LoadError
|
||||
end
|
||||
require 'rack'
|
||||
require 'rack/content_length'
|
||||
require 'rack/rewindable_input'
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
import mmap
|
||||
import os
|
||||
import struct
|
||||
import array
|
||||
import time
|
||||
import sys
|
||||
from optparse import OptionParser
|
||||
|
||||
class Cache:
|
||||
|
||||
def __init__(self, filename, cache_slots, block_size=65536, sample_sleep=1):
|
||||
|
||||
self.block_size = block_size
|
||||
self.cache_slots = cache_slots
|
||||
|
||||
self.key_size = 2048
|
||||
self.item_size = 2 + 2 + 4 + 8 + 8 + 8 + 8 + 8 + self.key_size
|
||||
self.block_size_start = self.item_size * self.cache_slots
|
||||
|
||||
fd = os.open(filename, os.O_RDONLY)
|
||||
self.cache_store = mmap.mmap(fd, 0, mmap.MAP_SHARED, mmap.PROT_READ)
|
||||
|
||||
self.sample_sleep = sample_sleep
|
||||
self.samples = 0
|
||||
self.history = []
|
||||
self.cache_full = 0
|
||||
self.cache_empty = 0
|
||||
self.cache_items = 0
|
||||
self.block_sizes = 0
|
||||
|
||||
def store_read_item_block(self, position):
|
||||
pos = self.cache_store.tell()
|
||||
# uwsgi cache stores cache entries first and then the blocks
|
||||
self.cache_store.seek(self.block_size_start + (position * self.block_size))
|
||||
buf = self.cache_store.read(self.block_size)
|
||||
self.cache_store.seek(pos)
|
||||
return buf
|
||||
|
||||
def store_read_item(self, position):
|
||||
buf = self.cache_store.read(self.item_size)
|
||||
fields = struct.unpack_from('@HHIQQQQQ2048c', buf)
|
||||
key = array.array('c', fields[8:self.key_size+8]).tostring().rstrip('\x00')
|
||||
|
||||
if [x for x in key if x!= '\x00']:
|
||||
buf = self.store_read_item_block(position)
|
||||
value = array.array('c', buf).tostring().rstrip('\x00')
|
||||
else:
|
||||
value = ''
|
||||
return (position, key, value, len(value))
|
||||
|
||||
def read(self):
|
||||
data = [self.store_read_item(i) for i in range(self.cache_slots)]
|
||||
self.cache_store.seek(0)
|
||||
self.update_stats(data)
|
||||
if self.sample_sleep:
|
||||
time.sleep(self.sample_sleep)
|
||||
return data
|
||||
|
||||
def update_stats(self, data):
|
||||
# data is a list of (position, key, value, len(value)) tuples
|
||||
items = len([1 for x in data if x[3] > 0])
|
||||
self.cache_items += items
|
||||
full, empty = items == self.cache_slots, items == 0
|
||||
if full:
|
||||
self.cache_full += 1
|
||||
if empty:
|
||||
self.cache_empty += 1
|
||||
self.samples += 1
|
||||
block_sizes = sum([x[3] for x in data])
|
||||
self.block_sizes += block_sizes
|
||||
self.history.append({'full': full, 'empty': empty, 'data': data, \
|
||||
'items': items, 'block_sizes': block_sizes})
|
||||
|
||||
def dump(self):
|
||||
return {
|
||||
'samples': self.samples,
|
||||
'history': self.history,
|
||||
'cache_slots': self.cache_slots,
|
||||
'sample_sleep': self.sample_sleep,
|
||||
'cache_empty': self.cache_empty,
|
||||
'cache_full': self.cache_full,
|
||||
'cache_items': self.cache_items,
|
||||
'block_sizes': self.block_sizes,
|
||||
}
|
||||
|
||||
def show_dump(self):
|
||||
d = self.dump()
|
||||
print
|
||||
print "Recorded %d samples (%d second(s) sleep between samples)" % \
|
||||
(d['samples'], d['sample_sleep'])
|
||||
print "Cache empty %d times, full %d times, %.2f items on average" % \
|
||||
(d['cache_empty'], d['cache_full'], d['cache_items'] / d['samples'])
|
||||
print "Block size average size: %d bytes" % \
|
||||
(d['block_sizes'] / d['cache_items'] * 8)
|
||||
print "Data in cache average: %d bytes" % \
|
||||
(d['block_sizes'] / d['samples'] * 8)
|
||||
|
||||
def main(options):
|
||||
cache = Cache(options.cache_store, options.cache_slots, options.block_size,
|
||||
options.sleep_time)
|
||||
print "Recording..."
|
||||
while True:
|
||||
try:
|
||||
data = cache.read()
|
||||
except KeyboardInterrupt:
|
||||
cache.show_dump()
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = OptionParser()
|
||||
parser.add_option("-s", "--cache-slots", dest="cache_slots", type="int",
|
||||
help="Slots available in the cache, uwsgi cache option")
|
||||
parser.add_option("-c", "--cache-store", dest="cache_store", default="uwsgi.cache",
|
||||
help="The filename of the cache store, uwsgi cache-store option. Default: uwsgi.cache")
|
||||
parser.add_option("-b", "--block-size", dest="block_size", default=65536, type="int",
|
||||
help="The size of the cache block, uwsgi cache-blocksize option. Default: 65536")
|
||||
parser.add_option("-t", "--sleep-time", dest="sleep_time", default=1, type="int",
|
||||
help="The time to sleep between each sample. Default: 1")
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
if not options.cache_slots:
|
||||
parser.error('Option -s / --cache-slots is mandatory')
|
||||
main(options)
|
||||
@@ -0,0 +1,14 @@
|
||||
service uwsgi
|
||||
{
|
||||
disable = no
|
||||
id = uwsgi-000
|
||||
type = UNLISTED
|
||||
socket_type = stream
|
||||
server = /root/uwsgi/uwsgi
|
||||
server_args = --chdir /root/uwsgi/ --module welcome --logto /tmp/uwsgi.log
|
||||
port = 3031
|
||||
bind = 127.0.0.1
|
||||
user = root
|
||||
wait = yes
|
||||
}
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
#!./uwsgi --import decoratortest -s :3035 -M --spooler myspool --enable-threads -p 8 --spooler-ordered
|
||||
import uwsgi
|
||||
|
||||
from uwsgidecorators import *
|
||||
|
||||
from uwsgicc import app as application
|
||||
|
||||
import time
|
||||
|
||||
|
||||
# register rpc function helloworld
|
||||
@rpc("helloworld")
|
||||
def hello2():
|
||||
return "[RPC] Hello World"
|
||||
|
||||
# register signal 1
|
||||
@signal(1)
|
||||
def what_time_is_it(num):
|
||||
print(time.asctime())
|
||||
|
||||
# register signal 100
|
||||
@signal(100, target='workers')
|
||||
def what_time_is_it(num):
|
||||
print("*** I AM THE WORKER %d AT %s ***" % (uwsgi.worker_id(), time.asctime()))
|
||||
|
||||
|
||||
# a 3 seconds timer
|
||||
@timer(3)
|
||||
def salut(num):
|
||||
print("Salut !!! 3 seconds elapsed and signal %d raised" % num)
|
||||
|
||||
# a 10 seconds red black timer (executed by the spooler)
|
||||
@rbtimer(10, target='spooler')
|
||||
def tenseconds(num):
|
||||
print("red black timer !!! 10 seconds elapsed and signal %d raised" % num)
|
||||
|
||||
# monitor /tmp directory
|
||||
@filemon("/tmp")
|
||||
def tmpmodified(num):
|
||||
print("/tmp has been modified")
|
||||
|
||||
|
||||
# spool a long running task
|
||||
@spool
|
||||
def a_long_task(args):
|
||||
for i in xrange(1,10):
|
||||
print("%s = %d" % ( str(args), i))
|
||||
print(uwsgi.call('helloworld'))
|
||||
time.sleep(1)
|
||||
|
||||
# continuosly spool a long running task
|
||||
@spoolforever
|
||||
def an_infinite_task(args):
|
||||
for i in xrange(1,4):
|
||||
print("infinite: %d %s" % (i, str(args)))
|
||||
print(uwsgi.call('helloworld'))
|
||||
uwsgi.signal(100)
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
# spool a task after 5 seconds
|
||||
@spool
|
||||
def delayed_task(args):
|
||||
print("*** I am a delayed spool job. It is %s [%s]***" % (time.asctime(), str(args)))
|
||||
# send a signal to all workers
|
||||
uwsgi.signal(100)
|
||||
|
||||
@spool
|
||||
def big_body_task(args):
|
||||
print("*** managing a task with a body of %d bytes ***" % len(args['body']))
|
||||
print(args['body'].swapcase())
|
||||
|
||||
# run a task every hour
|
||||
@cron(59, -1, -1, -1, -1)
|
||||
def one_hour_passed(num):
|
||||
print("received signal %d after 1 hour" % num)
|
||||
|
||||
@thread
|
||||
def a_running_thread():
|
||||
while True:
|
||||
time.sleep(2)
|
||||
print("i am a no-args thread")
|
||||
|
||||
@thread
|
||||
def a_running_thread_with_args(who):
|
||||
while True:
|
||||
time.sleep(2)
|
||||
print("Hello %s (from arged-thread)" % who)
|
||||
|
||||
@postfork
|
||||
@thread
|
||||
def a_post_fork_thread():
|
||||
while True:
|
||||
time.sleep(3)
|
||||
if uwsgi.i_am_the_spooler():
|
||||
print("Hello from a thread in the spooler")
|
||||
else:
|
||||
print("Hello from a thread in worker %d" % uwsgi.worker_id())
|
||||
|
||||
@postfork
|
||||
def fork_happened():
|
||||
print("fork() has been called [1]")
|
||||
|
||||
@postfork
|
||||
def fork_happened2():
|
||||
if uwsgi.i_am_the_spooler():
|
||||
return
|
||||
print("worker %d is waiting for signal 100..." % uwsgi.worker_id())
|
||||
uwsgi.signal_wait(100)
|
||||
print("worker %d received signal %d" % (uwsgi.worker_id(), uwsgi.signal_received()))
|
||||
print("fork() has been called [2] wid: %d" % uwsgi.worker_id())
|
||||
|
||||
@postfork
|
||||
@lock
|
||||
def locked_func():
|
||||
print("starting locked function on worker %d" % uwsgi.worker_id())
|
||||
for i in xrange(1, 5):
|
||||
time.sleep(1)
|
||||
print("[locked %d] waiting..." % uwsgi.worker_id())
|
||||
print("done with locked function on worker %d" % uwsgi.worker_id())
|
||||
|
||||
print(uwsgi.call('helloworld'))
|
||||
spool_filename = a_long_task.spool({'foo':'bar'}, hello='world')
|
||||
print("spool filename = %s" % spool_filename)
|
||||
an_infinite_task.spool(foo='bar', priority=3)
|
||||
when = int(time.time())+5
|
||||
print("scheduling a delayed task at %d" % when)
|
||||
delayed_task.spool(foo2='bar2', at=when)
|
||||
a_running_thread()
|
||||
a_running_thread_with_args("uWSGI")
|
||||
uwsgi_source_file = open('uwsgi.c','r')
|
||||
print(big_body_task.spool(priority=9,filename='uwsgi.c',body=uwsgi_source_file.read()))
|
||||
uwsgi_source_file.close()
|
||||
@@ -14,10 +14,11 @@ def index(request):
|
||||
w['load'] = (100 * (w['running_time']/1000))/total_load
|
||||
w['last_spawn_str'] = time.ctime(w['last_spawn'])
|
||||
|
||||
spooler_jobs = uwsgi.spooler_jobs()
|
||||
jobs = []
|
||||
for j in spooler_jobs:
|
||||
jobs.append({'file': j, 'env': uwsgi.parsefile(j)})
|
||||
if 'spooler' in uwsgi.opt:
|
||||
spooler_jobs = uwsgi.spooler_jobs()
|
||||
for j in spooler_jobs:
|
||||
jobs.append({'file': j, 'env': uwsgi.parsefile(j)})
|
||||
|
||||
return render_to_response('uwsgi.html', {'masterpid': uwsgi.masterpid(),
|
||||
'started_on': time.ctime(uwsgi.started_on),
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
from django.template.base import TemplateDoesNotExist
|
||||
from django.template.loader import BaseLoader
|
||||
from django.conf import settings
|
||||
|
||||
try:
|
||||
import uwsgi
|
||||
on_uwsgi = True
|
||||
except:
|
||||
on_uwsgi = False
|
||||
|
||||
|
||||
|
||||
|
||||
class Loader(BaseLoader):
|
||||
|
||||
is_usable = on_uwsgi
|
||||
|
||||
def symbolize(self, name):
|
||||
return name.replace('.','_').replace('/','_').replace('-','_')
|
||||
|
||||
def load_template_source(self, template_name, template_dirs=None):
|
||||
filename = 'templates_' + self.symbolize(template_name)
|
||||
for app in settings.INSTALLED_APPS:
|
||||
try:
|
||||
symbol = "%s_%s" % (self.symbolize(app), filename)
|
||||
return (uwsgi.embedded_data(symbol), "sym://%s" % symbol)
|
||||
except:
|
||||
pass
|
||||
raise TemplateDoesNotExist(template_name)
|
||||
@@ -6,37 +6,76 @@ extern struct uwsgi_server uwsgi;
|
||||
extern char **environ;
|
||||
|
||||
int emperor_queue;
|
||||
char *emperor_absolute_dir;
|
||||
|
||||
void emperor_send_stats(int);
|
||||
|
||||
struct uwsgi_instance {
|
||||
struct uwsgi_instance *ui_prev;
|
||||
struct uwsgi_instance *ui_next;
|
||||
|
||||
char name[0xff];
|
||||
pid_t pid;
|
||||
|
||||
int status;
|
||||
time_t born;
|
||||
time_t last_mod;
|
||||
time_t last_loyal;
|
||||
|
||||
uint64_t respawns;
|
||||
int use_config;
|
||||
|
||||
int pipe[2];
|
||||
int pipe_config[2];
|
||||
|
||||
char *config;
|
||||
uint32_t config_len;
|
||||
|
||||
int loyal;
|
||||
|
||||
int zerg;
|
||||
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
};
|
||||
|
||||
|
||||
struct uwsgi_instance *ui;
|
||||
|
||||
static void royal_death(int signum) {
|
||||
|
||||
|
||||
if (uwsgi.vassals_stop_hook) {
|
||||
|
||||
struct uwsgi_instance *c_ui = ui->ui_next;
|
||||
|
||||
while (c_ui) {
|
||||
uwsgi_log("running vassal stop-hook: %s %s\n", uwsgi.vassals_stop_hook, c_ui->name);
|
||||
if (setenv("UWSGI_VASSALS_DIR", emperor_absolute_dir, 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
int stop_hook_ret = uwsgi_run_command_and_wait(uwsgi.vassals_stop_hook, c_ui->name);
|
||||
uwsgi_log("%s stop-hook returned %d\n", c_ui->name, stop_hook_ret);
|
||||
c_ui = c_ui->ui_next;
|
||||
}
|
||||
}
|
||||
uwsgi_notify("The Emperor is buried.");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
struct uwsgi_instance {
|
||||
struct uwsgi_instance *ui_prev;
|
||||
struct uwsgi_instance *ui_next;
|
||||
|
||||
char name[0xff];
|
||||
pid_t pid;
|
||||
void emperor_stats() {
|
||||
|
||||
int status;
|
||||
time_t born;
|
||||
time_t last_mod;
|
||||
time_t last_loyal;
|
||||
struct uwsgi_instance *c_ui = ui->ui_next;
|
||||
|
||||
uint64_t respawns;
|
||||
int use_config;
|
||||
while (c_ui) {
|
||||
|
||||
int pipe[2];
|
||||
int pipe_config[2];
|
||||
uwsgi_log("vassal instance %s (last modified %d) status %d loyal %d zerg %d\n",c_ui->name, c_ui->last_mod, c_ui->status, c_ui->loyal, c_ui->zerg);
|
||||
|
||||
char *config;
|
||||
uint32_t config_len;
|
||||
c_ui = c_ui->ui_next;
|
||||
}
|
||||
|
||||
int loyal;
|
||||
};
|
||||
|
||||
struct uwsgi_instance *ui;
|
||||
}
|
||||
|
||||
struct uwsgi_instance *emperor_get_by_fd(int fd) {
|
||||
|
||||
@@ -84,8 +123,21 @@ void emperor_del(struct uwsgi_instance *c_ui) {
|
||||
close(c_ui->pipe_config[0]);
|
||||
}
|
||||
|
||||
if (uwsgi.vassals_stop_hook) {
|
||||
uwsgi_log("running vassal stop-hook: %s %s\n", uwsgi.vassals_stop_hook, c_ui->name);
|
||||
if (setenv("UWSGI_VASSALS_DIR", emperor_absolute_dir, 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
int stop_hook_ret = uwsgi_run_command_and_wait(uwsgi.vassals_stop_hook, c_ui->name);
|
||||
uwsgi_log("%s stop-hook returned %d\n", c_ui->name, stop_hook_ret);
|
||||
}
|
||||
|
||||
uwsgi_log("removed uwsgi instance %s\n", c_ui->name);
|
||||
|
||||
if (c_ui->zerg) {
|
||||
uwsgi.emperor_broodlord_count--;
|
||||
}
|
||||
|
||||
free(c_ui);
|
||||
|
||||
}
|
||||
@@ -119,20 +171,29 @@ void emperor_respawn(struct uwsgi_instance *c_ui, time_t mod) {
|
||||
c_ui->respawns++;
|
||||
c_ui->last_mod = mod;
|
||||
|
||||
uwsgi_log("reload the uwsgi instance %s\n", c_ui->name);
|
||||
uwsgi_log("[emperor] reload the uwsgi instance %s\n", c_ui->name);
|
||||
}
|
||||
|
||||
void emperor_add(char *name, time_t born, char *config, uint32_t config_size) {
|
||||
void emperor_add(char *name, time_t born, char *config, uint32_t config_size, uid_t uid, gid_t gid) {
|
||||
|
||||
struct uwsgi_instance *c_ui = ui;
|
||||
struct uwsgi_instance *n_ui = NULL;
|
||||
pid_t pid;
|
||||
char **argv;
|
||||
char **vassal_argv;
|
||||
char *uef;
|
||||
char **uenvs;
|
||||
int counter;
|
||||
char *colon = NULL;
|
||||
int i;
|
||||
|
||||
sleep(1);
|
||||
usleep(uwsgi.emperor_throttle*1000);
|
||||
|
||||
if (uwsgi.emperor_tyrant) {
|
||||
if (uid == 0 || gid == 0) {
|
||||
uwsgi_log("[emperor-tyrant] invalid permissions for file %s\n", name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (c_ui->ui_next) {
|
||||
c_ui = c_ui->ui_next;
|
||||
@@ -152,8 +213,16 @@ void emperor_add(char *name, time_t born, char *config, uint32_t config_size) {
|
||||
uwsgi_log("c_ui->ui_next = %p\n", c_ui->ui_next);
|
||||
#endif
|
||||
n_ui->ui_prev = c_ui;
|
||||
|
||||
if (strchr(name,':')) {
|
||||
n_ui->zerg = 1;
|
||||
uwsgi.emperor_broodlord_count++;
|
||||
}
|
||||
|
||||
memcpy(n_ui->name, name, strlen(name));
|
||||
n_ui->born = born;
|
||||
n_ui->uid = uid;
|
||||
n_ui->gid = gid;
|
||||
n_ui->last_mod = born;
|
||||
// start without loyalty
|
||||
n_ui->last_loyal = born;
|
||||
@@ -198,6 +267,24 @@ void emperor_add(char *name, time_t born, char *config, uint32_t config_size) {
|
||||
}
|
||||
else {
|
||||
|
||||
if (uwsgi.emperor_tyrant) {
|
||||
uwsgi_log("[emperor-tyrant] dropping privileges to %d %d for instance %s\n", (int) uid, (int) gid, name);
|
||||
if (setgid(gid)) {
|
||||
uwsgi_error("setgid()");
|
||||
exit(1);
|
||||
}
|
||||
if (setgroups(0, NULL)) {
|
||||
uwsgi_error("setgroups()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (setuid(uid)) {
|
||||
uwsgi_error("setuid()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
unsetenv("UWSGI_RELOADS");
|
||||
unsetenv("NOTIFY_SOCKET");
|
||||
|
||||
@@ -227,7 +314,9 @@ void emperor_add(char *name, time_t born, char *config, uint32_t config_size) {
|
||||
break;
|
||||
}
|
||||
free(oe);
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("putenv %s\n", ne);
|
||||
#endif
|
||||
|
||||
if (putenv(ne)) {
|
||||
uwsgi_error("putenv()");
|
||||
@@ -253,31 +342,61 @@ void emperor_add(char *name, time_t born, char *config, uint32_t config_size) {
|
||||
uct = uct->next;
|
||||
}
|
||||
|
||||
argv = uwsgi_malloc(sizeof(char *) * counter);
|
||||
vassal_argv = uwsgi_malloc(sizeof(char *) * counter);
|
||||
// set args
|
||||
argv[0] = uwsgi.binary_path;
|
||||
vassal_argv[0] = uwsgi.binary_path;
|
||||
|
||||
if (uwsgi.emperor_broodlord) {
|
||||
colon = strchr(name, ':');
|
||||
if (colon) {
|
||||
colon[0] = 0;
|
||||
}
|
||||
}
|
||||
if (!strcmp(name + (strlen(name) - 4), ".xml"))
|
||||
argv[1] = "--xml";
|
||||
vassal_argv[1] = "--xml";
|
||||
if (!strcmp(name + (strlen(name) - 4), ".ini"))
|
||||
argv[1] = "--ini";
|
||||
vassal_argv[1] = "--ini";
|
||||
if (!strcmp(name + (strlen(name) - 4), ".yml"))
|
||||
argv[1] = "--yaml";
|
||||
vassal_argv[1] = "--yaml";
|
||||
if (!strcmp(name + (strlen(name) - 5), ".yaml"))
|
||||
argv[1] = "--yaml";
|
||||
vassal_argv[1] = "--yaml";
|
||||
if (!strcmp(name + (strlen(name) - 3), ".js"))
|
||||
argv[1] = "--json";
|
||||
argv[2] = name;
|
||||
vassal_argv[1] = "--json";
|
||||
if (!strcmp(name + (strlen(name) - 5), ".json"))
|
||||
vassal_argv[1] = "--json";
|
||||
|
||||
if (colon) {
|
||||
colon[0] = ':';
|
||||
}
|
||||
vassal_argv[2] = name;
|
||||
counter = 3;
|
||||
uct = uwsgi.vassals_templates;
|
||||
while(uct) {
|
||||
argv[counter] = "--inherit";
|
||||
argv[counter+1] = uct->filename;
|
||||
vassal_argv[counter] = "--inherit";
|
||||
vassal_argv[counter+1] = uct->filename;
|
||||
counter+=2;
|
||||
uct = uct->next;
|
||||
}
|
||||
argv[counter] = NULL;
|
||||
vassal_argv[counter] = NULL;
|
||||
|
||||
// close all of the unneded fd
|
||||
for(i=3;i<sysconf(_SC_OPEN_MAX);i++) {
|
||||
if (i != n_ui->pipe[1]) {
|
||||
close(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.vassals_start_hook) {
|
||||
uwsgi_log("running vassal start-hook: %s %s\n", uwsgi.vassals_start_hook, n_ui->name);
|
||||
if (setenv("UWSGI_VASSALS_DIR", emperor_absolute_dir, 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
int start_hook_ret = uwsgi_run_command_and_wait(uwsgi.vassals_start_hook, n_ui->name);
|
||||
uwsgi_log("%s start-hook returned %d\n", n_ui->name, start_hook_ret);
|
||||
}
|
||||
|
||||
// start !!!
|
||||
if (execvp(argv[0], argv)) {
|
||||
if (execvp(vassal_argv[0], vassal_argv)) {
|
||||
uwsgi_error("execvp()");
|
||||
}
|
||||
uwsgi_log("is the uwsgi binary in your system PATH ?\n");
|
||||
@@ -317,9 +436,13 @@ void emperor_loop() {
|
||||
int interesting_fd;
|
||||
char notification_message[64];
|
||||
|
||||
uwsgi.emperor_stats_fd = -1;
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
uwsgi_unix_signal(SIGINT, royal_death);
|
||||
uwsgi_unix_signal(SIGTERM, royal_death);
|
||||
uwsgi_unix_signal(SIGQUIT, royal_death);
|
||||
uwsgi_unix_signal(SIGUSR1, emperor_stats);
|
||||
|
||||
memset(&ui_base, 0, sizeof(struct uwsgi_instance));
|
||||
|
||||
@@ -335,6 +458,23 @@ void emperor_loop() {
|
||||
uwsgi_log("*** starting uWSGI Emperor ***\n");
|
||||
}
|
||||
|
||||
if (uwsgi.emperor_stats) {
|
||||
char *tcp_port = strchr(uwsgi.emperor_stats, ':');
|
||||
if (tcp_port) {
|
||||
// disable deferred accept for this socket
|
||||
int current_defer_accept = uwsgi.no_defer_accept;
|
||||
uwsgi.no_defer_accept = 1;
|
||||
uwsgi.emperor_stats_fd = bind_to_tcp(uwsgi.emperor_stats, uwsgi.listen_queue, tcp_port);
|
||||
uwsgi.no_defer_accept = current_defer_accept;
|
||||
}
|
||||
else {
|
||||
uwsgi.emperor_stats_fd = bind_to_unix(uwsgi.emperor_stats, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
|
||||
}
|
||||
|
||||
event_queue_add_fd_read(emperor_queue, uwsgi.emperor_stats_fd);
|
||||
uwsgi_log("*** Emperor stats server enabled on %s fd: %d ***\n", uwsgi.emperor_stats, uwsgi.emperor_stats_fd);
|
||||
}
|
||||
|
||||
amqp_port = strchr(uwsgi.emperor_dir, ':');
|
||||
|
||||
if (amqp_port) {
|
||||
@@ -374,6 +514,8 @@ reconnect:
|
||||
uwsgi_error("glob()");
|
||||
exit(1);
|
||||
}
|
||||
globfree(&g);
|
||||
emperor_absolute_dir = realpath(".", NULL);
|
||||
}
|
||||
|
||||
ui = &ui_base;
|
||||
@@ -422,6 +564,7 @@ reconnect:
|
||||
ui_current->config = config;
|
||||
ui_current->config_len = msgsize;
|
||||
if (!msgsize) {
|
||||
// SAFE
|
||||
emperor_del(ui_current);
|
||||
}
|
||||
else {
|
||||
@@ -430,7 +573,7 @@ reconnect:
|
||||
}
|
||||
else {
|
||||
if (msgsize > 0) {
|
||||
emperor_add(config_file, time(NULL), config, msgsize);
|
||||
emperor_add(config_file, time(NULL), config, msgsize, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,19 +610,23 @@ reconnect:
|
||||
emperor_respawn(ui_current, time(NULL));
|
||||
}
|
||||
else {
|
||||
emperor_add(config_file, time(NULL), NULL, 0);
|
||||
emperor_add(config_file, time(NULL), NULL, 0, 0, 0);
|
||||
}
|
||||
|
||||
free(config_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (uwsgi.emperor_stats && uwsgi.emperor_stats_fd > -1 && interesting_fd == uwsgi.emperor_stats_fd) {
|
||||
emperor_send_stats(uwsgi.emperor_stats_fd);
|
||||
}
|
||||
else {
|
||||
ui_current = emperor_get_by_fd(interesting_fd);
|
||||
if (ui_current) {
|
||||
char byte;
|
||||
ssize_t rlen = read(interesting_fd, &byte, 1);
|
||||
if (rlen <= 0) {
|
||||
// SAFE
|
||||
emperor_del(ui_current);
|
||||
}
|
||||
else {
|
||||
@@ -489,10 +636,19 @@ reconnect:
|
||||
|
||||
// TODO post-start hook
|
||||
}
|
||||
else if (byte == 22) {
|
||||
emperor_stop(ui_current);
|
||||
}
|
||||
else if (byte == 30 && uwsgi.emperor_broodlord > 0 && uwsgi.emperor_broodlord_count < uwsgi.emperor_broodlord) {
|
||||
uwsgi_log("[emperor] going in broodlord mode: launching zergs for %s\n", ui_current->name);
|
||||
char *zerg_name = uwsgi_concat3(ui_current->name,":","zerg");
|
||||
emperor_add(zerg_name, time(NULL), NULL, 0, ui_current->uid, ui_current->gid);
|
||||
free(zerg_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log("unrecognized event on fd %d\n", interesting_fd);
|
||||
uwsgi_log("[emperor] unrecognized vassal event on fd %d\n", interesting_fd);
|
||||
event_queue_del_fd(emperor_queue, interesting_fd, event_queue_read());
|
||||
close(interesting_fd);
|
||||
}
|
||||
@@ -507,7 +663,8 @@ reconnect:
|
||||
!strcmp(de->d_name + (strlen(de->d_name) - 4), ".ini") ||
|
||||
!strcmp(de->d_name + (strlen(de->d_name) - 4), ".yml") ||
|
||||
!strcmp(de->d_name + (strlen(de->d_name) - 5), ".yaml") ||
|
||||
!strcmp(de->d_name + (strlen(de->d_name) - 3), ".js")
|
||||
!strcmp(de->d_name + (strlen(de->d_name) - 3), ".js") ||
|
||||
!strcmp(de->d_name + (strlen(de->d_name) - 5), ".json")
|
||||
) {
|
||||
|
||||
|
||||
@@ -523,13 +680,21 @@ reconnect:
|
||||
ui_current = emperor_get(de->d_name);
|
||||
|
||||
if (ui_current) {
|
||||
// check if uid or gid are changed, in such case, sotp the instance
|
||||
if (uwsgi.emperor_tyrant) {
|
||||
if (st.st_uid != ui_current->uid || st.st_gid != ui_current->gid) {
|
||||
uwsgi_log("!!! permissions of file %s changed. stopping the instance... !!!\n");
|
||||
emperor_stop(ui_current);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// check if mtime is changed and the uWSGI instance must be reloaded
|
||||
if (st.st_mtime > ui_current->last_mod) {
|
||||
emperor_respawn(ui_current, st.st_mtime);
|
||||
}
|
||||
}
|
||||
else {
|
||||
emperor_add(de->d_name, st.st_mtime, NULL, 0);
|
||||
emperor_add(de->d_name, st.st_mtime, NULL, 0, st.st_uid, st.st_gid);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -546,6 +711,7 @@ reconnect:
|
||||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 4), ".ini") ||
|
||||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 4), ".yml") ||
|
||||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 3), ".js") ||
|
||||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 5), ".json") ||
|
||||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 5), ".yaml")
|
||||
) {
|
||||
|
||||
@@ -562,17 +728,26 @@ reconnect:
|
||||
ui_current = emperor_get(g.gl_pathv[i]);
|
||||
|
||||
if (ui_current) {
|
||||
// check if uid or gid are changed, in such case, sotp the instance
|
||||
if (uwsgi.emperor_tyrant) {
|
||||
if (st.st_uid != ui_current->uid || st.st_gid != ui_current->gid) {
|
||||
uwsgi_log("!!! permissions of file %s changed. stopping the instance... !!!\n");
|
||||
emperor_stop(ui_current);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// check if mtime is changed and the uWSGI instance must be reloaded
|
||||
if (st.st_mtime > ui_current->last_mod) {
|
||||
emperor_respawn(ui_current, st.st_mtime);
|
||||
}
|
||||
}
|
||||
else {
|
||||
emperor_add(g.gl_pathv[i], st.st_mtime, NULL, 0);
|
||||
emperor_add(g.gl_pathv[i], st.st_mtime, NULL, 0, st.st_uid, st.st_gid);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
globfree(&g);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -609,26 +784,30 @@ reconnect:
|
||||
if (amqp_fd > -1) {
|
||||
if (!ui_current->loyal && (time(NULL)-ui_current->last_loyal) > 60) {
|
||||
uwsgi_log("!!! no loyalty showed by instance %s !!!\n", ui_current->name);
|
||||
// SAFE
|
||||
emperor_del(ui_current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ui_current->status == 1) {
|
||||
if (ui_current->config) free(ui_current->config);
|
||||
// SAFE
|
||||
emperor_del(ui_current);
|
||||
break;
|
||||
}
|
||||
else if (!ui_current->use_config && strncmp(ui_current->name, "http://",7) && stat(ui_current->name, &st)) {
|
||||
else if (!ui_current->use_config && strncmp(ui_current->name, "http://",7) && stat(ui_current->name, &st) && !ui_current->zerg) {
|
||||
emperor_stop(ui_current);
|
||||
}
|
||||
else if (ui_current->pid == diedpid) {
|
||||
if (ui_current->status == 0) {
|
||||
// respawn an accidentally dead instance if its exit code is not UWSGI_EXILE_CODE
|
||||
if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_EXILE_CODE) {
|
||||
// SAFE
|
||||
emperor_del(ui_current);
|
||||
}
|
||||
else {
|
||||
emperor_add(ui_current->name, ui_current->last_mod, ui_current->config, ui_current->config_len);
|
||||
// UNSAFE
|
||||
emperor_add(ui_current->name, ui_current->last_mod, ui_current->config, ui_current->config_len, ui_current->uid, ui_current->gid);
|
||||
emperor_del(ui_current);
|
||||
}
|
||||
break;
|
||||
@@ -636,6 +815,7 @@ reconnect:
|
||||
else if (ui_current->status == 1) {
|
||||
// remove 'marked for dead' instance
|
||||
if (ui_current->config) free(ui_current->config);
|
||||
// SAFE
|
||||
emperor_del(ui_current);
|
||||
break;
|
||||
}
|
||||
@@ -646,3 +826,73 @@ reconnect:
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define stats_send_llu(x, y) fprintf(output, x, (long long unsigned int) y)
|
||||
#define stats_send(x, y) fprintf(output, x, y)
|
||||
|
||||
void emperor_send_stats(int fd) {
|
||||
|
||||
struct sockaddr_un client_src;
|
||||
socklen_t client_src_len = 0;
|
||||
int client_fd = accept(fd, (struct sockaddr *) &client_src, &client_src_len);
|
||||
if (client_fd < 0) {
|
||||
uwsgi_error("accept()");
|
||||
return;
|
||||
}
|
||||
|
||||
FILE *output = fdopen(client_fd, "w");
|
||||
if (!output) {
|
||||
uwsgi_error("fdopen()");
|
||||
close(client_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
stats_send("{ \"version\": \"%s\",\n", UWSGI_VERSION);
|
||||
|
||||
fprintf(output,"\"pid\": %d,\n", (int)(getpid()));
|
||||
fprintf(output,"\"uid\": %d,\n", (int)(getuid()));
|
||||
fprintf(output,"\"gid\": %d,\n", (int)(getgid()));
|
||||
|
||||
char *cwd = uwsgi_get_cwd();
|
||||
stats_send("\"cwd\": \"%s\",\n", cwd);
|
||||
free(cwd);
|
||||
|
||||
stats_send("\"emperor\": \"%s\",\n", uwsgi.emperor_dir);
|
||||
|
||||
fprintf(output,"\"emperor_tyrant\": %d,\n", uwsgi.emperor_tyrant);
|
||||
|
||||
|
||||
fprintf(output, "\"vassals\": [\n");
|
||||
|
||||
struct uwsgi_instance *c_ui = ui->ui_next;
|
||||
|
||||
while (c_ui) {
|
||||
fprintf(output,"\t{");
|
||||
stats_send("\"id\": \"%s\", ", c_ui->name);
|
||||
fprintf(output,"\"pid\": %d, ", (int) c_ui->pid);
|
||||
|
||||
stats_send_llu( "\"born\": %llu, ", c_ui->born);
|
||||
stats_send_llu( "\"last_mod\": %llu, ", c_ui->last_mod);
|
||||
|
||||
fprintf(output,"\"loyal\": %d, ", c_ui->loyal);
|
||||
fprintf(output,"\"zerg\": %d, ", c_ui->zerg);
|
||||
|
||||
fprintf(output,"\"uid\": %d, ", (int)c_ui->uid);
|
||||
fprintf(output,"\"gid\": %d, ", (int)c_ui->gid);
|
||||
|
||||
stats_send_llu( "\"respawns\": %llu ", c_ui->respawns);
|
||||
c_ui = c_ui->ui_next;
|
||||
|
||||
if (c_ui) {
|
||||
fprintf(output,"},\n");
|
||||
}
|
||||
else {
|
||||
fprintf(output,"}\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fprintf(output,"]}\n");
|
||||
fclose(output);
|
||||
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ void *event_queue_alloc(int 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 (long) pe[id].portev_user;
|
||||
}
|
||||
|
||||
return (int) pe[id].portev_object;
|
||||
@@ -149,7 +149,7 @@ int event_queue_wait(int eq, int timeout, int *interesting_fd) {
|
||||
|
||||
|
||||
if (pe.portev_source == PORT_SOURCE_FILE || pe.portev_source == PORT_SOURCE_TIMER) {
|
||||
*interesting_fd = (int) pe.portev_user;
|
||||
*interesting_fd = (long) pe.portev_user;
|
||||
}
|
||||
else {
|
||||
*interesting_fd = (int) pe.portev_object;
|
||||
@@ -327,11 +327,13 @@ int event_queue_fd_write_to_read(int eq, int fd) {
|
||||
|
||||
struct kevent kev;
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
|
||||
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
@@ -476,7 +478,7 @@ int event_queue_add_file_monitor(int eq, char *filename, int *id) {
|
||||
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)) {
|
||||
if (port_associate(eq, PORT_SOURCE_FILE, (uintptr_t) &fo, FILE_MODIFIED|FILE_ATTRIB, (void *) (long) fmon_id)) {
|
||||
uwsgi_error("port_associate()");
|
||||
return -1;
|
||||
}
|
||||
@@ -506,7 +508,7 @@ struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
|
||||
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)) {
|
||||
if (port_associate(eq, PORT_SOURCE_FILE, (uintptr_t) &fo, FILE_MODIFIED|FILE_ATTRIB, (void *)(long)id)) {
|
||||
uwsgi_error("port_associate()");
|
||||
return NULL;
|
||||
}
|
||||
@@ -565,6 +567,16 @@ struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_EVENT_FILEMONITOR_USE_INOTIFY
|
||||
|
||||
|
||||
#ifdef OBSOLETE_LINUX_KERNEL
|
||||
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;
|
||||
}
|
||||
#else
|
||||
#include <sys/inotify.h>
|
||||
|
||||
int event_queue_add_file_monitor(int eq, char *filename, int *id) {
|
||||
@@ -591,7 +603,9 @@ int event_queue_add_file_monitor(int eq, char *filename, int *id) {
|
||||
|
||||
*id = inotify_add_watch(ifd, filename, IN_ATTRIB|IN_CREATE|IN_DELETE|IN_DELETE_SELF|IN_MODIFY|IN_MOVE_SELF|IN_MOVED_FROM|IN_MOVED_TO);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("added watch %d for filename %s\n", *id, filename);
|
||||
#endif
|
||||
|
||||
if (add_to_queue) {
|
||||
return event_queue_add_fd_read(eq, ifd);
|
||||
@@ -630,7 +644,9 @@ struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
|
||||
}
|
||||
else {
|
||||
items = isize/(sizeof(struct inotify_event));
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("inotify returned %d items\n", items);
|
||||
#endif
|
||||
for(j=0;j<items;j++) {
|
||||
iie = &bie[j];
|
||||
for(i=0;i<ushared->files_monitored_cnt;i++) {
|
||||
@@ -653,6 +669,8 @@ struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_EVENT_TIMER_USE_TIMERFD
|
||||
@@ -683,13 +701,23 @@ enum
|
||||
|
||||
|
||||
static int timerfd_create (clockid_t __clock_id, int __flags) {
|
||||
#ifdef __amd64__
|
||||
return syscall(283, __clock_id, __flags);
|
||||
#elif defined(__i386__)
|
||||
return syscall(322, __clock_id, __flags);
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int timerfd_settime (int __ufd, int __flags,
|
||||
__const struct itimerspec *__utmr,
|
||||
struct itimerspec *__otmr) {
|
||||
#ifdef __amd64__
|
||||
return syscall(286, __ufd, __flags, __utmr, __otmr);
|
||||
#elif defined(__i386__)
|
||||
return syscall(325, __ufd, __flags, __utmr, __otmr);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -761,7 +789,7 @@ int event_queue_add_timer(int eq, int *id, int sec) {
|
||||
timer_id++;
|
||||
|
||||
pnotif.portnfy_port = eq;
|
||||
pnotif.portnfy_user = (void *) timer_id;
|
||||
pnotif.portnfy_user = (void *) (long) timer_id;
|
||||
|
||||
sigev.sigev_notify = SIGEV_PORT;
|
||||
sigev.sigev_value.sival_ptr = &pnotif;
|
||||
@@ -816,8 +844,6 @@ int event_queue_add_timer(int eq, int *id, int sec) {
|
||||
*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()");
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
use POSIX;
|
||||
|
||||
open CONFIG,'welcome.ini';
|
||||
|
||||
dup2(fileno(CONFIG), 17);
|
||||
|
||||
exec './uwsgi','--ini','fd://17';
|
||||
@@ -0,0 +1,12 @@
|
||||
from flask import Flask, request
|
||||
app = Flask(__name__)
|
||||
app.debug = True
|
||||
|
||||
@app.route('/')
|
||||
def hello_world():
|
||||
return "<form method='POST' enctype='multipart/form-data' action='/upload'><input type='text' name='pippo'/><input type='file' name='ufile'/><input type='submit' value='upload'/></form>"
|
||||
|
||||
@app.route('/upload', methods=['GET', 'POST'])
|
||||
def upload_file():
|
||||
return str(len(request.form.get('pippo', 'boh'))) + request.form.get('pippo', 'boh')
|
||||
return request.files['ufile'].read()
|
||||
@@ -47,7 +47,7 @@ struct uwsgi_gateway *register_gateway(char *name, void (*loop)(void)) {
|
||||
}
|
||||
}
|
||||
|
||||
gw_pid = fork();
|
||||
gw_pid = uwsgi_fork(name);
|
||||
if (gw_pid < 0) {
|
||||
uwsgi_error("fork()");
|
||||
return NULL;
|
||||
@@ -60,6 +60,11 @@ struct uwsgi_gateway *register_gateway(char *name, void (*loop)(void)) {
|
||||
uwsgi_error("prctl()");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!uwsgi.sockets) {
|
||||
// wait for child end
|
||||
//waitpid(-1, &i, 0);
|
||||
}
|
||||
loop();
|
||||
// never here !!! (i hope)
|
||||
exit(1);
|
||||
@@ -85,7 +90,7 @@ struct uwsgi_gateway *register_gateway(char *name, void (*loop)(void)) {
|
||||
ug->loop = loop;
|
||||
ug->num = num;
|
||||
|
||||
uwsgi_log( "spawned uWSGI %s %d (pid: %d)\n", ug->name, ug->num, (int) ug->pid);
|
||||
uwsgi_log( "spawned %s %d (pid: %d)\n", ug->name, ug->num, (int) ug->pid);
|
||||
|
||||
uwsgi.gateways_cnt++;
|
||||
|
||||
@@ -98,7 +103,7 @@ void gateway_respawn(int id) {
|
||||
pid_t gw_pid;
|
||||
struct uwsgi_gateway *ug = &uwsgi.gateways[id];
|
||||
|
||||
gw_pid = fork();
|
||||
gw_pid = uwsgi_fork(ug->name);
|
||||
if (gw_pid < 0) {
|
||||
uwsgi_error("fork()");
|
||||
return;
|
||||
@@ -117,6 +122,12 @@ void gateway_respawn(int id) {
|
||||
}
|
||||
|
||||
ug->pid = gw_pid;
|
||||
uwsgi_log( "respawned uWSGI %s %d (pid: %d)\n", ug->name, ug->num, (int) gw_pid);
|
||||
ug->respawns++;
|
||||
if (ug->respawns == 1) {
|
||||
uwsgi_log( "spawned %s %d (pid: %d)\n", ug->name, ug->num, (int) gw_pid);
|
||||
}
|
||||
else {
|
||||
uwsgi_log( "respawned %s %d (pid: %d)\n", ug->name, ug->num, (int) gw_pid);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import uwsgi
|
||||
#uwsgi.cache_set('/', "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\nHello World from cache")
|
||||
def application(env, start_response):
|
||||
start_response('200 OK', [('Content-Type', 'text/html')])
|
||||
yield str(env['wsgi.input'].fileno())
|
||||
yield "<h1>Hello World</h1>"
|
||||
@@ -67,6 +67,11 @@ char *ini_get_line(char *ini, off_t size) {
|
||||
}
|
||||
}
|
||||
|
||||
// check if it is a stupid file without \n at the end
|
||||
if (ptr > ini) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
@@ -87,7 +92,7 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
char *section_asked = "uwsgi";
|
||||
char *colon;
|
||||
|
||||
if (!uwsgi_startswith(file, "http://", 7)) {
|
||||
if (uwsgi_check_scheme(file)) {
|
||||
colon = uwsgi_get_last_char(file, '/');
|
||||
colon = uwsgi_get_last_char(colon, ':');
|
||||
}
|
||||
@@ -102,7 +107,9 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("[uWSGI] getting INI configuration from %s\n", file);
|
||||
if (file[0] != 0) {
|
||||
uwsgi_log("[uWSGI] getting INI configuration from %s\n", file);
|
||||
}
|
||||
|
||||
ini = uwsgi_open_and_read(file, &len, 1, magic_table);
|
||||
|
||||
@@ -143,6 +150,11 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
|
||||
}
|
||||
|
||||
if (colon) {
|
||||
colon[0] = ':';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>it.unbit.uwsgi.emperor</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/Users/roberta/uwsgi/uwsgi</string>
|
||||
<string>--emperor</string>
|
||||
<string>/Users/*/Library/uwsgi/*.{xml,ini,yml,yaml,js}</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>it.unbit.uwsgi</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/Users/roberta/uwsgi/uwsgi</string>
|
||||
<string>--socket</string>
|
||||
<string>:3032</string>
|
||||
<string>--module</string>
|
||||
<string>welcome</string>
|
||||
<string>--master</string>
|
||||
<string>--die-on-term</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -30,7 +30,7 @@ void uwsgi_json_config(char *file, char *magic_table[]) {
|
||||
char *colon;
|
||||
int i;
|
||||
|
||||
if (!uwsgi_startswith(file, "http://", 7)) {
|
||||
if (uwsgi_check_scheme(file)) {
|
||||
colon = uwsgi_get_last_char(file, '/');
|
||||
colon = uwsgi_get_last_char(colon, ':');
|
||||
}
|
||||
@@ -49,7 +49,11 @@ void uwsgi_json_config(char *file, char *magic_table[]) {
|
||||
|
||||
json_data = uwsgi_open_and_read(file, &len, 1, magic_table);
|
||||
|
||||
#ifdef JANSSON_MAJOR_VERSION
|
||||
root = json_loads(json_data, 0, &error);
|
||||
#else
|
||||
root = json_loads(json_data, &error);
|
||||
#endif
|
||||
|
||||
if (!root) {
|
||||
uwsgi_log("error parsing JSON data: line %d %s\n", error.line, error.text);
|
||||
@@ -73,10 +77,10 @@ void uwsgi_json_config(char *file, char *magic_table[]) {
|
||||
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);
|
||||
add_exported_option((char *)key, strdup("1"), 0);
|
||||
}
|
||||
else if (json_is_false(config_value) || json_is_null(config_value)) {
|
||||
add_exported_option((char *)key, (char *) "0", 0);
|
||||
add_exported_option((char *)key, strdup("0"), 0);
|
||||
}
|
||||
else if (json_is_integer(config_value)) {
|
||||
add_exported_option((char *)key, uwsgi_num2str(json_integer_value(config_value)), 0);
|
||||
@@ -88,10 +92,10 @@ void uwsgi_json_config(char *file, char *magic_table[]) {
|
||||
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);
|
||||
add_exported_option((char *)key, strdup("1"), 0);
|
||||
}
|
||||
else if (json_is_false(config_array_item) || json_is_null(config_array_item)) {
|
||||
add_exported_option((char *)key, (char *) "0", 0);
|
||||
add_exported_option((char *)key, strdup("0"), 0);
|
||||
}
|
||||
else if (json_is_integer(config_array_item)) {
|
||||
add_exported_option((char *)key, uwsgi_num2str(json_integer_value(config_array_item)), 0);
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
#include "../uwsgi.h"
|
||||
|
||||
#ifdef OBSOLETE_LINUX_KERNEL
|
||||
#ifndef __u16
|
||||
#define __u16 u_int16_t
|
||||
#endif
|
||||
#ifndef __u32
|
||||
#define __u32 u_int32_t
|
||||
#endif
|
||||
#ifndef __s32
|
||||
#define __s32 int32_t
|
||||
#endif
|
||||
#ifndef __u8
|
||||
#define __u8 u_int8_t
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/if.h>
|
||||
|
||||
+26
-1
@@ -19,12 +19,22 @@
|
||||
|
||||
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
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "../uwsgi.h"
|
||||
|
||||
static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
|
||||
{
|
||||
rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
|
||||
}
|
||||
static inline void rb_set_color(struct rb_node *rb, int color)
|
||||
{
|
||||
rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
|
||||
}
|
||||
|
||||
|
||||
static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
|
||||
{
|
||||
struct rb_node *right = node->rb_right;
|
||||
@@ -282,3 +292,18 @@ void rb_erase(struct rb_node *node, struct rb_root *root)
|
||||
if (color == RB_BLACK)
|
||||
__rb_erase_color(child, parent, root);
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
void rb_link_node(struct rb_node * node, struct rb_node * parent,
|
||||
struct rb_node ** rb_link)
|
||||
#else
|
||||
inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
|
||||
struct rb_node ** rb_link)
|
||||
#endif
|
||||
{
|
||||
node->rb_parent_color = (unsigned long )parent;
|
||||
node->rb_left = node->rb_right = NULL;
|
||||
|
||||
*rb_link = node;
|
||||
}
|
||||
|
||||
|
||||
+8
-20
@@ -18,7 +18,7 @@
|
||||
|
||||
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
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
@@ -37,7 +37,6 @@ struct rb_root
|
||||
struct rb_node *rb_node;
|
||||
};
|
||||
|
||||
|
||||
#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3))
|
||||
#define rb_color(r) ((r)->rb_parent_color & 1)
|
||||
#define rb_is_red(r) (!rb_color(r))
|
||||
@@ -45,24 +44,13 @@ struct rb_root
|
||||
#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0)
|
||||
#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0)
|
||||
|
||||
static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
|
||||
{
|
||||
rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
|
||||
}
|
||||
static inline void rb_set_color(struct rb_node *rb, int color)
|
||||
{
|
||||
rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
|
||||
}
|
||||
|
||||
void rb_insert_color(struct rb_node *, struct rb_root *);
|
||||
void rb_erase(struct rb_node *, struct rb_root *);
|
||||
|
||||
static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
|
||||
struct rb_node ** rb_link)
|
||||
{
|
||||
node->rb_parent_color = (unsigned long )parent;
|
||||
node->rb_left = node->rb_right = NULL;
|
||||
|
||||
*rb_link = node;
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
void rb_link_node(struct rb_node *, struct rb_node *,
|
||||
struct rb_node **);
|
||||
#else
|
||||
inline void rb_link_node(struct rb_node *, struct rb_node *,
|
||||
struct rb_node **);
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,12 @@
|
||||
#ifdef UWSGI_LOCK_USE_MUTEX
|
||||
|
||||
#define UWSGI_LOCK_SIZE sizeof(pthread_mutexattr_t) + sizeof(pthread_mutex_t)
|
||||
|
||||
#ifdef OBSOLETE_LINUX_KERNEL
|
||||
#define UWSGI_RWLOCK_SIZE sizeof(pthread_mutexattr_t) + sizeof(pthread_mutex_t)
|
||||
#else
|
||||
#define UWSGI_RWLOCK_SIZE sizeof(pthread_rwlockattr_t) + sizeof(pthread_rwlock_t)
|
||||
#endif
|
||||
|
||||
// REMEMBER lock must contains space for both pthread_mutex_t and pthread_mutexattr_t !!!
|
||||
void uwsgi_lock_init(void *lock) {
|
||||
@@ -27,15 +32,27 @@ void uwsgi_lock_init(void *lock) {
|
||||
}
|
||||
|
||||
void uwsgi_rlock(void *lock) {
|
||||
#ifdef OBSOLETE_LINUX_KERNEL
|
||||
uwsgi_lock(lock);
|
||||
#else
|
||||
pthread_rwlock_rdlock((pthread_rwlock_t *) lock + sizeof(pthread_rwlockattr_t));
|
||||
#endif
|
||||
}
|
||||
|
||||
void uwsgi_wlock(void *lock) {
|
||||
#ifdef OBSOLETE_LINUX_KERNEL
|
||||
uwsgi_lock(lock);
|
||||
#else
|
||||
pthread_rwlock_wrlock((pthread_rwlock_t *) lock + sizeof(pthread_rwlockattr_t));
|
||||
#endif
|
||||
}
|
||||
|
||||
void uwsgi_rwunlock(void *lock) {
|
||||
#ifdef OBSOLETE_LINUX_KERNEL
|
||||
uwsgi_unlock(lock);
|
||||
#else
|
||||
pthread_rwlock_unlock((pthread_rwlock_t *) lock + sizeof(pthread_rwlockattr_t));
|
||||
#endif
|
||||
}
|
||||
|
||||
void uwsgi_lock(void *lock) {
|
||||
@@ -46,10 +63,14 @@ void uwsgi_lock(void *lock) {
|
||||
void uwsgi_unlock(void *lock) {
|
||||
|
||||
pthread_mutex_unlock((pthread_mutex_t *) lock + sizeof(pthread_mutexattr_t));
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_rwlock_init(void *lock) {
|
||||
|
||||
#ifdef OBSOLETE_LINUX_KERNEL
|
||||
uwsgi_lock_init(lock);
|
||||
#else
|
||||
if (pthread_rwlockattr_init((pthread_rwlockattr_t *) lock)) {
|
||||
uwsgi_log("unable to allocate rwlock structure\n");
|
||||
exit(1);
|
||||
@@ -63,6 +84,7 @@ void uwsgi_rwlock_init(void *lock) {
|
||||
uwsgi_log("unable to initialize rwlock\n");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -44,13 +44,14 @@ void log_request(struct wsgi_request *wsgi_req) {
|
||||
#ifdef UWSGI_SENDFILE
|
||||
char *msg1 = " via sendfile() ";
|
||||
#endif
|
||||
char *msg3 = " via route() ";
|
||||
|
||||
struct uwsgi_app *wi;
|
||||
|
||||
if (wsgi_req->do_not_log) return ;
|
||||
|
||||
if (wsgi_req->app_id >= 0) {
|
||||
wi = &uwsgi.apps[wsgi_req->app_id];
|
||||
wi = &uwsgi_apps[wsgi_req->app_id];
|
||||
if (wi->requests > 0) {
|
||||
app_req = wi->requests;
|
||||
}
|
||||
@@ -62,6 +63,11 @@ void log_request(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// mark route() requests
|
||||
if (wsgi_req->status == -17) {
|
||||
via = msg3;
|
||||
}
|
||||
|
||||
time_request = ctime((const time_t *) &wsgi_req->start_of_request.tv_sec);
|
||||
microseconds = wsgi_req->end_of_request.tv_sec * 1000000 + wsgi_req->end_of_request.tv_usec;
|
||||
microseconds2 = wsgi_req->start_of_request.tv_sec * 1000000 + wsgi_req->start_of_request.tv_usec;
|
||||
@@ -129,22 +135,22 @@ void log_request(struct wsgi_request *wsgi_req) {
|
||||
rlen = writev(2, logvec, logvecpos+1);
|
||||
}
|
||||
|
||||
void get_memusage() {
|
||||
void get_memusage(uint64_t *rss, uint64_t *vsz) {
|
||||
|
||||
#ifdef UNBIT
|
||||
uwsgi.workers[uwsgi.mywid].vsz_size = syscall(356);
|
||||
*vsz = syscall(356);
|
||||
#elif defined(__linux__)
|
||||
FILE *procfile;
|
||||
int i;
|
||||
procfile = fopen("/proc/self/stat", "r");
|
||||
if (procfile) {
|
||||
i = fscanf(procfile, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %llu %lld", (unsigned long long *) &uwsgi.workers[uwsgi.mywid].vsz_size, (unsigned long long *) &uwsgi.workers[uwsgi.mywid].rss_size);
|
||||
i = fscanf(procfile, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %llu %lld", (unsigned long long *) vsz, (unsigned long long *) rss);
|
||||
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;
|
||||
*rss = *rss * uwsgi.page_size;
|
||||
#elif defined (__sun__)
|
||||
psinfo_t info;
|
||||
int procfd;
|
||||
@@ -152,8 +158,8 @@ void get_memusage() {
|
||||
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;
|
||||
*rss = (uint64_t) info.pr_rssize * 1024;
|
||||
*vsz = (uint64_t) info.pr_size * 1024;
|
||||
}
|
||||
close(procfd);
|
||||
}
|
||||
@@ -164,8 +170,8 @@ void get_memusage() {
|
||||
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;
|
||||
*rss = t_info.resident_size;
|
||||
*vsz = t_info.virtual_size;
|
||||
}
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
|
||||
kvm_t *kv;
|
||||
@@ -173,6 +179,8 @@ void get_memusage() {
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
kv = kvm_open(NULL, "/dev/null", NULL, O_RDONLY, NULL);
|
||||
#elif defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
kv = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, NULL);
|
||||
#else
|
||||
kv = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);
|
||||
#endif
|
||||
@@ -182,8 +190,8 @@ void get_memusage() {
|
||||
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;
|
||||
*vsz = kproc->ki_size;
|
||||
*rss = kproc->ki_rssize * uwsgi.page_size;
|
||||
}
|
||||
#elif defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
struct kinfo_proc2 *kproc2;
|
||||
@@ -191,11 +199,11 @@ void get_memusage() {
|
||||
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;
|
||||
*vsz = (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;
|
||||
*vsz = kproc2->p_vm_msize * uwsgi.page_size;
|
||||
#endif
|
||||
uwsgi.workers[uwsgi.mywid].rss_size = kproc2->p_vm_rssize * uwsgi.page_size;
|
||||
*rss = kproc2->p_vm_rssize * uwsgi.page_size;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -205,13 +213,58 @@ void get_memusage() {
|
||||
area_info ai;
|
||||
int32 cookie;
|
||||
|
||||
uwsgi.workers[uwsgi.mywid].vsz_size = 0;
|
||||
uwsgi.workers[uwsgi.mywid].rss_size = 0;
|
||||
*vsz = 0;
|
||||
*rss = 0;
|
||||
while(get_next_area_info(0, &cookie, &ai) == B_OK) {
|
||||
uwsgi.workers[uwsgi.mywid].vsz_size += ai.ram_size;
|
||||
*vsz += ai.ram_size;
|
||||
if ( (ai.protection & B_WRITE_AREA) != 0) {
|
||||
uwsgi.workers[uwsgi.mywid].rss_size += ai.ram_size;
|
||||
*rss += ai.ram_size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_register_logger(char *name, ssize_t (*func)(struct uwsgi_logger *, char *, size_t)) {
|
||||
|
||||
struct uwsgi_logger *ul = uwsgi.loggers, *old_ul;
|
||||
|
||||
if (!ul) {
|
||||
uwsgi.loggers = uwsgi_malloc(sizeof(struct uwsgi_logger));
|
||||
ul = uwsgi.loggers;
|
||||
}
|
||||
else {
|
||||
while(ul) {
|
||||
old_ul = ul;
|
||||
ul = ul->next;
|
||||
}
|
||||
|
||||
ul = uwsgi_malloc(sizeof(struct uwsgi_logger));
|
||||
old_ul->next = ul;
|
||||
}
|
||||
|
||||
ul->name = name;
|
||||
ul->func = func;
|
||||
ul->next = NULL;
|
||||
ul->configured = 0;
|
||||
ul->fd = -1;
|
||||
ul->data = NULL;
|
||||
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("[uwsgi-logger] registered \"%s\"\n", ul->name);
|
||||
#endif
|
||||
}
|
||||
|
||||
struct uwsgi_logger *uwsgi_get_logger(char *name) {
|
||||
struct uwsgi_logger *ul = uwsgi.loggers;
|
||||
|
||||
while(ul) {
|
||||
if (!strcmp(ul->name, name)) {
|
||||
return ul;
|
||||
}
|
||||
ul = ul->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -66,19 +66,20 @@ void *simple_loop(void *arg1) {
|
||||
#endif
|
||||
|
||||
// initialize the main event queue to monitor sockets
|
||||
uwsgi.main_queue = event_queue_init();
|
||||
int main_queue = event_queue_init();
|
||||
|
||||
uwsgi_add_sockets_to_queue(uwsgi.main_queue);
|
||||
uwsgi_add_sockets_to_queue(main_queue);
|
||||
|
||||
if (uwsgi.signal_socket > -1) {
|
||||
event_queue_add_fd_read(uwsgi.main_queue, uwsgi.signal_socket);
|
||||
event_queue_add_fd_read(main_queue, uwsgi.signal_socket);
|
||||
event_queue_add_fd_read(main_queue, uwsgi.my_signal_socket);
|
||||
}
|
||||
|
||||
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
|
||||
|
||||
wsgi_req_setup(wsgi_req, core_id, NULL);
|
||||
|
||||
if (wsgi_req_accept(wsgi_req)) {
|
||||
if (wsgi_req_accept(main_queue, wsgi_req)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -91,6 +92,18 @@ void *simple_loop(void *arg1) {
|
||||
}
|
||||
|
||||
// end of the loop
|
||||
if (uwsgi.workers[uwsgi.mywid].destroy && uwsgi.workers[0].pid > 0) {
|
||||
#ifdef __APPLE__
|
||||
kill(uwsgi.workers[0].pid, SIGTERM);
|
||||
#else
|
||||
if (uwsgi.propagate_touch) {
|
||||
kill(uwsgi.workers[0].pid, SIGHUP);
|
||||
}
|
||||
else {
|
||||
gracefully_kill(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -103,7 +116,7 @@ void *zeromq_loop(void *arg1) {
|
||||
|
||||
struct wsgi_request *wsgi_req = uwsgi.wsgi_requests[core_id];
|
||||
uwsgi.zeromq_recv_flag = 0;
|
||||
zmq_pollitem_t zmq_poll_items[2];
|
||||
zmq_pollitem_t zmq_poll_items[3];
|
||||
char uwsgi_signal;
|
||||
|
||||
if (uwsgi.threads > 1) {
|
||||
@@ -147,6 +160,10 @@ void *zeromq_loop(void *arg1) {
|
||||
zmq_poll_items[1].socket = NULL;
|
||||
zmq_poll_items[1].fd = uwsgi.signal_socket;
|
||||
zmq_poll_items[1].events = ZMQ_POLLIN;
|
||||
|
||||
zmq_poll_items[2].socket = NULL;
|
||||
zmq_poll_items[2].fd = uwsgi.my_signal_socket;
|
||||
zmq_poll_items[2].events = ZMQ_POLLIN;
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +176,7 @@ void *zeromq_loop(void *arg1) {
|
||||
|
||||
|
||||
if (uwsgi.signal_socket > -1) {
|
||||
if (zmq_poll(zmq_poll_items, 2, -1) < 0) {
|
||||
if (zmq_poll(zmq_poll_items, 3, -1) < 0) {
|
||||
uwsgi_error("zmq_poll()");
|
||||
continue;
|
||||
}
|
||||
@@ -172,7 +189,9 @@ void *zeromq_loop(void *arg1) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log_verbose("master sent signal %d to worker %d\n", uwsgi_signal, uwsgi.mywid);
|
||||
#endif
|
||||
if (uwsgi_signal_handler(uwsgi_signal)) {
|
||||
uwsgi_log_verbose("error managing signal %d on worker %d\n", uwsgi_signal, uwsgi.mywid);
|
||||
}
|
||||
@@ -180,6 +199,26 @@ void *zeromq_loop(void *arg1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (zmq_poll_items[2].revents & ZMQ_POLLIN) {
|
||||
if (read(uwsgi.my_signal_socket, &uwsgi_signal, 1) <= 0) {
|
||||
if (uwsgi.no_orphans) {
|
||||
uwsgi_log_verbose("uWSGI worker %d screams: UAAAAAAH my master died, i will follow him...\n", uwsgi.mywid);
|
||||
end_me(0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log_verbose("master sent signal %d to worker %d\n", uwsgi_signal, uwsgi.mywid);
|
||||
#endif
|
||||
if (uwsgi_signal_handler(uwsgi_signal)) {
|
||||
uwsgi_log_verbose("error managing signal %d on worker %d\n", uwsgi_signal, uwsgi.mywid);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (zmq_poll_items[0].revents & ZMQ_POLLIN) {
|
||||
wsgi_req->poll.fd = wsgi_req->socket->proto_accept(wsgi_req, uwsgi.zmq_socket->fd);
|
||||
}
|
||||
|
||||
+407
-48
@@ -2,68 +2,427 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void worker_wakeup() {}
|
||||
|
||||
void master_check_cluster_nodes() {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
struct uwsgi_cluster_node *ucn = &uwsgi.shared->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 ;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ucn->name[0] != 0 && ucn->type == CLUSTER_NODE_STATIC && ucn->status == UWSGI_NODE_FAILED) {
|
||||
// should i retry ?
|
||||
if (uwsgi.master_cycles % ucn->errors == 0) {
|
||||
if (!uwsgi_ping_node(i, uwsgi.wsgi_req)) {
|
||||
ucn->status = UWSGI_NODE_OK;
|
||||
uwsgi_log("re-enabled cluster node %d/%s\n", i, ucn->name);
|
||||
}
|
||||
else {
|
||||
ucn->errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ucn->name[0] != 0 && ucn->type == CLUSTER_NODE_DYNAMIC) {
|
||||
// if the last_seen attr is higher than 30 secs ago, mark the node as dead
|
||||
if ((uwsgi.current_time - ucn->last_seen) > 30) {
|
||||
uwsgi_log_verbose("no presence announce in the last 30 seconds by node %s, i assume it is dead.\n", ucn->name);
|
||||
ucn->name[0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_fixup_fds(int wid, int muleid) {
|
||||
|
||||
int i;
|
||||
|
||||
// close the cache server
|
||||
if (uwsgi.cache_server_fd != -1) {
|
||||
close(uwsgi.cache_server_fd);
|
||||
}
|
||||
|
||||
if (uwsgi.master_process) {
|
||||
// fix the communication pipe
|
||||
close(uwsgi.shared->worker_signal_pipe[0]);
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
if (uwsgi.workers[i].signal_pipe[0] != -1) close(uwsgi.workers[i].signal_pipe[0]);
|
||||
if (i != wid) {
|
||||
if (uwsgi.workers[i].signal_pipe[1] != -1) close(uwsgi.workers[i].signal_pipe[1]);
|
||||
}
|
||||
}
|
||||
#ifdef UWSGI_SPOOLER
|
||||
if (uwsgi.shared->spooler_pid != getpid()) {
|
||||
if (uwsgi.shared->spooler_signal_pipe[0] != -1) close (uwsgi.shared->spooler_signal_pipe[0]);
|
||||
if (uwsgi.shared->spooler_signal_pipe[1] != -1) close (uwsgi.shared->spooler_signal_pipe[1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (uwsgi.shared->mule_signal_pipe[0] != -1) close(uwsgi.shared->mule_signal_pipe[0]);
|
||||
|
||||
if (muleid == 0) {
|
||||
if (uwsgi.shared->mule_signal_pipe[1] != -1) close(uwsgi.shared->mule_signal_pipe[1]);
|
||||
if (uwsgi.shared->mule_queue_pipe[1] != -1) close(uwsgi.shared->mule_queue_pipe[1]);
|
||||
}
|
||||
|
||||
for(i=0;i<uwsgi.mules_cnt;i++) {
|
||||
if (uwsgi.mules[i].signal_pipe[0] != -1) close(uwsgi.mules[i].signal_pipe[0]);
|
||||
if (muleid != i+1) {
|
||||
if (uwsgi.mules[i].signal_pipe[1] != -1) close(uwsgi.mules[i].signal_pipe[1]);
|
||||
if (uwsgi.mules[i].queue_pipe[1] != -1) close(uwsgi.mules[i].queue_pipe[1]);
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0;i<uwsgi.farms_cnt;i++) {
|
||||
if (uwsgi.farms[i].signal_pipe[0] != -1) close(uwsgi.farms[i].signal_pipe[0]);
|
||||
|
||||
if (muleid == 0) {
|
||||
if (uwsgi.farms[i].signal_pipe[1] != -1) close(uwsgi.farms[i].signal_pipe[1]);
|
||||
if (uwsgi.farms[i].queue_pipe[1] != -1) close(uwsgi.farms[i].queue_pipe[1]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_respawn_worker(int wid) {
|
||||
|
||||
int respawns = uwsgi.workers[wid].respawn_count;
|
||||
int i;
|
||||
|
||||
pid_t pid = fork();
|
||||
pid_t pid = uwsgi_fork(uwsgi.workers[wid].name);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (pid == 0) {
|
||||
signal(SIGWINCH, worker_wakeup);
|
||||
signal(SIGTSTP, worker_wakeup);
|
||||
uwsgi.mywid = wid;
|
||||
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].rss_size = 0;
|
||||
uwsgi.workers[uwsgi.mywid].vsz_size = 0;
|
||||
// do not reset worker counters on reload !!!
|
||||
//uwsgi.workers[uwsgi.mywid].requests = 0;
|
||||
// ...but maintain a delta counter (yes this is racy in multithread)
|
||||
uwsgi.workers[uwsgi.mywid].delta_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;
|
||||
uwsgi.workers[uwsgi.mywid].cheaped = 0;
|
||||
uwsgi.workers[uwsgi.mywid].busy = 0;
|
||||
uwsgi.workers[uwsgi.mywid].suspended = 0;
|
||||
uwsgi.workers[uwsgi.mywid].sig = 0;
|
||||
|
||||
// reset the apps count with a copy from the master
|
||||
uwsgi.workers[uwsgi.mywid].apps_cnt = uwsgi.workers[0].apps_cnt;
|
||||
|
||||
uwsgi_fixup_fds(wid, 0);
|
||||
|
||||
uwsgi.my_signal_socket = uwsgi.workers[wid].signal_pipe[1];
|
||||
|
||||
if (uwsgi.master_process) {
|
||||
if ((uwsgi.workers[uwsgi.mywid].respawn_count || uwsgi.cheap)) {
|
||||
for (i = 0; i < 0xFF; i++) {
|
||||
if (uwsgi.p[i]->master_fixup) {
|
||||
uwsgi.p[i]->master_fixup(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
else if (pid < 1) {
|
||||
uwsgi_error("fork()");
|
||||
}
|
||||
else {
|
||||
if (respawns > 0) {
|
||||
uwsgi_log("Respawned uWSGI worker %d (new pid: %d)\n", wid, (int) pid);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("spawned uWSGI worker %d (pid: %d, cores: %d)\n", wid, pid, uwsgi.cores);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_manage_signal_cron(time_t now) {
|
||||
|
||||
struct tm *uwsgi_cron_delta;
|
||||
int i;
|
||||
|
||||
uwsgi.current_time = now;
|
||||
uwsgi_cron_delta = localtime(&uwsgi.current_time);
|
||||
|
||||
if (uwsgi_cron_delta) {
|
||||
|
||||
// fix month
|
||||
uwsgi_cron_delta->tm_mon++;
|
||||
|
||||
uwsgi_lock(uwsgi.cron_table_lock);
|
||||
for (i = 0; i < ushared->cron_cnt; i++) {
|
||||
|
||||
struct uwsgi_cron *ucron = &ushared->cron[i];
|
||||
int uc_minute, uc_hour, uc_day, uc_month, uc_week;
|
||||
|
||||
uc_minute = ucron->minute;
|
||||
uc_hour = ucron->hour;
|
||||
uc_day = ucron->day;
|
||||
uc_month = ucron->month;
|
||||
uc_week = ucron->week;
|
||||
|
||||
if (ucron->minute == -1)
|
||||
uc_minute = uwsgi_cron_delta->tm_min;
|
||||
if (ucron->hour == -1)
|
||||
uc_hour = uwsgi_cron_delta->tm_hour;
|
||||
if (ucron->month == -1)
|
||||
uc_month = uwsgi_cron_delta->tm_mon;
|
||||
if (ucron->day == -1)
|
||||
uc_day = uwsgi_cron_delta->tm_mday;
|
||||
if (ucron->week == -1)
|
||||
uc_week = uwsgi_cron_delta->tm_wday;
|
||||
|
||||
int run_task = 0;
|
||||
// mday and wday are ORed
|
||||
if (ucron->day != -1 && ucron->week != -1) {
|
||||
if (uwsgi_cron_delta->tm_min == uc_minute && uwsgi_cron_delta->tm_hour == uc_hour && uwsgi_cron_delta->tm_mon == uc_month && (uwsgi_cron_delta->tm_mday == uc_day || uwsgi_cron_delta->tm_wday == uc_week)) {
|
||||
run_task = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (uwsgi_cron_delta->tm_min == uc_minute && uwsgi_cron_delta->tm_hour == uc_hour && uwsgi_cron_delta->tm_mon == uc_month && uwsgi_cron_delta->tm_mday == uc_day && uwsgi_cron_delta->tm_wday == uc_week) {
|
||||
run_task = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (run_task == 1) {
|
||||
// date match, signal it ?
|
||||
if (uwsgi.current_time - ucron->last_job > 60) {
|
||||
uwsgi_route_signal(ucron->sig);
|
||||
ucron->last_job = uwsgi.current_time;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
uwsgi_unlock(uwsgi.cron_table_lock);
|
||||
}
|
||||
else {
|
||||
uwsgi_error("localtime()");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_manage_command_cron(time_t now) {
|
||||
|
||||
struct tm *uwsgi_cron_delta;
|
||||
|
||||
struct uwsgi_cron *current_cron = uwsgi.crons;
|
||||
int uc_minute, uc_hour, uc_day, uc_month, uc_week;
|
||||
|
||||
uwsgi.current_time = now;
|
||||
uwsgi_cron_delta = localtime(&uwsgi.current_time);
|
||||
|
||||
|
||||
if (!uwsgi_cron_delta) {
|
||||
uwsgi_error("localtime()");
|
||||
return;
|
||||
}
|
||||
|
||||
while (current_cron) {
|
||||
|
||||
|
||||
uc_minute = current_cron->minute;
|
||||
uc_hour = current_cron->hour;
|
||||
uc_day = current_cron->day;
|
||||
uc_month = current_cron->month;
|
||||
uc_week = current_cron->week;
|
||||
|
||||
if (current_cron->minute == -1)
|
||||
uc_minute = uwsgi_cron_delta->tm_min;
|
||||
if (current_cron->hour == -1)
|
||||
uc_hour = uwsgi_cron_delta->tm_hour;
|
||||
if (current_cron->month == -1)
|
||||
uc_month = uwsgi_cron_delta->tm_mon;
|
||||
if (current_cron->day == -1)
|
||||
uc_day = uwsgi_cron_delta->tm_mday;
|
||||
if (current_cron->week == -1)
|
||||
uc_week = uwsgi_cron_delta->tm_wday;
|
||||
|
||||
int run_task = 0;
|
||||
// mday and wday are ORed
|
||||
if (current_cron->day != -1 && current_cron->week != -1) {
|
||||
if (uwsgi_cron_delta->tm_min == uc_minute && uwsgi_cron_delta->tm_hour == uc_hour && uwsgi_cron_delta->tm_mon == uc_month && (uwsgi_cron_delta->tm_mday == uc_day || uwsgi_cron_delta->tm_wday == uc_week)) {
|
||||
run_task = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (uwsgi_cron_delta->tm_min == uc_minute && uwsgi_cron_delta->tm_hour == uc_hour && uwsgi_cron_delta->tm_mon == uc_month && uwsgi_cron_delta->tm_mday == uc_day && uwsgi_cron_delta->tm_wday == uc_week) {
|
||||
run_task = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (run_task == 1) {
|
||||
|
||||
// date match, run command ?
|
||||
if (uwsgi.current_time - current_cron->last_job > 60) {
|
||||
//call command
|
||||
if (current_cron->command) {
|
||||
if (uwsgi_run_command(current_cron->command) >=0) {
|
||||
uwsgi_log_verbose("[uWSGI-cron] running %s\n", current_cron->command);
|
||||
}
|
||||
}
|
||||
current_cron->last_job = uwsgi.current_time;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
current_cron = current_cron->next;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#define stats_send_llu(x, y) fprintf(output, x, (long long unsigned int) y)
|
||||
#define stats_send(x, y) fprintf(output, x, y)
|
||||
|
||||
void uwsgi_send_stats(int fd) {
|
||||
|
||||
int i,j;
|
||||
struct sockaddr_un client_src;
|
||||
struct uwsgi_app *ua;
|
||||
socklen_t client_src_len = 0;
|
||||
int client_fd = accept(fd, (struct sockaddr *) &client_src, &client_src_len);
|
||||
if (client_fd < 0) {
|
||||
uwsgi_error("accept()");
|
||||
return;
|
||||
}
|
||||
|
||||
FILE *output = fdopen(client_fd, "w");
|
||||
if (!output) {
|
||||
uwsgi_error("fdopen()");
|
||||
close(client_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
stats_send("{ \"version\": \"%s\",\n", UWSGI_VERSION);
|
||||
|
||||
#ifdef __linux__
|
||||
stats_send_llu("\"listen_queue\": %llu,\n", uwsgi.shared->ti.tcpi_unacked);
|
||||
#endif
|
||||
|
||||
stats_send_llu("\"load\": %llu,\n", uwsgi.shared->load);
|
||||
|
||||
fprintf(output,"\"pid\": %d,\n", (int)(getpid()));
|
||||
fprintf(output,"\"uid\": %d,\n", (int)(getuid()));
|
||||
fprintf(output,"\"gid\": %d,\n", (int)(getgid()));
|
||||
|
||||
char *cwd = uwsgi_get_cwd();
|
||||
stats_send("\"cwd\": \"%s\",\n", cwd);
|
||||
free(cwd);
|
||||
|
||||
if (uwsgi.daemons) {
|
||||
fprintf(output, "\"daemons\": [\n");
|
||||
struct uwsgi_daemon *ud = uwsgi.daemons;
|
||||
while(ud) {
|
||||
fprintf(output, "\t{ \"cmd\": \"%s\", \"pid\": %d, \"respawns\": %llu }",
|
||||
ud->command, (int) ud->pid, (unsigned long long) ud->respawns-1);
|
||||
if (ud->next)
|
||||
fprintf(output, ",\n");
|
||||
else {
|
||||
fprintf(output, "\n");
|
||||
}
|
||||
ud = ud->next;
|
||||
}
|
||||
fprintf(output, "],\n");
|
||||
}
|
||||
|
||||
fprintf(output, "\"workers\": [\n");
|
||||
|
||||
for (i = 0; i < uwsgi.numproc; i++) {
|
||||
fprintf(output,"\t{");
|
||||
|
||||
fprintf(output,"\"id\": %d, ", uwsgi.workers[i+1].id);
|
||||
fprintf(output,"\"pid\": %d, ", (int) uwsgi.workers[i+1].pid);
|
||||
stats_send_llu("\"requests\": %llu, ", uwsgi.workers[i+1].requests);
|
||||
stats_send_llu("\"delta_requests\": %llu, ", uwsgi.workers[i+1].delta_requests);
|
||||
stats_send_llu("\"exceptions\": %llu, ", uwsgi.workers[i+1].exceptions);
|
||||
stats_send_llu("\"signals\": %llu, ", uwsgi.workers[i+1].signals);
|
||||
|
||||
if (uwsgi.workers[i + 1].cheaped) {
|
||||
fprintf(output,"\"status\": \"cheap\", ");
|
||||
}
|
||||
else if (uwsgi.workers[i + 1].suspended) {
|
||||
fprintf(output,"\"status\": \"pause\", ");
|
||||
}
|
||||
else {
|
||||
if (uwsgi.workers[i + 1].sig) {
|
||||
fprintf(output,"\"status\": \"sig%d\", ", uwsgi.workers[i + 1].signum);
|
||||
}
|
||||
else if (uwsgi.workers[i + 1].busy) {
|
||||
fprintf(output,"\"status\": \"busy\", ");
|
||||
}
|
||||
else {
|
||||
fprintf(output,"\"status\": \"idle\", ");
|
||||
}
|
||||
}
|
||||
|
||||
stats_send_llu("\"rss\": %llu, ", uwsgi.workers[i+1].rss_size);
|
||||
stats_send_llu("\"vsz\": %llu, ", uwsgi.workers[i+1].vsz_size);
|
||||
|
||||
stats_send_llu("\"running_time\": %llu, ", uwsgi.workers[i+1].running_time);
|
||||
stats_send_llu("\"last_spawn\": %llu, ", uwsgi.workers[i+1].last_spawn);
|
||||
stats_send_llu("\"respawn_count\": %llu, ", uwsgi.workers[i+1].respawn_count);
|
||||
stats_send_llu("\"tx\": %llu, ", uwsgi.workers[i+1].tx);
|
||||
stats_send_llu("\"avg_rt\": %llu, ", uwsgi.workers[i+1].avg_response_time);
|
||||
|
||||
fprintf(output,"\"apps\": [\n");
|
||||
|
||||
for(j=0;j<uwsgi.workers[i+1].apps_cnt;j++) {
|
||||
ua = &uwsgi.workers[i+1].apps[j];
|
||||
fprintf(output,"\t\t{ ");
|
||||
|
||||
fprintf(output, "\"id\": %d, ", j);
|
||||
fprintf(output, "\"modifier1\": %d, ", ua->modifier1);
|
||||
fprintf(output, "\"mountpoint\": \"%.*s\", ", ua->mountpoint_len, ua->mountpoint);
|
||||
|
||||
stats_send_llu( "\"requests\": %llu, ", ua->requests);
|
||||
stats_send_llu( "\"exceptions\": %llu, ", ua->exceptions);
|
||||
|
||||
if (ua->chdir) {
|
||||
fprintf(output, "\"chdir\": \"%s\", ", ua->chdir);
|
||||
}
|
||||
else {
|
||||
fprintf(output, "\"chdir\": \"\" ");
|
||||
}
|
||||
|
||||
if (j == uwsgi.workers[i+1].apps_cnt-1) {
|
||||
fprintf(output,"}\n");
|
||||
}
|
||||
else {
|
||||
fprintf(output,"},\n");
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(output,"\t\t]");
|
||||
|
||||
if (i == uwsgi.numproc-1) {
|
||||
fprintf(output,"}\n");
|
||||
}
|
||||
else {
|
||||
fprintf(output,"},\n");
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(output,"]}\n");
|
||||
fclose(output);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
|
||||
uWSGI mules are very simple workers only managing signals or running custom code in background.
|
||||
|
||||
By default they born in signal-only mode, but if you patch them (passing the script/code to run) they will became fully customized daemons.
|
||||
|
||||
*/
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_mule_handler(void);
|
||||
|
||||
void mule_send_msg(int fd, char *message, size_t len) {
|
||||
|
||||
socklen_t so_bufsize_len = sizeof(int);
|
||||
int so_bufsize = 0;
|
||||
|
||||
if (write(fd, message, len) != (ssize_t) len) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &so_bufsize, &so_bufsize_len)) {
|
||||
uwsgi_error("getsockopt()");
|
||||
}
|
||||
uwsgi_log("*** MULE MSG QUEUE IS FULL: buffer size %d bytes (you can tune it with --signal-bufsize) ***\n", so_bufsize);
|
||||
}
|
||||
else {
|
||||
uwsgi_error("mule_send_msg()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_mule(int id) {
|
||||
|
||||
int i;
|
||||
|
||||
pid_t pid = uwsgi_fork(uwsgi.mules[id-1].name);
|
||||
if (pid == 0) {
|
||||
uwsgi.muleid = id;
|
||||
// avoid race conditions
|
||||
uwsgi.mules[id-1].id = id;
|
||||
uwsgi.mules[id-1].pid = getpid();
|
||||
|
||||
uwsgi_fixup_fds(0, id);
|
||||
|
||||
uwsgi.my_signal_socket = uwsgi.mules[id-1].signal_pipe[1];
|
||||
uwsgi.signal_socket = uwsgi.shared->mule_signal_pipe[1];
|
||||
|
||||
uwsgi_close_all_sockets();
|
||||
|
||||
for (i = 0; i < 0xFF; i++) {
|
||||
if (uwsgi.p[i]->master_fixup) {
|
||||
uwsgi.p[i]->master_fixup(1);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 0xFF; i++) {
|
||||
if (uwsgi.p[i]->post_fork) {
|
||||
uwsgi.p[i]->post_fork();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (uwsgi.mules[id-1].patch) {
|
||||
for (i = 0; i < 0xFF; i++) {
|
||||
if (uwsgi.p[i]->mule) {
|
||||
if (uwsgi.p[i]->mule(uwsgi.mules[id-1].patch) == 1) {
|
||||
// never here
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_mule_handler();
|
||||
}
|
||||
else if (pid > 0) {
|
||||
uwsgi.mules[id-1].id = id;
|
||||
uwsgi.mules[id-1].pid = pid;
|
||||
uwsgi_log("spawned uWSGI mule %d (pid: %d)\n", id, (int) pid);
|
||||
}
|
||||
}
|
||||
|
||||
int uwsgi_farm_has_mule(struct uwsgi_farm *farm, int muleid) {
|
||||
|
||||
struct uwsgi_mule_farm *umf = farm->mules;
|
||||
|
||||
while(umf) {
|
||||
if (umf->mule->id == muleid) {
|
||||
return 1;
|
||||
}
|
||||
umf = umf->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int farm_has_signaled(int fd) {
|
||||
|
||||
int i;
|
||||
for(i=0;i<uwsgi.farms_cnt;i++) {
|
||||
struct uwsgi_mule_farm *umf = uwsgi.farms[i].mules;
|
||||
while(umf) {
|
||||
if (umf->mule->id == uwsgi.muleid && uwsgi.farms[i].signal_pipe[1] == fd) {
|
||||
return 1;
|
||||
}
|
||||
umf = umf->next;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int farm_has_msg(int fd) {
|
||||
|
||||
int i;
|
||||
for(i=0;i<uwsgi.farms_cnt;i++) {
|
||||
struct uwsgi_mule_farm *umf = uwsgi.farms[i].mules;
|
||||
while(umf) {
|
||||
if (umf->mule->id == uwsgi.muleid && uwsgi.farms[i].queue_pipe[1] == fd) {
|
||||
return 1;
|
||||
}
|
||||
umf = umf->next;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_mule_add_farm_to_queue(int queue) {
|
||||
|
||||
int i;
|
||||
for(i=0;i<uwsgi.farms_cnt;i++) {
|
||||
if (uwsgi_farm_has_mule(&uwsgi.farms[i], uwsgi.muleid)) {
|
||||
event_queue_add_fd_read(queue, uwsgi.farms[i].signal_pipe[1]);
|
||||
event_queue_add_fd_read(queue, uwsgi.farms[i].queue_pipe[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_mule_handler() {
|
||||
|
||||
ssize_t len;
|
||||
uint8_t uwsgi_signal;
|
||||
int rlen;
|
||||
int interesting_fd;
|
||||
|
||||
// this must be configurable
|
||||
char message[65536];
|
||||
|
||||
int mule_queue = event_queue_init();
|
||||
|
||||
event_queue_add_fd_read(mule_queue, uwsgi.signal_socket);
|
||||
event_queue_add_fd_read(mule_queue, uwsgi.my_signal_socket);
|
||||
event_queue_add_fd_read(mule_queue, uwsgi.mules[uwsgi.muleid-1].queue_pipe[1]);
|
||||
event_queue_add_fd_read(mule_queue, uwsgi.shared->mule_queue_pipe[1]);
|
||||
|
||||
uwsgi_mule_add_farm_to_queue(mule_queue);
|
||||
|
||||
for(;;) {
|
||||
rlen = event_queue_wait(mule_queue, -1, &interesting_fd);
|
||||
if (rlen <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (interesting_fd == uwsgi.signal_socket || interesting_fd == uwsgi.my_signal_socket || farm_has_signaled(interesting_fd)) {
|
||||
len = read(interesting_fd, &uwsgi_signal, 1);
|
||||
if (len <= 0) {
|
||||
uwsgi_log_verbose("uWSGI mule %d braying: my master died, i will follow him...\n", uwsgi.muleid);
|
||||
end_me(0);
|
||||
}
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log_verbose("master sent signal %d to mule %d\n", uwsgi_signal, uwsgi.muleid);
|
||||
#endif
|
||||
if (uwsgi_signal_handler(uwsgi_signal)) {
|
||||
uwsgi_log_verbose("error managing signal %d on mule %d\n", uwsgi_signal, uwsgi.muleid);
|
||||
}
|
||||
}
|
||||
else if (interesting_fd == uwsgi.mules[uwsgi.muleid-1].queue_pipe[1] || interesting_fd == uwsgi.shared->mule_queue_pipe[1] || farm_has_msg(interesting_fd)) {
|
||||
len = read(interesting_fd, message, 65536);
|
||||
if (len < 0) {
|
||||
uwsgi_error("read()");
|
||||
}
|
||||
else {
|
||||
int i,found = 0;
|
||||
for(i=0;i<0xff;i++) {
|
||||
if (uwsgi.p[i]->mule_msg) {
|
||||
if (uwsgi.p[i]->mule_msg(message, len)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
uwsgi_log("*** mule %d received a %d bytes message ***\n", uwsgi.muleid, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_mule *get_mule_by_id(int id) {
|
||||
|
||||
int i;
|
||||
|
||||
for(i=0;i<uwsgi.mules_cnt;i++) {
|
||||
if (uwsgi.mules[i].id == id) {
|
||||
return &uwsgi.mules[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_farm *get_farm_by_name(char *name) {
|
||||
|
||||
int i;
|
||||
|
||||
for(i=0;i<uwsgi.farms_cnt;i++) {
|
||||
if (!strcmp(uwsgi.farms[i].name, name)) {
|
||||
return &uwsgi.farms[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_mule_farm *uwsgi_mule_farm_new(struct uwsgi_mule_farm **umf, struct uwsgi_mule *um) {
|
||||
|
||||
struct uwsgi_mule_farm *uwsgi_mf = *umf, *old_umf;
|
||||
|
||||
if (!uwsgi_mf) {
|
||||
*umf = uwsgi_malloc(sizeof(struct uwsgi_mule_farm));
|
||||
uwsgi_mf = *umf;
|
||||
}
|
||||
else {
|
||||
while(uwsgi_mf) {
|
||||
old_umf = uwsgi_mf;
|
||||
uwsgi_mf = uwsgi_mf->next;
|
||||
}
|
||||
|
||||
uwsgi_mf = uwsgi_malloc(sizeof(struct uwsgi_mule_farm));
|
||||
old_umf->next = uwsgi_mf;
|
||||
}
|
||||
|
||||
uwsgi_mf->mule = um;
|
||||
uwsgi_mf->next = NULL;
|
||||
|
||||
return uwsgi_mf;
|
||||
}
|
||||
|
||||
ssize_t uwsgi_mule_get_msg(int manage_signals, int manage_farms, char *message, size_t buffer_size, int timeout) {
|
||||
|
||||
ssize_t len = 0;
|
||||
struct pollfd *mulepoll;
|
||||
int count = 4;
|
||||
int farms_count = 0;
|
||||
uint8_t uwsgi_signal;
|
||||
int i;
|
||||
|
||||
if (uwsgi.muleid == 0) return -1;
|
||||
|
||||
if (manage_signals) count = 2;
|
||||
|
||||
if (!manage_farms) goto next;
|
||||
|
||||
for(i=0;i<uwsgi.farms_cnt;i++) {
|
||||
if (uwsgi_farm_has_mule(&uwsgi.farms[i], uwsgi.muleid)) farms_count++;
|
||||
}
|
||||
next:
|
||||
|
||||
if (timeout > -1) timeout = timeout*1000;
|
||||
|
||||
mulepoll = uwsgi_malloc(sizeof(struct pollfd) * (count+farms_count));
|
||||
|
||||
mulepoll[0].fd = uwsgi.mules[uwsgi.muleid-1].queue_pipe[1];
|
||||
mulepoll[0].events = POLLIN;
|
||||
mulepoll[1].fd = uwsgi.shared->mule_queue_pipe[1];
|
||||
mulepoll[1].events = POLLIN;
|
||||
if (count > 2) {
|
||||
mulepoll[2].fd = uwsgi.signal_socket;
|
||||
mulepoll[2].events = POLLIN;
|
||||
mulepoll[3].fd = uwsgi.my_signal_socket;
|
||||
mulepoll[3].events = POLLIN;
|
||||
}
|
||||
|
||||
if (farms_count > 0) {
|
||||
int tmp_cnt = 0;
|
||||
for(i=0;i<uwsgi.farms_cnt;i++) {
|
||||
if (uwsgi_farm_has_mule(&uwsgi.farms[i], uwsgi.muleid)) {
|
||||
mulepoll[count+tmp_cnt].fd = uwsgi.farms[i].queue_pipe[1];
|
||||
mulepoll[count+tmp_cnt].events = POLLIN;
|
||||
tmp_cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ret = poll(mulepoll, count+farms_count, timeout);
|
||||
if (ret <= 0) {
|
||||
uwsgi_error("poll");
|
||||
}
|
||||
else {
|
||||
if (mulepoll[0].revents & POLLIN) {
|
||||
len = read(uwsgi.mules[uwsgi.muleid-1].queue_pipe[1], message, buffer_size);
|
||||
}
|
||||
else if (mulepoll[1].revents & POLLIN) {
|
||||
len = read(uwsgi.shared->mule_queue_pipe[1], message, buffer_size);
|
||||
}
|
||||
else {
|
||||
if (count > 2) {
|
||||
int interesting_fd = -1;
|
||||
if (mulepoll[2].revents & POLLIN) {
|
||||
interesting_fd = mulepoll[2].fd;
|
||||
}
|
||||
else if (mulepoll[3].revents & POLLIN) {
|
||||
interesting_fd = mulepoll[3].fd;
|
||||
}
|
||||
|
||||
if (interesting_fd > -1) {
|
||||
len = read(interesting_fd, &uwsgi_signal, 1);
|
||||
if (len <= 0) {
|
||||
uwsgi_log_verbose("uWSGI mule %d braying: my master died, i will follow him...\n", uwsgi.muleid);
|
||||
end_me(0);
|
||||
}
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log_verbose("master sent signal %d to mule %d\n", uwsgi_signal, uwsgi.muleid);
|
||||
#endif
|
||||
if (uwsgi_signal_handler(uwsgi_signal)) {
|
||||
uwsgi_log_verbose("error managing signal %d on mule %d\n", uwsgi_signal, uwsgi.mywid);
|
||||
}
|
||||
// set the error condition
|
||||
len = -1;
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
|
||||
// read messages in the farm
|
||||
for(i=0;i<farms_count;i++) {
|
||||
if (mulepoll[count+i].revents & POLLIN) {
|
||||
len = read(mulepoll[count+i].fd, message, buffer_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (len < 0) {
|
||||
uwsgi_error("read()");
|
||||
goto clear;
|
||||
}
|
||||
|
||||
clear:
|
||||
free(mulepoll);
|
||||
return len;
|
||||
}
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
from uwsgidecorators import *
|
||||
|
||||
@timer(3, target='mule1')
|
||||
def hello_timer(signum):
|
||||
print "3 seconds elapsed"
|
||||
|
||||
|
||||
@mulefunc
|
||||
def conto_fino_a_dieci(uno, due, tre):
|
||||
print "MULE ID %d: conto_fino_a_dieci" % uwsgi.mule_id(),uno,due,tre
|
||||
|
||||
@mulefunc(2)
|
||||
def conto_fino_a_venti(uno, due, tre):
|
||||
print "MULE ID %d: conto_fino_a_venti" % uwsgi.mule_id(),uno,due,tre
|
||||
|
||||
@mulefunc('topogigio')
|
||||
def conto_fino_a_trenta(uno, due, tre):
|
||||
print "MULE ID %d: conto_fino_a_trenta" % uwsgi.mule_id(),uno,due,tre
|
||||
|
||||
|
||||
|
||||
def application(e, sr):
|
||||
conto_fino_a_dieci(1,2,3)
|
||||
conto_fino_a_venti(4,5,6)
|
||||
conto_fino_a_trenta(7,8,9)
|
||||
sr('200 OK', [('Content-Type','text/html')])
|
||||
return "MULE !!!"
|
||||
+3
-8
@@ -1,14 +1,9 @@
|
||||
import werkzeug
|
||||
|
||||
def web3_app(environ):
|
||||
status = b'200 OK'
|
||||
headers = [(b'Content-type', b'text/plain')]
|
||||
body = [b'I am a Web3 app\n']
|
||||
return body, status, headers
|
||||
import uwsgi
|
||||
|
||||
def zero_app(e,s):
|
||||
s('200 OK', [ ('Content-Type', 'text/plain') ])
|
||||
return ""
|
||||
return "0"
|
||||
|
||||
def not_found(e,s):
|
||||
s('404 Not Found', [ ('Content-Type', 'text/plain') ])
|
||||
@@ -24,4 +19,4 @@ def internal_server_error(e, s):
|
||||
s('500 Internal Server Error', [ ('Content-Type', 'text/plain') ])
|
||||
return ""
|
||||
|
||||
applications = {'':web3_app, '/wsgi':wsgi_app, '/test':werkzeug.test_app, '/zero':zero_app, '/notfound':not_found, '/ise':internal_server_error}
|
||||
uwsgi.applications = {'/wsgi':wsgi_app, '/test':werkzeug.test_app, '/zero':zero_app, '/notfound':not_found, '/ise':internal_server_error}
|
||||
|
||||
@@ -94,7 +94,9 @@ check:
|
||||
linkpath_buf[linkpath_size] = '\0';
|
||||
strcpy(linkpath, linkpath_buf);
|
||||
} while ((linkpath_size = readlink(linkpath, linkpath_buf, 1023)) > 0);
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%s\n", linkpath);
|
||||
#endif
|
||||
free(plugin_entry_symbol);
|
||||
up = dlsym(plugin_handle, plugin_entry_symbol);
|
||||
char *slash = uwsgi_get_last_char(linkpath, '/');
|
||||
@@ -139,6 +141,9 @@ check:
|
||||
}
|
||||
free(plugin_name);
|
||||
free(plugin_entry_symbol);
|
||||
|
||||
if (up->on_load)
|
||||
up->on_load();
|
||||
return plugin_handle;
|
||||
}
|
||||
uwsgi_log( "%s\n", dlerror());
|
||||
|
||||
Vendored
+6
-2
@@ -9,6 +9,9 @@ void cache_command(char *key, uint16_t keylen, char *val, uint16_t vallen, void
|
||||
if (!uwsgi_strncmp(key, keylen, "key", 3)) {
|
||||
val = uwsgi_cache_get(val, vallen, &tmp_vallen);
|
||||
if (val && tmp_vallen > 0) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("cache value size: %llu\n", tmp_vallen);
|
||||
#endif
|
||||
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, val, tmp_vallen);
|
||||
}
|
||||
|
||||
@@ -31,6 +34,7 @@ int uwsgi_cache_request(struct wsgi_request *wsgi_req) {
|
||||
uint64_t vallen = 0;
|
||||
char *value;
|
||||
char *argv[3];
|
||||
uint16_t argvs[3];
|
||||
uint8_t argc = 0;
|
||||
|
||||
switch(wsgi_req->uh.modifier2) {
|
||||
@@ -49,9 +53,9 @@ int uwsgi_cache_request(struct wsgi_request *wsgi_req) {
|
||||
// set
|
||||
if (wsgi_req->uh.pktsize > 0) {
|
||||
argc = 3;
|
||||
if (!uwsgi_parse_array(wsgi_req->buffer, wsgi_req->uh.pktsize, argv, &argc)) {
|
||||
if (!uwsgi_parse_array(wsgi_req->buffer, wsgi_req->uh.pktsize, argv, argvs, &argc)) {
|
||||
if (argc > 1) {
|
||||
uwsgi_cache_set(argv[0], strlen(argv[0]), argv[1], strlen(argv[1]), 0, 0);
|
||||
uwsgi_cache_set(argv[0], argvs[0], argv[1], argvs[1], 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#define CARBON_OPT_BASE 178000
|
||||
#define CARBON_OPT_CARBON CARBON_OPT_BASE+1
|
||||
#define CARBON_OPT_CARBON_ID CARBON_OPT_BASE+2
|
||||
#define CARBON_OPT_CARBON_FREQ CARBON_OPT_BASE+3
|
||||
#define CARBON_OPT_CARBON_TIMEOUT CARBON_OPT_BASE+4
|
||||
|
||||
struct uwsgi_carbon {
|
||||
struct uwsgi_string_list *servers;
|
||||
int freq;
|
||||
int timeout;
|
||||
char *id;
|
||||
} u_carbon;
|
||||
|
||||
struct option carbon_options[] = {
|
||||
{"carbon", required_argument, 0, CARBON_OPT_CARBON},
|
||||
{"carbon-timeout", required_argument, 0, CARBON_OPT_CARBON_TIMEOUT},
|
||||
{"carbon-freq", required_argument, 0, CARBON_OPT_CARBON_FREQ},
|
||||
{"carbon-id", required_argument, 0, CARBON_OPT_CARBON_ID},
|
||||
{0, 0, 0, 0},
|
||||
|
||||
};
|
||||
|
||||
|
||||
int carbon_init() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int carbon_opt(int i, char *optarg) {
|
||||
|
||||
switch(i) {
|
||||
case CARBON_OPT_CARBON:
|
||||
uwsgi.master_process = 1;
|
||||
uwsgi_string_new_list(&u_carbon.servers, optarg);
|
||||
return 1;
|
||||
case CARBON_OPT_CARBON_ID:
|
||||
u_carbon.id = optarg;
|
||||
return 1;
|
||||
case CARBON_OPT_CARBON_FREQ:
|
||||
u_carbon.freq = atoi(optarg);
|
||||
return 1;
|
||||
case CARBON_OPT_CARBON_TIMEOUT:
|
||||
u_carbon.timeout = atoi(optarg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void carbon_post_init() {
|
||||
|
||||
int i;
|
||||
struct uwsgi_string_list *usl = u_carbon.servers;
|
||||
if (!uwsgi.sockets) return;
|
||||
if (!u_carbon.servers) return;
|
||||
|
||||
while(usl) {
|
||||
uwsgi_log("added carbon server %s\n", usl->value);
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
if (u_carbon.freq < 1) u_carbon.freq = 60;
|
||||
if (u_carbon.timeout < 1) u_carbon.timeout = 3;
|
||||
if (!u_carbon.id) {
|
||||
u_carbon.id = uwsgi_str(uwsgi.sockets->name);
|
||||
|
||||
for(i=0;i<(int)strlen(u_carbon.id);i++) {
|
||||
if (u_carbon.id[i] == '.') u_carbon.id[i] = '_';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void carbon_master_cycle() {
|
||||
|
||||
static time_t last_update = 0;
|
||||
char ptr[4096];
|
||||
int rlen, i;
|
||||
int fd;
|
||||
struct uwsgi_string_list *usl = u_carbon.servers;
|
||||
|
||||
if (!u_carbon.servers) return ;
|
||||
|
||||
if (last_update == 0) last_update = time(NULL);
|
||||
|
||||
// update
|
||||
if (uwsgi.current_time - last_update >= u_carbon.freq) {
|
||||
while(usl) {
|
||||
fd = uwsgi_connect(usl->value, u_carbon.timeout, 0);
|
||||
if (fd < 0) goto nxt;
|
||||
// put the socket in non-blocking mode
|
||||
uwsgi_socket_nb(fd);
|
||||
|
||||
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.requests %llu %llu\n", uwsgi.hostname, u_carbon.id, (unsigned long long ) uwsgi.workers[0].requests, (unsigned long long ) uwsgi.current_time);
|
||||
if (rlen < 1) goto clear;
|
||||
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
|
||||
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
rlen = snprintf(ptr, 4096, "uwsgi.%s.%s.worker%d.requests %llu %llu\n", uwsgi.hostname, u_carbon.id, i, (unsigned long long ) uwsgi.workers[i].requests, (unsigned long long ) uwsgi.current_time);
|
||||
if (rlen < 1) goto clear;
|
||||
if (write(fd, ptr, rlen) <= 0) { uwsgi_error("write()"); goto clear;}
|
||||
}
|
||||
clear:
|
||||
close(fd);
|
||||
nxt:
|
||||
usl = usl->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_plugin carbon_plugin = {
|
||||
|
||||
.options = carbon_options,
|
||||
.manage_opt = carbon_opt,
|
||||
|
||||
.master_cycle = carbon_master_cycle,
|
||||
|
||||
.post_init = carbon_post_init,
|
||||
.init = carbon_init,
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
NAME='proxy'
|
||||
NAME='carbon'
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
|
||||
GCC_LIST = ['proxy']
|
||||
GCC_LIST = ['carbon']
|
||||
+790
-29
@@ -1,27 +1,446 @@
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
#include <wordexp.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
char *cgi_docroot;
|
||||
struct uwsgi_cgi {
|
||||
struct uwsgi_dyn_dict *mountpoint;
|
||||
struct uwsgi_dyn_dict *helpers;
|
||||
int buffer_size;
|
||||
int timeout;
|
||||
struct uwsgi_string_list *index;
|
||||
struct uwsgi_string_list *allowed_ext;
|
||||
struct uwsgi_string_list *unset;
|
||||
struct uwsgi_string_list *loadlib;
|
||||
int optimize;
|
||||
int has_mountpoints;
|
||||
struct uwsgi_dyn_dict *default_cgi;
|
||||
int path_info;
|
||||
} uc ;
|
||||
|
||||
#define LONG_ARGS_CGI_BASE 17000 + ((9 + 1) * 100)
|
||||
#define LONG_ARGS_CGI LONG_ARGS_CGI_BASE + 1
|
||||
#define LONG_ARGS_CGI_BASE 17000 + ((9 + 1) * 1000)
|
||||
#define LONG_ARGS_CGI LONG_ARGS_CGI_BASE + 1
|
||||
#define LONG_ARGS_CGI_MAP_HELPER LONG_ARGS_CGI_BASE + 2
|
||||
#define LONG_ARGS_CGI_BUFFER_SIZE LONG_ARGS_CGI_BASE + 3
|
||||
#define LONG_ARGS_CGI_TIMEOUT LONG_ARGS_CGI_BASE + 4
|
||||
#define LONG_ARGS_CGI_INDEX LONG_ARGS_CGI_BASE + 5
|
||||
#define LONG_ARGS_CGI_ALLOWED_EXT LONG_ARGS_CGI_BASE + 6
|
||||
#define LONG_ARGS_CGI_UNSET LONG_ARGS_CGI_BASE + 7
|
||||
#define LONG_ARGS_CGI_LOADLIB LONG_ARGS_CGI_BASE + 8
|
||||
|
||||
struct option uwsgi_cgi_options[] = {
|
||||
|
||||
{"cgi", required_argument, 0, LONG_ARGS_CGI},
|
||||
{"cgi-map-helper", required_argument, 0, LONG_ARGS_CGI_MAP_HELPER},
|
||||
{"cgi-helper", required_argument, 0, LONG_ARGS_CGI_MAP_HELPER},
|
||||
{"cgi-buffer-size", required_argument, 0, LONG_ARGS_CGI_BUFFER_SIZE},
|
||||
{"cgi-timeout", required_argument, 0, LONG_ARGS_CGI_TIMEOUT},
|
||||
{"cgi-index", required_argument, 0, LONG_ARGS_CGI_INDEX},
|
||||
{"cgi-allowed-ext", required_argument, 0, LONG_ARGS_CGI_ALLOWED_EXT},
|
||||
{"cgi-unset", required_argument, 0, LONG_ARGS_CGI_UNSET},
|
||||
{"cgi-loadlib", required_argument, 0, LONG_ARGS_CGI_LOADLIB},
|
||||
{"cgi-optimize", no_argument, &uc.optimize, 1},
|
||||
{"cgi-optimized", no_argument, &uc.optimize, 1},
|
||||
{"cgi-path-info", no_argument, &uc.path_info, 1},
|
||||
{0, 0, 0, 0},
|
||||
|
||||
};
|
||||
|
||||
void uwsgi_cgi_404(struct wsgi_request *wsgi_req) {
|
||||
|
||||
wsgi_req->status = 404;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write(wsgi_req, "HTTP/1.0 404 Not Found\r\n\r\nNot Found", 35);
|
||||
}
|
||||
|
||||
void uwsgi_cgi_403(struct wsgi_request *wsgi_req) {
|
||||
|
||||
wsgi_req->status = 403;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write(wsgi_req, "HTTP/1.0 403 Forbidden\r\n\r\nForbidden", 35);
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_cgi_redirect_to_slash(struct wsgi_request *wsgi_req) {
|
||||
|
||||
struct iovec iov[6];
|
||||
|
||||
wsgi_req->status = 301;
|
||||
iov[0].iov_base = wsgi_req->protocol;
|
||||
iov[0].iov_len = wsgi_req->protocol_len;
|
||||
iov[1].iov_base = " 301 Moved Permanently\r\n";
|
||||
iov[1].iov_len = 24;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 2);
|
||||
|
||||
iov[0].iov_base = "Location: ";
|
||||
iov[0].iov_len = 10;
|
||||
iov[1].iov_base = wsgi_req->path_info;
|
||||
iov[1].iov_len = wsgi_req->path_info_len;
|
||||
iov[2].iov_base = "/";
|
||||
iov[2].iov_len = 1;
|
||||
|
||||
if (wsgi_req->query_string_len > 0) {
|
||||
iov[3].iov_base = "?";
|
||||
iov[3].iov_len = 1;
|
||||
iov[4].iov_base = wsgi_req->query_string;
|
||||
iov[4].iov_len = wsgi_req->query_string_len;
|
||||
iov[5].iov_base = "\r\n\r\n";
|
||||
iov[5].iov_len = 4;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 6);
|
||||
wsgi_req->header_cnt++;
|
||||
}
|
||||
else {
|
||||
iov[3].iov_base = "\r\n\r\n";
|
||||
iov[3].iov_len = 4;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 4);
|
||||
wsgi_req->header_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_cgi_apps() {
|
||||
|
||||
struct uwsgi_dyn_dict *udd = uc.mountpoint;
|
||||
struct stat st;
|
||||
|
||||
while(udd) {
|
||||
if (udd->vallen) {
|
||||
if (uc.optimize) {
|
||||
udd->value = realpath(udd->value, NULL);
|
||||
if (!udd->value) {
|
||||
uwsgi_log("unable to find CGI path %.*s\n", udd->vallen, udd->value);
|
||||
exit(1);
|
||||
}
|
||||
udd->vallen = strlen(udd->value);
|
||||
udd->status = 1;
|
||||
if (stat(udd->value, &st)) {
|
||||
uwsgi_error("stat()");
|
||||
uwsgi_log("something horrible happened during CGI initialization\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
udd->status = 2;
|
||||
}
|
||||
}
|
||||
uc.has_mountpoints = 1;
|
||||
uwsgi_log("initialized CGI mountpoint: %.*s = %.*s\n", udd->keylen, udd->key, udd->vallen, udd->value);
|
||||
}
|
||||
else {
|
||||
if (uc.optimize) {
|
||||
udd->key = realpath(udd->key, NULL);
|
||||
if (!udd->key) {
|
||||
uwsgi_log("unable to find CGI path %.*s\n", udd->keylen, udd->key);
|
||||
exit(1);
|
||||
}
|
||||
udd->keylen = strlen(udd->key);
|
||||
udd->status = 1;
|
||||
|
||||
if (stat(udd->key, &st)) {
|
||||
uwsgi_error("stat()");
|
||||
uwsgi_log("something horrible happened during CGI initialization\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
udd->status = 2;
|
||||
}
|
||||
|
||||
}
|
||||
uwsgi_log("initialized CGI path: %.*s\n", udd->keylen, udd->key);
|
||||
uc.default_cgi = udd;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_cgi_init(){
|
||||
|
||||
void (*cgi_sym)(void);
|
||||
|
||||
uwsgi_log("initialized CGI engine\n");
|
||||
if (!uc.buffer_size) uc.buffer_size = 65536;
|
||||
if (!uc.timeout) uc.timeout = 60;
|
||||
|
||||
struct uwsgi_string_list *ll = uc.loadlib;
|
||||
while(ll) {
|
||||
char *colon = strchr(ll->value, ':');
|
||||
if (!colon) {
|
||||
uwsgi_log("invalid cgi-loadlib syntax, must be in the form lib:func\n");
|
||||
exit(1);
|
||||
}
|
||||
*colon = 0;
|
||||
void *cgi_lib = dlopen(ll->value, RTLD_NOW | RTLD_GLOBAL);
|
||||
if (!cgi_lib) {
|
||||
uwsgi_log( "cgi-loadlib: %s\n", dlerror());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cgi_sym = dlsym(cgi_lib, colon+1);
|
||||
if (!cgi_sym) {
|
||||
uwsgi_log("unknown symbol %s in lib %s\n", colon+1, ll->value);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cgi_sym();
|
||||
uwsgi_log("[cgi-loadlib] loaded symbol %s from %s\n", colon+1, ll->value);
|
||||
|
||||
*colon = ':';
|
||||
ll = ll->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_cgi_get_helper(char *filename) {
|
||||
|
||||
struct uwsgi_dyn_dict *helpers = uc.helpers;
|
||||
size_t len = strlen(filename);
|
||||
|
||||
while(helpers) {
|
||||
if (len >= (size_t) helpers->keylen) {
|
||||
if (!uwsgi_strncmp((filename+len)-helpers->keylen, helpers->keylen, helpers->key, helpers->keylen)) {
|
||||
return helpers->value;
|
||||
}
|
||||
}
|
||||
helpers = helpers->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
|
||||
size_t i;
|
||||
char *key = buf, *value = NULL;
|
||||
size_t header_size = 0;
|
||||
int status_sent = 0;
|
||||
|
||||
struct uwsgi_string_list *ah = uwsgi.additional_headers;
|
||||
|
||||
struct iovec iov[4];
|
||||
|
||||
for(i=0;i<len;i++) {
|
||||
// end of a line
|
||||
if (buf[i] == '\n') {
|
||||
// end of headers
|
||||
if (key == NULL) {
|
||||
goto send_body;
|
||||
}
|
||||
// invalid header
|
||||
else if (value == NULL) {
|
||||
return -1;
|
||||
}
|
||||
header_size = (buf+i) - key;
|
||||
// security check
|
||||
if (buf+i > buf) {
|
||||
if ((buf[i-1]) == '\r') {
|
||||
header_size--;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("found CGI header: %.*s\n", header_size, key);
|
||||
#endif
|
||||
|
||||
if (status_sent == 0) {
|
||||
// "Status: NNN"
|
||||
if (header_size >= 11) {
|
||||
if (!strncasecmp("Status: ", key, 8)) {
|
||||
wsgi_req->status = uwsgi_str3_num(key+8);
|
||||
iov[0].iov_base = wsgi_req->protocol;
|
||||
iov[0].iov_len = wsgi_req->protocol_len;
|
||||
iov[1].iov_base = " ";
|
||||
iov[1].iov_len = 1;
|
||||
iov[2].iov_base = key+8;
|
||||
iov[2].iov_len = header_size - 8;
|
||||
iov[3].iov_base = "\r\n";
|
||||
iov[3].iov_len = 2;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 4);
|
||||
status_sent = 1;
|
||||
key = NULL;
|
||||
value = NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// default status
|
||||
if (status_sent == 0) {
|
||||
|
||||
// Location: X
|
||||
if (header_size >= 11) {
|
||||
if (!strncasecmp("Location: ", key, 10)) {
|
||||
|
||||
wsgi_req->status = 302;
|
||||
iov[0].iov_base = wsgi_req->protocol;
|
||||
iov[0].iov_len = wsgi_req->protocol_len;
|
||||
iov[1].iov_base = " 302 Found\r\n";
|
||||
iov[1].iov_len = 12;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 2);
|
||||
status_sent = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (status_sent == 0) {
|
||||
wsgi_req->status = 200;
|
||||
iov[0].iov_base = wsgi_req->protocol;
|
||||
iov[0].iov_len = wsgi_req->protocol_len;
|
||||
iov[1].iov_base = " 200 OK\r\n";
|
||||
iov[1].iov_len = 9;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 2);
|
||||
status_sent = 1;
|
||||
}
|
||||
}
|
||||
|
||||
iov[0].iov_base = key;
|
||||
iov[0].iov_len = header_size;
|
||||
iov[1].iov_base = "\r\n";
|
||||
iov[1].iov_len = 2;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 2);
|
||||
wsgi_req->header_cnt++;
|
||||
|
||||
key = NULL;
|
||||
value = NULL;
|
||||
}
|
||||
else if (buf[i] == ':') {
|
||||
value = buf+i;
|
||||
}
|
||||
else if (buf[i] != '\r') {
|
||||
if (key == NULL) {
|
||||
key = buf + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
send_body:
|
||||
|
||||
while(ah) {
|
||||
iov[0].iov_base = ah->value;
|
||||
iov[0].iov_len = ah->len;
|
||||
iov[1].iov_base = "\r\n";
|
||||
iov[1].iov_len = 2;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 2);
|
||||
wsgi_req->header_cnt++;
|
||||
ah = ah->next;
|
||||
}
|
||||
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, "\r\n", 2);
|
||||
if (len-i > 0) {
|
||||
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, buf+i, len-i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *uwsgi_cgi_get_docroot(char *path_info, uint16_t path_info_len, int *need_free, int *is_a_file, int *discard_base, char **script_name) {
|
||||
|
||||
struct uwsgi_dyn_dict *udd = uc.mountpoint, *choosen_udd = NULL;
|
||||
int best_found = 0;
|
||||
struct stat st;
|
||||
char *path = NULL;
|
||||
|
||||
if (uc.has_mountpoints) {
|
||||
while(udd) {
|
||||
if (udd->vallen) {
|
||||
if (!uwsgi_starts_with(path_info, path_info_len, udd->key, udd->keylen) && udd->keylen > best_found) {
|
||||
best_found = udd->keylen ;
|
||||
choosen_udd = udd;
|
||||
path = udd->value;
|
||||
*script_name = udd->key;
|
||||
*discard_base = udd->keylen;
|
||||
if (udd->key[udd->keylen-1] == '/') {
|
||||
*discard_base = *discard_base-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (choosen_udd == NULL) {
|
||||
choosen_udd = uc.default_cgi;
|
||||
if (!choosen_udd) return NULL;
|
||||
path = choosen_udd->key;
|
||||
}
|
||||
|
||||
if (choosen_udd->status == 0) {
|
||||
char *tmp_udd = realpath(path, NULL);
|
||||
if (!tmp_udd) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (stat(tmp_udd, &st)) {
|
||||
uwsgi_error("stat()");
|
||||
free(tmp_udd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
*is_a_file = 1;
|
||||
}
|
||||
|
||||
*need_free = 1;
|
||||
return tmp_udd;
|
||||
}
|
||||
|
||||
if (choosen_udd->status == 2)
|
||||
*is_a_file = 1;
|
||||
return path;
|
||||
}
|
||||
|
||||
int uwsgi_cgi_walk(struct wsgi_request *wsgi_req, char *full_path, char *docroot, size_t docroot_len, int discard_base, char **path_info) {
|
||||
|
||||
// and now start walking...
|
||||
uint16_t i;
|
||||
char *ptr = wsgi_req->path_info+discard_base;
|
||||
char *dst = full_path+docroot_len;
|
||||
char *part = ptr;
|
||||
int part_size = 0;
|
||||
struct stat st;
|
||||
|
||||
if (ptr[0] == '/') part_size++;
|
||||
|
||||
for(i=0;i<wsgi_req->path_info_len-discard_base;i++) {
|
||||
if (ptr[i] == '/') {
|
||||
memcpy(dst, part, part_size-1);
|
||||
*(dst+part_size-1) = 0;
|
||||
|
||||
if (stat(full_path, &st)) {
|
||||
uwsgi_cgi_404(wsgi_req);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// not a directory, stop walking
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
if (i < (wsgi_req->path_info_len-discard_base)-1) {
|
||||
*path_info = ptr + i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// check for buffer overflow !!!
|
||||
*(dst+part_size-1) = '/';
|
||||
*(dst+part_size) = 0;
|
||||
|
||||
dst += part_size ;
|
||||
part_size = 0;
|
||||
part = ptr + i + 1;
|
||||
}
|
||||
|
||||
part_size++;
|
||||
}
|
||||
|
||||
if (part < wsgi_req->path_info+wsgi_req->path_info_len) {
|
||||
memcpy(dst, part, part_size-1);
|
||||
*(dst+part_size-1) = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
@@ -30,8 +449,21 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
|
||||
int i;
|
||||
pid_t cgi_pid;
|
||||
int waitpid_status;
|
||||
char *argv[2];
|
||||
char *argv[3];
|
||||
char full_path[PATH_MAX];
|
||||
char tmp_path[PATH_MAX];
|
||||
int cgi_pipe[2];
|
||||
ssize_t len;
|
||||
struct stat cgi_stat;
|
||||
int need_free = 0;
|
||||
int is_a_file = 0;
|
||||
int discard_base = 0;
|
||||
size_t docroot_len = 0;
|
||||
size_t full_path_len = 0;
|
||||
char *helper = NULL;
|
||||
char *command = NULL;
|
||||
char *path_info = NULL;
|
||||
char *script_name = NULL;
|
||||
|
||||
/* Standard CGI request */
|
||||
if (!wsgi_req->uh.pktsize) {
|
||||
@@ -41,48 +473,251 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
|
||||
if (uwsgi_parse_vars(wsgi_req)) {
|
||||
uwsgi_log("Invalid CGI request. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// check for file availability (and 'runnability')
|
||||
|
||||
char *docroot = uwsgi_cgi_get_docroot(wsgi_req->path_info, wsgi_req->path_info_len, &need_free, &is_a_file, &discard_base, &script_name);
|
||||
|
||||
if (docroot == NULL) {
|
||||
uwsgi_cgi_404(wsgi_req);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
docroot_len = strlen(docroot);
|
||||
memcpy(full_path, docroot, docroot_len);
|
||||
|
||||
if (!is_a_file) {
|
||||
|
||||
*(full_path+docroot_len) = '/';
|
||||
*(full_path+docroot_len+1) = 0;
|
||||
|
||||
if (uwsgi_cgi_walk(wsgi_req, full_path, docroot, docroot_len, discard_base, &path_info)) {
|
||||
if (need_free)
|
||||
free(docroot);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
if (realpath(full_path, tmp_path) == NULL) {
|
||||
if (need_free)
|
||||
free(docroot);
|
||||
uwsgi_cgi_404(wsgi_req);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
full_path_len = strlen(tmp_path);
|
||||
// add +1 to copy the null byte
|
||||
memcpy(full_path, tmp_path, full_path_len+1);
|
||||
|
||||
if (uwsgi_starts_with(full_path, full_path_len, docroot, docroot_len)) {
|
||||
if (need_free)
|
||||
free(docroot);
|
||||
uwsgi_log("CGI security error: %s is not under %s\n", full_path, docroot);
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
*(full_path+docroot_len) = 0;
|
||||
path_info = wsgi_req->path_info+discard_base;
|
||||
}
|
||||
|
||||
if (stat(full_path, &cgi_stat)) {
|
||||
uwsgi_cgi_404(wsgi_req);
|
||||
if (need_free)
|
||||
free(docroot);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
if (S_ISDIR(cgi_stat.st_mode)) {
|
||||
|
||||
// add / to directories
|
||||
if (wsgi_req->path_info_len == 0 || wsgi_req->path_info[wsgi_req->path_info_len-1] != '/') {
|
||||
uwsgi_cgi_redirect_to_slash(wsgi_req);
|
||||
if (need_free)
|
||||
free(docroot);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
struct uwsgi_string_list *ci = uc.index;
|
||||
full_path[full_path_len] = '/';
|
||||
full_path_len++;
|
||||
int found = 0;
|
||||
while(ci) {
|
||||
if (full_path_len + ci->len + 1 < PATH_MAX) {
|
||||
// add + 1 to ensure null byte
|
||||
memcpy(full_path+full_path_len, ci->value, ci->len + 1);
|
||||
if (!access(full_path, R_OK)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ci = ci->next;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
uwsgi_cgi_404(wsgi_req);
|
||||
if (need_free)
|
||||
free(docroot);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
full_path_len = strlen(full_path);
|
||||
}
|
||||
|
||||
int cgi_allowed = 1;
|
||||
struct uwsgi_string_list *allowed = uc.allowed_ext;
|
||||
while(allowed) {
|
||||
cgi_allowed = 0;
|
||||
if (full_path_len >= allowed->len) {
|
||||
if (!uwsgi_strncmp(full_path+(full_path_len-allowed->len), allowed->len, allowed->value, allowed->len)) {
|
||||
cgi_allowed = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
allowed = allowed->next;
|
||||
}
|
||||
|
||||
if (!cgi_allowed) {
|
||||
uwsgi_cgi_403(wsgi_req);
|
||||
if (need_free)
|
||||
free(docroot);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
if (is_a_file) {
|
||||
command = docroot;
|
||||
}
|
||||
else {
|
||||
command = full_path;
|
||||
helper = uwsgi_cgi_get_helper(full_path);
|
||||
|
||||
if (helper == NULL) {
|
||||
if (access(full_path, X_OK)) {
|
||||
uwsgi_error("access()");
|
||||
uwsgi_cgi_403(wsgi_req);
|
||||
if (need_free)
|
||||
free(docroot);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pipe(cgi_pipe)) {
|
||||
if (need_free)
|
||||
free(docroot);
|
||||
uwsgi_error("pipe()");
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
cgi_pid = fork();
|
||||
|
||||
if (cgi_pid < 0) {
|
||||
uwsgi_error("fork()");
|
||||
if (need_free)
|
||||
free(docroot);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cgi_pid > 0) {
|
||||
// close input
|
||||
close(wsgi_req->poll.fd);
|
||||
wsgi_req->fd_closed = 1;
|
||||
|
||||
// now wait for fd
|
||||
if (waitpid(cgi_pid, &waitpid_status ,0) > 0) {
|
||||
uwsgi_log("CGI FINISHED\n");
|
||||
if (need_free)
|
||||
free(docroot);
|
||||
|
||||
close(cgi_pipe[1]);
|
||||
// wait for data
|
||||
char *headers_buf = uwsgi_malloc(uc.buffer_size);
|
||||
char *ptr = headers_buf;
|
||||
size_t remains = uc.buffer_size;
|
||||
int completed = 0;
|
||||
while(remains > 0) {
|
||||
int ret = uwsgi_waitfd(cgi_pipe[0], uc.timeout);
|
||||
if (ret > 0) {
|
||||
len = read(cgi_pipe[0], ptr, remains);
|
||||
if (len > 0) {
|
||||
ptr+=len;
|
||||
remains -= len;
|
||||
}
|
||||
else if (len == 0) {
|
||||
completed = 1;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
uwsgi_error("read()");
|
||||
goto clear;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (ret == 0) {
|
||||
uwsgi_log("CGI timeout !!!\n");
|
||||
goto clear;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
||||
if (uwsgi_cgi_parse(wsgi_req, headers_buf, uc.buffer_size-remains)) {
|
||||
uwsgi_log("invalid CGI output !!!\n");
|
||||
goto clear;
|
||||
}
|
||||
|
||||
while (!completed) {
|
||||
int ret = uwsgi_waitfd(cgi_pipe[0], uc.timeout);
|
||||
if (ret > 0) {
|
||||
len = read(cgi_pipe[0], headers_buf, uc.buffer_size);
|
||||
if (len > 0) {
|
||||
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, headers_buf, len);
|
||||
}
|
||||
// end of output
|
||||
else if (len == 0) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
uwsgi_error("read()");
|
||||
goto clear;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (ret == 0) {
|
||||
uwsgi_log("CGI timeout !!!\n");
|
||||
goto clear;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
clear:
|
||||
free(headers_buf);
|
||||
close(cgi_pipe[0]);
|
||||
|
||||
// now wait for process exit/death
|
||||
if (waitpid(cgi_pid, &waitpid_status, 0) < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
}
|
||||
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
// close all the fd except wsgi_req->poll.fd and 2;
|
||||
|
||||
for(i=0;i< (int)uwsgi.max_fd;i++) {
|
||||
if (i != wsgi_req->poll.fd && i != 2) {
|
||||
if (i != wsgi_req->poll.fd && i != 2 && i != cgi_pipe[1]) {
|
||||
close(i);
|
||||
}
|
||||
}
|
||||
|
||||
// now map wsgi_req->poll.fd to 0 && 1
|
||||
// now map wsgi_req->poll.fd to 0 & cgi_pipe[1] to 1
|
||||
if (wsgi_req->poll.fd != 0) {
|
||||
dup2(wsgi_req->poll.fd, 0);
|
||||
close(wsgi_req->poll.fd);
|
||||
}
|
||||
|
||||
dup2(0,1);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("mapping cgi_pipe %d to 1\n", cgi_pipe[1]);
|
||||
#endif
|
||||
|
||||
dup2(cgi_pipe[1],1);
|
||||
|
||||
// fill cgi env
|
||||
for(i=0;i<wsgi_req->var_cnt;i++) {
|
||||
// no need to free the putenv() memory
|
||||
@@ -92,19 +727,110 @@ int uwsgi_cgi_request(struct wsgi_request *wsgi_req) {
|
||||
i++;
|
||||
}
|
||||
|
||||
char *path_info = uwsgi_concat4n(cgi_docroot, strlen(cgi_docroot), "/", 1,wsgi_req->path_info, wsgi_req->path_info_len, "", 0);
|
||||
uwsgi_log("requested %s %s\n", path_info, realpath(path_info, full_path));
|
||||
|
||||
argv[0] = full_path;
|
||||
argv[1] = NULL;
|
||||
if (execv(argv[0], argv)) {
|
||||
uwsgi_error("execv()");
|
||||
if (setenv("GATEWAY_INTERFACE", "CGI/1.1", 0)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
|
||||
if (setenv("SERVER_SOFTWARE", uwsgi_concat2("uWSGI/", UWSGI_VERSION), 0)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
|
||||
// for newer php
|
||||
if (setenv("REDIRECT_STATUS", "200", 0)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
|
||||
if (path_info && wsgi_req->path_info_len-discard_base > 0) {
|
||||
if (setenv("PATH_INFO", uwsgi_concat2n(path_info, wsgi_req->path_info_len-discard_base, "", 0), 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
|
||||
if (setenv("PATH_TRANSLATED", uwsgi_concat4n(docroot, docroot_len, "/", 1, path_info, wsgi_req->path_info_len-discard_base, "", 0) , 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
}
|
||||
else {
|
||||
unsetenv("PATH_INFO");
|
||||
unsetenv("PATH_TRANSLATED");
|
||||
}
|
||||
|
||||
if (is_a_file) {
|
||||
if (setenv("DOCUMENT_ROOT", uwsgi.cwd, 0)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
|
||||
if (setenv("SCRIPT_FILENAME", docroot, 0)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
|
||||
if (script_name && discard_base > 1) {
|
||||
if (setenv("SCRIPT_NAME", uwsgi_concat2n(script_name, discard_base, "", 0), 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (setenv("DOCUMENT_ROOT", docroot, 0)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
|
||||
if (setenv("SCRIPT_FILENAME", full_path, 0)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
|
||||
if (setenv("SCRIPT_NAME", full_path+(docroot_len-discard_base), 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
|
||||
char *base = uwsgi_get_last_char(full_path, '/');
|
||||
if (base) {
|
||||
// a little trick :P
|
||||
*base = 0;
|
||||
if (chdir(full_path)) {
|
||||
uwsgi_error("chdir()");
|
||||
}
|
||||
*base = '/';
|
||||
}
|
||||
else {
|
||||
if (chdir(docroot)) {
|
||||
uwsgi_error("chdir()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_string_list *drop_env = uc.unset;
|
||||
while(drop_env) {
|
||||
unsetenv(drop_env->value);
|
||||
drop_env = drop_env->next;
|
||||
}
|
||||
|
||||
if (helper) {
|
||||
if (!uwsgi_starts_with(helper, strlen(helper), "sym://", 6)) {
|
||||
void (*cgi_func)(char *) = dlsym(RTLD_DEFAULT, helper+6);
|
||||
if (cgi_func) {
|
||||
cgi_func(command);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("unable to find symbol %s\n", helper+6);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
argv[0] = helper;
|
||||
argv[1] = command;
|
||||
argv[2] = NULL;
|
||||
}
|
||||
else {
|
||||
argv[0] = command;
|
||||
argv[1] = NULL;
|
||||
}
|
||||
|
||||
if (execvp(argv[0], argv)) {
|
||||
uwsgi_error("execvp()");
|
||||
}
|
||||
|
||||
// never here
|
||||
exit(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -116,10 +842,44 @@ void uwsgi_cgi_after_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
int uwsgi_cgi_manage_options(int i, char *optarg) {
|
||||
|
||||
char *value;
|
||||
|
||||
switch(i) {
|
||||
case LONG_ARGS_CGI:
|
||||
cgi_docroot = optarg;
|
||||
value = strchr(optarg, '=');
|
||||
if (!value) {
|
||||
uwsgi_dyn_dict_new(&uc.mountpoint, optarg, strlen(optarg), NULL, 0);
|
||||
}
|
||||
else {
|
||||
uwsgi_dyn_dict_new(&uc.mountpoint, optarg, value-optarg, value+1, strlen(value+1));
|
||||
}
|
||||
return 1;
|
||||
case LONG_ARGS_CGI_BUFFER_SIZE:
|
||||
uc.buffer_size = atoi(optarg);
|
||||
return 1;
|
||||
case LONG_ARGS_CGI_TIMEOUT:
|
||||
uc.timeout = atoi(optarg);
|
||||
return 1;
|
||||
case LONG_ARGS_CGI_INDEX:
|
||||
uwsgi_string_new_list(&uc.index, optarg);
|
||||
return 1;
|
||||
case LONG_ARGS_CGI_ALLOWED_EXT:
|
||||
uwsgi_string_new_list(&uc.allowed_ext, optarg);
|
||||
return 1;
|
||||
case LONG_ARGS_CGI_LOADLIB:
|
||||
uwsgi_string_new_list(&uc.loadlib, uwsgi_str(optarg));
|
||||
return 1;
|
||||
case LONG_ARGS_CGI_UNSET:
|
||||
uwsgi_string_new_list(&uc.unset, optarg);
|
||||
return 1;
|
||||
case LONG_ARGS_CGI_MAP_HELPER:
|
||||
value = strchr(optarg, '=');
|
||||
if (!value) {
|
||||
uwsgi_log("invalid CGI helper syntax, must be ext=command\n");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_dyn_dict_new(&uc.helpers, optarg, value-optarg, value+1, strlen(value+1));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -131,6 +891,7 @@ struct uwsgi_plugin cgi_plugin = {
|
||||
.name = "cgi",
|
||||
.modifier1 = 9,
|
||||
.init = uwsgi_cgi_init,
|
||||
.init_apps = uwsgi_cgi_apps,
|
||||
.options = uwsgi_cgi_options,
|
||||
.manage_opt = uwsgi_cgi_manage_options,
|
||||
.request = uwsgi_cgi_request,
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
class FakeClass {
|
||||
|
||||
public:
|
||||
char *foobar;
|
||||
uint16_t foobar_len;
|
||||
void hello_world(struct wsgi_request *);
|
||||
|
||||
};
|
||||
|
||||
void FakeClass::hello_world(struct wsgi_request *wsgi_req) {
|
||||
|
||||
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, (char *) "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n", 44);
|
||||
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, foobar, foobar_len);
|
||||
}
|
||||
|
||||
extern "C" int uwsgi_cplusplus_init(){
|
||||
uwsgi_log("Initializing example c++ plugin\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int uwsgi_cplusplus_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
FakeClass *fc;
|
||||
|
||||
// empty request ?
|
||||
if (!wsgi_req->uh.pktsize) {
|
||||
uwsgi_log( "Invalid request. skip.\n");
|
||||
goto clear;
|
||||
}
|
||||
|
||||
// get uwsgi variables
|
||||
if (uwsgi_parse_vars(wsgi_req)) {
|
||||
uwsgi_log("Invalid request. skip.\n");
|
||||
goto clear;
|
||||
}
|
||||
|
||||
fc = new FakeClass();
|
||||
// get PATH_INFO
|
||||
fc->foobar = uwsgi_get_var(wsgi_req, (char *) "PATH_INFO", 9, &fc->foobar_len);
|
||||
|
||||
if (fc->foobar) {
|
||||
// send output
|
||||
fc->hello_world(wsgi_req);
|
||||
}
|
||||
|
||||
delete fc;
|
||||
|
||||
clear:
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
|
||||
extern "C" void uwsgi_cplusplus_after_request(struct wsgi_request *wsgi_req) {
|
||||
uwsgi_log("logging c++ request\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
|
||||
int uwsgi_cplusplus_init(void);
|
||||
int uwsgi_cplusplus_request(struct wsgi_request *);
|
||||
void uwsgi_cplusplus_after_request(struct wsgi_request *);
|
||||
|
||||
struct uwsgi_plugin cplusplus_plugin = {
|
||||
|
||||
.name = "cplusplus",
|
||||
.modifier1 = 250,
|
||||
.init = uwsgi_cplusplus_init,
|
||||
.request = uwsgi_cplusplus_request,
|
||||
.after_request = uwsgi_cplusplus_after_request,
|
||||
|
||||
};
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
NAME='cplusplus'
|
||||
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = ['-lstdc++']
|
||||
GCC_LIST = ['base.cc', 'plugin']
|
||||
@@ -5,7 +5,7 @@ extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_echo_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
wsgi_req->response_size = wsgi_req->socket_proto_write(wsgi_req, wsgi_req->buffer, wsgi_req->uh.pktsize);
|
||||
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, wsgi_req->buffer, wsgi_req->uh.pktsize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+31
-28
@@ -94,8 +94,9 @@ void uwsgi_erlang_rpc(int fd, erlang_pid *from, ei_x_buff *x) {
|
||||
char *call;
|
||||
char buffer[0xffff];
|
||||
|
||||
char *argv[0xff] ;
|
||||
int argc;
|
||||
char *argv[256] ;
|
||||
uint16_t argvs[256] ;
|
||||
int argc = 0;
|
||||
uint16_t ret;
|
||||
ei_x_buff xr;
|
||||
|
||||
@@ -103,19 +104,20 @@ void uwsgi_erlang_rpc(int fd, erlang_pid *from, ei_x_buff *x) {
|
||||
|
||||
ei_get_type(x->buff, &x->index, &etype, &esize);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%d %c %c %c\n", etype, etype, ERL_SMALL_TUPLE_EXT, ERL_LARGE_TUPLE_EXT);
|
||||
#endif
|
||||
if (etype != ERL_SMALL_TUPLE_EXT && etype != ERL_LARGE_TUPLE_EXT) return;
|
||||
|
||||
uwsgi_log("decode tuple\n");
|
||||
ei_decode_tuple_header(x->buff, &x->index, &arity);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("rpc arity %d\n", arity);
|
||||
#endif
|
||||
if (arity != 3) return ;
|
||||
|
||||
ei_get_type(x->buff, &x->index, &etype, &esize);
|
||||
|
||||
uwsgi_log("%d %c\n", etype, etype);
|
||||
|
||||
if (etype != ERL_ATOM_EXT && etype != ERL_STRING_EXT) return ;
|
||||
|
||||
gen_call = uwsgi_malloc(esize);
|
||||
@@ -127,7 +129,9 @@ void uwsgi_erlang_rpc(int fd, erlang_pid *from, ei_x_buff *x) {
|
||||
ei_decode_string(x->buff, &x->index, gen_call);
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("gen call = %s\n", gen_call);
|
||||
#endif
|
||||
|
||||
ei_get_type(x->buff, &x->index, &etype, &esize);
|
||||
|
||||
@@ -138,13 +142,10 @@ void uwsgi_erlang_rpc(int fd, erlang_pid *from, ei_x_buff *x) {
|
||||
|
||||
ei_get_type(x->buff, &x->index, &etype, &esize);
|
||||
ei_skip_term(x->buff, &x->index);
|
||||
uwsgi_log("skip0 %d %c\n", etype, etype);
|
||||
ei_get_type(x->buff, &x->index, &etype, &esize);
|
||||
uwsgi_log("skip1 %d %c\n", etype, etype);
|
||||
ei_decode_ref(x->buff, &x->index, &eref);
|
||||
|
||||
ei_get_type(x->buff, &x->index, &etype, &esize);
|
||||
uwsgi_log("%d %c\n", etype, etype);
|
||||
|
||||
module = uwsgi_malloc(esize);
|
||||
|
||||
@@ -157,17 +158,16 @@ void uwsgi_erlang_rpc(int fd, erlang_pid *from, ei_x_buff *x) {
|
||||
|
||||
ei_get_type(x->buff, &x->index, &etype, &esize);
|
||||
|
||||
uwsgi_log("%d %c\n", etype, etype);
|
||||
|
||||
if (etype != ERL_SMALL_TUPLE_EXT) return ;
|
||||
|
||||
ei_decode_tuple_header(x->buff, &x->index, &arity);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("arity: %d\n", arity);
|
||||
#endif
|
||||
if (arity != 5) return ;
|
||||
|
||||
ei_get_type(x->buff, &x->index, &etype, &esize);
|
||||
uwsgi_log("%d %c\n", etype, etype);
|
||||
|
||||
char *method = uwsgi_malloc(esize);
|
||||
|
||||
@@ -181,7 +181,6 @@ void uwsgi_erlang_rpc(int fd, erlang_pid *from, ei_x_buff *x) {
|
||||
if (strcmp(method, "call")) return;
|
||||
|
||||
ei_get_type(x->buff, &x->index, &etype, &esize);
|
||||
uwsgi_log("%d %c\n", etype, etype);
|
||||
|
||||
if (etype != ERL_ATOM_EXT && etype != ERL_STRING_EXT) return ;
|
||||
|
||||
@@ -207,7 +206,9 @@ void uwsgi_erlang_rpc(int fd, erlang_pid *from, ei_x_buff *x) {
|
||||
ei_decode_string(x->buff, &x->index, call);
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("RPC %s %s\n", module, call);
|
||||
#endif
|
||||
|
||||
ei_get_type(x->buff, &x->index, &etype, &esize);
|
||||
|
||||
@@ -215,16 +216,20 @@ void uwsgi_erlang_rpc(int fd, erlang_pid *from, ei_x_buff *x) {
|
||||
argc = 1;
|
||||
argv[0] = uwsgi_malloc(esize+1);
|
||||
ei_decode_atom(x->buff, &x->index, argv[0]);
|
||||
argvs[1] = esize;
|
||||
}
|
||||
else if (etype == ERL_STRING_EXT) {
|
||||
argc = 1;
|
||||
argv[0] = uwsgi_malloc(esize+1);
|
||||
ei_decode_string(x->buff, &x->index, argv[0]);
|
||||
argvs[1] = esize;
|
||||
}
|
||||
|
||||
ret = uwsgi_rpc(call, argc, argv, buffer);
|
||||
ret = uwsgi_rpc(call, argc, argv, argvs, buffer);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("buffer: %.*s\n", ret, buffer);
|
||||
#endif
|
||||
|
||||
ei_x_new_with_version(&xr);
|
||||
|
||||
@@ -247,7 +252,6 @@ void erlang_loop() {
|
||||
int fd;
|
||||
|
||||
int eversion;
|
||||
int i;
|
||||
|
||||
ei_x_buff x, xr;
|
||||
|
||||
@@ -286,7 +290,7 @@ void erlang_loop() {
|
||||
if (em.msgtype == ERL_TICK)
|
||||
continue;
|
||||
|
||||
uwsgi_log("From: %s To: %s RegName: %s\n", em.from.node, em.to.node, em.toname);
|
||||
uwsgi_log("[erlang] message From: %s To (process): %s\n", em.from.node, em.toname);
|
||||
|
||||
|
||||
|
||||
@@ -300,20 +304,18 @@ void erlang_loop() {
|
||||
uwsgi_erlang_rpc(fd, &em.from, &x);
|
||||
}
|
||||
else {
|
||||
int uep = -1;
|
||||
for(i=0;i<uerl.uep_cnt;i++) {
|
||||
if (!strcmp(uerl.uep[i].name, em.toname)) {
|
||||
uep = i;
|
||||
struct uwsgi_erlang_process *uep = uerl.uep;
|
||||
while(uep) {
|
||||
if (!strcmp(uep->name, em.toname)) {
|
||||
if (uep->plugin) {
|
||||
uep->plugin(uep->func, &x);
|
||||
}
|
||||
break;
|
||||
}
|
||||
uep = uep->next;
|
||||
}
|
||||
|
||||
if (uep > -1) {
|
||||
if (uerl.uep[uep].plugin) {
|
||||
uerl.uep[uep].plugin( uerl.uep[uep].func, &x );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!uep) {
|
||||
uwsgi_log("!!! unregistered erlang process requested, dumping it !!!\n");
|
||||
dump_eterm(&x);
|
||||
}
|
||||
@@ -366,7 +368,6 @@ int erlang_init() {
|
||||
|
||||
if (uerl.name) {
|
||||
|
||||
uwsgi.master_process = 1;
|
||||
|
||||
host = strchr(uerl.name, '@');
|
||||
|
||||
@@ -422,10 +423,11 @@ int erlang_init() {
|
||||
uwsgi_log("Erlang C-Node %s registered on port %d\n", ei_thisnodename(&uerl.cnode), ntohs(sin.sin_port));
|
||||
|
||||
|
||||
if (register_fat_gateway("erlang", erlang_loop) == NULL) {
|
||||
if (register_fat_gateway("uWSGI erlang c-node", erlang_loop) == NULL) {
|
||||
uwsgi_log("unable to register the erlang gateway\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -435,7 +437,8 @@ int erlang_opt(int i, char *optarg) {
|
||||
|
||||
switch(i) {
|
||||
case LONG_ARGS_ERLANG:
|
||||
uerl.name = optarg;
|
||||
uwsgi.master_process = 1;
|
||||
uerl.name = optarg;
|
||||
return 1;
|
||||
case LONG_ARGS_ERLANG_COOKIE:
|
||||
uerl.cookie = optarg;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#include <ei.h>
|
||||
|
||||
#define MAX_UWSGI_ERLANG_PROCESSES 64
|
||||
|
||||
#define LONG_ARGS_ERLANG 17012
|
||||
#define LONG_ARGS_ERLANG_COOKIE 17013
|
||||
|
||||
@@ -12,6 +10,8 @@ struct uwsgi_erlang_process {
|
||||
char name[0xff];
|
||||
void (*plugin)(void *, ei_x_buff *);
|
||||
void *func;
|
||||
|
||||
struct uwsgi_erlang_process *next;
|
||||
};
|
||||
|
||||
struct uwsgi_erlang {
|
||||
@@ -24,7 +24,6 @@ struct uwsgi_erlang {
|
||||
|
||||
void *lock;
|
||||
|
||||
struct uwsgi_erlang_process uep[MAX_UWSGI_ERLANG_PROCESSES];
|
||||
int uep_cnt;
|
||||
struct uwsgi_erlang_process *uep;
|
||||
};
|
||||
|
||||
|
||||
@@ -2,21 +2,33 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_init(char *args){
|
||||
uwsgi_log("i am the example plugin initialization function with arg: %s\n", args);
|
||||
int uwsgi_example_init(){
|
||||
uwsgi_log("i am the example plugin initialization function\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_request(struct wsgi_request *wsgi_req) {
|
||||
int uwsgi_example_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
char *http = "HTTP/1.1 200 Ok\r\nContent-type: text/html\r\n\r\n<h1>Hello World</h1>";
|
||||
|
||||
wsgi_req->response_size += wsgi_req->socket_proto_write(wsgi_req, http, strlen(http));
|
||||
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, http, strlen(http));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_after_request(struct wsgi_request *wsgi_req) {
|
||||
void uwsgi_example_after_request(struct wsgi_request *wsgi_req) {
|
||||
uwsgi_log("i am the example plugin after request function\n");
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_plugin example_plugin = {
|
||||
|
||||
.name = "example",
|
||||
.modifier1 = 250,
|
||||
.init = uwsgi_example_init,
|
||||
.request = uwsgi_example_request,
|
||||
.after_request = uwsgi_example_after_request,
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
NAME='example'
|
||||
CFLAGS = ''
|
||||
LDFLAGS = ''
|
||||
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
GCC_LIST = ['example_plugin']
|
||||
|
||||
+369
-36
@@ -19,6 +19,10 @@
|
||||
#define LONG_ARGS_FASTROUTER_SUBSCRIPTION_SERVER 150005
|
||||
#define LONG_ARGS_FASTROUTER_TIMEOUT 150006
|
||||
#define LONG_ARGS_FASTROUTER_SUBSCRIPTION_SLOT 150007
|
||||
#define LONG_ARGS_FASTROUTER_USE_CODE_STRING 150008
|
||||
#define LONG_ARGS_FASTROUTER_TOLERANCE 150009
|
||||
#define LONG_ARGS_FASTROUTER_STATS 150010
|
||||
#define LONG_ARGS_FASTROUTER_ZERG 150011
|
||||
|
||||
#define FASTROUTER_STATUS_FREE 0
|
||||
#define FASTROUTER_STATUS_CONNECTING 1
|
||||
@@ -27,11 +31,16 @@
|
||||
#define FASTROUTER_STATUS_RESPONSE 4
|
||||
|
||||
#define add_timeout(x) uwsgi_add_rb_timer(ufr.timeouts, time(NULL)+ufr.socket_timeout, x)
|
||||
#define add_check_timeout(x) uwsgi_add_rb_timer(ufr.timeouts, time(NULL)+x, NULL)
|
||||
#define del_check_timeout(x) rb_erase(&x->rbt, ufr.timeouts);
|
||||
#define del_timeout(x) rb_erase(&x->timeout->rbt, ufr.timeouts); free(x->timeout);
|
||||
|
||||
void fastrouter_send_stats(int);
|
||||
|
||||
struct uwsgi_fastrouter_socket {
|
||||
char *name;
|
||||
int fd;
|
||||
char *zerg;
|
||||
struct uwsgi_fastrouter_socket *next;
|
||||
};
|
||||
|
||||
@@ -42,6 +51,8 @@ struct uwsgi_fastrouter {
|
||||
int use_cache;
|
||||
int nevents;
|
||||
|
||||
int queue;
|
||||
|
||||
int subscription_slot;
|
||||
|
||||
char *pattern;
|
||||
@@ -50,16 +61,41 @@ struct uwsgi_fastrouter {
|
||||
char *base;
|
||||
int base_len;
|
||||
|
||||
char *stats_server;
|
||||
|
||||
char *subscription_server;
|
||||
struct uwsgi_dict *subscription_dict;
|
||||
struct uwsgi_subscribe_slot *subscriptions;
|
||||
int subscription_regexp;
|
||||
|
||||
int socket_timeout;
|
||||
|
||||
uint8_t code_string_modifier1;
|
||||
char *code_string_code;
|
||||
char *code_string_function;
|
||||
|
||||
struct rb_root *timeouts;
|
||||
|
||||
struct uwsgi_rb_timer *subscriptions_check;
|
||||
|
||||
int cheap;
|
||||
int i_am_cheap;
|
||||
|
||||
int tolerance;
|
||||
} ufr;
|
||||
|
||||
static void fastrouter_go_cheap(void) {
|
||||
|
||||
static struct uwsgi_fastrouter_socket *uwsgi_fastrouter_new_socket(char *name) {
|
||||
uwsgi_log("[uwsgi-fastrouter] no more nodes available. Going cheap...\n");
|
||||
struct uwsgi_fastrouter_socket *ufr_sock = ufr.sockets;
|
||||
while(ufr_sock) {
|
||||
event_queue_del_fd(ufr.queue, ufr_sock->fd, event_queue_read());
|
||||
ufr_sock = ufr_sock->next;
|
||||
}
|
||||
ufr.i_am_cheap = 1;
|
||||
}
|
||||
|
||||
|
||||
static struct uwsgi_fastrouter_socket *uwsgi_fastrouter_new_socket(char *name, int fd) {
|
||||
|
||||
struct uwsgi_fastrouter_socket *uwsgi_sock = ufr.sockets, *old_uwsgi_sock;
|
||||
|
||||
@@ -79,6 +115,12 @@ static struct uwsgi_fastrouter_socket *uwsgi_fastrouter_new_socket(char *name) {
|
||||
|
||||
memset(uwsgi_sock, 0, sizeof(struct uwsgi_fastrouter_socket));
|
||||
uwsgi_sock->name = name;
|
||||
if (name) {
|
||||
uwsgi_sock->fd = -1;
|
||||
}
|
||||
else {
|
||||
uwsgi_sock->fd = fd;
|
||||
}
|
||||
|
||||
return uwsgi_sock;
|
||||
}
|
||||
@@ -87,13 +129,20 @@ static struct uwsgi_fastrouter_socket *uwsgi_fastrouter_new_socket(char *name) {
|
||||
|
||||
struct option fastrouter_options[] = {
|
||||
{"fastrouter", required_argument, 0, LONG_ARGS_FASTROUTER},
|
||||
{"fastrouter-zerg", required_argument, 0, LONG_ARGS_FASTROUTER_ZERG},
|
||||
{"fastrouter-use-cache", no_argument, &ufr.use_cache, 1},
|
||||
{"fastrouter-use-pattern", required_argument, 0, LONG_ARGS_FASTROUTER_USE_PATTERN},
|
||||
{"fastrouter-use-base", required_argument, 0, LONG_ARGS_FASTROUTER_USE_BASE},
|
||||
{"fastrouter-use-code-string", required_argument, 0, LONG_ARGS_FASTROUTER_USE_CODE_STRING},
|
||||
{"fastrouter-events", required_argument, 0, LONG_ARGS_FASTROUTER_EVENTS},
|
||||
{"fastrouter-cheap", no_argument, &ufr.cheap, 1},
|
||||
{"fastrouter-subscription-server", required_argument, 0, LONG_ARGS_FASTROUTER_SUBSCRIPTION_SERVER},
|
||||
{"fastrouter-subscription-slot", required_argument, 0, LONG_ARGS_FASTROUTER_SUBSCRIPTION_SLOT},
|
||||
{"fastrouter-subscription-use-regexp", no_argument, &ufr.subscription_regexp, 1},
|
||||
{"fastrouter-timeout", required_argument, 0, LONG_ARGS_FASTROUTER_TIMEOUT},
|
||||
{"fastrouter-stats", required_argument, 0, LONG_ARGS_FASTROUTER_STATS},
|
||||
{"fastrouter-stats-server", required_argument, 0, LONG_ARGS_FASTROUTER_STATS},
|
||||
{"fastrouter-ss", required_argument, 0, LONG_ARGS_FASTROUTER_STATS},
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
@@ -111,6 +160,15 @@ void fastrouter_manage_subscription(char *key, uint16_t keylen, char *val, uint1
|
||||
usr->address = val;
|
||||
usr->address_len = vallen;
|
||||
}
|
||||
else if (!uwsgi_strncmp("modifier1", 9, key, keylen)) {
|
||||
usr->modifier1 = uwsgi_str_num(val, vallen);
|
||||
}
|
||||
else if (!uwsgi_strncmp("cores", 5, key, keylen)) {
|
||||
usr->cores = uwsgi_str_num(val, vallen);
|
||||
}
|
||||
else if (!uwsgi_strncmp("load", 4, key, keylen)) {
|
||||
usr->load = uwsgi_str_num(val, vallen);
|
||||
}
|
||||
}
|
||||
|
||||
struct fastrouter_session {
|
||||
@@ -120,31 +178,58 @@ struct fastrouter_session {
|
||||
int status;
|
||||
struct uwsgi_header uh;
|
||||
uint8_t h_pos;
|
||||
char buffer[0xffff];
|
||||
uint16_t pos;
|
||||
|
||||
char *hostname;
|
||||
uint16_t hostname_len;
|
||||
|
||||
int has_key;
|
||||
|
||||
char *instance_address;
|
||||
uint64_t instance_address_len;
|
||||
|
||||
struct uwsgi_subscriber_name *un;
|
||||
struct uwsgi_subscribe_node *un;
|
||||
int pass_fd;
|
||||
|
||||
struct uwsgi_rb_timer *timeout;
|
||||
int instance_failed;
|
||||
|
||||
uint8_t modifier1;
|
||||
|
||||
char buffer[0xffff];
|
||||
};
|
||||
|
||||
static void close_session(struct fastrouter_session **fr_table, struct fastrouter_session *fr_session) {
|
||||
|
||||
close(fr_session->fd);
|
||||
fr_table[fr_session->fd] = NULL;
|
||||
if (fr_session->instance_fd != -1) {
|
||||
if (ufr.subscription_server && (fr_session->instance_failed || fr_session->status == FASTROUTER_STATUS_CONNECTING)) {
|
||||
uwsgi_log("marking %.*s as failed\n", (int) fr_session->instance_address_len,fr_session->instance_address);
|
||||
fr_session->un->len = 0;
|
||||
|
||||
if (ufr.subscriptions && fr_session->un && fr_session->un->len > 0) {
|
||||
// decrease reference count
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("[1] node %.*s refcnt: %llu\n", fr_session->un->len, fr_session->un->name, fr_session->un->reference);
|
||||
#endif
|
||||
fr_session->un->reference--;
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("[2] node %.*s refcnt: %llu\n", fr_session->un->len, fr_session->un->name, fr_session->un->reference);
|
||||
#endif
|
||||
if (fr_session->instance_failed || fr_session->status == FASTROUTER_STATUS_CONNECTING) {
|
||||
if (fr_session->un->death_mark == 0)
|
||||
uwsgi_log("[uwsgi-fastrouter] %.*s => marking %.*s as failed\n", (int) fr_session->hostname_len, fr_session->hostname, (int) fr_session->instance_address_len,fr_session->instance_address);
|
||||
fr_session->un->failcnt++;
|
||||
fr_session->un->death_mark = 1;
|
||||
// check if i can remove the node
|
||||
if (fr_session->un->reference == 0) {
|
||||
uwsgi_remove_subscribe_node(&ufr.subscriptions, fr_session->un);
|
||||
}
|
||||
if (ufr.subscriptions == NULL && ufr.cheap && !ufr.i_am_cheap) {
|
||||
fastrouter_go_cheap();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (fr_session->instance_fd != -1) {
|
||||
close(fr_session->instance_fd);
|
||||
fr_table[fr_session->instance_fd] = NULL;
|
||||
}
|
||||
@@ -168,7 +253,6 @@ static void expire_timeouts(struct fastrouter_session **fr_table) {
|
||||
|
||||
if (urbt->key <= current) {
|
||||
close_session(fr_table, (struct fastrouter_session *)urbt->data);
|
||||
uwsgi_log("timeout !!!\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -187,7 +271,14 @@ void fr_get_hostname(char *key, uint16_t keylen, char *val, uint16_t vallen, voi
|
||||
return;
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("HTTP_HOST", 9, key, keylen)) {
|
||||
if (!uwsgi_strncmp("HTTP_HOST", 9, key, keylen) && !fr_session->has_key) {
|
||||
fr_session->hostname = val;
|
||||
fr_session->hostname_len = vallen;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("UWSGI_FASTROUTER_KEY", 20, key, keylen)) {
|
||||
fr_session->has_key = 1;
|
||||
fr_session->hostname = val;
|
||||
fr_session->hostname_len = vallen;
|
||||
return;
|
||||
@@ -201,7 +292,6 @@ struct fastrouter_session *alloc_fr_session() {
|
||||
|
||||
void fastrouter_loop() {
|
||||
|
||||
int fr_queue;
|
||||
int nevents;
|
||||
int interesting_fd;
|
||||
int new_connection;
|
||||
@@ -243,17 +333,21 @@ void fastrouter_loop() {
|
||||
socklen_t solen = sizeof(int);
|
||||
|
||||
int ufr_subserver = -1;
|
||||
int ufr_stats_server = -1;
|
||||
|
||||
for(i=0;i<2048;i++) {
|
||||
fr_table[i] = NULL;
|
||||
}
|
||||
|
||||
fr_queue = event_queue_init();
|
||||
ufr.queue = event_queue_init();
|
||||
|
||||
struct uwsgi_fastrouter_socket *ufr_sock = ufr.sockets;
|
||||
|
||||
while(ufr_sock) {
|
||||
if (ufr_sock->name[0] == '=') {
|
||||
if (ufr_sock->fd > -1) {
|
||||
ufr_sock->name = uwsgi_getsockname(ufr_sock->fd);
|
||||
}
|
||||
else if (ufr_sock->name[0] == '=') {
|
||||
int shared_socket = atoi(ufr_sock->name+1);
|
||||
if (shared_socket >= 0) {
|
||||
ufr_sock->fd = uwsgi_get_shared_socket_fd_by_num(shared_socket);
|
||||
@@ -272,27 +366,59 @@ void fastrouter_loop() {
|
||||
}
|
||||
}
|
||||
|
||||
event_queue_add_fd_read(fr_queue, ufr_sock->fd);
|
||||
if (ufr_sock->zerg) {
|
||||
uwsgi_log("uwsgi fastrouter/proxy bound on %s (from zerg server %s)\n", ufr_sock->name, ufr_sock->zerg);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("uwsgi fastrouter/proxy bound on %s\n", ufr_sock->name);
|
||||
}
|
||||
|
||||
if (!ufr.cheap) {
|
||||
event_queue_add_fd_read(ufr.queue, ufr_sock->fd);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[uwsgi-fastrouter] cheap mode requested. Waiting for subscriptions...\n");
|
||||
ufr.i_am_cheap = 1;
|
||||
}
|
||||
ufr_sock = ufr_sock->next;
|
||||
}
|
||||
|
||||
|
||||
events = event_queue_alloc(ufr.nevents);
|
||||
|
||||
ufr.timeouts = uwsgi_init_rb_timer();
|
||||
if (!ufr.socket_timeout) ufr.socket_timeout = 30;
|
||||
|
||||
|
||||
if (ufr.subscription_server) {
|
||||
ufr_subserver = bind_to_udp(ufr.subscription_server, 0, 0);
|
||||
event_queue_add_fd_read(fr_queue, ufr_subserver);
|
||||
event_queue_add_fd_read(ufr.queue, ufr_subserver);
|
||||
if (!ufr.subscription_slot) ufr.subscription_slot = 30;
|
||||
ufr.subscription_dict = uwsgi_dict_create(ufr.subscription_slot, 0);
|
||||
// check for node status every 10 seconds
|
||||
//ufr.subscriptions_check = add_check_timeout(10);
|
||||
}
|
||||
|
||||
if (ufr.stats_server) {
|
||||
char *tcp_port = strchr(ufr.stats_server, ':');
|
||||
if (tcp_port) {
|
||||
// disable deferred accept for this socket
|
||||
int current_defer_accept = uwsgi.no_defer_accept;
|
||||
uwsgi.no_defer_accept = 1;
|
||||
ufr_stats_server = bind_to_tcp(ufr.stats_server, uwsgi.listen_queue, tcp_port);
|
||||
uwsgi.no_defer_accept = current_defer_accept;
|
||||
}
|
||||
else {
|
||||
ufr_stats_server = bind_to_unix(ufr.stats_server, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
|
||||
}
|
||||
|
||||
event_queue_add_fd_read(ufr.queue, ufr_stats_server);
|
||||
uwsgi_log("*** FastRouter stats server enabled on %s fd: %d ***\n", ufr.stats_server, ufr_stats_server);
|
||||
}
|
||||
|
||||
if (ufr.pattern) {
|
||||
init_magic_table(magic_table);
|
||||
}
|
||||
|
||||
ufr.timeouts = uwsgi_init_rb_timer();
|
||||
if (!ufr.socket_timeout) ufr.socket_timeout = 30;
|
||||
|
||||
for (;;) {
|
||||
|
||||
@@ -308,7 +434,7 @@ void fastrouter_loop() {
|
||||
}
|
||||
}
|
||||
|
||||
nevents = event_queue_wait_multi(fr_queue, delta, events, ufr.nevents);
|
||||
nevents = event_queue_wait_multi(ufr.queue, delta, events, ufr.nevents);
|
||||
|
||||
if (nevents == 0) {
|
||||
expire_timeouts(fr_table);
|
||||
@@ -335,12 +461,15 @@ void fastrouter_loop() {
|
||||
fr_table[new_connection]->status = FASTROUTER_STATUS_RECV_HDR;
|
||||
fr_table[new_connection]->h_pos = 0;
|
||||
fr_table[new_connection]->pos = 0;
|
||||
fr_table[new_connection]->un = NULL;
|
||||
fr_table[new_connection]->instance_failed = 0;
|
||||
fr_table[new_connection]->instance_address_len = 0;
|
||||
fr_table[new_connection]->hostname_len = 0;
|
||||
fr_table[new_connection]->hostname = NULL;
|
||||
|
||||
fr_table[new_connection]->timeout = add_timeout(fr_table[new_connection]);
|
||||
|
||||
event_queue_add_fd_read(fr_queue, new_connection);
|
||||
event_queue_add_fd_read(ufr.queue, new_connection);
|
||||
taken = 1;
|
||||
break;
|
||||
}
|
||||
@@ -352,15 +481,46 @@ void fastrouter_loop() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (interesting_fd == ufr_subserver) {
|
||||
if (interesting_fd == ufr_stats_server) {
|
||||
fastrouter_send_stats(ufr_stats_server);
|
||||
}
|
||||
else if (interesting_fd == ufr_subserver) {
|
||||
len = recv(ufr_subserver, bbuf, 4096, 0);
|
||||
#ifdef UWSGI_EVENT_USE_PORT
|
||||
event_queue_add_fd_read(fr_queue, ufr_subserver);
|
||||
event_queue_add_fd_read(ufr.queue, ufr_subserver);
|
||||
#endif
|
||||
if (len > 0) {
|
||||
memset(&usr, 0, sizeof(struct uwsgi_subscribe_req));
|
||||
uwsgi_hooked_parse(bbuf+4, len-4, fastrouter_manage_subscription, &usr);
|
||||
uwsgi_add_subscriber(ufr.subscription_dict, usr.key, usr.keylen, usr.address, usr.address_len);
|
||||
// subscribe request ?
|
||||
if (bbuf[3] == 0) {
|
||||
if (uwsgi_add_subscribe_node(&ufr.subscriptions, &usr, ufr.subscription_regexp) && ufr.i_am_cheap) {
|
||||
struct uwsgi_fastrouter_socket *ufr_sock = ufr.sockets;
|
||||
while(ufr_sock) {
|
||||
event_queue_add_fd_read(ufr.queue, ufr_sock->fd);
|
||||
ufr_sock = ufr_sock->next;
|
||||
}
|
||||
ufr.i_am_cheap = 0;
|
||||
uwsgi_log("[uwsgi-fastrouter] leaving cheap mode...\n");
|
||||
}
|
||||
}
|
||||
//unsubscribe
|
||||
else {
|
||||
struct uwsgi_subscribe_node *node = uwsgi_get_subscribe_node_by_name(&ufr.subscriptions, usr.key, usr.keylen, usr.address, usr.address_len, ufr.subscription_regexp);
|
||||
if (node && node->len) {
|
||||
if (node->death_mark == 0)
|
||||
uwsgi_log("[uwsgi-fastrouter] %.*s => marking %.*s as failed\n", (int) usr.keylen, usr.key, (int) usr.address_len, usr.address);
|
||||
node->failcnt++;
|
||||
node->death_mark = 1;
|
||||
// check if i can remove the node
|
||||
if (node->reference == 0) {
|
||||
uwsgi_remove_subscribe_node(&ufr.subscriptions, node);
|
||||
}
|
||||
if (ufr.subscriptions == NULL && ufr.cheap && !ufr.i_am_cheap) {
|
||||
fastrouter_go_cheap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -381,7 +541,8 @@ void fastrouter_loop() {
|
||||
case FASTROUTER_STATUS_RECV_HDR:
|
||||
len = recv(fr_session->fd, (char *)(&fr_session->uh) + fr_session->h_pos, 4-fr_session->h_pos, 0);
|
||||
if (len <= 0) {
|
||||
uwsgi_error("recv()");
|
||||
if (len < 0)
|
||||
uwsgi_error("recv()");
|
||||
close_session(fr_table, fr_session);
|
||||
break;
|
||||
}
|
||||
@@ -414,9 +575,16 @@ void fastrouter_loop() {
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
//uwsgi_log("requested domain %.*s\n", fr_session->hostname_len, fr_session->hostname);
|
||||
#endif
|
||||
if (ufr.use_cache) {
|
||||
fr_session->instance_address = uwsgi_cache_get(fr_session->hostname, fr_session->hostname_len, &fr_session->instance_address_len);
|
||||
char *cs_mod = uwsgi_str_contains(fr_session->instance_address, fr_session->instance_address_len, ',');
|
||||
if (cs_mod) {
|
||||
fr_session->modifier1 = uwsgi_str_num(cs_mod+1, (fr_session->instance_address_len - (cs_mod - fr_session->instance_address))-1);
|
||||
fr_session->instance_address_len = (cs_mod - fr_session->instance_address);
|
||||
}
|
||||
}
|
||||
else if (ufr.pattern) {
|
||||
magic_table['s'] = uwsgi_concat2n(fr_session->hostname, fr_session->hostname_len, "", 0);
|
||||
@@ -426,17 +594,34 @@ void fastrouter_loop() {
|
||||
fr_session->instance_address = tmp_socket_name;
|
||||
}
|
||||
else if (ufr.subscription_server) {
|
||||
fr_session->un = uwsgi_get_subscriber(ufr.subscription_dict, fr_session->hostname, fr_session->hostname_len);
|
||||
fr_session->un = uwsgi_get_subscribe_node(&ufr.subscriptions, fr_session->hostname, fr_session->hostname_len, ufr.subscription_regexp);
|
||||
if (fr_session->un && fr_session->un->len) {
|
||||
fr_session->instance_address = fr_session->un->name;
|
||||
fr_session->instance_address_len = fr_session->un->len;
|
||||
fr_session->modifier1 = fr_session->un->modifier1;
|
||||
}
|
||||
else if (ufr.subscriptions == NULL && ufr.cheap && !ufr.i_am_cheap) {
|
||||
fastrouter_go_cheap();
|
||||
}
|
||||
}
|
||||
else if (ufr.base) {
|
||||
tmp_socket_name = uwsgi_concat2nn(ufr.base, ufr.base_len, fr_session->hostname, fr_session->hostname_len, &tmp_socket_name_len);
|
||||
fr_session->instance_address_len = tmp_socket_name_len;
|
||||
fr_session->instance_address = tmp_socket_name;
|
||||
}
|
||||
else if (ufr.code_string_code && ufr.code_string_function) {
|
||||
if (uwsgi.p[ufr.code_string_modifier1]->code_string) {
|
||||
fr_session->instance_address = uwsgi.p[ufr.code_string_modifier1]->code_string("uwsgi_fastrouter", ufr.code_string_code, ufr.code_string_function, fr_session->hostname, fr_session->hostname_len);
|
||||
if (fr_session->instance_address) {
|
||||
fr_session->instance_address_len = strlen(fr_session->instance_address);
|
||||
char *cs_mod = uwsgi_str_contains(fr_session->instance_address, fr_session->instance_address_len, ',');
|
||||
if (cs_mod) {
|
||||
fr_session->modifier1 = uwsgi_str_num(cs_mod+1, (fr_session->instance_address_len - (cs_mod - fr_session->instance_address))-1);
|
||||
fr_session->instance_address_len = (cs_mod - fr_session->instance_address);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no address found
|
||||
if (!fr_session->instance_address_len) {
|
||||
@@ -452,10 +637,7 @@ void fastrouter_loop() {
|
||||
if (tmp_socket_name) free(tmp_socket_name);
|
||||
|
||||
if (fr_session->instance_fd < 0) {
|
||||
if (ufr.subscription_server) {
|
||||
uwsgi_log("marking %.*s as failed\n", (int) fr_session->instance_address_len,fr_session->instance_address);
|
||||
fr_session->un->len = 0;
|
||||
}
|
||||
fr_session->instance_failed = 1;
|
||||
close_session(fr_table, fr_session);
|
||||
break;
|
||||
}
|
||||
@@ -463,7 +645,7 @@ void fastrouter_loop() {
|
||||
|
||||
fr_session->status = FASTROUTER_STATUS_CONNECTING;
|
||||
fr_table[fr_session->instance_fd] = fr_session;
|
||||
event_queue_add_fd_write(fr_queue, fr_session->instance_fd);
|
||||
event_queue_add_fd_write(ufr.queue, fr_session->instance_fd);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -487,11 +669,17 @@ void fastrouter_loop() {
|
||||
break;
|
||||
}
|
||||
|
||||
fr_session->uh.modifier1 = fr_session->modifier1;
|
||||
|
||||
iov[0].iov_base = &fr_session->uh;
|
||||
iov[0].iov_len = 4;
|
||||
iov[1].iov_base = fr_session->buffer;
|
||||
iov[1].iov_len = fr_session->uh.pktsize;
|
||||
|
||||
// increment node requests counter
|
||||
if (fr_session->un)
|
||||
fr_session->un->requests++;
|
||||
|
||||
// fd passing: PERFORMANCE EXTREME BOOST !!!
|
||||
if (fr_session->pass_fd && !uwsgi.no_fd_passing) {
|
||||
msg.msg_name = NULL;
|
||||
@@ -523,7 +711,7 @@ void fastrouter_loop() {
|
||||
break;
|
||||
}
|
||||
|
||||
event_queue_fd_write_to_read(fr_queue, fr_session->instance_fd);
|
||||
event_queue_fd_write_to_read(ufr.queue, fr_session->instance_fd);
|
||||
fr_session->status = FASTROUTER_STATUS_RESPONSE;
|
||||
}
|
||||
|
||||
@@ -547,6 +735,10 @@ void fastrouter_loop() {
|
||||
close_session(fr_table, fr_session);
|
||||
break;
|
||||
}
|
||||
|
||||
// update transfer statistics
|
||||
if (fr_session->un)
|
||||
fr_session->un->transferred += len;
|
||||
}
|
||||
// body from client
|
||||
else if (interesting_fd == fr_session->fd) {
|
||||
@@ -575,7 +767,7 @@ void fastrouter_loop() {
|
||||
|
||||
// fallback to destroy !!!
|
||||
default:
|
||||
uwsgi_log("default action\n");
|
||||
uwsgi_log("unknown event: closing session\n");
|
||||
close_session(fr_table, fr_session);
|
||||
break;
|
||||
|
||||
@@ -597,9 +789,17 @@ int fastrouter_init() {
|
||||
|
||||
if (!ufr.nevents) ufr.nevents = 64;
|
||||
|
||||
if (register_gateway("fastrouter", fastrouter_loop) == NULL) {
|
||||
uwsgi_log("unable to register the fastrouter gateway\n");
|
||||
exit(1);
|
||||
if (ufr.code_string_code && ufr.code_string_function) {
|
||||
if (register_fat_gateway("uWSGI fastrouter", fastrouter_loop) == NULL) {
|
||||
uwsgi_log("unable to register the fastrouter gateway\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (register_gateway("uWSGI fastrouter", fastrouter_loop) == NULL) {
|
||||
uwsgi_log("unable to register the fastrouter gateway\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -608,13 +808,42 @@ int fastrouter_init() {
|
||||
|
||||
int fastrouter_opt(int i, char *optarg) {
|
||||
|
||||
char *cs;
|
||||
char *cs_code;
|
||||
char *cs_func;
|
||||
int zerg_fd;
|
||||
int *zerg;
|
||||
int j;
|
||||
struct uwsgi_fastrouter_socket *fr_sock;
|
||||
|
||||
switch(i) {
|
||||
case LONG_ARGS_FASTROUTER:
|
||||
uwsgi_fastrouter_new_socket(generate_socket_name(optarg));
|
||||
uwsgi_fastrouter_new_socket(generate_socket_name(optarg), -1);
|
||||
return 1;
|
||||
case LONG_ARGS_FASTROUTER_ZERG:
|
||||
zerg_fd = uwsgi_connect(optarg, 30, 0);
|
||||
if (zerg_fd < 0) {
|
||||
uwsgi_log("--- unable to connect to zerg server ---\n");
|
||||
exit(1);
|
||||
}
|
||||
zerg = uwsgi_attach_fd(zerg_fd, 8, "uwsgi-zerg", 11);
|
||||
if (zerg == NULL) {
|
||||
uwsgi_log("--- invalid data received from zerg-server ---\n");
|
||||
exit(1);
|
||||
}
|
||||
close(zerg_fd);
|
||||
for(j=0;j<8;j++) {
|
||||
if (zerg[j] == -1) break;
|
||||
fr_sock = uwsgi_fastrouter_new_socket(NULL, zerg[j]);
|
||||
fr_sock->zerg = optarg;
|
||||
}
|
||||
return 1;
|
||||
case LONG_ARGS_FASTROUTER_SUBSCRIPTION_SERVER:
|
||||
ufr.subscription_server = optarg;
|
||||
return 1;
|
||||
case LONG_ARGS_FASTROUTER_STATS:
|
||||
ufr.stats_server = optarg;
|
||||
return 1;
|
||||
case LONG_ARGS_FASTROUTER_EVENTS:
|
||||
ufr.nevents = atoi(optarg);
|
||||
return 1;
|
||||
@@ -628,6 +857,24 @@ int fastrouter_opt(int i, char *optarg) {
|
||||
// optimization
|
||||
ufr.base_len = strlen(ufr.base);
|
||||
return 1;
|
||||
case LONG_ARGS_FASTROUTER_USE_CODE_STRING:
|
||||
cs = uwsgi_str(optarg);
|
||||
cs_code = strchr(cs, ':');
|
||||
if (!cs_code) {
|
||||
uwsgi_log("invalid code_string option\n");
|
||||
exit(1);
|
||||
}
|
||||
cs_code[0] = 0;
|
||||
cs_func = strchr(cs_code+1, ':');
|
||||
if (!cs_func) {
|
||||
uwsgi_log("invalid code_string option\n");
|
||||
exit(1);
|
||||
}
|
||||
cs_func[0] = 0;
|
||||
ufr.code_string_modifier1 = atoi(cs);
|
||||
ufr.code_string_code = cs_code+1;
|
||||
ufr.code_string_function = cs_func+1;
|
||||
return 1;
|
||||
case LONG_ARGS_FASTROUTER_TIMEOUT:
|
||||
ufr.socket_timeout = atoi(optarg);
|
||||
return -1;
|
||||
@@ -647,3 +894,89 @@ struct uwsgi_plugin fastrouter_plugin = {
|
||||
.init = fastrouter_init,
|
||||
};
|
||||
|
||||
|
||||
#define stats_send_llu(x, y) fprintf(output, x, (long long unsigned int) y)
|
||||
#define stats_send(x, y) fprintf(output, x, y)
|
||||
|
||||
void fastrouter_send_stats(int fd) {
|
||||
|
||||
struct sockaddr_un client_src;
|
||||
socklen_t client_src_len = 0;
|
||||
int client_fd = accept(fd, (struct sockaddr *) &client_src, &client_src_len);
|
||||
if (client_fd < 0) {
|
||||
uwsgi_error("accept()");
|
||||
return;
|
||||
}
|
||||
|
||||
FILE *output = fdopen(client_fd, "w");
|
||||
if (!output) {
|
||||
uwsgi_error("fdopen()");
|
||||
close(client_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
stats_send("{ \"version\": \"%s\",\n", UWSGI_VERSION);
|
||||
|
||||
fprintf(output,"\"pid\": %d,\n", (int)(getpid()));
|
||||
fprintf(output,"\"uid\": %d,\n", (int)(getuid()));
|
||||
fprintf(output,"\"gid\": %d,\n", (int)(getgid()));
|
||||
|
||||
char *cwd = uwsgi_get_cwd();
|
||||
stats_send("\"cwd\": \"%s\",\n", cwd);
|
||||
free(cwd);
|
||||
|
||||
fprintf(output, "\"fastrouter\": [");
|
||||
struct uwsgi_fastrouter_socket *uwsgi_sock = ufr.sockets;
|
||||
while(uwsgi_sock) {
|
||||
if (uwsgi_sock->next) {
|
||||
stats_send("\"%s\",", uwsgi_sock->name);
|
||||
}
|
||||
else {
|
||||
stats_send("\"%s\"", uwsgi_sock->name);
|
||||
}
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
fprintf(output, "],\n");
|
||||
|
||||
if (ufr.subscription_server) {
|
||||
fprintf(output, "\"subscriptions\": [\n");
|
||||
struct uwsgi_subscribe_slot *s_slot = ufr.subscriptions;
|
||||
while(s_slot) {
|
||||
fprintf(output, "\t{ \"key\": \"%.*s\",\n", s_slot->keylen, s_slot->key);
|
||||
fprintf(output, "\t\t\"hits\": %llu,\n", (unsigned long long) s_slot->hits);
|
||||
fprintf(output, "\t\t\"nodes\": [\n");
|
||||
struct uwsgi_subscribe_node *s_node = s_slot->nodes;
|
||||
while(s_node) {
|
||||
fprintf(output, "\t\t\t{\"name\": \"%.*s\", \"modifier1\": %d, \"modifier2\": %d, \"last_check\": %llu, \"requests\": %llu, \"tx\": %llu, \"cores\": %llu, \"load\": %llu, \"ref\": %llu, \"failcnt\": %llu, \"death_mark\": %d}", s_node->len, s_node->name, s_node->modifier1, s_node->modifier2,
|
||||
(unsigned long long) s_node->last_check, (unsigned long long) s_node->requests, (unsigned long long) s_node->transferred,
|
||||
(unsigned long long) s_node->cores, (unsigned long long) s_node->load, (unsigned long long) s_node->reference,
|
||||
(unsigned long long) s_node->failcnt, s_node->death_mark);
|
||||
if (s_node->next) {
|
||||
fprintf(output, ",\n");
|
||||
}
|
||||
else {
|
||||
fprintf(output, "\n");
|
||||
}
|
||||
s_node = s_node->next;
|
||||
}
|
||||
fprintf(output, "\t\t]\n");
|
||||
if (s_slot->next) {
|
||||
fprintf(output, "\t},\n");
|
||||
}
|
||||
else {
|
||||
fprintf(output, "\t}\n");
|
||||
}
|
||||
s_slot = s_slot->next;
|
||||
// check for loopy optimization
|
||||
if (s_slot == ufr.subscriptions) break;
|
||||
}
|
||||
fprintf(output, "],\n");
|
||||
}
|
||||
|
||||
fprintf(output,"\"cheap\": %d\n", ufr.i_am_cheap);
|
||||
|
||||
fprintf(output,"}\n");
|
||||
fclose(output);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -58,14 +58,13 @@ void fiber_loop() {
|
||||
uwsgi.schedule_to_main = fiber_schedule_to_main;
|
||||
uwsgi.schedule_to_req = fiber_schedule_to_req;
|
||||
|
||||
// must run all the rack/ruby plugins without protection
|
||||
ur.unprotected = 1;
|
||||
|
||||
rb_protect(protected_async_loop, 0, &error);
|
||||
|
||||
if (error) {
|
||||
uwsgi_ruby_exception();
|
||||
exit(1);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// never here
|
||||
|
||||
@@ -9,6 +9,7 @@ NAME='fiber'
|
||||
CFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['CFLAGS']\"").read().rstrip().split()
|
||||
|
||||
CFLAGS.append('-Wno-unused-parameter')
|
||||
CFLAGS.append('-DRUBY19')
|
||||
|
||||
includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print Config::CONFIG['rubyhdrdir']\"").read().rstrip()
|
||||
if includedir == 'nil':
|
||||
|
||||
@@ -0,0 +1,356 @@
|
||||
#include "../python/uwsgi_python.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
extern struct uwsgi_python up;
|
||||
|
||||
struct option gevent_options[] = {
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
#define GEVENT_SWITCH PyObject *gswitch = python_call(ugevent.greenlet_switch, ugevent.greenlet_switch_args, 0, NULL); Py_DECREF(gswitch)
|
||||
#define GET_CURRENT_GREENLET python_call(ugevent.get_current, ugevent.get_current_args, 0, NULL)
|
||||
#define free_req_queue uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req
|
||||
#define stop_the_watchers ret = PyObject_CallMethod(timer, "stop", NULL);\
|
||||
if (ret) Py_DECREF(ret);\
|
||||
ret = PyObject_CallMethod(watcher, "stop", NULL);\
|
||||
if (ret) Py_DECREF(ret);
|
||||
|
||||
struct uwsgi_gevent {
|
||||
PyObject *greenlet_switch;
|
||||
PyObject *greenlet_switch_args;
|
||||
PyObject *get_current;
|
||||
PyObject *get_current_args;
|
||||
PyObject *hub;
|
||||
PyObject *hub_loop;
|
||||
PyObject *spawn;
|
||||
PyObject *greenlet_args;
|
||||
PyObject *signal_args;
|
||||
} ugevent;
|
||||
|
||||
|
||||
PyObject *py_uwsgi_gevent_signal_handler(PyObject * self, PyObject * args) {
|
||||
|
||||
uint8_t uwsgi_signal;
|
||||
int signal_socket;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i:uwsgi_gevent_signal_handler", &signal_socket)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (read(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);
|
||||
}
|
||||
// close the socket to end the mess...from now on the worker is alone (no master)
|
||||
else close(signal_socket);
|
||||
}
|
||||
else {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log_verbose("master sent signal %d to worker %d\n", uwsgi_signal, uwsgi.mywid);
|
||||
#endif
|
||||
if (uwsgi_signal_handler(uwsgi_signal)) {
|
||||
uwsgi_log_verbose("error managing signal %d on worker %d\n", uwsgi_signal, uwsgi.mywid);
|
||||
}
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_gevent_signal(PyObject * self, PyObject * args) {
|
||||
|
||||
PyTuple_SetItem(ugevent.signal_args, 1, PyInt_FromLong(uwsgi.signal_socket));
|
||||
|
||||
// spawn the signal_handler greenlet
|
||||
PyObject *new_gl = python_call(ugevent.spawn, ugevent.signal_args, 0, NULL);
|
||||
Py_DECREF(new_gl);
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
|
||||
}
|
||||
|
||||
// yes copy&paste no-DRY for me :P
|
||||
PyObject *py_uwsgi_gevent_my_signal(PyObject * self, PyObject * args) {
|
||||
|
||||
PyTuple_SetItem(ugevent.signal_args, 1, PyInt_FromLong(uwsgi.my_signal_socket));
|
||||
|
||||
// spawn the signal_handler greenlet
|
||||
PyObject *new_gl = python_call(ugevent.spawn, ugevent.signal_args, 0, NULL);
|
||||
Py_DECREF(new_gl);
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
PyObject *py_uwsgi_gevent_main(PyObject * self, PyObject * args) {
|
||||
|
||||
|
||||
struct wsgi_request *wsgi_req = find_first_available_wsgi_req();
|
||||
|
||||
if (wsgi_req == NULL) {
|
||||
uwsgi_log("async queue is full !!!\n");
|
||||
goto clear;
|
||||
}
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
|
||||
// fill wsgi_request structure
|
||||
wsgi_req_setup(wsgi_req, wsgi_req->async_id, uwsgi.sockets );
|
||||
|
||||
// mark core as used
|
||||
uwsgi.core[wsgi_req->async_id]->in_request = 1;
|
||||
|
||||
gettimeofday(&wsgi_req->start_of_request, NULL);
|
||||
|
||||
// enter harakiri mode
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
|
||||
set_harakiri(uwsgi.shared->options[UWSGI_OPTION_HARAKIRI]);
|
||||
}
|
||||
|
||||
// accept the connection
|
||||
if (wsgi_req_simple_accept(wsgi_req, uwsgi.sockets->fd)) {
|
||||
uwsgi_close_request(wsgi_req);
|
||||
free_req_queue;
|
||||
goto clear;
|
||||
}
|
||||
|
||||
// hack to easily pass wsgi_req pointer to the greenlet
|
||||
PyTuple_SetItem(ugevent.greenlet_args, 1, PyLong_FromLong((long)wsgi_req));
|
||||
|
||||
// spawn the request greenlet
|
||||
PyObject *new_gl = python_call(ugevent.spawn, ugevent.greenlet_args, 0, NULL);
|
||||
Py_DECREF(new_gl);
|
||||
|
||||
clear:
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject *uwsgi_gevent_wait(PyObject *watcher, PyObject *timer, PyObject *current) {
|
||||
|
||||
PyObject *ret;
|
||||
|
||||
// start the io watcher
|
||||
ret = PyObject_CallMethod(watcher, "start", "OO", current, watcher);
|
||||
if (!ret) return NULL;
|
||||
Py_DECREF(ret);
|
||||
|
||||
// start the timeout handler
|
||||
ret = PyObject_CallMethod(timer, "start", "OO", current, timer);
|
||||
if (!ret) return NULL;
|
||||
Py_DECREF(ret);
|
||||
|
||||
// pass control to the hub
|
||||
return PyObject_CallMethod(ugevent.hub, "switch", NULL);
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_gevent_request(PyObject * self, PyObject * args) {
|
||||
|
||||
PyObject *ret;
|
||||
PyObject *py_wsgi_req = PyTuple_GetItem(args, 0);
|
||||
struct wsgi_request *wsgi_req = (struct wsgi_request *) PyLong_AsLong(py_wsgi_req);
|
||||
int status ;
|
||||
|
||||
PyObject *current_greenlet = GET_CURRENT_GREENLET;
|
||||
PyObject *greenlet_switch = PyObject_GetAttrString(current_greenlet, "switch");
|
||||
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
|
||||
// create a watcher for request socket
|
||||
PyObject *watcher = PyObject_CallMethod(ugevent.hub_loop, "io", "ii", wsgi_req->poll.fd, 1);
|
||||
if (!watcher) goto clear1;
|
||||
|
||||
// a timer to implement timeoit (thanks Denis)
|
||||
PyObject *timer = PyObject_CallMethod(ugevent.hub_loop, "timer", "i", uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (!timer) goto clear0;
|
||||
|
||||
for(;;) {
|
||||
// wait for data in the socket
|
||||
PyObject *ret = uwsgi_gevent_wait(watcher, timer, greenlet_switch);
|
||||
if (!ret) goto clear_and_stop;
|
||||
|
||||
// do not forget to overwrite this pointer each time !!!
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
|
||||
// we can safely decref here as watcher and timer has got a +1 for start() method
|
||||
Py_DECREF(ret);
|
||||
if (ret == timer) {
|
||||
uwsgi_log( "timeout. skip request.\n");
|
||||
goto clear_and_stop;
|
||||
}
|
||||
else if (ret == watcher) {
|
||||
|
||||
status = wsgi_req->socket->proto(wsgi_req);
|
||||
if (status < 0) {
|
||||
goto clear_and_stop;
|
||||
}
|
||||
else if (status == 0) {
|
||||
stop_the_watchers;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log("unrecognized gevent event !!!\n");
|
||||
goto clear_and_stop;
|
||||
}
|
||||
|
||||
stop_the_watchers;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
wsgi_req->async_status = uwsgi.p[wsgi_req->uh.modifier1]->request(wsgi_req);
|
||||
if (wsgi_req->async_status <= UWSGI_OK) {
|
||||
goto clear;
|
||||
}
|
||||
// switch after each yield
|
||||
GEVENT_SWITCH;
|
||||
}
|
||||
|
||||
goto clear;
|
||||
|
||||
clear_and_stop:
|
||||
|
||||
stop_the_watchers;
|
||||
|
||||
clear:
|
||||
Py_DECREF(timer);
|
||||
clear0:
|
||||
Py_DECREF(watcher);
|
||||
clear1:
|
||||
Py_DECREF(greenlet_switch);
|
||||
Py_DECREF(current_greenlet);
|
||||
uwsgi_close_request(wsgi_req);
|
||||
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
|
||||
free_req_queue;
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
|
||||
|
||||
}
|
||||
|
||||
PyMethodDef uwsgi_gevent_main_def[] = { {"uwsgi_gevent_main", py_uwsgi_gevent_main, METH_VARARGS, ""} };
|
||||
PyMethodDef uwsgi_gevent_request_def[] = { {"uwsgi_gevent_request", py_uwsgi_gevent_request, METH_VARARGS, ""} };
|
||||
PyMethodDef uwsgi_gevent_signal_def[] = { {"uwsgi_gevent_signal", py_uwsgi_gevent_signal, METH_VARARGS, ""} };
|
||||
PyMethodDef uwsgi_gevent_my_signal_def[] = { {"uwsgi_gevent_my_signal", py_uwsgi_gevent_my_signal, METH_VARARGS, ""} };
|
||||
PyMethodDef uwsgi_gevent_signal_handler_def[] = { {"uwsgi_gevent_signal_handler", py_uwsgi_gevent_signal_handler, METH_VARARGS, ""} };
|
||||
|
||||
|
||||
void gevent_loop() {
|
||||
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
|
||||
if (uwsgi.async < 2) {
|
||||
uwsgi_log("the gevent loop engine requires async mode (--async <n>)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
PyObject *gevent_dict = get_uwsgi_pydict("gevent");
|
||||
if (!gevent_dict) uwsgi_pyexit;
|
||||
|
||||
PyObject *gevent_version = PyDict_GetItemString(gevent_dict, "version_info");
|
||||
if (!gevent_version) uwsgi_pyexit;
|
||||
|
||||
if (PyInt_AsLong(PyTuple_GetItem(gevent_version, 0)) < 1) {
|
||||
uwsgi_log("uWSGI requires at least gevent 1.x version\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ugevent.spawn = PyDict_GetItemString(gevent_dict, "spawn");
|
||||
if (!ugevent.spawn) uwsgi_pyexit;
|
||||
|
||||
ugevent.greenlet_switch = PyDict_GetItemString(gevent_dict, "sleep");
|
||||
if (!ugevent.greenlet_switch) uwsgi_pyexit;
|
||||
|
||||
ugevent.greenlet_switch_args = PyTuple_New(0);
|
||||
Py_INCREF(ugevent.greenlet_switch_args);
|
||||
|
||||
|
||||
PyObject *gevent_get_hub = PyDict_GetItemString(gevent_dict, "get_hub");
|
||||
|
||||
ugevent.hub = python_call(gevent_get_hub, PyTuple_New(0), 0, NULL);
|
||||
if (!ugevent.hub) uwsgi_pyexit;
|
||||
|
||||
ugevent.get_current = PyDict_GetItemString(gevent_dict, "getcurrent");
|
||||
if (!ugevent.get_current) uwsgi_pyexit;
|
||||
|
||||
ugevent.get_current_args = PyTuple_New(0);
|
||||
Py_INCREF(ugevent.get_current_args);
|
||||
|
||||
|
||||
ugevent.hub_loop = PyObject_GetAttrString(ugevent.hub, "loop");
|
||||
if (!ugevent.hub_loop) uwsgi_pyexit;
|
||||
|
||||
// this is the watcher for server socket
|
||||
PyObject *watcher = PyObject_CallMethod(ugevent.hub_loop, "io", "ii", uwsgi_sock->fd, 1);
|
||||
if (!watcher) uwsgi_pyexit;
|
||||
|
||||
// main greenlet waiting for connection
|
||||
PyObject *uwsgi_gevent_main = PyCFunction_New(uwsgi_gevent_main_def, NULL);
|
||||
Py_INCREF(uwsgi_gevent_main);
|
||||
|
||||
// greenlet to run at each request
|
||||
PyObject *uwsgi_request_greenlet = PyCFunction_New(uwsgi_gevent_request_def, NULL);
|
||||
Py_INCREF(uwsgi_request_greenlet);
|
||||
|
||||
// pre-fill the greenlet args
|
||||
ugevent.greenlet_args = PyTuple_New(2);
|
||||
PyTuple_SetItem(ugevent.greenlet_args, 0, uwsgi_request_greenlet);
|
||||
|
||||
if (uwsgi.signal_socket > -1) {
|
||||
// and these are the watcher for signal sockets
|
||||
|
||||
PyObject *signal_watcher = PyObject_CallMethod(ugevent.hub_loop, "io", "ii", uwsgi.signal_socket, 1);
|
||||
if (!signal_watcher) uwsgi_pyexit;
|
||||
|
||||
PyObject *my_signal_watcher = PyObject_CallMethod(ugevent.hub_loop, "io", "ii", uwsgi.my_signal_socket, 1);
|
||||
if (!my_signal_watcher) uwsgi_pyexit;
|
||||
|
||||
PyObject *uwsgi_greenlet_signal = PyCFunction_New(uwsgi_gevent_signal_def, NULL);
|
||||
Py_INCREF(uwsgi_greenlet_signal);
|
||||
|
||||
PyObject *uwsgi_greenlet_my_signal = PyCFunction_New(uwsgi_gevent_my_signal_def, NULL);
|
||||
Py_INCREF(uwsgi_greenlet_my_signal);
|
||||
|
||||
PyObject *uwsgi_greenlet_signal_handler = PyCFunction_New(uwsgi_gevent_signal_handler_def, NULL);
|
||||
Py_INCREF(uwsgi_greenlet_signal_handler);
|
||||
|
||||
ugevent.signal_args = PyTuple_New(2);
|
||||
PyTuple_SetItem(ugevent.signal_args, 0, uwsgi_greenlet_signal_handler);
|
||||
|
||||
// start the two signal watchers
|
||||
if (!PyObject_CallMethod(signal_watcher, "start", "O", uwsgi_greenlet_signal)) uwsgi_pyexit;
|
||||
if (!PyObject_CallMethod(my_signal_watcher, "start", "O", uwsgi_greenlet_my_signal)) uwsgi_pyexit;
|
||||
|
||||
}
|
||||
|
||||
// start the main greenlet
|
||||
PyObject_CallMethod(watcher, "start", "O", uwsgi_gevent_main);
|
||||
|
||||
if (!PyObject_CallMethod(ugevent.hub, "join", NULL)) {
|
||||
PyErr_Print();
|
||||
}
|
||||
|
||||
uwsgi_log("the gevent Hub is no more :(\n");
|
||||
|
||||
}
|
||||
|
||||
int gevent_init() {
|
||||
|
||||
uwsgi_register_loop( (char *) "gevent", gevent_loop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_plugin gevent_plugin = {
|
||||
|
||||
.name = "gevent",
|
||||
.init = gevent_init,
|
||||
.options = gevent_options,
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
from distutils import sysconfig
|
||||
|
||||
NAME='gevent'
|
||||
CFLAGS = ['-I' + sysconfig.get_python_inc(), '-I' + sysconfig.get_python_inc(plat_specific=True)]
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
|
||||
GCC_LIST = ['gevent']
|
||||
@@ -0,0 +1,120 @@
|
||||
#include "../../uwsgi.h"
|
||||
#include <zlib.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#define MAX_GELF 8192
|
||||
|
||||
struct graylog2_config {
|
||||
char *host;
|
||||
char json_buf[MAX_GELF];
|
||||
char escaped_buf[MAX_GELF];
|
||||
size_t escaped_len;
|
||||
char buffer[MAX_GELF];
|
||||
} g2c;
|
||||
|
||||
ssize_t uwsgi_graylog2_logger(struct uwsgi_logger *ul, char *message, size_t len) {
|
||||
|
||||
size_t i;
|
||||
|
||||
if (!ul->configured) {
|
||||
|
||||
if (!uwsgi.choosen_logger_arg) {
|
||||
uwsgi_log_safe("invalid graylog2 syntax\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ul->fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (ul->fd < 0) {
|
||||
uwsgi_error_safe("socket()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_socket_nb(ul->fd);
|
||||
|
||||
char *comma = strchr(uwsgi.choosen_logger_arg, ',');
|
||||
if (!comma) {
|
||||
uwsgi_log_safe("invalid graylog2 syntax\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
g2c.host = comma + 1;
|
||||
|
||||
*comma = 0;
|
||||
|
||||
char *colon = strchr(uwsgi.choosen_logger_arg, ':');
|
||||
if (!colon) {
|
||||
uwsgi_log_safe("invalid graylog2 syntax\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ul->addr_len = socket_to_in_addr(uwsgi.choosen_logger_arg, colon, 0, &ul->addr.sa_in);
|
||||
|
||||
*comma = ',';
|
||||
|
||||
ul->configured = 1;
|
||||
}
|
||||
|
||||
g2c.escaped_len = 0;
|
||||
|
||||
int truncated = 0;
|
||||
char *ptr = g2c.escaped_buf;
|
||||
uLongf destLen = MAX_GELF;
|
||||
|
||||
for(i=0;i<len;i++) {
|
||||
if (message[i] == '\\') {
|
||||
*ptr ++= '\\';
|
||||
g2c.escaped_len++;
|
||||
}
|
||||
else if (message[i] == '"') {
|
||||
*ptr ++= '\\';
|
||||
g2c.escaped_len++;
|
||||
}
|
||||
*ptr ++= message[i];
|
||||
g2c.escaped_len++;
|
||||
|
||||
if (!truncated) {
|
||||
if (g2c.escaped_len == 128) {
|
||||
truncated = 1;
|
||||
}
|
||||
else if (g2c.escaped_len > 128) {
|
||||
truncated = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (truncated) truncated = 128 - (truncated-1);
|
||||
else (truncated = g2c.escaped_len);
|
||||
|
||||
int rlen = snprintf(g2c.json_buf, MAX_GELF, "{ \"version\": \"1.0\", \"host\": \"%s\", \"short_message\": \"%.*s\", \"full_message\": \"%.*s\", \"timestamp\": %d, \"level\": 5, \"facility\": \"uWSGI-%s\" }",
|
||||
g2c.host, truncated, g2c.escaped_buf, (int)g2c.escaped_len, g2c.escaped_buf, (int) time(NULL), UWSGI_VERSION);
|
||||
|
||||
if (rlen > 0) {
|
||||
if (compressBound((uLong) rlen) <= MAX_GELF) {
|
||||
if (compress((Bytef *) g2c.buffer, &destLen, (Bytef *) g2c.json_buf, (uLong) rlen) == Z_OK) {
|
||||
return sendto(ul->fd, g2c.buffer, destLen, 0, (const struct sockaddr *) &ul->addr, ul->addr_len);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_graylog2_register() {
|
||||
uwsgi_register_logger("graylog2", uwsgi_graylog2_logger);
|
||||
}
|
||||
|
||||
int uwsgi_graylog2_init() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct uwsgi_plugin graylog2_plugin = {
|
||||
|
||||
.name = "graylog2",
|
||||
.on_load = uwsgi_graylog2_register,
|
||||
.init = uwsgi_graylog2_init
|
||||
|
||||
};
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
NAME='graylog2'
|
||||
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = ['-lz']
|
||||
GCC_LIST = ['graylog2_plugin']
|
||||
+32
-18
@@ -39,6 +39,7 @@ struct uwsgi_http {
|
||||
int server;
|
||||
|
||||
char *subscription_server;
|
||||
int subscription_regexp;
|
||||
|
||||
char *pattern;
|
||||
int pattern_len;
|
||||
@@ -60,7 +61,7 @@ struct uwsgi_http {
|
||||
|
||||
int socket_timeout;
|
||||
|
||||
struct uwsgi_dict *subscription_dict;
|
||||
struct uwsgi_subscribe_slot *subscriptions;
|
||||
|
||||
struct rb_root *timeouts;
|
||||
} uhttp;
|
||||
@@ -76,6 +77,7 @@ struct option http_options[] = {
|
||||
{"http-use-cluster", no_argument, &uhttp.use_cluster, 1},
|
||||
{"http-events", required_argument, 0, LONG_ARGS_HTTP_EVENTS},
|
||||
{"http-subscription-server", required_argument, 0, LONG_ARGS_HTTP_SUBSCRIPTION_SERVER},
|
||||
{"http-subscription-use-regexp", no_argument, &uhttp.subscription_regexp, 1},
|
||||
{"http-timeout", required_argument, 0, LONG_ARGS_HTTP_TIMEOUT},
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
@@ -136,8 +138,10 @@ struct http_session {
|
||||
char uss[MAX_HTTP_VEC*2];
|
||||
|
||||
char buffer[UMAX16];
|
||||
char path_info[UMAX16];
|
||||
uint16_t path_info_len;
|
||||
|
||||
struct uwsgi_subscriber_name *un;
|
||||
struct uwsgi_subscribe_node *un;
|
||||
|
||||
in_addr_t ip_addr;
|
||||
char ip[INET_ADDRSTRLEN];
|
||||
@@ -156,9 +160,9 @@ static void close_session(struct http_session **uhttp_table, struct http_session
|
||||
close(uhttp_session->fd);
|
||||
uhttp_table[uhttp_session->fd] = NULL;
|
||||
if (uhttp_session->instance_fd != -1) {
|
||||
if (uhttp.subscription_server && (uhttp_session->instance_failed || uhttp_session->status == HTTP_STATUS_CONNECTING)) {
|
||||
if (uhttp.subscriptions && (uhttp_session->instance_failed || uhttp_session->status == HTTP_STATUS_CONNECTING)) {
|
||||
uwsgi_log("marking %.*s as failed\n", (int) uhttp_session->instance_address_len,uhttp_session->instance_address);
|
||||
uhttp_session->un->len = 0;
|
||||
uwsgi_remove_subscribe_node(&uhttp.subscriptions, uhttp_session->un);
|
||||
}
|
||||
close(uhttp_session->instance_fd);
|
||||
uhttp_table[uhttp_session->instance_fd] = NULL;
|
||||
@@ -325,13 +329,19 @@ int http_parse(struct http_session *h_session) {
|
||||
base = ptr;
|
||||
while(ptr < watermark) {
|
||||
if (*ptr == '?' && !query_string) {
|
||||
h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "PATH_INFO", 9, base, ptr-base, &c);
|
||||
// PATH_INFO must be url-decoded !!!
|
||||
h_session->path_info_len = ptr-base;
|
||||
http_url_decode(base, &h_session->path_info_len, h_session->path_info);
|
||||
h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "PATH_INFO", 9, h_session->path_info, h_session->path_info_len, &c);
|
||||
query_string = ptr+1;
|
||||
}
|
||||
else if (*ptr == ' ') {
|
||||
h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "REQUEST_URI", 11, base, ptr-base, &c);
|
||||
if (!query_string) {
|
||||
h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "PATH_INFO", 9, base, ptr-base, &c);
|
||||
// PATH_INFO must be url-decoded !!!
|
||||
h_session->path_info_len = ptr-base;
|
||||
http_url_decode(base, &h_session->path_info_len, h_session->path_info);
|
||||
h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "PATH_INFO", 9, h_session->path_info, h_session->path_info_len, &c);
|
||||
h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, "QUERY_STRING", 12, "", 0, &c);
|
||||
}
|
||||
else {
|
||||
@@ -403,6 +413,14 @@ int http_parse(struct http_session *h_session) {
|
||||
ptr++;
|
||||
}
|
||||
|
||||
int i;
|
||||
for(i=0;i<uhttp.http_vars_cnt;i++) {
|
||||
char *equal = strchr(uhttp.http_vars[i],'=');
|
||||
if (equal) {
|
||||
h_session->uh.pktsize += http_add_uwsgi_var(h_session->iov, h_session->uss+c, h_session->uss+c+2, uhttp.http_vars[i], equal-uhttp.http_vars[i], equal+1, strlen(equal+1), &c);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("vec size: %d pkt size: %d load %d\n", c, h_session->uh.pktsize, uhttp.load);
|
||||
#endif
|
||||
@@ -466,7 +484,6 @@ void http_loop() {
|
||||
if (uhttp.subscription_server) {
|
||||
uhttp_subserver = bind_to_udp(uhttp.subscription_server, 0, 0);
|
||||
event_queue_add_fd_read(uhttp_queue, uhttp_subserver);
|
||||
uhttp.subscription_dict = uwsgi_dict_create(100, 0);
|
||||
}
|
||||
|
||||
if (uhttp.pattern) {
|
||||
@@ -542,7 +559,7 @@ void http_loop() {
|
||||
if (len > 0) {
|
||||
memset(&usr, 0, sizeof(struct uwsgi_subscribe_req));
|
||||
uwsgi_hooked_parse(bbuf+4, len-4, http_manage_subscription, &usr);
|
||||
uwsgi_add_subscriber(uhttp.subscription_dict, usr.key, usr.keylen, usr.address, usr.address_len);
|
||||
uwsgi_add_subscribe_node(&uhttp.subscriptions, &usr, uhttp.subscription_regexp);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -567,7 +584,8 @@ void http_loop() {
|
||||
event_queue_add_fd_read(uhttp_queue, uhttp_session->fd);
|
||||
#endif
|
||||
if (len <= 0) {
|
||||
uwsgi_error("recv()");
|
||||
if (len < 0)
|
||||
uwsgi_error("recv()");
|
||||
close_session(uhttp_table, uhttp_session);
|
||||
break;
|
||||
}
|
||||
@@ -622,7 +640,7 @@ void http_loop() {
|
||||
uhttp_session->instance_address_len = uhttp.to_len;
|
||||
}
|
||||
else if (uhttp.subscription_server) {
|
||||
uhttp_session->un = uwsgi_get_subscriber(uhttp.subscription_dict, uhttp_session->hostname, uhttp_session->hostname_len);
|
||||
uhttp_session->un = uwsgi_get_subscribe_node(&uhttp.subscriptions, uhttp_session->hostname, uhttp_session->hostname_len, uhttp.subscription_regexp);
|
||||
if (uhttp_session->un && uhttp_session->un->len) {
|
||||
uhttp_session->instance_address = uhttp_session->un->name;
|
||||
uhttp_session->instance_address_len = uhttp_session->un->len;
|
||||
@@ -639,6 +657,7 @@ void http_loop() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
uhttp_session->pass_fd = is_unix(uhttp_session->instance_address, uhttp_session->instance_address_len);
|
||||
|
||||
uhttp_session->instance_fd = uwsgi_connectn(uhttp_session->instance_address, uhttp_session->instance_address_len, 0, 1);
|
||||
@@ -652,10 +671,7 @@ void http_loop() {
|
||||
}
|
||||
|
||||
if (uhttp_session->instance_fd < 0) {
|
||||
if (uhttp.subscription_server) {
|
||||
uwsgi_log("marking %.*s as failed\n", (int) uhttp_session->instance_address_len,uhttp_session->instance_address);
|
||||
uhttp_session->un->len = 0;
|
||||
}
|
||||
uhttp_session->instance_failed = 1;
|
||||
close_session(uhttp_table, uhttp_session);
|
||||
break;
|
||||
}
|
||||
@@ -869,14 +885,12 @@ int http_init() {
|
||||
if (!uhttp.nevents) uhttp.nevents = 64;
|
||||
|
||||
if (!uhttp.base && !uhttp.use_cache && !uhttp.to && !uwsgi.sockets && !uhttp.subscription_server && !uhttp.use_cluster) {
|
||||
char *rand_name = uwsgi_malloc(64);
|
||||
snprintf(rand_name, 64, "%d_%d.sock", (int) time(NULL), (int) getpid());
|
||||
uwsgi.sockets = uwsgi_new_socket(rand_name);
|
||||
uwsgi_new_socket(uwsgi_concat2("127.0.0.1:0", ""));
|
||||
}
|
||||
|
||||
uhttp.server = bind_to_tcp(uhttp.socket_name, uwsgi.listen_queue, strchr(uhttp.socket_name,':'));
|
||||
|
||||
if (register_gateway("http", http_loop) == NULL) {
|
||||
if (register_gateway("uWSGI http", http_loop) == NULL) {
|
||||
uwsgi_log("unable to register the http gateway\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,16 @@ NAME='jvm'
|
||||
JVM_INCPATH = "/usr/lib/jvm/java-6-sun-1.6.0.15/include/ -I/usr/lib/jvm/java-6-sun-1.6.0.15/include/linux"
|
||||
JVM_LIBPATH = "/usr/lib/jvm/java-6-sun-1.6.0.15/jre/lib/i386/server/"
|
||||
|
||||
try:
|
||||
JVM_INCPATH = os.environ['UWSGICONFIG_JVM_INCPATH']
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
JVM_LIBPATH = os.environ['UWSGICONFIG_JVM_LIBPATH']
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
JVM_INCPATH = os.environ['UWSGICONFIG_JVM_INCPATH']
|
||||
except:
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
ssize_t uwsgi_socket_logger(struct uwsgi_logger *ul, char *message, size_t len) {
|
||||
|
||||
int family = AF_UNIX;
|
||||
|
||||
if (!ul->configured) {
|
||||
|
||||
char *comma = strchr(uwsgi.choosen_logger_arg, ',');
|
||||
if (comma) {
|
||||
ul->data = comma+1;
|
||||
*comma = 0;
|
||||
}
|
||||
|
||||
char *colon = strchr(uwsgi.choosen_logger_arg, ':');
|
||||
if (colon) {
|
||||
family = AF_INET;
|
||||
ul->addr_len = socket_to_in_addr(uwsgi.choosen_logger_arg, colon, 0, &ul->addr.sa_in);
|
||||
}
|
||||
else {
|
||||
ul->addr_len = socket_to_un_addr(uwsgi.choosen_logger_arg, &ul->addr.sa_un);
|
||||
}
|
||||
|
||||
ul->fd = socket(family, SOCK_DGRAM, 0);
|
||||
if (ul->fd < 0) {
|
||||
uwsgi_error_safe("socket()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(&ul->msg, 0, sizeof(struct msghdr));
|
||||
|
||||
ul->msg.msg_name = &ul->addr;
|
||||
ul->msg.msg_namelen = ul->addr_len;
|
||||
if (ul->data) {
|
||||
ul->msg.msg_iov = uwsgi_malloc(sizeof(struct iovec) * 2);
|
||||
ul->msg.msg_iov[0].iov_base = ul->data;
|
||||
ul->msg.msg_iov[0].iov_len = strlen(ul->data);
|
||||
ul->msg.msg_iovlen = 2;
|
||||
ul->count = 1;
|
||||
}
|
||||
else {
|
||||
ul->msg.msg_iov = uwsgi_malloc(sizeof(struct iovec));
|
||||
ul->msg.msg_iovlen = 1;
|
||||
}
|
||||
|
||||
if (comma) {
|
||||
*comma = ',' ;
|
||||
}
|
||||
|
||||
ul->configured = 1;
|
||||
}
|
||||
|
||||
|
||||
ul->msg.msg_iov[ul->count].iov_base = message;
|
||||
ul->msg.msg_iov[ul->count].iov_len = len;
|
||||
|
||||
return sendmsg(ul->fd, &ul->msg, 0);
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_logsocket_register() {
|
||||
uwsgi_register_logger("socket", uwsgi_socket_logger);
|
||||
}
|
||||
|
||||
int uwsgi_logsocket_init() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct uwsgi_plugin logsocket_plugin = {
|
||||
|
||||
.name = "logsocket",
|
||||
.on_load = uwsgi_logsocket_register,
|
||||
.init = uwsgi_logsocket_init
|
||||
|
||||
};
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
NAME='logsocket'
|
||||
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
GCC_LIST = ['logsocket_plugin']
|
||||
+97
-27
@@ -374,7 +374,7 @@ void uwsgi_lua_app() {
|
||||
luaL_openlibs(ulua.L[i]);
|
||||
luaL_register(ulua.L[i], "uwsgi", uwsgi_api);
|
||||
if (luaL_loadfile(ulua.L[i], ulua.filename)) {
|
||||
uwsgi_log("unable to load file %s\n", ulua.filename);
|
||||
uwsgi_log("unable to load file %s: %s\n", ulua.filename, lua_tostring(ulua.L[i], -1));
|
||||
exit(1);
|
||||
}
|
||||
// use a pcall
|
||||
@@ -403,8 +403,7 @@ int uwsgi_lua_request(struct wsgi_request *wsgi_req) {
|
||||
if ((i = lua_pcall(L, 0, 1, 0)) == 0) {
|
||||
if (lua_type(L, -1) == LUA_TSTRING) {
|
||||
http = lua_tolstring(L, -1, &slen);
|
||||
if ( (rlen = write(wsgi_req->poll.fd, http, slen)) != (ssize_t) slen) {
|
||||
perror("write()");
|
||||
if ( (rlen = wsgi_req->socket->proto_write(wsgi_req, (char *)http, slen)) != (ssize_t) slen) {
|
||||
return UWSGI_OK;
|
||||
}
|
||||
wsgi_req->response_size += rlen;
|
||||
@@ -420,12 +419,12 @@ int uwsgi_lua_request(struct wsgi_request *wsgi_req) {
|
||||
/* Standard WSAPI request */
|
||||
if (!wsgi_req->uh.pktsize) {
|
||||
uwsgi_log( "Invalid WSAPI request. skip.\n");
|
||||
goto clear;
|
||||
goto clear2;
|
||||
}
|
||||
|
||||
if (uwsgi_parse_vars(wsgi_req)) {
|
||||
uwsgi_log("Invalid WSAPI request. skip.\n");
|
||||
goto clear;
|
||||
goto clear2;
|
||||
}
|
||||
|
||||
// put function in the stack
|
||||
@@ -453,12 +452,16 @@ int uwsgi_lua_request(struct wsgi_request *wsgi_req) {
|
||||
lua_setfield(L, -2, "read");
|
||||
lua_setfield(L, -2, "input");
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("stack pos %d\n", lua_gettop(L));
|
||||
#endif
|
||||
|
||||
// call function
|
||||
i = lua_pcall(L, 1, 3, 0);
|
||||
if (i != 0) {
|
||||
uwsgi_log("%s\n", lua_tostring(L, -1));
|
||||
lua_pop(L, 1);
|
||||
lua_pushvalue(L, -1);
|
||||
goto clear;
|
||||
}
|
||||
|
||||
@@ -468,26 +471,30 @@ int uwsgi_lua_request(struct wsgi_request *wsgi_req) {
|
||||
// send status
|
||||
if (lua_type(L, -3) == LUA_TSTRING || lua_type(L, -3) == LUA_TNUMBER) {
|
||||
http = lua_tolstring(L, -3, &slen);
|
||||
if (write(wsgi_req->poll.fd, wsgi_req->protocol, wsgi_req->protocol_len) != wsgi_req->protocol_len) {
|
||||
perror("write()");
|
||||
if ( (rlen = wsgi_req->socket->proto_write_header(wsgi_req, wsgi_req->protocol, wsgi_req->protocol_len)) != wsgi_req->protocol_len) {
|
||||
lua_pushvalue(L, -1);
|
||||
goto clear;
|
||||
}
|
||||
if (write(wsgi_req->poll.fd, " ", 1) != 1) {
|
||||
perror("write()");
|
||||
wsgi_req->headers_size += rlen;
|
||||
if ( (rlen = wsgi_req->socket->proto_write_header(wsgi_req, " ", 1)) != 1) {
|
||||
lua_pushvalue(L, -1);
|
||||
goto clear;
|
||||
}
|
||||
if (write(wsgi_req->poll.fd, http, slen) != (ssize_t) slen) {
|
||||
perror("write()");
|
||||
wsgi_req->headers_size += rlen;
|
||||
if ( (rlen = wsgi_req->socket->proto_write_header(wsgi_req, (char *)http, slen)) != (ssize_t) slen) {
|
||||
lua_pushvalue(L, -1);
|
||||
goto clear;
|
||||
}
|
||||
wsgi_req->headers_size += rlen;
|
||||
// a performance hack
|
||||
ptrbuf = (char *) http;
|
||||
ptrbuf[3] = 0;
|
||||
wsgi_req->status = atoi(ptrbuf);
|
||||
if (write(wsgi_req->poll.fd, "\r\n", 2) != 2) {
|
||||
perror("write()");
|
||||
if ( (rlen = wsgi_req->socket->proto_write_header(wsgi_req, "\r\n", 2)) != 2) {
|
||||
lua_pushvalue(L, -1);
|
||||
goto clear;
|
||||
}
|
||||
wsgi_req->headers_size += rlen;
|
||||
}
|
||||
else {
|
||||
raw = 1;
|
||||
@@ -499,31 +506,41 @@ int uwsgi_lua_request(struct wsgi_request *wsgi_req) {
|
||||
lua_pushnil(L);
|
||||
while(lua_next(L, -3) != 0) {
|
||||
http = lua_tolstring(L, -2, &slen);
|
||||
if (write(wsgi_req->poll.fd, http, slen) != (ssize_t) slen) {
|
||||
perror("write()");
|
||||
if ( (rlen = wsgi_req->socket->proto_write_header(wsgi_req, (char *)http, slen)) != (ssize_t) slen) {
|
||||
lua_pop(L, 2);
|
||||
lua_pushvalue(L, -1);
|
||||
goto clear;
|
||||
}
|
||||
if (write(wsgi_req->poll.fd, ": ", 2) != 2) {
|
||||
perror("write()");
|
||||
wsgi_req->headers_size += rlen;
|
||||
if ( (rlen = wsgi_req->socket->proto_write_header(wsgi_req, ": ", 2)) != 2) {
|
||||
lua_pop(L, 2);
|
||||
lua_pushvalue(L, -1);
|
||||
goto clear;
|
||||
}
|
||||
wsgi_req->headers_size += rlen;
|
||||
http = lua_tolstring(L, -1, &slen);
|
||||
if (write(wsgi_req->poll.fd, http, slen) != (ssize_t) slen) {
|
||||
perror("write()");
|
||||
if ( (rlen = wsgi_req->socket->proto_write_header(wsgi_req, (char *)http, slen)) != (ssize_t) slen) {
|
||||
lua_pop(L, 2);
|
||||
lua_pushvalue(L, -1);
|
||||
goto clear;
|
||||
}
|
||||
if (write(wsgi_req->poll.fd, "\r\n", 2) != 2) {
|
||||
perror("write()");
|
||||
wsgi_req->headers_size += rlen;
|
||||
if ( (rlen = wsgi_req->socket->proto_write_header(wsgi_req, "\r\n", 2)) != 2) {
|
||||
lua_pop(L, 2);
|
||||
lua_pushvalue(L, -1);
|
||||
goto clear;
|
||||
}
|
||||
wsgi_req->headers_size += rlen;
|
||||
lua_pop(L, 1);
|
||||
wsgi_req->header_cnt++;
|
||||
}
|
||||
|
||||
if (!raw) {
|
||||
if (write(wsgi_req->poll.fd, "\r\n", 2) != 2) {
|
||||
perror("write()");
|
||||
if ( (rlen = wsgi_req->socket->proto_write_header(wsgi_req, "\r\n", 2)) != 2) {
|
||||
lua_pushvalue(L, -1);
|
||||
goto clear;
|
||||
}
|
||||
wsgi_req->headers_size += rlen;
|
||||
}
|
||||
|
||||
// send body with coroutine
|
||||
@@ -532,8 +549,9 @@ int uwsgi_lua_request(struct wsgi_request *wsgi_req) {
|
||||
while ( (i = lua_pcall(L, 0, 1, 0)) == 0) {
|
||||
if (lua_type(L, -1) == LUA_TSTRING) {
|
||||
http = lua_tolstring(L, -1, &slen);
|
||||
if ( (rlen = write(wsgi_req->poll.fd, http, slen)) != (ssize_t) slen) {
|
||||
perror("write()");
|
||||
if ( (rlen = wsgi_req->socket->proto_write(wsgi_req, (char *)http, slen)) != (ssize_t) slen) {
|
||||
lua_pop(L, 1);
|
||||
lua_pushvalue(L, -1);
|
||||
goto clear;
|
||||
}
|
||||
wsgi_req->response_size += rlen;
|
||||
@@ -550,6 +568,7 @@ int uwsgi_lua_request(struct wsgi_request *wsgi_req) {
|
||||
clear:
|
||||
|
||||
lua_pop(L, 4);
|
||||
clear2:
|
||||
|
||||
// set frequency
|
||||
lua_gc(L, LUA_GCCOLLECT, 0);
|
||||
@@ -590,6 +609,55 @@ int uwsgi_lua_magic(char *mountpoint, char *lazy) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *uwsgi_lua_code_string(char *id, char *code, char *func, char *key, uint16_t keylen) {
|
||||
|
||||
static struct lua_State *L = NULL;
|
||||
|
||||
if (!L) {
|
||||
L = luaL_newstate();
|
||||
luaL_openlibs(L);
|
||||
if (luaL_loadfile(L, code) || lua_pcall(L, 0, 0, 0)) {
|
||||
uwsgi_log("unable to load file %s: %s\n", code, lua_tostring(L, -1));
|
||||
lua_close(L);
|
||||
L = NULL;
|
||||
return NULL;
|
||||
}
|
||||
lua_getglobal(L, func);
|
||||
if (!lua_isfunction(L,-1)) {
|
||||
uwsgi_log("unable to find %s function in lua file %s\n", func, code);
|
||||
lua_close(L);
|
||||
L = NULL;
|
||||
return NULL;
|
||||
}
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_pushvalue(L, -1);
|
||||
lua_pushlstring(L, key, keylen);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("stack pos %d %.*s\n", lua_gettop(L), keylen, key);
|
||||
#endif
|
||||
|
||||
if (lua_pcall(L, 1, 1, 0) != 0) {
|
||||
uwsgi_log("CAZZO\n");
|
||||
uwsgi_log("error running function `f': %s",
|
||||
lua_tostring(L, -1));
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
if (lua_isstring(L, -1)) {
|
||||
const char *ret = lua_tolstring(L, -1, NULL);
|
||||
return (char *)ret;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int uwsgi_lua_signal_handler(uint8_t sig, void *handler) {
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
@@ -614,7 +682,7 @@ int uwsgi_lua_signal_handler(uint8_t sig, void *handler) {
|
||||
|
||||
}
|
||||
|
||||
uint16_t uwsgi_lua_rpc(void * func, uint8_t argc, char **argv, char *buffer) {
|
||||
uint16_t uwsgi_lua_rpc(void * func, uint8_t argc, char **argv, uint16_t argvs[], char *buffer) {
|
||||
|
||||
uint8_t i;
|
||||
const char *sv;
|
||||
@@ -630,7 +698,7 @@ uint16_t uwsgi_lua_rpc(void * func, uint8_t argc, char **argv, char *buffer) {
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ifunc);
|
||||
|
||||
for(i=0;i<argc;i++) {
|
||||
lua_pushstring(L, argv[i]);
|
||||
lua_pushlstring(L, argv[i], argvs[i]);
|
||||
}
|
||||
|
||||
if (lua_pcall(L, argc, 1, 0) != 0) {
|
||||
@@ -664,6 +732,8 @@ struct uwsgi_plugin lua_plugin = {
|
||||
.init_apps = uwsgi_lua_app,
|
||||
.magic = uwsgi_lua_magic,
|
||||
.signal_handler = uwsgi_lua_signal_handler,
|
||||
|
||||
.code_string = uwsgi_lua_code_string,
|
||||
.rpc = uwsgi_lua_rpc,
|
||||
|
||||
};
|
||||
|
||||
+21
-19
@@ -15,46 +15,48 @@ struct option nagios_options[] = {
|
||||
|
||||
int nagios() {
|
||||
|
||||
char *tcp_port;
|
||||
struct pollfd nagios_poll;
|
||||
// connect and send
|
||||
struct uwsgi_header uh;
|
||||
char *buf = NULL;
|
||||
|
||||
if (!use_nagios) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!uwsgi.sockets) {
|
||||
fprintf(stdout, "UWSGI UNKNOWN: you have specified an invalid socket\n");
|
||||
exit(3);
|
||||
}
|
||||
tcp_port = strchr(uwsgi.sockets->name, ':');
|
||||
if (tcp_port == NULL) {
|
||||
fprintf(stdout, "UWSGI UNKNOWN: you have specified an invalid socket\n");
|
||||
exit(3);
|
||||
}
|
||||
|
||||
tcp_port[0] = 0;
|
||||
|
||||
nagios_poll.fd = connect_to_tcp(uwsgi.sockets->name, atoi(tcp_port + 1), uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], 0);
|
||||
if (nagios_poll.fd < 0) {
|
||||
int fd = uwsgi_connect(uwsgi.sockets->name, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], 0);
|
||||
if (fd < 0) {
|
||||
fprintf(stdout, "UWSGI CRITICAL: could not connect() to workers\n");
|
||||
exit(2);
|
||||
}
|
||||
uwsgi.wsgi_req->uh.modifier1 = UWSGI_MODIFIER_PING;
|
||||
uwsgi.wsgi_req->uh.pktsize = 0;
|
||||
uwsgi.wsgi_req->uh.modifier2 = 0;
|
||||
if (write(nagios_poll.fd, uwsgi.wsgi_req, 4) != 4) {
|
||||
|
||||
uh.modifier1 = UWSGI_MODIFIER_PING;
|
||||
uh.pktsize = 0;
|
||||
uh.modifier2 = 0;
|
||||
if (write(fd, &uh, 4) != 4) {
|
||||
uwsgi_error("write()");
|
||||
fprintf(stdout, "UWSGI CRITICAL: could not send ping packet to workers\n");
|
||||
exit(2);
|
||||
}
|
||||
nagios_poll.events = POLLIN;
|
||||
if (!uwsgi_parse_response(&nagios_poll, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], (struct uwsgi_header *) uwsgi.wsgi_req, uwsgi.wsgi_req->buffer, uwsgi_proto_uwsgi_parser)) {
|
||||
|
||||
|
||||
int ret = uwsgi_read_response(fd, &uh, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], &buf);
|
||||
|
||||
if (ret == -2) {
|
||||
fprintf(stdout, "UWSGI CRITICAL: timed out waiting for response\n");
|
||||
exit(2);
|
||||
}
|
||||
else if (ret == -1) {
|
||||
fprintf(stdout, "UWSGI CRITICAL: error reading response\n");
|
||||
exit(2);
|
||||
}
|
||||
else {
|
||||
if (uwsgi.wsgi_req->uh.pktsize > 0) {
|
||||
fprintf(stdout, "UWSGI WARNING: %.*s\n", uwsgi.wsgi_req->uh.pktsize, uwsgi.wsgi_req->buffer);
|
||||
if (uh.pktsize > 0 && buf) {
|
||||
fprintf(stdout, "UWSGI WARNING: %.*s\n", uh.pktsize, buf);
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
PHP_ARG_WITH(uwsgi,,
|
||||
[ --with-uwsgi=UWSGISRCDIR Build PHP as a uWSGI plugin (UNIX/POSIX only)], no, no)
|
||||
|
||||
AC_MSG_CHECKING([for UWSGI])
|
||||
if test "$PHP_UWSGI" != "no"; then
|
||||
|
||||
INSTALL_IT="\$(INSTALL) -m 0755 $SAPI_SHARED $PHP_UWSGI/php_plugin.so"
|
||||
|
||||
UWSGI_CFLAGS=`cd $PHP_UWSGI ; python uwsgiconfig.py --cflags`
|
||||
UWSGI_CFLAGS="$UWSGI_CFLAGS -I$PHP_UWSGI"
|
||||
|
||||
PHP_SELECT_SAPI(uwsgi, shared, php_plugin.c, $UWSGI_CFLAGS)
|
||||
AC_MSG_RESULT([$PHP_UWSGI])
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
@@ -0,0 +1,494 @@
|
||||
#include "php.h"
|
||||
#include "SAPI.h"
|
||||
#include "php_main.h"
|
||||
#include "php_variables.h"
|
||||
|
||||
#include "ext/standard/php_smart_str.h"
|
||||
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
// http status codes list
|
||||
extern struct http_status_codes hsc[];
|
||||
|
||||
struct uwsgi_php {
|
||||
struct uwsgi_string_list *allowed_docroot;
|
||||
struct uwsgi_string_list *allowed_ext;
|
||||
} uphp;
|
||||
|
||||
#define LONG_ARGS_PHP_BASE 17000 + ((14 + 1) * 1000)
|
||||
#define LONG_ARGS_PHP_INI LONG_ARGS_PHP_BASE + 1
|
||||
#define LONG_ARGS_PHP_ALLOWED_DOCROOT LONG_ARGS_PHP_BASE + 2
|
||||
#define LONG_ARGS_PHP_ALLOWED_EXT LONG_ARGS_PHP_BASE + 3
|
||||
|
||||
struct option uwsgi_php_options[] = {
|
||||
|
||||
{"php-ini", required_argument, 0, LONG_ARGS_PHP_INI},
|
||||
{"php-config", required_argument, 0, LONG_ARGS_PHP_INI},
|
||||
{"php-allowed-docroot", required_argument, 0, LONG_ARGS_PHP_ALLOWED_DOCROOT},
|
||||
{"php-allowed-ext", required_argument, 0, LONG_ARGS_PHP_ALLOWED_EXT},
|
||||
{0, 0, 0, 0},
|
||||
|
||||
};
|
||||
|
||||
|
||||
static int sapi_uwsgi_ub_write(const char *str, uint str_length TSRMLS_DC)
|
||||
{
|
||||
struct wsgi_request *wsgi_req = (struct wsgi_request *) SG(server_context);
|
||||
|
||||
ssize_t len = wsgi_req->socket->proto_write(wsgi_req, (char *) str, str_length);
|
||||
if (len != str_length) {
|
||||
php_handle_aborted_connection();
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->response_size += len;
|
||||
return str_length;
|
||||
}
|
||||
|
||||
void uwsgi_php_404(struct wsgi_request *wsgi_req) {
|
||||
|
||||
wsgi_req->status = 404;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write(wsgi_req, "HTTP/1.0 404 Not Found\r\n\r\nNot Found", 35);
|
||||
}
|
||||
|
||||
void uwsgi_php_403(struct wsgi_request *wsgi_req) {
|
||||
|
||||
wsgi_req->status = 403;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write(wsgi_req, "HTTP/1.0 403 Forbidden\r\n\r\nForbidden", 35);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int sapi_uwsgi_send_headers(sapi_headers_struct *sapi_headers)
|
||||
{
|
||||
sapi_header_struct *h;
|
||||
zend_llist_position pos;
|
||||
struct iovec iov[6];
|
||||
char status[4];
|
||||
struct http_status_codes *http_sc;
|
||||
|
||||
struct wsgi_request *wsgi_req = (struct wsgi_request *) SG(server_context);
|
||||
wsgi_req->status = SG(sapi_headers).http_response_code;
|
||||
if (!wsgi_req->status) wsgi_req->status = 200;
|
||||
|
||||
iov[0].iov_base = wsgi_req->protocol;
|
||||
iov[0].iov_len = wsgi_req->protocol_len;
|
||||
|
||||
|
||||
iov[1].iov_base = " ";
|
||||
iov[1].iov_len = 1;
|
||||
|
||||
uwsgi_num2str2n(wsgi_req->status, status, 4);
|
||||
|
||||
iov[2].iov_base = status;
|
||||
iov[2].iov_len = 3;
|
||||
|
||||
iov[3].iov_base = " ";
|
||||
iov[3].iov_len = 1;
|
||||
|
||||
// get the status code
|
||||
for (http_sc = hsc; http_sc->message != NULL; http_sc++) {
|
||||
if (!strncmp(http_sc->key, status, 3)) {
|
||||
iov[4].iov_base = (char *) http_sc->message;
|
||||
iov[4].iov_len = http_sc->message_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (iov[4].iov_len == 0) {
|
||||
iov[4].iov_base = "Unknown";
|
||||
iov[4].iov_len = 7;
|
||||
}
|
||||
|
||||
iov[5].iov_base = "\r\n";
|
||||
iov[5].iov_len = 2;
|
||||
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 6);
|
||||
|
||||
h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
|
||||
while (h) {
|
||||
iov[0].iov_base = h->header;
|
||||
iov[0].iov_len = h->header_len;
|
||||
iov[1].iov_base = "\r\n";
|
||||
iov[1].iov_len = 2;
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_writev_header(wsgi_req, iov, 2);
|
||||
wsgi_req->header_cnt++;
|
||||
h = zend_llist_get_next_ex(&sapi_headers->headers, &pos);
|
||||
}
|
||||
|
||||
wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, "\r\n", 2);
|
||||
|
||||
return SAPI_HEADER_SENT_SUCCESSFULLY;
|
||||
}
|
||||
|
||||
static int sapi_uwsgi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
|
||||
{
|
||||
uint read_bytes = 0;
|
||||
size_t len;
|
||||
int fd = -1;
|
||||
|
||||
struct wsgi_request *wsgi_req = (struct wsgi_request *) SG(server_context);
|
||||
|
||||
if (wsgi_req->body_as_file) {
|
||||
fd = fileno((FILE *)wsgi_req->async_post);
|
||||
}
|
||||
else if (uwsgi.post_buffering > 0) {
|
||||
if (wsgi_req->post_cl > (size_t) uwsgi.post_buffering) {
|
||||
fd = fileno((FILE *)wsgi_req->async_post);
|
||||
}
|
||||
}
|
||||
else {
|
||||
fd = wsgi_req->poll.fd;
|
||||
}
|
||||
|
||||
|
||||
count_bytes = MIN(count_bytes, wsgi_req->post_cl - SG(read_post_bytes));
|
||||
|
||||
// data in memory
|
||||
if (fd == -1) {
|
||||
if (count_bytes > 0) {
|
||||
memcpy(buffer, wsgi_req->post_buffering_buf + wsgi_req->post_pos, count_bytes);
|
||||
wsgi_req->post_pos += count_bytes;
|
||||
}
|
||||
return count_bytes;
|
||||
}
|
||||
|
||||
while (read_bytes < count_bytes) {
|
||||
len = read(fd, buffer + read_bytes, count_bytes - read_bytes);
|
||||
if (len <= 0) {
|
||||
break;
|
||||
}
|
||||
read_bytes += len;
|
||||
}
|
||||
|
||||
return read_bytes;
|
||||
}
|
||||
|
||||
|
||||
static char *sapi_uwsgi_read_cookies(void)
|
||||
{
|
||||
uint16_t len = 0;
|
||||
struct wsgi_request *wsgi_req = (struct wsgi_request *) SG(server_context);
|
||||
|
||||
char *cookie = uwsgi_get_var(wsgi_req, (char *)"HTTP_COOKIE", 11, &len);
|
||||
if (cookie) {
|
||||
return estrndup(cookie, len);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void sapi_uwsgi_register_variables(zval *track_vars_array TSRMLS_DC)
|
||||
{
|
||||
int i;
|
||||
struct wsgi_request *wsgi_req = (struct wsgi_request *) SG(server_context);
|
||||
php_import_environment_variables(track_vars_array TSRMLS_CC);
|
||||
|
||||
for (i = 0; i < wsgi_req->var_cnt; i += 2) {
|
||||
php_register_variable_safe( estrndup(wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len),
|
||||
wsgi_req->hvec[i + 1].iov_base, wsgi_req->hvec[i + 1].iov_len,
|
||||
track_vars_array TSRMLS_CC);
|
||||
}
|
||||
|
||||
php_register_variable_safe("PATH_INFO", wsgi_req->path_info, wsgi_req->path_info_len, track_vars_array TSRMLS_CC);
|
||||
|
||||
php_register_variable_safe("SCRIPT_NAME", wsgi_req->script_name, wsgi_req->script_name_len, track_vars_array TSRMLS_CC);
|
||||
php_register_variable_safe("SCRIPT_FILENAME", wsgi_req->file, wsgi_req->file_len, track_vars_array TSRMLS_CC);
|
||||
|
||||
|
||||
if (wsgi_req->path_info_len) {
|
||||
char *path_translated = ecalloc(1, (wsgi_req->file_len - wsgi_req->script_name_len) + wsgi_req->path_info_len + 1);
|
||||
|
||||
memcpy(path_translated, wsgi_req->file, (wsgi_req->file_len - wsgi_req->script_name_len));
|
||||
memcpy(path_translated + (wsgi_req->file_len - wsgi_req->script_name_len), wsgi_req->path_info, wsgi_req->path_info_len);
|
||||
php_register_variable_safe("PATH_TRANSLATED", path_translated, (wsgi_req->file_len - wsgi_req->script_name_len) + wsgi_req->path_info_len , track_vars_array TSRMLS_CC);
|
||||
}
|
||||
|
||||
php_register_variable_safe("PHP_SELF", wsgi_req->script_name, wsgi_req->script_name_len, track_vars_array TSRMLS_CC);
|
||||
|
||||
|
||||
}
|
||||
|
||||
static sapi_module_struct uwsgi_sapi_module;
|
||||
|
||||
static int php_uwsgi_startup(sapi_module_struct *sapi_module)
|
||||
{
|
||||
if (php_module_startup(&uwsgi_sapi_module, NULL, 0)==FAILURE) {
|
||||
return FAILURE;
|
||||
} else {
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
static void sapi_uwsgi_log_message(char *message) {
|
||||
|
||||
uwsgi_log(message);
|
||||
}
|
||||
|
||||
static sapi_module_struct uwsgi_sapi_module = {
|
||||
"uwsgi",
|
||||
"uWSGI/php",
|
||||
|
||||
php_uwsgi_startup,
|
||||
php_module_shutdown_wrapper,
|
||||
|
||||
NULL, /* activate */
|
||||
NULL, /* deactivate */
|
||||
|
||||
sapi_uwsgi_ub_write,
|
||||
NULL,
|
||||
NULL, /* get uid */
|
||||
NULL, /* getenv */
|
||||
|
||||
php_error,
|
||||
|
||||
NULL,
|
||||
sapi_uwsgi_send_headers,
|
||||
NULL,
|
||||
sapi_uwsgi_read_post,
|
||||
sapi_uwsgi_read_cookies,
|
||||
|
||||
sapi_uwsgi_register_variables,
|
||||
sapi_uwsgi_log_message, /* Log message */
|
||||
NULL, /* Get request time */
|
||||
NULL, /* Child terminate */
|
||||
|
||||
STANDARD_SAPI_MODULE_PROPERTIES
|
||||
};
|
||||
|
||||
int uwsgi_php_init(void) {
|
||||
|
||||
struct http_status_codes *http_sc;
|
||||
|
||||
sapi_startup(&uwsgi_sapi_module);
|
||||
uwsgi_sapi_module.startup(&uwsgi_sapi_module);
|
||||
|
||||
// filling http status codes
|
||||
for (http_sc = hsc; http_sc->message != NULL; http_sc++) {
|
||||
http_sc->message_size = strlen(http_sc->message);
|
||||
}
|
||||
|
||||
|
||||
uwsgi_log("PHP %s initialized\n", PHP_VERSION);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_php_walk(struct wsgi_request *wsgi_req, char *full_path, char *docroot, size_t docroot_len, char **path_info) {
|
||||
|
||||
// and now start walking...
|
||||
uint16_t i;
|
||||
char *ptr = wsgi_req->path_info;
|
||||
char *dst = full_path+docroot_len;
|
||||
char *part = ptr;
|
||||
int part_size = 0;
|
||||
struct stat st;
|
||||
|
||||
if (ptr[0] == '/') part_size++;
|
||||
|
||||
for(i=0;i<wsgi_req->path_info_len;i++) {
|
||||
if (ptr[i] == '/') {
|
||||
memcpy(dst, part, part_size-1);
|
||||
*(dst+part_size-1) = 0;
|
||||
|
||||
if (stat(full_path, &st)) {
|
||||
uwsgi_php_404(wsgi_req);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// not a directory, stop walking
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
if (i < (wsgi_req->path_info_len)-1) {
|
||||
*path_info = ptr + i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// check for buffer overflow !!!
|
||||
*(dst+part_size-1) = '/';
|
||||
*(dst+part_size) = 0;
|
||||
|
||||
dst += part_size ;
|
||||
part_size = 0;
|
||||
part = ptr + i + 1;
|
||||
}
|
||||
|
||||
part_size++;
|
||||
}
|
||||
|
||||
if (part < wsgi_req->path_info+wsgi_req->path_info_len) {
|
||||
memcpy(dst, part, part_size-1);
|
||||
*(dst+part_size-1) = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_php_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
char real_filename[PATH_MAX+1];
|
||||
uint16_t docroot_len = 0;
|
||||
char *path_info = NULL;
|
||||
size_t real_filename_len = 0;
|
||||
|
||||
zend_file_handle file_handle;
|
||||
|
||||
SG(server_context) = (void *) wsgi_req;
|
||||
|
||||
if (uwsgi_parse_vars(wsgi_req)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *docroot = uwsgi_get_var(wsgi_req, (char *) "DOCUMENT_ROOT", 13, &docroot_len);
|
||||
|
||||
if (!docroot) {
|
||||
docroot = uwsgi.cwd;
|
||||
docroot_len = strlen(uwsgi.cwd);
|
||||
}
|
||||
|
||||
char *filename = uwsgi_concat4n(docroot, docroot_len, "/", 1, wsgi_req->path_info, wsgi_req->path_info_len, "", 0);
|
||||
|
||||
if (uwsgi_php_walk(wsgi_req, filename, docroot, docroot_len, &path_info)) {
|
||||
free(filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (path_info) {
|
||||
wsgi_req->path_info = path_info;
|
||||
wsgi_req->path_info_len = strlen(wsgi_req->path_info);
|
||||
}
|
||||
else {
|
||||
wsgi_req->path_info = "";
|
||||
wsgi_req->path_info_len = 0;
|
||||
}
|
||||
|
||||
|
||||
if (!realpath(filename, real_filename)) {
|
||||
free(filename);
|
||||
uwsgi_php_404(wsgi_req);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(filename);
|
||||
real_filename_len = strlen(real_filename);
|
||||
|
||||
if (uphp.allowed_docroot) {
|
||||
struct uwsgi_string_list *usl = uphp.allowed_docroot;
|
||||
while(usl) {
|
||||
if (!uwsgi_starts_with(real_filename, real_filename_len, usl->value, usl->len)) {
|
||||
goto secure;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
uwsgi_php_403(wsgi_req);
|
||||
uwsgi_log("PHP security error: %s is not under an allowed docroot\n", real_filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
secure:
|
||||
|
||||
if (uphp.allowed_ext) {
|
||||
struct uwsgi_string_list *usl = uphp.allowed_ext;
|
||||
while(usl) {
|
||||
if (real_filename_len >= usl->len) {
|
||||
if (!uwsgi_strncmp(real_filename+(real_filename_len-usl->len), usl->len, usl->value, usl->len)) {
|
||||
goto secure2;
|
||||
}
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
uwsgi_php_403(wsgi_req);
|
||||
uwsgi_log("PHP security error: %s does not end with an allowed extension\n", real_filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
secure2:
|
||||
|
||||
wsgi_req->file = real_filename;
|
||||
wsgi_req->file_len = strlen(wsgi_req->file);
|
||||
|
||||
if (docroot[docroot_len-1] == '/') {
|
||||
wsgi_req->script_name = real_filename + (docroot_len-1);
|
||||
}
|
||||
else {
|
||||
wsgi_req->script_name = real_filename + docroot_len;
|
||||
}
|
||||
|
||||
wsgi_req->script_name_len = strlen(wsgi_req->script_name);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("php filename = %s\n", real_filename);
|
||||
#endif
|
||||
|
||||
// now check for allowed paths and extensions
|
||||
|
||||
SG(request_info).request_uri = estrndup(wsgi_req->uri, wsgi_req->uri_len);
|
||||
SG(request_info).request_method = estrndup(wsgi_req->method, wsgi_req->method_len);
|
||||
SG(request_info).proto_num = 1001;
|
||||
|
||||
SG(request_info).query_string = estrndup(wsgi_req->query_string, wsgi_req->query_string_len);
|
||||
SG(request_info).content_length = wsgi_req->post_cl;
|
||||
SG(request_info).content_type = estrndup(wsgi_req->content_type, wsgi_req->content_type_len);
|
||||
|
||||
SG(request_info).path_translated = wsgi_req->file;
|
||||
|
||||
file_handle.type = ZEND_HANDLE_FILENAME;
|
||||
file_handle.filename = real_filename;
|
||||
file_handle.free_filename = 0;
|
||||
file_handle.opened_path = NULL;
|
||||
|
||||
|
||||
if (php_request_startup(TSRMLS_C) == FAILURE) {
|
||||
internal_server_error(wsgi_req, "unable to start php request");
|
||||
return -1;
|
||||
}
|
||||
|
||||
php_execute_script(&file_handle TSRMLS_CC);
|
||||
|
||||
php_request_shutdown(NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uwsgi_php_after_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_LOGGING])
|
||||
log_request(wsgi_req);
|
||||
}
|
||||
|
||||
int uwsgi_php_manage_options(int i, char *optarg) {
|
||||
|
||||
switch(i) {
|
||||
case LONG_ARGS_PHP_INI:
|
||||
uwsgi_sapi_module.php_ini_path_override = uwsgi_str(optarg);
|
||||
uwsgi_sapi_module.php_ini_ignore = 1;
|
||||
return 1;
|
||||
case LONG_ARGS_PHP_ALLOWED_DOCROOT:
|
||||
uwsgi_string_new_list(&uphp.allowed_docroot, optarg);
|
||||
return 1;
|
||||
case LONG_ARGS_PHP_ALLOWED_EXT:
|
||||
uwsgi_string_new_list(&uphp.allowed_ext, optarg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
SAPI_API struct uwsgi_plugin php_plugin = {
|
||||
.modifier1 = 14,
|
||||
.init = uwsgi_php_init,
|
||||
.request = uwsgi_php_request,
|
||||
.after_request = uwsgi_php_after_request,
|
||||
.options = uwsgi_php_options,
|
||||
.manage_opt = uwsgi_php_manage_options,
|
||||
};
|
||||
|
||||
@@ -16,31 +16,34 @@ struct option uwsgi_ping_options[] = {
|
||||
static void ping() {
|
||||
|
||||
struct uwsgi_header uh;
|
||||
struct pollfd uwsgi_poll;
|
||||
char *buf = NULL;
|
||||
|
||||
// use a 3 secs timeout by default
|
||||
if (!uping.ping_timeout) uping.ping_timeout = 3;
|
||||
|
||||
uwsgi_log("PING uwsgi host %s (timeout: %d)\n", uping.ping, uping.ping_timeout);
|
||||
|
||||
uwsgi_poll.fd = uwsgi_connect(uping.ping, uping.ping_timeout, 0);
|
||||
if (uwsgi_poll.fd < 0) {
|
||||
int fd = uwsgi_connect(uping.ping, uping.ping_timeout, 0);
|
||||
if (fd < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uh.modifier1 = UWSGI_MODIFIER_PING;
|
||||
uh.pktsize = 0;
|
||||
uh.modifier2 = 0;
|
||||
if (write(uwsgi_poll.fd, &uh, 4) != 4) {
|
||||
|
||||
if (write(fd, &uh, 4) != 4) {
|
||||
uwsgi_error("write()");
|
||||
exit(2);
|
||||
}
|
||||
uwsgi_poll.events = POLLIN;
|
||||
if (!uwsgi_parse_response(&uwsgi_poll, uping.ping_timeout, &uh, NULL, uwsgi_proto_uwsgi_parser)) {
|
||||
|
||||
int ret = uwsgi_read_response(fd, &uh, uping.ping_timeout, &buf);
|
||||
if (ret < 0) {
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
if (uh.pktsize > 0) {
|
||||
uwsgi_log("[WARNING] node %s message: %.*s\n", uping.ping, uh.pktsize, buf);
|
||||
exit(2);
|
||||
}
|
||||
else {
|
||||
@@ -92,6 +95,8 @@ int uwsgi_ping_manage_options(int i, char *optarg) {
|
||||
|
||||
switch(i) {
|
||||
case LONG_ARGS_PING:
|
||||
uwsgi.no_initial_output = 1;
|
||||
uwsgi.no_server = 1;
|
||||
uping.ping = optarg;
|
||||
return 1;
|
||||
case LONG_ARGS_PING_TIMEOUT:
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int connect_prober_callback(int interesting_fd, struct uwsgi_signal_probe *up) {
|
||||
|
||||
// is this a timeout event ?
|
||||
if (interesting_fd == -1) {
|
||||
// am i wating for something ?
|
||||
if (up->fd != -1) {
|
||||
if (up->cycles > (uint64_t) up->timeout) {
|
||||
// reset the cycle
|
||||
up->cycles = 0;
|
||||
close(up->fd);
|
||||
up->fd = -1;
|
||||
// state = NOOP
|
||||
up->state = 0;
|
||||
// avoid duplicated events
|
||||
if (!up->bad) {
|
||||
up->bad = 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ok register a new event
|
||||
else {
|
||||
if ((up->cycles % up->freq) == 0) {
|
||||
up->fd = uwsgi_connect(up->args, -1, 1);
|
||||
if (up->fd != -1) {
|
||||
// status = CONNECTING
|
||||
up->state = 1;
|
||||
event_queue_add_fd_write(uwsgi.master_queue, up->fd);
|
||||
return 0;
|
||||
}
|
||||
// signal the bad event (if not already bad)
|
||||
if (!up->bad) {
|
||||
up->bad = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (up->fd != -1) {
|
||||
// is this event for me ?
|
||||
if (interesting_fd == up->fd) {
|
||||
// uselsess here (we have only one state), only to show a good practice
|
||||
// check the state
|
||||
if (up->state == 1) {
|
||||
if (uwsgi_is_bad_connection(up->fd)) {
|
||||
// signal the bad connection (if needed)
|
||||
up->cycles = 0;
|
||||
close(up->fd);
|
||||
up->fd = -1;
|
||||
// state = NOOP
|
||||
up->state = 0;
|
||||
if (!up->bad) {
|
||||
up->bad = 1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// this is a good connection
|
||||
up->cycles = 0;
|
||||
close(up->fd);
|
||||
up->fd = -1;
|
||||
// state = NOOP
|
||||
up->state = 0;
|
||||
if (up->bad) {
|
||||
up->bad = 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// default action
|
||||
return 0;
|
||||
}
|
||||
|
||||
int probeconnect_init() {
|
||||
|
||||
uwsgi_probe_register(&uwsgi.probes, "connect", connect_prober_callback);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct uwsgi_plugin probeconnect_plugin = {
|
||||
|
||||
.init = probeconnect_init,
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
NAME='probeconnect'
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
|
||||
GCC_LIST = ['connectprobe']
|
||||
@@ -0,0 +1,132 @@
|
||||
#include "../../uwsgi.h"
|
||||
#include <libpq-fe.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
int pg_prober_callback(int, struct uwsgi_signal_probe *);
|
||||
int probepg_init(void);
|
||||
|
||||
int pg_prober_callback(int interesting_fd, struct uwsgi_signal_probe *up) {
|
||||
|
||||
// is this a timeout event ?
|
||||
if (interesting_fd == -1) {
|
||||
// am i wating for something ?
|
||||
if (up->fd != -1) {
|
||||
if (up->cycles > (uint64_t) up->timeout) {
|
||||
// reset the cycle
|
||||
up->cycles = 0;
|
||||
PQfinish((PGconn *) up->data);
|
||||
up->fd = -1;
|
||||
// state = NOOP
|
||||
up->state = 0;
|
||||
// avoid duplicated events
|
||||
if (!up->bad) {
|
||||
up->bad = 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ok register a new event
|
||||
else {
|
||||
if ((up->cycles % up->freq) == 0) {
|
||||
up->last_event = event_queue_write();
|
||||
up->data = (void *) PQconnectStart(up->args);
|
||||
if (up->data) {
|
||||
// status = CONNECTING
|
||||
up->state = PQstatus((PGconn *) up->data);
|
||||
if (up->state == CONNECTION_BAD)
|
||||
goto bad;
|
||||
up->fd = PQsocket((PGconn *) up->data);
|
||||
event_queue_add_fd_write(uwsgi.master_queue, up->fd);
|
||||
return 0;
|
||||
}
|
||||
bad:
|
||||
// signal the bad event (if not already bad)
|
||||
if (!up->bad) {
|
||||
up->bad = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (up->fd != -1) {
|
||||
// is this event for me ?
|
||||
if (interesting_fd == up->fd) {
|
||||
// check the state
|
||||
up->state = PQstatus((PGconn *) up->data);
|
||||
if (up->state == CONNECTION_BAD) {
|
||||
// signal the bad connection (if needed)
|
||||
up->cycles = 0;
|
||||
PQfinish((PGconn *) up->data);
|
||||
up->fd = -1;
|
||||
up->state = 0;
|
||||
if (!up->bad) {
|
||||
up->bad = 1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (up->state == CONNECTION_OK) {
|
||||
up->cycles = 0;
|
||||
PQfinish((PGconn *) up->data);
|
||||
up->fd = -1;
|
||||
// state = NOOP
|
||||
up->state = 0;
|
||||
if (up->bad) {
|
||||
up->bad = 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
// still wait...
|
||||
else {
|
||||
PostgresPollingStatusType wait_type = PQconnectPoll((PGconn *) up->data);
|
||||
// the connection is good
|
||||
if (wait_type == PGRES_POLLING_ACTIVE || wait_type == PGRES_POLLING_FAILED || wait_type == PGRES_POLLING_OK) {
|
||||
if (wait_type == PGRES_POLLING_ACTIVE)
|
||||
wait_type = PQconnectPoll((PGconn *) up->data);
|
||||
up->cycles = 0;
|
||||
up->fd = -1;
|
||||
// state = NOOP
|
||||
up->state = 0;
|
||||
PQfinish((PGconn *) up->data);
|
||||
if (wait_type == PGRES_POLLING_FAILED) {
|
||||
if (!up->bad) {
|
||||
up->bad = 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (up->bad) {
|
||||
up->bad = 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (wait_type == PGRES_POLLING_READING) {
|
||||
event_queue_del_fd(uwsgi.master_queue, up->fd, up->last_event);
|
||||
event_queue_add_fd_read(uwsgi.master_queue, up->fd);
|
||||
up->last_event = event_queue_read();
|
||||
}
|
||||
else if (wait_type == PGRES_POLLING_WRITING) {
|
||||
event_queue_del_fd(uwsgi.master_queue, up->fd, up->last_event);
|
||||
event_queue_add_fd_write(uwsgi.master_queue, up->fd);
|
||||
up->last_event = event_queue_write();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// default action
|
||||
return 0;
|
||||
}
|
||||
|
||||
int probepg_init() {
|
||||
|
||||
uwsgi_probe_register(&uwsgi.probes, "pg", pg_prober_callback);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct uwsgi_plugin probepg_plugin = {
|
||||
|
||||
.init = probepg_init,
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
import os
|
||||
|
||||
NAME='probepg'
|
||||
CFLAGS = os.popen('pg_config --cflags').read().rstrip().split()
|
||||
CFLAGS.append('-I' + os.popen('pg_config --includedir').read().rstrip())
|
||||
LDFLAGS = os.popen('pg_config --ldflags').read().rstrip().split()
|
||||
LIBS = ['-L' + os.popen('pg_config --libdir').read().rstrip(), '-lpq']
|
||||
|
||||
GCC_LIST = ['pgprobe']
|
||||
@@ -1,490 +0,0 @@
|
||||
/*
|
||||
|
||||
uWSGI proxy
|
||||
|
||||
it needs one of this tecnology to work:
|
||||
|
||||
- epoll (linux 2.6)
|
||||
- kqueue (various BSD and Darwin)
|
||||
- /dev/poll (Solaris)
|
||||
|
||||
*/
|
||||
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
#define LONG_ARGS_PROXY_WORKERS 50000
|
||||
|
||||
struct uwsgi_proxy {
|
||||
char *socket_name;
|
||||
int add_me;
|
||||
int workers;
|
||||
int fd;
|
||||
} uproxy;
|
||||
|
||||
struct option proxy_options[] = {
|
||||
{"proxy", required_argument, 0, LONG_ARGS_PROXY},
|
||||
{"proxy-node", required_argument, 0, LONG_ARGS_PROXY_NODE},
|
||||
{"proxy-max-connections", required_argument, 0, LONG_ARGS_PROXY_MAX_CONNECTIONS},
|
||||
{"proxy-workers", required_argument, 0, LONG_ARGS_PROXY_WORKERS},
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
#define UWSGI_PROXY_CONNECTING 1
|
||||
#define UWSGI_PROXY_WAITING 2
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_proxy_connection {
|
||||
|
||||
int dest_fd;
|
||||
int status;
|
||||
int retry;
|
||||
int node;
|
||||
};
|
||||
|
||||
static void end_proxy(void) {
|
||||
exit(UWSGI_END_CODE);
|
||||
}
|
||||
|
||||
|
||||
static void reload_proxy(void) {
|
||||
exit(UWSGI_RELOAD_CODE);
|
||||
}
|
||||
|
||||
static void uwsgi_proxy_close(struct uwsgi_proxy_connection *upcs, int fd) {
|
||||
|
||||
if (upcs[fd].dest_fd >= 0) {
|
||||
close(upcs[fd].dest_fd);
|
||||
upcs[upcs[fd].dest_fd].dest_fd = -1;
|
||||
upcs[upcs[fd].dest_fd].status = 0;
|
||||
upcs[upcs[fd].dest_fd].retry = 0;
|
||||
if (upcs[upcs[fd].dest_fd].node > -1) {
|
||||
if (uwsgi.shared->nodes[upcs[upcs[fd].dest_fd].node].connections > 0)
|
||||
uwsgi.shared->nodes[upcs[upcs[fd].dest_fd].node].connections--;
|
||||
}
|
||||
}
|
||||
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
upcs[fd].dest_fd = -1;
|
||||
upcs[fd].status = 0;
|
||||
upcs[fd].retry = 0;
|
||||
if (upcs[fd].node > -1) {
|
||||
if (uwsgi.shared->nodes[upcs[fd].node].connections > 0)
|
||||
uwsgi.shared->nodes[upcs[fd].node].connections--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int uwsgi_proxy_find_next_node(int current_node) {
|
||||
int i;
|
||||
|
||||
current_node++;
|
||||
if (current_node >= MAX_CLUSTER_NODES) {
|
||||
current_node = 0;
|
||||
}
|
||||
|
||||
// is it a good node ?
|
||||
if (uwsgi.shared->nodes[current_node].name[0] != 0 && uwsgi.shared->nodes[current_node].status == UWSGI_NODE_OK) {
|
||||
if (uwsgi.shared->nodes[current_node].connections < uwsgi.shared->nodes[current_node].workers)
|
||||
return current_node;
|
||||
}
|
||||
|
||||
// try to find a better one
|
||||
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
if (uwsgi.shared->nodes[i].name[0] != 0 && uwsgi.shared->nodes[i].status == UWSGI_NODE_OK) {
|
||||
if (uwsgi.shared->nodes[i].connections < uwsgi.shared->nodes[i].workers)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// ok, it is a very loaded system, fallback to round robin
|
||||
if (uwsgi.shared->nodes[current_node].name[0] != 0 && uwsgi.shared->nodes[current_node].status == UWSGI_NODE_OK) {
|
||||
return current_node;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
if (uwsgi.shared->nodes[i].name[0] != 0 && uwsgi.shared->nodes[i].status == UWSGI_NODE_OK) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void proxy_loop() {
|
||||
|
||||
int efd;
|
||||
|
||||
#ifdef __linux__
|
||||
struct epoll_event *eevents;
|
||||
struct epoll_event ev;
|
||||
#elif defined(__sun__)
|
||||
struct pollfd *eevents;
|
||||
struct pollfd ev;
|
||||
#else
|
||||
struct kevent *eevents;
|
||||
struct kevent ev;
|
||||
#endif
|
||||
|
||||
int max_events = 64;
|
||||
int nevents, i;
|
||||
const int nonblocking = 1;
|
||||
const int blocking = 0;
|
||||
|
||||
char buffer[4096];
|
||||
ssize_t rlen;
|
||||
ssize_t wlen;
|
||||
int max_connections = sysconf(_SC_OPEN_MAX);
|
||||
|
||||
int soopt;
|
||||
socklen_t solen = sizeof(int);
|
||||
|
||||
int rc;
|
||||
|
||||
struct uwsgi_proxy_connection *upcs;
|
||||
|
||||
struct sockaddr_in upc_addr;
|
||||
socklen_t upc_len = sizeof(struct sockaddr_in);
|
||||
|
||||
int next_node = -1;
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log( "allocating space for %d concurrent proxy connections\n", max_connections);
|
||||
#endif
|
||||
|
||||
// allocate memory for connections
|
||||
upcs = malloc(sizeof(struct uwsgi_proxy_connection) * max_connections);
|
||||
if (!upcs) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
}
|
||||
memset(upcs, 0, sizeof(struct uwsgi_proxy_connection) * max_connections);
|
||||
|
||||
if (uproxy.add_me) {
|
||||
uwsgi_cluster_simple_add_node(uwsgi.sockets[0].name, 1, CLUSTER_NODE_STATIC);
|
||||
}
|
||||
|
||||
efd = async_queue_init(uproxy.fd);
|
||||
if (efd < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
eevents = malloc(sizeof(struct epoll_event) * max_events);
|
||||
memset(&ev, 0, sizeof(struct epoll_event));
|
||||
#elif defined(__sun)
|
||||
eevents = malloc(sizeof(struct pollfd) * max_events);
|
||||
memset(&ev, 0, sizeof(struct pollfd));
|
||||
#else
|
||||
eevents = malloc(sizeof(struct kevent) * max_events);
|
||||
memset(&ev, 0, sizeof(struct kevent));
|
||||
#endif
|
||||
|
||||
if (!eevents) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
signal(SIGINT, (void *) &end_proxy);
|
||||
signal(SIGTERM, (void *) &reload_proxy);
|
||||
signal(SIGHUP, (void *) &reload_proxy);
|
||||
// and welcome to the loop...
|
||||
|
||||
for (;;) {
|
||||
|
||||
nevents = async_wait(efd, eevents, max_events, -1, 0);
|
||||
if (nevents < 0) {
|
||||
uwsgi_error("epoll_wait()");
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < nevents; i++) {
|
||||
|
||||
if ( (int)eevents[i].ASYNC_FD == uproxy.fd) {
|
||||
|
||||
if (eevents[i].ASYNC_IS_IN) {
|
||||
// new connection, accept it
|
||||
ev.ASYNC_FD = accept(uproxy.fd, (struct sockaddr *) &upc_addr, &upc_len);
|
||||
if ( (int) ev.ASYNC_FD < 0) {
|
||||
uwsgi_error("accept()");
|
||||
continue;
|
||||
}
|
||||
upcs[ev.ASYNC_FD].node = -1;
|
||||
|
||||
// now connect to the first worker available
|
||||
|
||||
upcs[ev.ASYNC_FD].dest_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (upcs[ev.ASYNC_FD].dest_fd < 0) {
|
||||
uwsgi_error("socket()");
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
upcs[upcs[ev.ASYNC_FD].dest_fd].node = -1;
|
||||
|
||||
// set nonblocking
|
||||
if (ioctl(upcs[ev.ASYNC_FD].dest_fd, FIONBIO, &nonblocking)) {
|
||||
uwsgi_error("ioctl()");
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
|
||||
upcs[ev.ASYNC_FD].status = 0;
|
||||
upcs[ev.ASYNC_FD].retry = 0;
|
||||
next_node = uwsgi_proxy_find_next_node(next_node);
|
||||
if (next_node == -1) {
|
||||
uwsgi_log( "unable to find an available worker in the cluster !\n");
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
upcs[upcs[ev.ASYNC_FD].dest_fd].node = next_node;
|
||||
rc = connect(upcs[ev.ASYNC_FD].dest_fd, (struct sockaddr *) &uwsgi.shared->nodes[next_node].ucn_addr, sizeof(struct sockaddr_in));
|
||||
uwsgi.shared->nodes[next_node].connections++;
|
||||
|
||||
if (!rc) {
|
||||
// connected to worker, put it in the epoll_list
|
||||
|
||||
if (async_add(efd, ev.ASYNC_FD, ASYNC_IN)) {
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
|
||||
upcs[upcs[ev.ASYNC_FD].dest_fd].dest_fd = ev.ASYNC_FD;
|
||||
upcs[upcs[ev.ASYNC_FD].dest_fd].status = 0;
|
||||
upcs[upcs[ev.ASYNC_FD].dest_fd].retry = 0;
|
||||
|
||||
ev.ASYNC_FD = upcs[ev.ASYNC_FD].dest_fd;
|
||||
|
||||
if (async_add(efd, ev.ASYNC_FD, ASYNC_IN)) {
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
|
||||
// re-set blocking
|
||||
if (ioctl(upcs[upcs[ev.ASYNC_FD].dest_fd].dest_fd, FIONBIO, &blocking)) {
|
||||
uwsgi_error("ioctl()");
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
else if (errno == EINPROGRESS) {
|
||||
// the socket is waiting, set status to CONNECTING
|
||||
upcs[ev.ASYNC_FD].status = UWSGI_PROXY_WAITING;
|
||||
upcs[upcs[ev.ASYNC_FD].dest_fd].dest_fd = ev.ASYNC_FD;
|
||||
upcs[upcs[ev.ASYNC_FD].dest_fd].status = UWSGI_PROXY_CONNECTING;
|
||||
upcs[upcs[ev.ASYNC_FD].dest_fd].retry = 0;
|
||||
|
||||
ev.ASYNC_FD = upcs[ev.ASYNC_FD].dest_fd;
|
||||
if (async_add(efd, ev.ASYNC_FD, ASYNC_OUT)) {
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// connection failed, retry with the next node ?
|
||||
uwsgi_error("connect()");
|
||||
// close only when all node are tried
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
uwsgi_log( "!!! something horrible happened to the uWSGI proxy, reloading it !!!\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// this is for clients/workers
|
||||
if (eevents[i].ASYNC_IS_IN) {
|
||||
|
||||
// is this a connected client/worker ?
|
||||
//uwsgi_log("ready %d\n", upcs[eevents[i].data.fd].status);
|
||||
|
||||
if (!upcs[eevents[i].ASYNC_FD].status) {
|
||||
if (upcs[eevents[i].ASYNC_FD].dest_fd >= 0) {
|
||||
|
||||
rlen = read(eevents[i].ASYNC_FD, buffer, 4096);
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("read()");
|
||||
uwsgi_proxy_close(upcs, eevents[i].ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
else if (rlen == 0) {
|
||||
uwsgi_proxy_close(upcs, eevents[i].ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
wlen = write(upcs[eevents[i].ASYNC_FD].dest_fd, buffer, rlen);
|
||||
if (wlen != rlen) {
|
||||
uwsgi_error("write()");
|
||||
uwsgi_proxy_close(upcs, eevents[i].ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_proxy_close(upcs, eevents[i].ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (upcs[eevents[i].ASYNC_FD].status == UWSGI_PROXY_WAITING) {
|
||||
// disconnected node
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
uwsgi_log( "UNKNOWN STATUS %d\n", upcs[eevents[i].ASYNC_FD].status);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (eevents[i].ASYNC_IS_OUT) {
|
||||
if (upcs[eevents[i].ASYNC_FD].status == UWSGI_PROXY_CONNECTING) {
|
||||
|
||||
|
||||
#ifdef UWSGI_PROXY_USE_KQUEUE
|
||||
if (getsockopt(eevents[i].ASYNC_FD, SOL_SOCKET, SO_ERROR, (void *) (&soopt), &solen) < 0) {
|
||||
uwsgi_error("getsockopt()");
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
/* is something bad ? */
|
||||
if (soopt) {
|
||||
uwsgi_log( "connect() %s\n", strerror(soopt));
|
||||
// increase errors on node
|
||||
uwsgi_log( "*** marking cluster node %d/%s as failed ***\n", upcs[eevents[i].ASYNC_FD].node, uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].name);
|
||||
if (uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].type == CLUSTER_NODE_DYNAMIC) {
|
||||
uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].name[0] = 0 ;
|
||||
}
|
||||
else {
|
||||
uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].errors++;
|
||||
uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].status = UWSGI_NODE_FAILED;
|
||||
}
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
|
||||
// increase errors on node
|
||||
#endif
|
||||
ev.ASYNC_FD = upcs[eevents[i].ASYNC_FD].dest_fd;
|
||||
upcs[ev.ASYNC_FD].status = 0;
|
||||
if (async_add(efd, ev.ASYNC_FD, ASYNC_IN)) {
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
|
||||
ev.ASYNC_FD = upcs[ev.ASYNC_FD].dest_fd;
|
||||
upcs[ev.ASYNC_FD].status = 0;
|
||||
|
||||
if (async_mod(efd, ev.ASYNC_FD, ASYNC_IN)) {
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
// re-set blocking
|
||||
if (ioctl(ev.ASYNC_FD, FIONBIO, &blocking)) {
|
||||
uwsgi_error("ioctl()");
|
||||
uwsgi_proxy_close(upcs, ev.ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log( "strange event for %d\n", (int) eevents[i].ASYNC_FD);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (upcs[eevents[i].ASYNC_FD].status == UWSGI_PROXY_CONNECTING) {
|
||||
if (getsockopt(eevents[i].ASYNC_FD, SOL_SOCKET, SO_ERROR, (void *) (&soopt), &solen) < 0) {
|
||||
uwsgi_error("getsockopt()");
|
||||
}
|
||||
/* is something bad ? */
|
||||
if (soopt) {
|
||||
uwsgi_log( "connect() %s\n", strerror(soopt));
|
||||
}
|
||||
|
||||
// increase errors on node
|
||||
uwsgi_log( "*** marking cluster node %d/%s as failed ***\n", upcs[eevents[i].ASYNC_FD].node, uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].name);
|
||||
if (uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].type == CLUSTER_NODE_DYNAMIC) {
|
||||
uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].name[0] = 0;
|
||||
}
|
||||
else {
|
||||
uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].errors++;
|
||||
uwsgi.shared->nodes[upcs[eevents[i].ASYNC_FD].node].status = UWSGI_NODE_FAILED;
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log( "STRANGE EVENT !!! %d %d %d\n", (int) eevents[i].ASYNC_FD, (int) eevents[i].ASYNC_EV, upcs[eevents[i].ASYNC_FD].status);
|
||||
}
|
||||
uwsgi_proxy_close(upcs, eevents[i].ASYNC_FD);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int proxy_init() {
|
||||
int i;
|
||||
char *tcp_port;
|
||||
|
||||
if (!uproxy.workers) uproxy.workers = 1 ;
|
||||
|
||||
if (uproxy.socket_name) {
|
||||
|
||||
tcp_port = strchr(uproxy.socket_name, ':');
|
||||
|
||||
if (tcp_port == NULL) {
|
||||
uproxy.fd = bind_to_unix(uproxy.socket_name, UWSGI_LISTEN_QUEUE, uwsgi.chmod_socket, uwsgi.abstract_socket);
|
||||
}
|
||||
else {
|
||||
uproxy.fd = bind_to_tcp(uproxy.socket_name, UWSGI_LISTEN_QUEUE, tcp_port);
|
||||
tcp_port[0] = ':';
|
||||
}
|
||||
|
||||
if (uproxy.fd < 0) {
|
||||
uwsgi_log( "unable to create the proxy server socket.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for(i=0;i<uproxy.workers;i++) {
|
||||
if (register_gateway("proxy", proxy_loop) == NULL) {
|
||||
uwsgi_log("unable to register the proxy gateway\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int proxy_opt(int i, char *optarg) {
|
||||
|
||||
switch(i) {
|
||||
|
||||
case LONG_ARGS_PROXY_NODE:
|
||||
if (uwsgi.cluster_fd >= 0 && !strcmp(optarg, "@self")) {
|
||||
uproxy.add_me = 1;
|
||||
}
|
||||
else {
|
||||
uwsgi_cluster_simple_add_node(optarg, 1, CLUSTER_NODE_STATIC);
|
||||
}
|
||||
return 1;
|
||||
case LONG_ARGS_PROXY:
|
||||
uproxy.socket_name = optarg;
|
||||
return 1;
|
||||
case LONG_ARGS_PROXY_WORKERS:
|
||||
uproxy.workers = atoi(optarg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_plugin proxy_plugin = {
|
||||
|
||||
.options = proxy_options,
|
||||
.manage_opt = proxy_opt,
|
||||
.init = proxy_init,
|
||||
};
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ struct uwsgi_perl {
|
||||
|
||||
void init_perl_embedded_module(void);
|
||||
void uwsgi_psgi_app(void);
|
||||
int psgi_response(struct wsgi_request *, PerlInterpreter *, AV*);
|
||||
int psgi_response(struct wsgi_request *, AV*);
|
||||
|
||||
#define psgi_xs(func) newXS("uwsgi::" #func, XS_##func, "uwsgi")
|
||||
#define psgi_check_args(x) if (items < x) Perl_croak(aTHX_ "Usage: uwsgi::%s takes %d arguments", __FUNCTION__ + 3, x)
|
||||
|
||||
+10
-15
@@ -41,19 +41,11 @@ XS(XS_stream)
|
||||
AV *response = (AV* ) SvREFCNT_inc(SvRV(ST(0))) ;
|
||||
|
||||
if (av_len(response) == 2) {
|
||||
|
||||
#ifdef my_perl
|
||||
while (psgi_response(wsgi_req, my_perl, response) != UWSGI_OK);
|
||||
#else
|
||||
while (psgi_response(wsgi_req, uperl.main, response) != UWSGI_OK);
|
||||
#endif
|
||||
while (psgi_response(wsgi_req, response) != UWSGI_OK);
|
||||
}
|
||||
else if (av_len(response) == 1) {
|
||||
#ifdef my_perl
|
||||
while (psgi_response(wsgi_req, my_perl, response) != UWSGI_OK);
|
||||
#else
|
||||
while (psgi_response(wsgi_req, uperl.main, response) != UWSGI_OK);
|
||||
#endif
|
||||
while (psgi_response(wsgi_req, response) != UWSGI_OK);
|
||||
|
||||
SvREFCNT_dec(response);
|
||||
ST(0) = sv_bless(newRV(sv_newmortal()), uperl.streaming_stash);
|
||||
XSRETURN(1);
|
||||
@@ -95,7 +87,7 @@ XS(XS_input_read) {
|
||||
}
|
||||
else if (uwsgi.post_buffering > 0) {
|
||||
fd = -1;
|
||||
if (wsgi_req->post_cl <= (size_t) uwsgi.post_buffering) {
|
||||
if (wsgi_req->post_cl > (size_t) uwsgi.post_buffering) {
|
||||
fd = fileno((FILE *)wsgi_req->async_post);
|
||||
}
|
||||
}
|
||||
@@ -236,6 +228,7 @@ xs_init(pTHX)
|
||||
void uwsgi_psgi_app() {
|
||||
|
||||
struct stat stat_psgi;
|
||||
int id = uwsgi_apps_cnt;
|
||||
|
||||
if (uperl.psgi) {
|
||||
|
||||
@@ -291,7 +284,6 @@ void uwsgi_psgi_app() {
|
||||
|
||||
uperl.psgibuffer[stat_psgi.st_size] = 0;
|
||||
|
||||
if (uwsgi.threads < 2) {
|
||||
uperl.psgi_main = perl_eval_pv(uwsgi_concat4("#line 1 ", uperl.psgi, "\n", uperl.psgibuffer), 0);
|
||||
if (!uperl.psgi_main) {
|
||||
uwsgi_log("unable to find PSGI function entry point.\n");
|
||||
@@ -303,11 +295,14 @@ void uwsgi_psgi_app() {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (uwsgi.threads < 2) {
|
||||
free(uperl.psgibuffer);
|
||||
close(uperl.fd);
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_add_app(id, 5, "", 0);
|
||||
uwsgi_log("PSGI app %d (%s) loaded at %p\n", id, uperl.psgi, uperl.psgi_main);
|
||||
|
||||
uwsgi_log("PSGI app (%s) loaded at %p\n", uperl.psgi, uperl.psgi_main);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+70
-63
@@ -3,7 +3,11 @@
|
||||
extern char **environ;
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#ifdef __APPLE__
|
||||
extern struct uwsgi_perl uperl;
|
||||
#else
|
||||
struct uwsgi_perl uperl;
|
||||
#endif
|
||||
|
||||
struct option uwsgi_perl_options[] = {
|
||||
|
||||
@@ -19,7 +23,7 @@ SV *uwsgi_perl_obj_new(char *class, size_t class_len) {
|
||||
|
||||
SV *newobj;
|
||||
// set current context ?
|
||||
//dTHX;
|
||||
dTHX;
|
||||
dSP;
|
||||
|
||||
ENTER;
|
||||
@@ -45,7 +49,7 @@ SV *uwsgi_perl_call_stream(SV *func) {
|
||||
|
||||
SV *ret = NULL;
|
||||
// set current context ?
|
||||
//dTHX;
|
||||
dTHX;
|
||||
dSP;
|
||||
|
||||
ENTER;
|
||||
@@ -75,7 +79,7 @@ int uwsgi_perl_obj_can(SV *obj, char *method, size_t len) {
|
||||
|
||||
int ret;
|
||||
// set current context ? needed for threading
|
||||
//dTHX;
|
||||
dTHX;
|
||||
dSP;
|
||||
|
||||
ENTER;
|
||||
@@ -103,6 +107,7 @@ SV *uwsgi_perl_obj_call(SV *obj, char *method) {
|
||||
|
||||
SV *ret = NULL;
|
||||
|
||||
dTHX;
|
||||
dSP;
|
||||
|
||||
ENTER;
|
||||
@@ -136,6 +141,7 @@ AV *psgi_call(struct wsgi_request *wsgi_req, SV *psgi_func, SV *env) {
|
||||
|
||||
AV *ret = NULL;
|
||||
|
||||
dTHX;
|
||||
dSP;
|
||||
|
||||
ENTER;
|
||||
@@ -145,6 +151,7 @@ AV *psgi_call(struct wsgi_request *wsgi_req, SV *psgi_func, SV *env) {
|
||||
PUTBACK;
|
||||
|
||||
call_sv(psgi_func, G_SCALAR | G_EVAL);
|
||||
|
||||
SPAGAIN;
|
||||
|
||||
if(SvTRUE(ERRSV)) {
|
||||
@@ -257,6 +264,10 @@ SV *build_psgi_env(struct wsgi_request *wsgi_req) {
|
||||
|
||||
if (!hv_store(env, "psgix.input.buffered", 20, newSViv(wsgi_req->body_as_file), 0)) goto clear;
|
||||
|
||||
if (uwsgi.master_process) {
|
||||
if (!hv_store(env, "psgix.harakiri", 14, newSViv(1), 0)) goto clear;
|
||||
}
|
||||
|
||||
SV *pe = uwsgi_perl_obj_new("uwsgi::error", 12);
|
||||
if (!hv_store(env, "psgi.errors", 11, pe, 0)) goto clear;
|
||||
|
||||
@@ -272,7 +283,7 @@ int uwsgi_perl_init(){
|
||||
|
||||
struct http_status_codes *http_sc;
|
||||
|
||||
int argc = 3;
|
||||
int argc;
|
||||
uperl.embedding[0] = "";
|
||||
uperl.embedding[1] = "-e";
|
||||
uperl.embedding[2] = "0";
|
||||
@@ -281,11 +292,18 @@ int uwsgi_perl_init(){
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
|
||||
if (setenv("PLACK_SERVER", "uwsgi", 0)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
|
||||
#ifdef PERL_VERSION_STRING
|
||||
uwsgi_log("initializing Perl %s environment\n", PERL_VERSION_STRING);
|
||||
#else
|
||||
uwsgi_log("initializing Perl environment\n");
|
||||
#endif
|
||||
|
||||
argc = 3;
|
||||
|
||||
PERL_SYS_INIT3(&argc, (char ***) &uperl.embedding, &environ);
|
||||
uperl.main = perl_alloc();
|
||||
if (!uperl.main) {
|
||||
@@ -311,51 +329,19 @@ int uwsgi_perl_init(){
|
||||
|
||||
}
|
||||
|
||||
#ifdef my_perl
|
||||
#ifdef USE_ITHREADS
|
||||
void uwsgi_perl_enable_threads() {
|
||||
|
||||
int i;
|
||||
|
||||
if (pthread_key_create(&uperl.u_interpreter, NULL)) {
|
||||
uwsgi_error("pthread_key_create()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uperl.interp = malloc( sizeof(PerlInterpreter*) * uwsgi.threads );
|
||||
if (!uperl.interp) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
}
|
||||
uperl.interp = uwsgi_malloc( sizeof(PerlInterpreter*) * uwsgi.threads );
|
||||
uperl.interp[0] = uperl.main;
|
||||
|
||||
for(i=1;i<uwsgi.threads;i++) {
|
||||
uperl.interp[i] = perl_clone(uperl.main, CLONEf_KEEP_PTR_TABLE);
|
||||
if (!uperl.interp[i]) {
|
||||
uwsgi_log("unable to create new perl interpreter\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
uperl.psgi_func = uwsgi_malloc( sizeof(SV*) * uwsgi.threads );
|
||||
|
||||
uperl.psgi_func = malloc( sizeof(SV*) * uwsgi.threads );
|
||||
if (!uperl.psgi_func) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
dTHXa(uperl.main);
|
||||
PERL_SET_CONTEXT(uperl.main);
|
||||
|
||||
uperl.psgi_main = perl_eval_pv(uperl.psgibuffer, 0);
|
||||
if (!uperl.psgi_main) {
|
||||
uwsgi_log("unable to find PSGI function entry point.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(SvTRUE(ERRSV)) {
|
||||
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -364,13 +350,12 @@ void uwsgi_perl_enable_threads() {
|
||||
|
||||
int uwsgi_perl_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
SV **harakiri;
|
||||
SV *psgi_func = uperl.psgi_main;
|
||||
// ugly hack
|
||||
register PerlInterpreter *my_perl = uperl.main;
|
||||
|
||||
#ifdef UWSGI_ASYNC
|
||||
if (wsgi_req->async_status == UWSGI_AGAIN) {
|
||||
return psgi_response(wsgi_req, my_perl, wsgi_req->async_placeholder);
|
||||
return psgi_response(wsgi_req, wsgi_req->async_placeholder);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -385,19 +370,14 @@ int uwsgi_perl_request(struct wsgi_request *wsgi_req) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef UWSGI_THREADING
|
||||
if (uwsgi.threads > 1 && wsgi_req->async_id > 0) {
|
||||
if (uwsgi.threads > 1) {
|
||||
psgi_func = uperl.psgi_func[wsgi_req->async_id];
|
||||
my_perl = pthread_getspecific(uperl.u_interpreter);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
ENTER;
|
||||
SAVETMPS;
|
||||
|
||||
|
||||
wsgi_req->async_environ = build_psgi_env(wsgi_req);
|
||||
if (!wsgi_req->async_environ) goto clear;
|
||||
|
||||
@@ -415,7 +395,7 @@ int uwsgi_perl_request(struct wsgi_request *wsgi_req) {
|
||||
goto clear2;
|
||||
}
|
||||
|
||||
while (psgi_response(wsgi_req, my_perl, wsgi_req->async_result) != UWSGI_OK) {
|
||||
while (psgi_response(wsgi_req, wsgi_req->async_result) != UWSGI_OK) {
|
||||
#ifdef UWSGI_ASYNC
|
||||
if (uwsgi.async > 1) {
|
||||
FREETMPS;
|
||||
@@ -426,6 +406,12 @@ int uwsgi_perl_request(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
|
||||
clear2:
|
||||
// check for psgix.harakiri
|
||||
harakiri = hv_fetch((HV*)SvRV( (SV*)wsgi_req->async_environ), "psgix.harakiri.commit", 21, 0);
|
||||
if (harakiri) {
|
||||
if (SvTRUE(*harakiri)) wsgi_req->async_plagued = 1;
|
||||
}
|
||||
|
||||
SvREFCNT_dec(wsgi_req->async_environ);
|
||||
SvREFCNT_dec(wsgi_req->async_result);
|
||||
clear:
|
||||
@@ -441,28 +427,49 @@ void uwsgi_perl_after_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_LOGGING])
|
||||
log_request(wsgi_req);
|
||||
|
||||
if (wsgi_req->async_plagued) {
|
||||
uwsgi_log("*** psgix.harakiri.commit requested ***\n");
|
||||
goodbye_cruel_world();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef USE_ITHREADS
|
||||
void uwsgi_perl_init_thread(int core_id) {
|
||||
|
||||
|
||||
pthread_setspecific(uperl.u_interpreter, uperl.interp[core_id]);
|
||||
|
||||
if (core_id > 0) {
|
||||
uperl.interp[core_id] = perl_clone(uperl.main, CLONEf_KEEP_PTR_TABLE);
|
||||
if (!uperl.interp[core_id]) {
|
||||
uwsgi_log("unable to create new perl interpreter\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
dTHXa(uperl.interp[core_id]);
|
||||
PERL_SET_CONTEXT(uperl.interp[core_id]);
|
||||
|
||||
uperl.psgi_func[core_id] = perl_eval_pv(uperl.psgibuffer, 0);
|
||||
if (!uperl.psgi_func[core_id]) {
|
||||
uwsgi_log("unable to find PSGI function entry point.\n");
|
||||
exit(1);
|
||||
}
|
||||
pthread_setspecific(uperl.u_interpreter, uperl.interp[core_id]);
|
||||
|
||||
if(SvTRUE(ERRSV)) {
|
||||
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
|
||||
exit(1);
|
||||
}
|
||||
uperl.psgi_func[0] = uperl.psgi_main;
|
||||
if (core_id > 0) {
|
||||
uperl.psgi_func[core_id] = perl_eval_pv(uwsgi_concat4("#line 1 ", uperl.psgi, "\n", uperl.psgibuffer), 0);
|
||||
|
||||
if (!uperl.psgi_func[core_id]) {
|
||||
uwsgi_log("unable to find PSGI function entry point.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(SvTRUE(ERRSV)) {
|
||||
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
int uwsgi_perl_manage_options(int i, char *optarg) {
|
||||
|
||||
@@ -503,11 +510,11 @@ struct uwsgi_plugin psgi_plugin = {
|
||||
.init_apps = uwsgi_psgi_app,
|
||||
//.magic = uwsgi_perl_magic,
|
||||
//.help = uwsgi_perl_help,
|
||||
#ifdef my_perl
|
||||
#ifdef USE_ITHREADS
|
||||
.enable_threads = uwsgi_perl_enable_threads,
|
||||
.init_thread = uwsgi_perl_init_thread,
|
||||
#endif
|
||||
.manage_opt = uwsgi_perl_manage_options,
|
||||
.init_thread = uwsgi_perl_init_thread,
|
||||
.request = uwsgi_perl_request,
|
||||
.after_request = uwsgi_perl_after_request,
|
||||
|
||||
|
||||
@@ -2,54 +2,9 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/* statistically ordered */
|
||||
struct http_status_codes hsc[] = {
|
||||
{"200", "OK"},
|
||||
{"302", "Found"},
|
||||
{"404", "Not Found"},
|
||||
{"500", "Internal Server Error"},
|
||||
{"301", "Moved Permanently"},
|
||||
{"304", "Not Modified"},
|
||||
{"303", "See Other"},
|
||||
{"403", "Forbidden"},
|
||||
{"307", "Temporary Redirect"},
|
||||
{"401", "Unauthorized"},
|
||||
{"400", "Bad Request"},
|
||||
{"405", "Method Not Allowed"},
|
||||
{"408", "Request Timeout"},
|
||||
extern struct http_status_codes hsc[];
|
||||
|
||||
{"100", "Continue"},
|
||||
{"101", "Switching Protocols"},
|
||||
{"201", "Created"},
|
||||
{"202", "Accepted"},
|
||||
{"203", "Non-Authoritative Information"},
|
||||
{"204", "No Content"},
|
||||
{"205", "Reset Content"},
|
||||
{"206", "Partial Content"},
|
||||
{"300", "Multiple Choices"},
|
||||
{"305", "Use Proxy"},
|
||||
{"402", "Payment Required"},
|
||||
{"406", "Not Acceptable"},
|
||||
{"407", "Proxy Authentication Required"},
|
||||
{"409", "Conflict"},
|
||||
{"410", "Gone"},
|
||||
{"411", "Length Required"},
|
||||
{"412", "Precondition Failed"},
|
||||
{"413", "Request Entity Too Large"},
|
||||
{"414", "Request-URI Too Long"},
|
||||
{"415", "Unsupported Media Type"},
|
||||
{"416", "Requested Range Not Satisfiable"},
|
||||
{"417", "Expectation Failed"},
|
||||
{"501", "Not Implemented"},
|
||||
{"502", "Bad Gateway"},
|
||||
{"503", "Service Unavailable"},
|
||||
{"504", "Gateway Timeout"},
|
||||
{"505", "HTTP Version Not Supported"},
|
||||
{ "", NULL },
|
||||
};
|
||||
|
||||
|
||||
int psgi_response(struct wsgi_request *wsgi_req, PerlInterpreter *my_perl, AV *response) {
|
||||
int psgi_response(struct wsgi_request *wsgi_req, AV *response) {
|
||||
|
||||
SV **status_code, **hitem ;
|
||||
AV *headers, *body =NULL;
|
||||
@@ -57,6 +12,7 @@ int psgi_response(struct wsgi_request *wsgi_req, PerlInterpreter *my_perl, AV *r
|
||||
struct http_status_codes *http_sc;
|
||||
int i,vi, base;
|
||||
char *chitem;
|
||||
SV **harakiri;
|
||||
|
||||
#ifdef UWSGI_ASYNC
|
||||
if (wsgi_req->async_status == UWSGI_AGAIN) {
|
||||
@@ -84,6 +40,12 @@ int psgi_response(struct wsgi_request *wsgi_req, PerlInterpreter *my_perl, AV *r
|
||||
SvREFCNT_dec(closed);
|
||||
}
|
||||
|
||||
// check for psgix.harakiri
|
||||
harakiri = hv_fetch((HV*)SvRV( (SV*)wsgi_req->async_environ), "psgix.harakiri.commit", 21, 0);
|
||||
if (harakiri) {
|
||||
if (SvTRUE(*harakiri)) wsgi_req->async_plagued = 1;
|
||||
}
|
||||
|
||||
SvREFCNT_dec(wsgi_req->async_environ);
|
||||
SvREFCNT_dec(wsgi_req->async_result);
|
||||
|
||||
@@ -185,6 +147,7 @@ int psgi_response(struct wsgi_request *wsgi_req, PerlInterpreter *my_perl, AV *r
|
||||
wsgi_req->sendfile_fd = SvIV(fn);
|
||||
SvREFCNT_dec(fn);
|
||||
wsgi_req->response_size += uwsgi_sendfile(wsgi_req);
|
||||
// no need to close here as perl GC will do the close()
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user