mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-10-04 16:08:31 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b64884961d | ||
|
|
619e853a19 | ||
|
|
050908a65e | ||
|
|
bcb1e623d9 | ||
|
|
57105c1bc7 | ||
|
|
8bb5b8a9f3 | ||
|
|
fba0d196ff | ||
|
|
e29c50c9a5 | ||
|
|
4ad9c8d034 | ||
|
|
059b4c6ba3 | ||
|
|
3ab96621db | ||
|
|
9bbe148112 | ||
|
|
e32de9b892 | ||
|
|
dea7f0fbb8 | ||
|
|
a684bc6124 | ||
|
|
849ba0856f | ||
|
|
f728e277e2 | ||
|
|
d11fed3511 | ||
|
|
f3b1acc55e | ||
|
|
61722a7876 | ||
|
|
e418a35159 | ||
|
|
cd29b033f0 | ||
|
|
f3f191558a | ||
|
|
c728471b94 | ||
|
|
4383578795 | ||
|
|
b2f127a798 | ||
|
|
f8212f9e4b | ||
|
|
5e70986bc9 | ||
|
|
d61dff3c26 | ||
|
|
2b2da8b7f4 | ||
|
|
827b142577 | ||
|
|
d753e1aeef | ||
|
|
8f7e5fc1bc | ||
|
|
650c251236 | ||
|
|
3acb67bd2a | ||
|
|
f9f0eb45e5 | ||
|
|
fe0c1a4bb3 | ||
|
|
eb90b773fa | ||
|
|
4f9369aa3a | ||
|
|
2ae323feee | ||
|
|
56a79ae09c | ||
|
|
48f6d5a240 | ||
|
|
49f717b616 | ||
|
|
77bae96c34 | ||
|
|
cbbaa24d6e | ||
|
|
37010c04ca | ||
|
|
5902749f9d | ||
|
|
b1db1ae651 | ||
|
|
d96e394947 | ||
|
|
89891c80ae | ||
|
|
edabc3cc6e | ||
|
|
9d4300d514 | ||
|
|
af1eac9fcc | ||
|
|
fd50b1e054 | ||
|
|
1239e740ab | ||
|
|
f6535488e5 | ||
|
|
c1c4dd01d2 | ||
|
|
5cc9c8405a | ||
|
|
990028697b | ||
|
|
666c7c5b3f | ||
|
|
1ccf9335dd | ||
|
|
f90bb6b53c | ||
|
|
0ad74e282c | ||
|
|
34d6c0ad16 | ||
|
|
4ceeb3b789 | ||
|
|
259c6c493f | ||
|
|
a3dd2e6efd | ||
|
|
af3860dbd7 | ||
|
|
980b4f3c9a | ||
|
|
efa0e0b27b | ||
|
|
d8d60e9a24 | ||
|
|
6f5a521692 | ||
|
|
522cbfe855 | ||
|
|
ed4425ee86 | ||
|
|
cb271e9a05 | ||
|
|
621cb99684 | ||
|
|
8600060d79 | ||
|
|
511a0aca0b | ||
|
|
0b0a0ccce1 | ||
|
|
e4e346772a | ||
|
|
f102ef64da | ||
|
|
192c73d53d | ||
|
|
07bd3f5df0 | ||
|
|
eae00a5c77 | ||
|
|
133dff6b76 | ||
|
|
cf634e11a9 | ||
|
|
18dfd10b71 | ||
|
|
54b4189ab9 | ||
|
|
7e58d78bfe | ||
|
|
6497c93e3e | ||
|
|
27d637a9b2 | ||
|
|
296f9304ba | ||
|
|
a04420e5ef | ||
|
|
2e4bc3dc6b | ||
|
|
773d853bb4 | ||
|
|
92e06b1078 | ||
|
|
1e6dd22fd8 | ||
|
|
e5eba6be46 | ||
|
|
456729f6e2 | ||
|
|
5f191b6e7f | ||
|
|
7435235502 | ||
|
|
764af285d3 | ||
|
|
3ed597368d | ||
|
|
2119e06e38 | ||
|
|
0770fd8815 | ||
|
|
6a94d1f91c | ||
|
|
f53c79cce7 | ||
|
|
a2e4c6e272 | ||
|
|
ce898614a0 | ||
|
|
0676c5e6a8 | ||
|
|
1469e68a33 | ||
|
|
f4ad33976d | ||
|
|
c8e12a6be3 | ||
|
|
48af1b28d4 | ||
|
|
b8c115a127 | ||
|
|
c009ab82f5 | ||
|
|
b0c421ff4b | ||
|
|
a39ac59757 | ||
|
|
d3792cba72 | ||
|
|
4aa17c40fc | ||
|
|
38b1f52723 | ||
|
|
30e50df5d4 | ||
|
|
22d9a2b831 | ||
|
|
6bccb62799 | ||
|
|
acd1215524 | ||
|
|
4381e816ae | ||
|
|
5760338445 | ||
|
|
e517bcea7c | ||
|
|
b6bdafa669 | ||
|
|
5bd10a99fb | ||
|
|
b8dfd1be85 | ||
|
|
3c810e5ca8 | ||
|
|
61a1ca4ca4 | ||
|
|
a71d9953a1 | ||
|
|
b20fbf5fe8 | ||
|
|
c73490fc80 | ||
|
|
da6b052bef | ||
|
|
08ea52164c | ||
|
|
4de3d534a8 | ||
|
|
7be55d71a8 | ||
|
|
6e24730025 | ||
|
|
513380d5c9 | ||
|
|
2f474b2af4 | ||
|
|
a062ef2ac2 | ||
|
|
b82566268a | ||
|
|
8d16ce28b9 | ||
|
|
2a9835649e | ||
|
|
9912ab6afb | ||
|
|
94f18e3508 | ||
|
|
25c812e4aa | ||
|
|
bddf8fe5c9 | ||
|
|
fbabb14c61 | ||
|
|
fd62e2ebb7 | ||
|
|
e96c43970d | ||
|
|
99eda6d084 | ||
|
|
91b2cc7570 | ||
|
|
0ff6277f28 | ||
|
|
dee99b6535 | ||
|
|
39260ebac0 | ||
|
|
ac3ec1781e | ||
|
|
e8925ac7b7 | ||
|
|
2877a5a05d | ||
|
|
9e3bfd261a | ||
|
|
636cd261e0 | ||
|
|
5fff6467a8 | ||
|
|
647c972ffe | ||
|
|
ed9ac16c78 | ||
|
|
4f1b610459 | ||
|
|
a68b9b9fa6 | ||
|
|
cd8e9f62b2 | ||
|
|
f3ee043246 | ||
|
|
949fdb5f86 | ||
|
|
d1c8a02151 | ||
|
|
7c0f002239 | ||
|
|
4d236b9b74 | ||
|
|
8d39eabf9d | ||
|
|
591cec9a2c | ||
|
|
057d0bc250 | ||
|
|
252731544b | ||
|
|
cdb901c091 | ||
|
|
00c5a77554 | ||
|
|
0e5f8acde5 | ||
|
|
d2ae982329 | ||
|
|
5307de6974 | ||
|
|
dc2f9f405d | ||
|
|
e610682b31 | ||
|
|
34b6bc5378 | ||
|
|
3d171f52b3 | ||
|
|
cfa4d2a3ad | ||
|
|
12bf2cd3af | ||
|
|
5089123e5a | ||
|
|
4d53d3a16a | ||
|
|
941dd70e3b | ||
|
|
609b5aeb0a | ||
|
|
8e6b810df8 | ||
|
|
f31186a0f9 | ||
|
|
b5a6da5448 | ||
|
|
0a9b5f05b0 | ||
|
|
7c8ae1737a | ||
|
|
0e502172c9 | ||
|
|
0dd2a34e22 | ||
|
|
f4b8f3e49d | ||
|
|
9610ec72ab | ||
|
|
32bf82552e | ||
|
|
d15f1a9e36 | ||
|
|
5e02bc3c84 | ||
|
|
d397036e29 | ||
|
|
c92fde03b9 | ||
|
|
e1598af32f | ||
|
|
fbfab14224 | ||
|
|
8ff56a694a | ||
|
|
639f26ff26 | ||
|
|
7d8a2968d5 | ||
|
|
f70c7c1e17 | ||
|
|
a89eb5d8cb | ||
|
|
4c9d30cc1b | ||
|
|
fd7d4fc944 | ||
|
|
7106301d86 | ||
|
|
f046d47eb2 | ||
|
|
0b8b6346be | ||
|
|
104c8a8b90 | ||
|
|
f25ab0fdd2 | ||
|
|
bb789d1ac0 | ||
|
|
e94315ca75 | ||
|
|
dd2e07122a | ||
|
|
375d446bf0 | ||
|
|
46eafeaa58 | ||
|
|
79dccaac9c | ||
|
|
cdf05dcef2 | ||
|
|
7d8aa98766 | ||
|
|
115470837e | ||
|
|
c226feaeca | ||
|
|
669c14ac71 | ||
|
|
1c5347ac90 | ||
|
|
83ce30a51e | ||
|
|
f75a637ef6 | ||
|
|
48d749f11b | ||
|
|
3f041350a2 | ||
|
|
39613d466a | ||
|
|
3c32980fe3 | ||
|
|
a1fbed315f | ||
|
|
c0083c5801 | ||
|
|
f86404f03f | ||
|
|
602f0385cb | ||
|
|
c32da58a7c | ||
|
|
d64a734292 | ||
|
|
65c047dca1 | ||
|
|
73b1887287 | ||
|
|
8d41a77baa | ||
|
|
0692bf45da | ||
|
|
9d5d439191 | ||
|
|
9f15345183 | ||
|
|
7d84413038 | ||
|
|
ecd4b9bc36 | ||
|
|
47d66ab368 | ||
|
|
54227db3e4 | ||
|
|
aecd9a7703 | ||
|
|
dd0551bf68 | ||
|
|
d649853a51 | ||
|
|
05ad7bf07e | ||
|
|
f29ac2117f | ||
|
|
91be1f8929 | ||
|
|
1e9c8c47bb | ||
|
|
63c8ce3bf8 | ||
|
|
d13b58869d | ||
|
|
49740e99fb | ||
|
|
09b136ed2c | ||
|
|
5be46f0cb3 | ||
|
|
e5094e7efa | ||
|
|
60580a0195 | ||
|
|
0a73039cfc | ||
|
|
94aed13978 | ||
|
|
9679645354 | ||
|
|
0c1a25b8a6 | ||
|
|
4a3c1e537b | ||
|
|
c355c93f12 | ||
|
|
5552e87087 | ||
|
|
67544158d9 | ||
|
|
f117f404fc | ||
|
|
d4130dbc4b | ||
|
|
e50a7c518f | ||
|
|
874b994e66 | ||
|
|
cc93687476 | ||
|
|
e354f3b37a | ||
|
|
d204e75c1c | ||
|
|
8c0e77b737 | ||
|
|
70f12c4407 | ||
|
|
ac78830a90 | ||
|
|
534f78acb3 | ||
|
|
443c2c5a29 | ||
|
|
feca5abc53 | ||
|
|
c643c3069c | ||
|
|
1cffe0dfe6 | ||
|
|
3761709ec4 | ||
|
|
956f54033c | ||
|
|
7afd4e39eb | ||
|
|
76866a05ba | ||
|
|
74eeee48ae | ||
|
|
3babcbe2bb | ||
|
|
1a50463ed9 | ||
|
|
a88244a700 | ||
|
|
7cf4cc788c | ||
|
|
990e7241e6 | ||
|
|
40d69f90d9 | ||
|
|
194f4897e3 | ||
|
|
d56e35651b | ||
|
|
58314c2800 | ||
|
|
0af894df06 | ||
|
|
9bfcec2999 | ||
|
|
65c513bec2 | ||
|
|
ec3a95dafb | ||
|
|
8386d7829d | ||
|
|
bb9c3e0d6c | ||
|
|
bc5b71a5ec | ||
|
|
2cdf1b7265 | ||
|
|
162c861e74 | ||
|
|
edb9c5f982 | ||
|
|
c88be57dd9 | ||
|
|
c1682f4ee4 | ||
|
|
799ac9310f | ||
|
|
2540e739c7 | ||
|
|
43ee6a305f | ||
|
|
0cb2e6852b | ||
|
|
a559e9ea63 | ||
|
|
89dfa7976a | ||
|
|
56a8d44cb0 | ||
|
|
7fc644d1a8 | ||
|
|
74d6bac54b | ||
|
|
5647aff995 | ||
|
|
cf67363164 | ||
|
|
1bdec68fb7 | ||
|
|
5698955384 | ||
|
|
732466e4e4 | ||
|
|
23165a1587 | ||
|
|
d9a8e071e2 | ||
|
|
e106a6ef61 | ||
|
|
297bd429a9 | ||
|
|
838bdd27a6 | ||
|
|
f50e179100 | ||
|
|
c6ddaf6b8d | ||
|
|
cbc06f92d0 | ||
|
|
386fac2421 | ||
|
|
3138d0b6c3 | ||
|
|
135a5a505c | ||
|
|
1b47a8932e | ||
|
|
01e4d07fb8 | ||
|
|
ec1bfdeb2a | ||
|
|
ac3d617037 | ||
|
|
253805daa6 | ||
|
|
63e4964808 | ||
|
|
57962d2e6e | ||
|
|
f81ea8e898 | ||
|
|
821af5d763 | ||
|
|
2e923aaf9e | ||
|
|
15b12983e1 | ||
|
|
15f0f8d294 | ||
|
|
c6658fca72 | ||
|
|
5bbc7ee673 | ||
|
|
37927c6f5d | ||
|
|
1a6ee9a775 | ||
|
|
d42649d80b | ||
|
|
2acd338429 | ||
|
|
7adcb19d1a | ||
|
|
a2f776b487 | ||
|
|
941ae2b5e3 | ||
|
|
e88d4bbb79 | ||
|
|
db352999b8 | ||
|
|
744fed60b9 | ||
|
|
df85a8e6a9 | ||
|
|
7ba7fd55d0 | ||
|
|
6fd2176b3e | ||
|
|
271ac33193 | ||
|
|
8d33491211 | ||
|
|
13a42599ea | ||
|
|
cb8878dc81 | ||
|
|
5e561c0d1e | ||
|
|
fbfe58948b | ||
|
|
e839a9eb89 | ||
|
|
b90779aecf | ||
|
|
2447f819cb | ||
|
|
6f956c6965 | ||
|
|
729fdd22c4 | ||
|
|
7b59668386 | ||
|
|
1e5739f8ea | ||
|
|
3ef7e9aee3 | ||
|
|
4854b3cbcf | ||
|
|
5273dbba90 | ||
|
|
b59f3b254f | ||
|
|
dda6bb2a5f | ||
|
|
0daff2cfe2 | ||
|
|
61ee03a99e | ||
|
|
06b6704be3 | ||
|
|
ab2a8c90cd | ||
|
|
21ada10805 | ||
|
|
3d8467506a | ||
|
|
8f996bb68d | ||
|
|
9f55579b87 | ||
|
|
215e514385 | ||
|
|
77bd73d597 | ||
|
|
3642198acd | ||
|
|
810a1463d5 | ||
|
|
d3dfdbb0ba | ||
|
|
f71f76c6e6 | ||
|
|
287a8c8a24 | ||
|
|
70d9dab5ef | ||
|
|
c9987aa721 | ||
|
|
874e8b5621 | ||
|
|
4b3b3f9200 | ||
|
|
994209ffb0 | ||
|
|
4cd5643c8f | ||
|
|
b7e2eaad0f | ||
|
|
71a5e8b768 | ||
|
|
6044af9e7a | ||
|
|
4e2178ffab | ||
|
|
37e153d5de | ||
|
|
e1316153be | ||
|
|
876f775698 | ||
|
|
2bd714c610 | ||
|
|
1b0c5bea6c | ||
|
|
1f8cadb15d | ||
|
|
83d24bee99 | ||
|
|
297111f2b6 | ||
|
|
0f354cbf2c | ||
|
|
1303efb2a4 | ||
|
|
234b09b17c | ||
|
|
fe4f621d79 | ||
|
|
3f83e91fb2 | ||
|
|
9aebb6c564 | ||
|
|
c7da6b2d45 | ||
|
|
bbf35be595 | ||
|
|
419875e6cf | ||
|
|
aa36a2ce5f | ||
|
|
4c669b17ef | ||
|
|
abb4c9b6da | ||
|
|
fe244e16d9 | ||
|
|
499202e84f | ||
|
|
e33b56890f | ||
|
|
63275e9ec7 | ||
|
|
c182f30e8d | ||
|
|
e365211cd0 | ||
|
|
4838baf01a | ||
|
|
7db8636da5 | ||
|
|
74d84be587 | ||
|
|
8dd74ced5d | ||
|
|
9cb97dd62d | ||
|
|
cd91830d65 | ||
|
|
1cefceba10 | ||
|
|
afc2e7dbe2 | ||
|
|
b1a9d2d497 | ||
|
|
ee129f02bc | ||
|
|
7ac4282047 | ||
|
|
50fe00d142 | ||
|
|
6dab462296 | ||
|
|
d614eabeac | ||
|
|
7da87bdf9d | ||
|
|
cf682773fb | ||
|
|
78a05ef9e8 | ||
|
|
17d9b5f58d | ||
|
|
385458b291 | ||
|
|
7a80ee49be | ||
|
|
e31d0a8693 | ||
|
|
9d43d6c9d4 | ||
|
|
b03008d1a6 | ||
|
|
94c29a396a | ||
|
|
bba8e503c1 | ||
|
|
9c2e9e42f9 | ||
|
|
82d5e0ead8 | ||
|
|
3d9a20953e | ||
|
|
1004ad0edc | ||
|
|
688a227886 | ||
|
|
7541195a5f | ||
|
|
db24fa7bd4 | ||
|
|
339c49f560 | ||
|
|
8dd943542e | ||
|
|
0f156fc25e | ||
|
|
8f7e65c467 | ||
|
|
08b2437146 | ||
|
|
912098c4c1 | ||
|
|
3d3b21afc9 | ||
|
|
3cd7a1163d | ||
|
|
e335c611a3 | ||
|
|
3409ce86e7 | ||
|
|
02a9d37c32 | ||
|
|
121124c3cd | ||
|
|
c6440ffa2d | ||
|
|
6bab2b2318 | ||
|
|
7ae7b3d715 | ||
|
|
2a2c650bec | ||
|
|
ed69d78a9b | ||
|
|
50c2fde29e | ||
|
|
96b35a3fff | ||
|
|
09a5ffeffb | ||
|
|
e4642e5e56 | ||
|
|
8236233489 | ||
|
|
5bfad8a1c5 | ||
|
|
c0dcbb7bac | ||
|
|
808216fbd2 | ||
|
|
f9a91fad63 | ||
|
|
7956bebb25 | ||
|
|
30633b2c9f | ||
|
|
c713c1013c | ||
|
|
becdd27467 | ||
|
|
2216aafcf1 | ||
|
|
7b3859b484 | ||
|
|
b1ab162bd2 | ||
|
|
a0dbcee7d5 | ||
|
|
5312a8a0f6 | ||
|
|
9e9b28a9cd | ||
|
|
572298e63d | ||
|
|
32a47c91b7 | ||
|
|
556905048e | ||
|
|
219d77fc17 | ||
|
|
e34371a974 | ||
|
|
c5099b6d38 | ||
|
|
d535c22723 | ||
|
|
fa68d2cae3 | ||
|
|
5a754e66fe | ||
|
|
83f9920705 | ||
|
|
f3dd60d683 | ||
|
|
e25e671104 | ||
|
|
c3b101baf4 | ||
|
|
b60c9b24b3 | ||
|
|
8aba421a87 | ||
|
|
15c0b5f5e9 | ||
|
|
f6271b1893 | ||
|
|
374317cffd | ||
|
|
6f7b158942 | ||
|
|
310eb53a37 | ||
|
|
badeafef59 | ||
|
|
35557de982 | ||
|
|
b0a7501212 | ||
|
|
f45db5456e | ||
|
|
2b58c79611 | ||
|
|
b7499f22f5 | ||
|
|
d55a5e1b8c | ||
|
|
e4ec5b000e | ||
|
|
dd983135c6 | ||
|
|
09fe2960b5 | ||
|
|
cf5794e22c | ||
|
|
2f2876fe6b | ||
|
|
1f1008c415 | ||
|
|
c02a936b61 | ||
|
|
d28cdaabb3 | ||
|
|
ec78213819 | ||
|
|
2a2303e37f | ||
|
|
90bc859222 | ||
|
|
a3be8d36fe | ||
|
|
de3e70c61f | ||
|
|
c3bba30af5 | ||
|
|
35566a8533 | ||
|
|
dda86dbc9c | ||
|
|
5f971812d1 | ||
|
|
17c8fff794 | ||
|
|
e4d5ca9209 | ||
|
|
8536bc349a | ||
|
|
e4b34921e1 | ||
|
|
f966ef8e69 | ||
|
|
df8efa31dd | ||
|
|
ee6aff6665 | ||
|
|
5f2abf9949 | ||
|
|
ee9b4a70d4 | ||
|
|
d5632f7715 | ||
|
|
efd10599a6 | ||
|
|
f0a846927e | ||
|
|
5e876e4adc | ||
|
|
d968e9f39e | ||
|
|
54fa0ab19f | ||
|
|
d63a570230 | ||
|
|
98e9822150 | ||
|
|
6a9809b301 | ||
|
|
47590a2b0d | ||
|
|
1447ae01bd | ||
|
|
d24ad0e61c | ||
|
|
0a0b27ad4c | ||
|
|
504151b695 | ||
|
|
813074b010 | ||
|
|
01cbcbad47 | ||
|
|
20b0dc0d1e | ||
|
|
6e6dd65cef | ||
|
|
e77f1d5069 | ||
|
|
41af8e54bb | ||
|
|
d598a10013 | ||
|
|
9af9cd09f9 | ||
|
|
b358c46413 | ||
|
|
45ffa98b5e | ||
|
|
f458877e53 | ||
|
|
544e598dcb | ||
|
|
360a94691d | ||
|
|
a297b9b981 | ||
|
|
7bb424622c | ||
|
|
0d382a846a | ||
|
|
e82430369e | ||
|
|
647e1e0826 | ||
|
|
b5802b4793 | ||
|
|
af5dbda00d | ||
|
|
4b889c90bf | ||
|
|
1313841dd3 | ||
|
|
b09c343627 | ||
|
|
ca97c0653f | ||
|
|
76edb7374e | ||
|
|
c8f53b9296 | ||
|
|
55a190312a | ||
|
|
7ebbac0dd8 | ||
|
|
1662f58a09 | ||
|
|
ac5ca4a002 | ||
|
|
ebadaa73a8 | ||
|
|
55fdc9d847 | ||
|
|
a409a82736 | ||
|
|
58e3b7166c | ||
|
|
cac413f725 | ||
|
|
73e3938d9a | ||
|
|
985114b7bd | ||
|
|
fb4a594add | ||
|
|
5d8f91c1ed | ||
|
|
759a9d4439 | ||
|
|
25b29df65e | ||
|
|
9f396466bd | ||
|
|
c79b36a59d | ||
|
|
de33a4a5a3 | ||
|
|
88e108cacc | ||
|
|
163d71c5b8 | ||
|
|
936d4b19a5 | ||
|
|
93cbd60f11 | ||
|
|
850cbea236 | ||
|
|
3ceda8993a | ||
|
|
ccad290b78 | ||
|
|
66d28aa958 | ||
|
|
3717b8cd13 | ||
|
|
6e5fc85e54 | ||
|
|
a3bbfde884 | ||
|
|
fd86c6cafa | ||
|
|
cb87f8f6d6 | ||
|
|
4ccd20eb23 | ||
|
|
9ced8f9bdd | ||
|
|
4eb174e9cb | ||
|
|
598250d469 | ||
|
|
6cc3faf14d | ||
|
|
8864f3c53c | ||
|
|
49dd3366fc | ||
|
|
5d253ab00f | ||
|
|
25db778f32 | ||
|
|
35fbd85fad | ||
|
|
c2d2f13bfb | ||
|
|
7add254781 | ||
|
|
970d899986 | ||
|
|
d719ed6a3b | ||
|
|
7fcc8ba6ac | ||
|
|
70e1bda986 | ||
|
|
32789e62a5 | ||
|
|
6297ed0455 | ||
|
|
1cbabf6296 | ||
|
|
e7f694cdc5 | ||
|
|
5f93d93cc1 | ||
|
|
15fa7a9c09 | ||
|
|
2e9e5af686 | ||
|
|
54c1055f15 | ||
|
|
114d71af8d | ||
|
|
757c3e7d95 | ||
|
|
0233f3e712 | ||
|
|
e23a7bfd80 | ||
|
|
6c67d205b8 | ||
|
|
aaaae5a602 | ||
|
|
5ddd773680 | ||
|
|
34bb5de3aa | ||
|
|
e23094e820 | ||
|
|
8d53e4aa54 | ||
|
|
ca1666789d | ||
|
|
211ed5c71c | ||
|
|
9f6a88d9d7 | ||
|
|
3d483f22ca | ||
|
|
a6bbb0cfa4 | ||
|
|
e6c9e53f14 |
+44
@@ -0,0 +1,44 @@
|
||||
language: c
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
|
||||
script:
|
||||
- echo -e "\n\n>>> Building uWSGI binary"
|
||||
- /usr/bin/python uwsgiconfig.py --build travis
|
||||
- echo -e "\n\n>>> Building python26 plugin"
|
||||
- /usr/bin/python2.6 -V
|
||||
- /usr/bin/python2.6 uwsgiconfig.py --plugin plugins/python base python26
|
||||
- echo -e "\n\n>>> Building python27 plugin"
|
||||
- /usr/bin/python2.7 -V
|
||||
- /usr/bin/python2.7 uwsgiconfig.py --plugin plugins/python base python27
|
||||
- echo -e "\n\n>>> Building python31 plugin"
|
||||
- /usr/bin/python3.1 -V
|
||||
- /usr/bin/python3.1 uwsgiconfig.py --plugin plugins/python base python31
|
||||
- echo -e "\n\n>>> Building python32 plugin"
|
||||
- /usr/bin/python3.2 -V
|
||||
- /usr/bin/python3.2 uwsgiconfig.py --plugin plugins/python base python32
|
||||
- echo -e "\n\n>>> Building python33 plugin"
|
||||
- /usr/bin/python3.3 -V
|
||||
- /usr/bin/python3.3 uwsgiconfig.py --plugin plugins/python base python33
|
||||
- echo -e "\n\n>>> Building rack 1.8.7 plugin"
|
||||
- /usr/bin/ruby1.8 -v
|
||||
- UWSGICONFIG_RUBYPATH=/usr/bin/ruby1.8 /usr/bin/python uwsgiconfig.py --plugin plugins/rack base rack187
|
||||
- echo -e "\n\n>>> Building rack 1.9.1 plugin"
|
||||
- /usr/bin/ruby1.9.1 -v
|
||||
- UWSGICONFIG_RUBYPATH=/usr/bin/ruby1.9.1 /usr/bin/python uwsgiconfig.py --plugin plugins/rack base rack191
|
||||
- echo -e "\n\n>>> Building cgi plugin"
|
||||
- /usr/bin/python uwsgiconfig.py --plugin plugins/cgi base
|
||||
- echo -e "\n\n>>> Building dummy plugin"
|
||||
- /usr/bin/python uwsgiconfig.py --plugin plugins/dummy base
|
||||
- echo -e "\n\n>>> Building done, starting tests"
|
||||
- ./tests/travis.sh
|
||||
|
||||
before_install:
|
||||
- sudo add-apt-repository -y ppa:fkrull/deadsnakes
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qqyf python2.6-dev python2.7-dev python3.1-dev python3.2-dev python3.3-dev rubygems1.8 ruby1.8-dev ruby1.9.1-dev
|
||||
- sudo apt-get install -qqyf libxml2-dev libpcre3-dev libcap2-dev
|
||||
- sudo apt-get install -qqyf curl
|
||||
|
||||
@@ -21,3 +21,4 @@ Roy Marples
|
||||
Aarni Koskela
|
||||
C Anthony Risinger
|
||||
Stephen Pierce
|
||||
Mingli Yuan
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
*** current ***
|
||||
|
||||
* 1.4.1
|
||||
* 1.5
|
||||
|
||||
- fixed typos in corerouter plugins
|
||||
- fixed offloading when the number of threads is higher than 1
|
||||
- fixed static_maps for non-existent paths
|
||||
- fixed uwsgi_connect() on modern Linux systems to reset the socket to blocking mode
|
||||
- added --not-alarm-log
|
||||
- support for TCP_FASTOPEN (Linux-only)
|
||||
- improved emperor reloading
|
||||
- added --get
|
||||
- Legion subsystem
|
||||
- emperor_zeromq plugin
|
||||
- SNI support
|
||||
- distributed SSL session cache
|
||||
|
||||
*** november 2012 ***
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
surprise i am empty !
|
||||
|
||||
Look in the online documentation on http://projects.unbit.it/uwsgi/
|
||||
Look in the online documentation on https://uwsgi-docs.readthedocs.org/en/latest/
|
||||
|
||||
+69
-45
@@ -1,3 +1,38 @@
|
||||
/*
|
||||
|
||||
*** mod_proxy_uwsgi ***
|
||||
|
||||
Copyright 2009-2013 Unbit S.a.s. <info@unbit.it>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
|
||||
To build:
|
||||
|
||||
apxs2 -i -c mod_proxy_uwsgi.c
|
||||
|
||||
To use:
|
||||
|
||||
LoadModule proxy_uwsgi_module /usr/lib/apache2/modules/mod_proxy_uwsgi.so
|
||||
ProxyPass / uwsgi://127.0.0.1:3031/
|
||||
|
||||
Docs:
|
||||
|
||||
http://uwsgi-docs.readthedocs.org/en/latest/Apache.html#mod-proxy-uwsgi
|
||||
|
||||
*/
|
||||
#define APR_WANT_MEMFUNC
|
||||
#define APR_WANT_STRFUNC
|
||||
#include "apr_strings.h"
|
||||
@@ -101,10 +136,26 @@ static int uwsgi_send_headers(request_rec *r, proxy_conn_rec *conn)
|
||||
ap_add_common_vars(r);
|
||||
ap_add_cgi_vars(r);
|
||||
|
||||
// this is not a security problem (in Linux) as uWSGI destroy the env memory area readable in /proc
|
||||
// and generally if you host untrusted apps in your server and allows them to read others uid /proc/<pid>
|
||||
// files you have higher problems...
|
||||
const char *auth = apr_table_get(r->headers_in, "Authorization");
|
||||
if (auth) {
|
||||
apr_table_setn(r->subprocess_env, "HTTP_AUTHORIZATION", auth);
|
||||
}
|
||||
|
||||
const char *script_name = apr_table_get(r->subprocess_env, "SCRIPT_NAME");
|
||||
const char *path_info = apr_table_get(r->subprocess_env, "PATH_INFO");
|
||||
|
||||
if (script_name && path_info) {
|
||||
apr_table_set(r->subprocess_env, "SCRIPT_NAME", apr_pstrndup(r->pool, script_name, strlen(script_name)-strlen(path_info)));
|
||||
if (strcmp(path_info, "/")) {
|
||||
apr_table_set(r->subprocess_env, "SCRIPT_NAME", apr_pstrndup(r->pool, script_name, strlen(script_name)-strlen(path_info)));
|
||||
}
|
||||
else {
|
||||
if (!strcmp(script_name, "/")) {
|
||||
apr_table_set(r->subprocess_env, "SCRIPT_NAME", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
env_table = apr_table_elts(r->subprocess_env);
|
||||
@@ -135,7 +186,7 @@ static int uwsgi_send_headers(request_rec *r, proxy_conn_rec *conn)
|
||||
buf[0] = 0;
|
||||
buf[1] = (uint8_t) (pktsize & 0xff);
|
||||
buf[2] = (uint8_t) ((pktsize >> 8) & 0xff);
|
||||
buf[0] = 0;
|
||||
buf[3] = 0;
|
||||
|
||||
return uwsgi_send(conn, buf, headerlen, r);
|
||||
}
|
||||
@@ -166,28 +217,6 @@ static int uwsgi_send_body(request_rec *r, proxy_conn_rec *conn)
|
||||
return OK;
|
||||
}
|
||||
|
||||
static
|
||||
apr_status_t ap_proxygetline(apr_bucket_brigade *bb, char *s, int n, request_rec *r,
|
||||
int fold, int *writen)
|
||||
{
|
||||
char *tmp_s = s;
|
||||
apr_status_t rv;
|
||||
apr_size_t len;
|
||||
|
||||
rv = ap_rgetline(&tmp_s, n, &len, r, fold, bb);
|
||||
apr_brigade_cleanup(bb);
|
||||
|
||||
if (rv == APR_SUCCESS) {
|
||||
*writen = (int) len;
|
||||
} else if (rv == APR_ENOSPC) {
|
||||
*writen = n;
|
||||
} else {
|
||||
*writen = -1;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_conf *conf)
|
||||
{
|
||||
|
||||
@@ -207,11 +236,7 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_
|
||||
|
||||
apr_bucket_brigade *bb = apr_brigade_create(r->pool, c->bucket_alloc);
|
||||
|
||||
|
||||
rc = ap_proxygetline(bb, buffer, sizeof(buffer), rp, 0, &len);
|
||||
if (len == 0) {
|
||||
rc = ap_proxygetline(bb, buffer, sizeof(buffer), rp, 0, &len);
|
||||
}
|
||||
len = ap_getline(buffer, sizeof(buffer), rp, 1);
|
||||
|
||||
if (len <= 0) {
|
||||
// oops
|
||||
@@ -220,25 +245,11 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_
|
||||
|
||||
backend->worker->s->read += len;
|
||||
|
||||
if (!apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
|
||||
if (!apr_date_checkmask(buffer, "HTTP/#.# ###*") || len >= sizeof(buffer)-1) {
|
||||
// oops
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
int major, minor;
|
||||
|
||||
major = buffer[5] - '0';
|
||||
minor = buffer[7] - '0';
|
||||
|
||||
/* If not an HTTP/1 message or
|
||||
* if the status line was > 8192 bytes
|
||||
*/
|
||||
if ((major != 1) || (len >= sizeof(buffer)-1)) {
|
||||
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
||||
apr_pstrcat(r->pool, "Corrupt status line returned by remote "
|
||||
"server: ", buffer, NULL));
|
||||
}
|
||||
|
||||
char keepchar = buffer[12];
|
||||
buffer[12] = '\0';
|
||||
r->status = atoi(&buffer[9]);
|
||||
@@ -326,7 +337,20 @@ static int uwsgi_handler(request_rec *r, proxy_worker *worker,
|
||||
}
|
||||
|
||||
// ADD PATH_INFO
|
||||
apr_table_add(r->subprocess_env, "PATH_INFO", url+strlen(worker->name));
|
||||
size_t w_len = strlen(worker->name);
|
||||
char *u_path_info = r->filename + 6 + w_len;
|
||||
int delta = 0;
|
||||
if (u_path_info[0] != '/') {
|
||||
delta = 1;
|
||||
}
|
||||
int decode_status = ap_unescape_url(url+w_len-delta);
|
||||
if (decode_status) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
"unable to decode uri: %s",
|
||||
url+w_len-delta);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
apr_table_add(r->subprocess_env, "PATH_INFO", url+w_len-delta);
|
||||
|
||||
|
||||
/* Create space for state information */
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
*** uWSGI/mod_uwsgi ***
|
||||
|
||||
Copyright 2009-2012 Unbit S.a.s. <info@unbit.it>
|
||||
Copyright 2009-2013 Unbit S.a.s. <info@unbit.it>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env ruby
|
||||
cmd = File.expand_path "#{File.dirname(__FILE__)}/../ext/uwsgi/uwsgi.ruby"
|
||||
|
||||
exec(cmd, *ARGV)
|
||||
+1
-7
@@ -6,13 +6,7 @@ json = auto
|
||||
sqlite3 = auto
|
||||
zeromq = auto
|
||||
snmp = true
|
||||
spooler = true
|
||||
embedded = true
|
||||
ssl = auto
|
||||
udp = true
|
||||
multicast = true
|
||||
threading = true
|
||||
minterpreters = true
|
||||
async = true
|
||||
ldap = auto
|
||||
pcre = auto
|
||||
@@ -29,7 +23,7 @@ plugins =
|
||||
bin_name = uwsgi
|
||||
append_version =
|
||||
plugin_dir = .
|
||||
embedded_plugins = %(main_plugin)s, ping, cache, nagios, rrdtool, carbon, rpc, corerouter, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool, redislog, mongodblog, router_rewrite, router_http, logfile, router_cache, rawrouter
|
||||
embedded_plugins = %(main_plugin)s, ping, cache, nagios, rrdtool, carbon, rpc, corerouter, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool, redislog, mongodblog, router_rewrite, router_http, logfile, router_cache, rawrouter, router_static, sslrouter
|
||||
as_shared_library = false
|
||||
|
||||
locking = auto
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = jvm,jwsgi
|
||||
inherit = base
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = mono
|
||||
inherit = base
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = jvm,ring
|
||||
inherit = base
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin =
|
||||
inherit = base
|
||||
@@ -5,14 +5,6 @@ yaml = true
|
||||
json = false
|
||||
sqlite3 = false
|
||||
zeromq = false
|
||||
snmp = false
|
||||
spooler = true
|
||||
embedded = true
|
||||
udp = true
|
||||
multicast = false
|
||||
threading = true
|
||||
minterpreters = true
|
||||
async = true
|
||||
ldap = true
|
||||
pcre = true
|
||||
routing = true
|
||||
|
||||
+4
-1
@@ -1,12 +1,15 @@
|
||||
use POSIX;
|
||||
use IO::Socket::INET;
|
||||
use IO::Socket::INET6;
|
||||
use IO::Socket::UNIX;
|
||||
|
||||
my $s = IO::Socket::INET->new(LocalAddr => '127.0.0.1', LocalPort => 1717, Proto => 'tcp', Reuse => 1);
|
||||
my $s2 = IO::Socket::INET->new(LocalAddr => '127.0.0.1', LocalPort => 3022, Proto => 'tcp', Reuse => 1);
|
||||
my $s3 = IO::Socket::INET6->new(LocalAddr => '::', LocalPort => 3017, Proto => 'tcp', Reuse => 1);
|
||||
my $s4 = IO::Socket::UNIX->new(Local => '/tmp/u.sock', Listen => 1);
|
||||
|
||||
dup2($s->fileno, 17);
|
||||
dup2($s2->fileno, 22);
|
||||
dup2($s3->fileno, 30);
|
||||
exec './uwsgi','-M', '--socket','fd://17', '--http-socket','fd://22', '--socket','fd://30';
|
||||
dup2($s4->fileno, 0);
|
||||
exec './uwsgi','-M', '--socket','fd://17', '--http-socket','fd://22', '--socket','fd://30','--stats',':5001';
|
||||
|
||||
+77
-4
@@ -136,7 +136,8 @@ static struct uwsgi_alarm_instance *uwsgi_alarm_get_instance(char *name) {
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_alarm_log_add(char *alarms, char *regexp) {
|
||||
#ifdef UWSGI_PCRE
|
||||
static int uwsgi_alarm_log_add(char *alarms, char *regexp, int negate) {
|
||||
|
||||
struct uwsgi_alarm_log *old_ual = NULL, *ual = uwsgi.alarm_logs;
|
||||
while (ual) {
|
||||
@@ -148,6 +149,7 @@ static int uwsgi_alarm_log_add(char *alarms, char *regexp) {
|
||||
if (uwsgi_regexp_build(regexp, &ual->pattern, &ual->pattern_extra)) {
|
||||
return -1;
|
||||
}
|
||||
ual->negate = negate;
|
||||
|
||||
if (old_ual) {
|
||||
old_ual->next = ual;
|
||||
@@ -161,8 +163,10 @@ static int uwsgi_alarm_log_add(char *alarms, char *regexp) {
|
||||
char *p = strtok(list, ",");
|
||||
while (p) {
|
||||
struct uwsgi_alarm_instance *uai = uwsgi_alarm_get_instance(p);
|
||||
if (!uai)
|
||||
if (!uai) {
|
||||
free(list);
|
||||
return -1;
|
||||
}
|
||||
struct uwsgi_alarm_ll *old_uall = NULL, *uall = ual->alarms;
|
||||
while (uall) {
|
||||
old_uall = uall;
|
||||
@@ -179,12 +183,38 @@ static int uwsgi_alarm_log_add(char *alarms, char *regexp) {
|
||||
}
|
||||
p = strtok(NULL, ",");
|
||||
}
|
||||
free(list);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void uwsgi_alarm_thread_loop(struct uwsgi_thread *ut) {
|
||||
char *buf = uwsgi_malloc(uwsgi.alarm_msg_size + sizeof(long));
|
||||
for (;;) {
|
||||
int interesting_fd = -1;
|
||||
int ret = event_queue_wait(ut->queue, -1, &interesting_fd);
|
||||
if (ret > 0) {
|
||||
ssize_t len = read(ut->pipe[1], buf, uwsgi.alarm_msg_size + sizeof(long));
|
||||
if (len > (ssize_t)(sizeof(long) + 1)) {
|
||||
size_t msg_size = len - sizeof(long);
|
||||
char *msg = buf + sizeof(long);
|
||||
long ptr = 0;
|
||||
memcpy(&ptr, buf, sizeof(long));
|
||||
struct uwsgi_alarm_instance *uai = (struct uwsgi_alarm_instance *) ptr;
|
||||
if (!uai)
|
||||
break;
|
||||
uwsgi_alarm_run(uai, msg, msg_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
|
||||
// initialize alarms, instances and log regexps
|
||||
void uwsgi_alarms_init() {
|
||||
|
||||
if (!uwsgi.master_process) return;
|
||||
|
||||
// first of all, create instance of alarms
|
||||
struct uwsgi_string_list *usl = uwsgi.alarm_list;
|
||||
while (usl) {
|
||||
@@ -211,6 +241,9 @@ void uwsgi_alarms_init() {
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
if (!uwsgi.alarm_instances) return;
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
// then map log-alarm
|
||||
usl = uwsgi.alarm_logs_list;
|
||||
while (usl) {
|
||||
@@ -223,15 +256,27 @@ void uwsgi_alarms_init() {
|
||||
*space = 0;
|
||||
char *regexp = space + 1;
|
||||
// here the log-alarm is created
|
||||
if (uwsgi_alarm_log_add(line, regexp)) {
|
||||
if (uwsgi_alarm_log_add(line, regexp, usl->custom)) {
|
||||
uwsgi_log("invalid log-alarm: %s\n", usl->value);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
usl = usl->next;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void uwsgi_alarm_thread_start() {
|
||||
if (!uwsgi.alarm_instances) return;
|
||||
// start the alarm_thread
|
||||
uwsgi.alarm_thread = uwsgi_thread_new(uwsgi_alarm_thread_loop);
|
||||
if (!uwsgi.alarm_thread) {
|
||||
uwsgi_log("unable to spawn alarm thread\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
// check if a log should raise an alarm
|
||||
void uwsgi_alarm_log_check(char *msg, size_t len) {
|
||||
if (!uwsgi_strncmp(msg, len, "[uwsgi-alarm", 12))
|
||||
@@ -239,11 +284,17 @@ void uwsgi_alarm_log_check(char *msg, size_t len) {
|
||||
struct uwsgi_alarm_log *ual = uwsgi.alarm_logs;
|
||||
while (ual) {
|
||||
if (uwsgi_regexp_match(ual->pattern, ual->pattern_extra, msg, len) >= 0) {
|
||||
uwsgi_alarm_log_run(ual, msg, len);
|
||||
if (!ual->negate) {
|
||||
uwsgi_alarm_log_run(ual, msg, len);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ual = ual->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// call the alarm func
|
||||
void uwsgi_alarm_run(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
|
||||
@@ -259,6 +310,7 @@ void uwsgi_alarm_run(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
|
||||
uai->last_msg_size = len;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
// call the alarms mapped to a log line
|
||||
void uwsgi_alarm_log_run(struct uwsgi_alarm_log *ual, char *msg, size_t len) {
|
||||
struct uwsgi_alarm_ll *uall = ual->alarms;
|
||||
@@ -267,3 +319,24 @@ void uwsgi_alarm_log_run(struct uwsgi_alarm_log *ual, char *msg, size_t len) {
|
||||
uall = uall->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// this is the api function workers,mules and whatever you want can call from code
|
||||
void uwsgi_alarm_trigger(char *alarm_instance_name, char *msg, size_t len) {
|
||||
if (!uwsgi.alarm_thread) return;
|
||||
if (len > uwsgi.alarm_msg_size) return;
|
||||
struct uwsgi_alarm_instance *uai = uwsgi_alarm_get_instance(alarm_instance_name);
|
||||
if (!uai) return;
|
||||
|
||||
struct iovec iov[2];
|
||||
iov[0].iov_base = &uai;
|
||||
iov[0].iov_len = sizeof(long);
|
||||
iov[1].iov_base = msg;
|
||||
iov[1].iov_len = len;
|
||||
|
||||
// now send the message to the alarm thread
|
||||
if (writev(uwsgi.alarm_thread->pipe[0], iov, 2) != (ssize_t) (len+sizeof(long))) {
|
||||
uwsgi_error("[uwsgi-alarm-error] uwsgi_alarm_trigger()/writev()");
|
||||
}
|
||||
}
|
||||
|
||||
+72
-43
@@ -1,7 +1,14 @@
|
||||
#include "uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_async_queue_is_full(time_t now) {
|
||||
if (now > uwsgi.async_queue_is_full) {
|
||||
uwsgi_log_verbose("[DANGER] async queue is full !!!\n");
|
||||
uwsgi.async_queue_is_full = now;
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_async_init() {
|
||||
int i;
|
||||
|
||||
@@ -33,7 +40,7 @@ struct wsgi_request *find_wsgi_req_by_fd(int fd) {
|
||||
return uwsgi.async_waiting_fd_table[fd];
|
||||
}
|
||||
|
||||
void runqueue_remove(struct uwsgi_async_request *u_request) {
|
||||
static void runqueue_remove(struct uwsgi_async_request *u_request) {
|
||||
|
||||
struct uwsgi_async_request *parent = u_request->prev;
|
||||
struct uwsgi_async_request *child = u_request->next;
|
||||
@@ -58,7 +65,7 @@ void runqueue_remove(struct uwsgi_async_request *u_request) {
|
||||
uwsgi.async_runqueue_cnt--;
|
||||
}
|
||||
|
||||
void runqueue_push(struct wsgi_request *wsgi_req) {
|
||||
static void runqueue_push(struct wsgi_request *wsgi_req) {
|
||||
|
||||
struct uwsgi_async_request *uar;
|
||||
|
||||
@@ -96,26 +103,25 @@ struct wsgi_request *find_first_available_wsgi_req() {
|
||||
return wsgi_req;
|
||||
}
|
||||
|
||||
void async_expire_timeouts() {
|
||||
static void async_expire_timeouts(uint64_t now) {
|
||||
|
||||
struct wsgi_request *wsgi_req;
|
||||
time_t current_time = uwsgi_now();
|
||||
struct uwsgi_async_fd *uaf = NULL, *current_uaf;
|
||||
|
||||
struct uwsgi_rb_timer *urbt;
|
||||
|
||||
for (;;) {
|
||||
|
||||
urbt = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts);
|
||||
urbt = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts, NULL);
|
||||
|
||||
if (urbt == NULL)
|
||||
return;
|
||||
|
||||
if (urbt->key <= current_time) {
|
||||
if (urbt->value <= now) {
|
||||
wsgi_req = (struct wsgi_request *) urbt->data;
|
||||
// timeout expired
|
||||
wsgi_req->async_timed_out = 1;
|
||||
rb_erase(&wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts);
|
||||
uwsgi_del_rb_timer(uwsgi.rb_async_timeouts, wsgi_req->async_timeout);
|
||||
free(wsgi_req->async_timeout);
|
||||
wsgi_req->async_timeout = NULL;
|
||||
uaf = wsgi_req->waiting_fds;
|
||||
@@ -138,12 +144,12 @@ void async_expire_timeouts() {
|
||||
|
||||
}
|
||||
|
||||
void async_add_fd_read(struct wsgi_request *wsgi_req, int fd, int timeout) {
|
||||
int async_add_fd_read(struct wsgi_request *wsgi_req, int fd, int timeout) {
|
||||
|
||||
struct uwsgi_async_fd *last_uad = NULL, *uad = wsgi_req->waiting_fds;
|
||||
|
||||
if (fd < 0)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
// find first slot
|
||||
while (uad) {
|
||||
@@ -168,8 +174,23 @@ void async_add_fd_read(struct wsgi_request *wsgi_req, int fd, int timeout) {
|
||||
async_add_timeout(wsgi_req, timeout);
|
||||
}
|
||||
uwsgi.async_waiting_fd_table[fd] = wsgi_req;
|
||||
event_queue_add_fd_read(uwsgi.async_queue, fd);
|
||||
wsgi_req->async_force_again = 1;
|
||||
return event_queue_add_fd_read(uwsgi.async_queue, fd);
|
||||
}
|
||||
|
||||
static int async_wait_fd_read(int fd, int timeout) {
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
if (async_add_fd_read(wsgi_req, fd, timeout)) {
|
||||
return -1;
|
||||
}
|
||||
if (uwsgi.schedule_to_main) {
|
||||
uwsgi.schedule_to_main(wsgi_req);
|
||||
}
|
||||
if (wsgi_req->async_timed_out) {
|
||||
wsgi_req->async_timed_out = 0;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void async_add_timeout(struct wsgi_request *wsgi_req, int timeout) {
|
||||
@@ -180,12 +201,12 @@ void async_add_timeout(struct wsgi_request *wsgi_req, int timeout) {
|
||||
|
||||
}
|
||||
|
||||
void async_add_fd_write(struct wsgi_request *wsgi_req, int fd, int timeout) {
|
||||
int async_add_fd_write(struct wsgi_request *wsgi_req, int fd, int timeout) {
|
||||
|
||||
struct uwsgi_async_fd *last_uad = NULL, *uad = wsgi_req->waiting_fds;
|
||||
|
||||
if (fd < 0)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
// find first slot
|
||||
while (uad) {
|
||||
@@ -211,12 +232,27 @@ void async_add_fd_write(struct wsgi_request *wsgi_req, int fd, int timeout) {
|
||||
}
|
||||
|
||||
uwsgi.async_waiting_fd_table[fd] = wsgi_req;
|
||||
event_queue_add_fd_write(uwsgi.async_queue, fd);
|
||||
wsgi_req->async_force_again = 1;
|
||||
return event_queue_add_fd_write(uwsgi.async_queue, fd);
|
||||
}
|
||||
|
||||
static int async_wait_fd_write(int fd, int timeout) {
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
if (async_add_fd_write(wsgi_req, fd, timeout)) {
|
||||
return -1;
|
||||
}
|
||||
if (uwsgi.schedule_to_main) {
|
||||
uwsgi.schedule_to_main(wsgi_req);
|
||||
}
|
||||
if (wsgi_req->async_timed_out) {
|
||||
wsgi_req->async_timed_out = 0;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void async_schedule_to_req(void) {
|
||||
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh.modifier1]->request(uwsgi.wsgi_req);
|
||||
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req);
|
||||
}
|
||||
|
||||
void async_loop() {
|
||||
@@ -233,7 +269,7 @@ void async_loop() {
|
||||
int is_a_new_connection;
|
||||
int proto_parser_status;
|
||||
|
||||
time_t now, last_now = 0;
|
||||
uint64_t now;
|
||||
|
||||
static struct uwsgi_async_request *current_request = NULL, *next_async_request = NULL;
|
||||
|
||||
@@ -243,6 +279,9 @@ void async_loop() {
|
||||
uwsgi.async_runqueue = NULL;
|
||||
uwsgi.async_runqueue_cnt = 0;
|
||||
|
||||
uwsgi.wait_write_hook = async_wait_fd_write;
|
||||
uwsgi.wait_read_hook = async_wait_fd_read;
|
||||
|
||||
if (uwsgi.signal_socket > -1) {
|
||||
event_queue_add_fd_read(uwsgi.async_queue, uwsgi.signal_socket);
|
||||
event_queue_add_fd_read(uwsgi.async_queue, uwsgi.my_signal_socket);
|
||||
@@ -252,20 +291,22 @@ void async_loop() {
|
||||
if (!uwsgi.schedule_to_req)
|
||||
uwsgi.schedule_to_req = async_schedule_to_req;
|
||||
|
||||
if (!uwsgi.schedule_to_main) {
|
||||
uwsgi_log("*** WARNING *** async mode without coroutine/greenthread engine loaded !!!\n");
|
||||
}
|
||||
|
||||
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
|
||||
|
||||
now = (uint64_t) uwsgi_now();
|
||||
if (uwsgi.async_runqueue_cnt) {
|
||||
timeout = 0;
|
||||
}
|
||||
else {
|
||||
min_timeout = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts);
|
||||
if (uwsgi.async_runqueue_cnt) {
|
||||
timeout = 0;
|
||||
}
|
||||
min_timeout = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts, NULL);
|
||||
if (min_timeout) {
|
||||
timeout = min_timeout->key - uwsgi_now();
|
||||
timeout = min_timeout->value - now;
|
||||
if (timeout <= 0) {
|
||||
async_expire_timeouts();
|
||||
async_expire_timeouts(now);
|
||||
timeout = 0;
|
||||
}
|
||||
}
|
||||
@@ -276,9 +317,10 @@ void async_loop() {
|
||||
|
||||
uwsgi.async_nevents = event_queue_wait_multi(uwsgi.async_queue, timeout, events, 64);
|
||||
|
||||
now = (uint64_t) uwsgi_now();
|
||||
// timeout ???
|
||||
if (uwsgi.async_nevents == 0) {
|
||||
async_expire_timeouts();
|
||||
async_expire_timeouts(now);
|
||||
}
|
||||
|
||||
|
||||
@@ -305,11 +347,7 @@ void async_loop() {
|
||||
|
||||
uwsgi.wsgi_req = find_first_available_wsgi_req();
|
||||
if (uwsgi.wsgi_req == NULL) {
|
||||
now = uwsgi_now();
|
||||
if (now > last_now) {
|
||||
uwsgi_log("async queue is full !!!\n");
|
||||
last_now = now;
|
||||
}
|
||||
uwsgi_async_queue_is_full((time_t)now);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -319,18 +357,6 @@ void async_loop() {
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
|
||||
break;
|
||||
}
|
||||
// on linux we do not need to reset the socket to blocking state
|
||||
#ifndef __linux__
|
||||
/* re-set blocking socket */
|
||||
int arg = uwsgi_sock->arg;
|
||||
arg &= (~O_NONBLOCK);
|
||||
if (fcntl(uwsgi.wsgi_req->poll.fd, F_SETFL, arg) < 0) {
|
||||
uwsgi_error("fcntl()");
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wsgi_req_async_recv(uwsgi.wsgi_req)) {
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
@@ -354,13 +380,14 @@ void async_loop() {
|
||||
if (uwsgi.wsgi_req) {
|
||||
proto_parser_status = uwsgi.wsgi_req->socket->proto(uwsgi.wsgi_req);
|
||||
// reset timeout
|
||||
rb_erase(&uwsgi.wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts);
|
||||
uwsgi_del_rb_timer(uwsgi.rb_async_timeouts, uwsgi.wsgi_req->async_timeout);
|
||||
free(uwsgi.wsgi_req->async_timeout);
|
||||
uwsgi.wsgi_req->async_timeout = NULL;
|
||||
// parsing complete
|
||||
if (!proto_parser_status) {
|
||||
// remove fd from event poll and fd proto table
|
||||
uwsgi.async_proto_fd_table[interesting_fd] = NULL;
|
||||
event_queue_del_fd(uwsgi.async_queue, interesting_fd, event_queue_read());
|
||||
// put request in the runqueue
|
||||
runqueue_push(uwsgi.wsgi_req);
|
||||
continue;
|
||||
@@ -395,7 +422,7 @@ void async_loop() {
|
||||
}
|
||||
uwsgi.wsgi_req->waiting_fds = NULL;
|
||||
if (uwsgi.wsgi_req->async_timeout) {
|
||||
rb_erase(&uwsgi.wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts);
|
||||
uwsgi_del_rb_timer(uwsgi.rb_async_timeouts, uwsgi.wsgi_req->async_timeout);
|
||||
free(uwsgi.wsgi_req->async_timeout);
|
||||
uwsgi.wsgi_req->async_timeout = NULL;
|
||||
}
|
||||
@@ -405,6 +432,8 @@ void async_loop() {
|
||||
|
||||
// put the request in the runqueue again
|
||||
runqueue_push(uwsgi.wsgi_req);
|
||||
// avoid managing other enqueued events...
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,7 +461,7 @@ void async_loop() {
|
||||
}
|
||||
uwsgi.wsgi_req->waiting_fds = NULL;
|
||||
if (uwsgi.wsgi_req->async_timeout) {
|
||||
rb_erase(&uwsgi.wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts);
|
||||
uwsgi_del_rb_timer(uwsgi.rb_async_timeouts, uwsgi.wsgi_req->async_timeout);
|
||||
free(uwsgi.wsgi_req->async_timeout);
|
||||
uwsgi.wsgi_req->async_timeout = NULL;
|
||||
}
|
||||
|
||||
+214
@@ -48,6 +48,50 @@ int uwsgi_buffer_ensure(struct uwsgi_buffer *ub, size_t len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_insert(struct uwsgi_buffer *ub, size_t pos, char *buf, size_t len) {
|
||||
size_t to_move = (ub->pos-pos);
|
||||
if (uwsgi_buffer_ensure(ub, len)) return -1;
|
||||
memmove(ub->buf+pos+len, ub->buf+pos, to_move);
|
||||
memcpy(ub->buf+pos, buf, len);
|
||||
ub->pos += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_insert_chunked(struct uwsgi_buffer *ub, size_t pos, size_t len) {
|
||||
// 0xFFFFFFFFFFFFFFFF\r\n\0
|
||||
char chunked[19];
|
||||
int ret = snprintf(chunked, 19, "%X\r\n", (unsigned int) len);
|
||||
if (ret <= 0 || ret > 19) {
|
||||
return -1;
|
||||
}
|
||||
return uwsgi_buffer_insert(ub, pos, chunked, ret);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append_chunked(struct uwsgi_buffer *ub, size_t len) {
|
||||
// 0xFFFFFFFFFFFFFFFF\r\n\0
|
||||
char chunked[19];
|
||||
int ret = snprintf(chunked, 19, "%X\r\n", (unsigned int) len);
|
||||
if (ret <= 0 || ret > 19) {
|
||||
return -1;
|
||||
}
|
||||
return uwsgi_buffer_append(ub, chunked, ret);
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_buffer_decapitate(struct uwsgi_buffer *ub, size_t len) {
|
||||
if (len > ub->pos) return -1;
|
||||
memmove(ub->buf, ub->buf + len, ub->pos-len);
|
||||
ub->pos = ub->pos-len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_byte(struct uwsgi_buffer *ub, char byte) {
|
||||
return uwsgi_buffer_append(ub, &byte, 1);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u8(struct uwsgi_buffer *ub, uint8_t u8) {
|
||||
return uwsgi_buffer_append(ub, (char *) &u8, 1);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append(struct uwsgi_buffer *ub, char *buf, size_t len) {
|
||||
|
||||
@@ -77,12 +121,173 @@ int uwsgi_buffer_append(struct uwsgi_buffer *ub, char *buf, size_t len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append_json(struct uwsgi_buffer *ub, char *buf, size_t len) {
|
||||
// need to escape \ and "
|
||||
size_t i;
|
||||
for(i=0;i<len;i++) {
|
||||
if (buf[i] == '"') {
|
||||
if (uwsgi_buffer_append(ub, "\\\"", 2)) return -1;
|
||||
}
|
||||
else if (buf[i] == '\\') {
|
||||
if (uwsgi_buffer_append(ub, "\\\\", 2)) return -1;
|
||||
}
|
||||
else {
|
||||
if (uwsgi_buffer_append(ub, buf+i, 1)) return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u16le(struct uwsgi_buffer *ub, uint16_t num) {
|
||||
uint8_t buf[2];
|
||||
buf[0] = (uint8_t) (num & 0xff);
|
||||
buf[1] = (uint8_t) ((num >> 8) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 2);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u16be(struct uwsgi_buffer *ub, uint16_t num) {
|
||||
uint8_t buf[2];
|
||||
buf[1] = (uint8_t) (num & 0xff);
|
||||
buf[0] = (uint8_t) ((num >> 8) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 2);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u24be(struct uwsgi_buffer *ub, uint32_t num) {
|
||||
uint8_t buf[3];
|
||||
buf[2] = (uint8_t) (num & 0xff);
|
||||
buf[1] = (uint8_t) ((num >> 8) & 0xff);
|
||||
buf[0] = (uint8_t) ((num >> 16) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 3);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u32be(struct uwsgi_buffer *ub, uint32_t num) {
|
||||
uint8_t buf[4];
|
||||
buf[3] = (uint8_t) (num & 0xff);
|
||||
buf[2] = (uint8_t) ((num >> 8) & 0xff);
|
||||
buf[1] = (uint8_t) ((num >> 16) & 0xff);
|
||||
buf[0] = (uint8_t) ((num >> 24) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 4);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u32le(struct uwsgi_buffer *ub, uint32_t num) {
|
||||
uint8_t buf[4];
|
||||
buf[0] = (uint8_t) (num & 0xff);
|
||||
buf[1] = (uint8_t) ((num >> 8) & 0xff);
|
||||
buf[2] = (uint8_t) ((num >> 16) & 0xff);
|
||||
buf[3] = (uint8_t) ((num >> 24) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 4);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u64be(struct uwsgi_buffer *ub, uint64_t num) {
|
||||
uint8_t buf[8];
|
||||
buf[7] = (uint8_t) (num & 0xff);
|
||||
buf[6] = (uint8_t) ((num >> 8) & 0xff);
|
||||
buf[5] = (uint8_t) ((num >> 16) & 0xff);
|
||||
buf[4] = (uint8_t) ((num >> 24) & 0xff);
|
||||
buf[3] = (uint8_t) ((num >> 32) & 0xff);
|
||||
buf[2] = (uint8_t) ((num >> 40) & 0xff);
|
||||
buf[1] = (uint8_t) ((num >> 48) & 0xff);
|
||||
buf[0] = (uint8_t) ((num >> 56) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 8);
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_buffer_append_ipv4(struct uwsgi_buffer *ub, void *addr) {
|
||||
char ip[INET_ADDRSTRLEN];
|
||||
if (!inet_ntop(AF_INET, addr, ip, INET_ADDRSTRLEN)) {
|
||||
uwsgi_error("uwsgi_buffer_append_ipv4() -> inet_ntop()");
|
||||
return -1;
|
||||
}
|
||||
return uwsgi_buffer_append(ub, ip, strlen(ip));
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_buffer_num64(struct uwsgi_buffer *ub, int64_t num) {
|
||||
char buf[sizeof(UMAX64_STR)+1];
|
||||
int ret = snprintf(buf, sizeof(UMAX64_STR)+1, "%lld", (long long) num);
|
||||
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
|
||||
return -1;
|
||||
}
|
||||
return uwsgi_buffer_append(ub, buf, ret);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append_keyval(struct uwsgi_buffer *ub, char *key, uint16_t keylen, char *val, uint16_t vallen) {
|
||||
if (uwsgi_buffer_u16le(ub, keylen)) return -1;
|
||||
if (uwsgi_buffer_append(ub, key, keylen)) return -1;
|
||||
if (uwsgi_buffer_u16le(ub, vallen)) return -1;
|
||||
return uwsgi_buffer_append(ub, val, vallen);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append_keyval32(struct uwsgi_buffer *ub, char *key, uint32_t keylen, char *val, uint32_t vallen) {
|
||||
if (uwsgi_buffer_u32be(ub, keylen)) return -1;
|
||||
if (uwsgi_buffer_append(ub, key, keylen)) return -1;
|
||||
if (uwsgi_buffer_u32be(ub, vallen)) return -1;
|
||||
return uwsgi_buffer_append(ub, val, vallen);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append_keynum(struct uwsgi_buffer *ub, char *key, uint16_t keylen, int64_t num) {
|
||||
char buf[sizeof(UMAX64_STR)+1];
|
||||
int ret = snprintf(buf, (sizeof(UMAX64_STR)+1), "%lld", (long long) num);
|
||||
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
|
||||
return -1;
|
||||
}
|
||||
if (uwsgi_buffer_u16le(ub, keylen)) return -1;
|
||||
if (uwsgi_buffer_append(ub, key, keylen)) return -1;
|
||||
if (uwsgi_buffer_u16le(ub, ret)) return -1;
|
||||
return uwsgi_buffer_append(ub, buf, ret);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append_valnum(struct uwsgi_buffer *ub, int64_t num) {
|
||||
char buf[sizeof(UMAX64_STR)+1];
|
||||
int ret = snprintf(buf, (sizeof(UMAX64_STR)+1), "%lld", (long long) num);
|
||||
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
|
||||
return -1;
|
||||
}
|
||||
if (uwsgi_buffer_u16le(ub, ret)) return -1;
|
||||
return uwsgi_buffer_append(ub, buf, ret);
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_buffer_append_keyipv4(struct uwsgi_buffer *ub, char *key, uint16_t keylen, void *addr) {
|
||||
if (uwsgi_buffer_u16le(ub, keylen)) return -1;
|
||||
if (uwsgi_buffer_append(ub, key, keylen)) return -1;
|
||||
if (uwsgi_buffer_u16le(ub, 15)) return -1;
|
||||
char *ptr = ub->buf + (ub->pos - 2);
|
||||
if (uwsgi_buffer_append_ipv4(ub, addr)) return -1;
|
||||
// fix the size
|
||||
*ptr = ((ub->buf+ub->pos) - (ptr+2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append_base64(struct uwsgi_buffer *ub, char *s, size_t len) {
|
||||
size_t b64_len = 0;
|
||||
char *b64 = uwsgi_base64_encode(s, len, &b64_len);
|
||||
if (!b64) return -1;
|
||||
int ret = uwsgi_buffer_append(ub, b64, b64_len);
|
||||
free(b64);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_buffer_destroy(struct uwsgi_buffer *ub) {
|
||||
if (ub->buf)
|
||||
free(ub->buf);
|
||||
free(ub);
|
||||
}
|
||||
|
||||
ssize_t uwsgi_buffer_write_simple(struct wsgi_request *wsgi_req, struct uwsgi_buffer *ub) {
|
||||
size_t remains = ub->pos;
|
||||
while(remains) {
|
||||
ssize_t len = write(wsgi_req->fd, ub->buf + (ub->pos - remains), remains);
|
||||
if (len <= 0) {
|
||||
return len;
|
||||
}
|
||||
remains -= len;
|
||||
}
|
||||
|
||||
return ub->pos;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_send(struct uwsgi_buffer *ub, int fd) {
|
||||
size_t remains = ub->pos;
|
||||
char *ptr = ub->buf;
|
||||
@@ -114,3 +319,12 @@ int uwsgi_buffer_send(struct uwsgi_buffer *ub, int fd) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_set_uh(struct uwsgi_buffer *ub, uint8_t modifier1, uint8_t modifier2) {
|
||||
if (ub->pos < 4) return -1;
|
||||
ub->buf[0] = modifier1;
|
||||
ub->buf[1] = (uint8_t) ((ub->pos - 4) & 0xff);
|
||||
ub->buf[2] = (uint8_t) (((ub->pos - 4) >> 8) & 0xff);
|
||||
ub->buf[3] = modifier2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
+1464
-239
File diff suppressed because it is too large
Load Diff
-464
@@ -1,464 +0,0 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
|
||||
#ifdef UWSGI_UDP
|
||||
|
||||
static void cluster_manage_opt(char *key, uint16_t keylen, char *value, uint16_t vallen, void *foobar) {
|
||||
|
||||
add_exported_option(uwsgi_concat2n(key, keylen, "", 0), uwsgi_concat2n(value, vallen, "", 0), 0);
|
||||
|
||||
}
|
||||
|
||||
void cluster_setup() {
|
||||
|
||||
int rlen;
|
||||
// get cluster configuration
|
||||
if (uwsgi.cluster != NULL) {
|
||||
// get multicast socket
|
||||
|
||||
uwsgi.cluster_fd = uwsgi_cluster_join(uwsgi.cluster);
|
||||
|
||||
uwsgi_log("JOINED CLUSTER: %s\n", uwsgi.cluster);
|
||||
|
||||
// ask for cluster options only if bot pre-existent options are set
|
||||
if (uwsgi.exported_opts_cnt == 1 && !uwsgi.cluster_nodes) {
|
||||
// now wait max 60 seconds and resend multicast request every 10 seconds
|
||||
for (;;) {
|
||||
uwsgi_log("asking \"%s\" uWSGI cluster for configuration data:\n", uwsgi.cluster);
|
||||
if (uwsgi_send_empty_pkt(uwsgi.cluster_fd, uwsgi.cluster, 99, 0) < 0) {
|
||||
uwsgi_log("unable to send multicast message to %s\n", uwsgi.cluster);
|
||||
continue;
|
||||
}
|
||||
waitfd:
|
||||
rlen = uwsgi_waitfd(uwsgi.cluster_fd, 10);
|
||||
if (rlen < 0) {
|
||||
break;
|
||||
}
|
||||
else if (rlen > 0) {
|
||||
// receive the packet
|
||||
char clusterbuf[4096];
|
||||
if (!uwsgi_hooked_parse_dict_dgram(uwsgi.cluster_fd, clusterbuf, 4096, 99, 1, cluster_manage_opt, NULL)) {
|
||||
uwsgi_configure();
|
||||
goto options_parsed;
|
||||
}
|
||||
else {
|
||||
goto waitfd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
options_parsed:
|
||||
|
||||
if (!uwsgi.cluster_nodes)
|
||||
uwsgi_cluster_add_me();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void uwsgi_cluster_add_node(struct uwsgi_cluster_node *nucn, int type) {
|
||||
|
||||
int i;
|
||||
struct uwsgi_cluster_node *ucn;
|
||||
char *tcp_port;
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("adding node\n");
|
||||
#endif
|
||||
|
||||
tcp_port = strchr(nucn->name, ':');
|
||||
#ifndef UWSGI_ZEROMQ
|
||||
if (tcp_port == NULL) {
|
||||
#else
|
||||
char *zmq_dash = strchr(nucn->name, '-');
|
||||
if (tcp_port == NULL && zmq_dash == NULL) {
|
||||
#endif
|
||||
|
||||
fprintf(stdout, "invalid cluster node name %s\n", nucn->name);
|
||||
return;
|
||||
}
|
||||
|
||||
// first check for already present node
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
ucn = &uwsgi.shared->nodes[i];
|
||||
if (ucn->name[0] != 0) {
|
||||
if (!strcmp(ucn->name, nucn->name)) {
|
||||
ucn->status = UWSGI_NODE_OK;
|
||||
ucn->last_seen = uwsgi_now();
|
||||
// update requests
|
||||
ucn->requests = nucn->requests;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
ucn = &uwsgi.shared->nodes[i];
|
||||
|
||||
if (ucn->name[0] == 0) {
|
||||
memcpy(ucn->name, nucn->name, strlen(nucn->name) + 1);
|
||||
memcpy(ucn->nodename, nucn->nodename, strlen(nucn->nodename) + 1);
|
||||
ucn->workers = nucn->workers;
|
||||
ucn->ucn_addr.sin_family = AF_INET;
|
||||
if (tcp_port) {
|
||||
ucn->ucn_addr.sin_port = htons(atoi(tcp_port + 1));
|
||||
tcp_port[0] = 0;
|
||||
}
|
||||
if (nucn->name[0] == 0) {
|
||||
ucn->ucn_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
}
|
||||
else {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%s\n", nucn->name);
|
||||
#endif
|
||||
ucn->ucn_addr.sin_addr.s_addr = inet_addr(nucn->name);
|
||||
}
|
||||
|
||||
ucn->type = type;
|
||||
// here memory can be freed, as it is allocated by uwsgi_concat2n
|
||||
if (type != CLUSTER_NODE_DYNAMIC && tcp_port) {
|
||||
tcp_port[0] = ':';
|
||||
}
|
||||
ucn->last_seen = uwsgi_now();
|
||||
ucn->requests = nucn->requests;
|
||||
uwsgi_log("[uWSGI cluster] added node %s\n", ucn->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("unable to add node %s\n", nucn->name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int uwsgi_cluster_add_me() {
|
||||
|
||||
const char *key1 = "hostname";
|
||||
const char *key2 = "address";
|
||||
const char *key3 = "workers";
|
||||
const char *key4 = "requests";
|
||||
|
||||
char *ptrbuf;
|
||||
uint16_t ustrlen;
|
||||
char numproc[6];
|
||||
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
char uuid_zmq_str[37];
|
||||
uuid_t uuid_zmq;
|
||||
if (!uwsgi.sockets && !uwsgi.zeromq) {
|
||||
#else
|
||||
if (!uwsgi.sockets) {
|
||||
#endif
|
||||
uwsgi_log("you need to specify at least a socket to start a uWSGI cluster\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
snprintf(numproc, 6, "%d", uwsgi.numproc);
|
||||
|
||||
size_t len;
|
||||
|
||||
if (uwsgi.sockets) {
|
||||
len = 2 + strlen(key1) + 2 + strlen(uwsgi.hostname) + 2 + strlen(key2) + 2 + strlen(uwsgi.sockets->name) + 2 + strlen(key3) + 2 + strlen(numproc) + 2 + strlen(key4) + 2 + 1;
|
||||
}
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
else if (uwsgi.zeromq) {
|
||||
uuid_generate(uuid_zmq);
|
||||
uuid_unparse(uuid_zmq, uuid_zmq_str);
|
||||
len = 2 + strlen(key1) + 2 + strlen(uwsgi.hostname) + 2 + strlen(key2) + 2 + strlen(uuid_zmq_str) + 2 + strlen(key3) + 2 + strlen(numproc) + 2 + strlen(key4) + 2 + 1;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
len = 2 + strlen(key1) + 2 + strlen(uwsgi.hostname) + 2 + strlen(key3) + 2 + strlen(numproc) + 2 + strlen(key4) + 2 + 1;
|
||||
}
|
||||
char *buf = uwsgi_malloc(len);
|
||||
|
||||
ptrbuf = buf;
|
||||
|
||||
ustrlen = strlen(key1);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key1, strlen(key1));
|
||||
ptrbuf += strlen(key1);
|
||||
|
||||
ustrlen = strlen(uwsgi.hostname);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, uwsgi.hostname, strlen(uwsgi.hostname));
|
||||
ptrbuf += strlen(uwsgi.hostname);
|
||||
|
||||
|
||||
if (uwsgi.sockets && uwsgi.sockets->name) {
|
||||
ustrlen = strlen(key2);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key2, strlen(key2));
|
||||
ptrbuf += strlen(key2);
|
||||
|
||||
ustrlen = strlen(uwsgi.sockets->name);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, uwsgi.sockets->name, strlen(uwsgi.sockets->name));
|
||||
ptrbuf += strlen(uwsgi.sockets->name);
|
||||
}
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
else if (uwsgi.zeromq) {
|
||||
ustrlen = strlen(key2);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key2, strlen(key2));
|
||||
ptrbuf += strlen(key2);
|
||||
|
||||
ustrlen = strlen(uuid_zmq_str);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, uuid_zmq_str, strlen(uuid_zmq_str));
|
||||
ptrbuf += strlen(uuid_zmq_str);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
ustrlen = strlen(key3);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key3, strlen(key3));
|
||||
ptrbuf += strlen(key3);
|
||||
|
||||
ustrlen = strlen(numproc);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, numproc, strlen(numproc));
|
||||
ptrbuf += strlen(numproc);
|
||||
|
||||
ustrlen = strlen(key4);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key4, strlen(key4));
|
||||
ptrbuf += strlen(key4);
|
||||
|
||||
ustrlen = 1;
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, "0", 1);
|
||||
ptrbuf += 1;
|
||||
|
||||
|
||||
uwsgi_string_sendto(uwsgi.cluster_fd, 95, 0, (struct sockaddr *) &uwsgi.mc_cluster_addr, sizeof(uwsgi.mc_cluster_addr), buf, len);
|
||||
|
||||
free(buf);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("add_me() successfull\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_cluster_join(char *name) {
|
||||
|
||||
int fd;
|
||||
char *cp;
|
||||
int broadcast = 0;
|
||||
|
||||
|
||||
|
||||
if (name[0] == ':') {
|
||||
fd = bind_to_udp(name, 0, 1);
|
||||
broadcast = 1;
|
||||
}
|
||||
else {
|
||||
fd = bind_to_udp(name, 1, 0);
|
||||
}
|
||||
|
||||
if (fd >= 0) {
|
||||
cp = strchr(name, ':');
|
||||
cp[0] = 0;
|
||||
uwsgi.mc_cluster_addr.sin_family = AF_INET;
|
||||
if (broadcast) {
|
||||
uwsgi.mc_cluster_addr.sin_addr.s_addr = INADDR_BROADCAST;
|
||||
}
|
||||
else {
|
||||
uwsgi.mc_cluster_addr.sin_addr.s_addr = inet_addr(name);
|
||||
}
|
||||
uwsgi.mc_cluster_addr.sin_port = htons(atoi(cp + 1));
|
||||
cp[0] = ':';
|
||||
|
||||
|
||||
// announce my presence to all the nodes
|
||||
uwsgi_string_sendto(fd, 73, 0, (struct sockaddr *) &uwsgi.mc_cluster_addr, sizeof(uwsgi.mc_cluster_addr), uwsgi.hostname, strlen(uwsgi.hostname));
|
||||
}
|
||||
else {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
return fd;
|
||||
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_cluster_best_node() {
|
||||
|
||||
int i;
|
||||
int best_node = -1;
|
||||
struct uwsgi_cluster_node *ucn;
|
||||
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
ucn = &uwsgi.shared->nodes[i];
|
||||
if (ucn->name[0] != 0 && ucn->status == UWSGI_NODE_OK) {
|
||||
if (best_node == -1) {
|
||||
best_node = i;
|
||||
}
|
||||
else {
|
||||
if (ucn->last_choosen < uwsgi.shared->nodes[best_node].last_choosen) {
|
||||
best_node = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (best_node == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uwsgi.shared->nodes[best_node].last_choosen = uwsgi_now();
|
||||
return uwsgi.shared->nodes[best_node].name;
|
||||
}
|
||||
|
||||
|
||||
void manage_cluster_announce(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
|
||||
|
||||
char *tmpstr;
|
||||
struct uwsgi_cluster_node *ucn = (struct uwsgi_cluster_node *) data;
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%.*s = %.*s\n", keylen, key, vallen, val);
|
||||
#endif
|
||||
|
||||
if (!uwsgi_strncmp("hostname", 8, key, keylen)) {
|
||||
strncpy(ucn->nodename, val, UMIN(vallen, 255));
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("address", 7, key, keylen)) {
|
||||
strncpy(ucn->name, val, UMIN(vallen, 100));
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("workers", 7, key, keylen)) {
|
||||
tmpstr = uwsgi_concat2n(val, vallen, "", 0);
|
||||
ucn->workers = atoi(tmpstr);
|
||||
free(tmpstr);
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("requests", 8, key, keylen)) {
|
||||
tmpstr = uwsgi_concat2n(val, vallen, "", 0);
|
||||
ucn->requests = strtoul(tmpstr, NULL, 0);
|
||||
free(tmpstr);
|
||||
}
|
||||
}
|
||||
|
||||
void manage_cluster_message(char *cluster_opt_buf, int cluster_opt_size) {
|
||||
|
||||
struct uwsgi_cluster_node nucn;
|
||||
|
||||
switch (uwsgi.workers[0].cores[0].req.uh.modifier1) {
|
||||
case 95:
|
||||
memset(&nucn, 0, sizeof(struct uwsgi_cluster_node));
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
uwsgi.workers[0].cores[0].req.uh.pktsize = uwsgi_swap16(uwsgi.workers[0].cores[0].req.uh.pktsize);
|
||||
#endif
|
||||
uwsgi_hooked_parse(uwsgi.workers[0].cores[0].req.buffer, uwsgi.workers[0].cores[0].req.uh.pktsize, manage_cluster_announce, &nucn);
|
||||
if (nucn.name[0] != 0) {
|
||||
uwsgi_cluster_add_node(&nucn, CLUSTER_NODE_DYNAMIC);
|
||||
}
|
||||
break;
|
||||
case 96:
|
||||
#ifdef __BIG_ENDIAN__
|
||||
uwsgi.workers[0].cores[0].req.uh.pktsize = uwsgi_swap16(uwsgi.workers[0].cores[0].req.uh.pktsize);
|
||||
#endif
|
||||
uwsgi_log_verbose("%.*s\n", uwsgi.workers[0].cores[0].req.uh.pktsize, uwsgi.workers[0].cores[0].req.buffer);
|
||||
break;
|
||||
case 98:
|
||||
if (kill(getpid(), SIGHUP)) {
|
||||
uwsgi_error("kill()");
|
||||
}
|
||||
break;
|
||||
case 99:
|
||||
if (uwsgi.cluster_nodes)
|
||||
break;
|
||||
if (uwsgi.workers[0].cores[0].req.uh.modifier2 == 0) {
|
||||
uwsgi_log("requested configuration data, sending %d bytes\n", cluster_opt_size);
|
||||
sendto(uwsgi.cluster_fd, cluster_opt_buf, cluster_opt_size, 0, (struct sockaddr *) &uwsgi.mc_cluster_addr, sizeof(uwsgi.mc_cluster_addr));
|
||||
}
|
||||
break;
|
||||
case 73:
|
||||
#ifdef __BIG_ENDIAN__
|
||||
uwsgi.workers[0].cores[0].req.uh.pktsize = uwsgi_swap16(uwsgi.workers[0].cores[0].req.uh.pktsize);
|
||||
#endif
|
||||
uwsgi_log_verbose("[uWSGI cluster %s] new node available: %.*s\n", uwsgi.cluster, uwsgi.workers[0].cores[0].req.uh.pktsize, uwsgi.workers[0].cores[0].req.buffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
char *uwsgi_setup_clusterbuf(size_t * size) {
|
||||
|
||||
size_t cluster_opt_size = 4;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
|
||||
//uwsgi_log("%s\n", uwsgi.exported_opts[i]->key);
|
||||
cluster_opt_size += 2 + strlen(uwsgi.exported_opts[i]->key);
|
||||
if (uwsgi.exported_opts[i]->value) {
|
||||
cluster_opt_size += 2 + strlen(uwsgi.exported_opts[i]->value);
|
||||
}
|
||||
else {
|
||||
cluster_opt_size += 2 + 1;
|
||||
}
|
||||
}
|
||||
|
||||
//uwsgi_log("cluster opts size: %d\n", cluster_opt_size);
|
||||
char *cluster_opt_buf = uwsgi_malloc(cluster_opt_size);
|
||||
|
||||
struct uwsgi_header *uh = (struct uwsgi_header *) cluster_opt_buf;
|
||||
|
||||
uh->modifier1 = 99;
|
||||
uh->pktsize = cluster_opt_size - 4;
|
||||
uh->modifier2 = 1;
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
uh->pktsize = uwsgi_swap16(uh->pktsize);
|
||||
#endif
|
||||
|
||||
char *cptrbuf = cluster_opt_buf + 4;
|
||||
|
||||
for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
|
||||
//uwsgi_log("%s\n", uwsgi.exported_opts[i]->key);
|
||||
uint16_t ustrlen = strlen(uwsgi.exported_opts[i]->key);
|
||||
*cptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*cptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(cptrbuf, uwsgi.exported_opts[i]->key, ustrlen);
|
||||
cptrbuf += ustrlen;
|
||||
|
||||
if (uwsgi.exported_opts[i]->value) {
|
||||
ustrlen = strlen(uwsgi.exported_opts[i]->value);
|
||||
*cptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*cptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(cptrbuf, uwsgi.exported_opts[i]->value, ustrlen);
|
||||
}
|
||||
else {
|
||||
ustrlen = 1;
|
||||
*cptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*cptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
*cptrbuf = '1';
|
||||
}
|
||||
cptrbuf += ustrlen;
|
||||
}
|
||||
|
||||
return cluster_opt_buf;
|
||||
}
|
||||
+14
-3
@@ -30,6 +30,16 @@ extern struct uwsgi_server uwsgi;
|
||||
*/
|
||||
|
||||
void uwsgi_daemons_smart_check() {
|
||||
static time_t last_run = 0;
|
||||
|
||||
time_t now = uwsgi_now();
|
||||
|
||||
if (now - last_run <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
last_run = now;
|
||||
|
||||
struct uwsgi_daemon *ud = uwsgi.daemons;
|
||||
while (ud) {
|
||||
if (ud->pidfile) {
|
||||
@@ -41,14 +51,14 @@ void uwsgi_daemons_smart_check() {
|
||||
}
|
||||
else {
|
||||
ud->pidfile_checks++;
|
||||
if (ud->pidfile_checks >= (uint64_t) ud->freq) {
|
||||
if (ud->pidfile_checks >= (unsigned int) ud->freq) {
|
||||
uwsgi_log("[uwsgi-daemons] found changed pidfile for \"%s\" (old_pid: %d new_pid: %d)\n", ud->command, (int) ud->pid, (int) checked_pid);
|
||||
uwsgi_spawn_daemon(ud);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (checked_pid != ud->pid) {
|
||||
uwsgi_log("[uwsgi-daemons] found changed pidfile for \"%s\" (old_pid: %d new_pid: %d)\n", ud->command, (int) ud->pid, (int) checked_pid);
|
||||
uwsgi_log("[uwsgi-daemons] found changed pid for \"%s\" (old_pid: %d new_pid: %d)\n", ud->command, (int) ud->pid, (int) checked_pid);
|
||||
ud->pid = checked_pid;
|
||||
}
|
||||
// all ok, pidfile and process found
|
||||
@@ -183,6 +193,7 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
|
||||
else {
|
||||
// close uwsgi sockets
|
||||
uwsgi_close_all_sockets();
|
||||
uwsgi_close_all_fds();
|
||||
|
||||
if (ud->daemonize) {
|
||||
/* refork... */
|
||||
@@ -204,7 +215,7 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
|
||||
exit(1);
|
||||
}
|
||||
if (devnull != 0) {
|
||||
if (dup2(devnull, 0)) {
|
||||
if (dup2(devnull, 0) < 0) {
|
||||
uwsgi_error("dup2()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
+116
-33
@@ -6,7 +6,6 @@ a supervisor for multiple uWSGI instances
|
||||
|
||||
*/
|
||||
#include "uwsgi.h"
|
||||
#include <glob.h>
|
||||
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
@@ -88,7 +87,7 @@ void uwsgi_emperor_blacklist_add(char *id) {
|
||||
}
|
||||
}
|
||||
|
||||
strcpy(uebi->id, id);
|
||||
strncpy(uebi->id, id, 0xff);
|
||||
gettimeofday(&uebi->first_attempt, NULL);
|
||||
memcpy(&uebi->last_attempt, &uebi->first_attempt, sizeof(struct timeval));
|
||||
uebi->throttle_level = uwsgi.emperor_throttle;
|
||||
@@ -186,8 +185,24 @@ void uwsgi_imperial_monitor_directory(struct uwsgi_emperor_scanner *ues) {
|
||||
|
||||
while (c_ui) {
|
||||
if (c_ui->scanner == ues) {
|
||||
if (stat(c_ui->name, &st)) {
|
||||
emperor_stop(c_ui);
|
||||
if (c_ui->zerg) {
|
||||
char *colon = strrchr(c_ui->name, ':');
|
||||
if (!colon) {
|
||||
emperor_stop(c_ui);
|
||||
}
|
||||
else {
|
||||
char *filename = uwsgi_calloc(0xff);
|
||||
memcpy(filename, c_ui->name, colon - c_ui->name);
|
||||
if (stat(filename, &st)) {
|
||||
emperor_stop(c_ui);
|
||||
}
|
||||
free(filename);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (stat(c_ui->name, &st)) {
|
||||
emperor_stop(c_ui);
|
||||
}
|
||||
}
|
||||
}
|
||||
c_ui = c_ui->ui_next;
|
||||
@@ -246,9 +261,25 @@ void uwsgi_imperial_monitor_glob(struct uwsgi_emperor_scanner *ues) {
|
||||
|
||||
while (c_ui) {
|
||||
if (c_ui->scanner == ues) {
|
||||
if (stat(c_ui->name, &st)) {
|
||||
emperor_stop(c_ui);
|
||||
}
|
||||
if (c_ui->zerg) {
|
||||
char *colon = strrchr(c_ui->name, ':');
|
||||
if (!colon) {
|
||||
emperor_stop(c_ui);
|
||||
}
|
||||
else {
|
||||
char *filename = uwsgi_calloc(0xff);
|
||||
memcpy(filename, c_ui->name, colon - c_ui->name);
|
||||
if (stat(filename, &st)) {
|
||||
emperor_stop(c_ui);
|
||||
}
|
||||
free(filename);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (stat(c_ui->name, &st)) {
|
||||
emperor_stop(c_ui);
|
||||
}
|
||||
}
|
||||
}
|
||||
c_ui = c_ui->ui_next;
|
||||
}
|
||||
@@ -325,7 +356,7 @@ static void emperor_stats() {
|
||||
|
||||
while (c_ui) {
|
||||
|
||||
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);
|
||||
uwsgi_log("vassal instance %s (last modified %lld) status %d loyal %d zerg %d\n", c_ui->name, (long long) c_ui->last_mod, c_ui->status, c_ui->loyal, c_ui->zerg);
|
||||
|
||||
c_ui = c_ui->ui_next;
|
||||
}
|
||||
@@ -417,18 +448,29 @@ void emperor_stop(struct uwsgi_instance *c_ui) {
|
||||
|
||||
void emperor_respawn(struct uwsgi_instance *c_ui, time_t mod) {
|
||||
|
||||
struct uwsgi_header uh;
|
||||
|
||||
// reload the uWSGI instance
|
||||
if (write(c_ui->pipe[0], "\1", 1) != 1) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
|
||||
// push the config to the config pipe (if needed)
|
||||
if (c_ui->use_config) {
|
||||
if (write(c_ui->pipe[0], "\0", 1) != 1) {
|
||||
uwsgi_error("write()");
|
||||
uh.modifier1 = 115;
|
||||
uh.pktsize = c_ui->config_len;
|
||||
uh.modifier2 = 0;
|
||||
if (write(c_ui->pipe_config[0], &uh, 4) != 4) {
|
||||
uwsgi_error("[uwsgi-emperor] write() header config");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (write(c_ui->pipe[0], "\1", 1) != 1) {
|
||||
uwsgi_error("write()");
|
||||
else {
|
||||
if (write(c_ui->pipe_config[0], c_ui->config, c_ui->config_len) != (long) c_ui->config_len) {
|
||||
uwsgi_error("[uwsgi-emperor] write() config");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
c_ui->respawns++;
|
||||
c_ui->last_mod = mod;
|
||||
c_ui->last_run = uwsgi_now();
|
||||
@@ -454,7 +496,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
|
||||
#endif
|
||||
|
||||
if (strlen(name) > (0xff - 1)) {
|
||||
uwsgi_log("[emperor] invalid vassal name\n", name);
|
||||
uwsgi_log("[emperor] invalid vassal name: %s\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -549,6 +591,10 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
|
||||
}
|
||||
}
|
||||
|
||||
if (n_ui->zerg) {
|
||||
uwsgi.emperor_broodlord_num++;
|
||||
}
|
||||
|
||||
// TODO pre-start hook
|
||||
|
||||
// a new uWSGI instance will start
|
||||
@@ -565,10 +611,19 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
|
||||
}
|
||||
|
||||
if (n_ui->use_config) {
|
||||
if (write(n_ui->pipe_config[0], n_ui->config, n_ui->config_len) <= 0) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
close(n_ui->pipe_config[0]);
|
||||
struct uwsgi_header uh;
|
||||
uh.modifier1 = 115;
|
||||
uh.pktsize = n_ui->config_len;
|
||||
uh.modifier2 = 0;
|
||||
if (write(n_ui->pipe_config[0], &uh, 4) != 4) {
|
||||
uwsgi_error("[uwsgi-emperor] write() header config");
|
||||
}
|
||||
else {
|
||||
if (write(n_ui->pipe_config[0], n_ui->config, n_ui->config_len) != (long) n_ui->config_len) {
|
||||
uwsgi_error("[uwsgi-emperor] write() config");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -602,6 +657,16 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
|
||||
}
|
||||
free(uef);
|
||||
|
||||
// add UWSGI_BROODLORD_NUM
|
||||
if (n_ui->zerg) {
|
||||
uef = uwsgi_num2str(uwsgi.emperor_broodlord_num);
|
||||
if (setenv("UWSGI_BROODLORD_NUM", uef, 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
exit(1);
|
||||
}
|
||||
free(uef);
|
||||
}
|
||||
|
||||
if (n_ui->use_config) {
|
||||
uef = uwsgi_num2str(n_ui->pipe_config[1]);
|
||||
if (setenv("UWSGI_EMPEROR_FD_CONFIG", uef, 1)) {
|
||||
@@ -618,6 +683,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
|
||||
char *oe = uwsgi_concat2n(*uenvs, strchr(*uenvs, '=') - *uenvs, "", 0);
|
||||
if (unsetenv(oe)) {
|
||||
uwsgi_error("unsetenv()");
|
||||
free(oe);
|
||||
break;
|
||||
}
|
||||
free(oe);
|
||||
@@ -709,7 +775,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
|
||||
exit(1);
|
||||
}
|
||||
if (stdin_fd != 0) {
|
||||
if (dup2(stdin_fd, 0)) {
|
||||
if (dup2(stdin_fd, 0) < 0) {
|
||||
uwsgi_error("dup2()");
|
||||
exit(1);
|
||||
}
|
||||
@@ -784,6 +850,8 @@ void uwsgi_imperial_monitor_directory_init(struct uwsgi_emperor_scanner *ues) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ues->arg = uwsgi.emperor_absolute_dir;
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_imperial_monitor *imperial_monitor_get_by_id(char *scheme) {
|
||||
@@ -988,9 +1056,9 @@ void emperor_loop() {
|
||||
}
|
||||
|
||||
// check if a monitor is mapped to that file descriptor
|
||||
if (uwsgi_emperor_scanner_event(interesting_fd))
|
||||
if (uwsgi_emperor_scanner_event(interesting_fd)) {
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
ui_current = emperor_get_by_fd(interesting_fd);
|
||||
if (ui_current) {
|
||||
@@ -998,9 +1066,7 @@ void emperor_loop() {
|
||||
ssize_t rlen = read(interesting_fd, &byte, 1);
|
||||
if (rlen <= 0) {
|
||||
// SAFE
|
||||
if (!ui_current->config_len) {
|
||||
emperor_del(ui_current);
|
||||
}
|
||||
emperor_del(ui_current);
|
||||
}
|
||||
else {
|
||||
if (byte == 17) {
|
||||
@@ -1021,7 +1087,7 @@ void emperor_loop() {
|
||||
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(NULL, zerg_name, uwsgi_now(), NULL, 0, ui_current->uid, ui_current->gid);
|
||||
emperor_add(ui_current->scanner, zerg_name, uwsgi_now(), NULL, 0, ui_current->uid, ui_current->gid);
|
||||
free(zerg_name);
|
||||
}
|
||||
}
|
||||
@@ -1322,13 +1388,21 @@ end:
|
||||
void uwsgi_emperor_start() {
|
||||
|
||||
if (!uwsgi.sockets && !ushared->gateways_cnt && !uwsgi.master_process) {
|
||||
if (uwsgi.emperor_procname) {
|
||||
uwsgi_set_processname(uwsgi.emperor_procname);
|
||||
}
|
||||
uwsgi_notify_ready();
|
||||
emperor_loop();
|
||||
// never here
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi.emperor_pid = uwsgi_fork("uWSGI Emperor");
|
||||
if (uwsgi.emperor_procname) {
|
||||
uwsgi.emperor_pid = uwsgi_fork(uwsgi.emperor_procname);
|
||||
}
|
||||
else {
|
||||
uwsgi.emperor_pid = uwsgi_fork("uWSGI Emperor");
|
||||
}
|
||||
if (uwsgi.emperor_pid < 0) {
|
||||
uwsgi_error("pid()");
|
||||
exit(1);
|
||||
@@ -1380,16 +1454,25 @@ void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *ues, char *name, char
|
||||
}
|
||||
// check if mtime is changed and the uWSGI instance must be reloaded
|
||||
if (ts > ui_current->last_mod) {
|
||||
// make a new config (free the old one)
|
||||
free(ui_current->config);
|
||||
ui_current->config = config;
|
||||
ui_current->config_len = strlen(config);
|
||||
// always respawn (no need for amqp-style rules)
|
||||
// make a new config (free the old one) if needed
|
||||
if (config) {
|
||||
if (ui_current->config)
|
||||
free(ui_current->config);
|
||||
ui_current->config = uwsgi_str(config);
|
||||
ui_current->config_len = strlen(ui_current->config);
|
||||
}
|
||||
// reload the instance
|
||||
emperor_respawn(ui_current, ts);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// make a copy of the config as it will be freed
|
||||
emperor_add(ues, name, ts, uwsgi_str(config), strlen((const char *) config), uid, gid);
|
||||
char *new_config = NULL;
|
||||
size_t new_config_len = 0;
|
||||
if (config) {
|
||||
new_config = uwsgi_str(config);
|
||||
new_config_len = strlen(new_config);
|
||||
}
|
||||
emperor_add(ues, name, ts, new_config, new_config_len, uid, gid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
// generate internal server error message
|
||||
void uwsgi_500(struct wsgi_request *wsgi_req) {
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "500 Internal Server Error", 25)) return;
|
||||
if (uwsgi_response_add_connection_close(wsgi_req)) return;
|
||||
uwsgi_response_write_body_do(wsgi_req, "Internal Server Error", 21);
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_404(struct wsgi_request *wsgi_req) {
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "404 Not Found", 13)) return;
|
||||
if (uwsgi_response_add_connection_close(wsgi_req)) return;
|
||||
if (uwsgi_response_add_header(wsgi_req, "Content-Type", 12, "text/plain", 10)) return;
|
||||
uwsgi_response_write_body_do(wsgi_req, "Not Found", 9);
|
||||
}
|
||||
|
||||
void uwsgi_403(struct wsgi_request *wsgi_req) {
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "403 Forbidden", 13)) return;
|
||||
if (uwsgi_response_add_connection_close(wsgi_req)) return;
|
||||
if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) return;
|
||||
uwsgi_response_write_body_do(wsgi_req, "Forbidden", 9);
|
||||
}
|
||||
|
||||
void uwsgi_redirect_to_slash(struct wsgi_request *wsgi_req) {
|
||||
|
||||
char *redirect = NULL;
|
||||
size_t redirect_len = 0;
|
||||
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "301 Moved Permanently", 21)) return;
|
||||
if (uwsgi_response_add_connection_close(wsgi_req)) return;
|
||||
|
||||
if (wsgi_req->query_string_len == 0) {
|
||||
redirect = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "/", 1);
|
||||
redirect_len = wsgi_req->path_info_len + 1;
|
||||
}
|
||||
else {
|
||||
redirect = uwsgi_concat3n(wsgi_req->path_info, wsgi_req->path_info_len, "/?", 2, wsgi_req->query_string, wsgi_req->query_string_len);
|
||||
redirect_len = wsgi_req->path_info_len + 2 + wsgi_req->query_string_len;
|
||||
}
|
||||
uwsgi_response_add_header(wsgi_req, "Location", 8, redirect, redirect_len);
|
||||
free(redirect);
|
||||
return;
|
||||
}
|
||||
|
||||
+15
-2
@@ -108,7 +108,7 @@ int event_queue_interesting_fd_has_error(void *events, int id) {
|
||||
|
||||
int event_queue_interesting_fd_is_read(void *events, int id) {
|
||||
port_event_t *pe = (port_event_t *) events;
|
||||
if (pe[id].portev_events = POLLIN) {
|
||||
if (pe[id].portev_events == POLLIN) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -124,7 +124,7 @@ int event_queue_interesting_fd_is_write(void *events, int id) {
|
||||
|
||||
int event_queue_add_fd_read(int eq, int fd) {
|
||||
|
||||
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, (void *) eq)) {
|
||||
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, NULL)) {
|
||||
uwsgi_error("port_associate");
|
||||
return -1;
|
||||
}
|
||||
@@ -171,6 +171,7 @@ int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
|
||||
int ret;
|
||||
uint_t nget = 1;
|
||||
timespec_t ts;
|
||||
|
||||
|
||||
if (timeout >= 0) {
|
||||
ts.tv_sec = timeout;
|
||||
@@ -189,6 +190,18 @@ int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint_t i;
|
||||
port_event_t *pe = (port_event_t *) events;
|
||||
for(i=0;i<nget;i++) {
|
||||
port_event_t *pe_i = &pe[i];
|
||||
if (pe_i->portev_source == PORT_SOURCE_FD) {
|
||||
// event must be readded (damn Oracle/Sun why the fu*k you made such a horrible choice ???? why not adding a ONESHOT flag ???)
|
||||
if (port_associate(eq, pe_i->portev_source, pe_i->portev_object, pe_i->portev_events, NULL)) {
|
||||
uwsgi_error("port_associate");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nget;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,499 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/*
|
||||
|
||||
Exceptions management
|
||||
|
||||
generally exceptions are printed in the logs, but if you enable
|
||||
an exception manager they will be stored in a (relatively big) uwsgi packet
|
||||
with the following structure.
|
||||
|
||||
"vars" -> keyval of request vars
|
||||
"backtrace" -> list of backtrace lines. Each line is a list of 5 elements filename,line,function,text,custom
|
||||
"unix" -> seconds since the epoch
|
||||
"class" -> the exception class
|
||||
"msg" -> a text message mapped to the extension
|
||||
"repr" -> a text message mapped to the extension in language-specific gergo
|
||||
"wid" -> worker id
|
||||
"core" -> the core generating the exception
|
||||
"pid" -> pid of the worker
|
||||
"node" -> hostname
|
||||
|
||||
Other vars can be added, but you cannot be sure they will be used by exceptions handler.
|
||||
|
||||
The exception-uwsgi packet is passed "as is" to the exception handler
|
||||
|
||||
Exceptions hooks:
|
||||
|
||||
a request plugin can export that hooks:
|
||||
|
||||
struct uwsgi_buffer *backtrace(struct wsgi_request *);
|
||||
struct uwsgi_buffer *exception_class(struct wsgi_request *);
|
||||
struct uwsgi_buffer *exception_msg(struct wsgi_request *);
|
||||
struct uwsgi_buffer *exception_repr(struct wsgi_request *);
|
||||
void exception_log(struct wsgi_request *);
|
||||
|
||||
Remember to reset the exception status (if possibile) after each call
|
||||
|
||||
Exceptions catcher:
|
||||
|
||||
This is a special development-mode in which exceptions are printed
|
||||
to the HTTP client.
|
||||
|
||||
*/
|
||||
|
||||
struct uwsgi_buffer *uwsgi_exception_handler_object(struct wsgi_request *wsgi_req) {
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(4096);
|
||||
if (uwsgi_buffer_append_keyval(ub, "vars", 4, wsgi_req->buffer,wsgi_req->uh->pktsize)) goto error;
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->backtrace) {
|
||||
struct uwsgi_buffer *bt = uwsgi.p[wsgi_req->uh->modifier1]->backtrace(wsgi_req);
|
||||
if (bt) {
|
||||
if (uwsgi_buffer_append_keyval(ub, "backtrace", 9, bt->buf, bt->pos)) {
|
||||
uwsgi_buffer_destroy(bt);
|
||||
goto error;
|
||||
}
|
||||
uwsgi_buffer_destroy(bt);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->exception_class) {
|
||||
struct uwsgi_buffer *ec = uwsgi.p[wsgi_req->uh->modifier1]->exception_class(wsgi_req);
|
||||
if (ec) {
|
||||
if (uwsgi_buffer_append_keyval(ub, "class", 5, ec->buf, ec->pos)) {
|
||||
uwsgi_buffer_destroy(ec);
|
||||
goto error;
|
||||
}
|
||||
uwsgi_buffer_destroy(ec);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->exception_msg) {
|
||||
struct uwsgi_buffer *em = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req);
|
||||
if (em) {
|
||||
if (uwsgi_buffer_append_keyval(ub, "msg", 3, em->buf, em->pos)) {
|
||||
uwsgi_buffer_destroy(em);
|
||||
goto error;
|
||||
}
|
||||
uwsgi_buffer_destroy(em);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->exception_repr) {
|
||||
struct uwsgi_buffer *er = uwsgi.p[wsgi_req->uh->modifier1]->exception_repr(wsgi_req);
|
||||
if (er) {
|
||||
if (uwsgi_buffer_append_keyval(ub, "repr", 4, er->buf, er->pos)) {
|
||||
uwsgi_buffer_destroy(er);
|
||||
goto error;
|
||||
}
|
||||
uwsgi_buffer_destroy(er);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi_buffer_append_keynum(ub, "unix", 4, uwsgi_now())) goto error;
|
||||
if (uwsgi_buffer_append_keynum(ub, "wid", 3, uwsgi.mywid)) goto error;
|
||||
if (uwsgi_buffer_append_keynum(ub, "pid", 3, uwsgi.mypid)) goto error;
|
||||
if (uwsgi_buffer_append_keynum(ub, "core", 4, wsgi_req->async_id)) goto error;
|
||||
if (uwsgi_buffer_append_keyval(ub, "node", 4, uwsgi.hostname, uwsgi.hostname_len)) goto error;
|
||||
|
||||
return ub;
|
||||
|
||||
error:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void append_vars_to_ubuf(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
|
||||
struct uwsgi_buffer *ub = (struct uwsgi_buffer *) data;
|
||||
|
||||
if (uwsgi_buffer_append(ub, key, keylen)) return;
|
||||
if (uwsgi_buffer_append(ub, " = ", 3)) return;
|
||||
if (uwsgi_buffer_append(ub, val, vallen)) return;
|
||||
if (uwsgi_buffer_append(ub, "\n", 1)) return;
|
||||
}
|
||||
|
||||
static void append_backtrace_to_ubuf(uint16_t pos, char *value, uint16_t len, void *data) {
|
||||
struct uwsgi_buffer *ub = (struct uwsgi_buffer *) data;
|
||||
|
||||
uint16_t item = 0;
|
||||
if (pos > 0) {
|
||||
item = pos % 5;
|
||||
}
|
||||
|
||||
switch(item) {
|
||||
// filename
|
||||
case 0:
|
||||
if (uwsgi_buffer_append(ub, "filename: \"", 11)) return;
|
||||
if (uwsgi_buffer_append(ub, value, len)) return;
|
||||
if (uwsgi_buffer_append(ub, "\" ", 2)) return;
|
||||
break;
|
||||
// lineno
|
||||
case 1:
|
||||
if (uwsgi_buffer_append(ub, "line: ", 6)) return;
|
||||
if (uwsgi_buffer_append(ub, value, len)) return;
|
||||
if (uwsgi_buffer_append(ub, " ", 1)) return;
|
||||
break;
|
||||
// function
|
||||
case 2:
|
||||
if (uwsgi_buffer_append(ub, "function: \"", 11)) return;
|
||||
if (uwsgi_buffer_append(ub, value, len)) return;
|
||||
if (uwsgi_buffer_append(ub, "\" ", 2)) return;
|
||||
break;
|
||||
// text
|
||||
case 3:
|
||||
if (len > 0) {
|
||||
if (uwsgi_buffer_append(ub, "text/code: \"", 12)) return;
|
||||
if (uwsgi_buffer_append(ub, value, len)) return;
|
||||
if (uwsgi_buffer_append(ub, "\" ", 2)) return;
|
||||
}
|
||||
break;
|
||||
// custom
|
||||
case 4:
|
||||
if (len > 0) {
|
||||
if (uwsgi_buffer_append(ub, "custom: \"", 9)) return;
|
||||
if (uwsgi_buffer_append(ub, value, len)) return;
|
||||
if (uwsgi_buffer_append(ub, "\" ", 2)) return;
|
||||
}
|
||||
if (uwsgi_buffer_append(ub, "\n", 1)) return;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_exceptions_catch(struct wsgi_request *wsgi_req) {
|
||||
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "500 Internal Server Error", 25)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(4096);
|
||||
if (uwsgi_buffer_append(ub, "uWSGI exceptions catcher for \"", 30)) goto error;
|
||||
if (uwsgi_buffer_append(ub, wsgi_req->method, wsgi_req->method_len)) goto error;
|
||||
if (uwsgi_buffer_append(ub, " ", 1)) goto error;
|
||||
if (uwsgi_buffer_append(ub, wsgi_req->uri, wsgi_req->uri_len)) goto error;
|
||||
if (uwsgi_buffer_append(ub, "\" (request plugin: \"", 20)) goto error;
|
||||
if (uwsgi_buffer_append(ub, (char *) uwsgi.p[wsgi_req->uh->modifier1]->name, strlen(uwsgi.p[wsgi_req->uh->modifier1]->name))) goto error;
|
||||
if (uwsgi_buffer_append(ub, "\", modifier1: ", 14 )) goto error;
|
||||
if (uwsgi_buffer_num64(ub, wsgi_req->uh->modifier1)) goto error;
|
||||
if (uwsgi_buffer_append(ub, ")\n\n", 3)) goto error;
|
||||
|
||||
if (uwsgi_buffer_append(ub, "Exception: ", 11)) goto error;
|
||||
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->exception_repr) {
|
||||
struct uwsgi_buffer *ub_exc_repr = uwsgi.p[wsgi_req->uh->modifier1]->exception_repr(wsgi_req);
|
||||
if (ub_exc_repr) {
|
||||
if (uwsgi_buffer_append(ub, ub_exc_repr->buf, ub_exc_repr->pos)) {
|
||||
uwsgi_buffer_destroy(ub_exc_repr);
|
||||
goto error;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub_exc_repr);
|
||||
}
|
||||
else {
|
||||
goto notavail3;
|
||||
}
|
||||
}
|
||||
else {
|
||||
notavail3:
|
||||
if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error;
|
||||
}
|
||||
|
||||
if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error;
|
||||
|
||||
if (uwsgi_buffer_append(ub, "Exception class: ", 17)) goto error;
|
||||
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->exception_class) {
|
||||
struct uwsgi_buffer *ub_exc_class = uwsgi.p[wsgi_req->uh->modifier1]->exception_class(wsgi_req);
|
||||
if (ub_exc_class) {
|
||||
if (uwsgi_buffer_append(ub, ub_exc_class->buf, ub_exc_class->pos)) {
|
||||
uwsgi_buffer_destroy(ub_exc_class);
|
||||
goto error;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub_exc_class);
|
||||
}
|
||||
else {
|
||||
goto notavail;
|
||||
}
|
||||
}
|
||||
else {
|
||||
notavail:
|
||||
if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error;
|
||||
}
|
||||
|
||||
if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error;
|
||||
|
||||
if (uwsgi_buffer_append(ub, "Exception message: ", 19)) goto error;
|
||||
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->exception_msg) {
|
||||
struct uwsgi_buffer *ub_exc_msg = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req);
|
||||
if (ub_exc_msg) {
|
||||
if (uwsgi_buffer_append(ub, ub_exc_msg->buf, ub_exc_msg->pos)) {
|
||||
uwsgi_buffer_destroy(ub_exc_msg);
|
||||
goto error;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub_exc_msg);
|
||||
}
|
||||
else {
|
||||
goto notavail2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
notavail2:
|
||||
if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error;
|
||||
}
|
||||
|
||||
if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error;
|
||||
|
||||
if (uwsgi_buffer_append(ub, "Backtrace:\n", 11)) goto error;
|
||||
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->backtrace) {
|
||||
struct uwsgi_buffer *ub_exc_bt = uwsgi.p[wsgi_req->uh->modifier1]->backtrace(wsgi_req);
|
||||
if (ub_exc_bt) {
|
||||
struct uwsgi_buffer *parsed_bt = uwsgi_buffer_new(4096);
|
||||
if (uwsgi_hooked_parse_array(ub_exc_bt->buf, ub_exc_bt->pos, append_backtrace_to_ubuf, parsed_bt)) {
|
||||
uwsgi_buffer_destroy(ub_exc_bt);
|
||||
uwsgi_buffer_destroy(parsed_bt);
|
||||
goto error;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub_exc_bt);
|
||||
if (uwsgi_buffer_append(ub, parsed_bt->buf, parsed_bt->pos)) {
|
||||
uwsgi_buffer_destroy(parsed_bt);
|
||||
goto error;
|
||||
}
|
||||
uwsgi_buffer_destroy(parsed_bt);
|
||||
}
|
||||
else {
|
||||
goto notavail4;
|
||||
}
|
||||
}
|
||||
else {
|
||||
notavail4:
|
||||
if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error;
|
||||
}
|
||||
|
||||
if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error;
|
||||
|
||||
if (uwsgi_hooked_parse(wsgi_req->buffer, wsgi_req->uh->pktsize, append_vars_to_ubuf, ub)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
static void uwsgi_exception_run_handlers(struct uwsgi_buffer *ub) {
|
||||
struct uwsgi_string_list *usl = uwsgi.exception_handlers_instance;
|
||||
struct iovec iov[2];
|
||||
iov[1].iov_base = ub->buf;
|
||||
iov[1].iov_len = ub->pos;
|
||||
while(usl) {
|
||||
struct uwsgi_exception_handler_instance *uehi = (struct uwsgi_exception_handler_instance *) usl->custom_ptr;
|
||||
iov[0].iov_base = &uehi;
|
||||
iov[0].iov_len = sizeof(long);
|
||||
// now send the message to the exception handler thread
|
||||
if (writev(uwsgi.exception_handler_thread->pipe[0], iov, 2) != (ssize_t) (ub->pos+sizeof(long))) {
|
||||
uwsgi_error("[uwsgi-exception-handler-error] uwsgi_exception_run_handlers()/writev()");
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_manage_exception(struct wsgi_request *wsgi_req,int catch) {
|
||||
|
||||
int do_exit = uwsgi.reload_on_exception;
|
||||
|
||||
if (!wsgi_req) goto log2;
|
||||
|
||||
if (do_exit) goto check_catch;
|
||||
|
||||
if (wsgi_req && uwsgi.exception_handlers_instance) {
|
||||
struct uwsgi_buffer *ehi = uwsgi_exception_handler_object(wsgi_req);
|
||||
if (ehi) {
|
||||
uwsgi_exception_run_handlers(ehi);
|
||||
uwsgi_buffer_destroy(ehi);
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].exceptions++;
|
||||
uwsgi_apps[wsgi_req->app_id].exceptions++;
|
||||
|
||||
if (uwsgi.reload_on_exception_type && uwsgi.p[wsgi_req->uh->modifier1]->exception_class) {
|
||||
struct uwsgi_buffer *ub = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req);
|
||||
if (ub) {
|
||||
struct uwsgi_string_list *usl = uwsgi.reload_on_exception_type;
|
||||
while (usl) {
|
||||
if (!uwsgi_strncmp(usl->value, usl->len, ub->buf, ub->len)) {
|
||||
do_exit = 1;
|
||||
uwsgi_buffer_destroy(ub);
|
||||
goto check_catch;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.reload_on_exception_value && uwsgi.p[wsgi_req->uh->modifier1]->exception_msg) {
|
||||
struct uwsgi_buffer *ub = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req);
|
||||
if (ub) {
|
||||
struct uwsgi_string_list *usl = uwsgi.reload_on_exception_value;
|
||||
while (usl) {
|
||||
if (!uwsgi_strncmp(usl->value, usl->len, ub->buf, ub->len)) {
|
||||
do_exit = 1;
|
||||
uwsgi_buffer_destroy(ub);
|
||||
goto check_catch;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.reload_on_exception_repr && uwsgi.p[wsgi_req->uh->modifier1]->exception_repr) {
|
||||
struct uwsgi_buffer *ub = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req);
|
||||
if (ub) {
|
||||
struct uwsgi_string_list *usl = uwsgi.reload_on_exception_repr;
|
||||
while (usl) {
|
||||
if (!uwsgi_strncmp(usl->value, usl->len, ub->buf, ub->len)) {
|
||||
do_exit = 1;
|
||||
uwsgi_buffer_destroy(ub);
|
||||
goto check_catch;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
}
|
||||
}
|
||||
|
||||
check_catch:
|
||||
if (catch && wsgi_req) {
|
||||
if (uwsgi_exceptions_catch(wsgi_req)) {
|
||||
// for now, just goto, new features could be added
|
||||
goto log;
|
||||
}
|
||||
}
|
||||
|
||||
log:
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->exception_log) {
|
||||
uwsgi.p[wsgi_req->uh->modifier1]->exception_log(wsgi_req);
|
||||
}
|
||||
|
||||
log2:
|
||||
if (do_exit) {
|
||||
exit(UWSGI_EXCEPTION_CODE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_exception_handler *uwsgi_register_exception_handler(char *name, int (*func)(struct uwsgi_exception_handler_instance *, char *, size_t)) {
|
||||
struct uwsgi_exception_handler *old_ueh = NULL, *ueh = uwsgi.exception_handlers;
|
||||
while(ueh) {
|
||||
if (!strcmp(name, ueh->name)) {
|
||||
return NULL;
|
||||
}
|
||||
old_ueh = ueh;
|
||||
ueh = ueh->next;
|
||||
}
|
||||
|
||||
ueh = uwsgi_calloc(sizeof(struct uwsgi_exception_handler));
|
||||
ueh->name = name;
|
||||
ueh->func = func;
|
||||
|
||||
if (old_ueh) {
|
||||
old_ueh->next = ueh;
|
||||
}
|
||||
else {
|
||||
uwsgi.exception_handlers = ueh;
|
||||
}
|
||||
|
||||
return ueh;
|
||||
}
|
||||
|
||||
struct uwsgi_exception_handler *uwsgi_exception_handler_by_name(char *name) {
|
||||
struct uwsgi_exception_handler *ueh = uwsgi.exception_handlers;
|
||||
while(ueh) {
|
||||
if (!strcmp(name, ueh->name)) {
|
||||
return ueh;
|
||||
}
|
||||
ueh = ueh->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void uwsgi_exception_handler_thread_loop(struct uwsgi_thread *ut) {
|
||||
char *buf = uwsgi_malloc(uwsgi.exception_handler_msg_size + sizeof(long));
|
||||
for (;;) {
|
||||
int interesting_fd = -1;
|
||||
int ret = event_queue_wait(ut->queue, -1, &interesting_fd);
|
||||
if (ret > 0) {
|
||||
ssize_t len = read(ut->pipe[1], buf, uwsgi.alarm_msg_size + sizeof(long));
|
||||
if (len > (ssize_t)(sizeof(long) + 1)) {
|
||||
size_t msg_size = len - sizeof(long);
|
||||
char *msg = buf + sizeof(long);
|
||||
long ptr = 0;
|
||||
memcpy(&ptr, buf, sizeof(long));
|
||||
struct uwsgi_exception_handler_instance *uehi = (struct uwsgi_exception_handler_instance *) ptr;
|
||||
if (!uehi)
|
||||
break;
|
||||
if (uehi->handler->func(uehi, msg, msg_size)) {
|
||||
uwsgi_log("[uwsgi-exception] error running the handler \"%s\" args: \"%s\"\n", uehi->handler->name, uehi->arg ? uehi->arg : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void uwsgi_exception_setup_handlers() {
|
||||
|
||||
struct uwsgi_string_list *usl = uwsgi.exception_handlers_instance;
|
||||
while(usl) {
|
||||
char *handler = uwsgi_str(usl->value);
|
||||
char *colon = strchr(handler, ':');
|
||||
if (colon) {
|
||||
*colon = 0;
|
||||
}
|
||||
struct uwsgi_exception_handler *ueh = uwsgi_exception_handler_by_name(handler);
|
||||
if (!ueh) {
|
||||
uwsgi_log("unable to find exception handler: %s\n", handler);
|
||||
free(handler);
|
||||
exit(1);
|
||||
}
|
||||
free(handler);
|
||||
|
||||
struct uwsgi_exception_handler_instance *uehi = uwsgi_calloc(sizeof(struct uwsgi_exception_handler_instance));
|
||||
uehi->handler = ueh;
|
||||
if (colon) {
|
||||
uehi->arg = colon+1;
|
||||
}
|
||||
usl->custom_ptr = uehi;
|
||||
usl = usl->next;
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_exceptions_handler_thread_start() {
|
||||
|
||||
// start the exception_handler_thread
|
||||
uwsgi.exception_handler_thread = uwsgi_thread_new(uwsgi_exception_handler_thread_loop);
|
||||
if (!uwsgi.exception_handler_thread) {
|
||||
uwsgi_log("unable to spawn exception handler thread\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -41,6 +41,10 @@ struct uwsgi_gateway *register_gateway(char *name, void (*loop) (int, void *), v
|
||||
return ug;
|
||||
}
|
||||
|
||||
static void gateway_brutal_end() {
|
||||
_exit(UWSGI_END_CODE);
|
||||
}
|
||||
|
||||
void gateway_respawn(int id) {
|
||||
|
||||
pid_t gw_pid;
|
||||
@@ -65,6 +69,7 @@ void gateway_respawn(int id) {
|
||||
}
|
||||
#endif
|
||||
uwsgi.mypid = getpid();
|
||||
atexit(gateway_brutal_end);
|
||||
signal(SIGALRM, SIG_IGN);
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
signal(SIGINT, end_me);
|
||||
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
// Bernstein classic hash (this is not static as it is used by other areas)
|
||||
uint32_t djb33x_hash(char *key, uint64_t keylen) {
|
||||
|
||||
register uint32_t hash = 5381;
|
||||
uint64_t i;
|
||||
|
||||
for (i = 0; i < keylen; i++) {
|
||||
hash = ((hash << 5) + hash) ^ key[i];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
// Murmur2 hash Copyright (C) Austin Appleby
|
||||
// adapted from nginx
|
||||
uint32_t murmur2_hash(char *key, uint64_t keylen) {
|
||||
|
||||
uint32_t h, k;
|
||||
uint8_t *ukey = (uint8_t *) key;
|
||||
h = 0 ^ keylen;
|
||||
while (keylen >= 4) {
|
||||
k = ukey[0];
|
||||
k |= ukey[1] << 8;
|
||||
k |= ukey[2] << 16;
|
||||
k |= ukey[3] << 24;
|
||||
|
||||
k *= 0x5bd1e995;
|
||||
k ^= k >> 24;
|
||||
k *= 0x5bd1e995;
|
||||
|
||||
h *= 0x5bd1e995;
|
||||
h ^= k;
|
||||
|
||||
ukey += 4;
|
||||
keylen -= 4;
|
||||
}
|
||||
|
||||
switch (keylen) {
|
||||
case 3:
|
||||
h ^= key[2] << 16;
|
||||
case 2:
|
||||
h ^= key[1] << 8;
|
||||
case 1:
|
||||
h ^= key[0];
|
||||
h *= 0x5bd1e995;
|
||||
}
|
||||
|
||||
h ^= h >> 13;
|
||||
h *= 0x5bd1e995;
|
||||
h ^= h >> 15;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_hash_algo *uwsgi_hash_algo_get(char *name) {
|
||||
struct uwsgi_hash_algo *uha = uwsgi.hash_algos;
|
||||
while(uha) {
|
||||
if (!strcmp(name, uha->name)) {
|
||||
return uha;
|
||||
}
|
||||
uha = uha->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
void uwsgi_hash_algo_register(char *name, uint32_t (*func)(char *, uint64_t)) {
|
||||
|
||||
struct uwsgi_hash_algo *old_uha = NULL, *uha = uwsgi.hash_algos;
|
||||
while(uha) {
|
||||
if (!strcmp(uha->name, name)) return;
|
||||
old_uha = uha;
|
||||
uha = uha->next;
|
||||
}
|
||||
|
||||
uha = uwsgi_calloc(sizeof(struct uwsgi_hash_algo));
|
||||
uha->name = name;
|
||||
uha->func = func;
|
||||
if (old_uha) {
|
||||
old_uha->next = uha;
|
||||
}
|
||||
else {
|
||||
uwsgi.hash_algos = uha;
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_hash_algo_register_all() {
|
||||
uwsgi_hash_algo_register("djb33x", djb33x_hash);
|
||||
uwsgi_hash_algo_register("murmur2", murmur2_hash);
|
||||
}
|
||||
+4
-4
@@ -54,9 +54,9 @@ char *ini_get_key(char *key) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
char *ini_get_line(char *ini, off_t size) {
|
||||
char *ini_get_line(char *ini, size_t size) {
|
||||
|
||||
off_t i;
|
||||
size_t i;
|
||||
char *ptr = ini;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
@@ -78,7 +78,7 @@ char *ini_get_line(char *ini, off_t size) {
|
||||
|
||||
void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
|
||||
int len = 0;
|
||||
size_t len = 0;
|
||||
char *ini;
|
||||
|
||||
char *ini_line;
|
||||
@@ -109,7 +109,7 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
}
|
||||
|
||||
if (file[0] != 0) {
|
||||
uwsgi_log("[uWSGI] getting INI configuration from %s\n", file);
|
||||
uwsgi_log_initial("[uWSGI] getting INI configuration from %s\n", file);
|
||||
}
|
||||
|
||||
ini = uwsgi_open_and_read(file, &len, 1, magic_table);
|
||||
|
||||
+167
-12
@@ -2,6 +2,61 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct http_status_codes {
|
||||
const char key[3];
|
||||
const char *message;
|
||||
int message_size;
|
||||
};
|
||||
|
||||
/* statistically ordered */
|
||||
struct http_status_codes hsc[] = {
|
||||
{"200", "OK"},
|
||||
{"302", "Found"},
|
||||
{"404", "Not Found"},
|
||||
{"500", "Internal Server Error"},
|
||||
{"301", "Moved Permanently"},
|
||||
{"304", "Not Modified"},
|
||||
{"303", "See Other"},
|
||||
{"403", "Forbidden"},
|
||||
{"307", "Temporary Redirect"},
|
||||
{"401", "Unauthorized"},
|
||||
{"400", "Bad Request"},
|
||||
{"405", "Method Not Allowed"},
|
||||
{"408", "Request Timeout"},
|
||||
|
||||
{"100", "Continue"},
|
||||
{"101", "Switching Protocols"},
|
||||
{"201", "Created"},
|
||||
{"202", "Accepted"},
|
||||
{"203", "Non-Authoritative Information"},
|
||||
{"204", "No Content"},
|
||||
{"205", "Reset Content"},
|
||||
{"206", "Partial Content"},
|
||||
{"300", "Multiple Choices"},
|
||||
{"305", "Use Proxy"},
|
||||
{"402", "Payment Required"},
|
||||
{"406", "Not Acceptable"},
|
||||
{"407", "Proxy Authentication Required"},
|
||||
{"409", "Conflict"},
|
||||
{"410", "Gone"},
|
||||
{"411", "Length Required"},
|
||||
{"412", "Precondition Failed"},
|
||||
{"413", "Request Entity Too Large"},
|
||||
{"414", "Request-URI Too Long"},
|
||||
{"415", "Unsupported Media Type"},
|
||||
{"416", "Requested Range Not Satisfiable"},
|
||||
{"417", "Expectation Failed"},
|
||||
{"501", "Not Implemented"},
|
||||
{"502", "Bad Gateway"},
|
||||
{"503", "Service Unavailable"},
|
||||
{"504", "Gateway Timeout"},
|
||||
{"505", "HTTP Version Not Supported"},
|
||||
{"", NULL},
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
void uwsgi_init_default() {
|
||||
|
||||
uwsgi.cpus = 1;
|
||||
@@ -13,7 +68,6 @@ void uwsgi_init_default() {
|
||||
|
||||
uwsgi.signal_socket = -1;
|
||||
uwsgi.my_signal_socket = -1;
|
||||
uwsgi.cache_server_fd = -1;
|
||||
uwsgi.stats_fd = -1;
|
||||
|
||||
uwsgi.stats_pusher_default_freq = 3;
|
||||
@@ -32,15 +86,18 @@ void uwsgi_init_default() {
|
||||
uwsgi.subscribe_freq = 10;
|
||||
uwsgi.subscription_tolerance = 17;
|
||||
|
||||
uwsgi.cluster_fd = -1;
|
||||
uwsgi.cores = 1;
|
||||
uwsgi.threads = 1;
|
||||
|
||||
// default max number of rpc slot
|
||||
uwsgi.rpc_max = 64;
|
||||
|
||||
uwsgi.offload_threads_events = 64;
|
||||
|
||||
uwsgi.default_app = -1;
|
||||
|
||||
uwsgi.buffer_size = 4096;
|
||||
uwsgi.body_read_warning = 8;
|
||||
uwsgi.numproc = 1;
|
||||
|
||||
uwsgi.forkbomb_delay = 2;
|
||||
@@ -52,18 +109,22 @@ void uwsgi_init_default() {
|
||||
|
||||
uwsgi.log_master_bufsize = 8192;
|
||||
|
||||
uwsgi.worker_reload_mercy = 60;
|
||||
|
||||
uwsgi.max_vars = MAX_VARS;
|
||||
uwsgi.vec_size = 4 + 1 + (4 * MAX_VARS);
|
||||
|
||||
uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] = 4;
|
||||
uwsgi.shared->options[UWSGI_OPTION_LOGGING] = 1;
|
||||
|
||||
#ifdef UWSGI_SPOOLER
|
||||
// a workers hould be running for at least 10 seconds
|
||||
uwsgi.shared->options[UWSGI_OPTION_MIN_WORKER_LIFETIME] = 10;
|
||||
|
||||
uwsgi.shared->spooler_frequency = 30;
|
||||
|
||||
uwsgi.shared->spooler_signal_pipe[0] = -1;
|
||||
uwsgi.shared->spooler_signal_pipe[1] = -1;
|
||||
#endif
|
||||
|
||||
uwsgi.shared->mule_signal_pipe[0] = -1;
|
||||
uwsgi.shared->mule_signal_pipe[1] = -1;
|
||||
|
||||
@@ -73,20 +134,37 @@ void uwsgi_init_default() {
|
||||
uwsgi.shared->worker_log_pipe[0] = -1;
|
||||
uwsgi.shared->worker_log_pipe[1] = -1;
|
||||
|
||||
uwsgi.shared->worker_req_log_pipe[0] = -1;
|
||||
uwsgi.shared->worker_req_log_pipe[1] = -1;
|
||||
|
||||
uwsgi.req_log_fd = 2;
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
// 1 day of tolerance
|
||||
uwsgi.subscriptions_sign_check_tolerance = 3600 * 24;
|
||||
uwsgi.ssl_sessions_timeout = 300;
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_ALARM
|
||||
uwsgi.alarm_freq = 3;
|
||||
#endif
|
||||
uwsgi.alarm_msg_size = 8192;
|
||||
|
||||
uwsgi.exception_handler_msg_size = 65536;
|
||||
|
||||
#ifdef UWSGI_MULTICAST
|
||||
uwsgi.multicast_ttl = 1;
|
||||
#endif
|
||||
uwsgi.multicast_loop = 1;
|
||||
|
||||
// filling http status codes
|
||||
struct http_status_codes *http_sc;
|
||||
for (http_sc = hsc; http_sc->message != NULL; http_sc++) {
|
||||
http_sc->message_size = strlen(http_sc->message);
|
||||
}
|
||||
|
||||
uwsgi.empty = "";
|
||||
|
||||
uwsgi.wait_read_hook = uwsgi_simple_wait_read_hook;
|
||||
uwsgi.wait_write_hook = uwsgi_simple_wait_write_hook;
|
||||
|
||||
uwsgi_websockets_init();
|
||||
}
|
||||
|
||||
void uwsgi_setup_reload() {
|
||||
@@ -229,7 +307,8 @@ void uwsgi_setup_workers() {
|
||||
|
||||
// this is a trick for avoiding too much memory areas
|
||||
void *ts = uwsgi_calloc_shared(sizeof(void *) * uwsgi.max_apps * uwsgi.cores);
|
||||
void *buffers = uwsgi_malloc_shared(uwsgi.buffer_size * uwsgi.cores);
|
||||
// add 4 bytes for uwsgi header
|
||||
void *buffers = uwsgi_malloc_shared((uwsgi.buffer_size+4) * uwsgi.cores);
|
||||
void *hvec = uwsgi_malloc_shared(sizeof(struct iovec) * uwsgi.vec_size * uwsgi.cores);
|
||||
void *post_buf = NULL;
|
||||
if (uwsgi.post_buffering > 0)
|
||||
@@ -239,8 +318,8 @@ void uwsgi_setup_workers() {
|
||||
for (j = 0; j < uwsgi.cores; j++) {
|
||||
// allocate shared memory for thread states (required for some language, like python)
|
||||
uwsgi.workers[i].cores[j].ts = ts + ((sizeof(void *) * uwsgi.max_apps) * j);
|
||||
// raw per-request buffer
|
||||
uwsgi.workers[i].cores[j].buffer = buffers + (uwsgi.buffer_size * j);
|
||||
// raw per-request buffer (+4 bytes for uwsgi header)
|
||||
uwsgi.workers[i].cores[j].buffer = buffers + ((uwsgi.buffer_size+4) * j);
|
||||
// iovec for uwsgi vars
|
||||
uwsgi.workers[i].cores[j].hvec = hvec + ((sizeof(struct iovec) * uwsgi.vec_size) * j);
|
||||
if (post_buf)
|
||||
@@ -262,7 +341,11 @@ void uwsgi_setup_workers() {
|
||||
}
|
||||
|
||||
total_memory *= (uwsgi.numproc + uwsgi.master_process);
|
||||
uwsgi_log("mapped %llu bytes (%llu KB) for %d cores\n", total_memory, total_memory / 1024, uwsgi.cores * uwsgi.numproc);
|
||||
if (uwsgi.numproc > 0)
|
||||
uwsgi_log("mapped %llu bytes (%llu KB) for %d cores\n", (unsigned long long) total_memory, (unsigned long long) (total_memory / 1024), uwsgi.cores * uwsgi.numproc);
|
||||
|
||||
// allocate signal table
|
||||
uwsgi.shared->signal_table = uwsgi_calloc_shared(sizeof(struct uwsgi_signal_entry) * 256 * (uwsgi.numproc + 1));
|
||||
|
||||
}
|
||||
|
||||
@@ -293,3 +376,75 @@ pid_t uwsgi_daemonize2() {
|
||||
|
||||
return uwsgi.mypid;
|
||||
}
|
||||
|
||||
// fix/check related options
|
||||
void sanitize_args() {
|
||||
|
||||
if (uwsgi.async > 1) {
|
||||
uwsgi.cores = uwsgi.async;
|
||||
}
|
||||
|
||||
if (uwsgi.threads > 1) {
|
||||
uwsgi.has_threads = 1;
|
||||
uwsgi.cores = uwsgi.threads;
|
||||
}
|
||||
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
|
||||
if (!uwsgi.post_buffering) {
|
||||
uwsgi_log(" *** WARNING: you have enabled harakiri without post buffering. Slow upload could be rejected on post-unbuffered webservers *** \n");
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.write_errors_exception_only) {
|
||||
uwsgi.ignore_sigpipe = 1;
|
||||
uwsgi.ignore_write_errors = 1;
|
||||
}
|
||||
|
||||
if (uwsgi.cheaper_count == 0) uwsgi.cheaper = 0;
|
||||
|
||||
if (uwsgi.cheaper_count > 0 && uwsgi.cheaper_count >= uwsgi.numproc) {
|
||||
uwsgi_log("invalid cheaper value: must be lower than processes\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (uwsgi.cheaper && uwsgi.cheaper_count) {
|
||||
if (uwsgi.cheaper_initial) {
|
||||
if (uwsgi.cheaper_initial < uwsgi.cheaper_count) {
|
||||
uwsgi_log("warning: invalid cheaper-initial value (%d), must be equal or higher than cheaper (%d), using %d as initial number of workers\n",
|
||||
uwsgi.cheaper_initial, uwsgi.cheaper_count, uwsgi.cheaper_count);
|
||||
uwsgi.cheaper_initial = uwsgi.cheaper_count;
|
||||
}
|
||||
else if (uwsgi.cheaper_initial > uwsgi.numproc) {
|
||||
uwsgi_log("warning: invalid cheaper-initial value (%d), must be lower or equal than worker count (%d), using %d as initial number of workers\n",
|
||||
uwsgi.cheaper_initial, uwsgi.numproc, uwsgi.numproc);
|
||||
uwsgi.cheaper_initial = uwsgi.numproc;
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi.cheaper_initial = uwsgi.cheaper_count;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.auto_snapshot > 0 && uwsgi.auto_snapshot > uwsgi.numproc) {
|
||||
uwsgi_log("invalid auto-snapshot value: must be <= than processes\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME] > 0 && uwsgi.shared->options[UWSGI_OPTION_MIN_WORKER_LIFETIME] >= uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME]) {
|
||||
uwsgi_log("invalid min-worker-lifetime value (%d), must be lower than max-worker-lifetime (%d)\n",
|
||||
uwsgi.shared->options[UWSGI_OPTION_MIN_WORKER_LIFETIME], uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const char *uwsgi_http_status_msg(char *status, uint16_t *len) {
|
||||
struct http_status_codes *http_sc;
|
||||
for (http_sc = hsc; http_sc->message != NULL; http_sc++) {
|
||||
if (!strncmp(http_sc->key, status, 3)) {
|
||||
*len = http_sc->message_size;
|
||||
return http_sc->message;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+2
-2
@@ -13,7 +13,7 @@ extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_json_config(char *file, char *magic_table[]) {
|
||||
|
||||
int len = 0;
|
||||
size_t len = 0;
|
||||
char *json_data;
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ void uwsgi_json_config(char *file, char *magic_table[]) {
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("[uWSGI] getting JSON configuration from %s\n", file);
|
||||
uwsgi_log_initial("[uWSGI] getting JSON configuration from %s\n", file);
|
||||
|
||||
json_data = uwsgi_open_and_read(file, &len, 1, magic_table);
|
||||
|
||||
|
||||
+936
@@ -0,0 +1,936 @@
|
||||
#include "../uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/*
|
||||
|
||||
uWSGI Legions subsystem
|
||||
|
||||
A Legion is a group of uWSGI instances sharing a single object. This single
|
||||
object can be owned only by the instance with the higher valor. Such an instance is the
|
||||
Lord of the Legion. There can only be one (and only one) Lord for each Legion.
|
||||
If a member of a Legion spawns with an higher valor than the current Lord, it became the new Lord.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
struct uwsgi_legion *uwsgi_legion_get_by_socket(int fd) {
|
||||
struct uwsgi_legion *ul = uwsgi.legions;
|
||||
while (ul) {
|
||||
if (ul->socket == fd) {
|
||||
return ul;
|
||||
}
|
||||
ul = ul->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_legion *uwsgi_legion_get_by_name(char *name) {
|
||||
struct uwsgi_legion *ul = uwsgi.legions;
|
||||
while (ul) {
|
||||
if (!strcmp(name, ul->legion)) {
|
||||
return ul;
|
||||
}
|
||||
ul = ul->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_parse_legion(char *key, uint16_t keylen, char *value, uint16_t vallen, void *data) {
|
||||
struct uwsgi_legion *ul = (struct uwsgi_legion *) data;
|
||||
|
||||
if (!uwsgi_strncmp(key, keylen, "legion", 6)) {
|
||||
ul->legion = value;
|
||||
ul->legion_len = vallen;
|
||||
}
|
||||
else if (!uwsgi_strncmp(key, keylen, "valor", 5)) {
|
||||
ul->valor = uwsgi_str_num(value, vallen);
|
||||
}
|
||||
else if (!uwsgi_strncmp(key, keylen, "name", 4)) {
|
||||
ul->name = value;
|
||||
ul->name_len = vallen;
|
||||
}
|
||||
else if (!uwsgi_strncmp(key, keylen, "pid", 3)) {
|
||||
ul->pid = uwsgi_str_num(value, vallen);
|
||||
}
|
||||
else if (!uwsgi_strncmp(key, keylen, "unix", 4)) {
|
||||
ul->unix_check = uwsgi_str_num(value, vallen);
|
||||
}
|
||||
else if (!uwsgi_strncmp(key, keylen, "checksum", 8)) {
|
||||
ul->checksum = uwsgi_str_num(value, vallen);
|
||||
}
|
||||
else if (!uwsgi_strncmp(key, keylen, "uuid", 4)) {
|
||||
if (vallen == 36) {
|
||||
memcpy(ul->uuid, value, 36);
|
||||
}
|
||||
}
|
||||
else if (!uwsgi_strncmp(key, keylen, "lord_valor", 10)) {
|
||||
ul->lord_valor = uwsgi_str_num(value, vallen);
|
||||
}
|
||||
else if (!uwsgi_strncmp(key, keylen, "lord_uuid", 9)) {
|
||||
if (vallen == 36) {
|
||||
memcpy(ul->lord_uuid, value, 36);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// critical section (remember to lock when you use it)
|
||||
struct uwsgi_legion_node *uwsgi_legion_add_node(struct uwsgi_legion *ul, uint16_t valor, char *name, uint16_t name_len, char *uuid) {
|
||||
|
||||
struct uwsgi_legion_node *node = uwsgi_calloc(sizeof(struct uwsgi_legion_node));
|
||||
if (!name_len)
|
||||
goto error;
|
||||
node->name = uwsgi_calloc(name_len);
|
||||
node->name_len = name_len;
|
||||
memcpy(node->name, name, name_len);
|
||||
node->valor = valor;
|
||||
memcpy(node->uuid, uuid, 36);
|
||||
|
||||
if (ul->nodes_tail) {
|
||||
node->prev = ul->nodes_tail;
|
||||
ul->nodes_tail->next = node;
|
||||
}
|
||||
|
||||
ul->nodes_tail = node;
|
||||
|
||||
if (!ul->nodes_head) {
|
||||
ul->nodes_head = node;
|
||||
}
|
||||
|
||||
return node;
|
||||
|
||||
|
||||
error:
|
||||
free(node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// critical section (remember to lock when you use it)
|
||||
void uwsgi_legion_remove_node(struct uwsgi_legion *ul, struct uwsgi_legion_node *node) {
|
||||
// check if the node is the first one
|
||||
if (node == ul->nodes_head) {
|
||||
ul->nodes_head = node->next;
|
||||
}
|
||||
|
||||
// check if the node is the last one
|
||||
if (node == ul->nodes_tail) {
|
||||
ul->nodes_tail = node->prev;
|
||||
}
|
||||
|
||||
if (node->prev) {
|
||||
node->prev->next = node->next;
|
||||
}
|
||||
|
||||
if (node->next) {
|
||||
node->next->prev = node->prev;
|
||||
}
|
||||
|
||||
if (node->name_len) {
|
||||
free(node->name);
|
||||
}
|
||||
|
||||
if (node->scroll_len) {
|
||||
free(node->scroll);
|
||||
}
|
||||
|
||||
free(node);
|
||||
}
|
||||
|
||||
struct uwsgi_legion_node *uwsgi_legion_get_node(struct uwsgi_legion *ul, uint64_t valor, char *name, uint16_t name_len, char *uuid) {
|
||||
struct uwsgi_legion_node *nodes = ul->nodes_head;
|
||||
while (nodes) {
|
||||
if (valor != nodes->valor)
|
||||
goto next;
|
||||
if (name_len != nodes->name_len)
|
||||
goto next;
|
||||
if (memcmp(nodes->name, name, name_len))
|
||||
goto next;
|
||||
if (memcmp(nodes->uuid, uuid, 36))
|
||||
goto next;
|
||||
return nodes;
|
||||
next:
|
||||
nodes = nodes->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void legions_check_nodes() {
|
||||
|
||||
struct uwsgi_legion *legion = uwsgi.legions;
|
||||
while (legion) {
|
||||
time_t now = uwsgi_now();
|
||||
|
||||
struct uwsgi_legion_node *node = legion->nodes_head;
|
||||
while (node) {
|
||||
|
||||
if (now - node->last_seen > uwsgi.legion_tolerance) {
|
||||
struct uwsgi_legion_node *tmp_node = node;
|
||||
node = node->next;
|
||||
uwsgi_log("[uwsgi-legion] node: %.*s valor: %llu uuid: %.*s left Legion %s\n", tmp_node->name_len, tmp_node->name, tmp_node->valor, 36, tmp_node->uuid, legion->legion);
|
||||
pthread_mutex_lock(&legion->lock);
|
||||
uwsgi_legion_remove_node(legion, tmp_node);
|
||||
pthread_mutex_unlock(&legion->lock);
|
||||
continue;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
legion = legion->next;
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_legion_node *uwsgi_legion_get_lord(struct uwsgi_legion *);
|
||||
|
||||
static void legions_report_quorum(struct uwsgi_legion *ul, uint64_t best_valor, char *best_uuid, int votes) {
|
||||
struct uwsgi_legion_node *nodes = ul->nodes_head;
|
||||
uwsgi_log("\n[uwsgi-legion] --- WE HAVE QUORUM FOR LEGION %s !!! (valor: %llu uuid: %.*s checksum: %llu votes: %d) ---\n", ul->legion, best_valor, 36, best_uuid, ul->checksum, votes);
|
||||
while (nodes) {
|
||||
uwsgi_log("[uwsgi-legion-node] node: %.*s valor: %llu uuid: %.*s last_seen: %d vote_valor: %llu vote_uuid: %.*s\n", nodes->name_len, nodes->name, nodes->valor, 36, nodes->uuid, nodes->last_seen, nodes->lord_valor, 36, nodes->lord_uuid);
|
||||
nodes = nodes->next;
|
||||
}
|
||||
uwsgi_log("[uwsgi-legion] --- END OF QUORUM REPORT ---\n\n");
|
||||
}
|
||||
|
||||
uint64_t uwsgi_legion_checksum(struct uwsgi_legion *ul) {
|
||||
uint16_t i;
|
||||
uint64_t checksum = ul->valor;
|
||||
for(i=0;i<36;i++) {
|
||||
checksum += ul->uuid[i];
|
||||
}
|
||||
|
||||
struct uwsgi_legion_node *nodes = ul->nodes_head;
|
||||
while (nodes) {
|
||||
checksum += nodes->valor;
|
||||
for(i=0;i<36;i++) {
|
||||
checksum += nodes->uuid[i];
|
||||
}
|
||||
nodes = nodes->next;
|
||||
}
|
||||
|
||||
return checksum;
|
||||
|
||||
}
|
||||
|
||||
static void legions_check_nodes_step2() {
|
||||
struct uwsgi_legion *ul = uwsgi.legions;
|
||||
while (ul) {
|
||||
// ok now we can check the status of the lord
|
||||
int i_am_the_best = 0;
|
||||
uint64_t best_valor = 0;
|
||||
char best_uuid[36];
|
||||
struct uwsgi_legion_node *node = uwsgi_legion_get_lord(ul);
|
||||
if (node) {
|
||||
// a node is the best candidate
|
||||
best_valor = node->valor;
|
||||
memcpy(best_uuid, node->uuid, 36);
|
||||
}
|
||||
else {
|
||||
// no potential Lord is available, i will propose myself
|
||||
best_valor = ul->valor;
|
||||
memcpy(best_uuid, ul->uuid, 36);
|
||||
i_am_the_best = 1;
|
||||
}
|
||||
|
||||
// calculate the checksum
|
||||
uint64_t new_checksum = uwsgi_legion_checksum(ul);
|
||||
if (new_checksum != ul->checksum) {
|
||||
ul->changed = 1;
|
||||
}
|
||||
ul->checksum = new_checksum;
|
||||
|
||||
// ... ok let's see if all of the nodes agree on the lord
|
||||
// ... but first check if i am not alone...
|
||||
int votes = 1;
|
||||
struct uwsgi_legion_node *nodes = ul->nodes_head;
|
||||
while (nodes) {
|
||||
if (nodes->checksum != ul->checksum) {
|
||||
votes = 0;
|
||||
break;
|
||||
}
|
||||
if (nodes->lord_valor != best_valor) {
|
||||
votes = 0;
|
||||
break;
|
||||
}
|
||||
if (memcmp(nodes->lord_uuid, best_uuid, 36)) {
|
||||
votes = 0;
|
||||
break;
|
||||
}
|
||||
votes++;
|
||||
nodes = nodes->next;
|
||||
}
|
||||
|
||||
// we have quorum !!!
|
||||
if (votes > 0 && votes >= ul->quorum) {
|
||||
// something changed ???
|
||||
if (ul->changed) {
|
||||
legions_report_quorum(ul, best_valor, best_uuid, votes);
|
||||
ul->changed = 0;
|
||||
}
|
||||
if (i_am_the_best) {
|
||||
if (!ul->i_am_the_lord) {
|
||||
uwsgi_log("[uwsgi-legion] i am now the Lord of the Legion %s\n", ul->legion);
|
||||
// triggering lord hooks
|
||||
struct uwsgi_string_list *usl = ul->lord_hooks;
|
||||
while (usl) {
|
||||
int ret = uwsgi_legion_action_call("lord", ul, usl);
|
||||
if (ret) {
|
||||
uwsgi_log("[uwsgi-legion] ERROR, lord hook returned: %d\n", ret);
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
ul->i_am_the_lord = uwsgi_now();
|
||||
// trick: reduce the time needed by the old lord to unlord itself
|
||||
uwsgi_legion_announce(ul);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ul->i_am_the_lord) {
|
||||
uwsgi_log("[uwsgi-legion] a new Lord (valor: %llu uuid: %.*s) raised for Legion %s...\n", ul->lord_valor, 36, ul->lord_uuid, ul->legion);
|
||||
// no more lord, trigger unlord hooks
|
||||
struct uwsgi_string_list *usl = ul->unlord_hooks;
|
||||
while (usl) {
|
||||
int ret = uwsgi_legion_action_call("unlord", ul, usl);
|
||||
if (ret) {
|
||||
uwsgi_log("[uwsgi-legion] ERROR, unlord hook returned: %d\n", ret);
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
ul->i_am_the_lord = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (votes > 0 && votes < ul->quorum && (uwsgi_now() - ul->last_warning >= 60)) {
|
||||
uwsgi_log("[uwsgi-legion] no quorum: only %d vote(s) for Legion %s, %d needed to elect a Lord\n", votes, ul->legion, ul->quorum);
|
||||
ul->last_warning = uwsgi_now();
|
||||
}
|
||||
|
||||
ul = ul->next;
|
||||
}
|
||||
}
|
||||
|
||||
// check who should be the lord of the legion
|
||||
struct uwsgi_legion_node *uwsgi_legion_get_lord(struct uwsgi_legion *ul) {
|
||||
|
||||
char best_uuid[36];
|
||||
|
||||
memcpy(best_uuid, ul->uuid, 36);
|
||||
uint64_t best_valor = ul->valor;
|
||||
|
||||
struct uwsgi_legion_node *best_node = NULL;
|
||||
|
||||
struct uwsgi_legion_node *nodes = ul->nodes_head;
|
||||
while (nodes) {
|
||||
if (nodes->valor > best_valor) {
|
||||
best_node = nodes;
|
||||
best_valor = nodes->valor;
|
||||
memcpy(best_uuid, nodes->uuid, 36);
|
||||
}
|
||||
else if (nodes->valor == best_valor) {
|
||||
if (uwsgi_uuid_cmp(nodes->uuid, best_uuid) > 0) {
|
||||
best_node = nodes;
|
||||
best_valor = nodes->valor;
|
||||
memcpy(best_uuid, nodes->uuid, 36);
|
||||
}
|
||||
}
|
||||
nodes = nodes->next;
|
||||
}
|
||||
|
||||
// first round ?
|
||||
if (ul->lord_valor == 0) {
|
||||
ul->changed = 1;
|
||||
}
|
||||
else if (best_valor != ul->lord_valor) {
|
||||
ul->changed = 1;
|
||||
}
|
||||
else {
|
||||
if (memcmp(best_uuid, ul->lord_uuid, 36)) {
|
||||
ul->changed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
ul->lord_valor = best_valor;
|
||||
memcpy(ul->lord_uuid, best_uuid, 36);
|
||||
|
||||
return best_node;
|
||||
}
|
||||
|
||||
|
||||
static void *legion_loop(void *foobar) {
|
||||
|
||||
time_t last_round = uwsgi_now();
|
||||
|
||||
unsigned char *crypted_buf = uwsgi_malloc(UMAX16 - EVP_MAX_BLOCK_LENGTH - 4);
|
||||
unsigned char *clear_buf = uwsgi_malloc(UMAX16);
|
||||
|
||||
struct uwsgi_legion legion_msg;
|
||||
|
||||
if (!uwsgi.legion_freq)
|
||||
uwsgi.legion_freq = 3;
|
||||
if (!uwsgi.legion_tolerance)
|
||||
uwsgi.legion_tolerance = 15;
|
||||
if (!uwsgi.legion_skew_tolerance)
|
||||
uwsgi.legion_skew_tolerance = 60;
|
||||
|
||||
int first_round = 1;
|
||||
for (;;) {
|
||||
int timeout = uwsgi.legion_freq;
|
||||
time_t now = uwsgi_now();
|
||||
if (now > last_round) {
|
||||
timeout -= (now - last_round);
|
||||
if (timeout < 0) {
|
||||
timeout = 0;
|
||||
}
|
||||
}
|
||||
last_round = now;
|
||||
// wait for event
|
||||
int interesting_fd = -1;
|
||||
int rlen = event_queue_wait(uwsgi.legion_queue, timeout, &interesting_fd);
|
||||
|
||||
now = uwsgi_now();
|
||||
if (timeout == 0 || rlen == 0 || (now - last_round) >= timeout) {
|
||||
struct uwsgi_legion *legions = uwsgi.legions;
|
||||
while (legions) {
|
||||
uwsgi_legion_announce(legions);
|
||||
legions = legions->next;
|
||||
}
|
||||
last_round = now;
|
||||
}
|
||||
|
||||
// check the nodes
|
||||
legions_check_nodes();
|
||||
|
||||
if (rlen > 0) {
|
||||
struct uwsgi_legion *ul = uwsgi_legion_get_by_socket(interesting_fd);
|
||||
if (!ul)
|
||||
continue;
|
||||
// ensure the first 4 bytes are valid
|
||||
ssize_t len = read(ul->socket, crypted_buf, (UMAX16 - EVP_MAX_BLOCK_LENGTH - 4));
|
||||
if (len < 0) {
|
||||
uwsgi_error("[uwsgi-legion] read()");
|
||||
continue;
|
||||
}
|
||||
else if (len < 4) {
|
||||
uwsgi_log("[uwsgi-legion] invalid packet size: %d\n", (int) len);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct uwsgi_header *uh = (struct uwsgi_header *) crypted_buf;
|
||||
|
||||
if (uh->modifier1 != 109) {
|
||||
uwsgi_log("[uwsgi-legion] invalid modifier1");
|
||||
continue;
|
||||
}
|
||||
|
||||
int d_len = 0;
|
||||
int d2_len = 0;
|
||||
// decrypt packet using the secret
|
||||
if (EVP_DecryptInit_ex(ul->decrypt_ctx, NULL, NULL, NULL, NULL) <= 0) {
|
||||
uwsgi_error("[uwsgi-legion] EVP_DecryptInit_ex()");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (EVP_DecryptUpdate(ul->decrypt_ctx, clear_buf, &d_len, crypted_buf + 4, len - 4) <= 0) {
|
||||
uwsgi_error("[uwsgi-legion] EVP_DecryptUpdate()");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (EVP_DecryptFinal_ex(ul->decrypt_ctx, clear_buf + d_len, &d2_len) <= 0) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
uwsgi_log("[uwsgi-legion] EVP_DecryptFinal_ex()\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
d_len += d2_len;
|
||||
|
||||
if (d_len != uh->pktsize) {
|
||||
uwsgi_log("[uwsgi-legion] invalid packet size\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// parse packet
|
||||
memset(&legion_msg, 0, sizeof(struct uwsgi_legion));
|
||||
if (uwsgi_hooked_parse((char *) clear_buf, d_len, uwsgi_parse_legion, &legion_msg)) {
|
||||
uwsgi_log("[uwsgi-legion] invalid packet\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uwsgi_strncmp(ul->legion, ul->legion_len, legion_msg.legion, legion_msg.legion_len)) {
|
||||
uwsgi_log("[uwsgi-legion] invalid legion name\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// check for loop packets... (expecially when in multicast mode)
|
||||
if (!uwsgi_strncmp(uwsgi.hostname, uwsgi.hostname_len, legion_msg.name, legion_msg.name_len)) {
|
||||
if (legion_msg.pid == ul->pid) {
|
||||
if (legion_msg.valor == ul->valor) {
|
||||
if (!memcmp(legion_msg.uuid, ul->uuid, 36)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check for "tolerable" unix time
|
||||
if (legion_msg.unix_check < (uwsgi_now() - uwsgi.legion_skew_tolerance)) {
|
||||
uwsgi_log("[uwsgi-legion] untolerable packet received for Legion %s , check your clock !!!\n", ul->legion);
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if the node is already accounted
|
||||
struct uwsgi_legion_node *node = uwsgi_legion_get_node(ul, legion_msg.valor, legion_msg.name, legion_msg.name_len, legion_msg.uuid);
|
||||
if (!node) {
|
||||
// add the new node
|
||||
pthread_mutex_lock(&ul->lock);
|
||||
node = uwsgi_legion_add_node(ul, legion_msg.valor, legion_msg.name, legion_msg.name_len, legion_msg.uuid);
|
||||
pthread_mutex_unlock(&ul->lock);
|
||||
uwsgi_log("[uwsgi-legion] node: %.*s valor: %llu uuid: %.*s joined Legion %s\n", node->name_len, node->name, node->valor, 36, node->uuid, ul->legion);
|
||||
}
|
||||
|
||||
node->last_seen = uwsgi_now();
|
||||
node->lord_valor = legion_msg.lord_valor;
|
||||
node->checksum = legion_msg.checksum;
|
||||
memcpy(node->lord_uuid, legion_msg.lord_uuid, 36);
|
||||
|
||||
}
|
||||
|
||||
// skip the first round if i no packet is received
|
||||
if (first_round) {
|
||||
first_round = 0;
|
||||
continue;
|
||||
}
|
||||
legions_check_nodes_step2();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int uwsgi_legion_action_call(char *phase, struct uwsgi_legion *ul, struct uwsgi_string_list *usl) {
|
||||
struct uwsgi_legion_action *ula = uwsgi_legion_action_get(usl->custom_ptr);
|
||||
if (!ula) {
|
||||
uwsgi_log("[uwsgi-legion] ERROR unable to find legion_action \"%s\"\n", (char *) usl->custom_ptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_log("[uwsgi-legion] (phase: %s legion: %s) calling %s\n", phase, ul->legion, usl->value);
|
||||
return ula->func(ul, usl->value + usl->custom);
|
||||
}
|
||||
|
||||
static int legion_action_cmd(struct uwsgi_legion *ul, char *arg) {
|
||||
return uwsgi_run_command_and_wait(NULL, arg);
|
||||
}
|
||||
|
||||
static int legion_action_signal(struct uwsgi_legion *ul, char *arg) {
|
||||
return uwsgi_signal_send(uwsgi.signal_socket, atoi(arg));
|
||||
}
|
||||
|
||||
static int legion_action_log(struct uwsgi_legion *ul, char *arg) {
|
||||
char *logline = uwsgi_concat2(arg, "\n");
|
||||
uwsgi_log(logline);
|
||||
free(logline);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uwsgi_start_legions() {
|
||||
pthread_t legion_loop_t;
|
||||
|
||||
if (!uwsgi.legions)
|
||||
return;
|
||||
|
||||
// register embedded actions
|
||||
uwsgi_legion_action_register("cmd", legion_action_cmd);
|
||||
uwsgi_legion_action_register("signal", legion_action_signal);
|
||||
uwsgi_legion_action_register("log", legion_action_log);
|
||||
|
||||
uwsgi.legion_queue = event_queue_init();
|
||||
struct uwsgi_legion *legion = uwsgi.legions;
|
||||
while (legion) {
|
||||
char *colon = strchr(legion->addr, ':');
|
||||
if (colon) {
|
||||
legion->socket = bind_to_udp(legion->addr, 0, 0);
|
||||
}
|
||||
else {
|
||||
legion->socket = bind_to_unix_dgram(legion->addr);
|
||||
}
|
||||
if (legion->socket < 0 || event_queue_add_fd_read(uwsgi.legion_queue, legion->socket)) {
|
||||
uwsgi_log("[uwsgi-legion] unable to activate legion %s\n", legion->legion);
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_socket_nb(legion->socket);
|
||||
legion->pid = uwsgi.mypid;
|
||||
uwsgi_uuid(legion->uuid);
|
||||
struct uwsgi_string_list *usl = legion->setup_hooks;
|
||||
while (usl) {
|
||||
int ret = uwsgi_legion_action_call("setup", legion, usl);
|
||||
if (ret) {
|
||||
uwsgi_log("[uwsgi-legion] ERROR, setup hook returned: %d\n", ret);
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
legion = legion->next;
|
||||
}
|
||||
|
||||
#ifndef UWSGI_UUID
|
||||
uwsgi_log("WARNING: you are not using libuuid to generate Legions UUID\n");
|
||||
#endif
|
||||
|
||||
if (pthread_create(&legion_loop_t, NULL, legion_loop, NULL)) {
|
||||
uwsgi_error("pthread_create()");
|
||||
uwsgi_log("unable to run the legion server !!!\n");
|
||||
}
|
||||
else {
|
||||
uwsgi_log("legion manager thread enabled\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_legion_add(struct uwsgi_legion *ul) {
|
||||
struct uwsgi_legion *old_legion = NULL, *legion = uwsgi.legions;
|
||||
while (legion) {
|
||||
old_legion = legion;
|
||||
legion = legion->next;
|
||||
}
|
||||
|
||||
if (old_legion) {
|
||||
old_legion->next = ul;
|
||||
}
|
||||
else {
|
||||
uwsgi.legions = ul;
|
||||
}
|
||||
}
|
||||
|
||||
int uwsgi_legion_announce(struct uwsgi_legion *ul) {
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(4096);
|
||||
|
||||
if (uwsgi_buffer_append_keyval(ub, "legion", 6, ul->legion, ul->legion_len))
|
||||
goto err;
|
||||
if (uwsgi_buffer_append_keynum(ub, "valor", 5, ul->valor))
|
||||
goto err;
|
||||
if (uwsgi_buffer_append_keynum(ub, "unix", 4, uwsgi_now()))
|
||||
goto err;
|
||||
if (uwsgi_buffer_append_keynum(ub, "lord", 4, ul->i_am_the_lord ? ul->i_am_the_lord : 0))
|
||||
goto err;
|
||||
if (uwsgi_buffer_append_keyval(ub, "name", 4, uwsgi.hostname, uwsgi.hostname_len))
|
||||
goto err;
|
||||
if (uwsgi_buffer_append_keynum(ub, "pid", 3, ul->pid))
|
||||
goto err;
|
||||
if (uwsgi_buffer_append_keyval(ub, "uuid", 4, ul->uuid, 36))
|
||||
goto err;
|
||||
if (uwsgi_buffer_append_keynum(ub, "checksum", 8, ul->checksum))
|
||||
goto err;
|
||||
if (uwsgi_buffer_append_keynum(ub, "lord_valor", 10, ul->lord_valor))
|
||||
goto err;
|
||||
if (uwsgi_buffer_append_keyval(ub, "lord_uuid", 9, ul->lord_uuid, 36))
|
||||
goto err;
|
||||
#ifdef UWSGI_UUID
|
||||
#endif
|
||||
|
||||
unsigned char *encrypted = uwsgi_malloc(ub->pos + 4 + EVP_MAX_BLOCK_LENGTH);
|
||||
if (EVP_EncryptInit_ex(ul->encrypt_ctx, NULL, NULL, NULL, NULL) <= 0) {
|
||||
uwsgi_error("[uwsgi-legion] EVP_EncryptInit_ex()");
|
||||
goto err;
|
||||
}
|
||||
|
||||
int e_len = 0;
|
||||
|
||||
if (EVP_EncryptUpdate(ul->encrypt_ctx, encrypted + 4, &e_len, (unsigned char *) ub->buf, ub->pos) <= 0) {
|
||||
uwsgi_error("[uwsgi-legion] EVP_EncryptUpdate()");
|
||||
goto err;
|
||||
}
|
||||
|
||||
int tmplen = 0;
|
||||
if (EVP_EncryptFinal_ex(ul->encrypt_ctx, encrypted + 4 + e_len, &tmplen) <= 0) {
|
||||
uwsgi_error("[uwsgi-legion] EVP_EncryptFinal_ex()");
|
||||
goto err;
|
||||
}
|
||||
|
||||
e_len += tmplen;
|
||||
uint16_t pktsize = ub->pos;
|
||||
encrypted[0] = 109;
|
||||
encrypted[1] = (unsigned char) (pktsize & 0xff);
|
||||
encrypted[2] = (unsigned char) ((pktsize >> 8) & 0xff);
|
||||
encrypted[3] = 0;
|
||||
|
||||
struct uwsgi_string_list *usl = ul->nodes;
|
||||
while (usl) {
|
||||
if (sendto(ul->socket, encrypted, e_len + 4, 0, usl->custom_ptr, usl->custom) != e_len + 4) {
|
||||
uwsgi_error("[uwsgi-legion] sendto()");
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
uwsgi_buffer_destroy(ub);
|
||||
free(encrypted);
|
||||
return 0;
|
||||
err:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void uwsgi_opt_legion_node(char *opt, char *value, void *foobar) {
|
||||
|
||||
char *legion = uwsgi_str(value);
|
||||
|
||||
char *space = strchr(legion, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid legion-node syntax, must be <legion> <addr>\n");
|
||||
exit(1);
|
||||
}
|
||||
*space = 0;
|
||||
|
||||
struct uwsgi_legion *ul = uwsgi_legion_get_by_name(legion);
|
||||
if (!ul) {
|
||||
uwsgi_log("unknown legion: %s\n", legion);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct uwsgi_string_list *usl = uwsgi_string_new_list(&ul->nodes, space + 1);
|
||||
char *port = strchr(usl->value, ':');
|
||||
if (!port) {
|
||||
uwsgi_log("[uwsgi-legion] invalid udp address: %s\n", usl->value);
|
||||
exit(1);
|
||||
}
|
||||
// no need to zero the memory, socket_to_in_addr will do that
|
||||
struct sockaddr_in *sin = uwsgi_malloc(sizeof(struct sockaddr_in));
|
||||
usl->custom = socket_to_in_addr(usl->value, port, 0, sin);
|
||||
usl->custom_ptr = sin;
|
||||
}
|
||||
|
||||
void uwsgi_opt_legion_quorum(char *opt, char *value, void *foobar) {
|
||||
|
||||
char *legion = uwsgi_str(value);
|
||||
|
||||
char *space = strchr(legion, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid legion-quorum syntax, must be <legion> <quorum>\n");
|
||||
exit(1);
|
||||
}
|
||||
*space = 0;
|
||||
|
||||
struct uwsgi_legion *ul = uwsgi_legion_get_by_name(legion);
|
||||
if (!ul) {
|
||||
uwsgi_log("unknown legion: %s\n", legion);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ul->quorum = atoi(space+1);
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_opt_legion_hook(char *opt, char *value, void *foobar) {
|
||||
|
||||
char *legion = uwsgi_str(value);
|
||||
|
||||
char *space = strchr(legion, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid %s syntax, must be <legion> <action>\n", opt);
|
||||
exit(1);
|
||||
}
|
||||
*space = 0;
|
||||
|
||||
struct uwsgi_legion *ul = uwsgi_legion_get_by_name(legion);
|
||||
if (!ul) {
|
||||
uwsgi_log("unknown legion: %s\n", legion);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct uwsgi_string_list *usl = NULL;
|
||||
|
||||
if (!strcmp(opt, "legion-lord")) {
|
||||
usl = uwsgi_string_new_list(&ul->lord_hooks, space + 1);
|
||||
}
|
||||
else if (!strcmp(opt, "legion-unlord")) {
|
||||
usl = uwsgi_string_new_list(&ul->unlord_hooks, space + 1);
|
||||
}
|
||||
else if (!strcmp(opt, "legion-setup")) {
|
||||
usl = uwsgi_string_new_list(&ul->setup_hooks, space + 1);
|
||||
}
|
||||
else if (!strcmp(opt, "legion-death")) {
|
||||
usl = uwsgi_string_new_list(&ul->death_hooks, space + 1);
|
||||
}
|
||||
|
||||
if (!usl)
|
||||
return;
|
||||
|
||||
char *port = strchr(usl->value, ':');
|
||||
if (!port) {
|
||||
uwsgi_log("[uwsgi-legion] invalid %s action: %s\n", opt, usl->value);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// pointer to action plugin
|
||||
usl->custom_ptr = uwsgi_concat2n(usl->value, port - usl->value, "", 0);
|
||||
// add that to check the plugin value
|
||||
usl->custom = port - usl->value + 1;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_opt_legion(char *opt, char *value, void *foobar) {
|
||||
|
||||
// legion addr valor algo:secret
|
||||
char *legion = uwsgi_str(value);
|
||||
char *space = strchr(legion, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid legion syntax, must be <legion> <addr> <valor> <algo:secret>\n");
|
||||
exit(1);
|
||||
}
|
||||
*space = 0;
|
||||
char *addr = space + 1;
|
||||
|
||||
space = strchr(addr, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid legion syntax, must be <legion> <addr> <valor> <algo:secret>\n");
|
||||
exit(1);
|
||||
}
|
||||
*space = 0;
|
||||
char *valor = space + 1;
|
||||
|
||||
space = strchr(valor, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid legion syntax, must be <legion> <addr> <valor> <algo:secret>\n");
|
||||
exit(1);
|
||||
}
|
||||
*space = 0;
|
||||
char *algo_secret = space + 1;
|
||||
|
||||
char *colon = strchr(algo_secret, ':');
|
||||
if (!colon) {
|
||||
uwsgi_log("invalid legion syntax, must be <legion> <addr> <valor> <algo:secret>\n");
|
||||
exit(1);
|
||||
}
|
||||
*colon = 0;
|
||||
char *secret = colon + 1;
|
||||
|
||||
char *iv = strchr(secret, ' ');
|
||||
if (iv) {
|
||||
*iv = 0;
|
||||
iv++;
|
||||
}
|
||||
|
||||
if (!uwsgi.ssl_initialized) {
|
||||
uwsgi_ssl_init();
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX *ctx = uwsgi_malloc(sizeof(EVP_CIPHER_CTX));
|
||||
EVP_CIPHER_CTX_init(ctx);
|
||||
|
||||
const EVP_CIPHER *cipher = EVP_get_cipherbyname(algo_secret);
|
||||
if (!cipher) {
|
||||
uwsgi_log("[uwsgi-legion] unable to find algorithm/cipher %s\n", algo_secret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int cipher_len = EVP_CIPHER_key_length(cipher);
|
||||
size_t s_len = strlen(secret);
|
||||
if ((unsigned int) cipher_len > s_len) {
|
||||
char *secret_tmp = uwsgi_malloc(cipher_len);
|
||||
memcpy(secret_tmp, secret, s_len);
|
||||
memset(secret_tmp + s_len, 0, cipher_len - s_len);
|
||||
secret = secret_tmp;
|
||||
}
|
||||
|
||||
int iv_len = EVP_CIPHER_iv_length(cipher);
|
||||
size_t s_iv_len = 0;
|
||||
if (iv) {
|
||||
s_iv_len = strlen(iv);
|
||||
}
|
||||
if ((unsigned int) iv_len > s_iv_len) {
|
||||
char *secret_tmp = uwsgi_malloc(iv_len);
|
||||
memcpy(secret_tmp, iv, s_iv_len);
|
||||
memset(secret_tmp + s_iv_len, '0', iv_len - s_iv_len);
|
||||
iv = secret_tmp;
|
||||
}
|
||||
|
||||
if (EVP_EncryptInit_ex(ctx, cipher, NULL, (const unsigned char *) secret, (const unsigned char *) iv) <= 0) {
|
||||
uwsgi_error("EVP_EncryptInit_ex()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX *ctx2 = uwsgi_malloc(sizeof(EVP_CIPHER_CTX));
|
||||
EVP_CIPHER_CTX_init(ctx2);
|
||||
|
||||
if (EVP_DecryptInit_ex(ctx2, cipher, NULL, (const unsigned char *) secret, (const unsigned char *) iv) <= 0) {
|
||||
uwsgi_error("EVP_DecryptInit_ex()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// we use shared memory, as we want to export legion status to the api
|
||||
struct uwsgi_legion *ul = uwsgi_calloc_shared(sizeof(struct uwsgi_legion));
|
||||
ul->legion = legion;
|
||||
ul->legion_len = strlen(ul->legion);
|
||||
|
||||
ul->valor = strtol(valor, (char **) NULL, 10);
|
||||
ul->addr = addr;
|
||||
|
||||
ul->encrypt_ctx = ctx;
|
||||
ul->decrypt_ctx = ctx2;
|
||||
|
||||
pthread_mutex_init(&ul->lock, NULL);
|
||||
|
||||
uwsgi_legion_add(ul);
|
||||
}
|
||||
|
||||
struct uwsgi_legion_action *uwsgi_legion_action_get(char *name) {
|
||||
struct uwsgi_legion_action *ula = uwsgi.legion_actions;
|
||||
while (ula) {
|
||||
if (!strcmp(name, ula->name)) {
|
||||
return ula;
|
||||
}
|
||||
ula = ula->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void uwsgi_legion_action_register(char *name, int (*func) (struct uwsgi_legion *, char *)) {
|
||||
if (uwsgi_legion_action_get(name)) {
|
||||
uwsgi_log("[uwsgi-legion] action \"%s\" is already registered !!!\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
struct uwsgi_legion_action *old_ula = NULL, *ula = uwsgi.legion_actions;
|
||||
while (ula) {
|
||||
old_ula = ula;
|
||||
ula = ula->next;
|
||||
}
|
||||
|
||||
ula = uwsgi_calloc(sizeof(struct uwsgi_legion_action));
|
||||
ula->name = name;
|
||||
ula->func = func;
|
||||
|
||||
if (old_ula) {
|
||||
old_ula->next = ula;
|
||||
}
|
||||
else {
|
||||
uwsgi.legion_actions = ula;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_legion_atexit(void) {
|
||||
struct uwsgi_legion *legion = uwsgi.legions;
|
||||
while (legion) {
|
||||
if (getpid() != legion->pid)
|
||||
goto next;
|
||||
struct uwsgi_string_list *usl = legion->death_hooks;
|
||||
while (usl) {
|
||||
int ret = uwsgi_legion_action_call("death", legion, usl);
|
||||
if (ret) {
|
||||
uwsgi_log("[uwsgi-legion] ERROR, death hook returned: %d\n", ret);
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
next:
|
||||
legion = legion->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_legion_i_am_the_lord(char *name) {
|
||||
struct uwsgi_legion *legion = uwsgi_legion_get_by_name(name);
|
||||
if (legion && legion->i_am_the_lord) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+36
-4
@@ -45,6 +45,10 @@ static struct uwsgi_lock_item *uwsgi_register_lock(char *id, int rw) {
|
||||
|
||||
#ifdef UWSGI_LOCK_USE_MUTEX
|
||||
|
||||
#ifdef OBSOLETE_LINUX_KERNEL
|
||||
#undef EOWNERDEAD
|
||||
#endif
|
||||
|
||||
#ifdef EOWNERDEAD
|
||||
#define UWSGI_LOCK_ENGINE_NAME "pthread robust mutexes"
|
||||
int uwsgi_pthread_robust_mutexes_enabled = 1;
|
||||
@@ -60,6 +64,12 @@ int uwsgi_pthread_robust_mutexes_enabled = 1;
|
||||
#define UWSGI_RWLOCK_SIZE sizeof(pthread_rwlock_t)
|
||||
#endif
|
||||
|
||||
#ifndef PTHREAD_PRIO_INHERIT
|
||||
int pthread_mutexattr_setprotocol (pthread_mutexattr_t *__attr,
|
||||
int __protocol);
|
||||
#define PTHREAD_PRIO_INHERIT 1
|
||||
#endif
|
||||
|
||||
// REMEMBER lock must contains space for both pthread_mutex_t and pthread_mutexattr_t !!!
|
||||
struct uwsgi_lock_item *uwsgi_lock_fast_init(char *id) {
|
||||
|
||||
@@ -81,8 +91,15 @@ retry:
|
||||
}
|
||||
|
||||
#ifdef EOWNERDEAD
|
||||
#ifndef PTHREAD_MUTEX_ROBUST
|
||||
#define PTHREAD_MUTEX_ROBUST PTHREAD_MUTEX_ROBUST_NP
|
||||
#endif
|
||||
if (pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT)) {
|
||||
uwsgi_log("unable to set PTHREAD_PRIO_INHERIT\n");
|
||||
exit(1);
|
||||
}
|
||||
if (uwsgi_pthread_robust_mutexes_enabled) {
|
||||
if (pthread_mutexattr_setrobust_np(&attr, PTHREAD_MUTEX_ROBUST_NP)) {
|
||||
if (pthread_mutexattr_setrobust_np(&attr, PTHREAD_MUTEX_ROBUST)) {
|
||||
uwsgi_log("unable to make the mutex 'robust'\n");
|
||||
exit(1);
|
||||
}
|
||||
@@ -460,7 +477,9 @@ void uwsgi_lock_ipcsem(struct uwsgi_lock_item *uli) {
|
||||
|
||||
memcpy(&semid, uli->lock_ptr, sizeof(int));
|
||||
|
||||
retry:
|
||||
if (semop(semid, &sb, 1)) {
|
||||
if (errno == EINTR) goto retry;
|
||||
uwsgi_error("semop()");
|
||||
}
|
||||
}
|
||||
@@ -475,7 +494,9 @@ void uwsgi_unlock_ipcsem(struct uwsgi_lock_item *uli) {
|
||||
|
||||
memcpy(&semid, uli->lock_ptr, sizeof(int));
|
||||
|
||||
retry:
|
||||
if (semop(semid, &sb, 1)) {
|
||||
if (errno == EINTR) goto retry;
|
||||
uwsgi_error("semop()");
|
||||
}
|
||||
|
||||
@@ -540,6 +561,10 @@ pid_t uwsgi_rwlock_ipcsem_check(struct uwsgi_lock_item *uli) {
|
||||
|
||||
void uwsgi_setup_locking() {
|
||||
|
||||
int i;
|
||||
|
||||
if (uwsgi.locking_setup) return;
|
||||
|
||||
// use the fastest available locking
|
||||
if (uwsgi.lock_engine) {
|
||||
if (!strcmp(uwsgi.lock_engine, "ipcsem")) {
|
||||
@@ -556,8 +581,10 @@ void uwsgi_setup_locking() {
|
||||
uwsgi.lock_ops.rwunlock = uwsgi_rwunlock_ipcsem;
|
||||
uwsgi.lock_size = 8;
|
||||
uwsgi.rwlock_size = 8;
|
||||
return;
|
||||
goto ready;
|
||||
}
|
||||
uwsgi_log("unable to find lock engine \"%s\"\n", uwsgi.lock_engine);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_log_initial("lock engine: %s\n", UWSGI_LOCK_ENGINE_NAME);
|
||||
@@ -576,8 +603,8 @@ void uwsgi_setup_locking() {
|
||||
uwsgi.lock_size = UWSGI_LOCK_SIZE;
|
||||
uwsgi.rwlock_size = UWSGI_RWLOCK_SIZE;
|
||||
|
||||
ready:
|
||||
// application generic lock
|
||||
int i;
|
||||
uwsgi.user_lock = uwsgi_malloc(sizeof(void *) * (uwsgi.locks + 1));
|
||||
for (i = 0; i < uwsgi.locks + 1; i++) {
|
||||
uwsgi.user_lock[i] = uwsgi_lock_init(uwsgi_concat2("user ", uwsgi_num2str(i)));
|
||||
@@ -608,8 +635,13 @@ void uwsgi_setup_locking() {
|
||||
uwsgi.cron_table_lock = uwsgi_lock_init("cron");
|
||||
}
|
||||
|
||||
uwsgi.rpc_table_lock = uwsgi_lock_init("rpc");
|
||||
if (uwsgi.use_thunder_lock) {
|
||||
// process shared thunder lock
|
||||
uwsgi.the_thunder_lock = uwsgi_lock_init("thunder");
|
||||
}
|
||||
|
||||
uwsgi.rpc_table_lock = uwsgi_lock_init("rpc");
|
||||
uwsgi.locking_setup = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+498
-80
@@ -144,6 +144,21 @@ void create_logpipe(void) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (uwsgi.req_log_master) {
|
||||
#if defined(SOCK_SEQPACKET) && defined(__linux__)
|
||||
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, uwsgi.shared->worker_req_log_pipe)) {
|
||||
#else
|
||||
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, uwsgi.shared->worker_req_log_pipe)) {
|
||||
#endif
|
||||
uwsgi_error("socketpair()\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_socket_nb(uwsgi.shared->worker_req_log_pipe[0]);
|
||||
uwsgi_socket_nb(uwsgi.shared->worker_req_log_pipe[1]);
|
||||
uwsgi.req_log_fd = uwsgi.shared->worker_req_log_pipe[1];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
@@ -194,7 +209,6 @@ void logto(char *logfile) {
|
||||
|
||||
int fd;
|
||||
|
||||
#ifdef UWSGI_UDP
|
||||
char *udp_port;
|
||||
struct sockaddr_in udp_addr;
|
||||
|
||||
@@ -230,7 +244,6 @@ void logto(char *logfile) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
if (uwsgi.log_truncate) {
|
||||
fd = open(logfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP);
|
||||
}
|
||||
@@ -248,9 +261,7 @@ void logto(char *logfile) {
|
||||
uwsgi_error("chmod()");
|
||||
}
|
||||
}
|
||||
#ifdef UWSGI_UDP
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* stdout */
|
||||
@@ -294,62 +305,71 @@ void uwsgi_setup_log() {
|
||||
|
||||
}
|
||||
|
||||
static struct uwsgi_logger *setup_choosen_logger(struct uwsgi_string_list *usl) {
|
||||
char *id = NULL;
|
||||
char *name = usl->value;
|
||||
|
||||
char *space = strchr(name, ' ');
|
||||
if (space) {
|
||||
int is_id = 1;
|
||||
int i;
|
||||
for (i = 0; i < (space - name); i++) {
|
||||
if (!isalnum(name[i])) {
|
||||
is_id = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_id) {
|
||||
id = uwsgi_concat2n(name, space - name, "", 0);
|
||||
name = space + 1;
|
||||
}
|
||||
}
|
||||
|
||||
char *colon = strchr(name, ':');
|
||||
if (colon) {
|
||||
*colon = 0;
|
||||
}
|
||||
|
||||
struct uwsgi_logger *choosen_logger = uwsgi_get_logger(name);
|
||||
if (!choosen_logger) {
|
||||
uwsgi_log("unable to find logger %s\n", name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// make a copy of the logger
|
||||
struct uwsgi_logger *copy_of_choosen_logger = uwsgi_malloc(sizeof(struct uwsgi_logger));
|
||||
memcpy(copy_of_choosen_logger, choosen_logger, sizeof(struct uwsgi_logger));
|
||||
choosen_logger = copy_of_choosen_logger;
|
||||
choosen_logger->id = id;
|
||||
choosen_logger->next = NULL;
|
||||
|
||||
if (colon) {
|
||||
choosen_logger->arg = colon + 1;
|
||||
// check for empty string
|
||||
if (*choosen_logger->arg == 0) {
|
||||
choosen_logger->arg = NULL;
|
||||
}
|
||||
*colon = ':';
|
||||
}
|
||||
return choosen_logger;
|
||||
}
|
||||
|
||||
void uwsgi_setup_log_master(void) {
|
||||
|
||||
struct uwsgi_string_list *usl = uwsgi.requested_logger;
|
||||
while (usl) {
|
||||
char *id = NULL;
|
||||
char *name = usl->value;
|
||||
|
||||
char *space = strchr(name, ' ');
|
||||
if (space) {
|
||||
int is_id = 1;
|
||||
int i;
|
||||
for (i = 0; i < (space - name); i++) {
|
||||
if (!isalnum(name[i])) {
|
||||
is_id = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_id) {
|
||||
id = uwsgi_concat2n(name, space - name, "", 0);
|
||||
name = space + 1;
|
||||
}
|
||||
}
|
||||
|
||||
char *colon = strchr(name, ':');
|
||||
if (colon) {
|
||||
*colon = 0;
|
||||
}
|
||||
|
||||
struct uwsgi_logger *choosen_logger = uwsgi_get_logger(name);
|
||||
if (!choosen_logger) {
|
||||
uwsgi_log("unable to find logger %s\n", name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// make a copy of the logger
|
||||
struct uwsgi_logger *copy_of_choosen_logger = uwsgi_malloc(sizeof(struct uwsgi_logger));
|
||||
memcpy(copy_of_choosen_logger, choosen_logger, sizeof(struct uwsgi_logger));
|
||||
choosen_logger = copy_of_choosen_logger;
|
||||
choosen_logger->id = id;
|
||||
choosen_logger->next = NULL;
|
||||
|
||||
if (colon) {
|
||||
choosen_logger->arg = colon + 1;
|
||||
// check for empty string
|
||||
if (*choosen_logger->arg == 0) {
|
||||
choosen_logger->arg = NULL;
|
||||
}
|
||||
*colon = ':';
|
||||
}
|
||||
|
||||
struct uwsgi_logger *choosen_logger = setup_choosen_logger(usl);
|
||||
uwsgi_append_logger(choosen_logger);
|
||||
|
||||
usl = usl->next;
|
||||
|
||||
}
|
||||
|
||||
usl = uwsgi.requested_req_logger;
|
||||
while (usl) {
|
||||
struct uwsgi_logger *choosen_logger = setup_choosen_logger(usl);
|
||||
uwsgi_append_req_logger(choosen_logger);
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
// set logger by its id
|
||||
struct uwsgi_regexp_list *url = uwsgi.log_route;
|
||||
@@ -357,6 +377,11 @@ void uwsgi_setup_log_master(void) {
|
||||
url->custom_ptr = uwsgi_get_logger_from_id(url->custom_str);
|
||||
url = url->next;
|
||||
}
|
||||
url = uwsgi.log_req_route;
|
||||
while (url) {
|
||||
url->custom_ptr = uwsgi_get_logger_from_id(url->custom_str);
|
||||
url = url->next;
|
||||
}
|
||||
#endif
|
||||
|
||||
uwsgi.original_log_fd = dup(1);
|
||||
@@ -458,13 +483,13 @@ void uwsgi_check_logrotate(void) {
|
||||
uwsgi_error_open(uwsgi.logfile);
|
||||
grace_them_all(0);
|
||||
}
|
||||
if (dup2(fd, uwsgi.original_log_fd) < 0) {
|
||||
uwsgi_error("dup2()");
|
||||
grace_them_all(0);
|
||||
else {
|
||||
if (dup2(fd, uwsgi.original_log_fd) < 0) {
|
||||
uwsgi_error("dup2()");
|
||||
grace_them_all(0);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
}
|
||||
else {
|
||||
uwsgi_error("unable to rotate log: rename()");
|
||||
@@ -527,7 +552,7 @@ void log_request(struct wsgi_request *wsgi_req) {
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_LOG_BIG] && (wsgi_req->response_size >= uwsgi.shared->options[UWSGI_OPTION_LOG_BIG])) {
|
||||
goto logit;
|
||||
}
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_LOG_SENDFILE] && (wsgi_req->sendfile_fd > -1 && wsgi_req->sendfile_obj == wsgi_req->async_result)) {
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_LOG_SENDFILE] && wsgi_req->via == UWSGI_VIA_SENDFILE) {
|
||||
goto logit;
|
||||
}
|
||||
|
||||
@@ -572,16 +597,19 @@ void uwsgi_logit_simple(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
}
|
||||
|
||||
if (wsgi_req->sendfile_fd > -1 && wsgi_req->sendfile_obj == wsgi_req->async_result) { //wsgi_req->sendfile_fd_size > 0 ) {
|
||||
via = msg1;
|
||||
}
|
||||
|
||||
// mark route() requests
|
||||
if (wsgi_req->status == -17) {
|
||||
via = msg3;
|
||||
}
|
||||
else if (wsgi_req->status == -30) {
|
||||
via = msg4;
|
||||
// mark requests via (sendfile, route, offload...)
|
||||
switch(wsgi_req->via) {
|
||||
case UWSGI_VIA_SENDFILE:
|
||||
via = msg1;
|
||||
break;
|
||||
case UWSGI_VIA_ROUTE:
|
||||
via = msg3;
|
||||
break;
|
||||
case UWSGI_VIA_OFFLOAD:
|
||||
via = msg4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef __sun__
|
||||
@@ -622,11 +650,13 @@ void uwsgi_logit_simple(struct wsgi_request *wsgi_req) {
|
||||
|
||||
}
|
||||
|
||||
rlen = snprintf(logpkt, 4096, "[pid: %d|app: %d|req: %d/%llu] %.*s (%.*s) {%d vars in %d bytes} [%.*s] %.*s %.*s => generated %llu bytes in %llu %s%s(%.*s %d) %d headers in %llu bytes (%d switches on core %d)\n", (int) uwsgi.mypid, wsgi_req->app_id, app_req, (unsigned long long) uwsgi.workers[0].requests, wsgi_req->remote_addr_len, wsgi_req->remote_addr, wsgi_req->remote_user_len, wsgi_req->remote_user, wsgi_req->var_cnt, wsgi_req->uh.pktsize, 24, time_request, wsgi_req->method_len, wsgi_req->method, wsgi_req->uri_len, wsgi_req->uri, (unsigned long long) wsgi_req->response_size, (unsigned long long) rt, tsize, via, wsgi_req->protocol_len, wsgi_req->protocol, wsgi_req->status, wsgi_req->header_cnt, (unsigned long long) wsgi_req->headers_size, wsgi_req->switches, wsgi_req->async_id);
|
||||
rlen = snprintf(logpkt, 4096, "[pid: %d|app: %d|req: %d/%llu] %.*s (%.*s) {%d vars in %d bytes} [%.*s] %.*s %.*s => generated %llu bytes in %llu %s%s(%.*s %d) %d headers in %llu bytes (%d switches on core %d)\n", (int) uwsgi.mypid, wsgi_req->app_id, app_req, (unsigned long long) uwsgi.workers[0].requests, wsgi_req->remote_addr_len, wsgi_req->remote_addr, wsgi_req->remote_user_len, wsgi_req->remote_user, wsgi_req->var_cnt, wsgi_req->uh->pktsize,
|
||||
24, time_request, wsgi_req->method_len, wsgi_req->method, wsgi_req->uri_len, wsgi_req->uri, (unsigned long long) wsgi_req->response_size, (unsigned long long) rt, tsize, via, wsgi_req->protocol_len, wsgi_req->protocol, wsgi_req->status, wsgi_req->header_cnt, (unsigned long long) wsgi_req->headers_size, wsgi_req->switches, wsgi_req->async_id);
|
||||
|
||||
// not enough space for logging the request, just log a (safe) minimal message
|
||||
if (rlen > 4096) {
|
||||
rlen = snprintf(logpkt, 4096, "[pid: %d|app: %d|req: %d/%llu] 0.0.0.0 () {%d vars in %d bytes} [%.*s] - - => generated %llu bytes in %llu %s%s(- %d) %d headers in %llu bytes (%d switches on core %d)\n", (int) uwsgi.mypid, wsgi_req->app_id, app_req, (unsigned long long) uwsgi.workers[0].requests, wsgi_req->var_cnt, wsgi_req->uh.pktsize, 24, time_request, (unsigned long long) wsgi_req->response_size, (unsigned long long) rt, tsize, via, wsgi_req->status, wsgi_req->header_cnt, (unsigned long long) wsgi_req->headers_size, wsgi_req->switches, wsgi_req->async_id);
|
||||
rlen = snprintf(logpkt, 4096, "[pid: %d|app: %d|req: %d/%llu] 0.0.0.0 () {%d vars in %d bytes} [%.*s] - - => generated %llu bytes in %llu %s%s(- %d) %d headers in %llu bytes (%d switches on core %d)\n", (int) uwsgi.mypid, wsgi_req->app_id, app_req, (unsigned long long) uwsgi.workers[0].requests, wsgi_req->var_cnt, wsgi_req->uh->pktsize,
|
||||
24, time_request, (unsigned long long) wsgi_req->response_size, (unsigned long long) rt, tsize, via, wsgi_req->status, wsgi_req->header_cnt, (unsigned long long) wsgi_req->headers_size, wsgi_req->switches, wsgi_req->async_id);
|
||||
// argh, last resort, truncate it
|
||||
if (rlen > 4096) {
|
||||
rlen = 4096;
|
||||
@@ -637,7 +667,7 @@ void uwsgi_logit_simple(struct wsgi_request *wsgi_req) {
|
||||
logvec[logvecpos].iov_len = rlen;
|
||||
|
||||
// do not check for errors
|
||||
rlen = writev(2, logvec, logvecpos + 1);
|
||||
rlen = writev(uwsgi.req_log_fd, logvec, logvecpos + 1);
|
||||
}
|
||||
|
||||
void get_memusage(uint64_t * rss, uint64_t * vsz) {
|
||||
@@ -761,6 +791,7 @@ void uwsgi_register_logger(char *name, ssize_t(*func) (struct uwsgi_logger *, ch
|
||||
ul->configured = 0;
|
||||
ul->fd = -1;
|
||||
ul->data = NULL;
|
||||
ul->buf = NULL;
|
||||
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
@@ -785,6 +816,24 @@ void uwsgi_append_logger(struct uwsgi_logger *ul) {
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_append_req_logger(struct uwsgi_logger *ul) {
|
||||
|
||||
if (!uwsgi.choosen_req_logger) {
|
||||
uwsgi.choosen_req_logger = ul;
|
||||
return;
|
||||
}
|
||||
|
||||
struct uwsgi_logger *ucl = uwsgi.choosen_req_logger;
|
||||
while (ucl) {
|
||||
if (!ucl->next) {
|
||||
ucl->next = ul;
|
||||
return;
|
||||
}
|
||||
ucl = ucl->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_logger *uwsgi_get_logger(char *name) {
|
||||
struct uwsgi_logger *ul = uwsgi.loggers;
|
||||
|
||||
@@ -815,6 +864,7 @@ struct uwsgi_logger *uwsgi_get_logger_from_id(char *id) {
|
||||
void uwsgi_logit_lf(struct wsgi_request *wsgi_req) {
|
||||
struct uwsgi_logchunk *logchunk = uwsgi.logchunks;
|
||||
ssize_t rlen = 0;
|
||||
const char *empty_var = "-";
|
||||
while (logchunk) {
|
||||
int pos = logchunk->vec;
|
||||
// raw string
|
||||
@@ -851,18 +901,25 @@ void uwsgi_logit_lf(struct wsgi_request *wsgi_req) {
|
||||
uwsgi.logvectors[wsgi_req->async_id][pos].iov_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.logvectors[wsgi_req->async_id][pos].iov_len == 0 && logchunk->type != 0) {
|
||||
uwsgi.logvectors[wsgi_req->async_id][pos].iov_base = (char *) empty_var;
|
||||
uwsgi.logvectors[wsgi_req->async_id][pos].iov_len = 1;
|
||||
}
|
||||
logchunk = logchunk->next;
|
||||
}
|
||||
|
||||
// do not check for errors
|
||||
rlen = writev(2, uwsgi.logvectors[wsgi_req->async_id], uwsgi.logformat_vectors);
|
||||
rlen = writev(uwsgi.req_log_fd, uwsgi.logvectors[wsgi_req->async_id], uwsgi.logformat_vectors);
|
||||
|
||||
// free allocated memory
|
||||
logchunk = uwsgi.logchunks;
|
||||
while (logchunk) {
|
||||
if (logchunk->free) {
|
||||
if (uwsgi.logvectors[wsgi_req->async_id][logchunk->vec].iov_len > 0) {
|
||||
free(uwsgi.logvectors[wsgi_req->async_id][logchunk->vec].iov_base);
|
||||
if (uwsgi.logvectors[wsgi_req->async_id][logchunk->vec].iov_base != empty_var) {
|
||||
free(uwsgi.logvectors[wsgi_req->async_id][logchunk->vec].iov_base);
|
||||
}
|
||||
}
|
||||
}
|
||||
logchunk = logchunk->next;
|
||||
@@ -923,17 +980,39 @@ void uwsgi_build_log_format(char *format) {
|
||||
|
||||
}
|
||||
|
||||
ssize_t uwsgi_lf_status(struct wsgi_request *wsgi_req, char **buf) {
|
||||
static ssize_t uwsgi_lf_status(struct wsgi_request *wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(wsgi_req->status);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
ssize_t uwsgi_lf_epoch(struct wsgi_request * wsgi_req, char **buf) {
|
||||
|
||||
static ssize_t uwsgi_lf_rsize(struct wsgi_request *wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(wsgi_req->response_size);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_hsize(struct wsgi_request *wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(wsgi_req->headers_size);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_size(struct wsgi_request *wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(wsgi_req->headers_size+wsgi_req->response_size);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_cl(struct wsgi_request *wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(wsgi_req->post_cl);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uwsgi_lf_epoch(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(uwsgi_now());
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
ssize_t uwsgi_lf_ctime(struct wsgi_request * wsgi_req, char **buf) {
|
||||
static ssize_t uwsgi_lf_ctime(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_malloc(26);
|
||||
#ifdef __sun__
|
||||
ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, *buf, 26);
|
||||
@@ -943,23 +1022,98 @@ ssize_t uwsgi_lf_ctime(struct wsgi_request * wsgi_req, char **buf) {
|
||||
return 24;
|
||||
}
|
||||
|
||||
ssize_t uwsgi_lf_time(struct wsgi_request * wsgi_req, char **buf) {
|
||||
static ssize_t uwsgi_lf_time(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(wsgi_req->start_of_request / 1000000);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uwsgi_lf_ltime(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_malloc(64);
|
||||
time_t now = wsgi_req->start_of_request / 1000000;
|
||||
size_t ret = strftime(*buf, 64, "%d/%b/%Y:%H:%M:%S %z", localtime(&now));
|
||||
if (ret == 0) {
|
||||
*buf[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t uwsgi_lf_micros(struct wsgi_request * wsgi_req, char **buf) {
|
||||
|
||||
static ssize_t uwsgi_lf_micros(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(wsgi_req->end_of_request - wsgi_req->start_of_request);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
ssize_t uwsgi_lf_msecs(struct wsgi_request * wsgi_req, char **buf) {
|
||||
static ssize_t uwsgi_lf_msecs(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str((wsgi_req->end_of_request - wsgi_req->start_of_request) / 1000);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_pid(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(uwsgi.mypid);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_wid(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(uwsgi.mywid);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_switches(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(wsgi_req->switches);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_vars(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(wsgi_req->var_cnt);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_core(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(wsgi_req->async_id);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_vsz(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(uwsgi.workers[uwsgi.mywid].vsz_size);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_rss(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(uwsgi.workers[uwsgi.mywid].rss_size);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_vszM(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(uwsgi.workers[uwsgi.mywid].vsz_size / 1024 / 1024);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_rssM(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(uwsgi.workers[uwsgi.mywid].rss_size / 1024 / 1024);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_pktsize(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(wsgi_req->uh->pktsize);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_modifier1(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(wsgi_req->uh->modifier1);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_modifier2(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(wsgi_req->uh->modifier2);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_headers(struct wsgi_request * wsgi_req, char **buf) {
|
||||
*buf = uwsgi_num2str(wsgi_req->header_cnt);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
||||
void uwsgi_add_logchunk(int variable, int pos, char *ptr, size_t len) {
|
||||
|
||||
@@ -1018,11 +1172,39 @@ void uwsgi_add_logchunk(int variable, int pos, char *ptr, size_t len) {
|
||||
logchunk->pos = offsetof(struct wsgi_request, protocol);
|
||||
logchunk->pos_len = offsetof(struct wsgi_request, protocol_len);
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "uagent", 6)) {
|
||||
logchunk->pos = offsetof(struct wsgi_request, user_agent);
|
||||
logchunk->pos_len = offsetof(struct wsgi_request, user_agent_len);
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "referer", 7)) {
|
||||
logchunk->pos = offsetof(struct wsgi_request, referer);
|
||||
logchunk->pos_len = offsetof(struct wsgi_request, referer_len);
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "status", 6)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_status;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "rsize", 5)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_rsize;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "hsize", 5)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_hsize;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "size", 4)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_size;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "cl", 2)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_cl;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "micros", 6)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_micros;
|
||||
@@ -1038,6 +1220,11 @@ void uwsgi_add_logchunk(int variable, int pos, char *ptr, size_t len) {
|
||||
logchunk->func = uwsgi_lf_time;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "ltime", 5)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_ltime;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "ctime", 5)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_ctime;
|
||||
@@ -1048,9 +1235,240 @@ void uwsgi_add_logchunk(int variable, int pos, char *ptr, size_t len) {
|
||||
logchunk->func = uwsgi_lf_epoch;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "pid", 3)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_pid;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "wid", 3)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_wid;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "switches", 8)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_switches;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "vars", 4)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_vars;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "core", 4)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_core;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "vsz", 3)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_vsz;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "rss", 3)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_rss;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "vszM", 4)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_vszM;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "rssM", 4)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_rssM;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "pktsize", 7)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_pktsize;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "modifier1", 9)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_modifier1;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "modifier2", 9)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_modifier2;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_strncmp(ptr, len, "headers", 7)) {
|
||||
logchunk->type = 3;
|
||||
logchunk->func = uwsgi_lf_headers;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
// logvar
|
||||
else {
|
||||
logchunk->type = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int uwsgi_master_log(void) {
|
||||
|
||||
ssize_t rlen = read(uwsgi.shared->worker_log_pipe[0], uwsgi.log_master_buf, uwsgi.log_master_bufsize);
|
||||
if (rlen > 0) {
|
||||
#ifdef UWSGI_PCRE
|
||||
uwsgi_alarm_log_check(uwsgi.log_master_buf, rlen);
|
||||
struct uwsgi_regexp_list *url = uwsgi.log_drain_rules;
|
||||
while (url) {
|
||||
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, uwsgi.log_master_buf, rlen) >= 0) {
|
||||
return 0;
|
||||
}
|
||||
url = url->next;
|
||||
}
|
||||
if (uwsgi.log_filter_rules) {
|
||||
int show = 0;
|
||||
url = uwsgi.log_filter_rules;
|
||||
while (url) {
|
||||
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, uwsgi.log_master_buf, rlen) >= 0) {
|
||||
show = 1;
|
||||
break;
|
||||
}
|
||||
url = url->next;
|
||||
}
|
||||
if (!show)
|
||||
return 0;
|
||||
}
|
||||
|
||||
url = uwsgi.log_route;
|
||||
int finish = 0;
|
||||
while (url) {
|
||||
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, uwsgi.log_master_buf, rlen) >= 0) {
|
||||
struct uwsgi_logger *ul_route = (struct uwsgi_logger *) url->custom_ptr;
|
||||
if (ul_route) {
|
||||
ul_route->func(ul_route, uwsgi.log_master_buf, rlen);
|
||||
finish = 1;
|
||||
}
|
||||
}
|
||||
url = url->next;
|
||||
}
|
||||
if (finish)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
int raw_log = 1;
|
||||
|
||||
struct uwsgi_logger *ul = uwsgi.choosen_logger;
|
||||
while (ul) {
|
||||
// check for named logger
|
||||
if (ul->id) {
|
||||
goto next;
|
||||
}
|
||||
ul->func(ul, uwsgi.log_master_buf, rlen);
|
||||
raw_log = 0;
|
||||
next:
|
||||
ul = ul->next;
|
||||
}
|
||||
|
||||
if (raw_log) {
|
||||
rlen = write(uwsgi.original_log_fd, uwsgi.log_master_buf, rlen);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int uwsgi_master_req_log(void) {
|
||||
|
||||
ssize_t rlen = read(uwsgi.shared->worker_req_log_pipe[0], uwsgi.log_master_buf, uwsgi.log_master_bufsize);
|
||||
if (rlen > 0) {
|
||||
#ifdef UWSGI_PCRE
|
||||
struct uwsgi_regexp_list *url = uwsgi.log_req_route;
|
||||
int finish = 0;
|
||||
while (url) {
|
||||
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, uwsgi.log_master_buf, rlen) >= 0) {
|
||||
struct uwsgi_logger *ul_route = (struct uwsgi_logger *) url->custom_ptr;
|
||||
if (ul_route) {
|
||||
ul_route->func(ul_route, uwsgi.log_master_buf, rlen);
|
||||
finish = 1;
|
||||
}
|
||||
}
|
||||
url = url->next;
|
||||
}
|
||||
if (finish)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
int raw_log = 1;
|
||||
|
||||
struct uwsgi_logger *ul = uwsgi.choosen_req_logger;
|
||||
while (ul) {
|
||||
// check for named logger
|
||||
if (ul->id) {
|
||||
goto next;
|
||||
}
|
||||
ul->func(ul, uwsgi.log_master_buf, rlen);
|
||||
raw_log = 0;
|
||||
next:
|
||||
ul = ul->next;
|
||||
}
|
||||
|
||||
if (raw_log) {
|
||||
rlen = write(uwsgi.original_log_fd, uwsgi.log_master_buf, rlen);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void *logger_thread_loop(void *noarg) {
|
||||
struct pollfd logpoll[2];
|
||||
|
||||
// block all signals
|
||||
sigset_t smask;
|
||||
sigfillset(&smask);
|
||||
pthread_sigmask(SIG_BLOCK, &smask, NULL);
|
||||
|
||||
logpoll[0].events = POLLIN;
|
||||
logpoll[0].fd = uwsgi.shared->worker_log_pipe[0];
|
||||
|
||||
int logpolls = 1;
|
||||
|
||||
if (uwsgi.req_log_master) {
|
||||
logpoll[1].events = POLLIN;
|
||||
logpoll[1].fd = uwsgi.shared->worker_req_log_pipe[0];
|
||||
}
|
||||
|
||||
|
||||
for (;;) {
|
||||
int ret = poll(logpoll, logpolls, -1);
|
||||
if (ret > 0) {
|
||||
if (logpoll[0].revents & POLLIN) {
|
||||
pthread_mutex_lock(&uwsgi.threaded_logger_lock);
|
||||
uwsgi_master_log();
|
||||
pthread_mutex_unlock(&uwsgi.threaded_logger_lock);
|
||||
}
|
||||
else if (logpolls > 1 && logpoll[1].revents & POLLIN) {
|
||||
pthread_mutex_lock(&uwsgi.threaded_logger_lock);
|
||||
uwsgi_master_req_log();
|
||||
pthread_mutex_unlock(&uwsgi.threaded_logger_lock);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void uwsgi_threaded_logger_spawn() {
|
||||
pthread_t logger_thread;
|
||||
|
||||
if (pthread_create(&logger_thread, NULL, logger_thread_loop, NULL)) {
|
||||
uwsgi_error("pthread_create()");
|
||||
uwsgi_log("falling back to non-threaded logger...\n");
|
||||
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_log_pipe[0]);
|
||||
if (uwsgi.req_log_master) {
|
||||
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_req_log_pipe[0]);
|
||||
}
|
||||
uwsgi.threaded_logger = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-6
@@ -64,12 +64,10 @@ void simple_loop() {
|
||||
|
||||
void uwsgi_loop_cores_run(void *(*func) (void *)) {
|
||||
int i;
|
||||
#ifdef UWSGI_THREADING
|
||||
for (i = 1; i < uwsgi.threads; i++) {
|
||||
long j = i;
|
||||
pthread_create(&uwsgi.workers[uwsgi.mywid].cores[i].thread_id, &uwsgi.threads_attr, func, (void *) j);
|
||||
}
|
||||
#endif
|
||||
long y = 0;
|
||||
func((void *) y);
|
||||
}
|
||||
@@ -120,12 +118,9 @@ void *simple_loop_run(void *arg1) {
|
||||
|
||||
struct wsgi_request *wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[core_id].req;
|
||||
|
||||
#ifdef UWSGI_THREADING
|
||||
if (uwsgi.threads > 1) {
|
||||
uwsgi_setup_thread_req(core_id, wsgi_req);
|
||||
}
|
||||
#endif
|
||||
|
||||
// initialize the main event queue to monitor sockets
|
||||
int main_queue = event_queue_init();
|
||||
|
||||
@@ -146,7 +141,7 @@ void *simple_loop_run(void *arg1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (wsgi_req_recv(wsgi_req)) {
|
||||
if (wsgi_req_recv(main_queue, wsgi_req)) {
|
||||
uwsgi_destroy_request(wsgi_req);
|
||||
continue;
|
||||
}
|
||||
|
||||
+166
-876
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,278 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
// check if all of the workers are dead and exit uWSGI
|
||||
void uwsgi_master_check_death() {
|
||||
if (uwsgi_instance_is_dying) {
|
||||
int i;
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
if (uwsgi.workers[i].pid > 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
uwsgi_log("goodbye to uWSGI.\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
// check if all of the workers are dead, and trigger a reload
|
||||
int uwsgi_master_check_reload(char **argv) {
|
||||
if (uwsgi_instance_is_reloading) {
|
||||
int i;
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
if (uwsgi.workers[i].pid > 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
uwsgi_reload(argv);
|
||||
// never here (unless in shared library mode)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check for chain reload
|
||||
void uwsgi_master_check_chain() {
|
||||
if (!uwsgi.status.chain_reloading) return;
|
||||
if (uwsgi.status.chain_reloading > uwsgi.numproc) {
|
||||
uwsgi.status.chain_reloading = 0;
|
||||
uwsgi_log_verbose("chain reloading complete\n");
|
||||
}
|
||||
int i;
|
||||
uwsgi_block_signal(SIGHUP);
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].cursed_at == 0 && i == uwsgi.status.chain_reloading) {
|
||||
uwsgi_curse(i, SIGHUP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
uwsgi_unblock_signal(SIGHUP);
|
||||
}
|
||||
|
||||
|
||||
// special function for assuming all of the workers are dead
|
||||
void uwsgi_master_commit_status() {
|
||||
int i;
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
uwsgi.workers[i].pid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_master_check_idle() {
|
||||
|
||||
static time_t last_request_timecheck = 0;
|
||||
static uint64_t last_request_count = 0;
|
||||
int i;
|
||||
int waitpid_status;
|
||||
|
||||
if (!uwsgi.idle || uwsgi.status.is_cheap)
|
||||
return;
|
||||
|
||||
uwsgi.current_time = uwsgi_now();
|
||||
if (!last_request_timecheck)
|
||||
last_request_timecheck = uwsgi.current_time;
|
||||
|
||||
// security check, stop the check if there are busy workers
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
|
||||
if (uwsgi_worker_is_busy(i)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (last_request_count != uwsgi.workers[0].requests) {
|
||||
last_request_timecheck = uwsgi.current_time;
|
||||
last_request_count = uwsgi.workers[0].requests;
|
||||
}
|
||||
// a bit of over-engeneering to avoid clock skews
|
||||
else if (last_request_timecheck < uwsgi.current_time && (uwsgi.current_time - last_request_timecheck > uwsgi.idle)) {
|
||||
uwsgi_log("workers have been inactive for more than %d seconds (%llu-%llu)\n", uwsgi.idle, (unsigned long long) uwsgi.current_time, (unsigned long long) last_request_timecheck);
|
||||
uwsgi.status.is_cheap = 1;
|
||||
if (uwsgi.die_on_idle) {
|
||||
if (uwsgi.has_emperor) {
|
||||
char byte = 22;
|
||||
if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
|
||||
uwsgi_error("write()");
|
||||
kill_them_all(0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
kill_them_all(0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
uwsgi.workers[i].cheaped = 1;
|
||||
if (uwsgi.workers[i].pid == 0)
|
||||
continue;
|
||||
kill(uwsgi.workers[i].pid, SIGKILL);
|
||||
if (waitpid(uwsgi.workers[i].pid, &waitpid_status, 0) < 0) {
|
||||
if (errno != ECHILD)
|
||||
uwsgi_error("uwsgi_master_check_idle()/waitpid()");
|
||||
}
|
||||
}
|
||||
uwsgi_add_sockets_to_queue(uwsgi.master_queue, -1);
|
||||
uwsgi_log("cheap mode enabled: waiting for socket connection...\n");
|
||||
last_request_timecheck = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_master_check_workers_deadline() {
|
||||
int i;
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
/* first check for harakiri */
|
||||
if (uwsgi.workers[i].harakiri > 0) {
|
||||
if (uwsgi.workers[i].harakiri < (time_t) uwsgi.current_time) {
|
||||
trigger_harakiri(i);
|
||||
}
|
||||
}
|
||||
/* then user-defined harakiri */
|
||||
if (uwsgi.workers[i].user_harakiri > 0) {
|
||||
if (uwsgi.workers[i].user_harakiri < (time_t) uwsgi.current_time) {
|
||||
trigger_harakiri(i);
|
||||
}
|
||||
}
|
||||
// then for evil memory checkers
|
||||
if (uwsgi.evil_reload_on_as) {
|
||||
if ((rlim_t) uwsgi.workers[i].vsz_size >= uwsgi.evil_reload_on_as) {
|
||||
uwsgi_log("*** EVIL RELOAD ON WORKER %d ADDRESS SPACE: %lld (pid: %d) ***\n", i, (long long) uwsgi.workers[i].vsz_size, uwsgi.workers[i].pid);
|
||||
kill(uwsgi.workers[i].pid, SIGKILL);
|
||||
uwsgi.workers[i].vsz_size = 0;
|
||||
}
|
||||
}
|
||||
if (uwsgi.evil_reload_on_rss) {
|
||||
if ((rlim_t) uwsgi.workers[i].rss_size >= uwsgi.evil_reload_on_rss) {
|
||||
uwsgi_log("*** EVIL RELOAD ON WORKER %d RSS: %lld (pid: %d) ***\n", i, (long long) uwsgi.workers[i].rss_size, uwsgi.workers[i].pid);
|
||||
kill(uwsgi.workers[i].pid, SIGKILL);
|
||||
uwsgi.workers[i].rss_size = 0;
|
||||
}
|
||||
}
|
||||
// check if worker was running longer than allowed lifetime
|
||||
if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cheaped == 0 && uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME] > 0) {
|
||||
uint64_t lifetime = uwsgi_now() - uwsgi.workers[i].last_spawn;
|
||||
if (lifetime > uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME] && uwsgi.workers[i].manage_next_request == 1) {
|
||||
uwsgi_log("worker %d lifetime reached, it was running for %llu second(s)\n", i, (unsigned long long) lifetime);
|
||||
uwsgi.workers[i].manage_next_request = 0;
|
||||
kill(uwsgi.workers[i].pid, SIGWINCH);
|
||||
}
|
||||
}
|
||||
|
||||
// need to find a better way
|
||||
//uwsgi.workers[i].last_running_time = uwsgi.workers[i].running_time;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_master_check_gateways_deadline() {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ushared->gateways_cnt; i++) {
|
||||
if (ushared->gateways_harakiri[i] > 0) {
|
||||
if (ushared->gateways_harakiri[i] < (time_t) uwsgi.current_time) {
|
||||
if (ushared->gateways[i].pid > 0) {
|
||||
kill(ushared->gateways[i].pid, SIGKILL);
|
||||
}
|
||||
ushared->gateways_harakiri[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_master_check_mules_deadline() {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
if (uwsgi.mules[i].harakiri > 0) {
|
||||
if (uwsgi.mules[i].harakiri < (time_t) uwsgi.current_time) {
|
||||
uwsgi_log("*** HARAKIRI ON MULE %d HANDLING SIGNAL %d (pid: %d) ***\n", i + 1, uwsgi.mules[i].signum, uwsgi.mules[i].pid);
|
||||
kill(uwsgi.mules[i].pid, SIGKILL);
|
||||
uwsgi.mules[i].harakiri = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_master_check_spoolers_deadline() {
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
while (uspool) {
|
||||
if (uspool->harakiri > 0 && uspool->harakiri < (time_t) uwsgi.current_time) {
|
||||
uwsgi_log("*** HARAKIRI ON THE SPOOLER (pid: %d) ***\n", uspool->pid);
|
||||
kill(uspool->pid, SIGKILL);
|
||||
uspool->harakiri = 0;
|
||||
}
|
||||
uspool = uspool->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_master_check_spoolers_death(int diedpid) {
|
||||
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
while (uspool) {
|
||||
if (uspool->pid > 0 && diedpid == uspool->pid) {
|
||||
uwsgi_log("OOOPS the spooler is no more...trying respawn...\n");
|
||||
uspool->respawned++;
|
||||
uspool->pid = spooler_start(uspool);
|
||||
return -1;
|
||||
}
|
||||
uspool = uspool->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_master_check_emperor_death(int diedpid) {
|
||||
if (uwsgi.emperor_pid >= 0 && diedpid == uwsgi.emperor_pid) {
|
||||
uwsgi_log_verbose("!!! Emperor died !!!\n");
|
||||
uwsgi_emperor_start();
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_master_check_mules_death(int diedpid) {
|
||||
int i;
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
if (uwsgi.mules[i].pid == diedpid) {
|
||||
uwsgi_log("OOOPS mule %d (pid: %d) crippled...trying respawn...\n", i + 1, uwsgi.mules[i].pid);
|
||||
uwsgi_mule(i + 1);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_master_check_gateways_death(int diedpid) {
|
||||
int i;
|
||||
for (i = 0; i < ushared->gateways_cnt; i++) {
|
||||
if (ushared->gateways[i].pid == diedpid) {
|
||||
gateway_respawn(i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_master_check_daemons_death(int diedpid) {
|
||||
/* reload the daemons */
|
||||
if (uwsgi_daemon_check_pid_reload(diedpid)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_worker_is_busy(int wid) {
|
||||
int i;
|
||||
for(i=0;i<uwsgi.cores;i++) {
|
||||
if (uwsgi.workers[wid].cores[i].in_request) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_master_manage_events(int interesting_fd) {
|
||||
|
||||
// is a logline ?
|
||||
if (uwsgi.log_master && !uwsgi.threaded_logger) {
|
||||
// stderr log ?
|
||||
if (interesting_fd == uwsgi.shared->worker_log_pipe[0]) {
|
||||
uwsgi_master_log();
|
||||
return 0;
|
||||
}
|
||||
// req log ?
|
||||
if (uwsgi.req_log_master && interesting_fd == uwsgi.shared->worker_req_log_pipe[0]) {
|
||||
uwsgi_master_req_log();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// stats server ?
|
||||
if (uwsgi.stats && uwsgi.stats_fd > -1) {
|
||||
if (interesting_fd == uwsgi.stats_fd) {
|
||||
uwsgi_send_stats(uwsgi.stats_fd, uwsgi_master_generate_stats);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// a zerg connection ?
|
||||
if (uwsgi.zerg_server) {
|
||||
if (interesting_fd == uwsgi.zerg_server_fd) {
|
||||
uwsgi_manage_zerg(uwsgi.zerg_server_fd, 0, NULL);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// emperor event ?
|
||||
if (uwsgi.has_emperor) {
|
||||
if (interesting_fd == uwsgi.emperor_fd) {
|
||||
uwsgi_master_manage_emperor();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// wakeup from cheap mode ?
|
||||
if (uwsgi.status.is_cheap) {
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
while (uwsgi_sock) {
|
||||
if (interesting_fd == uwsgi_sock->fd) {
|
||||
uwsgi.status.is_cheap = 0;
|
||||
uwsgi_del_sockets_from_queue(uwsgi.master_queue);
|
||||
// how many worker we need to respawn ?
|
||||
int needed = uwsgi.numproc;
|
||||
// if in cheaper mode, just respawn the minimal amount
|
||||
if (uwsgi.cheaper) {
|
||||
needed = uwsgi.cheaper_count;
|
||||
}
|
||||
int i;
|
||||
for (i = 1; i <= needed; i++) {
|
||||
if (uwsgi_respawn_worker(i))
|
||||
return -1;
|
||||
}
|
||||
// here we continue instead of returning
|
||||
break;
|
||||
}
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// an SNMP request ?
|
||||
if (uwsgi.snmp_addr && interesting_fd == uwsgi.snmp_fd) {
|
||||
uwsgi_master_manage_snmp(uwsgi.snmp_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// a UDP request ?
|
||||
if (uwsgi.udp_socket && interesting_fd == uwsgi.udp_fd) {
|
||||
uwsgi_master_manage_udp(uwsgi.udp_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// check if some file monitor is ready
|
||||
// no need to lock as we are only getting registered items (and only the master can register them)
|
||||
int i;
|
||||
for (i = 0; i < ushared->files_monitored_cnt; i++) {
|
||||
if (ushared->files_monitored[i].registered) {
|
||||
if (interesting_fd == ushared->files_monitored[i].fd) {
|
||||
struct uwsgi_fmon *uf = event_queue_ack_file_monitor(uwsgi.master_queue, interesting_fd);
|
||||
// now call the file_monitor handler
|
||||
if (uf)
|
||||
uwsgi_route_signal(uf->sig);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if some timer elapsed
|
||||
// no need to lock again
|
||||
for (i = 0; i < ushared->timers_cnt; i++) {
|
||||
if (ushared->timers[i].registered) {
|
||||
if (interesting_fd == ushared->timers[i].fd) {
|
||||
struct uwsgi_timer *ut = event_queue_ack_timer(interesting_fd);
|
||||
// now call the timer handler
|
||||
if (ut)
|
||||
uwsgi_route_signal(ut->sig);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t uwsgi_signal;
|
||||
// check for worker signal
|
||||
if (interesting_fd == uwsgi.shared->worker_signal_pipe[0]) {
|
||||
ssize_t rlen = read(interesting_fd, &uwsgi_signal, 1);
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("uwsgi_master_manage_events()/read()");
|
||||
}
|
||||
else if (rlen > 0) {
|
||||
uwsgi_route_signal(uwsgi_signal);
|
||||
}
|
||||
else {
|
||||
// TODO restart workers here
|
||||
uwsgi_log_verbose("lost connection with workers !!!\n");
|
||||
close(interesting_fd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check for spooler signal
|
||||
if (uwsgi.spoolers) {
|
||||
if (interesting_fd == uwsgi.shared->spooler_signal_pipe[0]) {
|
||||
ssize_t rlen = read(interesting_fd, &uwsgi_signal, 1);
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("uwsgi_master_manage_events()/read()");
|
||||
}
|
||||
else if (rlen > 0) {
|
||||
uwsgi_route_signal(uwsgi_signal);
|
||||
}
|
||||
else {
|
||||
// TODO restart spoolers here
|
||||
uwsgi_log_verbose("lost connection with spoolers\n");
|
||||
close(interesting_fd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// check for mules signal
|
||||
if (uwsgi.mules_cnt > 0) {
|
||||
if (interesting_fd == uwsgi.shared->mule_signal_pipe[0]) {
|
||||
ssize_t rlen = read(interesting_fd, &uwsgi_signal, 1);
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("uwsgi_master_manage_events()/read()");
|
||||
}
|
||||
else if (rlen > 0) {
|
||||
uwsgi_route_signal(uwsgi_signal);
|
||||
}
|
||||
else {
|
||||
// TODO respawn mules here
|
||||
uwsgi_log_verbose("lost connection with mules\n");
|
||||
close(interesting_fd);
|
||||
}
|
||||
// return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
+329
-64
@@ -5,15 +5,82 @@ extern struct uwsgi_server uwsgi;
|
||||
void worker_wakeup() {
|
||||
}
|
||||
|
||||
uint64_t uwsgi_worker_exceptions(int wid) {
|
||||
uint64_t total = 0;
|
||||
int i;
|
||||
for(i=0;i<uwsgi.cores;i++) {
|
||||
total += uwsgi.workers[wid].cores[i].exceptions;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
void uwsgi_curse(int wid, int sig) {
|
||||
uwsgi.workers[wid].cursed_at = uwsgi_now();
|
||||
uwsgi.workers[wid].no_mercy_at = uwsgi.workers[wid].cursed_at + uwsgi.worker_reload_mercy;
|
||||
|
||||
if (sig) {
|
||||
(void) kill(uwsgi.workers[wid].pid, sig);
|
||||
}
|
||||
}
|
||||
|
||||
static void uwsgi_signal_spoolers(int signum) {
|
||||
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
while (uspool) {
|
||||
if (uspool->pid > 0) {
|
||||
kill(uspool->pid, signum);
|
||||
uwsgi_log("killing the spooler with pid %d\n", uspool->pid);
|
||||
}
|
||||
uspool = uspool->next;
|
||||
}
|
||||
|
||||
}
|
||||
void uwsgi_destroy_processes() {
|
||||
|
||||
int i;
|
||||
int waitpid_status;
|
||||
|
||||
uwsgi_signal_spoolers(SIGKILL);
|
||||
|
||||
if (uwsgi.emperor_pid >= 0) {
|
||||
kill(uwsgi.emperor_pid, SIGKILL);
|
||||
waitpid(uwsgi.emperor_pid, &waitpid_status, 0);
|
||||
uwsgi_log("The Emperor has been buried (pid: %d)\n", (int) uwsgi.emperor_pid);
|
||||
}
|
||||
|
||||
|
||||
uwsgi_detach_daemons();
|
||||
|
||||
for (i = 0; i < ushared->gateways_cnt; i++) {
|
||||
if (ushared->gateways[i].pid > 0) {
|
||||
kill(ushared->gateways[i].pid, SIGKILL);
|
||||
waitpid(ushared->gateways[i].pid, &waitpid_status, 0);
|
||||
uwsgi_log("gateway \"%s %d\" has been buried (pid: %d)\n", ushared->gateways[i].name, ushared->gateways[i].num, (int) ushared->gateways[i].pid);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO mules can be programmed to be gracefully reloaded
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
if (uwsgi.mules[i].pid > 0) {
|
||||
kill(uwsgi.mules[i].pid, SIGKILL);
|
||||
waitpid(uwsgi.mules[i].pid, &waitpid_status, 0);
|
||||
uwsgi_log("mule %d has been buried (pid: %d)\n", i, (int) uwsgi.mules[i].pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void uwsgi_master_cleanup_hooks(void) {
|
||||
|
||||
int j;
|
||||
|
||||
// could be an inherited atexit hook
|
||||
if (uwsgi.mywid > 0)
|
||||
if (uwsgi.mypid != uwsgi.workers[0].pid)
|
||||
return;
|
||||
|
||||
uwsgi.cleaning = 1;
|
||||
uwsgi.status.is_cleaning = 1;
|
||||
|
||||
for (j = 0; j < uwsgi.gp_cnt; j++) {
|
||||
if (uwsgi.gp[j]->master_cleanup) {
|
||||
@@ -78,8 +145,7 @@ int uwsgi_calc_cheaper(void) {
|
||||
#endif
|
||||
uwsgi.workers[oldest_worker].cheaped = 1;
|
||||
uwsgi.workers[oldest_worker].manage_next_request = 0;
|
||||
// wakeup task in case of wait
|
||||
(void) kill(uwsgi.workers[oldest_worker].pid, SIGWINCH);
|
||||
uwsgi_curse(oldest_worker, SIGWINCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +197,7 @@ int uwsgi_cheaper_algo_spare(void) {
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
|
||||
// if a non-busy worker is found, the overload_count is decremented and stop the cycle
|
||||
if (uwsgi.workers[i].busy == 0) {
|
||||
if (uwsgi_worker_is_busy(i) == 0) {
|
||||
if (overload_count > 0)
|
||||
overload_count--;
|
||||
goto healthy;
|
||||
@@ -174,7 +240,7 @@ healthy:
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
|
||||
active_workers++;
|
||||
if (uwsgi.workers[i].busy == 1)
|
||||
if (uwsgi_worker_is_busy(i) == 1)
|
||||
busy_workers++;
|
||||
}
|
||||
}
|
||||
@@ -307,43 +373,44 @@ void uwsgi_reload(char **argv) {
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
if (found) continue;
|
||||
|
||||
if (!found) {
|
||||
if (uwsgi.has_emperor) {
|
||||
if (i == uwsgi.emperor_fd) {
|
||||
found = 1;
|
||||
}
|
||||
if (uwsgi.has_emperor) {
|
||||
if (i == uwsgi.emperor_fd) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == uwsgi.emperor_fd_config) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.log_master) {
|
||||
if (uwsgi.original_log_fd > -1) {
|
||||
if (i == uwsgi.original_log_fd) {
|
||||
found = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.shared->worker_log_pipe[0] > -1) {
|
||||
if (i == uwsgi.shared->worker_log_pipe[0]) {
|
||||
found = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.shared->worker_log_pipe[1] > -1) {
|
||||
if (i == uwsgi.shared->worker_log_pipe[1]) {
|
||||
found = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
#ifdef __APPLE__
|
||||
fcntl(i, F_SETFD, FD_CLOEXEC);
|
||||
fcntl(i, F_SETFD, FD_CLOEXEC);
|
||||
#else
|
||||
close(i);
|
||||
close(i);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UWSGI_AS_SHARED_LIBRARY
|
||||
@@ -373,44 +440,10 @@ void uwsgi_reload(char **argv) {
|
||||
|
||||
}
|
||||
|
||||
void master_check_cluster_nodes() {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
struct uwsgi_cluster_node *ucn = &uwsgi.shared->nodes[i];
|
||||
|
||||
if (ucn->name[0] != 0 && ucn->type == CLUSTER_NODE_STATIC && ucn->status == UWSGI_NODE_FAILED) {
|
||||
// should i retry ?
|
||||
if (uwsgi.master_cycles % ucn->errors == 0) {
|
||||
if (!uwsgi_ping_node(i, uwsgi.wsgi_req)) {
|
||||
ucn->status = UWSGI_NODE_OK;
|
||||
uwsgi_log("re-enabled cluster node %d/%s\n", i, ucn->name);
|
||||
}
|
||||
else {
|
||||
ucn->errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ucn->name[0] != 0 && ucn->type == CLUSTER_NODE_DYNAMIC) {
|
||||
// if the last_seen attr is higher than 30 secs ago, mark the node as dead
|
||||
if ((uwsgi.current_time - ucn->last_seen) > 30) {
|
||||
uwsgi_log_verbose("no presence announce in the last 30 seconds by node %s, i assume it is dead.\n", ucn->name);
|
||||
ucn->name[0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_fixup_fds(int wid, int muleid, struct uwsgi_gateway *ug) {
|
||||
|
||||
int i;
|
||||
|
||||
// close the cache server
|
||||
if (uwsgi.cache_server_fd != -1) {
|
||||
close(uwsgi.cache_server_fd);
|
||||
}
|
||||
|
||||
if (uwsgi.master_process) {
|
||||
if (uwsgi.master_queue > -1)
|
||||
close(uwsgi.master_queue);
|
||||
@@ -443,14 +476,13 @@ void uwsgi_fixup_fds(int wid, int muleid, struct uwsgi_gateway *ug) {
|
||||
close(uwsgi.workers[i].signal_pipe[1]);
|
||||
}
|
||||
}
|
||||
#ifdef UWSGI_SPOOLER
|
||||
|
||||
if (uwsgi.i_am_a_spooler && uwsgi.i_am_a_spooler->pid != getpid()) {
|
||||
if (uwsgi.shared->spooler_signal_pipe[0] != -1)
|
||||
close(uwsgi.shared->spooler_signal_pipe[0]);
|
||||
if (uwsgi.shared->spooler_signal_pipe[1] != -1)
|
||||
close(uwsgi.shared->spooler_signal_pipe[1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (uwsgi.shared->mule_signal_pipe[0] != -1)
|
||||
close(uwsgi.shared->mule_signal_pipe[0]);
|
||||
@@ -503,12 +535,15 @@ int uwsgi_respawn_worker(int wid) {
|
||||
uwsgi.workers[wid].pending_harakiri = 0;
|
||||
uwsgi.workers[wid].rss_size = 0;
|
||||
uwsgi.workers[wid].vsz_size = 0;
|
||||
// ... reset stopped_at
|
||||
uwsgi.workers[wid].cursed_at = 0;
|
||||
uwsgi.workers[wid].no_mercy_at = 0;
|
||||
|
||||
// internal statuses should be reset too
|
||||
|
||||
uwsgi.workers[wid].cheaped = 0;
|
||||
uwsgi.workers[wid].busy = 0;
|
||||
uwsgi.workers[wid].suspended = 0;
|
||||
// SUSPENSION is managed by the user, not the master...
|
||||
//uwsgi.workers[wid].suspended = 0;
|
||||
uwsgi.workers[wid].sig = 0;
|
||||
|
||||
// this is required for various checks
|
||||
@@ -547,7 +582,6 @@ int uwsgi_respawn_worker(int wid) {
|
||||
uwsgi.workers[uwsgi.mywid].manage_next_request = 1;
|
||||
/*
|
||||
uwsgi.workers[uwsgi.mywid].cheaped = 0;
|
||||
uwsgi.workers[uwsgi.mywid].busy = 0;
|
||||
uwsgi.workers[uwsgi.mywid].suspended = 0;
|
||||
uwsgi.workers[uwsgi.mywid].sig = 0;
|
||||
*/
|
||||
@@ -555,12 +589,18 @@ int uwsgi_respawn_worker(int wid) {
|
||||
// reset the apps count with a copy from the master
|
||||
uwsgi.workers[uwsgi.mywid].apps_cnt = uwsgi.workers[0].apps_cnt;
|
||||
|
||||
// reset wsgi_request structures
|
||||
for(i=0;i<uwsgi.cores;i++) {
|
||||
uwsgi.workers[uwsgi.mywid].cores[i].in_request = 0;
|
||||
memset(&uwsgi.workers[uwsgi.mywid].cores[i].req, 0, sizeof(struct wsgi_request));
|
||||
}
|
||||
|
||||
uwsgi_fixup_fds(wid, 0, NULL);
|
||||
|
||||
uwsgi.my_signal_socket = uwsgi.workers[wid].signal_pipe[1];
|
||||
|
||||
if (uwsgi.master_process) {
|
||||
if ((uwsgi.workers[uwsgi.mywid].respawn_count || uwsgi.cheap)) {
|
||||
if ((uwsgi.workers[uwsgi.mywid].respawn_count || uwsgi.status.is_cheap)) {
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->master_fixup) {
|
||||
uwsgi.p[i]->master_fixup(1);
|
||||
@@ -715,7 +755,7 @@ void uwsgi_manage_command_cron(time_t now) {
|
||||
}
|
||||
}
|
||||
if (current_cron->month < 0) {
|
||||
if ((uwsgi_cron_delta->tm_hour % abs(current_cron->month)) == 0) {
|
||||
if ((uwsgi_cron_delta->tm_mon % abs(current_cron->month)) == 0) {
|
||||
uc_month = uwsgi_cron_delta->tm_mon;
|
||||
}
|
||||
}
|
||||
@@ -861,6 +901,66 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
if (uwsgi_stats_comma(us))
|
||||
goto end;
|
||||
|
||||
if (uwsgi.caches) {
|
||||
|
||||
|
||||
if (uwsgi_stats_key(us, "caches"))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_list_open(us)) goto end;
|
||||
|
||||
struct uwsgi_cache *uc = uwsgi.caches;
|
||||
while(uc) {
|
||||
if (uwsgi_stats_object_open(us))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keyval_comma(us, "name", uc->name ? uc->name : "default"))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keyval_comma(us, "hash", uc->hash->name))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "hashsize", (unsigned long long) uc->hashsize))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "keysize", (unsigned long long) uc->keysize))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "max_items", (unsigned long long) uc->max_items))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "blocks", (unsigned long long) uc->blocks))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "blocksize", (unsigned long long) uc->blocksize))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "items", (unsigned long long) uc->n_items))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "hits", (unsigned long long) uc->hits))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "miss", (unsigned long long) uc->miss))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong(us, "full", (unsigned long long) uc->full))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_object_close(us))
|
||||
goto end;
|
||||
|
||||
if (uc->next) {
|
||||
if (uwsgi_stats_comma(us))
|
||||
goto end;
|
||||
}
|
||||
uc = uc->next;
|
||||
}
|
||||
|
||||
if (uwsgi_stats_comma(us))
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (uwsgi_stats_key(us, "sockets"))
|
||||
goto end;
|
||||
|
||||
@@ -920,7 +1020,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
goto end;
|
||||
if (uwsgi_stats_keylong_comma(us, "delta_requests", (unsigned long long) uwsgi.workers[i + 1].delta_requests))
|
||||
goto end;
|
||||
if (uwsgi_stats_keylong_comma(us, "exceptions", (unsigned long long) uwsgi.workers[i + 1].exceptions))
|
||||
if (uwsgi_stats_keylong_comma(us, "exceptions", (unsigned long long) uwsgi_worker_exceptions(i + 1)))
|
||||
goto end;
|
||||
if (uwsgi_stats_keylong_comma(us, "harakiri_count", (unsigned long long) uwsgi.workers[i + 1].harakiri_count))
|
||||
goto end;
|
||||
@@ -938,7 +1038,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
if (uwsgi_stats_keyval_comma(us, "status", "cheap"))
|
||||
goto end;
|
||||
}
|
||||
else if (uwsgi.workers[i + 1].suspended && !uwsgi.workers[i + 1].busy) {
|
||||
else if (uwsgi.workers[i + 1].suspended && !uwsgi_worker_is_busy(i+1)) {
|
||||
if (uwsgi_stats_keyval_comma(us, "status", "pause"))
|
||||
goto end;
|
||||
}
|
||||
@@ -947,7 +1047,7 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
if (uwsgi_stats_keyvalnum_comma(us, "status", "sig", (unsigned long long) uwsgi.workers[i + 1].signum))
|
||||
goto end;
|
||||
}
|
||||
else if (uwsgi.workers[i + 1].busy) {
|
||||
else if (uwsgi_worker_is_busy(i+1)) {
|
||||
if (uwsgi_stats_keyval_comma(us, "status", "busy"))
|
||||
goto end;
|
||||
}
|
||||
@@ -1052,7 +1152,21 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
if (uwsgi_stats_keylong_comma(us, "offloaded_requests", (unsigned long long) uc->offloaded_requests))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong(us, "in_request", (unsigned long long) uc->in_request))
|
||||
if (uwsgi_stats_keylong_comma(us, "write_errors", (unsigned long long) uc->write_errors))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "in_request", (unsigned long long) uc->in_request))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_key(us, "vars"))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_list_open(us))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_dump_vars(us, uc)) goto end;
|
||||
|
||||
if (uwsgi_stats_list_close(us))
|
||||
goto end;
|
||||
|
||||
|
||||
@@ -1080,7 +1194,6 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
if (uwsgi_stats_list_close(us))
|
||||
goto end;
|
||||
|
||||
#ifdef UWSGI_SPOOLER
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
if (uspool) {
|
||||
if (uwsgi_stats_comma(us))
|
||||
@@ -1119,12 +1232,147 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
if (uwsgi_stats_list_close(us))
|
||||
goto end;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
struct uwsgi_legion *legion = NULL;
|
||||
if (uwsgi.legions) {
|
||||
|
||||
if (uwsgi_stats_comma(us))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_key(us, "legions"))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_list_open(us))
|
||||
goto end;
|
||||
|
||||
legion = uwsgi.legions;
|
||||
while (legion) {
|
||||
if (uwsgi_stats_object_open(us))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keyval_comma(us, "legion", legion->legion))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keyval_comma(us, "addr", legion->addr))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keyval_comma(us, "uuid", legion->uuid))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "valor", (unsigned long long) legion->valor))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "checksum", (unsigned long long) legion->checksum))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "quorum", (unsigned long long) legion->quorum))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "i_am_the_lord", (unsigned long long) legion->i_am_the_lord))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "lord_valor", (unsigned long long) legion->lord_valor))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_keyvaln_comma(us, "lord_uuid", legion->lord_uuid, 36))
|
||||
goto end;
|
||||
|
||||
// legion nodes start
|
||||
if (uwsgi_stats_key(us, "nodes"))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_list_open(us))
|
||||
goto end;
|
||||
|
||||
struct uwsgi_string_list *nodes = legion->nodes;
|
||||
while (nodes) {
|
||||
|
||||
if (uwsgi_stats_str(us, nodes->value))
|
||||
goto end;
|
||||
|
||||
nodes = nodes->next;
|
||||
if (nodes) {
|
||||
if (uwsgi_stats_comma(us))
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi_stats_list_close(us))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_comma(us))
|
||||
goto end;
|
||||
|
||||
|
||||
// legion members start
|
||||
if (uwsgi_stats_key(us, "members"))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_list_open(us))
|
||||
goto end;
|
||||
|
||||
pthread_mutex_lock(&legion->lock);
|
||||
struct uwsgi_legion_node *node = legion->nodes_head;
|
||||
while (node) {
|
||||
if (uwsgi_stats_object_open(us))
|
||||
goto unlock_legion_mutex;
|
||||
|
||||
if (uwsgi_stats_keyvaln_comma(us, "name", node->name, node->name_len))
|
||||
goto unlock_legion_mutex;
|
||||
|
||||
if (uwsgi_stats_keyval_comma(us, "uuid", node->uuid))
|
||||
goto unlock_legion_mutex;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "valor", (unsigned long long) node->valor))
|
||||
goto unlock_legion_mutex;
|
||||
|
||||
if (uwsgi_stats_keylong_comma(us, "checksum", (unsigned long long) node->checksum))
|
||||
goto unlock_legion_mutex;
|
||||
|
||||
if (uwsgi_stats_keylong(us, "last_seen", (unsigned long long) node->last_seen))
|
||||
goto unlock_legion_mutex;
|
||||
|
||||
if (uwsgi_stats_object_close(us))
|
||||
goto unlock_legion_mutex;
|
||||
|
||||
node = node->next;
|
||||
if (node) {
|
||||
if (uwsgi_stats_comma(us))
|
||||
goto unlock_legion_mutex;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&legion->lock);
|
||||
|
||||
if (uwsgi_stats_list_close(us))
|
||||
goto end;
|
||||
// legion nodes end
|
||||
|
||||
if (uwsgi_stats_object_close(us))
|
||||
goto end;
|
||||
|
||||
legion = legion->next;
|
||||
if (legion) {
|
||||
if (uwsgi_stats_comma(us))
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi_stats_list_close(us))
|
||||
goto end;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
if (uwsgi_stats_object_close(us))
|
||||
goto end;
|
||||
|
||||
return us;
|
||||
#ifdef UWSGI_SSL
|
||||
unlock_legion_mutex:
|
||||
if (legion)
|
||||
pthread_mutex_unlock(&legion->lock);
|
||||
#endif
|
||||
end:
|
||||
free(us->base);
|
||||
free(us);
|
||||
@@ -1221,3 +1469,20 @@ void trigger_harakiri(int i) {
|
||||
// to avoid races
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_master_fix_request_counters() {
|
||||
int i;
|
||||
uint64_t total_counter = 0;
|
||||
for (i = 1; i <= uwsgi.numproc;i++) {
|
||||
uint64_t tmp_counter = 0;
|
||||
int j;
|
||||
for(j=0;j<uwsgi.cores;j++) {
|
||||
tmp_counter += uwsgi.workers[i].cores[j].requests;
|
||||
}
|
||||
uwsgi.workers[i].requests = tmp_counter;
|
||||
total_counter += tmp_counter;
|
||||
}
|
||||
|
||||
uwsgi.workers[0].requests = total_counter;
|
||||
}
|
||||
|
||||
|
||||
+15
-3
@@ -41,10 +41,22 @@ void uwsgi_mule(int id) {
|
||||
uwsgi_error("prctl()");
|
||||
}
|
||||
#endif
|
||||
|
||||
signal(SIGALRM, SIG_IGN);
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
signal(SIGINT, end_me);
|
||||
signal(SIGTERM, end_me);
|
||||
signal(SIGUSR1, SIG_IGN);
|
||||
signal(SIGUSR2, SIG_IGN);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGSTOP, SIG_IGN);
|
||||
signal(SIGTSTP, SIG_IGN);
|
||||
|
||||
uwsgi.muleid = id;
|
||||
// avoid race conditions
|
||||
uwsgi.mules[id - 1].id = id;
|
||||
uwsgi.mules[id - 1].pid = getpid();
|
||||
uwsgi.mypid = uwsgi.mules[id - 1].pid;
|
||||
|
||||
uwsgi_fixup_fds(0, id, NULL);
|
||||
|
||||
@@ -70,8 +82,8 @@ void uwsgi_mule(int id) {
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->mule) {
|
||||
if (uwsgi.p[i]->mule(uwsgi.mules[id - 1].patch) == 1) {
|
||||
// never here
|
||||
break;
|
||||
// never here ?
|
||||
end_me(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -198,7 +210,7 @@ void uwsgi_mule_handler() {
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
uwsgi_log("*** mule %d received a %d bytes message ***\n", uwsgi.muleid, len);
|
||||
uwsgi_log("*** mule %d received a %ld bytes message ***\n", uwsgi.muleid, (long) len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-3
@@ -20,7 +20,9 @@ void uwsgi_systemd_notify(char *message) {
|
||||
|
||||
msghdr->msg_iovlen = 3;
|
||||
|
||||
sendmsg(uwsgi.notification_fd, msghdr, 0);
|
||||
if (sendmsg(uwsgi.notification_fd, msghdr, 0) < 0) {
|
||||
uwsgi_error("sendmsg()");
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_systemd_notify_ready(void) {
|
||||
@@ -33,8 +35,9 @@ void uwsgi_systemd_notify_ready(void) {
|
||||
|
||||
msghdr->msg_iovlen = 1;
|
||||
|
||||
sendmsg(uwsgi.notification_fd, msghdr, 0);
|
||||
|
||||
if (sendmsg(uwsgi.notification_fd, msghdr, 0) < 0) {
|
||||
uwsgi_error("sendmsg()");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+194
-74
@@ -4,6 +4,17 @@
|
||||
|
||||
uWSGI offloading subsystem
|
||||
|
||||
steps to offload a task
|
||||
|
||||
1) allocate a uwsgi_offload_request structure (could be on stack)
|
||||
struct uwsgi_offload_request uor;
|
||||
2) prepare it for a specific engine (last argument is the takeover flag)
|
||||
uwsgi_offload_setup(my_engine, &uor, 1)
|
||||
3) run it (last argument is the waiter)
|
||||
int uwsgi_offload_run(wsgi_req, &uor, NULL);
|
||||
|
||||
between 2 and 3 you can set specific values
|
||||
|
||||
*/
|
||||
|
||||
|
||||
@@ -13,19 +24,20 @@ extern struct uwsgi_server uwsgi;
|
||||
#define uwsgi_offload_0r_1w(x, y) if (event_queue_del_fd(ut->queue, x, event_queue_read())) return -1;\
|
||||
if (event_queue_fd_read_to_write(ut->queue, y)) return -1;
|
||||
|
||||
static int uwsgi_offload_net_transfer(struct uwsgi_thread *, struct uwsgi_offload_request *, int);
|
||||
static int uwsgi_offload_sendfile_transfer(struct uwsgi_thread *, struct uwsgi_offload_request *, int);
|
||||
void uwsgi_offload_setup(struct uwsgi_offload_engine *uoe, struct uwsgi_offload_request *uor, struct wsgi_request *wsgi_req, uint8_t takeover) {
|
||||
|
||||
static void uwsgi_offload_setup(struct uwsgi_offload_request *uor, struct wsgi_request *wsgi_req,
|
||||
int (*func)(struct uwsgi_thread *, struct uwsgi_offload_request *, int)) {
|
||||
|
||||
wsgi_req->fd_closed = 1;
|
||||
memset(uor, 0, sizeof(struct uwsgi_offload_request));
|
||||
uor->s = wsgi_req->poll.fd;
|
||||
uor->func = func;
|
||||
// put socket in non-blocking mode
|
||||
uwsgi_socket_nb(uor->s);
|
||||
|
||||
|
||||
uor->engine = uoe;
|
||||
|
||||
uor->s = wsgi_req->fd;
|
||||
uor->fd = -1;
|
||||
uor->fd2 = -1;
|
||||
// an engine could changes behaviour based on pipe anf takeover values
|
||||
uor->pipe[0] = -1;
|
||||
uor->pipe[1] = -1;
|
||||
uor->takeover = takeover;
|
||||
|
||||
}
|
||||
|
||||
static int uwsgi_offload_enqueue(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) {
|
||||
@@ -38,79 +50,92 @@ static int uwsgi_offload_enqueue(struct wsgi_request *wsgi_req, struct uwsgi_off
|
||||
struct uwsgi_thread *ut = uwsgi.offload_thread[uc->offload_rr];
|
||||
uc->offload_rr++;
|
||||
if (write(ut->pipe[0], uor, sizeof(struct uwsgi_offload_request)) != sizeof(struct uwsgi_offload_request)) {
|
||||
if (uor->takeover) {
|
||||
wsgi_req->fd_closed = 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_offload_request_net_do(struct wsgi_request *wsgi_req, char *socket, struct uwsgi_buffer *ubuf) {
|
||||
/*
|
||||
|
||||
// fill offload request
|
||||
struct uwsgi_offload_request uor;
|
||||
uwsgi_offload_setup(&uor, wsgi_req, uwsgi_offload_net_transfer);
|
||||
transfer offload engine:
|
||||
name -> socket name
|
||||
ubuf -> data to send
|
||||
|
||||
uor.fd = uwsgi_connect(socket, 0, 1);
|
||||
if (uor.fd < 0) {
|
||||
uwsgi_error("uwsgi_offload_request_net_do() -> connect()");
|
||||
goto error;
|
||||
*/
|
||||
|
||||
int u_offload_transfer_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) {
|
||||
|
||||
if (!uor->name) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uor.ubuf = ubuf;
|
||||
|
||||
if (uwsgi_offload_enqueue(wsgi_req, &uor)) {
|
||||
goto error2;
|
||||
uor->fd = uwsgi_connect(uor->ubuf->buf, 0, 1);
|
||||
if (uor->fd < 0) {
|
||||
uwsgi_error("u_offload_transfer_prepare()/connect()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error2:
|
||||
close(uor.fd);
|
||||
error:
|
||||
wsgi_req->fd_closed = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int uwsgi_offload_request_sendfile_do(struct wsgi_request *wsgi_req, char *filename, size_t len) {
|
||||
/*
|
||||
|
||||
// fill offload request
|
||||
struct uwsgi_offload_request uor;
|
||||
uwsgi_offload_setup(&uor, wsgi_req, uwsgi_offload_sendfile_transfer);
|
||||
sendfile offload engine:
|
||||
name -> filename to transfer
|
||||
fd -> file descriptor of file to transfer
|
||||
fd2 -> sendfile destination (default wsgi_req->fd)
|
||||
len -> size of the file or amount of data to transfer
|
||||
pos -> position in the file
|
||||
|
||||
uor.fd = open(filename, O_RDONLY | O_NONBLOCK);
|
||||
if (uor.fd < 0) {
|
||||
uwsgi_error_open(filename);
|
||||
goto error;
|
||||
*/
|
||||
|
||||
static int u_offload_sendfile_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) {
|
||||
|
||||
if (!uor->name && uor->fd == -1) return -1;
|
||||
|
||||
if (uor->name) {
|
||||
uor->fd = open(uor->name, O_RDONLY | O_NONBLOCK);
|
||||
if (uor->fd < 0) {
|
||||
uwsgi_error_open(uor->name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// make a fstat to get the file size
|
||||
if (!len) {
|
||||
if (!uor->len) {
|
||||
struct stat st;
|
||||
if (fstat(uor.fd, &st)) {
|
||||
uwsgi_error("fstat()");
|
||||
goto error2;
|
||||
if (fstat(uor->fd, &st)) {
|
||||
uwsgi_error("u_offload_sendfile_prepare()/fstat()");
|
||||
if (uor->name) {
|
||||
close(uor->fd);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
len = st.st_size;
|
||||
uor->len = st.st_size;
|
||||
}
|
||||
|
||||
uor.len = len;
|
||||
|
||||
if (uwsgi_offload_enqueue(wsgi_req, &uor)) {
|
||||
goto error2;
|
||||
if (uor->fd2 == -1) {
|
||||
uor->fd2 = uor->s;
|
||||
}
|
||||
uor->s = -1;
|
||||
|
||||
return 0;
|
||||
|
||||
error2:
|
||||
close(uor.fd);
|
||||
error:
|
||||
wsgi_req->fd_closed = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void uwsgi_offload_close(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor) {
|
||||
// close the socket and the file descriptor
|
||||
close(uor->s);
|
||||
close(uor->fd);
|
||||
if (uor->takeover && uor->s > -1) {
|
||||
close(uor->s);
|
||||
}
|
||||
if (uor->fd != -1) {
|
||||
close(uor->fd);
|
||||
}
|
||||
if (uor->fd2 != -1) {
|
||||
close(uor->fd2);
|
||||
}
|
||||
// remove the structure from the linked list;
|
||||
struct uwsgi_offload_request *prev = uor->prev;
|
||||
struct uwsgi_offload_request *next = uor->next;
|
||||
@@ -139,6 +164,11 @@ static void uwsgi_offload_close(struct uwsgi_thread *ut, struct uwsgi_offload_re
|
||||
uwsgi_buffer_destroy(uor->ubuf);
|
||||
}
|
||||
|
||||
if (uor->pipe[0] != -1) {
|
||||
close(uor->pipe[1]);
|
||||
close(uor->pipe[0]);
|
||||
}
|
||||
|
||||
free(uor);
|
||||
}
|
||||
|
||||
@@ -159,7 +189,7 @@ static void uwsgi_offload_append(struct uwsgi_thread *ut, struct uwsgi_offload_r
|
||||
static struct uwsgi_offload_request *uwsgi_offload_get_by_fd(struct uwsgi_thread *ut, int s) {
|
||||
struct uwsgi_offload_request *uor = ut->offload_requests_head;
|
||||
while (uor) {
|
||||
if (uor->s == s || uor->fd == s) {
|
||||
if (uor->s == s || uor->fd == s || uor->fd2 == s) {
|
||||
return uor;
|
||||
}
|
||||
uor = uor->next;
|
||||
@@ -185,8 +215,8 @@ static void uwsgi_offload_loop(struct uwsgi_thread *ut) {
|
||||
free(uor);
|
||||
continue;
|
||||
}
|
||||
// start monitoring socket for write
|
||||
if (uor->func(ut, uor, -1)) {
|
||||
// cal the event function for the first time
|
||||
if (uor->engine->event_func(ut, uor, -1)) {
|
||||
uwsgi_offload_close(ut, uor);
|
||||
continue;
|
||||
}
|
||||
@@ -199,7 +229,7 @@ static void uwsgi_offload_loop(struct uwsgi_thread *ut) {
|
||||
if (!uor)
|
||||
continue;
|
||||
// run the hook
|
||||
if (uor->func(ut, uor, interesting_fd)) {
|
||||
if (uor->engine->event_func(ut, uor, interesting_fd)) {
|
||||
uwsgi_offload_close(ut, uor);
|
||||
}
|
||||
}
|
||||
@@ -221,14 +251,14 @@ the offload task starts after having acquired the file fd
|
||||
|
||||
*/
|
||||
|
||||
static int uwsgi_offload_sendfile_transfer(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) {
|
||||
static int u_offload_sendfile_do(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) {
|
||||
|
||||
if (fd == -1) {
|
||||
if (event_queue_add_fd_write(ut->queue, uor->s)) return -1;
|
||||
if (event_queue_add_fd_write(ut->queue, uor->fd2)) return -1;
|
||||
return 0;
|
||||
}
|
||||
#if defined(__linux__) || defined(__sun__)
|
||||
ssize_t len = sendfile(uor->s, uor->fd, &uor->pos, 128 * 1024);
|
||||
ssize_t len = sendfile(uor->fd2, uor->fd, &uor->pos, 128 * 1024);
|
||||
if (len > 0) {
|
||||
uor->written += len;
|
||||
if (uor->written >= uor->len) {
|
||||
@@ -238,25 +268,25 @@ static int uwsgi_offload_sendfile_transfer(struct uwsgi_thread *ut, struct uwsgi
|
||||
}
|
||||
else if (len < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("sendfile()");
|
||||
uwsgi_error("u_offload_sendfile_do()");
|
||||
}
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
off_t sbytes = 0;
|
||||
int ret = sendfile(uor->fd, uor->s, uor->pos, 0, NULL, &sbytes, 0);
|
||||
int ret = sendfile(uor->fd, uor->fd2, uor->pos, 0, NULL, &sbytes, 0);
|
||||
// transfer finished
|
||||
if (ret == -1) {
|
||||
uor->pos += sbytes;
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("sendfile()");
|
||||
uwsgi_error("u_offload_sendfile_do()");
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
off_t len = 0;
|
||||
int ret = sendfile(uor->fd, uor->s, uor->pos, &len, NULL, 0);
|
||||
int ret = sendfile(uor->fd, uor->fd2, uor->pos, &len, NULL, 0);
|
||||
// transfer finished
|
||||
if (ret == -1) {
|
||||
uor->pos += len;
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("sendfile()");
|
||||
uwsgi_error("u_offload_sendfile_do()");
|
||||
}
|
||||
#endif
|
||||
return -1;
|
||||
@@ -273,7 +303,7 @@ the offload task starts soon after the call to connect()
|
||||
3 -> write to s
|
||||
4 -> write to fd
|
||||
*/
|
||||
static int uwsgi_offload_net_transfer(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) {
|
||||
static int u_offload_transfer_do(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) {
|
||||
|
||||
ssize_t rlen;
|
||||
|
||||
@@ -289,7 +319,7 @@ static int uwsgi_offload_net_transfer(struct uwsgi_thread *ut, struct uwsgi_offl
|
||||
if (fd == uor->fd) {
|
||||
uor->status = 1;
|
||||
// ok try to send the request right now...
|
||||
return uwsgi_offload_net_transfer(ut, uor, fd);
|
||||
return u_offload_transfer_do(ut, uor, fd);
|
||||
}
|
||||
return -1;
|
||||
// write event (or just connected)
|
||||
@@ -307,7 +337,7 @@ static int uwsgi_offload_net_transfer(struct uwsgi_thread *ut, struct uwsgi_offl
|
||||
}
|
||||
else if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("uwsgi_offload_net_transfer() -> write()");
|
||||
uwsgi_error("u_offload_transfer_do() -> write()");
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
@@ -327,11 +357,11 @@ static int uwsgi_offload_net_transfer(struct uwsgi_thread *ut, struct uwsgi_offl
|
||||
}
|
||||
if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("uwsgi_offload_net_transfer() -> read()/fd");
|
||||
uwsgi_error("u_offload_transfer_do() -> read()/fd");
|
||||
}
|
||||
}
|
||||
else if (fd == uor->s) {
|
||||
rlen = read(uor->fd, uor->buf, 4096);
|
||||
rlen = read(uor->s, uor->buf, 4096);
|
||||
if (rlen > 0) {
|
||||
uor->to_write = rlen;
|
||||
uor->pos = 0;
|
||||
@@ -341,7 +371,7 @@ static int uwsgi_offload_net_transfer(struct uwsgi_thread *ut, struct uwsgi_offl
|
||||
}
|
||||
if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("uwsgi_offload_net_transfer() -> read()/s");
|
||||
uwsgi_error("u_offload_transfer_do() -> read()/s");
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
@@ -360,7 +390,7 @@ static int uwsgi_offload_net_transfer(struct uwsgi_thread *ut, struct uwsgi_offl
|
||||
}
|
||||
else if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("uwsgi_offload_net_transfer() -> write()/s");
|
||||
uwsgi_error("u_offload_transfer_do() -> write()/s");
|
||||
}
|
||||
return -1;
|
||||
// write event on fd
|
||||
@@ -378,7 +408,7 @@ static int uwsgi_offload_net_transfer(struct uwsgi_thread *ut, struct uwsgi_offl
|
||||
}
|
||||
else if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("uwsgi_offload_net_transfer() -> write()/fd");
|
||||
uwsgi_error("u_offload_transfer_do() -> write()/fd");
|
||||
}
|
||||
return -1;
|
||||
default:
|
||||
@@ -387,3 +417,93 @@ static int uwsgi_offload_net_transfer(struct uwsgi_thread *ut, struct uwsgi_offl
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int uwsgi_offload_run(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor, int *wait) {
|
||||
|
||||
if (uor->engine->prepare_func(wsgi_req, uor)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wait) {
|
||||
if (pipe(uor->pipe)) {
|
||||
uwsgi_error("uwsgi_offload_setup()/pipe()");
|
||||
return -1;
|
||||
}
|
||||
*wait = uor->pipe[0];
|
||||
uwsgi_socket_nb(uor->pipe[0]);
|
||||
uwsgi_socket_nb(uor->pipe[1]);
|
||||
}
|
||||
|
||||
if (uor->takeover) {
|
||||
wsgi_req->fd_closed = 1;
|
||||
}
|
||||
|
||||
if (uwsgi_offload_enqueue(wsgi_req, uor)) {
|
||||
close(uor->pipe[0]);
|
||||
close(uor->pipe[1]);
|
||||
if (uor->takeover) {
|
||||
wsgi_req->fd_closed = 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
};
|
||||
|
||||
struct uwsgi_offload_engine *uwsgi_offload_engine_by_name(char *name) {
|
||||
struct uwsgi_offload_engine *uoe = uwsgi.offload_engines;
|
||||
while(uoe) {
|
||||
if (!strcmp(name, uoe->name)) {
|
||||
return uoe;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_offload_engine *uwsgi_offload_register_engine(char *name, int (*prepare_func)(struct wsgi_request *, struct uwsgi_offload_request *), int (*event_func) (struct uwsgi_thread *, struct uwsgi_offload_request *, int)) {
|
||||
|
||||
struct uwsgi_offload_engine *old_engine=NULL,*engine=uwsgi.offload_engines;
|
||||
while(engine) {
|
||||
if (!strcmp(engine->name, name)) {
|
||||
return engine;
|
||||
}
|
||||
old_engine = engine;
|
||||
engine = engine->next;
|
||||
}
|
||||
|
||||
engine = uwsgi_calloc(sizeof(struct uwsgi_offload_engine));
|
||||
engine->name = name;
|
||||
engine->prepare_func = prepare_func;
|
||||
engine->event_func = event_func;
|
||||
|
||||
if (old_engine) {
|
||||
old_engine->next = engine;
|
||||
}
|
||||
else {
|
||||
uwsgi.offload_engines = engine;
|
||||
}
|
||||
|
||||
return engine;
|
||||
}
|
||||
|
||||
void uwsgi_offload_engines_register_all() {
|
||||
uwsgi.offload_engine_sendfile = uwsgi_offload_register_engine("sendfile", u_offload_sendfile_prepare, u_offload_sendfile_do);
|
||||
uwsgi.offload_engine_transfer = uwsgi_offload_register_engine("transfer", u_offload_transfer_prepare, u_offload_transfer_do);
|
||||
}
|
||||
|
||||
int uwsgi_offload_request_sendfile_do(struct wsgi_request *wsgi_req, int fd, size_t len) {
|
||||
struct uwsgi_offload_request uor;
|
||||
uwsgi_offload_setup(uwsgi.offload_engine_sendfile, &uor, wsgi_req, 1);
|
||||
uor.fd = fd;
|
||||
uor.len = len;
|
||||
return uwsgi_offload_run(wsgi_req, &uor, NULL);
|
||||
}
|
||||
|
||||
int uwsgi_offload_request_net_do(struct wsgi_request *wsgi_req, char *socketname, struct uwsgi_buffer *ubuf) {
|
||||
struct uwsgi_offload_request uor;
|
||||
uwsgi_offload_setup(uwsgi.offload_engine_transfer, &uor, wsgi_req, 1);
|
||||
uor.name = socketname;
|
||||
uor.ubuf = ubuf;
|
||||
return uwsgi_offload_run(wsgi_req, &uor, NULL);
|
||||
}
|
||||
|
||||
+3
-4
@@ -24,7 +24,7 @@ static void uwsgi_plugin_parse_section(char *filename) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static int plugin_already_loaded(const char *plugin) {
|
||||
int plugin_already_loaded(const char *plugin) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
@@ -76,8 +76,8 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
|
||||
char *plugin_filename = NULL;
|
||||
|
||||
int need_free = 0;
|
||||
char *plugin_name = plugin;
|
||||
char *plugin_symbol_name_start = plugin;
|
||||
char *plugin_name = uwsgi_strip(uwsgi_str(plugin));
|
||||
char *plugin_symbol_name_start = plugin_name;
|
||||
|
||||
struct uwsgi_plugin *up;
|
||||
char linkpath_buf[1024], linkpath[1024];
|
||||
@@ -165,7 +165,6 @@ success:
|
||||
uwsgi_log("%s\n", linkpath);
|
||||
#endif
|
||||
free(plugin_entry_symbol);
|
||||
up = dlsym(plugin_handle, plugin_entry_symbol);
|
||||
char *slash = uwsgi_get_last_char(linkpath, '/');
|
||||
if (!slash) {
|
||||
slash = linkpath;
|
||||
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
|
||||
upload progress facilities
|
||||
|
||||
*/
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
char *uwsgi_upload_progress_create(struct wsgi_request *wsgi_req, int *fd) {
|
||||
const char *x_progress_id = "X-Progress-ID=";
|
||||
char *xpi_ptr = (char *) x_progress_id;
|
||||
uint16_t i;
|
||||
char *upload_progress_filename = NULL;
|
||||
|
||||
if (wsgi_req->uri_len <= 51)
|
||||
return NULL;
|
||||
|
||||
|
||||
for (i = 0; i < wsgi_req->uri_len; i++) {
|
||||
if (wsgi_req->uri[i] == xpi_ptr[0]) {
|
||||
if (xpi_ptr[0] == '=') {
|
||||
if (wsgi_req->uri + i + 36 <= wsgi_req->uri + wsgi_req->uri_len) {
|
||||
upload_progress_filename = wsgi_req->uri + i + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
xpi_ptr++;
|
||||
}
|
||||
else {
|
||||
xpi_ptr = (char *) x_progress_id;
|
||||
}
|
||||
}
|
||||
|
||||
// now check for valid uuid (from spec available at http://en.wikipedia.org/wiki/Universally_unique_identifier)
|
||||
if (!upload_progress_filename)
|
||||
return NULL;
|
||||
|
||||
uwsgi_log("upload progress uuid = %.*s\n", 36, upload_progress_filename);
|
||||
if (!check_hex(upload_progress_filename, 8))
|
||||
return NULL;
|
||||
if (upload_progress_filename[8] != '-')
|
||||
return NULL;
|
||||
|
||||
if (!check_hex(upload_progress_filename + 9, 4))
|
||||
return NULL;
|
||||
if (upload_progress_filename[13] != '-')
|
||||
return NULL;
|
||||
|
||||
if (!check_hex(upload_progress_filename + 14, 4))
|
||||
return NULL;
|
||||
if (upload_progress_filename[18] != '-')
|
||||
return NULL;
|
||||
|
||||
if (!check_hex(upload_progress_filename + 19, 4))
|
||||
return NULL;
|
||||
if (upload_progress_filename[23] != '-')
|
||||
return NULL;
|
||||
|
||||
if (!check_hex(upload_progress_filename + 24, 12))
|
||||
return NULL;
|
||||
|
||||
upload_progress_filename = uwsgi_concat4n(uwsgi.upload_progress, strlen(uwsgi.upload_progress), "/", 1, upload_progress_filename, 36, ".js", 3);
|
||||
// here we use O_EXCL to avoid eventual application bug in uuid generation/using
|
||||
*fd = open(upload_progress_filename, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP);
|
||||
if (*fd < 0) {
|
||||
uwsgi_error_open(upload_progress_filename);
|
||||
free(upload_progress_filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return upload_progress_filename;
|
||||
}
|
||||
|
||||
int uwsgi_upload_progress_update(struct wsgi_request *wsgi_req, int fd, size_t remains) {
|
||||
char buf[4096];
|
||||
|
||||
int ret = snprintf(buf, 4096, "{ \"state\" : \"uploading\", \"received\" : %llu, \"size\" : %llu }\r\n", (unsigned long long) (wsgi_req->post_cl - remains), (unsigned long long) wsgi_req->post_cl);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lseek(fd, 0, SEEK_SET)) {
|
||||
uwsgi_error("uwsgi_upload_progress_update()/lseek()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (write(fd, buf, ret) != ret) {
|
||||
uwsgi_error("uwsgi_upload_progress_update()/write()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fsync(fd)) {
|
||||
uwsgi_error("uwsgi_upload_progress_update()/fsync()");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uwsgi_upload_progress_destroy(char *filename, int fd) {
|
||||
close(fd);
|
||||
if (unlink(filename)) {
|
||||
uwsgi_error("uwsgi_upload_progress_destroy()/unlink()");
|
||||
}
|
||||
free(filename);
|
||||
}
|
||||
+367
-1383
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -65,7 +65,7 @@ void uwsgi_init_queue() {
|
||||
|
||||
uwsgi.queue_lock = uwsgi_rwlock_init("queue");
|
||||
|
||||
uwsgi_log("*** Queue subsystem initialized: %dMB preallocated ***\n", (uwsgi.queue_blocksize * uwsgi.queue_size) / (1024 * 1024));
|
||||
uwsgi_log("*** Queue subsystem initialized: %luMB preallocated ***\n", (uwsgi.queue_blocksize * uwsgi.queue_size) / (1024 * 1024));
|
||||
}
|
||||
|
||||
char *uwsgi_queue_get(uint64_t index, uint64_t * size) {
|
||||
|
||||
+334
-32
@@ -1,65 +1,367 @@
|
||||
/*
|
||||
|
||||
uWSGI timers implementation
|
||||
uWSGI rbtree implementation based on nginx
|
||||
|
||||
based on Linux hrtimers and nginx timeout management.
|
||||
|
||||
rbtree with allowed duplicate keys is used
|
||||
Copyright (C) Igor Sysoev
|
||||
Copyright (C) Nginx, Inc.
|
||||
Copyright (C) Unbit S.a.s.
|
||||
|
||||
The red-black tree code is based on the algorithm described in
|
||||
the "Introduction to Algorithms" by Cormen, Leiserson and Rivest.
|
||||
*/
|
||||
|
||||
#include "uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
struct rb_root *uwsgi_init_rb_timer() {
|
||||
#define uwsgi_rbt_red(node) ((node)->color = 1)
|
||||
#define uwsgi_rbt_black(node) ((node)->color = 0)
|
||||
#define uwsgi_rbt_is_red(node) ((node)->color)
|
||||
#define uwsgi_rbt_is_black(node) (!uwsgi_rbt_is_red(node))
|
||||
#define uwsgi_rbt_copy_color(n1, n2) (n1->color = n2->color)
|
||||
|
||||
struct rb_root *u_rb_root = uwsgi_malloc(sizeof(struct rb_root));
|
||||
|
||||
u_rb_root->rb_node = NULL;
|
||||
struct uwsgi_rbtree *uwsgi_init_rb_timer() {
|
||||
|
||||
return u_rb_root;
|
||||
struct uwsgi_rbtree *tree = uwsgi_calloc(sizeof(struct uwsgi_rbtree));
|
||||
struct uwsgi_rb_timer *sentinel = uwsgi_calloc(sizeof(struct uwsgi_rb_timer));
|
||||
// no need to set it black, calloc already did it
|
||||
//uwsgi_rbt_black(sentinel);
|
||||
tree->root = sentinel;
|
||||
tree->sentinel = sentinel;
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
struct uwsgi_rb_timer *uwsgi_min_rb_timer(struct rb_root *root) {
|
||||
struct uwsgi_rb_timer *uwsgi_min_rb_timer(struct uwsgi_rbtree *tree, struct uwsgi_rb_timer *node) {
|
||||
|
||||
struct rb_node *node = root->rb_node;
|
||||
if (!node)
|
||||
node = tree->root;
|
||||
struct uwsgi_rb_timer *sentinel = tree->sentinel;
|
||||
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
if (tree->root == sentinel) return NULL;
|
||||
|
||||
while (node->rb_left != NULL) {
|
||||
node = node->rb_left;
|
||||
while (node->left != sentinel) {
|
||||
node = node->left;
|
||||
}
|
||||
|
||||
return ((struct uwsgi_rb_timer *) node);
|
||||
return node;
|
||||
}
|
||||
|
||||
struct uwsgi_rb_timer *uwsgi_add_rb_timer(struct rb_root *root, time_t key, void *data) {
|
||||
static void uwsgi_rbtree_lr(struct uwsgi_rb_timer **root, struct uwsgi_rb_timer *sentinel, struct uwsgi_rb_timer *node) {
|
||||
|
||||
struct uwsgi_rb_timer *urbt = uwsgi_malloc(sizeof(struct uwsgi_rb_timer));
|
||||
struct rb_node **p = &root->rb_node, *parent = NULL;
|
||||
struct uwsgi_rb_timer *current_rb_timer;
|
||||
struct uwsgi_rb_timer *temp;
|
||||
|
||||
memset(urbt, 0, sizeof(struct uwsgi_rb_timer));
|
||||
temp = node->right;
|
||||
node->right = temp->left;
|
||||
|
||||
urbt->key = key;
|
||||
urbt->data = data;
|
||||
if (temp->left != sentinel) {
|
||||
temp->left->parent = node;
|
||||
}
|
||||
|
||||
while (*p) {
|
||||
parent = *p;
|
||||
temp->parent = node->parent;
|
||||
|
||||
current_rb_timer = (struct uwsgi_rb_timer *) parent;
|
||||
if (node == *root) {
|
||||
*root = temp;
|
||||
|
||||
}
|
||||
else if (node == node->parent->left) {
|
||||
node->parent->left = temp;
|
||||
|
||||
}
|
||||
else {
|
||||
node->parent->right = temp;
|
||||
}
|
||||
|
||||
temp->left = node;
|
||||
node->parent = temp;
|
||||
}
|
||||
|
||||
|
||||
static void uwsgi_rbtree_rr(struct uwsgi_rb_timer **root, struct uwsgi_rb_timer *sentinel, struct uwsgi_rb_timer *node) {
|
||||
|
||||
struct uwsgi_rb_timer *temp;
|
||||
|
||||
temp = node->left;
|
||||
node->left = temp->right;
|
||||
|
||||
if (temp->right != sentinel) {
|
||||
temp->right->parent = node;
|
||||
}
|
||||
|
||||
temp->parent = node->parent;
|
||||
|
||||
if (node == *root) {
|
||||
*root = temp;
|
||||
|
||||
}
|
||||
else if (node == node->parent->right) {
|
||||
node->parent->right = temp;
|
||||
|
||||
}
|
||||
else {
|
||||
node->parent->left = temp;
|
||||
}
|
||||
|
||||
temp->right = node;
|
||||
node->parent = temp;
|
||||
}
|
||||
|
||||
|
||||
static void uwsgi_rbt_add(struct uwsgi_rb_timer *temp, struct uwsgi_rb_timer *node, struct uwsgi_rb_timer *sentinel) {
|
||||
struct uwsgi_rb_timer **p;
|
||||
|
||||
for (;;) {
|
||||
|
||||
p = (node->value < temp->value) ? &temp->left : &temp->right;
|
||||
if (*p == sentinel)
|
||||
break;
|
||||
temp = *p;
|
||||
}
|
||||
|
||||
*p = node;
|
||||
node->parent = temp;
|
||||
node->left = sentinel;
|
||||
node->right = sentinel;
|
||||
uwsgi_rbt_red(node);
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_rb_timer *uwsgi_add_rb_timer(struct uwsgi_rbtree *tree, uint64_t value, void *data) {
|
||||
|
||||
struct uwsgi_rb_timer *node = uwsgi_malloc(sizeof(struct uwsgi_rb_timer));
|
||||
struct uwsgi_rb_timer *new_node = node;
|
||||
node->value = value;
|
||||
node->data = data;
|
||||
|
||||
struct uwsgi_rb_timer *temp = NULL;
|
||||
|
||||
/* a binary tree insert */
|
||||
|
||||
struct uwsgi_rb_timer **root = &tree->root;
|
||||
struct uwsgi_rb_timer *sentinel = tree->sentinel;
|
||||
|
||||
if (*root == sentinel) {
|
||||
node->parent = NULL;
|
||||
node->left = sentinel;
|
||||
node->right = sentinel;
|
||||
uwsgi_rbt_black(node);
|
||||
*root = node;
|
||||
return new_node;
|
||||
}
|
||||
|
||||
uwsgi_rbt_add(*root, node, sentinel);
|
||||
|
||||
/* re-balance tree */
|
||||
|
||||
while (node != *root && uwsgi_rbt_is_red(node->parent)) {
|
||||
|
||||
if (node->parent == node->parent->parent->left) {
|
||||
temp = node->parent->parent->right;
|
||||
|
||||
if (uwsgi_rbt_is_red(temp)) {
|
||||
uwsgi_rbt_black(node->parent);
|
||||
uwsgi_rbt_black(temp);
|
||||
uwsgi_rbt_red(node->parent->parent);
|
||||
node = node->parent->parent;
|
||||
|
||||
}
|
||||
else {
|
||||
if (node == node->parent->right) {
|
||||
node = node->parent;
|
||||
uwsgi_rbtree_lr(root, sentinel, node);
|
||||
}
|
||||
|
||||
uwsgi_rbt_black(node->parent);
|
||||
uwsgi_rbt_red(node->parent->parent);
|
||||
uwsgi_rbtree_rr(root, sentinel, node->parent->parent);
|
||||
}
|
||||
|
||||
if (key <= current_rb_timer->key) {
|
||||
p = &(*p)->rb_left;
|
||||
}
|
||||
else {
|
||||
p = &(*p)->rb_right;
|
||||
temp = node->parent->parent->left;
|
||||
|
||||
if (uwsgi_rbt_is_red(temp)) {
|
||||
uwsgi_rbt_black(node->parent);
|
||||
uwsgi_rbt_black(temp);
|
||||
uwsgi_rbt_red(node->parent->parent);
|
||||
node = node->parent->parent;
|
||||
|
||||
}
|
||||
else {
|
||||
if (node == node->parent->left) {
|
||||
node = node->parent;
|
||||
uwsgi_rbtree_rr(root, sentinel, node);
|
||||
}
|
||||
|
||||
uwsgi_rbt_black(node->parent);
|
||||
uwsgi_rbt_red(node->parent->parent);
|
||||
uwsgi_rbtree_lr(root, sentinel, node->parent->parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rb_link_node((struct rb_node *) urbt, parent, p);
|
||||
uwsgi_rbt_black(*root);
|
||||
|
||||
rb_insert_color((struct rb_node *) urbt, root);
|
||||
return new_node;
|
||||
}
|
||||
|
||||
return urbt;
|
||||
void uwsgi_del_rb_timer(struct uwsgi_rbtree *tree, struct uwsgi_rb_timer *node) {
|
||||
uint8_t red;
|
||||
struct uwsgi_rb_timer **root, *sentinel, *subst, *temp, *w;
|
||||
|
||||
/* a binary tree delete */
|
||||
|
||||
root = &tree->root;
|
||||
sentinel = tree->sentinel;
|
||||
|
||||
if (node->left == sentinel) {
|
||||
temp = node->right;
|
||||
subst = node;
|
||||
|
||||
}
|
||||
else if (node->right == sentinel) {
|
||||
temp = node->left;
|
||||
subst = node;
|
||||
|
||||
}
|
||||
else {
|
||||
subst = uwsgi_min_rb_timer(tree, node->right);
|
||||
|
||||
if (subst->left != sentinel) {
|
||||
temp = subst->left;
|
||||
}
|
||||
else {
|
||||
temp = subst->right;
|
||||
}
|
||||
}
|
||||
|
||||
if (subst == *root) {
|
||||
*root = temp;
|
||||
uwsgi_rbt_black(temp);
|
||||
return;
|
||||
}
|
||||
|
||||
red = uwsgi_rbt_is_red(subst);
|
||||
|
||||
if (subst == subst->parent->left) {
|
||||
subst->parent->left = temp;
|
||||
|
||||
}
|
||||
else {
|
||||
subst->parent->right = temp;
|
||||
}
|
||||
|
||||
if (subst == node) {
|
||||
|
||||
temp->parent = subst->parent;
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
if (subst->parent == node) {
|
||||
temp->parent = subst;
|
||||
|
||||
}
|
||||
else {
|
||||
temp->parent = subst->parent;
|
||||
}
|
||||
|
||||
subst->left = node->left;
|
||||
subst->right = node->right;
|
||||
subst->parent = node->parent;
|
||||
uwsgi_rbt_copy_color(subst, node);
|
||||
|
||||
if (node == *root) {
|
||||
*root = subst;
|
||||
|
||||
}
|
||||
else {
|
||||
if (node == node->parent->left) {
|
||||
node->parent->left = subst;
|
||||
}
|
||||
else {
|
||||
node->parent->right = subst;
|
||||
}
|
||||
}
|
||||
|
||||
if (subst->left != sentinel) {
|
||||
subst->left->parent = subst;
|
||||
}
|
||||
|
||||
if (subst->right != sentinel) {
|
||||
subst->right->parent = subst;
|
||||
}
|
||||
}
|
||||
|
||||
if (red) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* a delete fixup */
|
||||
|
||||
while (temp != *root && uwsgi_rbt_is_black(temp)) {
|
||||
|
||||
if (temp == temp->parent->left) {
|
||||
w = temp->parent->right;
|
||||
|
||||
if (uwsgi_rbt_is_red(w)) {
|
||||
uwsgi_rbt_black(w);
|
||||
uwsgi_rbt_red(temp->parent);
|
||||
uwsgi_rbtree_lr(root, sentinel, temp->parent);
|
||||
w = temp->parent->right;
|
||||
}
|
||||
|
||||
if (uwsgi_rbt_is_black(w->left) && uwsgi_rbt_is_black(w->right)) {
|
||||
uwsgi_rbt_red(w);
|
||||
temp = temp->parent;
|
||||
|
||||
}
|
||||
else {
|
||||
if (uwsgi_rbt_is_black(w->right)) {
|
||||
uwsgi_rbt_black(w->left);
|
||||
uwsgi_rbt_red(w);
|
||||
uwsgi_rbtree_rr(root, sentinel, w);
|
||||
w = temp->parent->right;
|
||||
}
|
||||
|
||||
uwsgi_rbt_copy_color(w, temp->parent);
|
||||
uwsgi_rbt_black(temp->parent);
|
||||
uwsgi_rbt_black(w->right);
|
||||
uwsgi_rbtree_lr(root, sentinel, temp->parent);
|
||||
temp = *root;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
w = temp->parent->left;
|
||||
|
||||
if (uwsgi_rbt_is_red(w)) {
|
||||
uwsgi_rbt_black(w);
|
||||
uwsgi_rbt_red(temp->parent);
|
||||
uwsgi_rbtree_rr(root, sentinel, temp->parent);
|
||||
w = temp->parent->left;
|
||||
}
|
||||
|
||||
if (uwsgi_rbt_is_black(w->left) && uwsgi_rbt_is_black(w->right)) {
|
||||
uwsgi_rbt_red(w);
|
||||
temp = temp->parent;
|
||||
|
||||
}
|
||||
else {
|
||||
if (uwsgi_rbt_is_black(w->left)) {
|
||||
uwsgi_rbt_black(w->right);
|
||||
uwsgi_rbt_red(w);
|
||||
uwsgi_rbtree_lr(root, sentinel, w);
|
||||
w = temp->parent->left;
|
||||
}
|
||||
|
||||
uwsgi_rbt_copy_color(w, temp->parent);
|
||||
uwsgi_rbt_black(temp->parent);
|
||||
uwsgi_rbt_black(w->left);
|
||||
uwsgi_rbtree_rr(root, sentinel, temp->parent);
|
||||
temp = *root;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_rbt_black(temp);
|
||||
}
|
||||
|
||||
+572
@@ -0,0 +1,572 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_simple_wait_read_hook(int fd, int timeout) {
|
||||
struct pollfd upoll;
|
||||
timeout = timeout * 1000;
|
||||
|
||||
upoll.fd = fd;
|
||||
upoll.events = POLLIN;
|
||||
upoll.revents = 0;
|
||||
int ret = poll(&upoll, 1, timeout);
|
||||
|
||||
if (ret > 0) {
|
||||
if (upoll.revents & POLLIN) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (ret < 0) {
|
||||
uwsgi_error("uwsgi_simple_wait_read_hook()/poll()");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
seek()/rewind() language-independent implementations.
|
||||
*/
|
||||
|
||||
void uwsgi_request_body_seek(struct wsgi_request *wsgi_req, off_t pos) {
|
||||
if (wsgi_req->post_file) {
|
||||
if (pos < 0) {
|
||||
if (fseek(wsgi_req->post_file, pos, SEEK_CUR)) {
|
||||
uwsgi_error("uwsgi_request_body_seek()/fseek()");
|
||||
}
|
||||
wsgi_req->post_pos = ftell(wsgi_req->post_file);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fseek(wsgi_req->post_file, pos, SEEK_SET)) {
|
||||
uwsgi_error("uwsgi_request_body_seek()/fseek()");
|
||||
}
|
||||
wsgi_req->post_pos = ftell(wsgi_req->post_file);
|
||||
return;
|
||||
}
|
||||
|
||||
if (uwsgi.post_buffering) {
|
||||
if (pos < 0) {
|
||||
if (pos > (off_t) wsgi_req->post_pos) {
|
||||
wsgi_req->post_pos = 0;
|
||||
return;
|
||||
}
|
||||
wsgi_req->post_pos -= pos;
|
||||
return;
|
||||
}
|
||||
if (pos >= (off_t) uwsgi.post_buffering) {
|
||||
pos = uwsgi.post_buffering - 1;
|
||||
}
|
||||
wsgi_req->post_pos = pos;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
read() and readline() language-independent implementations.
|
||||
|
||||
*/
|
||||
|
||||
#define uwsgi_read_error0(x) uwsgi_log("[uwsgi-body-read] Error reading %llu bytes. Content-Length: %llu consumed: %llu left: %llu message: Client closed connection\n",\
|
||||
(unsigned long long) x,\
|
||||
(unsigned long long) wsgi_req->post_cl, (unsigned long long) wsgi_req->post_pos, (unsigned long long) wsgi_req->post_cl-wsgi_req->post_pos);
|
||||
|
||||
#define uwsgi_read_error(x) uwsgi_log("[uwsgi-body-read] Error reading %llu bytes. Content-Length: %llu consumed: %llu left: %llu message: %s\n",\
|
||||
(unsigned long long) x,\
|
||||
(unsigned long long) wsgi_req->post_cl, (unsigned long long) wsgi_req->post_pos, (unsigned long long) wsgi_req->post_cl-wsgi_req->post_pos,\
|
||||
strerror(errno));
|
||||
|
||||
#define uwsgi_read_timeout(x) uwsgi_log("[uwsgi-body-read] Timeout reading %llu bytes. Content-Length: %llu consumed: %llu left: %llu\n",\
|
||||
(unsigned long long) x,\
|
||||
(unsigned long long) wsgi_req->post_cl, (unsigned long long) wsgi_req->post_pos, (unsigned long long) wsgi_req->post_cl-wsgi_req->post_pos);
|
||||
|
||||
static int consume_body_for_readline(struct wsgi_request *wsgi_req) {
|
||||
|
||||
size_t remains = UMIN(uwsgi.buffer_size, wsgi_req->post_cl - wsgi_req->post_pos);
|
||||
|
||||
int ret;
|
||||
|
||||
// allocate more memory if needed
|
||||
if (wsgi_req->post_readline_size - wsgi_req->post_readline_watermark == 0) {
|
||||
memcpy(wsgi_req->post_readline_buf, wsgi_req->post_readline_buf + wsgi_req->post_readline_pos, wsgi_req->post_readline_watermark - wsgi_req->post_readline_pos);
|
||||
wsgi_req->post_readline_watermark -= wsgi_req->post_readline_pos;
|
||||
wsgi_req->post_readline_pos = 0;
|
||||
// still something to use ?
|
||||
if (wsgi_req->post_readline_size - wsgi_req->post_readline_watermark < remains) {
|
||||
char *tmp_buf = realloc(wsgi_req->post_readline_buf, wsgi_req->post_readline_size + remains);
|
||||
if (!tmp_buf) {
|
||||
uwsgi_error("consume_body_for_readline()/realloc()");
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->post_readline_buf = tmp_buf;
|
||||
wsgi_req->post_readline_size += remains;
|
||||
// INFORM THE USER HIS readline() USAGE IS FOOLISH
|
||||
if (!wsgi_req->post_warning && wsgi_req->post_readline_size > (uwsgi.body_read_warning * 1024*1024)) {
|
||||
uwsgi_log("[uwsgi-warning] you are using readline() on request body allocating over than %llu MB, that is really bad and can be avoided...\n", (unsigned long long) (wsgi_req->post_readline_size/(1024*1024)));
|
||||
wsgi_req->post_warning = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// read from a file
|
||||
if (wsgi_req->post_file) {
|
||||
size_t ret = fread(wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark, wsgi_req->post_readline_size - wsgi_req->post_readline_watermark, 1, wsgi_req->post_file);
|
||||
if (ret == 0) {
|
||||
uwsgi_error("consume_body_for_readline()/fread()");
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->post_pos += wsgi_req->post_readline_size - wsgi_req->post_readline_watermark;
|
||||
wsgi_req->post_readline_watermark += wsgi_req->post_readline_size - wsgi_req->post_readline_watermark;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// read from post_buffering memory
|
||||
if (uwsgi.post_buffering) {
|
||||
wsgi_req->post_pos += wsgi_req->post_readline_size - wsgi_req->post_readline_watermark;
|
||||
memcpy(wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark, wsgi_req->post_buffering_buf + wsgi_req->post_pos, wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
|
||||
wsgi_req->post_readline_watermark += wsgi_req->post_readline_size - wsgi_req->post_readline_watermark;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// read from socket
|
||||
ssize_t len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark , wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
|
||||
if (len > 0) {
|
||||
wsgi_req->post_pos += len;
|
||||
wsgi_req->post_readline_watermark += len;
|
||||
return 0;
|
||||
}
|
||||
if (len == 0) {
|
||||
uwsgi_read_error(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
|
||||
return -1;
|
||||
}
|
||||
if (len < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
goto wait;
|
||||
}
|
||||
uwsgi_read_error(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
|
||||
return -1;
|
||||
}
|
||||
wait:
|
||||
ret = uwsgi_wait_read_req(wsgi_req);
|
||||
if (ret > 0) {
|
||||
len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark , wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
|
||||
if (len > 0) {
|
||||
wsgi_req->post_pos += len;
|
||||
wsgi_req->post_readline_watermark += len;
|
||||
return 0;
|
||||
}
|
||||
uwsgi_read_error(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
|
||||
return -1;
|
||||
}
|
||||
// 0 means timeout
|
||||
else if (ret == 0) {
|
||||
uwsgi_read_timeout(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
|
||||
return -1;
|
||||
}
|
||||
uwsgi_read_error(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO take hint into account
|
||||
// readline_buf is allocated when needed and freed at the end of the request
|
||||
char *uwsgi_request_body_readline(struct wsgi_request *wsgi_req, ssize_t hint, ssize_t *rlen) {
|
||||
|
||||
// return 0 if no post_cl or pos >= post_cl and no residual data
|
||||
if ((!wsgi_req->post_cl || wsgi_req->post_pos >= wsgi_req->post_cl ) && !wsgi_req->post_readline_pos) {
|
||||
return uwsgi.empty;
|
||||
}
|
||||
|
||||
// some residual data ?
|
||||
if (wsgi_req->post_readline_pos > 0) {
|
||||
size_t i;
|
||||
for(i=wsgi_req->post_readline_pos;i<wsgi_req->post_readline_watermark;i++) {
|
||||
// found a newline
|
||||
if (wsgi_req->post_readline_buf[i] == '\n') {
|
||||
*rlen = (i+1)-wsgi_req->post_readline_pos;
|
||||
char *buf = wsgi_req->post_readline_buf + wsgi_req->post_readline_pos;
|
||||
wsgi_req->post_readline_pos += *rlen;
|
||||
// all the readline buffer has been consumed
|
||||
if (wsgi_req->post_readline_pos >= wsgi_req->post_readline_watermark) {
|
||||
wsgi_req->post_readline_pos = 0;
|
||||
wsgi_req->post_readline_watermark = 0;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
// ok, no newline found, continue below
|
||||
}
|
||||
|
||||
// allocate memory on the first round
|
||||
if (!wsgi_req->post_readline_buf) {
|
||||
size_t amount = UMIN(uwsgi.buffer_size, wsgi_req->post_cl);
|
||||
wsgi_req->post_readline_buf = malloc(amount);
|
||||
if (!wsgi_req->post_readline_buf) {
|
||||
uwsgi_error("uwsgi_request_body_readline()/malloc()");
|
||||
*rlen = -1;
|
||||
return NULL;
|
||||
}
|
||||
wsgi_req->post_readline_size = amount;
|
||||
}
|
||||
|
||||
// ok, no newline found, consume a bit more of memory and retry
|
||||
for(;;) {
|
||||
// no more data to consume
|
||||
if (wsgi_req->post_pos >= wsgi_req->post_cl) break;
|
||||
|
||||
if (consume_body_for_readline(wsgi_req)) {
|
||||
*rlen = -1;
|
||||
return NULL;
|
||||
}
|
||||
size_t i;
|
||||
for(i=wsgi_req->post_readline_pos;i<wsgi_req->post_readline_watermark;i++) {
|
||||
if (wsgi_req->post_readline_buf[i] == '\n') {
|
||||
*rlen = (i+1)-wsgi_req->post_readline_pos;
|
||||
char *buf = wsgi_req->post_readline_buf + wsgi_req->post_readline_pos;
|
||||
wsgi_req->post_readline_pos += *rlen;
|
||||
if (wsgi_req->post_readline_pos >= wsgi_req->post_readline_watermark) {
|
||||
wsgi_req->post_readline_pos = 0;
|
||||
wsgi_req->post_readline_watermark = 0;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no line found, let's return all
|
||||
*rlen = wsgi_req->post_readline_size - wsgi_req->post_readline_pos;
|
||||
char *buf = wsgi_req->post_readline_buf + wsgi_req->post_readline_pos;
|
||||
wsgi_req->post_readline_pos = 0;
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_request_body_read(struct wsgi_request *wsgi_req, ssize_t hint, ssize_t *rlen) {
|
||||
|
||||
int ret = -1;
|
||||
size_t remains = hint;
|
||||
|
||||
// return empty if no post_cl or pos >= post_cl and no residual data
|
||||
if ((!wsgi_req->post_cl || wsgi_req->post_pos >= wsgi_req->post_cl ) && !wsgi_req->post_readline_pos) {
|
||||
return uwsgi.empty;
|
||||
}
|
||||
|
||||
// return the whole input
|
||||
if (remains <= 0) {
|
||||
remains = wsgi_req->post_cl;
|
||||
}
|
||||
|
||||
// some residual data ?
|
||||
if (wsgi_req->post_readline_pos > 0) {
|
||||
if (remains <= (wsgi_req->post_readline_watermark - wsgi_req->post_readline_pos)) {
|
||||
*rlen = remains;
|
||||
char *buf = wsgi_req->post_readline_buf + wsgi_req->post_readline_pos;
|
||||
wsgi_req->post_readline_pos += remains;
|
||||
return buf;
|
||||
}
|
||||
// the hint is higher than residual data, let's copy it to read() memory and go on
|
||||
size_t avail = wsgi_req->post_readline_watermark - wsgi_req->post_readline_pos;
|
||||
// check if we have enough memory...
|
||||
if (avail > wsgi_req->post_read_buf_size) {
|
||||
char *tmp_buf = realloc(wsgi_req->post_read_buf, avail);
|
||||
if (!tmp_buf) {
|
||||
uwsgi_error("uwsgi_request_body_read()/realloc()");
|
||||
*rlen = -1;
|
||||
return NULL;
|
||||
}
|
||||
wsgi_req->post_read_buf = tmp_buf;
|
||||
wsgi_req->post_read_buf_size = avail;
|
||||
if (!wsgi_req->post_warning && wsgi_req->post_read_buf_size > (uwsgi.body_read_warning * 1024*1024)) {
|
||||
uwsgi_log("[uwsgi-warning] you are using read() on request body allocating over than %llu MB, that is really bad and can be avoided...\n", (unsigned long long) (wsgi_req->post_read_buf_size/(1024*1024)));
|
||||
wsgi_req->post_warning = 1;
|
||||
}
|
||||
}
|
||||
// fix remains...
|
||||
if (remains > 0) {
|
||||
remains -= avail;
|
||||
}
|
||||
*rlen += avail;
|
||||
memcpy(wsgi_req->post_read_buf, wsgi_req->post_readline_buf + wsgi_req->post_readline_pos, avail);
|
||||
wsgi_req->post_readline_pos = 0;
|
||||
wsgi_req->post_readline_watermark = 0;
|
||||
}
|
||||
|
||||
if (remains + wsgi_req->post_pos > wsgi_req->post_cl) {
|
||||
remains = wsgi_req->post_cl - wsgi_req->post_pos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (remains == 0) {
|
||||
if (*rlen > 0) {
|
||||
return wsgi_req->post_read_buf;
|
||||
}
|
||||
else {
|
||||
return uwsgi.empty;
|
||||
}
|
||||
}
|
||||
|
||||
// read from post buffering memory
|
||||
if (uwsgi.post_buffering > 0 && !wsgi_req->post_file) {
|
||||
*rlen += remains;
|
||||
char *buf = wsgi_req->post_buffering_buf+wsgi_req->post_pos;
|
||||
wsgi_req->post_pos += remains;
|
||||
return buf;
|
||||
}
|
||||
|
||||
// ok we need to check if we need to allocate memory
|
||||
if (!wsgi_req->post_read_buf) {
|
||||
wsgi_req->post_read_buf = malloc(remains);
|
||||
if (!wsgi_req->post_read_buf) {
|
||||
uwsgi_error("uwsgi_request_body_read()/malloc()");
|
||||
*rlen = -1;
|
||||
return NULL;
|
||||
}
|
||||
wsgi_req->post_read_buf_size = remains;
|
||||
}
|
||||
// need to realloc ?
|
||||
else {
|
||||
if ((remains+*rlen) > wsgi_req->post_read_buf_size) {
|
||||
char *tmp_buf = realloc(wsgi_req->post_read_buf, (remains+*rlen));
|
||||
if (!tmp_buf) {
|
||||
uwsgi_error("uwsgi_request_body_read()/realloc()");
|
||||
*rlen = -1;
|
||||
return NULL;
|
||||
}
|
||||
wsgi_req->post_read_buf = tmp_buf;
|
||||
wsgi_req->post_read_buf_size = (remains+*rlen);
|
||||
if (!wsgi_req->post_warning && wsgi_req->post_read_buf_size > (uwsgi.body_read_warning * 1024*1024)) {
|
||||
uwsgi_log("[uwsgi-warning] you are using read() on request body allocating over than %llu MB, that is really bad and can be avoided...\n", (unsigned long long) (wsgi_req->post_read_buf_size/(1024*1024)));
|
||||
wsgi_req->post_warning = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check for disk buffered body first (they are all read in one shot)
|
||||
if (wsgi_req->post_file) {
|
||||
if (fread(wsgi_req->post_read_buf + *rlen, remains, 1, wsgi_req->post_file) != 1) {
|
||||
*rlen = -1;
|
||||
uwsgi_log("%llu\n", remains);
|
||||
uwsgi_error("uwsgi_request_body_read()/fread()");
|
||||
return NULL;
|
||||
}
|
||||
*rlen += remains;
|
||||
wsgi_req->post_pos+= remains;
|
||||
return wsgi_req->post_read_buf;
|
||||
}
|
||||
|
||||
// ok read all the required bytes...
|
||||
while(remains > 0) {
|
||||
// here we first try to read (as data could be already available)
|
||||
ssize_t len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_read_buf + *rlen , remains);
|
||||
if (len > 0) {
|
||||
wsgi_req->post_pos+=len;
|
||||
remains -= len;
|
||||
*rlen += len;
|
||||
continue;
|
||||
}
|
||||
// client closed connection...
|
||||
if (len == 0) {
|
||||
*rlen = -1;
|
||||
uwsgi_read_error0(remains);
|
||||
return NULL;
|
||||
}
|
||||
if (len < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
goto wait;
|
||||
}
|
||||
*rlen = -1;
|
||||
uwsgi_read_error(remains);
|
||||
return NULL;
|
||||
}
|
||||
wait:
|
||||
ret = uwsgi_wait_read_req(wsgi_req);
|
||||
if (ret > 0) {
|
||||
len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_read_buf + *rlen, remains);
|
||||
if (len > 0) {
|
||||
wsgi_req->post_pos+=len;
|
||||
remains -= len;
|
||||
*rlen += len;
|
||||
continue;
|
||||
}
|
||||
*rlen = -1;
|
||||
if (len == 0) {
|
||||
uwsgi_read_error0(remains);
|
||||
}
|
||||
else {
|
||||
uwsgi_read_error(remains);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
// 0 means timeout
|
||||
else if (ret == 0) {
|
||||
*rlen = 0;
|
||||
uwsgi_read_timeout(remains);
|
||||
return NULL;
|
||||
}
|
||||
*rlen = -1;
|
||||
uwsgi_read_error(remains);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return wsgi_req->post_read_buf;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
post buffering
|
||||
|
||||
*/
|
||||
|
||||
int uwsgi_postbuffer_do_in_mem(struct wsgi_request *wsgi_req) {
|
||||
|
||||
size_t remains = wsgi_req->post_cl;
|
||||
int ret;
|
||||
char *ptr = wsgi_req->post_buffering_buf;
|
||||
|
||||
while (remains > 0) {
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
|
||||
inc_harakiri(uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
}
|
||||
|
||||
ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, ptr, remains);
|
||||
if (rlen > 0) {
|
||||
remains -= rlen;
|
||||
ptr += rlen;
|
||||
continue;
|
||||
}
|
||||
if (rlen == 0) {
|
||||
uwsgi_read_error0(remains);
|
||||
return -1;
|
||||
}
|
||||
if (rlen < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
goto wait;
|
||||
}
|
||||
uwsgi_read_error(remains);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wait:
|
||||
ret = uwsgi_wait_read_req(wsgi_req);
|
||||
if (ret > 0) {
|
||||
rlen = wsgi_req->socket->proto_read_body(wsgi_req, ptr, remains);
|
||||
if (rlen > 0) {
|
||||
remains -= rlen;
|
||||
ptr += rlen;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
uwsgi_read_error(remains);
|
||||
return -1;
|
||||
}
|
||||
uwsgi_read_timeout(remains);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_postbuffer_do_in_disk(struct wsgi_request *wsgi_req) {
|
||||
|
||||
size_t post_remains = wsgi_req->post_cl;
|
||||
int ret;
|
||||
int upload_progress_fd = -1;
|
||||
char *upload_progress_filename = NULL;
|
||||
|
||||
wsgi_req->post_file = tmpfile();
|
||||
if (!wsgi_req->post_file) {
|
||||
uwsgi_error("uwsgi_postbuffer_do_in_disk()/tmpfile()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (uwsgi.upload_progress) {
|
||||
// first check for X-Progress-ID size
|
||||
// separator + 'X-Progress-ID' + '=' + uuid
|
||||
upload_progress_filename = uwsgi_upload_progress_create(wsgi_req, &upload_progress_fd);
|
||||
if (!upload_progress_filename) {
|
||||
uwsgi_log("invalid X-Progress-ID value: must be a UUID\n");
|
||||
}
|
||||
}
|
||||
|
||||
// manage buffered data and upload progress
|
||||
while (post_remains > 0) {
|
||||
|
||||
// during post buffering we need to constantly reset the harakiri
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
|
||||
inc_harakiri(uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
}
|
||||
|
||||
// we use the already available post buffering buffer to read chunks....
|
||||
size_t remains = UMIN(post_remains, uwsgi.post_buffering);
|
||||
|
||||
// first try to read data (there could be something already available
|
||||
ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_buffering_buf, remains);
|
||||
if (rlen > 0) goto write;
|
||||
if (rlen == 0) {
|
||||
uwsgi_read_error0(remains);
|
||||
goto end;
|
||||
}
|
||||
if (rlen < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
goto wait;
|
||||
}
|
||||
uwsgi_read_error(remains);
|
||||
goto end;
|
||||
}
|
||||
|
||||
wait:
|
||||
ret = uwsgi_wait_read_req(wsgi_req);
|
||||
if (ret > 0) {
|
||||
rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_buffering_buf, remains);
|
||||
if (rlen > 0) goto write;
|
||||
if (rlen == 0) {
|
||||
uwsgi_read_error0(remains);
|
||||
}
|
||||
else {
|
||||
uwsgi_read_error(remains);
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
if (ret < 0) {
|
||||
uwsgi_read_error(remains);
|
||||
goto end;
|
||||
}
|
||||
uwsgi_read_timeout(remains);
|
||||
goto end;
|
||||
|
||||
write:
|
||||
if (fwrite(wsgi_req->post_buffering_buf, rlen, 1, wsgi_req->post_file) != 1) {
|
||||
uwsgi_error("uwsgi_postbuffer_do_in_disk()/fwrite()");
|
||||
goto end;
|
||||
}
|
||||
|
||||
post_remains -= rlen;
|
||||
|
||||
if (upload_progress_filename) {
|
||||
// stop updating it on errors
|
||||
if (uwsgi_upload_progress_update(wsgi_req, upload_progress_fd, post_remains)) {
|
||||
uwsgi_upload_progress_destroy(upload_progress_filename, upload_progress_fd);
|
||||
upload_progress_filename = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
rewind(wsgi_req->post_file);
|
||||
|
||||
if (upload_progress_filename) {
|
||||
uwsgi_upload_progress_destroy(upload_progress_filename, upload_progress_fd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
end:
|
||||
if (upload_progress_filename) {
|
||||
uwsgi_upload_progress_destroy(upload_progress_filename, upload_progress_fd);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
+10
-1
@@ -65,7 +65,15 @@ char *uwsgi_regexp_apply_ovec(char *src, int src_n, char *dst, int dst_n, int *o
|
||||
int i;
|
||||
int dollar = 0;
|
||||
|
||||
char *res = uwsgi_malloc(dst_n + (src_n * n) + 1);
|
||||
size_t dollars = n;
|
||||
|
||||
for(i=0;i<dst_n;i++) {
|
||||
if (dst[i] == '$') {
|
||||
dollars++;
|
||||
}
|
||||
}
|
||||
|
||||
char *res = uwsgi_malloc(dst_n + (src_n * dollars) + 1);
|
||||
char *ptr = res;
|
||||
|
||||
for (i = 0; i < dst_n; i++) {
|
||||
@@ -79,6 +87,7 @@ char *uwsgi_regexp_apply_ovec(char *src, int src_n, char *dst, int dst_n, int *o
|
||||
}
|
||||
}
|
||||
else {
|
||||
*ptr++ = '$';
|
||||
*ptr++ = dst[i];
|
||||
}
|
||||
dollar = 0;
|
||||
|
||||
+635
-57
@@ -1,65 +1,226 @@
|
||||
#ifdef UWSGI_ROUTING
|
||||
#include "uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_apply_routes(struct wsgi_request *wsgi_req) {
|
||||
struct uwsgi_buffer *uwsgi_routing_translate(struct wsgi_request *wsgi_req, struct uwsgi_route *ur, char *subject, uint16_t subject_len, char *data, size_t data_len) {
|
||||
|
||||
char *pass1 = data;
|
||||
size_t pass1_len = data_len;
|
||||
|
||||
// cannot fail
|
||||
if (subject) {
|
||||
pass1 = uwsgi_regexp_apply_ovec(subject, subject_len, data, data_len, ur->ovector, ur->ovn);
|
||||
pass1_len = strlen(pass1);
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(pass1_len);
|
||||
size_t i;
|
||||
int status = 0;
|
||||
char *key = NULL;
|
||||
size_t keylen = 0;
|
||||
for(i=0;i<pass1_len;i++) {
|
||||
switch(status) {
|
||||
case 0:
|
||||
if (pass1[i] == '$') {
|
||||
status = 1;
|
||||
break;
|
||||
}
|
||||
if (uwsgi_buffer_append(ub, pass1 + i, 1)) goto error;
|
||||
break;
|
||||
case 1:
|
||||
if (pass1[i] == '{') {
|
||||
status = 2;
|
||||
key = pass1+i+1;
|
||||
keylen = 0;
|
||||
break;
|
||||
}
|
||||
status = 0;
|
||||
key = NULL;
|
||||
keylen = 0;
|
||||
if (uwsgi_buffer_append(ub, "$", 1)) goto error;
|
||||
if (uwsgi_buffer_append(ub, pass1 + i, 1)) goto error;
|
||||
break;
|
||||
case 2:
|
||||
if (pass1[i] == '}') {
|
||||
uint16_t vallen = 0;
|
||||
char *value = uwsgi_get_var(wsgi_req, key, keylen, &vallen);
|
||||
if (value) {
|
||||
if (uwsgi_buffer_append(ub, value, vallen)) goto error;
|
||||
}
|
||||
status = 0;
|
||||
key = NULL;
|
||||
keylen = 0;
|
||||
break;
|
||||
}
|
||||
keylen++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// fix the buffer
|
||||
if (status == 1) {
|
||||
if (uwsgi_buffer_append(ub, "$", 1)) goto error;
|
||||
}
|
||||
else if (status == 2) {
|
||||
if (uwsgi_buffer_append(ub, "${", 2)) goto error;
|
||||
if (keylen > 0) {
|
||||
if (uwsgi_buffer_append(ub, key, keylen)) goto error;
|
||||
}
|
||||
}
|
||||
|
||||
// add the final NULL byte (to simplify plugin work)
|
||||
|
||||
if (uwsgi_buffer_append(ub, "\0", 1)) goto error;
|
||||
|
||||
if (pass1 != data) {
|
||||
free(pass1);
|
||||
}
|
||||
return ub;
|
||||
|
||||
error:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int uwsgi_apply_routes_do(struct wsgi_request *wsgi_req, char *subject, uint16_t subject_len) {
|
||||
|
||||
struct uwsgi_route *routes = uwsgi.routes;
|
||||
void *goon_func = NULL;
|
||||
int n = -1;
|
||||
|
||||
if (!routes)
|
||||
while (routes) {
|
||||
|
||||
if (wsgi_req->route_goto > 0 && wsgi_req->route_pc < wsgi_req->route_goto) {
|
||||
goto next;
|
||||
}
|
||||
if (goon_func && goon_func == routes->func) {
|
||||
goto next;
|
||||
}
|
||||
goon_func = NULL;
|
||||
wsgi_req->route_goto = 0;
|
||||
|
||||
if (!routes->if_func) {
|
||||
if (!subject) {
|
||||
char **subject2 = (char **) (((char *) (wsgi_req)) + routes->subject);
|
||||
uint16_t *subject_len2 = (uint16_t *) (((char *) (wsgi_req)) + routes->subject_len);
|
||||
subject = *subject2 ;
|
||||
subject_len = *subject_len2;
|
||||
}
|
||||
n = uwsgi_regexp_match_ovec(routes->pattern, routes->pattern_extra, subject, subject_len, routes->ovector, routes->ovn);
|
||||
}
|
||||
else {
|
||||
int ret = routes->if_func(wsgi_req, routes);
|
||||
// error
|
||||
if (ret < 0) {
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
// true
|
||||
if (!routes->if_negate) {
|
||||
if (ret == 0) {
|
||||
goto next;
|
||||
}
|
||||
n = ret;
|
||||
}
|
||||
else {
|
||||
if (ret > 0) {
|
||||
goto next;
|
||||
}
|
||||
n = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (n >= 0) {
|
||||
wsgi_req->is_routing = 1;
|
||||
int ret = routes->func(wsgi_req, routes);
|
||||
wsgi_req->is_routing = 0;
|
||||
if (ret == UWSGI_ROUTE_BREAK) {
|
||||
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].routed_requests++;
|
||||
return ret;
|
||||
}
|
||||
if (ret == UWSGI_ROUTE_CONTINUE) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret == UWSGI_ROUTE_GOON) {
|
||||
goon_func = routes->func;
|
||||
}
|
||||
}
|
||||
next:
|
||||
routes = routes->next;
|
||||
if (routes) wsgi_req->route_pc++;
|
||||
}
|
||||
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
}
|
||||
|
||||
int uwsgi_apply_routes(struct wsgi_request *wsgi_req) {
|
||||
|
||||
if (!uwsgi.routes)
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
|
||||
// avoid loops
|
||||
if (wsgi_req->is_routing)
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
|
||||
if (uwsgi_parse_vars(wsgi_req)) {
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
|
||||
while (routes) {
|
||||
char **subject = (char **) (((char *) (wsgi_req)) + routes->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *) (wsgi_req)) + routes->subject_len);
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("route subject = %.*s\n", *subject_len, *subject);
|
||||
#endif
|
||||
int n = uwsgi_regexp_match_ovec(routes->pattern, routes->pattern_extra, *subject, *subject_len, routes->ovector, routes->ovn);
|
||||
if (n >= 0) {
|
||||
int ret = routes->func(wsgi_req, routes);
|
||||
if (ret == UWSGI_ROUTE_BREAK) uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].routed_requests++;
|
||||
if (ret != UWSGI_ROUTE_NEXT) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
routes = routes->next;
|
||||
}
|
||||
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
return uwsgi_apply_routes_do(wsgi_req, NULL, 0);
|
||||
}
|
||||
|
||||
int uwsgi_apply_routes_fast(struct wsgi_request *wsgi_req, char *uri, int len) {
|
||||
|
||||
struct uwsgi_route *routes = uwsgi.routes;
|
||||
int uwsgi_apply_routes_fast(struct wsgi_request *wsgi_req, char *subject, uint16_t subject_len) {
|
||||
|
||||
if (!routes)
|
||||
if (!uwsgi.routes)
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
|
||||
while (routes) {
|
||||
int n = uwsgi_regexp_match_ovec(routes->pattern, routes->pattern_extra, uri, len, routes->ovector, routes->ovn);
|
||||
if (n >= 0) {
|
||||
int ret = routes->func(wsgi_req, routes);
|
||||
if (ret == UWSGI_ROUTE_BREAK) uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].routed_requests++;
|
||||
if (ret != UWSGI_ROUTE_NEXT) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
// avoid loops
|
||||
if (wsgi_req->is_routing)
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
|
||||
routes = routes->next;
|
||||
}
|
||||
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
return uwsgi_apply_routes_do(wsgi_req, subject, subject_len);
|
||||
}
|
||||
|
||||
static void *uwsgi_route_get_condition_func(char *name) {
|
||||
struct uwsgi_route_condition *urc = uwsgi.route_conditions;
|
||||
while(urc) {
|
||||
if (!strcmp(urc->name, name)) {
|
||||
return urc->func;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
|
||||
|
||||
struct uwsgi_route *old_ur = NULL,*ur = uwsgi.routes;
|
||||
uint64_t pos = 0;
|
||||
while(ur) {
|
||||
old_ur = ur;
|
||||
ur = ur->next;
|
||||
pos++;
|
||||
}
|
||||
ur = uwsgi_calloc(sizeof(struct uwsgi_route));
|
||||
if (old_ur) {
|
||||
old_ur->next = ur;
|
||||
}
|
||||
else {
|
||||
uwsgi.routes = ur;
|
||||
}
|
||||
|
||||
ur->pos = pos;
|
||||
|
||||
// is it a label ?
|
||||
if (foobar == NULL) {
|
||||
ur->label = value;
|
||||
ur->label_len = strlen(value);
|
||||
return;
|
||||
}
|
||||
|
||||
char *route = uwsgi_str(value);
|
||||
|
||||
char *space = strchr(route, ' ');
|
||||
@@ -70,23 +231,27 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
|
||||
|
||||
*space = 0;
|
||||
|
||||
struct uwsgi_route *ur = uwsgi.routes;
|
||||
if (!ur) {
|
||||
uwsgi.routes = uwsgi_calloc(sizeof(struct uwsgi_route));
|
||||
ur = uwsgi.routes;
|
||||
}
|
||||
else {
|
||||
while (ur) {
|
||||
if (!ur->next) {
|
||||
ur->next = uwsgi_calloc(sizeof(struct uwsgi_route));
|
||||
ur = ur->next;
|
||||
break;
|
||||
}
|
||||
ur = ur->next;
|
||||
if (!strcmp(foobar, "if") || !strcmp(foobar, "if-not")) {
|
||||
char *colon = strchr(route, ':');
|
||||
if (!colon) {
|
||||
uwsgi_log("invalid route condition syntax\n");
|
||||
exit(1);
|
||||
}
|
||||
*colon = 0;
|
||||
|
||||
if (!strcmp(foobar, "if-not")) {
|
||||
ur->if_negate = 1;
|
||||
}
|
||||
|
||||
foobar = colon+1;
|
||||
ur->if_func = uwsgi_route_get_condition_func(route);
|
||||
if (!ur->if_func) {
|
||||
uwsgi_log("unable to find \"%s\" route condition\n", route);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcmp(foobar, "http_host")) {
|
||||
else if (!strcmp(foobar, "http_host")) {
|
||||
ur->subject = offsetof(struct wsgi_request, host);
|
||||
ur->subject_len = offsetof(struct wsgi_request, host_len);
|
||||
}
|
||||
@@ -98,21 +263,44 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
|
||||
ur->subject = offsetof(struct wsgi_request, query_string);
|
||||
ur->subject_len = offsetof(struct wsgi_request, query_string_len);
|
||||
}
|
||||
else if (!strcmp(foobar, "remote_addr")) {
|
||||
ur->subject = offsetof(struct wsgi_request, remote_addr);
|
||||
ur->subject_len = offsetof(struct wsgi_request, remote_addr_len);
|
||||
}
|
||||
else if (!strcmp(foobar, "user_agent")) {
|
||||
ur->subject = offsetof(struct wsgi_request, user_agent);
|
||||
ur->subject_len = offsetof(struct wsgi_request, user_agent_len);
|
||||
}
|
||||
else if (!strcmp(foobar, "referer")) {
|
||||
ur->subject = offsetof(struct wsgi_request, referer);
|
||||
ur->subject_len = offsetof(struct wsgi_request, referer_len);
|
||||
}
|
||||
else if (!strcmp(foobar, "remote_user")) {
|
||||
ur->subject = offsetof(struct wsgi_request, remote_user);
|
||||
ur->subject_len = offsetof(struct wsgi_request, remote_user_len);
|
||||
}
|
||||
else {
|
||||
ur->subject = offsetof(struct wsgi_request, path_info);
|
||||
ur->subject_len = offsetof(struct wsgi_request, path_info_len);
|
||||
}
|
||||
|
||||
if (uwsgi_regexp_build(route, &ur->pattern, &ur->pattern_extra)) {
|
||||
exit(1);
|
||||
}
|
||||
ur->subject_str = foobar;
|
||||
ur->subject_str_len = strlen(ur->subject_str);
|
||||
ur->regexp = route;
|
||||
|
||||
ur->ovn = uwsgi_regexp_ovector(ur->pattern, ur->pattern_extra);
|
||||
if (ur->ovn > 0) {
|
||||
ur->ovector = uwsgi_calloc(sizeof(int) * (3 * (ur->ovn + 1)));
|
||||
if (ur->subject && ur->subject_len) {
|
||||
if (uwsgi_regexp_build(route, &ur->pattern, &ur->pattern_extra)) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ur->ovn = uwsgi_regexp_ovector(ur->pattern, ur->pattern_extra);
|
||||
if (ur->ovn > 0) {
|
||||
ur->ovector = uwsgi_calloc(sizeof(int) * (3 * (ur->ovn + 1)));
|
||||
}
|
||||
}
|
||||
|
||||
char *command = space + 1;
|
||||
ur->action = uwsgi_str(command);
|
||||
|
||||
char *colon = strchr(command, ':');
|
||||
if (!colon) {
|
||||
@@ -138,6 +326,7 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
|
||||
last_ur->is_last = 1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
r = r->next;
|
||||
}
|
||||
@@ -146,6 +335,355 @@ void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int uwsgi_route_api_func(struct wsgi_request *wsgi_req, char *router, char *args) {
|
||||
struct uwsgi_route *ur = NULL;
|
||||
struct uwsgi_router *r = uwsgi.routers;
|
||||
while(r) {
|
||||
if (!strcmp(router, r->name)) {
|
||||
goto found;
|
||||
}
|
||||
r = r->next;
|
||||
}
|
||||
return -1;
|
||||
found:
|
||||
ur = uwsgi_calloc(sizeof(struct uwsgi_route));
|
||||
// initialize the virtual route
|
||||
if (r->func(ur, args)) {
|
||||
free(ur);
|
||||
return -1;
|
||||
}
|
||||
// call it
|
||||
int ret = ur->func(wsgi_req, ur);
|
||||
if (ur->free) {
|
||||
ur->free(ur);
|
||||
}
|
||||
free(ur);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// continue/last route
|
||||
|
||||
static int uwsgi_router_continue_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
}
|
||||
|
||||
static int uwsgi_router_continue(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_continue_func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// break route
|
||||
|
||||
static int uwsgi_router_break_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
|
||||
if (route->data_len >= 3) {
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, route->data, route->data_len)) goto end;
|
||||
if (uwsgi_response_add_connection_close(wsgi_req)) goto end;
|
||||
if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) goto end;
|
||||
// no need to check for return value
|
||||
uwsgi_response_write_headers_do(wsgi_req);
|
||||
}
|
||||
end:
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
|
||||
static int uwsgi_router_break(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_break_func;
|
||||
ur->data = arg;
|
||||
ur->data_len = strlen(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// goon route
|
||||
static int uwsgi_router_goon_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
|
||||
return UWSGI_ROUTE_GOON;
|
||||
}
|
||||
static int uwsgi_router_goon(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_goon_func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// log route
|
||||
static int uwsgi_router_log_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
|
||||
uwsgi_log("%.*s\n", ub->pos, ub->buf);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
static int uwsgi_router_log(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_log_func;
|
||||
ur->data = arg;
|
||||
ur->data_len = strlen(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// logvar route
|
||||
static int uwsgi_router_logvar_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data2, ur->data2_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
uwsgi_logvar_add(wsgi_req, ur->data, ur->data_len, ub->buf, ub->pos);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
static int uwsgi_router_logvar(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_logvar_func;
|
||||
char *equal = strchr(arg, '=');
|
||||
if (!equal) {
|
||||
uwsgi_log("invalid logvar syntax, must be key=value\n");
|
||||
exit(1);
|
||||
}
|
||||
ur->data = arg;
|
||||
ur->data_len = equal-arg;
|
||||
ur->data2 = equal+1;
|
||||
ur->data2_len = strlen(ur->data2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// goto route
|
||||
|
||||
static int uwsgi_router_goto_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
// build the label (if needed)
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
|
||||
// find the label
|
||||
struct uwsgi_route *routes = uwsgi.routes;
|
||||
while(routes) {
|
||||
if (!routes->label) goto next;
|
||||
if (!uwsgi_strncmp(routes->label, routes->label_len, ub->buf, ub->pos)) {
|
||||
wsgi_req->route_goto = routes->pos;
|
||||
goto found;
|
||||
}
|
||||
next:
|
||||
routes = routes->next;
|
||||
}
|
||||
|
||||
wsgi_req->route_goto = ur->custom;
|
||||
|
||||
found:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
if (wsgi_req->route_goto <= wsgi_req->route_pc) {
|
||||
wsgi_req->route_goto = 0;
|
||||
uwsgi_log("[uwsgi-route] ERROR \"goto\" instruction can only jump forward (check your label !!!)\n");
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
static int uwsgi_router_goto(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_goto_func;
|
||||
ur->data = arg;
|
||||
ur->data_len = strlen(arg);
|
||||
ur->custom = atoi(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// addvar route
|
||||
static int uwsgi_router_addvar_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data2, ur->data2_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
|
||||
if (!uwsgi_req_append(wsgi_req, ur->data, ur->data_len, ub->buf, ub->pos)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_router_addvar(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_addvar_func;
|
||||
char *equal = strchr(arg, '=');
|
||||
if (!equal) {
|
||||
uwsgi_log("[uwsgi-route] invalid addvar syntax, must be KEY=VAL\n");
|
||||
exit(1);
|
||||
}
|
||||
ur->data = arg;
|
||||
ur->data_len = equal-arg;
|
||||
ur->data2 = equal+1;
|
||||
ur->data2_len = strlen(ur->data2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// addheader route
|
||||
static int uwsgi_router_addheader_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
uwsgi_additional_header_add(wsgi_req, ub->buf, ub->pos);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_router_addheader(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_addheader_func;
|
||||
ur->data = arg;
|
||||
ur->data_len = strlen(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// remheader route
|
||||
static int uwsgi_router_remheader_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
uwsgi_remove_header(wsgi_req, ub->buf, ub->pos);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_router_remheader(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_remheader_func;
|
||||
ur->data = arg;
|
||||
ur->data_len = strlen(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// signal route
|
||||
static int uwsgi_router_signal_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
|
||||
uwsgi_signal_send(uwsgi.signal_socket, route->custom);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
static int uwsgi_router_signal(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_signal_func;
|
||||
ur->custom = atoi(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// send route
|
||||
static int uwsgi_router_send_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
|
||||
uwsgi_response_write_body_do(wsgi_req, route->data, route->data_len);
|
||||
if (route->custom) {
|
||||
uwsgi_response_write_body_do(wsgi_req, "\r\n", 2);
|
||||
}
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
static int uwsgi_router_send(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_send_func;
|
||||
ur->data = arg;
|
||||
ur->data_len = strlen(arg);
|
||||
return 0;
|
||||
}
|
||||
static int uwsgi_router_send_crnl(struct uwsgi_route *ur, char *arg) {
|
||||
uwsgi_router_send(ur, arg);
|
||||
ur->custom = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_route_condition_exists(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len);
|
||||
if (!ub) return -1;
|
||||
if (uwsgi_file_exists(ub->buf)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 1;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_route_condition_isfile(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len);
|
||||
if (!ub) return -1;
|
||||
if (uwsgi_is_file(ub->buf)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 1;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_route_condition_isdir(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len);
|
||||
if (!ub) return -1;
|
||||
if (uwsgi_is_dir(ub->buf)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 1;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_route_condition_islink(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len);
|
||||
if (!ub) return -1;
|
||||
if (uwsgi_is_link(ub->buf)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 1;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_route_condition_isexec(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len);
|
||||
if (!ub) return -1;
|
||||
if (!access(ub->buf, X_OK)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 1;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// register embedded routers
|
||||
void uwsgi_register_embedded_routers() {
|
||||
uwsgi_register_router("continue", uwsgi_router_continue);
|
||||
uwsgi_register_router("last", uwsgi_router_continue);
|
||||
uwsgi_register_router("break", uwsgi_router_break);
|
||||
uwsgi_register_router("goon", uwsgi_router_goon);
|
||||
uwsgi_register_router("log", uwsgi_router_log);
|
||||
uwsgi_register_router("logvar", uwsgi_router_logvar);
|
||||
uwsgi_register_router("goto", uwsgi_router_goto);
|
||||
uwsgi_register_router("addvar", uwsgi_router_addvar);
|
||||
uwsgi_register_router("addheader", uwsgi_router_addheader);
|
||||
uwsgi_register_router("delheader", uwsgi_router_remheader);
|
||||
uwsgi_register_router("remheader", uwsgi_router_remheader);
|
||||
uwsgi_register_router("signal", uwsgi_router_signal);
|
||||
uwsgi_register_router("send", uwsgi_router_send);
|
||||
uwsgi_register_router("send-crnl", uwsgi_router_send_crnl);
|
||||
|
||||
uwsgi_register_route_condition("exists", uwsgi_route_condition_exists);
|
||||
uwsgi_register_route_condition("isfile", uwsgi_route_condition_isfile);
|
||||
uwsgi_register_route_condition("isdir", uwsgi_route_condition_isdir);
|
||||
uwsgi_register_route_condition("islink", uwsgi_route_condition_islink);
|
||||
uwsgi_register_route_condition("isexec", uwsgi_route_condition_isexec);
|
||||
}
|
||||
|
||||
struct uwsgi_router *uwsgi_register_router(char *name, int (*func) (struct uwsgi_route *, char *)) {
|
||||
|
||||
struct uwsgi_router *ur = uwsgi.routers;
|
||||
@@ -169,4 +707,44 @@ struct uwsgi_router *uwsgi_register_router(char *name, int (*func) (struct uwsgi
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_route_condition *uwsgi_register_route_condition(char *name, int (*func) (struct wsgi_request *, struct uwsgi_route *)) {
|
||||
struct uwsgi_route_condition *old_urc = NULL,*urc = uwsgi.route_conditions;
|
||||
while(urc) {
|
||||
if (!strcmp(urc->name, name)) {
|
||||
return urc;
|
||||
}
|
||||
old_urc = urc;
|
||||
urc = urc->next;
|
||||
}
|
||||
|
||||
urc = uwsgi_calloc(sizeof(struct uwsgi_route_condition));
|
||||
urc->name = name;
|
||||
urc->func = func;
|
||||
|
||||
if (old_urc) {
|
||||
old_urc->next = urc;
|
||||
}
|
||||
else {
|
||||
uwsgi.route_conditions = urc;
|
||||
}
|
||||
|
||||
return urc;
|
||||
}
|
||||
|
||||
void uwsgi_routing_dump() {
|
||||
struct uwsgi_route *routes = uwsgi.routes;
|
||||
if (!routes) return;
|
||||
uwsgi_log("*** dumping internal routing table ***\n");
|
||||
while(routes) {
|
||||
if (routes->label) {
|
||||
uwsgi_log("[rule: %llu] label: %s\n", (unsigned long long ) routes->pos, routes->label);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[rule: %llu] subject: %s %s: %s%s action: %s\n", (unsigned long long ) routes->pos, routes->subject_str, routes->if_func ? "func" : "regexp", routes->if_negate ? "!" : "", routes->regexp, routes->action);
|
||||
}
|
||||
routes = routes->next;
|
||||
}
|
||||
uwsgi_log("*** end of the internal routing table ***\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
+78
-42
@@ -7,25 +7,51 @@ int uwsgi_register_rpc(char *name, uint8_t modifier1, uint8_t args, void *func)
|
||||
struct uwsgi_rpc *urpc;
|
||||
int ret = -1;
|
||||
|
||||
if (uwsgi.mywid != 0) {
|
||||
uwsgi_log("you can register RPC functions only in the master\n");
|
||||
if (uwsgi.mywid == 0 && uwsgi.workers[0].pid != uwsgi.mypid) {
|
||||
uwsgi_log("only the master and the workers can register RPC functions\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_lock(uwsgi.rpc_table_lock);
|
||||
|
||||
if (uwsgi.shared->rpc_count < MAX_RPC) {
|
||||
urpc = &uwsgi.shared->rpc_table[uwsgi.shared->rpc_count];
|
||||
// first check if a function is already registered
|
||||
size_t i;
|
||||
for(i=0;i<uwsgi.shared->rpc_count[uwsgi.mywid];i++) {
|
||||
int pos = (uwsgi.mywid * uwsgi.rpc_max) + i;
|
||||
urpc = &uwsgi.rpc_table[pos];
|
||||
if (!strcmp(name, urpc->name)) {
|
||||
goto already;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.shared->rpc_count[uwsgi.mywid] < uwsgi.rpc_max) {
|
||||
int pos = (uwsgi.mywid * uwsgi.rpc_max) + uwsgi.shared->rpc_count[uwsgi.mywid];
|
||||
urpc = &uwsgi.rpc_table[pos];
|
||||
uwsgi.shared->rpc_count[uwsgi.mywid]++;
|
||||
already:
|
||||
memcpy(urpc->name, name, strlen(name));
|
||||
urpc->modifier1 = modifier1;
|
||||
urpc->args = args;
|
||||
urpc->func = func;
|
||||
|
||||
uwsgi.shared->rpc_count++;
|
||||
urpc->shared = uwsgi.mywid == 0 ? 1 : 0;
|
||||
|
||||
ret = 0;
|
||||
uwsgi_log("registered RPC function %s\n", name);
|
||||
if (uwsgi.mywid == 0) {
|
||||
uwsgi_log("registered shared/inherited RPC function \"%s\"\n", name);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("registered RPC function \"%s\" on worker %d\n", name, uwsgi.mywid);
|
||||
}
|
||||
}
|
||||
|
||||
// implement cow
|
||||
if (uwsgi.mywid == 0) {
|
||||
int i;
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
uwsgi.shared->rpc_count[i] = uwsgi.shared->rpc_count[0];
|
||||
int pos = (i * uwsgi.rpc_max);
|
||||
memcpy(&uwsgi.rpc_table[pos], uwsgi.rpc_table, sizeof(struct uwsgi_rpc) * uwsgi.rpc_max);
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_unlock(uwsgi.rpc_table_lock);
|
||||
@@ -36,13 +62,15 @@ int uwsgi_register_rpc(char *name, uint8_t modifier1, uint8_t args, void *func)
|
||||
uint16_t uwsgi_rpc(char *name, uint8_t argc, char *argv[], uint16_t argvs[], char *output) {
|
||||
|
||||
struct uwsgi_rpc *urpc = NULL;
|
||||
int i;
|
||||
uint64_t i;
|
||||
uint16_t ret = 0;
|
||||
|
||||
for (i = 0; i < uwsgi.shared->rpc_count; i++) {
|
||||
if (uwsgi.shared->rpc_table[i].name[0] != 0) {
|
||||
if (!strcmp(uwsgi.shared->rpc_table[i].name, name)) {
|
||||
urpc = &uwsgi.shared->rpc_table[i];
|
||||
int pos = (uwsgi.mywid * uwsgi.rpc_max);
|
||||
|
||||
for (i = 0; i < uwsgi.shared->rpc_count[uwsgi.mywid]; i++) {
|
||||
if (uwsgi.rpc_table[pos + i].name[0] != 0) {
|
||||
if (!strcmp(uwsgi.rpc_table[pos + i].name, name)) {
|
||||
urpc = &uwsgi.rpc_table[pos + i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -62,25 +90,31 @@ char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t
|
||||
|
||||
uint8_t i;
|
||||
uint16_t ulen;
|
||||
struct uwsgi_header uh;
|
||||
struct uwsgi_header *uh = NULL;
|
||||
char *buffer = NULL;
|
||||
|
||||
*len = 0;
|
||||
|
||||
if (node == NULL || !strcmp(node, "")) {
|
||||
// allocate the whole buffer
|
||||
buffer = uwsgi_malloc(65536);
|
||||
buffer = uwsgi_malloc(UMAX16);
|
||||
*len = uwsgi_rpc(func, argc, argv, argvs, buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
// connect to node
|
||||
int fd = uwsgi_connect(node, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], 0);
|
||||
|
||||
// connect to node (async way)
|
||||
int fd = uwsgi_connect(node, 0, 1);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
// wait for connection;
|
||||
int ret = uwsgi.wait_write_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (ret <= 0) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// prepare a uwsgi array
|
||||
uint16_t buffer_size = 2 + strlen(func);
|
||||
|
||||
@@ -89,14 +123,16 @@ char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t
|
||||
}
|
||||
|
||||
// allocate the whole buffer
|
||||
buffer = uwsgi_malloc(65536);
|
||||
buffer = uwsgi_malloc(4+buffer_size);
|
||||
|
||||
uh.modifier1 = 173;
|
||||
uh.pktsize = buffer_size;
|
||||
uh.modifier2 = 0;
|
||||
// set the uwsgi header
|
||||
uh = (struct uwsgi_header *) buffer;
|
||||
uh->modifier1 = 173;
|
||||
uh->pktsize = buffer_size;
|
||||
uh->modifier2 = 0;
|
||||
|
||||
// add func to the array
|
||||
char *bufptr = buffer;
|
||||
char *bufptr = buffer + 4;
|
||||
ulen = strlen(func);
|
||||
*bufptr++ = (uint8_t) (ulen & 0xff);
|
||||
*bufptr++ = (uint8_t) ((ulen >> 8) & 0xff);
|
||||
@@ -111,33 +147,33 @@ char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t
|
||||
bufptr += ulen;
|
||||
}
|
||||
|
||||
if (write(fd, &uh, 4) != 4) {
|
||||
uwsgi_error("write()");
|
||||
close(fd);
|
||||
free(buffer);
|
||||
return NULL;
|
||||
// ok the reuqest is ready, let's send it in non blocking way
|
||||
if (uwsgi_write_true_nb(fd, buffer, buffer_size+4, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (write(fd, buffer, buffer_size) != buffer_size) {
|
||||
uwsgi_error("write()");
|
||||
close(fd);
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (uwsgi_read_response(fd, &uh, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], &buffer) < 0) {
|
||||
close(fd);
|
||||
free(buffer);
|
||||
return NULL;
|
||||
// ok time to wait for the response in non blocking way
|
||||
size_t rlen = buffer_size+4;
|
||||
if (uwsgi_read_with_realloc(fd, &buffer, &rlen, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
*len = uh.pktsize;
|
||||
*len = rlen;
|
||||
if (*len == 0) {
|
||||
free(buffer);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
return buffer;
|
||||
|
||||
error:
|
||||
close(fd);
|
||||
free(buffer);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_rpc_init() {
|
||||
uwsgi.rpc_table = uwsgi_calloc_shared((sizeof(struct uwsgi_rpc) * uwsgi.rpc_max) * (uwsgi.numproc+1));
|
||||
uwsgi.shared->rpc_count = uwsgi_calloc_shared(sizeof(uint64_t) * (uwsgi.numproc+1));
|
||||
}
|
||||
|
||||
+24
-159
@@ -2,173 +2,38 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
ssize_t uwsgi_sendfile(struct wsgi_request * wsgi_req) {
|
||||
|
||||
int fd = wsgi_req->sendfile_fd;
|
||||
int sockfd = wsgi_req->poll.fd;
|
||||
struct stat stat_buf;
|
||||
ssize_t sst = 0;
|
||||
|
||||
if (!wsgi_req->sendfile_fd_size) {
|
||||
|
||||
if (fstat(fd, &stat_buf)) {
|
||||
uwsgi_error("fstat()");
|
||||
goto end;
|
||||
}
|
||||
else {
|
||||
wsgi_req->sendfile_fd_size = stat_buf.st_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (wsgi_req->sendfile_fd_size) {
|
||||
|
||||
if (!wsgi_req->sendfile_fd_chunk)
|
||||
wsgi_req->sendfile_fd_chunk = 4096;
|
||||
|
||||
if (wsgi_req->socket->proto_sendfile) {
|
||||
sst = wsgi_req->socket->proto_sendfile(wsgi_req);
|
||||
}
|
||||
else {
|
||||
sst = uwsgi_do_sendfile(sockfd, wsgi_req->sendfile_fd, wsgi_req->sendfile_fd_size, wsgi_req->sendfile_fd_chunk, &wsgi_req->sendfile_fd_pos, uwsgi.async);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
end:
|
||||
return sst;
|
||||
}
|
||||
|
||||
ssize_t uwsgi_do_sendfile(int sockfd, int filefd, size_t filesize, size_t chunk, off_t * pos, int async) {
|
||||
// sendfile() abstraction
|
||||
ssize_t uwsgi_sendfile_do(int sockfd, int filefd, size_t pos, size_t len) {
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
|
||||
int sf_ret;
|
||||
|
||||
off_t sf_len = filesize;
|
||||
|
||||
if (async > 1) {
|
||||
sf_len = chunk;
|
||||
sf_ret = sendfile(filefd, sockfd, *pos, 0, NULL, &sf_len, 0);
|
||||
*pos += sf_len;
|
||||
}
|
||||
else {
|
||||
sf_ret = sendfile(filefd, sockfd, 0, 0, NULL, &sf_len, 0);
|
||||
}
|
||||
|
||||
if (sf_ret < 0) {
|
||||
if (errno != EAGAIN) {
|
||||
uwsgi_error("sendfile()");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return sf_len;
|
||||
off_t sf_len = len;
|
||||
int sf_ret = sendfile(filefd, sockfd, pos, len, NULL, &sf_len, 0);
|
||||
if (sf_ret == 0 || (sf_ret == -1 && errno == EAGAIN)) return sf_len;
|
||||
return -1;
|
||||
#elif defined(__APPLE__)
|
||||
int sf_ret;
|
||||
off_t sf_len = filesize;
|
||||
|
||||
if (async > 1) {
|
||||
sf_len = chunk;
|
||||
sf_ret = sendfile(filefd, sockfd, *pos, &sf_len, NULL, 0);
|
||||
*pos += sf_len;
|
||||
}
|
||||
else {
|
||||
sf_ret = sendfile(filefd, sockfd, 0, &sf_len, NULL, 0);
|
||||
}
|
||||
|
||||
if (sf_ret) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("sf_len = %d\n", sf_len);
|
||||
#endif
|
||||
uwsgi_error("sendfile()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sf_len;
|
||||
|
||||
off_t sf_len = len;
|
||||
int sf_ret = sendfile(filefd, sockfd, pos, &sf_len, NULL, 0);
|
||||
if (sf_ret == 0 || (sf_ret == -1 && errno == EAGAIN)) return sf_len;
|
||||
return -1;
|
||||
#elif defined(__linux__) || defined(__sun__)
|
||||
int sf_ret;
|
||||
size_t written = 0;
|
||||
|
||||
if (async > 1) {
|
||||
sf_ret = sendfile(sockfd, filefd, pos, chunk);
|
||||
if (sf_ret < 0) {
|
||||
uwsgi_error("sendfile()");
|
||||
return 0;
|
||||
}
|
||||
return sf_ret;
|
||||
}
|
||||
|
||||
while (written < filesize) {
|
||||
sf_ret = sendfile(sockfd, filefd, pos, filesize - written);
|
||||
if (sf_ret < 0) {
|
||||
uwsgi_error("sendfile()");
|
||||
return 0;
|
||||
}
|
||||
else if (sf_ret == 0) {
|
||||
return 0;
|
||||
}
|
||||
written += sf_ret;
|
||||
}
|
||||
return written;
|
||||
|
||||
off_t off = pos;
|
||||
return sendfile(sockfd, filefd, &off, len);
|
||||
#else
|
||||
static size_t nosf_buf_size = 0;
|
||||
static char *nosf_buf;
|
||||
char *nosf_buf2;
|
||||
|
||||
ssize_t jlen = 0;
|
||||
ssize_t rlen = 0;
|
||||
ssize_t i = 0;
|
||||
|
||||
if (!nosf_buf) {
|
||||
nosf_buf = malloc(chunk);
|
||||
}
|
||||
else if (chunk != nosf_buf_size) {
|
||||
nosf_buf2 = realloc(nosf_buf, chunk);
|
||||
if (!nosf_buf2) {
|
||||
free(nosf_buf);
|
||||
// for platform not supporting sendfile we need to rely on boring read/write
|
||||
// generally that platforms have very low memory, so use a 8k buffer
|
||||
char buf[8192];
|
||||
if (pos > 0) {
|
||||
if (lseek(filefd, pos, SEEK_SET)) {
|
||||
uwsgi_error("uwsgi_sendfile_do()/seek()");
|
||||
return -1;
|
||||
}
|
||||
nosf_buf = nosf_buf2;
|
||||
}
|
||||
|
||||
if (!nosf_buf) {
|
||||
uwsgi_error("sendfile malloc()/realloc()");
|
||||
return 0;
|
||||
ssize_t rlen = read(filefd, buf, UMIN(len, 8192));
|
||||
if (rlen <= 0) {
|
||||
uwsgi_error("uwsgi_sendfile_do()/read()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
nosf_buf_size = chunk;
|
||||
|
||||
if (async > 1) {
|
||||
jlen = read(filefd, nosf_buf, chunk);
|
||||
if (jlen <= 0) {
|
||||
uwsgi_error("read()");
|
||||
return 0;
|
||||
}
|
||||
jlen = write(sockfd, nosf_buf, jlen);
|
||||
if (jlen <= 0) {
|
||||
uwsgi_error("write()");
|
||||
return 0;
|
||||
}
|
||||
return jlen;
|
||||
}
|
||||
|
||||
while (i < (int) filesize) {
|
||||
jlen = read(filefd, nosf_buf, chunk);
|
||||
if (jlen <= 0) {
|
||||
uwsgi_error("read()");
|
||||
break;
|
||||
}
|
||||
i += jlen;
|
||||
jlen = write(sockfd, nosf_buf, jlen);
|
||||
if (jlen <= 0) {
|
||||
uwsgi_error("write()");
|
||||
break;
|
||||
}
|
||||
rlen += jlen;
|
||||
}
|
||||
|
||||
return rlen;
|
||||
return write(sockfd, buf, rlen);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
+2
-9
@@ -106,13 +106,11 @@ void uwsgi_setup_inherited_sockets() {
|
||||
//now close all the unbound fd
|
||||
for (j = 3; j < (int) uwsgi.max_fd; j++) {
|
||||
int useless = 1;
|
||||
#ifdef UWSGI_MULTICAST
|
||||
if (j == uwsgi.cluster_fd)
|
||||
continue;
|
||||
#endif
|
||||
if (uwsgi.has_emperor) {
|
||||
if (j == uwsgi.emperor_fd)
|
||||
continue;
|
||||
if (j == uwsgi.emperor_fd_config)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uwsgi.shared->worker_log_pipe[0] > -1) {
|
||||
@@ -130,11 +128,6 @@ void uwsgi_setup_inherited_sockets() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uwsgi.cache_server && uwsgi.cache_server_fd != -1) {
|
||||
if (j == uwsgi.cache_server_fd)
|
||||
continue;
|
||||
}
|
||||
|
||||
struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets;
|
||||
int found = 0;
|
||||
while (ugs) {
|
||||
|
||||
+27
-12
@@ -6,7 +6,9 @@ int uwsgi_signal_handler(uint8_t sig) {
|
||||
|
||||
struct uwsgi_signal_entry *use = NULL;
|
||||
|
||||
use = &uwsgi.shared->signal_table[sig];
|
||||
int pos = (uwsgi.mywid * 256) + sig;
|
||||
|
||||
use = &uwsgi.shared->signal_table[pos];
|
||||
|
||||
if (!use->handler)
|
||||
return -1;
|
||||
@@ -55,13 +57,11 @@ int uwsgi_signal_handler(uint8_t sig) {
|
||||
set_mule_harakiri(uwsgi.shared->options[UWSGI_OPTION_MULE_HARAKIRI]);
|
||||
}
|
||||
}
|
||||
#ifdef UWSGI_SPOOLER
|
||||
else if (uwsgi.i_am_a_spooler && (getpid() == uwsgi.i_am_a_spooler->pid)) {
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
|
||||
set_spooler_harakiri(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int ret = uwsgi.p[use->modifier1]->signal_handler(sig, use->handler);
|
||||
|
||||
@@ -77,20 +77,19 @@ int uwsgi_signal_handler(uint8_t sig) {
|
||||
set_mule_harakiri(0);
|
||||
}
|
||||
}
|
||||
#ifdef UWSGI_SPOOLER
|
||||
else if (uwsgi.i_am_a_spooler && (getpid() == uwsgi.i_am_a_spooler->pid)) {
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
|
||||
set_spooler_harakiri(0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int uwsgi_signal_registered(uint8_t sig) {
|
||||
|
||||
if (uwsgi.shared->signal_table[sig].handler != NULL)
|
||||
int pos = (uwsgi.mywid * 256) + sig;
|
||||
if (uwsgi.shared->signal_table[pos].handler != NULL)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@@ -100,15 +99,23 @@ int uwsgi_register_signal(uint8_t sig, char *receiver, void *handler, uint8_t mo
|
||||
|
||||
struct uwsgi_signal_entry *use = NULL;
|
||||
|
||||
if (!uwsgi.master_process) return -1;
|
||||
|
||||
if (uwsgi.mywid == 0 && uwsgi.workers[0].pid != uwsgi.mypid) {
|
||||
uwsgi_log("only the master and the workers can register signal handlers\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strlen(receiver) > 63)
|
||||
return -1;
|
||||
|
||||
uwsgi_lock(uwsgi.signal_table_lock);
|
||||
|
||||
use = &uwsgi.shared->signal_table[sig];
|
||||
int pos = (uwsgi.mywid * 256) + sig;
|
||||
use = &uwsgi.shared->signal_table[pos];
|
||||
|
||||
if (use->handler) {
|
||||
uwsgi_log("[uwsgi-signal] you cannot re-register a signal !!!\n");
|
||||
if (use->handler && uwsgi.mywid == 0) {
|
||||
uwsgi_log("[uwsgi-signal] you cannot re-register a signal as the master !!!\n");
|
||||
uwsgi_unlock(uwsgi.signal_table_lock);
|
||||
return -1;
|
||||
}
|
||||
@@ -125,6 +132,15 @@ int uwsgi_register_signal(uint8_t sig, char *receiver, void *handler, uint8_t mo
|
||||
uwsgi_log("[uwsgi-signal] signum %d registered (wid: %d modifier1: %d target: %s)\n", sig, uwsgi.mywid, modifier1, receiver);
|
||||
}
|
||||
|
||||
// check for cow
|
||||
if (uwsgi.mywid == 0) {
|
||||
int i;
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
int pos = (i * 256);
|
||||
memcpy(&uwsgi.shared->signal_table[pos], use, sizeof(struct uwsgi_signal_entry) * 256);
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_unlock(uwsgi.signal_table_lock);
|
||||
|
||||
return 0;
|
||||
@@ -426,7 +442,8 @@ int uwsgi_signal_send(int fd, uint8_t sig) {
|
||||
|
||||
void uwsgi_route_signal(uint8_t sig) {
|
||||
|
||||
struct uwsgi_signal_entry *use = &ushared->signal_table[sig];
|
||||
int pos = (uwsgi.mywid * 256) + sig;
|
||||
struct uwsgi_signal_entry *use = &ushared->signal_table[pos];
|
||||
int i;
|
||||
|
||||
// send to first available worker
|
||||
@@ -457,7 +474,6 @@ void uwsgi_route_signal(uint8_t sig) {
|
||||
else if (!strcmp(use->receiver, "subscribed")) {
|
||||
}
|
||||
// route to spooler
|
||||
#ifdef UWSGI_SPOOLER
|
||||
else if (!strcmp(use->receiver, "spooler")) {
|
||||
if (ushared->worker_signal_pipe[0] != -1) {
|
||||
if (uwsgi_signal_send(ushared->spooler_signal_pipe[0], sig)) {
|
||||
@@ -465,7 +481,6 @@ void uwsgi_route_signal(uint8_t sig) {
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (!strcmp(use->receiver, "mules")) {
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
if (uwsgi_signal_send(uwsgi.mules[i].signal_pipe[0], sig)) {
|
||||
|
||||
+15
-6
@@ -1,6 +1,4 @@
|
||||
#ifdef UWSGI_SNMP
|
||||
|
||||
#include "uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
@@ -408,6 +406,17 @@ int uwsgi_setup_snmp(void) {
|
||||
|
||||
return snmp_fd;
|
||||
}
|
||||
#else
|
||||
#warning "*** SNMP support is disabled ***"
|
||||
#endif
|
||||
|
||||
void uwsgi_master_manage_snmp(int snmp_fd) {
|
||||
struct sockaddr_in udp_client;
|
||||
socklen_t udp_len = sizeof(udp_client);
|
||||
ssize_t rlen = recvfrom(snmp_fd, uwsgi.wsgi_req->buffer, uwsgi.buffer_size, 0, (struct sockaddr *) &udp_client, &udp_len);
|
||||
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("recvfrom()");
|
||||
}
|
||||
else if (rlen > 0) {
|
||||
manage_snmp(snmp_fd, (uint8_t *) uwsgi.wsgi_req->buffer, rlen, &udp_client);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+139
-137
@@ -168,7 +168,6 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst
|
||||
return serverfd;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_UDP
|
||||
int bind_to_udp(char *socket_name, int multicast, int broadcast) {
|
||||
int serverfd;
|
||||
struct sockaddr_in uws_addr;
|
||||
@@ -176,10 +175,7 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
|
||||
int bcast = 1;
|
||||
int reuse = 1;
|
||||
|
||||
#ifdef UWSGI_MULTICAST
|
||||
struct ip_mreq mc;
|
||||
uint8_t loop = 1;
|
||||
#endif
|
||||
|
||||
udp_port = strchr(socket_name, ':');
|
||||
if (udp_port == NULL) {
|
||||
@@ -196,7 +192,6 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
|
||||
uws_addr.sin_family = AF_INET;
|
||||
uws_addr.sin_port = htons(atoi(udp_port + 1));
|
||||
|
||||
#ifdef UWSGI_MULTICAST
|
||||
if (!broadcast && !multicast) {
|
||||
char quad[4];
|
||||
char *first_part = strchr(socket_name, '.');
|
||||
@@ -207,9 +202,6 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
|
||||
multicast = 1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (!broadcast) {
|
||||
#endif
|
||||
if (!strcmp(socket_name, "255.255.255.255")) {
|
||||
broadcast = 1;
|
||||
}
|
||||
@@ -236,14 +228,12 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
|
||||
uwsgi_error("setsockopt()");
|
||||
}
|
||||
|
||||
#ifdef UWSGI_MULTICAST
|
||||
if (multicast) {
|
||||
// if multicast is enabled remember to bind to INADDR_ANY
|
||||
uws_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
mc.imr_multiaddr.s_addr = inet_addr(socket_name);
|
||||
mc.imr_interface.s_addr = INADDR_ANY;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (broadcast) {
|
||||
if (setsockopt(serverfd, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast))) {
|
||||
@@ -259,10 +249,9 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_MULTICAST
|
||||
if (multicast) {
|
||||
uwsgi_log("[uWSGI] joining multicast group: %s:%d\n", socket_name, ntohs(uws_addr.sin_port));
|
||||
if (setsockopt(serverfd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop))) {
|
||||
uwsgi_log("[uwsgi-mcast] joining multicast group: %s:%d\n", socket_name, ntohs(uws_addr.sin_port));
|
||||
if (setsockopt(serverfd, IPPROTO_IP, IP_MULTICAST_LOOP, &uwsgi.multicast_loop, sizeof(uwsgi.multicast_loop))) {
|
||||
uwsgi_error("setsockopt()");
|
||||
}
|
||||
|
||||
@@ -275,13 +264,11 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
udp_port[0] = ':';
|
||||
return serverfd;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
int uwsgi_connectn(char *socket_name, uint16_t len, int timeout, int async) {
|
||||
|
||||
@@ -474,7 +461,7 @@ char *generate_socket_name(char *socket_name) {
|
||||
|
||||
}
|
||||
|
||||
uwsgi_log("unable to find avalid socket address\n");
|
||||
uwsgi_log("unable to find a valid socket address\n");
|
||||
#endif
|
||||
uwsgi_nuclear_blast();
|
||||
}
|
||||
@@ -547,12 +534,30 @@ socklen_t socket_to_in_addr(char *socket_name, char *port, int portn, struct soc
|
||||
int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
|
||||
|
||||
int serverfd;
|
||||
#ifdef AF_INET6
|
||||
struct sockaddr_in6 uws_addr;
|
||||
#else
|
||||
struct sockaddr_in uws_addr;
|
||||
#endif
|
||||
int reuse = 1;
|
||||
int family = AF_INET;
|
||||
socklen_t addr_len = sizeof(struct sockaddr_in);
|
||||
|
||||
socket_to_in_addr(socket_name, tcp_port, 0, &uws_addr);
|
||||
#ifdef AF_INET6
|
||||
if (socket_name[0] == '[' && tcp_port[-1] == ']') {
|
||||
family = AF_INET6;
|
||||
socket_to_in_addr6(socket_name, tcp_port, 0, &uws_addr);
|
||||
addr_len = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
socket_to_in_addr(socket_name, tcp_port, 0, (struct sockaddr_in *) &uws_addr);
|
||||
#ifdef AF_INET6
|
||||
}
|
||||
#endif
|
||||
|
||||
serverfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
serverfd = socket(family, SOCK_STREAM, 0);
|
||||
if (serverfd < 0) {
|
||||
uwsgi_error("socket()");
|
||||
uwsgi_nuclear_blast();
|
||||
@@ -586,6 +591,19 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
|
||||
#endif
|
||||
}
|
||||
|
||||
if (uwsgi.tcp_fast_open) {
|
||||
#ifdef TCP_FASTOPEN
|
||||
if (setsockopt(serverfd, SOL_TCP, TCP_FASTOPEN, (const void *) &uwsgi.tcp_fast_open, sizeof(int)) < 0) {
|
||||
uwsgi_error("TCP_FASTOPEN setsockopt()");
|
||||
}
|
||||
else {
|
||||
uwsgi_log("TCP_FASTOPEN enabled on %s\n", socket_name);
|
||||
}
|
||||
#else
|
||||
uwsgi_log("!!! your system does not support TCP_FASTOPEN !!!\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (uwsgi.so_send_timeout) {
|
||||
struct timeval tv;
|
||||
tv.tv_sec = uwsgi.so_send_timeout;
|
||||
@@ -621,7 +639,7 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
|
||||
}
|
||||
|
||||
|
||||
if (bind(serverfd, (struct sockaddr *) &uws_addr, sizeof(uws_addr)) != 0) {
|
||||
if (bind(serverfd, (struct sockaddr *) &uws_addr, addr_len) != 0) {
|
||||
if (errno == EADDRINUSE) {
|
||||
uwsgi_log("probably another instance of uWSGI is running on the same address (%s).\n", socket_name);
|
||||
}
|
||||
@@ -630,9 +648,9 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
long somaxconn = uwsgi_num_from_file("/proc/sys/net/core/somaxconn");
|
||||
long somaxconn = uwsgi_num_from_file("/proc/sys/net/core/somaxconn", 1);
|
||||
if (somaxconn > 0 && uwsgi.listen_queue > somaxconn) {
|
||||
uwsgi_log("Listen queue size is greater than the system max net.core.somaxconn (%i).\n", somaxconn);
|
||||
uwsgi_log("Listen queue size is greater than the system max net.core.somaxconn (%li).\n", somaxconn);
|
||||
uwsgi_nuclear_blast();
|
||||
}
|
||||
#endif
|
||||
@@ -707,7 +725,16 @@ int timed_connect(struct pollfd *fdpoll, const struct sockaddr *addr, int addr_s
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = connect(fdpoll->fd, addr, addr_size);
|
||||
#ifdef MSG_FASTOPEN
|
||||
if (addr->sa_family == AF_INET && uwsgi.tcp_fast_open_client) {
|
||||
ret = sendto(fdpoll->fd, "", 0, MSG_FASTOPEN, addr, addr_size);
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
ret = connect(fdpoll->fd, addr, addr_size);
|
||||
#ifdef MSG_FASTOPEN
|
||||
}
|
||||
#endif
|
||||
|
||||
if (async) {
|
||||
if (ret < 0 && errno != EINPROGRESS) {
|
||||
@@ -923,6 +950,7 @@ struct uwsgi_socket *uwsgi_new_socket(char *name) {
|
||||
char *auto_port = uwsgi_num2str(ntohs(sin.sin_port));
|
||||
char *auto_ip = inet_ntoa(sin.sin_addr);
|
||||
uwsgi_sock->name = uwsgi_concat3n(auto_ip, strlen(auto_ip), ":", 1, auto_port, strlen(auto_port));
|
||||
free(auto_port);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1042,7 +1070,7 @@ void uwsgi_add_socket_from_fd(struct uwsgi_socket *uwsgi_sock, int fd) {
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef UWSGI_IPV6
|
||||
#ifdef AF_INET6
|
||||
else if (gsa.sa->sa_family == AF_INET6) {
|
||||
char *computed_addr;
|
||||
char computed_port[6];
|
||||
@@ -1358,87 +1386,7 @@ nextsock:
|
||||
}
|
||||
|
||||
|
||||
#ifdef UWSGI_IPV6
|
||||
int bind_to_tcp6(char *socket_name, int listen_queue, char *tcp_port) {
|
||||
|
||||
int serverfd;
|
||||
struct sockaddr_in6 uws_addr;
|
||||
int reuse = 1;
|
||||
|
||||
socket_to_in_addr6(socket_name, tcp_port, 0, &uws_addr);
|
||||
|
||||
serverfd = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
if (serverfd < 0) {
|
||||
uwsgi_error("socket()");
|
||||
uwsgi_nuclear_blast();
|
||||
}
|
||||
|
||||
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) {
|
||||
uwsgi_error("setsockopt()");
|
||||
uwsgi_nuclear_blast();
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
#ifdef IP_FREEBIND
|
||||
if (uwsgi.freebind) {
|
||||
if (setsockopt(serverfd, SOL_IP, IP_FREEBIND, (const void *) &uwsgi.freebind, sizeof(int)) < 0) {
|
||||
uwsgi_error("setsockopt()");
|
||||
uwsgi_nuclear_blast();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (uwsgi.reuse_port) {
|
||||
#ifdef SO_REUSEPORT
|
||||
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEPORT, (const void *) &uwsgi.reuse_port, sizeof(int)) < 0) {
|
||||
uwsgi_error("setsockopt()");
|
||||
uwsgi_nuclear_blast();
|
||||
}
|
||||
#else
|
||||
uwsgi_log("!!! your system does not support SO_REUSEPORT !!!\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!uwsgi.no_defer_accept) {
|
||||
|
||||
#ifdef __linux__
|
||||
if (setsockopt(serverfd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], sizeof(int))) {
|
||||
uwsgi_error("setsockopt()");
|
||||
}
|
||||
// OSX has no SO_ACCEPTFILTER !!!
|
||||
#elif defined(__freebsd__)
|
||||
struct accept_filter_arg afa;
|
||||
strcpy(afa.af_name, "dataready");
|
||||
afa.af_arg[0] = 0;
|
||||
if (setsockopt(serverfd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(struct accept_filter_arg))) {
|
||||
uwsgi_error("setsockopt()");
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (bind(serverfd, (struct sockaddr *) &uws_addr, sizeof(uws_addr)) != 0) {
|
||||
if (errno == EADDRINUSE) {
|
||||
uwsgi_log("probably another instance of uWSGI is running on the same address.\n");
|
||||
}
|
||||
uwsgi_error("bind()");
|
||||
uwsgi_nuclear_blast();
|
||||
}
|
||||
|
||||
if (listen(serverfd, listen_queue) != 0) {
|
||||
uwsgi_error("listen()");
|
||||
uwsgi_nuclear_blast();
|
||||
}
|
||||
|
||||
|
||||
if (tcp_port)
|
||||
tcp_port[0] = ':';
|
||||
|
||||
return serverfd;
|
||||
}
|
||||
|
||||
#ifdef AF_INET6
|
||||
socklen_t socket_to_in_addr6(char *socket_name, char *port, int portn, struct sockaddr_in6 * sin_addr) {
|
||||
|
||||
memset(sin_addr, 0, sizeof(struct sockaddr_in6));
|
||||
@@ -1494,9 +1442,9 @@ void uwsgi_setup_shared_sockets() {
|
||||
uwsgi_log("uwsgi shared socket %d bound to UNIX address %s fd %d\n", uwsgi_get_shared_socket_num(shared_sock), shared_sock->name, shared_sock->fd);
|
||||
}
|
||||
else {
|
||||
#ifdef UWSGI_IPV6
|
||||
#ifdef AF_INET6
|
||||
if (shared_sock->name[0] == '[' && tcp_port[-1] == ']') {
|
||||
shared_sock->fd = bind_to_tcp6(shared_sock->name, uwsgi.listen_queue, tcp_port);
|
||||
shared_sock->fd = bind_to_tcp(shared_sock->name, uwsgi.listen_queue, tcp_port);
|
||||
shared_sock->family = AF_INET6;
|
||||
// fix socket name
|
||||
shared_sock->name = uwsgi_getsockname(shared_sock->fd);
|
||||
@@ -1509,7 +1457,7 @@ void uwsgi_setup_shared_sockets() {
|
||||
// fix socket name
|
||||
shared_sock->name = uwsgi_getsockname(shared_sock->fd);
|
||||
uwsgi_log("uwsgi shared socket %d bound to TCP address %s fd %d\n", uwsgi_get_shared_socket_num(shared_sock), shared_sock->name, shared_sock->fd);
|
||||
#ifdef UWSGI_IPV6
|
||||
#ifdef AF_INET6
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1539,9 +1487,7 @@ void uwsgi_setup_shared_sockets() {
|
||||
}
|
||||
shared_sock->fd = i;
|
||||
}
|
||||
else {
|
||||
free(sock);
|
||||
}
|
||||
free(sock);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1611,7 +1557,7 @@ void uwsgi_map_sockets() {
|
||||
exit(1);
|
||||
}
|
||||
if (fd != uwsgi_sock->fd) {
|
||||
if (dup2(fd, uwsgi_sock->fd)) {
|
||||
if (dup2(fd, uwsgi_sock->fd) < 0) {
|
||||
uwsgi_error("dup2()");
|
||||
exit(1);
|
||||
}
|
||||
@@ -1655,9 +1601,9 @@ void uwsgi_bind_sockets() {
|
||||
uwsgi_log("uwsgi socket %d bound to UNIX address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd);
|
||||
}
|
||||
else {
|
||||
#ifdef UWSGI_IPV6
|
||||
#ifdef AF_INET6
|
||||
if (uwsgi_sock->name[0] == '[' && tcp_port[-1] == ']') {
|
||||
uwsgi_sock->fd = bind_to_tcp6(uwsgi_sock->name, uwsgi.listen_queue, tcp_port);
|
||||
uwsgi_sock->fd = bind_to_tcp(uwsgi_sock->name, uwsgi.listen_queue, tcp_port);
|
||||
uwsgi_log("uwsgi socket %d bound to TCP6 address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd);
|
||||
uwsgi_sock->family = AF_INET6;
|
||||
}
|
||||
@@ -1666,7 +1612,7 @@ void uwsgi_bind_sockets() {
|
||||
uwsgi_sock->fd = bind_to_tcp(uwsgi_sock->name, uwsgi.listen_queue, tcp_port);
|
||||
uwsgi_log("uwsgi socket %d bound to TCP address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd);
|
||||
uwsgi_sock->family = AF_INET;
|
||||
#ifdef UWSGI_IPV6
|
||||
#ifdef AF_INET6
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1702,14 +1648,14 @@ void uwsgi_bind_sockets() {
|
||||
gsa.sa = (struct sockaddr *) &usa;
|
||||
if (!uwsgi.skip_zero && !getsockname(0, gsa.sa, &socket_type_len)) {
|
||||
if (gsa.sa->sa_family == AF_UNIX) {
|
||||
uwsgi_sock = uwsgi_new_socket(usa.sa_un.sun_path);
|
||||
uwsgi_sock = uwsgi_new_socket(uwsgi_getsockname(0));
|
||||
uwsgi_sock->family = AF_UNIX;
|
||||
uwsgi_sock->fd = 0;
|
||||
uwsgi_sock->bound = 1;
|
||||
uwsgi_log("uwsgi socket %d inherited UNIX address %s fd 0\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name);
|
||||
}
|
||||
else {
|
||||
uwsgi_sock = uwsgi_new_socket(uwsgi_concat2("::", ""));
|
||||
uwsgi_sock = uwsgi_new_socket(uwsgi_getsockname(0));
|
||||
uwsgi_sock->family = AF_INET;
|
||||
uwsgi_sock->fd = 0;
|
||||
uwsgi_sock->bound = 1;
|
||||
@@ -1723,7 +1669,7 @@ void uwsgi_bind_sockets() {
|
||||
exit(1);
|
||||
}
|
||||
if (fd != 0) {
|
||||
if (dup2(fd, 0)) {
|
||||
if (dup2(fd, 0) < 0) {
|
||||
uwsgi_error("dup2()");
|
||||
exit(1);
|
||||
}
|
||||
@@ -1742,14 +1688,14 @@ void uwsgi_bind_sockets() {
|
||||
uwsgi_sock = uwsgi.sockets;
|
||||
while (uwsgi_sock) {
|
||||
if (uwsgi_sock->auto_port) {
|
||||
#ifdef UWSGI_IPV6
|
||||
#ifdef AF_INET6
|
||||
if (uwsgi_sock->family == AF_INET6) {
|
||||
uwsgi_log("uwsgi socket %d bound to TCP6 address %s (port auto-assigned) fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd);
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
uwsgi_log("uwsgi socket %d bound to TCP address %s (port auto-assigned) fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd);
|
||||
#ifdef UWSGI_IPV6
|
||||
#ifdef AF_INET6
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1760,6 +1706,7 @@ void uwsgi_bind_sockets() {
|
||||
}
|
||||
|
||||
void uwsgi_set_sockets_protocols() {
|
||||
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
while (uwsgi_sock) {
|
||||
char *requested_protocol = uwsgi_sock->proto_name;
|
||||
@@ -1781,6 +1728,7 @@ void uwsgi_set_sockets_protocols() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
setup_proto:
|
||||
if (!requested_protocol) {
|
||||
requested_protocol = uwsgi.protocol;
|
||||
@@ -1789,28 +1737,70 @@ setup_proto:
|
||||
if (requested_protocol && !strcmp("http", requested_protocol)) {
|
||||
uwsgi_sock->proto = uwsgi_proto_http_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_uwsgi_write;
|
||||
uwsgi_sock->proto_writev = uwsgi_proto_uwsgi_writev;
|
||||
uwsgi_sock->proto_write_header = uwsgi_proto_uwsgi_write_header;
|
||||
uwsgi_sock->proto_writev_header = uwsgi_proto_uwsgi_writev_header;
|
||||
uwsgi_sock->proto_sendfile = NULL;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_base_close;
|
||||
if (uwsgi.offload_threads > 0)
|
||||
uwsgi_sock->can_offload = 1;
|
||||
}
|
||||
|
||||
else if (requested_protocol && (!strcmp("fastcgi", requested_protocol) || !strcmp("fcgi", requested_protocol))) {
|
||||
if (uwsgi.protocol && (!strcmp(uwsgi.protocol, "fastcgi") || !strcmp(uwsgi.protocol, "fcgi"))) {
|
||||
uwsgi.shared->options[UWSGI_OPTION_CGI_MODE] = 1;
|
||||
}
|
||||
uwsgi_sock->proto = uwsgi_proto_fastcgi_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_writev = uwsgi_proto_fastcgi_writev;
|
||||
uwsgi_sock->proto_write_header = uwsgi_proto_fastcgi_write_header;
|
||||
uwsgi_sock->proto_writev_header = uwsgi_proto_fastcgi_writev_header;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_cgi_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_fastcgi_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_fastcgi_close;
|
||||
}
|
||||
else if (requested_protocol && (!strcmp("fastcgi-nph", requested_protocol) || !strcmp("fcgi-nph", requested_protocol))) {
|
||||
uwsgi_sock->proto = uwsgi_proto_fastcgi_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_fastcgi_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_fastcgi_close;
|
||||
}
|
||||
|
||||
else if (requested_protocol && (!strcmp("scgi", requested_protocol) || !strcmp("scgi", requested_protocol))) {
|
||||
uwsgi_sock->proto = uwsgi_proto_scgi_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_cgi_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_base_close;
|
||||
}
|
||||
|
||||
else if (requested_protocol && (!strcmp("scgi-nph", requested_protocol) || !strcmp("scgi-nph", requested_protocol))) {
|
||||
uwsgi_sock->proto = uwsgi_proto_scgi_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_base_close;
|
||||
}
|
||||
|
||||
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
else if (requested_protocol && !strcmp("zmq", requested_protocol)) {
|
||||
uwsgi.zeromq = 1;
|
||||
@@ -1819,11 +1809,13 @@ setup_proto:
|
||||
else {
|
||||
uwsgi_sock->proto = uwsgi_proto_uwsgi_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_uwsgi_write;
|
||||
uwsgi_sock->proto_writev = uwsgi_proto_uwsgi_writev;
|
||||
uwsgi_sock->proto_write_header = uwsgi_proto_uwsgi_write_header;
|
||||
uwsgi_sock->proto_writev_header = uwsgi_proto_uwsgi_writev_header;
|
||||
uwsgi_sock->proto_sendfile = NULL;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_base_close;
|
||||
if (uwsgi.offload_threads > 0)
|
||||
uwsgi_sock->can_offload = 1;
|
||||
@@ -1834,3 +1826,13 @@ nextsock:
|
||||
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_tcp_nodelay(int fd) {
|
||||
#ifdef TCP_NODELAY
|
||||
int flag = 1;
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int))) {
|
||||
uwsgi_error("uwsgi_tcp_nodelay()/setsockopt()");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+12
-7
@@ -1,4 +1,3 @@
|
||||
#ifdef UWSGI_SPOOLER
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
@@ -97,8 +96,18 @@ pid_t spooler_start(struct uwsgi_spooler * uspool) {
|
||||
exit(1);
|
||||
}
|
||||
else if (pid == 0) {
|
||||
|
||||
signal(SIGALRM, SIG_IGN);
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
signal(SIGINT, end_me);
|
||||
signal(SIGTERM, end_me);
|
||||
// USR1 will be used to wake up the spooler
|
||||
uwsgi_unix_signal(SIGUSR1, spooler_wakeup);
|
||||
signal(SIGUSR2, SIG_IGN);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGSTOP, SIG_IGN);
|
||||
signal(SIGTSTP, SIG_IGN);
|
||||
|
||||
uwsgi.mywid = -1;
|
||||
uwsgi.mypid = getpid();
|
||||
uspool->pid = uwsgi.mypid;
|
||||
@@ -245,7 +254,7 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core
|
||||
close(fd);
|
||||
|
||||
if (!uwsgi.spooler_quiet)
|
||||
uwsgi_log("[spooler] written %d bytes to file %s\n", size + body_len + 4, filename);
|
||||
uwsgi_log("[spooler] written %lu bytes to file %s\n", (unsigned long) size + body_len + 4, filename);
|
||||
|
||||
// and here waiting threads can continue
|
||||
uwsgi_unlock(uspool->lock);
|
||||
@@ -538,7 +547,7 @@ void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) {
|
||||
uspool->tasks++;
|
||||
if (ret == -2) {
|
||||
if (!uwsgi.spooler_quiet)
|
||||
uwsgi_log("[spooler %s pid: %d] done with task %s after %d seconds\n", uspool->dir, (int) uwsgi.mypid, task, uwsgi_now() - now);
|
||||
uwsgi_log("[spooler %s pid: %d] done with task %s after %lld seconds\n", uspool->dir, (int) uwsgi.mypid, task, (long long) uwsgi_now() - now);
|
||||
destroy_spool(dir, task);
|
||||
}
|
||||
// re-spool it
|
||||
@@ -574,7 +583,3 @@ void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#warning "*** Spooler support is disabled ***"
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ extern struct uwsgi_server uwsgi;
|
||||
static int uwsgi_sqlite3_config_callback(void *magic_table, int field_count, char **fields, char **col) {
|
||||
// make a copy of the string
|
||||
if (field_count >= 2) {
|
||||
int value_len = strlen(fields[1]) + 1;
|
||||
size_t value_len = strlen(fields[1]) + 1;
|
||||
char *value = magic_sub(fields[1], value_len, &value_len, (char **) magic_table);
|
||||
add_exported_option(uwsgi_strncopy(fields[0], strlen(fields[0])), value, 0);
|
||||
}
|
||||
|
||||
+499
@@ -0,0 +1,499 @@
|
||||
#include "../uwsgi.h"
|
||||
#include <openssl/rand.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
/*
|
||||
|
||||
ssl additional datas are retrieved via indexes.
|
||||
|
||||
You can create an index with SSL_CTX_get_ex_new_index and
|
||||
set data in it with SSL_CTX_set_ex_data
|
||||
|
||||
*/
|
||||
|
||||
void uwsgi_ssl_init(void) {
|
||||
OPENSSL_config(NULL);
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
OpenSSL_add_all_algorithms();
|
||||
uwsgi.ssl_initialized = 1;
|
||||
}
|
||||
|
||||
void uwsgi_ssl_info_cb(SSL const *ssl, int where, int ret) {
|
||||
if (where & SSL_CB_HANDSHAKE_DONE) {
|
||||
if (ssl->s3) {
|
||||
ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int uwsgi_ssl_verify_callback(int ok, X509_STORE_CTX * x509_store) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int uwsgi_ssl_session_new_cb(SSL *ssl, SSL_SESSION *sess) {
|
||||
char session_blob[4096];
|
||||
int len = i2d_SSL_SESSION(sess, NULL);
|
||||
if (len > 4096) {
|
||||
if (uwsgi.ssl_verbose) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to store session of size %d\n", len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char *p = (unsigned char *) session_blob;
|
||||
i2d_SSL_SESSION(sess, &p);
|
||||
|
||||
// ok let's write the value to the cache
|
||||
uwsgi_wlock(uwsgi.ssl_sessions_cache->lock);
|
||||
if (uwsgi_cache_set2(uwsgi.ssl_sessions_cache, (char *) sess->session_id, sess->session_id_length, session_blob, len, uwsgi.ssl_sessions_timeout, 0)) {
|
||||
if (uwsgi.ssl_verbose) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to store session of size %d in the cache\n", len);
|
||||
}
|
||||
}
|
||||
uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SSL_SESSION *uwsgi_ssl_session_get_cb(SSL *ssl, unsigned char *key, int keylen, int *copy) {
|
||||
|
||||
uint64_t valsize = 0;
|
||||
|
||||
*copy = 0;
|
||||
uwsgi_rlock(uwsgi.ssl_sessions_cache->lock);
|
||||
char *value = uwsgi_cache_get2(uwsgi.ssl_sessions_cache, (char *)key, keylen, &valsize);
|
||||
if (!value) {
|
||||
uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock);
|
||||
if (uwsgi.ssl_verbose) {
|
||||
uwsgi_log("[uwsgi-ssl] cache miss\n");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
SSL_SESSION *sess = d2i_SSL_SESSION(NULL, (const unsigned char **)&value, valsize);
|
||||
uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock);
|
||||
return sess;
|
||||
}
|
||||
|
||||
void uwsgi_ssl_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess) {
|
||||
uwsgi_wlock(uwsgi.ssl_sessions_cache->lock);
|
||||
if (uwsgi_cache_del2(uwsgi.ssl_sessions_cache, (char *) sess->session_id, sess->session_id_length, 0, 0)) {
|
||||
if (uwsgi.ssl_verbose) {
|
||||
uwsgi_log("[uwsgi-ssl] error removing cache item\n");
|
||||
}
|
||||
}
|
||||
uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock);
|
||||
}
|
||||
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
static int uwsgi_sni_cb(SSL *ssl, int *ad, void *arg) {
|
||||
const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
|
||||
if (!servername) return SSL_TLSEXT_ERR_NOACK;
|
||||
size_t servername_len = strlen(servername);
|
||||
|
||||
struct uwsgi_string_list *usl = uwsgi.sni;
|
||||
while(usl) {
|
||||
if (!uwsgi_strncmp(usl->value, usl->len, (char *)servername, servername_len)) {
|
||||
SSL_set_SSL_CTX(ssl, usl->custom_ptr);
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
struct uwsgi_regexp_list *url = uwsgi.sni_regexp;
|
||||
while(url) {
|
||||
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, (char *)servername, servername_len) >= 0) {
|
||||
SSL_set_SSL_CTX(ssl, url->custom_ptr);
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
url = url->next;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (uwsgi.sni_dir) {
|
||||
size_t sni_dir_len = strlen(uwsgi.sni_dir);
|
||||
char *sni_dir_cert = uwsgi_concat4n(uwsgi.sni_dir, sni_dir_len, "/", 1, (char *) servername, servername_len, ".crt", 4);
|
||||
char *sni_dir_key = uwsgi_concat4n(uwsgi.sni_dir, sni_dir_len, "/", 1, (char *) servername, servername_len, ".key", 4);
|
||||
char *sni_dir_client_ca = uwsgi_concat4n(uwsgi.sni_dir, sni_dir_len, "/", 1, (char *) servername, servername_len, ".ca", 3);
|
||||
if (uwsgi_file_exists(sni_dir_cert) && uwsgi_file_exists(sni_dir_key)) {
|
||||
char *client_ca = NULL;
|
||||
if (uwsgi_file_exists(sni_dir_client_ca)) {
|
||||
client_ca = sni_dir_client_ca;
|
||||
}
|
||||
usl = uwsgi_ssl_add_sni_item(uwsgi_str((char *)servername), sni_dir_cert, sni_dir_key, uwsgi.sni_dir_ciphers, client_ca);
|
||||
if (!usl) goto done;
|
||||
free(sni_dir_cert);
|
||||
free(sni_dir_key);
|
||||
free(sni_dir_client_ca);
|
||||
SSL_set_SSL_CTX(ssl, usl->custom_ptr);
|
||||
uwsgi_log("[uwsgi-sni for pid %d] added context for %s\n", (int) getpid(), servername);
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
done:
|
||||
free(sni_dir_cert);
|
||||
free(sni_dir_key);
|
||||
free(sni_dir_client_ca);
|
||||
}
|
||||
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
#endif
|
||||
|
||||
SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ciphers, char *client_ca) {
|
||||
|
||||
SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
|
||||
if (!ctx) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to initialize context \"%s\"\n", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// this part is taken from nginx and stud, removing unneeded functionality
|
||||
// stud (for me) has made the best choice on choosing DH approach
|
||||
|
||||
long ssloptions = SSL_OP_NO_SSLv2 | SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION;
|
||||
// disable compression (if possibile)
|
||||
#ifdef SSL_OP_NO_COMPRESSION
|
||||
ssloptions |= SSL_OP_NO_COMPRESSION;
|
||||
#endif
|
||||
|
||||
// release/reuse buffers as soon as possibile
|
||||
#ifdef SSL_MODE_RELEASE_BUFFERS
|
||||
SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
|
||||
#endif
|
||||
|
||||
if (SSL_CTX_use_certificate_chain_file(ctx, crt) <= 0) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to assign certificate %s for context \"%s\"\n", crt, name);
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// this part is based from stud
|
||||
BIO *bio = BIO_new_file(crt, "r");
|
||||
if (bio) {
|
||||
DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
|
||||
BIO_free(bio);
|
||||
if (dh) {
|
||||
SSL_CTX_set_tmp_dh(ctx, dh);
|
||||
DH_free(dh);
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
|
||||
#ifndef OPENSSL_NO_ECDH
|
||||
#ifdef NID_X9_62_prime256v1
|
||||
EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||||
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
|
||||
EC_KEY_free(ecdh);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) <= 0) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to assign key %s for context \"%s\"\n", key, name);
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// if ciphers are specified, prefer server ciphers
|
||||
if (ciphers && strlen(ciphers) > 0) {
|
||||
if (SSL_CTX_set_cipher_list(ctx, ciphers) == 0) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to set requested ciphers (%s) for context \"%s\"\n", ciphers, name);
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssloptions |= SSL_OP_CIPHER_SERVER_PREFERENCE;
|
||||
}
|
||||
|
||||
// set session context (if possibile), this is required for client certificate authentication
|
||||
if (name) {
|
||||
SSL_CTX_set_session_id_context(ctx, (unsigned char *) name, strlen(name));
|
||||
}
|
||||
|
||||
if (client_ca) {
|
||||
if (client_ca[0] == '!') {
|
||||
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, uwsgi_ssl_verify_callback);
|
||||
client_ca++;
|
||||
}
|
||||
else {
|
||||
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, uwsgi_ssl_verify_callback);
|
||||
}
|
||||
// in the future we should allow to set the verify depth
|
||||
SSL_CTX_set_verify_depth(ctx, 1);
|
||||
if (SSL_CTX_load_verify_locations(ctx, client_ca, NULL) == 0) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to set ssl verify locations (%s) for context \"%s\"\n", client_ca, name);
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
STACK_OF(X509_NAME) * list = SSL_load_client_CA_file(client_ca);
|
||||
if (!list) {
|
||||
uwsgi_log("unable to load client CA certificate (%s) for context \"%s\"\n", client_ca, name);
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SSL_CTX_set_client_CA_list(ctx, list);
|
||||
}
|
||||
|
||||
|
||||
SSL_CTX_set_info_callback(ctx, uwsgi_ssl_info_cb);
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
SSL_CTX_set_tlsext_servername_callback(ctx, uwsgi_sni_cb);
|
||||
#endif
|
||||
|
||||
// disable session caching by default
|
||||
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
|
||||
|
||||
if (uwsgi.ssl_sessions_use_cache) {
|
||||
|
||||
// we need to early initialize locking and caching
|
||||
uwsgi_setup_locking();
|
||||
uwsgi_cache_create_all();
|
||||
|
||||
uwsgi.ssl_sessions_cache = uwsgi_cache_by_name(uwsgi.ssl_sessions_use_cache);
|
||||
if (!uwsgi.ssl_sessions_cache) {
|
||||
uwsgi_log("unable to find cache \"%s\"\n", uwsgi.ssl_sessions_use_cache ? uwsgi.ssl_sessions_use_cache : "default");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!uwsgi.ssl_sessions_cache->max_items) {
|
||||
uwsgi_log("you have to enable uWSGI cache to use it as SSL session store !!!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (uwsgi.ssl_sessions_cache->blocksize < 4096) {
|
||||
uwsgi_log("cache blocksize for SSL session store must be at least 4096 bytes\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER|
|
||||
SSL_SESS_CACHE_NO_INTERNAL|
|
||||
SSL_SESS_CACHE_NO_AUTO_CLEAR);
|
||||
|
||||
#ifdef SSL_OP_NO_TICKET
|
||||
ssloptions |= SSL_OP_NO_TICKET;
|
||||
#endif
|
||||
|
||||
// just for fun
|
||||
SSL_CTX_sess_set_cache_size(ctx, 0);
|
||||
|
||||
// set the callback for ssl sessions
|
||||
SSL_CTX_sess_set_new_cb(ctx, uwsgi_ssl_session_new_cb);
|
||||
SSL_CTX_sess_set_get_cb(ctx, uwsgi_ssl_session_get_cb);
|
||||
SSL_CTX_sess_set_remove_cb(ctx, uwsgi_ssl_session_remove_cb);
|
||||
}
|
||||
|
||||
SSL_CTX_set_timeout(ctx, uwsgi.ssl_sessions_timeout);
|
||||
|
||||
SSL_CTX_set_options(ctx, ssloptions);
|
||||
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_rsa_sign(char *algo_key, char *message, size_t message_len, unsigned int *s_len) {
|
||||
|
||||
// openssl could not be initialized
|
||||
if (!uwsgi.ssl_initialized) {
|
||||
uwsgi_ssl_init();
|
||||
}
|
||||
|
||||
*s_len = 0;
|
||||
EVP_PKEY *pk = NULL;
|
||||
|
||||
char *algo = uwsgi_str(algo_key);
|
||||
char *colon = strchr(algo, ':');
|
||||
if (!colon) {
|
||||
uwsgi_log("invalid RSA signature syntax, must be: <digest>:<pemfile>\n");
|
||||
free(algo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*colon = 0;
|
||||
char *keyfile = colon + 1;
|
||||
char *signature = NULL;
|
||||
|
||||
FILE *kf = fopen(keyfile, "r");
|
||||
if (!kf) {
|
||||
uwsgi_error_open(keyfile);
|
||||
free(algo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (PEM_read_PrivateKey(kf, &pk, NULL, NULL) == 0) {
|
||||
uwsgi_log("unable to load private key: %s\n", keyfile);
|
||||
free(algo);
|
||||
fclose(kf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fclose(kf);
|
||||
|
||||
EVP_MD_CTX *ctx = EVP_MD_CTX_create();
|
||||
if (!ctx) {
|
||||
free(algo);
|
||||
EVP_PKEY_free(pk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const EVP_MD *md = EVP_get_digestbyname(algo);
|
||||
if (!md) {
|
||||
uwsgi_log("unknown digest algo: %s\n", algo);
|
||||
free(algo);
|
||||
EVP_PKEY_free(pk);
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*s_len = EVP_PKEY_size(pk);
|
||||
signature = uwsgi_malloc(*s_len);
|
||||
|
||||
if (EVP_SignInit_ex(ctx, md, NULL) == 0) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
free(signature);
|
||||
signature = NULL;
|
||||
*s_len = 0;
|
||||
goto clear;
|
||||
}
|
||||
|
||||
if (EVP_SignUpdate(ctx, message, message_len) == 0) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
free(signature);
|
||||
signature = NULL;
|
||||
*s_len = 0;
|
||||
goto clear;
|
||||
}
|
||||
|
||||
|
||||
if (EVP_SignFinal(ctx, (unsigned char *) signature, s_len, pk) == 0) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
free(signature);
|
||||
signature = NULL;
|
||||
*s_len = 0;
|
||||
goto clear;
|
||||
}
|
||||
|
||||
clear:
|
||||
free(algo);
|
||||
EVP_PKEY_free(pk);
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
return signature;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_sanitize_cert_filename(char *base, char *key, uint16_t keylen) {
|
||||
uint16_t i;
|
||||
char *filename = uwsgi_concat4n(base, strlen(base), "/", 1, key, keylen, ".pem\0", 5);
|
||||
|
||||
for (i = strlen(base) + 1; i < (strlen(base) + 1) + keylen; i++) {
|
||||
if (filename[i] >= '0' && filename[i] <= '9')
|
||||
continue;
|
||||
if (filename[i] >= 'A' && filename[i] <= 'Z')
|
||||
continue;
|
||||
if (filename[i] >= 'a' && filename[i] <= 'z')
|
||||
continue;
|
||||
if (filename[i] == '.')
|
||||
continue;
|
||||
if (filename[i] == '-')
|
||||
continue;
|
||||
if (filename[i] == '_')
|
||||
continue;
|
||||
filename[i] = '_';
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
char *uwsgi_ssl_rand(size_t len) {
|
||||
unsigned char *buf = uwsgi_calloc(len+1);
|
||||
if (RAND_bytes(buf, len) <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
return (char *) buf;
|
||||
}
|
||||
|
||||
char *uwsgi_sha1(char *src, size_t len, char *dst) {
|
||||
SHA_CTX sha;
|
||||
SHA1_Init(&sha);
|
||||
SHA1_Update(&sha, src, len);
|
||||
SHA1_Final((unsigned char *)dst, &sha);
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *uwsgi_sha1_2n(char *s1, size_t len1, char *s2, size_t len2, char *dst) {
|
||||
SHA_CTX sha;
|
||||
SHA1_Init(&sha);
|
||||
SHA1_Update(&sha, s1, len1);
|
||||
SHA1_Update(&sha, s2, len2);
|
||||
SHA1_Final((unsigned char *)dst, &sha);
|
||||
return dst;
|
||||
}
|
||||
|
||||
void uwsgi_opt_sni(char *opt, char *value, void *foobar) {
|
||||
char *client_ca = NULL;
|
||||
char *v = uwsgi_str(value);
|
||||
|
||||
char *space = strchr(v, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid %s syntax, must be sni_key<space>crt,key[,ciphers,client_ca]\n", opt);
|
||||
exit(1);
|
||||
}
|
||||
*space = 0;
|
||||
char *crt = space+1;
|
||||
char *key = strchr(crt, ',');
|
||||
if (!key) {
|
||||
uwsgi_log("invalid %s syntax, must be sni_key<space>crt,key[,ciphers,client_ca]\n", opt);
|
||||
exit(1);
|
||||
}
|
||||
*key = '\0'; key++;
|
||||
|
||||
char *ciphers = strchr(key, ',');
|
||||
if (ciphers) {
|
||||
*ciphers = '\0'; ciphers++;
|
||||
client_ca = strchr(ciphers, ',');
|
||||
if (client_ca) {
|
||||
*client_ca = '\0'; client_ca++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!uwsgi.ssl_initialized) {
|
||||
uwsgi_ssl_init();
|
||||
}
|
||||
|
||||
SSL_CTX *ctx = uwsgi_ssl_new_server_context(v, crt, key, ciphers, client_ca);
|
||||
if (!ctx) {
|
||||
uwsgi_log("[uwsgi-ssl] DANGER unable to initialize context for \"%s\"\n", v);
|
||||
free(v);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
if (!strcmp(opt, "sni-regexp")) {
|
||||
struct uwsgi_regexp_list *url = uwsgi_regexp_new_list(&uwsgi.sni_regexp, v);
|
||||
url->custom_ptr = ctx;
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
struct uwsgi_string_list *usl = uwsgi_string_new_list(&uwsgi.sni, v);
|
||||
usl->custom_ptr = ctx;
|
||||
#ifdef UWSGI_PCRE
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_string_list *uwsgi_ssl_add_sni_item(char *name, char *crt, char *key, char *ciphers, char *client_ca) {
|
||||
if (!uwsgi.ssl_initialized) {
|
||||
uwsgi_ssl_init();
|
||||
}
|
||||
SSL_CTX *ctx = uwsgi_ssl_new_server_context(name, crt, key, ciphers, client_ca);
|
||||
if (!ctx) {
|
||||
uwsgi_log("[uwsgi-ssl] DANGER unable to initialize context for \"%s\"\n", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_string_list *usl = uwsgi_string_new_list(&uwsgi.sni, name);
|
||||
usl->custom_ptr = ctx;
|
||||
return usl;
|
||||
}
|
||||
+605
@@ -0,0 +1,605 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_static_want_gzip(struct wsgi_request *wsgi_req, char *filename, size_t filename_len, struct stat *st) {
|
||||
// check for filename size
|
||||
if (filename_len + 4 > PATH_MAX) return 0;
|
||||
// check for supported encodings
|
||||
if (!uwsgi_contains_n(wsgi_req->encoding, wsgi_req->encoding_len, "gzip", 4) ) return 0;
|
||||
|
||||
// check for 'all'
|
||||
if (uwsgi.static_gzip_all) goto gzip;
|
||||
|
||||
// check for dirs/prefix
|
||||
struct uwsgi_string_list *usl = uwsgi.static_gzip_dir;
|
||||
while(usl) {
|
||||
if (!uwsgi_starts_with(filename, filename_len, usl->value, usl->len)) {
|
||||
goto gzip;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
// check for ext/suffix
|
||||
usl = uwsgi.static_gzip_ext;
|
||||
while(usl) {
|
||||
if (!uwsgi_strncmp(filename + (filename_len - usl->len), usl->len, usl->value, usl->len)) {
|
||||
goto gzip;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
// check for regexp
|
||||
struct uwsgi_regexp_list *url = uwsgi.static_gzip;
|
||||
while(url) {
|
||||
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, filename, filename_len) >= 0) {
|
||||
goto gzip;
|
||||
}
|
||||
url = url->next;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
gzip:
|
||||
|
||||
memcpy(filename + filename_len, ".gz\0", 4);
|
||||
filename_len += 3;
|
||||
|
||||
if (stat(filename, st)) {
|
||||
filename_len -= 3;
|
||||
filename[filename_len] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int set_http_date(time_t t, char *dst) {
|
||||
|
||||
static char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
|
||||
static char *months[] = {
|
||||
"Jan", "Feb", "Mar", "Apr",
|
||||
"May", "Jun", "Jul", "Aug",
|
||||
"Sep", "Oct", "Nov", "Dec"
|
||||
};
|
||||
|
||||
struct tm *hdtm = gmtime(&t);
|
||||
|
||||
int ret = snprintf(dst, 31, "%s, %02d %s %4d %02d:%02d:%02d GMT",
|
||||
week[hdtm->tm_wday], hdtm->tm_mday, months[hdtm->tm_mon], hdtm->tm_year + 1900, hdtm->tm_hour, hdtm->tm_min, hdtm->tm_sec);
|
||||
if (ret <= 0 || ret > 31) {
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// only RFC 1123 is supported
|
||||
static time_t parse_http_date(char *date, uint16_t len) {
|
||||
|
||||
struct tm hdtm;
|
||||
|
||||
if (len != 29 && date[3] != ',')
|
||||
return 0;
|
||||
|
||||
hdtm.tm_mday = uwsgi_str2_num(date + 5);
|
||||
|
||||
switch (date[8]) {
|
||||
case 'J':
|
||||
if (date[9] == 'a') {
|
||||
hdtm.tm_mon = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (date[9] == 'u') {
|
||||
if (date[10] == 'n') {
|
||||
hdtm.tm_mon = 5;
|
||||
break;
|
||||
}
|
||||
|
||||
if (date[10] == 'l') {
|
||||
hdtm.tm_mon = 6;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
case 'F':
|
||||
hdtm.tm_mon = 1;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
if (date[9] != 'a')
|
||||
return 0;
|
||||
|
||||
if (date[10] == 'r') {
|
||||
hdtm.tm_mon = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (date[10] == 'y') {
|
||||
hdtm.tm_mon = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
case 'A':
|
||||
if (date[10] == 'r') {
|
||||
hdtm.tm_mon = 3;
|
||||
break;
|
||||
}
|
||||
if (date[10] == 'g') {
|
||||
hdtm.tm_mon = 7;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case 'S':
|
||||
hdtm.tm_mon = 8;
|
||||
break;
|
||||
|
||||
case 'O':
|
||||
hdtm.tm_mon = 9;
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
hdtm.tm_mon = 10;
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
hdtm.tm_mon = 11;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
hdtm.tm_year = uwsgi_str4_num(date + 12) - 1900;
|
||||
|
||||
hdtm.tm_hour = uwsgi_str2_num(date + 17);
|
||||
hdtm.tm_min = uwsgi_str2_num(date + 20);
|
||||
hdtm.tm_sec = uwsgi_str2_num(date + 23);
|
||||
|
||||
return timegm(&hdtm);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int uwsgi_add_expires_type(struct wsgi_request *wsgi_req, char *mime_type, int mime_type_len, struct stat *st) {
|
||||
|
||||
struct uwsgi_dyn_dict *udd = uwsgi.static_expires_type;
|
||||
time_t now = wsgi_req->start_of_request / 1000000;
|
||||
// 30+1
|
||||
char expires[31];
|
||||
|
||||
while (udd) {
|
||||
if (!uwsgi_strncmp(udd->key, udd->keylen, mime_type, mime_type_len)) {
|
||||
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
||||
int size = set_http_date(now + delta, expires);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
udd = uwsgi.static_expires_type_mtime;
|
||||
while (udd) {
|
||||
if (!uwsgi_strncmp(udd->key, udd->keylen, mime_type, mime_type_len)) {
|
||||
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
||||
int size = set_http_date(st->st_mtime + delta, expires);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
int uwsgi_add_expires(struct wsgi_request *wsgi_req, char *filename, int filename_len, struct stat *st) {
|
||||
|
||||
struct uwsgi_dyn_dict *udd = uwsgi.static_expires;
|
||||
time_t now = wsgi_req->start_of_request / 1000000;
|
||||
// 30+1
|
||||
char expires[31];
|
||||
|
||||
while (udd) {
|
||||
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, filename, filename_len) >= 0) {
|
||||
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
||||
int size = set_http_date(now + delta, expires);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
udd = uwsgi.static_expires_mtime;
|
||||
while (udd) {
|
||||
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, filename, filename_len) >= 0) {
|
||||
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
||||
int size = set_http_date(st->st_mtime + delta, expires);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_add_expires_path_info(struct wsgi_request *wsgi_req, struct stat *st) {
|
||||
|
||||
struct uwsgi_dyn_dict *udd = uwsgi.static_expires_path_info;
|
||||
time_t now = wsgi_req->start_of_request / 1000000;
|
||||
// 30+1
|
||||
char expires[31];
|
||||
|
||||
while (udd) {
|
||||
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->path_info, wsgi_req->path_info_len) >= 0) {
|
||||
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
||||
int size = set_http_date(now + delta, expires);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
udd = uwsgi.static_expires_path_info_mtime;
|
||||
while (udd) {
|
||||
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->path_info, wsgi_req->path_info_len) >= 0) {
|
||||
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
||||
int size = set_http_date(st->st_mtime + delta, expires);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_add_expires_uri(struct wsgi_request *wsgi_req, struct stat *st) {
|
||||
|
||||
struct uwsgi_dyn_dict *udd = uwsgi.static_expires_uri;
|
||||
time_t now = wsgi_req->start_of_request / 1000000;
|
||||
// 30+1
|
||||
char expires[31];
|
||||
|
||||
while (udd) {
|
||||
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->uri, wsgi_req->uri_len) >= 0) {
|
||||
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
||||
int size = set_http_date(now + delta, expires);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
udd = uwsgi.static_expires_uri_mtime;
|
||||
while (udd) {
|
||||
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->uri, wsgi_req->uri_len) >= 0) {
|
||||
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
||||
int size = set_http_date(st->st_mtime + delta, expires);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
char *uwsgi_get_mime_type(char *name, int namelen, int *size) {
|
||||
|
||||
int i;
|
||||
int count = 0;
|
||||
char *ext = NULL;
|
||||
for (i = namelen - 1; i >= 0; i--) {
|
||||
if (!isalnum((int) name[i])) {
|
||||
if (name[i] == '.') {
|
||||
ext = name + (namelen - count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!ext)
|
||||
return NULL;
|
||||
|
||||
struct uwsgi_dyn_dict *udd = uwsgi.mimetypes;
|
||||
while (udd) {
|
||||
if (!uwsgi_strncmp(ext, count, udd->key, udd->keylen)) {
|
||||
udd->hits++;
|
||||
// auto optimization
|
||||
if (udd->prev) {
|
||||
if (udd->hits > udd->prev->hits) {
|
||||
struct uwsgi_dyn_dict *udd_parent = udd->prev->prev, *udd_prev = udd->prev;
|
||||
if (udd_parent) {
|
||||
udd_parent->next = udd;
|
||||
}
|
||||
|
||||
if (udd->next) {
|
||||
udd->next->prev = udd_prev;
|
||||
}
|
||||
|
||||
udd_prev->prev = udd;
|
||||
udd_prev->next = udd->next;
|
||||
|
||||
udd->prev = udd_parent;
|
||||
udd->next = udd_prev;
|
||||
|
||||
if (udd->prev == NULL) {
|
||||
uwsgi.mimetypes = udd;
|
||||
}
|
||||
}
|
||||
}
|
||||
*size = udd->vallen;
|
||||
return udd->value;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssize_t uwsgi_append_static_path(char *dir, size_t dir_len, char *file, size_t file_len) {
|
||||
|
||||
|
||||
size_t len = dir_len;
|
||||
|
||||
if (len + 1 + file_len > PATH_MAX) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dir[len - 1] == '/') {
|
||||
memcpy(dir + len, file, file_len);
|
||||
dir[len + file_len] = 0;
|
||||
len += file_len;
|
||||
}
|
||||
else {
|
||||
dir[len] = '/';
|
||||
memcpy(dir + len + 1, file, file_len);
|
||||
dir[len + 1 + file_len] = 0;
|
||||
len += 1 + file_len;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int uwsgi_static_stat(char *filename, size_t *filename_len, struct stat *st) {
|
||||
|
||||
int ret = stat(filename, st);
|
||||
// if non-existant return -1
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
if (S_ISREG(st->st_mode))
|
||||
return 0;
|
||||
|
||||
// check for index
|
||||
if (S_ISDIR(st->st_mode)) {
|
||||
struct uwsgi_string_list *usl = uwsgi.static_index;
|
||||
while (usl) {
|
||||
ssize_t new_len = uwsgi_append_static_path(filename, *filename_len, usl->value, usl->len);
|
||||
if (new_len >= 0) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("checking for %s\n", filename);
|
||||
#endif
|
||||
if (!uwsgi_static_stat(filename, filename_len, st)) {
|
||||
*filename_len = new_len;
|
||||
return 0;
|
||||
}
|
||||
// reset to original name
|
||||
filename[*filename_len] = 0;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, size_t real_filename_len, struct stat *st) {
|
||||
|
||||
int mime_type_size = 0;
|
||||
char http_last_modified[49];
|
||||
|
||||
if (uwsgi.threads > 1)
|
||||
pthread_mutex_lock(&uwsgi.lock_static);
|
||||
|
||||
char *mime_type = uwsgi_get_mime_type(real_filename, real_filename_len, &mime_type_size);
|
||||
|
||||
if (uwsgi.threads > 1)
|
||||
pthread_mutex_unlock(&uwsgi.lock_static);
|
||||
|
||||
if (wsgi_req->if_modified_since_len) {
|
||||
time_t ims = parse_http_date(wsgi_req->if_modified_since, wsgi_req->if_modified_since_len);
|
||||
if (st->st_mtime <= ims) {
|
||||
uwsgi_response_prepare_headers(wsgi_req, "304 Not Modified", 16);
|
||||
return uwsgi_response_write_headers_do(wsgi_req);
|
||||
}
|
||||
}
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("[uwsgi-fileserve] file %s found\n", real_filename);
|
||||
#endif
|
||||
|
||||
// HTTP status
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1;
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
uwsgi_add_expires(wsgi_req, real_filename, real_filename_len, st);
|
||||
uwsgi_add_expires_path_info(wsgi_req, st);
|
||||
uwsgi_add_expires_uri(wsgi_req, st);
|
||||
#endif
|
||||
|
||||
// Content-Type (if available)
|
||||
if (mime_type_size > 0 && mime_type) {
|
||||
if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_size)) return -1;
|
||||
// check for content-type related headers
|
||||
uwsgi_add_expires_type(wsgi_req, mime_type, mime_type_size, st);
|
||||
}
|
||||
|
||||
// increase static requests counter
|
||||
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].static_requests++;
|
||||
|
||||
// nginx
|
||||
if (uwsgi.file_serve_mode == 1) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "X-Accel-Redirect", 16, real_filename, real_filename_len)) return -1;
|
||||
// this is the final header (\r\n added)
|
||||
int size = set_http_date(st->st_mtime, http_last_modified);
|
||||
if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
|
||||
}
|
||||
// apache
|
||||
else if (uwsgi.file_serve_mode == 2) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "X-Sendfile", 10, real_filename, real_filename_len)) return -1;
|
||||
// this is the final header (\r\n added)
|
||||
int size = set_http_date(st->st_mtime, http_last_modified);
|
||||
if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
|
||||
}
|
||||
// raw
|
||||
else {
|
||||
// here we need to choose if we want the gzip variant;
|
||||
if (uwsgi_static_want_gzip(wsgi_req, real_filename, real_filename_len, st)) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "gzip", 4)) return -1;
|
||||
}
|
||||
// set Content-Length
|
||||
if (uwsgi_response_add_content_length(wsgi_req, st->st_size)) return -1;
|
||||
int size = set_http_date(st->st_mtime, http_last_modified);
|
||||
if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
|
||||
|
||||
// if it is a HEAD request just skip transfer
|
||||
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) {
|
||||
wsgi_req->status = 200;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Ok, the file must be transferred from uWSGI
|
||||
// offloading will be automatically managed
|
||||
int fd = open(real_filename, O_RDONLY);
|
||||
if (fd < 0) return -1;
|
||||
// fd will be closed in the following function
|
||||
uwsgi_response_sendfile_do(wsgi_req, fd, 0, st->st_size);
|
||||
}
|
||||
|
||||
wsgi_req->status = 200;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_t document_root_len, char *path_info, uint16_t path_info_len, int is_a_file) {
|
||||
|
||||
struct stat st;
|
||||
char real_filename[PATH_MAX + 1];
|
||||
size_t real_filename_len = 0;
|
||||
char *filename = NULL;
|
||||
size_t filename_len = 0;
|
||||
|
||||
|
||||
if (!is_a_file) {
|
||||
filename = uwsgi_concat3n(document_root, document_root_len, "/", 1, path_info, path_info_len);
|
||||
filename_len = document_root_len + 1 + path_info_len;
|
||||
}
|
||||
else {
|
||||
filename = uwsgi_concat2n(document_root, document_root_len, "", 0);
|
||||
filename_len = document_root_len;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("[uwsgi-fileserve] checking for %s\n", filename);
|
||||
#endif
|
||||
|
||||
if (uwsgi.static_cache_paths) {
|
||||
uwsgi_rlock(uwsgi.static_cache_paths->lock);
|
||||
uint64_t item_len;
|
||||
char *item = uwsgi_cache_get2(uwsgi.static_cache_paths, filename, filename_len, &item_len);
|
||||
if (item && item_len > 0 && item_len <= PATH_MAX) {
|
||||
memcpy(real_filename, item, item_len);
|
||||
real_filename_len = item_len;
|
||||
uwsgi_rwunlock(uwsgi.static_cache_paths->lock);
|
||||
goto found;
|
||||
}
|
||||
uwsgi_rwunlock(uwsgi.static_cache_paths->lock);
|
||||
}
|
||||
|
||||
if (!realpath(filename, real_filename)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("[uwsgi-fileserve] unable to get realpath() of the static file\n");
|
||||
#endif
|
||||
free(filename);
|
||||
return -1;
|
||||
}
|
||||
real_filename_len = strlen(real_filename);
|
||||
|
||||
if (uwsgi.static_cache_paths) {
|
||||
uwsgi_wlock(uwsgi.static_cache_paths->lock);
|
||||
uwsgi_cache_set2(uwsgi.static_cache_paths, filename, filename_len, real_filename, real_filename_len, uwsgi.use_static_cache_paths, UWSGI_CACHE_FLAG_UPDATE);
|
||||
uwsgi_rwunlock(uwsgi.static_cache_paths->lock);
|
||||
}
|
||||
|
||||
found:
|
||||
free(filename);
|
||||
|
||||
if (uwsgi_starts_with(real_filename, real_filename_len, document_root, document_root_len)) {
|
||||
struct uwsgi_string_list *safe = uwsgi.static_safe;
|
||||
while(safe) {
|
||||
if (!uwsgi_starts_with(real_filename, real_filename_len, safe->value, safe->len)) {
|
||||
goto safe;
|
||||
}
|
||||
safe = safe->next;
|
||||
}
|
||||
uwsgi_log("[uwsgi-fileserve] security error: %s is not under %.*s or a safe path\n", real_filename, document_root_len, document_root);
|
||||
return -1;
|
||||
}
|
||||
|
||||
safe:
|
||||
|
||||
if (!uwsgi_static_stat(real_filename, &real_filename_len, &st)) {
|
||||
|
||||
// check for skippable ext
|
||||
struct uwsgi_string_list *sse = uwsgi.static_skip_ext;
|
||||
while (sse) {
|
||||
if (real_filename_len >= sse->len) {
|
||||
if (!uwsgi_strncmp(real_filename + (real_filename_len - sse->len), sse->len, sse->value, sse->len)) {
|
||||
#ifdef UWSGI_ROUTING
|
||||
if (uwsgi_apply_routes_fast(wsgi_req, real_filename, real_filename_len) == UWSGI_ROUTE_BREAK)
|
||||
return 0;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
sse = sse->next;
|
||||
}
|
||||
|
||||
return uwsgi_real_file_serve(wsgi_req, real_filename, real_filename_len, &st);
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
+65
-8
@@ -13,6 +13,7 @@ struct uwsgi_stats *uwsgi_stats_new(size_t chunk_size) {
|
||||
us->chunk = chunk_size;
|
||||
us->size = chunk_size;
|
||||
us->tabs = 1;
|
||||
us->dirty = 0;
|
||||
us->minified = uwsgi.stats_minified;
|
||||
if (!us->minified) {
|
||||
us->base[1] = '\n';
|
||||
@@ -373,7 +374,7 @@ struct uwsgi_stats_pusher *uwsgi_stats_pusher_get(char *name) {
|
||||
return usp;
|
||||
}
|
||||
|
||||
void uwsgi_stats_pusher_add(struct uwsgi_stats_pusher *pusher, char *arg) {
|
||||
struct uwsgi_stats_pusher_instance *uwsgi_stats_pusher_add(struct uwsgi_stats_pusher *pusher, char *arg) {
|
||||
struct uwsgi_stats_pusher_instance *old_uspi = NULL, *uspi = uwsgi.stats_pusher_instances;
|
||||
while (uspi) {
|
||||
old_uspi = uspi;
|
||||
@@ -389,6 +390,8 @@ void uwsgi_stats_pusher_add(struct uwsgi_stats_pusher *pusher, char *arg) {
|
||||
else {
|
||||
uwsgi.stats_pusher_instances = uspi;
|
||||
}
|
||||
|
||||
return uspi;
|
||||
}
|
||||
|
||||
void uwsgi_stats_pusher_loop(struct uwsgi_thread *ut) {
|
||||
@@ -413,12 +416,17 @@ void uwsgi_stats_pusher_loop(struct uwsgi_thread *ut) {
|
||||
while (uspi) {
|
||||
int delta = uspi->freq ? uspi->freq : uwsgi.stats_pusher_default_freq;
|
||||
if ((uspi->last_run + delta) <= now) {
|
||||
if (!us) {
|
||||
us = uwsgi_master_generate_stats();
|
||||
if (!us)
|
||||
goto next;
|
||||
if (uspi->raw) {
|
||||
uspi->pusher->func(uspi, now, NULL, 0);
|
||||
}
|
||||
else {
|
||||
if (!us) {
|
||||
us = uwsgi_master_generate_stats();
|
||||
if (!us)
|
||||
goto next;
|
||||
}
|
||||
uspi->pusher->func(uspi, now, us->base, us->pos);
|
||||
}
|
||||
uspi->pusher->func(uspi, us->base, us->pos);
|
||||
uspi->last_run = now;
|
||||
}
|
||||
next:
|
||||
@@ -456,7 +464,7 @@ void uwsgi_stats_pusher_setup() {
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_register_stats_pusher(char *name, void (*func) (struct uwsgi_stats_pusher_instance *, char *, size_t)) {
|
||||
struct uwsgi_stats_pusher *uwsgi_register_stats_pusher(char *name, void (*func) (struct uwsgi_stats_pusher_instance *, time_t, char *, size_t)) {
|
||||
|
||||
struct uwsgi_stats_pusher *pusher = uwsgi.stats_pushers, *old_pusher = NULL;
|
||||
|
||||
@@ -475,6 +483,8 @@ void uwsgi_register_stats_pusher(char *name, void (*func) (struct uwsgi_stats_pu
|
||||
else {
|
||||
uwsgi.stats_pushers = pusher;
|
||||
}
|
||||
|
||||
return pusher;
|
||||
}
|
||||
|
||||
struct uwsgi_stats_pusher_file_conf {
|
||||
@@ -483,7 +493,7 @@ struct uwsgi_stats_pusher_file_conf {
|
||||
char *separator;
|
||||
};
|
||||
|
||||
void uwsgi_stats_pusher_file(struct uwsgi_stats_pusher_instance *uspi, char *json, size_t json_len) {
|
||||
void uwsgi_stats_pusher_file(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) {
|
||||
struct uwsgi_stats_pusher_file_conf *uspic = (struct uwsgi_stats_pusher_file_conf *) uspi->data;
|
||||
if (!uspi->configured) {
|
||||
uspic = uwsgi_calloc(sizeof(struct uwsgi_stats_pusher_file_conf));
|
||||
@@ -520,3 +530,50 @@ void uwsgi_stats_pusher_file(struct uwsgi_stats_pusher_instance *uspi, char *jso
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void stats_dump_var(char *k, uint16_t kl, char *v, uint16_t vl, void *data) {
|
||||
struct uwsgi_stats *us = (struct uwsgi_stats *) data;
|
||||
if (us->dirty) return;
|
||||
uint16_t i;
|
||||
// replace " with '
|
||||
for(i=0;i<kl;i++) {
|
||||
if (k[i] == '"') {
|
||||
k[i] = '\'';
|
||||
}
|
||||
}
|
||||
for(i=0;i<vl;i++) {
|
||||
if (v[i] == '"') {
|
||||
v[i] = '\'';
|
||||
}
|
||||
}
|
||||
char *var = uwsgi_concat3n(k, kl, "=", 1, v,vl);
|
||||
if (uwsgi_stats_str(us, var)) {
|
||||
us->dirty = 1;
|
||||
free(var);
|
||||
return;
|
||||
}
|
||||
free(var);
|
||||
if (uwsgi_stats_comma(us)) {
|
||||
us->dirty = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int uwsgi_stats_dump_vars(struct uwsgi_stats *us, struct uwsgi_core *uc) {
|
||||
if (!uc->in_request) return 0;
|
||||
struct uwsgi_header *uh = (struct uwsgi_header *) uwsgi.workers[0].cores[0].buffer;
|
||||
uint16_t pktsize = uh->pktsize;
|
||||
if (!pktsize) return 0;
|
||||
char *dst = uwsgi.workers[0].cores[0].buffer;
|
||||
memcpy(dst, uc->buffer+4, uwsgi.buffer_size);
|
||||
// ok now check if something changed...
|
||||
if (!uc->in_request) return 0;
|
||||
if (uh->pktsize != pktsize) return 0;
|
||||
if (memcmp(dst, uc->buffer+4, uwsgi.buffer_size)) return 0;
|
||||
// nothing changed let's dump vars
|
||||
int ret = uwsgi_hooked_parse(dst, pktsize, stats_dump_var, us);
|
||||
if (ret) return -1;
|
||||
if (us->dirty) return -1;
|
||||
if (uwsgi_stats_str(us, "")) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#include "../uwsgi.h"
|
||||
|
||||
/*
|
||||
|
||||
Storage subsystem: filesystem-like abstraction
|
||||
|
||||
struct uwsgi_storage_engine {
|
||||
char *name;
|
||||
uint16_t name_len;
|
||||
int64_t (*get)(char *, uint16_t, char *, uint64_t, uint64_t, uint64_t);
|
||||
int64_t (*set)(char *, uint16_t, char *, uint64_t, uint64_t, uint64_t);
|
||||
};
|
||||
|
||||
struct uwsgi_storage {
|
||||
char *name;
|
||||
uint16_t name_len;
|
||||
struct uwsgi_storage_engine *engine;
|
||||
};
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
struct uwsgi_storage* uwsgi_storage_by_name(char *name, uint16_t name_len) {
|
||||
if (!name_len) {
|
||||
name_len = strlen(name);
|
||||
}
|
||||
struct uwsgi_storage *s = uwsgi.virtualdisks;
|
||||
while(s) {
|
||||
if (!uwsgi_strncmp(s->name, s->name_len, name, name_len)) {
|
||||
return s;
|
||||
}
|
||||
s = s->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int64_t uwsgi_storage_get(struct uwsgi_storage *storage, char *key, uint16_t key_len, char *out_buf, uint64_t pos, uint64_t size, uint64_t flags) {
|
||||
if (!storage->get) return -1;
|
||||
return storage->get(key, key_len, out_buf, pos, size, flags);
|
||||
}
|
||||
|
||||
int64_t uwsgi_storage_set(struct uwsgi_storage *storage, char *key, uint16_t key_len, char *in_buf, uint64_t pos, uint64_t size, uint64_t flags) {
|
||||
if (!storage->set) return -1;
|
||||
return storage->set(key, key_len, out_buf, pos, size, flags);
|
||||
}
|
||||
+340
@@ -0,0 +1,340 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
// check if a string_list contains an item
|
||||
struct uwsgi_string_list *uwsgi_string_list_has_item(struct uwsgi_string_list *list, char *key, size_t keylen) {
|
||||
struct uwsgi_string_list *usl = list;
|
||||
while (usl) {
|
||||
if (keylen == usl->len) {
|
||||
if (!memcmp(key, usl->value, keylen)) {
|
||||
return usl;
|
||||
}
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// lower a string
|
||||
char *uwsgi_lower(char *str, size_t size) {
|
||||
size_t i;
|
||||
for (i = 0; i < size; i++) {
|
||||
str[i] = tolower((int) str[i]);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
// check if a string is contained in another one
|
||||
char *uwsgi_str_contains(char *str, int slen, char what) {
|
||||
|
||||
int i;
|
||||
for (i = 0; i < slen; i++) {
|
||||
if (str[i] == what) {
|
||||
return str + i;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int uwsgi_contains_n(char *s1, size_t s1_len, char *s2, size_t s2_len) {
|
||||
size_t i;
|
||||
char *ptr = s2;
|
||||
for (i = 0; i < s1_len; i++) {
|
||||
if (s1[i] == *ptr) {
|
||||
ptr++;
|
||||
if (ptr == s2 + s2_len) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ptr = s2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// fast compare 2 sized strings
|
||||
int uwsgi_strncmp(char *src, int slen, char *dst, int dlen) {
|
||||
|
||||
if (slen != dlen)
|
||||
return 1;
|
||||
|
||||
return memcmp(src, dst, dlen);
|
||||
|
||||
}
|
||||
|
||||
// fast compare 2 sized strings (case insensitive)
|
||||
int uwsgi_strnicmp(char *src, int slen, char *dst, int dlen) {
|
||||
|
||||
if (slen != dlen)
|
||||
return 1;
|
||||
|
||||
return strncasecmp(src, dst, dlen);
|
||||
|
||||
}
|
||||
|
||||
// fast sized check of initial part of a string
|
||||
int uwsgi_starts_with(char *src, int slen, char *dst, int dlen) {
|
||||
|
||||
if (slen < dlen)
|
||||
return -1;
|
||||
|
||||
return memcmp(src, dst, dlen);
|
||||
}
|
||||
|
||||
|
||||
// unsized check
|
||||
int uwsgi_startswith(char *src, char *what, int wlen) {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < wlen; i++) {
|
||||
if (src[i] != what[i])
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// concatenate strings
|
||||
char *uwsgi_concatn(int c, ...) {
|
||||
|
||||
va_list s;
|
||||
char *item;
|
||||
int j = c;
|
||||
char *buf;
|
||||
size_t len = 1;
|
||||
size_t tlen = 1;
|
||||
|
||||
va_start(s, c);
|
||||
while (j > 0) {
|
||||
item = va_arg(s, char *);
|
||||
if (item == NULL) {
|
||||
break;
|
||||
}
|
||||
len += va_arg(s, int);
|
||||
j--;
|
||||
}
|
||||
va_end(s);
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
memset(buf, 0, len);
|
||||
|
||||
j = c;
|
||||
|
||||
len = 0;
|
||||
|
||||
va_start(s, c);
|
||||
while (j > 0) {
|
||||
item = va_arg(s, char *);
|
||||
if (item == NULL) {
|
||||
break;
|
||||
}
|
||||
tlen = va_arg(s, int);
|
||||
memcpy(buf + len, item, tlen);
|
||||
len += tlen;
|
||||
j--;
|
||||
}
|
||||
va_end(s);
|
||||
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_concat2(char *one, char *two) {
|
||||
|
||||
char *buf;
|
||||
size_t len = strlen(one) + strlen(two) + 1;
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
buf[len - 1] = 0;
|
||||
|
||||
memcpy(buf, one, strlen(one));
|
||||
memcpy(buf + strlen(one), two, strlen(two));
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_concat4(char *one, char *two, char *three, char *four) {
|
||||
|
||||
char *buf;
|
||||
size_t len = strlen(one) + strlen(two) + strlen(three) + strlen(four) + 1;
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
buf[len - 1] = 0;
|
||||
|
||||
memcpy(buf, one, strlen(one));
|
||||
memcpy(buf + strlen(one), two, strlen(two));
|
||||
memcpy(buf + strlen(one) + strlen(two), three, strlen(three));
|
||||
memcpy(buf + strlen(one) + strlen(two) + strlen(three), four, strlen(four));
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_concat3(char *one, char *two, char *three) {
|
||||
|
||||
char *buf;
|
||||
size_t len = strlen(one) + strlen(two) + strlen(three) + 1;
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
buf[len - 1] = 0;
|
||||
|
||||
memcpy(buf, one, strlen(one));
|
||||
memcpy(buf + strlen(one), two, strlen(two));
|
||||
memcpy(buf + strlen(one) + strlen(two), three, strlen(three));
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_concat2n(char *one, int s1, char *two, int s2) {
|
||||
|
||||
char *buf;
|
||||
size_t len = s1 + s2 + 1;
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
buf[len - 1] = 0;
|
||||
|
||||
memcpy(buf, one, s1);
|
||||
memcpy(buf + s1, two, s2);
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_concat2nn(char *one, int s1, char *two, int s2, int *len) {
|
||||
|
||||
char *buf;
|
||||
*len = s1 + s2 + 1;
|
||||
|
||||
|
||||
buf = uwsgi_malloc(*len);
|
||||
buf[*len - 1] = 0;
|
||||
|
||||
memcpy(buf, one, s1);
|
||||
memcpy(buf + s1, two, s2);
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_concat3n(char *one, int s1, char *two, int s2, char *three, int s3) {
|
||||
|
||||
char *buf;
|
||||
size_t len = s1 + s2 + s3 + 1;
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
buf[len - 1] = 0;
|
||||
|
||||
memcpy(buf, one, s1);
|
||||
memcpy(buf + s1, two, s2);
|
||||
memcpy(buf + s1 + s2, three, s3);
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_concat4n(char *one, int s1, char *two, int s2, char *three, int s3, char *four, int s4) {
|
||||
|
||||
char *buf;
|
||||
size_t len = s1 + s2 + s3 + s4 + 1;
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
buf[len - 1] = 0;
|
||||
|
||||
memcpy(buf, one, s1);
|
||||
memcpy(buf + s1, two, s2);
|
||||
memcpy(buf + s1 + s2, three, s3);
|
||||
memcpy(buf + s1 + s2 + s3, four, s4);
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
// concat unsized strings
|
||||
char *uwsgi_concat(int c, ...) {
|
||||
|
||||
va_list s;
|
||||
char *item;
|
||||
size_t len = 1;
|
||||
int j = c;
|
||||
char *buf;
|
||||
|
||||
va_start(s, c);
|
||||
while (j > 0) {
|
||||
item = va_arg(s, char *);
|
||||
if (item == NULL) {
|
||||
break;
|
||||
}
|
||||
len += (int) strlen(item);
|
||||
j--;
|
||||
}
|
||||
va_end(s);
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
memset(buf, 0, len);
|
||||
|
||||
j = c;
|
||||
|
||||
len = 0;
|
||||
|
||||
va_start(s, c);
|
||||
while (j > 0) {
|
||||
item = va_arg(s, char *);
|
||||
if (item == NULL) {
|
||||
break;
|
||||
}
|
||||
memcpy(buf + len, item, strlen(item));
|
||||
len += strlen(item);
|
||||
j--;
|
||||
}
|
||||
va_end(s);
|
||||
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_strncopy(char *s, int len) {
|
||||
|
||||
char *buf;
|
||||
|
||||
buf = uwsgi_malloc(len + 1);
|
||||
buf[len] = 0;
|
||||
|
||||
memcpy(buf, s, len);
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
// this move a string back of one char and put a 0 at the end (used in uwsgi parsers for buffer reusing)
|
||||
char *uwsgi_cheap_string(char *buf, int len) {
|
||||
|
||||
int i;
|
||||
char *cheap_buf = buf - 1;
|
||||
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
*cheap_buf++ = buf[i];
|
||||
}
|
||||
|
||||
|
||||
buf[len - 1] = 0;
|
||||
|
||||
return buf - 1;
|
||||
}
|
||||
|
||||
+254
-176
@@ -91,7 +91,7 @@ static struct uwsgi_subscribe_node *uwsgi_subscription_algo_lrc(struct uwsgi_sub
|
||||
if (min_rc == 0 || node->reference < min_rc) {
|
||||
min_rc = node->reference;
|
||||
choosen_node = node;
|
||||
if (min_rc == 0 && !(node->next && node->next->reference <= node->reference && node->next->requests <= node->requests))
|
||||
if (min_rc == 0 && !(node->next && node->next->reference <= node->reference && node->next->last_requests <= node->last_requests))
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -125,7 +125,7 @@ static struct uwsgi_subscribe_node *uwsgi_subscription_algo_wlrc(struct uwsgi_su
|
||||
if (min_rc == 0 || ref < min_rc) {
|
||||
min_rc = ref;
|
||||
choosen_node = node;
|
||||
if (min_rc == 0 && !(node->next && next_node_ref <= ref && node->next->requests <= node->requests))
|
||||
if (min_rc == 0 && !(node->next && next_node_ref <= ref && node->next->last_requests <= node->last_requests))
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -376,6 +376,7 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
|
||||
node->weight = usr->weight;
|
||||
if (!node->weight)
|
||||
node->weight = 1;
|
||||
node->last_requests = 0;
|
||||
return node;
|
||||
}
|
||||
old_node = node;
|
||||
@@ -394,6 +395,7 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
|
||||
node->modifier1 = usr->modifier1;
|
||||
node->modifier2 = usr->modifier2;
|
||||
node->requests = 0;
|
||||
node->last_requests = 0;
|
||||
node->transferred = 0;
|
||||
node->reference = 0;
|
||||
node->death_mark = 0;
|
||||
@@ -470,6 +472,7 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
|
||||
current_slot->nodes->len = usr->address_len;
|
||||
current_slot->nodes->reference = 0;
|
||||
current_slot->nodes->requests = 0;
|
||||
current_slot->nodes->last_requests = 0;
|
||||
current_slot->nodes->transferred = 0;
|
||||
current_slot->nodes->death_mark = 0;
|
||||
current_slot->nodes->failcnt = 0;
|
||||
@@ -514,31 +517,8 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
|
||||
}
|
||||
|
||||
|
||||
// TODO rewrite it using uwsgi buffers
|
||||
void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8_t modifier1, uint8_t modifier2, uint8_t cmd, char *socket_name, char *sign) {
|
||||
|
||||
char value_cores[sizeof(UMAX64_STR) + 1];
|
||||
char value_load[sizeof(UMAX64_STR) + 1];
|
||||
char value_weight[sizeof(UMAX64_STR) + 1];
|
||||
|
||||
|
||||
int value_cores_size = uwsgi_long2str2n(uwsgi.numproc * uwsgi.cores, value_cores, sizeof(UMAX64_STR));
|
||||
int value_load_size = uwsgi_long2str2n(uwsgi.shared->load, value_load, sizeof(UMAX64_STR));
|
||||
|
||||
int value_weight_size = 0;
|
||||
|
||||
if (uwsgi.auto_weight) {
|
||||
value_weight_size = uwsgi_long2str2n(uwsgi.numproc * uwsgi.cores, value_weight, sizeof(UMAX64_STR));
|
||||
}
|
||||
else {
|
||||
value_weight_size = uwsgi_long2str2n(uwsgi.weight, value_weight, sizeof(UMAX64_STR));
|
||||
}
|
||||
|
||||
char value_modifier1[4];
|
||||
char value_modifier2[4];
|
||||
int value_modifier1_size = uwsgi_long2str2n(modifier1, value_modifier1, 3);
|
||||
int value_modifier2_size = uwsgi_long2str2n(modifier2, value_modifier2, 3);
|
||||
|
||||
if (socket_name == NULL && !uwsgi.sockets)
|
||||
return;
|
||||
|
||||
@@ -546,173 +526,44 @@ void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8
|
||||
socket_name = uwsgi.sockets->name;
|
||||
}
|
||||
|
||||
size_t ssb_size = 4 + (2 + 3) + (2 + keysize) + (2 + 7) + (2 + strlen(socket_name)) + (2 + 9 + 2 + value_modifier1_size) + (2 + 9 + 2 + value_modifier2_size) + (2 + 5 + 2 + value_cores_size) + (2 + 4 + 2 + value_load_size) + (2 + 6 + 2 + value_weight_size);
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(4096);
|
||||
|
||||
char *subscrbuf = uwsgi_malloc(ssb_size);
|
||||
// leave space for uwsgi header
|
||||
char *ssb = subscrbuf + 4;
|
||||
// make space for uwsgi header
|
||||
ub->pos = 4;
|
||||
|
||||
// key = "domain"
|
||||
uint16_t ustrlen = 3;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, "key", ustrlen);
|
||||
ssb += ustrlen;
|
||||
|
||||
ustrlen = keysize;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, key, ustrlen);
|
||||
ssb += ustrlen;
|
||||
|
||||
// address = "first uwsgi socket"
|
||||
ustrlen = 7;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, "address", ustrlen);
|
||||
ssb += ustrlen;
|
||||
|
||||
ustrlen = strlen(socket_name);
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, socket_name, ustrlen);
|
||||
ssb += ustrlen;
|
||||
|
||||
// modifier1 = "modifier1"
|
||||
ustrlen = 9;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, "modifier1", ustrlen);
|
||||
ssb += ustrlen;
|
||||
|
||||
ustrlen = value_modifier1_size;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, value_modifier1, value_modifier1_size);
|
||||
ssb += ustrlen;
|
||||
|
||||
// modifier2 = "modifier2"
|
||||
ustrlen = 9;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, "modifier2", ustrlen);
|
||||
ssb += ustrlen;
|
||||
|
||||
ustrlen = value_modifier2_size;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, value_modifier2, value_modifier2_size);
|
||||
ssb += ustrlen;
|
||||
|
||||
// cores = uwsgi.numproc * uwsgi.cores
|
||||
ustrlen = 5;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, "cores", ustrlen);
|
||||
ssb += ustrlen;
|
||||
|
||||
ustrlen = value_cores_size;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, value_cores, value_cores_size);
|
||||
ssb += ustrlen;
|
||||
|
||||
// load
|
||||
ustrlen = 4;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, "load", ustrlen);
|
||||
ssb += ustrlen;
|
||||
|
||||
ustrlen = value_load_size;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, value_load, value_load_size);
|
||||
ssb += ustrlen;
|
||||
|
||||
// weight
|
||||
ustrlen = 6;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, "weight", ustrlen);
|
||||
ssb += ustrlen;
|
||||
|
||||
ustrlen = value_weight_size;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, value_weight, value_weight_size);
|
||||
ssb += ustrlen;
|
||||
if (uwsgi_buffer_append_keyval(ub, "key", 3, key, keysize)) goto end;
|
||||
if (uwsgi_buffer_append_keyval(ub, "address", 7, socket_name, strlen(socket_name))) goto end;
|
||||
if (uwsgi_buffer_append_keynum(ub, "modifier1", 9, modifier1)) goto end;
|
||||
if (uwsgi_buffer_append_keynum(ub, "modifier2", 9, modifier2)) goto end;
|
||||
if (uwsgi_buffer_append_keynum(ub, "cores", 5, uwsgi.numproc * uwsgi.cores)) goto end;
|
||||
if (uwsgi_buffer_append_keynum(ub, "load", 4, uwsgi.shared->load)) goto end;
|
||||
if (uwsgi.auto_weight) {
|
||||
if (uwsgi_buffer_append_keynum(ub, "weight", 6, uwsgi.numproc * uwsgi.cores )) goto end;
|
||||
}
|
||||
else {
|
||||
if (uwsgi_buffer_append_keynum(ub, "weight", 6, uwsgi.weight )) goto end;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
if (sign) {
|
||||
// add space for "unix" item
|
||||
char unix_dst[sizeof(UMAX64_STR) + 1];
|
||||
if (snprintf(unix_dst, sizeof(UMAX64_STR) + 1, "%lu", (unsigned long) (uwsgi_now() + (time_t) cmd)) < 1) {
|
||||
uwsgi_error("unable to generate unix time for subscription !!!\n");
|
||||
free(subscrbuf);
|
||||
return;
|
||||
}
|
||||
ssb_size += 2 + 4 + 2 + strlen(unix_dst);
|
||||
char *new_buf = realloc(subscrbuf, ssb_size);
|
||||
if (!new_buf) {
|
||||
uwsgi_error("realloc()");
|
||||
free(subscrbuf);
|
||||
return;
|
||||
}
|
||||
|
||||
// fix ssb (new_buf base could be changed)
|
||||
ssb = (new_buf + (ssb - subscrbuf));
|
||||
subscrbuf = new_buf;
|
||||
|
||||
ustrlen = 4;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, "unix", ustrlen);
|
||||
ssb += ustrlen;
|
||||
|
||||
ustrlen = strlen(unix_dst);
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, unix_dst, strlen(unix_dst));
|
||||
ssb += ustrlen;
|
||||
if (uwsgi_buffer_append_keynum(ub, "unix", 4, (uwsgi_now() + (time_t) cmd) )) goto end;
|
||||
|
||||
unsigned int signature_len = 0;
|
||||
char *signature = uwsgi_rsa_sign(sign, subscrbuf + 4, ssb_size - 4, &signature_len);
|
||||
char *signature = uwsgi_rsa_sign(sign, ub->buf + 4, ub->pos - 4, &signature_len);
|
||||
if (signature && signature_len > 0) {
|
||||
// add space for "sign" item
|
||||
ssb_size += 2 + 4 + 2 + signature_len;
|
||||
char *new_buf = realloc(subscrbuf, ssb_size);
|
||||
if (!new_buf) {
|
||||
uwsgi_error("realloc()");
|
||||
if (uwsgi_buffer_append_keyval(ub, "sign", 4, signature, signature_len)) {
|
||||
free(signature);
|
||||
free(subscrbuf);
|
||||
return;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// fix ssb (new_buf base could be changed)
|
||||
ssb = (new_buf + (ssb - subscrbuf));
|
||||
subscrbuf = new_buf;
|
||||
|
||||
ustrlen = 4;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, "sign", ustrlen);
|
||||
ssb += ustrlen;
|
||||
|
||||
ustrlen = signature_len;
|
||||
*ssb++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ssb++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ssb, signature, signature_len);
|
||||
ssb += ustrlen;
|
||||
|
||||
free(signature);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
send_udp_message(224, cmd, udp_address, subscrbuf, ssb_size - 4);
|
||||
free(subscrbuf);
|
||||
send_udp_message(224, cmd, udp_address, ub->buf, ub->pos - 4);
|
||||
end:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
}
|
||||
|
||||
|
||||
@@ -756,3 +607,230 @@ struct uwsgi_subscribe_slot **uwsgi_subscription_init_ht() {
|
||||
}
|
||||
return uwsgi_calloc(sizeof(struct uwsgi_subscription_slot *) * UMAX16);
|
||||
}
|
||||
|
||||
void uwsgi_subscribe(char *subscription, uint8_t cmd) {
|
||||
|
||||
size_t subfile_size;
|
||||
size_t i;
|
||||
char *key = NULL;
|
||||
int keysize = 0;
|
||||
char *modifier1 = NULL;
|
||||
int modifier1_len = 0;
|
||||
char *socket_name = NULL;
|
||||
char *udp_address = subscription;
|
||||
char *udp_port = NULL;
|
||||
char *subscription_key = NULL;
|
||||
char *sign = NULL;
|
||||
|
||||
// check for explicit socket_name
|
||||
char *equal = strchr(subscription, '=');
|
||||
if (equal) {
|
||||
socket_name = subscription;
|
||||
if (socket_name[0] == '=') {
|
||||
equal = strchr(socket_name + 1, '=');
|
||||
if (!equal)
|
||||
return;
|
||||
*equal = '\0';
|
||||
struct uwsgi_socket *us = uwsgi_get_shared_socket_by_num(atoi(socket_name + 1));
|
||||
if (!us)
|
||||
return;
|
||||
socket_name = us->name;
|
||||
}
|
||||
*equal = '\0';
|
||||
udp_address = equal + 1;
|
||||
}
|
||||
|
||||
// check for unix socket
|
||||
if (udp_address[0] != '/') {
|
||||
udp_port = strchr(udp_address, ':');
|
||||
if (!udp_port) {
|
||||
if (equal)
|
||||
*equal = '=';
|
||||
return;
|
||||
}
|
||||
subscription_key = strchr(udp_port + 1, ':');
|
||||
}
|
||||
else {
|
||||
subscription_key = strchr(udp_address + 1, ':');
|
||||
}
|
||||
|
||||
if (!subscription_key) {
|
||||
if (equal)
|
||||
*equal = '=';
|
||||
return;
|
||||
}
|
||||
|
||||
udp_address = uwsgi_concat2n(udp_address, subscription_key - udp_address, "", 0);
|
||||
|
||||
if (subscription_key[1] == '@') {
|
||||
if (!uwsgi_file_exists(subscription_key + 2))
|
||||
goto clear;
|
||||
char *lines = uwsgi_open_and_read(subscription_key + 2, &subfile_size, 1, NULL);
|
||||
if (subfile_size > 0) {
|
||||
key = lines;
|
||||
for (i = 0; i < subfile_size; i++) {
|
||||
if (lines[i] == 0) {
|
||||
if (keysize > 0) {
|
||||
if (key[0] != '#' && key[0] != '\n') {
|
||||
modifier1 = strchr(key, ',');
|
||||
if (modifier1) {
|
||||
modifier1[0] = 0;
|
||||
modifier1++;
|
||||
modifier1_len = strlen(modifier1);
|
||||
keysize = strlen(key);
|
||||
}
|
||||
uwsgi_send_subscription(udp_address, key, keysize, uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign);
|
||||
modifier1 = NULL;
|
||||
modifier1_len = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (lines[i] == '\n') {
|
||||
if (keysize > 0) {
|
||||
if (key[0] != '#' && key[0] != '\n') {
|
||||
lines[i] = 0;
|
||||
modifier1 = strchr(key, ',');
|
||||
if (modifier1) {
|
||||
modifier1[0] = 0;
|
||||
modifier1++;
|
||||
modifier1_len = strlen(modifier1);
|
||||
keysize = strlen(key);
|
||||
}
|
||||
uwsgi_send_subscription(udp_address, key, keysize, uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign);
|
||||
modifier1 = NULL;
|
||||
modifier1_len = 0;
|
||||
lines[i] = '\n';
|
||||
}
|
||||
}
|
||||
key = lines + i + 1;
|
||||
keysize = 0;
|
||||
continue;
|
||||
}
|
||||
keysize++;
|
||||
}
|
||||
|
||||
free(lines);
|
||||
}
|
||||
}
|
||||
else {
|
||||
modifier1 = strchr(subscription_key + 1, ',');
|
||||
if (modifier1) {
|
||||
modifier1[0] = 0;
|
||||
modifier1++;
|
||||
|
||||
sign = strchr(modifier1 + 1, ',');
|
||||
if (sign) {
|
||||
*sign = 0;
|
||||
sign++;
|
||||
}
|
||||
modifier1_len = strlen(modifier1);
|
||||
}
|
||||
|
||||
uwsgi_send_subscription(udp_address, subscription_key + 1, strlen(subscription_key + 1), uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign);
|
||||
if (modifier1)
|
||||
modifier1[-1] = ',';
|
||||
if (sign)
|
||||
sign[-1] = ',';
|
||||
}
|
||||
|
||||
clear:
|
||||
if (equal)
|
||||
*equal = '=';
|
||||
free(udp_address);
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_subscribe2(char *arg, uint8_t cmd) {
|
||||
|
||||
char *s2_server = NULL;
|
||||
char *s2_key = NULL;
|
||||
char *s2_socket = NULL;
|
||||
char *s2_addr = NULL;
|
||||
char *s2_weight = NULL;
|
||||
char *s2_sign = NULL;
|
||||
char *s2_modifier1 = NULL;
|
||||
char *s2_modifier2 = NULL;
|
||||
char *s2_check = NULL;
|
||||
|
||||
if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=',
|
||||
"server", &s2_server,
|
||||
"key", &s2_key,
|
||||
"socket", &s2_socket,
|
||||
"addr", &s2_addr,
|
||||
"weight", &s2_weight,
|
||||
"modifier1", &s2_modifier1,
|
||||
"modifier2", &s2_modifier2,
|
||||
"sign", &s2_sign,
|
||||
"check", &s2_check,
|
||||
NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s2_server || !s2_key) goto end;
|
||||
|
||||
if (s2_check) {
|
||||
if (uwsgi_file_exists(s2_check)) goto end;
|
||||
}
|
||||
|
||||
if (s2_weight) {
|
||||
uwsgi.weight = atoi(s2_weight);
|
||||
}
|
||||
|
||||
if (s2_socket) {
|
||||
struct uwsgi_socket *us = uwsgi_get_socket_by_num(atoi(s2_socket));
|
||||
if (us) {
|
||||
if (s2_addr) {
|
||||
free(s2_addr);
|
||||
}
|
||||
s2_addr = uwsgi_str(us->name);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t modifier1 = 0;
|
||||
uint8_t modifier2 = 0;
|
||||
|
||||
if (s2_modifier1) {
|
||||
modifier1 = atoi(s2_modifier1);
|
||||
}
|
||||
|
||||
if (s2_modifier2) {
|
||||
modifier2 = atoi(s2_modifier2);
|
||||
}
|
||||
|
||||
uwsgi_send_subscription(s2_server, s2_key, strlen(s2_key), modifier1, modifier2, cmd, s2_addr, s2_sign);
|
||||
end:
|
||||
if (s2_server) free(s2_server);
|
||||
if (s2_key) free(s2_key);
|
||||
if (s2_socket) free(s2_socket);
|
||||
if (s2_addr) free(s2_addr);
|
||||
if (s2_weight) free(s2_weight);
|
||||
if (s2_modifier1) free(s2_modifier1);
|
||||
if (s2_modifier2) free(s2_modifier2);
|
||||
if (s2_sign) free(s2_sign);
|
||||
if (s2_check) free(s2_check);
|
||||
}
|
||||
|
||||
void uwsgi_subscribe_all(uint8_t cmd, int verbose) {
|
||||
// -- subscribe
|
||||
struct uwsgi_string_list *subscriptions = uwsgi.subscriptions;
|
||||
while (subscriptions) {
|
||||
if (verbose) {
|
||||
uwsgi_log("%s %s\n", cmd ? "unsubscribing from" : "subscribing to", subscriptions->value);
|
||||
}
|
||||
uwsgi_subscribe(subscriptions->value, cmd);
|
||||
subscriptions = subscriptions->next;
|
||||
}
|
||||
|
||||
// --subscribe2
|
||||
subscriptions = uwsgi.subscriptions2;
|
||||
while (subscriptions) {
|
||||
if (verbose) {
|
||||
uwsgi_log("%s %s\n", cmd ? "unsubscribing from" : "subscribing to", subscriptions->value);
|
||||
}
|
||||
uwsgi_subscribe2(subscriptions->value, cmd);
|
||||
subscriptions = subscriptions->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
|
||||
uWSGI timebomb
|
||||
|
||||
this is a simple thread waiting for a timeout and calling exit
|
||||
with the specified value.
|
||||
|
||||
You can use it as a last resort in async apps that could block
|
||||
normal uWSGI behaviours
|
||||
|
||||
*/
|
||||
|
||||
struct time_bomb {
|
||||
int timeout;
|
||||
int exit_code;
|
||||
};
|
||||
|
||||
static void *time_bomb(void *arg) {
|
||||
|
||||
// block all signals
|
||||
sigset_t smask;
|
||||
sigfillset(&smask);
|
||||
pthread_sigmask(SIG_BLOCK, &smask, NULL);
|
||||
|
||||
struct time_bomb *tb = (struct time_bomb *) arg;
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = tb->timeout;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
uwsgi_log_verbose("*** BOOOOOOM ***\n");
|
||||
exit(tb->exit_code);
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_time_bomb(int timeout, int exit_code) {
|
||||
|
||||
pthread_t time_bomb_thread;
|
||||
|
||||
struct time_bomb *tb = uwsgi_malloc(sizeof(struct time_bomb));
|
||||
tb->timeout = timeout;
|
||||
tb->exit_code = exit_code;
|
||||
|
||||
if (pthread_create(&time_bomb_thread, NULL, time_bomb, (void *) tb)) {
|
||||
uwsgi_error("pthread_create()");
|
||||
uwsgi_log("unable to setup the time bomb, goodbye\n");
|
||||
exit(exit_code);
|
||||
}
|
||||
else {
|
||||
uwsgi_log_verbose("Fire in the hole !!! (%d seconds to detonation)\n", timeout);
|
||||
}
|
||||
|
||||
}
|
||||
+492
-1754
File diff suppressed because it is too large
Load Diff
+332
-318
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,359 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
/*
|
||||
|
||||
uWSGI websockets functions
|
||||
|
||||
sponsored by 20Tab S.r.l. <info@20tab.com>
|
||||
|
||||
*/
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
static struct uwsgi_buffer *uwsgi_websocket_message(char *msg, size_t len) {
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(10 + len);
|
||||
if (uwsgi_buffer_u8(ub, 0x81)) goto error;
|
||||
if (len < 126) {
|
||||
if (uwsgi_buffer_u8(ub, len)) goto error;
|
||||
}
|
||||
else if (len <= (uint16_t) 0xffff) {
|
||||
if (uwsgi_buffer_u8(ub, 126)) goto error;
|
||||
if (uwsgi_buffer_u16be(ub, len)) goto error;
|
||||
}
|
||||
else {
|
||||
if (uwsgi_buffer_u8(ub, 127)) goto error;
|
||||
if (uwsgi_buffer_u64be(ub, len)) goto error;
|
||||
}
|
||||
|
||||
if (uwsgi_buffer_append(ub, msg, len)) goto error;
|
||||
return ub;
|
||||
|
||||
error:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int uwsgi_websockets_ping(struct wsgi_request *wsgi_req) {
|
||||
if (uwsgi_response_write_body_do(wsgi_req, uwsgi.websockets_ping->buf, uwsgi.websockets_ping->pos)) {
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->websocket_last_ping = uwsgi_now();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_websockets_pong(struct wsgi_request *wsgi_req) {
|
||||
return uwsgi_response_write_body_do(wsgi_req, uwsgi.websockets_pong->buf, uwsgi.websockets_pong->pos);
|
||||
}
|
||||
|
||||
static int uwsgi_websockets_check_pingpong(struct wsgi_request *wsgi_req) {
|
||||
time_t now = uwsgi_now();
|
||||
// first round
|
||||
if (wsgi_req->websocket_last_ping == 0) {
|
||||
return uwsgi_websockets_ping(wsgi_req);
|
||||
}
|
||||
// pong not received ?
|
||||
if (wsgi_req->websocket_last_pong < wsgi_req->websocket_last_ping) {
|
||||
if (wsgi_req->websocket_last_ping - wsgi_req->websocket_last_pong > uwsgi.websockets_pong_tolerance) {
|
||||
uwsgi_log("[uwsgi-websocket] no PONG received in %d seconds !!!\n", uwsgi.websockets_pong_tolerance);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// pong received, send anther ping
|
||||
if (now - wsgi_req->websocket_last_ping >= uwsgi.websockets_ping_freq) {
|
||||
return uwsgi_websockets_ping(wsgi_req);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_websocket_send_do(struct wsgi_request *wsgi_req, char *msg, size_t len) {
|
||||
struct uwsgi_buffer *ub = uwsgi_websocket_message(msg, len);
|
||||
if (!ub) return -1;
|
||||
|
||||
ssize_t ret = uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_websocket_send(struct wsgi_request *wsgi_req, char *msg, size_t len) {
|
||||
if (wsgi_req->websocket_closed) {
|
||||
return -1;
|
||||
}
|
||||
ssize_t ret = uwsgi_websocket_send_do(wsgi_req, msg, len);
|
||||
if (ret < 0) {
|
||||
wsgi_req->websocket_closed = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void uwsgi_websocket_parse_header(struct wsgi_request *wsgi_req) {
|
||||
uint8_t byte1 = wsgi_req->websocket_buf->buf[0];
|
||||
uint8_t byte2 = wsgi_req->websocket_buf->buf[1];
|
||||
wsgi_req->websocket_opcode = byte1 & 0xf;
|
||||
wsgi_req->websocket_has_mask = byte2 >> 7;
|
||||
wsgi_req->websocket_size = byte2 & 0x7f;
|
||||
}
|
||||
|
||||
static struct uwsgi_buffer *uwsgi_websockets_parse(struct wsgi_request *wsgi_req) {
|
||||
// de-mask buffer
|
||||
uint8_t *ptr = (uint8_t *) (wsgi_req->websocket_buf->buf + (wsgi_req->websocket_pktsize - wsgi_req->websocket_size));
|
||||
size_t i;
|
||||
|
||||
if (wsgi_req->websocket_has_mask) {
|
||||
uint8_t *mask = ptr-4;
|
||||
for(i=0;i<wsgi_req->websocket_size;i++) {
|
||||
ptr[i] = ptr[i] ^ mask[i%4];
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(wsgi_req->websocket_size);
|
||||
if (uwsgi_buffer_append(ub, (char *) ptr, wsgi_req->websocket_size)) goto error;
|
||||
if (uwsgi_buffer_decapitate(wsgi_req->websocket_buf, wsgi_req->websocket_pktsize)) goto error;
|
||||
wsgi_req->websocket_phase = 0;
|
||||
wsgi_req->websocket_need = 2;
|
||||
return ub;
|
||||
error:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uwsgi_websockets_recv_pkt(struct wsgi_request *wsgi_req, int nb) {
|
||||
|
||||
int ret = -1;
|
||||
|
||||
for(;;) {
|
||||
ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->websocket_buf->buf + wsgi_req->websocket_buf->pos, wsgi_req->websocket_buf->len - wsgi_req->websocket_buf->pos);
|
||||
if (rlen > 0) return rlen;
|
||||
if (rlen == 0) return -1;
|
||||
if (rlen < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
if (nb) {
|
||||
if (uwsgi_websockets_check_pingpong(wsgi_req)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
goto wait;
|
||||
}
|
||||
uwsgi_error("uwsgi_websockets_recv_pkt()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wait:
|
||||
ret = uwsgi.wait_read_hook(wsgi_req->fd, uwsgi.websockets_ping_freq);
|
||||
if (ret > 0) {
|
||||
rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->websocket_buf->buf + wsgi_req->websocket_buf->pos, wsgi_req->websocket_buf->len - wsgi_req->websocket_buf->pos);
|
||||
if (rlen > 0) return rlen;
|
||||
if (rlen <= 0) return -1;
|
||||
}
|
||||
if (ret < 0) {
|
||||
uwsgi_error("uwsgi_websockets_recv_pkt()");
|
||||
return -1;
|
||||
}
|
||||
// send unsolicited pong
|
||||
if (uwsgi_websockets_check_pingpong(wsgi_req)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static struct uwsgi_buffer *uwsgi_websocket_recv_do(struct wsgi_request *wsgi_req, int nb) {
|
||||
if (!wsgi_req->websocket_buf) {
|
||||
// this buffer will be destroyed on connection close
|
||||
wsgi_req->websocket_buf = uwsgi_buffer_new(uwsgi.page_size);
|
||||
// need 2 byte header
|
||||
wsgi_req->websocket_need = 2;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
size_t remains = wsgi_req->websocket_buf->pos;
|
||||
// i have data;
|
||||
if (remains >= wsgi_req->websocket_need) {
|
||||
switch(wsgi_req->websocket_phase) {
|
||||
// header
|
||||
case 0:
|
||||
uwsgi_websocket_parse_header(wsgi_req);
|
||||
wsgi_req->websocket_pktsize = 2 + (wsgi_req->websocket_has_mask*4);
|
||||
if (wsgi_req->websocket_size == 126) {
|
||||
wsgi_req->websocket_need += 2;
|
||||
wsgi_req->websocket_phase = 1;
|
||||
wsgi_req->websocket_pktsize += 2;
|
||||
}
|
||||
else if (wsgi_req->websocket_size == 127) {
|
||||
wsgi_req->websocket_need += 8;
|
||||
wsgi_req->websocket_phase = 1;
|
||||
wsgi_req->websocket_pktsize += 8;
|
||||
}
|
||||
else {
|
||||
wsgi_req->websocket_phase = 2;
|
||||
}
|
||||
break;
|
||||
// size
|
||||
case 1:
|
||||
if (wsgi_req->websocket_size == 126) {
|
||||
wsgi_req->websocket_size = uwsgi_be16(wsgi_req->websocket_buf->buf+2);
|
||||
}
|
||||
else if (wsgi_req->websocket_size == 127) {
|
||||
wsgi_req->websocket_size = uwsgi_be64(wsgi_req->websocket_buf->buf+2);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[uwsgi-websocket] BUG error in websocket parser\n");
|
||||
return NULL;
|
||||
}
|
||||
if (wsgi_req->websocket_size > (uwsgi.websockets_max_size*1024)) {
|
||||
uwsgi_log("[uwsgi-websocket] invalid packet size received: %llu, max allowed: %llu\n", wsgi_req->websocket_size, uwsgi.websockets_max_size * 1024);
|
||||
return NULL;
|
||||
}
|
||||
wsgi_req->websocket_phase = 2;
|
||||
break;
|
||||
// mask check
|
||||
case 2:
|
||||
if (wsgi_req->websocket_has_mask) {
|
||||
wsgi_req->websocket_need += 4;
|
||||
wsgi_req->websocket_phase = 3;
|
||||
}
|
||||
else {
|
||||
wsgi_req->websocket_need += wsgi_req->websocket_size;
|
||||
wsgi_req->websocket_phase = 4;
|
||||
}
|
||||
break;
|
||||
// mask
|
||||
case 3:
|
||||
wsgi_req->websocket_pktsize += wsgi_req->websocket_size;
|
||||
wsgi_req->websocket_need += wsgi_req->websocket_size;
|
||||
wsgi_req->websocket_phase = 4;
|
||||
break;
|
||||
// message
|
||||
case 4:
|
||||
switch (wsgi_req->websocket_opcode) {
|
||||
// message
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
return uwsgi_websockets_parse(wsgi_req);
|
||||
// close
|
||||
case 0x8:
|
||||
return NULL;
|
||||
// ping
|
||||
case 0x9:
|
||||
if (uwsgi_websockets_pong(wsgi_req)) {
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
// pong
|
||||
case 0xA:
|
||||
wsgi_req->websocket_last_pong = uwsgi_now();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// reset the status
|
||||
wsgi_req->websocket_phase = 0;
|
||||
wsgi_req->websocket_need = 2;
|
||||
// decapitate the buffer
|
||||
if (uwsgi_buffer_decapitate(wsgi_req->websocket_buf, wsgi_req->websocket_pktsize)) return NULL;
|
||||
break;
|
||||
// oops
|
||||
default:
|
||||
uwsgi_log("[uwsgi-websocket] BUG error in websocket parser\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
// need more data
|
||||
else {
|
||||
if (uwsgi_buffer_ensure(wsgi_req->websocket_buf, uwsgi.page_size)) return NULL;
|
||||
ssize_t len = uwsgi_websockets_recv_pkt(wsgi_req, nb);
|
||||
if (len <= 0) {
|
||||
if (nb == 1 && len == 0) {
|
||||
// return an empty buffer to signal blocking event
|
||||
return uwsgi_buffer_new(0);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
// update buffer size
|
||||
wsgi_req->websocket_buf->pos+=len;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *uwsgi_websocket_recv(struct wsgi_request *wsgi_req) {
|
||||
if (wsgi_req->websocket_closed) {
|
||||
return NULL;
|
||||
}
|
||||
struct uwsgi_buffer *ub = uwsgi_websocket_recv_do(wsgi_req, 0);
|
||||
if (!ub) {
|
||||
wsgi_req->websocket_closed = 1;
|
||||
}
|
||||
return ub;
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *uwsgi_websocket_recv_nb(struct wsgi_request *wsgi_req) {
|
||||
if (wsgi_req->websocket_closed) {
|
||||
return NULL;
|
||||
}
|
||||
struct uwsgi_buffer *ub = uwsgi_websocket_recv_do(wsgi_req, 1);
|
||||
if (!ub) {
|
||||
wsgi_req->websocket_closed = 1;
|
||||
}
|
||||
return ub;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ssize_t uwsgi_websockets_simple_send(struct wsgi_request *wsgi_req, struct uwsgi_buffer *ub) {
|
||||
ssize_t len = wsgi_req->socket->proto_write(wsgi_req, ub->buf, ub->pos);
|
||||
if (wsgi_req->write_errors > 0) {
|
||||
return -1;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int uwsgi_websocket_handshake(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *origin, uint16_t origin_len) {
|
||||
#ifdef UWSGI_SSL
|
||||
char sha1[20];
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "101 Web Socket Protocol Handshake", 33)) return -1;
|
||||
if (uwsgi_response_add_header(wsgi_req, "Upgrade", 7, "WebSocket", 9)) return -1;
|
||||
if (uwsgi_response_add_header(wsgi_req, "Connection", 10, "Upgrade", 7)) return -1;
|
||||
if (origin_len > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Origin", 20, origin, origin_len)) return -1;
|
||||
}
|
||||
else {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Origin", 20, "*", 1)) return -1;
|
||||
}
|
||||
// generate websockets sha1 and encode it to base64
|
||||
if (!uwsgi_sha1_2n(key, key_len, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", 36, sha1)) return -1;
|
||||
size_t b64_len = 0;
|
||||
char *b64 = uwsgi_base64_encode(sha1, 20, &b64_len);
|
||||
if (!b64) return -1;
|
||||
|
||||
if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Accept", 20, b64, b64_len)) {
|
||||
free(b64);
|
||||
return -1;
|
||||
}
|
||||
free(b64);
|
||||
|
||||
wsgi_req->websocket_last_pong = uwsgi_now();
|
||||
|
||||
return uwsgi_response_write_headers_do(wsgi_req);
|
||||
#else
|
||||
uwsgi_log("you need to build uWSGI with SSL support to use the websocket handshake api function !!!\n");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void uwsgi_websockets_init() {
|
||||
uwsgi.websockets_pong = uwsgi_buffer_new(2);
|
||||
uwsgi_buffer_append(uwsgi.websockets_pong, "\x8A\0", 2);
|
||||
uwsgi.websockets_ping = uwsgi_buffer_new(2);
|
||||
uwsgi_buffer_append(uwsgi.websockets_ping, "\x89\0", 2);
|
||||
uwsgi.websockets_ping_freq = 30;
|
||||
uwsgi.websockets_pong_tolerance = 3;
|
||||
uwsgi.websockets_max_size = 1024;
|
||||
}
|
||||
+299
@@ -0,0 +1,299 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_response_add_content_length(struct wsgi_request *wsgi_req, uint64_t cl) {
|
||||
char buf[sizeof(UMAX64_STR)+1];
|
||||
int ret = snprintf(buf, sizeof(UMAX64_STR)+1, "%llu", (unsigned long long) cl);
|
||||
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
return uwsgi_response_add_header(wsgi_req, "Content-Length", 14, buf, ret);
|
||||
}
|
||||
|
||||
// status could be NNN or NNN message
|
||||
int uwsgi_response_prepare_headers(struct wsgi_request *wsgi_req, char *status, uint16_t status_len) {
|
||||
|
||||
if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || status_len < 3 || wsgi_req->write_errors) return -1;
|
||||
|
||||
if (!wsgi_req->headers) {
|
||||
wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size);
|
||||
wsgi_req->headers->limit = UMAX16;
|
||||
}
|
||||
|
||||
// reset the buffer (could be useful for rollbacks...)
|
||||
wsgi_req->headers->pos = 0;
|
||||
struct uwsgi_buffer *hh = NULL;
|
||||
if (status_len <= 4) {
|
||||
char *new_sc = NULL;
|
||||
size_t new_sc_len = 0;
|
||||
uint16_t sc_len = 0;
|
||||
const char *sc = uwsgi_http_status_msg(status, &sc_len);
|
||||
if (sc) {
|
||||
new_sc = uwsgi_concat3n(status, 3, " ", 1, (char *)sc, sc_len);
|
||||
new_sc_len = 4+sc_len;
|
||||
}
|
||||
else {
|
||||
new_sc = uwsgi_concat2n(status, 3, " Unknown", 8);
|
||||
new_sc_len = 11;
|
||||
}
|
||||
hh = wsgi_req->socket->proto_prepare_headers(wsgi_req, new_sc, new_sc_len);
|
||||
free(new_sc);
|
||||
}
|
||||
else {
|
||||
hh = wsgi_req->socket->proto_prepare_headers(wsgi_req, status, status_len);
|
||||
}
|
||||
if (!hh) {wsgi_req->write_errors++; return -1;}
|
||||
if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error;
|
||||
uwsgi_buffer_destroy(hh);
|
||||
wsgi_req->status = uwsgi_str3_num(status);
|
||||
return 0;
|
||||
error:
|
||||
uwsgi_buffer_destroy(hh);
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
//each protocol has its header generator
|
||||
int uwsgi_response_add_header(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) {
|
||||
|
||||
if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || wsgi_req->write_errors) return -1;
|
||||
|
||||
struct uwsgi_string_list *rh = uwsgi.remove_headers;
|
||||
while(rh) {
|
||||
if (!uwsgi_strnicmp(key, key_len, rh->value, rh->len)) {
|
||||
return 0;
|
||||
}
|
||||
rh = rh->next;
|
||||
}
|
||||
rh = wsgi_req->remove_headers;
|
||||
while(rh) {
|
||||
if (!uwsgi_strnicmp(key, key_len, rh->value, rh->len)) {
|
||||
return 0;
|
||||
}
|
||||
rh = rh->next;
|
||||
}
|
||||
|
||||
if (!wsgi_req->headers) {
|
||||
wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size);
|
||||
wsgi_req->headers->limit = UMAX16;
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *hh = wsgi_req->socket->proto_add_header(wsgi_req, key, key_len, value, value_len);
|
||||
if (!hh) { wsgi_req->write_errors++ ; return -1;}
|
||||
if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error;
|
||||
wsgi_req->header_cnt++;
|
||||
uwsgi_buffer_destroy(hh);
|
||||
return 0;
|
||||
error:
|
||||
uwsgi_buffer_destroy(hh);
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int uwsgi_response_write_headers_do(struct wsgi_request *wsgi_req) {
|
||||
if (wsgi_req->headers_sent || !wsgi_req->headers || wsgi_req->response_size || wsgi_req->write_errors) {
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
struct uwsgi_string_list *ah = uwsgi.additional_headers;
|
||||
while(ah) {
|
||||
if (uwsgi_response_add_header(wsgi_req, NULL, 0, ah->value, ah->len)) return -1;
|
||||
ah = ah->next;
|
||||
}
|
||||
|
||||
ah = wsgi_req->additional_headers;
|
||||
while(ah) {
|
||||
if (uwsgi_response_add_header(wsgi_req, NULL, 0, ah->value, ah->len)) return -1;
|
||||
ah = ah->next;
|
||||
}
|
||||
|
||||
|
||||
if (wsgi_req->socket->proto_fix_headers(wsgi_req)) { wsgi_req->write_errors++ ; return -1;}
|
||||
|
||||
for(;;) {
|
||||
int ret = wsgi_req->socket->proto_write_headers(wsgi_req, wsgi_req->headers->buf, wsgi_req->headers->pos);
|
||||
if (ret < 0) {
|
||||
if (!uwsgi.ignore_write_errors) {
|
||||
uwsgi_error("uwsgi_response_write_headers_do()");
|
||||
}
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
if (ret == UWSGI_OK) {
|
||||
break;
|
||||
}
|
||||
ret = uwsgi_wait_write_req(wsgi_req);
|
||||
if (ret < 0) { wsgi_req->write_errors++; return -1;}
|
||||
if (ret == 0) {
|
||||
uwsgi_log("uwsgi_response_write_headers_do() TIMEOUT !!!\n");
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
wsgi_req->headers_size += wsgi_req->write_pos;
|
||||
// reset for the next write
|
||||
wsgi_req->write_pos = 0;
|
||||
wsgi_req->headers_sent = 1;
|
||||
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
|
||||
if (wsgi_req->write_errors) return -1;
|
||||
|
||||
if (!wsgi_req->headers_sent) {
|
||||
int ret = uwsgi_response_write_headers_do(wsgi_req);
|
||||
if (ret == UWSGI_OK) goto sendbody;
|
||||
if (ret == UWSGI_AGAIN) return UWSGI_AGAIN;
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
sendbody:
|
||||
|
||||
if (len == 0) return UWSGI_OK;
|
||||
|
||||
for(;;) {
|
||||
int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len);
|
||||
if (ret < 0) {
|
||||
if (!uwsgi.ignore_write_errors) {
|
||||
uwsgi_error("uwsgi_response_write_body_do()");
|
||||
}
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
if (ret == UWSGI_OK) {
|
||||
break;
|
||||
}
|
||||
ret = uwsgi_wait_write_req(wsgi_req);
|
||||
if (ret < 0) { wsgi_req->write_errors++; return -1;}
|
||||
if (ret == 0) {
|
||||
uwsgi_log("uwsgi_response_write_body_do() TIMEOUT !!!\n");
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
wsgi_req->response_size += wsgi_req->write_pos;
|
||||
// reset for the next write
|
||||
wsgi_req->write_pos = 0;
|
||||
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
int uwsgi_response_sendfile_do(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) {
|
||||
|
||||
int can_close = 1;
|
||||
|
||||
if (fd == wsgi_req->sendfile_fd) can_close = 0;
|
||||
|
||||
if (wsgi_req->write_errors) return -1;
|
||||
|
||||
if (!wsgi_req->headers_sent) {
|
||||
int ret = uwsgi_response_write_headers_do(wsgi_req);
|
||||
if (ret == UWSGI_OK) goto sendfile;
|
||||
if (ret == UWSGI_AGAIN) return UWSGI_AGAIN;
|
||||
wsgi_req->write_errors++;
|
||||
if (can_close) close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sendfile:
|
||||
|
||||
if (len == 0) {
|
||||
struct stat st;
|
||||
if (fstat(fd, &st)) {
|
||||
uwsgi_error("fstat()");
|
||||
wsgi_req->write_errors++;
|
||||
if (can_close) close(fd);
|
||||
return -1;
|
||||
}
|
||||
len = st.st_size;
|
||||
}
|
||||
|
||||
if (wsgi_req->socket->can_offload) {
|
||||
// of we cannot close the socket (before the app will close it later)
|
||||
// let's dup it
|
||||
if (!can_close) {
|
||||
int tmp_fd = dup(fd);
|
||||
if (tmp_fd < 0) {
|
||||
uwsgi_error("uwsgi_response_sendfile_do()/dup()");
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
fd = tmp_fd;
|
||||
can_close = 1;
|
||||
}
|
||||
if (!uwsgi_offload_request_sendfile_do(wsgi_req, fd, len)) {
|
||||
wsgi_req->via = UWSGI_VIA_OFFLOAD;
|
||||
wsgi_req->response_size += len;
|
||||
return 0;
|
||||
}
|
||||
wsgi_req->write_errors++;
|
||||
if (can_close) close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
wsgi_req->via = UWSGI_VIA_SENDFILE;
|
||||
|
||||
for(;;) {
|
||||
int ret = wsgi_req->socket->proto_sendfile(wsgi_req, fd, pos, len);
|
||||
if (ret < 0) {
|
||||
if (!uwsgi.ignore_write_errors) {
|
||||
uwsgi_error("uwsgi_response_sendfile_do()");
|
||||
}
|
||||
wsgi_req->write_errors++;
|
||||
if (can_close) close(fd);
|
||||
return -1;
|
||||
}
|
||||
if (ret == UWSGI_OK) {
|
||||
break;
|
||||
}
|
||||
ret = uwsgi_wait_write_req(wsgi_req);
|
||||
if (ret < 0) {
|
||||
wsgi_req->write_errors++;
|
||||
if (can_close) close(fd);
|
||||
return -1;
|
||||
}
|
||||
if (ret == 0) {
|
||||
uwsgi_log("uwsgi_response_sendfile_do() TIMEOUT !!!\n");
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
wsgi_req->response_size += wsgi_req->write_pos;
|
||||
// reset for the next write
|
||||
wsgi_req->write_pos = 0;
|
||||
// close the file descriptor
|
||||
if (can_close) close(fd);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_simple_wait_write_hook(int fd, int timeout) {
|
||||
struct pollfd upoll;
|
||||
timeout = timeout * 1000;
|
||||
|
||||
upoll.fd = fd;
|
||||
upoll.events = POLLOUT;
|
||||
upoll.revents = 0;
|
||||
int ret = poll(&upoll, 1, timeout);
|
||||
|
||||
if (ret > 0) {
|
||||
if (upoll.revents & POLLOUT) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (ret < 0) {
|
||||
uwsgi_error("uwsgi_simple_wait_write_hook()/poll()");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
+3
-3
@@ -20,7 +20,7 @@ void uwsgi_xml_config(char *filename, struct wsgi_request *wsgi_req, char *magic
|
||||
|
||||
char *xml_id;
|
||||
char *xml_content;
|
||||
int xml_size = 0;
|
||||
size_t xml_size = 0;
|
||||
|
||||
if (uwsgi_check_scheme(filename)) {
|
||||
colon = uwsgi_get_last_char(filename, '/');
|
||||
@@ -47,7 +47,7 @@ void uwsgi_xml_config(char *filename, struct wsgi_request *wsgi_req, char *magic
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_log("[uWSGI] parsing config file %s\n", filename);
|
||||
uwsgi_log_initial("[uWSGI] parsing config file %s\n", filename);
|
||||
|
||||
element = xmlDocGetRootElement(doc);
|
||||
if (element == NULL) {
|
||||
@@ -221,7 +221,7 @@ void uwsgi_xml_config(char *filename, struct wsgi_request *wsgi_req, char *magic
|
||||
char *colon;
|
||||
|
||||
char *xml_content;
|
||||
int xml_size = 0;
|
||||
size_t xml_size = 0;
|
||||
int done = 0;
|
||||
|
||||
if (uwsgi_check_scheme(filename)) {
|
||||
|
||||
+5
-5
@@ -61,9 +61,9 @@ int yaml_get_depth(char *line) {
|
||||
return depth;
|
||||
}
|
||||
|
||||
char *yaml_get_line(char *yaml, off_t size) {
|
||||
char *yaml_get_line(char *yaml, size_t size) {
|
||||
|
||||
off_t i;
|
||||
size_t i;
|
||||
char *ptr = yaml;
|
||||
int comment = 0;
|
||||
|
||||
@@ -96,7 +96,7 @@ char *yaml_get_line(char *yaml, off_t size) {
|
||||
|
||||
void uwsgi_yaml_config(char *file, char *magic_table[]) {
|
||||
|
||||
int len = 0;
|
||||
size_t len = 0;
|
||||
char *yaml;
|
||||
|
||||
int in_uwsgi_section = 0;
|
||||
@@ -122,7 +122,7 @@ void uwsgi_yaml_config(char *file, char *magic_table[]) {
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("[uWSGI] getting YAML configuration from %s\n", file);
|
||||
uwsgi_log_initial("[uWSGI] getting YAML configuration from %s\n", file);
|
||||
|
||||
yaml = uwsgi_open_and_read(file, &len, 1, magic_table);
|
||||
|
||||
@@ -137,7 +137,7 @@ void uwsgi_yaml_config(char *file, char *magic_table[]) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
yaml_parser_set_input_string(&parser, (const unsigned char *) yaml, (size_t) len - 1);
|
||||
yaml_parser_set_input_string(&parser, (unsigned char *) yaml, (size_t) len - 1);
|
||||
|
||||
while (parsing) {
|
||||
if (!yaml_parser_scan(&parser, &token)) {
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
|
||||
int uwsgi_deflate_init(z_stream *z, char *dict, size_t dict_len) {
|
||||
z->zalloc = Z_NULL;
|
||||
z->zfree = Z_NULL;
|
||||
z->opaque = Z_NULL;
|
||||
if (deflateInit2(z, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 9, Z_DEFAULT_STRATEGY) != Z_OK) {
|
||||
//if (deflateInit(z, Z_DEFAULT_COMPRESSION)) {
|
||||
return -1;
|
||||
}
|
||||
if (dict && dict_len) {
|
||||
if (deflateSetDictionary(z, (Bytef *) dict, dict_len) != Z_OK) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_deflate(z_stream *z, char *buf, size_t len, size_t *dlen) {
|
||||
|
||||
// calculate the amount of bytes needed for output (+30 should be enough)
|
||||
Bytef *dbuf = uwsgi_malloc(len+30);
|
||||
z->avail_in = len;
|
||||
z->next_in = (Bytef *) buf;
|
||||
z->avail_out = len+30;
|
||||
z->next_out = dbuf;
|
||||
|
||||
if (len > 0) {
|
||||
if (deflate(z, Z_SYNC_FLUSH) != Z_OK) {
|
||||
free(dbuf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (deflate(z, Z_FINISH) != Z_STREAM_END) {
|
||||
free(dbuf);
|
||||
return NULL;
|
||||
}
|
||||
deflateEnd(z);
|
||||
}
|
||||
|
||||
*dlen = (z->next_out - dbuf);
|
||||
return (char *) dbuf;
|
||||
}
|
||||
|
||||
void uwsgi_crc32(uint32_t *ctx, char *buf, size_t len) {
|
||||
if (!buf) {
|
||||
*ctx = crc32(*ctx, Z_NULL, 0);
|
||||
}
|
||||
else {
|
||||
*ctx = crc32(*ctx, (const Bytef *) buf, len);
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
{% extends "admin/base_site.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<div class="breadcrumbs">
|
||||
<a href="../">{% trans 'Home' %}</a> ›
|
||||
{% trans 'uWSGI' %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div id="content-main">
|
||||
<h1>uWSGI status</h1>
|
||||
<b>masterpid:</b> {{masterpid}}<br/>
|
||||
<b>started_on:</b> {{started_on}}<br/>
|
||||
<b>buffer size:</b> {{buffer_size}}<br/>
|
||||
<b>workers:</b> {{numproc}}<br/>
|
||||
<b>total requests:</b> {{total_requests}}<br/>
|
||||
|
||||
<br/>
|
||||
|
||||
<div class="module" style="width:860px">
|
||||
<table>
|
||||
<caption style="width:860px">workers</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="row">id</th>
|
||||
<th scope="row">pid</th>
|
||||
<th scope="row">requests</th>
|
||||
<th scope="row">running time (milliseconds)</th>
|
||||
<th scope="row">load</th>
|
||||
<th scope="row">last spawn</th>
|
||||
<th scope="row">respawn count</th>
|
||||
<th scope="row">address space (vsz)</th>
|
||||
<th scope="row">resident memory (rss)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for w in workers %}
|
||||
<tr>
|
||||
<td align="center">{{w.id}}</td>
|
||||
<td align="center">{{w.pid}}</td>
|
||||
<td align="right">{{w.requests}}</td>
|
||||
<td align="right">{{w.running_time}}</td>
|
||||
<td align="right">{{w.load|floatformat:2}} %</td>
|
||||
<td align="right">{{w.last_spawn_str}}</td>
|
||||
<td align="right">{{w.respawn_count}}</td>
|
||||
<td align="right">{{w.vsz|filesizeformat}}</td>
|
||||
<td align="right">{{w.rss|filesizeformat}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="module" style="width:860px">
|
||||
<table>
|
||||
<caption style="width:860px">spooler jobs</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="row">job filename</th>
|
||||
<th scope="row">environment</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for j in jobs %}
|
||||
<tr>
|
||||
<td align="left">{{j.file}}</td>
|
||||
<td align="left">{{j.env}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% if masterpid %}
|
||||
<br/>
|
||||
<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="reload/" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="submit" value="gracefully reload uWSGI" name="_reload"/>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from django.conf.urls.defaults import *
|
||||
|
||||
urlpatterns = patterns('uwsgi_admin.views',
|
||||
(r'^$', 'index'),
|
||||
(r'^reload/$', 'reload')
|
||||
)
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
import uwsgi
|
||||
import time
|
||||
from django.shortcuts import render_to_response
|
||||
from django.template import RequestContext
|
||||
from django.contrib.admin.views.decorators import staff_member_required
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import HttpResponseRedirect
|
||||
|
||||
|
||||
def index(request):
|
||||
workers = uwsgi.workers()
|
||||
total_load = time.time() - uwsgi.started_on
|
||||
for w in workers:
|
||||
w['load'] = (100 * (w['running_time']/1000))/total_load
|
||||
w['last_spawn_str'] = time.ctime(w['last_spawn'])
|
||||
|
||||
jobs = []
|
||||
if 'spooler' in uwsgi.opt:
|
||||
spooler_jobs = uwsgi.spooler_jobs()
|
||||
for j in spooler_jobs:
|
||||
jobs.append({'file': j, 'env': uwsgi.parsefile(j)})
|
||||
|
||||
return render_to_response('uwsgi.html', {'masterpid': uwsgi.masterpid(),
|
||||
'started_on': time.ctime(uwsgi.started_on),
|
||||
'buffer_size': uwsgi.buffer_size,
|
||||
'total_requests': uwsgi.total_requests(),
|
||||
'numproc': uwsgi.numproc,
|
||||
'workers': workers,
|
||||
'jobs': jobs,
|
||||
}, RequestContext(request, {}))
|
||||
index = staff_member_required(index)
|
||||
|
||||
def reload(request):
|
||||
if uwsgi.masterpid() > 0:
|
||||
uwsgi.reload()
|
||||
request.user.message_set.create(message="uWSGI reloaded")
|
||||
else:
|
||||
request.user.message_set.create(message="The uWSGI master process is not active")
|
||||
|
||||
return HttpResponseRedirect(reverse(index))
|
||||
|
||||
reload = staff_member_required(reload)
|
||||
@@ -1,29 +0,0 @@
|
||||
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)
|
||||
@@ -0,0 +1,77 @@
|
||||
# to run the server
|
||||
# uwsgi --plugin psgi,coroae --http-socket :9090 --http-socket-modifier1 5 --coroae 8 --psgi examples/corostream.pl --master
|
||||
# to test it
|
||||
# curl -D /dev/stdout -N --raw http://localhost:9090/
|
||||
|
||||
use Coro::AnyEvent;
|
||||
use AnyEvent::HTTP;
|
||||
|
||||
my $signal_handler = sub {
|
||||
my $signum = shift;
|
||||
print "i am the signal ".$signum."\n" ;
|
||||
};
|
||||
|
||||
my $signal_timer = sub {
|
||||
my $signum = shift;
|
||||
print "2 seconds elapsed\n";
|
||||
};
|
||||
|
||||
uwsgi::register_signal(17, '', $signal_handler);
|
||||
uwsgi::register_signal(30, '', $signal_timer);
|
||||
|
||||
# raise the signal 30 every 2 seconds
|
||||
uwsgi::add_timer(30, 2);
|
||||
|
||||
sub streamer {
|
||||
$responder = shift;
|
||||
# generate the headers and start streaming the response
|
||||
my $writer = $responder->( [200, ['Content-Type' => 'text/plain']]);
|
||||
|
||||
$writer->write("Hello, the streaming is starting...\n");
|
||||
|
||||
for(my $i=0;$i<5;$i++) {
|
||||
Coro::AnyEvent::sleep 1;
|
||||
$writer->write("[".$i."] one seconds elapsed...\n");
|
||||
}
|
||||
|
||||
$writer->write("let me show you the coroae plugin source taken from github\n\n");
|
||||
|
||||
# this condvar will allow us to wait for the github response
|
||||
my $w = AnyEvent->condvar;
|
||||
|
||||
my $uwsgi_coroae_src = '';
|
||||
|
||||
http_get 'https://raw.github.com/unbit/uwsgi/master/plugins/coroae/coroae.c', sub { $uwsgi_coroae_src = $_[0] ; $w->send;};
|
||||
|
||||
$w->recv;
|
||||
|
||||
$writer->write($uwsgi_coroae_src);
|
||||
|
||||
Coro::AnyEvent::sleep 1;
|
||||
|
||||
$writer->write("now let's raise a uwsgi signal...\n");
|
||||
|
||||
uwsgi::signal(17);
|
||||
|
||||
Coro::AnyEvent::sleep 1;
|
||||
|
||||
$writer->write("another one second elapsed, time to finish.\n");
|
||||
|
||||
Coro::AnyEvent::sleep 1;
|
||||
|
||||
$writer->write("Goodbye\n");
|
||||
|
||||
$writer->close;
|
||||
|
||||
print "the request ended, but we are still here\n";
|
||||
|
||||
Coro::AnyEvent::sleep 1;
|
||||
|
||||
print "another second elapsed, time to end (really)\n";
|
||||
}
|
||||
|
||||
# our PSGI app
|
||||
my $app = sub {
|
||||
my $env = shift;
|
||||
return \&streamer;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
require 'net/http'
|
||||
|
||||
Net::HTTP.start("uwsgi.it") do |http|
|
||||
resp = http.get("/install")
|
||||
open("install.sh", "wb") do |file|
|
||||
file.write(resp.body)
|
||||
end
|
||||
end
|
||||
|
||||
system("bash install.sh rack #{Dir.pwd}/uwsgi.ruby")
|
||||
|
||||
open("Makefile", "w") do |file|
|
||||
file.write("all:\n")
|
||||
file.write("\t\n")
|
||||
end
|
||||
+2
-1
@@ -15,10 +15,11 @@ rpc result:<br/>
|
||||
|
||||
<?
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
uwsgi_cache_update('foobar', $_POST['cache_val']);
|
||||
echo uwsgi_cache_update('foobar', $_POST['cache_val']);
|
||||
}
|
||||
|
||||
?>
|
||||
cache value: <?= uwsgi_cache_get('foobar') ?><br/>
|
||||
<form method="POST">
|
||||
<input type="text" name="cache_val" value="<?=uwsgi_cache_get('foobar')?>"/>
|
||||
<input type="submit" value="cache set" />
|
||||
|
||||
+14
-2
@@ -132,10 +132,16 @@ void linux_namespace_jail() {
|
||||
|
||||
if (strcmp(uwsgi.ns, "/")) {
|
||||
ns_tmp_mountpoint = uwsgi_concat2(uwsgi.ns, "/.uwsgi_ns_tmp_mountpoint");
|
||||
mkdir(ns_tmp_mountpoint, S_IRWXU);
|
||||
if (mkdir(ns_tmp_mountpoint, S_IRWXU) < 0) {
|
||||
uwsgi_error("mkdir() ns_tmp_mountpoint");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ns_tmp_mountpoint2 = uwsgi_concat2(ns_tmp_mountpoint, "/.uwsgi_ns_tmp_mountpoint");
|
||||
mkdir(ns_tmp_mountpoint2, S_IRWXU);
|
||||
if (mkdir(ns_tmp_mountpoint2, S_IRWXU) < 0) {
|
||||
uwsgi_error("mkdir() ns_tmp_mountpoint2");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (mount(uwsgi.ns, ns_tmp_mountpoint, "none", MS_BIND, NULL)) {
|
||||
uwsgi_error("mount()");
|
||||
@@ -201,10 +207,16 @@ void linux_namespace_jail() {
|
||||
|
||||
unmounted = 0;
|
||||
procmounts = fopen("/proc/self/mounts", "r");
|
||||
if (!procmounts)
|
||||
break;
|
||||
while (fgets(line, 1024, procmounts) != NULL) {
|
||||
delim0 = strchr(line, ' ');
|
||||
if (!delim0)
|
||||
continue;
|
||||
delim0++;
|
||||
delim1 = strchr(delim0, ' ');
|
||||
if (!delim1)
|
||||
continue;
|
||||
*delim1 = 0;
|
||||
// and now check for keep-mounts
|
||||
if (uwsgi_is_a_keep_mount(delim0)) continue;
|
||||
|
||||
-309
@@ -1,309 +0,0 @@
|
||||
/*
|
||||
|
||||
*** uWSGI, stripped down version of Linux rbtree ***
|
||||
|
||||
|
||||
Red Black Trees
|
||||
(C) 1999 Andrea Arcangeli <andrea@suse.de>
|
||||
(C) 2002 David Woodhouse <dwmw2@infradead.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 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;
|
||||
struct rb_node *parent = rb_parent(node);
|
||||
|
||||
if ((node->rb_right = right->rb_left))
|
||||
rb_set_parent(right->rb_left, node);
|
||||
right->rb_left = node;
|
||||
|
||||
rb_set_parent(right, parent);
|
||||
|
||||
if (parent)
|
||||
{
|
||||
if (node == parent->rb_left)
|
||||
parent->rb_left = right;
|
||||
else
|
||||
parent->rb_right = right;
|
||||
}
|
||||
else
|
||||
root->rb_node = right;
|
||||
rb_set_parent(node, right);
|
||||
}
|
||||
|
||||
static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
|
||||
{
|
||||
struct rb_node *left = node->rb_left;
|
||||
struct rb_node *parent = rb_parent(node);
|
||||
|
||||
if ((node->rb_left = left->rb_right))
|
||||
rb_set_parent(left->rb_right, node);
|
||||
left->rb_right = node;
|
||||
|
||||
rb_set_parent(left, parent);
|
||||
|
||||
if (parent)
|
||||
{
|
||||
if (node == parent->rb_right)
|
||||
parent->rb_right = left;
|
||||
else
|
||||
parent->rb_left = left;
|
||||
}
|
||||
else
|
||||
root->rb_node = left;
|
||||
rb_set_parent(node, left);
|
||||
}
|
||||
|
||||
void rb_insert_color(struct rb_node *node, struct rb_root *root)
|
||||
{
|
||||
struct rb_node *parent, *gparent;
|
||||
|
||||
while ((parent = rb_parent(node)) && rb_is_red(parent))
|
||||
{
|
||||
gparent = rb_parent(parent);
|
||||
|
||||
if (parent == gparent->rb_left)
|
||||
{
|
||||
{
|
||||
register struct rb_node *uncle = gparent->rb_right;
|
||||
if (uncle && rb_is_red(uncle))
|
||||
{
|
||||
rb_set_black(uncle);
|
||||
rb_set_black(parent);
|
||||
rb_set_red(gparent);
|
||||
node = gparent;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent->rb_right == node)
|
||||
{
|
||||
register struct rb_node *tmp;
|
||||
__rb_rotate_left(parent, root);
|
||||
tmp = parent;
|
||||
parent = node;
|
||||
node = tmp;
|
||||
}
|
||||
|
||||
rb_set_black(parent);
|
||||
rb_set_red(gparent);
|
||||
__rb_rotate_right(gparent, root);
|
||||
} else {
|
||||
{
|
||||
register struct rb_node *uncle = gparent->rb_left;
|
||||
if (uncle && rb_is_red(uncle))
|
||||
{
|
||||
rb_set_black(uncle);
|
||||
rb_set_black(parent);
|
||||
rb_set_red(gparent);
|
||||
node = gparent;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent->rb_left == node)
|
||||
{
|
||||
register struct rb_node *tmp;
|
||||
__rb_rotate_right(parent, root);
|
||||
tmp = parent;
|
||||
parent = node;
|
||||
node = tmp;
|
||||
}
|
||||
|
||||
rb_set_black(parent);
|
||||
rb_set_red(gparent);
|
||||
__rb_rotate_left(gparent, root);
|
||||
}
|
||||
}
|
||||
|
||||
rb_set_black(root->rb_node);
|
||||
}
|
||||
|
||||
static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
|
||||
struct rb_root *root)
|
||||
{
|
||||
struct rb_node *other;
|
||||
|
||||
while ((!node || rb_is_black(node)) && node != root->rb_node)
|
||||
{
|
||||
if (parent->rb_left == node)
|
||||
{
|
||||
other = parent->rb_right;
|
||||
if (rb_is_red(other))
|
||||
{
|
||||
rb_set_black(other);
|
||||
rb_set_red(parent);
|
||||
__rb_rotate_left(parent, root);
|
||||
other = parent->rb_right;
|
||||
}
|
||||
if ((!other->rb_left || rb_is_black(other->rb_left)) &&
|
||||
(!other->rb_right || rb_is_black(other->rb_right)))
|
||||
{
|
||||
rb_set_red(other);
|
||||
node = parent;
|
||||
parent = rb_parent(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!other->rb_right || rb_is_black(other->rb_right))
|
||||
{
|
||||
rb_set_black(other->rb_left);
|
||||
rb_set_red(other);
|
||||
__rb_rotate_right(other, root);
|
||||
other = parent->rb_right;
|
||||
}
|
||||
rb_set_color(other, rb_color(parent));
|
||||
rb_set_black(parent);
|
||||
rb_set_black(other->rb_right);
|
||||
__rb_rotate_left(parent, root);
|
||||
node = root->rb_node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
other = parent->rb_left;
|
||||
if (rb_is_red(other))
|
||||
{
|
||||
rb_set_black(other);
|
||||
rb_set_red(parent);
|
||||
__rb_rotate_right(parent, root);
|
||||
other = parent->rb_left;
|
||||
}
|
||||
if ((!other->rb_left || rb_is_black(other->rb_left)) &&
|
||||
(!other->rb_right || rb_is_black(other->rb_right)))
|
||||
{
|
||||
rb_set_red(other);
|
||||
node = parent;
|
||||
parent = rb_parent(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!other->rb_left || rb_is_black(other->rb_left))
|
||||
{
|
||||
rb_set_black(other->rb_right);
|
||||
rb_set_red(other);
|
||||
__rb_rotate_left(other, root);
|
||||
other = parent->rb_left;
|
||||
}
|
||||
rb_set_color(other, rb_color(parent));
|
||||
rb_set_black(parent);
|
||||
rb_set_black(other->rb_left);
|
||||
__rb_rotate_right(parent, root);
|
||||
node = root->rb_node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node)
|
||||
rb_set_black(node);
|
||||
}
|
||||
|
||||
void rb_erase(struct rb_node *node, struct rb_root *root)
|
||||
{
|
||||
struct rb_node *child, *parent;
|
||||
int color;
|
||||
|
||||
if (!node->rb_left)
|
||||
child = node->rb_right;
|
||||
else if (!node->rb_right)
|
||||
child = node->rb_left;
|
||||
else
|
||||
{
|
||||
struct rb_node *old = node, *left;
|
||||
|
||||
node = node->rb_right;
|
||||
while ((left = node->rb_left) != NULL)
|
||||
node = left;
|
||||
|
||||
if (rb_parent(old)) {
|
||||
if (rb_parent(old)->rb_left == old)
|
||||
rb_parent(old)->rb_left = node;
|
||||
else
|
||||
rb_parent(old)->rb_right = node;
|
||||
} else
|
||||
root->rb_node = node;
|
||||
|
||||
child = node->rb_right;
|
||||
parent = rb_parent(node);
|
||||
color = rb_color(node);
|
||||
|
||||
if (parent == old) {
|
||||
parent = node;
|
||||
} else {
|
||||
if (child)
|
||||
rb_set_parent(child, parent);
|
||||
parent->rb_left = child;
|
||||
|
||||
node->rb_right = old->rb_right;
|
||||
rb_set_parent(old->rb_right, node);
|
||||
}
|
||||
|
||||
node->rb_parent_color = old->rb_parent_color;
|
||||
node->rb_left = old->rb_left;
|
||||
rb_set_parent(old->rb_left, node);
|
||||
|
||||
goto color;
|
||||
}
|
||||
|
||||
parent = rb_parent(node);
|
||||
color = rb_color(node);
|
||||
|
||||
if (child)
|
||||
rb_set_parent(child, parent);
|
||||
if (parent)
|
||||
{
|
||||
if (parent->rb_left == node)
|
||||
parent->rb_left = child;
|
||||
else
|
||||
parent->rb_right = child;
|
||||
}
|
||||
else
|
||||
root->rb_node = child;
|
||||
|
||||
color:
|
||||
if (color == RB_BLACK)
|
||||
__rb_erase_color(child, parent, root);
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ struct uwsgi_alarm_curl_opt {
|
||||
};
|
||||
|
||||
|
||||
#ifdef CURLOPT_MAIL_RCPT
|
||||
static void uwsgi_alarm_curl_to(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc) {
|
||||
uacc->to = arg;
|
||||
struct curl_slist *list = NULL;
|
||||
@@ -29,6 +30,7 @@ static void uwsgi_alarm_curl_to(CURL *curl, CURLoption option, char *arg, struct
|
||||
}
|
||||
curl_easy_setopt(curl, option, list);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void uwsgi_alarm_curl_ssl(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc) {
|
||||
curl_easy_setopt(curl, option, (long)CURLUSESSL_ALL);
|
||||
@@ -44,8 +46,12 @@ static void uwsgi_alarm_curl_set_subject(CURL *curl, CURLoption option, char *ar
|
||||
|
||||
static struct uwsgi_alarm_curl_opt uaco[] = {
|
||||
{"url", CURLOPT_URL, NULL},
|
||||
#ifdef CURLOPT_MAIL_RCPT
|
||||
{"mail_to", CURLOPT_MAIL_RCPT, uwsgi_alarm_curl_to },
|
||||
#endif
|
||||
#ifdef CURLOPT_MAIL_FROM
|
||||
{"mail_from", CURLOPT_MAIL_FROM, NULL},
|
||||
#endif
|
||||
{"subject", 0, uwsgi_alarm_curl_set_subject},
|
||||
{"ssl", CURLOPT_USE_SSL, uwsgi_alarm_curl_ssl},
|
||||
{"auth_user", CURLOPT_USERNAME, NULL},
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user