mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-10-04 16:08:31 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2263c6a618 | ||
|
|
b4ecd504e3 | ||
|
|
f226f29428 | ||
|
|
b87a284390 | ||
|
|
f63dcd0d9c | ||
|
|
7f5563d581 | ||
|
|
d8a61a920e | ||
|
|
5a4900da8e | ||
|
|
677c30057a | ||
|
|
26113e091b | ||
|
|
1b5e98f593 | ||
|
|
0aa5201947 | ||
|
|
e3951baa3f | ||
|
|
9f9dbbab9e | ||
|
|
d546bbadbd | ||
|
|
2b7f25054f | ||
|
|
bb3f6bcf7e | ||
|
|
41da7175d1 | ||
|
|
446763b58a | ||
|
|
3e9337a0fc | ||
|
|
028806165b | ||
|
|
e4be42edbb | ||
|
|
230fa1f3bb | ||
|
|
d74653bbad | ||
|
|
38049b0897 | ||
|
|
b4af646929 | ||
|
|
b21ec73a52 | ||
|
|
c595844f0e | ||
|
|
fe8ee7c7b3 | ||
|
|
cd382c6bc0 | ||
|
|
e68296c293 | ||
|
|
cc189feae5 | ||
|
|
18e19027a1 | ||
|
|
2d2e0e4757 | ||
|
|
a9f50d79f9 | ||
|
|
0ccd31bee0 | ||
|
|
3ea82b2bcd | ||
|
|
6dad7b3ced | ||
|
|
f96ebd2b07 | ||
|
|
b8d0e7a3ac | ||
|
|
14cca3d497 | ||
|
|
c343ca0cc3 | ||
|
|
527d371bda | ||
|
|
b87a800a9a | ||
|
|
e406993ed1 | ||
|
|
eeff935fc9 | ||
|
|
0791394f1a | ||
|
|
082a407b06 | ||
|
|
8a89b49df1 | ||
|
|
2314b9cbab | ||
|
|
d0cca85c83 | ||
|
|
6a7a5cbcba | ||
|
|
ecccc82cc8 | ||
|
|
02693489fe | ||
|
|
0f5dba5828 | ||
|
|
e528d4c4b7 | ||
|
|
52a3af6acf | ||
|
|
dcefea9958 | ||
|
|
59121ff834 | ||
|
|
7f5bb6d472 | ||
|
|
639c1a508c | ||
|
|
417a26fc64 | ||
|
|
210ccd0063 | ||
|
|
1bf0162d38 | ||
|
|
e93027fd7e | ||
|
|
807060706f | ||
|
|
a317f88d3c | ||
|
|
e17a7f0701 | ||
|
|
db325eb9fe | ||
|
|
b41a4c8c3b | ||
|
|
73b4d11d18 | ||
|
|
8162b87287 | ||
|
|
70e9e4f3ee | ||
|
|
e61ae376b3 | ||
|
|
2d57b0e926 | ||
|
|
ae683af07a | ||
|
|
3c4f6a9171 | ||
|
|
39986e546c | ||
|
|
2e81a80f7b | ||
|
|
fcb3aa38c8 | ||
|
|
00a38d8ec5 | ||
|
|
07a0ab4227 | ||
|
|
d4a9a2c543 | ||
|
|
2b523fc60d | ||
|
|
0c26928236 | ||
|
|
8401e56a22 | ||
|
|
5109f9ae0b | ||
|
|
c9bc06669a | ||
|
|
a83fb2672c | ||
|
|
8f9ecb44d9 | ||
|
|
bfcc09a8de | ||
|
|
f8a8c997db | ||
|
|
132b996f30 | ||
|
|
12f970cdfb | ||
|
|
9afa963225 | ||
|
|
ed368d0d51 | ||
|
|
21f21d34ba | ||
|
|
f37823c809 | ||
|
|
6eaefcff5e | ||
|
|
79235c1cc3 | ||
|
|
29135f014b | ||
|
|
13c998fb8d | ||
|
|
71bfd0d636 | ||
|
|
51e99e0f5a | ||
|
|
66e7beefc4 | ||
|
|
f2b10c35b7 | ||
|
|
e951eba96c | ||
|
|
9fe18da7a3 | ||
|
|
a14fdead14 | ||
|
|
9a671a4991 | ||
|
|
8f5e7b124a | ||
|
|
5f7464d015 | ||
|
|
238dd6c1d0 | ||
|
|
82e4e54edc | ||
|
|
9946cbb9da | ||
|
|
2474adb23a | ||
|
|
f40757bb67 | ||
|
|
bc29479930 | ||
|
|
4ec78edaa3 | ||
|
|
aa0271158d | ||
|
|
c0aa5bfe17 | ||
|
|
3f8e6a8cc8 | ||
|
|
ef0316fc2e | ||
|
|
7274efab15 | ||
|
|
e44b62b6b2 | ||
|
|
31c041d435 | ||
|
|
35f47371ed | ||
|
|
c5412e1620 | ||
|
|
a9b4c52811 | ||
|
|
5ce40b6ac8 | ||
|
|
b93dcbf46f | ||
|
|
8051a2bc98 | ||
|
|
78d8b221fc | ||
|
|
d51cada284 | ||
|
|
389eef9e88 | ||
|
|
270fb0c50d | ||
|
|
e7e9dfee88 | ||
|
|
3bafae276d | ||
|
|
cfebe2927d | ||
|
|
1d4294a845 | ||
|
|
12cfdd9864 | ||
|
|
add930c517 | ||
|
|
32972978be | ||
|
|
c8bad3550e | ||
|
|
ecc55d789d | ||
|
|
88555e2c20 | ||
|
|
ec2bfcd302 | ||
|
|
f1f81ed4c4 | ||
|
|
87933cca26 | ||
|
|
2dcd8624a2 | ||
|
|
7fcef76bbe | ||
|
|
2a5c4e938d | ||
|
|
274eae27ef | ||
|
|
207220bc50 | ||
|
|
fb8c4439c7 | ||
|
|
894be9c41e | ||
|
|
0a4bff8963 | ||
|
|
d515f3e279 | ||
|
|
e8aa0e1e26 | ||
|
|
46a8aae908 | ||
|
|
a9f90464e6 | ||
|
|
4bcdba2334 | ||
|
|
64a8f3464a | ||
|
|
e640bd6f9b | ||
|
|
71a6726bcf | ||
|
|
fe13774b4b | ||
|
|
ecc3a5e8e2 | ||
|
|
dd1881576a | ||
|
|
322a2d2365 | ||
|
|
a76d7a1c66 | ||
|
|
5631dcabf8 | ||
|
|
3f731e2577 | ||
|
|
7a1b7f299b | ||
|
|
322673215e | ||
|
|
b58a0c4969 | ||
|
|
c5fe8c6d30 | ||
|
|
7f54f5075d | ||
|
|
95d4cea3bb | ||
|
|
d6ff3ac018 | ||
|
|
1f4099c874 | ||
|
|
8cd298de34 | ||
|
|
851df33977 | ||
|
|
17f3f3d9a0 | ||
|
|
4273489e42 | ||
|
|
57077ac68c | ||
|
|
45f61435a1 | ||
|
|
28153af4ad | ||
|
|
341cfd90b6 | ||
|
|
82342577a4 | ||
|
|
9d735fdbea | ||
|
|
1775526b89 | ||
|
|
c84f205c74 | ||
|
|
591faabc00 | ||
|
|
e945003d07 | ||
|
|
26c6ec4283 | ||
|
|
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 | ||
|
|
e13734ae6c | ||
|
|
cf62b03e33 | ||
|
|
b2f292c2da | ||
|
|
b96b6a24a6 | ||
|
|
b2a1237781 | ||
|
|
a48af2e226 | ||
|
|
33446c3179 | ||
|
|
242e01e37a | ||
|
|
41eba2b486 | ||
|
|
24763fdbd2 | ||
|
|
951cbf3eba | ||
|
|
8759b66206 | ||
|
|
93aacace5f | ||
|
|
8406fb12be | ||
|
|
6af3ea267e | ||
|
|
9ff37ce019 | ||
|
|
f4187680bd | ||
|
|
57b72ac17d | ||
|
|
5c64839734 | ||
|
|
e4de9a8bc7 | ||
|
|
689b4afb44 | ||
|
|
ceebaa7d9d | ||
|
|
0fa2c543ec | ||
|
|
519df88126 | ||
|
|
75b275591d | ||
|
|
2f901f08cb | ||
|
|
b041fe4473 | ||
|
|
f5d6cb65f9 | ||
|
|
9c94aedb29 | ||
|
|
d248b290f2 | ||
|
|
cb48070db1 | ||
|
|
cd34bac104 | ||
|
|
c966fbb163 | ||
|
|
feac596efc | ||
|
|
981ddfcefe | ||
|
|
5e561b6578 | ||
|
|
fab495fadc | ||
|
|
ecbda6dc26 | ||
|
|
e23766e4d0 | ||
|
|
6d9de4c618 | ||
|
|
4ca14f6046 | ||
|
|
d856c9920d | ||
|
|
fd62440265 | ||
|
|
d4041c9e1d | ||
|
|
dc9e1bd324 | ||
|
|
89bbd967ed | ||
|
|
276ada315d | ||
|
|
bdd0d408a0 | ||
|
|
5ddaa2e436 | ||
|
|
f9d0e75056 | ||
|
|
7776a1f0be | ||
|
|
a33a57d8af | ||
|
|
9371e2b8de | ||
|
|
6c1a842f7d | ||
|
|
d746deaf02 | ||
|
|
09fca72b4c | ||
|
|
2ffc31e578 | ||
|
|
2a254d195a | ||
|
|
95d3ee4e61 | ||
|
|
4d56474511 | ||
|
|
46a33b268a | ||
|
|
b0829cc2e3 | ||
|
|
93a0913182 | ||
|
|
0605148e21 | ||
|
|
e7b5c7c8e4 | ||
|
|
b2a0fd1914 | ||
|
|
9cc89a6052 | ||
|
|
1606b8b775 | ||
|
|
cfac385f8e | ||
|
|
99fd4572cb | ||
|
|
d3194ca011 | ||
|
|
af61a9e33f | ||
|
|
4896e22a62 | ||
|
|
7882d12a80 | ||
|
|
9342acc500 | ||
|
|
929a919c9d | ||
|
|
d1f6e97dd7 | ||
|
|
f9d76f90eb | ||
|
|
2de5e8994f | ||
|
|
7e935253a2 | ||
|
|
4c20d83573 | ||
|
|
7035a676a2 | ||
|
|
736f99d10b | ||
|
|
ea422a4576 | ||
|
|
e274f53286 | ||
|
|
c03dcf4617 | ||
|
|
d70c7ceb89 | ||
|
|
9ae1354d1a | ||
|
|
b29f0b9436 | ||
|
|
e01cd802d8 | ||
|
|
c7b57c9776 | ||
|
|
3a48b898ad | ||
|
|
4f4771b527 | ||
|
|
b43df60d7f | ||
|
|
10a5661218 | ||
|
|
a99670cfb5 | ||
|
|
7967e8ac3c | ||
|
|
e105ebe273 | ||
|
|
11d2c004c2 | ||
|
|
e8bfa12372 | ||
|
|
317e9efa2d | ||
|
|
4b99bff520 | ||
|
|
99f584cff0 | ||
|
|
fc6a79dcc9 | ||
|
|
75af812b83 | ||
|
|
0f4e1eb7e2 | ||
|
|
a3e0c2260f | ||
|
|
3f63caa5eb | ||
|
|
61bd3fb0e6 | ||
|
|
d6b4b8ea6e | ||
|
|
3a451fb42f | ||
|
|
7017712c6d | ||
|
|
49140c3387 | ||
|
|
1d9edc3e34 | ||
|
|
fffe070e30 | ||
|
|
29ce04adce | ||
|
|
c487fb0cf0 | ||
|
|
503fcd5ed5 | ||
|
|
7136beeff7 | ||
|
|
64c7d71c35 | ||
|
|
d2d714e933 | ||
|
|
f7399ef2ec | ||
|
|
4014bc53bd | ||
|
|
b8f42a8d0b | ||
|
|
b40442a0f8 | ||
|
|
bee3bf5d43 | ||
|
|
59cc3d7c04 | ||
|
|
8dc072732b | ||
|
|
37b7c31849 | ||
|
|
738b886267 | ||
|
|
8679f8b845 | ||
|
|
ecfae75886 | ||
|
|
cefc9fcc58 | ||
|
|
03104063cb | ||
|
|
ef10dc054f | ||
|
|
242497102e | ||
|
|
0242b464e7 | ||
|
|
353b837f67 | ||
|
|
d70ecab49f | ||
|
|
c65adaaac7 | ||
|
|
4f0406c1cc | ||
|
|
6ea535a74d | ||
|
|
2e66ae9abe | ||
|
|
39aa8ca8be | ||
|
|
ef80a7bba9 | ||
|
|
8a65125ae5 | ||
|
|
86d9b4bc0e | ||
|
|
1d691139c7 | ||
|
|
94eb4f078e | ||
|
|
47f3b39870 | ||
|
|
c67d26f8cc | ||
|
|
9c99b29e47 | ||
|
|
5ce2020d6f | ||
|
|
d965587d9d | ||
|
|
4f85c215cd | ||
|
|
1015ef9611 | ||
|
|
adcbc061b1 | ||
|
|
42229b08ce | ||
|
|
7bac625537 | ||
|
|
a3e9a288d3 | ||
|
|
946a46df86 | ||
|
|
e368b2da5e | ||
|
|
6b32ac086e | ||
|
|
1651e3b0ef | ||
|
|
fee6c65365 | ||
|
|
6070bd70a7 | ||
|
|
86ea390ba8 | ||
|
|
e9158255a1 | ||
|
|
cd80885a49 | ||
|
|
8925ea06e1 | ||
|
|
f1135c736a | ||
|
|
c9f0786edd | ||
|
|
7e52f14786 | ||
|
|
e35dcdbcdb | ||
|
|
c59a3cb35a | ||
|
|
a9703f8533 | ||
|
|
0de510b777 | ||
|
|
8a0fa1ffc4 | ||
|
|
4ca422a0a8 | ||
|
|
a979abf0c6 | ||
|
|
d12ddded55 | ||
|
|
3beead6459 | ||
|
|
248741a81f | ||
|
|
188b66e92c | ||
|
|
5ae1c6fbd1 | ||
|
|
51b9b5d070 | ||
|
|
dafe3bb12c | ||
|
|
973e508af7 | ||
|
|
8e31bb612e | ||
|
|
f920ac0fb0 | ||
|
|
ae1b5afd7d | ||
|
|
1f2bae130e | ||
|
|
4417e55862 | ||
|
|
74a84bdd3a | ||
|
|
b764252e7f | ||
|
|
2fd71be9d9 | ||
|
|
d65f873e77 | ||
|
|
1427c9ce1c | ||
|
|
c3de9320d7 | ||
|
|
674151e485 | ||
|
|
9c042ffc1c | ||
|
|
c5dc74b021 | ||
|
|
97137488f9 | ||
|
|
8cff01a1c7 | ||
|
|
3c8452313e | ||
|
|
322b130fc9 | ||
|
|
6c001c2fda | ||
|
|
5d4050817d | ||
|
|
0a1147a4f6 | ||
|
|
f92cb0e6a2 | ||
|
|
8b79c76261 | ||
|
|
0015b51262 | ||
|
|
b1dc8cd9c6 | ||
|
|
3269e2d288 | ||
|
|
71a9747d96 | ||
|
|
455d041ce4 | ||
|
|
88205f8dd1 | ||
|
|
7d9dadddf6 | ||
|
|
57e78dd76f | ||
|
|
7d0d2b33f4 | ||
|
|
03c739102d | ||
|
|
392bb8d7b1 | ||
|
|
505b35be29 | ||
|
|
fdb002ad9b | ||
|
|
557c46373f | ||
|
|
3cde8be505 | ||
|
|
c2cf1f3a62 | ||
|
|
956cb1f13c | ||
|
|
f698b558e1 | ||
|
|
ca832900a0 | ||
|
|
6a6227a8e7 | ||
|
|
8539cdb5a7 | ||
|
|
15194e6b55 | ||
|
|
5cea1de1ba | ||
|
|
e735b9e31f | ||
|
|
9ff8f8899f | ||
|
|
d908c4ef35 | ||
|
|
207f50726d | ||
|
|
212559fcce | ||
|
|
cf480e499c | ||
|
|
f2e27f5154 | ||
|
|
d932a4feae | ||
|
|
da6e05072f | ||
|
|
13277d9d71 | ||
|
|
f17f8b337f | ||
|
|
ffb454e414 | ||
|
|
424f5a09e7 | ||
|
|
c29a6f6446 | ||
|
|
6f7edf0941 | ||
|
|
a4c4b7e8d2 | ||
|
|
837f6f3a54 | ||
|
|
13041da6bf | ||
|
|
046824dae7 | ||
|
|
269a588d9d | ||
|
|
50ae12518a | ||
|
|
a932937adf | ||
|
|
23bd924ace | ||
|
|
e8f39685cc | ||
|
|
2122bacb33 | ||
|
|
3cb3c83442 | ||
|
|
d552d5257c | ||
|
|
0aff486a73 | ||
|
|
b887f3fc27 | ||
|
|
b30e2c4ad8 | ||
|
|
040b17e5eb | ||
|
|
770114a21c | ||
|
|
2864568f09 | ||
|
|
56eaa88dd7 | ||
|
|
bb54b90640 | ||
|
|
34502eeabe | ||
|
|
ae90f29fa3 | ||
|
|
1eeda4faaa | ||
|
|
18046c976e | ||
|
|
530bf85cf9 | ||
|
|
5261a9fed5 | ||
|
|
26d0d8dfdc | ||
|
|
eddf494b07 | ||
|
|
689a4ef6d4 | ||
|
|
9398304c60 | ||
|
|
e904f9f76e | ||
|
|
5df34ecfd8 | ||
|
|
a96951880d | ||
|
|
c4425627ee | ||
|
|
7033a0b5d2 | ||
|
|
a491be3975 | ||
|
|
c664ac21bb | ||
|
|
2205c0c33d | ||
|
|
e9c54a4228 | ||
|
|
a38427944c | ||
|
|
124db58683 | ||
|
|
aa075f9aaa | ||
|
|
305f8a0667 | ||
|
|
9d8238a2bb | ||
|
|
3fccd4c5c0 | ||
|
|
1a330e49f6 | ||
|
|
7c09f294bf | ||
|
|
22c520043f | ||
|
|
859c1eed0e | ||
|
|
e942668613 | ||
|
|
169c3a7970 | ||
|
|
22892ce550 | ||
|
|
2f5132c539 | ||
|
|
d737bd0d35 | ||
|
|
665958f1f5 | ||
|
|
4bf86892ab | ||
|
|
bab89d1152 | ||
|
|
4322c3b538 | ||
|
|
9fabfd77ee | ||
|
|
94ce4187c9 | ||
|
|
e78388e287 | ||
|
|
e3014bd0dc | ||
|
|
36c79b100e | ||
|
|
f6641aeca1 | ||
|
|
278187e738 | ||
|
|
668831d437 | ||
|
|
340f1e24ae | ||
|
|
44e773f737 | ||
|
|
03aae347b0 | ||
|
|
e393f36f0a | ||
|
|
b169193723 | ||
|
|
2de9b9d5c7 | ||
|
|
bde43ee7b2 | ||
|
|
4921e676d3 | ||
|
|
b76a47231c | ||
|
|
2561d26b95 | ||
|
|
4492bf517b | ||
|
|
c195e7e8ea | ||
|
|
667b418e28 | ||
|
|
0ee7ba6aae | ||
|
|
8a656908e1 | ||
|
|
4f05d04c7f | ||
|
|
c0fcbb7b85 | ||
|
|
fe36479d5c | ||
|
|
849829d6c0 | ||
|
|
a77e9d3241 | ||
|
|
fe26d41215 | ||
|
|
4d86712d4d | ||
|
|
006197a7c3 | ||
|
|
434aeb9761 | ||
|
|
b1ca831269 | ||
|
|
8fc9b14db4 | ||
|
|
36cc5434fd | ||
|
|
70c30a62e6 | ||
|
|
56827398d1 | ||
|
|
bd5cc93872 | ||
|
|
88be144a81 | ||
|
|
8046194696 | ||
|
|
3012cb6bf9 | ||
|
|
cf74ccaaef | ||
|
|
8749053f30 | ||
|
|
8368ce0e4c | ||
|
|
c6c2157c1d | ||
|
|
4740c81280 | ||
|
|
f4f6e628b8 | ||
|
|
55239207f4 | ||
|
|
d912e951a0 | ||
|
|
b0c3184565 | ||
|
|
b3c9c5057f | ||
|
|
1c022ee01d | ||
|
|
18589d86ff | ||
|
|
5a7b5d37b4 | ||
|
|
3e2115aa21 | ||
|
|
3f4a041e07 | ||
|
|
59eb46895c | ||
|
|
2f452cc6f6 | ||
|
|
770bb1d122 | ||
|
|
4a036fb2ad | ||
|
|
2ef72ad80f | ||
|
|
c9088067d5 | ||
|
|
6f772f77c9 | ||
|
|
2430617427 | ||
|
|
28888720bd | ||
|
|
32a1ba27ba | ||
|
|
b750ee2aa3 | ||
|
|
86aa5190b1 | ||
|
|
55288af936 | ||
|
|
827d2e461b | ||
|
|
8400bcf8bc | ||
|
|
4dcfde541a | ||
|
|
cf04a87688 | ||
|
|
65f88593b8 | ||
|
|
dbdf453724 | ||
|
|
e7f157b102 | ||
|
|
d30a5a4a50 | ||
|
|
b0cfb0ca1f | ||
|
|
c150f8c793 | ||
|
|
46733c0673 | ||
|
|
772d1c8a5a | ||
|
|
3f4bbdebe5 | ||
|
|
0394977658 | ||
|
|
33c9d01baf | ||
|
|
1367ee1e40 | ||
|
|
8ddeed80cf | ||
|
|
e796a57f14 | ||
|
|
839962370a | ||
|
|
0a993c10e0 | ||
|
|
aaaef51f2a | ||
|
|
8e10efd027 | ||
|
|
13c112430d | ||
|
|
05a40e786c | ||
|
|
64e05bed38 | ||
|
|
6f39909cd4 | ||
|
|
b4e41532eb | ||
|
|
4ca33d3f88 | ||
|
|
b40cdfbe66 | ||
|
|
e775b18fd5 | ||
|
|
b1506712c9 | ||
|
|
7af2be5f1c | ||
|
|
27b1c63563 | ||
|
|
7b8fbf0f96 | ||
|
|
a748686349 | ||
|
|
e2a0173d36 | ||
|
|
4d25e05986 | ||
|
|
c2091c52eb | ||
|
|
d74928fa0f | ||
|
|
dc8bf75b73 | ||
|
|
cc5ae8bf31 | ||
|
|
f62f7f9282 | ||
|
|
c3cbcbb0d5 | ||
|
|
ec2889b202 | ||
|
|
474d04d6a1 | ||
|
|
18f535413f | ||
|
|
85ca80f7ea | ||
|
|
097d10439d | ||
|
|
209d96131d | ||
|
|
4baed7b7b8 | ||
|
|
9f02286018 | ||
|
|
1b7d3b5fe9 | ||
|
|
a6d7aa7da3 | ||
|
|
11fe76f26d | ||
|
|
1b6fdf6093 | ||
|
|
fa3badcfd0 | ||
|
|
ce1b022025 | ||
|
|
6e81548daa | ||
|
|
bb7271ec17 | ||
|
|
f6ca42a4b0 | ||
|
|
bcf5d3a480 | ||
|
|
fffe26ceac | ||
|
|
fd17bdf963 | ||
|
|
a168009382 | ||
|
|
f624f92e4d | ||
|
|
f065171aa1 | ||
|
|
b7532abcc8 | ||
|
|
59aa0308c7 | ||
|
|
6b5708a563 | ||
|
|
c1a4834624 | ||
|
|
35ce3630c6 | ||
|
|
c686912707 | ||
|
|
963964afef | ||
|
|
53666dd289 | ||
|
|
d8d292348e | ||
|
|
678726859c | ||
|
|
bedafceac3 | ||
|
|
a3635bc45f | ||
|
|
8cc8394676 | ||
|
|
e5124093ff | ||
|
|
6d1d5d6bf8 | ||
|
|
8964b45558 | ||
|
|
eb0e9e7d1a | ||
|
|
17254ee863 | ||
|
|
85fdfdd81f | ||
|
|
3d194cd8cc | ||
|
|
3cc591fd8b | ||
|
|
3bb43745b8 | ||
|
|
beb12b6804 | ||
|
|
9a9cb2f8fe | ||
|
|
6b7fed814c | ||
|
|
47e26d93c0 | ||
|
|
de51c46fd8 | ||
|
|
d342bdaf72 | ||
|
|
7ee0150e2b | ||
|
|
cd5b0e7e58 | ||
|
|
aebda4aced | ||
|
|
26b7e6aabf | ||
|
|
9b16859c33 | ||
|
|
d662bf6064 | ||
|
|
a695a27b9c | ||
|
|
e46077f576 | ||
|
|
6ec3b05ce5 | ||
|
|
f9d561993a | ||
|
|
c0b59234d0 | ||
|
|
f041509f15 | ||
|
|
06b4300d09 | ||
|
|
7bf2194a08 | ||
|
|
b6bdf37a1d | ||
|
|
4060436099 | ||
|
|
406b6098c5 | ||
|
|
a5606098aa | ||
|
|
ff9bab4b4e | ||
|
|
6e881293ff | ||
|
|
5fac82cfee | ||
|
|
83da420cfc | ||
|
|
b2abccd302 | ||
|
|
99d9e8cd67 | ||
|
|
9fe275141f | ||
|
|
8c833101d8 | ||
|
|
0c6f9faaf1 | ||
|
|
a93ff5bf1f | ||
|
|
d258c1b417 | ||
|
|
6e473a75bd | ||
|
|
433de267a6 | ||
|
|
2beca32c36 | ||
|
|
15aaddb4d3 | ||
|
|
35ddb777b4 | ||
|
|
b15a0a2d4b | ||
|
|
95bda63c40 | ||
|
|
62b24fcd2a | ||
|
|
df0406902e | ||
|
|
71d57274e5 | ||
|
|
08c6258459 | ||
|
|
9a4e950480 | ||
|
|
e2dcdba5a7 | ||
|
|
c39cf848de | ||
|
|
5ccf2254eb | ||
|
|
dd291b9b71 | ||
|
|
0515fbb2d6 | ||
|
|
6692276472 | ||
|
|
81c09a9c9c | ||
|
|
6a0a367ec3 | ||
|
|
bdf533d62b | ||
|
|
1aba0bc26c | ||
|
|
aac6e9a365 | ||
|
|
9da732d96c | ||
|
|
328ba43ed2 | ||
|
|
62d3253b02 | ||
|
|
e5ba01e707 | ||
|
|
82c25f7f8c | ||
|
|
8791866ea0 | ||
|
|
8f10b8fece | ||
|
|
0d28d210d4 | ||
|
|
2368a5a050 | ||
|
|
74a9b1b41d | ||
|
|
672c49e8eb | ||
|
|
225db32636 | ||
|
|
01541e4a50 | ||
|
|
357e260b45 | ||
|
|
a2513b1851 | ||
|
|
bbe8604054 | ||
|
|
58a33de7f7 |
@@ -0,0 +1,9 @@
|
||||
*.o
|
||||
*.py[co]
|
||||
*.class
|
||||
*.jar
|
||||
|
||||
/uwsgi
|
||||
/uwsgibuild.*
|
||||
|
||||
/t/ring/target
|
||||
@@ -50,3 +50,9 @@ ede5c664978bb40e476e8d4a5789562928f28507 1.1-rc3
|
||||
ef99144291f06822d026e981d5d856cbec14d867 1.1-rc4
|
||||
e1568fd16b7b586cc72deb4dfccbbe64ae0b84df 1.1
|
||||
24c8fe5a26e557db41cf1cee45b8964d5885e484 1.2-rc1
|
||||
29de0fb320bc0a1ce84972f9f249360e315d3c10 1.2-rc2
|
||||
c3cdecbf2bac591336baddd14f9ac22e18d6e200 1.2
|
||||
14524da00a8b382dffb1d16a0e70cdf4a946f369 1.3-rc2
|
||||
883b946db9038372cb1d76cb1d328a3093140e7b 1.3-rc3
|
||||
aeea5a5d2e8b62ad55e23d539e1be02f2b6962af 1.3-rc4
|
||||
620e0cb6ccdb0ce27561b4240cb3a0ef4c3527fd 1.3
|
||||
|
||||
+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
|
||||
|
||||
@@ -18,3 +18,7 @@ Lukas Lalinsky
|
||||
Steven Fernandez
|
||||
Łukasz Mierzwa
|
||||
Roy Marples
|
||||
Aarni Koskela
|
||||
C Anthony Risinger
|
||||
Stephen Pierce
|
||||
Mingli Yuan
|
||||
|
||||
@@ -1,596 +0,0 @@
|
||||
*** march 2012 ***
|
||||
|
||||
* 1.1 [20120317]
|
||||
|
||||
- new options parser subsystem
|
||||
- improved php support
|
||||
- multiple spooler with multiprocessing
|
||||
- segmentation fault and floating point exceptions manager
|
||||
- never-swap option
|
||||
- zergpool plugin
|
||||
- perl/psgi multiple interpreters support
|
||||
- deadlock detector
|
||||
- pluggable cheaper algos
|
||||
- new internal routing susbsystem
|
||||
- preliminary support for config logic
|
||||
- log rotation infrastructure
|
||||
- support for paste loggers
|
||||
- threading improvements
|
||||
- plugins can now mapped to specific modifiers
|
||||
- <app> tag is deprecated (use mount option)
|
||||
- report startup time for apps
|
||||
- reintroduced expat support
|
||||
- reintroduced remote spooler plugin
|
||||
- various fastrouter optimizations
|
||||
- added ruby rvm support
|
||||
|
||||
|
||||
*** december 2011 ***
|
||||
|
||||
* 1.0 [20111230]
|
||||
|
||||
- adaptive process spawning (--cheaper option)
|
||||
- new control options --stop, --reload, --suspend, --resume, --pause
|
||||
- stats framework
|
||||
- new subscription system
|
||||
- support for mime types in static file serving
|
||||
- posix capablities support
|
||||
- uWSGI mules and farms
|
||||
- support for multiple --touch-reload options
|
||||
- new logging subsystem
|
||||
- new custom locking subsystem
|
||||
- process name handling
|
||||
- better (and faster) HTTP parser
|
||||
- perl and python threading improvements
|
||||
- new plugins: rrdtool, carbon, cgi, php
|
||||
- various improvements in the Rack/ruby plugin
|
||||
- Linux KSM support
|
||||
- refactored ping and nagios plugins
|
||||
- support for signals in lazy mode
|
||||
- optimized static-file serving
|
||||
- support for linux unshare()
|
||||
|
||||
*** august 2011 ***
|
||||
|
||||
* 0.9.9 [20110829]
|
||||
|
||||
- various spooler improvements
|
||||
- upload progress optimizations and fixes
|
||||
- new emperor mode: Tyrant
|
||||
- allows multiple --ini options
|
||||
- better binary path detection
|
||||
- gevent loop engine support
|
||||
- resolve domain names in socket logging
|
||||
- snmp fixes and reintroduction of the snmp-api
|
||||
- fixed grunt mode
|
||||
- you can specify build profile via env var UWSGI_PROFILE
|
||||
- reintroduction of string-based multiapp
|
||||
- new option --emperor-throttle
|
||||
- improved queue and sharedarea subsystems
|
||||
- uWSGI can now be built as a shared library
|
||||
- new api attribute: uwsgi.magic_table
|
||||
- improved apache2 module
|
||||
- new option --pyshell
|
||||
- allow threads in gateways
|
||||
- fastrouter improvements
|
||||
- the application list is now shared and exported to the api
|
||||
- allows setting the thread stack size
|
||||
- UWSGI_APPID for better multiapp hosting
|
||||
- better reloading in lazy mode
|
||||
- native pump support
|
||||
- various rack fixes
|
||||
- support for attaching binary data in the executable
|
||||
- new option --set
|
||||
- extreme-optimized http protocol parser
|
||||
- WSGI handler optimizations
|
||||
|
||||
*** july 2011 ***
|
||||
|
||||
* 0.9.8.3 [20110723]
|
||||
|
||||
- implemented uwsgi.SymZipImporter to load embedded zip files
|
||||
- OSX Lion is officially supported
|
||||
- fixed xinetd support (example file added in contrib)
|
||||
- suppot for systemd socket activation
|
||||
- added --freebind option (Linux only)
|
||||
|
||||
* 0.9.8.2 [20110719]
|
||||
|
||||
- fixed an ini and yaml parsing bug spotted by Raffaele Colace
|
||||
- spooler has been extremely improved
|
||||
- new option --chown-socket
|
||||
- added uwsgidecorators for elegant uwsgi api access from python
|
||||
- the rack plugin is now stable
|
||||
- support for embedding config and generic files in the server binary
|
||||
- high-performance cache-server
|
||||
- accept() is now locked on all threads in the same workers
|
||||
- preliminary implementation of hooks in emperor
|
||||
- support for C++ in server core
|
||||
- tcp port auto-bind
|
||||
- implemented workers, workerN and spooler signal target
|
||||
- prefork/multithread uwsgi.signal_wait() implementation
|
||||
- export uwsgi.node in WSGI vars
|
||||
- new option --import (python plugin)
|
||||
- support for unlimited number of Linux cgroups
|
||||
- broodlord mode
|
||||
|
||||
*** june 2011 ***
|
||||
|
||||
* 0.9.8.1 [20110625]
|
||||
|
||||
- the build system has been improved
|
||||
- various threading fixes
|
||||
- fix python GIL status after reload
|
||||
- new option --propagate-touch
|
||||
- fixed uwsgi.sendfile
|
||||
- fixed readline() support in wsgi.input
|
||||
- fixed dynamic touch reload
|
||||
- new option --logto2
|
||||
- export %c in config files
|
||||
- fixed libyaml support
|
||||
- support passing modifiers in subscription system
|
||||
- reset random seed in spooler
|
||||
- subscribe from a list in a text file
|
||||
- allow binding on port 0 (auto-assignment)
|
||||
- reset random seed on grunt
|
||||
- fix vhost mode for empty hostname
|
||||
- fixed python3+virtualenv support
|
||||
- tasks are now allowed to chdir() in spooler
|
||||
- better zeromq+clustering support
|
||||
- clustering has been refactored
|
||||
- fixed rpc
|
||||
- report correct worker id in cheap mode
|
||||
- fixed a fd-leak in attach-daemon
|
||||
- use setsid() in attach-daemon
|
||||
- zerg mode
|
||||
- added psgix.harakiri
|
||||
- allows magic vars in sqlite3 config db
|
||||
- added UWSGI_FASTROUTER_KEY var
|
||||
- slowdown async-queue-is-full messages
|
||||
- new option --cron
|
||||
- --vassals-start-hook and --vassals-stop-hook
|
||||
- the proxy plugin has been removed
|
||||
|
||||
* 0.9.8 [20110605]
|
||||
|
||||
- support for --callable in virtualhosting mode
|
||||
- a NetBSD fix
|
||||
- abstract unix socket can be prefixed with \0 (nginx-style)
|
||||
- add /lib to the linker in sun-like systems
|
||||
- a mercy mode of 5 seconds is enabled by default on SIGINT/SIGQUIT
|
||||
|
||||
* 0.9.8-rc4 [20110602]
|
||||
|
||||
- fixed REMOTE_ADDR when --protocol=http
|
||||
- official support for OpenIndiana
|
||||
- added a welcome.py test script
|
||||
- new api attribute uwsgi.version_info
|
||||
- improved the admin plugin
|
||||
- two new management flag for backlog queue monitoring
|
||||
- fixed uwsgi_log for bigger loglines
|
||||
- new option --early-emperor to allows out-of-jail emperors
|
||||
- emperor can now spawn other emperors (sub-emperors)
|
||||
- fixed idle mode in single-process
|
||||
- fixed solaris iovec
|
||||
|
||||
*** may 2011 ***
|
||||
|
||||
* 0.9.8-rc3 [20110530]
|
||||
|
||||
- snapshotting support
|
||||
- fixed python 3.x spooler
|
||||
- improvements for grunt processes
|
||||
- better abstract unix socket
|
||||
- --log-socket allows logging to generic DGRAM sockets
|
||||
- a bunch of solaris fixes
|
||||
- new option --no-fd-passing for fastrouter
|
||||
- --fastrouter-subscription-slot to set the number of slot in subscription server
|
||||
- unlimited shared sockets
|
||||
- fixed netlink compilation
|
||||
- auto-reconnect on emperor+amqp server disconnection
|
||||
- various emperor fixes
|
||||
- unlimited fastrouter sockets
|
||||
- better cgroup support
|
||||
- --add-header option allow adding of custom HTTP response headers
|
||||
- cheap and idle operational modes
|
||||
|
||||
|
||||
* 0.9.8-rc2 [20110521]
|
||||
|
||||
- new option --die-on-term
|
||||
- fixed touch reload
|
||||
- a couple of optimizations for wsgi.input
|
||||
- systemd integration
|
||||
|
||||
* 0.9.8-rc1 [20110514]
|
||||
|
||||
- massive code cleanup and refactoring
|
||||
- added vassals loyalty concept
|
||||
- fixed virtualhosting with dynamic virtualenv
|
||||
- fixed reloading on grand-central-dispatch-enabled OSX
|
||||
- improved PSGI support with uGreen and async support
|
||||
- improved Rack support with complete fiber+async in ruby 1.9
|
||||
- support for JSON config files
|
||||
- native multi-protocol support (added fastcgi and http)
|
||||
- Mongrel2 support
|
||||
- support for templates in vassals
|
||||
- various threading fixes
|
||||
- gcc-4.6 support
|
||||
- support for logging via zeromq
|
||||
- support for configuration passed via pipe/stdin
|
||||
- pythonpath entries are now unlimited
|
||||
- socket entries are unlimited
|
||||
- pythonpath can be a glob
|
||||
- lazy mode added
|
||||
- new language-independent profiling subsystem
|
||||
- support for configuration stored in a sqlite3 db
|
||||
- allow workers to survive to syslogd death (when --log-syslog is used)
|
||||
- fix traceback in Python 3.x
|
||||
- support for uwsgi signals in threads
|
||||
- plugin autoloading
|
||||
- graceful reloading for threads
|
||||
- new wsgi.input object
|
||||
- support for alternative allocators (tcmalloc and jemalloc)
|
||||
|
||||
|
||||
*** april 2011 ***
|
||||
|
||||
* 0.9.7.2 [20110406]
|
||||
|
||||
- new option --touch-reload <file> to reload the stack on <file> modification
|
||||
--static-map <mountpoint=documentroot> allows to serve static files
|
||||
- fixed --post-limit management
|
||||
- disallow empty socket names
|
||||
- implemented exception_info WSGI support
|
||||
- new options --reload-on-as <n> and --reload-on-rss <n> allows
|
||||
to recycle workers when their memory usage is higher than <n> MB
|
||||
- fixed syslog support (use --log-syslog[=facility] to enable it)
|
||||
- improved plugin loading system
|
||||
- added support for RabbitMQ as event dispatcher for the Emperor
|
||||
- fixed FreeBSD memory report
|
||||
- PSGI plugin can be compiled without ithreads
|
||||
- various Emperor fixes
|
||||
- fixed a regression with setgroups()
|
||||
- support for shared sockets (used in jails within network namespaces)
|
||||
|
||||
*** march 2011 ***
|
||||
|
||||
* 0.9.7.1 [20110326]
|
||||
|
||||
- fixed python stackless support
|
||||
- added persistence for queue
|
||||
- forbid daemonizing in vassal mode
|
||||
- modifier1 30 is available again
|
||||
- allow python modules to be mapped/aliased via http
|
||||
- added --pidfile2 and --logfile-chown
|
||||
- added UWSGI_CACHE_GET dynamic variable
|
||||
- 304/If-Modified-Since support for --check-static
|
||||
- option --check-cache for integrated caching
|
||||
- option --map-socket to assign specific workers to socket
|
||||
- fixed unix fd passing on older OSX versions
|
||||
- fixed post-buffering without pep3333-input
|
||||
- fixed python threading without uwsgi cores
|
||||
- support for Linux network namespace
|
||||
- build with sys.abiflags if necessary
|
||||
|
||||
|
||||
* 0.9.7 [20110317]
|
||||
|
||||
- fixed psgi compilation on GNU systems
|
||||
- improved --pep3333-input
|
||||
- better error reporting on failed open/fopen
|
||||
- fixed uGreen
|
||||
- added greenlet support
|
||||
- various solaris fixes
|
||||
- new help system
|
||||
- updated async support
|
||||
- fixed uwsgi.cache_get in python
|
||||
|
||||
* 0.9.7-rc3 [20110312]
|
||||
|
||||
- added support for persistent cache (--cache-store <filename>)
|
||||
- less verbose file monitoring
|
||||
- fixed a race condition in emperor startup
|
||||
- fixed erlang empty list encoding
|
||||
- improved snmp support
|
||||
- fixed cache modifier 111 for 3 and 4
|
||||
- preliminary cpu-affinity support (Linux only)
|
||||
- fixed ldap support
|
||||
- auto-configure ldap compilation
|
||||
- added --allowed-modifiers (allow only a subset of modifiers)
|
||||
- fixed a bug with getopt_long
|
||||
|
||||
* 0.9.7-rc2 [20110309]
|
||||
|
||||
- added cron-like interface to signal framework
|
||||
- improved Linux namespaces support
|
||||
- fixed multithreading + --max-requests
|
||||
- added support for reference in configuration files
|
||||
|
||||
* 0.9.7-rc1 [20110307]
|
||||
|
||||
- export %v in emperor mode
|
||||
- fixed signal race condition in server reload
|
||||
- fixed http router post handling bug
|
||||
- added uwsgi.erlang_register_process in pyerl plugin
|
||||
- fixed unix socket inherit
|
||||
- fixed linux namespace support in recent kernel/gcc
|
||||
- ported threading to python 3.2
|
||||
- add build date to uWSGI startup info
|
||||
- do not allow clustering without defining a socket
|
||||
- kill all the gateways/daemons on startup errors
|
||||
- fixed vacuum after chdir()
|
||||
- fixed gateways reload
|
||||
- re-added support for OpenBSD and NetBSD
|
||||
- fixed post-buffering in python
|
||||
- use erlang binary for python string
|
||||
- fixed memory leak in pyerl plugin
|
||||
- removed broken log rotation (post-poned)
|
||||
- fixed no_argument options in ini and yaml parsing
|
||||
|
||||
* 0.9.7-beta1 [20110301]
|
||||
|
||||
- fully modular re-design
|
||||
- advanced build system with presets
|
||||
- threading support
|
||||
- emperor mode for massive auto-hosting
|
||||
- caching subsystem
|
||||
- message queue (even stacked) support
|
||||
- improved server reloading system
|
||||
- support for Linux Cgroups and Namespaces
|
||||
- integrated upload progress
|
||||
- Clustering infrastructure via multicast, broadcast or subscriptions
|
||||
- support for attaching/monitoring external apps to the master process
|
||||
- improved virtualhosting mode
|
||||
- extremely improved Python support with better usage of multiple interpreters
|
||||
- improved multiple apps support
|
||||
- Production ready, evented HTTP router/proxy/load-balancer
|
||||
- Production ready, evented uwsgi router/proxy/load-balancer
|
||||
- new Erlang stack
|
||||
- Internal signal subsystem
|
||||
- support for RubyOnRails and Rack apps
|
||||
- A huge series of fixes and optimizations
|
||||
|
||||
*** february 2011 ***
|
||||
|
||||
* 0.9.6.8 [20110207]
|
||||
|
||||
- fixed a bug when using --limit-as
|
||||
- fixed a erlang buffer initialization
|
||||
- added --ignore-sigpipe
|
||||
- added --master-as-root
|
||||
|
||||
*** january 2011 ***
|
||||
|
||||
* 0.9.6.7 [20110130]
|
||||
|
||||
- a huge amount of async optimizations and fixes
|
||||
- --logdate takes an optional strftime-like value
|
||||
- follow $PATH on reloading
|
||||
- uwsgi.core is exported in WSGI env
|
||||
- uwsgi.log() respect for --logdate
|
||||
- initial banner respect for --logdate
|
||||
- fixed --post-buffering
|
||||
- default listen backlog queue is now 100
|
||||
- Python 3 support is no more marked as experimental
|
||||
- Python 3.2 support
|
||||
- new option --chroot-reload will force a reload of the uWSGI stack after a chroot
|
||||
- fixed a typo in INI parsing
|
||||
|
||||
*** december 2010 ***
|
||||
|
||||
* 0.9.6.6 [20101230]
|
||||
|
||||
- support for YAML configuration files
|
||||
- backported python module aliasing from 0.9.7-dev
|
||||
- better apache2 module (support for SetEnv directive, fixed REQUEST_URI and improved connection handling)
|
||||
- uwsgi.post_fork_hook implementation (to execute function after fork()) (thanks George Kollias)
|
||||
- option --gid calls setgroups() after setgid() (thanks Jorge Cardona)
|
||||
- fixed uGreen compilation (and uGreen is now built by default)
|
||||
- fixed timeout and thundering herd problem in async modes (many thanks to Test157 for giving us a good async-test-app)
|
||||
- disable TCP_INFO in older Linux kernels (thanks Bo Shi)
|
||||
- enable TCP_INFO in FreeBSD (limited usage due to FreeBSD kernel support)
|
||||
- fixed static virtualhosting mode using xml files (thanks Guido Notari of Link I.T. spa)
|
||||
- new option --close-on-exec (thanks Jean-Baptiste Quenot)
|
||||
- use HTTP_HOST var (and fallback to SERVER_NAME) in virtual hosting mode
|
||||
- fixed a buffer overflow in automatic socket_name allocation (spotted by Riccardo Magliocchetti)
|
||||
- Official support for Nexenta
|
||||
|
||||
|
||||
*** september 2010 ***
|
||||
|
||||
* 0.9.6.5 [20100929]
|
||||
|
||||
- PEP 3333 support
|
||||
- fix --pythonpath with --wsgi-file
|
||||
- x-wsgiorg.uwsgi.version renamed to uwsgi.version
|
||||
|
||||
* 0.9.6.4 [20100925]
|
||||
|
||||
- fix a stupid bug in conditional logging backport
|
||||
|
||||
* 0.9.6.3 [20100925]
|
||||
|
||||
- fix a buffer overflow in .ini parsing (it throws a glibc error on malloc)
|
||||
- backport of conditional logging from 0.9.7-dev
|
||||
- backport of backlog queue monitor from 0.9.7-dev (only Linux)
|
||||
|
||||
* 0.9.6.2 [20100915]
|
||||
|
||||
- fix a regression in virtual hosting mode
|
||||
- fix pythonpath usage in --ini and --ini-paste
|
||||
- new uwsgi packet var: UWSGI_CHDIR
|
||||
|
||||
* 0.9.6.1 [20100912]
|
||||
|
||||
- print the request uri during SIGPIPE or HARAKIRI
|
||||
- added SIGUSR2 support (it will print the current running request, if available)
|
||||
- protocol parsing optimization
|
||||
- fixed --logto support
|
||||
- new --eval option allows inline definition of WSGI script
|
||||
- support for defining WSGI script in xml using CDATA
|
||||
- allow --pp as --pythonpath shortcut
|
||||
- various spooler optimizations and fixes
|
||||
- added -O2 optimization by default
|
||||
- added uwsgi.is_a_reload commodity function
|
||||
- .ini file support fix
|
||||
- SNMP agent fix
|
||||
- support for subprocesses generated by master
|
||||
- fix a regression in SCRIPT_NAME handling
|
||||
- Haiku official support
|
||||
- gcc 2.95 support
|
||||
- dynamic app management optimizations
|
||||
- export x-wsgiorg.uwsgi.version in WSGI env
|
||||
|
||||
*** august 2010 ***
|
||||
|
||||
* 0.9.6 [20100829]
|
||||
|
||||
- better handling of SCRIPT_NAME
|
||||
- vacuum option for deleting unix sockets and pidfiles after usage
|
||||
- advanced XML configuration
|
||||
- new configuration systems: INI files and LDAP
|
||||
- embedded HTTP server for development/testing
|
||||
- better signal handling
|
||||
- PSGI plugin improved
|
||||
- usability fixes and new commodities options for root startup
|
||||
- grunt processes (detached workers)
|
||||
- preliminary integrated virtualhosting mode
|
||||
- new option catch-exceptions can redirect python exceptions to your browser
|
||||
- logging improvements (--logto and --logdate options)
|
||||
- Full PEP 333 compliant usage of wsgi.file_wrapper
|
||||
- re-initialize random seed after every fork() [security fix]
|
||||
- fix Spooler's usage of stdin
|
||||
- export WSGI environment in uwsgi.env (for doing evil things)
|
||||
- logsize tracking (uwsgi.logsize) for future embedded log rotation
|
||||
|
||||
*** july 2010 ***
|
||||
|
||||
* 0.9.5.4 [20100706]
|
||||
|
||||
*** june 2010 ***
|
||||
|
||||
* 0.9.5.3 [20100628]
|
||||
|
||||
- fixed linux x86_64 compilation (sorry)
|
||||
|
||||
* 0.9.5.2 [20100626] *
|
||||
|
||||
- fixed a request parsing bug
|
||||
- applied debian fixes
|
||||
- fixed multiple interpreter sys.argv
|
||||
- improved --chmod-socket
|
||||
- fixed uid 0 SIGHUP
|
||||
- updated nginx and apache modules
|
||||
- updated PSGI, lua and example plugin
|
||||
- fixed --pyargv with python 3.x
|
||||
- improved plugin build system
|
||||
|
||||
*** may 2010 ***
|
||||
|
||||
* 0.9.5.1 [20100519] *
|
||||
|
||||
- fixed paste support
|
||||
- added a new modifier (22)
|
||||
- full support for configuration via environment variables
|
||||
- nginx_string option in nginx module
|
||||
- fix for harakiri without master
|
||||
- backported unladen swallow support for 0.9.6-dev
|
||||
- fixed address space limit detection via getrlimit()
|
||||
- http body buffering implementation
|
||||
- added --prio option (to set priority)
|
||||
- added --post-limit to limit the size of uploads
|
||||
- added --logto option to allow udp logging without daemonizing
|
||||
- applied Gentoo's packagers fixes for build system
|
||||
|
||||
* 0.9.5 [20100501] *
|
||||
|
||||
- hook based request/modifier management
|
||||
- plugin support via dlopen
|
||||
- on-the-fly management flag
|
||||
- integrated proxy
|
||||
- logging via udp
|
||||
- improved spooler for cron-like apps
|
||||
- async support
|
||||
- green thread platform (uGreen) on top of the async mode
|
||||
- transparent Erlang integration
|
||||
- embedded snmp agent
|
||||
- nagios mode
|
||||
- improved python 3.x support
|
||||
- improved xml configuration
|
||||
- new build system
|
||||
- address space usage limiting
|
||||
- lot of portability fixes
|
||||
- lot of optimizations and code refactoring
|
||||
|
||||
|
||||
*** april 2010 ***
|
||||
|
||||
* Fourth Maintenance release [20100427] *
|
||||
|
||||
- backported non-yielding app optimization from 0.9.5
|
||||
- backported udp logging from 0.9.5
|
||||
- backported uwsgi_error() from 0.9.5 (no more dumb perror())
|
||||
- fix a rare (but possible) segmentation fault
|
||||
- added --version
|
||||
- updated apache2 module
|
||||
|
||||
*** march 2010 ***
|
||||
|
||||
* Third Maintenance release [20100310] *
|
||||
|
||||
- fix sendfile on 64bit
|
||||
- include setup.py
|
||||
|
||||
*** february 2010 ***
|
||||
* Maintenance release *
|
||||
|
||||
- better support for NetBSD
|
||||
- threading fix for FreeBSD
|
||||
- sendfile portability fixes
|
||||
- new makefiles
|
||||
- example app for testing static file serving
|
||||
- fixes for ROCK_SOLID mode
|
||||
|
||||
*** january 2010 ***
|
||||
|
||||
- Integrated Spooler
|
||||
- better error management
|
||||
- long options
|
||||
- clustering functions
|
||||
- experimental lighttpd module
|
||||
- official support for OpenBSD and OpenSolaris
|
||||
- FastFuncs
|
||||
- new functions for embedded module
|
||||
- reliable harakiri
|
||||
- better Makefiles
|
||||
- python threads support in master process
|
||||
- proper timeout handling in apache2 module
|
||||
- endianess fixes all over the place
|
||||
- paste support
|
||||
- Django app for managing and monitoring the uWSGI server
|
||||
- options for changin uid/gid and chrooting when run by root
|
||||
- lot of bugfixes and optimizations
|
||||
|
||||
*** 20091129 Version 0.9.3 ***
|
||||
|
||||
- Nginx 0.7.x module
|
||||
- configuration via python module
|
||||
- support (non-standard) for Python 3.x
|
||||
- Twisted client resource adapter
|
||||
- graceful restart of worker processes and hot-plug substitution/upgrade of the uWSGI server
|
||||
- shared memory area to share data between workers/processes
|
||||
- Tomcat handler
|
||||
- support for virtualenv
|
||||
- tons of bugfixes and optimizations
|
||||
|
||||
*** 20090829 Version 0.9.2 ***
|
||||
|
||||
- TCP support
|
||||
- configurable internal timeout (socket/poll)
|
||||
- Cherokee handler
|
||||
- code refactoring
|
||||
- Makefiles
|
||||
- customizable harakiri handler (put an harakiri(environ, start_response) function in your wsgi script)
|
||||
- limit requests per worker
|
||||
- a lot of bugfix and optimizations
|
||||
@@ -3,3 +3,6 @@ all:
|
||||
|
||||
clean:
|
||||
python uwsgiconfig.py --clean
|
||||
|
||||
check:
|
||||
python uwsgiconfig.py --check
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -0,0 +1,464 @@
|
||||
/*
|
||||
|
||||
*** 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"
|
||||
#include "apr_hooks.h"
|
||||
#include "apr_optional_hooks.h"
|
||||
#include "apr_buckets.h"
|
||||
|
||||
#include "httpd.h"
|
||||
#include "http_config.h"
|
||||
#include "http_log.h"
|
||||
#include "http_protocol.h"
|
||||
#include "http_request.h"
|
||||
#include "util_script.h"
|
||||
|
||||
#include "mod_proxy.h"
|
||||
|
||||
|
||||
#define UWSGI_SCHEME "uwsgi"
|
||||
#define UWSGI_DEFAULT_PORT 3031
|
||||
|
||||
module AP_MODULE_DECLARE_DATA proxy_uwsgi_module;
|
||||
|
||||
|
||||
static int uwsgi_canon(request_rec *r, char *url)
|
||||
{
|
||||
char *host, sport[sizeof(":65535")];
|
||||
const char *err, *path;
|
||||
apr_port_t port = UWSGI_DEFAULT_PORT;
|
||||
|
||||
if (strncasecmp(url, UWSGI_SCHEME "://", sizeof(UWSGI_SCHEME) + 2)) {
|
||||
return DECLINED;
|
||||
}
|
||||
url += sizeof(UWSGI_SCHEME); /* Keep slashes */
|
||||
|
||||
err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
|
||||
if (err) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
"error parsing URL %s: %s", url, err);
|
||||
return HTTP_BAD_REQUEST;
|
||||
}
|
||||
|
||||
apr_snprintf(sport, sizeof(sport), ":%u", port);
|
||||
|
||||
if (ap_strchr(host, ':')) { /* if literal IPv6 address */
|
||||
host = apr_pstrcat(r->pool, "[", host, "]", NULL);
|
||||
}
|
||||
|
||||
path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
|
||||
r->proxyreq);
|
||||
if (!path) {
|
||||
return HTTP_BAD_REQUEST;
|
||||
}
|
||||
|
||||
r->filename = apr_pstrcat(r->pool, "proxy:" UWSGI_SCHEME "://", host, sport, "/",
|
||||
path, NULL);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_send(proxy_conn_rec *conn, const char *buf, apr_size_t length,
|
||||
request_rec *r)
|
||||
{
|
||||
apr_status_t rv;
|
||||
apr_size_t written;
|
||||
|
||||
while (length > 0) {
|
||||
written = length;
|
||||
if ((rv = apr_socket_send(conn->sock, buf, &written)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
|
||||
"sending data to %s:%u failed",
|
||||
conn->hostname, conn->port);
|
||||
return HTTP_SERVICE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
/* count for stats */
|
||||
conn->worker->s->transferred += written;
|
||||
buf += written;
|
||||
length -= written;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Send uwsgi header block
|
||||
*/
|
||||
static int uwsgi_send_headers(request_rec *r, proxy_conn_rec *conn)
|
||||
{
|
||||
char *buf, *ptr;
|
||||
|
||||
const apr_array_header_t *env_table;
|
||||
const apr_table_entry_t *env;
|
||||
|
||||
int j;
|
||||
|
||||
apr_size_t headerlen = 4;
|
||||
uint16_t pktsize, keylen, vallen;
|
||||
|
||||
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) {
|
||||
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);
|
||||
env = (apr_table_entry_t *)env_table->elts;
|
||||
|
||||
for (j = 0; j < env_table->nelts; ++j) {
|
||||
headerlen += 2 + strlen(env[j].key) + 2 + strlen(env[j].val) ;
|
||||
}
|
||||
|
||||
ptr = buf = apr_palloc(r->pool, headerlen);
|
||||
|
||||
ptr+=4;
|
||||
|
||||
for (j = 0; j < env_table->nelts; ++j) {
|
||||
keylen = strlen(env[j].key);
|
||||
*ptr++= (uint8_t) (keylen & 0xff);
|
||||
*ptr++= (uint8_t) ((keylen >> 8) & 0xff);
|
||||
memcpy(ptr, env[j].key, keylen) ; ptr+=keylen;
|
||||
|
||||
vallen = strlen(env[j].val);
|
||||
*ptr++= (uint8_t) (vallen & 0xff);
|
||||
*ptr++= (uint8_t) ((vallen >> 8) & 0xff);
|
||||
memcpy(ptr, env[j].val, vallen) ; ptr+=vallen;
|
||||
}
|
||||
|
||||
pktsize = headerlen-4;
|
||||
|
||||
buf[0] = 0;
|
||||
buf[1] = (uint8_t) (pktsize & 0xff);
|
||||
buf[2] = (uint8_t) ((pktsize >> 8) & 0xff);
|
||||
buf[3] = 0;
|
||||
|
||||
return uwsgi_send(conn, buf, headerlen, r);
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_send_body(request_rec *r, proxy_conn_rec *conn)
|
||||
{
|
||||
if (ap_should_client_block(r)) {
|
||||
char *buf = apr_palloc(r->pool, AP_IOBUFSIZE);
|
||||
int status;
|
||||
apr_size_t readlen;
|
||||
|
||||
readlen = ap_get_client_block(r, buf, AP_IOBUFSIZE);
|
||||
while (readlen > 0) {
|
||||
status = uwsgi_send(conn, buf, readlen, r);
|
||||
if (status != OK) {
|
||||
return HTTP_SERVICE_UNAVAILABLE;
|
||||
}
|
||||
readlen = ap_get_client_block(r, buf, AP_IOBUFSIZE);
|
||||
}
|
||||
if (readlen == -1) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
"receiving request body failed");
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
|
||||
static request_rec *ap_proxy_make_fake_req(conn_rec *c, request_rec *r)
|
||||
{
|
||||
apr_pool_t *pool;
|
||||
request_rec *rp;
|
||||
|
||||
apr_pool_create(&pool, c->pool);
|
||||
|
||||
rp = apr_pcalloc(pool, sizeof(*r));
|
||||
|
||||
rp->pool = pool;
|
||||
rp->status = HTTP_OK;
|
||||
|
||||
rp->headers_in = apr_table_make(pool, 50);
|
||||
rp->subprocess_env = apr_table_make(pool, 50);
|
||||
rp->headers_out = apr_table_make(pool, 12);
|
||||
rp->err_headers_out = apr_table_make(pool, 5);
|
||||
rp->notes = apr_table_make(pool, 5);
|
||||
|
||||
rp->server = r->server;
|
||||
rp->log = r->log;
|
||||
rp->proxyreq = r->proxyreq;
|
||||
rp->request_time = r->request_time;
|
||||
rp->connection = c;
|
||||
rp->output_filters = c->output_filters;
|
||||
rp->input_filters = c->input_filters;
|
||||
rp->proto_output_filters = c->output_filters;
|
||||
rp->proto_input_filters = c->input_filters;
|
||||
rp->useragent_ip = c->client_ip;
|
||||
rp->useragent_addr = c->client_addr;
|
||||
|
||||
rp->request_config = ap_create_request_config(pool);
|
||||
proxy_run_create_req(r, rp);
|
||||
|
||||
return rp;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_conf *conf)
|
||||
{
|
||||
|
||||
char buffer[HUGE_STRING_LEN];
|
||||
const char *buf;
|
||||
char *value, *end;
|
||||
int len;
|
||||
apr_status_t rc;
|
||||
conn_rec *c = r->connection;
|
||||
apr_off_t readbytes;
|
||||
apr_status_t rv;
|
||||
apr_bucket *e;
|
||||
apr_read_type_e mode = APR_NONBLOCK_READ;
|
||||
|
||||
request_rec *rp = ap_proxy_make_fake_req(backend->connection, r);
|
||||
rp->proxyreq = PROXYREQ_RESPONSE;
|
||||
|
||||
apr_bucket_brigade *bb = apr_brigade_create(r->pool, c->bucket_alloc);
|
||||
|
||||
len = ap_getline(buffer, sizeof(buffer), rp, 1);
|
||||
|
||||
if (len <= 0) {
|
||||
// oops
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
backend->worker->s->read += len;
|
||||
|
||||
if (!apr_date_checkmask(buffer, "HTTP/#.# ###*") || len >= sizeof(buffer)-1) {
|
||||
// oops
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
char keepchar = buffer[12];
|
||||
buffer[12] = '\0';
|
||||
r->status = atoi(&buffer[9]);
|
||||
|
||||
if (keepchar != '\0') {
|
||||
buffer[12] = keepchar;
|
||||
} else {
|
||||
/* 2616 requires the space in Status-Line; the origin
|
||||
* server may have sent one but ap_rgetline_core will
|
||||
* have stripped it. */
|
||||
buffer[12] = ' ';
|
||||
buffer[13] = '\0';
|
||||
}
|
||||
r->status_line = apr_pstrdup(r->pool, &buffer[9]);
|
||||
|
||||
// start parsing headers;
|
||||
while ((len = ap_getline(buffer, sizeof(buffer), rp, 1)) > 0) {
|
||||
value = strchr(buffer, ':');
|
||||
// invalid header skip
|
||||
if (!value) continue;
|
||||
*value = '\0';
|
||||
++value;
|
||||
while (apr_isspace(*value)) ++value;
|
||||
for (end = &value[strlen(value)-1]; end > value && apr_isspace(*end); --end) *end = '\0';
|
||||
apr_table_add(r->headers_out, buffer, value);
|
||||
}
|
||||
|
||||
|
||||
if ((buf = apr_table_get(r->headers_out, "Content-Type"))) {
|
||||
ap_set_content_type(r, apr_pstrdup(r->pool, buf));
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
rv = ap_get_brigade(rp->input_filters, bb,
|
||||
AP_MODE_READBYTES, mode,
|
||||
conf->io_buffer_size);
|
||||
if (APR_STATUS_IS_EAGAIN(rv)
|
||||
|| (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb))) {
|
||||
e = apr_bucket_flush_create(c->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, e);
|
||||
if (ap_pass_brigade(r->output_filters, bb) || c->aborted) {
|
||||
break;
|
||||
}
|
||||
apr_brigade_cleanup(bb);
|
||||
mode = APR_BLOCK_READ;
|
||||
continue;
|
||||
}
|
||||
else if (rv == APR_EOF) {
|
||||
break;
|
||||
}
|
||||
else if (rv != APR_SUCCESS) {
|
||||
ap_proxy_backend_broke(r, bb);
|
||||
ap_pass_brigade(r->output_filters, bb);
|
||||
}
|
||||
|
||||
mode = APR_NONBLOCK_READ;
|
||||
apr_brigade_length(bb, 0, &readbytes);
|
||||
backend->worker->s->read += readbytes;
|
||||
ap_pass_brigade(r->output_filters, bb);
|
||||
apr_brigade_cleanup(bb);
|
||||
}
|
||||
e = apr_bucket_eos_create(c->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, e);
|
||||
ap_pass_brigade(r->output_filters, bb);
|
||||
|
||||
apr_brigade_cleanup(bb);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int uwsgi_handler(request_rec *r, proxy_worker *worker,
|
||||
proxy_server_conf *conf, char *url,
|
||||
const char *proxyname, apr_port_t proxyport)
|
||||
{
|
||||
int status;
|
||||
proxy_conn_rec *backend = NULL;
|
||||
apr_pool_t *p = r->pool;
|
||||
apr_uri_t *uri = apr_palloc(r->pool, sizeof(*uri));
|
||||
char server_portstr[32];
|
||||
|
||||
if (strncasecmp(url, UWSGI_SCHEME "://", sizeof(UWSGI_SCHEME) + 2)) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
|
||||
"declining URL %s", url);
|
||||
return DECLINED;
|
||||
}
|
||||
|
||||
// ADD PATH_INFO
|
||||
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
|
||||
size_t w_len = strlen(worker->s->name);
|
||||
#else
|
||||
size_t w_len = strlen(worker->name);
|
||||
#endif
|
||||
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 */
|
||||
status = ap_proxy_acquire_connection(UWSGI_SCHEME, &backend, worker,
|
||||
r->server);
|
||||
if (status != OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
backend->is_ssl = 0;
|
||||
|
||||
/* Step One: Determine Who To Connect To */
|
||||
status = ap_proxy_determine_connection(p, r, conf, worker, backend,
|
||||
uri, &url, proxyname, proxyport,
|
||||
server_portstr, sizeof(server_portstr));
|
||||
if (status != OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
/* Step Two: Make the Connection */
|
||||
if (ap_proxy_connect_backend(UWSGI_SCHEME, backend, worker, r->server)) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
"failed to make connection to backend: %s:%u",
|
||||
backend->hostname, backend->port);
|
||||
status = HTTP_SERVICE_UNAVAILABLE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Step Three: Create conn_rec */
|
||||
if (!backend->connection) {
|
||||
if ((status = ap_proxy_connection_create(UWSGI_SCHEME, backend,
|
||||
r->connection, r->server)) != OK)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Step Four: Process the Request */
|
||||
if ( ((status = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) != OK)
|
||||
|| ((status = uwsgi_send_headers(r, backend)) != OK)
|
||||
|| ((status = uwsgi_send_body(r, backend)) != OK)
|
||||
|| ((status = uwsgi_response(r, backend, conf)) != OK)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (backend) {
|
||||
backend->close = 1; /* always close the socket */
|
||||
ap_proxy_release_connection(UWSGI_SCHEME, backend, r->server);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static void register_hooks(apr_pool_t *p)
|
||||
{
|
||||
proxy_hook_scheme_handler(uwsgi_handler, NULL, NULL, APR_HOOK_FIRST);
|
||||
proxy_hook_canon_handler(uwsgi_canon, NULL, NULL, APR_HOOK_FIRST);
|
||||
}
|
||||
|
||||
|
||||
module AP_MODULE_DECLARE_DATA proxy_uwsgi_module = {
|
||||
STANDARD20_MODULE_STUFF,
|
||||
NULL, /* create per-directory config structure */
|
||||
NULL, /* merge per-directory config structures */
|
||||
NULL, /* create per-server config structure */
|
||||
NULL, /* merge per-server config structures */
|
||||
NULL, /* command table */
|
||||
register_hooks /* register hooks */
|
||||
};
|
||||
+18
-3
@@ -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
|
||||
@@ -367,7 +367,7 @@ static int uwsgi_handler(request_rec *r) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "REMOTE_USER", "", &pkt_size) ;
|
||||
}
|
||||
|
||||
if (r->user) {
|
||||
if (ap_auth_type(r) != NULL) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "AUTH_TYPE", (char *) ap_auth_type(r), &pkt_size) ;
|
||||
}
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "DOCUMENT_ROOT", (char *) ap_document_root(r), &pkt_size) ;
|
||||
@@ -517,7 +517,22 @@ static int uwsgi_handler(request_rec *r) {
|
||||
free(uwsgi_vars);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
apr_brigade_write(bb, NULL, NULL, buf, cnt);
|
||||
if (!c->cgi_mode) {
|
||||
b = apr_bucket_transient_create(buf, cnt, r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||
b = apr_bucket_flush_create(r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||
if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS) {
|
||||
close(uwsgi_poll.fd);
|
||||
apr_brigade_destroy(bb);
|
||||
free(uwsgi_vars);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
apr_brigade_cleanup(bb);
|
||||
}
|
||||
else {
|
||||
apr_brigade_write(bb, NULL, NULL, buf, cnt);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// EOF
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env ruby
|
||||
cmd = File.expand_path "#{File.dirname(__FILE__)}/../ext/uwsgi/uwsgi.ruby"
|
||||
|
||||
exec(cmd, *ARGV)
|
||||
@@ -1 +0,0 @@
|
||||
object file for embedded files will be put here
|
||||
@@ -0,0 +1,34 @@
|
||||
[uwsgi]
|
||||
xml = auto
|
||||
yaml = true
|
||||
json = auto
|
||||
sqlite3 = auto
|
||||
zeromq = auto
|
||||
ssl = auto
|
||||
ldap = auto
|
||||
pcre = auto
|
||||
routing = auto
|
||||
debug = false
|
||||
unbit = false
|
||||
xml_implementation = libxml2
|
||||
yaml_implementation = auto
|
||||
malloc_implementation = libc
|
||||
extras =
|
||||
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, router_static, sslrouter
|
||||
as_shared_library = false
|
||||
|
||||
locking = auto
|
||||
event = auto
|
||||
timer = auto
|
||||
filemonitor = auto
|
||||
|
||||
blacklist =
|
||||
whitelist =
|
||||
|
||||
embed_files =
|
||||
|
||||
embed_config =
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = cgi
|
||||
inherit = base
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
main_plugin =
|
||||
inherit = base
|
||||
embedded_plugins = null
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
[uwsgi]
|
||||
# pypy,jvm,ring,jwsgi
|
||||
main_plugin = erlang,psgi,rack,lua,python,gevent,php,cgi,mono,pyerl,go
|
||||
inherit = base
|
||||
+2
-47
@@ -1,48 +1,3 @@
|
||||
[uwsgi]
|
||||
xml = auto
|
||||
ini = true
|
||||
yaml = true
|
||||
json = auto
|
||||
sqlite3 = auto
|
||||
zeromq = auto
|
||||
snmp = true
|
||||
sctp = false
|
||||
spooler = true
|
||||
embedded = true
|
||||
udp = true
|
||||
multicast = true
|
||||
threading = true
|
||||
sendfile = true
|
||||
minterpreters = true
|
||||
async = true
|
||||
ldap = auto
|
||||
pcre = auto
|
||||
routing = auto
|
||||
debug = false
|
||||
unbit = false
|
||||
xml_implementation = libxml2
|
||||
yaml_implementation = auto
|
||||
malloc_implementation = libc
|
||||
extras =
|
||||
plugins =
|
||||
bin_name = uwsgi
|
||||
append_version =
|
||||
plugin_dir = .
|
||||
embedded_plugins = python, ping, cache, nagios, rrdtool, carbon, rpc, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool
|
||||
as_shared_library = false
|
||||
|
||||
locking = auto
|
||||
event = auto
|
||||
timer = auto
|
||||
filemonitor = auto
|
||||
|
||||
blacklist =
|
||||
whitelist =
|
||||
|
||||
embed_files =
|
||||
|
||||
embed_config =
|
||||
|
||||
[python]
|
||||
paste = true
|
||||
web3 = true
|
||||
main_plugin = python,gevent
|
||||
inherit = base
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
main_plugin = python
|
||||
inherit = base
|
||||
embed_files = bootstrap3.py,django.zip,djapp.zip
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
main_plugin = python
|
||||
inherit = base
|
||||
|
||||
embed_files = embedme.py,uwsgidecorators.py
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = +,erlang
|
||||
main_plugin = erlang
|
||||
inherit = base
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = python, ping, cache, nagios, rpc, fastrouter, http, gevent
|
||||
main_plugin = python,gevent
|
||||
inherit = base
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
[uwsgi]
|
||||
main_plugin = go
|
||||
inherit = base
|
||||
bin_name = libuwsgi.so
|
||||
as_shared_library = true
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = gridfs
|
||||
inherit = base
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = jvm,jwsgi
|
||||
inherit = base
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
inherit = base
|
||||
bin_name = libuwsgi.so
|
||||
embedded_plugins = null
|
||||
as_shared_library = true
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = lua
|
||||
main_plugin = lua
|
||||
inherit = base
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
main_plugin =
|
||||
inherit = base
|
||||
plugins = lua
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
inherit = base
|
||||
plugins = python, ping, rack, psgi, cache, http, fastrouter
|
||||
plugin_dir = plugins
|
||||
embedded_plugins = null
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = mono
|
||||
inherit = base
|
||||
@@ -1,4 +1,4 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
inherit = base
|
||||
plugin_dir = /usr/lib/uwsgi
|
||||
embedded_plugins = null
|
||||
embedded_plugins =
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = php
|
||||
inherit = base
|
||||
@@ -0,0 +1,34 @@
|
||||
[uwsgi]
|
||||
xml = true
|
||||
yaml = true
|
||||
json = true
|
||||
sqlite3 = true
|
||||
zeromq = true
|
||||
ssl = true
|
||||
ldap = true
|
||||
pcre = true
|
||||
routing = true
|
||||
debug = false
|
||||
unbit = false
|
||||
xml_implementation = libxml2
|
||||
yaml_implementation = libyaml
|
||||
malloc_implementation = libc
|
||||
extras =
|
||||
plugins =
|
||||
bin_name = /usr/lib/libuwsgi.so
|
||||
append_version = ubuntu
|
||||
plugin_dir = /usr/lib/uwsgi
|
||||
embedded_plugins =
|
||||
as_shared_library = true
|
||||
|
||||
locking = auto
|
||||
event = auto
|
||||
timer = auto
|
||||
filemonitor = auto
|
||||
|
||||
blacklist =
|
||||
whitelist =
|
||||
|
||||
embed_files =
|
||||
|
||||
embed_config =
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = psgi
|
||||
main_plugin = psgi
|
||||
inherit = base
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = +,erlang,pyerl
|
||||
main_plugin = python,erlang,pyerl
|
||||
inherit = base
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = +,lua
|
||||
main_plugin = python,lua
|
||||
inherit = base
|
||||
|
||||
+2
-4
@@ -1,5 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
bin_name = libuwsgi.so
|
||||
embedded_plugins = symcall
|
||||
as_shared_library = true
|
||||
main_plugin = pypy
|
||||
inherit = base
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
[uwsgi]
|
||||
xml = true
|
||||
ini = true
|
||||
snmp = true
|
||||
sctp = false
|
||||
erlang = false
|
||||
spooler = true
|
||||
embedded = true
|
||||
udp = true
|
||||
multicast = true
|
||||
threading = true
|
||||
sendfile = true
|
||||
proxy = true
|
||||
minterpreters = true
|
||||
async = true
|
||||
http = true
|
||||
evdis = false
|
||||
ldap = false
|
||||
routing = false
|
||||
stackless = false
|
||||
debug = false
|
||||
unbit = false
|
||||
xml_implementation = libxml2
|
||||
plugins =
|
||||
bin_name = uwsgi
|
||||
plugin_dir = .
|
||||
embedded_plugins = python, ping, nagios, rack
|
||||
|
||||
[python]
|
||||
paste = true
|
||||
web3 = true
|
||||
@@ -0,0 +1,6 @@
|
||||
[uwsgi]
|
||||
main_plugin = python,gevent
|
||||
inherit = base
|
||||
plugins = jvm,ring
|
||||
plugin_dir = .
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
main_plugin = pyuwsgi
|
||||
inherit = base
|
||||
bin_name = pyuwsgi.so
|
||||
embedded_plugins = pyuwsgi,python,ping,cache,nagios,rpc,ugreen
|
||||
as_shared_library = true
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = rack, ping, cache, nagios, rpc, fastrouter, http, ugreen
|
||||
main_plugin = rack
|
||||
inherit = base
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
[uwsgi]
|
||||
xml = true
|
||||
ini = true
|
||||
yaml = true
|
||||
snmp = true
|
||||
sctp = false
|
||||
erlang = false
|
||||
spooler = false
|
||||
embedded = false
|
||||
udp = true
|
||||
multicast = false
|
||||
threading = true
|
||||
sendfile = true
|
||||
nagios = true
|
||||
proxy = true
|
||||
minterpreters = true
|
||||
async = true
|
||||
ugreen = false
|
||||
http = true
|
||||
evdis = false
|
||||
ldap = false
|
||||
routing = false
|
||||
stackless = false
|
||||
debug = false
|
||||
unbit = false
|
||||
xml_implementation = libxml2
|
||||
plugins = rack
|
||||
bin_name = uwsgi
|
||||
plugin_dir = .
|
||||
embedded_plugins =
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = jvm,ring
|
||||
inherit = base
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin =
|
||||
inherit = base
|
||||
+13
-14
@@ -1,21 +1,11 @@
|
||||
[uwsgi]
|
||||
xml = true
|
||||
ini = true
|
||||
yaml = true
|
||||
json = false
|
||||
sqlite3 = false
|
||||
zeromq = false
|
||||
snmp = false
|
||||
sctp = false
|
||||
spooler = true
|
||||
embedded = true
|
||||
udp = true
|
||||
multicast = false
|
||||
threading = true
|
||||
sendfile = true
|
||||
minterpreters = true
|
||||
async = true
|
||||
ldap = true
|
||||
ssl = true
|
||||
ldap = false
|
||||
pcre = true
|
||||
routing = true
|
||||
debug = false
|
||||
@@ -23,13 +13,22 @@ unbit = true
|
||||
xml_implementation = expat
|
||||
yaml_implementation = auto
|
||||
malloc_implementation = libc
|
||||
extras =
|
||||
plugins =
|
||||
bin_name = /opt/unbit/bin/uwsgi
|
||||
bin_name = /opt/unbit/uwsgi19/lib/libuwsgi.so
|
||||
append_version = unbit
|
||||
plugin_dir = /opt/unbit/uwsgi_plugins
|
||||
plugin_dir = /opt/unbit/uwsgi19/plugins
|
||||
embedded_plugins =
|
||||
as_shared_library = true
|
||||
|
||||
locking = auto
|
||||
event = auto
|
||||
timer = auto
|
||||
filemonitor = auto
|
||||
|
||||
blacklist =
|
||||
whitelist =
|
||||
|
||||
embed_files =
|
||||
|
||||
embed_config =
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
[uwsgi]
|
||||
inherit = unbit
|
||||
json = false
|
||||
embedded_plugins = python
|
||||
bin_name = ../bin/uwsgi
|
||||
plugin_dir = ../bin/uwsgi_plugins
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
[uwsgi]
|
||||
xml = false
|
||||
ini = true
|
||||
yaml = false
|
||||
json = false
|
||||
sqlite3 = false
|
||||
zeromq = false
|
||||
snmp = false
|
||||
sctp = false
|
||||
spooler = true
|
||||
embedded = true
|
||||
udp = true
|
||||
multicast = false
|
||||
threading = true
|
||||
sendfile = true
|
||||
minterpreters = true
|
||||
async = true
|
||||
evdis = false
|
||||
ldap = false
|
||||
pcre = true
|
||||
routing = true
|
||||
debug = false
|
||||
unbit = false
|
||||
xml_implementation = libxml2
|
||||
yaml_implementation = auto
|
||||
malloc_implementation = libc
|
||||
extras =
|
||||
plugins =
|
||||
bin_name = uwsgi
|
||||
append_version =
|
||||
plugin_dir = .
|
||||
embedded_plugins =
|
||||
as_shared_library = false
|
||||
|
||||
locking = auto
|
||||
event = auto
|
||||
timer = auto
|
||||
filemonitor = auto
|
||||
|
||||
blacklist =
|
||||
whitelist =
|
||||
|
||||
embed_files =
|
||||
|
||||
embed_config =
|
||||
|
||||
[python]
|
||||
paste = true
|
||||
web3 = true
|
||||
@@ -1,443 +0,0 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_init_cache() {
|
||||
int i;
|
||||
|
||||
if (!uwsgi.cache_blocksize)
|
||||
uwsgi.cache_blocksize = UMAX16;
|
||||
|
||||
uwsgi.cache_hashtable = (uint64_t *) mmap(NULL, sizeof(uint64_t) * UMAX16, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (!uwsgi.cache_hashtable) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(uwsgi.cache_hashtable, 0, sizeof(uint64_t) * UMAX16);
|
||||
|
||||
uwsgi.cache_unused_stack = (uint64_t *) mmap(NULL, sizeof(uint64_t) * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (!uwsgi.cache_unused_stack) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(uwsgi.cache_unused_stack, 0, sizeof(uint64_t) * uwsgi.cache_max_items);
|
||||
|
||||
// the first cache item is always zero
|
||||
uwsgi.shared->cache_first_available_item = 1;
|
||||
uwsgi.shared->cache_unused_stack_ptr = 0;
|
||||
|
||||
//uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (uwsgi.cache_store) {
|
||||
uwsgi.cache_filesize = (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items) + (uwsgi.cache_blocksize * uwsgi.cache_max_items);
|
||||
int cache_fd;
|
||||
struct stat cst;
|
||||
|
||||
if (stat(uwsgi.cache_store, &cst)) {
|
||||
uwsgi_log("creating a new cache store file: %s\n", uwsgi.cache_store);
|
||||
cache_fd = open(uwsgi.cache_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
if (cache_fd >= 0) {
|
||||
// fill the caching store
|
||||
if (ftruncate(cache_fd, uwsgi.cache_filesize)) {
|
||||
uwsgi_log("ftruncate()");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((size_t) cst.st_size != uwsgi.cache_filesize || !S_ISREG(cst.st_mode)) {
|
||||
uwsgi_log("invalid cache store file. Please remove it or fix cache blocksize/items to match its size\n");
|
||||
exit(1);
|
||||
}
|
||||
cache_fd = open(uwsgi.cache_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
uwsgi_log("recovered cache from backing store file: %s\n", uwsgi.cache_store);
|
||||
}
|
||||
|
||||
if (cache_fd < 0) {
|
||||
uwsgi_error_open(uwsgi.cache_store);
|
||||
exit(1);
|
||||
}
|
||||
uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, uwsgi.cache_filesize, PROT_READ | PROT_WRITE, MAP_SHARED, cache_fd, 0);
|
||||
uwsgi_cache_fix();
|
||||
|
||||
}
|
||||
else {
|
||||
uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items) + (uwsgi.cache_blocksize * uwsgi.cache_max_items), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
for (i = 0; i < (int) uwsgi.cache_max_items; i++) {
|
||||
memset(&uwsgi.cache_items[i], 0, sizeof(struct uwsgi_cache_item));
|
||||
}
|
||||
}
|
||||
if (!uwsgi.cache_items) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
uwsgi.cache = mmap(NULL, uwsgi.cache_blocksize * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (!uwsgi.cache) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
*/
|
||||
|
||||
uwsgi.cache = ((void *) uwsgi.cache_items) + (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items);
|
||||
|
||||
uwsgi.cache_lock = uwsgi_rwlock_init("cache");
|
||||
|
||||
uwsgi_log("*** Cache subsystem initialized: %dMB (key: %llu bytes, keys: %llu bytes, data: %llu bytes) preallocated ***\n", ((uwsgi.cache_blocksize * uwsgi.cache_max_items) + (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items)) / (1024 * 1024),
|
||||
(unsigned long long) sizeof(struct uwsgi_cache_item), (unsigned long long) sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items, (unsigned long long) uwsgi.cache_blocksize * uwsgi.cache_max_items);
|
||||
}
|
||||
|
||||
uint32_t djb33x_hash(char *key, int keylen) {
|
||||
|
||||
register uint32_t hash = 5381;
|
||||
int i;
|
||||
|
||||
for(i=0;i<keylen;i++) {
|
||||
hash = ((hash << 5) + hash) ^ key[i];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
inline uint64_t uwsgi_cache_get_index(char *key, uint16_t keylen) {
|
||||
|
||||
uint32_t hash = djb33x_hash(key, keylen);
|
||||
|
||||
int hash_key = hash % 0xffff;
|
||||
|
||||
uint64_t slot = uwsgi.cache_hashtable[hash_key];
|
||||
|
||||
struct uwsgi_cache_item *uci;
|
||||
uint64_t rounds = 0;
|
||||
|
||||
//uwsgi_log("found slot %d for key %d\n", slot, hash_key);
|
||||
|
||||
uci = &uwsgi.cache_items[slot];
|
||||
|
||||
// first round
|
||||
if (uci->djbhash != hash) return 0;
|
||||
if (uci->keysize != keylen) goto cycle;
|
||||
if (memcmp(uci->key, key, keylen)) goto cycle;
|
||||
|
||||
return slot;
|
||||
|
||||
cycle:
|
||||
while(uci->next) {
|
||||
slot = uci->next;
|
||||
uci = &uwsgi.cache_items[slot];
|
||||
rounds++;
|
||||
if (rounds > uwsgi.cache_max_items) {
|
||||
uwsgi_log("ALARM !!! cache-loop (and potential deadlock) detected slot = %llu prev = %llu next = %llu\n", uci->next, slot, uci->prev, uci->next);
|
||||
// terrible case: the whole uWSGI stack can deadlock, leaving only the master alive
|
||||
// if the master is avalable, trigger a brutal reload
|
||||
if (uwsgi.master_process) {
|
||||
kill(uwsgi.workers[0].pid, SIGTERM);
|
||||
}
|
||||
// otherwise kill the current worker (could be pretty useless...)
|
||||
else {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (uci->djbhash != hash) return 0;
|
||||
if (uci->keysize != keylen) continue;
|
||||
if (!memcmp(uci->key, key, keylen)) return slot;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t uwsgi_cache_exists(char *key, uint16_t keylen) {
|
||||
|
||||
return uwsgi_cache_get_index(key, keylen);
|
||||
}
|
||||
|
||||
char *uwsgi_cache_get(char *key, uint16_t keylen, uint64_t *valsize) {
|
||||
|
||||
uint64_t index = uwsgi_cache_get_index(key, keylen);
|
||||
|
||||
if (index) {
|
||||
if (uwsgi.cache_items[index].flags & UWSGI_CACHE_FLAG_UNGETTABLE) return NULL;
|
||||
*valsize = uwsgi.cache_items[index].valsize;
|
||||
uwsgi.cache_items[index].hits++;
|
||||
return uwsgi.cache+(index*uwsgi.cache_blocksize);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int uwsgi_cache_del(char *key, uint16_t keylen, uint64_t index) {
|
||||
|
||||
struct uwsgi_cache_item *uci;
|
||||
int ret = -1;
|
||||
|
||||
if (!index)
|
||||
index = uwsgi_cache_get_index(key, keylen);
|
||||
|
||||
if (index) {
|
||||
uci = &uwsgi.cache_items[index] ;
|
||||
uci->keysize = 0;
|
||||
uci->valsize = 0;
|
||||
uwsgi.shared->cache_unused_stack_ptr++;
|
||||
uwsgi.cache_unused_stack[uwsgi.shared->cache_unused_stack_ptr] = index;
|
||||
// try to return to initial condition...
|
||||
if (index == uwsgi.shared->cache_first_available_item-1) {
|
||||
uwsgi.shared->cache_first_available_item--;
|
||||
//uwsgi_log("FACI: %llu STACK PTR: %llu\n", (unsigned long long) uwsgi.shared->cache_first_available_item, (unsigned long long) uwsgi.shared->cache_unused_stack_ptr);
|
||||
}
|
||||
ret = 0;
|
||||
// relink collisioned entry
|
||||
if (uci->prev) {
|
||||
uwsgi.cache_items[uci->prev].next = uci->next;
|
||||
}
|
||||
else {
|
||||
// set next as the new entry point (could be 0)
|
||||
uwsgi.cache_hashtable[uci->djbhash % 0xffff] = uci->next;
|
||||
}
|
||||
|
||||
if (uci->next) {
|
||||
uwsgi.cache_items[uci->next].prev = uci->prev;
|
||||
}
|
||||
|
||||
if (!uci->prev && !uci->next) {
|
||||
// reset hashtable entry
|
||||
//uwsgi_log("!!! resetted hashtable entry !!!\n");
|
||||
uwsgi.cache_hashtable[uci->djbhash % 0xffff] = 0;
|
||||
}
|
||||
uci->djbhash = 0;
|
||||
uci->prev = 0;
|
||||
uci->next = 0;
|
||||
uci->expires = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void uwsgi_cache_fix() {
|
||||
|
||||
uint64_t i;
|
||||
|
||||
for(i=0;i< uwsgi.cache_max_items;i++) {
|
||||
// valid record ?
|
||||
if (uwsgi.cache_items[i].keysize) {
|
||||
if (!uwsgi.cache_items[i].prev) {
|
||||
// put value in hash_table
|
||||
uwsgi.cache_hashtable[ uwsgi.cache_items[i].djbhash % 0xffff] = i;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// put this record in unused stack
|
||||
uwsgi.shared->cache_first_available_item = i;
|
||||
uwsgi.shared->cache_unused_stack_ptr++;
|
||||
uwsgi.cache_unused_stack[uwsgi.shared->cache_unused_stack_ptr] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int uwsgi_cache_set(char *key, uint16_t keylen, char *val, uint64_t vallen, uint64_t expires, uint16_t flags) {
|
||||
|
||||
uint64_t index = 0, last_index = 0 ;
|
||||
|
||||
struct uwsgi_cache_item *uci, *ucii;
|
||||
|
||||
int ret = -1;
|
||||
int slot;
|
||||
|
||||
if (!keylen || !vallen) return -1;
|
||||
|
||||
if (keylen > UWSGI_CACHE_MAX_KEY_SIZE) return -1;
|
||||
|
||||
if (uwsgi.shared->cache_first_available_item >= uwsgi.cache_max_items && !uwsgi.shared->cache_unused_stack_ptr) {
|
||||
uwsgi_log("*** DANGER cache is FULL !!! ***\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
//uwsgi_log("putting cache data in key %.*s %d\n", keylen, key, vallen);
|
||||
index = uwsgi_cache_get_index(key, keylen);
|
||||
if (!index) {
|
||||
if (uwsgi.shared->cache_unused_stack_ptr) {
|
||||
//uwsgi_log("!!! REUSING CACHE SLOT !!! (faci: %llu)\n", (unsigned long long) uwsgi.shared->cache_first_available_item);
|
||||
index = uwsgi.cache_unused_stack[uwsgi.shared->cache_unused_stack_ptr];
|
||||
uwsgi.shared->cache_unused_stack_ptr--;
|
||||
}
|
||||
else {
|
||||
index = uwsgi.shared->cache_first_available_item;
|
||||
if (uwsgi.shared->cache_first_available_item < uwsgi.cache_max_items) {
|
||||
uwsgi.shared->cache_first_available_item++;
|
||||
}
|
||||
}
|
||||
uci = &uwsgi.cache_items[index] ;
|
||||
if (expires) expires += time(NULL);
|
||||
uci->expires = expires;
|
||||
uci->djbhash = djb33x_hash(key, keylen);
|
||||
uci->hits = 0;
|
||||
uci->flags = flags;
|
||||
memcpy(uci->key, key, keylen);
|
||||
memcpy(uwsgi.cache+(index*uwsgi.cache_blocksize), val, vallen);
|
||||
|
||||
// set this as late as possibile (to reduce races risk)
|
||||
|
||||
uci->valsize = vallen;
|
||||
uci->keysize = keylen;
|
||||
ret = 0;
|
||||
// now put the value in the 16bit hashtable
|
||||
slot = uci->djbhash % 0xffff;
|
||||
// reset values
|
||||
uci->prev = 0;
|
||||
uci->next = 0;
|
||||
|
||||
if (uwsgi.cache_hashtable[slot] == 0) {
|
||||
uwsgi.cache_hashtable[slot] = index;
|
||||
}
|
||||
else {
|
||||
//uwsgi_log("HASH COLLISION !!!!\n");
|
||||
// append to first available next
|
||||
last_index = uwsgi.cache_hashtable[slot];
|
||||
ucii = &uwsgi.cache_items[ last_index ];
|
||||
while(ucii->next) {
|
||||
last_index = ucii->next;
|
||||
ucii = &uwsgi.cache_items[ last_index ];
|
||||
}
|
||||
ucii->next = index;
|
||||
uci->prev = last_index;
|
||||
}
|
||||
}
|
||||
else if (flags & UWSGI_CACHE_FLAG_UPDATE) {
|
||||
uci = &uwsgi.cache_items[index] ;
|
||||
if (expires) {
|
||||
expires += time(NULL);
|
||||
uci->expires = expires;
|
||||
}
|
||||
memcpy(uwsgi.cache+(index*uwsgi.cache_blocksize), val, vallen);
|
||||
uci->valsize = vallen;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
end:
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* THIS PART IS HEAVILY OPTIMIZED: PERFORMANCE NOT ELEGANCE !!! */
|
||||
|
||||
void *cache_thread_loop(void *fd_ptr) {
|
||||
|
||||
int *fd_tmp = (int *) fd_ptr;
|
||||
int fd = *fd_tmp;
|
||||
int i;
|
||||
ssize_t len;
|
||||
char uwsgi_packet[UMAX16+4];
|
||||
struct uwsgi_header *uh = (struct uwsgi_header *) uwsgi_packet;
|
||||
char *val;
|
||||
uint64_t vallen;
|
||||
char *key;
|
||||
uint16_t keylen;
|
||||
struct pollfd ctl_poll;
|
||||
char *watermark;
|
||||
struct sockaddr_un ctl_sun;
|
||||
socklen_t ctl_sun_len;
|
||||
|
||||
ctl_poll.events = POLLIN;
|
||||
|
||||
for(;;) {
|
||||
ctl_sun_len = sizeof(struct sockaddr_un);
|
||||
pthread_mutex_lock(&uwsgi.cache_server_lock);
|
||||
|
||||
ctl_poll.fd = accept(fd, (struct sockaddr *) &ctl_sun, &ctl_sun_len);
|
||||
|
||||
pthread_mutex_unlock(&uwsgi.cache_server_lock);
|
||||
|
||||
if (ctl_poll.fd < 0) {
|
||||
uwsgi_error("cache accept()");
|
||||
continue;
|
||||
}
|
||||
i = 0;
|
||||
while(i < 4) {
|
||||
len = poll(&ctl_poll, 1, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (len <= 0) {
|
||||
uwsgi_error("cache poll()");
|
||||
goto clear;
|
||||
}
|
||||
len = read(ctl_poll.fd, uwsgi_packet+i, 4-i);
|
||||
if (len < 0) {
|
||||
uwsgi_error("cache read()");
|
||||
goto clear;
|
||||
}
|
||||
i+=len;
|
||||
}
|
||||
|
||||
if (uh->pktsize == 0) goto clear;
|
||||
|
||||
while(i < 4+uh->pktsize) {
|
||||
len = poll(&ctl_poll, 1, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (len <= 0) {
|
||||
uwsgi_error("cache poll()");
|
||||
goto clear;
|
||||
}
|
||||
len = read(ctl_poll.fd, uwsgi_packet+i, (4+uh->pktsize)-i);
|
||||
if (len < 0) {
|
||||
uwsgi_error("cache read()");
|
||||
goto clear;
|
||||
}
|
||||
i+=len;
|
||||
}
|
||||
|
||||
watermark = uwsgi_packet+4+uh->pktsize;
|
||||
|
||||
// get first parameter
|
||||
memcpy(&keylen, uwsgi_packet+4, 2);
|
||||
#ifdef __BIG_ENDIAN__
|
||||
keylen = uwsgi_swap16(keylen);
|
||||
#endif
|
||||
if (uwsgi_packet+6+keylen > watermark) goto clear;
|
||||
key = uwsgi_packet+6+keylen+2;
|
||||
memcpy(&keylen, key-2, 2);
|
||||
#ifdef __BIG_ENDIAN__
|
||||
keylen = uwsgi_swap16(keylen);
|
||||
#endif
|
||||
|
||||
if (key+keylen > watermark) goto clear;
|
||||
|
||||
val = uwsgi_cache_get(key, keylen, &vallen);
|
||||
if (val && vallen > 0) {
|
||||
if (write(ctl_poll.fd, val, vallen) < 0) {
|
||||
uwsgi_error("cache write()");
|
||||
}
|
||||
}
|
||||
|
||||
clear:
|
||||
close(ctl_poll.fd);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int uwsgi_cache_server(char *socket, int threads) {
|
||||
|
||||
int *fd = uwsgi_malloc(sizeof(int));
|
||||
|
||||
int i;
|
||||
pthread_t thread_id;
|
||||
char *tcp_port = strchr(socket, ':');
|
||||
if (tcp_port) {
|
||||
*fd = bind_to_tcp(socket, uwsgi.listen_queue, tcp_port);
|
||||
}
|
||||
else {
|
||||
*fd = bind_to_unix(socket, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
|
||||
}
|
||||
|
||||
pthread_mutex_init(&uwsgi.cache_server_lock, NULL);
|
||||
|
||||
if (threads < 1) threads = 1;
|
||||
|
||||
uwsgi_log("*** cache-optimized server enabled on fd %d (%d threads) ***\n", *fd, threads);
|
||||
|
||||
for(i=0;i<threads;i++) {
|
||||
pthread_create(&thread_id, NULL, cache_thread_loop, (void *) fd);
|
||||
}
|
||||
|
||||
return *fd;
|
||||
}
|
||||
|
||||
@@ -1,363 +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(-1);
|
||||
goto options_parsed;
|
||||
}
|
||||
else {
|
||||
goto waitfd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
options_parsed:
|
||||
|
||||
if (!uwsgi.cluster_nodes)
|
||||
uwsgi_cluster_add_me();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void uwsgi_cluster_add_node(struct uwsgi_cluster_node *nucn, int type) {
|
||||
|
||||
int i;
|
||||
struct uwsgi_cluster_node *ucn;
|
||||
char *tcp_port;
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("adding node\n");
|
||||
#endif
|
||||
|
||||
tcp_port = strchr(nucn->name, ':');
|
||||
#ifndef UWSGI_ZEROMQ
|
||||
if (tcp_port == NULL) {
|
||||
#else
|
||||
char *zmq_dash = strchr(nucn->name, '-');
|
||||
if (tcp_port == NULL && zmq_dash == NULL) {
|
||||
#endif
|
||||
|
||||
fprintf(stdout, "invalid cluster node name %s\n", nucn->name);
|
||||
return;
|
||||
}
|
||||
|
||||
// first check for already present node
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
ucn = &uwsgi.shared->nodes[i];
|
||||
if (ucn->name[0] != 0) {
|
||||
if (!strcmp(ucn->name, nucn->name)) {
|
||||
ucn->status = UWSGI_NODE_OK;
|
||||
ucn->last_seen = time(NULL);
|
||||
// update requests
|
||||
ucn->requests = nucn->requests;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
ucn = &uwsgi.shared->nodes[i];
|
||||
|
||||
if (ucn->name[0] == 0) {
|
||||
memcpy(ucn->name, nucn->name, strlen(nucn->name) + 1);
|
||||
memcpy(ucn->nodename, nucn->nodename, strlen(nucn->nodename) + 1);
|
||||
ucn->workers = nucn->workers;
|
||||
ucn->ucn_addr.sin_family = AF_INET;
|
||||
if (tcp_port) {
|
||||
ucn->ucn_addr.sin_port = htons(atoi(tcp_port + 1));
|
||||
tcp_port[0] = 0;
|
||||
}
|
||||
if (nucn->name[0] == 0) {
|
||||
ucn->ucn_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
}
|
||||
else {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%s\n", nucn->name);
|
||||
#endif
|
||||
ucn->ucn_addr.sin_addr.s_addr = inet_addr(nucn->name);
|
||||
}
|
||||
|
||||
ucn->type = type;
|
||||
// here memory can be freed, as it is allocated by uwsgi_concat2n
|
||||
if (type != CLUSTER_NODE_DYNAMIC && tcp_port) {
|
||||
tcp_port[0] = ':';
|
||||
}
|
||||
ucn->last_seen = time(NULL);
|
||||
ucn->requests = nucn->requests;
|
||||
uwsgi_log("[uWSGI cluster] added node %s\n", ucn->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("unable to add node %s\n", nucn->name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int uwsgi_cluster_add_me() {
|
||||
|
||||
const char *key1 = "hostname";
|
||||
const char *key2 = "address";
|
||||
const char *key3 = "workers";
|
||||
const char *key4 = "requests";
|
||||
|
||||
char *ptrbuf;
|
||||
uint16_t ustrlen;
|
||||
char numproc[6];
|
||||
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
char uuid_zmq_str[37];
|
||||
uuid_t uuid_zmq;
|
||||
if (!uwsgi.sockets && !uwsgi.zeromq) {
|
||||
#else
|
||||
if (!uwsgi.sockets) {
|
||||
#endif
|
||||
uwsgi_log("you need to specify at least a socket to start a uWSGI cluster\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
snprintf(numproc, 6, "%d", uwsgi.numproc);
|
||||
|
||||
size_t len;
|
||||
|
||||
if (uwsgi.sockets) {
|
||||
len = 2 + strlen(key1) + 2 + strlen(uwsgi.hostname) + 2 + strlen(key2) + 2 + strlen(uwsgi.sockets->name) + 2 + strlen(key3) + 2 + strlen(numproc) + 2 + strlen(key4) + 2 + 1;
|
||||
}
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
else if (uwsgi.zeromq) {
|
||||
uuid_generate(uuid_zmq);
|
||||
uuid_unparse(uuid_zmq, uuid_zmq_str);
|
||||
len = 2 + strlen(key1) + 2 + strlen(uwsgi.hostname) + 2 + strlen(key2) + 2 + strlen(uuid_zmq_str) + 2 + strlen(key3) + 2 + strlen(numproc) + 2 + strlen(key4) + 2 + 1;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
len = 2 + strlen(key1) + 2 + strlen(uwsgi.hostname) + 2 + strlen(key3) + 2 + strlen(numproc) + 2 + strlen(key4) + 2 + 1;
|
||||
}
|
||||
char *buf = uwsgi_malloc(len);
|
||||
|
||||
ptrbuf = buf;
|
||||
|
||||
ustrlen = strlen(key1);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key1, strlen(key1));
|
||||
ptrbuf += strlen(key1);
|
||||
|
||||
ustrlen = strlen(uwsgi.hostname);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, uwsgi.hostname, strlen(uwsgi.hostname));
|
||||
ptrbuf += strlen(uwsgi.hostname);
|
||||
|
||||
|
||||
if (uwsgi.sockets && uwsgi.sockets->name) {
|
||||
ustrlen = strlen(key2);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key2, strlen(key2));
|
||||
ptrbuf += strlen(key2);
|
||||
|
||||
ustrlen = strlen(uwsgi.sockets->name);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, uwsgi.sockets->name, strlen(uwsgi.sockets->name));
|
||||
ptrbuf += strlen(uwsgi.sockets->name);
|
||||
}
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
else if (uwsgi.zeromq) {
|
||||
ustrlen = strlen(key2);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key2, strlen(key2));
|
||||
ptrbuf += strlen(key2);
|
||||
|
||||
ustrlen = strlen(uuid_zmq_str);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, uuid_zmq_str, strlen(uuid_zmq_str));
|
||||
ptrbuf += strlen(uuid_zmq_str);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
ustrlen = strlen(key3);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key3, strlen(key3));
|
||||
ptrbuf += strlen(key3);
|
||||
|
||||
ustrlen = strlen(numproc);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, numproc, strlen(numproc));
|
||||
ptrbuf += strlen(numproc);
|
||||
|
||||
ustrlen = strlen(key4);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key4, strlen(key4));
|
||||
ptrbuf += strlen(key4);
|
||||
|
||||
ustrlen = 1;
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, "0", 1);
|
||||
ptrbuf += 1;
|
||||
|
||||
|
||||
uwsgi_string_sendto(uwsgi.cluster_fd, 95, 0, (struct sockaddr *) &uwsgi.mc_cluster_addr, sizeof(uwsgi.mc_cluster_addr), buf, len);
|
||||
|
||||
free(buf);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("add_me() successfull\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_cluster_join(char *name) {
|
||||
|
||||
int fd;
|
||||
char *cp;
|
||||
int broadcast = 0;
|
||||
|
||||
|
||||
|
||||
if (name[0] == ':') {
|
||||
fd = bind_to_udp(name, 0, 1);
|
||||
broadcast = 1;
|
||||
}
|
||||
else {
|
||||
fd = bind_to_udp(name, 1, 0);
|
||||
}
|
||||
|
||||
if (fd >= 0) {
|
||||
cp = strchr(name, ':');
|
||||
cp[0] = 0;
|
||||
uwsgi.mc_cluster_addr.sin_family = AF_INET;
|
||||
if (broadcast) {
|
||||
uwsgi.mc_cluster_addr.sin_addr.s_addr = INADDR_BROADCAST;
|
||||
}
|
||||
else {
|
||||
uwsgi.mc_cluster_addr.sin_addr.s_addr = inet_addr(name);
|
||||
}
|
||||
uwsgi.mc_cluster_addr.sin_port = htons(atoi(cp + 1));
|
||||
cp[0] = ':';
|
||||
|
||||
|
||||
// announce my presence to all the nodes
|
||||
uwsgi_string_sendto(fd, 73, 0, (struct sockaddr *) &uwsgi.mc_cluster_addr, sizeof(uwsgi.mc_cluster_addr), uwsgi.hostname, strlen(uwsgi.hostname));
|
||||
}
|
||||
else {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
return fd;
|
||||
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_cluster_best_node() {
|
||||
|
||||
int i;
|
||||
int best_node = -1;
|
||||
struct uwsgi_cluster_node *ucn;
|
||||
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
ucn = &uwsgi.shared->nodes[i];
|
||||
if (ucn->name[0] != 0 && ucn->status == UWSGI_NODE_OK) {
|
||||
if (best_node == -1) {
|
||||
best_node = i;
|
||||
}
|
||||
else {
|
||||
if (ucn->last_choosen < uwsgi.shared->nodes[best_node].last_choosen) {
|
||||
best_node = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (best_node == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uwsgi.shared->nodes[best_node].last_choosen = time(NULL);
|
||||
return uwsgi.shared->nodes[best_node].name;
|
||||
}
|
||||
|
||||
|
||||
void manage_cluster_announce(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
|
||||
|
||||
char *tmpstr;
|
||||
struct uwsgi_cluster_node *ucn = (struct uwsgi_cluster_node *) data;
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%.*s = %.*s\n", keylen, key, vallen, val);
|
||||
#endif
|
||||
|
||||
if (!uwsgi_strncmp("hostname", 8, key, keylen)) {
|
||||
strncpy(ucn->nodename, val, UMIN(vallen, 255));
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("address", 7, key, keylen)) {
|
||||
strncpy(ucn->name, val, UMIN(vallen, 100));
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("workers", 7, key, keylen)) {
|
||||
tmpstr = uwsgi_concat2n(val, vallen, "", 0);
|
||||
ucn->workers = atoi(tmpstr);
|
||||
free(tmpstr);
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("requests", 8, key, keylen)) {
|
||||
tmpstr = uwsgi_concat2n(val, vallen, "", 0);
|
||||
ucn->requests = strtoul(tmpstr, NULL, 0);
|
||||
free(tmpstr);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +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);
|
||||
dup2($s4->fileno, 0);
|
||||
exec './uwsgi','-M', '--socket','fd://17', '--http-socket','fd://22', '--socket','fd://30','--stats',':5001';
|
||||
@@ -0,0 +1,24 @@
|
||||
require 'socket'
|
||||
require 'openssl'
|
||||
|
||||
secret = 'ciaociao'
|
||||
iv = ''
|
||||
address = '127.0.0.1'
|
||||
port = 1717
|
||||
algo = 'bf-cbc'
|
||||
|
||||
s = UDPSocket.new
|
||||
s.bind(address, port)
|
||||
cipher = OpenSSL::Cipher.new(algo)
|
||||
cipher.decrypt
|
||||
cipher.key = secret + ("\0" * (cipher.key_len - secret.length))
|
||||
cipher.iv = iv + ("0" * (cipher.iv_len - iv.length))
|
||||
|
||||
loop do
|
||||
msg, sender = s.recvfrom(8192)
|
||||
cipher.reset
|
||||
begin
|
||||
puts cipher.update(msg) + cipher.final
|
||||
rescue
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,114 @@
|
||||
require 'sinatra'
|
||||
require 'socket'
|
||||
require 'json'
|
||||
|
||||
module EmperorStats
|
||||
def self.uwsgi_get_stats(server)
|
||||
parts = server.split(':')
|
||||
if parts.length > 1
|
||||
s = TCPSocket.open(parts[0], parts[1])
|
||||
else
|
||||
s = UNIXSocket.open(server)
|
||||
end
|
||||
return JSON.parse(s.read())
|
||||
end
|
||||
end
|
||||
|
||||
template = <<eof
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><%=@title%></title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="unbit">
|
||||
<link href="http://unbit.github.com/bootstrap/css/bootstrap.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */
|
||||
}
|
||||
</style>
|
||||
<link href="http://unbit.github.com/bootstrap/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a class="brand" href="#"><%=@title%></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<hr/>
|
||||
<h1>Emperor: <%=@stats['emperor']%></h1>
|
||||
<hr/>
|
||||
|
||||
<div class="row">
|
||||
<div class="span8">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>name</th><th>pid</th><th>first run</th>
|
||||
<th>last respawn</th>
|
||||
<th>last heartbeat</th>
|
||||
<th>loyal</th>
|
||||
<th>respawns</th>
|
||||
<% if @stats['emperor_tyrant'] == 1 %>
|
||||
<th>uid</th>
|
||||
<th>gid</th>
|
||||
<% end %>
|
||||
</tr>
|
||||
</thead>
|
||||
<% for vassal in @stats['vassals'] %>
|
||||
<tr>
|
||||
<td><%=vassal['id']%></td>
|
||||
<td><%=vassal['pid']%></td>
|
||||
<td><%=Time.at(vassal['first_run']).strftime("%d %b %Y %H:%M:%S")%></td>
|
||||
<td><%=Time.at(vassal['last_run']).strftime("%d %b %Y %H:%M:%S")%></td>
|
||||
<td><% if vassal['last_heartbeat'] > 0 %><%=Time.at(vassal['last_heartbeat']).strftime("%d %b %Y %H:%M:%S")%><% end %></td>
|
||||
<td><% if vassal['loyal'] > 0 %><%=Time.at(vassal['last_loyal']).strftime("%d %b %Y %H:%M:%S")%><% end %></td>
|
||||
<td><%=vassal['respawns']%></td>
|
||||
<% if @stats['emperor_tyrant'] == 1 %>
|
||||
<td><%=vassal['uid']%></td>
|
||||
<td><%=vassal['gid']%></td>
|
||||
<% end %>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="span4">
|
||||
<h3>blacklist</h3>
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr><th>name</th><th>throttle</th></tr>
|
||||
<% for bli in @stats['blacklist'] %>
|
||||
<tr>
|
||||
<td><%=bli['id']%></td>
|
||||
<td><%=bli['throttle_level']%></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script src="http://unbit.github.com/jquery-1.7.2.min.js" type="text/javascript"></script>
|
||||
<script src="http://unbit.github.com/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
|
||||
</body>
|
||||
</html>
|
||||
eof
|
||||
|
||||
get '/' do
|
||||
@stats = EmperorStats::uwsgi_get_stats(ENV['EMPEROR'])
|
||||
@title = 'uWSGI Emperor monitor'
|
||||
erb template
|
||||
end
|
||||
|
||||
run Sinatra::Application
|
||||
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use Crypt::OpenSSL::RSA;
|
||||
use IO::Socket::INET;
|
||||
|
||||
open PK,$ARGV[3];
|
||||
my @lines = <PK>;
|
||||
close PK;
|
||||
|
||||
$rsa_priv = Crypt::OpenSSL::RSA->new_private_key(join('',@lines));
|
||||
|
||||
my %items = {};
|
||||
|
||||
$items{'key'} = $ARGV[1];
|
||||
$items{'address'} = $ARGV[2];
|
||||
|
||||
my $uwsgi_pkt = '';
|
||||
|
||||
foreach(keys %items) {
|
||||
$uwsgi_pkt .= pack('v', length($_)).$_.pack('v', length($items{$_})).$items{$_};
|
||||
}
|
||||
|
||||
my $unix_check = time();
|
||||
|
||||
$uwsgi_pkt .= pack('v', 4).'unix'.pack('v', length($unix_check)).$unix_check;
|
||||
|
||||
my $signature = $rsa_priv->sign($uwsgi_pkt);
|
||||
|
||||
$uwsgi_pkt .= pack('v', 4).'sign'.pack('v', length($signature)).$signature;
|
||||
|
||||
|
||||
my $udp = new IO::Socket::INET(PeerAddr => $ARGV[0], Proto => 'udp');
|
||||
|
||||
$udp->send(pack('CvC', 224, length($uwsgi_pkt), 0).$uwsgi_pkt);
|
||||
|
||||
print ''.(length($uwsgi_pkt)+4).' bytes sent to '.$ARGV[0]."\n";
|
||||
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use IO::Socket::INET;
|
||||
|
||||
my %items = {};
|
||||
|
||||
$items{'key'} = $ARGV[1];
|
||||
$items{'address'} = $ARGV[2];
|
||||
|
||||
my $uwsgi_pkt = '';
|
||||
|
||||
foreach(keys %items) {
|
||||
$uwsgi_pkt .= pack('v', length($_)).$_.pack('v', length($items{$_})).$items{$_};
|
||||
}
|
||||
|
||||
my $udp = new IO::Socket::INET(PeerAddr => $ARGV[0], Proto => 'udp');
|
||||
|
||||
$udp->send(pack('CvC', 224, length($uwsgi_pkt), 0).$uwsgi_pkt);
|
||||
|
||||
print ''.(length($uwsgi_pkt)+4).' bytes sent to '.$ARGV[0]."\n";
|
||||
@@ -0,0 +1,96 @@
|
||||
require 'sinatra'
|
||||
require 'socket'
|
||||
require 'json'
|
||||
|
||||
module USubscribers
|
||||
def self.uwsgi_get_stats(server)
|
||||
parts = server.split(':')
|
||||
if parts.length > 1
|
||||
s = TCPSocket.open(parts[0], parts[1])
|
||||
else
|
||||
s = UNIXSocket.open(server)
|
||||
end
|
||||
return JSON.parse(s.read())
|
||||
end
|
||||
end
|
||||
|
||||
template = <<eof
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><%=@title%></title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="unbit">
|
||||
<link href="http://unbit.github.com/bootstrap/css/bootstrap.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */
|
||||
}
|
||||
</style>
|
||||
<link href="http://unbit.github.com/bootstrap/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a class="brand" href="#"><%=@title%></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% for server in @servers.keys %>
|
||||
<div class="container">
|
||||
<hr/>
|
||||
<h1>SubscriptionServer: <%=server%></h1>
|
||||
<hr/>
|
||||
|
||||
<div class="row">
|
||||
<% for pool in @servers[server] %>
|
||||
<div class="span6">
|
||||
<h3><%=pool['key']%> (<%=pool['hits']%> hits)</h3>
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>node</th><th>load</th><th>requests</th>
|
||||
<th>last check</th>
|
||||
<th>fail count</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<% for node in pool['nodes'] %>
|
||||
<tr>
|
||||
<td><%=node['name']%></td><td><%=node['load']%></td><td><%=node['requests']%></td>
|
||||
<td><%=Time.at(node['last_check']).strftime("%d-%m-%Y %H:%M:%S")%></td>
|
||||
<td><%=node['failcnt']%></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<% end %>
|
||||
|
||||
<script src="http://unbit.github.com/jquery-1.7.2.min.js" type="text/javascript"></script>
|
||||
<script src="http://unbit.github.com/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
|
||||
</body>
|
||||
</html>
|
||||
eof
|
||||
|
||||
get '/' do
|
||||
@servers = {}
|
||||
for server in ENV['U_SERVERS'].split(',')
|
||||
stats = USubscribers::uwsgi_get_stats(server)
|
||||
if stats
|
||||
@servers[server] = stats['subscriptions']
|
||||
end
|
||||
end
|
||||
@title = 'uWSGI subscriptions viewer'
|
||||
erb template
|
||||
end
|
||||
|
||||
run Sinatra::Application
|
||||
+342
@@ -0,0 +1,342 @@
|
||||
#include "../uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
// generate a uwsgi signal on alarm
|
||||
void uwsgi_alarm_init_signal(struct uwsgi_alarm_instance *uai) {
|
||||
uai->data8 = atoi(uai->arg);
|
||||
}
|
||||
|
||||
void uwsgi_alarm_func_signal(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
|
||||
uwsgi_route_signal(uai->data8);
|
||||
}
|
||||
|
||||
// run a command on alarm
|
||||
void uwsgi_alarm_init_cmd(struct uwsgi_alarm_instance *uai) {
|
||||
uai->data_ptr = uai->arg;
|
||||
}
|
||||
|
||||
void uwsgi_alarm_func_cmd(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
|
||||
int pipe[2];
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe)) {
|
||||
return;
|
||||
}
|
||||
uwsgi_socket_nb(pipe[0]);
|
||||
uwsgi_socket_nb(pipe[1]);
|
||||
if (write(pipe[1], msg, len) != (ssize_t) len) {
|
||||
close(pipe[0]);
|
||||
close(pipe[1]);
|
||||
return;
|
||||
}
|
||||
uwsgi_run_command(uai->data_ptr, pipe, -1);
|
||||
close(pipe[0]);
|
||||
close(pipe[1]);
|
||||
}
|
||||
|
||||
// pass the log line to a mule
|
||||
|
||||
void uwsgi_alarm_init_mule(struct uwsgi_alarm_instance *uai) {
|
||||
uai->data32 = atoi(uai->arg);
|
||||
if (uai->data32 > (uint32_t) uwsgi.mules_cnt) {
|
||||
uwsgi_log_alarm("] invalid mule_id (%d mules available), fallback to 0\n", uwsgi.mules_cnt);
|
||||
uai->data32 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_alarm_func_mule(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
|
||||
// skip if mules are not available
|
||||
if (uwsgi.mules_cnt == 0)
|
||||
return;
|
||||
int fd = uwsgi.shared->mule_queue_pipe[0];
|
||||
if (uai->data32 > 0) {
|
||||
int mule_id = uai->data32 - 1;
|
||||
fd = uwsgi.mules[mule_id].queue_pipe[0];
|
||||
}
|
||||
mule_send_msg(fd, msg, len);
|
||||
}
|
||||
|
||||
|
||||
// register a new alarm
|
||||
void uwsgi_register_alarm(char *name, void (*init) (struct uwsgi_alarm_instance *), void (*func) (struct uwsgi_alarm_instance *, char *, size_t)) {
|
||||
struct uwsgi_alarm *old_ua = NULL, *ua = uwsgi.alarms;
|
||||
while (ua) {
|
||||
// skip already initialized alarms
|
||||
if (!strcmp(ua->name, name)) {
|
||||
return;
|
||||
}
|
||||
old_ua = ua;
|
||||
ua = ua->next;
|
||||
}
|
||||
|
||||
ua = uwsgi_calloc(sizeof(struct uwsgi_alarm));
|
||||
ua->name = name;
|
||||
ua->init = init;
|
||||
ua->func = func;
|
||||
|
||||
if (old_ua) {
|
||||
old_ua->next = ua;
|
||||
}
|
||||
else {
|
||||
uwsgi.alarms = ua;
|
||||
}
|
||||
}
|
||||
|
||||
// register embedded alarms
|
||||
void uwsgi_register_embedded_alarms() {
|
||||
uwsgi_register_alarm("signal", uwsgi_alarm_init_signal, uwsgi_alarm_func_signal);
|
||||
uwsgi_register_alarm("cmd", uwsgi_alarm_init_cmd, uwsgi_alarm_func_cmd);
|
||||
uwsgi_register_alarm("mule", uwsgi_alarm_init_mule, uwsgi_alarm_func_mule);
|
||||
}
|
||||
|
||||
static int uwsgi_alarm_add(char *name, char *plugin, char *arg) {
|
||||
struct uwsgi_alarm *ua = uwsgi.alarms;
|
||||
while (ua) {
|
||||
if (!strcmp(ua->name, plugin)) {
|
||||
break;
|
||||
}
|
||||
ua = ua->next;
|
||||
}
|
||||
|
||||
if (!ua)
|
||||
return -1;
|
||||
|
||||
struct uwsgi_alarm_instance *old_uai = NULL, *uai = uwsgi.alarm_instances;
|
||||
while (uai) {
|
||||
old_uai = uai;
|
||||
uai = uai->next;
|
||||
}
|
||||
|
||||
uai = uwsgi_calloc(sizeof(struct uwsgi_alarm_instance));
|
||||
uai->name = name;
|
||||
uai->alarm = ua;
|
||||
uai->arg = arg;
|
||||
uai->last_msg = uwsgi_malloc(uwsgi.log_master_bufsize);
|
||||
|
||||
if (old_uai) {
|
||||
old_uai->next = uai;
|
||||
}
|
||||
else {
|
||||
uwsgi.alarm_instances = uai;
|
||||
}
|
||||
|
||||
ua->init(uai);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get an alarm instance by its name
|
||||
static struct uwsgi_alarm_instance *uwsgi_alarm_get_instance(char *name) {
|
||||
struct uwsgi_alarm_instance *uai = uwsgi.alarm_instances;
|
||||
while (uai) {
|
||||
if (!strcmp(name, uai->name)) {
|
||||
return uai;
|
||||
}
|
||||
uai = uai->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#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) {
|
||||
old_ual = ual;
|
||||
ual = ual->next;
|
||||
}
|
||||
|
||||
ual = uwsgi_calloc(sizeof(struct uwsgi_alarm_log));
|
||||
if (uwsgi_regexp_build(regexp, &ual->pattern, &ual->pattern_extra)) {
|
||||
return -1;
|
||||
}
|
||||
ual->negate = negate;
|
||||
|
||||
if (old_ual) {
|
||||
old_ual->next = ual;
|
||||
}
|
||||
else {
|
||||
uwsgi.alarm_logs = ual;
|
||||
}
|
||||
|
||||
// map instances to the log
|
||||
char *list = uwsgi_str(alarms);
|
||||
char *p = strtok(list, ",");
|
||||
while (p) {
|
||||
struct uwsgi_alarm_instance *uai = uwsgi_alarm_get_instance(p);
|
||||
if (!uai) {
|
||||
free(list);
|
||||
return -1;
|
||||
}
|
||||
struct uwsgi_alarm_ll *old_uall = NULL, *uall = ual->alarms;
|
||||
while (uall) {
|
||||
old_uall = uall;
|
||||
uall = uall->next;
|
||||
}
|
||||
|
||||
uall = uwsgi_calloc(sizeof(struct uwsgi_alarm_ll));
|
||||
uall->alarm = uai;
|
||||
if (old_uall) {
|
||||
old_uall->next = uall;
|
||||
}
|
||||
else {
|
||||
ual->alarms = uall;
|
||||
}
|
||||
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) {
|
||||
char *line = uwsgi_str(usl->value);
|
||||
char *space = strchr(line, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid alarm syntax: %s\n", usl->value);
|
||||
exit(1);
|
||||
}
|
||||
*space = 0;
|
||||
char *plugin = space + 1;
|
||||
char *colon = strchr(plugin, ':');
|
||||
if (!colon) {
|
||||
uwsgi_log("invalid alarm syntax: %s\n", usl->value);
|
||||
exit(1);
|
||||
}
|
||||
*colon = 0;
|
||||
char *arg = colon + 1;
|
||||
// here the alarm is mapped to a name and initialized
|
||||
if (uwsgi_alarm_add(line, plugin, arg)) {
|
||||
uwsgi_log("invalid alarm: %s\n", usl->value);
|
||||
exit(1);
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
if (!uwsgi.alarm_instances) return;
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
// then map log-alarm
|
||||
usl = uwsgi.alarm_logs_list;
|
||||
while (usl) {
|
||||
char *line = uwsgi_str(usl->value);
|
||||
char *space = strchr(line, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid log-alarm syntax: %s\n", usl->value);
|
||||
exit(1);
|
||||
}
|
||||
*space = 0;
|
||||
char *regexp = space + 1;
|
||||
// here the log-alarm is created
|
||||
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))
|
||||
return;
|
||||
struct uwsgi_alarm_log *ual = uwsgi.alarm_logs;
|
||||
while (ual) {
|
||||
if (uwsgi_regexp_match(ual->pattern, ual->pattern_extra, msg, len) >= 0) {
|
||||
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) {
|
||||
time_t now = uwsgi_now();
|
||||
// avoid alarm storming/loop if last message is the same
|
||||
if (!uwsgi_strncmp(msg, len, uai->last_msg, uai->last_msg_size)) {
|
||||
if (now - uai->last_run < uwsgi.alarm_freq)
|
||||
return;
|
||||
}
|
||||
uai->alarm->func(uai, msg, len);
|
||||
uai->last_run = uwsgi_now();
|
||||
memcpy(uai->last_msg, msg, 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;
|
||||
while (uall) {
|
||||
uwsgi_alarm_run(uall->alarm, msg, 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()");
|
||||
}
|
||||
}
|
||||
+196
-143
@@ -1,7 +1,37 @@
|
||||
#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;
|
||||
|
||||
uwsgi.async_queue = event_queue_init();
|
||||
|
||||
if (uwsgi.async_queue < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_add_sockets_to_queue(uwsgi.async_queue, -1);
|
||||
|
||||
uwsgi.rb_async_timeouts = uwsgi_init_rb_timer();
|
||||
|
||||
uwsgi.async_queue_unused = uwsgi_malloc(sizeof(struct wsgi_request *) * uwsgi.async);
|
||||
|
||||
for (i = 0; i < uwsgi.async; i++) {
|
||||
uwsgi.async_queue_unused[i] = &uwsgi.workers[uwsgi.mywid].cores[i].req;
|
||||
}
|
||||
|
||||
uwsgi.async_queue_unused_ptr = uwsgi.async - 1;
|
||||
|
||||
}
|
||||
|
||||
struct wsgi_request *find_wsgi_req_proto_by_fd(int fd) {
|
||||
return uwsgi.async_proto_fd_table[fd];
|
||||
}
|
||||
@@ -10,51 +40,51 @@ 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;
|
||||
|
||||
if (parent) {
|
||||
parent->next = child;
|
||||
}
|
||||
if (child) {
|
||||
child->prev = parent;
|
||||
}
|
||||
|
||||
if (parent == NULL) {
|
||||
uwsgi.async_runqueue = child;
|
||||
}
|
||||
if (parent) {
|
||||
parent->next = child;
|
||||
}
|
||||
if (child) {
|
||||
child->prev = parent;
|
||||
}
|
||||
|
||||
if (parent == NULL) {
|
||||
uwsgi.async_runqueue = child;
|
||||
}
|
||||
|
||||
if (u_request == uwsgi.async_runqueue_last) {
|
||||
uwsgi.async_runqueue_last = parent;
|
||||
}
|
||||
|
||||
free(u_request);
|
||||
free(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;
|
||||
|
||||
if (uwsgi.async_runqueue == NULL) {
|
||||
// empty runqueue, create a new one
|
||||
uwsgi.async_runqueue = uwsgi_malloc(sizeof(struct uwsgi_async_request));
|
||||
uwsgi.async_runqueue->next = NULL;
|
||||
uwsgi.async_runqueue->prev = NULL;
|
||||
uwsgi.async_runqueue->wsgi_req = wsgi_req;
|
||||
uwsgi.async_runqueue_last = uwsgi.async_runqueue;
|
||||
}
|
||||
else {
|
||||
// empty runqueue, create a new one
|
||||
uwsgi.async_runqueue = uwsgi_malloc(sizeof(struct uwsgi_async_request));
|
||||
uwsgi.async_runqueue->next = NULL;
|
||||
uwsgi.async_runqueue->prev = NULL;
|
||||
uwsgi.async_runqueue->wsgi_req = wsgi_req;
|
||||
uwsgi.async_runqueue_last = uwsgi.async_runqueue;
|
||||
}
|
||||
else {
|
||||
uar = uwsgi_malloc(sizeof(struct uwsgi_async_request));
|
||||
uar->prev = uwsgi.async_runqueue_last;
|
||||
uar->next = NULL;
|
||||
uar->wsgi_req = wsgi_req;
|
||||
uwsgi.async_runqueue_last->next = uar;
|
||||
uwsgi.async_runqueue_last = uar;
|
||||
}
|
||||
uar->prev = uwsgi.async_runqueue_last;
|
||||
uar->next = NULL;
|
||||
uar->wsgi_req = wsgi_req;
|
||||
uwsgi.async_runqueue_last->next = uar;
|
||||
uwsgi.async_runqueue_last = uar;
|
||||
}
|
||||
|
||||
uwsgi.async_runqueue_cnt++;
|
||||
|
||||
@@ -73,30 +103,30 @@ 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 = time(NULL);
|
||||
struct uwsgi_async_fd *uaf = NULL, *current_uaf;
|
||||
|
||||
struct uwsgi_rb_timer *urbt;
|
||||
|
||||
for(;;) {
|
||||
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 == NULL)
|
||||
return;
|
||||
|
||||
if (urbt->key <= current_time) {
|
||||
wsgi_req = (struct wsgi_request *) urbt->data;
|
||||
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;
|
||||
// remove fds from monitoring (no problem modifying the queue here, as the function is executed only when there are no fd ready)
|
||||
while(uaf) {
|
||||
while (uaf) {
|
||||
event_queue_del_fd(uwsgi.async_queue, uaf->fd, uaf->event);
|
||||
uwsgi.async_waiting_fd_table[uaf->fd] = NULL;
|
||||
current_uaf = uaf;
|
||||
@@ -106,22 +136,23 @@ void async_expire_timeouts() {
|
||||
wsgi_req->waiting_fds = NULL;
|
||||
// put th request in the runqueue
|
||||
runqueue_push(wsgi_req);
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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 ;
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
// find first slot
|
||||
while(uad) {
|
||||
while (uad) {
|
||||
last_uad = uad;
|
||||
uad = uad->next;
|
||||
}
|
||||
@@ -143,57 +174,93 @@ 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) {
|
||||
|
||||
if (timeout > 0 && wsgi_req->async_timeout == NULL) {
|
||||
wsgi_req->async_timeout = uwsgi_add_rb_timer(uwsgi.rb_async_timeouts, time(NULL)+timeout, wsgi_req);
|
||||
}
|
||||
wsgi_req->async_timeout = uwsgi_add_rb_timer(uwsgi.rb_async_timeouts, uwsgi_now() + timeout, wsgi_req);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
struct uwsgi_async_fd *last_uad = NULL, *uad = wsgi_req->waiting_fds;
|
||||
|
||||
if (fd < 0) return ;
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
// find first slot
|
||||
while(uad) {
|
||||
last_uad = uad;
|
||||
uad = uad->next;
|
||||
}
|
||||
// find first slot
|
||||
while (uad) {
|
||||
last_uad = uad;
|
||||
uad = uad->next;
|
||||
}
|
||||
|
||||
uad = uwsgi_malloc(sizeof(struct uwsgi_async_fd));
|
||||
uad->fd = fd;
|
||||
uad = uwsgi_malloc(sizeof(struct uwsgi_async_fd));
|
||||
uad->fd = fd;
|
||||
uad->event = event_queue_write();
|
||||
uad->prev = last_uad;
|
||||
uad->next = NULL;
|
||||
uad->prev = last_uad;
|
||||
uad->next = NULL;
|
||||
|
||||
if (last_uad) {
|
||||
last_uad->next = uad;
|
||||
}
|
||||
else {
|
||||
wsgi_req->waiting_fds = uad;
|
||||
}
|
||||
if (last_uad) {
|
||||
last_uad->next = uad;
|
||||
}
|
||||
else {
|
||||
wsgi_req->waiting_fds = uad;
|
||||
}
|
||||
|
||||
if (timeout > 0) {
|
||||
async_add_timeout(wsgi_req, timeout);
|
||||
}
|
||||
|
||||
uwsgi.async_waiting_fd_table[fd] = wsgi_req;
|
||||
event_queue_add_fd_write(uwsgi.async_queue, fd);
|
||||
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(void *arg1) {
|
||||
void async_loop() {
|
||||
|
||||
if (uwsgi.async < 2) {
|
||||
uwsgi_log("the async loop engine requires async mode (--async <n>)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct uwsgi_async_fd *tmp_uaf;
|
||||
int interesting_fd, i;
|
||||
@@ -202,7 +269,7 @@ void *async_loop(void *arg1) {
|
||||
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;
|
||||
|
||||
@@ -212,93 +279,84 @@ void *async_loop(void *arg1) {
|
||||
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);
|
||||
}
|
||||
|
||||
// set a default request manager
|
||||
if (!uwsgi.schedule_to_req) uwsgi.schedule_to_req = async_schedule_to_req;
|
||||
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;
|
||||
}
|
||||
if (min_timeout) {
|
||||
timeout = min_timeout->key - time(NULL);
|
||||
if (timeout <= 0) {
|
||||
async_expire_timeouts();
|
||||
timeout = 0;
|
||||
}
|
||||
min_timeout = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts, NULL);
|
||||
if (min_timeout) {
|
||||
timeout = min_timeout->value - now;
|
||||
if (timeout <= 0) {
|
||||
async_expire_timeouts(now);
|
||||
timeout = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
timeout = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
for(i=0;i<uwsgi.async_nevents;i++) {
|
||||
for (i = 0; i < uwsgi.async_nevents; i++) {
|
||||
// manage events
|
||||
interesting_fd = event_queue_interesting_fd(events, i);
|
||||
|
||||
if (uwsgi.signal_socket > -1 && (interesting_fd == uwsgi.signal_socket || interesting_fd == uwsgi.my_signal_socket)) {
|
||||
uwsgi_receive_signal(interesting_fd, "worker", uwsgi.mywid);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
is_a_new_connection = 0;
|
||||
|
||||
// new request coming in ?
|
||||
|
||||
uwsgi_sock = uwsgi.sockets;
|
||||
while(uwsgi_sock) {
|
||||
while (uwsgi_sock) {
|
||||
|
||||
if (interesting_fd == uwsgi_sock->fd) {
|
||||
|
||||
is_a_new_connection = 1;
|
||||
is_a_new_connection = 1;
|
||||
|
||||
uwsgi.wsgi_req = find_first_available_wsgi_req();
|
||||
if (uwsgi.wsgi_req == NULL) {
|
||||
now = time(NULL);
|
||||
if (now > last_now) {
|
||||
uwsgi_log("async queue is full !!!\n");
|
||||
last_now = now;
|
||||
}
|
||||
break;;
|
||||
uwsgi_async_queue_is_full((time_t)now);
|
||||
break;
|
||||
}
|
||||
|
||||
wsgi_req_setup(uwsgi.wsgi_req, uwsgi.wsgi_req->async_id, uwsgi_sock );
|
||||
wsgi_req_setup(uwsgi.wsgi_req, uwsgi.wsgi_req->async_id, uwsgi_sock);
|
||||
if (wsgi_req_simple_accept(uwsgi.wsgi_req, interesting_fd)) {
|
||||
#ifdef UWSGI_EVENT_USE_PORT
|
||||
event_queue_add_fd_read(uwsgi.async_queue, interesting_fd);
|
||||
#endif
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
|
||||
break;
|
||||
}
|
||||
#ifdef UWSGI_EVENT_USE_PORT
|
||||
event_queue_add_fd_read(uwsgi.async_queue, interesting_fd);
|
||||
#endif
|
||||
|
||||
// on linux we do not need to reset the socket to blocking state
|
||||
#ifndef __linux__
|
||||
if (uwsgi.numproc > 1) {
|
||||
/* re-set blocking socket */
|
||||
if (fcntl(uwsgi.wsgi_req->poll.fd, F_SETFL, uwsgi_sock->arg) < 0) {
|
||||
uwsgi_error("fcntl()");
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wsgi_req_async_recv(uwsgi.wsgi_req)) {
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
@@ -322,22 +380,21 @@ void *async_loop(void *arg1) {
|
||||
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
|
||||
#ifndef UWSGI_EVENT_USE_PORT
|
||||
event_queue_del_fd(uwsgi.async_queue, interesting_fd, event_queue_read());
|
||||
#endif
|
||||
// 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;
|
||||
}
|
||||
else if (proto_parser_status == -1) {
|
||||
uwsgi_log("error parsing request\n");
|
||||
else if (proto_parser_status < 0) {
|
||||
if (proto_parser_status == -1)
|
||||
uwsgi_log("error parsing request\n");
|
||||
uwsgi.async_proto_fd_table[interesting_fd] = NULL;
|
||||
close(interesting_fd);
|
||||
continue;
|
||||
@@ -356,27 +413,27 @@ void *async_loop(void *arg1) {
|
||||
}
|
||||
|
||||
// remove all the fd monitors and timeout
|
||||
while(uwsgi.wsgi_req->waiting_fds) {
|
||||
#ifndef UWSGI_EVENT_USE_PORT
|
||||
event_queue_del_fd(uwsgi.async_queue, uwsgi.wsgi_req->waiting_fds->fd, uwsgi.wsgi_req->waiting_fds->event);
|
||||
#endif
|
||||
tmp_uaf = uwsgi.wsgi_req->waiting_fds;
|
||||
uwsgi.async_waiting_fd_table[tmp_uaf->fd] = NULL;
|
||||
uwsgi.wsgi_req->waiting_fds = tmp_uaf->next;
|
||||
free(tmp_uaf);
|
||||
}
|
||||
while (uwsgi.wsgi_req->waiting_fds) {
|
||||
tmp_uaf = uwsgi.wsgi_req->waiting_fds;
|
||||
uwsgi.async_waiting_fd_table[tmp_uaf->fd] = NULL;
|
||||
event_queue_del_fd(uwsgi.async_queue, tmp_uaf->fd, tmp_uaf->event);
|
||||
uwsgi.wsgi_req->waiting_fds = tmp_uaf->next;
|
||||
free(tmp_uaf);
|
||||
}
|
||||
uwsgi.wsgi_req->waiting_fds = NULL;
|
||||
if (uwsgi.wsgi_req->async_timeout) {
|
||||
rb_erase(&uwsgi.wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts);
|
||||
free(uwsgi.wsgi_req->async_timeout);
|
||||
uwsgi.wsgi_req->async_timeout = NULL;
|
||||
}
|
||||
if (uwsgi.wsgi_req->async_timeout) {
|
||||
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;
|
||||
}
|
||||
|
||||
uwsgi.wsgi_req->async_ready_fd = 1;
|
||||
uwsgi.wsgi_req->async_last_ready_fd = interesting_fd;
|
||||
|
||||
// put the request in the runqueue again
|
||||
runqueue_push(uwsgi.wsgi_req);
|
||||
// avoid managing other enqueued events...
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,20 +452,18 @@ void *async_loop(void *arg1) {
|
||||
// request ended ?
|
||||
if (uwsgi.wsgi_req->async_status <= UWSGI_OK) {
|
||||
// remove all the monitored fds and timeout
|
||||
while(uwsgi.wsgi_req->waiting_fds) {
|
||||
#ifndef UWSGI_EVENT_USE_PORT
|
||||
event_queue_del_fd(uwsgi.async_queue, uwsgi.wsgi_req->waiting_fds->fd, uwsgi.wsgi_req->waiting_fds->event);
|
||||
#endif
|
||||
while (uwsgi.wsgi_req->waiting_fds) {
|
||||
tmp_uaf = uwsgi.wsgi_req->waiting_fds;
|
||||
uwsgi.async_waiting_fd_table[tmp_uaf->fd] = NULL;
|
||||
event_queue_del_fd(uwsgi.async_queue, tmp_uaf->fd, tmp_uaf->event);
|
||||
uwsgi.wsgi_req->waiting_fds = tmp_uaf->next;
|
||||
free(tmp_uaf);
|
||||
}
|
||||
uwsgi.wsgi_req->waiting_fds = NULL;
|
||||
if (uwsgi.wsgi_req->async_timeout) {
|
||||
rb_erase(&uwsgi.wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts);
|
||||
free(uwsgi.wsgi_req->async_timeout);
|
||||
uwsgi.wsgi_req->async_timeout = NULL;
|
||||
uwsgi_del_rb_timer(uwsgi.rb_async_timeouts, uwsgi.wsgi_req->async_timeout);
|
||||
free(uwsgi.wsgi_req->async_timeout);
|
||||
uwsgi.wsgi_req->async_timeout = NULL;
|
||||
}
|
||||
|
||||
// remove from the list
|
||||
@@ -422,7 +477,7 @@ void *async_loop(void *arg1) {
|
||||
|
||||
}
|
||||
else if (uwsgi.wsgi_req->waiting_fds || uwsgi.wsgi_req->async_timeout) {
|
||||
// remove this request from suspended list
|
||||
// remove this request from suspended list
|
||||
runqueue_remove(current_request);
|
||||
}
|
||||
|
||||
@@ -433,6 +488,4 @@ void *async_loop(void *arg1) {
|
||||
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
+356
@@ -0,0 +1,356 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_buffer *uwsgi_buffer_new(size_t len) {
|
||||
struct uwsgi_buffer *ub = uwsgi_calloc(sizeof(struct uwsgi_buffer));
|
||||
|
||||
if (len) {
|
||||
ub->buf = uwsgi_malloc(len);
|
||||
ub->len = len;
|
||||
}
|
||||
return ub;
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_buffer_fix(struct uwsgi_buffer *ub, size_t len) {
|
||||
if (ub->limit > 0 && len > ub->limit)
|
||||
return -1;
|
||||
if (ub->len < len) {
|
||||
char *new_buf = realloc(ub->buf, len);
|
||||
if (!new_buf) {
|
||||
uwsgi_error("uwsgi_buffer_fix()");
|
||||
return -1;
|
||||
}
|
||||
ub->buf = new_buf;
|
||||
ub->len = len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_ensure(struct uwsgi_buffer *ub, size_t len) {
|
||||
size_t remains = ub->len - ub->pos;
|
||||
if (remains < len) {
|
||||
size_t new_len = ub->len + (len - remains);
|
||||
if (ub->limit > 0 && new_len > ub->limit) {
|
||||
new_len = ub->limit;
|
||||
if (new_len == ub->len)
|
||||
return -1;
|
||||
}
|
||||
char *new_buf = realloc(ub->buf, new_len);
|
||||
if (!new_buf) {
|
||||
uwsgi_error("uwsgi_buffer_ensure()");
|
||||
return -1;
|
||||
}
|
||||
ub->buf = new_buf;
|
||||
ub->len = new_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) {
|
||||
|
||||
size_t remains = ub->len - ub->pos;
|
||||
|
||||
if (len > remains) {
|
||||
size_t chunk_size = UMAX(len, (size_t) uwsgi.page_size);
|
||||
if (ub->limit > 0 && ub->len + chunk_size > ub->limit) {
|
||||
// retry with another minimal size
|
||||
if (len < (size_t) uwsgi.page_size) {
|
||||
chunk_size = len;
|
||||
}
|
||||
if (ub->len + chunk_size > ub->limit)
|
||||
return -1;
|
||||
}
|
||||
char *new_buf = realloc(ub->buf, ub->len + chunk_size);
|
||||
if (!new_buf) {
|
||||
uwsgi_error("uwsgi_buffer_append()");
|
||||
return -1;
|
||||
}
|
||||
ub->buf = new_buf;
|
||||
ub->len += chunk_size;
|
||||
}
|
||||
|
||||
memcpy(ub->buf + ub->pos, buf, len);
|
||||
ub->pos += 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;
|
||||
|
||||
while (remains > 0) {
|
||||
int ret = uwsgi_waitfd_write(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (ret > 0) {
|
||||
ssize_t len = write(fd, ptr, remains);
|
||||
if (len > 0) {
|
||||
ptr += len;
|
||||
remains -= len;
|
||||
}
|
||||
else if (len == 0) {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
uwsgi_error("uwsgi_buffer_send()");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (ret == 0) {
|
||||
uwsgi_log("timeout while sending buffer !!!\n");
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *uwsgi_buffer_from_file(char *filename) {
|
||||
struct stat st;
|
||||
int fd = open(filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fstat(fd, &st)) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(st.st_size);
|
||||
|
||||
ssize_t len = read(fd, ub->buf, st.st_size);
|
||||
close(fd);
|
||||
if (len != st.st_size) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ub->pos = len;
|
||||
return ub;
|
||||
}
|
||||
|
||||
+1698
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,46 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
// in the future we will need to use the best clock source for each os/system
|
||||
time_t uwsgi_now() {
|
||||
return uwsgi.clock->seconds();
|
||||
}
|
||||
|
||||
uint64_t uwsgi_micros() {
|
||||
return uwsgi.clock->microseconds();
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_register_clock(struct uwsgi_clock *clock) {
|
||||
struct uwsgi_clock *clocks = uwsgi.clocks;
|
||||
|
||||
clock->next = NULL;
|
||||
|
||||
if (!clocks) {
|
||||
uwsgi.clocks = clock;
|
||||
return;
|
||||
}
|
||||
|
||||
while (clocks) {
|
||||
if (!clocks->next) {
|
||||
clocks->next = clock;
|
||||
return;
|
||||
}
|
||||
clocks = clocks->next;
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_set_clock(char *name) {
|
||||
struct uwsgi_clock *clocks = uwsgi.clocks;
|
||||
while (clocks) {
|
||||
if (!strcmp(name, clocks->name)) {
|
||||
uwsgi.clock = clocks;
|
||||
return;
|
||||
}
|
||||
clocks = clocks->next;
|
||||
}
|
||||
|
||||
uwsgi_log("unable to set \"%s\" clock\n", name);
|
||||
exit(1);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
|
||||
pluggable configuration system
|
||||
|
||||
*/
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_configurator *uwsgi_register_configurator(char *name, void (*func)(char *, char **)) {
|
||||
struct uwsgi_configurator *old_uc = NULL,*uc = uwsgi.configurators;
|
||||
while(uc) {
|
||||
if (!strcmp(uc->name, name)) {
|
||||
return uc;
|
||||
}
|
||||
old_uc = uc;
|
||||
uc = uc->next;
|
||||
}
|
||||
|
||||
uc = uwsgi_calloc(sizeof(struct uwsgi_configurator));
|
||||
uc->name = name;
|
||||
uc->func = func;
|
||||
|
||||
if (old_uc) {
|
||||
old_uc->next = uc;
|
||||
}
|
||||
else {
|
||||
uwsgi.configurators = uc;
|
||||
}
|
||||
|
||||
return uc;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
|
||||
cookie management functions (mainly used by the internal routing subsystem)
|
||||
|
||||
*/
|
||||
|
||||
static char *check_cookie(char *cookie, uint16_t cookie_len, char *key, uint16_t keylen, uint16_t *vallen) {
|
||||
uint16_t orig_cookie_len = cookie_len-1;
|
||||
// first lstrip white spaces
|
||||
char *ptr = cookie;
|
||||
uint16_t i;
|
||||
for(i=0;i<cookie_len;i++) {
|
||||
if (isspace((int)ptr[i])) {
|
||||
cookie++;
|
||||
cookie_len--;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// then rstrip (skipping the first char...)
|
||||
for(i=orig_cookie_len;i>0;i--) {
|
||||
if (isspace((int)ptr[i])) {
|
||||
cookie_len--;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// now search for the first equal sign
|
||||
char *equal = memchr(cookie, '=', cookie_len);
|
||||
if (!equal) return NULL;
|
||||
|
||||
if (uwsgi_strncmp(key, keylen, cookie, equal-cookie)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cookie_len -= (equal-cookie)+1;
|
||||
if (cookie_len == 0) return NULL;
|
||||
|
||||
*vallen = cookie_len;
|
||||
return equal+1;
|
||||
}
|
||||
|
||||
char *uwsgi_get_cookie(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
|
||||
uint16_t i;
|
||||
|
||||
char *cookie = wsgi_req->cookie;
|
||||
uint16_t cookie_len = 0;
|
||||
char *ptr = wsgi_req->cookie;
|
||||
//start splitting by ;
|
||||
for(i=0;i<wsgi_req->cookie_len;i++) {
|
||||
if (!cookie) {
|
||||
cookie = ptr + i;
|
||||
}
|
||||
if (ptr[i] == ';') {
|
||||
char *value = check_cookie(cookie, cookie_len, key, keylen, vallen);
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
cookie_len = 0;
|
||||
cookie = NULL;
|
||||
}
|
||||
else {
|
||||
cookie_len++;
|
||||
}
|
||||
}
|
||||
|
||||
if (cookie_len > 0) {
|
||||
char *value = check_cookie(cookie, cookie_len, key, keylen, vallen);
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
+314
@@ -0,0 +1,314 @@
|
||||
#include "../uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/*
|
||||
|
||||
External uwsgi daemons
|
||||
|
||||
There are 3 kind of daemons (read: external applications) that can be managed
|
||||
by uWSGI.
|
||||
|
||||
1) dumb daemons (attached with --attach-daemon)
|
||||
they must not daemonize() and when they exit() the master is notified (via waitpid)
|
||||
and the process is respawned
|
||||
2) smart daemons with daemonization
|
||||
you specify a pidfile and a command
|
||||
- on startup - if the pidfile does not exists or contains a not-available pid (checked with kill(pid, 0))
|
||||
the daemon is respawned
|
||||
- on master ckeck - if the pidfile does not exist or if it point to a non-existent pid
|
||||
the daemon is respawned
|
||||
3) smart daemons without daemonization
|
||||
same as 2, but the daemonization and pidfile creation is managed by uWSGI
|
||||
|
||||
status:
|
||||
|
||||
0 -> never started
|
||||
1 -> just started
|
||||
2 -> started and monitored (only in pidfile based)
|
||||
|
||||
*/
|
||||
|
||||
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) {
|
||||
int checked_pid = uwsgi_check_pidfile(ud->pidfile);
|
||||
if (checked_pid <= 0) {
|
||||
// monitored instance
|
||||
if (ud->status == 2) {
|
||||
uwsgi_spawn_daemon(ud);
|
||||
}
|
||||
else {
|
||||
ud->pidfile_checks++;
|
||||
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 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
|
||||
else {
|
||||
ud->status = 2;
|
||||
}
|
||||
}
|
||||
ud = ud->next;
|
||||
}
|
||||
}
|
||||
|
||||
// this function is called when a dumb daemon dies and we do not wat to respawn it
|
||||
int uwsgi_daemon_check_pid_death(pid_t diedpid) {
|
||||
struct uwsgi_daemon *ud = uwsgi.daemons;
|
||||
while (ud) {
|
||||
if (ud->pid == diedpid && !ud->pidfile) {
|
||||
uwsgi_log("daemon \"%s\" (pid: %d) annihilated\n", ud->command, (int) diedpid);
|
||||
return -1;
|
||||
}
|
||||
ud = ud->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// this function is called when a dumb daemon dies and we want to respawn it
|
||||
int uwsgi_daemon_check_pid_reload(pid_t diedpid) {
|
||||
struct uwsgi_daemon *ud = uwsgi.daemons;
|
||||
while (ud) {
|
||||
if (ud->pid == diedpid && !ud->pidfile) {
|
||||
uwsgi_spawn_daemon(ud);
|
||||
return 1;
|
||||
}
|
||||
ud = ud->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int uwsgi_check_pidfile(char *filename) {
|
||||
struct stat st;
|
||||
pid_t ret = -1;
|
||||
int fd = open(filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
uwsgi_error_open(filename);
|
||||
goto end;
|
||||
}
|
||||
if (fstat(fd, &st)) {
|
||||
uwsgi_error("fstat()");
|
||||
goto end2;
|
||||
}
|
||||
char *pidstr = uwsgi_calloc(st.st_size + 1);
|
||||
if (read(fd, pidstr, st.st_size) != st.st_size) {
|
||||
uwsgi_error("read()");
|
||||
goto end3;
|
||||
}
|
||||
pid_t pid = atoi(pidstr);
|
||||
if (pid <= 0)
|
||||
goto end3;
|
||||
if (!kill(pid, 0)) {
|
||||
ret = pid;
|
||||
}
|
||||
end3:
|
||||
free(pidstr);
|
||||
end2:
|
||||
close(fd);
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void uwsgi_daemons_spawn_all() {
|
||||
struct uwsgi_daemon *ud = uwsgi.daemons;
|
||||
while (ud) {
|
||||
if (!ud->registered) {
|
||||
if (ud->pidfile) {
|
||||
int checked_pid = uwsgi_check_pidfile(ud->pidfile);
|
||||
if (checked_pid <= 0) {
|
||||
uwsgi_spawn_daemon(ud);
|
||||
}
|
||||
else {
|
||||
ud->pid = checked_pid;
|
||||
uwsgi_log("[uwsgi-daemons] found valid/active pidfile for \"%s\" (pid: %d)\n", ud->command, (int) ud->pid);
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_spawn_daemon(ud);
|
||||
}
|
||||
ud->registered = 1;
|
||||
}
|
||||
ud = ud->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_detach_daemons() {
|
||||
struct uwsgi_daemon *ud = uwsgi.daemons;
|
||||
while (ud) {
|
||||
if (ud->pid > 0 && !ud->pidfile)
|
||||
kill(-ud->pid, SIGKILL);
|
||||
ud = ud->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
|
||||
|
||||
int devnull = -1;
|
||||
int throttle = 0;
|
||||
|
||||
if (uwsgi.current_time - ud->last_spawn <= 3) {
|
||||
throttle = ud->respawns - (uwsgi.current_time - ud->last_spawn);
|
||||
}
|
||||
|
||||
pid_t pid = uwsgi_fork("uWSGI external daemon");
|
||||
if (pid < 0) {
|
||||
uwsgi_error("fork()");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pid > 0) {
|
||||
ud->pid = pid;
|
||||
ud->status = 1;
|
||||
ud->pidfile_checks = 0;
|
||||
if (ud->respawns == 0) {
|
||||
ud->born = uwsgi_now();
|
||||
}
|
||||
|
||||
ud->respawns++;
|
||||
ud->last_spawn = uwsgi_now();
|
||||
|
||||
}
|
||||
else {
|
||||
// close uwsgi sockets
|
||||
uwsgi_close_all_sockets();
|
||||
uwsgi_close_all_fds();
|
||||
|
||||
if (ud->daemonize) {
|
||||
/* refork... */
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
uwsgi_error("fork()");
|
||||
exit(1);
|
||||
}
|
||||
if (pid != 0) {
|
||||
_exit(0);
|
||||
}
|
||||
uwsgi_write_pidfile(ud->pidfile);
|
||||
}
|
||||
|
||||
if (!uwsgi.daemons_honour_stdin) {
|
||||
// /dev/null will became stdin
|
||||
devnull = open("/dev/null", O_RDONLY);
|
||||
if (devnull < 0) {
|
||||
uwsgi_error("/dev/null open()");
|
||||
exit(1);
|
||||
}
|
||||
if (devnull != 0) {
|
||||
if (dup2(devnull, 0) < 0) {
|
||||
uwsgi_error("dup2()");
|
||||
exit(1);
|
||||
}
|
||||
close(devnull);
|
||||
}
|
||||
}
|
||||
|
||||
if (setsid() < 0) {
|
||||
uwsgi_error("setsid()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!ud->pidfile) {
|
||||
#ifdef __linux__
|
||||
if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) {
|
||||
uwsgi_error("prctl()");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
if (throttle) {
|
||||
uwsgi_log("[uwsgi-daemons] throttling \"%s\" for %d seconds\n", ud->command, throttle);
|
||||
sleep(throttle);
|
||||
}
|
||||
|
||||
uwsgi_log("[uwsgi-daemons] %sspawning \"%s\"\n", ud->respawns > 0 ? "re" : "", ud->command);
|
||||
uwsgi_exec_command_with_args(ud->command);
|
||||
uwsgi_log("[uwsgi-daemons] unable to spawn \"%s\"\n", ud->command);
|
||||
|
||||
// never here;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_opt_add_daemon(char *opt, char *value, void *none) {
|
||||
|
||||
struct uwsgi_daemon *uwsgi_ud = uwsgi.daemons, *old_ud;
|
||||
char *pidfile = NULL;
|
||||
int daemonize = 0;
|
||||
int freq = 10;
|
||||
|
||||
char *command = uwsgi_str(value);
|
||||
|
||||
if (!strcmp(opt, "smart-attach-daemon") || !strcmp(opt, "smart-attach-daemon2")) {
|
||||
char *space = strchr(command, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid smart-attach-daemon syntax: %s\n", command);
|
||||
exit(1);
|
||||
}
|
||||
*space = 0;
|
||||
pidfile = command;
|
||||
// check for freq
|
||||
char *comma = strchr(pidfile, ',');
|
||||
if (comma) {
|
||||
*comma = 0;
|
||||
freq = atoi(comma + 1);
|
||||
}
|
||||
command = space + 1;
|
||||
if (!strcmp(opt, "smart-attach-daemon2")) {
|
||||
daemonize = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!uwsgi_ud) {
|
||||
uwsgi.daemons = uwsgi_malloc(sizeof(struct uwsgi_daemon));
|
||||
uwsgi_ud = uwsgi.daemons;
|
||||
}
|
||||
else {
|
||||
while (uwsgi_ud) {
|
||||
old_ud = uwsgi_ud;
|
||||
uwsgi_ud = uwsgi_ud->next;
|
||||
}
|
||||
|
||||
uwsgi_ud = uwsgi_malloc(sizeof(struct uwsgi_daemon));
|
||||
old_ud->next = uwsgi_ud;
|
||||
}
|
||||
|
||||
uwsgi_ud->command = command;
|
||||
uwsgi_ud->pid = 0;
|
||||
uwsgi_ud->status = 0;
|
||||
uwsgi_ud->freq = freq;
|
||||
uwsgi_ud->registered = 0;
|
||||
uwsgi_ud->next = NULL;
|
||||
uwsgi_ud->respawns = 0;
|
||||
uwsgi_ud->last_spawn = 0;
|
||||
uwsgi_ud->daemonize = daemonize;
|
||||
uwsgi_ud->pidfile = pidfile;
|
||||
|
||||
uwsgi.daemons_cnt++;
|
||||
|
||||
}
|
||||
+1700
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
|
||||
+1394
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_gateway *register_gateway(char *name, void (*loop) (int, void *), void *data) {
|
||||
|
||||
struct uwsgi_gateway *ug;
|
||||
int num = 1, i;
|
||||
|
||||
if (ushared->gateways_cnt >= MAX_GATEWAYS) {
|
||||
uwsgi_log("you can register max %d gateways\n", MAX_GATEWAYS);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ushared->gateways_cnt; i++) {
|
||||
if (!strcmp(name, ushared->gateways[i].name)) {
|
||||
num++;
|
||||
}
|
||||
}
|
||||
|
||||
char *fullname = uwsgi_concat3(name, " ", uwsgi_num2str(num));
|
||||
|
||||
ug = &ushared->gateways[ushared->gateways_cnt];
|
||||
ug->pid = 0;
|
||||
ug->name = name;
|
||||
ug->loop = loop;
|
||||
ug->num = num;
|
||||
ug->fullname = fullname;
|
||||
ug->data = data;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, ug->internal_subscription_pipe)) {
|
||||
uwsgi_error("socketpair()");
|
||||
}
|
||||
|
||||
if (!uwsgi.master_process)
|
||||
gateway_respawn(ushared->gateways_cnt);
|
||||
|
||||
ushared->gateways_cnt++;
|
||||
|
||||
|
||||
return ug;
|
||||
}
|
||||
|
||||
static void gateway_brutal_end() {
|
||||
_exit(UWSGI_END_CODE);
|
||||
}
|
||||
|
||||
void gateway_respawn(int id) {
|
||||
|
||||
pid_t gw_pid;
|
||||
struct uwsgi_gateway *ug = &ushared->gateways[id];
|
||||
|
||||
if (uwsgi.master_process)
|
||||
uwsgi.shared->gateways_harakiri[id] = 0;
|
||||
|
||||
gw_pid = uwsgi_fork(ug->fullname);
|
||||
if (gw_pid < 0) {
|
||||
uwsgi_error("fork()");
|
||||
return;
|
||||
}
|
||||
|
||||
if (gw_pid == 0) {
|
||||
uwsgi_fixup_fds(0, 0, ug);
|
||||
if (uwsgi.master_as_root)
|
||||
uwsgi_as_root();
|
||||
#ifdef __linux__
|
||||
if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) {
|
||||
uwsgi_error("prctl()");
|
||||
}
|
||||
#endif
|
||||
uwsgi.mypid = getpid();
|
||||
atexit(gateway_brutal_end);
|
||||
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);
|
||||
|
||||
ug->loop(id, ug->data);
|
||||
// never here !!! (i hope)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ug->pid = gw_pid;
|
||||
ug->respawns++;
|
||||
if (ug->respawns == 1) {
|
||||
uwsgi_log("spawned %s %d (pid: %d)\n", ug->name, ug->num, (int) gw_pid);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("respawned %s %d (pid: %d)\n", ug->name, ug->num, (int) gw_pid);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_gateway_socket *uwsgi_new_gateway_socket(char *name, char *owner) {
|
||||
|
||||
struct uwsgi_gateway_socket *uwsgi_sock = uwsgi.gateway_sockets, *old_uwsgi_sock;
|
||||
|
||||
if (!uwsgi_sock) {
|
||||
uwsgi.gateway_sockets = uwsgi_malloc(sizeof(struct uwsgi_gateway_socket));
|
||||
uwsgi_sock = uwsgi.gateway_sockets;
|
||||
}
|
||||
else {
|
||||
while (uwsgi_sock) {
|
||||
old_uwsgi_sock = uwsgi_sock;
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
uwsgi_sock = uwsgi_malloc(sizeof(struct uwsgi_gateway_socket));
|
||||
old_uwsgi_sock->next = uwsgi_sock;
|
||||
}
|
||||
|
||||
memset(uwsgi_sock, 0, sizeof(struct uwsgi_gateway_socket));
|
||||
uwsgi_sock->fd = -1;
|
||||
uwsgi_sock->shared = 0;
|
||||
uwsgi_sock->name = name;
|
||||
uwsgi_sock->name_len = strlen(name);
|
||||
uwsgi_sock->owner = owner;
|
||||
|
||||
return uwsgi_sock;
|
||||
}
|
||||
|
||||
struct uwsgi_gateway_socket *uwsgi_new_gateway_socket_from_fd(int fd, char *owner) {
|
||||
|
||||
struct uwsgi_gateway_socket *uwsgi_sock = uwsgi.gateway_sockets, *old_uwsgi_sock;
|
||||
|
||||
if (!uwsgi_sock) {
|
||||
uwsgi.gateway_sockets = uwsgi_malloc(sizeof(struct uwsgi_gateway_socket));
|
||||
uwsgi_sock = uwsgi.gateway_sockets;
|
||||
}
|
||||
else {
|
||||
while (uwsgi_sock) {
|
||||
old_uwsgi_sock = uwsgi_sock;
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
uwsgi_sock = uwsgi_malloc(sizeof(struct uwsgi_gateway_socket));
|
||||
old_uwsgi_sock->next = uwsgi_sock;
|
||||
}
|
||||
|
||||
memset(uwsgi_sock, 0, sizeof(struct uwsgi_gateway_socket));
|
||||
uwsgi_sock->fd = fd;
|
||||
uwsgi_sock->name = uwsgi_getsockname(fd);
|
||||
uwsgi_sock->name_len = strlen(uwsgi_sock->name);
|
||||
uwsgi_sock->owner = owner;
|
||||
|
||||
return uwsgi_sock;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_gateway_go_cheap(char *gw_id, int queue, int *i_am_cheap) {
|
||||
|
||||
uwsgi_log("[%s pid %d] no more nodes available. Going cheap...\n", gw_id, (int) uwsgi.mypid);
|
||||
struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets;
|
||||
while (ugs) {
|
||||
if (!strcmp(ugs->owner, gw_id) && !ugs->subscription) {
|
||||
event_queue_del_fd(queue, ugs->fd, event_queue_read());
|
||||
}
|
||||
ugs = ugs->next;
|
||||
}
|
||||
*i_am_cheap = 1;
|
||||
}
|
||||
+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);
|
||||
}
|
||||
+34
-25
@@ -1,6 +1,4 @@
|
||||
#ifdef UWSGI_INI
|
||||
|
||||
#include "uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
@@ -9,11 +7,13 @@ extern struct uwsgi_server uwsgi;
|
||||
This memory must not be freed for all the server lifecycle
|
||||
*/
|
||||
|
||||
static char *last_file = NULL;
|
||||
|
||||
void ini_rstrip(char *line) {
|
||||
|
||||
off_t i;
|
||||
|
||||
for(i = strlen(line)-1;i>=0; i--) {
|
||||
for (i = strlen(line) - 1; i >= 0; i--) {
|
||||
if (line[i] == ' ' || line[i] == '\t' || line[i] == '\r') {
|
||||
line[i] = 0;
|
||||
continue;
|
||||
@@ -27,7 +27,7 @@ char *ini_lstrip(char *line) {
|
||||
off_t i;
|
||||
char *ptr = line;
|
||||
|
||||
for(i=0;i< (int) strlen(line);i++) {
|
||||
for (i = 0; i < (int) strlen(line); i++) {
|
||||
if (line[i] == ' ' || line[i] == '\t' || line[i] == '\r') {
|
||||
ptr++;
|
||||
continue;
|
||||
@@ -43,7 +43,7 @@ char *ini_get_key(char *key) {
|
||||
off_t i;
|
||||
char *ptr = key;
|
||||
|
||||
for(i=0;i< (int) strlen(key);i++) {
|
||||
for (i = 0; i < (int) strlen(key); i++) {
|
||||
ptr++;
|
||||
if (key[i] == '=') {
|
||||
key[i] = 0;
|
||||
@@ -54,12 +54,12 @@ 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++) {
|
||||
for (i = 0; i < size; i++) {
|
||||
ptr++;
|
||||
if (ini[i] == '\n') {
|
||||
ini[i] = 0;
|
||||
@@ -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;
|
||||
@@ -92,28 +92,39 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
char *section_asked = "uwsgi";
|
||||
char *colon;
|
||||
|
||||
|
||||
if (uwsgi_check_scheme(file)) {
|
||||
colon = uwsgi_get_last_char(file, '/');
|
||||
colon = uwsgi_get_last_char(colon, ':');
|
||||
}
|
||||
else {
|
||||
colon = uwsgi_get_last_char(file, ':');
|
||||
}
|
||||
colon = uwsgi_get_last_char(file, '/');
|
||||
colon = uwsgi_get_last_char(colon, ':');
|
||||
}
|
||||
else {
|
||||
colon = uwsgi_get_last_char(file, ':');
|
||||
}
|
||||
|
||||
if (colon) {
|
||||
colon[0] = 0;
|
||||
if (colon[1] != 0) {
|
||||
section_asked = colon+1;
|
||||
section_asked = colon + 1;
|
||||
}
|
||||
|
||||
if (colon == file) {
|
||||
file = last_file;
|
||||
}
|
||||
}
|
||||
|
||||
if (file[0] != 0) {
|
||||
uwsgi_log("[uWSGI] getting INI configuration from %s\n", file);
|
||||
if (file[0] != 0 && file != last_file) {
|
||||
uwsgi_log_initial("[uWSGI] getting INI configuration from %s\n", file);
|
||||
}
|
||||
|
||||
ini = uwsgi_open_and_read(file, &len, 1, magic_table);
|
||||
if (file != last_file) {
|
||||
if (last_file) {
|
||||
free(last_file);
|
||||
}
|
||||
last_file = uwsgi_str(file);
|
||||
}
|
||||
|
||||
while(len) {
|
||||
while (len) {
|
||||
ini_line = ini_get_line(ini, len);
|
||||
if (ini_line == NULL) {
|
||||
break;
|
||||
@@ -125,8 +136,8 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
ini_rstrip(key);
|
||||
if (key[0] != 0) {
|
||||
if (key[0] == '[') {
|
||||
section = key+1;
|
||||
section[strlen(section)-1] = 0;
|
||||
section = key + 1;
|
||||
section[strlen(section) - 1] = 0;
|
||||
}
|
||||
else if (key[0] == ';' || key[0] == '#') {
|
||||
// this is a comment
|
||||
@@ -139,7 +150,7 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
ini_rstrip(key);
|
||||
val = ini_lstrip(val);
|
||||
ini_rstrip(val);
|
||||
add_exported_option((char *)key, val, 0);
|
||||
add_exported_option((char *) key, val, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -156,5 +167,3 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+450
@@ -0,0 +1,450 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
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;
|
||||
|
||||
uwsgi.backtrace_depth = 64;
|
||||
uwsgi.max_apps = 64;
|
||||
|
||||
uwsgi.master_queue = -1;
|
||||
|
||||
uwsgi.signal_socket = -1;
|
||||
uwsgi.my_signal_socket = -1;
|
||||
uwsgi.stats_fd = -1;
|
||||
|
||||
uwsgi.stats_pusher_default_freq = 3;
|
||||
|
||||
uwsgi.original_log_fd = -1;
|
||||
|
||||
uwsgi.emperor_fd_config = -1;
|
||||
// default emperor scan frequency
|
||||
uwsgi.emperor_freq = 3;
|
||||
uwsgi.emperor_throttle = 1000;
|
||||
uwsgi.emperor_heartbeat = 30;
|
||||
// max 3 minutes throttling
|
||||
uwsgi.emperor_max_throttle = 1000 * 180;
|
||||
uwsgi.emperor_pid = -1;
|
||||
|
||||
uwsgi.subscribe_freq = 10;
|
||||
uwsgi.subscription_tolerance = 17;
|
||||
|
||||
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;
|
||||
|
||||
uwsgi.async = 1;
|
||||
uwsgi.listen_queue = 100;
|
||||
|
||||
uwsgi.cheaper_overload = 3;
|
||||
|
||||
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;
|
||||
|
||||
// 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;
|
||||
|
||||
uwsgi.shared->mule_signal_pipe[0] = -1;
|
||||
uwsgi.shared->mule_signal_pipe[1] = -1;
|
||||
|
||||
uwsgi.shared->mule_queue_pipe[0] = -1;
|
||||
uwsgi.shared->mule_queue_pipe[1] = -1;
|
||||
|
||||
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
|
||||
|
||||
uwsgi.alarm_freq = 3;
|
||||
uwsgi.alarm_msg_size = 8192;
|
||||
|
||||
uwsgi.exception_handler_msg_size = 65536;
|
||||
|
||||
uwsgi.multicast_ttl = 1;
|
||||
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() {
|
||||
|
||||
char env_reload_buf[11];
|
||||
|
||||
char *env_reloads = getenv("UWSGI_RELOADS");
|
||||
if (env_reloads) {
|
||||
//convert env value to int
|
||||
uwsgi.reloads = atoi(env_reloads);
|
||||
uwsgi.reloads++;
|
||||
//convert reloads to string
|
||||
int rlen = snprintf(env_reload_buf, 10, "%u", uwsgi.reloads);
|
||||
if (rlen > 0) {
|
||||
env_reload_buf[rlen] = 0;
|
||||
if (setenv("UWSGI_RELOADS", env_reload_buf, 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
}
|
||||
uwsgi.is_a_reload = 1;
|
||||
}
|
||||
else {
|
||||
if (setenv("UWSGI_RELOADS", "0", 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_autoload_plugins_by_name(char *argv_zero) {
|
||||
|
||||
char *plugins_requested = NULL;
|
||||
|
||||
char *original_proc_name = getenv("UWSGI_ORIGINAL_PROC_NAME");
|
||||
if (!original_proc_name) {
|
||||
// here we use argv[0];
|
||||
original_proc_name = argv_zero;
|
||||
setenv("UWSGI_ORIGINAL_PROC_NAME", original_proc_name, 1);
|
||||
}
|
||||
char *p = strrchr(original_proc_name, '/');
|
||||
if (p == NULL)
|
||||
p = original_proc_name;
|
||||
p = strstr(p, "uwsgi_");
|
||||
if (p != NULL) {
|
||||
plugins_requested = strtok(uwsgi_str(p + 6), "_");
|
||||
while (plugins_requested) {
|
||||
uwsgi_log("[uwsgi] implicit plugin requested %s\n", plugins_requested);
|
||||
uwsgi_load_plugin(-1, plugins_requested, NULL);
|
||||
plugins_requested = strtok(NULL, "_");
|
||||
}
|
||||
}
|
||||
|
||||
plugins_requested = getenv("UWSGI_PLUGINS");
|
||||
if (plugins_requested) {
|
||||
plugins_requested = uwsgi_concat2(plugins_requested, "");
|
||||
char *p = strtok(plugins_requested, ",");
|
||||
while (p != NULL) {
|
||||
uwsgi_load_plugin(-1, p, NULL);
|
||||
p = strtok(NULL, ",");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_commandline_config() {
|
||||
int i;
|
||||
|
||||
uwsgi.option_index = -1;
|
||||
|
||||
char *optname;
|
||||
while ((i = getopt_long(uwsgi.argc, uwsgi.argv, uwsgi.short_options, uwsgi.long_options, &uwsgi.option_index)) != -1) {
|
||||
|
||||
if (i == '?') {
|
||||
uwsgi_log("getopt_long() error\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (uwsgi.option_index > -1) {
|
||||
optname = (char *) uwsgi.long_options[uwsgi.option_index].name;
|
||||
}
|
||||
else {
|
||||
optname = uwsgi_get_optname_by_index(i);
|
||||
}
|
||||
if (!optname) {
|
||||
uwsgi_log("unable to parse command line options\n");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi.option_index = -1;
|
||||
add_exported_option(optname, optarg, 0);
|
||||
}
|
||||
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("optind:%d argc:%d\n", optind, uwsgi.argc);
|
||||
#endif
|
||||
|
||||
if (optind < uwsgi.argc) {
|
||||
for (i = optind; i < uwsgi.argc; i++) {
|
||||
char *lazy = uwsgi.argv[i];
|
||||
if (lazy[0] != '[') {
|
||||
uwsgi_opt_load(NULL, lazy, NULL);
|
||||
// manage magic mountpoint
|
||||
int magic = 0;
|
||||
int j;
|
||||
for (j = 0; j < uwsgi.gp_cnt; j++) {
|
||||
if (uwsgi.gp[j]->magic) {
|
||||
if (uwsgi.gp[j]->magic(NULL, lazy)) {
|
||||
magic = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!magic) {
|
||||
for (j = 0; j < 256; j++) {
|
||||
if (uwsgi.p[j]->magic) {
|
||||
if (uwsgi.p[j]->magic(NULL, lazy)) {
|
||||
magic = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_setup_workers() {
|
||||
int i, j;
|
||||
// allocate shared memory for workers + master
|
||||
uwsgi.workers = (struct uwsgi_worker *) uwsgi_calloc_shared(sizeof(struct uwsgi_worker) * (uwsgi.numproc + 1));
|
||||
|
||||
for (i = 0; i <= uwsgi.numproc; i++) {
|
||||
// allocate memory for apps
|
||||
uwsgi.workers[i].apps = (struct uwsgi_app *) uwsgi_calloc_shared(sizeof(struct uwsgi_app) * uwsgi.max_apps);
|
||||
|
||||
// allocate memory for cores
|
||||
uwsgi.workers[i].cores = (struct uwsgi_core *) uwsgi_calloc_shared(sizeof(struct uwsgi_core) * uwsgi.cores);
|
||||
|
||||
// this is a trick for avoiding too much memory areas
|
||||
void *ts = uwsgi_calloc_shared(sizeof(void *) * uwsgi.max_apps * 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)
|
||||
post_buf = uwsgi_malloc_shared(uwsgi.post_buffering_bufsize * uwsgi.cores);
|
||||
|
||||
|
||||
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 (+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)
|
||||
uwsgi.workers[i].cores[j].post_buf = post_buf + (uwsgi.post_buffering_bufsize * j);
|
||||
}
|
||||
|
||||
// master does not need to following steps...
|
||||
if (i == 0)
|
||||
continue;
|
||||
uwsgi.workers[i].signal_pipe[0] = -1;
|
||||
uwsgi.workers[i].signal_pipe[1] = -1;
|
||||
snprintf(uwsgi.workers[i].name, 0xff, "uWSGI worker %d", i);
|
||||
snprintf(uwsgi.workers[i].snapshot_name, 0xff, "uWSGI snapshot %d", i);
|
||||
}
|
||||
|
||||
uint64_t total_memory = (sizeof(struct uwsgi_app) * uwsgi.max_apps) + (sizeof(struct uwsgi_core) * uwsgi.cores) + (sizeof(void *) * uwsgi.max_apps * uwsgi.cores) + (uwsgi.buffer_size * uwsgi.cores) + (sizeof(struct iovec) * uwsgi.vec_size * uwsgi.cores);
|
||||
if (uwsgi.post_buffering > 0) {
|
||||
total_memory += (uwsgi.post_buffering_bufsize * uwsgi.cores);
|
||||
}
|
||||
|
||||
total_memory *= (uwsgi.numproc + uwsgi.master_process);
|
||||
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));
|
||||
|
||||
}
|
||||
|
||||
pid_t uwsgi_daemonize2() {
|
||||
if (uwsgi.has_emperor) {
|
||||
logto(uwsgi.daemonize2);
|
||||
}
|
||||
else {
|
||||
if (!uwsgi.is_a_reload) {
|
||||
uwsgi_log("*** daemonizing uWSGI ***\n");
|
||||
daemonize(uwsgi.daemonize2);
|
||||
}
|
||||
else if (uwsgi.log_reopen) {
|
||||
logto(uwsgi.daemonize2);
|
||||
}
|
||||
}
|
||||
uwsgi.mypid = getpid();
|
||||
|
||||
uwsgi.workers[0].pid = uwsgi.mypid;
|
||||
|
||||
if (uwsgi.pidfile && !uwsgi.is_a_reload) {
|
||||
uwsgi_write_pidfile(uwsgi.pidfile);
|
||||
}
|
||||
|
||||
if (uwsgi.pidfile2 && !uwsgi.is_a_reload) {
|
||||
uwsgi_write_pidfile(uwsgi.pidfile2);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
#ifdef UWSGI_JSON
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#include <jansson.h>
|
||||
|
||||
|
||||
/*
|
||||
I really love the jansson library...
|
||||
*/
|
||||
|
||||
void uwsgi_json_config(char *file, char *magic_table[]) {
|
||||
|
||||
size_t len = 0;
|
||||
char *json_data;
|
||||
|
||||
|
||||
const char *key;
|
||||
|
||||
json_t *root;
|
||||
json_error_t error;
|
||||
json_t *config;
|
||||
json_t *config_value, *config_array_item;
|
||||
|
||||
void *config_iter;
|
||||
|
||||
char *object_asked = "uwsgi";
|
||||
char *colon;
|
||||
int i;
|
||||
|
||||
if (uwsgi_check_scheme(file)) {
|
||||
colon = uwsgi_get_last_char(file, '/');
|
||||
colon = uwsgi_get_last_char(colon, ':');
|
||||
}
|
||||
else {
|
||||
colon = uwsgi_get_last_char(file, ':');
|
||||
}
|
||||
|
||||
if (colon) {
|
||||
colon[0] = 0;
|
||||
if (colon[1] != 0) {
|
||||
object_asked = colon + 1;
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log_initial("[uWSGI] getting JSON configuration from %s\n", file);
|
||||
|
||||
json_data = uwsgi_open_and_read(file, &len, 1, magic_table);
|
||||
|
||||
#ifdef JANSSON_MAJOR_VERSION
|
||||
root = json_loads(json_data, 0, &error);
|
||||
#else
|
||||
root = json_loads(json_data, &error);
|
||||
#endif
|
||||
|
||||
if (!root) {
|
||||
uwsgi_log("error parsing JSON data: line %d %s\n", error.line, error.text);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
config = json_object_get(root, object_asked);
|
||||
|
||||
if (!json_is_object(config)) {
|
||||
uwsgi_log("you must define a object named %s in your JSON data\n", object_asked);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
config_iter = json_object_iter(config);
|
||||
|
||||
while (config_iter) {
|
||||
key = json_object_iter_key(config_iter);
|
||||
config_value = json_object_iter_value(config_iter);
|
||||
|
||||
if (json_is_string(config_value)) {
|
||||
add_exported_option((char *) key, (char *) json_string_value(config_value), 0);
|
||||
}
|
||||
else if (json_is_true(config_value)) {
|
||||
add_exported_option((char *) key, strdup("1"), 0);
|
||||
}
|
||||
else if (json_is_false(config_value) || json_is_null(config_value)) {
|
||||
add_exported_option((char *) key, strdup("0"), 0);
|
||||
}
|
||||
else if (json_is_integer(config_value)) {
|
||||
add_exported_option((char *) key, uwsgi_num2str(json_integer_value(config_value)), 0);
|
||||
}
|
||||
else if (json_is_array(config_value)) {
|
||||
for (i = 0; i < (int) json_array_size(config_value); i++) {
|
||||
config_array_item = json_array_get(config_value, i);
|
||||
if (json_is_string(config_array_item)) {
|
||||
add_exported_option((char *) key, (char *) json_string_value(config_array_item), 0);
|
||||
}
|
||||
else if (json_is_true(config_array_item)) {
|
||||
add_exported_option((char *) key, strdup("1"), 0);
|
||||
}
|
||||
else if (json_is_false(config_array_item) || json_is_null(config_array_item)) {
|
||||
add_exported_option((char *) key, strdup("0"), 0);
|
||||
}
|
||||
else if (json_is_integer(config_array_item)) {
|
||||
add_exported_option((char *) key, uwsgi_num2str(json_integer_value(config_array_item)), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config_iter = json_object_iter_next(config, config_iter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+68
-67
@@ -19,25 +19,25 @@ void ldap2uwsgi(char *ldapname, char *uwsginame) {
|
||||
|
||||
int i;
|
||||
|
||||
for(i=0;i< (int) strlen(ldapname);i++) {
|
||||
if (isupper( (int)ldapname[i])) {
|
||||
for (i = 0; i < (int) strlen(ldapname); i++) {
|
||||
if (isupper((int) ldapname[i])) {
|
||||
*ptr++ = '-';
|
||||
*ptr++ = tolower( (int) ldapname[i]);
|
||||
*ptr++ = tolower((int) ldapname[i]);
|
||||
}
|
||||
else {
|
||||
*ptr++ = ldapname[i];
|
||||
}
|
||||
}
|
||||
|
||||
*ptr++= 0;
|
||||
*ptr++ = 0;
|
||||
}
|
||||
|
||||
int calc_ldap_name(char *name) {
|
||||
int i;
|
||||
int counter = 0;
|
||||
|
||||
for(i=0;i< (int)strlen(name);i++) {
|
||||
if (isupper( (int) name[i])) {
|
||||
for (i = 0; i < (int) strlen(name); i++) {
|
||||
if (isupper((int) name[i])) {
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ struct uwsgi_ldap_entry {
|
||||
};
|
||||
|
||||
|
||||
void uwsgi_name_to_ldap(char *src, char *dst) {
|
||||
void uwsgi_name_to_ldap(char *src, char *dst) {
|
||||
|
||||
int i;
|
||||
char *ptr = dst;
|
||||
@@ -61,16 +61,16 @@ void uwsgi_name_to_ldap(char *src, char *dst) {
|
||||
|
||||
strcat(dst, " 'uWSGI");
|
||||
|
||||
ptr+= 7;
|
||||
ptr += 7;
|
||||
|
||||
for(i=0;i< (int)strlen(src);i++) {
|
||||
if (src[i] == '-') {
|
||||
i++;
|
||||
*ptr++= toupper( (int) src[i]);
|
||||
}
|
||||
else {
|
||||
*ptr++= src[i];
|
||||
}
|
||||
for (i = 0; i < (int) strlen(src); i++) {
|
||||
if (src[i] == '-') {
|
||||
i++;
|
||||
*ptr++ = toupper((int) src[i]);
|
||||
}
|
||||
else {
|
||||
*ptr++ = src[i];
|
||||
}
|
||||
}
|
||||
|
||||
strcat(dst, "'");
|
||||
@@ -82,7 +82,7 @@ struct uwsgi_ldap_entry *get_ldap_by_num(struct uwsgi_ldap_entry *root, int num,
|
||||
int i;
|
||||
struct uwsgi_ldap_entry *ule;
|
||||
|
||||
for(i=0;i<count;i++) {
|
||||
for (i = 0; i < count; i++) {
|
||||
ule = &root[i];
|
||||
if (ule->num == num) {
|
||||
return ule;
|
||||
@@ -96,9 +96,9 @@ struct uwsgi_ldap_entry *search_ldap_cache(struct uwsgi_ldap_entry *root, char *
|
||||
int i;
|
||||
struct uwsgi_ldap_entry *ule;
|
||||
|
||||
for(i=0;i<count;i++) {
|
||||
for (i = 0; i < count; i++) {
|
||||
ule = &root[i];
|
||||
if (uwsgi_list_has_str(ule->names, name+1)) {
|
||||
if (uwsgi_list_has_str(ule->names, name + 1)) {
|
||||
return ule;
|
||||
}
|
||||
}
|
||||
@@ -114,23 +114,24 @@ struct uwsgi_ldap_entry *get_ldap_names(int *count) {
|
||||
|
||||
*count = 0;
|
||||
|
||||
ule = uwsgi_malloc(sizeof(struct uwsgi_ldap_entry)*uwsgi_count_options(op));
|
||||
ule = uwsgi_malloc(sizeof(struct uwsgi_ldap_entry) * uwsgi_count_options(op));
|
||||
|
||||
while( op && op->name ) {
|
||||
while (op && op->name) {
|
||||
|
||||
uwsgi_name_to_ldap((char *)op->name, ldap_name);
|
||||
uwsgi_name_to_ldap((char *) op->name, ldap_name);
|
||||
|
||||
entry = search_ldap_cache(ule, ldap_name, *count);
|
||||
|
||||
if (entry) goto next;
|
||||
if (entry)
|
||||
goto next;
|
||||
|
||||
entry = &ule[*count] ;
|
||||
entry = &ule[*count];
|
||||
entry->num = *count;
|
||||
strcpy(entry->names, ldap_name);
|
||||
*count = *count+1;
|
||||
*count = *count + 1;
|
||||
|
||||
entry->has_arg = op->type;
|
||||
|
||||
|
||||
next:
|
||||
op++;
|
||||
}
|
||||
@@ -150,7 +151,7 @@ void uwsgi_opt_ldap_dump_ldif(char *opt, char *foo, void *bar) {
|
||||
|
||||
struct uwsgi_ldap_entry *entry, *ule = get_ldap_names(&items);
|
||||
|
||||
for(i=0;i<items;i++) {
|
||||
for (i = 0; i < items; i++) {
|
||||
|
||||
entry = &ule[i];
|
||||
uwsgi_log("olcAttributeTypes: ( 1.3.6.1.4.1.35156.17.4.%d NAME (%s", entry->num, entry->names);
|
||||
@@ -168,19 +169,19 @@ void uwsgi_opt_ldap_dump_ldif(char *opt, char *foo, void *bar) {
|
||||
|
||||
uwsgi_log("olcObjectClasses: ( 1.3.6.1.4.1.35156.17.3.1 NAME 'uWSGIConfig' SUP top AUXILIARY DESC 'uWSGI configuration' MAY ( ");
|
||||
|
||||
|
||||
for(i=0;i<items;i++) {
|
||||
|
||||
entry = &ule[i];
|
||||
for (i = 0; i < items; i++) {
|
||||
|
||||
char *list2 = uwsgi_concat2(entry->names+1, "");
|
||||
entry = &ule[i];
|
||||
|
||||
char *list2 = uwsgi_concat2(entry->names + 1, "");
|
||||
char *p = strtok(list2, " ");
|
||||
while (p != NULL) {
|
||||
uwsgi_log("%.*s $ ", strlen(p)-2, p+1);
|
||||
p = strtok(NULL, " ");
|
||||
}
|
||||
while (p != NULL) {
|
||||
uwsgi_log("%.*s $ ", strlen(p) - 2, p + 1);
|
||||
p = strtok(NULL, " ");
|
||||
}
|
||||
|
||||
free(list2);
|
||||
free(list2);
|
||||
|
||||
}
|
||||
|
||||
@@ -198,38 +199,38 @@ void uwsgi_opt_ldap_dump(char *opt, char *foo, void *bar) {
|
||||
|
||||
struct uwsgi_ldap_entry *entry, *ule = get_ldap_names(&items);
|
||||
|
||||
for(i=0;i<items;i++) {
|
||||
for (i = 0; i < items; i++) {
|
||||
|
||||
entry = &ule[i];
|
||||
uwsgi_log("attributetype ( 1.3.6.1.4.1.35156.17.4.%d NAME (%s", entry->num, entry->names);
|
||||
entry = &ule[i];
|
||||
uwsgi_log("attributetype ( 1.3.6.1.4.1.35156.17.4.%d NAME (%s", entry->num, entry->names);
|
||||
|
||||
if (entry->has_arg) {
|
||||
uwsgi_log(" ) SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )\n");
|
||||
}
|
||||
else {
|
||||
uwsgi_log(" ) SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )\n");
|
||||
}
|
||||
}
|
||||
if (entry->has_arg) {
|
||||
uwsgi_log(" ) SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )\n");
|
||||
}
|
||||
else {
|
||||
uwsgi_log(" ) SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uwsgi_log("attributetype ( 1.3.6.1.4.1.35156.17.4.50000 NAME 'uWSGInull' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )\n");
|
||||
|
||||
uwsgi_log("objectclass ( 1.3.6.1.4.1.35156.17.3.1 NAME 'uWSGIConfig' SUP top AUXILIARY DESC 'uWSGI configuration' MAY ( ");
|
||||
|
||||
for(i=0;i<items;i++) {
|
||||
for (i = 0; i < items; i++) {
|
||||
|
||||
entry = &ule[i];
|
||||
entry = &ule[i];
|
||||
|
||||
char *list2 = uwsgi_concat2(entry->names+1, "");
|
||||
char *p = strtok(list2, " ");
|
||||
while (p != NULL) {
|
||||
uwsgi_log("%.*s $ ", strlen(p)-2, p+1);
|
||||
p = strtok(NULL, " ");
|
||||
}
|
||||
char *list2 = uwsgi_concat2(entry->names + 1, "");
|
||||
char *p = strtok(list2, " ");
|
||||
while (p != NULL) {
|
||||
uwsgi_log("%.*s $ ", strlen(p) - 2, p + 1);
|
||||
p = strtok(NULL, " ");
|
||||
}
|
||||
|
||||
free(list2);
|
||||
free(list2);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -264,7 +265,7 @@ void uwsgi_ldap_config(char *url) {
|
||||
uwsgi_log("unable to parse LDAP url.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
uwsgi_log("[uWSGI] getting LDAP configuration from %s\n", url);
|
||||
|
||||
url_slash = strchr(url, '/');
|
||||
@@ -281,25 +282,25 @@ void uwsgi_ldap_config(char *url) {
|
||||
#endif
|
||||
|
||||
#if LDAP_API_VERSION >= 3000
|
||||
if ( (ret = ldap_initialize( &ldp, url)) != LDAP_SUCCESS) {
|
||||
if ((ret = ldap_initialize(&ldp, url)) != LDAP_SUCCESS) {
|
||||
uwsgi_log("LDAP: %s\n", ldap_err2string(ret));
|
||||
exit(1);
|
||||
}
|
||||
#else
|
||||
if ( (ldp = ldap_init( ldap_url->lud_host, ldap_url->lud_port)) == NULL) {
|
||||
if ((ldp = ldap_init(ldap_url->lud_host, ldap_url->lud_port)) == NULL) {
|
||||
uwsgi_error("ldap_init()");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if ( (ret = ldap_set_option(ldp, LDAP_OPT_PROTOCOL_VERSION, &desired_version)) != LDAP_OPT_SUCCESS) {
|
||||
if ((ret = ldap_set_option(ldp, LDAP_OPT_PROTOCOL_VERSION, &desired_version)) != LDAP_OPT_SUCCESS) {
|
||||
uwsgi_log("LDAP: %s\n", ldap_err2string(ret));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
if ( (ret = ldap_search_ext_s(ldp, ldap_url->lud_dn, ldap_url->lud_scope, ldap_url->lud_filter, NULL, 0, NULL, NULL, NULL, 1, &results)) != LDAP_SUCCESS) {
|
||||
if ((ret = ldap_search_ext_s(ldp, ldap_url->lud_dn, ldap_url->lud_scope, ldap_url->lud_filter, NULL, 0, NULL, NULL, NULL, 1, &results)) != LDAP_SUCCESS) {
|
||||
uwsgi_log("LDAP: %s\n", ldap_err2string(ret));
|
||||
exit(1);
|
||||
}
|
||||
@@ -318,17 +319,17 @@ void uwsgi_ldap_config(char *url) {
|
||||
entry = ldap_first_entry(ldp, results);
|
||||
|
||||
int found = 0;
|
||||
for( attr = ldap_first_attribute(ldp, entry, &ber); attr != NULL; attr = ldap_next_attribute(ldp, entry, ber)) {
|
||||
if (!strncmp(attr,"uWSGI",5)) {
|
||||
for (attr = ldap_first_attribute(ldp, entry, &ber); attr != NULL; attr = ldap_next_attribute(ldp, entry, ber)) {
|
||||
if (!strncmp(attr, "uWSGI", 5)) {
|
||||
|
||||
found = 1;
|
||||
uwsgi_attr = malloc( calc_ldap_name(attr) + 1 );
|
||||
uwsgi_attr = malloc(calc_ldap_name(attr) + 1);
|
||||
if (!uwsgi_attr) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ldap2uwsgi(attr+5, uwsgi_attr);
|
||||
ldap2uwsgi(attr + 5, uwsgi_attr);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_debug("LDAP attribute: %s = --%s\n", attr, uwsgi_attr);
|
||||
@@ -336,7 +337,7 @@ void uwsgi_ldap_config(char *url) {
|
||||
bervalues = ldap_get_values_len(ldp, entry, attr);
|
||||
if (bervalues) {
|
||||
// do not free uwsgi_attr/uwsgi_val;
|
||||
char *uwsgi_val = malloc( bervalues[0]->bv_len + 1 );
|
||||
char *uwsgi_val = malloc(bervalues[0]->bv_len + 1);
|
||||
if (!uwsgi_val) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
@@ -345,7 +346,7 @@ void uwsgi_ldap_config(char *url) {
|
||||
memcpy(uwsgi_val, bervalues[0]->bv_val, bervalues[0]->bv_len);
|
||||
uwsgi_val[bervalues[0]->bv_len] = 0;
|
||||
|
||||
add_exported_option((char*) uwsgi_attr, uwsgi_val, 0);
|
||||
add_exported_option((char *) uwsgi_attr, uwsgi_val, 0);
|
||||
free(bervalues);
|
||||
}
|
||||
else {
|
||||
+1116
File diff suppressed because it is too large
Load Diff
+327
-100
@@ -20,7 +20,7 @@ static struct uwsgi_lock_item *uwsgi_register_lock(char *id, int rw) {
|
||||
return uwsgi.registered_locks;
|
||||
}
|
||||
|
||||
while(uli) {
|
||||
while (uli) {
|
||||
if (!uli->next) {
|
||||
uli->next = uwsgi_malloc_shared(sizeof(struct uwsgi_lock_item));
|
||||
if (rw) {
|
||||
@@ -45,8 +45,13 @@ 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;
|
||||
#else
|
||||
#define UWSGI_LOCK_ENGINE_NAME "pthread mutexes"
|
||||
#endif
|
||||
@@ -59,62 +64,94 @@ static struct uwsgi_lock_item *uwsgi_register_lock(char *id, int rw) {
|
||||
#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) {
|
||||
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0);
|
||||
|
||||
if (pthread_mutexattr_init(&attr)) {
|
||||
uwsgi_log("unable to allocate mutexattr structure\n");
|
||||
exit(1);
|
||||
}
|
||||
if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) {
|
||||
uwsgi_log("unable to share mutex\n");
|
||||
exit(1);
|
||||
}
|
||||
struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0);
|
||||
|
||||
#ifdef EOWNERDEAD
|
||||
if (pthread_mutexattr_setrobust_np(&attr, PTHREAD_MUTEX_ROBUST_NP)) {
|
||||
uwsgi_log("unable to make the mutex 'robust'\n");
|
||||
exit(1);
|
||||
}
|
||||
retry:
|
||||
#endif
|
||||
if (pthread_mutexattr_init(&attr)) {
|
||||
uwsgi_log("unable to allocate mutexattr structure\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) {
|
||||
uwsgi_log("unable to share mutex\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#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)) {
|
||||
uwsgi_log("unable to make the mutex 'robust'\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pthread_mutex_init((pthread_mutex_t *) uli->lock_ptr, &attr)) {
|
||||
uwsgi_log("unable to initialize mutex\n");
|
||||
exit(1);
|
||||
}
|
||||
if (pthread_mutex_init((pthread_mutex_t *) uli->lock_ptr, &attr)) {
|
||||
#ifdef EOWNERDEAD
|
||||
if (uwsgi_pthread_robust_mutexes_enabled) {
|
||||
uwsgi_log("!!! it looks like your kernel does not support pthread robust mutexes !!!\n");
|
||||
uwsgi_log("!!! falling back to standard pthread mutexes !!!\n");
|
||||
uwsgi_pthread_robust_mutexes_enabled = 0;
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
goto retry;
|
||||
}
|
||||
#endif
|
||||
uwsgi_log("unable to initialize mutex\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
|
||||
#ifndef EOWNERDEAD
|
||||
#ifdef EOWNERDEAD
|
||||
if (!uwsgi_pthread_robust_mutexes_enabled) {
|
||||
uli->can_deadlock = 1;
|
||||
}
|
||||
#else
|
||||
uli->can_deadlock = 1;
|
||||
#endif
|
||||
|
||||
return uli;
|
||||
}
|
||||
|
||||
pid_t uwsgi_lock_fast_check(struct uwsgi_lock_item *uli) {
|
||||
pid_t uwsgi_lock_fast_check(struct uwsgi_lock_item * uli) {
|
||||
|
||||
if (pthread_mutex_trylock((pthread_mutex_t *) uli->lock_ptr) == 0 ) {
|
||||
pthread_mutex_unlock((pthread_mutex_t *) uli->lock_ptr);
|
||||
if (pthread_mutex_trylock((pthread_mutex_t *) uli->lock_ptr) == 0) {
|
||||
pthread_mutex_unlock((pthread_mutex_t *) uli->lock_ptr);
|
||||
return 0;
|
||||
}
|
||||
return uli->pid;
|
||||
}
|
||||
|
||||
pid_t uwsgi_rwlock_fast_check(struct uwsgi_lock_item *uli) {
|
||||
pid_t uwsgi_rwlock_fast_check(struct uwsgi_lock_item * uli) {
|
||||
#ifdef OBSOLETE_LINUX_KERNEL
|
||||
return uwsgi_lock_fast_check(uli);
|
||||
#else
|
||||
|
||||
if (pthread_rwlock_trywrlock((pthread_rwlock_t *) uli->lock_ptr) == 0 ) {
|
||||
pthread_rwlock_unlock((pthread_rwlock_t *) uli->lock_ptr);
|
||||
if (pthread_rwlock_trywrlock((pthread_rwlock_t *) uli->lock_ptr) == 0) {
|
||||
pthread_rwlock_unlock((pthread_rwlock_t *) uli->lock_ptr);
|
||||
return 0;
|
||||
}
|
||||
return uli->pid;
|
||||
return uli->pid;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -129,7 +166,7 @@ void uwsgi_lock_fast(struct uwsgi_lock_item *uli) {
|
||||
#else
|
||||
pthread_mutex_lock((pthread_mutex_t *) uli->lock_ptr);
|
||||
#endif
|
||||
uli->pid = uwsgi.mypid;
|
||||
uli->pid = uwsgi.mypid;
|
||||
}
|
||||
|
||||
void uwsgi_unlock_fast(struct uwsgi_lock_item *uli) {
|
||||
@@ -144,7 +181,7 @@ void uwsgi_rlock_fast(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_lock_fast(uli);
|
||||
#else
|
||||
pthread_rwlock_rdlock((pthread_rwlock_t *) uli->lock_ptr);
|
||||
uli->pid = uwsgi.mypid;
|
||||
uli->pid = uwsgi.mypid;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -153,7 +190,7 @@ void uwsgi_wlock_fast(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_lock_fast(uli);
|
||||
#else
|
||||
pthread_rwlock_wrlock((pthread_rwlock_t *) uli->lock_ptr);
|
||||
uli->pid = uwsgi.mypid;
|
||||
uli->pid = uwsgi.mypid;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -162,7 +199,7 @@ void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_unlock_fast(uli);
|
||||
#else
|
||||
pthread_rwlock_unlock((pthread_rwlock_t *) uli->lock_ptr);
|
||||
uli->pid = 0;
|
||||
uli->pid = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -176,20 +213,20 @@ struct uwsgi_lock_item *uwsgi_rwlock_fast_init(char *id) {
|
||||
|
||||
struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 1);
|
||||
|
||||
if (pthread_rwlockattr_init(&attr)) {
|
||||
uwsgi_log("unable to allocate rwlock structure\n");
|
||||
exit(1);
|
||||
}
|
||||
if (pthread_rwlockattr_init(&attr)) {
|
||||
uwsgi_log("unable to allocate rwlock structure\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) {
|
||||
uwsgi_log("unable to share rwlock\n");
|
||||
exit(1);
|
||||
}
|
||||
if (pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) {
|
||||
uwsgi_log("unable to share rwlock\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pthread_rwlock_init((pthread_rwlock_t *) uli->lock_ptr, &attr)) {
|
||||
uwsgi_log("unable to initialize rwlock\n");
|
||||
exit(1);
|
||||
}
|
||||
if (pthread_rwlock_init((pthread_rwlock_t *) uli->lock_ptr, &attr)) {
|
||||
uwsgi_log("unable to initialize rwlock\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pthread_rwlockattr_destroy(&attr);
|
||||
|
||||
@@ -215,36 +252,46 @@ struct uwsgi_lock_item *uwsgi_rwlock_fast_init(char *id) {
|
||||
#define UWSGI_RWLOCK_SIZE sizeof(struct umtx)
|
||||
#define UWSGI_LOCK_ENGINE_NAME "FreeBSD umtx"
|
||||
|
||||
struct uwsgi_lock_item *uwsgi_rwlock_fast_init(char *id) { return uwsgi_lock_fast_init(id) ;}
|
||||
void uwsgi_rlock_fast(struct uwsgi_lock_item *uli) { uwsgi_lock_fast(uli);}
|
||||
void uwsgi_wlock_fast(struct uwsgi_lock_item *uli) { uwsgi_lock_fast(uli);}
|
||||
void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) { uwsgi_unlock_fast(uli); }
|
||||
struct uwsgi_lock_item *uwsgi_rwlock_fast_init(char *id) {
|
||||
return uwsgi_lock_fast_init(id);
|
||||
}
|
||||
void uwsgi_rlock_fast(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_lock_fast(uli);
|
||||
}
|
||||
void uwsgi_wlock_fast(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_lock_fast(uli);
|
||||
}
|
||||
void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_unlock_fast(uli);
|
||||
}
|
||||
|
||||
struct uwsgi_lock_item *uwsgi_lock_fast_init(char *id) {
|
||||
struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0);
|
||||
umtx_init((struct umtx*) uli->lock_ptr);
|
||||
umtx_init((struct umtx *) uli->lock_ptr);
|
||||
return uli;
|
||||
}
|
||||
|
||||
void uwsgi_lock_fast(struct uwsgi_lock_item *uli) {
|
||||
umtx_lock((struct umtx*) uli->lock_ptr, (u_long) getpid() );
|
||||
umtx_lock((struct umtx *) uli->lock_ptr, (u_long) getpid());
|
||||
uli->pid = uwsgi.mypid;
|
||||
}
|
||||
|
||||
void uwsgi_unlock_fast(struct uwsgi_lock_item *uli) {
|
||||
umtx_unlock((struct umtx*) uli->lock_ptr, (u_long) getpid() );
|
||||
umtx_unlock((struct umtx *) uli->lock_ptr, (u_long) getpid());
|
||||
uli->pid = 0;
|
||||
}
|
||||
|
||||
pid_t uwsgi_lock_fast_check(struct uwsgi_lock_item *uli) {
|
||||
if (umtx_trylock((struct umtx*) uli->lock_ptr, (u_long) getpid() )) {
|
||||
umtx_unlock((struct umtx*) uli->lock_ptr, (u_long) getpid() );
|
||||
if (umtx_trylock((struct umtx *) uli->lock_ptr, (u_long) getpid())) {
|
||||
umtx_unlock((struct umtx *) uli->lock_ptr, (u_long) getpid());
|
||||
return 0;
|
||||
}
|
||||
return uli->pid;
|
||||
}
|
||||
|
||||
pid_t uwsgi_rwlock_fast_check(struct uwsgi_lock_item *uli) { return uwsgi_lock_fast_check(uli); }
|
||||
pid_t uwsgi_rwlock_fast_check(struct uwsgi_lock_item * uli) {
|
||||
return uwsgi_lock_fast_check(uli);
|
||||
}
|
||||
|
||||
#elif defined(UWSGI_LOCK_USE_POSIX_SEM)
|
||||
|
||||
@@ -255,36 +302,46 @@ pid_t uwsgi_rwlock_fast_check(struct uwsgi_lock_item *uli) { return uwsgi_lock_f
|
||||
#include <semaphore.h>
|
||||
|
||||
struct uwsgi_lock_item *uwsgi_lock_fast_init(char *id) {
|
||||
struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0);
|
||||
sem_init((sem_t*) uli->lock_ptr, 1, 1);
|
||||
struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0);
|
||||
sem_init((sem_t *) uli->lock_ptr, 1, 1);
|
||||
uli->can_deadlock = 1;
|
||||
return uli;
|
||||
return uli;
|
||||
}
|
||||
|
||||
struct uwsgi_lock_item *uwsgi_rwlock_fast_init(char *id) { return uwsgi_lock_fast_init(id) ;}
|
||||
struct uwsgi_lock_item *uwsgi_rwlock_fast_init(char *id) {
|
||||
return uwsgi_lock_fast_init(id);
|
||||
}
|
||||
|
||||
void uwsgi_lock_fast(struct uwsgi_lock_item *uli) {
|
||||
sem_wait((sem_t *) uli->lock_ptr);
|
||||
uli->pid = uwsgi.mypid;
|
||||
sem_wait((sem_t *) uli->lock_ptr);
|
||||
uli->pid = uwsgi.mypid;
|
||||
}
|
||||
|
||||
void uwsgi_unlock_fast(struct uwsgi_lock_item *uli) {
|
||||
sem_post((sem_t*) uli->lock_ptr);
|
||||
uli->pid = 0;
|
||||
sem_post((sem_t *) uli->lock_ptr);
|
||||
uli->pid = 0;
|
||||
}
|
||||
|
||||
pid_t uwsgi_lock_fast_check(struct uwsgi_lock_item *uli) {
|
||||
if (sem_trywait((sem_t *) uli->lock_ptr) == 0) {
|
||||
sem_post((sem_t*) uli->lock_ptr);
|
||||
return 0;
|
||||
}
|
||||
return uli->pid;
|
||||
sem_post((sem_t *) uli->lock_ptr);
|
||||
return 0;
|
||||
}
|
||||
return uli->pid;
|
||||
}
|
||||
|
||||
pid_t uwsgi_rwlock_fast_check(struct uwsgi_lock_item *uli) { return uwsgi_lock_fast_check(uli); }
|
||||
void uwsgi_rlock_fast(struct uwsgi_lock_item *uli) { uwsgi_lock_fast(uli);}
|
||||
void uwsgi_wlock_fast(struct uwsgi_lock_item *uli) { uwsgi_lock_fast(uli);}
|
||||
void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) { uwsgi_unlock_fast(uli); }
|
||||
pid_t uwsgi_rwlock_fast_check(struct uwsgi_lock_item * uli) {
|
||||
return uwsgi_lock_fast_check(uli);
|
||||
}
|
||||
void uwsgi_rlock_fast(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_lock_fast(uli);
|
||||
}
|
||||
void uwsgi_wlock_fast(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_lock_fast(uli);
|
||||
}
|
||||
void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_unlock_fast(uli);
|
||||
}
|
||||
|
||||
|
||||
#elif defined(UWSGI_LOCK_USE_OSX_SPINLOCK)
|
||||
@@ -322,19 +379,81 @@ pid_t uwsgi_lock_fast_check(struct uwsgi_lock_item *uli) {
|
||||
return uli->pid;
|
||||
}
|
||||
|
||||
struct uwsgi_lock_item *uwsgi_rwlock_fast_init(char *id) {
|
||||
struct uwsgi_lock_item *uwsgi_rwlock_fast_init(char *id) {
|
||||
struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 1);
|
||||
memset(uli->lock_ptr, 0, UWSGI_LOCK_SIZE);
|
||||
uli->can_deadlock = 1;
|
||||
return uli;
|
||||
}
|
||||
|
||||
void uwsgi_rlock_fast(struct uwsgi_lock_item *uli) { uwsgi_lock_fast(uli);}
|
||||
void uwsgi_wlock_fast(struct uwsgi_lock_item *uli) { uwsgi_lock_fast(uli);}
|
||||
void uwsgi_rlock_fast(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_lock_fast(uli);
|
||||
}
|
||||
void uwsgi_wlock_fast(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_lock_fast(uli);
|
||||
}
|
||||
|
||||
pid_t uwsgi_rwlock_fast_check(struct uwsgi_lock_item *uli) { return uwsgi_lock_fast_check(uli); }
|
||||
pid_t uwsgi_rwlock_fast_check(struct uwsgi_lock_item *uli) {
|
||||
return uwsgi_lock_fast_check(uli);
|
||||
}
|
||||
|
||||
void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_unlock_fast(uli);
|
||||
}
|
||||
|
||||
#elif defined(UWSGI_LOCK_USE_WINDOWS_MUTEX)
|
||||
|
||||
#define UWSGI_LOCK_ENGINE_NAME "windows mutexes"
|
||||
#define UWSGI_LOCK_SIZE sizeof(HANDLE)
|
||||
#define UWSGI_RWLOCK_SIZE sizeof(HANDLE)
|
||||
|
||||
|
||||
struct uwsgi_lock_item *uwsgi_lock_fast_init(char *id) {
|
||||
|
||||
struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0);
|
||||
struct _SECURITY_ATTRIBUTES sa;
|
||||
memset(&sa, 0, sizeof(struct _SECURITY_ATTRIBUTES));
|
||||
sa.bInheritHandle = 1;
|
||||
uli->lock_ptr = CreateMutex(&sa, FALSE, NULL);
|
||||
return uli;
|
||||
}
|
||||
|
||||
void uwsgi_lock_fast(struct uwsgi_lock_item *uli) {
|
||||
WaitForSingleObject(uli->lock_ptr, INFINITE);
|
||||
uli->pid = uwsgi.mypid;
|
||||
}
|
||||
|
||||
void uwsgi_unlock_fast(struct uwsgi_lock_item *uli) {
|
||||
ReleaseMutex(uli->lock_ptr);
|
||||
uli->pid = 0;
|
||||
}
|
||||
|
||||
pid_t uwsgi_lock_fast_check(struct uwsgi_lock_item *uli) {
|
||||
if (WaitForSingleObject(uli->lock_ptr, 0) == WAIT_TIMEOUT) {
|
||||
return 0;
|
||||
}
|
||||
return uli->pid;
|
||||
}
|
||||
|
||||
struct uwsgi_lock_item *uwsgi_rwlock_fast_init(char *id) {
|
||||
return uwsgi_lock_fast_init(id);
|
||||
}
|
||||
|
||||
void uwsgi_rlock_fast(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_lock_fast(uli);
|
||||
}
|
||||
void uwsgi_wlock_fast(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_lock_fast(uli);
|
||||
}
|
||||
|
||||
pid_t uwsgi_rwlock_fast_check(struct uwsgi_lock_item *uli) {
|
||||
return uwsgi_lock_fast_check(uli);
|
||||
}
|
||||
|
||||
void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_unlock_fast(uli);
|
||||
}
|
||||
|
||||
void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) { uwsgi_unlock_fast(uli); }
|
||||
|
||||
#else
|
||||
|
||||
@@ -364,10 +483,10 @@ struct uwsgi_lock_item *uwsgi_lock_ipcsem_init(char *id) {
|
||||
// used by ftok
|
||||
static int counter = 1;
|
||||
union semun {
|
||||
int val;
|
||||
int val;
|
||||
struct semid_ds *buf;
|
||||
ushort *array;
|
||||
} semu ;
|
||||
} semu;
|
||||
int semid;
|
||||
key_t myKey;
|
||||
|
||||
@@ -380,10 +499,10 @@ struct uwsgi_lock_item *uwsgi_lock_ipcsem_init(char *id) {
|
||||
exit(1);
|
||||
}
|
||||
counter++;
|
||||
semid = semget(myKey, 1, IPC_CREAT|0666);
|
||||
semid = semget(myKey, 1, IPC_CREAT | 0666);
|
||||
}
|
||||
else {
|
||||
semid = semget(IPC_PRIVATE, 1, IPC_CREAT|IPC_EXCL| 0666);
|
||||
semid = semget(IPC_PRIVATE, 1, IPC_CREAT | IPC_EXCL | 0666);
|
||||
}
|
||||
|
||||
if (semid < 0) {
|
||||
@@ -398,7 +517,7 @@ struct uwsgi_lock_item *uwsgi_lock_ipcsem_init(char *id) {
|
||||
uwsgi_error("semctl()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
return uli;
|
||||
}
|
||||
|
||||
@@ -412,9 +531,11 @@ 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()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_unlock_ipcsem(struct uwsgi_lock_item *uli) {
|
||||
@@ -427,16 +548,26 @@ 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()");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_lock_item *uwsgi_rwlock_ipcsem_init(char *id) { return uwsgi_lock_ipcsem_init(id);}
|
||||
void uwsgi_rlock_ipcsem(struct uwsgi_lock_item *uli) { uwsgi_lock_ipcsem(uli);}
|
||||
void uwsgi_wlock_ipcsem(struct uwsgi_lock_item *uli) { uwsgi_lock_ipcsem(uli);}
|
||||
void uwsgi_rwunlock_ipcsem(struct uwsgi_lock_item *uli) { uwsgi_unlock_ipcsem(uli); }
|
||||
struct uwsgi_lock_item *uwsgi_rwlock_ipcsem_init(char *id) {
|
||||
return uwsgi_lock_ipcsem_init(id);
|
||||
}
|
||||
void uwsgi_rlock_ipcsem(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_lock_ipcsem(uli);
|
||||
}
|
||||
void uwsgi_wlock_ipcsem(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_lock_ipcsem(uli);
|
||||
}
|
||||
void uwsgi_rwunlock_ipcsem(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_unlock_ipcsem(uli);
|
||||
}
|
||||
|
||||
// ipc cannot deadlock
|
||||
pid_t uwsgi_lock_ipcsem_check(struct uwsgi_lock_item *uli) {
|
||||
@@ -447,13 +578,17 @@ void uwsgi_ipcsem_clear(void) {
|
||||
|
||||
struct uwsgi_lock_item *uli = uwsgi.registered_locks;
|
||||
|
||||
if (!uwsgi.workers) goto clear;
|
||||
if (!uwsgi.workers)
|
||||
goto clear;
|
||||
|
||||
if (uwsgi.mywid == 0) goto clear;
|
||||
if (uwsgi.mywid == 0)
|
||||
goto clear;
|
||||
|
||||
if (uwsgi.master_process && getpid() == uwsgi.workers[0].pid) goto clear;
|
||||
if (uwsgi.master_process && getpid() == uwsgi.workers[0].pid)
|
||||
goto clear;
|
||||
|
||||
if (!uwsgi.master_process && uwsgi.mywid == 1) goto clear;
|
||||
if (!uwsgi.master_process && uwsgi.mywid == 1)
|
||||
goto clear;
|
||||
|
||||
return;
|
||||
|
||||
@@ -462,7 +597,7 @@ clear:
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("removing sysvipc semaphores...\n");
|
||||
#endif
|
||||
while(uli) {
|
||||
while (uli) {
|
||||
int semid = 0;
|
||||
memcpy(&semid, uli->lock_ptr, sizeof(int));
|
||||
if (semctl(semid, 0, IPC_RMID)) {
|
||||
@@ -473,12 +608,18 @@ clear:
|
||||
}
|
||||
|
||||
|
||||
pid_t uwsgi_rwlock_ipcsem_check(struct uwsgi_lock_item *uli) { return uwsgi_lock_ipcsem_check(uli); }
|
||||
pid_t uwsgi_rwlock_ipcsem_check(struct uwsgi_lock_item *uli) {
|
||||
return uwsgi_lock_ipcsem_check(uli);
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_setup_locking() {
|
||||
|
||||
// use the fastest avaikable locking
|
||||
int i;
|
||||
|
||||
if (uwsgi.locking_setup) return;
|
||||
|
||||
// use the fastest available locking
|
||||
if (uwsgi.lock_engine) {
|
||||
if (!strcmp(uwsgi.lock_engine, "ipcsem")) {
|
||||
uwsgi_log_initial("lock engine: ipcsem\n");
|
||||
@@ -494,8 +635,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);
|
||||
@@ -513,6 +656,55 @@ void uwsgi_setup_locking() {
|
||||
uwsgi.lock_ops.rwunlock = uwsgi_rwunlock_fast;
|
||||
uwsgi.lock_size = UWSGI_LOCK_SIZE;
|
||||
uwsgi.rwlock_size = UWSGI_RWLOCK_SIZE;
|
||||
|
||||
ready:
|
||||
// application generic lock
|
||||
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)));
|
||||
}
|
||||
|
||||
// event queue lock (mitigate same event on multiple queues)
|
||||
if (uwsgi.threads > 1) {
|
||||
pthread_mutex_init(&uwsgi.thunder_mutex, NULL);
|
||||
}
|
||||
|
||||
if (uwsgi.master_process) {
|
||||
// signal table lock
|
||||
uwsgi.signal_table_lock = uwsgi_lock_init("signal");
|
||||
|
||||
// fmon table lock
|
||||
uwsgi.fmon_table_lock = uwsgi_lock_init("filemon");
|
||||
|
||||
// timer table lock
|
||||
uwsgi.timer_table_lock = uwsgi_lock_init("timer");
|
||||
|
||||
// probe table lock
|
||||
uwsgi.probe_table_lock = uwsgi_lock_init("probe");
|
||||
|
||||
// rb_timer table lock
|
||||
uwsgi.rb_timer_table_lock = uwsgi_lock_init("rbtimer");
|
||||
|
||||
// cron table lock
|
||||
uwsgi.cron_table_lock = uwsgi_lock_init("cron");
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
// register locking for legions
|
||||
struct uwsgi_legion *ul = uwsgi.legions;
|
||||
while(ul) {
|
||||
ul->lock = uwsgi_lock_init(uwsgi_concat2("legion_", ul->legion));
|
||||
ul = ul->next;
|
||||
}
|
||||
#endif
|
||||
uwsgi.locking_setup = 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -534,16 +726,51 @@ int uwsgi_fcntl_lock(int fd) {
|
||||
int uwsgi_fcntl_is_locked(int fd) {
|
||||
|
||||
struct flock fl;
|
||||
fl.l_type = F_WRLCK;
|
||||
fl.l_whence = SEEK_SET;
|
||||
fl.l_start = 0;
|
||||
fl.l_len = 0;
|
||||
fl.l_pid = 0;
|
||||
fl.l_type = F_WRLCK;
|
||||
fl.l_whence = SEEK_SET;
|
||||
fl.l_start = 0;
|
||||
fl.l_len = 0;
|
||||
fl.l_pid = 0;
|
||||
|
||||
if (fcntl(fd, F_SETLK, &fl)) {
|
||||
if (fcntl(fd, F_SETLK, &fl)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_deadlock_check(pid_t diedpid) {
|
||||
struct uwsgi_lock_item *uli = uwsgi.registered_locks;
|
||||
while (uli) {
|
||||
if (!uli->can_deadlock)
|
||||
goto nextlock;
|
||||
pid_t locked_pid = 0;
|
||||
if (uli->rw) {
|
||||
locked_pid = uwsgi_rwlock_check(uli);
|
||||
}
|
||||
else {
|
||||
locked_pid = uwsgi_lock_check(uli);
|
||||
}
|
||||
if (locked_pid == diedpid) {
|
||||
uwsgi_log("[deadlock-detector] pid %d was holding lock %s (%p)\n", (int) diedpid, uli->id, uli->lock_ptr);
|
||||
if (uli->rw) {
|
||||
uwsgi_rwunlock(uli);
|
||||
}
|
||||
else {
|
||||
uwsgi_unlock(uli);
|
||||
}
|
||||
}
|
||||
nextlock:
|
||||
uli = uli->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_user_lock(int lock_num) {
|
||||
uwsgi_lock(uwsgi.user_lock[lock_num]);
|
||||
}
|
||||
|
||||
void uwsgi_user_unlock(int lock_num) {
|
||||
uwsgi_unlock(uwsgi.user_lock[lock_num]);
|
||||
}
|
||||
+1495
File diff suppressed because it is too large
Load Diff
+166
@@ -0,0 +1,166 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct wsgi_request *threaded_current_wsgi_req() {
|
||||
return pthread_getspecific(uwsgi.tur_key);
|
||||
}
|
||||
struct wsgi_request *simple_current_wsgi_req() {
|
||||
return uwsgi.wsgi_req;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_register_loop(char *name, void (*func) (void)) {
|
||||
|
||||
struct uwsgi_loop *old_loop = NULL, *loop = uwsgi.loops;
|
||||
|
||||
while (loop) {
|
||||
// check if the loop engine is already registered
|
||||
if (!strcmp(name, loop->name))
|
||||
return;
|
||||
old_loop = loop;
|
||||
loop = loop->next;
|
||||
}
|
||||
|
||||
loop = uwsgi_calloc(sizeof(struct uwsgi_loop));
|
||||
loop->name = name;
|
||||
loop->loop = func;
|
||||
|
||||
if (old_loop) {
|
||||
old_loop->next = loop;
|
||||
}
|
||||
else {
|
||||
uwsgi.loops = loop;
|
||||
}
|
||||
}
|
||||
|
||||
void *uwsgi_get_loop(char *name) {
|
||||
|
||||
struct uwsgi_loop *loop = uwsgi.loops;
|
||||
|
||||
while (loop) {
|
||||
if (!strcmp(name, loop->name)) {
|
||||
return loop->loop;
|
||||
}
|
||||
loop = loop->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
this is the default (simple) loop.
|
||||
|
||||
it will run simple_loop_run function for each spawned thread
|
||||
|
||||
simple_loop_run monitors sockets and signals descriptors
|
||||
and manages them.
|
||||
|
||||
*/
|
||||
|
||||
void simple_loop() {
|
||||
uwsgi_loop_cores_run(simple_loop_run);
|
||||
}
|
||||
|
||||
void uwsgi_loop_cores_run(void *(*func) (void *)) {
|
||||
int i;
|
||||
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);
|
||||
}
|
||||
long y = 0;
|
||||
func((void *) y);
|
||||
}
|
||||
|
||||
void uwsgi_setup_thread_req(long core_id, struct wsgi_request *wsgi_req) {
|
||||
int i;
|
||||
sigset_t smask;
|
||||
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &i);
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &i);
|
||||
pthread_setspecific(uwsgi.tur_key, (void *) wsgi_req);
|
||||
|
||||
if (core_id > 0) {
|
||||
// block all signals on new threads
|
||||
sigfillset(&smask);
|
||||
#ifdef UWSGI_DEBUG
|
||||
sigdelset(&smask, SIGSEGV);
|
||||
#endif
|
||||
pthread_sigmask(SIG_BLOCK, &smask, NULL);
|
||||
|
||||
// run per-thread socket hook
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
while (uwsgi_sock) {
|
||||
if (uwsgi_sock->proto_thread_fixup) {
|
||||
uwsgi_sock->proto_thread_fixup(uwsgi_sock, core_id);
|
||||
}
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->init_thread) {
|
||||
uwsgi.p[i]->init_thread(core_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void simple_loop_run_int(int core_id) {
|
||||
long y = core_id;
|
||||
simple_loop_run((void *) y);
|
||||
}
|
||||
|
||||
void *simple_loop_run(void *arg1) {
|
||||
|
||||
long core_id = (long) arg1;
|
||||
|
||||
struct wsgi_request *wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[core_id].req;
|
||||
|
||||
if (uwsgi.threads > 1) {
|
||||
uwsgi_setup_thread_req(core_id, wsgi_req);
|
||||
}
|
||||
// initialize the main event queue to monitor sockets
|
||||
int main_queue = event_queue_init();
|
||||
|
||||
uwsgi_add_sockets_to_queue(main_queue, core_id);
|
||||
|
||||
if (uwsgi.signal_socket > -1) {
|
||||
event_queue_add_fd_read(main_queue, uwsgi.signal_socket);
|
||||
event_queue_add_fd_read(main_queue, uwsgi.my_signal_socket);
|
||||
}
|
||||
|
||||
|
||||
// ok we are ready, let's start managing requests and signals
|
||||
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
|
||||
|
||||
wsgi_req_setup(wsgi_req, core_id, NULL);
|
||||
|
||||
if (wsgi_req_accept(main_queue, wsgi_req)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (wsgi_req_recv(main_queue, wsgi_req)) {
|
||||
uwsgi_destroy_request(wsgi_req);
|
||||
continue;
|
||||
}
|
||||
|
||||
uwsgi_close_request(wsgi_req);
|
||||
}
|
||||
|
||||
// end of the loop
|
||||
if (uwsgi.workers[uwsgi.mywid].destroy && uwsgi.workers[0].pid > 0) {
|
||||
#ifdef __APPLE__
|
||||
kill(uwsgi.workers[0].pid, SIGTERM);
|
||||
#else
|
||||
if (uwsgi.propagate_touch) {
|
||||
kill(uwsgi.workers[0].pid, SIGHUP);
|
||||
}
|
||||
else {
|
||||
gracefully_kill(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
+924
@@ -0,0 +1,924 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_restore_auto_snapshot(int signum) {
|
||||
|
||||
if (uwsgi.workers[1].snapshot > 0) {
|
||||
uwsgi.restore_snapshot = 1;
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[WARNING] no snapshot available\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_block_signal(int signum) {
|
||||
sigset_t smask;
|
||||
sigemptyset(&smask);
|
||||
sigaddset(&smask, signum);
|
||||
if (sigprocmask(SIG_BLOCK, &smask, NULL)) {
|
||||
uwsgi_error("sigprocmask()");
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_unblock_signal(int signum) {
|
||||
sigset_t smask;
|
||||
sigemptyset(&smask);
|
||||
sigaddset(&smask, signum);
|
||||
if (sigprocmask(SIG_UNBLOCK, &smask, NULL)) {
|
||||
uwsgi_error("sigprocmask()");
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_master_manage_udp(int udp_fd) {
|
||||
struct sockaddr_in udp_client;
|
||||
char udp_client_addr[16];
|
||||
int i;
|
||||
|
||||
socklen_t udp_len = sizeof(udp_client);
|
||||
ssize_t rlen = recvfrom(udp_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) {
|
||||
|
||||
memset(udp_client_addr, 0, 16);
|
||||
if (inet_ntop(AF_INET, &udp_client.sin_addr.s_addr, udp_client_addr, 16)) {
|
||||
if (uwsgi.wsgi_req->buffer[0] == UWSGI_MODIFIER_MULTICAST_ANNOUNCE) {
|
||||
}
|
||||
else if (uwsgi.wsgi_req->buffer[0] == 0x30 && uwsgi.snmp) {
|
||||
manage_snmp(udp_fd, (uint8_t *) uwsgi.wsgi_req->buffer, rlen, &udp_client);
|
||||
}
|
||||
else {
|
||||
|
||||
// loop the various udp manager until one returns true
|
||||
int udp_managed = 0;
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->manage_udp) {
|
||||
if (uwsgi.p[i]->manage_udp(udp_client_addr, udp_client.sin_port, uwsgi.wsgi_req->buffer, rlen)) {
|
||||
udp_managed = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// else a simple udp logger
|
||||
if (!udp_managed) {
|
||||
uwsgi_log("[udp:%s:%d] %.*s", udp_client_addr, ntohs(udp_client.sin_port), (int) rlen, uwsgi.wsgi_req->buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_error("inet_ntop()");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_master_manage_emperor() {
|
||||
char byte;
|
||||
ssize_t rlen = read(uwsgi.emperor_fd, &byte, 1);
|
||||
if (rlen > 0) {
|
||||
uwsgi_log_verbose("received message %d from emperor\n", byte);
|
||||
// remove me
|
||||
if (byte == 0) {
|
||||
close(uwsgi.emperor_fd);
|
||||
if (!uwsgi.status.brutally_reloading)
|
||||
kill_them_all(0);
|
||||
}
|
||||
// reload me
|
||||
else if (byte == 1) {
|
||||
// un-lazy the stack to trigger a real reload
|
||||
uwsgi.lazy = 0;
|
||||
uwsgi_block_signal(SIGHUP);
|
||||
grace_them_all(0);
|
||||
uwsgi_unblock_signal(SIGHUP);
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log("lost connection with my emperor !!!\n");
|
||||
close(uwsgi.emperor_fd);
|
||||
if (!uwsgi.status.brutally_reloading)
|
||||
kill_them_all(0);
|
||||
sleep(2);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_master_restore_snapshot() {
|
||||
int i, waitpid_status;
|
||||
uwsgi_log("[snapshot] restoring workers...\n");
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
if (uwsgi.workers[i].pid == 0)
|
||||
continue;
|
||||
kill(uwsgi.workers[i].pid, SIGKILL);
|
||||
if (waitpid(uwsgi.workers[i].pid, &waitpid_status, 0) < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
}
|
||||
if (uwsgi.auto_snapshot > 0 && i > uwsgi.auto_snapshot) {
|
||||
uwsgi.workers[i].pid = 0;
|
||||
uwsgi.workers[i].snapshot = 0;
|
||||
}
|
||||
else {
|
||||
uwsgi.workers[i].pid = uwsgi.workers[i].snapshot;
|
||||
uwsgi.workers[i].snapshot = 0;
|
||||
kill(uwsgi.workers[i].pid, SIGURG);
|
||||
uwsgi_log("Restored uWSGI worker %d (pid: %d)\n", i, (int) uwsgi.workers[i].pid);
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi.restore_snapshot = 0;
|
||||
}
|
||||
|
||||
void suspend_resume_them_all(int signum) {
|
||||
|
||||
int i;
|
||||
int suspend = 0;
|
||||
|
||||
if (uwsgi.workers[0].suspended == 1) {
|
||||
uwsgi_log_verbose("*** (SIGTSTP received) resuming workers ***\n");
|
||||
uwsgi.workers[0].suspended = 0;
|
||||
}
|
||||
else {
|
||||
uwsgi_log_verbose("*** PAUSE (press start to resume, if you do not have a joypad send SIGTSTP) ***\n");
|
||||
suspend = 1;
|
||||
uwsgi.workers[0].suspended = 1;
|
||||
}
|
||||
|
||||
// subscribe/unsubscribe if needed
|
||||
uwsgi_subscribe_all(suspend, 1);
|
||||
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
uwsgi.workers[i].suspended = suspend;
|
||||
if (uwsgi.workers[i].pid > 0) {
|
||||
if (kill(uwsgi.workers[i].pid, SIGTSTP)) {
|
||||
uwsgi_error("kill()");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_master_check_mercy() {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cursed_at) {
|
||||
if (uwsgi_now() > uwsgi.workers[i].no_mercy_at) {
|
||||
uwsgi_log_verbose("worker %d (pid: %d) is taking too much time to die...NO MERCY !!!\n", i, uwsgi.workers[i].pid);
|
||||
// yes that look strangem but we avoid callign it again if we skip waitpid() call below
|
||||
uwsgi_curse(i, SIGKILL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void expire_rb_timeouts(struct uwsgi_rbtree *tree) {
|
||||
|
||||
uint64_t current = (uint64_t) uwsgi_now();
|
||||
struct uwsgi_rb_timer *urbt;
|
||||
struct uwsgi_signal_rb_timer *usrbt;
|
||||
|
||||
for (;;) {
|
||||
|
||||
urbt = uwsgi_min_rb_timer(tree, NULL);
|
||||
|
||||
if (urbt == NULL)
|
||||
return;
|
||||
|
||||
if (urbt->value <= current) {
|
||||
// remove the timeout and add another
|
||||
usrbt = (struct uwsgi_signal_rb_timer *) urbt->data;
|
||||
uwsgi_del_rb_timer(tree, urbt);
|
||||
free(urbt);
|
||||
usrbt->iterations_done++;
|
||||
uwsgi_route_signal(usrbt->sig);
|
||||
if (!usrbt->iterations || usrbt->iterations_done < usrbt->iterations) {
|
||||
usrbt->uwsgi_rb_timer = uwsgi_add_rb_timer(tree, uwsgi_now() + usrbt->value, usrbt);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int uwsgi_get_tcp_info(int fd) {
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
socklen_t tis = sizeof(struct tcp_info);
|
||||
|
||||
if (!getsockopt(fd, IPPROTO_TCP, TCP_INFO, &uwsgi.shared->ti, &tis)) {
|
||||
|
||||
// checks for older kernels
|
||||
#if defined(__linux__)
|
||||
if (!uwsgi.shared->ti.tcpi_sacked) {
|
||||
#elif defined(__FreeBSD__)
|
||||
if (!uwsgi.shared->ti.__tcpi_sacked) {
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
uwsgi.shared->load = (uint64_t) uwsgi.shared->ti.tcpi_unacked;
|
||||
uwsgi.shared->max_load = (uint64_t) uwsgi.shared->ti.tcpi_sacked;
|
||||
#elif defined(__FreeBSD__)
|
||||
uwsgi.shared->load = (uint64_t) uwsgi.shared->ti.__tcpi_unacked;
|
||||
uwsgi.shared->max_load = (uint64_t) uwsgi.shared->ti.__tcpi_sacked;
|
||||
#endif
|
||||
|
||||
uwsgi.shared->options[UWSGI_OPTION_BACKLOG_STATUS] = uwsgi.shared->load;
|
||||
if (uwsgi.vassal_sos_backlog > 0 && uwsgi.has_emperor) {
|
||||
if (uwsgi.shared->load >= (uint64_t) uwsgi.vassal_sos_backlog) {
|
||||
// ask emperor for help
|
||||
char byte = 30;
|
||||
if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
else {
|
||||
uwsgi_log("asking emperor for reinforcements (backlog: %llu)...\n", (unsigned long long ) uwsgi.shared->load);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (uwsgi.shared->load >= uwsgi.shared->max_load) {
|
||||
uwsgi_log_verbose("*** uWSGI listen queue of socket %d full !!! (%llu/%llu) ***\n", fd, (unsigned long long ) uwsgi.shared->load, (unsigned long long ) uwsgi.shared->max_load);
|
||||
uwsgi.shared->options[UWSGI_OPTION_BACKLOG_ERRORS]++;
|
||||
}
|
||||
|
||||
return uwsgi.shared->load;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/sockios.h>
|
||||
|
||||
#ifdef UNBIT
|
||||
#define SIOBKLGQ 0x8908
|
||||
#endif
|
||||
|
||||
#ifdef SIOBKLGQ
|
||||
|
||||
int get_linux_unbit_SIOBKLGQ(int fd) {
|
||||
|
||||
int queue = 0;
|
||||
if (ioctl(fd, SIOBKLGQ, &queue) >= 0) {
|
||||
uwsgi.shared->load = queue;
|
||||
uwsgi.shared->options[UWSGI_OPTION_BACKLOG_STATUS] = queue;
|
||||
if (queue >= uwsgi.listen_queue) {
|
||||
uwsgi_log_verbose("*** uWSGI listen queue of socket %d full !!! (%d/%d) ***\n", fd, queue, uwsgi.listen_queue);
|
||||
uwsgi.shared->options[UWSGI_OPTION_BACKLOG_ERRORS]++;
|
||||
}
|
||||
return queue;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
int master_loop(char **argv, char **environ) {
|
||||
|
||||
struct timeval last_respawn;
|
||||
int last_respawn_rate = 0;
|
||||
|
||||
pid_t diedpid;
|
||||
int waitpid_status;
|
||||
|
||||
time_t now = 0;
|
||||
|
||||
int i = 0;
|
||||
int rlen;
|
||||
|
||||
int check_interval = 1;
|
||||
|
||||
struct uwsgi_rb_timer *min_timeout;
|
||||
struct uwsgi_rbtree *rb_timers = uwsgi_init_rb_timer();
|
||||
|
||||
|
||||
if (uwsgi.procname_master) {
|
||||
uwsgi_set_processname(uwsgi.procname_master);
|
||||
}
|
||||
else if (uwsgi.procname) {
|
||||
uwsgi_set_processname(uwsgi.procname);
|
||||
}
|
||||
else if (uwsgi.auto_procname) {
|
||||
uwsgi_set_processname("uWSGI master");
|
||||
}
|
||||
|
||||
|
||||
uwsgi.current_time = uwsgi_now();
|
||||
|
||||
uwsgi_unix_signal(SIGTSTP, suspend_resume_them_all);
|
||||
uwsgi_unix_signal(SIGHUP, grace_them_all);
|
||||
if (uwsgi.die_on_term) {
|
||||
uwsgi_unix_signal(SIGTERM, kill_them_all);
|
||||
uwsgi_unix_signal(SIGQUIT, reap_them_all);
|
||||
}
|
||||
else {
|
||||
uwsgi_unix_signal(SIGTERM, reap_them_all);
|
||||
uwsgi_unix_signal(SIGQUIT, kill_them_all);
|
||||
}
|
||||
uwsgi_unix_signal(SIGINT, kill_them_all);
|
||||
uwsgi_unix_signal(SIGUSR1, stats);
|
||||
if (uwsgi.auto_snapshot) {
|
||||
uwsgi_unix_signal(SIGURG, uwsgi_restore_auto_snapshot);
|
||||
}
|
||||
|
||||
atexit(uwsgi_master_cleanup_hooks);
|
||||
|
||||
uwsgi.master_queue = event_queue_init();
|
||||
|
||||
/* route signals to workers... */
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("adding %d to signal poll\n", uwsgi.shared->worker_signal_pipe[0]);
|
||||
#endif
|
||||
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_signal_pipe[0]);
|
||||
|
||||
if (uwsgi.spoolers) {
|
||||
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->spooler_signal_pipe[0]);
|
||||
}
|
||||
|
||||
if (uwsgi.mules_cnt > 0) {
|
||||
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->mule_signal_pipe[0]);
|
||||
}
|
||||
|
||||
if (uwsgi.log_master) {
|
||||
uwsgi.log_master_buf = uwsgi_malloc(uwsgi.log_master_bufsize);
|
||||
if (!uwsgi.threaded_logger) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("adding %d to master logging\n", uwsgi.shared->worker_log_pipe[0]);
|
||||
#endif
|
||||
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]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_threaded_logger_spawn();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
uwsgi_start_legions();
|
||||
#endif
|
||||
|
||||
uwsgi_cache_start_sweepers();
|
||||
uwsgi_cache_start_sync_servers();
|
||||
|
||||
uwsgi.wsgi_req->buffer = uwsgi.workers[0].cores[0].buffer;
|
||||
|
||||
if (uwsgi.has_emperor) {
|
||||
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.emperor_fd);
|
||||
}
|
||||
|
||||
if (uwsgi.zerg_server) {
|
||||
uwsgi.zerg_server_fd = bind_to_unix(uwsgi.zerg_server, uwsgi.listen_queue, 0, 0);
|
||||
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.zerg_server_fd);
|
||||
uwsgi_log("*** Zerg server enabled on %s ***\n", uwsgi.zerg_server);
|
||||
}
|
||||
|
||||
if (uwsgi.stats) {
|
||||
char *tcp_port = strchr(uwsgi.stats, ':');
|
||||
if (tcp_port) {
|
||||
// disable deferred accept for this socket
|
||||
int current_defer_accept = uwsgi.no_defer_accept;
|
||||
uwsgi.no_defer_accept = 1;
|
||||
uwsgi.stats_fd = bind_to_tcp(uwsgi.stats, uwsgi.listen_queue, tcp_port);
|
||||
uwsgi.no_defer_accept = current_defer_accept;
|
||||
}
|
||||
else {
|
||||
uwsgi.stats_fd = bind_to_unix(uwsgi.stats, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
|
||||
}
|
||||
|
||||
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.stats_fd);
|
||||
uwsgi_log("*** Stats server enabled on %s fd: %d ***\n", uwsgi.stats, uwsgi.stats_fd);
|
||||
}
|
||||
|
||||
|
||||
if (uwsgi.stats_pusher_instances) {
|
||||
if (!uwsgi_thread_new(uwsgi_stats_pusher_loop)) {
|
||||
uwsgi_log("!!! unable to spawn stats pusher thread !!!\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.udp_socket) {
|
||||
uwsgi.udp_fd = bind_to_udp(uwsgi.udp_socket, 0, 0);
|
||||
if (uwsgi.udp_fd < 0) {
|
||||
uwsgi_log("unable to bind to udp socket. SNMP services will be disabled.\n");
|
||||
}
|
||||
else {
|
||||
uwsgi_log("UDP server enabled.\n");
|
||||
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.udp_fd);
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi.snmp_fd = uwsgi_setup_snmp();
|
||||
|
||||
if (uwsgi.status.is_cheap) {
|
||||
uwsgi_add_sockets_to_queue(uwsgi.master_queue, -1);
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
uwsgi.workers[i].cheaped = 1;
|
||||
}
|
||||
uwsgi_log("cheap mode enabled: waiting for socket connection...\n");
|
||||
}
|
||||
|
||||
|
||||
// spawn mules
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
size_t mule_patch_size = 0;
|
||||
uwsgi.mules[i].patch = uwsgi_string_get_list(&uwsgi.mules_patches, i, &mule_patch_size);
|
||||
uwsgi_mule(i + 1);
|
||||
}
|
||||
|
||||
// spawn gateways
|
||||
for (i = 0; i < ushared->gateways_cnt; i++) {
|
||||
if (ushared->gateways[i].pid == 0) {
|
||||
gateway_respawn(i);
|
||||
}
|
||||
}
|
||||
|
||||
// spawn daemons
|
||||
uwsgi_daemons_spawn_all();
|
||||
|
||||
// first subscription
|
||||
uwsgi_subscribe_all(0, 1);
|
||||
|
||||
// sync the cache store if needed
|
||||
uwsgi_cache_sync_all();
|
||||
|
||||
if (uwsgi.queue_store && uwsgi.queue_filesize) {
|
||||
if (msync(uwsgi.queue_header, uwsgi.queue_filesize, MS_ASYNC)) {
|
||||
uwsgi_error("msync()");
|
||||
}
|
||||
}
|
||||
|
||||
// update touches timestamps
|
||||
uwsgi_check_touches(uwsgi.touch_reload);
|
||||
uwsgi_check_touches(uwsgi.touch_logrotate);
|
||||
uwsgi_check_touches(uwsgi.touch_logreopen);
|
||||
uwsgi_check_touches(uwsgi.touch_chain_reload);
|
||||
uwsgi_check_touches(uwsgi.touch_workers_reload);
|
||||
uwsgi_check_touches(uwsgi.touch_gracefully_stop);
|
||||
|
||||
// setup cheaper algos (can be stacked)
|
||||
uwsgi.cheaper_algo = uwsgi_cheaper_algo_spare;
|
||||
if (uwsgi.requested_cheaper_algo) {
|
||||
uwsgi.cheaper_algo = NULL;
|
||||
struct uwsgi_cheaper_algo *uca = uwsgi.cheaper_algos;
|
||||
while (uca) {
|
||||
if (!strcmp(uca->name, uwsgi.requested_cheaper_algo)) {
|
||||
uwsgi.cheaper_algo = uca->func;
|
||||
break;
|
||||
}
|
||||
uca = uca->next;
|
||||
}
|
||||
|
||||
if (!uwsgi.cheaper_algo) {
|
||||
uwsgi_log("unable to find requested cheaper algorithm, falling back to spare\n");
|
||||
uwsgi.cheaper_algo = uwsgi_cheaper_algo_spare;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// here really starts the master loop
|
||||
|
||||
for (;;) {
|
||||
//uwsgi_log("uwsgi.ready_to_reload %d %d\n", uwsgi.ready_to_reload, uwsgi.numproc);
|
||||
|
||||
// run master_cycle hook for every plugin
|
||||
for (i = 0; i < uwsgi.gp_cnt; i++) {
|
||||
if (uwsgi.gp[i]->master_cycle) {
|
||||
uwsgi.gp[i]->master_cycle();
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->master_cycle) {
|
||||
uwsgi.p[i]->master_cycle();
|
||||
}
|
||||
}
|
||||
|
||||
// check for death (before reload !!!)
|
||||
uwsgi_master_check_death();
|
||||
// check for realod
|
||||
if (uwsgi_master_check_reload(argv)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// check chain reload
|
||||
uwsgi_master_check_chain();
|
||||
|
||||
// check if some worker is taking too much to die...
|
||||
uwsgi_master_check_mercy();
|
||||
|
||||
// check for daemons (smart and dumb)
|
||||
uwsgi_daemons_smart_check();
|
||||
|
||||
|
||||
if (uwsgi.respawn_snapshots) {
|
||||
for (i = 1; i <= uwsgi.respawn_snapshots; i++) {
|
||||
if (uwsgi_respawn_worker(i))
|
||||
return 0;
|
||||
}
|
||||
|
||||
uwsgi.respawn_snapshots = 0;
|
||||
}
|
||||
|
||||
if (uwsgi.restore_snapshot) {
|
||||
uwsgi_master_restore_snapshot();
|
||||
continue;
|
||||
}
|
||||
|
||||
// cheaper management
|
||||
if (uwsgi.cheaper && !uwsgi.status.is_cheap && !uwsgi_instance_is_reloading && !uwsgi_instance_is_dying && !uwsgi.workers[0].suspended) {
|
||||
if (!uwsgi_calc_cheaper())
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// check if someone is dead
|
||||
diedpid = waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
|
||||
if (diedpid == -1) {
|
||||
if (errno == ECHILD) {
|
||||
// something did not work as expected, just assume all has been cleared
|
||||
uwsgi_master_commit_status();
|
||||
diedpid = 0;
|
||||
}
|
||||
else {
|
||||
uwsgi_error("waitpid()");
|
||||
/* here is better to reload all the uWSGI stack */
|
||||
uwsgi_log("something horrible happened...\n");
|
||||
reap_them_all(0);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// no one died just run all of the standard master tasks
|
||||
if (diedpid == 0) {
|
||||
|
||||
/* all processes ok, doing status scan after N seconds */
|
||||
check_interval = uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL];
|
||||
if (!check_interval)
|
||||
check_interval = 1;
|
||||
|
||||
|
||||
// add unregistered file monitors
|
||||
// locking is not needed as monitors can only increase
|
||||
for (i = 0; i < ushared->files_monitored_cnt; i++) {
|
||||
if (!ushared->files_monitored[i].registered) {
|
||||
ushared->files_monitored[i].fd = event_queue_add_file_monitor(uwsgi.master_queue, ushared->files_monitored[i].filename, &ushared->files_monitored[i].id);
|
||||
ushared->files_monitored[i].registered = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// add unregistered timers
|
||||
// locking is not needed as timers can only increase
|
||||
for (i = 0; i < ushared->timers_cnt; i++) {
|
||||
if (!ushared->timers[i].registered) {
|
||||
ushared->timers[i].fd = event_queue_add_timer(uwsgi.master_queue, &ushared->timers[i].id, ushared->timers[i].value);
|
||||
ushared->timers[i].registered = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// add unregistered rb_timers
|
||||
// locking is not needed as rb_timers can only increase
|
||||
for (i = 0; i < ushared->rb_timers_cnt; i++) {
|
||||
if (!ushared->rb_timers[i].registered) {
|
||||
ushared->rb_timers[i].uwsgi_rb_timer = uwsgi_add_rb_timer(rb_timers, uwsgi_now() + ushared->rb_timers[i].value, &ushared->rb_timers[i]);
|
||||
ushared->rb_timers[i].registered = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int interesting_fd = -1;
|
||||
|
||||
if (ushared->rb_timers_cnt > 0) {
|
||||
min_timeout = uwsgi_min_rb_timer(rb_timers, NULL);
|
||||
if (min_timeout == NULL) {
|
||||
check_interval = uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL];
|
||||
}
|
||||
else {
|
||||
check_interval = min_timeout->value - uwsgi_now();
|
||||
if (check_interval <= 0) {
|
||||
expire_rb_timeouts(rb_timers);
|
||||
check_interval = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// wait for event
|
||||
rlen = event_queue_wait(uwsgi.master_queue, check_interval, &interesting_fd);
|
||||
|
||||
if (rlen == 0) {
|
||||
if (ushared->rb_timers_cnt > 0) {
|
||||
expire_rb_timeouts(rb_timers);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// check uwsgi-cron table
|
||||
if (ushared->cron_cnt) {
|
||||
uwsgi_manage_signal_cron(uwsgi_now());
|
||||
}
|
||||
|
||||
if (uwsgi.crons) {
|
||||
uwsgi_manage_command_cron(uwsgi_now());
|
||||
}
|
||||
|
||||
|
||||
// check for probes
|
||||
if (ushared->probes_cnt > 0) {
|
||||
uwsgi_lock(uwsgi.probe_table_lock);
|
||||
for (i = 0; i < ushared->probes_cnt; i++) {
|
||||
if (interesting_fd == -1) {
|
||||
// increment cycles
|
||||
ushared->probes[i].cycles++;
|
||||
}
|
||||
if (ushared->probes[i].func(interesting_fd, &ushared->probes[i])) {
|
||||
uwsgi_route_signal(ushared->probes[i].sig);
|
||||
}
|
||||
}
|
||||
uwsgi_unlock(uwsgi.probe_table_lock);
|
||||
}
|
||||
|
||||
// some event returned
|
||||
if (rlen > 0) {
|
||||
// if the following function returns -1, a new worker has just spawned
|
||||
if (uwsgi_master_manage_events(interesting_fd)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
now = uwsgi_now();
|
||||
if (now - uwsgi.current_time < 1) {
|
||||
continue;
|
||||
}
|
||||
uwsgi.current_time = now;
|
||||
|
||||
// checking logsize
|
||||
if (uwsgi.logfile) {
|
||||
uwsgi_check_logrotate();
|
||||
}
|
||||
|
||||
// this will be incremented at (more or less) regular intervals
|
||||
uwsgi.master_cycles++;
|
||||
|
||||
// recalculate requests counter on race conditions risky configurations
|
||||
// a bit of inaccuracy is better than locking;)
|
||||
uwsgi_master_fix_request_counters();
|
||||
|
||||
// check for idle
|
||||
uwsgi_master_check_idle();
|
||||
|
||||
check_interval = uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL];
|
||||
if (!check_interval)
|
||||
check_interval = 1;
|
||||
|
||||
|
||||
// get listen_queue status
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
while (uwsgi_sock) {
|
||||
if (uwsgi_sock->family == AF_INET) {
|
||||
uwsgi_sock->queue = uwsgi_get_tcp_info(uwsgi_sock->fd);
|
||||
}
|
||||
#ifdef __linux__
|
||||
#ifdef SIOBKLGQ
|
||||
else if (uwsgi_sock->family == AF_UNIX) {
|
||||
uwsgi_sock->queue = get_linux_unbit_SIOBKLGQ(uwsgi_sock->fd);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
// check if some worker has to die (harakiri, evil checks...)
|
||||
uwsgi_master_check_workers_deadline();
|
||||
|
||||
uwsgi_master_check_gateways_deadline();
|
||||
uwsgi_master_check_mules_deadline();
|
||||
uwsgi_master_check_spoolers_deadline();
|
||||
|
||||
#ifdef __linux__
|
||||
#ifdef MADV_MERGEABLE
|
||||
if (uwsgi.linux_ksm > 0 && (uwsgi.master_cycles % uwsgi.linux_ksm) == 0) {
|
||||
uwsgi_linux_ksm_map();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// resubscribe every 10 cycles by default
|
||||
if (( (uwsgi.subscriptions || uwsgi.subscriptions2) && ((uwsgi.master_cycles % uwsgi.subscribe_freq) == 0 || uwsgi.master_cycles == 1)) && !uwsgi_instance_is_reloading && !uwsgi_instance_is_dying && !uwsgi.workers[0].suspended) {
|
||||
uwsgi_subscribe_all(0, 0);
|
||||
}
|
||||
|
||||
uwsgi_cache_sync_all();
|
||||
|
||||
if (uwsgi.queue_store && uwsgi.queue_filesize && uwsgi.queue_store_sync && ((uwsgi.master_cycles % uwsgi.queue_store_sync) == 0)) {
|
||||
if (msync(uwsgi.queue_header, uwsgi.queue_filesize, MS_ASYNC)) {
|
||||
uwsgi_error("msync()");
|
||||
}
|
||||
}
|
||||
|
||||
// check touch_reload
|
||||
if (!uwsgi_instance_is_reloading && !uwsgi_instance_is_dying) {
|
||||
char *touched = uwsgi_check_touches(uwsgi.touch_reload);
|
||||
if (touched) {
|
||||
uwsgi_log_verbose("*** %s has been touched... grace them all !!! ***\n", touched);
|
||||
uwsgi_block_signal(SIGHUP);
|
||||
grace_them_all(0);
|
||||
uwsgi_unblock_signal(SIGHUP);
|
||||
continue;
|
||||
}
|
||||
touched = uwsgi_check_touches(uwsgi.touch_workers_reload);
|
||||
if (touched) {
|
||||
uwsgi_log_verbose("*** %s has been touched... workers reload !!! ***\n", touched);
|
||||
uwsgi_block_signal(SIGHUP);
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
if (uwsgi.workers[i].pid > 0) {
|
||||
uwsgi_curse(i, SIGHUP);
|
||||
}
|
||||
}
|
||||
uwsgi_unblock_signal(SIGHUP);
|
||||
continue;
|
||||
}
|
||||
touched = uwsgi_check_touches(uwsgi.touch_chain_reload);
|
||||
if (touched) {
|
||||
if (uwsgi.status.chain_reloading == 0) {
|
||||
uwsgi_log_verbose("*** %s has been touched... chain reload !!! ***\n", touched);
|
||||
uwsgi.status.chain_reloading = 1;
|
||||
}
|
||||
else {
|
||||
uwsgi_log_verbose("*** %s has been touched... but chain reload is already running ***\n", touched);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
// no one died
|
||||
if (diedpid <= 0)
|
||||
continue;
|
||||
|
||||
// check for deadlocks first
|
||||
uwsgi_deadlock_check(diedpid);
|
||||
|
||||
// reload gateways and daemons only on normal workflow (+outworld status)
|
||||
if (!uwsgi_instance_is_reloading && !uwsgi_instance_is_dying) {
|
||||
|
||||
if (uwsgi_master_check_emperor_death(diedpid)) continue;
|
||||
if (uwsgi_master_check_spoolers_death(diedpid)) continue;
|
||||
if (uwsgi_master_check_mules_death(diedpid)) continue;
|
||||
if (uwsgi_master_check_gateways_death(diedpid)) continue;
|
||||
if (uwsgi_master_check_daemons_death(diedpid)) continue;
|
||||
}
|
||||
|
||||
|
||||
/* What happens here ?
|
||||
|
||||
case 1) the diedpid is not a worker, report it and continue
|
||||
case 2) the diedpid is a worker and we are not in a reload procedure -> reload it
|
||||
case 3) the diedpid is a worker and we are in graceful reload -> uwsgi.ready_to_reload++ and continue
|
||||
case 3) the diedpid is a worker and we are in brutal reload -> uwsgi.ready_to_die++ and continue
|
||||
|
||||
|
||||
*/
|
||||
|
||||
int thewid = find_worker_id(diedpid);
|
||||
if (thewid <= 0) {
|
||||
// check spooler, mules, gateways and daemons
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
while (uspool) {
|
||||
if (uspool->pid > 0 && diedpid == uspool->pid) {
|
||||
uwsgi_log("spooler (pid: %d) annihilated\n", (int) diedpid);
|
||||
goto next;
|
||||
}
|
||||
uspool = uspool->next;
|
||||
}
|
||||
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
if (uwsgi.mules[i].pid == diedpid) {
|
||||
uwsgi_log("mule %d (pid: %d) annihilated\n", i + 1, (int) diedpid);
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ushared->gateways_cnt; i++) {
|
||||
if (ushared->gateways[i].pid == diedpid) {
|
||||
uwsgi_log("gateway %d (%s, pid: %d) annihilated\n", i + 1, ushared->gateways[i].fullname, (int) diedpid);
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi_daemon_check_pid_death(diedpid))
|
||||
goto next;
|
||||
|
||||
if (WIFEXITED(waitpid_status)) {
|
||||
uwsgi_log("subprocess %d exited with code %d\n", (int) diedpid, WEXITSTATUS(waitpid_status));
|
||||
}
|
||||
else if (WIFSIGNALED(waitpid_status)) {
|
||||
uwsgi_log("subprocess %d exited by signal %d\n", (int) diedpid, WTERMSIG(waitpid_status));
|
||||
}
|
||||
else if (WIFSTOPPED(waitpid_status)) {
|
||||
uwsgi_log("subprocess %d stopped\n", (int) diedpid);
|
||||
}
|
||||
next:
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// ok a worker died...
|
||||
uwsgi.workers[thewid].pid = 0;
|
||||
// only to be safe :P
|
||||
uwsgi.workers[thewid].harakiri = 0;
|
||||
|
||||
// ok, if we are reloading or dying, just continue the master loop
|
||||
// as soon as all of the workers have pid == 0, the action (exit, or reload) is triggered
|
||||
if (uwsgi_instance_is_reloading || uwsgi_instance_is_dying) {
|
||||
uwsgi_log("worker %d buried after %d seconds\n", thewid, (int) (uwsgi_now()-uwsgi.workers[thewid].cursed_at));
|
||||
uwsgi.workers[thewid].cursed_at = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// if we are stopping workers, just end here
|
||||
|
||||
if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_FAILED_APP_CODE) {
|
||||
uwsgi_log("OOPS ! failed loading app in worker %d (pid %d) :( trying again...\n", thewid, (int) diedpid);
|
||||
}
|
||||
else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_DE_HIJACKED_CODE) {
|
||||
uwsgi_log("...restoring worker %d (pid: %d)...\n", thewid, (int) diedpid);
|
||||
}
|
||||
else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_EXCEPTION_CODE) {
|
||||
uwsgi_log("... monitored exception detected, respawning worker %d (pid: %d)...\n", thewid, (int) diedpid);
|
||||
}
|
||||
else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_QUIET_CODE) {
|
||||
// noop
|
||||
}
|
||||
else if (uwsgi.workers[thewid].manage_next_request) {
|
||||
if (WIFSIGNALED(waitpid_status)) {
|
||||
uwsgi_log("DAMN ! worker %d (pid: %d) died, killed by signal %d :( trying respawn ...\n", thewid, (int) diedpid, (int) WTERMSIG(waitpid_status));
|
||||
}
|
||||
else {
|
||||
uwsgi_log("DAMN ! worker %d (pid: %d) died :( trying respawn ...\n", thewid, (int) diedpid);
|
||||
}
|
||||
}
|
||||
else if (uwsgi.workers[thewid].cursed_at > 0) {
|
||||
uwsgi_log("worker %d killed successfully (pid: %d)\n", thewid, (int) diedpid);
|
||||
}
|
||||
// manage_next_request is zero, but killed by signal...
|
||||
else if (WIFSIGNALED(waitpid_status)) {
|
||||
uwsgi_log("DAMN ! worker %d (pid: %d) MISTERIOUSLY killed by signal %d :( trying respawn ...\n", thewid, (int) diedpid, (int) WTERMSIG(waitpid_status));
|
||||
}
|
||||
|
||||
if (uwsgi.workers[thewid].cheaped == 1) {
|
||||
uwsgi_log("uWSGI worker %d cheaped.\n", thewid);
|
||||
continue;
|
||||
}
|
||||
|
||||
// avoid fork bombing
|
||||
gettimeofday(&last_respawn, NULL);
|
||||
if (last_respawn.tv_sec <= uwsgi.respawn_delta + check_interval) {
|
||||
last_respawn_rate++;
|
||||
if (last_respawn_rate > uwsgi.numproc) {
|
||||
if (uwsgi.forkbomb_delay > 0) {
|
||||
uwsgi_log("worker respawning too fast !!! i have to sleep a bit (%d seconds)...\n", uwsgi.forkbomb_delay);
|
||||
/* use --forkbomb-delay 0 to disable sleeping */
|
||||
sleep(uwsgi.forkbomb_delay);
|
||||
}
|
||||
last_respawn_rate = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
last_respawn_rate = 0;
|
||||
}
|
||||
gettimeofday(&last_respawn, NULL);
|
||||
uwsgi.respawn_delta = last_respawn.tv_sec;
|
||||
|
||||
// are we chain reloading it ?
|
||||
if (uwsgi.status.chain_reloading == thewid) {
|
||||
uwsgi.status.chain_reloading++;
|
||||
}
|
||||
|
||||
// respawn the worker (if needed)
|
||||
if (uwsgi_respawn_worker(thewid))
|
||||
return 0;
|
||||
|
||||
// end of the loop
|
||||
}
|
||||
|
||||
// never here
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
+1487
File diff suppressed because it is too large
Load Diff
+470
@@ -0,0 +1,470 @@
|
||||
/*
|
||||
|
||||
uWSGI mules are very simple workers only managing signals or running custom code in background.
|
||||
|
||||
By default they born in signal-only mode, but if you patch them (passing the script/code to run) they will became fully customized daemons.
|
||||
|
||||
*/
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_mule_handler(void);
|
||||
|
||||
void mule_send_msg(int fd, char *message, size_t len) {
|
||||
|
||||
socklen_t so_bufsize_len = sizeof(int);
|
||||
int so_bufsize = 0;
|
||||
|
||||
if (write(fd, message, len) != (ssize_t) len) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &so_bufsize, &so_bufsize_len)) {
|
||||
uwsgi_error("getsockopt()");
|
||||
}
|
||||
uwsgi_log("*** MULE MSG QUEUE IS FULL: buffer size %d bytes (you can tune it with --signal-bufsize) ***\n", so_bufsize);
|
||||
}
|
||||
else {
|
||||
uwsgi_error("mule_send_msg()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_mule(int id) {
|
||||
|
||||
int i;
|
||||
|
||||
pid_t pid = uwsgi_fork(uwsgi.mules[id - 1].name);
|
||||
if (pid == 0) {
|
||||
#ifdef __linux__
|
||||
if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) {
|
||||
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);
|
||||
|
||||
uwsgi.my_signal_socket = uwsgi.mules[id - 1].signal_pipe[1];
|
||||
uwsgi.signal_socket = uwsgi.shared->mule_signal_pipe[1];
|
||||
|
||||
uwsgi_close_all_sockets();
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->master_fixup) {
|
||||
uwsgi.p[i]->master_fixup(1);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->post_fork) {
|
||||
uwsgi.p[i]->post_fork();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (uwsgi.mules[id - 1].patch) {
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->mule) {
|
||||
if (uwsgi.p[i]->mule(uwsgi.mules[id - 1].patch) == 1) {
|
||||
// never here ?
|
||||
end_me(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_mule_handler();
|
||||
}
|
||||
else if (pid > 0) {
|
||||
uwsgi.mules[id - 1].id = id;
|
||||
uwsgi.mules[id - 1].pid = pid;
|
||||
uwsgi_log("spawned uWSGI mule %d (pid: %d)\n", id, (int) pid);
|
||||
}
|
||||
}
|
||||
|
||||
int uwsgi_farm_has_mule(struct uwsgi_farm *farm, int muleid) {
|
||||
|
||||
struct uwsgi_mule_farm *umf = farm->mules;
|
||||
|
||||
while (umf) {
|
||||
if (umf->mule->id == muleid) {
|
||||
return 1;
|
||||
}
|
||||
umf = umf->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int farm_has_signaled(int fd) {
|
||||
|
||||
int i;
|
||||
for (i = 0; i < uwsgi.farms_cnt; i++) {
|
||||
struct uwsgi_mule_farm *umf = uwsgi.farms[i].mules;
|
||||
while (umf) {
|
||||
if (umf->mule->id == uwsgi.muleid && uwsgi.farms[i].signal_pipe[1] == fd) {
|
||||
return 1;
|
||||
}
|
||||
umf = umf->next;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int farm_has_msg(int fd) {
|
||||
|
||||
int i;
|
||||
for (i = 0; i < uwsgi.farms_cnt; i++) {
|
||||
struct uwsgi_mule_farm *umf = uwsgi.farms[i].mules;
|
||||
while (umf) {
|
||||
if (umf->mule->id == uwsgi.muleid && uwsgi.farms[i].queue_pipe[1] == fd) {
|
||||
return 1;
|
||||
}
|
||||
umf = umf->next;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_mule_add_farm_to_queue(int queue) {
|
||||
|
||||
int i;
|
||||
for (i = 0; i < uwsgi.farms_cnt; i++) {
|
||||
if (uwsgi_farm_has_mule(&uwsgi.farms[i], uwsgi.muleid)) {
|
||||
event_queue_add_fd_read(queue, uwsgi.farms[i].signal_pipe[1]);
|
||||
event_queue_add_fd_read(queue, uwsgi.farms[i].queue_pipe[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_mule_handler() {
|
||||
|
||||
ssize_t len;
|
||||
uint8_t uwsgi_signal;
|
||||
int rlen;
|
||||
int interesting_fd;
|
||||
|
||||
// this must be configurable
|
||||
char message[65536];
|
||||
|
||||
int mule_queue = event_queue_init();
|
||||
|
||||
event_queue_add_fd_read(mule_queue, uwsgi.signal_socket);
|
||||
event_queue_add_fd_read(mule_queue, uwsgi.my_signal_socket);
|
||||
event_queue_add_fd_read(mule_queue, uwsgi.mules[uwsgi.muleid - 1].queue_pipe[1]);
|
||||
event_queue_add_fd_read(mule_queue, uwsgi.shared->mule_queue_pipe[1]);
|
||||
|
||||
uwsgi_mule_add_farm_to_queue(mule_queue);
|
||||
|
||||
for (;;) {
|
||||
rlen = event_queue_wait(mule_queue, -1, &interesting_fd);
|
||||
if (rlen <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (interesting_fd == uwsgi.signal_socket || interesting_fd == uwsgi.my_signal_socket || farm_has_signaled(interesting_fd)) {
|
||||
len = read(interesting_fd, &uwsgi_signal, 1);
|
||||
if (len <= 0) {
|
||||
if (len < 0 && (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)) continue;
|
||||
uwsgi_log_verbose("uWSGI mule %d braying: my master died, i will follow him...\n", uwsgi.muleid);
|
||||
end_me(0);
|
||||
}
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log_verbose("master sent signal %d to mule %d\n", uwsgi_signal, uwsgi.muleid);
|
||||
#endif
|
||||
if (uwsgi_signal_handler(uwsgi_signal)) {
|
||||
uwsgi_log_verbose("error managing signal %d on mule %d\n", uwsgi_signal, uwsgi.muleid);
|
||||
}
|
||||
}
|
||||
else if (interesting_fd == uwsgi.mules[uwsgi.muleid - 1].queue_pipe[1] || interesting_fd == uwsgi.shared->mule_queue_pipe[1] || farm_has_msg(interesting_fd)) {
|
||||
len = read(interesting_fd, message, 65536);
|
||||
if (len < 0) {
|
||||
if (errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) {
|
||||
uwsgi_error("uwsgi_mule_handler/read()");
|
||||
}
|
||||
}
|
||||
else {
|
||||
int i, found = 0;
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->mule_msg) {
|
||||
if (uwsgi.p[i]->mule_msg(message, len)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
uwsgi_log("*** mule %d received a %ld bytes message ***\n", uwsgi.muleid, (long) len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_mule *get_mule_by_id(int id) {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
if (uwsgi.mules[i].id == id) {
|
||||
return &uwsgi.mules[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_farm *get_farm_by_name(char *name) {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < uwsgi.farms_cnt; i++) {
|
||||
if (!strcmp(uwsgi.farms[i].name, name)) {
|
||||
return &uwsgi.farms[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_mule_farm *uwsgi_mule_farm_new(struct uwsgi_mule_farm **umf, struct uwsgi_mule *um) {
|
||||
|
||||
struct uwsgi_mule_farm *uwsgi_mf = *umf, *old_umf;
|
||||
|
||||
if (!uwsgi_mf) {
|
||||
*umf = uwsgi_malloc(sizeof(struct uwsgi_mule_farm));
|
||||
uwsgi_mf = *umf;
|
||||
}
|
||||
else {
|
||||
while (uwsgi_mf) {
|
||||
old_umf = uwsgi_mf;
|
||||
uwsgi_mf = uwsgi_mf->next;
|
||||
}
|
||||
|
||||
uwsgi_mf = uwsgi_malloc(sizeof(struct uwsgi_mule_farm));
|
||||
old_umf->next = uwsgi_mf;
|
||||
}
|
||||
|
||||
uwsgi_mf->mule = um;
|
||||
uwsgi_mf->next = NULL;
|
||||
|
||||
return uwsgi_mf;
|
||||
}
|
||||
|
||||
ssize_t uwsgi_mule_get_msg(int manage_signals, int manage_farms, char *message, size_t buffer_size, int timeout) {
|
||||
|
||||
ssize_t len = 0;
|
||||
struct pollfd *mulepoll;
|
||||
int count = 4;
|
||||
int farms_count = 0;
|
||||
uint8_t uwsgi_signal;
|
||||
int i;
|
||||
|
||||
if (uwsgi.muleid == 0)
|
||||
return -1;
|
||||
|
||||
if (manage_signals)
|
||||
count = 2;
|
||||
|
||||
if (!manage_farms)
|
||||
goto next;
|
||||
|
||||
for (i = 0; i < uwsgi.farms_cnt; i++) {
|
||||
if (uwsgi_farm_has_mule(&uwsgi.farms[i], uwsgi.muleid))
|
||||
farms_count++;
|
||||
}
|
||||
next:
|
||||
|
||||
if (timeout > -1)
|
||||
timeout = timeout * 1000;
|
||||
|
||||
mulepoll = uwsgi_malloc(sizeof(struct pollfd) * (count + farms_count));
|
||||
|
||||
mulepoll[0].fd = uwsgi.mules[uwsgi.muleid - 1].queue_pipe[1];
|
||||
mulepoll[0].events = POLLIN;
|
||||
mulepoll[1].fd = uwsgi.shared->mule_queue_pipe[1];
|
||||
mulepoll[1].events = POLLIN;
|
||||
if (count > 2) {
|
||||
mulepoll[2].fd = uwsgi.signal_socket;
|
||||
mulepoll[2].events = POLLIN;
|
||||
mulepoll[3].fd = uwsgi.my_signal_socket;
|
||||
mulepoll[3].events = POLLIN;
|
||||
}
|
||||
|
||||
if (farms_count > 0) {
|
||||
int tmp_cnt = 0;
|
||||
for (i = 0; i < uwsgi.farms_cnt; i++) {
|
||||
if (uwsgi_farm_has_mule(&uwsgi.farms[i], uwsgi.muleid)) {
|
||||
mulepoll[count + tmp_cnt].fd = uwsgi.farms[i].queue_pipe[1];
|
||||
mulepoll[count + tmp_cnt].events = POLLIN;
|
||||
tmp_cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ret = poll(mulepoll, count + farms_count, timeout);
|
||||
if (ret <= 0) {
|
||||
uwsgi_error("poll");
|
||||
}
|
||||
else {
|
||||
if (mulepoll[0].revents & POLLIN) {
|
||||
len = read(uwsgi.mules[uwsgi.muleid - 1].queue_pipe[1], message, buffer_size);
|
||||
}
|
||||
else if (mulepoll[1].revents & POLLIN) {
|
||||
len = read(uwsgi.shared->mule_queue_pipe[1], message, buffer_size);
|
||||
}
|
||||
else {
|
||||
if (count > 2) {
|
||||
int interesting_fd = -1;
|
||||
if (mulepoll[2].revents & POLLIN) {
|
||||
interesting_fd = mulepoll[2].fd;
|
||||
}
|
||||
else if (mulepoll[3].revents & POLLIN) {
|
||||
interesting_fd = mulepoll[3].fd;
|
||||
}
|
||||
|
||||
if (interesting_fd > -1) {
|
||||
len = read(interesting_fd, &uwsgi_signal, 1);
|
||||
if (len <= 0) {
|
||||
if (len < 0 && (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)) goto clear;
|
||||
uwsgi_log_verbose("uWSGI mule %d braying: my master died, i will follow him...\n", uwsgi.muleid);
|
||||
end_me(0);
|
||||
}
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log_verbose("master sent signal %d to mule %d\n", uwsgi_signal, uwsgi.muleid);
|
||||
#endif
|
||||
if (uwsgi_signal_handler(uwsgi_signal)) {
|
||||
uwsgi_log_verbose("error managing signal %d on mule %d\n", uwsgi_signal, uwsgi.muleid);
|
||||
}
|
||||
// set the error condition
|
||||
len = -1;
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
|
||||
// read messages in the farm
|
||||
for (i = 0; i < farms_count; i++) {
|
||||
if (mulepoll[count + i].revents & POLLIN) {
|
||||
len = read(mulepoll[count + i].fd, message, buffer_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (len < 0) {
|
||||
uwsgi_error("read()");
|
||||
goto clear;
|
||||
}
|
||||
|
||||
clear:
|
||||
free(mulepoll);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_opt_add_mule(char *opt, char *value, void *foobar) {
|
||||
|
||||
uwsgi.mules_cnt++;
|
||||
uwsgi_string_new_list(&uwsgi.mules_patches, value);
|
||||
}
|
||||
|
||||
void uwsgi_opt_add_mules(char *opt, char *value, void *foobar) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < atoi(value); i++) {
|
||||
uwsgi.mules_cnt++;
|
||||
uwsgi_string_new_list(&uwsgi.mules_patches, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_opt_add_farm(char *opt, char *value, void *foobar) {
|
||||
uwsgi.farms_cnt++;
|
||||
uwsgi_string_new_list(&uwsgi.farms_list, value);
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_setup_mules_and_farms() {
|
||||
int i;
|
||||
if (uwsgi.mules_cnt > 0) {
|
||||
uwsgi.mules = (struct uwsgi_mule *) uwsgi_calloc_shared(sizeof(struct uwsgi_mule) * uwsgi.mules_cnt);
|
||||
|
||||
create_signal_pipe(uwsgi.shared->mule_signal_pipe);
|
||||
create_signal_pipe(uwsgi.shared->mule_queue_pipe);
|
||||
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
// create the socket pipe
|
||||
create_signal_pipe(uwsgi.mules[i].signal_pipe);
|
||||
create_signal_pipe(uwsgi.mules[i].queue_pipe);
|
||||
|
||||
uwsgi.mules[i].id = i + 1;
|
||||
|
||||
snprintf(uwsgi.mules[i].name, 0xff, "uWSGI mule %d", i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.farms_cnt > 0) {
|
||||
uwsgi.farms = (struct uwsgi_farm *) uwsgi_calloc_shared(sizeof(struct uwsgi_farm) * uwsgi.farms_cnt);
|
||||
|
||||
struct uwsgi_string_list *farm_name = uwsgi.farms_list;
|
||||
for (i = 0; i < uwsgi.farms_cnt; i++) {
|
||||
|
||||
char *farm_value = uwsgi_str(farm_name->value);
|
||||
|
||||
char *mules_list = strchr(farm_value, ':');
|
||||
if (!mules_list) {
|
||||
uwsgi_log("invalid farm value (%s) must be in the form name:mule[,muleN].\n", farm_value);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
mules_list[0] = 0;
|
||||
mules_list++;
|
||||
|
||||
strncpy(uwsgi.farms[i].name, farm_value, 0xff);
|
||||
free(farm_value);
|
||||
|
||||
// create the socket pipe
|
||||
create_signal_pipe(uwsgi.farms[i].signal_pipe);
|
||||
create_signal_pipe(uwsgi.farms[i].queue_pipe);
|
||||
|
||||
char *p = strtok(mules_list, ",");
|
||||
while (p != NULL) {
|
||||
struct uwsgi_mule *um = get_mule_by_id(atoi(p));
|
||||
if (!um) {
|
||||
uwsgi_log("invalid mule id: %s\n", p);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_mule_farm_new(&uwsgi.farms[i].mules, um);
|
||||
|
||||
p = strtok(NULL, ",");
|
||||
}
|
||||
uwsgi_log("created farm %d name: %s mules:%s\n", i + 1, uwsgi.farms[i].name, strchr(farm_name->value, ':') + 1);
|
||||
|
||||
farm_name = farm_name->next;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+18
-13
@@ -16,25 +16,28 @@ void uwsgi_systemd_notify(char *message) {
|
||||
iovec[1].iov_len = strlen(message);
|
||||
|
||||
iovec[2].iov_base = "\n";
|
||||
iovec[2].iov_len = 1;
|
||||
iovec[2].iov_len = 1;
|
||||
|
||||
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) {
|
||||
|
||||
struct msghdr *msghdr = (struct msghdr *) uwsgi.notification_object;
|
||||
struct iovec *iovec = msghdr->msg_iov;
|
||||
struct iovec *iovec = msghdr->msg_iov;
|
||||
|
||||
iovec[0].iov_base = "STATUS=uWSGI is ready\nREADY=1\n";
|
||||
iovec[0].iov_len = 30;
|
||||
iovec[0].iov_base = "STATUS=uWSGI is ready\nREADY=1\n";
|
||||
iovec[0].iov_len = 30;
|
||||
|
||||
msghdr->msg_iovlen = 1;
|
||||
|
||||
sendmsg(uwsgi.notification_fd, msghdr, 0);
|
||||
|
||||
if (sendmsg(uwsgi.notification_fd, msghdr, 0) < 0) {
|
||||
uwsgi_error("sendmsg()");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,24 +52,26 @@ void uwsgi_systemd_init(char *systemd_socket) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t len = strlen(systemd_socket);
|
||||
sd_sun = uwsgi_malloc(sizeof(struct sockaddr_un));
|
||||
memset(sd_sun, 0, sizeof(struct sockaddr_un));
|
||||
sd_sun->sun_family = AF_UNIX;
|
||||
strncpy(sd_sun->sun_path, systemd_socket, sizeof(sd_sun->sun_path));
|
||||
if (sd_sun->sun_path[0] == '@') sd_sun->sun_path[0] = 0;
|
||||
strncpy(sd_sun->sun_path, systemd_socket, UMIN(len, sizeof(sd_sun->sun_path)));
|
||||
if (sd_sun->sun_path[0] == '@')
|
||||
sd_sun->sun_path[0] = 0;
|
||||
|
||||
msghdr = uwsgi_malloc(sizeof(struct msghdr));
|
||||
memset(msghdr, 0, sizeof(struct msghdr));
|
||||
|
||||
msghdr->msg_iov = uwsgi_malloc(sizeof(struct iovec)*3);
|
||||
memset(msghdr->msg_iov, 0, sizeof(struct iovec)*3);
|
||||
msghdr->msg_iov = uwsgi_malloc(sizeof(struct iovec) * 3);
|
||||
memset(msghdr->msg_iov, 0, sizeof(struct iovec) * 3);
|
||||
|
||||
msghdr->msg_name = sd_sun;
|
||||
msghdr->msg_namelen = sizeof(struct sockaddr_un);
|
||||
msghdr->msg_namelen = sizeof(struct sockaddr_un) - (sizeof(sd_sun->sun_path) - len);
|
||||
|
||||
uwsgi.notification_object = msghdr;
|
||||
|
||||
uwsgi.notify = uwsgi_systemd_notify;
|
||||
uwsgi.notify_ready = uwsgi_systemd_notify_ready;
|
||||
|
||||
|
||||
}
|
||||
+509
@@ -0,0 +1,509 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
/*
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#define uwsgi_offload_retry if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) return 0;
|
||||
#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;
|
||||
|
||||
void uwsgi_offload_setup(struct uwsgi_offload_engine *uoe, struct uwsgi_offload_request *uor, struct wsgi_request *wsgi_req, uint8_t takeover) {
|
||||
|
||||
memset(uor, 0, sizeof(struct uwsgi_offload_request));
|
||||
|
||||
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) {
|
||||
struct uwsgi_core *uc = &uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id];
|
||||
uc->offloaded_requests++;
|
||||
// round robin
|
||||
if (uc->offload_rr >= uwsgi.offload_threads) {
|
||||
uc->offload_rr = 0;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
transfer offload engine:
|
||||
name -> socket name
|
||||
ubuf -> data to send
|
||||
|
||||
*/
|
||||
|
||||
int u_offload_transfer_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) {
|
||||
|
||||
if (!uor->name) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uor->fd = uwsgi_connect(uor->ubuf->buf, 0, 1);
|
||||
if (uor->fd < 0) {
|
||||
uwsgi_error("u_offload_transfer_prepare()/connect()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
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 (!uor->len) {
|
||||
struct stat st;
|
||||
if (fstat(uor->fd, &st)) {
|
||||
uwsgi_error("u_offload_sendfile_prepare()/fstat()");
|
||||
if (uor->name) {
|
||||
close(uor->fd);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
uor->len = st.st_size;
|
||||
}
|
||||
|
||||
if (uor->fd2 == -1) {
|
||||
uor->fd2 = uor->s;
|
||||
}
|
||||
uor->s = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uwsgi_offload_close(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor) {
|
||||
// close the socket and the file descriptor
|
||||
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;
|
||||
|
||||
if (uor == ut->offload_requests_head) {
|
||||
ut->offload_requests_head = next;
|
||||
}
|
||||
|
||||
if (uor == ut->offload_requests_tail) {
|
||||
ut->offload_requests_tail = prev;
|
||||
}
|
||||
|
||||
if (prev) {
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
if (next) {
|
||||
next->prev = prev;
|
||||
}
|
||||
|
||||
if (uor->buf) {
|
||||
free(uor->buf);
|
||||
}
|
||||
|
||||
if (uor->ubuf) {
|
||||
uwsgi_buffer_destroy(uor->ubuf);
|
||||
}
|
||||
|
||||
if (uor->pipe[0] != -1) {
|
||||
close(uor->pipe[1]);
|
||||
close(uor->pipe[0]);
|
||||
}
|
||||
|
||||
free(uor);
|
||||
}
|
||||
|
||||
static void uwsgi_offload_append(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor) {
|
||||
|
||||
if (!ut->offload_requests_head) {
|
||||
ut->offload_requests_head = uor;
|
||||
}
|
||||
|
||||
if (ut->offload_requests_tail) {
|
||||
ut->offload_requests_tail->next = uor;
|
||||
uor->prev = ut->offload_requests_tail;
|
||||
}
|
||||
|
||||
ut->offload_requests_tail = uor;
|
||||
}
|
||||
|
||||
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 || uor->fd2 == s) {
|
||||
return uor;
|
||||
}
|
||||
uor = uor->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void uwsgi_offload_loop(struct uwsgi_thread *ut) {
|
||||
|
||||
int i;
|
||||
void *events = event_queue_alloc(uwsgi.offload_threads_events);
|
||||
|
||||
for (;;) {
|
||||
int nevents = event_queue_wait_multi(ut->queue, -1, events, uwsgi.offload_threads_events);
|
||||
for (i = 0; i < nevents; i++) {
|
||||
int interesting_fd = event_queue_interesting_fd(events, i);
|
||||
if (interesting_fd == ut->pipe[1]) {
|
||||
struct uwsgi_offload_request *uor = uwsgi_malloc(sizeof(struct uwsgi_offload_request));
|
||||
ssize_t len = read(ut->pipe[1], uor, sizeof(struct uwsgi_offload_request));
|
||||
if (len != sizeof(struct uwsgi_offload_request)) {
|
||||
uwsgi_error("read()");
|
||||
free(uor);
|
||||
continue;
|
||||
}
|
||||
// cal the event function for the first time
|
||||
if (uor->engine->event_func(ut, uor, -1)) {
|
||||
uwsgi_offload_close(ut, uor);
|
||||
continue;
|
||||
}
|
||||
uwsgi_offload_append(ut, uor);
|
||||
continue;
|
||||
}
|
||||
|
||||
// get the task from the interesting fd
|
||||
struct uwsgi_offload_request *uor = uwsgi_offload_get_by_fd(ut, interesting_fd);
|
||||
if (!uor)
|
||||
continue;
|
||||
// run the hook
|
||||
if (uor->engine->event_func(ut, uor, interesting_fd)) {
|
||||
uwsgi_offload_close(ut, uor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_thread *uwsgi_offload_thread_start() {
|
||||
return uwsgi_thread_new(uwsgi_offload_loop);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
the offload task starts after having acquired the file fd
|
||||
|
||||
uor->len -> the size of the file
|
||||
uor->pos -> start writing from pos (default 0)
|
||||
|
||||
status: none
|
||||
|
||||
*/
|
||||
|
||||
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->fd2)) return -1;
|
||||
return 0;
|
||||
}
|
||||
#if defined(__linux__) || defined(__sun__)
|
||||
ssize_t len = sendfile(uor->fd2, uor->fd, &uor->pos, 128 * 1024);
|
||||
if (len > 0) {
|
||||
uor->written += len;
|
||||
if (uor->written >= uor->len) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (len < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_sendfile_do()");
|
||||
}
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
off_t 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("u_offload_sendfile_do()");
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
off_t len = 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("u_offload_sendfile_do()");
|
||||
}
|
||||
#endif
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
the offload task starts soon after the call to connect()
|
||||
|
||||
status:
|
||||
0 -> waiting for connection on fd
|
||||
1 -> sending request to fd (write event)
|
||||
2 -> start waiting for read on s and fd
|
||||
3 -> write to s
|
||||
4 -> write to fd
|
||||
*/
|
||||
static int u_offload_transfer_do(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) {
|
||||
|
||||
ssize_t rlen;
|
||||
|
||||
// setup
|
||||
if (fd == -1) {
|
||||
event_queue_add_fd_write(ut->queue, uor->fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch(uor->status) {
|
||||
// waiting for connection
|
||||
case 0:
|
||||
if (fd == uor->fd) {
|
||||
uor->status = 1;
|
||||
// ok try to send the request right now...
|
||||
return u_offload_transfer_do(ut, uor, fd);
|
||||
}
|
||||
return -1;
|
||||
// write event (or just connected)
|
||||
case 1:
|
||||
if (fd == uor->fd) {
|
||||
rlen = write(uor->fd, uor->ubuf->buf + uor->written, uor->ubuf->pos-uor->written);
|
||||
if (rlen > 0) {
|
||||
uor->written += rlen;
|
||||
if (uor->written >= (size_t)uor->ubuf->pos) {
|
||||
uor->status = 2;
|
||||
if (event_queue_add_fd_read(ut->queue, uor->s)) return -1;
|
||||
if (event_queue_fd_write_to_read(ut->queue, uor->fd)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_transfer_do() -> write()");
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
// read event from s or fd
|
||||
case 2:
|
||||
if (!uor->buf) {
|
||||
uor->buf = uwsgi_malloc(4096);
|
||||
}
|
||||
if (fd == uor->fd) {
|
||||
rlen = read(uor->fd, uor->buf, 4096);
|
||||
if (rlen > 0) {
|
||||
uor->to_write = rlen;
|
||||
uor->pos = 0;
|
||||
uwsgi_offload_0r_1w(uor->fd, uor->s)
|
||||
uor->status = 3;
|
||||
return 0;
|
||||
}
|
||||
if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_transfer_do() -> read()/fd");
|
||||
}
|
||||
}
|
||||
else if (fd == uor->s) {
|
||||
rlen = read(uor->s, uor->buf, 4096);
|
||||
if (rlen > 0) {
|
||||
uor->to_write = rlen;
|
||||
uor->pos = 0;
|
||||
uwsgi_offload_0r_1w(uor->s, uor->fd)
|
||||
uor->status = 4;
|
||||
return 0;
|
||||
}
|
||||
if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_transfer_do() -> read()/s");
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
// write event on s
|
||||
case 3:
|
||||
rlen = write(uor->s, uor->buf + uor->pos, uor->to_write);
|
||||
if (rlen > 0) {
|
||||
uor->to_write -= rlen;
|
||||
uor->pos += rlen;
|
||||
if (uor->to_write == 0) {
|
||||
if (event_queue_fd_write_to_read(ut->queue, uor->s)) return -1;
|
||||
if (event_queue_add_fd_read(ut->queue, uor->fd)) return -1;
|
||||
uor->status = 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_transfer_do() -> write()/s");
|
||||
}
|
||||
return -1;
|
||||
// write event on fd
|
||||
case 4:
|
||||
rlen = write(uor->fd, uor->buf + uor->pos, uor->to_write);
|
||||
if (rlen > 0) {
|
||||
uor->to_write -= rlen;
|
||||
uor->pos += rlen;
|
||||
if (uor->to_write == 0) {
|
||||
if (event_queue_fd_write_to_read(ut->queue, uor->fd)) return -1;
|
||||
if (event_queue_add_fd_read(ut->queue, uor->s)) return -1;
|
||||
uor->status = 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_transfer_do() -> write()/fd");
|
||||
}
|
||||
return -1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
+93
-62
@@ -2,7 +2,29 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
static int plugin_already_loaded(const char *plugin) {
|
||||
#ifdef UWSGI_ELF
|
||||
static void uwsgi_plugin_parse_section(char *filename) {
|
||||
size_t s_len = 0;
|
||||
char *buf = uwsgi_elf_section(filename, "uwsgi", &s_len);
|
||||
if (buf) {
|
||||
char *ctx = NULL;
|
||||
char *p = strtok_r(buf, "\n", &ctx);
|
||||
while (p) {
|
||||
char *equal = strchr(p, '=');
|
||||
if (equal) {
|
||||
*equal = 0;
|
||||
if (!strcmp(p, "requires")) {
|
||||
uwsgi_load_plugin(-1, equal + 1, NULL);
|
||||
}
|
||||
}
|
||||
p = strtok_r(NULL, "\n", &ctx);
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int plugin_already_loaded(const char *plugin) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
@@ -12,7 +34,7 @@ static int plugin_already_loaded(const char *plugin) {
|
||||
uwsgi_log("%s plugin already available\n", plugin);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (uwsgi.p[i]->alias) {
|
||||
if (!strcmp(plugin, uwsgi.p[i]->alias)) {
|
||||
@@ -20,29 +42,29 @@ static int plugin_already_loaded(const char *plugin) {
|
||||
uwsgi_log("%s plugin already available\n", plugin);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0;i<uwsgi.gp_cnt;i++) {
|
||||
for (i = 0; i < uwsgi.gp_cnt; i++) {
|
||||
|
||||
if (uwsgi.gp[i]->name) {
|
||||
if (!strcmp(plugin, uwsgi.gp[i]->name)) {
|
||||
if (!strcmp(plugin, uwsgi.gp[i]->name)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%s plugin already available\n", plugin);
|
||||
uwsgi_log("%s plugin already available\n", plugin);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (uwsgi.gp[i]->alias) {
|
||||
if (!strcmp(plugin, uwsgi.gp[i]->alias)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (uwsgi.gp[i]->alias) {
|
||||
if (!strcmp(plugin, uwsgi.gp[i]->alias)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%s plugin already available\n", plugin);
|
||||
uwsgi_log("%s plugin already available\n", plugin);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -54,9 +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];
|
||||
@@ -66,7 +87,7 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
|
||||
if (colon) {
|
||||
colon[0] = 0;
|
||||
modifier = atoi(plugin_name);
|
||||
plugin_name = colon+1;
|
||||
plugin_name = colon + 1;
|
||||
colon[0] = ':';
|
||||
}
|
||||
|
||||
@@ -79,10 +100,13 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
|
||||
|
||||
// step 1: check for absolute plugin (stop if it fails)
|
||||
if (strchr(plugin_name, '/')) {
|
||||
#ifdef UWSGI_ELF
|
||||
uwsgi_plugin_parse_section(plugin_name);
|
||||
#endif
|
||||
plugin_handle = dlopen(plugin_name, RTLD_NOW | RTLD_GLOBAL);
|
||||
if (!plugin_handle) {
|
||||
if (!has_option)
|
||||
uwsgi_log( "%s\n", dlerror());
|
||||
uwsgi_log("%s\n", dlerror());
|
||||
goto end;
|
||||
}
|
||||
plugin_symbol_name_start = uwsgi_get_last_char(plugin_name, '/');
|
||||
@@ -93,8 +117,11 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
|
||||
|
||||
// step dir, check for user-supplied plugins directory
|
||||
struct uwsgi_string_list *pdir = uwsgi.plugins_dir;
|
||||
while(pdir) {
|
||||
while (pdir) {
|
||||
plugin_filename = uwsgi_concat3(pdir->value, "/", plugin_name);
|
||||
#ifdef UWSGI_ELF
|
||||
uwsgi_plugin_parse_section(plugin_filename);
|
||||
#endif
|
||||
plugin_handle = dlopen(plugin_filename, RTLD_NOW | RTLD_GLOBAL);
|
||||
if (plugin_handle) {
|
||||
plugin_abs_path = plugin_filename;
|
||||
@@ -109,19 +136,22 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
|
||||
// last step: search in compile-time plugin_dir
|
||||
if (!plugin_handle) {
|
||||
plugin_filename = uwsgi_concat3(UWSGI_PLUGIN_DIR, "/", plugin_name);
|
||||
#ifdef UWSGI_ELF
|
||||
uwsgi_plugin_parse_section(plugin_filename);
|
||||
#endif
|
||||
plugin_handle = dlopen(plugin_filename, RTLD_NOW | RTLD_GLOBAL);
|
||||
plugin_abs_path = plugin_filename;
|
||||
//free(plugin_filename);
|
||||
}
|
||||
|
||||
success:
|
||||
if (!plugin_handle) {
|
||||
if (!plugin_handle) {
|
||||
if (!has_option)
|
||||
uwsgi_log( "%s\n", dlerror());
|
||||
}
|
||||
else {
|
||||
char *plugin_entry_symbol = uwsgi_concat2n(plugin_symbol_name_start, strlen(plugin_symbol_name_start)-3, "", 0);
|
||||
up = dlsym(plugin_handle, plugin_entry_symbol);
|
||||
uwsgi_log("!!! UNABLE to load uWSGI plugin: %s !!!\n", dlerror());
|
||||
}
|
||||
else {
|
||||
char *plugin_entry_symbol = uwsgi_concat2n(plugin_symbol_name_start, strlen(plugin_symbol_name_start) - 3, "", 0);
|
||||
up = dlsym(plugin_handle, plugin_entry_symbol);
|
||||
if (!up) {
|
||||
// is it a link ?
|
||||
memset(linkpath_buf, 0, 1024);
|
||||
@@ -129,13 +159,12 @@ success:
|
||||
if ((linkpath_size = readlink(plugin_abs_path, linkpath_buf, 1023)) > 0) {
|
||||
do {
|
||||
linkpath_buf[linkpath_size] = '\0';
|
||||
strncpy(linkpath, linkpath_buf, linkpath_size+1);
|
||||
strncpy(linkpath, linkpath_buf, linkpath_size + 1);
|
||||
} while ((linkpath_size = readlink(linkpath, linkpath_buf, 1023)) > 0);
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%s\n", linkpath);
|
||||
#endif
|
||||
free(plugin_entry_symbol);
|
||||
up = dlsym(plugin_handle, plugin_entry_symbol);
|
||||
char *slash = uwsgi_get_last_char(linkpath, '/');
|
||||
if (!slash) {
|
||||
slash = linkpath;
|
||||
@@ -143,16 +172,16 @@ success:
|
||||
else {
|
||||
slash++;
|
||||
}
|
||||
plugin_entry_symbol = uwsgi_concat2n(slash, strlen(slash)-3, "",0);
|
||||
plugin_entry_symbol = uwsgi_concat2n(slash, strlen(slash) - 3, "", 0);
|
||||
up = dlsym(plugin_handle, plugin_entry_symbol);
|
||||
}
|
||||
}
|
||||
if (up) {
|
||||
if (up) {
|
||||
if (!up->name) {
|
||||
uwsgi_log("the loaded plugin (%s) has no .name attribute\n", plugin_name);
|
||||
if (dlclose(plugin_handle)) {
|
||||
uwsgi_error("dlclose()");
|
||||
}
|
||||
uwsgi_error("dlclose()");
|
||||
}
|
||||
if (need_free)
|
||||
free(plugin_name);
|
||||
if (plugin_filename)
|
||||
@@ -162,8 +191,8 @@ success:
|
||||
}
|
||||
if (plugin_already_loaded(up->name)) {
|
||||
if (dlclose(plugin_handle)) {
|
||||
uwsgi_error("dlclose()");
|
||||
}
|
||||
uwsgi_error("dlclose()");
|
||||
}
|
||||
if (need_free)
|
||||
free(plugin_name);
|
||||
if (plugin_filename)
|
||||
@@ -178,8 +207,8 @@ success:
|
||||
if (!strcmp(has_option, op->name)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
op++;
|
||||
}
|
||||
op++;
|
||||
}
|
||||
if (!found) {
|
||||
if (dlclose(plugin_handle)) {
|
||||
@@ -192,13 +221,14 @@ success:
|
||||
free(plugin_entry_symbol);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
if (modifier != -1) {
|
||||
fill_plugin_table(modifier, up);
|
||||
fill_plugin_table(modifier, up);
|
||||
up->modifier1 = modifier;
|
||||
}
|
||||
else {
|
||||
fill_plugin_table(up->modifier1, up);
|
||||
fill_plugin_table(up->modifier1, up);
|
||||
}
|
||||
if (need_free)
|
||||
free(plugin_name);
|
||||
@@ -209,10 +239,10 @@ success:
|
||||
if (up->on_load)
|
||||
up->on_load();
|
||||
return plugin_handle;
|
||||
}
|
||||
}
|
||||
if (!has_option)
|
||||
uwsgi_log( "%s\n", dlerror());
|
||||
}
|
||||
uwsgi_log("%s\n", dlerror());
|
||||
}
|
||||
|
||||
end:
|
||||
if (need_free)
|
||||
@@ -227,14 +257,14 @@ int uwsgi_try_autoload(char *option) {
|
||||
DIR *d;
|
||||
struct dirent *dp;
|
||||
// step dir, check for user-supplied plugins directory
|
||||
struct uwsgi_string_list *pdir = uwsgi.plugins_dir;
|
||||
while(pdir) {
|
||||
struct uwsgi_string_list *pdir = uwsgi.plugins_dir;
|
||||
while (pdir) {
|
||||
d = opendir(pdir->value);
|
||||
if (d) {
|
||||
while ((dp = readdir(d)) != NULL) {
|
||||
if (uwsgi_endswith(dp->d_name, "_plugin.so")) {
|
||||
char *filename = uwsgi_concat3(pdir->value, "/", dp->d_name);
|
||||
if (uwsgi_load_plugin(-1, filename, option)) {
|
||||
if (uwsgi_load_plugin(-1, filename, option)) {
|
||||
uwsgi_log("option \"%s\" found in plugin %s\n", option, filename);
|
||||
free(filename);
|
||||
closedir(d);
|
||||
@@ -247,27 +277,28 @@ int uwsgi_try_autoload(char *option) {
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
pdir = pdir->next;
|
||||
}
|
||||
pdir = pdir->next;
|
||||
}
|
||||
|
||||
// last step: search in compile-time plugin_dir
|
||||
// last step: search in compile-time plugin_dir
|
||||
d = opendir(UWSGI_PLUGIN_DIR);
|
||||
if (!d) return 0;
|
||||
if (!d)
|
||||
return 0;
|
||||
|
||||
while((dp = readdir(d)) != NULL) {
|
||||
while ((dp = readdir(d)) != NULL) {
|
||||
if (uwsgi_endswith(dp->d_name, "_plugin.so")) {
|
||||
char *filename = uwsgi_concat3(UWSGI_PLUGIN_DIR, "/", dp->d_name);
|
||||
if (uwsgi_load_plugin(-1, filename, option)) {
|
||||
uwsgi_log("option \"%s\" found in plugin %s\n", option, filename);
|
||||
free(filename);
|
||||
closedir(d);
|
||||
// add new options
|
||||
build_options();
|
||||
return 1;
|
||||
}
|
||||
char *filename = uwsgi_concat3(UWSGI_PLUGIN_DIR, "/", dp->d_name);
|
||||
if (uwsgi_load_plugin(-1, filename, option)) {
|
||||
uwsgi_log("option \"%s\" found in plugin %s\n", option, filename);
|
||||
free(filename);
|
||||
closedir(d);
|
||||
// add new options
|
||||
build_options();
|
||||
return 1;
|
||||
}
|
||||
free(filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
|
||||
+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);
|
||||
}
|
||||
+1086
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,57 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
|
||||
QUERY_STRING management functions (mainly used by the internal routing subsystem)
|
||||
|
||||
*/
|
||||
|
||||
static char *check_qs(char *qs, uint16_t qs_len, char *key, uint16_t keylen, uint16_t *vallen) {
|
||||
// search for the equal sign
|
||||
char *equal = memchr(qs, '=', qs_len);
|
||||
if (!equal) return NULL;
|
||||
|
||||
if (uwsgi_strncmp(key, keylen, qs, equal-qs)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qs_len -= (equal-qs)+1;
|
||||
if (qs_len == 0) return NULL;
|
||||
|
||||
*vallen = qs_len;
|
||||
return equal+1;
|
||||
}
|
||||
|
||||
char *uwsgi_get_qs(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
|
||||
uint16_t i;
|
||||
|
||||
char *qs = wsgi_req->query_string;
|
||||
uint16_t qs_len = 0;
|
||||
char *ptr = wsgi_req->query_string;
|
||||
//start splitting by ;
|
||||
for(i=0;i<wsgi_req->query_string_len;i++) {
|
||||
if (!qs) {
|
||||
qs = ptr + i;
|
||||
}
|
||||
if (ptr[i] == '&') {
|
||||
char *value = check_qs(qs, qs_len, key, keylen, vallen);
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
qs_len = 0;
|
||||
qs = NULL;
|
||||
}
|
||||
else {
|
||||
qs_len++;
|
||||
}
|
||||
}
|
||||
|
||||
if (qs_len > 0) {
|
||||
char *value = check_qs(qs, qs_len, key, keylen, vallen);
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_init_queue() {
|
||||
if (!uwsgi.queue_blocksize)
|
||||
uwsgi.queue_blocksize = 8192;
|
||||
|
||||
if ((uwsgi.queue_blocksize * uwsgi.queue_size) % uwsgi.page_size != 0) {
|
||||
uwsgi_log("invalid queue size/blocksize %llu: must be a multiple of memory page size (%d bytes)\n", (unsigned long long) uwsgi.queue_blocksize, uwsgi.page_size);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (uwsgi.queue_store) {
|
||||
uwsgi.queue_filesize = uwsgi.queue_blocksize * uwsgi.queue_size + 16;
|
||||
int queue_fd;
|
||||
struct stat qst;
|
||||
|
||||
if (stat(uwsgi.queue_store, &qst)) {
|
||||
uwsgi_log("creating a new queue store file: %s\n", uwsgi.queue_store);
|
||||
queue_fd = open(uwsgi.queue_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
if (queue_fd >= 0) {
|
||||
// fill the queue store
|
||||
if (ftruncate(queue_fd, uwsgi.queue_filesize)) {
|
||||
uwsgi_log("ftruncate()");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((size_t) qst.st_size != uwsgi.queue_filesize || !S_ISREG(qst.st_mode)) {
|
||||
uwsgi_log("invalid queue store file. Please remove it or fix queue blocksize/items to match its size\n");
|
||||
exit(1);
|
||||
}
|
||||
queue_fd = open(uwsgi.queue_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
uwsgi_log("recovered queue from backing store file: %s\n", uwsgi.queue_store);
|
||||
}
|
||||
|
||||
if (queue_fd < 0) {
|
||||
uwsgi_error_open(uwsgi.queue_store);
|
||||
exit(1);
|
||||
}
|
||||
uwsgi.queue = mmap(NULL, uwsgi.queue_filesize, PROT_READ | PROT_WRITE, MAP_SHARED, queue_fd, 0);
|
||||
|
||||
// fix header
|
||||
uwsgi.queue_header = uwsgi.queue;
|
||||
uwsgi.queue += 16;
|
||||
close(queue_fd);
|
||||
}
|
||||
else {
|
||||
uwsgi.queue = mmap(NULL, (uwsgi.queue_blocksize * uwsgi.queue_size) + 16, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
// fix header
|
||||
uwsgi.queue_header = uwsgi.queue;
|
||||
uwsgi.queue += 16;
|
||||
uwsgi.queue_header->pos = 0;
|
||||
uwsgi.queue_header->pull_pos = 0;
|
||||
}
|
||||
if (!uwsgi.queue) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
uwsgi.queue_lock = uwsgi_rwlock_init("queue");
|
||||
|
||||
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) {
|
||||
|
||||
struct uwsgi_queue_item *uqi;
|
||||
char *ptr = (char *) uwsgi.queue;
|
||||
|
||||
if (index >= uwsgi.queue_size)
|
||||
return NULL;
|
||||
|
||||
ptr = ptr + (uwsgi.queue_blocksize * index);
|
||||
|
||||
uqi = (struct uwsgi_queue_item *) ptr;
|
||||
|
||||
*size = uqi->size;
|
||||
|
||||
return ptr + sizeof(struct uwsgi_queue_item);
|
||||
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_queue_pop(uint64_t * size) {
|
||||
|
||||
struct uwsgi_queue_item *uqi;
|
||||
char *ptr = (char *) uwsgi.queue;
|
||||
|
||||
if (uwsgi.queue_header->pos == 0) {
|
||||
uwsgi.queue_header->pos = uwsgi.queue_size - 1;
|
||||
}
|
||||
else {
|
||||
uwsgi.queue_header->pos--;
|
||||
}
|
||||
|
||||
ptr = ptr + (uwsgi.queue_blocksize * uwsgi.queue_header->pos);
|
||||
uqi = (struct uwsgi_queue_item *) ptr;
|
||||
|
||||
if (!uqi->size)
|
||||
return NULL;
|
||||
|
||||
*size = uqi->size;
|
||||
// remove item
|
||||
uqi->size = 0;
|
||||
|
||||
return ptr + sizeof(struct uwsgi_queue_item);
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_queue_pull(uint64_t * size) {
|
||||
|
||||
struct uwsgi_queue_item *uqi;
|
||||
char *ptr = (char *) uwsgi.queue;
|
||||
|
||||
ptr = ptr + (uwsgi.queue_blocksize * uwsgi.queue_header->pull_pos);
|
||||
uqi = (struct uwsgi_queue_item *) ptr;
|
||||
|
||||
if (!uqi->size)
|
||||
return NULL;
|
||||
|
||||
*size = uqi->size;
|
||||
|
||||
uwsgi.queue_header->pull_pos++;
|
||||
|
||||
if (uwsgi.queue_header->pull_pos >= uwsgi.queue_size)
|
||||
uwsgi.queue_header->pull_pos = 0;
|
||||
|
||||
// remove item
|
||||
uqi->size = 0;
|
||||
|
||||
return ptr + sizeof(struct uwsgi_queue_item);
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_queue_push(char *message, uint64_t size) {
|
||||
|
||||
struct uwsgi_queue_item *uqi;
|
||||
char *ptr = (char *) uwsgi.queue;
|
||||
|
||||
if (size > uwsgi.queue_blocksize + sizeof(struct uwsgi_queue_item))
|
||||
return 0;
|
||||
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
ptr = ptr + (uwsgi.queue_blocksize * uwsgi.queue_header->pos);
|
||||
uqi = (struct uwsgi_queue_item *) ptr;
|
||||
|
||||
ptr += sizeof(struct uwsgi_queue_item);
|
||||
|
||||
uqi->size = size;
|
||||
uqi->ts = uwsgi_now();
|
||||
memcpy(ptr, message, size);
|
||||
|
||||
uwsgi.queue_header->pos++;
|
||||
|
||||
if (uwsgi.queue_header->pos >= uwsgi.queue_size)
|
||||
uwsgi.queue_header->pos = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int uwsgi_queue_set(uint64_t pos, char *message, uint64_t size) {
|
||||
|
||||
struct uwsgi_queue_item *uqi;
|
||||
char *ptr = (char *) uwsgi.queue;
|
||||
|
||||
if (size > uwsgi.queue_blocksize + sizeof(struct uwsgi_queue_item))
|
||||
return 0;
|
||||
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
if (pos >= uwsgi.queue_size)
|
||||
return 0;
|
||||
|
||||
ptr = ptr + (uwsgi.queue_blocksize * pos);
|
||||
uqi = (struct uwsgi_queue_item *) ptr;
|
||||
|
||||
ptr += sizeof(struct uwsgi_queue_item);
|
||||
|
||||
uqi->size = size;
|
||||
uqi->ts = uwsgi_now();
|
||||
memcpy(ptr, message, size);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,367 @@
|
||||
/*
|
||||
|
||||
uWSGI rbtree implementation based on nginx
|
||||
|
||||
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>
|
||||
|
||||
#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 uwsgi_rbtree *uwsgi_init_rb_timer() {
|
||||
|
||||
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 uwsgi_rbtree *tree, struct uwsgi_rb_timer *node) {
|
||||
|
||||
if (!node)
|
||||
node = tree->root;
|
||||
struct uwsgi_rb_timer *sentinel = tree->sentinel;
|
||||
|
||||
if (tree->root == sentinel) return NULL;
|
||||
|
||||
while (node->left != sentinel) {
|
||||
node = node->left;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static void uwsgi_rbtree_lr(struct uwsgi_rb_timer **root, struct uwsgi_rb_timer *sentinel, struct uwsgi_rb_timer *node) {
|
||||
|
||||
struct uwsgi_rb_timer *temp;
|
||||
|
||||
temp = node->right;
|
||||
node->right = temp->left;
|
||||
|
||||
if (temp->left != sentinel) {
|
||||
temp->left->parent = node;
|
||||
}
|
||||
|
||||
temp->parent = node->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);
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_rbt_black(*root);
|
||||
|
||||
return new_node;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
remains = UMIN(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark, wsgi_req->post_cl - wsgi_req->post_pos);
|
||||
|
||||
// read from a file
|
||||
if (wsgi_req->post_file) {
|
||||
size_t ret = fread(wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark, remains, 1, wsgi_req->post_file);
|
||||
if (ret == 0) {
|
||||
uwsgi_error("consume_body_for_readline()/fread()");
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->post_pos += remains;
|
||||
wsgi_req->post_readline_watermark += remains;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// read from post_buffering memory
|
||||
if (uwsgi.post_buffering) {
|
||||
memcpy(wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark, wsgi_req->post_buffering_buf + wsgi_req->post_pos, remains);
|
||||
wsgi_req->post_pos += remains;
|
||||
wsgi_req->post_readline_watermark += remains;
|
||||
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 , remains);
|
||||
if (len > 0) {
|
||||
wsgi_req->post_pos += len;
|
||||
wsgi_req->post_readline_watermark += len;
|
||||
return 0;
|
||||
}
|
||||
if (len == 0) {
|
||||
uwsgi_read_error(remains);
|
||||
return -1;
|
||||
}
|
||||
if (len < 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) {
|
||||
len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark , remains);
|
||||
if (len > 0) {
|
||||
wsgi_req->post_pos += len;
|
||||
wsgi_req->post_readline_watermark += len;
|
||||
return 0;
|
||||
}
|
||||
uwsgi_read_error(remains);
|
||||
return -1;
|
||||
}
|
||||
// 0 means timeout
|
||||
else if (ret == 0) {
|
||||
uwsgi_read_timeout(remains);
|
||||
return -1;
|
||||
}
|
||||
uwsgi_read_error(remains);
|
||||
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_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;
|
||||
}
|
||||
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
#ifdef UWSGI_PCRE
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_opt_pcre_jit(char *opt, char *value, void *foobar) {
|
||||
#if defined(PCRE_STUDY_JIT_COMPILE) && defined(PCRE_CONFIG_JIT)
|
||||
int has_jit = 0, ret;
|
||||
ret = pcre_config(PCRE_CONFIG_JIT, &has_jit);
|
||||
if (ret != 0 || has_jit != 1)
|
||||
return;
|
||||
uwsgi.pcre_jit = PCRE_STUDY_JIT_COMPILE;
|
||||
#endif
|
||||
}
|
||||
|
||||
int uwsgi_regexp_build(char *re, pcre ** pattern, pcre_extra ** pattern_extra) {
|
||||
|
||||
const char *errstr;
|
||||
int erroff;
|
||||
|
||||
*pattern = pcre_compile((const char *) re, 0, &errstr, &erroff, NULL);
|
||||
if (!*pattern) {
|
||||
uwsgi_log("pcre error: %s at offset %d\n", errstr, erroff);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int opt = uwsgi.pcre_jit;
|
||||
|
||||
*pattern_extra = (pcre_extra *) pcre_study((const pcre *) *pattern, opt, &errstr);
|
||||
if (*pattern_extra == NULL && errstr != NULL) {
|
||||
pcre_free(*pattern);
|
||||
uwsgi_log("pcre (study) error: %s\n", errstr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_regexp_match(pcre * pattern, pcre_extra * pattern_extra, char *subject, int length) {
|
||||
|
||||
return pcre_exec((const pcre *) pattern, (const pcre_extra *) pattern_extra, subject, length, 0, 0, NULL, 0);
|
||||
}
|
||||
|
||||
int uwsgi_regexp_match_ovec(pcre * pattern, pcre_extra * pattern_extra, char *subject, int length, int *ovec, int n) {
|
||||
|
||||
if (n > 0) {
|
||||
return pcre_exec((const pcre *) pattern, (const pcre_extra *) pattern_extra, subject, length, 0, 0, ovec, (n + 1) * 3);
|
||||
}
|
||||
return pcre_exec((const pcre *) pattern, (const pcre_extra *) pattern_extra, subject, length, 0, 0, NULL, 0);
|
||||
}
|
||||
|
||||
int uwsgi_regexp_ovector(pcre * pattern, pcre_extra * pattern_extra) {
|
||||
|
||||
int n;
|
||||
|
||||
if (pcre_fullinfo((const pcre *) pattern, (const pcre_extra *) pattern_extra, PCRE_INFO_CAPTURECOUNT, &n))
|
||||
return 0;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
char *uwsgi_regexp_apply_ovec(char *src, int src_n, char *dst, int dst_n, int *ovector, int n) {
|
||||
|
||||
int i;
|
||||
int dollar = 0;
|
||||
|
||||
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++) {
|
||||
if (dollar) {
|
||||
if (isdigit((int) dst[i])) {
|
||||
int pos = (dst[i] - 48);
|
||||
if (pos <= n) {
|
||||
pos = pos * 2;
|
||||
memcpy(ptr, src + ovector[pos], ovector[pos + 1] - ovector[pos]);
|
||||
ptr += ovector[pos + 1] - ovector[pos];
|
||||
}
|
||||
}
|
||||
else {
|
||||
*ptr++ = '$';
|
||||
*ptr++ = dst[i];
|
||||
}
|
||||
dollar = 0;
|
||||
}
|
||||
else {
|
||||
if (dst[i] == '$') {
|
||||
dollar = 1;
|
||||
}
|
||||
else {
|
||||
*ptr++ = dst[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*ptr++ = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
+972
@@ -0,0 +1,972 @@
|
||||
#ifdef UWSGI_ROUTING
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_route_var *uwsgi_register_route_var(char *name, char *(*func)(struct wsgi_request *, char *, uint16_t, uint16_t *)) {
|
||||
|
||||
struct uwsgi_route_var *old_urv = NULL,*urv = uwsgi.route_vars;
|
||||
while(urv) {
|
||||
if (!strcmp(urv->name, name)) {
|
||||
return urv;
|
||||
}
|
||||
old_urv = urv;
|
||||
urv = urv->next;
|
||||
}
|
||||
|
||||
urv = uwsgi_calloc(sizeof(struct uwsgi_route_var));
|
||||
urv->name = name;
|
||||
urv->name_len = strlen(name);
|
||||
urv->func = func;
|
||||
|
||||
if (old_urv) {
|
||||
old_urv->next = urv;
|
||||
}
|
||||
else {
|
||||
uwsgi.route_vars = urv;
|
||||
}
|
||||
|
||||
return urv;
|
||||
}
|
||||
|
||||
struct uwsgi_route_var *uwsgi_get_route_var(char *name, uint16_t name_len) {
|
||||
struct uwsgi_route_var *urv = uwsgi.route_vars;
|
||||
while(urv) {
|
||||
if (!uwsgi_strncmp(urv->name, urv->name_len, name, name_len)) {
|
||||
return urv;
|
||||
}
|
||||
urv = urv->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
int need_free = 0;
|
||||
char *value = NULL;
|
||||
char *bracket = memchr(key, '[', keylen);
|
||||
if (bracket && keylen > 0 && key[keylen-1] == ']') {
|
||||
struct uwsgi_route_var *urv = uwsgi_get_route_var(key, bracket - key);
|
||||
if (urv) {
|
||||
need_free = urv->need_free;
|
||||
value = urv->func(wsgi_req, bracket + 1, keylen - (urv->name_len+2), &vallen);
|
||||
}
|
||||
else {
|
||||
value = uwsgi_get_var(wsgi_req, key, keylen, &vallen);
|
||||
}
|
||||
}
|
||||
else {
|
||||
value = uwsgi_get_var(wsgi_req, key, keylen, &vallen);
|
||||
}
|
||||
if (value) {
|
||||
if (uwsgi_buffer_append(ub, value, vallen)) {
|
||||
if (need_free) {
|
||||
free(value);
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
if (need_free) {
|
||||
free(value);
|
||||
}
|
||||
}
|
||||
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;
|
||||
// .. but came back of 1 position to avoid accounting it
|
||||
ub->pos--;
|
||||
|
||||
if (pass1 != data) {
|
||||
free(pass1);
|
||||
}
|
||||
return ub;
|
||||
|
||||
error:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
char *orig_subject = subject;
|
||||
uint16_t orig_subject_len = subject_len;
|
||||
|
||||
while (routes) {
|
||||
|
||||
if (routes->label) goto next;
|
||||
|
||||
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) {
|
||||
// could be a "run"
|
||||
if (!routes->subject) {
|
||||
n = 0;
|
||||
goto run;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
run:
|
||||
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:
|
||||
subject = orig_subject;
|
||||
subject_len = orig_subject_len;
|
||||
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;
|
||||
}
|
||||
|
||||
// in case of static files serving previous rules could be applied
|
||||
if (wsgi_req->routes_applied) {
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
}
|
||||
|
||||
return uwsgi_apply_routes_do(wsgi_req, NULL, 0);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
urc = urc->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
|
||||
|
||||
char *space = NULL;
|
||||
char *command = NULL;
|
||||
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);
|
||||
|
||||
if (!strcmp(foobar, "run")) {
|
||||
command = route;
|
||||
goto done;
|
||||
}
|
||||
|
||||
space = strchr(route, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid route syntax\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
*space = 0;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
else if (!strcmp(foobar, "http_host")) {
|
||||
ur->subject = offsetof(struct wsgi_request, host);
|
||||
ur->subject_len = offsetof(struct wsgi_request, host_len);
|
||||
}
|
||||
else if (!strcmp(foobar, "request_uri")) {
|
||||
ur->subject = offsetof(struct wsgi_request, uri);
|
||||
ur->subject_len = offsetof(struct wsgi_request, uri_len);
|
||||
}
|
||||
else if (!strcmp(foobar, "query_string")) {
|
||||
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);
|
||||
}
|
||||
|
||||
ur->subject_str = foobar;
|
||||
ur->subject_str_len = strlen(ur->subject_str);
|
||||
ur->regexp = route;
|
||||
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
command = space + 1;
|
||||
done:
|
||||
ur->action = uwsgi_str(command);
|
||||
|
||||
char *colon = strchr(command, ':');
|
||||
if (!colon) {
|
||||
uwsgi_log("invalid route syntax\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
*colon = 0;
|
||||
|
||||
struct uwsgi_router *r = uwsgi.routers;
|
||||
while (r) {
|
||||
if (!strcmp(r->name, command)) {
|
||||
if (r->func(ur, colon + 1) == 0) {
|
||||
// apply is_last
|
||||
struct uwsgi_route *last_ur = ur;
|
||||
ur = uwsgi.routes;
|
||||
while (ur) {
|
||||
if (ur->func == last_ur->func) {
|
||||
ur->is_last = 0;
|
||||
}
|
||||
ur = ur->next;
|
||||
}
|
||||
last_ur->is_last = 1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
r = r->next;
|
||||
}
|
||||
|
||||
uwsgi_log("unable to register route \"%s\"\n", value);
|
||||
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;
|
||||
}
|
||||
free(args);
|
||||
return -1;
|
||||
found:
|
||||
ur = uwsgi_calloc(sizeof(struct uwsgi_route));
|
||||
// initialize the virtual route
|
||||
if (r->func(ur, args)) {
|
||||
free(ur);
|
||||
free(args);
|
||||
return -1;
|
||||
}
|
||||
// call it
|
||||
int ret = ur->func(wsgi_req, ur);
|
||||
if (ur->free) {
|
||||
ur->free(ur);
|
||||
}
|
||||
free(ur);
|
||||
free(args);
|
||||
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_regexp(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len);
|
||||
if (!semicolon) return 0;
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str);
|
||||
if (!ub) return -1;
|
||||
|
||||
pcre *pattern;
|
||||
pcre_extra *pattern_extra;
|
||||
char *re = uwsgi_concat2n(semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str), "", 0);
|
||||
if (uwsgi_regexp_build(re, &pattern, &pattern_extra)) {
|
||||
free(re);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return -1;
|
||||
}
|
||||
free(re);
|
||||
|
||||
if (uwsgi_regexp_match(pattern, pattern_extra, ub->buf, ub->pos) >= 0) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
pcre_free(pattern);
|
||||
#ifdef PCRE_STUDY_JIT_COMPILE
|
||||
pcre_free_study(pattern_extra);
|
||||
#else
|
||||
pcre_free(pattern_extra);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
uwsgi_buffer_destroy(ub);
|
||||
pcre_free(pattern);
|
||||
#ifdef PCRE_STUDY_JIT_COMPILE
|
||||
pcre_free_study(pattern_extra);
|
||||
#else
|
||||
pcre_free(pattern_extra);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_route_condition_empty(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 (ub->pos == 0) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_route_condition_equal(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len);
|
||||
if (!semicolon) return 0;
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str);
|
||||
if (!ub) return -1;
|
||||
|
||||
struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str));
|
||||
if (!ub2) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!uwsgi_strncmp(ub->buf, ub->pos, ub2->buf, ub2->pos)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
uwsgi_buffer_destroy(ub2);
|
||||
return 1;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
uwsgi_buffer_destroy(ub2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_route_condition_startswith(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len);
|
||||
if (!semicolon) return 0;
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str);
|
||||
if (!ub) return -1;
|
||||
|
||||
struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str));
|
||||
if (!ub2) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!uwsgi_starts_with(ub->buf, ub->pos, ub2->buf, ub2->pos)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
uwsgi_buffer_destroy(ub2);
|
||||
return 1;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
uwsgi_buffer_destroy(ub2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_route_condition_endswith(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len);
|
||||
if (!semicolon) return 0;
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str);
|
||||
if (!ub) return -1;
|
||||
|
||||
struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str));
|
||||
if (!ub2) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ub2->pos < ub->pos) goto zero;
|
||||
if(!uwsgi_strncmp(ub->buf + (ub->pos - ub2->pos), ub2->pos, ub2->buf, ub2->pos)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
uwsgi_buffer_destroy(ub2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
zero:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
uwsgi_buffer_destroy(ub2);
|
||||
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);
|
||||
uwsgi_register_route_condition("equal", uwsgi_route_condition_equal);
|
||||
uwsgi_register_route_condition("isequal", uwsgi_route_condition_equal);
|
||||
uwsgi_register_route_condition("eq", uwsgi_route_condition_equal);
|
||||
uwsgi_register_route_condition("==", uwsgi_route_condition_equal);
|
||||
uwsgi_register_route_condition("startswith", uwsgi_route_condition_startswith);
|
||||
uwsgi_register_route_condition("endswith", uwsgi_route_condition_endswith);
|
||||
uwsgi_register_route_condition("regexp", uwsgi_route_condition_regexp);
|
||||
uwsgi_register_route_condition("re", uwsgi_route_condition_regexp);
|
||||
|
||||
uwsgi_register_route_condition("empty", uwsgi_route_condition_empty);
|
||||
|
||||
uwsgi_register_route_var("cookie", uwsgi_get_cookie);
|
||||
uwsgi_register_route_var("qs", uwsgi_get_qs);
|
||||
}
|
||||
|
||||
struct uwsgi_router *uwsgi_register_router(char *name, int (*func) (struct uwsgi_route *, char *)) {
|
||||
|
||||
struct uwsgi_router *ur = uwsgi.routers;
|
||||
if (!ur) {
|
||||
uwsgi.routers = uwsgi_calloc(sizeof(struct uwsgi_router));
|
||||
uwsgi.routers->name = name;
|
||||
uwsgi.routers->func = func;
|
||||
return uwsgi.routers;
|
||||
}
|
||||
|
||||
while (ur) {
|
||||
if (!ur->next) {
|
||||
ur->next = uwsgi_calloc(sizeof(struct uwsgi_router));
|
||||
ur->next->name = name;
|
||||
ur->next->func = func;
|
||||
return ur->next;
|
||||
}
|
||||
ur = ur->next;
|
||||
}
|
||||
|
||||
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 if (!routes->subject_str && !routes->if_func) {
|
||||
uwsgi_log("[rule: %llu] action: %s\n", (unsigned long long ) routes->pos, routes->action);
|
||||
}
|
||||
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
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
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.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);
|
||||
|
||||
// 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;
|
||||
urpc->shared = uwsgi.mywid == 0 ? 1 : 0;
|
||||
|
||||
ret = 0;
|
||||
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);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t uwsgi_rpc(char *name, uint8_t argc, char *argv[], uint16_t argvs[], char *output) {
|
||||
|
||||
struct uwsgi_rpc *urpc = NULL;
|
||||
uint64_t i;
|
||||
uint16_t ret = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (urpc) {
|
||||
if (uwsgi.p[urpc->modifier1]->rpc) {
|
||||
ret = uwsgi.p[urpc->modifier1]->rpc(urpc->func, argc, argv, argvs, output);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t argvs[], uint16_t * len) {
|
||||
|
||||
uint8_t i;
|
||||
uint16_t ulen;
|
||||
struct uwsgi_header *uh = NULL;
|
||||
char *buffer = NULL;
|
||||
|
||||
*len = 0;
|
||||
|
||||
if (node == NULL || !strcmp(node, "")) {
|
||||
// allocate the whole buffer
|
||||
buffer = uwsgi_malloc(UMAX16);
|
||||
*len = uwsgi_rpc(func, argc, argv, argvs, buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
buffer_size += 2 + argvs[i];
|
||||
}
|
||||
|
||||
// allocate the whole buffer
|
||||
buffer = uwsgi_malloc(4+buffer_size);
|
||||
|
||||
// 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 + 4;
|
||||
ulen = strlen(func);
|
||||
*bufptr++ = (uint8_t) (ulen & 0xff);
|
||||
*bufptr++ = (uint8_t) ((ulen >> 8) & 0xff);
|
||||
memcpy(bufptr, func, ulen);
|
||||
bufptr += ulen;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
ulen = argvs[i];
|
||||
*bufptr++ = (uint8_t) (ulen & 0xff);
|
||||
*bufptr++ = (uint8_t) ((ulen >> 8) & 0xff);
|
||||
memcpy(bufptr, argv[i], ulen);
|
||||
bufptr += ulen;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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 = rlen;
|
||||
if (*len == 0) {
|
||||
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));
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
// sendfile() abstraction
|
||||
ssize_t uwsgi_sendfile_do(int sockfd, int filefd, size_t pos, size_t len) {
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
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__)
|
||||
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__)
|
||||
off_t off = pos;
|
||||
return sendfile(sockfd, filefd, &off, len);
|
||||
#else
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
ssize_t rlen = read(filefd, buf, UMIN(len, 8192));
|
||||
if (rlen <= 0) {
|
||||
uwsgi_error("uwsgi_sendfile_do()/read()");
|
||||
return -1;
|
||||
}
|
||||
return write(sockfd, buf, rlen);
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
|
||||
void uwsgi_setup_systemd() {
|
||||
struct uwsgi_socket *uwsgi_sock = NULL;
|
||||
int i;
|
||||
|
||||
char *listen_pid = getenv("LISTEN_PID");
|
||||
if (listen_pid) {
|
||||
if (atoi(listen_pid) == (int) getpid()) {
|
||||
char *listen_fds = getenv("LISTEN_FDS");
|
||||
if (listen_fds) {
|
||||
int systemd_fds = atoi(listen_fds);
|
||||
if (systemd_fds > 0) {
|
||||
uwsgi_log("- SystemD socket activation detected -\n");
|
||||
for (i = 3; i < 3 + systemd_fds; i++) {
|
||||
uwsgi_sock = uwsgi_new_socket(NULL);
|
||||
uwsgi_add_socket_from_fd(uwsgi_sock, i);
|
||||
}
|
||||
uwsgi.skip_zero = 1;
|
||||
}
|
||||
unsetenv("LISTEN_PID");
|
||||
unsetenv("LISTEN_FDS");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_setup_upstart() {
|
||||
|
||||
struct uwsgi_socket *uwsgi_sock = NULL;
|
||||
|
||||
char *upstart_events = getenv("UPSTART_EVENTS");
|
||||
if (upstart_events && !strcmp(upstart_events, "socket")) {
|
||||
char *upstart_fds = getenv("UPSTART_FDS");
|
||||
if (upstart_fds) {
|
||||
uwsgi_log("- Upstart socket bridge detected (job: %s) -\n", getenv("UPSTART_JOB"));
|
||||
uwsgi_sock = uwsgi_new_socket(NULL);
|
||||
uwsgi_add_socket_from_fd(uwsgi_sock, atoi(upstart_fds));
|
||||
uwsgi.skip_zero = 1;
|
||||
}
|
||||
unsetenv("UPSTART_EVENTS");
|
||||
unsetenv("UPSTART_FDS");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_setup_zerg() {
|
||||
|
||||
struct uwsgi_socket *uwsgi_sock = NULL;
|
||||
int i;
|
||||
|
||||
struct uwsgi_string_list *zn = uwsgi.zerg_node;
|
||||
while (zn) {
|
||||
if (uwsgi_zerg_attach(zn->value)) {
|
||||
if (!uwsgi.zerg_fallback) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
zn = zn->next;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (uwsgi.zerg) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("attaching zerg sockets...\n");
|
||||
#endif
|
||||
int zerg_fd;
|
||||
i = 0;
|
||||
for (;;) {
|
||||
zerg_fd = uwsgi.zerg[i];
|
||||
if (zerg_fd == -1) {
|
||||
break;
|
||||
}
|
||||
uwsgi_sock = uwsgi_new_socket(NULL);
|
||||
uwsgi_add_socket_from_fd(uwsgi_sock, zerg_fd);
|
||||
i++;
|
||||
}
|
||||
|
||||
uwsgi_log("zerg sockets attached\n");
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_setup_inherited_sockets() {
|
||||
|
||||
int j;
|
||||
union uwsgi_sockaddr usa;
|
||||
union uwsgi_sockaddr_ptr gsa;
|
||||
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
while (uwsgi_sock) {
|
||||
//a bit overengineering
|
||||
if (uwsgi_sock->name[0] != 0 && !uwsgi_sock->bound) {
|
||||
for (j = 3; j < (int) uwsgi.max_fd; j++) {
|
||||
uwsgi_add_socket_from_fd(uwsgi_sock, j);
|
||||
}
|
||||
}
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
//now close all the unbound fd
|
||||
for (j = 3; j < (int) uwsgi.max_fd; j++) {
|
||||
int useless = 1;
|
||||
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) {
|
||||
if (j == uwsgi.shared->worker_log_pipe[0])
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uwsgi.shared->worker_log_pipe[1] > -1) {
|
||||
if (j == uwsgi.shared->worker_log_pipe[1])
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uwsgi.shared->worker_req_log_pipe[0] > -1) {
|
||||
if (j == uwsgi.shared->worker_req_log_pipe[0])
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uwsgi.shared->worker_req_log_pipe[1] > -1) {
|
||||
if (j == uwsgi.shared->worker_req_log_pipe[1])
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uwsgi.original_log_fd > -1) {
|
||||
if (j == uwsgi.original_log_fd)
|
||||
continue;
|
||||
}
|
||||
|
||||
struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets;
|
||||
int found = 0;
|
||||
while (ugs) {
|
||||
if (ugs->fd == j) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
ugs = ugs->next;
|
||||
}
|
||||
if (found)
|
||||
continue;
|
||||
|
||||
|
||||
int y;
|
||||
found = 0;
|
||||
for (y = 0; y < ushared->gateways_cnt; y++) {
|
||||
if (ushared->gateways[y].internal_subscription_pipe[0] == j) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
if (ushared->gateways[y].internal_subscription_pipe[1] == j) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
continue;
|
||||
|
||||
|
||||
socklen_t socket_type_len = sizeof(struct sockaddr_un);
|
||||
gsa.sa = (struct sockaddr *) &usa;
|
||||
if (!getsockname(j, gsa.sa, &socket_type_len)) {
|
||||
uwsgi_sock = uwsgi.sockets;
|
||||
while (uwsgi_sock) {
|
||||
if (uwsgi_sock->fd == j && uwsgi_sock->bound) {
|
||||
useless = 0;
|
||||
break;
|
||||
}
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
if (useless) {
|
||||
uwsgi_sock = uwsgi.shared_sockets;
|
||||
while (uwsgi_sock) {
|
||||
if (uwsgi_sock->fd == j && uwsgi_sock->bound) {
|
||||
useless = 0;
|
||||
break;
|
||||
}
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (useless) {
|
||||
close(j);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+620
@@ -0,0 +1,620 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_signal_handler(uint8_t sig) {
|
||||
|
||||
struct uwsgi_signal_entry *use = NULL;
|
||||
|
||||
int pos = (uwsgi.mywid * 256) + sig;
|
||||
|
||||
use = &uwsgi.shared->signal_table[pos];
|
||||
|
||||
if (!use->handler)
|
||||
return -1;
|
||||
|
||||
if (!uwsgi.p[use->modifier1]->signal_handler) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// check for COW
|
||||
if (uwsgi.master_process) {
|
||||
if (use->wid != 0 && use->wid != uwsgi.mywid) {
|
||||
uwsgi_log("[uwsgi-signal] you have registered this signal in worker %d memory area, only that process will be able to run it\n", use->wid);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
// in lazy mode (without a master), only the same worker will be able to run handlers
|
||||
else if (uwsgi.lazy) {
|
||||
if (use->wid != uwsgi.mywid) {
|
||||
uwsgi_log("[uwsgi-signal] you have registered this signal in worker %d memory area, only that process will be able to run it\n", use->wid);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// when master is not active, worker1 is the COW-leader
|
||||
if (use->wid != 1 && use->wid != uwsgi.mywid) {
|
||||
uwsgi_log("[uwsgi-signal] you have registered this signal in worker %d memory area, only that process will be able to run it\n", use->wid);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// set harakiri here (if required and if i am a worker)
|
||||
|
||||
if (uwsgi.mywid > 0) {
|
||||
uwsgi.workers[uwsgi.mywid].sig = 1;
|
||||
uwsgi.workers[uwsgi.mywid].signum = sig;
|
||||
uwsgi.workers[uwsgi.mywid].signals++;
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
|
||||
set_harakiri(uwsgi.shared->options[UWSGI_OPTION_HARAKIRI]);
|
||||
}
|
||||
}
|
||||
else if (uwsgi.muleid > 0) {
|
||||
uwsgi.mules[uwsgi.muleid - 1].sig = 1;
|
||||
uwsgi.mules[uwsgi.muleid - 1].signum = sig;
|
||||
uwsgi.mules[uwsgi.muleid - 1].signals++;
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_MULE_HARAKIRI] > 0) {
|
||||
set_mule_harakiri(uwsgi.shared->options[UWSGI_OPTION_MULE_HARAKIRI]);
|
||||
}
|
||||
}
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
int ret = uwsgi.p[use->modifier1]->signal_handler(sig, use->handler);
|
||||
|
||||
if (uwsgi.mywid > 0) {
|
||||
uwsgi.workers[uwsgi.mywid].sig = 0;
|
||||
if (uwsgi.workers[uwsgi.mywid].harakiri > 0) {
|
||||
set_harakiri(0);
|
||||
}
|
||||
}
|
||||
else if (uwsgi.muleid > 0) {
|
||||
uwsgi.mules[uwsgi.muleid - 1].sig = 0;
|
||||
if (uwsgi.mules[uwsgi.muleid - 1].harakiri > 0) {
|
||||
set_mule_harakiri(0);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int uwsgi_signal_registered(uint8_t sig) {
|
||||
|
||||
int pos = (uwsgi.mywid * 256) + sig;
|
||||
if (uwsgi.shared->signal_table[pos].handler != NULL)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_register_signal(uint8_t sig, char *receiver, void *handler, uint8_t modifier1) {
|
||||
|
||||
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);
|
||||
|
||||
int pos = (uwsgi.mywid * 256) + sig;
|
||||
use = &uwsgi.shared->signal_table[pos];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
strncpy(use->receiver, receiver, strlen(receiver) + 1);
|
||||
use->handler = handler;
|
||||
use->modifier1 = modifier1;
|
||||
use->wid = uwsgi.mywid;
|
||||
|
||||
if (use->receiver[0] == 0) {
|
||||
uwsgi_log("[uwsgi-signal] signum %d registered (wid: %d modifier1: %d target: default, any worker)\n", sig, uwsgi.mywid, modifier1);
|
||||
}
|
||||
else {
|
||||
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], &uwsgi.shared->signal_table[0], sizeof(struct uwsgi_signal_entry) * 256);
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_unlock(uwsgi.signal_table_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_add_file_monitor(uint8_t sig, char *filename) {
|
||||
|
||||
if (strlen(filename) > (0xff - 1)) {
|
||||
uwsgi_log("uwsgi_add_file_monitor: invalid filename length\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_lock(uwsgi.fmon_table_lock);
|
||||
|
||||
if (ushared->files_monitored_cnt < 64) {
|
||||
|
||||
// fill the fmon table, the master will use it to add items to the event queue
|
||||
memcpy(ushared->files_monitored[ushared->files_monitored_cnt].filename, filename, strlen(filename));
|
||||
ushared->files_monitored[ushared->files_monitored_cnt].registered = 0;
|
||||
ushared->files_monitored[ushared->files_monitored_cnt].sig = sig;
|
||||
|
||||
ushared->files_monitored_cnt++;
|
||||
}
|
||||
else {
|
||||
uwsgi_log("you can register max 64 file monitors !!!\n");
|
||||
uwsgi_unlock(uwsgi.fmon_table_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_unlock(uwsgi.fmon_table_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_probe *uwsgi_probe_register(struct uwsgi_probe **up, char *name, int (*func) (int, struct uwsgi_signal_probe *)) {
|
||||
|
||||
struct uwsgi_probe *uwsgi_up = *up, *old_up;
|
||||
|
||||
if (!uwsgi_up) {
|
||||
*up = uwsgi_malloc(sizeof(struct uwsgi_probe));
|
||||
uwsgi_up = *up;
|
||||
}
|
||||
else {
|
||||
while (uwsgi_up) {
|
||||
old_up = uwsgi_up;
|
||||
uwsgi_up = uwsgi_up->next;
|
||||
}
|
||||
|
||||
uwsgi_up = uwsgi_malloc(sizeof(struct uwsgi_probe));
|
||||
old_up->next = uwsgi_up;
|
||||
}
|
||||
|
||||
uwsgi_up->name = name;
|
||||
uwsgi_up->func = func;
|
||||
uwsgi_up->next = NULL;
|
||||
|
||||
uwsgi_log("registered new probe \"%s\" at %p\n", name, uwsgi_up);
|
||||
|
||||
return uwsgi_up;
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_add_probe(uint8_t sig, char *kind, char *args, int timeout, int freq) {
|
||||
|
||||
uwsgi_lock(uwsgi.probe_table_lock);
|
||||
|
||||
if (ushared->probes_cnt < MAX_PROBES) {
|
||||
|
||||
struct uwsgi_probe *up = uwsgi.probes;
|
||||
while (up) {
|
||||
if (!strcmp(up->name, kind)) {
|
||||
break;
|
||||
}
|
||||
up = up->next;
|
||||
}
|
||||
|
||||
if (!up) {
|
||||
uwsgi_log("unable to find probe \"%s\" !!!\n", kind);
|
||||
uwsgi_unlock(uwsgi.probe_table_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// fill the probe table
|
||||
ushared->probes[ushared->probes_cnt].func = up->func;
|
||||
strncpy(ushared->probes[ushared->probes_cnt].args, args, 1024 - 1);
|
||||
ushared->probes[ushared->probes_cnt].registered = 0;
|
||||
ushared->probes[ushared->probes_cnt].sig = sig;
|
||||
ushared->probes[ushared->probes_cnt].fd = -1;
|
||||
ushared->probes[ushared->probes_cnt].state = 0;
|
||||
ushared->probes[ushared->probes_cnt].last_event = 0;
|
||||
ushared->probes[ushared->probes_cnt].data = NULL;
|
||||
ushared->probes[ushared->probes_cnt].cycles = 0;
|
||||
ushared->probes[ushared->probes_cnt].bad = 0;
|
||||
|
||||
if (!timeout) {
|
||||
timeout = uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT];
|
||||
}
|
||||
ushared->probes[ushared->probes_cnt].timeout = timeout;
|
||||
if (!freq) {
|
||||
freq = 1;
|
||||
}
|
||||
ushared->probes[ushared->probes_cnt].freq = freq;
|
||||
ushared->probes_cnt++;
|
||||
}
|
||||
else {
|
||||
uwsgi_log("you can register max %d probes !!!\n", MAX_PROBES);
|
||||
uwsgi_unlock(uwsgi.probe_table_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_unlock(uwsgi.probe_table_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_add_timer(uint8_t sig, int secs) {
|
||||
|
||||
if (!uwsgi.master_process) return -1;
|
||||
|
||||
uwsgi_lock(uwsgi.timer_table_lock);
|
||||
|
||||
if (ushared->timers_cnt < 64) {
|
||||
|
||||
// fill the timer table, the master will use it to add items to the event queue
|
||||
ushared->timers[ushared->timers_cnt].value = secs;
|
||||
ushared->timers[ushared->timers_cnt].registered = 0;
|
||||
ushared->timers[ushared->timers_cnt].sig = sig;
|
||||
ushared->timers_cnt++;
|
||||
}
|
||||
else {
|
||||
uwsgi_log("you can register max 64 timers !!!\n");
|
||||
uwsgi_unlock(uwsgi.timer_table_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_unlock(uwsgi.timer_table_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_opt_add_cron(char *opt, char *value, void *foobar) {
|
||||
|
||||
int i;
|
||||
|
||||
struct uwsgi_cron *old_uc, *uc = uwsgi.crons;
|
||||
if (!uc) {
|
||||
uc = uwsgi_malloc(sizeof(struct uwsgi_cron));
|
||||
uwsgi.crons = uc;
|
||||
}
|
||||
else {
|
||||
old_uc = uc;
|
||||
while (uc->next) {
|
||||
uc = uc->next;
|
||||
old_uc = uc;
|
||||
}
|
||||
|
||||
old_uc->next = uwsgi_malloc(sizeof(struct uwsgi_cron));
|
||||
uc = old_uc->next;
|
||||
}
|
||||
|
||||
memset(uc, 0, sizeof(struct uwsgi_cron));
|
||||
|
||||
if (sscanf(value, "%d %d %d %d %d %n", &uc->minute, &uc->hour, &uc->day, &uc->month, &uc->week, &i) != 5) {
|
||||
uwsgi_log("invalid cron syntax\n");
|
||||
exit(1);
|
||||
}
|
||||
uc->command = value + i;
|
||||
}
|
||||
|
||||
int uwsgi_signal_add_cron(uint8_t sig, int minute, int hour, int day, int month, int week) {
|
||||
|
||||
if (!uwsgi.master_process)
|
||||
return -1;
|
||||
|
||||
uwsgi_lock(uwsgi.cron_table_lock);
|
||||
|
||||
if (ushared->cron_cnt < MAX_CRONS) {
|
||||
|
||||
ushared->cron[ushared->cron_cnt].sig = sig;
|
||||
ushared->cron[ushared->cron_cnt].minute = minute;
|
||||
ushared->cron[ushared->cron_cnt].hour = hour;
|
||||
ushared->cron[ushared->cron_cnt].day = day;
|
||||
ushared->cron[ushared->cron_cnt].month = month;
|
||||
ushared->cron[ushared->cron_cnt].week = week;
|
||||
ushared->cron_cnt++;
|
||||
}
|
||||
else {
|
||||
uwsgi_log("you can register max %d cron !!!\n", MAX_CRONS);
|
||||
uwsgi_unlock(uwsgi.cron_table_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_unlock(uwsgi.cron_table_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_signal_add_rb_timer(uint8_t sig, int secs, int iterations) {
|
||||
|
||||
if (!uwsgi.master_process)
|
||||
return -1;
|
||||
|
||||
uwsgi_lock(uwsgi.rb_timer_table_lock);
|
||||
|
||||
if (ushared->rb_timers_cnt < 64) {
|
||||
|
||||
// fill the timer table, the master will use it to add items to the event queue
|
||||
ushared->rb_timers[ushared->rb_timers_cnt].value = secs;
|
||||
ushared->rb_timers[ushared->rb_timers_cnt].registered = 0;
|
||||
ushared->rb_timers[ushared->rb_timers_cnt].iterations = iterations;
|
||||
ushared->rb_timers[ushared->rb_timers_cnt].iterations_done = 0;
|
||||
ushared->rb_timers[ushared->rb_timers_cnt].sig = sig;
|
||||
ushared->rb_timers_cnt++;
|
||||
}
|
||||
else {
|
||||
uwsgi_log("you can register max 64 rb_timers !!!\n");
|
||||
uwsgi_unlock(uwsgi.rb_timer_table_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_unlock(uwsgi.rb_timer_table_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void create_signal_pipe(int *sigpipe) {
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sigpipe)) {
|
||||
uwsgi_error("socketpair()\n");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_socket_nb(sigpipe[0]);
|
||||
uwsgi_socket_nb(sigpipe[1]);
|
||||
|
||||
if (uwsgi.signal_bufsize) {
|
||||
if (setsockopt(sigpipe[0], SOL_SOCKET, SO_SNDBUF, &uwsgi.signal_bufsize, sizeof(int))) {
|
||||
uwsgi_error("setsockopt()");
|
||||
}
|
||||
if (setsockopt(sigpipe[0], SOL_SOCKET, SO_RCVBUF, &uwsgi.signal_bufsize, sizeof(int))) {
|
||||
uwsgi_error("setsockopt()");
|
||||
}
|
||||
|
||||
if (setsockopt(sigpipe[1], SOL_SOCKET, SO_SNDBUF, &uwsgi.signal_bufsize, sizeof(int))) {
|
||||
uwsgi_error("setsockopt()");
|
||||
}
|
||||
if (setsockopt(sigpipe[1], SOL_SOCKET, SO_RCVBUF, &uwsgi.signal_bufsize, sizeof(int))) {
|
||||
uwsgi_error("setsockopt()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int uwsgi_remote_signal_send(char *addr, uint8_t sig) {
|
||||
|
||||
struct uwsgi_header uh;
|
||||
|
||||
uh.modifier1 = 110;
|
||||
uh.pktsize = 0;
|
||||
uh.modifier2 = sig;
|
||||
|
||||
int fd = uwsgi_connect(addr, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
if (write(fd, (char *) &uh, 4) != 4) {
|
||||
uwsgi_error("uwsgi_remote_signal_send()");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = uwsgi_read_response(fd, &uh, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], NULL);
|
||||
|
||||
close(fd);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_signal_send(int fd, uint8_t sig) {
|
||||
|
||||
socklen_t so_bufsize_len = sizeof(int);
|
||||
int so_bufsize = 0;
|
||||
|
||||
if (write(fd, &sig, 1) != 1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &so_bufsize, &so_bufsize_len)) {
|
||||
uwsgi_error("getsockopt()");
|
||||
}
|
||||
uwsgi_log("*** SIGNAL QUEUE IS FULL: buffer size %d bytes (you can tune it with --signal-bufsize) ***\n", so_bufsize);
|
||||
}
|
||||
else {
|
||||
uwsgi_error("uwsgi_signal_send()");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_route_signal(uint8_t sig) {
|
||||
|
||||
int pos = (uwsgi.mywid * 256) + sig;
|
||||
struct uwsgi_signal_entry *use = &ushared->signal_table[pos];
|
||||
int i;
|
||||
|
||||
// send to first available worker
|
||||
if (use->receiver[0] == 0 || !strcmp(use->receiver, "worker") || !strcmp(use->receiver, "worker0")) {
|
||||
if (uwsgi_signal_send(ushared->worker_signal_pipe[0], sig)) {
|
||||
uwsgi_log("could not deliver signal %d to workers pool\n", sig);
|
||||
}
|
||||
}
|
||||
// send to all workers
|
||||
else if (!strcmp(use->receiver, "workers")) {
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
if (uwsgi_signal_send(uwsgi.workers[i].signal_pipe[0], sig)) {
|
||||
uwsgi_log("could not deliver signal %d to worker %d\n", sig, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
// route to specific worker
|
||||
else if (!strncmp(use->receiver, "worker", 6)) {
|
||||
i = atoi(use->receiver + 6);
|
||||
if (i > uwsgi.numproc) {
|
||||
uwsgi_log("invalid signal target: %s\n", use->receiver);
|
||||
}
|
||||
if (uwsgi_signal_send(uwsgi.workers[i].signal_pipe[0], sig)) {
|
||||
uwsgi_log("could not deliver signal %d to worker %d\n", sig, i);
|
||||
}
|
||||
}
|
||||
// route to subscribed
|
||||
else if (!strcmp(use->receiver, "subscribed")) {
|
||||
}
|
||||
// route to spooler
|
||||
else if (!strcmp(use->receiver, "spooler")) {
|
||||
if (ushared->worker_signal_pipe[0] != -1) {
|
||||
if (uwsgi_signal_send(ushared->spooler_signal_pipe[0], sig)) {
|
||||
uwsgi_log("could not deliver signal %d to the spooler\n", sig);
|
||||
}
|
||||
}
|
||||
}
|
||||
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)) {
|
||||
uwsgi_log("could not deliver signal %d to mule %d\n", sig, i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strncmp(use->receiver, "mule", 4)) {
|
||||
i = atoi(use->receiver + 4);
|
||||
if (i > uwsgi.mules_cnt) {
|
||||
uwsgi_log("invalid signal target: %s\n", use->receiver);
|
||||
}
|
||||
else if (i == 0) {
|
||||
if (uwsgi_signal_send(ushared->mule_signal_pipe[0], sig)) {
|
||||
uwsgi_log("could not deliver signal %d to a mule\n", sig);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (uwsgi_signal_send(uwsgi.mules[i - 1].signal_pipe[0], sig)) {
|
||||
uwsgi_log("could not deliver signal %d to mule %d\n", sig, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strncmp(use->receiver, "farm_", 5)) {
|
||||
char *name = use->receiver + 5;
|
||||
struct uwsgi_farm *uf = get_farm_by_name(name);
|
||||
if (!uf) {
|
||||
uwsgi_log("unknown farm: %s\n", name);
|
||||
return;
|
||||
}
|
||||
if (uwsgi_signal_send(uf->signal_pipe[0], sig)) {
|
||||
uwsgi_log("could not deliver signal %d to farm %d (%s)\n", sig, uf->id, uf->name);
|
||||
}
|
||||
}
|
||||
else if (!strncmp(use->receiver, "farm", 4)) {
|
||||
i = atoi(use->receiver + 4);
|
||||
if (i > uwsgi.farms_cnt || i <= 0) {
|
||||
uwsgi_log("invalid signal target: %s\n", use->receiver);
|
||||
}
|
||||
else {
|
||||
if (uwsgi_signal_send(uwsgi.farms[i - 1].signal_pipe[0], sig)) {
|
||||
uwsgi_log("could not deliver signal %d to farm %d (%s)\n", sig, i, uwsgi.farms[i - 1].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
// unregistered signal, sending it to all the workers
|
||||
uwsgi_log("^^^ UNSUPPORTED SIGNAL TARGET: %s ^^^\n", use->receiver);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_signal_wait(int signum) {
|
||||
|
||||
int wait_for_specific_signal = 0;
|
||||
uint8_t uwsgi_signal = 0;
|
||||
int received_signal = -1;
|
||||
int ret;
|
||||
struct pollfd pfd[2];
|
||||
|
||||
if (signum > -1) {
|
||||
wait_for_specific_signal = 1;
|
||||
}
|
||||
|
||||
pfd[0].fd = uwsgi.signal_socket;
|
||||
pfd[0].events = POLLIN;
|
||||
pfd[1].fd = uwsgi.my_signal_socket;
|
||||
pfd[1].events = POLLIN;
|
||||
|
||||
cycle:
|
||||
ret = poll(pfd, 2, -1);
|
||||
if (ret > 0) {
|
||||
if (pfd[0].revents == POLLIN) {
|
||||
if (read(uwsgi.signal_socket, &uwsgi_signal, 1) != 1) {
|
||||
uwsgi_error("read()");
|
||||
}
|
||||
else {
|
||||
(void) uwsgi_signal_handler(uwsgi_signal);
|
||||
if (wait_for_specific_signal) {
|
||||
if (signum != uwsgi_signal)
|
||||
goto cycle;
|
||||
}
|
||||
received_signal = uwsgi_signal;
|
||||
}
|
||||
}
|
||||
if (pfd[1].revents == POLLIN) {
|
||||
if (read(uwsgi.my_signal_socket, &uwsgi_signal, 1) != 1) {
|
||||
uwsgi_error("read()");
|
||||
}
|
||||
else {
|
||||
(void) uwsgi_signal_handler(uwsgi_signal);
|
||||
if (wait_for_specific_signal) {
|
||||
if (signum != uwsgi_signal)
|
||||
goto cycle;
|
||||
}
|
||||
}
|
||||
received_signal = uwsgi_signal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return received_signal;
|
||||
}
|
||||
|
||||
void uwsgi_receive_signal(int fd, char *name, int id) {
|
||||
|
||||
uint8_t uwsgi_signal;
|
||||
|
||||
ssize_t ret = read(fd, &uwsgi_signal, 1);
|
||||
|
||||
if (ret == 0) {
|
||||
goto destroy;
|
||||
}
|
||||
else if (ret < 0 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
|
||||
uwsgi_error("[uwsgi-signal] read()");
|
||||
goto destroy;
|
||||
}
|
||||
else if (ret > 0) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log_verbose("master sent signal %d to %s %d\n", uwsgi_signal, name, id);
|
||||
#endif
|
||||
if (uwsgi_signal_handler(uwsgi_signal)) {
|
||||
uwsgi_log_verbose("error managing signal %d on %s %d\n", uwsgi_signal, name, id);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
destroy:
|
||||
// better to kill the whole worker...
|
||||
uwsgi_log_verbose("uWSGI %s %d screams: UAAAAAAH my master disconnected: i will kill myself !!!\n", name, id);
|
||||
end_me(0);
|
||||
|
||||
}
|
||||
+117
-64
@@ -1,6 +1,4 @@
|
||||
#ifdef UWSGI_SNMP
|
||||
|
||||
#include "uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
@@ -249,11 +247,14 @@ static uint64_t get_uwsgi_snmp_value(uint64_t val, uint8_t * oid_t) {
|
||||
static uint64_t get_uwsgi_custom_snmp_value(uint64_t val, uint8_t * oid_t) {
|
||||
|
||||
val--;
|
||||
uwsgi_wlock(uwsgi.snmp_lock);
|
||||
if (uwsgi.shared->snmp_value[val].type) {
|
||||
*oid_t = uwsgi.shared->snmp_value[val].type;
|
||||
uwsgi_rwunlock(uwsgi.snmp_lock);
|
||||
return uwsgi.shared->snmp_value[val].val;
|
||||
}
|
||||
|
||||
uwsgi_rwunlock(uwsgi.snmp_lock);
|
||||
*oid_t = SNMP_NULL;
|
||||
return 0;
|
||||
}
|
||||
@@ -278,92 +279,144 @@ static int get_snmp_integer(uint8_t * ptr, uint64_t * val) {
|
||||
#ifdef __BIG_ENDIAN__
|
||||
for (i = 0; i < tlen; i++) {
|
||||
#else
|
||||
for (i = tlen - 1; i >= 0; i--) {
|
||||
for (i = tlen - 1; i >= 0; i--) {
|
||||
#endif
|
||||
cval[j] = ptr[1 + i];
|
||||
j++;
|
||||
}
|
||||
|
||||
return tlen + 1;
|
||||
cval[j] = ptr[1 + i];
|
||||
j++;
|
||||
}
|
||||
|
||||
static uint8_t snmp_int_to_snmp(uint64_t snmp_val, uint8_t oid_type, uint8_t * buffer) {
|
||||
uint8_t tlen;
|
||||
int i, j;
|
||||
uint8_t *ptr = (uint8_t *) &snmp_val;
|
||||
return tlen + 1;
|
||||
}
|
||||
|
||||
// check for counter, counter64 or gauge
|
||||
static uint8_t snmp_int_to_snmp(uint64_t snmp_val, uint8_t oid_type, uint8_t * buffer) {
|
||||
uint8_t tlen;
|
||||
int i, j;
|
||||
uint8_t *ptr = (uint8_t *) & snmp_val;
|
||||
|
||||
if (oid_type == SNMP_COUNTER64) {
|
||||
tlen = 8;
|
||||
}
|
||||
else if (oid_type == SNMP_NULL || oid_type == 0) {
|
||||
tlen = 0;
|
||||
}
|
||||
else {
|
||||
tlen = 4;
|
||||
}
|
||||
// check for counter, counter64 or gauge
|
||||
|
||||
buffer[0] = tlen;
|
||||
if (oid_type == SNMP_COUNTER64) {
|
||||
tlen = 8;
|
||||
}
|
||||
else if (oid_type == SNMP_NULL || oid_type == 0) {
|
||||
tlen = 0;
|
||||
}
|
||||
else {
|
||||
tlen = 4;
|
||||
}
|
||||
|
||||
j = 1;
|
||||
buffer[0] = tlen;
|
||||
|
||||
j = 1;
|
||||
#ifdef __BIG_ENDIAN__
|
||||
for (i = 0; i < tlen; i++) {
|
||||
for (i = 0; i < tlen; i++) {
|
||||
#else
|
||||
for (i = tlen - 1; i >= 0; i--) {
|
||||
for (i = tlen - 1; i >= 0; i--) {
|
||||
#endif
|
||||
buffer[j] = ptr[i];
|
||||
j++;
|
||||
}
|
||||
buffer[j] = ptr[i];
|
||||
j++;
|
||||
}
|
||||
|
||||
return tlen + 1;
|
||||
}
|
||||
return tlen + 1;
|
||||
}
|
||||
|
||||
static ssize_t build_snmp_response(uint8_t oid1, uint8_t oid2, uint8_t * buffer, int size, uint8_t * seq1, uint8_t * seq2, uint8_t * seq3) {
|
||||
uint64_t snmp_val;
|
||||
uint8_t oid_sz;
|
||||
uint8_t oid_type;
|
||||
static ssize_t build_snmp_response(uint8_t oid1, uint8_t oid2, uint8_t * buffer, int size, uint8_t * seq1, uint8_t * seq2, uint8_t * seq3) {
|
||||
uint64_t snmp_val;
|
||||
uint8_t oid_sz;
|
||||
uint8_t oid_type;
|
||||
|
||||
if (oid1 == 1) {
|
||||
snmp_val = get_uwsgi_snmp_value(oid2, &oid_type);
|
||||
}
|
||||
else if (oid1 == 2) {
|
||||
snmp_val = get_uwsgi_custom_snmp_value(oid2, &oid_type);
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
if (oid1 == 1) {
|
||||
snmp_val = get_uwsgi_snmp_value(oid2, &oid_type);
|
||||
}
|
||||
else if (oid1 == 2) {
|
||||
snmp_val = get_uwsgi_custom_snmp_value(oid2, &oid_type);
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer[size - 2] = oid_type;
|
||||
oid_sz = snmp_int_to_snmp(snmp_val, oid_type, buffer + (size - 1));
|
||||
buffer[size - 2] = oid_type;
|
||||
oid_sz = snmp_int_to_snmp(snmp_val, oid_type, buffer + (size - 1));
|
||||
|
||||
if (oid_sz < 1)
|
||||
return -1;
|
||||
if (oid_sz < 1)
|
||||
return -1;
|
||||
|
||||
oid_sz--;
|
||||
oid_sz--;
|
||||
|
||||
buffer[1] += oid_sz;
|
||||
*seq1 += oid_sz;
|
||||
*seq2 += oid_sz;
|
||||
*seq3 += oid_sz;
|
||||
buffer[1] += oid_sz;
|
||||
*seq1 += oid_sz;
|
||||
*seq2 += oid_sz;
|
||||
*seq3 += oid_sz;
|
||||
|
||||
return size + oid_sz;
|
||||
return size + oid_sz;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_opt_snmp(char *opt, char *value, void *foobar) {
|
||||
uwsgi.snmp = 1;
|
||||
if (value) {
|
||||
uwsgi.snmp_addr = value;
|
||||
uwsgi.master_process = 1;
|
||||
}
|
||||
if (value) {
|
||||
uwsgi.snmp_addr = value;
|
||||
uwsgi.master_process = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_opt_snmp_community(char *opt, char *value, void *foobar) {
|
||||
uwsgi.snmp = 1;
|
||||
uwsgi.snmp_community = value;
|
||||
uwsgi.snmp_community = value;
|
||||
}
|
||||
#else
|
||||
#warning "*** SNMP support is disabled ***"
|
||||
#endif
|
||||
|
||||
int uwsgi_setup_snmp(void) {
|
||||
int snmp_fd = -1;
|
||||
int i;
|
||||
if (uwsgi.snmp) {
|
||||
if (uwsgi.snmp_community) {
|
||||
if (strlen(uwsgi.snmp_community) > 72) {
|
||||
uwsgi_log("*** warning the supplied SNMP community string will be truncated to 72 chars ***\n");
|
||||
memcpy(uwsgi.shared->snmp_community, uwsgi.snmp_community, 72);
|
||||
}
|
||||
else {
|
||||
memcpy(uwsgi.shared->snmp_community, uwsgi.snmp_community, strlen(uwsgi.snmp_community) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi.shared->snmp_gvalue[0].type = SNMP_COUNTER64;
|
||||
uwsgi.shared->snmp_gvalue[0].val = &uwsgi.workers[0].requests;
|
||||
|
||||
for (i = 0; i < uwsgi.numproc; i++) {
|
||||
uwsgi.shared->snmp_gvalue[30 + i].type = SNMP_COUNTER64;
|
||||
uwsgi.shared->snmp_gvalue[30 + i].val = &uwsgi.workers[i + 1].requests;
|
||||
}
|
||||
|
||||
if (uwsgi.snmp_addr) {
|
||||
snmp_fd = bind_to_udp(uwsgi.snmp_addr, 0, 0);
|
||||
if (snmp_fd < 0) {
|
||||
uwsgi_log("unable to bind to udp socket. SNMP service will be disabled.\n");
|
||||
}
|
||||
else {
|
||||
uwsgi_log("SNMP server enabled on %s\n", uwsgi.snmp_addr);
|
||||
event_queue_add_fd_read(uwsgi.master_queue, snmp_fd);
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log("SNMP agent enabled.\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return snmp_fd;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
+769
-256
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user