mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-10-04 07:58:33 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab4afdbeaa | ||
|
|
54e2d698cb | ||
|
|
8b0565c0b8 | ||
|
|
102d6f25ed | ||
|
|
d0a53aa976 | ||
|
|
f8cf808e47 | ||
|
|
f8bbd2177e | ||
|
|
f44c145941 | ||
|
|
f34ac9f6aa | ||
|
|
b971230fd9 | ||
|
|
5c6340caac | ||
|
|
c0b97b47d3 | ||
|
|
a6b7f6e5bb | ||
|
|
1b99f9a750 | ||
|
|
a434195318 | ||
|
|
a6a8faea78 | ||
|
|
31458320ab | ||
|
|
037a1f7f77 | ||
|
|
10d4d10ac9 | ||
|
|
00e8d509f8 | ||
|
|
c9ca14df4d | ||
|
|
841cdfc62d | ||
|
|
fc7026c076 | ||
|
|
b96581c183 | ||
|
|
4fa5d72af6 | ||
|
|
f4be581666 | ||
|
|
24fb5518d8 | ||
|
|
2e8061d62a | ||
|
|
23d70f6936 | ||
|
|
95ea88628a | ||
|
|
68b411f487 | ||
|
|
40bfbc0a44 | ||
|
|
fc9b6ea275 | ||
|
|
522f3bb3a1 | ||
|
|
743c7ceaa6 | ||
|
|
c780cd47ce | ||
|
|
54e7e01c05 | ||
|
|
7d422d11e4 | ||
|
|
5c35b60d1d | ||
|
|
94353efb3f | ||
|
|
0586a2ba47 | ||
|
|
be6081c6f7 | ||
|
|
955fb6479e | ||
|
|
1b334e8cf7 | ||
|
|
718e198ac8 | ||
|
|
3757e5a8bb | ||
|
|
d505964321 | ||
|
|
1114c1a429 | ||
|
|
f58a9c6119 | ||
|
|
e791cb2c00 | ||
|
|
f741dbb01b | ||
|
|
d5f0741e8d | ||
|
|
b265ed8313 | ||
|
|
6cb160bb26 | ||
|
|
009a3f2c0d | ||
|
|
11b3d1fb94 | ||
|
|
7a39472700 | ||
|
|
4489b48603 | ||
|
|
d2f69af964 | ||
|
|
34e9dabffc | ||
|
|
6a4f46639e | ||
|
|
0d07ff25f9 | ||
|
|
c1d9c4ef12 | ||
|
|
0227ff7a9b | ||
|
|
082b178ae3 | ||
|
|
0e695cbd6e | ||
|
|
be2ed4dc4a | ||
|
|
4777666588 | ||
|
|
5647057ecc | ||
|
|
94cb950058 | ||
|
|
8d65371bf6 | ||
|
|
c747a36ae1 | ||
|
|
e51cb65857 | ||
|
|
8fa4fdb8c8 | ||
|
|
d584857c78 | ||
|
|
f0b1d79f8b | ||
|
|
28566ad772 | ||
|
|
40c0e139d4 | ||
|
|
04f2444ea0 | ||
|
|
9f71d28afa | ||
|
|
af262fb325 | ||
|
|
243657b5aa | ||
|
|
032302edaa | ||
|
|
d4bd658d84 | ||
|
|
78843c3e06 | ||
|
|
692ba1f6b3 | ||
|
|
400a9d72ef | ||
|
|
11f8f0385a | ||
|
|
c40d15981c | ||
|
|
baa1bf21f1 | ||
|
|
3dd3122236 | ||
|
|
927ef2ccde | ||
|
|
af6eaf6737 | ||
|
|
7c543f5627 | ||
|
|
b06e35c610 | ||
|
|
842c2148d7 | ||
|
|
a2a94bd78e | ||
|
|
4452c30fc8 | ||
|
|
f462792c8e | ||
|
|
03879fdc0c | ||
|
|
389d0b95d5 | ||
|
|
6ec32e192f | ||
|
|
22c034cdca | ||
|
|
396d8c3022 | ||
|
|
a535ecbe17 | ||
|
|
fd436c3e4f | ||
|
|
e5c245ea2f | ||
|
|
3008b7c83b | ||
|
|
eca6cd3066 | ||
|
|
691a41f290 | ||
|
|
df4cf539a1 | ||
|
|
baa1167dfe | ||
|
|
d8a83ab7cf | ||
|
|
8184351b3b | ||
|
|
4a4dbbcf69 | ||
|
|
56f79efc74 | ||
|
|
ea073a9bbd | ||
|
|
c5b2ca4b20 | ||
|
|
c0f9d8d2ff | ||
|
|
497660279f | ||
|
|
625395bd26 | ||
|
|
79a7797409 | ||
|
|
3b13de3e6e | ||
|
|
7f99855527 | ||
|
|
8c29178f81 | ||
|
|
ed71000033 | ||
|
|
20860ed069 | ||
|
|
2e62f13917 | ||
|
|
1b2a83ce70 | ||
|
|
113ec5ae9e | ||
|
|
68e81828d1 | ||
|
|
543790dc83 | ||
|
|
be24060578 | ||
|
|
bdedc1c94c | ||
|
|
e2454aa898 | ||
|
|
dfa4834be3 | ||
|
|
f204249110 | ||
|
|
f4c25a6cd1 | ||
|
|
fbfbacce14 | ||
|
|
a0eed32b3f | ||
|
|
9fe9fe1bb6 | ||
|
|
192312e3ea | ||
|
|
ee46fe6ba6 | ||
|
|
58abd07a88 | ||
|
|
c246a6008e | ||
|
|
706f1b59c3 | ||
|
|
ddbc8920f7 | ||
|
|
7e3bf6868e | ||
|
|
4c7ecef577 | ||
|
|
e3da0aaad4 | ||
|
|
99e576e40c | ||
|
|
7604ce3441 | ||
|
|
a0082b5b98 | ||
|
|
c90c639348 | ||
|
|
2e188dc25a | ||
|
|
312d21cb3f | ||
|
|
4ee138be7c | ||
|
|
299aef99b3 | ||
|
|
06953e4547 | ||
|
|
7565ee8740 | ||
|
|
10377f02a3 | ||
|
|
a41e6e2c61 | ||
|
|
6b2b909d33 | ||
|
|
70cd18bffb | ||
|
|
d6be4bcad9 | ||
|
|
85530b5d8e | ||
|
|
e3848e84d3 | ||
|
|
4ec9312b10 | ||
|
|
aedf3b2455 | ||
|
|
2210ec7f71 | ||
|
|
a9bee41707 | ||
|
|
3adbfd100f | ||
|
|
8d8de4b8da | ||
|
|
099403d554 | ||
|
|
13938a6aa7 | ||
|
|
9be3a4aaf8 | ||
|
|
009e42f349 | ||
|
|
207dd3bc77 | ||
|
|
feec6b3151 | ||
|
|
bf8207f0f1 | ||
|
|
9fcbc6ee68 | ||
|
|
dcb58aaa34 | ||
|
|
7163d8ddd4 | ||
|
|
c7b24eec45 | ||
|
|
1e7098f787 | ||
|
|
b28f0d9863 | ||
|
|
b49c4f4af9 | ||
|
|
2c39aafb0b | ||
|
|
1036d9c18b | ||
|
|
f0c8cbf190 | ||
|
|
f51db4481b | ||
|
|
717eba7ab3 | ||
|
|
3cc971ba55 | ||
|
|
23b3d7483f | ||
|
|
ba03837e29 | ||
|
|
06952fbaff | ||
|
|
27be00b4cc | ||
|
|
b50a377190 | ||
|
|
1ed9cb0bec | ||
|
|
a548ede3c7 | ||
|
|
de26c09030 | ||
|
|
19aa7c2560 | ||
|
|
215e0c4cbc | ||
|
|
d484acefa4 | ||
|
|
4032efd3e8 | ||
|
|
f9d412bcca | ||
|
|
5f52063b9e | ||
|
|
87833abb42 | ||
|
|
0fcbd5e334 | ||
|
|
5b55bf5f5c | ||
|
|
b8cc1d962f | ||
|
|
762c73e2ac | ||
|
|
57cd0e9135 | ||
|
|
5e0a85bff0 | ||
|
|
d2eaef524c | ||
|
|
a98c5a3931 | ||
|
|
040da07323 | ||
|
|
34f43ec97b | ||
|
|
7e3cfe94d6 | ||
|
|
e2c3b650a1 | ||
|
|
404dfaeda7 | ||
|
|
a1ec530945 | ||
|
|
b8dfd617f2 | ||
|
|
f34ed4dc47 | ||
|
|
cd2ff0e585 | ||
|
|
449955562f | ||
|
|
41a4bbccfc | ||
|
|
87b17c001d | ||
|
|
67b7753814 | ||
|
|
b190744b77 | ||
|
|
4b603071d8 | ||
|
|
16c55f0217 | ||
|
|
c989f2fb33 | ||
|
|
6429a47b0d | ||
|
|
f8a48a3ae9 | ||
|
|
fb3272d165 | ||
|
|
be5f67906e | ||
|
|
f730023e88 | ||
|
|
50954d34db | ||
|
|
ef2d9e781f | ||
|
|
a9bb310a20 | ||
|
|
86f37556da | ||
|
|
a57617c09a | ||
|
|
63ac62cf1d | ||
|
|
ac371730fd | ||
|
|
4ed6588c80 | ||
|
|
81d20edc4c | ||
|
|
a9fc6adccf | ||
|
|
21ad94ba4e | ||
|
|
571b9f27e1 | ||
|
|
cbf9ccf062 | ||
|
|
dd8fd8f19c | ||
|
|
1535b8ee13 | ||
|
|
f2491536dd | ||
|
|
88ce0181b3 | ||
|
|
4ad2658090 | ||
|
|
8d80c5e84d | ||
|
|
bae9235103 | ||
|
|
8ae2d0d00c | ||
|
|
373b89e70c | ||
|
|
c14e18b270 | ||
|
|
68ec3afd1a | ||
|
|
8918e81256 | ||
|
|
469fd697cb | ||
|
|
20844ebfca | ||
|
|
38652076d3 | ||
|
|
f13ae47fc0 | ||
|
|
ad4ee9d5c3 | ||
|
|
03a4e900ea | ||
|
|
b52dbf2aa0 | ||
|
|
c7a22c3b53 | ||
|
|
775aae3f1e | ||
|
|
862731ba91 | ||
|
|
8c302eee51 | ||
|
|
b6d34067c4 | ||
|
|
dbe15195b7 | ||
|
|
5642aa1eb5 | ||
|
|
5dd465ccc1 | ||
|
|
ae78c3007e | ||
|
|
16211d9439 | ||
|
|
515619fe2a | ||
|
|
a7d550165d | ||
|
|
efceacd9e5 | ||
|
|
ea5ebc2d15 | ||
|
|
fba82c203c | ||
|
|
a50516af7a | ||
|
|
6056b51653 | ||
|
|
23a3170c59 | ||
|
|
e136128408 | ||
|
|
fce94e0f54 | ||
|
|
06fa65bc5d | ||
|
|
571ec5ca72 | ||
|
|
39bc0ecd46 | ||
|
|
7a5373360c | ||
|
|
15453ffef6 | ||
|
|
a25747a096 | ||
|
|
bb1ef59b52 | ||
|
|
6bb3af840d | ||
|
|
0223c74ecc | ||
|
|
c7004d7ba4 | ||
|
|
915d2e9192 | ||
|
|
df79b9367b | ||
|
|
ce3d026037 | ||
|
|
d0f6c4130b | ||
|
|
26bcf28182 | ||
|
|
272d1ccc03 | ||
|
|
6c440af24e | ||
|
|
8954520cb9 | ||
|
|
31bde74fab | ||
|
|
13c64a383c | ||
|
|
809028f11b | ||
|
|
dee9d2ba1e | ||
|
|
29d80ce061 | ||
|
|
abcd3242d8 | ||
|
|
f4762299f9 | ||
|
|
107f4309a4 | ||
|
|
d2a8df19ea | ||
|
|
29efd15534 | ||
|
|
e7fb216a8d | ||
|
|
952b96cdcb | ||
|
|
8ee82fc296 | ||
|
|
afe2bfb856 | ||
|
|
5b63e9aea0 | ||
|
|
91f70259e2 | ||
|
|
f120cacc03 | ||
|
|
aff1d782b8 | ||
|
|
b489fd8a24 | ||
|
|
47e0eb68c2 | ||
|
|
9498e25245 | ||
|
|
a33e18b589 | ||
|
|
f2dcdf2289 | ||
|
|
74c53e8a61 | ||
|
|
1feed87c10 | ||
|
|
f89742d81a | ||
|
|
340b9d603e | ||
|
|
1c0fc64243 | ||
|
|
1d5173d923 | ||
|
|
49a8bf0b9b | ||
|
|
0a7e5a41a2 | ||
|
|
43ff563429 | ||
|
|
2daf6f1f66 | ||
|
|
985f56768f | ||
|
|
35278588f5 | ||
|
|
f6545be647 | ||
|
|
f387d27582 | ||
|
|
5d8e5d943f | ||
|
|
4046f76cb2 | ||
|
|
8baeb0af2f | ||
|
|
63e0105a0f | ||
|
|
70daa57caf | ||
|
|
db0f7951a9 | ||
|
|
45a7a3066d | ||
|
|
c73a6723d7 | ||
|
|
fb55f57531 | ||
|
|
8cf4d5802a | ||
|
|
e3c042e567 | ||
|
|
5435f8927c | ||
|
|
e1e65c46ac | ||
|
|
e1f3665a8e | ||
|
|
ef09a010cf | ||
|
|
3f5d79c755 | ||
|
|
3b5468f39f | ||
|
|
5598c7cc22 | ||
|
|
d6fdb812a2 | ||
|
|
e6d5f6c612 | ||
|
|
8f10daa2bf | ||
|
|
f027153452 | ||
|
|
0ebda93a50 | ||
|
|
dc4e8950d2 | ||
|
|
0f5336028f | ||
|
|
e02341bffe | ||
|
|
ac92ff4079 | ||
|
|
a5da77bc54 | ||
|
|
0441e88b82 | ||
|
|
815f4abec0 | ||
|
|
4f9e2ff3f6 | ||
|
|
ce8dd001bf | ||
|
|
d4e90f5215 | ||
|
|
da13562890 | ||
|
|
d320075ab0 | ||
|
|
4061826da4 | ||
|
|
2854321891 | ||
|
|
c4181cdc55 | ||
|
|
327582b695 | ||
|
|
f56b9be4c5 | ||
|
|
28ccace24f | ||
|
|
13f82176e3 | ||
|
|
be4d324f6b | ||
|
|
36486caabb | ||
|
|
b3af255727 | ||
|
|
a56f726f7d | ||
|
|
24d6470f38 | ||
|
|
7e079e4c40 | ||
|
|
0d9bc03c53 | ||
|
|
7598666768 | ||
|
|
cd6f027705 | ||
|
|
0803a7f0b0 | ||
|
|
0eb956db4a | ||
|
|
76c6ae6d16 | ||
|
|
40054e3494 | ||
|
|
8927dfd538 | ||
|
|
68f734fcad | ||
|
|
af4c7f74d5 | ||
|
|
4581d1e7ce | ||
|
|
d465f61506 | ||
|
|
5cae9b9ba4 | ||
|
|
428a2d9366 | ||
|
|
1c00b54b06 | ||
|
|
6228fb91da | ||
|
|
307cf3a0ef | ||
|
|
f723a804c0 | ||
|
|
24ac19e2d6 | ||
|
|
38147d50ff | ||
|
|
9f7db10582 | ||
|
|
ed35a50e6c | ||
|
|
fae08f49cf | ||
|
|
35f5b5b2eb | ||
|
|
b785c8fccf | ||
|
|
597c3cd7f1 | ||
|
|
bbbe01ef4b | ||
|
|
ea1e1cb65f | ||
|
|
a1d31ae954 | ||
|
|
fa0ed9489a | ||
|
|
7bb7b351e0 | ||
|
|
cb45f207a6 | ||
|
|
82ffb60bdd | ||
|
|
ec38ce9a26 | ||
|
|
8279926bab | ||
|
|
ac17b0910e | ||
|
|
aae3e7ff17 | ||
|
|
4cfff98cd1 | ||
|
|
19ee50949c | ||
|
|
ec27d624c3 | ||
|
|
0dc8803ff8 | ||
|
|
e8ea1a55f9 | ||
|
|
a0cb71ca78 | ||
|
|
5c5aef3827 | ||
|
|
737a7f4d51 | ||
|
|
c3ee774d56 | ||
|
|
2d5adacc65 | ||
|
|
b7a8cc0297 | ||
|
|
317b0f79a8 | ||
|
|
4644578276 | ||
|
|
f1d450c12f | ||
|
|
6624f75ec7 | ||
|
|
8941505ea0 | ||
|
|
18b177db25 | ||
|
|
27421f3642 | ||
|
|
30f9479e85 | ||
|
|
a9f7631ab4 | ||
|
|
cb8519510f | ||
|
|
f7881bfb78 | ||
|
|
4cf4c75d5d | ||
|
|
91bcbc77b3 | ||
|
|
b1db4d35c3 | ||
|
|
060462b849 | ||
|
|
0e08c0211c | ||
|
|
e69cc2bcd5 | ||
|
|
996af7d46c | ||
|
|
e8e66f15da | ||
|
|
cd09b4a55d | ||
|
|
f4a1d76396 | ||
|
|
ab8cc168e5 | ||
|
|
5e43ef6fae | ||
|
|
caa3614f78 | ||
|
|
a81ca89ae9 | ||
|
|
5861705cd6 | ||
|
|
4e68dacad3 | ||
|
|
4f8f15a3b6 | ||
|
|
aa6b86fbdf | ||
|
|
7a18ff48ba | ||
|
|
e354de9f5e | ||
|
|
10073bc4ae | ||
|
|
6fd051b248 | ||
|
|
1cf034881e | ||
|
|
1393281c74 | ||
|
|
edf95a4b0a | ||
|
|
8887f83f7f | ||
|
|
7513d80440 | ||
|
|
67289b7cf1 | ||
|
|
a88f478fac | ||
|
|
d385661a93 | ||
|
|
e8895ba773 | ||
|
|
5a23a8d457 | ||
|
|
e01a3d8bd2 | ||
|
|
b270bd24d7 | ||
|
|
ab989ebf16 | ||
|
|
7c31b6657f | ||
|
|
ba7d322aaf | ||
|
|
537187b7f8 | ||
|
|
d22a7c7223 | ||
|
|
c9f986fa59 | ||
|
|
d7388ca5e7 | ||
|
|
df5ad62ebf | ||
|
|
41dab14020 | ||
|
|
744e166e9d | ||
|
|
5a3b93f763 | ||
|
|
656de924eb | ||
|
|
703444dd40 | ||
|
|
ff8ca18e8f | ||
|
|
1f90be1ae1 | ||
|
|
ee95c2eb0b | ||
|
|
6606f3f0dc | ||
|
|
bcd97f7247 | ||
|
|
271e7f8f4c | ||
|
|
e78d8594a8 | ||
|
|
659360b366 | ||
|
|
6c1c86ea79 | ||
|
|
5da36b7199 | ||
|
|
294452eef7 | ||
|
|
3ac0e28d9c | ||
|
|
ce22b69a2f | ||
|
|
8b31a998ed | ||
|
|
dad97bc104 | ||
|
|
e20e43eee0 | ||
|
|
aafd4e757d | ||
|
|
575fc26bd7 | ||
|
|
5743eb2575 | ||
|
|
31972ded93 | ||
|
|
28321a0f94 | ||
|
|
406dfbc770 | ||
|
|
c59595cefc | ||
|
|
7108ee1ba0 | ||
|
|
cf8e68f7a0 | ||
|
|
a9510c2209 | ||
|
|
b2be5943a8 | ||
|
|
8f19fe292e | ||
|
|
d3e7668d0a | ||
|
|
88e67a74e5 | ||
|
|
7fecda1a23 | ||
|
|
56b6fa88f9 | ||
|
|
e847cfe4bc | ||
|
|
1a854ae3ba | ||
|
|
c75180bf95 | ||
|
|
d496450b84 | ||
|
|
d2636ed133 | ||
|
|
59de0c2085 | ||
|
|
4b7df29bd1 | ||
|
|
b099ba6a29 | ||
|
|
164069e194 | ||
|
|
b3e4ff8613 | ||
|
|
3eb5ec3543 | ||
|
|
c3c698a615 | ||
|
|
ac6d2f3e83 | ||
|
|
d1f1b8a43a | ||
|
|
85586a621c | ||
|
|
1a384a334f | ||
|
|
8901afded5 | ||
|
|
ab12703a11 | ||
|
|
9992b4c964 | ||
|
|
9a2dbd08cd | ||
|
|
5f92a00b71 | ||
|
|
7bd9d51217 | ||
|
|
80c649aa40 | ||
|
|
6c8fe2cc53 | ||
|
|
dcc7167d75 | ||
|
|
e3a52e4039 | ||
|
|
498f6162f7 | ||
|
|
33d85d3670 | ||
|
|
afbf5b9633 | ||
|
|
a8505be6c0 | ||
|
|
4a07632569 | ||
|
|
d4f0589c39 | ||
|
|
a9989d46fc | ||
|
|
99cf598c0c | ||
|
|
a6af22b8f0 | ||
|
|
0961d61a88 | ||
|
|
7b76a2d749 | ||
|
|
b516f1d3ec | ||
|
|
8fdef7a1f9 | ||
|
|
10258db4ae | ||
|
|
621c9523cf | ||
|
|
c415adab28 | ||
|
|
7fef1048b3 | ||
|
|
1e7aaeeeed | ||
|
|
c5b4564001 | ||
|
|
a9127c8d79 | ||
|
|
a0f7a5c70f | ||
|
|
ecf3cae35b | ||
|
|
d553bc8014 | ||
|
|
a1553d3632 | ||
|
|
bb42ae1b4a | ||
|
|
61ac2efe0e | ||
|
|
1c0a3ec413 | ||
|
|
8b7e93385b | ||
|
|
c742624054 | ||
|
|
8011f0615d | ||
|
|
8096b2198f | ||
|
|
3556bd5283 | ||
|
|
26710694af | ||
|
|
0f397eeb55 | ||
|
|
bf929398a9 | ||
|
|
4f8a0f753e | ||
|
|
7db5da9566 | ||
|
|
4d1389805c | ||
|
|
ee87e2b946 | ||
|
|
6356d78768 | ||
|
|
afdf7e740e | ||
|
|
51ce3ddf78 | ||
|
|
192186056e | ||
|
|
336a7febd7 | ||
|
|
63e73d1b73 | ||
|
|
a02ab9a723 | ||
|
|
95f15ab9dd | ||
|
|
5d0ea0066a | ||
|
|
9ff6b2da9b | ||
|
|
6ac7e27847 | ||
|
|
4ed1c5e747 | ||
|
|
bae3bc096f | ||
|
|
9d73683de2 | ||
|
|
f5fec0ab71 | ||
|
|
9909ab10c4 | ||
|
|
65cff01fee | ||
|
|
10190a3012 | ||
|
|
79ab696f4e | ||
|
|
cb603682e4 | ||
|
|
c986a06bf7 | ||
|
|
e2843a6cee | ||
|
|
ea1f239807 | ||
|
|
8d7618146a | ||
|
|
eb9e419bb0 | ||
|
|
f98f71ac26 | ||
|
|
03baaaebcb | ||
|
|
cbca954508 | ||
|
|
22ba6cc406 | ||
|
|
6bd172acb4 | ||
|
|
818ba4416f | ||
|
|
adff12841c | ||
|
|
480c306591 | ||
|
|
cbd1481cb7 | ||
|
|
d1c1871222 | ||
|
|
15a94b8fb0 | ||
|
|
66be54e6a7 | ||
|
|
62c85cc2eb | ||
|
|
1ae05a9ebc | ||
|
|
3457c70f30 | ||
|
|
c1ec9126da | ||
|
|
398da2fac7 | ||
|
|
47f33d6346 | ||
|
|
2cad82d537 | ||
|
|
8d06d78537 | ||
|
|
b61be000de | ||
|
|
9ca6de6e7a | ||
|
|
5c03c25e96 | ||
|
|
23843163ad | ||
|
|
8b07fbbedc | ||
|
|
5bf55220d4 | ||
|
|
0e1de3d6e8 | ||
|
|
3a7ba3675b | ||
|
|
5c0deb5bdb | ||
|
|
50dcbc2b01 | ||
|
|
90d72f7843 | ||
|
|
90ee59c70d | ||
|
|
59eda11c1b | ||
|
|
78684a424f | ||
|
|
4a936dda6e | ||
|
|
094d4b99a4 | ||
|
|
382268308e | ||
|
|
97315d27b9 | ||
|
|
26ae573b72 | ||
|
|
803c44d783 | ||
|
|
90f3f1037a | ||
|
|
ce39a751d9 | ||
|
|
ceebf7d32d | ||
|
|
8da59bf0ac | ||
|
|
d25979502a | ||
|
|
549bc3bf9f | ||
|
|
22b2f325e0 | ||
|
|
6615d1b90c | ||
|
|
8f045c4254 | ||
|
|
a4434349e5 | ||
|
|
01272be25f | ||
|
|
be0beed403 | ||
|
|
453d2abed5 | ||
|
|
57e9ccbef0 | ||
|
|
989124772b | ||
|
|
72400e4b91 | ||
|
|
900cba29a7 | ||
|
|
f177a65c1e | ||
|
|
b6baf9016d | ||
|
|
86ac6e8044 | ||
|
|
66d8fb95db | ||
|
|
22da8d9ba2 | ||
|
|
819e9c1b16 | ||
|
|
dd4b2e8bc2 | ||
|
|
e2f7ac2017 | ||
|
|
31b5cf6926 | ||
|
|
25fe3035c2 | ||
|
|
0cf56823cd | ||
|
|
c2f36968c3 | ||
|
|
a508c7f53e | ||
|
|
48de68031d | ||
|
|
81ef85af82 | ||
|
|
16b65d7dbe | ||
|
|
5a98e6511b | ||
|
|
2418f08e22 | ||
|
|
80a821bc20 | ||
|
|
378f78bd87 | ||
|
|
f010591e19 | ||
|
|
5274abdcca | ||
|
|
48f9e8c5c8 | ||
|
|
5c02117fde | ||
|
|
bc56a188f8 | ||
|
|
b6df1b22ab | ||
|
|
0fbf2dd5bb | ||
|
|
38c126d11a | ||
|
|
7dff602e5e | ||
|
|
e401f32815 | ||
|
|
12e94b70a7 | ||
|
|
884de3959c | ||
|
|
fe12325e50 | ||
|
|
bea86f3f79 | ||
|
|
7a5f3667da | ||
|
|
0813788c98 | ||
|
|
b1ca73e7f0 | ||
|
|
ebf9e9b1a3 | ||
|
|
b0abab7a1d | ||
|
|
995bb493df | ||
|
|
1b2375fc84 | ||
|
|
b7315bcb5a | ||
|
|
2c9ebdaa69 | ||
|
|
fbd9e5b4d7 | ||
|
|
b9a3425b6d | ||
|
|
d4742c611b | ||
|
|
c645a590aa | ||
|
|
275a7fe63f | ||
|
|
0ff16d8312 | ||
|
|
1cb31d6c7e | ||
|
|
8a6eb553df | ||
|
|
946af8b9ee | ||
|
|
098a1f647e | ||
|
|
c9681dc430 | ||
|
|
ff0b8b2d53 | ||
|
|
75f520d43a | ||
|
|
65209748ba | ||
|
|
cd604ef07b | ||
|
|
51da8bc531 | ||
|
|
2374ba12bd | ||
|
|
0a75aaec25 | ||
|
|
a8c286ae83 | ||
|
|
9cbdfc7764 | ||
|
|
cb1423436f | ||
|
|
2fb391795a | ||
|
|
9ec20f2d8f | ||
|
|
9323ca5136 | ||
|
|
978e6072ab | ||
|
|
d0e3869d54 | ||
|
|
15c7e956f2 | ||
|
|
ed61545ec7 | ||
|
|
1aac5becdc | ||
|
|
4bca26debc | ||
|
|
d6eecd1637 | ||
|
|
00e7620d2e | ||
|
|
d657283aad | ||
|
|
70a879ea94 | ||
|
|
591ee22472 | ||
|
|
956b05d39d | ||
|
|
5bdad6d4cb | ||
|
|
29a6ac6ed7 | ||
|
|
8f7f091e9b | ||
|
|
63dfe7628b | ||
|
|
ce507e7851 | ||
|
|
a9cd76173e | ||
|
|
44f8ffb434 | ||
|
|
28c395f111 | ||
|
|
39df68c38e | ||
|
|
b33ca9225a | ||
|
|
bd137afecf | ||
|
|
a3b9bed8c2 | ||
|
|
0a157739bc | ||
|
|
c46b08ad5e | ||
|
|
754e6193a4 | ||
|
|
56b49fe2dd | ||
|
|
36a7215f94 | ||
|
|
702247affd | ||
|
|
e752b1f8e5 | ||
|
|
920eee36e3 | ||
|
|
a5070a5d98 | ||
|
|
ccb5aefa61 | ||
|
|
378b08e37c | ||
|
|
5763483c91 | ||
|
|
559f8ee095 | ||
|
|
4382ef360c | ||
|
|
0cb576cf1a | ||
|
|
dee4d047b4 | ||
|
|
2520cc7bb9 | ||
|
|
192c31efe0 | ||
|
|
a1d8ebc2d2 | ||
|
|
14a9de2147 | ||
|
|
a760a9a3f1 | ||
|
|
efd14e1c7a | ||
|
|
6019c46cee | ||
|
|
ec6acfbc1c | ||
|
|
e925dbaad6 | ||
|
|
8321adf0bc | ||
|
|
e1c5e9e874 | ||
|
|
0aec581714 | ||
|
|
b77b8623d1 | ||
|
|
5ab986d6d9 | ||
|
|
09b8332236 | ||
|
|
d05345abc0 | ||
|
|
804c369f0d | ||
|
|
8f67fc886c | ||
|
|
ca3b1a9b30 | ||
|
|
63c1dbb3ed | ||
|
|
9a424dfe29 | ||
|
|
0a6eb596bb | ||
|
|
34452376db | ||
|
|
53a90a59c5 | ||
|
|
ec491ebd83 | ||
|
|
cdc41c305e | ||
|
|
6cf67b399c | ||
|
|
dc3c56bccc | ||
|
|
4657f2039a | ||
|
|
b0082fbd0d | ||
|
|
ede1b4df11 | ||
|
|
d78a3d1f8a | ||
|
|
6152555f26 | ||
|
|
bbad505044 | ||
|
|
11c5429184 | ||
|
|
4e865c4525 | ||
|
|
2fa785a539 | ||
|
|
296a8449c9 | ||
|
|
f20213ff10 | ||
|
|
8a7067ee24 | ||
|
|
a3024e9f5a | ||
|
|
86e651f5e7 | ||
|
|
409710b2b1 | ||
|
|
14a406a276 | ||
|
|
28a283b1c1 | ||
|
|
ccf298a148 | ||
|
|
914b600af4 | ||
|
|
4944994667 | ||
|
|
3a487578a5 | ||
|
|
39eeccb16a | ||
|
|
32acd3b9d1 | ||
|
|
c57baae477 | ||
|
|
4a6ed633b9 | ||
|
|
2ab1845547 | ||
|
|
f4d2e1f20c | ||
|
|
81dca1f690 | ||
|
|
2b331fd68f | ||
|
|
cc77e4dba7 | ||
|
|
620a13a308 | ||
|
|
42d4ba09d7 | ||
|
|
ca071fa52f | ||
|
|
d38e5dec7b | ||
|
|
e5db38f7c0 | ||
|
|
68a29730c0 | ||
|
|
5c33c4d341 | ||
|
|
a1d6270089 | ||
|
|
1968175b00 | ||
|
|
cf1e2aeeba | ||
|
|
199b0b9f57 | ||
|
|
87a0daa465 | ||
|
|
c2af90b58f | ||
|
|
62f01453af | ||
|
|
375d6ee331 | ||
|
|
222ca2915b | ||
|
|
5ca848f9fe | ||
|
|
68d878ff6b | ||
|
|
782a7b418a | ||
|
|
724d7854ad | ||
|
|
f8e64d17e8 | ||
|
|
3b40799000 | ||
|
|
709964ca92 | ||
|
|
d2cdedc610 | ||
|
|
b7d0730343 | ||
|
|
30b4ea7d49 | ||
|
|
546dadbd06 | ||
|
|
76edf902de | ||
|
|
7c4caef5e7 | ||
|
|
068024134c | ||
|
|
538ab57b6e | ||
|
|
fd6d9148f3 | ||
|
|
f033f59755 | ||
|
|
7168c6dd69 | ||
|
|
f121d41c2f | ||
|
|
e56e774eac | ||
|
|
6d9b0918a3 | ||
|
|
d445418611 | ||
|
|
6d15a51c9a | ||
|
|
42a615efdd | ||
|
|
54cd1f79a6 | ||
|
|
8ed8f46374 | ||
|
|
dd3a2996a4 | ||
|
|
bf1f90a96a | ||
|
|
2d6200231a | ||
|
|
032cd23304 | ||
|
|
de4c0a9e1c | ||
|
|
e33f8e8920 | ||
|
|
22615c7921 | ||
|
|
9d8809c580 | ||
|
|
96b92c98ff | ||
|
|
07939acecd | ||
|
|
30abcb2563 | ||
|
|
35ce8f2b8d | ||
|
|
d6453eab38 | ||
|
|
e0964d07ea | ||
|
|
fc359f1956 | ||
|
|
322261d65d | ||
|
|
bd1163c439 | ||
|
|
e203a8c706 | ||
|
|
6a1ba2af74 | ||
|
|
22569e64df | ||
|
|
dcafe41cde | ||
|
|
dd2adc08a3 | ||
|
|
d7534d2673 | ||
|
|
0a59920025 | ||
|
|
77602a8de4 | ||
|
|
65b3fde97c | ||
|
|
b690148452 | ||
|
|
4c7bc9ada6 | ||
|
|
432651489f | ||
|
|
82aa232a37 | ||
|
|
19b13bf7a7 | ||
|
|
f7e25d807d | ||
|
|
cf05316b95 | ||
|
|
001c4386b5 | ||
|
|
572527f8cb | ||
|
|
b4252beda6 | ||
|
|
d82ee16e0c | ||
|
|
e4d65c07ce | ||
|
|
86fcb78cc3 | ||
|
|
5beb422d75 | ||
|
|
53679879ca | ||
|
|
a8ad766182 | ||
|
|
cbb2d30f79 | ||
|
|
c5e00bcec6 | ||
|
|
51535d374d | ||
|
|
1e057e6c35 | ||
|
|
b23e8ab862 | ||
|
|
0f7f13dfb2 | ||
|
|
aa19ccda1d | ||
|
|
cd0129e780 | ||
|
|
506c9023e6 | ||
|
|
d47c25ea4c | ||
|
|
010651073c | ||
|
|
76364e3799 | ||
|
|
f9fd0a0203 | ||
|
|
edbff83fd6 | ||
|
|
8dfbde5d16 | ||
|
|
888991f8c1 | ||
|
|
ece03922d6 | ||
|
|
47bb827e6e | ||
|
|
a56003d847 | ||
|
|
61022c398c | ||
|
|
00bd8cc525 | ||
|
|
cf6a232aef | ||
|
|
59d1a45ef0 | ||
|
|
0b5f9fcb48 | ||
|
|
f713ffd6a1 | ||
|
|
22ba9d81d4 | ||
|
|
309bc98d7f | ||
|
|
9b8646a583 | ||
|
|
48d1b87ab8 | ||
|
|
c5f849d846 | ||
|
|
31fbb6e4f5 | ||
|
|
4d9a88e999 | ||
|
|
252e8484a8 | ||
|
|
1b89203932 | ||
|
|
2263c6a618 | ||
|
|
673cb3ee21 | ||
|
|
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 | ||
|
|
15194e6b55 |
+13
@@ -0,0 +1,13 @@
|
||||
*.o
|
||||
*.py[co]
|
||||
*.class
|
||||
*.jar
|
||||
*~
|
||||
*.so
|
||||
|
||||
/uwsgi
|
||||
/uwsgibuild.*
|
||||
|
||||
/t/ring/target
|
||||
|
||||
core/dot_h.c
|
||||
@@ -1,55 +0,0 @@
|
||||
d3850b52334a91d005b0fe45e1e38ba0997a1fb8 no_server mode
|
||||
2d8a617299153ed2efa6ecee7920e9d36c29e0f5 0.9.5beta1
|
||||
04722a2d0121080d14a64df097c278860db5ce8a 0.9.5rc1
|
||||
820cc64ab296dc4589ef72a33a6b804c22a0430c 0.9.5rc2
|
||||
b0db39cfad5ac6d4f00bbb3f9c57cf73206e2afb 0.9.5
|
||||
9f8b98ad1dfa51b86b13fa624c65f73523075fc4 0.9.5.1
|
||||
a83e7a482e65befcfbb0e24af8cd5d15190acdd7 0.9.6-rc1
|
||||
b8f67c6cd0d62f864db9b2b265b4e260ad7d873c 0.9.6-rc2
|
||||
35918dd4b3771158b2b57410613ef029e08bbd60 0.9.6
|
||||
5f25d1f97f9dde3e391a668c1c610a52a5db8244 0.9.6.1
|
||||
ef31fc61ac48018c464f28ebfdf865b96bf83f18 0.9.6.2
|
||||
9e100c1f085034396cec586f0c76ad3f9800d1a5 0.9.7-beta1
|
||||
ff4111eb8f55b958ec91c70163e10f3372a9b94d 0.9.7-rc1
|
||||
eb8aff2926230bb114fb90f67203440a2c534bf1 0.9.7-rc2
|
||||
311eef929ec8fd0a5dc8c16531afb7bb42d36d01 0.9.7-rc3
|
||||
4b50c04e414f1d9ab8b0b5910aba83d09ac21abb 0.9.7
|
||||
d9b9b540f7dce8cb05d2e61ca8b4d75f2ea25f62 0.9.7.1
|
||||
d9b9b540f7dce8cb05d2e61ca8b4d75f2ea25f62 0.9.7.1
|
||||
0000000000000000000000000000000000000000 0.9.7.1
|
||||
0000000000000000000000000000000000000000 0.9.7.1
|
||||
486e7760bcbc2191ddb9b4aee6c98dbd5fc4c754 0.9.7.1
|
||||
a5f13497b39269621f8f1e56e14d2cc141452e79 0.9.7.2
|
||||
d1e57707f6317f134fea7d12f6588d8690f74f3f 0.9.8-rc1
|
||||
e91bc724325e14c13b8f548c0b6a315c48a1c32a 0.9.8-rc2
|
||||
4fb424d52f226a0a087fea89709f5eb540e03f25 0.9.8-rc3
|
||||
0f1f3924ee5309a9990d9af1ffc68846e3dfb31b 0.9.8-rc4
|
||||
42efe1f329005618c8b44f901979ebcecd5216fb 0.9.8
|
||||
fd8477b6348faf16588106055ca59df1c488f76a 0.9.8.1
|
||||
7169ef1d68d3dab4737bcc3f9e082839e5a06cc1 0.9.8.2
|
||||
f4d3c4dcd7a63e21fcc9d8d567374c69935178bd 0.9.8.3
|
||||
6945ee03c7ea95eb19217ef1e1fb17d9ae26adbc 0.9.9-beta1
|
||||
fb168b0b86169219aa9b8e40f0caa6297cf34dbc 0.9.9-rc1
|
||||
6aa667612019fcff8e68af9469f73aff6fa378a8 0.9.9-rc2
|
||||
376ffd8f190623e5e2521fe9fa64bf03c31e71be 0.9.9
|
||||
7048ae11cfc8453c6bb599af3c0dfacd7ebae43c 1.0-rc1
|
||||
7a4e021ea7ba2953e474326612c3bb82d6817f0e 1.0-rc2
|
||||
4e4e781ef89ac33e71a7e92741d54549240ed156 1.0-rc3
|
||||
24f7e260ea345c2cd73e2fd8191dddbd1b039062 1.0-rc4
|
||||
043ba93dd69cf6924e98db3cb9a8759cce997367 1.0-rc5
|
||||
a2b8f25fd17ed7424d1470a287d0b3144d2a12c8 1.0-rc6
|
||||
a3ca2e8e27c5c12c44ba0cacb4de4cb51377f184 1.0-rc7
|
||||
365e2514cc19f0366365318f12a1d63113b02924 1.0-rc8
|
||||
5da6fe43a8c29056bc9442c684615e11a3699795 1.0-rc9
|
||||
af490b8c30f83bc5fb6f3837a760981474647755 1.0-rc10
|
||||
3c70927335856883283fe4db448e092cecc0ccdb 1.0
|
||||
8fe7bb792399cb6e6a24e20551f4149409660363 1.0.1
|
||||
1d1702789710ec1c20613d2490b14f70756e67ec 1.1-rc1
|
||||
901f0cb5de36ea907b26d64ac9ce54605ec531d2 1.1-rc2
|
||||
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
|
||||
+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,10 @@ Lukas Lalinsky
|
||||
Steven Fernandez
|
||||
Łukasz Mierzwa
|
||||
Roy Marples
|
||||
Aarni Koskela
|
||||
C Anthony Risinger
|
||||
Stephen Pierce
|
||||
Mingli Yuan
|
||||
Natanael Copa
|
||||
Roberto Leandrini
|
||||
Ryan Petrello
|
||||
|
||||
@@ -1,636 +0,0 @@
|
||||
*** current ***
|
||||
|
||||
* 1.3
|
||||
|
||||
- python tracebacker
|
||||
- user-governed harakiri
|
||||
- simplified external plugin development
|
||||
- Linux namespace mountpoint improvements
|
||||
- secured subscription system
|
||||
- merged routers codebase (fastrouter, http, rawrouter)
|
||||
- https support in the http router
|
||||
- config report at the end of uWSGI build process
|
||||
- support for keepalive in the http router
|
||||
- improved subscription system (multicast and unix socket)
|
||||
- custom options
|
||||
- graceful reloads on shared sockets
|
||||
- configurable log-master buffer size
|
||||
- extreme-optimizations for the stats subsystem
|
||||
|
||||
|
||||
*** april 2012 ***
|
||||
|
||||
* 1.2 [20120430]
|
||||
|
||||
- PyPy support
|
||||
- Improved gevent support with threads
|
||||
- Python auto-reload subsystem
|
||||
- added --spooler-max-tasks
|
||||
- pthread robust mutexes support in Linux and Solaris
|
||||
- posix semaphores support in FreeBSD9
|
||||
- thread-safe ctime() reporting
|
||||
- interval support in cron subsystem
|
||||
- improved syslog support
|
||||
- better management of disconnected clients
|
||||
- static files serving improvements
|
||||
- another set of multithreading optimizations
|
||||
- minor fixes in the Rack plugin
|
||||
- Upstart socket-activation support
|
||||
|
||||
|
||||
*** 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
|
||||
@@ -1,3 +1,19 @@
|
||||
----------------------------------------------------------------------
|
||||
|
||||
LINKING EXCEPTION
|
||||
|
||||
In addition to the permissions in the GNU General Public License,
|
||||
the authors give you unlimited permission to link the compiled
|
||||
version of this library into combinations with other programs,
|
||||
and to distribute those combinations without any restriction
|
||||
coming from the use of this file. (The General Public License
|
||||
restrictions do apply in other respects; for example, they cover
|
||||
modification of the file, and distribution when not linked into
|
||||
a combined executable.)
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
PYTHON := python
|
||||
|
||||
all:
|
||||
python uwsgiconfig.py --build
|
||||
$(PYTHON) uwsgiconfig.py --build $(PROFILE)
|
||||
|
||||
clean:
|
||||
python uwsgiconfig.py --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/
|
||||
|
||||
+106
-39
@@ -1,3 +1,38 @@
|
||||
/*
|
||||
|
||||
*** mod_proxy_uwsgi ***
|
||||
|
||||
Copyright 2009-2013 Unbit S.a.s. <info@unbit.it>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
|
||||
To build:
|
||||
|
||||
apxs2 -i -c mod_proxy_uwsgi.c
|
||||
|
||||
To use:
|
||||
|
||||
LoadModule proxy_uwsgi_module /usr/lib/apache2/modules/mod_proxy_uwsgi.so
|
||||
ProxyPass / uwsgi://127.0.0.1:3031/
|
||||
|
||||
Docs:
|
||||
|
||||
http://uwsgi-docs.readthedocs.org/en/latest/Apache.html#mod-proxy-uwsgi
|
||||
|
||||
*/
|
||||
#define APR_WANT_MEMFUNC
|
||||
#define APR_WANT_STRFUNC
|
||||
#include "apr_strings.h"
|
||||
@@ -101,10 +136,26 @@ static int uwsgi_send_headers(request_rec *r, proxy_conn_rec *conn)
|
||||
ap_add_common_vars(r);
|
||||
ap_add_cgi_vars(r);
|
||||
|
||||
// this is not a security problem (in Linux) as uWSGI destroy the env memory area readable in /proc
|
||||
// and generally if you host untrusted apps in your server and allows them to read others uid /proc/<pid>
|
||||
// files you have higher problems...
|
||||
const char *auth = apr_table_get(r->headers_in, "Authorization");
|
||||
if (auth) {
|
||||
apr_table_setn(r->subprocess_env, "HTTP_AUTHORIZATION", auth);
|
||||
}
|
||||
|
||||
const char *script_name = apr_table_get(r->subprocess_env, "SCRIPT_NAME");
|
||||
const char *path_info = apr_table_get(r->subprocess_env, "PATH_INFO");
|
||||
|
||||
if (script_name && path_info) {
|
||||
apr_table_set(r->subprocess_env, "SCRIPT_NAME", apr_pstrndup(r->pool, script_name, strlen(script_name)-strlen(path_info)));
|
||||
if (strcmp(path_info, "/")) {
|
||||
apr_table_set(r->subprocess_env, "SCRIPT_NAME", apr_pstrndup(r->pool, script_name, strlen(script_name)-strlen(path_info)));
|
||||
}
|
||||
else {
|
||||
if (!strcmp(script_name, "/")) {
|
||||
apr_table_set(r->subprocess_env, "SCRIPT_NAME", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
env_table = apr_table_elts(r->subprocess_env);
|
||||
@@ -135,7 +186,7 @@ static int uwsgi_send_headers(request_rec *r, proxy_conn_rec *conn)
|
||||
buf[0] = 0;
|
||||
buf[1] = (uint8_t) (pktsize & 0xff);
|
||||
buf[2] = (uint8_t) ((pktsize >> 8) & 0xff);
|
||||
buf[0] = 0;
|
||||
buf[3] = 0;
|
||||
|
||||
return uwsgi_send(conn, buf, headerlen, r);
|
||||
}
|
||||
@@ -166,27 +217,44 @@ static int uwsgi_send_body(request_rec *r, proxy_conn_rec *conn)
|
||||
return OK;
|
||||
}
|
||||
|
||||
static
|
||||
apr_status_t ap_proxygetline(apr_bucket_brigade *bb, char *s, int n, request_rec *r,
|
||||
int fold, int *writen)
|
||||
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
|
||||
static request_rec *ap_proxy_make_fake_req(conn_rec *c, request_rec *r)
|
||||
{
|
||||
char *tmp_s = s;
|
||||
apr_status_t rv;
|
||||
apr_size_t len;
|
||||
apr_pool_t *pool;
|
||||
request_rec *rp;
|
||||
|
||||
rv = ap_rgetline(&tmp_s, n, &len, r, fold, bb);
|
||||
apr_brigade_cleanup(bb);
|
||||
apr_pool_create(&pool, c->pool);
|
||||
|
||||
if (rv == APR_SUCCESS) {
|
||||
*writen = (int) len;
|
||||
} else if (rv == APR_ENOSPC) {
|
||||
*writen = n;
|
||||
} else {
|
||||
*writen = -1;
|
||||
}
|
||||
rp = apr_pcalloc(pool, sizeof(*r));
|
||||
|
||||
return rv;
|
||||
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)
|
||||
{
|
||||
@@ -207,11 +275,7 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_
|
||||
|
||||
apr_bucket_brigade *bb = apr_brigade_create(r->pool, c->bucket_alloc);
|
||||
|
||||
|
||||
rc = ap_proxygetline(bb, buffer, sizeof(buffer), rp, 0, &len);
|
||||
if (len == 0) {
|
||||
rc = ap_proxygetline(bb, buffer, sizeof(buffer), rp, 0, &len);
|
||||
}
|
||||
len = ap_getline(buffer, sizeof(buffer), rp, 1);
|
||||
|
||||
if (len <= 0) {
|
||||
// oops
|
||||
@@ -220,25 +284,11 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_
|
||||
|
||||
backend->worker->s->read += len;
|
||||
|
||||
if (!apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
|
||||
if (!apr_date_checkmask(buffer, "HTTP/#.# ###*") || len >= sizeof(buffer)-1) {
|
||||
// oops
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
int major, minor;
|
||||
|
||||
major = buffer[5] - '0';
|
||||
minor = buffer[7] - '0';
|
||||
|
||||
/* If not an HTTP/1 message or
|
||||
* if the status line was > 8192 bytes
|
||||
*/
|
||||
if ((major != 1) || (len >= sizeof(buffer)-1)) {
|
||||
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
|
||||
apr_pstrcat(r->pool, "Corrupt status line returned by remote "
|
||||
"server: ", buffer, NULL));
|
||||
}
|
||||
|
||||
char keepchar = buffer[12];
|
||||
buffer[12] = '\0';
|
||||
r->status = atoi(&buffer[9]);
|
||||
@@ -326,7 +376,24 @@ static int uwsgi_handler(request_rec *r, proxy_worker *worker,
|
||||
}
|
||||
|
||||
// ADD PATH_INFO
|
||||
apr_table_add(r->subprocess_env, "PATH_INFO", url+strlen(worker->name));
|
||||
#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 */
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
*** uWSGI/mod_uwsgi ***
|
||||
|
||||
Copyright 2009-2012 Unbit S.a.s. <info@unbit.it>
|
||||
Copyright 2009-2013 Unbit S.a.s. <info@unbit.it>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -7,7 +7,7 @@ filename = sys.argv[1]
|
||||
size = os.path.getsize(filename)
|
||||
|
||||
f = open(filename, 'r')
|
||||
print(f.read())
|
||||
os.write(1, f.read())
|
||||
f.close()
|
||||
|
||||
print(struct.pack("<Q", size))
|
||||
os.write(1, (struct.pack("<Q", size)))
|
||||
|
||||
@@ -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,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = python,gevent,psgi,lua,php,rack,jvm,jwsgi,ring,mono,transformation_toupper,coroae,v8,cgi,xslt,webdav,ssi,ldap,gccgo,rados
|
||||
inherit = base
|
||||
+2
-14
@@ -1,24 +1,12 @@
|
||||
[uwsgi]
|
||||
xml = auto
|
||||
ini = true
|
||||
yaml = true
|
||||
json = auto
|
||||
sqlite3 = auto
|
||||
zeromq = auto
|
||||
snmp = true
|
||||
spooler = true
|
||||
embedded = true
|
||||
ssl = auto
|
||||
udp = true
|
||||
multicast = true
|
||||
threading = true
|
||||
sendfile = true
|
||||
minterpreters = true
|
||||
async = true
|
||||
ldap = auto
|
||||
pcre = auto
|
||||
routing = auto
|
||||
ipv6 = false
|
||||
matheval = auto
|
||||
debug = false
|
||||
unbit = false
|
||||
xml_implementation = libxml2
|
||||
@@ -29,7 +17,7 @@ plugins =
|
||||
bin_name = uwsgi
|
||||
append_version =
|
||||
plugin_dir = .
|
||||
embedded_plugins = %(main_plugin)s, ping, cache, nagios, rrdtool, carbon, rpc, corerouter, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool, redislog, router_rewrite, router_http
|
||||
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, spooler, cheaper_busyness, symcall, transformation_tofile, transformation_gzip, transformation_chunked, transformation_offload, router_memcached, router_redis, router_hash, router_expires, router_metrics, transformation_template, stats_pusher_socket
|
||||
as_shared_library = false
|
||||
|
||||
locking = auto
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = psgi,coroae
|
||||
inherit = base
|
||||
@@ -0,0 +1,4 @@
|
||||
[uwsgi]
|
||||
# pypy,go
|
||||
main_plugin = erlang,psgi,rack,lua,python,gevent,php,cgi,pyerl,glusterfs,pty,xslt,msgpack,geoip,v8,pam,ldap,mono,jvm,ring,jwsgi
|
||||
inherit = base
|
||||
@@ -1,3 +1,4 @@
|
||||
[uwsgi]
|
||||
main_plugin = python
|
||||
main_plugin = python,gevent
|
||||
inherit = base
|
||||
debug = false
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
[uwsgi]
|
||||
main_plugin = glusterfs
|
||||
inherit = base
|
||||
matheval = false
|
||||
@@ -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,34 +1,23 @@
|
||||
[uwsgi]
|
||||
xml = false
|
||||
ini = true
|
||||
yaml = false
|
||||
json = false
|
||||
sqlite3 = false
|
||||
zeromq = false
|
||||
snmp = 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
|
||||
ssl = false
|
||||
pcre = false
|
||||
routing = false
|
||||
matheval = false
|
||||
debug = false
|
||||
unbit = false
|
||||
xml_implementation = libxml2
|
||||
yaml_implementation = auto
|
||||
xml_implementation = none
|
||||
yaml_implementation = none
|
||||
malloc_implementation = libc
|
||||
extras =
|
||||
extras =
|
||||
plugins =
|
||||
bin_name = uwsgi
|
||||
append_version =
|
||||
plugin_dir = .
|
||||
embedded_plugins =
|
||||
embedded_plugins = %(main_plugin)s
|
||||
as_shared_library = false
|
||||
|
||||
locking = auto
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = mono
|
||||
inherit = base
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin =
|
||||
inherit = base
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = psgi
|
||||
inherit = minimal
|
||||
@@ -0,0 +1,32 @@
|
||||
[uwsgi]
|
||||
xml = true
|
||||
yaml = true
|
||||
json = true
|
||||
zeromq = true
|
||||
ssl = 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 =
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = python
|
||||
inherit = minimal
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = pypy
|
||||
inherit = minimal
|
||||
@@ -1,30 +0,0 @@
|
||||
[uwsgi]
|
||||
xml = true
|
||||
ini = true
|
||||
snmp = true
|
||||
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,29 +0,0 @@
|
||||
[uwsgi]
|
||||
xml = true
|
||||
ini = true
|
||||
yaml = true
|
||||
snmp = true
|
||||
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 = rados
|
||||
inherit = base
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = rack
|
||||
inherit = minimal
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = jvm,ring
|
||||
inherit = base
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = rack,rbthreads,fiber
|
||||
inherit = base
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = jvm,servlet
|
||||
inherit = base
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin =
|
||||
inherit = base
|
||||
+12
-14
@@ -1,20 +1,9 @@
|
||||
[uwsgi]
|
||||
xml = true
|
||||
ini = true
|
||||
yaml = true
|
||||
json = false
|
||||
sqlite3 = false
|
||||
zeromq = false
|
||||
snmp = false
|
||||
spooler = true
|
||||
embedded = true
|
||||
udp = true
|
||||
multicast = false
|
||||
threading = true
|
||||
sendfile = true
|
||||
minterpreters = true
|
||||
async = true
|
||||
ldap = true
|
||||
ssl = true
|
||||
pcre = true
|
||||
routing = true
|
||||
debug = false
|
||||
@@ -22,13 +11,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
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = v8
|
||||
inherit = base
|
||||
@@ -1 +0,0 @@
|
||||
the uwsgi handler is included in the official Cherokee distribution
|
||||
+4
-1
@@ -1,12 +1,15 @@
|
||||
use POSIX;
|
||||
use IO::Socket::INET;
|
||||
use IO::Socket::INET6;
|
||||
use IO::Socket::UNIX;
|
||||
|
||||
my $s = IO::Socket::INET->new(LocalAddr => '127.0.0.1', LocalPort => 1717, Proto => 'tcp', Reuse => 1);
|
||||
my $s2 = IO::Socket::INET->new(LocalAddr => '127.0.0.1', LocalPort => 3022, Proto => 'tcp', Reuse => 1);
|
||||
my $s3 = IO::Socket::INET6->new(LocalAddr => '::', LocalPort => 3017, Proto => 'tcp', Reuse => 1);
|
||||
my $s4 = IO::Socket::UNIX->new(Local => '/tmp/u.sock', Listen => 1);
|
||||
|
||||
dup2($s->fileno, 17);
|
||||
dup2($s2->fileno, 22);
|
||||
dup2($s3->fileno, 30);
|
||||
exec './uwsgi','-M', '--socket','fd://17', '--http-socket','fd://22', '--socket','fd://30';
|
||||
dup2($s4->fileno, 0);
|
||||
exec './uwsgi','-M', '--socket','fd://17', '--http-socket','fd://22', '--socket','fd://30','--stats',':5001';
|
||||
|
||||
@@ -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,61 @@
|
||||
"""
|
||||
Greenlets support
|
||||
|
||||
simply --pypy-exec this file to enable PyPy's greenlet mode
|
||||
|
||||
Example:
|
||||
|
||||
uwsgi --http-socket :9090 --pypy-home /opt/pypy --pypy-wsgi werkzeug.testapp:test_app --pypy-exec contrib/pypy/uwsgi_pypy_greenlets.py --async 8
|
||||
"""
|
||||
|
||||
import greenlet
|
||||
|
||||
uwsgi_pypy_greenlets = {}
|
||||
|
||||
def uwsgi_pypy_greenlet_wrapper():
|
||||
lib.async_schedule_to_req_green()
|
||||
|
||||
@ffi.callback("void()")
|
||||
def uwsgi_pypy_greenlet_schedule():
|
||||
id = lib.uwsgi.wsgi_req.async_id
|
||||
modifier1 = lib.uwsgi.wsgi_req.uh.modifier1;
|
||||
|
||||
# generate a new greenlet
|
||||
if not lib.uwsgi.wsgi_req.suspended:
|
||||
uwsgi_pypy_greenlets[id] = greenlet.greenlet(uwsgi_pypy_greenlet_wrapper)
|
||||
lib.uwsgi.wsgi_req.suspended = 1
|
||||
|
||||
# this is called in the main stack
|
||||
if lib.uwsgi.p[modifier1].suspend:
|
||||
lib.uwsgi.p[modifier1].suspend(ffi.NULL)
|
||||
|
||||
# let's switch
|
||||
uwsgi_pypy_greenlets[id].switch()
|
||||
|
||||
# back to the main stack
|
||||
if lib.uwsgi.p[modifier1].resume:
|
||||
lib.uwsgi.p[modifier1].resume(ffi.NULL)
|
||||
|
||||
@ffi.callback("void(struct wsgi_request *)")
|
||||
def uwsgi_pypy_greenlet_switch(wsgi_req):
|
||||
id = wsgi_req.async_id
|
||||
modifier1 = wsgi_req.uh.modifier1;
|
||||
|
||||
# this is called in the current greenlet
|
||||
if lib.uwsgi.p[modifier1].suspend:
|
||||
lib.uwsgi.p[modifier1].suspend(wsgi_req)
|
||||
|
||||
uwsgi_pypy_main_greenlet.switch()
|
||||
|
||||
# back to the greenlet
|
||||
if lib.uwsgi.p[modifier1].resume:
|
||||
lib.uwsgi.p[modifier1].resume(wsgi_req)
|
||||
|
||||
# update current running greenlet
|
||||
lib.uwsgi.wsgi_req = wsgi_req
|
||||
|
||||
if lib.uwsgi.async <= 1:
|
||||
raise Exception("pypy greenlets require async mode !!!")
|
||||
lib.uwsgi.schedule_to_main = uwsgi_pypy_greenlet_switch
|
||||
lib.uwsgi.schedule_to_req = uwsgi_pypy_greenlet_schedule
|
||||
uwsgi_pypy_main_greenlet = greenlet.getcurrent()
|
||||
@@ -0,0 +1,15 @@
|
||||
# uWSGI - Emperor
|
||||
#
|
||||
|
||||
description "uWSGI Emperor"
|
||||
|
||||
start on runlevel [2345]
|
||||
stop on runlevel [!2345]
|
||||
|
||||
respawn
|
||||
|
||||
env LOGTO=/tmp/uwsgi.log
|
||||
env BINPATH=/home/foo/uwsgi/uwsgi
|
||||
env VASSALS=/etc/uwsgi
|
||||
|
||||
exec $BINPATH --emperor $VASSALS --logto $LOGTO
|
||||
@@ -11,7 +11,6 @@ respawn
|
||||
env LOGTO=/tmp/uwsgi.log
|
||||
env BINPATH=/home/foo/uwsgi/uwsgi
|
||||
|
||||
# --no-orphans avoid workers without master
|
||||
# --die-on-term could be a good idea
|
||||
exec $BINPATH --no-orphans --socket :3033 --uid 1001 --gid 1001 --limit-as 256 -w simple_app --logto $LOGTO -M -p 4
|
||||
# --die-on-term is upstart friendly
|
||||
exec $BINPATH --die-on-term --socket :3033 --uid 1001 --gid 1001 --limit-as 256 -w simple_app --logto $LOGTO -M -p 4
|
||||
|
||||
|
||||
+470
@@ -0,0 +1,470 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
// simply log an alarm
|
||||
void uwsgi_alarm_init_log(struct uwsgi_alarm_instance *uai) {
|
||||
}
|
||||
|
||||
void uwsgi_alarm_func_log(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
|
||||
if (msg[len-1] != '\n') {
|
||||
if (uai->arg && strlen(uai->arg) > 0) {
|
||||
uwsgi_log_alarm("] %s %.*s\n", uai->arg, len, msg);
|
||||
}
|
||||
else {
|
||||
uwsgi_log_alarm("] %.*s\n", len, msg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (uai->arg && strlen(uai->arg) > 0) {
|
||||
uwsgi_log_alarm("] %s %.*s", uai->arg, len, msg);
|
||||
}
|
||||
else {
|
||||
uwsgi_log_alarm("] %.*s", len, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
uwsgi_register_alarm("log", uwsgi_alarm_init_log, uwsgi_alarm_func_log);
|
||||
}
|
||||
|
||||
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, *ctx = NULL;
|
||||
uwsgi_foreach_token(list, ",", p, ctx) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
free(list);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void uwsgi_alarm_thread_loop(struct uwsgi_thread *ut) {
|
||||
// add uwsgi_alarm_fd;
|
||||
struct uwsgi_alarm_fd *uafd = uwsgi.alarm_fds;
|
||||
while(uafd) {
|
||||
event_queue_add_fd_read(ut->queue, uafd->fd);
|
||||
uafd = uafd->next;
|
||||
}
|
||||
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) {
|
||||
if (interesting_fd == ut->pipe[1]) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
// check for alarm_fd
|
||||
else {
|
||||
uafd = uwsgi.alarm_fds;
|
||||
int fd_read = 0;
|
||||
while(uafd) {
|
||||
if (interesting_fd == uafd->fd) {
|
||||
if (fd_read) goto raise;
|
||||
size_t remains = uafd->buf_len;
|
||||
while(remains) {
|
||||
ssize_t len = read(uafd->fd, uafd->buf + (uafd->buf_len-remains), remains);
|
||||
if (len <= 0) {
|
||||
uwsgi_error("[uwsgi-alarm-fd]/read()");
|
||||
uwsgi_log("[uwsgi-alarm-fd] i will stop monitoring fd %d\n", uafd->fd);
|
||||
event_queue_del_fd(ut->queue, uafd->fd, event_queue_read());
|
||||
break;
|
||||
}
|
||||
remains-=len;
|
||||
}
|
||||
fd_read = 1;
|
||||
raise:
|
||||
uwsgi_alarm_run(uafd->alarm, uafd->msg, uafd->msg_len);
|
||||
}
|
||||
uafd = uafd->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
// map alarm file descriptors
|
||||
usl = uwsgi.alarm_fd_list;
|
||||
while(usl) {
|
||||
char *space0 = strchr(usl->value, ' ');
|
||||
if (!space0) {
|
||||
uwsgi_log("invalid alarm-fd syntax: %s\n", usl->value);
|
||||
exit(1);
|
||||
}
|
||||
*space0 = 0;
|
||||
size_t buf_len = 1;
|
||||
char *space1 = strchr(space0+1, ' ');
|
||||
if (!space1) {
|
||||
uwsgi_log("invalid alarm-fd syntax: %s\n", usl->value);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char *colon = strchr(space0+1, ':');
|
||||
if (colon) {
|
||||
buf_len = strtoul(colon+1, NULL, 10);
|
||||
*colon = 0;
|
||||
}
|
||||
int fd = atoi(space0+1);
|
||||
uwsgi_add_alarm_fd(fd, usl->value, buf_len, space1+1, strlen(space1+1));
|
||||
*space0 = ' ';
|
||||
*space1 = ' ';
|
||||
if (colon) {
|
||||
*colon = ':';
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
#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()");
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_alarm_fd *uwsgi_add_alarm_fd(int fd, char *alarm, size_t buf_len, char *msg, size_t msg_len) {
|
||||
struct uwsgi_alarm_fd *old_uafd = NULL, *uafd = uwsgi.alarm_fds;
|
||||
struct uwsgi_alarm_instance *uai = uwsgi_alarm_get_instance(alarm);
|
||||
if (!uai) {
|
||||
uwsgi_log("unable to find alarm \"%s\"\n", alarm);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!buf_len) buf_len = 1;
|
||||
|
||||
while(uafd) {
|
||||
// check if an equal alarm has been added
|
||||
if (uafd->fd == fd && uafd->alarm == uai) {
|
||||
return uafd;
|
||||
}
|
||||
old_uafd = uafd;
|
||||
uafd = uafd->next;
|
||||
}
|
||||
|
||||
uafd = uwsgi_calloc(sizeof(struct uwsgi_alarm_fd));
|
||||
uafd->fd = fd;
|
||||
uafd->buf = uwsgi_malloc(buf_len);
|
||||
uafd->buf_len = buf_len;
|
||||
uafd->msg = msg;
|
||||
uafd->msg_len = msg_len;
|
||||
uafd->alarm = uai;
|
||||
|
||||
if (!old_uafd) {
|
||||
uwsgi.alarm_fds = uafd;
|
||||
}
|
||||
else {
|
||||
old_uafd->next = uafd;
|
||||
}
|
||||
|
||||
// avoid the fd to be closed
|
||||
uwsgi_add_safe_fd(fd);
|
||||
uwsgi_log("[uwsgi-alarm] added fd %d\n", fd);
|
||||
|
||||
return uafd;
|
||||
}
|
||||
+286
-218
@@ -1,27 +1,55 @@
|
||||
#include "uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/*
|
||||
|
||||
This is a general purpose async loop engine (it expects a coroutine based approach)
|
||||
|
||||
You can see it as an hub holding the following structures:
|
||||
|
||||
1) the runqueue, cores ready to be run are appended in this list
|
||||
|
||||
2) the fd list, this is a list of monitored file descriptors, a core can wait for all the file descriptors it needs
|
||||
|
||||
3) the timeout value, if set the current core will timeout aftert he specified number of seconds (unless an event cancel it)
|
||||
|
||||
|
||||
IMPORTANT: this is not a callback based engine !!!
|
||||
|
||||
*/
|
||||
|
||||
// this is called whenever a new connection is ready, but there are no cores to handle it
|
||||
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);
|
||||
}
|
||||
if (uwsgi.async_queue < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_add_sockets_to_queue(uwsgi.async_queue, -1);
|
||||
uwsgi_add_sockets_to_queue(uwsgi.async_queue, -1);
|
||||
|
||||
uwsgi.rb_async_timeouts = uwsgi_init_rb_timer();
|
||||
uwsgi.rb_async_timeouts = uwsgi_init_rb_timer();
|
||||
|
||||
uwsgi.async_queue_unused = uwsgi_malloc(sizeof(struct wsgi_request *) * uwsgi.async);
|
||||
// a stack of unused cores
|
||||
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;
|
||||
}
|
||||
// fill it with default values
|
||||
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;
|
||||
// the first available core is the last one
|
||||
uwsgi.async_queue_unused_ptr = uwsgi.async - 1;
|
||||
|
||||
}
|
||||
|
||||
@@ -33,54 +61,54 @@ 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 (u_request == uwsgi.async_runqueue) {
|
||||
uwsgi.async_runqueue = child;
|
||||
}
|
||||
|
||||
if (u_request == uwsgi.async_runqueue_last) {
|
||||
uwsgi.async_runqueue_last = parent;
|
||||
}
|
||||
|
||||
free(u_request);
|
||||
|
||||
uwsgi.async_runqueue_cnt--;
|
||||
free(u_request);
|
||||
}
|
||||
|
||||
void runqueue_push(struct wsgi_request *wsgi_req) {
|
||||
static void runqueue_push(struct wsgi_request *wsgi_req) {
|
||||
|
||||
struct uwsgi_async_request *uar;
|
||||
// do not push the same request in the runqueue
|
||||
struct uwsgi_async_request *uar = uwsgi.async_runqueue;
|
||||
while(uar) {
|
||||
if (uar->wsgi_req == wsgi_req) return;
|
||||
uar = uar->next;
|
||||
}
|
||||
|
||||
uar = uwsgi_malloc(sizeof(struct uwsgi_async_request));
|
||||
uar->prev = NULL;
|
||||
uar->next = NULL;
|
||||
uar->wsgi_req = wsgi_req;
|
||||
|
||||
if (uwsgi.async_runqueue == NULL) {
|
||||
// empty runqueue, create a new one
|
||||
uwsgi.async_runqueue = uwsgi_malloc(sizeof(struct uwsgi_async_request));
|
||||
uwsgi.async_runqueue->next = NULL;
|
||||
uwsgi.async_runqueue->prev = NULL;
|
||||
uwsgi.async_runqueue->wsgi_req = wsgi_req;
|
||||
uwsgi.async_runqueue_last = uwsgi.async_runqueue;
|
||||
}
|
||||
else {
|
||||
uar = uwsgi_malloc(sizeof(struct uwsgi_async_request));
|
||||
uar->prev = uwsgi.async_runqueue_last;
|
||||
uar->next = NULL;
|
||||
uar->wsgi_req = wsgi_req;
|
||||
uwsgi.async_runqueue_last->next = uar;
|
||||
uwsgi.async_runqueue_last = uar;
|
||||
}
|
||||
|
||||
uwsgi.async_runqueue_cnt++;
|
||||
uwsgi.async_runqueue = uar;
|
||||
}
|
||||
else {
|
||||
uar->prev = uwsgi.async_runqueue_last;
|
||||
}
|
||||
|
||||
if (uwsgi.async_runqueue_last) {
|
||||
uwsgi.async_runqueue_last->next = uar;
|
||||
}
|
||||
uwsgi.async_runqueue_last = uar;
|
||||
}
|
||||
|
||||
struct wsgi_request *find_first_available_wsgi_req() {
|
||||
@@ -96,55 +124,62 @@ struct wsgi_request *find_first_available_wsgi_req() {
|
||||
return wsgi_req;
|
||||
}
|
||||
|
||||
void async_expire_timeouts() {
|
||||
void async_reset_request(struct wsgi_request *wsgi_req) {
|
||||
if (wsgi_req->async_timeout) {
|
||||
uwsgi_del_rb_timer(uwsgi.rb_async_timeouts, wsgi_req->async_timeout);
|
||||
free(wsgi_req->async_timeout);
|
||||
wsgi_req->async_timeout = NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_async_fd *uaf = wsgi_req->waiting_fds;
|
||||
while (uaf) {
|
||||
event_queue_del_fd(uwsgi.async_queue, uaf->fd, uaf->event);
|
||||
uwsgi.async_waiting_fd_table[uaf->fd] = NULL;
|
||||
struct uwsgi_async_fd *current_uaf = uaf;
|
||||
uaf = current_uaf->next;
|
||||
free(current_uaf);
|
||||
}
|
||||
|
||||
wsgi_req->waiting_fds = NULL;
|
||||
}
|
||||
|
||||
static void async_expire_timeouts(uint64_t now) {
|
||||
|
||||
struct wsgi_request *wsgi_req;
|
||||
time_t current_time = uwsgi_now();
|
||||
struct uwsgi_async_fd *uaf = NULL, *current_uaf;
|
||||
|
||||
struct uwsgi_rb_timer *urbt;
|
||||
|
||||
for(;;) {
|
||||
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);
|
||||
free(wsgi_req->async_timeout);
|
||||
wsgi_req->async_timeout = NULL;
|
||||
uaf = wsgi_req->waiting_fds;
|
||||
// remove fds from monitoring (no problem modifying the queue here, as the function is executed only when there are no fd ready)
|
||||
while(uaf) {
|
||||
event_queue_del_fd(uwsgi.async_queue, uaf->fd, uaf->event);
|
||||
uwsgi.async_waiting_fd_table[uaf->fd] = NULL;
|
||||
current_uaf = uaf;
|
||||
uaf = current_uaf->next;
|
||||
free(current_uaf);
|
||||
}
|
||||
wsgi_req->waiting_fds = NULL;
|
||||
// put th request in the runqueue
|
||||
// reset teh request
|
||||
async_reset_request(wsgi_req);
|
||||
// push it 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) {
|
||||
// find last slot
|
||||
while (uad) {
|
||||
last_uad = uad;
|
||||
uad = uad->next;
|
||||
}
|
||||
@@ -166,74 +201,175 @@ 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();
|
||||
|
||||
wsgi_req->async_ready_fd = 0;
|
||||
|
||||
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) {
|
||||
|
||||
wsgi_req->async_ready_fd = 0;
|
||||
|
||||
if (timeout > 0 && wsgi_req->async_timeout == NULL) {
|
||||
wsgi_req->async_timeout = uwsgi_add_rb_timer(uwsgi.rb_async_timeouts, uwsgi_now()+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 last 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();
|
||||
|
||||
wsgi_req->async_ready_fd = 0;
|
||||
|
||||
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);
|
||||
#ifdef UWSGI_ROUTING
|
||||
if (uwsgi_apply_routes(uwsgi.wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
goto end;
|
||||
}
|
||||
// a trick to avoid calling routes again
|
||||
uwsgi.wsgi_req->is_routing = 1;
|
||||
#endif
|
||||
if (uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req) <= UWSGI_OK) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (uwsgi.schedule_to_main) {
|
||||
uwsgi.schedule_to_main(uwsgi.wsgi_req);
|
||||
}
|
||||
return;
|
||||
|
||||
end:
|
||||
async_reset_request(uwsgi.wsgi_req);
|
||||
uwsgi_close_request(uwsgi.wsgi_req);
|
||||
uwsgi.wsgi_req->async_status = UWSGI_OK;
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
|
||||
}
|
||||
|
||||
void *async_loop(void *arg1) {
|
||||
void async_schedule_to_req_green(void) {
|
||||
struct wsgi_request *wsgi_req = uwsgi.wsgi_req;
|
||||
#ifdef UWSGI_ROUTING
|
||||
if (uwsgi_apply_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
goto end;
|
||||
}
|
||||
#endif
|
||||
for(;;) {
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req) <= UWSGI_OK) {
|
||||
break;
|
||||
}
|
||||
wsgi_req->switches++;
|
||||
if (uwsgi.schedule_fix) {
|
||||
uwsgi.schedule_fix(wsgi_req);
|
||||
}
|
||||
// switch after each yield
|
||||
uwsgi.schedule_to_main(wsgi_req);
|
||||
}
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
end:
|
||||
#endif
|
||||
// re-set the global state
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
async_reset_request(wsgi_req);
|
||||
uwsgi_close_request(wsgi_req);
|
||||
// re-set the global state (routing could have changed it)
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
wsgi_req->async_status = UWSGI_OK;
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = wsgi_req;
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
struct uwsgi_rb_timer *min_timeout;
|
||||
int timeout;
|
||||
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;
|
||||
struct uwsgi_async_request *current_request = NULL;
|
||||
|
||||
void *events = event_queue_alloc(64);
|
||||
struct uwsgi_socket *uwsgi_sock;
|
||||
|
||||
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);
|
||||
@@ -241,94 +377,75 @@ void *async_loop(void *arg1) {
|
||||
}
|
||||
|
||||
// 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("*** DANGER *** async mode without coroutine/greenthread engine loaded !!!\n");
|
||||
}
|
||||
|
||||
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
|
||||
|
||||
if (uwsgi.async_runqueue_cnt) {
|
||||
now = (uint64_t) uwsgi_now();
|
||||
if (uwsgi.async_runqueue) {
|
||||
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 - uwsgi_now();
|
||||
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);
|
||||
|
||||
// signals are executed in the main stack... in the future we could have dedicated stacks for them
|
||||
if (uwsgi.signal_socket > -1 && (interesting_fd == uwsgi.signal_socket || interesting_fd == uwsgi.my_signal_socket)) {
|
||||
uwsgi_receive_signal(interesting_fd, "worker", uwsgi.mywid);
|
||||
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 = uwsgi_now();
|
||||
if (now > last_now) {
|
||||
uwsgi_log("async queue is full !!!\n");
|
||||
last_now = now;
|
||||
}
|
||||
uwsgi_async_queue_is_full((time_t)now);
|
||||
break;
|
||||
}
|
||||
|
||||
wsgi_req_setup(uwsgi.wsgi_req, uwsgi.wsgi_req->async_id, uwsgi_sock );
|
||||
// on error re-insert the request in the queue
|
||||
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__
|
||||
/* re-set blocking socket */
|
||||
int arg = uwsgi_sock->arg;
|
||||
arg &= (~O_NONBLOCK);
|
||||
if (fcntl(uwsgi.wsgi_req->poll.fd, F_SETFL, arg) < 0) {
|
||||
uwsgi_error("fcntl()");
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wsgi_req_async_recv(uwsgi.wsgi_req)) {
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
@@ -336,6 +453,9 @@ void *async_loop(void *arg1) {
|
||||
break;
|
||||
}
|
||||
|
||||
// by default the core is in UWSGI_AGAIN mode
|
||||
uwsgi.wsgi_req->async_status = UWSGI_AGAIN;
|
||||
// some protocol (like zeromq) do not need additional parsing, just push it in the runqueue
|
||||
if (uwsgi.wsgi_req->do_not_add_to_async_queue) {
|
||||
runqueue_push(uwsgi.wsgi_req);
|
||||
}
|
||||
@@ -352,23 +472,17 @@ 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);
|
||||
free(uwsgi.wsgi_req->async_timeout);
|
||||
uwsgi.wsgi_req->async_timeout = NULL;
|
||||
async_reset_request(uwsgi.wsgi_req);
|
||||
// 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 < 0) {
|
||||
if (proto_parser_status == -1)
|
||||
uwsgi_log("error parsing request\n");
|
||||
uwsgi.async_proto_fd_table[interesting_fd] = NULL;
|
||||
close(interesting_fd);
|
||||
continue;
|
||||
@@ -378,7 +492,7 @@ void *async_loop(void *arg1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// app event
|
||||
// app-registered event
|
||||
uwsgi.wsgi_req = find_wsgi_req_by_fd(interesting_fd);
|
||||
// unknown fd, remove it (for safety)
|
||||
if (uwsgi.wsgi_req == NULL) {
|
||||
@@ -387,22 +501,7 @@ 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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
async_reset_request(uwsgi.wsgi_req);
|
||||
uwsgi.wsgi_req->async_ready_fd = 1;
|
||||
uwsgi.wsgi_req->async_last_ready_fd = interesting_fd;
|
||||
|
||||
@@ -411,59 +510,28 @@ void *async_loop(void *arg1) {
|
||||
}
|
||||
}
|
||||
|
||||
// event queue managed, give cpu to runqueue
|
||||
if (!current_request)
|
||||
current_request = uwsgi.async_runqueue;
|
||||
|
||||
if (uwsgi.async_runqueue_cnt) {
|
||||
// event queue managed, give cpu to runqueue
|
||||
current_request = uwsgi.async_runqueue;
|
||||
|
||||
while(current_request) {
|
||||
|
||||
// current_request could be nulled on error/end of request
|
||||
struct uwsgi_async_request *next_request = current_request->next;
|
||||
|
||||
uwsgi.wsgi_req = current_request->wsgi_req;
|
||||
|
||||
uwsgi.schedule_to_req();
|
||||
uwsgi.wsgi_req->switches++;
|
||||
|
||||
next_async_request = current_request->next;
|
||||
// request ended ?
|
||||
if (uwsgi.wsgi_req->async_status <= UWSGI_OK) {
|
||||
// remove all the monitored fds and timeout
|
||||
while(uwsgi.wsgi_req->waiting_fds) {
|
||||
#ifndef UWSGI_EVENT_USE_PORT
|
||||
event_queue_del_fd(uwsgi.async_queue, uwsgi.wsgi_req->waiting_fds->fd, uwsgi.wsgi_req->waiting_fds->event);
|
||||
#endif
|
||||
tmp_uaf = uwsgi.wsgi_req->waiting_fds;
|
||||
uwsgi.async_waiting_fd_table[tmp_uaf->fd] = NULL;
|
||||
uwsgi.wsgi_req->waiting_fds = tmp_uaf->next;
|
||||
free(tmp_uaf);
|
||||
}
|
||||
uwsgi.wsgi_req->waiting_fds = NULL;
|
||||
if (uwsgi.wsgi_req->async_timeout) {
|
||||
rb_erase(&uwsgi.wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts);
|
||||
free(uwsgi.wsgi_req->async_timeout);
|
||||
uwsgi.wsgi_req->async_timeout = NULL;
|
||||
}
|
||||
|
||||
// remove from the list
|
||||
runqueue_remove(current_request);
|
||||
|
||||
uwsgi_close_request(uwsgi.wsgi_req);
|
||||
|
||||
// push wsgi_request in the unused stack
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
|
||||
|
||||
}
|
||||
else if (uwsgi.wsgi_req->waiting_fds || uwsgi.wsgi_req->async_timeout) {
|
||||
// remove this request from suspended list
|
||||
if (uwsgi.wsgi_req->async_status <= UWSGI_OK ||
|
||||
uwsgi.wsgi_req->waiting_fds || uwsgi.wsgi_req->async_timeout) {
|
||||
// remove from the runqueue
|
||||
runqueue_remove(current_request);
|
||||
}
|
||||
|
||||
current_request = next_async_request;
|
||||
|
||||
current_request = next_request;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
+346
-6
@@ -3,6 +3,9 @@
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_buffer *uwsgi_buffer_new(size_t len) {
|
||||
#ifdef UWSGI_DEBUG_BUFFER
|
||||
uwsgi_log("[uwsgi-buffer] allocating a new buffer of %llu\n", (unsigned long long) len);
|
||||
#endif
|
||||
struct uwsgi_buffer *ub = uwsgi_calloc(sizeof(struct uwsgi_buffer));
|
||||
|
||||
if (len) {
|
||||
@@ -10,7 +13,87 @@ struct uwsgi_buffer *uwsgi_buffer_new(size_t 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) {
|
||||
@@ -19,9 +102,17 @@ int uwsgi_buffer_append(struct uwsgi_buffer *ub, char *buf, size_t len) {
|
||||
|
||||
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("realloc()");
|
||||
uwsgi_error("uwsgi_buffer_append()");
|
||||
return -1;
|
||||
}
|
||||
ub->buf = new_buf;
|
||||
@@ -33,28 +124,234 @@ int uwsgi_buffer_append(struct uwsgi_buffer *ub, char *buf, size_t len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append_json(struct uwsgi_buffer *ub, char *buf, size_t len) {
|
||||
// need to escape \ and "
|
||||
size_t i;
|
||||
for(i=0;i<len;i++) {
|
||||
if (buf[i] == '"') {
|
||||
if (uwsgi_buffer_append(ub, "\\\"", 2)) return -1;
|
||||
}
|
||||
else if (buf[i] == '\\') {
|
||||
if (uwsgi_buffer_append(ub, "\\\\", 2)) return -1;
|
||||
}
|
||||
else {
|
||||
if (uwsgi_buffer_append(ub, buf+i, 1)) return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u16le(struct uwsgi_buffer *ub, uint16_t num) {
|
||||
uint8_t buf[2];
|
||||
buf[0] = (uint8_t) (num & 0xff);
|
||||
buf[1] = (uint8_t) ((num >> 8) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 2);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u16be(struct uwsgi_buffer *ub, uint16_t num) {
|
||||
uint8_t buf[2];
|
||||
buf[1] = (uint8_t) (num & 0xff);
|
||||
buf[0] = (uint8_t) ((num >> 8) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 2);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u24be(struct uwsgi_buffer *ub, uint32_t num) {
|
||||
uint8_t buf[3];
|
||||
buf[2] = (uint8_t) (num & 0xff);
|
||||
buf[1] = (uint8_t) ((num >> 8) & 0xff);
|
||||
buf[0] = (uint8_t) ((num >> 16) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 3);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u32be(struct uwsgi_buffer *ub, uint32_t num) {
|
||||
uint8_t buf[4];
|
||||
buf[3] = (uint8_t) (num & 0xff);
|
||||
buf[2] = (uint8_t) ((num >> 8) & 0xff);
|
||||
buf[1] = (uint8_t) ((num >> 16) & 0xff);
|
||||
buf[0] = (uint8_t) ((num >> 24) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 4);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_f32be(struct uwsgi_buffer *ub, float num) {
|
||||
uint8_t buf[4];
|
||||
uint32_t *pnum = (uint32_t *) #
|
||||
buf[3] = (uint8_t) (*pnum & 0xff);
|
||||
buf[2] = (uint8_t) ((*pnum >> 8) & 0xff);
|
||||
buf[1] = (uint8_t) ((*pnum >> 16) & 0xff);
|
||||
buf[0] = (uint8_t) ((*pnum >> 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_u64le(struct uwsgi_buffer *ub, uint64_t num) {
|
||||
uint8_t buf[8];
|
||||
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);
|
||||
buf[4] = (uint8_t) ((num >> 32) & 0xff);
|
||||
buf[5] = (uint8_t) ((num >> 40) & 0xff);
|
||||
buf[6] = (uint8_t) ((num >> 48) & 0xff);
|
||||
buf[7] = (uint8_t) ((num >> 56) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 8);
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_buffer_f64be(struct uwsgi_buffer *ub, double num) {
|
||||
uint8_t buf[8];
|
||||
uint64_t *pnum = (uint64_t *) #
|
||||
buf[7] = (uint8_t) (*pnum & 0xff);
|
||||
buf[6] = (uint8_t) ((*pnum >> 8) & 0xff);
|
||||
buf[5] = (uint8_t) ((*pnum >> 16) & 0xff);
|
||||
buf[4] = (uint8_t) ((*pnum >> 24) & 0xff);
|
||||
buf[3] = (uint8_t) ((*pnum >> 32) & 0xff);
|
||||
buf[2] = (uint8_t) ((*pnum >> 40) & 0xff);
|
||||
buf[1] = (uint8_t) ((*pnum >> 48) & 0xff);
|
||||
buf[0] = (uint8_t) ((*pnum >> 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);
|
||||
#ifdef UWSGI_DEBUG_BUFFER
|
||||
uwsgi_log("[uwsgi-buffer] destroying buffer of %llu bytes\n", (unsigned long long) ub->len);
|
||||
if (ub->freed) {
|
||||
uwsgi_log("[uwsgi-buffer][BUG] buffer at %p already destroyed !!!\n", ub);
|
||||
}
|
||||
ub->freed = 1;
|
||||
#endif
|
||||
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) {
|
||||
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("write()");
|
||||
uwsgi_error("uwsgi_buffer_send()");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -69,3 +366,46 @@ int uwsgi_buffer_send(struct uwsgi_buffer *ub, int fd) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_set_uh(struct uwsgi_buffer *ub, uint8_t modifier1, uint8_t modifier2) {
|
||||
if (ub->pos < 4) return -1;
|
||||
ub->buf[0] = modifier1;
|
||||
ub->buf[1] = (uint8_t) ((ub->pos - 4) & 0xff);
|
||||
ub->buf[2] = (uint8_t) (((ub->pos - 4) >> 8) & 0xff);
|
||||
ub->buf[3] = modifier2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void uwsgi_buffer_map(struct uwsgi_buffer *ub, char *buf, size_t len) {
|
||||
if (ub->buf) {
|
||||
free(ub->buf);
|
||||
}
|
||||
ub->buf = buf;
|
||||
ub->pos = len;
|
||||
ub->len = len;
|
||||
}
|
||||
|
||||
+1767
-257
File diff suppressed because it is too large
Load Diff
+162
@@ -0,0 +1,162 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/*
|
||||
|
||||
Chunked input implementation
|
||||
|
||||
--chunked-input-limit <bytes> (default 1MB)
|
||||
|
||||
--chunked-input-timeout <s> (default --socket-timeout)
|
||||
|
||||
chunk = uwsgi.chunked_read([timeout])
|
||||
|
||||
timeout = -1 (wait forever)
|
||||
timeout = 0 (default)
|
||||
|
||||
*/
|
||||
|
||||
static ssize_t uwsgi_chunked_input_recv(struct wsgi_request *wsgi_req, int timeout, int nb) {
|
||||
|
||||
if (timeout == 0) timeout = uwsgi.chunked_input_timeout;
|
||||
if (timeout == 0) timeout = uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT];
|
||||
|
||||
int ret = -1;
|
||||
|
||||
for(;;) {
|
||||
ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->chunked_input_buf->buf + wsgi_req->chunked_input_buf->pos, wsgi_req->chunked_input_buf->len - wsgi_req->chunked_input_buf->pos);
|
||||
if (rlen > 0) return rlen;
|
||||
if (rlen == 0) return -1;
|
||||
if (rlen < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
if (nb) return -1;
|
||||
goto wait;
|
||||
}
|
||||
uwsgi_error("uwsgi_chunked_input_recv()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wait:
|
||||
ret = uwsgi.wait_read_hook(wsgi_req->fd, timeout);
|
||||
if (ret > 0) {
|
||||
rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->chunked_input_buf->buf + wsgi_req->chunked_input_buf->pos, wsgi_req->chunked_input_buf->len - wsgi_req->chunked_input_buf->pos);
|
||||
if (rlen > 0) return rlen;
|
||||
if (rlen <= 0) return -1;
|
||||
}
|
||||
if (ret < 0) {
|
||||
uwsgi_error("uwsgi_chunked_input_recv()");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_chunked_readline(struct wsgi_request *wsgi_req) {
|
||||
size_t i;
|
||||
int found = 0;
|
||||
for(i=0;i<wsgi_req->chunked_input_buf->pos;i++) {
|
||||
if (found) {
|
||||
if (wsgi_req->chunked_input_buf->buf[i] == '\n') {
|
||||
// strtoul will stop at \r
|
||||
size_t num = strtoul(wsgi_req->chunked_input_buf->buf, NULL, 16);
|
||||
if (uwsgi_buffer_decapitate(wsgi_req->chunked_input_buf, i+1)) return -1;
|
||||
return num;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if ((wsgi_req->chunked_input_buf->buf[i] >= '0' && wsgi_req->chunked_input_buf->buf[i] <= '9') ||
|
||||
(wsgi_req->chunked_input_buf->buf[i] >= 'a' && wsgi_req->chunked_input_buf->buf[i] <= 'z') ||
|
||||
(wsgi_req->chunked_input_buf->buf[i] >= 'A' && wsgi_req->chunked_input_buf->buf[i] <= 'Z')) continue;
|
||||
if (wsgi_req->chunked_input_buf->buf[i] == '\r') { found = 1; continue; }
|
||||
return -1;
|
||||
}
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
0 -> waiting for \r\n
|
||||
1 -> waiting for whole body
|
||||
|
||||
*/
|
||||
|
||||
char *uwsgi_chunked_read(struct wsgi_request *wsgi_req, size_t *len, int timeout, int nb) {
|
||||
|
||||
if (!wsgi_req->chunked_input_buf) {
|
||||
wsgi_req->chunked_input_buf = uwsgi_buffer_new(uwsgi.page_size);
|
||||
wsgi_req->chunked_input_buf->limit = uwsgi.chunked_input_limit;
|
||||
}
|
||||
|
||||
// the whole chunk stream has been consumed
|
||||
if (wsgi_req->chunked_input_complete) {
|
||||
*len = 0;
|
||||
return wsgi_req->chunked_input_buf->buf;
|
||||
}
|
||||
|
||||
if (wsgi_req->chunked_input_decapitate > 0) {
|
||||
if (uwsgi_buffer_decapitate(wsgi_req->chunked_input_buf, wsgi_req->chunked_input_decapitate)) return NULL;
|
||||
wsgi_req->chunked_input_decapitate = 0;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
if (wsgi_req->chunked_input_need > 0 || wsgi_req->chunked_input_buf->pos == 0) {
|
||||
if (uwsgi_buffer_ensure(wsgi_req->chunked_input_buf, UMAX((uint64_t)uwsgi.page_size, wsgi_req->chunked_input_need))) return NULL;
|
||||
ssize_t rlen = uwsgi_chunked_input_recv(wsgi_req, timeout, nb);
|
||||
if (rlen <= 0) return NULL;
|
||||
// update buffer position
|
||||
wsgi_req->chunked_input_buf->pos += rlen;
|
||||
if (wsgi_req->chunked_input_need > 0) {
|
||||
if ((size_t)rlen > wsgi_req->chunked_input_need) {
|
||||
wsgi_req->chunked_input_need = 0;
|
||||
}
|
||||
else {
|
||||
wsgi_req->chunked_input_need -= rlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wsgi_req->chunked_input_need > 0) continue;
|
||||
|
||||
// ok we have a frame, let's parse it
|
||||
if (wsgi_req->chunked_input_buf->pos > 0) {
|
||||
switch(wsgi_req->chunked_input_parser_status) {
|
||||
case 0:
|
||||
wsgi_req->chunked_input_chunk_len = uwsgi_chunked_readline(wsgi_req);
|
||||
if (wsgi_req->chunked_input_chunk_len == -2) {
|
||||
wsgi_req->chunked_input_need++;
|
||||
break;
|
||||
}
|
||||
else if (wsgi_req->chunked_input_chunk_len < 0) {
|
||||
return NULL;
|
||||
}
|
||||
else if (wsgi_req->chunked_input_chunk_len == 0) {
|
||||
*len = 0;
|
||||
wsgi_req->chunked_input_complete = 1;
|
||||
return wsgi_req->chunked_input_buf->buf;
|
||||
}
|
||||
// if here the buffer has been already decapitated
|
||||
if ((size_t)(wsgi_req->chunked_input_chunk_len+2) > wsgi_req->chunked_input_buf->pos) {
|
||||
wsgi_req->chunked_input_need = (wsgi_req->chunked_input_chunk_len+2) - wsgi_req->chunked_input_buf->pos;
|
||||
wsgi_req->chunked_input_parser_status = 1;
|
||||
break;
|
||||
}
|
||||
*len = wsgi_req->chunked_input_chunk_len;
|
||||
wsgi_req->chunked_input_decapitate = wsgi_req->chunked_input_chunk_len+2;
|
||||
return wsgi_req->chunked_input_buf->buf;
|
||||
case 1:
|
||||
if ((size_t)(wsgi_req->chunked_input_chunk_len+2) > wsgi_req->chunked_input_buf->pos) {
|
||||
wsgi_req->chunked_input_need = (wsgi_req->chunked_input_chunk_len+2) - wsgi_req->chunked_input_buf->pos;
|
||||
break;
|
||||
}
|
||||
*len = wsgi_req->chunked_input_chunk_len;
|
||||
wsgi_req->chunked_input_decapitate = wsgi_req->chunked_input_chunk_len+2;
|
||||
wsgi_req->chunked_input_parser_status = 0;
|
||||
return wsgi_req->chunked_input_buf->buf;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
int main() {}
|
||||
+4
-4
@@ -4,11 +4,11 @@ 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();
|
||||
return uwsgi.clock->seconds();
|
||||
}
|
||||
|
||||
uint64_t uwsgi_micros() {
|
||||
return uwsgi.clock->microseconds();
|
||||
return uwsgi.clock->microseconds();
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ void uwsgi_register_clock(struct uwsgi_clock *clock) {
|
||||
return;
|
||||
}
|
||||
|
||||
while(clocks) {
|
||||
while (clocks) {
|
||||
if (!clocks->next) {
|
||||
clocks->next = clock;
|
||||
return;
|
||||
@@ -33,7 +33,7 @@ void uwsgi_register_clock(struct uwsgi_clock *clock) {
|
||||
|
||||
void uwsgi_set_clock(char *name) {
|
||||
struct uwsgi_clock *clocks = uwsgi.clocks;
|
||||
while(clocks) {
|
||||
while (clocks) {
|
||||
if (!strcmp(name, clocks->name)) {
|
||||
uwsgi.clock = clocks;
|
||||
return;
|
||||
|
||||
-464
@@ -1,464 +0,0 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
|
||||
#ifdef UWSGI_UDP
|
||||
|
||||
static void cluster_manage_opt(char *key, uint16_t keylen, char *value, uint16_t vallen, void *foobar) {
|
||||
|
||||
add_exported_option( uwsgi_concat2n(key, keylen, "", 0), uwsgi_concat2n(value, vallen, "", 0), 0);
|
||||
|
||||
}
|
||||
|
||||
void cluster_setup() {
|
||||
|
||||
int rlen;
|
||||
// get cluster configuration
|
||||
if (uwsgi.cluster != NULL) {
|
||||
// get multicast socket
|
||||
|
||||
uwsgi.cluster_fd = uwsgi_cluster_join(uwsgi.cluster);
|
||||
|
||||
uwsgi_log("JOINED CLUSTER: %s\n", uwsgi.cluster);
|
||||
|
||||
// ask for cluster options only if bot pre-existent options are set
|
||||
if (uwsgi.exported_opts_cnt == 1 && !uwsgi.cluster_nodes) {
|
||||
// now wait max 60 seconds and resend multicast request every 10 seconds
|
||||
for (;;) {
|
||||
uwsgi_log("asking \"%s\" uWSGI cluster for configuration data:\n", uwsgi.cluster);
|
||||
if (uwsgi_send_empty_pkt(uwsgi.cluster_fd, uwsgi.cluster, 99, 0) < 0) {
|
||||
uwsgi_log("unable to send multicast message to %s\n", uwsgi.cluster);
|
||||
continue;
|
||||
}
|
||||
waitfd:
|
||||
rlen = uwsgi_waitfd(uwsgi.cluster_fd, 10);
|
||||
if (rlen < 0) {
|
||||
break;
|
||||
}
|
||||
else if (rlen > 0) {
|
||||
// receive the packet
|
||||
char clusterbuf[4096];
|
||||
if (!uwsgi_hooked_parse_dict_dgram(uwsgi.cluster_fd, clusterbuf, 4096, 99, 1, cluster_manage_opt, NULL)) {
|
||||
uwsgi_configure();
|
||||
goto options_parsed;
|
||||
}
|
||||
else {
|
||||
goto waitfd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
options_parsed:
|
||||
|
||||
if (!uwsgi.cluster_nodes)
|
||||
uwsgi_cluster_add_me();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void uwsgi_cluster_add_node(struct uwsgi_cluster_node *nucn, int type) {
|
||||
|
||||
int i;
|
||||
struct uwsgi_cluster_node *ucn;
|
||||
char *tcp_port;
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("adding node\n");
|
||||
#endif
|
||||
|
||||
tcp_port = strchr(nucn->name, ':');
|
||||
#ifndef UWSGI_ZEROMQ
|
||||
if (tcp_port == NULL) {
|
||||
#else
|
||||
char *zmq_dash = strchr(nucn->name, '-');
|
||||
if (tcp_port == NULL && zmq_dash == NULL) {
|
||||
#endif
|
||||
|
||||
fprintf(stdout, "invalid cluster node name %s\n", nucn->name);
|
||||
return;
|
||||
}
|
||||
|
||||
// first check for already present node
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
ucn = &uwsgi.shared->nodes[i];
|
||||
if (ucn->name[0] != 0) {
|
||||
if (!strcmp(ucn->name, nucn->name)) {
|
||||
ucn->status = UWSGI_NODE_OK;
|
||||
ucn->last_seen = uwsgi_now();
|
||||
// update requests
|
||||
ucn->requests = nucn->requests;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
ucn = &uwsgi.shared->nodes[i];
|
||||
|
||||
if (ucn->name[0] == 0) {
|
||||
memcpy(ucn->name, nucn->name, strlen(nucn->name) + 1);
|
||||
memcpy(ucn->nodename, nucn->nodename, strlen(nucn->nodename) + 1);
|
||||
ucn->workers = nucn->workers;
|
||||
ucn->ucn_addr.sin_family = AF_INET;
|
||||
if (tcp_port) {
|
||||
ucn->ucn_addr.sin_port = htons(atoi(tcp_port + 1));
|
||||
tcp_port[0] = 0;
|
||||
}
|
||||
if (nucn->name[0] == 0) {
|
||||
ucn->ucn_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
}
|
||||
else {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%s\n", nucn->name);
|
||||
#endif
|
||||
ucn->ucn_addr.sin_addr.s_addr = inet_addr(nucn->name);
|
||||
}
|
||||
|
||||
ucn->type = type;
|
||||
// here memory can be freed, as it is allocated by uwsgi_concat2n
|
||||
if (type != CLUSTER_NODE_DYNAMIC && tcp_port) {
|
||||
tcp_port[0] = ':';
|
||||
}
|
||||
ucn->last_seen = uwsgi_now();
|
||||
ucn->requests = nucn->requests;
|
||||
uwsgi_log("[uWSGI cluster] added node %s\n", ucn->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("unable to add node %s\n", nucn->name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int uwsgi_cluster_add_me() {
|
||||
|
||||
const char *key1 = "hostname";
|
||||
const char *key2 = "address";
|
||||
const char *key3 = "workers";
|
||||
const char *key4 = "requests";
|
||||
|
||||
char *ptrbuf;
|
||||
uint16_t ustrlen;
|
||||
char numproc[6];
|
||||
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
char uuid_zmq_str[37];
|
||||
uuid_t uuid_zmq;
|
||||
if (!uwsgi.sockets && !uwsgi.zeromq) {
|
||||
#else
|
||||
if (!uwsgi.sockets) {
|
||||
#endif
|
||||
uwsgi_log("you need to specify at least a socket to start a uWSGI cluster\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
snprintf(numproc, 6, "%d", uwsgi.numproc);
|
||||
|
||||
size_t len;
|
||||
|
||||
if (uwsgi.sockets) {
|
||||
len = 2 + strlen(key1) + 2 + strlen(uwsgi.hostname) + 2 + strlen(key2) + 2 + strlen(uwsgi.sockets->name) + 2 + strlen(key3) + 2 + strlen(numproc) + 2 + strlen(key4) + 2 + 1;
|
||||
}
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
else if (uwsgi.zeromq) {
|
||||
uuid_generate(uuid_zmq);
|
||||
uuid_unparse(uuid_zmq, uuid_zmq_str);
|
||||
len = 2 + strlen(key1) + 2 + strlen(uwsgi.hostname) + 2 + strlen(key2) + 2 + strlen(uuid_zmq_str) + 2 + strlen(key3) + 2 + strlen(numproc) + 2 + strlen(key4) + 2 + 1;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
len = 2 + strlen(key1) + 2 + strlen(uwsgi.hostname) + 2 + strlen(key3) + 2 + strlen(numproc) + 2 + strlen(key4) + 2 + 1;
|
||||
}
|
||||
char *buf = uwsgi_malloc(len);
|
||||
|
||||
ptrbuf = buf;
|
||||
|
||||
ustrlen = strlen(key1);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key1, strlen(key1));
|
||||
ptrbuf += strlen(key1);
|
||||
|
||||
ustrlen = strlen(uwsgi.hostname);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, uwsgi.hostname, strlen(uwsgi.hostname));
|
||||
ptrbuf += strlen(uwsgi.hostname);
|
||||
|
||||
|
||||
if (uwsgi.sockets && uwsgi.sockets->name) {
|
||||
ustrlen = strlen(key2);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key2, strlen(key2));
|
||||
ptrbuf += strlen(key2);
|
||||
|
||||
ustrlen = strlen(uwsgi.sockets->name);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, uwsgi.sockets->name, strlen(uwsgi.sockets->name));
|
||||
ptrbuf += strlen(uwsgi.sockets->name);
|
||||
}
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
else if (uwsgi.zeromq) {
|
||||
ustrlen = strlen(key2);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key2, strlen(key2));
|
||||
ptrbuf += strlen(key2);
|
||||
|
||||
ustrlen = strlen(uuid_zmq_str);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, uuid_zmq_str, strlen(uuid_zmq_str));
|
||||
ptrbuf += strlen(uuid_zmq_str);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
ustrlen = strlen(key3);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key3, strlen(key3));
|
||||
ptrbuf += strlen(key3);
|
||||
|
||||
ustrlen = strlen(numproc);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, numproc, strlen(numproc));
|
||||
ptrbuf += strlen(numproc);
|
||||
|
||||
ustrlen = strlen(key4);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key4, strlen(key4));
|
||||
ptrbuf += strlen(key4);
|
||||
|
||||
ustrlen = 1;
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, "0", 1);
|
||||
ptrbuf += 1;
|
||||
|
||||
|
||||
uwsgi_string_sendto(uwsgi.cluster_fd, 95, 0, (struct sockaddr *) &uwsgi.mc_cluster_addr, sizeof(uwsgi.mc_cluster_addr), buf, len);
|
||||
|
||||
free(buf);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("add_me() successfull\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_cluster_join(char *name) {
|
||||
|
||||
int fd;
|
||||
char *cp;
|
||||
int broadcast = 0;
|
||||
|
||||
|
||||
|
||||
if (name[0] == ':') {
|
||||
fd = bind_to_udp(name, 0, 1);
|
||||
broadcast = 1;
|
||||
}
|
||||
else {
|
||||
fd = bind_to_udp(name, 1, 0);
|
||||
}
|
||||
|
||||
if (fd >= 0) {
|
||||
cp = strchr(name, ':');
|
||||
cp[0] = 0;
|
||||
uwsgi.mc_cluster_addr.sin_family = AF_INET;
|
||||
if (broadcast) {
|
||||
uwsgi.mc_cluster_addr.sin_addr.s_addr = INADDR_BROADCAST;
|
||||
}
|
||||
else {
|
||||
uwsgi.mc_cluster_addr.sin_addr.s_addr = inet_addr(name);
|
||||
}
|
||||
uwsgi.mc_cluster_addr.sin_port = htons(atoi(cp + 1));
|
||||
cp[0] = ':';
|
||||
|
||||
|
||||
// announce my presence to all the nodes
|
||||
uwsgi_string_sendto(fd, 73, 0, (struct sockaddr *) &uwsgi.mc_cluster_addr, sizeof(uwsgi.mc_cluster_addr), uwsgi.hostname, strlen(uwsgi.hostname));
|
||||
}
|
||||
else {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
return fd;
|
||||
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_cluster_best_node() {
|
||||
|
||||
int i;
|
||||
int best_node = -1;
|
||||
struct uwsgi_cluster_node *ucn;
|
||||
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
ucn = &uwsgi.shared->nodes[i];
|
||||
if (ucn->name[0] != 0 && ucn->status == UWSGI_NODE_OK) {
|
||||
if (best_node == -1) {
|
||||
best_node = i;
|
||||
}
|
||||
else {
|
||||
if (ucn->last_choosen < uwsgi.shared->nodes[best_node].last_choosen) {
|
||||
best_node = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (best_node == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uwsgi.shared->nodes[best_node].last_choosen = uwsgi_now();
|
||||
return uwsgi.shared->nodes[best_node].name;
|
||||
}
|
||||
|
||||
|
||||
void manage_cluster_announce(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
|
||||
|
||||
char *tmpstr;
|
||||
struct uwsgi_cluster_node *ucn = (struct uwsgi_cluster_node *) data;
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%.*s = %.*s\n", keylen, key, vallen, val);
|
||||
#endif
|
||||
|
||||
if (!uwsgi_strncmp("hostname", 8, key, keylen)) {
|
||||
strncpy(ucn->nodename, val, UMIN(vallen, 255));
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("address", 7, key, keylen)) {
|
||||
strncpy(ucn->name, val, UMIN(vallen, 100));
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("workers", 7, key, keylen)) {
|
||||
tmpstr = uwsgi_concat2n(val, vallen, "", 0);
|
||||
ucn->workers = atoi(tmpstr);
|
||||
free(tmpstr);
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("requests", 8, key, keylen)) {
|
||||
tmpstr = uwsgi_concat2n(val, vallen, "", 0);
|
||||
ucn->requests = strtoul(tmpstr, NULL, 0);
|
||||
free(tmpstr);
|
||||
}
|
||||
}
|
||||
|
||||
void manage_cluster_message(char *cluster_opt_buf, int cluster_opt_size) {
|
||||
|
||||
struct uwsgi_cluster_node nucn;
|
||||
|
||||
switch (uwsgi.workers[0].cores[0].req.uh.modifier1) {
|
||||
case 95:
|
||||
memset(&nucn, 0, sizeof(struct uwsgi_cluster_node));
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
uwsgi.workers[0].cores[0].req.uh.pktsize = uwsgi_swap16(uwsgi.wsgi_requests[0]->uh.pktsize);
|
||||
#endif
|
||||
uwsgi_hooked_parse(uwsgi.workers[0].cores[0].req.buffer, uwsgi.workers[0].cores[0].req.uh.pktsize, manage_cluster_announce, &nucn);
|
||||
if (nucn.name[0] != 0) {
|
||||
uwsgi_cluster_add_node(&nucn, CLUSTER_NODE_DYNAMIC);
|
||||
}
|
||||
break;
|
||||
case 96:
|
||||
#ifdef __BIG_ENDIAN__
|
||||
uwsgi.workers[0].cores[0].req.uh.pktsize = uwsgi_swap16(uwsgi.wsgi_requests[0]->uh.pktsize);
|
||||
#endif
|
||||
uwsgi_log_verbose("%.*s\n", uwsgi.workers[0].cores[0].req.uh.pktsize, uwsgi.workers[0].cores[0].req.buffer);
|
||||
break;
|
||||
case 98:
|
||||
if (kill(getpid(), SIGHUP)) {
|
||||
uwsgi_error("kill()");
|
||||
}
|
||||
break;
|
||||
case 99:
|
||||
if (uwsgi.cluster_nodes)
|
||||
break;
|
||||
if (uwsgi.workers[0].cores[0].req.uh.modifier2 == 0) {
|
||||
uwsgi_log("requested configuration data, sending %d bytes\n", cluster_opt_size);
|
||||
sendto(uwsgi.cluster_fd, cluster_opt_buf, cluster_opt_size, 0, (struct sockaddr *) &uwsgi.mc_cluster_addr, sizeof(uwsgi.mc_cluster_addr));
|
||||
}
|
||||
break;
|
||||
case 73:
|
||||
#ifdef __BIG_ENDIAN__
|
||||
uwsgi.workers[0].cores[0].req.uh.pktsize = uwsgi_swap16(uwsgi.workers[0].cores[0].req.uh.pktsize);
|
||||
#endif
|
||||
uwsgi_log_verbose("[uWSGI cluster %s] new node available: %.*s\n", uwsgi.cluster, uwsgi.workers[0].cores[0].req.uh.pktsize, uwsgi.workers[0].cores[0].req.buffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
char *uwsgi_setup_clusterbuf(size_t *size) {
|
||||
|
||||
size_t cluster_opt_size = 4;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
|
||||
//uwsgi_log("%s\n", uwsgi.exported_opts[i]->key);
|
||||
cluster_opt_size += 2 + strlen(uwsgi.exported_opts[i]->key);
|
||||
if (uwsgi.exported_opts[i]->value) {
|
||||
cluster_opt_size += 2 + strlen(uwsgi.exported_opts[i]->value);
|
||||
}
|
||||
else {
|
||||
cluster_opt_size += 2 + 1;
|
||||
}
|
||||
}
|
||||
|
||||
//uwsgi_log("cluster opts size: %d\n", cluster_opt_size);
|
||||
char *cluster_opt_buf = uwsgi_malloc(cluster_opt_size);
|
||||
|
||||
struct uwsgi_header *uh = (struct uwsgi_header *) cluster_opt_buf;
|
||||
|
||||
uh->modifier1 = 99;
|
||||
uh->pktsize = cluster_opt_size - 4;
|
||||
uh->modifier2 = 1;
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
uh->pktsize = uwsgi_swap16(uh->pktsize);
|
||||
#endif
|
||||
|
||||
char *cptrbuf = cluster_opt_buf + 4;
|
||||
|
||||
for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
|
||||
//uwsgi_log("%s\n", uwsgi.exported_opts[i]->key);
|
||||
uint16_t ustrlen = strlen(uwsgi.exported_opts[i]->key);
|
||||
*cptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*cptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(cptrbuf, uwsgi.exported_opts[i]->key, ustrlen);
|
||||
cptrbuf += ustrlen;
|
||||
|
||||
if (uwsgi.exported_opts[i]->value) {
|
||||
ustrlen = strlen(uwsgi.exported_opts[i]->value);
|
||||
*cptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*cptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(cptrbuf, uwsgi.exported_opts[i]->value, ustrlen);
|
||||
}
|
||||
else {
|
||||
ustrlen = 1;
|
||||
*cptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*cptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
*cptrbuf = '1';
|
||||
}
|
||||
cptrbuf += ustrlen;
|
||||
}
|
||||
|
||||
return cluster_opt_buf;
|
||||
}
|
||||
+635
@@ -0,0 +1,635 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
int uwsgi_logic_opt_if_exists(char *key, char *value) {
|
||||
|
||||
if (uwsgi_file_exists(uwsgi.logic_opt_data)) {
|
||||
add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_logic_opt_if_not_exists(char *key, char *value) {
|
||||
|
||||
if (!uwsgi_file_exists(uwsgi.logic_opt_data)) {
|
||||
add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_logic_opt_for(char *key, char *value) {
|
||||
|
||||
char *p, *ctx = NULL;
|
||||
uwsgi_foreach_token(uwsgi.logic_opt_data, " ", p, ctx) {
|
||||
add_exported_option(key, uwsgi_substitute(value, "%(_)", p), 0);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int uwsgi_logic_opt_for_glob(char *key, char *value) {
|
||||
|
||||
glob_t g;
|
||||
int i;
|
||||
if (glob(uwsgi.logic_opt_data, GLOB_MARK | GLOB_NOCHECK, NULL, &g)) {
|
||||
uwsgi_error("uwsgi_logic_opt_for_glob()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < (int) g.gl_pathc; i++) {
|
||||
add_exported_option(key, uwsgi_substitute(value, "%(_)", g.gl_pathv[i]), 0);
|
||||
}
|
||||
|
||||
globfree(&g);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int uwsgi_logic_opt_for_times(char *key, char *value) {
|
||||
|
||||
int num = atoi(uwsgi.logic_opt_data);
|
||||
int i;
|
||||
char str_num[11];
|
||||
|
||||
for (i = 1; i <= num; i++) {
|
||||
int ret = uwsgi_num2str2(i, str_num);
|
||||
// security check
|
||||
if (ret < 0 || ret > 11) {
|
||||
exit(1);
|
||||
}
|
||||
add_exported_option(key, uwsgi_substitute(value, "%(_)", str_num), 0);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_logic_opt_if_opt(char *key, char *value) {
|
||||
|
||||
// check for env-value syntax
|
||||
char *equal = strchr(uwsgi.logic_opt_data, '=');
|
||||
if (equal)
|
||||
*equal = 0;
|
||||
|
||||
char *p = uwsgi_get_exported_opt(uwsgi.logic_opt_data);
|
||||
if (equal)
|
||||
*equal = '=';
|
||||
|
||||
if (p) {
|
||||
if (equal) {
|
||||
if (strcmp(equal + 1, p))
|
||||
return 0;
|
||||
}
|
||||
add_exported_option(key, uwsgi_substitute(value, "%(_)", p), 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_logic_opt_if_not_opt(char *key, char *value) {
|
||||
|
||||
// check for env-value syntax
|
||||
char *equal = strchr(uwsgi.logic_opt_data, '=');
|
||||
if (equal)
|
||||
*equal = 0;
|
||||
|
||||
char *p = uwsgi_get_exported_opt(uwsgi.logic_opt_data);
|
||||
if (equal)
|
||||
*equal = '=';
|
||||
|
||||
if (p) {
|
||||
if (equal) {
|
||||
if (!strcmp(equal + 1, p))
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
add_exported_option(key, uwsgi_substitute(value, "%(_)", p), 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int uwsgi_logic_opt_if_env(char *key, char *value) {
|
||||
|
||||
// check for env-value syntax
|
||||
char *equal = strchr(uwsgi.logic_opt_data, '=');
|
||||
if (equal)
|
||||
*equal = 0;
|
||||
|
||||
char *p = getenv(uwsgi.logic_opt_data);
|
||||
if (equal)
|
||||
*equal = '=';
|
||||
|
||||
if (p) {
|
||||
if (equal) {
|
||||
if (strcmp(equal + 1, p))
|
||||
return 0;
|
||||
}
|
||||
add_exported_option(key, uwsgi_substitute(value, "%(_)", p), 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_logic_opt_if_not_env(char *key, char *value) {
|
||||
|
||||
// check for env-value syntax
|
||||
char *equal = strchr(uwsgi.logic_opt_data, '=');
|
||||
if (equal)
|
||||
*equal = 0;
|
||||
|
||||
char *p = getenv(uwsgi.logic_opt_data);
|
||||
if (equal)
|
||||
*equal = '=';
|
||||
|
||||
if (p) {
|
||||
if (equal) {
|
||||
if (!strcmp(equal + 1, p))
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
add_exported_option(key, uwsgi_substitute(value, "%(_)", p), 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int uwsgi_logic_opt_if_reload(char *key, char *value) {
|
||||
if (uwsgi.is_a_reload) {
|
||||
add_exported_option(key, value, 0);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_logic_opt_if_not_reload(char *key, char *value) {
|
||||
if (!uwsgi.is_a_reload) {
|
||||
add_exported_option(key, value, 0);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_logic_opt_if_file(char *key, char *value) {
|
||||
|
||||
if (uwsgi_is_file(uwsgi.logic_opt_data)) {
|
||||
add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_logic_opt_if_not_file(char *key, char *value) {
|
||||
|
||||
if (!uwsgi_is_file(uwsgi.logic_opt_data)) {
|
||||
add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_logic_opt_if_dir(char *key, char *value) {
|
||||
|
||||
if (uwsgi_is_dir(uwsgi.logic_opt_data)) {
|
||||
add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_logic_opt_if_not_dir(char *key, char *value) {
|
||||
|
||||
if (!uwsgi_is_dir(uwsgi.logic_opt_data)) {
|
||||
add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int uwsgi_logic_opt_if_plugin(char *key, char *value) {
|
||||
|
||||
if (plugin_already_loaded(uwsgi.logic_opt_data)) {
|
||||
add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_logic_opt_if_not_plugin(char *key, char *value) {
|
||||
|
||||
if (!plugin_already_loaded(uwsgi.logic_opt_data)) {
|
||||
add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_count_options(struct uwsgi_option *uopt) {
|
||||
|
||||
struct uwsgi_option *aopt;
|
||||
int count = 0;
|
||||
|
||||
while ((aopt = uopt)) {
|
||||
if (!aopt->name)
|
||||
break;
|
||||
count++;
|
||||
uopt++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int uwsgi_opt_exists(char *name) {
|
||||
struct uwsgi_option *op = uwsgi.options;
|
||||
while (op->name) {
|
||||
if (!strcmp(name, op->name)) return 1;
|
||||
op++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
avoid loops here !!!
|
||||
*/
|
||||
struct uwsgi_option *uwsgi_opt_get(char *name) {
|
||||
struct uwsgi_option *op;
|
||||
int round = 0;
|
||||
retry:
|
||||
round++;
|
||||
if (round > 2) goto end;
|
||||
op = uwsgi.options;
|
||||
|
||||
while (op->name) {
|
||||
if (!strcmp(name, op->name)) {
|
||||
return op;
|
||||
}
|
||||
op++;
|
||||
}
|
||||
|
||||
if (uwsgi.autoload) {
|
||||
if (uwsgi_try_autoload(name)) goto retry;
|
||||
}
|
||||
|
||||
end:
|
||||
if (uwsgi.strict) {
|
||||
uwsgi_log("[strict-mode] unknown config directive: %s\n", name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void add_exported_option(char *key, char *value, int configured) {
|
||||
add_exported_option_do(key, value, configured, 0);
|
||||
}
|
||||
|
||||
void add_exported_option_do(char *key, char *value, int configured, int placeholder_only) {
|
||||
|
||||
struct uwsgi_string_list *blacklist = uwsgi.blacklist;
|
||||
struct uwsgi_string_list *whitelist = uwsgi.whitelist;
|
||||
|
||||
while (blacklist) {
|
||||
if (!strcmp(key, blacklist->value)) {
|
||||
uwsgi_log("uWSGI error: forbidden option \"%s\" (by blacklist)\n", key);
|
||||
exit(1);
|
||||
}
|
||||
blacklist = blacklist->next;
|
||||
}
|
||||
|
||||
if (whitelist) {
|
||||
int allowed = 0;
|
||||
while (whitelist) {
|
||||
if (!strcmp(key, whitelist->value)) {
|
||||
allowed = 1;
|
||||
break;
|
||||
}
|
||||
whitelist = whitelist->next;
|
||||
}
|
||||
if (!allowed) {
|
||||
uwsgi_log("uWSGI error: forbidden option \"%s\" (by whitelist)\n", key);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.blacklist_context) {
|
||||
if (uwsgi_list_has_str(uwsgi.blacklist_context, key)) {
|
||||
uwsgi_log("uWSGI error: forbidden option \"%s\" (by blacklist)\n", key);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.whitelist_context) {
|
||||
if (!uwsgi_list_has_str(uwsgi.whitelist_context, key)) {
|
||||
uwsgi_log("uWSGI error: forbidden option \"%s\" (by whitelist)\n", key);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.logic_opt_running)
|
||||
goto add;
|
||||
|
||||
if (!strcmp(key, "end") || !strcmp(key, "endfor") || !strcmp(key, "endif")) {
|
||||
if (uwsgi.logic_opt_data) {
|
||||
free(uwsgi.logic_opt_data);
|
||||
}
|
||||
uwsgi.logic_opt = NULL;
|
||||
uwsgi.logic_opt_arg = NULL;
|
||||
uwsgi.logic_opt_cycles = 0;
|
||||
uwsgi.logic_opt_data = NULL;
|
||||
}
|
||||
|
||||
if (uwsgi.logic_opt) {
|
||||
if (uwsgi.logic_opt_data) {
|
||||
free(uwsgi.logic_opt_data);
|
||||
}
|
||||
uwsgi.logic_opt_data = uwsgi_str(uwsgi.logic_opt_arg);
|
||||
uwsgi.logic_opt_cycles++;
|
||||
uwsgi.logic_opt_running = 1;
|
||||
uwsgi.logic_opt(key, value);
|
||||
uwsgi.logic_opt_running = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
add:
|
||||
|
||||
if (!uwsgi.exported_opts) {
|
||||
uwsgi.exported_opts = uwsgi_malloc(sizeof(struct uwsgi_opt *));
|
||||
}
|
||||
else {
|
||||
uwsgi.exported_opts = realloc(uwsgi.exported_opts, sizeof(struct uwsgi_opt *) * (uwsgi.exported_opts_cnt + 1));
|
||||
if (!uwsgi.exported_opts) {
|
||||
uwsgi_error("realloc()");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int id = uwsgi.exported_opts_cnt;
|
||||
uwsgi.exported_opts[id] = uwsgi_malloc(sizeof(struct uwsgi_opt));
|
||||
uwsgi.exported_opts[id]->key = key;
|
||||
uwsgi.exported_opts[id]->value = value;
|
||||
uwsgi.exported_opts[id]->configured = configured;
|
||||
uwsgi.exported_opts_cnt++;
|
||||
uwsgi.dirty_config = 1;
|
||||
|
||||
if (placeholder_only) {
|
||||
if (uwsgi_opt_exists(key)) {
|
||||
uwsgi_log("you cannot use %s as a placeholder, it is already available as an option\n");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi.exported_opts[id]->configured = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
struct uwsgi_option *op = uwsgi_opt_get(key);
|
||||
if (op) {
|
||||
// requires master ?
|
||||
if (op->flags & UWSGI_OPT_MASTER) {
|
||||
uwsgi.master_process = 1;
|
||||
}
|
||||
// requires log_master ?
|
||||
if (op->flags & UWSGI_OPT_LOG_MASTER) {
|
||||
uwsgi.master_process = 1;
|
||||
uwsgi.log_master = 1;
|
||||
}
|
||||
if (op->flags & UWSGI_OPT_REQ_LOG_MASTER) {
|
||||
uwsgi.master_process = 1;
|
||||
uwsgi.log_master = 1;
|
||||
uwsgi.req_log_master = 1;
|
||||
}
|
||||
// requires threads ?
|
||||
if (op->flags & UWSGI_OPT_THREADS) {
|
||||
uwsgi.has_threads = 1;
|
||||
}
|
||||
// requires cheaper mode ?
|
||||
if (op->flags & UWSGI_OPT_CHEAPER) {
|
||||
uwsgi.cheaper = 1;
|
||||
}
|
||||
// requires virtualhosting ?
|
||||
if (op->flags & UWSGI_OPT_VHOST) {
|
||||
uwsgi.vhost = 1;
|
||||
}
|
||||
// requires memusage ?
|
||||
if (op->flags & UWSGI_OPT_MEMORY) {
|
||||
uwsgi.force_get_memusage = 1;
|
||||
}
|
||||
// requires auto procname ?
|
||||
if (op->flags & UWSGI_OPT_PROCNAME) {
|
||||
uwsgi.auto_procname = 1;
|
||||
}
|
||||
// requires lazy ?
|
||||
if (op->flags & UWSGI_OPT_LAZY) {
|
||||
uwsgi.lazy = 1;
|
||||
}
|
||||
// requires no_initial ?
|
||||
if (op->flags & UWSGI_OPT_NO_INITIAL) {
|
||||
uwsgi.no_initial_output = 1;
|
||||
}
|
||||
// requires no_server ?
|
||||
if (op->flags & UWSGI_OPT_NO_SERVER) {
|
||||
uwsgi.no_server = 1;
|
||||
}
|
||||
// requires post_buffering ?
|
||||
if (op->flags & UWSGI_OPT_POST_BUFFERING) {
|
||||
if (!uwsgi.post_buffering)
|
||||
uwsgi.post_buffering = 4096;
|
||||
}
|
||||
// requires building mime dict ?
|
||||
if (op->flags & UWSGI_OPT_MIME) {
|
||||
uwsgi.build_mime_dict = 1;
|
||||
}
|
||||
// enable metrics ?
|
||||
if (op->flags & UWSGI_OPT_METRICS) {
|
||||
uwsgi.has_metrics = 1;
|
||||
}
|
||||
// immediate ?
|
||||
if (op->flags & UWSGI_OPT_IMMEDIATE) {
|
||||
op->func(key, value, op->data);
|
||||
uwsgi.exported_opts[id]->configured = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_fallback_config() {
|
||||
if (uwsgi.fallback_config && uwsgi.last_exit_code == 1) {
|
||||
uwsgi_log_verbose("!!! %s (pid: %d) exited with status %d !!!\n", uwsgi.binary_path, (int) getpid(), uwsgi.last_exit_code);
|
||||
uwsgi_log_verbose("!!! Fallback config to %s !!!\n", uwsgi.fallback_config);
|
||||
char *argv[3];
|
||||
argv[0] = uwsgi.binary_path;
|
||||
argv[1] = uwsgi.fallback_config;
|
||||
argv[2] = NULL;
|
||||
execvp(uwsgi.binary_path, argv);
|
||||
uwsgi_error("execvp()");
|
||||
// never here
|
||||
}
|
||||
}
|
||||
|
||||
int uwsgi_manage_opt(char *key, char *value) {
|
||||
|
||||
struct uwsgi_option *op = uwsgi_opt_get(key);
|
||||
if (op) {
|
||||
op->func(key, value, op->data);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_configure() {
|
||||
|
||||
int i;
|
||||
|
||||
// and now apply the remaining configs
|
||||
restart:
|
||||
for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
|
||||
if (uwsgi.exported_opts[i]->configured)
|
||||
continue;
|
||||
uwsgi.dirty_config = 0;
|
||||
uwsgi.exported_opts[i]->configured = uwsgi_manage_opt(uwsgi.exported_opts[i]->key, uwsgi.exported_opts[i]->value);
|
||||
// some option could cause a dirty config tree
|
||||
if (uwsgi.dirty_config)
|
||||
goto restart;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_opt_custom(char *key, char *value, void *data ) {
|
||||
struct uwsgi_custom_option *uco = (struct uwsgi_custom_option *)data;
|
||||
size_t i, count = 1;
|
||||
size_t value_len = 0;
|
||||
if (value)
|
||||
value_len = strlen(value);
|
||||
off_t pos = 0;
|
||||
char **opt_argv;
|
||||
char *tmp_val = NULL, *p = NULL;
|
||||
|
||||
// now count the number of args
|
||||
for (i = 0; i < value_len; i++) {
|
||||
if (value[i] == ' ') {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
// allocate a tmp array
|
||||
opt_argv = uwsgi_calloc(sizeof(char *) * count);
|
||||
//make a copy of the value;
|
||||
if (value_len > 0) {
|
||||
tmp_val = uwsgi_str(value);
|
||||
// fill the array of options
|
||||
char *p, *ctx = NULL;
|
||||
uwsgi_foreach_token(tmp_val, " ", p, ctx) {
|
||||
opt_argv[pos] = p;
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// no argument specified
|
||||
opt_argv[0] = "";
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("found custom option %s with %d args\n", key, count);
|
||||
#endif
|
||||
|
||||
// now make a copy of the option template
|
||||
char *tmp_opt = uwsgi_str(uco->value);
|
||||
// split it
|
||||
char *ctx = NULL;
|
||||
uwsgi_foreach_token(tmp_opt, ";", p, ctx) {
|
||||
char *equal = strchr(p, '=');
|
||||
if (!equal)
|
||||
goto clear;
|
||||
*equal = '\0';
|
||||
|
||||
// build the key
|
||||
char *new_key = uwsgi_str(p);
|
||||
for (i = 0; i < count; i++) {
|
||||
char *old_key = new_key;
|
||||
char *tmp_num = uwsgi_num2str(i + 1);
|
||||
char *placeholder = uwsgi_concat2((char *) "$", tmp_num);
|
||||
free(tmp_num);
|
||||
new_key = uwsgi_substitute(old_key, placeholder, opt_argv[i]);
|
||||
if (new_key != old_key)
|
||||
free(old_key);
|
||||
free(placeholder);
|
||||
}
|
||||
|
||||
// build the value
|
||||
char *new_value = uwsgi_str(equal + 1);
|
||||
for (i = 0; i < count; i++) {
|
||||
char *old_value = new_value;
|
||||
char *tmp_num = uwsgi_num2str(i + 1);
|
||||
char *placeholder = uwsgi_concat2((char *) "$", tmp_num);
|
||||
free(tmp_num);
|
||||
new_value = uwsgi_substitute(old_value, placeholder, opt_argv[i]);
|
||||
if (new_value != old_value)
|
||||
free(old_value);
|
||||
free(placeholder);
|
||||
}
|
||||
// ignore return value here
|
||||
uwsgi_manage_opt(new_key, new_value);
|
||||
}
|
||||
|
||||
clear:
|
||||
free(tmp_val);
|
||||
free(tmp_opt);
|
||||
free(opt_argv);
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
+320
@@ -0,0 +1,320 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_cron *uwsgi_cron_add(char *crontab) {
|
||||
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(crontab, "%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 = crontab + i;
|
||||
uc->pid = -1;
|
||||
return uc;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_opt_add_cron(char *opt, char *value, void *foobar) {
|
||||
uwsgi_cron_add(value);
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_opt_add_unique_cron(char *opt, char *value, void *foobar) {
|
||||
struct uwsgi_cron *uc = uwsgi_cron_add(value);
|
||||
uc->unique = 1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
void uwsgi_opt_add_legion_cron(char *opt, char *value, void *foobar) {
|
||||
char *space = strchr(value, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid %s syntax, must be prefixed with a legion name\n", opt);
|
||||
exit(1);
|
||||
}
|
||||
char *legion = uwsgi_concat2n(value, space-value, "", 0);
|
||||
struct uwsgi_cron *uc = uwsgi_cron_add(space+1);
|
||||
uc->legion = legion;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_opt_add_unique_legion_cron(char *opt, char *value, void *foobar) {
|
||||
char *space = strchr(value, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid %s syntax, must be prefixed with a legion name\n", opt);
|
||||
exit(1);
|
||||
}
|
||||
char *legion = uwsgi_concat2n(value, space-value, "", 0);
|
||||
struct uwsgi_cron *uc = uwsgi_cron_add(space+1);
|
||||
uc->legion = legion;
|
||||
uc->unique = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void uwsgi_opt_add_cron2(char *opt, char *value, void *foobar) {
|
||||
|
||||
char *c_minute = NULL;
|
||||
char *c_hour = NULL;
|
||||
char *c_day = NULL;
|
||||
char *c_month = NULL;
|
||||
char *c_week = NULL;
|
||||
char *c_unique = NULL;
|
||||
char *c_harakiri = NULL;
|
||||
char *c_legion = NULL;
|
||||
|
||||
char *c_command = value;
|
||||
|
||||
char *space = strchr(value, ' ');
|
||||
if (space) {
|
||||
if (uwsgi_str_contains(value, space - value, '=')) {
|
||||
// --cron2 key=val command
|
||||
*space = 0;
|
||||
c_command = space + 1;
|
||||
}
|
||||
|
||||
// no point in parsing key=val list if there is none
|
||||
if (uwsgi_kvlist_parse(value, strlen(value), ',', '=',
|
||||
"minute", &c_minute,
|
||||
"hour", &c_hour,
|
||||
"day", &c_day,
|
||||
"month", &c_month,
|
||||
"week", &c_week,
|
||||
"unique", &c_unique,
|
||||
"harakiri", &c_harakiri,
|
||||
"legion", &c_legion,
|
||||
NULL)) {
|
||||
uwsgi_log("unable to parse cron definition: %s\n", value);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (uwsgi_str_contains(value, strlen(value), '=')) {
|
||||
// --cron2 key=val
|
||||
uwsgi_log("unable to parse cron definition: %s\n", value);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
uc->command = c_command;
|
||||
if (!uc->command) {
|
||||
uwsgi_log("[uwsgi-cron] invalid command in cron definition: %s\n", value);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// defaults
|
||||
uc->minute = -1;
|
||||
uc->hour = -1;
|
||||
uc->day = -1;
|
||||
uc->month = -1;
|
||||
uc->week = -1;
|
||||
|
||||
uc->unique = 0;
|
||||
uc->mercy = 0;
|
||||
uc->harakiri = 0;
|
||||
uc->pid = -1;
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
uc->legion = c_legion;
|
||||
#endif
|
||||
|
||||
if (c_minute)
|
||||
uc->minute = atoi(c_minute);
|
||||
|
||||
if (c_hour)
|
||||
uc->hour = atoi(c_hour);
|
||||
|
||||
if (c_day)
|
||||
uc->day = atoi(c_day);
|
||||
|
||||
if (c_month)
|
||||
uc->month = atoi(c_month);
|
||||
|
||||
if (c_week)
|
||||
uc->week = atoi(c_week);
|
||||
|
||||
if (c_unique)
|
||||
uc->unique = atoi(c_unique);
|
||||
|
||||
if (c_harakiri) {
|
||||
if (atoi(c_harakiri)) {
|
||||
// harakiri > 0
|
||||
uc->mercy = atoi(c_harakiri);
|
||||
}
|
||||
else {
|
||||
// harakiri == 0
|
||||
uc->mercy = -1;
|
||||
}
|
||||
}
|
||||
else if (uwsgi.cron_harakiri) {
|
||||
uc->harakiri = uwsgi.cron_harakiri;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void uwsgi_manage_signal_cron(time_t now) {
|
||||
|
||||
struct tm *uwsgi_cron_delta;
|
||||
int i;
|
||||
|
||||
uwsgi_cron_delta = localtime(&now);
|
||||
|
||||
if (uwsgi_cron_delta) {
|
||||
|
||||
// fix month
|
||||
uwsgi_cron_delta->tm_mon++;
|
||||
|
||||
uwsgi_lock(uwsgi.cron_table_lock);
|
||||
for (i = 0; i < ushared->cron_cnt; i++) {
|
||||
|
||||
struct uwsgi_cron *ucron = &ushared->cron[i];
|
||||
|
||||
int run_task = uwsgi_cron_task_needs_execution(uwsgi_cron_delta, ucron->minute, ucron->hour, ucron->day, ucron->month, ucron->week);
|
||||
|
||||
if (run_task == 1) {
|
||||
// date match, signal it ?
|
||||
if (now - ucron->last_job >= 60) {
|
||||
uwsgi_route_signal(ucron->sig);
|
||||
ucron->last_job = now;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
uwsgi_unlock(uwsgi.cron_table_lock);
|
||||
}
|
||||
else {
|
||||
uwsgi_error("localtime()");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_manage_command_cron(time_t now) {
|
||||
|
||||
struct tm *uwsgi_cron_delta;
|
||||
|
||||
struct uwsgi_cron *current_cron = uwsgi.crons;
|
||||
|
||||
uwsgi_cron_delta = localtime(&now);
|
||||
|
||||
|
||||
if (!uwsgi_cron_delta) {
|
||||
uwsgi_error("uwsgi_manage_command_cron()/localtime()");
|
||||
return;
|
||||
}
|
||||
|
||||
// fix month
|
||||
uwsgi_cron_delta->tm_mon++;
|
||||
|
||||
while (current_cron) {
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
// check for legion cron
|
||||
if (current_cron->legion) {
|
||||
if (!uwsgi_legion_i_am_the_lord(current_cron->legion))
|
||||
goto next;
|
||||
}
|
||||
#endif
|
||||
|
||||
// skip unique crons that are still running
|
||||
if (current_cron->unique && current_cron->pid >= 0)
|
||||
goto next;
|
||||
|
||||
int run_task = uwsgi_cron_task_needs_execution(uwsgi_cron_delta, current_cron->minute, current_cron->hour, current_cron->day, current_cron->month, current_cron->week);
|
||||
if (run_task == 1) {
|
||||
|
||||
// date match, run command ?
|
||||
if (now - current_cron->last_job >= 60) {
|
||||
//call command
|
||||
if (current_cron->command) {
|
||||
if (current_cron->func) {
|
||||
current_cron->func(current_cron, now);
|
||||
}
|
||||
else {
|
||||
pid_t pid = uwsgi_run_command(current_cron->command, NULL, -1);
|
||||
if (pid >= 0) {
|
||||
current_cron->pid = pid;
|
||||
current_cron->started_at = now;
|
||||
uwsgi_log_verbose("[uwsgi-cron] running \"%s\" (pid %d)\n", current_cron->command, current_cron->pid);
|
||||
if (current_cron->mercy) {
|
||||
//uwsgi_cron->mercy can be negative to inform master that harakiri should be disabled for this cron
|
||||
if (current_cron->mercy > 0)
|
||||
current_cron->harakiri = now + current_cron->mercy;
|
||||
}
|
||||
else if (uwsgi.cron_harakiri)
|
||||
current_cron->harakiri = now + uwsgi.cron_harakiri;
|
||||
}
|
||||
}
|
||||
}
|
||||
current_cron->last_job = now;
|
||||
}
|
||||
}
|
||||
|
||||
next:
|
||||
current_cron = current_cron->next;
|
||||
}
|
||||
}
|
||||
|
||||
+421
@@ -0,0 +1,421 @@
|
||||
#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) {
|
||||
#ifdef UWSGI_SSL
|
||||
if (ud->legion) {
|
||||
if (uwsgi_legion_i_am_the_lord(ud->legion)) {
|
||||
// lord, spawn if not running
|
||||
if (ud->pid <= 0) {
|
||||
uwsgi_spawn_daemon(ud);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// not lord, kill daemon if running
|
||||
if (ud->pid > 0) {
|
||||
if (!kill(ud->pid, 0)) {
|
||||
uwsgi_log("[uwsgi_daemons] stopping legion \"%s\" daemon: %s (pid: %d)\n", ud->legion, ud->command, ud->pid);
|
||||
kill(-ud->pid, SIGTERM);
|
||||
}
|
||||
else {
|
||||
// pid already died
|
||||
ud->pid = -1;
|
||||
}
|
||||
}
|
||||
ud = ud->next;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
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) {
|
||||
if (!ud->has_daemonized) {
|
||||
uwsgi_log_verbose("[uwsgi-daemons] \"%s\" (pid: %d) did not daemonize !!!\n", ud->command, (int) ud->pid);
|
||||
ud->pidfile_checks = 0;
|
||||
}
|
||||
else {
|
||||
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 want to respawn it
|
||||
int uwsgi_daemon_check_pid_death(pid_t diedpid) {
|
||||
struct uwsgi_daemon *ud = uwsgi.daemons;
|
||||
while (ud) {
|
||||
if (ud->pid == diedpid) {
|
||||
if (!ud->pidfile) {
|
||||
uwsgi_log("daemon \"%s\" (pid: %d) annihilated\n", ud->command, (int) diedpid);
|
||||
ud->pid = -1;
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
if (!ud->has_daemonized) {
|
||||
ud->has_daemonized = 1;
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[uwsgi-daemons] BUG !!! daemon \"%s\" has already daemonized !!!\n", ud->command);
|
||||
}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
#ifdef UWSGI_SSL
|
||||
if (ud->pid == diedpid && ud->legion && !uwsgi_legion_i_am_the_lord(ud->legion)) {
|
||||
// part of legion but not lord, don't respawn
|
||||
ud->pid = -1;
|
||||
uwsgi_log("uwsgi-daemons] legion \"%s\" daemon \"%s\" (pid: %d) annihilated\n", ud->legion, ud->command, (int) diedpid);
|
||||
ud = ud->next;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (ud->pid == diedpid && !ud->pidfile) {
|
||||
if (ud->control) {
|
||||
gracefully_kill_them_all(0);
|
||||
return 0;
|
||||
}
|
||||
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) {
|
||||
#ifdef UWSGI_SSL
|
||||
if (ud->legion && !uwsgi_legion_i_am_the_lord(ud->legion)) {
|
||||
// part of legion, register but don't spawn it yet
|
||||
if (ud->pidfile) {
|
||||
ud->pid = uwsgi_check_pidfile(ud->pidfile);
|
||||
if (ud->pid > 0)
|
||||
uwsgi_log("[uwsgi-daemons] found valid/active pidfile for \"%s\" (pid: %d)\n", ud->command, (int) ud->pid);
|
||||
}
|
||||
ud->registered = 1;
|
||||
ud = ud->next;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
ud->registered = 1;
|
||||
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 = ud->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_detach_daemons() {
|
||||
struct uwsgi_daemon *ud = uwsgi.daemons;
|
||||
while (ud) {
|
||||
#ifdef UWSGI_SSL
|
||||
// stop any legion daemon, doesn't matter if dumb or smart
|
||||
if (ud->pid > 0 && (ud->legion || !ud->pidfile)) {
|
||||
#else
|
||||
// stop only dumb daemons
|
||||
if (ud->pid > 0 && !ud->pidfile) {
|
||||
#endif
|
||||
uwsgi_log("[uwsgi-daemons] stopping daemon (pid: %d): %s\n", (int) ud->pid, ud->command);
|
||||
// try to gracefully stop daemon, kill it if it won't die
|
||||
// if mercy is not set then wait up to 3 seconds
|
||||
time_t timeout = uwsgi_now() + (uwsgi.reload_mercy ? uwsgi.reload_mercy : 3);
|
||||
int waitpid_status;
|
||||
while (!kill(ud->pid, 0)) {
|
||||
kill(-ud->pid, SIGTERM);
|
||||
sleep(1);
|
||||
waitpid(-ud->pid, &waitpid_status, WNOHANG);
|
||||
if (uwsgi_now() >= timeout) {
|
||||
uwsgi_log("[uwsgi-daemons] daemon did not die in time, killing (pid: %d): %s\n", (int) ud->pid, ud->command);
|
||||
kill(-ud->pid, SIGKILL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// unregister daemon to prevent it from being respawned
|
||||
ud->registered = 0;
|
||||
}
|
||||
ud = ud->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
|
||||
|
||||
// skip unregistered daemons
|
||||
if (!ud->registered) return;
|
||||
|
||||
int throttle = 0;
|
||||
|
||||
if (uwsgi.current_time - ud->last_spawn <= 3) {
|
||||
throttle = ud->respawns - (uwsgi.current_time - ud->last_spawn);
|
||||
// if ud->respawns == 0 then we can end up with throttle < 0
|
||||
if (throttle <= 0) throttle = 1;
|
||||
}
|
||||
|
||||
pid_t pid = uwsgi_fork("uWSGI external daemon");
|
||||
if (pid < 0) {
|
||||
uwsgi_error("fork()");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pid > 0) {
|
||||
ud->has_daemonized = 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
|
||||
uwsgi_remap_fd(0, "/dev/null");
|
||||
}
|
||||
|
||||
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((unsigned int) 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 *space = NULL;
|
||||
|
||||
char *command = uwsgi_str(value);
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
char *legion = NULL;
|
||||
if (!uwsgi_starts_with(opt, strlen(command), "legion-", 7)) {
|
||||
space = strchr(command, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid legion daemon syntax: %s\n", command);
|
||||
exit(1);
|
||||
}
|
||||
*space = 0;
|
||||
legion = command;
|
||||
command = space+1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!strcmp(opt, "smart-attach-daemon") || !strcmp(opt, "smart-attach-daemon2") || !strcmp(opt, "legion-smart-attach-daemon") || !strcmp(opt, "legion-smart-attach-daemon2")) {
|
||||
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") || !strcmp(opt, "legion-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_ud->control = 0;
|
||||
if (!strcmp(opt, "attach-control-daemon")) {
|
||||
uwsgi_ud->control = 1;
|
||||
}
|
||||
#ifdef UWSGI_SSL
|
||||
uwsgi_ud->legion = legion;
|
||||
#endif
|
||||
|
||||
uwsgi.daemons_cnt++;
|
||||
|
||||
}
|
||||
+992
-225
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;
|
||||
}
|
||||
|
||||
+792
-316
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 (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.exception_handler_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() {
|
||||
if (!uwsgi.exception_handlers_instance) return;
|
||||
// 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);
|
||||
}
|
||||
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/*
|
||||
|
||||
the --master-fifo option create a unix named pipe (fifo) you can use to send management
|
||||
commands to the master:
|
||||
|
||||
echo r > myfifo
|
||||
|
||||
*/
|
||||
|
||||
// this var can be accessed by plugins and hooks
|
||||
void (*uwsgi_fifo_table[256])(int);
|
||||
|
||||
static char *uwsgi_fifo_by_slot() {
|
||||
int count = 0;
|
||||
struct uwsgi_string_list *usl;
|
||||
uwsgi_foreach(usl, uwsgi.master_fifo) {
|
||||
if (count == uwsgi.master_fifo_slot) return usl->value;
|
||||
count++;
|
||||
}
|
||||
return uwsgi.master_fifo->value;
|
||||
}
|
||||
|
||||
static void uwsgi_fifo_set_slot_zero() { uwsgi.master_fifo_slot = 0; }
|
||||
static void uwsgi_fifo_set_slot_one() { uwsgi.master_fifo_slot = 1; }
|
||||
static void uwsgi_fifo_set_slot_two() { uwsgi.master_fifo_slot = 2; }
|
||||
static void uwsgi_fifo_set_slot_three() { uwsgi.master_fifo_slot = 3; }
|
||||
static void uwsgi_fifo_set_slot_four() { uwsgi.master_fifo_slot = 4; }
|
||||
static void uwsgi_fifo_set_slot_five() { uwsgi.master_fifo_slot = 5; }
|
||||
static void uwsgi_fifo_set_slot_six() { uwsgi.master_fifo_slot = 6; }
|
||||
static void uwsgi_fifo_set_slot_seven() { uwsgi.master_fifo_slot = 7; }
|
||||
static void uwsgi_fifo_set_slot_eight() { uwsgi.master_fifo_slot = 8; }
|
||||
static void uwsgi_fifo_set_slot_nine() { uwsgi.master_fifo_slot = 9; }
|
||||
|
||||
/*
|
||||
|
||||
this is called as soon as possibile allowing plugins (or hooks) to override it
|
||||
|
||||
*/
|
||||
void uwsgi_master_fifo_prepare() {
|
||||
int i;
|
||||
for(i=0;i<256;i++) {
|
||||
uwsgi_fifo_table[i] = NULL;
|
||||
}
|
||||
|
||||
uwsgi_fifo_table['0'] = uwsgi_fifo_set_slot_zero;
|
||||
uwsgi_fifo_table['1'] = uwsgi_fifo_set_slot_one;
|
||||
uwsgi_fifo_table['2'] = uwsgi_fifo_set_slot_two;
|
||||
uwsgi_fifo_table['3'] = uwsgi_fifo_set_slot_three;
|
||||
uwsgi_fifo_table['4'] = uwsgi_fifo_set_slot_four;
|
||||
uwsgi_fifo_table['5'] = uwsgi_fifo_set_slot_five;
|
||||
uwsgi_fifo_table['6'] = uwsgi_fifo_set_slot_six;
|
||||
uwsgi_fifo_table['7'] = uwsgi_fifo_set_slot_seven;
|
||||
uwsgi_fifo_table['8'] = uwsgi_fifo_set_slot_eight;
|
||||
uwsgi_fifo_table['9'] = uwsgi_fifo_set_slot_nine;
|
||||
|
||||
uwsgi_fifo_table['-'] = uwsgi_cheaper_decrease;
|
||||
uwsgi_fifo_table['+'] = uwsgi_cheaper_increase;
|
||||
uwsgi_fifo_table['c'] = uwsgi_chain_reload;
|
||||
uwsgi_fifo_table['C'] = uwsgi_go_cheap;
|
||||
uwsgi_fifo_table['f'] = uwsgi_refork_master;
|
||||
uwsgi_fifo_table['l'] = uwsgi_log_reopen;
|
||||
uwsgi_fifo_table['L'] = uwsgi_log_rotate;
|
||||
uwsgi_fifo_table['p'] = suspend_resume_them_all;
|
||||
uwsgi_fifo_table['P'] = uwsgi_update_pidfiles;
|
||||
uwsgi_fifo_table['q'] = gracefully_kill_them_all;
|
||||
uwsgi_fifo_table['Q'] = kill_them_all;
|
||||
uwsgi_fifo_table['r'] = grace_them_all;
|
||||
uwsgi_fifo_table['R'] = reap_them_all;
|
||||
uwsgi_fifo_table['s'] = stats;
|
||||
uwsgi_fifo_table['w'] = uwsgi_reload_workers;
|
||||
uwsgi_fifo_table['W'] = uwsgi_brutally_reload_workers;
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_master_fifo() {
|
||||
|
||||
char *path = uwsgi_fifo_by_slot();
|
||||
|
||||
unlink(path);
|
||||
|
||||
if (mkfifo(path, S_IRUSR|S_IWUSR)) {
|
||||
uwsgi_error("uwsgi_master_fifo()/mkfifo()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int fd = open(path, O_RDONLY|O_NONBLOCK);
|
||||
if (fd < 0) {
|
||||
uwsgi_error("uwsgi_master_fifo()/open()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_socket_nb(fd);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int uwsgi_master_fifo_manage(int fd) {
|
||||
unsigned char cmd;
|
||||
ssize_t rlen = read(fd, &cmd, 1);
|
||||
if (rlen < 0) {
|
||||
if (uwsgi_is_again()) return 0;
|
||||
uwsgi_error("uwsgi_master_fifo_manage()/read()");
|
||||
exit(1);
|
||||
}
|
||||
// fifo destroyed, recreate it
|
||||
else if (rlen == 0) {
|
||||
close(fd);
|
||||
uwsgi.master_fifo_fd = uwsgi_master_fifo();
|
||||
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.master_fifo_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (uwsgi_fifo_table[(int) cmd]) {
|
||||
uwsgi_fifo_table[(int) cmd](0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#ifdef UWSGI_EVENT_FILEMONITOR_USE_INOTIFY
|
||||
#ifndef OBSOLETE_LINUX_KERNEL
|
||||
#include <sys/inotify.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
void uwsgi_fsmon_setup() {
|
||||
struct uwsgi_string_list *usl = uwsgi.fs_reload;
|
||||
while(usl) {
|
||||
if (uwsgi_register_fsmon(usl)) {
|
||||
uwsgi_log("[uwsgi-fsmon] unable to register monitor for \"%s\"\n", usl->value);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[uwsgi-fsmon] registered monitor for \"%s\"\n", usl->value);
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
usl = uwsgi.fs_brutal_reload;
|
||||
while(usl) {
|
||||
if (uwsgi_register_fsmon(usl)) {
|
||||
uwsgi_log("[uwsgi-fsmon] unable to register monitor for \"%s\"\n", usl->value);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[uwsgi-fsmon] registered monitor for \"%s\"\n", usl->value);
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
usl = uwsgi.fs_signal;
|
||||
while(usl) {
|
||||
char *copy = uwsgi_str(usl->value);
|
||||
char *space = strchr(copy, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("[uwsgi-fsmon] invalid syntax: \"%s\"\n", usl->value);
|
||||
free(copy);
|
||||
goto next;
|
||||
}
|
||||
*space = 0;
|
||||
usl->value = copy;
|
||||
usl->len = strlen(copy);
|
||||
usl->custom_ptr = space+1;
|
||||
if (uwsgi_register_fsmon(usl)) {
|
||||
uwsgi_log("[uwsgi-fsmon] unable to register monitor for \"%s\"\n", usl->value);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[uwsgi-fsmon] registered monitor for \"%s\"\n", usl->value);
|
||||
}
|
||||
next:
|
||||
usl = usl->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_register_fsmon(struct uwsgi_string_list *usl) {
|
||||
#ifdef UWSGI_EVENT_FILEMONITOR_USE_INOTIFY
|
||||
#ifndef OBSOLETE_LINUX_KERNEL
|
||||
static int inotify_fd = -1;
|
||||
if (inotify_fd == -1) {
|
||||
inotify_fd = inotify_init();
|
||||
if (inotify_fd < 0) {
|
||||
uwsgi_error("uwsgi_register_fsmon()/inotify_init()");
|
||||
return -1;
|
||||
}
|
||||
if (event_queue_add_fd_read(uwsgi.master_queue, inotify_fd)) {
|
||||
uwsgi_error("uwsgi_register_fsmon()/event_queue_add_fd_read()");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
int wd = inotify_add_watch(inotify_fd, usl->value, IN_ATTRIB | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_MOVED_FROM | IN_MOVED_TO);
|
||||
if (wd < 0) {
|
||||
uwsgi_error("uwsgi_register_fsmon()/inotify_add_watch()");
|
||||
return -1;
|
||||
}
|
||||
usl->custom = inotify_fd;
|
||||
usl->custom2 = wd;
|
||||
return 0;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef UWSGI_EVENT_FILEMONITOR_USE_KQUEUE
|
||||
struct kevent kev;
|
||||
int fd = open(usl->value, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
uwsgi_error_open(usl->value);
|
||||
uwsgi_error("uwsgi_register_fsmon()/open()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE | NOTE_DELETE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE, 0, 0);
|
||||
if (kevent(uwsgi.master_queue, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("uwsgi_register_fsmon()/kevent()");
|
||||
return -1;
|
||||
}
|
||||
usl->custom = fd;
|
||||
usl->custom2 = fd;
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
uwsgi_log("[uwsgi-fsmon] filesystem monitoring interface not available in this platform !!!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct uwsgi_string_list *uwsgi_fsmon_ack(int interesting_fd) {
|
||||
int found_fd = -1;
|
||||
struct uwsgi_string_list *usl = uwsgi.fs_reload;
|
||||
while(usl) {
|
||||
if ((int)usl->custom == interesting_fd) {
|
||||
found_fd = usl->custom;
|
||||
goto found;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
usl = uwsgi.fs_brutal_reload;
|
||||
while(usl) {
|
||||
if ((int)usl->custom == interesting_fd) {
|
||||
found_fd = usl->custom;
|
||||
goto found;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
usl = uwsgi.fs_signal;
|
||||
while(usl) {
|
||||
if ((int)usl->custom == interesting_fd) {
|
||||
found_fd = usl->custom;
|
||||
goto found;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
found:
|
||||
if (found_fd == -1) return NULL;
|
||||
#ifdef UWSGI_EVENT_FILEMONITOR_USE_INOTIFY
|
||||
#ifndef OBSOLETE_LINUX_KERNEL
|
||||
unsigned int isize = 0;
|
||||
if (ioctl(found_fd, FIONREAD, &isize) < 0) {
|
||||
uwsgi_error("uwsgi_fsmon_ack()/ioctl()");
|
||||
return 0;
|
||||
}
|
||||
if (isize == 0) return NULL;
|
||||
struct inotify_event *ie = uwsgi_malloc(isize);
|
||||
// read from the inotify descriptor
|
||||
ssize_t len = read(found_fd, ie, isize);
|
||||
if (len < 0) { free(ie); uwsgi_error("uwsgi_fsmon_ack()/read()"); return NULL;}
|
||||
found_fd = ie->wd;
|
||||
free(ie);
|
||||
#endif
|
||||
#endif
|
||||
// search for the item id and print it
|
||||
usl = uwsgi.fs_reload;
|
||||
while(usl) {
|
||||
if ((int)usl->custom2 == found_fd) {
|
||||
uwsgi_log("[uwsgi-fsmon] \"%s\" has been modified\n", usl->value);
|
||||
return uwsgi.fs_reload;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
usl = uwsgi.fs_brutal_reload;
|
||||
while(usl) {
|
||||
if ((int)usl->custom2 == found_fd) {
|
||||
uwsgi_log("[uwsgi-fsmon] \"%s\" has been modified\n", usl->value);
|
||||
return uwsgi.fs_brutal_reload;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
usl = uwsgi.fs_signal;
|
||||
while(usl) {
|
||||
if ((int)usl->custom2 == found_fd) {
|
||||
uwsgi_log("[uwsgi-fsmon] \"%s\" has been modified\n", usl->value);
|
||||
return usl;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int uwsgi_fsmon_event(int interesting_fd) {
|
||||
|
||||
struct uwsgi_string_list *usl = uwsgi_fsmon_ack(interesting_fd);
|
||||
|
||||
if (!usl) return 0;
|
||||
|
||||
if (usl == uwsgi.fs_reload) {
|
||||
uwsgi_block_signal(SIGHUP);
|
||||
grace_them_all(0);
|
||||
uwsgi_unblock_signal(SIGHUP);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (usl == uwsgi.fs_brutal_reload) {
|
||||
if (uwsgi.die_on_term) {
|
||||
uwsgi_block_signal(SIGQUIT);
|
||||
reap_them_all(0);
|
||||
uwsgi_unblock_signal(SIGQUIT);
|
||||
}
|
||||
else {
|
||||
uwsgi_block_signal(SIGTERM);
|
||||
reap_them_all(0);
|
||||
uwsgi_unblock_signal(SIGTERM);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// fallback to signal
|
||||
uwsgi_route_signal(atoi(usl->custom_ptr));
|
||||
return 1;
|
||||
}
|
||||
|
||||
+97
-82
@@ -2,43 +2,56 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_gateway *register_gateway(char *name, void (*loop)(int, void *), void *data) {
|
||||
struct uwsgi_gateway *register_gateway(char *name, void (*loop) (int, void *), void *data) {
|
||||
|
||||
struct uwsgi_gateway *ug;
|
||||
int num=1,i;
|
||||
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;
|
||||
}
|
||||
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++;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < ushared->gateways_cnt; i++) {
|
||||
if (!strcmp(name, ushared->gateways[i].name)) {
|
||||
num++;
|
||||
}
|
||||
}
|
||||
|
||||
char *fullname = uwsgi_concat3(name, " ", uwsgi_num2str(num));
|
||||
char *str = uwsgi_num2str(num);
|
||||
char *fullname = uwsgi_concat3(name, " ", str);
|
||||
free(str);
|
||||
|
||||
ug = &ushared->gateways[ushared->gateways_cnt];
|
||||
ug->pid = 0;
|
||||
ug->name = name;
|
||||
ug->loop = loop;
|
||||
ug->num = 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 defined(SOCK_SEQPACKET) && defined(__linux__)
|
||||
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, ug->internal_subscription_pipe)) {
|
||||
#else
|
||||
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, ug->internal_subscription_pipe)) {
|
||||
#endif
|
||||
uwsgi_error("socketpair()");
|
||||
}
|
||||
|
||||
if (!uwsgi.master_process)
|
||||
uwsgi_socket_nb(ug->internal_subscription_pipe[0]);
|
||||
uwsgi_socket_nb(ug->internal_subscription_pipe[1]);
|
||||
|
||||
if (!uwsgi.master_process && !uwsgi.force_gateway)
|
||||
gateway_respawn(ushared->gateways_cnt);
|
||||
|
||||
ushared->gateways_cnt++;
|
||||
ushared->gateways_cnt++;
|
||||
|
||||
|
||||
return ug;
|
||||
return ug;
|
||||
}
|
||||
|
||||
static void gateway_brutal_end() {
|
||||
_exit(UWSGI_END_CODE);
|
||||
}
|
||||
|
||||
void gateway_respawn(int id) {
|
||||
@@ -48,114 +61,116 @@ void gateway_respawn(int id) {
|
||||
|
||||
if (uwsgi.master_process)
|
||||
uwsgi.shared->gateways_harakiri[id] = 0;
|
||||
|
||||
|
||||
gw_pid = uwsgi_fork(ug->fullname);
|
||||
if (gw_pid < 0) {
|
||||
uwsgi_error("fork()");
|
||||
uwsgi_error("fork()");
|
||||
return;
|
||||
}
|
||||
|
||||
if (gw_pid == 0) {
|
||||
uwsgi_fixup_fds(0, 0, ug);
|
||||
if (uwsgi.master_as_root) uwsgi_as_root();
|
||||
uwsgi_close_all_sockets();
|
||||
if (uwsgi.master_as_root)
|
||||
uwsgi_as_root();
|
||||
#ifdef __linux__
|
||||
if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0,0,0)) {
|
||||
uwsgi_error("prctl()");
|
||||
}
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
uwsgi_sock = uwsgi_malloc(sizeof(struct uwsgi_gateway_socket));
|
||||
old_uwsgi_sock->next = uwsgi_sock;
|
||||
}
|
||||
|
||||
memset(uwsgi_sock, 0, sizeof(struct uwsgi_gateway_socket));
|
||||
memset(uwsgi_sock, 0, sizeof(struct uwsgi_gateway_socket));
|
||||
uwsgi_sock->fd = -1;
|
||||
uwsgi_sock->shared = 0;
|
||||
uwsgi_sock->name = name;
|
||||
uwsgi_sock->name = name;
|
||||
uwsgi_sock->name_len = strlen(name);
|
||||
uwsgi_sock->owner = owner;
|
||||
|
||||
return uwsgi_sock;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
uwsgi_sock = uwsgi_malloc(sizeof(struct uwsgi_gateway_socket));
|
||||
old_uwsgi_sock->next = uwsgi_sock;
|
||||
}
|
||||
|
||||
memset(uwsgi_sock, 0, sizeof(struct uwsgi_gateway_socket));
|
||||
memset(uwsgi_sock, 0, sizeof(struct uwsgi_gateway_socket));
|
||||
uwsgi_sock->fd = fd;
|
||||
uwsgi_sock->name = uwsgi_getsockname(fd);
|
||||
uwsgi_sock->name = uwsgi_getsockname(fd);
|
||||
uwsgi_sock->name_len = strlen(uwsgi_sock->name);
|
||||
uwsgi_sock->owner = owner;
|
||||
uwsgi_sock->owner = owner;
|
||||
|
||||
return uwsgi_sock;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
#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
|
||||
static 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;
|
||||
}
|
||||
|
||||
static uint32_t random_hash(char *key, uint64_t keylen) {
|
||||
return (uint32_t) rand();
|
||||
}
|
||||
|
||||
/*
|
||||
not atomic, avoid its use in multithreaded modes
|
||||
*/
|
||||
static uint32_t rr_hash(char *key, uint64_t keylen) {
|
||||
static uint32_t rr = 0;
|
||||
uint32_t max_value = uwsgi_str_num(key, keylen);
|
||||
uint32_t ret = rr;
|
||||
rr++;
|
||||
if (rr > max_value) {
|
||||
rr = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
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);
|
||||
uwsgi_hash_algo_register("random", random_hash);
|
||||
uwsgi_hash_algo_register("rand", random_hash);
|
||||
uwsgi_hash_algo_register("rr", rr_hash);
|
||||
}
|
||||
+217
@@ -0,0 +1,217 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/*
|
||||
|
||||
advanced (pluggable) hooks
|
||||
|
||||
they are executed before the other hooks, and can be extended by plugins
|
||||
|
||||
if a plugin tries to register an hook with a name already available in the list, its function
|
||||
will be overridden
|
||||
|
||||
*/
|
||||
|
||||
struct uwsgi_hook *uwsgi_hook_by_name(char *name) {
|
||||
struct uwsgi_hook *uh = uwsgi.hooks;
|
||||
while(uh) {
|
||||
if (!strcmp(uh->name, name)) {
|
||||
return uh;
|
||||
}
|
||||
uh = uh->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void uwsgi_register_hook(char *name, int (*func)(char *)) {
|
||||
struct uwsgi_hook *old_uh = NULL, *uh = uwsgi.hooks;
|
||||
while(uh) {
|
||||
if (!strcmp(uh->name, name)) {
|
||||
uh->func = func;
|
||||
return;
|
||||
}
|
||||
old_uh = uh;
|
||||
uh = uh->next;
|
||||
}
|
||||
|
||||
uh = uwsgi_calloc(sizeof(struct uwsgi_hook));
|
||||
uh->name = name;
|
||||
uh->func = func;
|
||||
|
||||
if (old_uh) {
|
||||
old_uh->next = uh;
|
||||
}
|
||||
else {
|
||||
uwsgi.hooks = uh;
|
||||
}
|
||||
}
|
||||
|
||||
static int uwsgi_hook_chdir(char *arg) {
|
||||
int ret = chdir(arg);
|
||||
if (ret) {
|
||||
uwsgi_error("uwsgi_hook_chdir()");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int uwsgi_hook_exec(char *arg) {
|
||||
int ret = uwsgi_run_command_and_wait(NULL, arg);
|
||||
if (ret != 0) {
|
||||
uwsgi_log("command \"%s\" exited with non-zero code: %d\n", arg, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int uwsgi_hook_exit(char *arg) {
|
||||
int exit_code = 0;
|
||||
if (strlen(arg) > 1) {
|
||||
exit_code = atoi(arg);
|
||||
}
|
||||
exit(exit_code);
|
||||
}
|
||||
|
||||
static int uwsgi_hook_print(char *arg) {
|
||||
char *line = uwsgi_concat2(arg, "\n");
|
||||
uwsgi_log(line);
|
||||
free(line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_hook_callint(char *arg) {
|
||||
char *space = strchr(arg, ' ');
|
||||
if (space) {
|
||||
*space = 0;
|
||||
int num = atoi(space+1);
|
||||
void (*func)(int) = dlsym(RTLD_DEFAULT, arg);
|
||||
if (!func) {
|
||||
uwsgi_log("unable to call function \"%s(%d)\"\n", arg, num);
|
||||
*space = ' ';
|
||||
return -1;
|
||||
}
|
||||
*space = ' ';
|
||||
func(num);
|
||||
}
|
||||
else {
|
||||
void (*func)(void) = dlsym(RTLD_DEFAULT, arg);
|
||||
if (!func) {
|
||||
uwsgi_log("unable to call function \"%s\"\n", arg);
|
||||
return -1;
|
||||
}
|
||||
func();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_hook_call(char *arg) {
|
||||
char *space = strchr(arg, ' ');
|
||||
if (space) {
|
||||
*space = 0;
|
||||
void (*func)(char *) = dlsym(RTLD_DEFAULT, arg);
|
||||
if (!func) {
|
||||
uwsgi_log("unable to call function \"%s(%s)\"\n", arg, space + 1);
|
||||
*space = ' ';
|
||||
return -1;
|
||||
}
|
||||
*space = ' ';
|
||||
func(space + 1);
|
||||
}
|
||||
else {
|
||||
void (*func)(void) = dlsym(RTLD_DEFAULT, arg);
|
||||
if (!func) {
|
||||
uwsgi_log("unable to call function \"%s\"\n", arg);
|
||||
return -1;
|
||||
}
|
||||
func();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_hook_callintret(char *arg) {
|
||||
char *space = strchr(arg, ' ');
|
||||
if (space) {
|
||||
*space = 0;
|
||||
int num = atoi(space+1);
|
||||
int (*func)(int) = dlsym(RTLD_DEFAULT, arg);
|
||||
if (!func) {
|
||||
uwsgi_log("unable to call function \"%s(%d)\"\n", arg, num);
|
||||
*space = ' ';
|
||||
return -1;
|
||||
}
|
||||
*space = ' ';
|
||||
return func(num);
|
||||
}
|
||||
int (*func)(void) = dlsym(RTLD_DEFAULT, arg);
|
||||
if (!func) {
|
||||
uwsgi_log("unable to call function \"%s\"\n", arg);
|
||||
return -1;
|
||||
}
|
||||
return func();
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_hook_callret(char *arg) {
|
||||
char *space = strchr(arg, ' ');
|
||||
if (space) {
|
||||
*space = 0;
|
||||
int (*func)(char *) = dlsym(RTLD_DEFAULT, arg);
|
||||
if (!func) {
|
||||
uwsgi_log("unable to call function \"%s(%s)\"\n", arg, space + 1);
|
||||
*space = ' ';
|
||||
return -1;
|
||||
}
|
||||
*space = ' ';
|
||||
return func(space + 1);
|
||||
}
|
||||
int (*func)(void) = dlsym(RTLD_DEFAULT, arg);
|
||||
if (!func) {
|
||||
uwsgi_log("unable to call function \"%s\"\n", arg);
|
||||
return -1;
|
||||
}
|
||||
return func();
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_register_base_hooks() {
|
||||
uwsgi_register_hook("cd", uwsgi_hook_chdir);
|
||||
uwsgi_register_hook("exec", uwsgi_hook_exec);
|
||||
|
||||
uwsgi_register_hook("mount", uwsgi_mount_hook);
|
||||
uwsgi_register_hook("umount", uwsgi_umount_hook);
|
||||
|
||||
uwsgi_register_hook("call", uwsgi_hook_call);
|
||||
uwsgi_register_hook("callret", uwsgi_hook_callret);
|
||||
|
||||
uwsgi_register_hook("callint", uwsgi_hook_callint);
|
||||
uwsgi_register_hook("callintret", uwsgi_hook_callintret);
|
||||
|
||||
// for testing
|
||||
uwsgi_register_hook("exit", uwsgi_hook_exit);
|
||||
uwsgi_register_hook("print", uwsgi_hook_print);
|
||||
}
|
||||
|
||||
void uwsgi_hooks_run(struct uwsgi_string_list *l, char *phase, int fatal) {
|
||||
struct uwsgi_string_list *usl = NULL;
|
||||
uwsgi_foreach(usl, l) {
|
||||
char *colon = strchr(usl->value, ':');
|
||||
if (!colon) {
|
||||
uwsgi_log("invalid hook syntax, must be hook:args\n");
|
||||
exit(1);
|
||||
}
|
||||
*colon = 0;
|
||||
struct uwsgi_hook *uh = uwsgi_hook_by_name(usl->value);
|
||||
if (!uh) {
|
||||
uwsgi_log("hook not found: %s\n", usl->value);
|
||||
exit(1);
|
||||
}
|
||||
*colon = ':';
|
||||
|
||||
uwsgi_log("running \"%s\" (%s)...\n", usl->value, phase);
|
||||
|
||||
int ret = uh->func(colon+1);
|
||||
if (fatal && ret != 0) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
+40
-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;
|
||||
@@ -91,29 +91,41 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
|
||||
char *section_asked = "uwsgi";
|
||||
char *colon;
|
||||
int got_section = 0;
|
||||
|
||||
|
||||
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 +137,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
|
||||
@@ -136,10 +148,11 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
val = ini_get_key(key);
|
||||
|
||||
if (!strcmp(section, section_asked)) {
|
||||
got_section = 1;
|
||||
ini_rstrip(key);
|
||||
val = ini_lstrip(val);
|
||||
ini_rstrip(val);
|
||||
add_exported_option((char *)key, val, 0);
|
||||
add_exported_option((char *) key, val, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,11 +163,13 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
|
||||
}
|
||||
|
||||
if (!got_section) {
|
||||
uwsgi_log("*** WARNING: Can't find section \"%s\" in INI configuration file %s ***\n", section_asked, file);
|
||||
}
|
||||
|
||||
if (colon) {
|
||||
colon[0] = ':';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+409
-171
@@ -2,104 +2,211 @@
|
||||
|
||||
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"},
|
||||
{"509", "Bandwidth Limit Exceeded"},
|
||||
{"", NULL},
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
void uwsgi_init_default() {
|
||||
|
||||
uwsgi.cpus = 1;
|
||||
|
||||
uwsgi.backtrace_depth = 64;
|
||||
uwsgi.max_apps = 64;
|
||||
uwsgi.max_apps = 64;
|
||||
|
||||
uwsgi.master_queue = -1;
|
||||
uwsgi.master_queue = -1;
|
||||
|
||||
uwsgi.signal_socket = -1;
|
||||
uwsgi.my_signal_socket = -1;
|
||||
uwsgi.cache_server_fd = -1;
|
||||
uwsgi.stats_fd = -1;
|
||||
uwsgi.signal_socket = -1;
|
||||
uwsgi.my_signal_socket = -1;
|
||||
uwsgi.stats_fd = -1;
|
||||
|
||||
uwsgi.original_log_fd = -1;
|
||||
uwsgi.stats_pusher_default_freq = 3;
|
||||
|
||||
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.original_log_fd = -1;
|
||||
|
||||
uwsgi.subscribe_freq = 10;
|
||||
uwsgi.subscription_tolerance = 17;
|
||||
uwsgi.emperor_fd_config = -1;
|
||||
uwsgi.emperor_fd_proxy = -1;
|
||||
// default emperor scan frequency
|
||||
uwsgi.emperor_freq = 3;
|
||||
uwsgi.emperor_throttle = 1000;
|
||||
uwsgi.emperor_heartbeat = 30;
|
||||
uwsgi.emperor_curse_tolerance = 30;
|
||||
// max 3 minutes throttling
|
||||
uwsgi.emperor_max_throttle = 1000 * 180;
|
||||
uwsgi.emperor_pid = -1;
|
||||
|
||||
uwsgi.cluster_fd = -1;
|
||||
uwsgi.cores = 1;
|
||||
uwsgi.threads = 1;
|
||||
uwsgi.subscribe_freq = 10;
|
||||
uwsgi.subscription_tolerance = 17;
|
||||
|
||||
uwsgi.default_app = -1;
|
||||
uwsgi.cores = 1;
|
||||
uwsgi.threads = 1;
|
||||
|
||||
uwsgi.buffer_size = 4096;
|
||||
uwsgi.numproc = 1;
|
||||
// default max number of rpc slot
|
||||
uwsgi.rpc_max = 64;
|
||||
|
||||
uwsgi.forkbomb_delay = 2;
|
||||
uwsgi.offload_threads_events = 64;
|
||||
|
||||
uwsgi.async = 1;
|
||||
uwsgi.listen_queue = 100;
|
||||
uwsgi.default_app = -1;
|
||||
|
||||
uwsgi.cheaper_overload = 3;
|
||||
uwsgi.buffer_size = 4096;
|
||||
uwsgi.body_read_warning = 8;
|
||||
uwsgi.numproc = 1;
|
||||
|
||||
uwsgi.log_master_bufsize = 8192;
|
||||
uwsgi.forkbomb_delay = 2;
|
||||
|
||||
uwsgi.max_vars = MAX_VARS;
|
||||
uwsgi.vec_size = 4 + 1 + (4 * MAX_VARS);
|
||||
uwsgi.async = 1;
|
||||
uwsgi.listen_queue = 100;
|
||||
|
||||
uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] = 4;
|
||||
uwsgi.shared->options[UWSGI_OPTION_LOGGING] = 1;
|
||||
uwsgi.cheaper_overload = 3;
|
||||
|
||||
#ifdef UWSGI_SPOOLER
|
||||
uwsgi.shared->spooler_frequency = 30;
|
||||
uwsgi.log_master_bufsize = 8192;
|
||||
|
||||
uwsgi.shared->spooler_signal_pipe[0] = -1;
|
||||
uwsgi.shared->spooler_signal_pipe[1] = -1;
|
||||
#endif
|
||||
uwsgi.shared->mule_signal_pipe[0] = -1;
|
||||
uwsgi.shared->mule_signal_pipe[1] = -1;
|
||||
uwsgi.worker_reload_mercy = 60;
|
||||
|
||||
uwsgi.shared->mule_queue_pipe[0] = -1;
|
||||
uwsgi.shared->mule_queue_pipe[1] = -1;
|
||||
uwsgi.max_vars = MAX_VARS;
|
||||
uwsgi.vec_size = 4 + 1 + (4 * MAX_VARS);
|
||||
|
||||
uwsgi.shared->worker_log_pipe[0] = -1;
|
||||
uwsgi.shared->worker_log_pipe[1] = -1;
|
||||
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;
|
||||
// 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 = "";
|
||||
|
||||
#ifdef __linux__
|
||||
uwsgi.cgroup_dir_mode = "0700";
|
||||
#endif
|
||||
|
||||
uwsgi.wait_read_hook = uwsgi_simple_wait_read_hook;
|
||||
uwsgi.wait_write_hook = uwsgi_simple_wait_write_hook;
|
||||
|
||||
uwsgi_websockets_init();
|
||||
|
||||
// 1 MB default limit
|
||||
uwsgi.chunked_input_limit = 1024*1024;
|
||||
|
||||
// clear reforked status
|
||||
uwsgi.master_is_reforked = 0;
|
||||
|
||||
uwsgi.master_fifo_fd = -1;
|
||||
uwsgi_master_fifo_prepare();
|
||||
}
|
||||
|
||||
void uwsgi_setup_reload() {
|
||||
|
||||
char env_reload_buf[11];
|
||||
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()");
|
||||
}
|
||||
}
|
||||
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()");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -108,33 +215,31 @@ 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, "_");
|
||||
}
|
||||
}
|
||||
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) {
|
||||
char *ctx = NULL;
|
||||
uwsgi_foreach_token(uwsgi_str(p + 6), "_", plugins_requested, ctx) {
|
||||
uwsgi_log("[uwsgi] implicit plugin requested %s\n", plugins_requested);
|
||||
uwsgi_load_plugin(-1, plugins_requested, 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, ",");
|
||||
}
|
||||
}
|
||||
plugins_requested = getenv("UWSGI_PLUGINS");
|
||||
if (plugins_requested) {
|
||||
plugins_requested = uwsgi_concat2(plugins_requested, "");
|
||||
char *p, *ctx = NULL;
|
||||
uwsgi_foreach_token(plugins_requested, ",", p, ctx) {
|
||||
uwsgi_load_plugin(-1, p, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -143,112 +248,245 @@ void uwsgi_commandline_config() {
|
||||
|
||||
uwsgi.option_index = -1;
|
||||
|
||||
char *optname;
|
||||
while ((i = getopt_long(uwsgi.argc, uwsgi.argv, uwsgi.short_options, uwsgi.long_options, &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 (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);
|
||||
}
|
||||
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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
int i, j;
|
||||
// allocate shared memory for workers + master
|
||||
uwsgi.workers = (struct uwsgi_worker *) uwsgi_calloc_shared(sizeof(struct uwsgi_worker) * (uwsgi.numproc + 1 + uwsgi.grunt));
|
||||
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);
|
||||
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);
|
||||
// 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);
|
||||
void *buffers = uwsgi_malloc_shared(uwsgi.buffer_size * uwsgi.cores);
|
||||
void *hvec = uwsgi_malloc_shared(sizeof(struct iovec) * uwsgi.vec_size * uwsgi.cores);
|
||||
// add 4 bytes for uwsgi header
|
||||
void *buffers = uwsgi_malloc_shared((uwsgi.buffer_size+4) * uwsgi.cores);
|
||||
void *hvec = uwsgi_malloc_shared(sizeof(struct iovec) * uwsgi.vec_size * uwsgi.cores);
|
||||
void *post_buf = NULL;
|
||||
if (uwsgi.post_buffering > 0)
|
||||
post_buf = uwsgi_malloc_shared(uwsgi.post_buffering_bufsize * uwsgi.cores);
|
||||
|
||||
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
|
||||
uwsgi.workers[i].cores[j].buffer = buffers + (uwsgi.buffer_size * 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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
// 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);
|
||||
uwsgi_log("mapped %llu bytes (%llu KB) for %d cores\n", total_memory, total_memory / 1024, uwsgi.cores*uwsgi.numproc);
|
||||
if (uwsgi.numproc > 0)
|
||||
uwsgi_log("mapped %llu bytes (%llu KB) for %d cores\n", (unsigned long long) total_memory, (unsigned long long) (total_memory / 1024), uwsgi.cores * uwsgi.numproc);
|
||||
|
||||
// allocate signal table
|
||||
uwsgi.shared->signal_table = uwsgi_calloc_shared(sizeof(struct uwsgi_signal_entry) * 256 * (uwsgi.numproc + 1));
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
uwsgi_fixup_routes(uwsgi.routes);
|
||||
uwsgi_fixup_routes(uwsgi.error_routes);
|
||||
uwsgi_fixup_routes(uwsgi.response_routes);
|
||||
uwsgi_fixup_routes(uwsgi.final_routes);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (uwsgi.log_master) uwsgi_setup_log_master();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (uwsgi.cheaper_rss_limit_soft && uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG] != 1 && uwsgi.force_get_memusage != 1) {
|
||||
uwsgi_log("enabling cheaper-rss-limit-soft requires enabling also memory-report\n");
|
||||
exit(1);
|
||||
}
|
||||
if (uwsgi.cheaper_rss_limit_hard && !uwsgi.cheaper_rss_limit_soft) {
|
||||
uwsgi_log("enabling cheaper-rss-limit-hard requires setting also cheaper-rss-limit-soft\n");
|
||||
exit(1);
|
||||
}
|
||||
if ( uwsgi.cheaper_rss_limit_hard && uwsgi.cheaper_rss_limit_hard <= uwsgi.cheaper_rss_limit_soft) {
|
||||
uwsgi_log("cheaper-rss-limit-hard value must be higher than cheaper-rss-limit-soft value\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* here we try to choose if thunder lock is a good thing */
|
||||
#ifdef UNBIT
|
||||
if (uwsgi.numproc > 1 && !uwsgi.map_socket) {
|
||||
uwsgi.use_thunder_lock = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
+33
-31
@@ -13,7 +13,7 @@ extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_json_config(char *file, char *magic_table[]) {
|
||||
|
||||
int len = 0;
|
||||
size_t len = 0;
|
||||
char *json_data;
|
||||
|
||||
|
||||
@@ -31,25 +31,25 @@ void uwsgi_json_config(char *file, char *magic_table[]) {
|
||||
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, ':');
|
||||
}
|
||||
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;
|
||||
object_asked = colon + 1;
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("[uWSGI] getting JSON configuration from %s\n", file);
|
||||
uwsgi_log_initial("[uWSGI] getting JSON configuration from %s\n", file);
|
||||
|
||||
json_data = uwsgi_open_and_read(file, &len, 1, magic_table);
|
||||
|
||||
#ifdef JANSSON_MAJOR_VERSION
|
||||
#ifdef JANSSON_MAJOR_VERSION
|
||||
root = json_loads(json_data, 0, &error);
|
||||
#else
|
||||
root = json_loads(json_data, &error);
|
||||
@@ -66,46 +66,48 @@ void uwsgi_json_config(char *file, char *magic_table[]) {
|
||||
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) {
|
||||
while (config_iter) {
|
||||
key = json_object_iter_key(config_iter);
|
||||
config_value = json_object_iter_value(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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
if (colon) colon[0] = ':';
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
-369
@@ -1,369 +0,0 @@
|
||||
#ifdef UWSGI_LDAP
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#include <ldap.h>
|
||||
|
||||
#ifndef LDAP_OPT_SUCCESS
|
||||
#define LDAP_OPT_SUCCESS LDAP_SUCCESS
|
||||
#endif
|
||||
|
||||
#ifndef ldap_unbind_ext_s
|
||||
#define ldap_unbind_ext_s ldap_unbind_ext
|
||||
#endif
|
||||
|
||||
void ldap2uwsgi(char *ldapname, char *uwsginame) {
|
||||
char *ptr = uwsginame;
|
||||
|
||||
int i;
|
||||
|
||||
for(i=0;i< (int) strlen(ldapname);i++) {
|
||||
if (isupper( (int)ldapname[i])) {
|
||||
*ptr++ = '-';
|
||||
*ptr++ = tolower( (int) ldapname[i]);
|
||||
}
|
||||
else {
|
||||
*ptr++ = ldapname[i];
|
||||
}
|
||||
}
|
||||
|
||||
*ptr++= 0;
|
||||
}
|
||||
|
||||
int calc_ldap_name(char *name) {
|
||||
int i;
|
||||
int counter = 0;
|
||||
|
||||
for(i=0;i< (int)strlen(name);i++) {
|
||||
if (isupper( (int) name[i])) {
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
return strlen(name) + counter;
|
||||
}
|
||||
|
||||
struct uwsgi_ldap_entry {
|
||||
int num;
|
||||
char names[1024];
|
||||
int has_arg;
|
||||
};
|
||||
|
||||
|
||||
void uwsgi_name_to_ldap(char *src, char *dst) {
|
||||
|
||||
int i;
|
||||
char *ptr = dst;
|
||||
|
||||
memset(dst, 0, 1024);
|
||||
|
||||
strcat(dst, " 'uWSGI");
|
||||
|
||||
ptr+= 7;
|
||||
|
||||
for(i=0;i< (int)strlen(src);i++) {
|
||||
if (src[i] == '-') {
|
||||
i++;
|
||||
*ptr++= toupper( (int) src[i]);
|
||||
}
|
||||
else {
|
||||
*ptr++= src[i];
|
||||
}
|
||||
}
|
||||
|
||||
strcat(dst, "'");
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_ldap_entry *get_ldap_by_num(struct uwsgi_ldap_entry *root, int num, int count) {
|
||||
|
||||
int i;
|
||||
struct uwsgi_ldap_entry *ule;
|
||||
|
||||
for(i=0;i<count;i++) {
|
||||
ule = &root[i];
|
||||
if (ule->num == num) {
|
||||
return ule;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_ldap_entry *search_ldap_cache(struct uwsgi_ldap_entry *root, char *name, int count) {
|
||||
int i;
|
||||
struct uwsgi_ldap_entry *ule;
|
||||
|
||||
for(i=0;i<count;i++) {
|
||||
ule = &root[i];
|
||||
if (uwsgi_list_has_str(ule->names, name+1)) {
|
||||
return ule;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_ldap_entry *get_ldap_names(int *count) {
|
||||
|
||||
struct uwsgi_option *op = uwsgi.options;
|
||||
struct uwsgi_ldap_entry *ule, *entry;
|
||||
char ldap_name[1024];
|
||||
|
||||
*count = 0;
|
||||
|
||||
ule = uwsgi_malloc(sizeof(struct uwsgi_ldap_entry)*uwsgi_count_options(op));
|
||||
|
||||
while( op && op->name ) {
|
||||
|
||||
uwsgi_name_to_ldap((char *)op->name, ldap_name);
|
||||
|
||||
entry = search_ldap_cache(ule, ldap_name, *count);
|
||||
|
||||
if (entry) goto next;
|
||||
|
||||
entry = &ule[*count] ;
|
||||
entry->num = *count;
|
||||
strcpy(entry->names, ldap_name);
|
||||
*count = *count+1;
|
||||
|
||||
entry->has_arg = op->type;
|
||||
|
||||
next:
|
||||
op++;
|
||||
}
|
||||
|
||||
return ule;
|
||||
}
|
||||
|
||||
void uwsgi_opt_ldap_dump_ldif(char *opt, char *foo, void *bar) {
|
||||
|
||||
int i;
|
||||
int items;
|
||||
|
||||
uwsgi_log("\n");
|
||||
uwsgi_log("dn: cn=uwsgi,cn=schema,cn=config\n");
|
||||
uwsgi_log("objectClass: olcSchemaConfig\n");
|
||||
uwsgi_log("cn: uwsgi\n");
|
||||
|
||||
struct uwsgi_ldap_entry *entry, *ule = get_ldap_names(&items);
|
||||
|
||||
for(i=0;i<items;i++) {
|
||||
|
||||
entry = &ule[i];
|
||||
uwsgi_log("olcAttributeTypes: ( 1.3.6.1.4.1.35156.17.4.%d NAME (%s", entry->num, entry->names);
|
||||
|
||||
if (entry->has_arg) {
|
||||
uwsgi_log(" ) SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )\n");
|
||||
}
|
||||
else {
|
||||
uwsgi_log(" ) SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )\n");
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("olcAttributeTypes: ( 1.3.6.1.4.1.35156.17.4.50000 NAME 'uWSGInull' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )\n");
|
||||
|
||||
|
||||
uwsgi_log("olcObjectClasses: ( 1.3.6.1.4.1.35156.17.3.1 NAME 'uWSGIConfig' SUP top AUXILIARY DESC 'uWSGI configuration' MAY ( ");
|
||||
|
||||
|
||||
for(i=0;i<items;i++) {
|
||||
|
||||
entry = &ule[i];
|
||||
|
||||
char *list2 = uwsgi_concat2(entry->names+1, "");
|
||||
char *p = strtok(list2, " ");
|
||||
while (p != NULL) {
|
||||
uwsgi_log("%.*s $ ", strlen(p)-2, p+1);
|
||||
p = strtok(NULL, " ");
|
||||
}
|
||||
|
||||
free(list2);
|
||||
|
||||
}
|
||||
|
||||
uwsgi_log("uWSGInull ))\n");
|
||||
|
||||
uwsgi_log("\n");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void uwsgi_opt_ldap_dump(char *opt, char *foo, void *bar) {
|
||||
|
||||
int i;
|
||||
int items;
|
||||
|
||||
struct uwsgi_ldap_entry *entry, *ule = get_ldap_names(&items);
|
||||
|
||||
for(i=0;i<items;i++) {
|
||||
|
||||
entry = &ule[i];
|
||||
uwsgi_log("attributetype ( 1.3.6.1.4.1.35156.17.4.%d NAME (%s", entry->num, entry->names);
|
||||
|
||||
if (entry->has_arg) {
|
||||
uwsgi_log(" ) SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )\n");
|
||||
}
|
||||
else {
|
||||
uwsgi_log(" ) SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uwsgi_log("attributetype ( 1.3.6.1.4.1.35156.17.4.50000 NAME 'uWSGInull' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )\n");
|
||||
|
||||
uwsgi_log("objectclass ( 1.3.6.1.4.1.35156.17.3.1 NAME 'uWSGIConfig' SUP top AUXILIARY DESC 'uWSGI configuration' MAY ( ");
|
||||
|
||||
for(i=0;i<items;i++) {
|
||||
|
||||
entry = &ule[i];
|
||||
|
||||
char *list2 = uwsgi_concat2(entry->names+1, "");
|
||||
char *p = strtok(list2, " ");
|
||||
while (p != NULL) {
|
||||
uwsgi_log("%.*s $ ", strlen(p)-2, p+1);
|
||||
p = strtok(NULL, " ");
|
||||
}
|
||||
|
||||
free(list2);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
uwsgi_log("uWSGInull ))\n");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void uwsgi_ldap_config(char *url) {
|
||||
|
||||
LDAP *ldp;
|
||||
LDAPMessage *results, *entry;
|
||||
BerElement *ber;
|
||||
struct berval **bervalues;
|
||||
char *attr;
|
||||
char *uwsgi_attr;
|
||||
|
||||
char *url_slash;
|
||||
|
||||
int desired_version = LDAP_VERSION3;
|
||||
int ret;
|
||||
|
||||
LDAPURLDesc *ldap_url;
|
||||
|
||||
if (!ldap_is_ldap_url(url)) {
|
||||
uwsgi_log("invalid LDAP url.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (ldap_url_parse(url, &ldap_url) != LDAP_SUCCESS) {
|
||||
uwsgi_log("unable to parse LDAP url.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_log("[uWSGI] getting LDAP configuration from %s\n", url);
|
||||
|
||||
url_slash = strchr(url, '/');
|
||||
url_slash = strchr(url_slash + 1, '/');
|
||||
|
||||
url_slash = strchr(url_slash + 1, '/');
|
||||
if (url_slash) {
|
||||
url_slash[0] = 0;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_debug("LDAP URL: %s\n", url);
|
||||
uwsgi_debug("LDAP BASE DN: %s\n", ldap_url->lud_dn);
|
||||
#endif
|
||||
|
||||
#if LDAP_API_VERSION >= 3000
|
||||
if ( (ret = ldap_initialize( &ldp, url)) != LDAP_SUCCESS) {
|
||||
uwsgi_log("LDAP: %s\n", ldap_err2string(ret));
|
||||
exit(1);
|
||||
}
|
||||
#else
|
||||
if ( (ldp = ldap_init( ldap_url->lud_host, ldap_url->lud_port)) == NULL) {
|
||||
uwsgi_error("ldap_init()");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if ( (ret = ldap_set_option(ldp, LDAP_OPT_PROTOCOL_VERSION, &desired_version)) != LDAP_OPT_SUCCESS) {
|
||||
uwsgi_log("LDAP: %s\n", ldap_err2string(ret));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
if ( (ret = ldap_search_ext_s(ldp, ldap_url->lud_dn, ldap_url->lud_scope, ldap_url->lud_filter, NULL, 0, NULL, NULL, NULL, 1, &results)) != LDAP_SUCCESS) {
|
||||
uwsgi_log("LDAP: %s\n", ldap_err2string(ret));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_debug("LDAP connection initialized %p\n", ldp);
|
||||
#endif
|
||||
|
||||
free(ldap_url);
|
||||
|
||||
if (ldap_count_entries(ldp, results) < 1) {
|
||||
uwsgi_log("no LDAP entry found\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
entry = ldap_first_entry(ldp, results);
|
||||
|
||||
int found = 0;
|
||||
for( attr = ldap_first_attribute(ldp, entry, &ber); attr != NULL; attr = ldap_next_attribute(ldp, entry, ber)) {
|
||||
if (!strncmp(attr,"uWSGI",5)) {
|
||||
|
||||
found = 1;
|
||||
uwsgi_attr = malloc( calc_ldap_name(attr) + 1 );
|
||||
if (!uwsgi_attr) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ldap2uwsgi(attr+5, uwsgi_attr);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_debug("LDAP attribute: %s = --%s\n", attr, uwsgi_attr);
|
||||
#endif
|
||||
bervalues = ldap_get_values_len(ldp, entry, attr);
|
||||
if (bervalues) {
|
||||
// do not free uwsgi_attr/uwsgi_val;
|
||||
char *uwsgi_val = malloc( bervalues[0]->bv_len + 1 );
|
||||
if (!uwsgi_val) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memcpy(uwsgi_val, bervalues[0]->bv_val, bervalues[0]->bv_len);
|
||||
uwsgi_val[bervalues[0]->bv_len] = 0;
|
||||
|
||||
add_exported_option((char*) uwsgi_attr, uwsgi_val, 0);
|
||||
free(bervalues);
|
||||
}
|
||||
else {
|
||||
free(uwsgi_attr);
|
||||
}
|
||||
}
|
||||
free(attr);
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
uwsgi_log("no uWSGI LDAP entry found\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
free(ber);
|
||||
free(results);
|
||||
|
||||
ldap_unbind_ext_s(ldp, NULL, NULL);
|
||||
|
||||
}
|
||||
#endif
|
||||
+1201
File diff suppressed because it is too large
Load Diff
+361
-148
@@ -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,6 +45,10 @@ static struct uwsgi_lock_item *uwsgi_register_lock(char *id, int rw) {
|
||||
|
||||
#ifdef UWSGI_LOCK_USE_MUTEX
|
||||
|
||||
#ifdef OBSOLETE_LINUX_KERNEL
|
||||
#undef EOWNERDEAD
|
||||
#endif
|
||||
|
||||
#ifdef EOWNERDEAD
|
||||
#define UWSGI_LOCK_ENGINE_NAME "pthread robust mutexes"
|
||||
int uwsgi_pthread_robust_mutexes_enabled = 1;
|
||||
@@ -60,36 +64,49 @@ int uwsgi_pthread_robust_mutexes_enabled = 1;
|
||||
#define UWSGI_RWLOCK_SIZE sizeof(pthread_rwlock_t)
|
||||
#endif
|
||||
|
||||
#ifndef PTHREAD_PRIO_INHERIT
|
||||
int pthread_mutexattr_setprotocol (pthread_mutexattr_t *__attr,
|
||||
int __protocol);
|
||||
#define PTHREAD_PRIO_INHERIT 1
|
||||
#endif
|
||||
|
||||
// REMEMBER lock must contains space for both pthread_mutex_t and pthread_mutexattr_t !!!
|
||||
struct uwsgi_lock_item *uwsgi_lock_fast_init(char *id) {
|
||||
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0);
|
||||
|
||||
struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0);
|
||||
|
||||
#ifdef EOWNERDEAD
|
||||
retry:
|
||||
#endif
|
||||
if (pthread_mutexattr_init(&attr)) {
|
||||
uwsgi_log("unable to allocate mutexattr structure\n");
|
||||
exit(1);
|
||||
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);
|
||||
}
|
||||
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_NP)) {
|
||||
uwsgi_log("unable to make the mutex 'robust'\n");
|
||||
exit(1);
|
||||
}
|
||||
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)) {
|
||||
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");
|
||||
@@ -99,9 +116,9 @@ retry:
|
||||
goto retry;
|
||||
}
|
||||
#endif
|
||||
uwsgi_log("unable to initialize mutex\n");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_log("unable to initialize mutex\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
|
||||
@@ -116,25 +133,25 @@ retry:
|
||||
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
|
||||
}
|
||||
|
||||
@@ -149,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) {
|
||||
@@ -164,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
|
||||
}
|
||||
|
||||
@@ -173,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
|
||||
}
|
||||
|
||||
@@ -182,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
|
||||
}
|
||||
|
||||
@@ -196,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);
|
||||
|
||||
@@ -235,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)
|
||||
|
||||
@@ -275,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)
|
||||
@@ -342,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
|
||||
|
||||
@@ -375,8 +474,6 @@ void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) { uwsgi_unlock_fast(uli);
|
||||
|
||||
#define UWSGI_LOCK_ENGINE_NAME "ipcsem"
|
||||
|
||||
#define UWSGI_IPCSEM_ATEXIT 1
|
||||
|
||||
#endif
|
||||
|
||||
struct uwsgi_lock_item *uwsgi_lock_ipcsem_init(char *id) {
|
||||
@@ -384,10 +481,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;
|
||||
|
||||
@@ -396,18 +493,18 @@ struct uwsgi_lock_item *uwsgi_lock_ipcsem_init(char *id) {
|
||||
if (uwsgi.ftok) {
|
||||
myKey = ftok(uwsgi.ftok, counter);
|
||||
if (myKey < 0) {
|
||||
uwsgi_error("ftok()");
|
||||
uwsgi_error("uwsgi_lock_ipcsem_init()/ftok()");
|
||||
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) {
|
||||
uwsgi_error("semget()");
|
||||
uwsgi_error("uwsgi_lock_ipcsem_init()/semget()");
|
||||
exit(1);
|
||||
}
|
||||
// do this now, to allows triggering of atexit hook in case of problems
|
||||
@@ -415,10 +512,10 @@ struct uwsgi_lock_item *uwsgi_lock_ipcsem_init(char *id) {
|
||||
|
||||
semu.val = 1;
|
||||
if (semctl(semid, 0, SETVAL, semu)) {
|
||||
uwsgi_error("semctl()");
|
||||
uwsgi_error("uwsgi_lock_ipcsem_init()/semctl()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
return uli;
|
||||
}
|
||||
|
||||
@@ -432,9 +529,17 @@ void uwsgi_lock_ipcsem(struct uwsgi_lock_item *uli) {
|
||||
|
||||
memcpy(&semid, uli->lock_ptr, sizeof(int));
|
||||
|
||||
retry:
|
||||
if (semop(semid, &sb, 1)) {
|
||||
uwsgi_error("semop()");
|
||||
}
|
||||
if (errno == EINTR) goto retry;
|
||||
uwsgi_error("uwsgi_lock_ipcsem()/semop()");
|
||||
#ifdef EIDRM
|
||||
if (errno == EIDRM) {
|
||||
exit(UWSGI_BRUTAL_RELOAD_CODE);
|
||||
}
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_unlock_ipcsem(struct uwsgi_lock_item *uli) {
|
||||
@@ -447,16 +552,32 @@ void uwsgi_unlock_ipcsem(struct uwsgi_lock_item *uli) {
|
||||
|
||||
memcpy(&semid, uli->lock_ptr, sizeof(int));
|
||||
|
||||
retry:
|
||||
if (semop(semid, &sb, 1)) {
|
||||
uwsgi_error("semop()");
|
||||
}
|
||||
if (errno == EINTR) goto retry;
|
||||
uwsgi_error("uwsgi_unlock_ipcsem()/semop()");
|
||||
#ifdef EIDRM
|
||||
if (errno == EIDRM) {
|
||||
exit(UWSGI_BRUTAL_RELOAD_CODE);
|
||||
}
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -465,15 +586,21 @@ pid_t uwsgi_lock_ipcsem_check(struct uwsgi_lock_item *uli) {
|
||||
|
||||
void uwsgi_ipcsem_clear(void) {
|
||||
|
||||
if (uwsgi.persistent_ipcsem) return;
|
||||
|
||||
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;
|
||||
|
||||
@@ -482,22 +609,69 @@ clear:
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("removing sysvipc semaphores...\n");
|
||||
#endif
|
||||
while(uli) {
|
||||
#ifdef GETPID
|
||||
while (uli) {
|
||||
int semid = 0;
|
||||
memcpy(&semid, uli->lock_ptr, sizeof(int));
|
||||
int ret = semctl(semid, 0, GETPID);
|
||||
if (ret > 0) {
|
||||
if (ret != (int) getpid() && !kill((pid_t) ret, 0)) {
|
||||
uwsgi_log("found ipcsem mapped to alive pid %d. skipping ipcsem removal.\n", ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
uli = uli->next;
|
||||
}
|
||||
uli = uwsgi.registered_locks;
|
||||
#endif
|
||||
while (uli) {
|
||||
int semid = 0;
|
||||
memcpy(&semid, uli->lock_ptr, sizeof(int));
|
||||
if (semctl(semid, 0, IPC_RMID)) {
|
||||
uwsgi_error("semctl()");
|
||||
uwsgi_error("uwsgi_ipcsem_clear()/semctl()");
|
||||
}
|
||||
uli = uli->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#ifdef UNBIT
|
||||
/*
|
||||
Unbit-specific workaround for robust-mutexes
|
||||
*/
|
||||
void *uwsgi_robust_mutexes_watchdog_loop(void *arg) {
|
||||
for(;;) {
|
||||
uwsgi_lock(uwsgi.the_thunder_lock);
|
||||
uwsgi_unlock(uwsgi.the_thunder_lock);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
void uwsgi_robust_mutexes_watchdog() {
|
||||
pthread_t tid;
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
// 32K should be more than enough...
|
||||
pthread_attr_setstacksize(&attr, 32 * 1024);
|
||||
|
||||
if (pthread_create(&tid, &attr, uwsgi_robust_mutexes_watchdog_loop, NULL)) {
|
||||
uwsgi_error("uwsgi_robust_mutexes_watchdog()/pthread_create()");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void uwsgi_setup_locking() {
|
||||
|
||||
int i;
|
||||
|
||||
if (uwsgi.locking_setup) return;
|
||||
|
||||
// use the fastest available locking
|
||||
if (uwsgi.lock_engine) {
|
||||
if (!strcmp(uwsgi.lock_engine, "ipcsem")) {
|
||||
@@ -514,8 +688,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);
|
||||
@@ -534,40 +710,61 @@ void uwsgi_setup_locking() {
|
||||
uwsgi.lock_size = UWSGI_LOCK_SIZE;
|
||||
uwsgi.rwlock_size = UWSGI_RWLOCK_SIZE;
|
||||
|
||||
ready:
|
||||
// application generic lock
|
||||
int i;
|
||||
uwsgi.user_lock = uwsgi_malloc(sizeof(void *) * (uwsgi.locks + 1));
|
||||
for (i = 0; i < uwsgi.locks + 1; i++) {
|
||||
uwsgi.user_lock[i] = uwsgi_lock_init(uwsgi_concat2("user ", uwsgi_num2str(i)));
|
||||
}
|
||||
uwsgi.user_lock = uwsgi_malloc(sizeof(void *) * (uwsgi.locks + 1));
|
||||
for (i = 0; i < uwsgi.locks + 1; i++) {
|
||||
char *num = uwsgi_num2str(i);
|
||||
uwsgi.user_lock[i] = uwsgi_lock_init(uwsgi_concat2("user ", num));
|
||||
free(num);
|
||||
}
|
||||
|
||||
// event queue lock (mitigate same event on multiple queues)
|
||||
if (uwsgi.threads > 1) {
|
||||
pthread_mutex_init(&uwsgi.thunder_mutex, NULL);
|
||||
}
|
||||
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");
|
||||
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");
|
||||
// fmon table lock
|
||||
uwsgi.fmon_table_lock = uwsgi_lock_init("filemon");
|
||||
|
||||
// timer table lock
|
||||
uwsgi.timer_table_lock = uwsgi_lock_init("timer");
|
||||
// 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");
|
||||
|
||||
// rb_timer table lock
|
||||
uwsgi.rb_timer_table_lock = uwsgi_lock_init("rbtimer");
|
||||
// cron table lock
|
||||
uwsgi.cron_table_lock = uwsgi_lock_init("cron");
|
||||
}
|
||||
|
||||
// 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");
|
||||
#ifdef UNBIT
|
||||
// we have a serious bug on Unbit (and very probably on older libc)
|
||||
// when all of the workers die in the same moment the pthread robust mutes is left
|
||||
// in inconsistent state and we have no way to recover
|
||||
// we span a thread in the master constantly ensuring the lock is ok
|
||||
// for now we apply it only for Unbit (where thunder-lock is automatically enabled)
|
||||
uwsgi_robust_mutexes_watchdog();
|
||||
#endif
|
||||
}
|
||||
|
||||
uwsgi.rpc_table_lock = uwsgi_lock_init("rpc");
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -589,43 +786,59 @@ 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);
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
uli = uli->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_user_lock(int lock_num) {
|
||||
if (lock_num < 0 || lock_num > uwsgi.locks) {
|
||||
return -1;
|
||||
}
|
||||
uwsgi_lock(uwsgi.user_lock[lock_num]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_user_unlock(int lock_num) {
|
||||
if (lock_num < 0 || lock_num > uwsgi.locks) {
|
||||
return -1;
|
||||
}
|
||||
uwsgi_unlock(uwsgi.user_lock[lock_num]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
+1425
-441
File diff suppressed because it is too large
Load Diff
+92
-48
@@ -10,73 +10,117 @@ struct wsgi_request *simple_current_wsgi_req() {
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_register_loop(char *name, void *loop) {
|
||||
void uwsgi_register_loop(char *name, void (*func) (void)) {
|
||||
|
||||
if (uwsgi.loops_cnt >= MAX_LOOPS) {
|
||||
uwsgi_log("you can define %d loops at max\n", MAX_LOOPS);
|
||||
exit(1);
|
||||
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;
|
||||
}
|
||||
|
||||
uwsgi.loops[uwsgi.loops_cnt].name = name;
|
||||
uwsgi.loops[uwsgi.loops_cnt].loop = loop;
|
||||
uwsgi.loops_cnt++;
|
||||
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) {
|
||||
|
||||
int i;
|
||||
struct uwsgi_loop *loop = uwsgi.loops;
|
||||
|
||||
for (i = 0; i < uwsgi.loops_cnt; i++) {
|
||||
if (!strcmp(name, uwsgi.loops[i].name)) {
|
||||
return uwsgi.loops[i].loop;
|
||||
while (loop) {
|
||||
if (!strcmp(name, loop->name)) {
|
||||
return loop->loop;
|
||||
}
|
||||
loop = loop->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *simple_loop(void *arg1) {
|
||||
/*
|
||||
|
||||
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;
|
||||
|
||||
#ifdef UWSGI_THREADING
|
||||
int i;
|
||||
sigset_t smask;
|
||||
|
||||
if (uwsgi.threads > 1) {
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &i);
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &i);
|
||||
pthread_setspecific(uwsgi.tur_key, (void *) wsgi_req);
|
||||
|
||||
if (core_id > 0) {
|
||||
// block all signals on new threads
|
||||
sigfillset(&smask);
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
uwsgi_setup_thread_req(core_id, wsgi_req);
|
||||
}
|
||||
#endif
|
||||
|
||||
// initialize the main event queue to monitor sockets
|
||||
int main_queue = event_queue_init();
|
||||
|
||||
@@ -97,7 +141,7 @@ void *simple_loop(void *arg1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (wsgi_req_recv(wsgi_req)) {
|
||||
if (wsgi_req_recv(main_queue, wsgi_req)) {
|
||||
uwsgi_destroy_request(wsgi_req);
|
||||
continue;
|
||||
}
|
||||
|
||||
+359
-935
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,338 @@
|
||||
#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;
|
||||
int i;
|
||||
int needed_procs = 0;
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cheaped == 0) {
|
||||
needed_procs++;
|
||||
}
|
||||
}
|
||||
if (uwsgi.status.chain_reloading > needed_procs) {
|
||||
uwsgi.status.chain_reloading = 0;
|
||||
uwsgi_log_verbose("chain reloading complete\n");
|
||||
}
|
||||
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()");
|
||||
}
|
||||
else {
|
||||
uwsgi.workers[i].pid = 0;
|
||||
}
|
||||
}
|
||||
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) {
|
||||
uwsgi_log("*** HARAKIRI ON GATEWAY %s %d (pid: %d) ***\n", ushared->gateways[i].name, ushared->gateways[i].num, ushared->gateways[i].pid);
|
||||
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;
|
||||
}
|
||||
}
|
||||
// user harakiri
|
||||
if (uwsgi.mules[i].user_harakiri > 0) {
|
||||
if (uwsgi.mules[i].user_harakiri < (time_t) uwsgi.current_time) {
|
||||
uwsgi_log("*** HARAKIRI ON MULE %d (pid: %d) ***\n", i + 1, uwsgi.mules[i].pid);
|
||||
kill(uwsgi.mules[i].pid, SIGKILL);
|
||||
uwsgi.mules[i].user_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;
|
||||
}
|
||||
if (uspool->user_harakiri > 0 && uspool->user_harakiri < (time_t) uwsgi.current_time) {
|
||||
uwsgi_log("*** HARAKIRI ON THE SPOOLER (pid: %d) ***\n", uspool->pid);
|
||||
kill(uspool->pid, SIGKILL);
|
||||
uspool->user_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;
|
||||
}
|
||||
|
||||
int uwsgi_master_check_cron_death(int diedpid) {
|
||||
struct uwsgi_cron *uc = uwsgi.crons;
|
||||
while (uc) {
|
||||
if (uc->pid == (pid_t) diedpid) {
|
||||
uwsgi_log("[uwsgi-cron] command \"%s\" running with pid %d exited after %d second(s)\n", uc->command, uc->pid, uwsgi_now() - uc->started_at);
|
||||
uc->pid = -1;
|
||||
uc->started_at = 0;
|
||||
return -1;
|
||||
}
|
||||
uc = uc->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uwsgi_master_check_crons_deadline() {
|
||||
struct uwsgi_cron *uc = uwsgi.crons;
|
||||
while (uc) {
|
||||
if (uc->pid >= 0 && uc->harakiri > 0 && uc->harakiri < (time_t) uwsgi.current_time) {
|
||||
uwsgi_log("*** HARAKIRI ON CRON \"%s\" (pid: %d) ***\n", uc->command, uc->pid);
|
||||
kill(-uc->pid, SIGKILL);
|
||||
}
|
||||
uc = uc->next;
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_master_check_mountpoints() {
|
||||
struct uwsgi_string_list *usl;
|
||||
uwsgi_foreach(usl, uwsgi.mountpoints_check) {
|
||||
if (uwsgi_check_mountpoint(usl->value)) {
|
||||
uwsgi_log_verbose("mountpoint %s failed, triggering detonation...\n", usl->value);
|
||||
uwsgi_nuclear_blast();
|
||||
//never here
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.master_fifo_fd > -1 && interesting_fd == uwsgi.master_fifo_fd) {
|
||||
return uwsgi_master_fifo_manage(uwsgi.master_fifo_fd);
|
||||
}
|
||||
|
||||
// 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 (uwsgi.emperor_fd_proxy > -1 && interesting_fd == uwsgi.emperor_fd_proxy) {
|
||||
uwsgi_master_manage_emperor_proxy();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (interesting_fd == uwsgi.emperor_fd) {
|
||||
uwsgi_master_manage_emperor();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi_fsmon_event(interesting_fd)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// reload on fd
|
||||
if (uwsgi.reload_on_fd) {
|
||||
// custom -> fd
|
||||
// custom2 -> len (optional, default 1)
|
||||
// custom_ptr -> log message (optional)
|
||||
struct uwsgi_string_list *usl = uwsgi.reload_on_fd;
|
||||
while(usl) {
|
||||
if (interesting_fd == (int) usl->custom) {
|
||||
char stack_tmp[8];
|
||||
char *tmp = stack_tmp;
|
||||
if (usl->custom2 > 8) {
|
||||
tmp = uwsgi_malloc(usl->custom2);
|
||||
}
|
||||
if (read(interesting_fd, tmp, usl->custom2) <= 0) {
|
||||
uwsgi_error("[reload-on-fd] read()");
|
||||
}
|
||||
if (usl->custom_ptr) {
|
||||
uwsgi_log_verbose("*** fd %d ready: %s ***\n", interesting_fd, usl->custom_ptr);
|
||||
}
|
||||
else {
|
||||
uwsgi_log_verbose("*** fd %d ready !!! ***\n", interesting_fd);
|
||||
}
|
||||
uwsgi_block_signal(SIGHUP);
|
||||
grace_them_all(0);
|
||||
uwsgi_unblock_signal(SIGHUP);
|
||||
return 0;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
}
|
||||
|
||||
// brutal reload on fd
|
||||
if (uwsgi.brutal_reload_on_fd) {
|
||||
// custom -> fd
|
||||
// custom2 -> len (optional, default 1)
|
||||
// custom_ptr -> log message (optional)
|
||||
struct uwsgi_string_list *usl = uwsgi.brutal_reload_on_fd;
|
||||
while(usl) {
|
||||
if (interesting_fd == (int) usl->custom) {
|
||||
char stack_tmp[8];
|
||||
char *tmp = stack_tmp;
|
||||
if (usl->custom2 > 8) {
|
||||
tmp = uwsgi_malloc(usl->custom2);
|
||||
}
|
||||
if (read(interesting_fd, tmp, usl->custom2) <= 0) {
|
||||
uwsgi_error("[brutal-reload-on-fd] read()");
|
||||
}
|
||||
if (usl->custom_ptr) {
|
||||
uwsgi_log_verbose("*** fd %d ready: %s ***\n", interesting_fd, usl->custom_ptr);
|
||||
}
|
||||
else {
|
||||
uwsgi_log_verbose("*** fd %d ready !!! ***\n", interesting_fd);
|
||||
}
|
||||
if (uwsgi.die_on_term) {
|
||||
uwsgi_block_signal(SIGQUIT);
|
||||
reap_them_all(0);
|
||||
uwsgi_unblock_signal(SIGQUIT);
|
||||
}
|
||||
else {
|
||||
uwsgi_block_signal(SIGTERM);
|
||||
reap_them_all(0);
|
||||
uwsgi_unblock_signal(SIGTERM);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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;
|
||||
|
||||
}
|
||||
+1012
-466
File diff suppressed because it is too large
Load Diff
+988
@@ -0,0 +1,988 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/*
|
||||
|
||||
uWSGI metrics subsystem
|
||||
|
||||
a metric is a node in a linked list reachable via a numeric id (OID, in SNMP way) or a simple string:
|
||||
|
||||
uwsgi.worker.1.requests
|
||||
uwsgi.custom.foo.bar
|
||||
|
||||
the oid representation:
|
||||
|
||||
1.3.6.1.4.1.35156.17 = iso.org.dod.internet.private.enterprise.unbit.uwsgi
|
||||
1.3.6.1.4.1.35156.17.3.1.1 = iso.org.dod.internet.private.enterprise.unbit.uwsgi.worker.1.requests
|
||||
1.3.6.1.4.1.35156.17.3.1.1 = iso.org.dod.internet.private.enterprise.unbit.uwsgi.worker.1.requests
|
||||
1.3.6.1.4.1.35156.17.3.1.2.1.1 = iso.org.dod.internet.private.enterprise.unbit.uwsgi.worker.1.core.1.requests
|
||||
...
|
||||
|
||||
each metric is a collected value with a specific frequency
|
||||
metrics are meant for numeric values signed 64 bit, but they can be exposed as:
|
||||
|
||||
gauge
|
||||
counter
|
||||
absolute
|
||||
|
||||
metrics are managed by a dedicated thread (in the master) holding a linked list of all the items. For few metrics it is a good (read: simple) approach,
|
||||
but you can cache lookups in a uWSGI cache for really big list. (TODO)
|
||||
|
||||
struct uwsgi_metric *um = uwsgi_register_metric("worker.1.requests", "3.1.1", UWSGI_METRIC_COUNTER, "ptr", &uwsgi.workers[1].requests, 0, NULL);
|
||||
prototype: struct uwsgi_metric *uwsgi_register_metric(char *name, char *oid, uint8_t value_type, char *collector, void *ptr, uint32_t freq, void *custom);
|
||||
|
||||
value_type = UWSGI_METRIC_COUNTER/UWSGI_METRIC_GAUGE/UWSGI_METRIC_ABSOLUTE
|
||||
collect_way = "ptr" -> get from a pointer / UWSGI_METRIC_FUNC -> get from a func with the prototype int64_t func(struct uwsgi_metric *); / UWSGI_METRIC_FILE -> get the value from a file, ptr is the filename
|
||||
|
||||
For some metric (or all ?) you may want to hold a value even after a server reload. For such a reason you can specify a directory on wich the server (on startup/restart) will look for
|
||||
a file named like the metric and will read the initial value from it. It may look an old-fashioned and quite inefficient way, but it is the most versatile for a sysadmin (allowing him/her
|
||||
to even modify the values manually)
|
||||
|
||||
When registering a metric with the same name of an already registered one, the new one will overwrite the previous one. This allows plugins writer to override default behaviours
|
||||
|
||||
Applications are allowed to update metrics (but they cannot register new ones), with simple api funcs:
|
||||
|
||||
uwsgi.metric_set("worker.1.requests", N)
|
||||
uwsgi.metric_inc("worker.1.requests", N=1)
|
||||
uwsgi.metric_dec("worker.1.requests", N=1)
|
||||
uwsgi.metric_mul("worker.1.requests", N=1)
|
||||
uwsgi.metric_div("worker.1.requests", N=1)
|
||||
|
||||
and obviously they can get values:
|
||||
|
||||
uwsgi.metric_get("worker.1.requests")
|
||||
|
||||
Updating metrics from your app MUST BE ATOMIC, for such a reason a uWSGI rwlock is initialized on startup and used for each operation (simple reading from a metric does not require locking)
|
||||
|
||||
Metrics can be updated from the internal routing subsystem too:
|
||||
|
||||
route-if = equal:${REQUEST_URI};/foobar metricinc:foobar.test 2
|
||||
|
||||
and can be accessed as ${metric[foobar.test]}
|
||||
|
||||
The stats server exports the metrics list in the "metrics" attribute (obviously some info could be redundant)
|
||||
|
||||
*/
|
||||
|
||||
|
||||
int64_t uwsgi_metric_collector_file(struct uwsgi_metric *metric) {
|
||||
char *filename = metric->arg1;
|
||||
if (!filename) return 0;
|
||||
int split_pos = metric->arg1n;
|
||||
|
||||
char buf[4096];
|
||||
int64_t ret = 0;
|
||||
int fd = open(filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
uwsgi_error_open(filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t rlen = read(fd, buf, 4096);
|
||||
if (rlen <= 0) goto end;
|
||||
|
||||
char *ptr = buf;
|
||||
ssize_t i;
|
||||
int pos = 0;
|
||||
int found = 0;
|
||||
for(i=0;i<rlen;i++) {
|
||||
if (!found) {
|
||||
if (buf[i] == ' ' || buf[i] == '\t' || buf[i] == '\r' || buf[i] == 0 || buf[i] == '\n') {
|
||||
if (pos == split_pos) goto found;
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!(buf[i] == ' ' || buf[i] == '\t' || buf[i] == '\r' || buf[i] == 0 || buf[i] == '\n')) {
|
||||
found = 0;
|
||||
ptr = buf + i;
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pos == split_pos) goto found;
|
||||
goto end;
|
||||
found:
|
||||
ret = strtoll(ptr, NULL, 10);
|
||||
end:
|
||||
close(fd);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
allowed chars for metrics name
|
||||
|
||||
0-9
|
||||
a-z
|
||||
A-Z
|
||||
.
|
||||
-
|
||||
_
|
||||
|
||||
*/
|
||||
|
||||
static int uwsgi_validate_metric_name(char *buf) {
|
||||
size_t len = strlen(buf);
|
||||
size_t i;
|
||||
for(i=0;i<len;i++) {
|
||||
if ( !(
|
||||
(buf[i] >= '0' && buf[i] <= '9') ||
|
||||
(buf[i] >= 'a' && buf[i] <= 'z') ||
|
||||
(buf[i] >= 'A' && buf[i] <= 'Z') ||
|
||||
buf[i] == '.' || buf[i] == '-' || buf[i] == '_'
|
||||
)) {
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
allowed chars for metrics oid
|
||||
|
||||
0-9
|
||||
.
|
||||
|
||||
oids can be null
|
||||
*/
|
||||
|
||||
static int uwsgi_validate_metric_oid(char *buf) {
|
||||
if (!buf) return 1;
|
||||
size_t len = strlen(buf);
|
||||
size_t i;
|
||||
for(i=0;i<len;i++) {
|
||||
if ( !(
|
||||
(buf[i] >= '0' && buf[i] <= '9') ||
|
||||
buf[i] == '.'
|
||||
)) {
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void uwsgi_metric_append(struct uwsgi_metric *um) {
|
||||
struct uwsgi_metric *old_metric=NULL,*metric=uwsgi.metrics;
|
||||
while(metric) {
|
||||
old_metric = metric;
|
||||
metric = metric->next;
|
||||
}
|
||||
|
||||
if (old_metric) {
|
||||
old_metric->next = um;
|
||||
}
|
||||
else {
|
||||
uwsgi.metrics = um;
|
||||
}
|
||||
|
||||
uwsgi.metrics_cnt++;
|
||||
}
|
||||
|
||||
struct uwsgi_metric_collector *uwsgi_metric_collector_by_name(char *name) {
|
||||
if (!name) return NULL;
|
||||
struct uwsgi_metric_collector *umc = uwsgi.metric_collectors;
|
||||
while(umc) {
|
||||
if (!strcmp(name, umc->name)) return umc;
|
||||
umc = umc->next;
|
||||
}
|
||||
uwsgi_log("unable to find metric collector \"%s\"\n", name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct uwsgi_metric *uwsgi_register_metric_do(char *name, char *oid, uint8_t value_type, char *collector, void *ptr, uint32_t freq, void *custom, int do_not_push) {
|
||||
if (!uwsgi.has_metrics) return NULL;
|
||||
struct uwsgi_metric *old_metric=NULL,*metric=uwsgi.metrics;
|
||||
|
||||
if (!uwsgi_validate_metric_name(name)) {
|
||||
uwsgi_log("invalid metric name: %s\n", name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!uwsgi_validate_metric_oid(oid)) {
|
||||
uwsgi_log("invalid metric oid: %s\n", oid);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while(metric) {
|
||||
if (!strcmp(metric->name, name)) {
|
||||
goto found;
|
||||
}
|
||||
old_metric = metric;
|
||||
metric = metric->next;
|
||||
}
|
||||
|
||||
metric = uwsgi_calloc(sizeof(struct uwsgi_metric));
|
||||
// always make a copy of the name (se we can use stack for building strings)
|
||||
metric->name = uwsgi_str(name);
|
||||
metric->name_len = strlen(metric->name);
|
||||
|
||||
if (!do_not_push) {
|
||||
if (old_metric) {
|
||||
old_metric->next = metric;
|
||||
}
|
||||
else {
|
||||
uwsgi.metrics = metric;
|
||||
}
|
||||
|
||||
uwsgi.metrics_cnt++;
|
||||
}
|
||||
|
||||
found:
|
||||
metric->oid = oid;
|
||||
if (metric->oid) {
|
||||
metric->oid_len = strlen(oid);
|
||||
metric->oid = uwsgi_str(oid);
|
||||
char *p, *ctx = NULL;
|
||||
char *oid_tmp = uwsgi_str(metric->oid);
|
||||
// slower but we save lot of memory
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(1);
|
||||
uwsgi_foreach_token(oid_tmp, ".", p, ctx) {
|
||||
uint64_t l = strtoull(p, NULL, 10);
|
||||
if (uwsgi_base128(ub, l, 1)) {
|
||||
uwsgi_log("unable to encode oid %s to asn/ber\n", metric->oid);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
metric->asn = ub->buf;
|
||||
metric->asn_len = ub->pos;
|
||||
ub->buf = NULL;
|
||||
uwsgi_buffer_destroy(ub);
|
||||
free(oid_tmp);
|
||||
}
|
||||
metric->type = value_type;
|
||||
metric->collector = uwsgi_metric_collector_by_name(collector);
|
||||
metric->ptr = ptr;
|
||||
metric->freq = freq;
|
||||
if (!metric->freq) metric->freq = 1;
|
||||
metric->custom = custom;
|
||||
|
||||
if (uwsgi.metrics_dir) {
|
||||
char *filename = uwsgi_concat3(uwsgi.metrics_dir, "/", name);
|
||||
int fd = open(filename, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP);
|
||||
if (fd < 0) {
|
||||
uwsgi_error_open(filename);
|
||||
exit(1);
|
||||
}
|
||||
// fill the file
|
||||
if (lseek(fd, uwsgi.page_size-1, SEEK_SET) < 0) {
|
||||
uwsgi_error("uwsgi_register_metric()/lseek()");
|
||||
uwsgi_log("unable to register metric: %s\n", name);
|
||||
exit(1);
|
||||
}
|
||||
if (write(fd, "\0", 1) != 1) {
|
||||
uwsgi_error("uwsgi_register_metric()/write()");
|
||||
uwsgi_log("unable to register metric: %s\n", name);
|
||||
exit(1);
|
||||
}
|
||||
metric->map = mmap(NULL, uwsgi.page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (metric->map == MAP_FAILED) {
|
||||
uwsgi_error("uwsgi_register_metric()/mmap()");
|
||||
uwsgi_log("unable to register metric: %s\n", name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// we can now safely close the file descriptor and update the file from memory
|
||||
close(fd);
|
||||
free(filename);
|
||||
}
|
||||
|
||||
return metric;
|
||||
}
|
||||
|
||||
struct uwsgi_metric *uwsgi_register_metric(char *name, char *oid, uint8_t value_type, char *collector, void *ptr, uint32_t freq, void *custom) {
|
||||
return uwsgi_register_metric_do(name, oid, value_type, collector, ptr, freq, custom, 0);
|
||||
}
|
||||
|
||||
struct uwsgi_metric *uwsgi_register_keyval_metric(char *arg) {
|
||||
char *m_name = NULL;
|
||||
char *m_oid = NULL;
|
||||
char *m_type = NULL;
|
||||
char *m_collector = NULL;
|
||||
char *m_freq = NULL;
|
||||
char *m_arg1 = NULL;
|
||||
char *m_arg2 = NULL;
|
||||
char *m_arg3 = NULL;
|
||||
char *m_arg1n = NULL;
|
||||
char *m_arg2n = NULL;
|
||||
char *m_arg3n = NULL;
|
||||
char *m_initial_value = NULL;
|
||||
char *m_children = NULL;
|
||||
char *m_alias = NULL;
|
||||
|
||||
if (!strchr(arg, '=')) {
|
||||
m_name = uwsgi_str(arg);
|
||||
}
|
||||
else if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=',
|
||||
"name", &m_name,
|
||||
"oid", &m_oid,
|
||||
"type", &m_type,
|
||||
"initial_value", &m_initial_value,
|
||||
"collector", &m_collector,
|
||||
"freq", &m_freq,
|
||||
"arg1", &m_arg1,
|
||||
"arg2", &m_arg2,
|
||||
"arg3", &m_arg3,
|
||||
"arg1n", &m_arg1n,
|
||||
"arg2n", &m_arg2n,
|
||||
"arg3n", &m_arg3n,
|
||||
"children", &m_children,
|
||||
"alias", &m_alias,
|
||||
NULL)) {
|
||||
uwsgi_log("invalid metric keyval syntax: %s\n", arg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!m_name) {
|
||||
uwsgi_log("you need to specify a metric name: %s\n", arg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uint8_t type = UWSGI_METRIC_COUNTER;
|
||||
char *collector = NULL;
|
||||
uint32_t freq = 0;
|
||||
int64_t initial_value = 0;
|
||||
|
||||
if (m_type) {
|
||||
if (!strcmp(m_type, "gauge")) {
|
||||
type = UWSGI_METRIC_GAUGE;
|
||||
}
|
||||
else if (!strcmp(m_type, "absolute")) {
|
||||
type = UWSGI_METRIC_ABSOLUTE;
|
||||
}
|
||||
else if (!strcmp(m_type, "alias")) {
|
||||
type = UWSGI_METRIC_ALIAS;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_collector) {
|
||||
collector = m_collector;
|
||||
}
|
||||
|
||||
if (m_freq) freq = strtoul(m_freq, NULL, 10);
|
||||
|
||||
|
||||
if (m_initial_value) {
|
||||
initial_value = strtoll(m_initial_value, NULL, 10);
|
||||
}
|
||||
|
||||
struct uwsgi_metric* um = uwsgi_register_metric(m_name, m_oid, type, collector, NULL, freq, NULL);
|
||||
um->initial_value = initial_value;
|
||||
|
||||
if (m_children) {
|
||||
char *p, *ctx = NULL;
|
||||
uwsgi_foreach_token(m_children, ";", p, ctx) {
|
||||
struct uwsgi_metric *child = uwsgi_metric_find_by_name(p);
|
||||
if (!child) {
|
||||
uwsgi_log("unable to find metric \"%s\"\n", p);
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_metric_add_child(um, child);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_alias) {
|
||||
struct uwsgi_metric *alias = uwsgi_metric_find_by_name(m_alias);
|
||||
if (!alias) {
|
||||
uwsgi_log("unable to find metric \"%s\"\n", m_alias);
|
||||
exit(1);
|
||||
}
|
||||
um->ptr = (void *) alias;
|
||||
}
|
||||
|
||||
um->arg1 = m_arg1;
|
||||
um->arg2 = m_arg2;
|
||||
um->arg3 = m_arg3;
|
||||
|
||||
if (m_arg1n) um->arg1n = strtoll(m_arg1n, NULL, 10);
|
||||
if (m_arg2n) um->arg2n = strtoll(m_arg2n, NULL, 10);
|
||||
if (m_arg3n) um->arg3n = strtoll(m_arg3n, NULL, 10);
|
||||
|
||||
free(m_name);
|
||||
if (m_oid) free(m_oid);
|
||||
if (m_type) free(m_type);
|
||||
if (m_collector) free(m_collector);
|
||||
if (m_freq) free(m_freq);
|
||||
/*
|
||||
DO NOT FREE THEM
|
||||
if (m_arg1) free(m_arg1);
|
||||
if (m_arg2) free(m_arg2);
|
||||
if (m_arg3) free(m_arg3);
|
||||
*/
|
||||
if (m_arg1n) free(m_arg1n);
|
||||
if (m_arg2n) free(m_arg2n);
|
||||
if (m_arg3n) free(m_arg3n);
|
||||
if (m_initial_value) free(m_initial_value);
|
||||
if (m_children) free(m_children);
|
||||
if (m_alias) free(m_alias);
|
||||
return um;
|
||||
}
|
||||
|
||||
static void *uwsgi_metrics_loop(void *arg) {
|
||||
|
||||
// block signals on this thread
|
||||
sigset_t smask;
|
||||
sigfillset(&smask);
|
||||
#ifndef UWSGI_DEBUG
|
||||
sigdelset(&smask, SIGSEGV);
|
||||
#endif
|
||||
pthread_sigmask(SIG_BLOCK, &smask, NULL);
|
||||
|
||||
for(;;) {
|
||||
struct uwsgi_metric *metric = uwsgi.metrics;
|
||||
// every second scan the whole metrics tree
|
||||
time_t now = uwsgi_now();
|
||||
while(metric) {
|
||||
if (!metric->last_update) {
|
||||
metric->last_update = now;
|
||||
}
|
||||
else {
|
||||
if ((uint32_t) (now - metric->last_update) < metric->freq) goto next;
|
||||
}
|
||||
uwsgi_wlock(uwsgi.metrics_lock);
|
||||
int64_t value = *metric->value;
|
||||
// gather the new value based on the type of collection strategy
|
||||
if (metric->collector) {
|
||||
*metric->value = metric->initial_value + metric->collector->func(metric);
|
||||
}
|
||||
int64_t new_value = *metric->value;
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
|
||||
metric->last_update = now;
|
||||
|
||||
if (uwsgi.metrics_dir && metric->map) {
|
||||
if (value != new_value) {
|
||||
int ret = snprintf(metric->map, uwsgi.page_size, "%lld\n", (long long) new_value);
|
||||
if (ret > 0) {
|
||||
memset(metric->map+ret, 0, 4096-ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// thresholds;
|
||||
struct uwsgi_metric_threshold *umt = metric->thresholds;
|
||||
while(umt) {
|
||||
if (new_value >= umt->value) {
|
||||
if (umt->reset) {
|
||||
uwsgi_wlock(uwsgi.metrics_lock);
|
||||
*metric->value = umt->reset_value;
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
}
|
||||
|
||||
if (umt->alarm) {
|
||||
if (umt->last_alarm + umt->rate <= now) {
|
||||
if (umt->msg) {
|
||||
uwsgi_alarm_trigger(umt->alarm, umt->msg, umt->msg_len);
|
||||
}
|
||||
else {
|
||||
uwsgi_alarm_trigger(umt->alarm, metric->name, metric->name_len);
|
||||
}
|
||||
umt->last_alarm = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
umt = umt->next;
|
||||
}
|
||||
next:
|
||||
metric = metric->next;
|
||||
}
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_metrics_start_collector() {
|
||||
if (!uwsgi.has_metrics) return;
|
||||
pthread_t t;
|
||||
pthread_create(&t, NULL, uwsgi_metrics_loop, NULL);
|
||||
uwsgi_log("metrics collector thread started\n");
|
||||
}
|
||||
|
||||
struct uwsgi_metric *uwsgi_metric_find_by_name(char *name) {
|
||||
struct uwsgi_metric *um = uwsgi.metrics;
|
||||
while(um) {
|
||||
if (!strcmp(um->name, name)) {
|
||||
return um;
|
||||
}
|
||||
um = um->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_metric *uwsgi_metric_find_by_namen(char *name, size_t len) {
|
||||
struct uwsgi_metric *um = uwsgi.metrics;
|
||||
while(um) {
|
||||
if (!uwsgi_strncmp(um->name, um->name_len, name, len)) {
|
||||
return um;
|
||||
}
|
||||
um = um->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_metric_child *uwsgi_metric_add_child(struct uwsgi_metric *parent, struct uwsgi_metric *child) {
|
||||
struct uwsgi_metric_child *umc = parent->children, *old_umc = NULL;
|
||||
while(umc) {
|
||||
old_umc = umc;
|
||||
umc = umc->next;
|
||||
}
|
||||
|
||||
umc = uwsgi_calloc(sizeof(struct uwsgi_metric_child));
|
||||
umc->um = child;
|
||||
if (old_umc) {
|
||||
old_umc->next = umc;
|
||||
}
|
||||
else {
|
||||
parent->children = umc;
|
||||
}
|
||||
return umc;
|
||||
}
|
||||
|
||||
struct uwsgi_metric *uwsgi_metric_find_by_oid(char *oid) {
|
||||
struct uwsgi_metric *um = uwsgi.metrics;
|
||||
while(um) {
|
||||
if (um->oid && !strcmp(um->oid, oid)) {
|
||||
return um;
|
||||
}
|
||||
um = um->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_metric *uwsgi_metric_find_by_oidn(char *oid, size_t len) {
|
||||
struct uwsgi_metric *um = uwsgi.metrics;
|
||||
while(um) {
|
||||
if (um->oid && !uwsgi_strncmp(um->oid, um->oid_len, oid, len)) {
|
||||
return um;
|
||||
}
|
||||
um = um->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_metric *uwsgi_metric_find_by_asn(char *asn, size_t len) {
|
||||
struct uwsgi_metric *um = uwsgi.metrics;
|
||||
while(um) {
|
||||
if (um->oid && um->asn && !uwsgi_strncmp(um->asn, um->asn_len, asn, len)) {
|
||||
return um;
|
||||
}
|
||||
um = um->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
api functions
|
||||
|
||||
metric_set
|
||||
metric_inc
|
||||
metric_dec
|
||||
metric_mul
|
||||
metric_div
|
||||
|
||||
*/
|
||||
|
||||
#define um_op struct uwsgi_metric *um = NULL;\
|
||||
if (!uwsgi.has_metrics) return -1;\
|
||||
if (name) {\
|
||||
um = uwsgi_metric_find_by_name(name);\
|
||||
}\
|
||||
else if (oid) {\
|
||||
um = uwsgi_metric_find_by_oid(oid);\
|
||||
}\
|
||||
if (!um) return -1;\
|
||||
if (um->collector || um->type == UWSGI_METRIC_ALIAS) return -1;\
|
||||
uwsgi_rlock(uwsgi.metrics_lock)
|
||||
|
||||
int uwsgi_metric_set(char *name, char *oid, int64_t value) {
|
||||
um_op;
|
||||
*um->value = value;
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_metric_inc(char *name, char *oid, int64_t value) {
|
||||
um_op;
|
||||
*um->value += value;
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_metric_dec(char *name, char *oid, int64_t value) {
|
||||
um_op;
|
||||
*um->value -= value;
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_metric_mul(char *name, char *oid, int64_t value) {
|
||||
um_op;
|
||||
*um->value *= value;
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_metric_div(char *name, char *oid, int64_t value) {
|
||||
// avoid division by zero
|
||||
if (value == 0) return -1;
|
||||
um_op;
|
||||
*um->value /= value;
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t uwsgi_metric_get(char *name, char *oid) {
|
||||
if (!uwsgi.has_metrics) return 0;
|
||||
int64_t ret = 0;
|
||||
struct uwsgi_metric *um = NULL;
|
||||
if (name) {
|
||||
um = uwsgi_metric_find_by_name(name);
|
||||
}
|
||||
else if (oid) {
|
||||
um = uwsgi_metric_find_by_oid(oid);
|
||||
}
|
||||
if (!um) return 0;
|
||||
|
||||
// now (in rlocked context) we get the value from
|
||||
// the map
|
||||
uwsgi_rlock(uwsgi.metrics_lock);
|
||||
ret = *um->value;
|
||||
// unlock
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int64_t uwsgi_metric_getn(char *name, size_t nlen, char *oid, size_t olen) {
|
||||
if (!uwsgi.has_metrics) return 0;
|
||||
int64_t ret = 0;
|
||||
struct uwsgi_metric *um = NULL;
|
||||
if (name) {
|
||||
um = uwsgi_metric_find_by_namen(name, nlen);
|
||||
}
|
||||
else if (oid) {
|
||||
um = uwsgi_metric_find_by_oidn(oid, olen);
|
||||
}
|
||||
if (!um) return 0;
|
||||
|
||||
// now (in rlocked context) we get the value from
|
||||
// the map
|
||||
uwsgi_rlock(uwsgi.metrics_lock);
|
||||
ret = *um->value;
|
||||
// unlock
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define uwsgi_metric_name(f, n) if (snprintf(buf, 4096, f, n) <= 1) { uwsgi_log("unable to register metric name %s\n", f); exit(1);}
|
||||
#define uwsgi_metric_name2(f, n, n2) if (snprintf(buf, 4096, f, n, n2) <= 1) { uwsgi_log("unable to register metric name %s\n", f); exit(1);}
|
||||
|
||||
#define uwsgi_metric_oid(f, n) if (snprintf(buf2, 4096, f, n) <= 1) { uwsgi_log("unable to register metric oid %s\n", f); exit(1);}
|
||||
#define uwsgi_metric_oid2(f, n, n2) if (snprintf(buf2, 4096, f, n, n2) <= 1) { uwsgi_log("unable to register metric oid %s\n", f); exit(1);}
|
||||
|
||||
void uwsgi_setup_metrics() {
|
||||
|
||||
if (!uwsgi.has_metrics) return;
|
||||
|
||||
char buf[4096];
|
||||
char buf2[4096];
|
||||
|
||||
// create the main rwlock
|
||||
uwsgi.metrics_lock = uwsgi_rwlock_init("metrics");
|
||||
|
||||
// get realpath of the storage dir
|
||||
if (uwsgi.metrics_dir) {
|
||||
char *dir = uwsgi_expand_path(uwsgi.metrics_dir, strlen(uwsgi.metrics_dir), NULL);
|
||||
if (!dir) {
|
||||
uwsgi_error("uwsgi_setup_metrics()/uwsgi_expand_path()");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi.metrics_dir = dir;
|
||||
}
|
||||
|
||||
// the 'core' namespace
|
||||
uwsgi_register_metric("core.routed_signals", "5.1", UWSGI_METRIC_COUNTER, "ptr", &uwsgi.shared->routed_signals, 0, NULL);
|
||||
uwsgi_register_metric("core.unrouted_signals", "5.2", UWSGI_METRIC_COUNTER, "ptr", &uwsgi.shared->unrouted_signals, 0, NULL);
|
||||
|
||||
uwsgi_register_metric("core.busy_workers", "5.3", UWSGI_METRIC_GAUGE, "ptr", &uwsgi.shared->busy_workers, 0, NULL);
|
||||
uwsgi_register_metric("core.idle_workers", "5.4", UWSGI_METRIC_GAUGE, "ptr", &uwsgi.shared->idle_workers, 0, NULL);
|
||||
uwsgi_register_metric("core.overloaded", "5.5", UWSGI_METRIC_COUNTER, "ptr", &uwsgi.shared->overloaded, 0, NULL);
|
||||
|
||||
// parents are appended only at the end
|
||||
struct uwsgi_metric *total_tx = uwsgi_register_metric_do("core.total_tx", "5.100", UWSGI_METRIC_COUNTER, "sum", NULL, 0, NULL, 1);
|
||||
struct uwsgi_metric *total_rss = uwsgi_register_metric_do("core.total_rss", "5.101", UWSGI_METRIC_GAUGE, "sum", NULL, 0, NULL, 1);
|
||||
struct uwsgi_metric *total_vsz = uwsgi_register_metric_do("core.total_vsz", "5.102", UWSGI_METRIC_GAUGE, "sum", NULL, 0, NULL, 1);
|
||||
|
||||
// create the 'worker' namespace
|
||||
int i;
|
||||
for(i=0;i<=uwsgi.numproc;i++) {
|
||||
|
||||
uwsgi_metric_name("worker.%d.requests", i) ; uwsgi_metric_oid("3.%d.1", i);
|
||||
uwsgi_register_metric(buf, buf2, UWSGI_METRIC_COUNTER, "ptr", &uwsgi.workers[i].requests, 0, NULL);
|
||||
|
||||
uwsgi_metric_name("worker.%d.delta_requests", i) ; uwsgi_metric_oid("3.%d.2", i);
|
||||
uwsgi_register_metric(buf, buf2, UWSGI_METRIC_ABSOLUTE, "ptr", &uwsgi.workers[i].delta_requests, 0, NULL);
|
||||
|
||||
uwsgi_metric_name("worker.%d.failed_requests", i) ; uwsgi_metric_oid("3.%d.13", i);
|
||||
uwsgi_register_metric(buf, buf2, UWSGI_METRIC_COUNTER, "ptr", &uwsgi.workers[i].failed_requests, 0, NULL);
|
||||
|
||||
uwsgi_metric_name("worker.%d.respawns", i) ; uwsgi_metric_oid("3.%d.14", i);
|
||||
uwsgi_register_metric(buf, buf2, UWSGI_METRIC_COUNTER, "ptr", &uwsgi.workers[i].respawn_count, 0, NULL);
|
||||
|
||||
uwsgi_metric_name("worker.%d.avg_response_time", i) ; uwsgi_metric_oid("3.%d.8", i);
|
||||
uwsgi_register_metric(buf, buf2, UWSGI_METRIC_GAUGE, "ptr", &uwsgi.workers[i].avg_response_time, 0, NULL);
|
||||
|
||||
uwsgi_metric_name("worker.%d.total_rx", i) ; uwsgi_metric_oid("3.%d.9", i);
|
||||
struct uwsgi_metric *tx = uwsgi_register_metric(buf, buf2, UWSGI_METRIC_COUNTER, "ptr", &uwsgi.workers[i].tx, 0, NULL);
|
||||
uwsgi_metric_add_child(total_tx, tx);
|
||||
|
||||
uwsgi_metric_name("worker.%d.rss_size", i) ; uwsgi_metric_oid("3.%d.11", i);
|
||||
struct uwsgi_metric *rss = uwsgi_register_metric(buf, buf2, UWSGI_METRIC_GAUGE, "ptr", &uwsgi.workers[i].rss_size, 0, NULL);
|
||||
uwsgi_metric_add_child(total_rss, rss);
|
||||
|
||||
uwsgi_metric_name("worker.%d.vsz_size", i) ; uwsgi_metric_oid("3.%d.12", i);
|
||||
struct uwsgi_metric *vsz = uwsgi_register_metric(buf, buf2, UWSGI_METRIC_GAUGE, "ptr", &uwsgi.workers[i].vsz_size, 0, NULL);
|
||||
uwsgi_metric_add_child(total_vsz, vsz);
|
||||
|
||||
int j;
|
||||
for(j=0;j<uwsgi.cores;j++) {
|
||||
uwsgi_metric_name2("worker.%d.core.%d.requests", i, j) ; uwsgi_metric_oid2("3.%d.2.%d.1", i, j);
|
||||
uwsgi_register_metric(buf, buf2, UWSGI_METRIC_COUNTER, "ptr", &uwsgi.workers[i].cores[j].requests, 0, NULL);
|
||||
|
||||
uwsgi_metric_name2("worker.%d.core.%d.write_errors", i, j) ; uwsgi_metric_oid2("3.%d.2.%d.3", i, j);
|
||||
uwsgi_register_metric(buf, buf2, UWSGI_METRIC_COUNTER, "ptr", &uwsgi.workers[i].cores[j].write_errors, 0, NULL);
|
||||
|
||||
uwsgi_metric_name2("worker.%d.core.%d.routed_requests", i, j) ; uwsgi_metric_oid2("3.%d.2.%d.4", i, j);
|
||||
uwsgi_register_metric(buf, buf2, UWSGI_METRIC_COUNTER, "ptr", &uwsgi.workers[i].cores[j].routed_requests, 0, NULL);
|
||||
|
||||
uwsgi_metric_name2("worker.%d.core.%d.static_requests", i, j) ; uwsgi_metric_oid2("3.%d.2.%d.5", i, j);
|
||||
uwsgi_register_metric(buf, buf2, UWSGI_METRIC_COUNTER, "ptr", &uwsgi.workers[i].cores[j].static_requests, 0, NULL);
|
||||
|
||||
uwsgi_metric_name2("worker.%d.core.%d.offloaded_requests", i, j) ; uwsgi_metric_oid2("3.%d.2.%d.6", i, j);
|
||||
uwsgi_register_metric(buf, buf2, UWSGI_METRIC_COUNTER, "ptr", &uwsgi.workers[i].cores[j].offloaded_requests, 0, NULL);
|
||||
|
||||
uwsgi_metric_name2("worker.%d.core.%d.exceptions", i, j) ; uwsgi_metric_oid2("3.%d.2.%d.7", i, j);
|
||||
uwsgi_register_metric(buf, buf2, UWSGI_METRIC_COUNTER, "ptr", &uwsgi.workers[i].cores[j].exceptions, 0, NULL);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// append parents
|
||||
uwsgi_metric_append(total_tx);
|
||||
uwsgi_metric_append(total_rss);
|
||||
uwsgi_metric_append(total_vsz);
|
||||
|
||||
// sockets
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
int pos = 0;
|
||||
while(uwsgi_sock) {
|
||||
uwsgi_metric_name("socket.%d.listen_queue", pos) ; uwsgi_metric_oid("7.%d.1", pos);
|
||||
uwsgi_register_metric(buf, buf2, UWSGI_METRIC_GAUGE, "ptr", &uwsgi_sock->queue, 0, NULL);
|
||||
pos++;
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
// create aliases
|
||||
uwsgi_register_metric("rss_size", NULL, UWSGI_METRIC_ALIAS, NULL, total_rss, 0, NULL);
|
||||
uwsgi_register_metric("vsz_size", NULL, UWSGI_METRIC_ALIAS, NULL, total_vsz, 0, NULL);
|
||||
|
||||
// create custom/user-defined metrics
|
||||
struct uwsgi_string_list *usl;
|
||||
uwsgi_foreach(usl, uwsgi.additional_metrics) {
|
||||
struct uwsgi_metric *um = uwsgi_register_keyval_metric(usl->value);
|
||||
if (um) {
|
||||
uwsgi_log("added custom metric: %s\n", um->name);
|
||||
}
|
||||
}
|
||||
|
||||
// allocate shared memory
|
||||
int64_t *values = uwsgi_calloc_shared(sizeof(int64_t) * uwsgi.metrics_cnt);
|
||||
pos = 0;
|
||||
|
||||
struct uwsgi_metric *metric = uwsgi.metrics;
|
||||
while(metric) {
|
||||
metric->value = &values[pos];
|
||||
pos++;
|
||||
metric = metric->next;
|
||||
}
|
||||
|
||||
// remap aliases
|
||||
metric = uwsgi.metrics;
|
||||
while(metric) {
|
||||
if (metric->type == UWSGI_METRIC_ALIAS) {
|
||||
struct uwsgi_metric *alias = (struct uwsgi_metric *) metric->ptr;
|
||||
if (!alias) {
|
||||
uwsgi_log("metric alias \"%s\" requires a mapping !!!\n", metric->name);
|
||||
exit(1);
|
||||
}
|
||||
metric->value = alias->value;
|
||||
metric->oid = alias->oid;
|
||||
}
|
||||
if (metric->initial_value) {
|
||||
*metric->value = metric->initial_value;
|
||||
}
|
||||
metric = metric->next;
|
||||
}
|
||||
|
||||
// setup thresholds
|
||||
uwsgi_foreach(usl, uwsgi.metrics_threshold) {
|
||||
char *m_key = NULL;
|
||||
char *m_value = NULL;
|
||||
char *m_alarm = NULL;
|
||||
char *m_rate = NULL;
|
||||
char *m_reset = NULL;
|
||||
char *m_msg = NULL;
|
||||
if (uwsgi_kvlist_parse(usl->value, usl->len, ',', '=',
|
||||
"key", &m_key,
|
||||
"value", &m_value,
|
||||
"alarm", &m_alarm,
|
||||
"rate", &m_rate,
|
||||
"msg", &m_msg,
|
||||
"reset", &m_reset,
|
||||
NULL)) {
|
||||
uwsgi_log("invalid metric threshold keyval syntax: %s\n", usl->value);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!m_key || !m_value) {
|
||||
uwsgi_log("metric's threshold requires a key and a value: %s\n", usl->value);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct uwsgi_metric *um = uwsgi_metric_find_by_name(m_key);
|
||||
if (!um) {
|
||||
uwsgi_log("unable to find metric %s\n", m_key);
|
||||
}
|
||||
|
||||
struct uwsgi_metric_threshold *umt = uwsgi_calloc(sizeof(struct uwsgi_metric_threshold));
|
||||
umt->value = strtoll(m_value, NULL, 10);
|
||||
if (m_reset) {
|
||||
umt->reset = 1;
|
||||
umt->reset_value = strtoll(m_reset, NULL, 10);
|
||||
}
|
||||
|
||||
if (m_rate) {
|
||||
umt->rate = (int32_t) atoi(m_rate);
|
||||
}
|
||||
|
||||
umt->alarm = m_alarm;
|
||||
|
||||
if (m_msg) {
|
||||
umt->msg = m_msg;
|
||||
umt->msg_len = strlen(m_msg);
|
||||
}
|
||||
|
||||
free(m_key);
|
||||
free(m_value);
|
||||
if (m_rate) free(m_rate);
|
||||
if (m_reset) free(m_reset);
|
||||
|
||||
if (um->thresholds) {
|
||||
struct uwsgi_metric_threshold *umt_list = um->thresholds;
|
||||
while(umt_list) {
|
||||
if (!umt_list->next) {
|
||||
umt_list->next = umt;
|
||||
break;
|
||||
}
|
||||
umt_list = umt_list->next;
|
||||
}
|
||||
}
|
||||
else {
|
||||
um->thresholds = umt;
|
||||
}
|
||||
|
||||
uwsgi_log("added threshold for metric %s (value: %lld)\n", um->name, umt->value);
|
||||
}
|
||||
|
||||
uwsgi_log("initialized %llu metrics\n", uwsgi.metrics_cnt);
|
||||
|
||||
if (uwsgi.metrics_dir) {
|
||||
uwsgi_log("memory allocated for metrics storage: %llu bytes (%llu MB)\n", uwsgi.metrics_cnt * uwsgi.page_size, (uwsgi.metrics_cnt * uwsgi.page_size)/1024/1024);
|
||||
if (uwsgi.metrics_dir_restore) {
|
||||
metric = uwsgi.metrics;
|
||||
while(metric) {
|
||||
if (metric->map) {
|
||||
metric->initial_value = strtoll(metric->map, NULL, 10);
|
||||
}
|
||||
metric = metric->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_metric_collector *uwsgi_register_metric_collector(char *name, int64_t (*func)(struct uwsgi_metric *)) {
|
||||
struct uwsgi_metric_collector *collector = uwsgi.metric_collectors, *old_collector = NULL;
|
||||
|
||||
while(collector) {
|
||||
if (!strcmp(collector->name, name)) goto found;
|
||||
old_collector = collector;
|
||||
collector = collector->next;
|
||||
}
|
||||
|
||||
collector = uwsgi_calloc(sizeof(struct uwsgi_metric_collector));
|
||||
collector->name = name;
|
||||
if (old_collector) {
|
||||
old_collector->next = collector;
|
||||
}
|
||||
else {
|
||||
uwsgi.metric_collectors = collector;
|
||||
}
|
||||
found:
|
||||
collector->func = func;
|
||||
|
||||
return collector;
|
||||
}
|
||||
|
||||
static int64_t uwsgi_metric_collector_ptr(struct uwsgi_metric *um) {
|
||||
return *um->ptr;
|
||||
}
|
||||
|
||||
static int64_t uwsgi_metric_collector_sum(struct uwsgi_metric *um) {
|
||||
int64_t total = 0;
|
||||
struct uwsgi_metric_child *umc = um->children;
|
||||
while(umc) {
|
||||
struct uwsgi_metric *c = umc->um;
|
||||
total += *c->value;
|
||||
umc = umc->next;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
static int64_t uwsgi_metric_collector_func(struct uwsgi_metric *um) {
|
||||
if (!um->arg1) return 0;
|
||||
int64_t (*func)(struct uwsgi_metric *) = (int64_t (*)(struct uwsgi_metric *)) um->custom;
|
||||
if (!func) {
|
||||
func = dlsym(RTLD_DEFAULT, um->arg1);
|
||||
um->custom = func;
|
||||
}
|
||||
if (!func) return 0;
|
||||
return func(um);
|
||||
}
|
||||
|
||||
void uwsgi_metrics_collectors_setup() {
|
||||
uwsgi_register_metric_collector("ptr", uwsgi_metric_collector_ptr);
|
||||
uwsgi_register_metric_collector("file", uwsgi_metric_collector_file);
|
||||
uwsgi_register_metric_collector("sum", uwsgi_metric_collector_sum);
|
||||
uwsgi_register_metric_collector("func", uwsgi_metric_collector_func);
|
||||
}
|
||||
+254
@@ -0,0 +1,254 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
|
||||
jail systems (Linux namespaces, FreeBSD jails...) heavily rely on mount/umount
|
||||
|
||||
to simplify setups (expecially because the mount command could not be available in
|
||||
the initial phase of jailing, we need an api to mount/umount filesystems
|
||||
|
||||
int uwsgi_mount(char *fs, char *what, char *where, int flags);
|
||||
int uwsgi_umount(char *where, int flags);
|
||||
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
#ifndef MS_REC
|
||||
#define MS_REC 16384
|
||||
#endif
|
||||
#include <sys/statfs.h>
|
||||
#endif
|
||||
|
||||
struct uwsgi_mount_flag {
|
||||
char *key;
|
||||
uint64_t value;
|
||||
};
|
||||
|
||||
static struct uwsgi_mount_flag umflags[] = {
|
||||
#ifdef MS_BIND
|
||||
{"bind", MS_BIND},
|
||||
#endif
|
||||
#ifdef MS_DIRSYNC
|
||||
{"dirsync", MS_DIRSYNC},
|
||||
#endif
|
||||
#ifdef MS_MANDLOCK
|
||||
{"mandlock", MS_MANDLOCK},
|
||||
#endif
|
||||
#ifdef MS_MOVE
|
||||
{"move", MS_MOVE},
|
||||
#endif
|
||||
#ifdef MS_NOATIME
|
||||
{"noatime", MS_NOATIME},
|
||||
#endif
|
||||
#ifdef MS_NODEV
|
||||
{"nodev", MS_NODEV},
|
||||
#endif
|
||||
#ifdef MS_NOEXEC
|
||||
{"noexec", MS_NOEXEC},
|
||||
#endif
|
||||
#ifdef MS_RDONLY
|
||||
{"rdonly", MS_RDONLY},
|
||||
{"readonly", MS_RDONLY},
|
||||
{"ro", MS_RDONLY},
|
||||
#endif
|
||||
#ifdef MS_REMOUNT
|
||||
{"remount", MS_REMOUNT},
|
||||
#endif
|
||||
#ifdef MS_SYNCHRONOUS
|
||||
{"sync", MS_SYNCHRONOUS},
|
||||
#endif
|
||||
#ifdef MNT_FORCE
|
||||
{"force", MNT_FORCE},
|
||||
#endif
|
||||
#ifdef MNT_DETACH
|
||||
{"detach", MNT_DETACH},
|
||||
#endif
|
||||
#ifdef MS_REC
|
||||
{"rec", MS_REC},
|
||||
{"recursive", MS_REC},
|
||||
#endif
|
||||
#ifdef MS_PRIVATE
|
||||
{"private", MS_PRIVATE},
|
||||
#endif
|
||||
#ifdef MS_SHARED
|
||||
{"shared", MS_SHARED},
|
||||
#endif
|
||||
#ifdef MNT_RDONLY
|
||||
{"rdonly", MNT_RDONLY},
|
||||
{"readonly", MNT_RDONLY},
|
||||
{"ro", MNT_RDONLY},
|
||||
#endif
|
||||
#ifdef MNT_NOEXEC
|
||||
{"noexec", MNT_NOEXEC},
|
||||
#endif
|
||||
#ifdef MNT_NOSUID
|
||||
{"nosuid", MNT_NOSUID},
|
||||
#endif
|
||||
#ifdef MNT_NOATIME
|
||||
{"noatime", MNT_NOATIME},
|
||||
#endif
|
||||
#ifdef MNT_SNAPSHOT
|
||||
{"snapshot", MNT_SNAPSHOT},
|
||||
#endif
|
||||
{NULL, 0},
|
||||
};
|
||||
|
||||
uint64_t uwsgi_mount_flag(char *mflag) {
|
||||
struct uwsgi_mount_flag *umf = umflags;
|
||||
while(umf->key) {
|
||||
if (!strcmp(umf->key, mflag)) return umf->value;
|
||||
umf++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_mount(char *fs, char *what, char *where, char *flags) {
|
||||
#if defined(__FreeBSD__) || defined(__GNU_kFreeBSD__)
|
||||
struct iovec iov[6];
|
||||
#endif
|
||||
unsigned long mountflags = 0;
|
||||
if (!flags) goto parsed;
|
||||
char *mflags = uwsgi_str(flags);
|
||||
char *p, *ctx = NULL;
|
||||
uwsgi_foreach_token(mflags, ",", p, ctx) {
|
||||
unsigned long flag = (unsigned long) uwsgi_mount_flag(p);
|
||||
if (!flag) {
|
||||
uwsgi_log("unknown mount flag \"%s\"\n", p);
|
||||
exit(1);
|
||||
}
|
||||
mountflags |= flag;
|
||||
}
|
||||
free(mflags);
|
||||
parsed:
|
||||
#ifdef __linux__
|
||||
return mount(what, where, fs, mountflags, NULL);
|
||||
#elif defined(__FreeBSD__) || defined(__GNU_kFreeBSD__)
|
||||
iov[0].iov_base = "fstype";
|
||||
iov[0].iov_len = 7;
|
||||
iov[1].iov_base = fs;
|
||||
iov[1].iov_len = strlen(fs) + 1;
|
||||
|
||||
iov[2].iov_base = "fspath";
|
||||
iov[2].iov_len = 7;
|
||||
iov[3].iov_base = where;
|
||||
iov[3].iov_len = strlen(where) + 1;
|
||||
|
||||
iov[4].iov_base = "target";
|
||||
iov[4].iov_len = 7;
|
||||
iov[5].iov_base = what;
|
||||
iov[5].iov_len = strlen(what) + 1;
|
||||
|
||||
return nmount(iov, 6, (int) mountflags);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
int uwsgi_umount(char *where, char *flags) {
|
||||
unsigned long mountflags = 0;
|
||||
if (!flags) goto parsed;
|
||||
char *mflags = uwsgi_str(flags);
|
||||
char *p, *ctx = NULL;
|
||||
uwsgi_foreach_token(mflags, ",", p, ctx) {
|
||||
unsigned long flag = (unsigned long) uwsgi_mount_flag(p);
|
||||
if (!flag) {
|
||||
uwsgi_log("unknown umount flag \"%s\"\n", p);
|
||||
exit(1);
|
||||
}
|
||||
mountflags |= flag;
|
||||
}
|
||||
free(mflags);
|
||||
parsed:
|
||||
#ifdef __linux__
|
||||
// we need a special case for recursive umount
|
||||
if (mountflags & MS_REC) {
|
||||
mountflags &= ~MS_REC;
|
||||
int unmounted = 1;
|
||||
char *slashed = uwsgi_concat2(where, "/");
|
||||
while (unmounted) {
|
||||
unmounted = 0;
|
||||
FILE *procmounts = fopen("/proc/self/mounts", "r");
|
||||
if (!procmounts) {
|
||||
uwsgi_log("the /proc filesystem must be mounted for recursive umount\n");
|
||||
uwsgi_error("open()");
|
||||
exit(1);
|
||||
}
|
||||
char line[1024];
|
||||
while (fgets(line, 1024, procmounts) != NULL) {
|
||||
char *delim0 = strchr(line, ' ');
|
||||
if (!delim0) continue;
|
||||
delim0++;
|
||||
char *delim1 = strchr(delim0, ' ');
|
||||
if (!delim1) continue;
|
||||
*delim1 = 0;
|
||||
if (!uwsgi_starts_with(delim0, strlen(delim0), slashed, strlen(slashed))) goto unmountable;
|
||||
continue;
|
||||
unmountable:
|
||||
if (!umount2(delim0, mountflags)) unmounted++;
|
||||
}
|
||||
fclose(procmounts);
|
||||
}
|
||||
free(slashed);
|
||||
}
|
||||
return umount2(where, mountflags);
|
||||
#elif defined(__FreeBSD__) || defined(__GNU_kFreeBSD__)
|
||||
return unmount(where, mountflags);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
int uwsgi_mount_hook(char *arg) {
|
||||
char *tmp_arg = uwsgi_str(arg);
|
||||
char *fs = tmp_arg;
|
||||
char *what = strchr(fs, ' ');
|
||||
if (!what) goto error;
|
||||
*what = 0; what++;
|
||||
char *where = strchr(what, ' ');
|
||||
if (!where) goto error;
|
||||
*where = 0; where++;
|
||||
char *flags = strchr(where, ' ');
|
||||
if (flags) {
|
||||
*flags = 0; flags++;
|
||||
}
|
||||
if (uwsgi_mount(fs, what, where, flags)) {
|
||||
uwsgi_error("uwsgi_mount()");
|
||||
free(tmp_arg);
|
||||
return -1;
|
||||
}
|
||||
free(tmp_arg);
|
||||
return 0;
|
||||
error:
|
||||
free(tmp_arg);
|
||||
uwsgi_log("uwsgi_mount_hook() invalid syntax\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int uwsgi_umount_hook(char *arg) {
|
||||
char *tmp_arg = uwsgi_str(arg);
|
||||
char *where = tmp_arg;
|
||||
char *flags = strchr(where, ' ');
|
||||
if (flags) {
|
||||
*flags = 0; flags++;
|
||||
}
|
||||
if (uwsgi_umount(where, flags)) {
|
||||
uwsgi_error("uwsgi_umount()");
|
||||
free(tmp_arg);
|
||||
return -1;
|
||||
}
|
||||
free(tmp_arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_check_mountpoint(char *mountpoint) {
|
||||
#ifdef __linux__
|
||||
struct statfs sfs;
|
||||
int ret = statfs(mountpoint, &sfs);
|
||||
if (ret) {
|
||||
uwsgi_error("uwsgi_check_mountpoint()/statfs()");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
uwsgi_log("this platform does not support mountpoints check !!!\n");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
+248
-222
@@ -19,14 +19,14 @@ void mule_send_msg(int fd, char *message, size_t len) {
|
||||
|
||||
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()");
|
||||
}
|
||||
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()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,63 +34,81 @@ void uwsgi_mule(int id) {
|
||||
|
||||
int i;
|
||||
|
||||
pid_t pid = uwsgi_fork(uwsgi.mules[id-1].name);
|
||||
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()");
|
||||
}
|
||||
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.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.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
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (uwsgi.p[i]->master_fixup) {
|
||||
uwsgi.p[i]->master_fixup(1);
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_mule_handler();
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->post_fork) {
|
||||
uwsgi.p[i]->post_fork();
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_mule_run();
|
||||
|
||||
}
|
||||
else if (pid > 0) {
|
||||
uwsgi.mules[id-1].id = id;
|
||||
uwsgi.mules[id-1].pid = pid;
|
||||
uwsgi.mules[id - 1].id = id;
|
||||
uwsgi.mules[id - 1].pid = pid;
|
||||
uwsgi_log("spawned uWSGI mule %d (pid: %d)\n", id, (int) pid);
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_mule_run() {
|
||||
int id = uwsgi.muleid;
|
||||
int i;
|
||||
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();
|
||||
}
|
||||
|
||||
int uwsgi_farm_has_mule(struct uwsgi_farm *farm, int muleid) {
|
||||
|
||||
struct uwsgi_mule_farm *umf = farm->mules;
|
||||
|
||||
while(umf) {
|
||||
while (umf) {
|
||||
if (umf->mule->id == muleid) {
|
||||
return 1;
|
||||
}
|
||||
@@ -103,54 +121,54 @@ int uwsgi_farm_has_mule(struct uwsgi_farm *farm, int muleid) {
|
||||
int farm_has_signaled(int fd) {
|
||||
|
||||
int i;
|
||||
for(i=0;i<uwsgi.farms_cnt;i++) {
|
||||
for (i = 0; i < uwsgi.farms_cnt; i++) {
|
||||
struct uwsgi_mule_farm *umf = uwsgi.farms[i].mules;
|
||||
while(umf) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_mule_add_farm_to_queue(int queue) {
|
||||
|
||||
int i;
|
||||
for(i=0;i<uwsgi.farms_cnt;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]);
|
||||
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];
|
||||
|
||||
@@ -158,12 +176,12 @@ void uwsgi_mule_handler() {
|
||||
|
||||
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.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(;;) {
|
||||
for (;;) {
|
||||
rlen = event_queue_wait(mule_queue, -1, &interesting_fd);
|
||||
if (rlen <= 0) {
|
||||
continue;
|
||||
@@ -172,33 +190,36 @@ void uwsgi_mule_handler() {
|
||||
if (interesting_fd == uwsgi.signal_socket || interesting_fd == uwsgi.my_signal_socket || farm_has_signaled(interesting_fd)) {
|
||||
len = read(interesting_fd, &uwsgi_signal, 1);
|
||||
if (len <= 0) {
|
||||
uwsgi_log_verbose("uWSGI mule %d braying: my master died, i will follow him...\n", uwsgi.muleid);
|
||||
end_me(0);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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)) {
|
||||
else if (interesting_fd == uwsgi.mules[uwsgi.muleid - 1].queue_pipe[1] || interesting_fd == uwsgi.shared->mule_queue_pipe[1] || farm_has_msg(interesting_fd)) {
|
||||
len = read(interesting_fd, message, 65536);
|
||||
if (len < 0) {
|
||||
uwsgi_error("read()");
|
||||
}
|
||||
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)) {
|
||||
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 %d bytes message ***\n", uwsgi.muleid, len);
|
||||
uwsgi_log("*** mule %d received a %ld bytes message ***\n", uwsgi.muleid, (long) len);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -209,7 +230,7 @@ struct uwsgi_mule *get_mule_by_id(int id) {
|
||||
|
||||
int i;
|
||||
|
||||
for(i=0;i<uwsgi.mules_cnt;i++) {
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
if (uwsgi.mules[i].id == id) {
|
||||
return &uwsgi.mules[i];
|
||||
}
|
||||
@@ -220,229 +241,234 @@ struct uwsgi_mule *get_mule_by_id(int id) {
|
||||
|
||||
struct uwsgi_farm *get_farm_by_name(char *name) {
|
||||
|
||||
int i;
|
||||
int i;
|
||||
|
||||
for(i=0;i<uwsgi.farms_cnt;i++) {
|
||||
if (!strcmp(uwsgi.farms[i].name, name)) {
|
||||
return &uwsgi.farms[i];
|
||||
}
|
||||
}
|
||||
for (i = 0; i < uwsgi.farms_cnt; i++) {
|
||||
if (!strcmp(uwsgi.farms[i].name, name)) {
|
||||
return &uwsgi.farms[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
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;
|
||||
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;
|
||||
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 = uwsgi_malloc(sizeof(struct uwsgi_mule_farm));
|
||||
old_umf->next = uwsgi_mf;
|
||||
}
|
||||
|
||||
uwsgi_mf->mule = um;
|
||||
uwsgi_mf->next = NULL;
|
||||
uwsgi_mf->mule = um;
|
||||
uwsgi_mf->next = NULL;
|
||||
|
||||
return uwsgi_mf;
|
||||
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;
|
||||
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 (uwsgi.muleid == 0)
|
||||
return -1;
|
||||
|
||||
if (manage_signals) count = 2;
|
||||
if (manage_signals)
|
||||
count = 2;
|
||||
|
||||
if (!manage_farms) goto next;
|
||||
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++;
|
||||
}
|
||||
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;
|
||||
if (timeout > -1)
|
||||
timeout = timeout * 1000;
|
||||
|
||||
mulepoll = uwsgi_malloc(sizeof(struct pollfd) * (count+farms_count));
|
||||
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;
|
||||
}
|
||||
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++) {
|
||||
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;
|
||||
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;
|
||||
}
|
||||
int ret = poll(mulepoll, count + farms_count, timeout);
|
||||
if (ret <= 0) {
|
||||
uwsgi_error("poll");
|
||||
}
|
||||
else {
|
||||
if (mulepoll[0].revents & POLLIN) {
|
||||
len = read(uwsgi.mules[uwsgi.muleid - 1].queue_pipe[1], message, buffer_size);
|
||||
}
|
||||
else if (mulepoll[1].revents & POLLIN) {
|
||||
len = read(uwsgi.shared->mule_queue_pipe[1], message, buffer_size);
|
||||
}
|
||||
else {
|
||||
if (count > 2) {
|
||||
int interesting_fd = -1;
|
||||
if (mulepoll[2].revents & POLLIN) {
|
||||
interesting_fd = mulepoll[2].fd;
|
||||
}
|
||||
else if (mulepoll[3].revents & POLLIN) {
|
||||
interesting_fd = mulepoll[3].fd;
|
||||
}
|
||||
|
||||
if (interesting_fd > -1) {
|
||||
len = read(interesting_fd, &uwsgi_signal, 1);
|
||||
if (len <= 0) {
|
||||
uwsgi_log_verbose("uWSGI mule %d braying: my master died, i will follow him...\n", uwsgi.muleid);
|
||||
end_me(0);
|
||||
}
|
||||
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);
|
||||
uwsgi_log_verbose("master sent signal %d to mule %d\n", uwsgi_signal, uwsgi.muleid);
|
||||
#endif
|
||||
if (uwsgi_signal_handler(uwsgi_signal)) {
|
||||
uwsgi_log_verbose("error managing signal %d on mule %d\n", uwsgi_signal, uwsgi.mywid);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (len < 0) {
|
||||
uwsgi_error("read()");
|
||||
goto clear;
|
||||
}
|
||||
|
||||
clear:
|
||||
free(mulepoll);
|
||||
return len;
|
||||
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);
|
||||
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);
|
||||
}
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
create_signal_pipe(uwsgi.shared->mule_signal_pipe);
|
||||
create_msg_pipe(uwsgi.shared->mule_queue_pipe, uwsgi.mule_msg_size);
|
||||
|
||||
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);
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
// create the socket pipe
|
||||
create_signal_pipe(uwsgi.mules[i].signal_pipe);
|
||||
create_msg_pipe(uwsgi.mules[i].queue_pipe, uwsgi.mule_msg_size);
|
||||
|
||||
uwsgi.mules[i].id = i + 1;
|
||||
uwsgi.mules[i].id = i + 1;
|
||||
|
||||
snprintf(uwsgi.mules[i].name, 0xff, "uWSGI mule %d", 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);
|
||||
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++) {
|
||||
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 *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);
|
||||
}
|
||||
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++;
|
||||
mules_list[0] = 0;
|
||||
mules_list++;
|
||||
|
||||
strncpy(uwsgi.farms[i].name, farm_value, 0xff);
|
||||
strncpy(uwsgi.farms[i].name, farm_value, 0xff);
|
||||
|
||||
|
||||
// create the socket pipe
|
||||
create_signal_pipe(uwsgi.farms[i].signal_pipe);
|
||||
create_signal_pipe(uwsgi.farms[i].queue_pipe);
|
||||
// create the socket pipe
|
||||
create_signal_pipe(uwsgi.farms[i].signal_pipe);
|
||||
create_msg_pipe(uwsgi.farms[i].queue_pipe, uwsgi.mule_msg_size);
|
||||
|
||||
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);
|
||||
}
|
||||
char *p, *ctx = NULL;
|
||||
uwsgi_foreach_token(mules_list, ",", p, ctx) {
|
||||
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);
|
||||
uwsgi_mule_farm_new(&uwsgi.farms[i].mules, um);
|
||||
}
|
||||
uwsgi_log("created farm %d name: %s mules:%s\n", i + 1, uwsgi.farms[i].name, strchr(farm_name->value, ':') + 1);
|
||||
|
||||
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;
|
||||
free(farm_value);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
||||
}
|
||||
|
||||
+658
@@ -0,0 +1,658 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
pipe offload engine:
|
||||
fd -> the file descriptor to read from
|
||||
len -> amount of data to transfer
|
||||
|
||||
*/
|
||||
|
||||
static int u_offload_pipe_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) {
|
||||
|
||||
if (uor->fd < 0 || !uor->len) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
memory offload engine:
|
||||
buf -> pointer to the memory to transfer (memory is freed at the end)
|
||||
len -> amount of data to transfer
|
||||
|
||||
*/
|
||||
|
||||
static int u_offload_memory_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) {
|
||||
|
||||
if (!uor->buf || !uor->len) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
transfer offload engine:
|
||||
name -> socket name
|
||||
ubuf -> data to send
|
||||
|
||||
*/
|
||||
|
||||
static 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->name, 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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
offload memory transfer
|
||||
|
||||
uor->len -> the size of the memory chunk
|
||||
uor->buf -> the memory to transfer
|
||||
uor->written -> written bytes
|
||||
|
||||
status: none
|
||||
|
||||
*/
|
||||
|
||||
static int u_offload_memory_do(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) {
|
||||
if (fd == -1) {
|
||||
if (event_queue_add_fd_write(ut->queue, uor->s)) return -1;
|
||||
return 0;
|
||||
}
|
||||
ssize_t rlen = write(uor->s, uor->buf + uor->written, uor->len - uor->written);
|
||||
if (rlen > 0) {
|
||||
uor->written += rlen;
|
||||
if (uor->written >= uor->len) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_memory_do()");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
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__) || defined(__GNU_kFreeBSD__)
|
||||
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__) && !defined(NO_SENDFILE)
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
pipe offloading
|
||||
status:
|
||||
0 -> waiting for data on fd
|
||||
1 -> waiting for write to s
|
||||
*/
|
||||
|
||||
static int u_offload_pipe_do(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) {
|
||||
|
||||
ssize_t rlen;
|
||||
|
||||
// setup
|
||||
if (fd == -1) {
|
||||
event_queue_add_fd_read(ut->queue, uor->fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch(uor->status) {
|
||||
// read event from fd
|
||||
case 0:
|
||||
if (!uor->buf) {
|
||||
uor->buf = uwsgi_malloc(4096);
|
||||
}
|
||||
rlen = read(uor->fd, uor->buf, 4096);
|
||||
if (rlen > 0) {
|
||||
uor->to_write = rlen;
|
||||
uor->pos = 0;
|
||||
if (event_queue_del_fd(ut->queue, uor->fd, event_queue_read())) return -1;
|
||||
if (event_queue_add_fd_write(ut->queue, uor->s)) return -1;
|
||||
uor->status = 1;
|
||||
return 0;
|
||||
}
|
||||
if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_pipe_do() -> read()");
|
||||
}
|
||||
return -1;
|
||||
// write event on s
|
||||
case 1:
|
||||
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_del_fd(ut->queue, uor->s, event_queue_write())) return -1;
|
||||
if (event_queue_add_fd_read(ut->queue, uor->fd)) return -1;
|
||||
uor->status = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_pipe_do() -> write()");
|
||||
}
|
||||
return -1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
uwsgi.offload_engine_memory = uwsgi_offload_register_engine("memory", u_offload_memory_prepare, u_offload_memory_do);
|
||||
uwsgi.offload_engine_pipe = uwsgi_offload_register_engine("pipe", u_offload_pipe_prepare, u_offload_pipe_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);
|
||||
}
|
||||
|
||||
int uwsgi_offload_request_memory_do(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
struct uwsgi_offload_request uor;
|
||||
uwsgi_offload_setup(uwsgi.offload_engine_memory, &uor, wsgi_req, 1);
|
||||
uor.buf = buf;
|
||||
uor.len = len;
|
||||
return uwsgi_offload_run(wsgi_req, &uor, NULL);
|
||||
}
|
||||
|
||||
int uwsgi_offload_request_pipe_do(struct wsgi_request *wsgi_req, int fd, size_t len) {
|
||||
struct uwsgi_offload_request uor;
|
||||
uwsgi_offload_setup(uwsgi.offload_engine_pipe, &uor, wsgi_req, 1);
|
||||
uor.fd = fd;
|
||||
uor.len = len;
|
||||
return uwsgi_offload_run(wsgi_req, &uor, NULL);
|
||||
}
|
||||
+115
-64
@@ -2,7 +2,31 @@
|
||||
|
||||
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")) {
|
||||
if (!plugin_already_loaded(equal+1)) {
|
||||
uwsgi_load_plugin(-1, equal + 1, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
p = strtok_r(NULL, "\n", &ctx);
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
struct uwsgi_plugin *uwsgi_plugin_get(const char *plugin) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
@@ -11,42 +35,49 @@ static int plugin_already_loaded(const char *plugin) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%s plugin already available\n", plugin);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
return uwsgi.p[i];
|
||||
}
|
||||
}
|
||||
if (uwsgi.p[i]->alias) {
|
||||
if (!strcmp(plugin, uwsgi.p[i]->alias)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%s plugin already available\n", plugin);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
return uwsgi.p[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 uwsgi.p[i];
|
||||
}
|
||||
}
|
||||
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 uwsgi.p[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int plugin_already_loaded(const char *plugin) {
|
||||
struct uwsgi_plugin *up = uwsgi_plugin_get(plugin);
|
||||
if (up) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
|
||||
|
||||
void *plugin_handle = NULL;
|
||||
@@ -54,9 +85,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,10 +96,16 @@ 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] = ':';
|
||||
}
|
||||
|
||||
char *init_func = strchr(plugin_name, '|');
|
||||
if (init_func) {
|
||||
init_func[0] = 0;
|
||||
init_func++;
|
||||
}
|
||||
|
||||
if (!uwsgi_endswith(plugin_name, "_plugin.so")) {
|
||||
plugin_name = uwsgi_concat2(plugin_name, "_plugin.so");
|
||||
need_free = 1;
|
||||
@@ -79,10 +115,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 +132,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 +151,28 @@ 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 {
|
||||
if (init_func) {
|
||||
void (*plugin_init_func)() = dlsym(plugin_handle, init_func);
|
||||
if (plugin_init_func) {
|
||||
plugin_init_func();
|
||||
}
|
||||
}
|
||||
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 +180,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 +193,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 +212,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 +228,8 @@ success:
|
||||
if (!strcmp(has_option, op->name)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
op++;
|
||||
}
|
||||
op++;
|
||||
}
|
||||
if (!found) {
|
||||
if (dlclose(plugin_handle)) {
|
||||
@@ -192,14 +242,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);
|
||||
@@ -210,10 +260,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)
|
||||
@@ -228,14 +278,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);
|
||||
@@ -248,27 +298,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);
|
||||
}
|
||||
+798
-1672
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;
|
||||
}
|
||||
+97
-89
@@ -4,132 +4,137 @@ extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_init_queue() {
|
||||
if (!uwsgi.queue_blocksize)
|
||||
uwsgi.queue_blocksize = 8192;
|
||||
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_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 (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 (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);
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
// 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 == MAP_FAILED) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
uwsgi.queue_lock = uwsgi_rwlock_init("queue");
|
||||
uwsgi.queue_lock = uwsgi_rwlock_init("queue");
|
||||
|
||||
uwsgi_log("*** Queue subsystem initialized: %dMB preallocated ***\n", (uwsgi.queue_blocksize * uwsgi.queue_size) / (1024 * 1024));
|
||||
uwsgi_log("*** Queue subsystem initialized: %luMB preallocated ***\n", (uwsgi.queue_blocksize * uwsgi.queue_size) / (1024 * 1024));
|
||||
}
|
||||
|
||||
char *uwsgi_queue_get(uint64_t index, uint64_t *size) {
|
||||
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;
|
||||
if (index >= uwsgi.queue_size)
|
||||
return NULL;
|
||||
|
||||
ptr = ptr + (uwsgi.queue_blocksize*index);
|
||||
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) {
|
||||
char *uwsgi_queue_pop(uint64_t * size) {
|
||||
|
||||
struct uwsgi_queue_item *uqi;
|
||||
char *ptr = (char *) uwsgi.queue;
|
||||
struct uwsgi_queue_item *uqi;
|
||||
char *ptr = (char *) uwsgi.queue;
|
||||
|
||||
if (uwsgi.queue_header->pos == 0) {
|
||||
uwsgi.queue_header->pos = uwsgi.queue_size-1;
|
||||
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;
|
||||
ptr = ptr + (uwsgi.queue_blocksize * uwsgi.queue_header->pos);
|
||||
uqi = (struct uwsgi_queue_item *) ptr;
|
||||
|
||||
if (!uqi->size) return NULL;
|
||||
if (!uqi->size)
|
||||
return NULL;
|
||||
|
||||
*size = uqi->size;
|
||||
*size = uqi->size;
|
||||
// remove item
|
||||
uqi->size = 0;
|
||||
|
||||
return ptr + sizeof(struct uwsgi_queue_item);
|
||||
return ptr + sizeof(struct uwsgi_queue_item);
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_queue_pull(uint64_t *size) {
|
||||
char *uwsgi_queue_pull(uint64_t * size) {
|
||||
|
||||
struct uwsgi_queue_item *uqi;
|
||||
char *ptr = (char *) uwsgi.queue;
|
||||
char *ptr = (char *) uwsgi.queue;
|
||||
|
||||
ptr = ptr + (uwsgi.queue_blocksize*uwsgi.queue_header->pull_pos);
|
||||
ptr = ptr + (uwsgi.queue_blocksize * uwsgi.queue_header->pull_pos);
|
||||
uqi = (struct uwsgi_queue_item *) ptr;
|
||||
|
||||
if (!uqi->size) return NULL;
|
||||
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;
|
||||
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);
|
||||
|
||||
}
|
||||
@@ -142,9 +147,10 @@ int uwsgi_queue_push(char *message, uint64_t size) {
|
||||
if (size > uwsgi.queue_blocksize + sizeof(struct uwsgi_queue_item))
|
||||
return 0;
|
||||
|
||||
if (!size) return 0;
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
ptr = ptr + (uwsgi.queue_blocksize*uwsgi.queue_header->pos);
|
||||
ptr = ptr + (uwsgi.queue_blocksize * uwsgi.queue_header->pos);
|
||||
uqi = (struct uwsgi_queue_item *) ptr;
|
||||
|
||||
ptr += sizeof(struct uwsgi_queue_item);
|
||||
@@ -154,33 +160,35 @@ int uwsgi_queue_push(char *message, uint64_t size) {
|
||||
memcpy(ptr, message, size);
|
||||
|
||||
uwsgi.queue_header->pos++;
|
||||
|
||||
if (uwsgi.queue_header->pos >= uwsgi.queue_size) uwsgi.queue_header->pos = 0;
|
||||
|
||||
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;
|
||||
struct uwsgi_queue_item *uqi;
|
||||
char *ptr = (char *) uwsgi.queue;
|
||||
|
||||
if (size > uwsgi.queue_blocksize + sizeof(struct uwsgi_queue_item))
|
||||
return 0;
|
||||
if (size > uwsgi.queue_blocksize + sizeof(struct uwsgi_queue_item))
|
||||
return 0;
|
||||
|
||||
if (!size) return 0;
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
if (pos >= uwsgi.queue_size) return 0;
|
||||
if (pos >= uwsgi.queue_size)
|
||||
return 0;
|
||||
|
||||
ptr = ptr + (uwsgi.queue_blocksize*pos);
|
||||
uqi = (struct uwsgi_queue_item *) ptr;
|
||||
ptr = ptr + (uwsgi.queue_blocksize * pos);
|
||||
uqi = (struct uwsgi_queue_item *) ptr;
|
||||
|
||||
ptr += sizeof(struct uwsgi_queue_item);
|
||||
ptr += sizeof(struct uwsgi_queue_item);
|
||||
|
||||
uqi->size = size;
|
||||
uqi->ts = uwsgi_now();
|
||||
memcpy(ptr, message, size);
|
||||
uqi->size = size;
|
||||
uqi->ts = uwsgi_now();
|
||||
memcpy(ptr, message, size);
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
+334
-31
@@ -1,64 +1,367 @@
|
||||
/*
|
||||
|
||||
uWSGI timers implementation
|
||||
uWSGI rbtree implementation based on nginx
|
||||
|
||||
based on Linux hrtimers and nginx timeout management.
|
||||
|
||||
rbtree with allowed duplicate keys is used
|
||||
Copyright (C) Igor Sysoev
|
||||
Copyright (C) Nginx, Inc.
|
||||
Copyright (C) Unbit S.a.s.
|
||||
|
||||
The red-black tree code is based on the algorithm described in
|
||||
the "Introduction to Algorithms" by Cormen, Leiserson and Rivest.
|
||||
*/
|
||||
|
||||
#include "uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
struct rb_root *uwsgi_init_rb_timer() {
|
||||
#define uwsgi_rbt_red(node) ((node)->color = 1)
|
||||
#define uwsgi_rbt_black(node) ((node)->color = 0)
|
||||
#define uwsgi_rbt_is_red(node) ((node)->color)
|
||||
#define uwsgi_rbt_is_black(node) (!uwsgi_rbt_is_red(node))
|
||||
#define uwsgi_rbt_copy_color(n1, n2) (n1->color = n2->color)
|
||||
|
||||
struct rb_root *u_rb_root = uwsgi_malloc(sizeof(struct rb_root));
|
||||
|
||||
u_rb_root->rb_node = NULL;
|
||||
struct uwsgi_rbtree *uwsgi_init_rb_timer() {
|
||||
|
||||
return u_rb_root;
|
||||
struct uwsgi_rbtree *tree = uwsgi_calloc(sizeof(struct uwsgi_rbtree));
|
||||
struct uwsgi_rb_timer *sentinel = uwsgi_calloc(sizeof(struct uwsgi_rb_timer));
|
||||
// no need to set it black, calloc already did it
|
||||
//uwsgi_rbt_black(sentinel);
|
||||
tree->root = sentinel;
|
||||
tree->sentinel = sentinel;
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
struct uwsgi_rb_timer *uwsgi_min_rb_timer(struct rb_root *root) {
|
||||
struct uwsgi_rb_timer *uwsgi_min_rb_timer(struct uwsgi_rbtree *tree, struct uwsgi_rb_timer *node) {
|
||||
|
||||
struct rb_node *node = root->rb_node;
|
||||
if (!node)
|
||||
node = tree->root;
|
||||
struct uwsgi_rb_timer *sentinel = tree->sentinel;
|
||||
|
||||
if (node == NULL) return NULL;
|
||||
if (tree->root == sentinel) return NULL;
|
||||
|
||||
while(node->rb_left != NULL) {
|
||||
node = node->rb_left;
|
||||
while (node->left != sentinel) {
|
||||
node = node->left;
|
||||
}
|
||||
|
||||
return ((struct uwsgi_rb_timer *) node);
|
||||
return node;
|
||||
}
|
||||
|
||||
struct uwsgi_rb_timer *uwsgi_add_rb_timer(struct rb_root *root, time_t key, void *data) {
|
||||
static void uwsgi_rbtree_lr(struct uwsgi_rb_timer **root, struct uwsgi_rb_timer *sentinel, struct uwsgi_rb_timer *node) {
|
||||
|
||||
struct uwsgi_rb_timer *urbt = uwsgi_malloc(sizeof(struct uwsgi_rb_timer));
|
||||
struct rb_node **p = &root->rb_node, *parent = NULL;
|
||||
struct uwsgi_rb_timer *current_rb_timer;
|
||||
struct uwsgi_rb_timer *temp;
|
||||
|
||||
memset(urbt, 0, sizeof(struct uwsgi_rb_timer));
|
||||
temp = node->right;
|
||||
node->right = temp->left;
|
||||
|
||||
urbt->key = key;
|
||||
urbt->data = data;
|
||||
if (temp->left != sentinel) {
|
||||
temp->left->parent = node;
|
||||
}
|
||||
|
||||
while(*p) {
|
||||
parent = *p;
|
||||
temp->parent = node->parent;
|
||||
|
||||
current_rb_timer = (struct uwsgi_rb_timer *) parent;
|
||||
if (node == *root) {
|
||||
*root = temp;
|
||||
|
||||
}
|
||||
else if (node == node->parent->left) {
|
||||
node->parent->left = temp;
|
||||
|
||||
}
|
||||
else {
|
||||
node->parent->right = temp;
|
||||
}
|
||||
|
||||
temp->left = node;
|
||||
node->parent = temp;
|
||||
}
|
||||
|
||||
|
||||
static void uwsgi_rbtree_rr(struct uwsgi_rb_timer **root, struct uwsgi_rb_timer *sentinel, struct uwsgi_rb_timer *node) {
|
||||
|
||||
struct uwsgi_rb_timer *temp;
|
||||
|
||||
temp = node->left;
|
||||
node->left = temp->right;
|
||||
|
||||
if (temp->right != sentinel) {
|
||||
temp->right->parent = node;
|
||||
}
|
||||
|
||||
temp->parent = node->parent;
|
||||
|
||||
if (node == *root) {
|
||||
*root = temp;
|
||||
|
||||
}
|
||||
else if (node == node->parent->right) {
|
||||
node->parent->right = temp;
|
||||
|
||||
}
|
||||
else {
|
||||
node->parent->left = temp;
|
||||
}
|
||||
|
||||
temp->right = node;
|
||||
node->parent = temp;
|
||||
}
|
||||
|
||||
|
||||
static void uwsgi_rbt_add(struct uwsgi_rb_timer *temp, struct uwsgi_rb_timer *node, struct uwsgi_rb_timer *sentinel) {
|
||||
struct uwsgi_rb_timer **p;
|
||||
|
||||
for (;;) {
|
||||
|
||||
p = (node->value < temp->value) ? &temp->left : &temp->right;
|
||||
if (*p == sentinel)
|
||||
break;
|
||||
temp = *p;
|
||||
}
|
||||
|
||||
*p = node;
|
||||
node->parent = temp;
|
||||
node->left = sentinel;
|
||||
node->right = sentinel;
|
||||
uwsgi_rbt_red(node);
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_rb_timer *uwsgi_add_rb_timer(struct uwsgi_rbtree *tree, uint64_t value, void *data) {
|
||||
|
||||
struct uwsgi_rb_timer *node = uwsgi_malloc(sizeof(struct uwsgi_rb_timer));
|
||||
struct uwsgi_rb_timer *new_node = node;
|
||||
node->value = value;
|
||||
node->data = data;
|
||||
|
||||
struct uwsgi_rb_timer *temp = NULL;
|
||||
|
||||
/* a binary tree insert */
|
||||
|
||||
struct uwsgi_rb_timer **root = &tree->root;
|
||||
struct uwsgi_rb_timer *sentinel = tree->sentinel;
|
||||
|
||||
if (*root == sentinel) {
|
||||
node->parent = NULL;
|
||||
node->left = sentinel;
|
||||
node->right = sentinel;
|
||||
uwsgi_rbt_black(node);
|
||||
*root = node;
|
||||
return new_node;
|
||||
}
|
||||
|
||||
uwsgi_rbt_add(*root, node, sentinel);
|
||||
|
||||
/* re-balance tree */
|
||||
|
||||
while (node != *root && uwsgi_rbt_is_red(node->parent)) {
|
||||
|
||||
if (node->parent == node->parent->parent->left) {
|
||||
temp = node->parent->parent->right;
|
||||
|
||||
if (uwsgi_rbt_is_red(temp)) {
|
||||
uwsgi_rbt_black(node->parent);
|
||||
uwsgi_rbt_black(temp);
|
||||
uwsgi_rbt_red(node->parent->parent);
|
||||
node = node->parent->parent;
|
||||
|
||||
}
|
||||
else {
|
||||
if (node == node->parent->right) {
|
||||
node = node->parent;
|
||||
uwsgi_rbtree_lr(root, sentinel, node);
|
||||
}
|
||||
|
||||
uwsgi_rbt_black(node->parent);
|
||||
uwsgi_rbt_red(node->parent->parent);
|
||||
uwsgi_rbtree_rr(root, sentinel, node->parent->parent);
|
||||
}
|
||||
|
||||
if (key <= current_rb_timer->key) {
|
||||
p = &(*p)->rb_left;
|
||||
}
|
||||
else {
|
||||
p = &(*p)->rb_right;
|
||||
temp = node->parent->parent->left;
|
||||
|
||||
if (uwsgi_rbt_is_red(temp)) {
|
||||
uwsgi_rbt_black(node->parent);
|
||||
uwsgi_rbt_black(temp);
|
||||
uwsgi_rbt_red(node->parent->parent);
|
||||
node = node->parent->parent;
|
||||
|
||||
}
|
||||
else {
|
||||
if (node == node->parent->left) {
|
||||
node = node->parent;
|
||||
uwsgi_rbtree_rr(root, sentinel, node);
|
||||
}
|
||||
|
||||
uwsgi_rbt_black(node->parent);
|
||||
uwsgi_rbt_red(node->parent->parent);
|
||||
uwsgi_rbtree_lr(root, sentinel, node->parent->parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rb_link_node((struct rb_node *) urbt, parent, p);
|
||||
uwsgi_rbt_black(*root);
|
||||
|
||||
rb_insert_color((struct rb_node *) urbt, root);
|
||||
return new_node;
|
||||
}
|
||||
|
||||
return urbt;
|
||||
void uwsgi_del_rb_timer(struct uwsgi_rbtree *tree, struct uwsgi_rb_timer *node) {
|
||||
uint8_t red;
|
||||
struct uwsgi_rb_timer **root, *sentinel, *subst, *temp, *w;
|
||||
|
||||
/* a binary tree delete */
|
||||
|
||||
root = &tree->root;
|
||||
sentinel = tree->sentinel;
|
||||
|
||||
if (node->left == sentinel) {
|
||||
temp = node->right;
|
||||
subst = node;
|
||||
|
||||
}
|
||||
else if (node->right == sentinel) {
|
||||
temp = node->left;
|
||||
subst = node;
|
||||
|
||||
}
|
||||
else {
|
||||
subst = uwsgi_min_rb_timer(tree, node->right);
|
||||
|
||||
if (subst->left != sentinel) {
|
||||
temp = subst->left;
|
||||
}
|
||||
else {
|
||||
temp = subst->right;
|
||||
}
|
||||
}
|
||||
|
||||
if (subst == *root) {
|
||||
*root = temp;
|
||||
uwsgi_rbt_black(temp);
|
||||
return;
|
||||
}
|
||||
|
||||
red = uwsgi_rbt_is_red(subst);
|
||||
|
||||
if (subst == subst->parent->left) {
|
||||
subst->parent->left = temp;
|
||||
|
||||
}
|
||||
else {
|
||||
subst->parent->right = temp;
|
||||
}
|
||||
|
||||
if (subst == node) {
|
||||
|
||||
temp->parent = subst->parent;
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
if (subst->parent == node) {
|
||||
temp->parent = subst;
|
||||
|
||||
}
|
||||
else {
|
||||
temp->parent = subst->parent;
|
||||
}
|
||||
|
||||
subst->left = node->left;
|
||||
subst->right = node->right;
|
||||
subst->parent = node->parent;
|
||||
uwsgi_rbt_copy_color(subst, node);
|
||||
|
||||
if (node == *root) {
|
||||
*root = subst;
|
||||
|
||||
}
|
||||
else {
|
||||
if (node == node->parent->left) {
|
||||
node->parent->left = subst;
|
||||
}
|
||||
else {
|
||||
node->parent->right = subst;
|
||||
}
|
||||
}
|
||||
|
||||
if (subst->left != sentinel) {
|
||||
subst->left->parent = subst;
|
||||
}
|
||||
|
||||
if (subst->right != sentinel) {
|
||||
subst->right->parent = subst;
|
||||
}
|
||||
}
|
||||
|
||||
if (red) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* a delete fixup */
|
||||
|
||||
while (temp != *root && uwsgi_rbt_is_black(temp)) {
|
||||
|
||||
if (temp == temp->parent->left) {
|
||||
w = temp->parent->right;
|
||||
|
||||
if (uwsgi_rbt_is_red(w)) {
|
||||
uwsgi_rbt_black(w);
|
||||
uwsgi_rbt_red(temp->parent);
|
||||
uwsgi_rbtree_lr(root, sentinel, temp->parent);
|
||||
w = temp->parent->right;
|
||||
}
|
||||
|
||||
if (uwsgi_rbt_is_black(w->left) && uwsgi_rbt_is_black(w->right)) {
|
||||
uwsgi_rbt_red(w);
|
||||
temp = temp->parent;
|
||||
|
||||
}
|
||||
else {
|
||||
if (uwsgi_rbt_is_black(w->right)) {
|
||||
uwsgi_rbt_black(w->left);
|
||||
uwsgi_rbt_red(w);
|
||||
uwsgi_rbtree_rr(root, sentinel, w);
|
||||
w = temp->parent->right;
|
||||
}
|
||||
|
||||
uwsgi_rbt_copy_color(w, temp->parent);
|
||||
uwsgi_rbt_black(temp->parent);
|
||||
uwsgi_rbt_black(w->right);
|
||||
uwsgi_rbtree_lr(root, sentinel, temp->parent);
|
||||
temp = *root;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
w = temp->parent->left;
|
||||
|
||||
if (uwsgi_rbt_is_red(w)) {
|
||||
uwsgi_rbt_black(w);
|
||||
uwsgi_rbt_red(temp->parent);
|
||||
uwsgi_rbtree_rr(root, sentinel, temp->parent);
|
||||
w = temp->parent->left;
|
||||
}
|
||||
|
||||
if (uwsgi_rbt_is_black(w->left) && uwsgi_rbt_is_black(w->right)) {
|
||||
uwsgi_rbt_red(w);
|
||||
temp = temp->parent;
|
||||
|
||||
}
|
||||
else {
|
||||
if (uwsgi_rbt_is_black(w->left)) {
|
||||
uwsgi_rbt_black(w->right);
|
||||
uwsgi_rbt_red(w);
|
||||
uwsgi_rbtree_lr(root, sentinel, w);
|
||||
w = temp->parent->left;
|
||||
}
|
||||
|
||||
uwsgi_rbt_copy_color(w, temp->parent);
|
||||
uwsgi_rbt_black(temp->parent);
|
||||
uwsgi_rbt_black(w->left);
|
||||
uwsgi_rbtree_rr(root, sentinel, temp->parent);
|
||||
temp = *root;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_rbt_black(temp);
|
||||
}
|
||||
|
||||
+574
@@ -0,0 +1,574 @@
|
||||
#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 ((off_t) wsgi_req->post_pos - pos < 0) {
|
||||
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;
|
||||
}else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
goto wait;
|
||||
}
|
||||
*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 = uwsgi_tmpfile();
|
||||
if (!wsgi_req->post_file) {
|
||||
uwsgi_error("uwsgi_postbuffer_do_in_disk()/uwsgi_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;
|
||||
}
|
||||
|
||||
+45
-22
@@ -1,46 +1,60 @@
|
||||
#ifdef UWSGI_PCRE
|
||||
#include "uwsgi.h"
|
||||
|
||||
int uwsgi_regexp_build(char *re, pcre **pattern, pcre_extra **pattern_extra) {
|
||||
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) {
|
||||
*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;
|
||||
}
|
||||
|
||||
*pattern_extra = (pcre_extra *) pcre_study((const pcre*)*pattern, 0, &errstr);
|
||||
if (*pattern_extra == NULL && errstr != NULL) {
|
||||
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) {
|
||||
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 );
|
||||
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 ) {
|
||||
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, ovec, (n + 1) * 3);
|
||||
}
|
||||
return pcre_exec((const pcre*)pattern, (const pcre_extra *)pattern_extra, subject, length, 0, 0, NULL, 0 );
|
||||
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 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))
|
||||
if (pcre_fullinfo((const pcre *) pattern, (const pcre_extra *) pattern_extra, PCRE_INFO_CAPTURECOUNT, &n))
|
||||
return 0;
|
||||
|
||||
return n;
|
||||
@@ -51,35 +65,44 @@ char *uwsgi_regexp_apply_ovec(char *src, int src_n, char *dst, int dst_n, int *o
|
||||
int i;
|
||||
int dollar = 0;
|
||||
|
||||
char *res = uwsgi_malloc( dst_n + (src_n * n) + 1);
|
||||
size_t dollars = n;
|
||||
|
||||
for(i=0;i<dst_n;i++) {
|
||||
if (dst[i] == '$') {
|
||||
dollars++;
|
||||
}
|
||||
}
|
||||
|
||||
char *res = uwsgi_malloc(dst_n + (src_n * dollars) + 1);
|
||||
char *ptr = res;
|
||||
|
||||
for(i=0;i<dst_n;i++) {
|
||||
for (i = 0; i < dst_n; i++) {
|
||||
if (dollar) {
|
||||
if (isdigit((int)dst[i])) {
|
||||
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];
|
||||
memcpy(ptr, src + ovector[pos], ovector[pos + 1] - ovector[pos]);
|
||||
ptr += ovector[pos + 1] - ovector[pos];
|
||||
}
|
||||
}
|
||||
else {
|
||||
*ptr++= dst[i];
|
||||
*ptr++ = '$';
|
||||
*ptr++ = dst[i];
|
||||
}
|
||||
dollar = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (dst[i] == '$') {
|
||||
dollar = 1;
|
||||
}
|
||||
else {
|
||||
*ptr++= dst[i];
|
||||
*ptr++ = dst[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*ptr++= 0;
|
||||
*ptr++ = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
+1807
-72
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