mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-10-04 16:08:31 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
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 | ||
|
|
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 |
@@ -0,0 +1,9 @@
|
||||
*.o
|
||||
*.py[co]
|
||||
*.class
|
||||
*.jar
|
||||
|
||||
/uwsgi
|
||||
/uwsgibuild.*
|
||||
|
||||
/t/ring/target
|
||||
@@ -53,3 +53,6 @@ e1568fd16b7b586cc72deb4dfccbbe64ae0b84df 1.1
|
||||
29de0fb320bc0a1ce84972f9f249360e315d3c10 1.2-rc2
|
||||
c3cdecbf2bac591336baddd14f9ac22e18d6e200 1.2
|
||||
14524da00a8b382dffb1d16a0e70cdf4a946f369 1.3-rc2
|
||||
883b946db9038372cb1d76cb1d328a3093140e7b 1.3-rc3
|
||||
aeea5a5d2e8b62ad55e23d539e1be02f2b6962af 1.3-rc4
|
||||
620e0cb6ccdb0ce27561b4240cb3a0ef4c3527fd 1.3
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
language: c
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
|
||||
script:
|
||||
- echo -e "\n\n>>> Building uWSGI binary"
|
||||
- /usr/bin/python uwsgiconfig.py --build travis
|
||||
- echo -e "\n\n>>> Building python26 plugin"
|
||||
- /usr/bin/python2.6 -V
|
||||
- /usr/bin/python2.6 uwsgiconfig.py --plugin plugins/python base python26
|
||||
- echo -e "\n\n>>> Building python27 plugin"
|
||||
- /usr/bin/python2.7 -V
|
||||
- /usr/bin/python2.7 uwsgiconfig.py --plugin plugins/python base python27
|
||||
- echo -e "\n\n>>> Building python31 plugin"
|
||||
- /usr/bin/python3.1 -V
|
||||
- /usr/bin/python3.1 uwsgiconfig.py --plugin plugins/python base python31
|
||||
- echo -e "\n\n>>> Building python32 plugin"
|
||||
- /usr/bin/python3.2 -V
|
||||
- /usr/bin/python3.2 uwsgiconfig.py --plugin plugins/python base python32
|
||||
- echo -e "\n\n>>> Building python33 plugin"
|
||||
- /usr/bin/python3.3 -V
|
||||
- /usr/bin/python3.3 uwsgiconfig.py --plugin plugins/python base python33
|
||||
- echo -e "\n\n>>> Building rack 1.8.7 plugin"
|
||||
- /usr/bin/ruby1.8 -v
|
||||
- UWSGICONFIG_RUBYPATH=/usr/bin/ruby1.8 /usr/bin/python uwsgiconfig.py --plugin plugins/rack base rack187
|
||||
- echo -e "\n\n>>> Building rack 1.9.1 plugin"
|
||||
- /usr/bin/ruby1.9.1 -v
|
||||
- UWSGICONFIG_RUBYPATH=/usr/bin/ruby1.9.1 /usr/bin/python uwsgiconfig.py --plugin plugins/rack base rack191
|
||||
- echo -e "\n\n>>> Building cgi plugin"
|
||||
- /usr/bin/python uwsgiconfig.py --plugin plugins/cgi base
|
||||
- echo -e "\n\n>>> Building dummy plugin"
|
||||
- /usr/bin/python uwsgiconfig.py --plugin plugins/dummy base
|
||||
- echo -e "\n\n>>> Building done, starting tests"
|
||||
- ./tests/travis.sh
|
||||
|
||||
before_install:
|
||||
- sudo add-apt-repository -y ppa:fkrull/deadsnakes
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qqyf python2.6-dev python2.7-dev python3.1-dev python3.2-dev python3.3-dev rubygems1.8 ruby1.8-dev ruby1.9.1-dev
|
||||
- sudo apt-get install -qqyf libxml2-dev libpcre3-dev libcap2-dev
|
||||
- sudo apt-get install -qqyf curl
|
||||
|
||||
@@ -18,3 +18,7 @@ Lukas Lalinsky
|
||||
Steven Fernandez
|
||||
Łukasz Mierzwa
|
||||
Roy Marples
|
||||
Aarni Koskela
|
||||
C Anthony Risinger
|
||||
Stephen Pierce
|
||||
Mingli Yuan
|
||||
|
||||
@@ -1,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
|
||||
@@ -3,3 +3,6 @@ all:
|
||||
|
||||
clean:
|
||||
python uwsgiconfig.py --clean
|
||||
|
||||
check:
|
||||
python uwsgiconfig.py --check
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
surprise i am empty !
|
||||
|
||||
Look in the online documentation on http://projects.unbit.it/uwsgi/
|
||||
Look in the online documentation on https://uwsgi-docs.readthedocs.org/en/latest/
|
||||
|
||||
+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
|
||||
|
||||
@@ -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
|
||||
inherit = base
|
||||
+1
-14
@@ -1,24 +1,11 @@
|
||||
[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
|
||||
debug = false
|
||||
unbit = false
|
||||
xml_implementation = libxml2
|
||||
@@ -29,7 +16,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
|
||||
as_shared_library = false
|
||||
|
||||
locking = auto
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
[uwsgi]
|
||||
# pypy,jvm,ring,jwsgi
|
||||
main_plugin = erlang,psgi,rack,lua,python,gevent,php,cgi,mono,pyerl,go
|
||||
inherit = base
|
||||
@@ -1,3 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = python
|
||||
main_plugin = python,gevent
|
||||
inherit = base
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
[uwsgi]
|
||||
main_plugin = go
|
||||
inherit = base
|
||||
bin_name = libuwsgi.so
|
||||
as_shared_library = true
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = gridfs
|
||||
inherit = base
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = jvm,jwsgi
|
||||
inherit = base
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = mono
|
||||
inherit = base
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin =
|
||||
inherit = base
|
||||
@@ -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 =
|
||||
@@ -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 = jvm,ring
|
||||
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
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
[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
|
||||
debug = false
|
||||
unbit = false
|
||||
xml_implementation = libxml2
|
||||
yaml_implementation = auto
|
||||
malloc_implementation = libc
|
||||
extras =
|
||||
plugins =
|
||||
bin_name = uwsgi
|
||||
append_version =
|
||||
plugin_dir = .
|
||||
embedded_plugins =
|
||||
as_shared_library = false
|
||||
|
||||
locking = auto
|
||||
event = auto
|
||||
timer = auto
|
||||
filemonitor = auto
|
||||
|
||||
blacklist =
|
||||
whitelist =
|
||||
|
||||
embed_files =
|
||||
|
||||
embed_config =
|
||||
@@ -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
|
||||
+471
@@ -0,0 +1,471 @@
|
||||
#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 = strtok(list, ",");
|
||||
while (p) {
|
||||
struct uwsgi_alarm_instance *uai = uwsgi_alarm_get_instance(p);
|
||||
if (!uai) {
|
||||
free(list);
|
||||
return -1;
|
||||
}
|
||||
struct uwsgi_alarm_ll *old_uall = NULL, *uall = ual->alarms;
|
||||
while (uall) {
|
||||
old_uall = uall;
|
||||
uall = uall->next;
|
||||
}
|
||||
|
||||
uall = uwsgi_calloc(sizeof(struct uwsgi_alarm_ll));
|
||||
uall->alarm = uai;
|
||||
if (old_uall) {
|
||||
old_uall->next = uall;
|
||||
}
|
||||
else {
|
||||
ual->alarms = uall;
|
||||
}
|
||||
p = strtok(NULL, ",");
|
||||
}
|
||||
free(list);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void uwsgi_alarm_thread_loop(struct uwsgi_thread *ut) {
|
||||
// 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;
|
||||
}
|
||||
+263
-209
@@ -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,153 @@ void async_add_fd_read(struct wsgi_request *wsgi_req, int fd, int timeout) {
|
||||
async_add_timeout(wsgi_req, timeout);
|
||||
}
|
||||
uwsgi.async_waiting_fd_table[fd] = wsgi_req;
|
||||
event_queue_add_fd_read(uwsgi.async_queue, fd);
|
||||
|
||||
wsgi_req->async_force_again = 1;
|
||||
return event_queue_add_fd_read(uwsgi.async_queue, fd);
|
||||
}
|
||||
|
||||
static int async_wait_fd_read(int fd, int timeout) {
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
if (async_add_fd_read(wsgi_req, fd, timeout)) {
|
||||
return -1;
|
||||
}
|
||||
if (uwsgi.schedule_to_main) {
|
||||
uwsgi.schedule_to_main(wsgi_req);
|
||||
}
|
||||
if (wsgi_req->async_timed_out) {
|
||||
wsgi_req->async_timed_out = 0;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void async_add_timeout(struct wsgi_request *wsgi_req, int timeout) {
|
||||
|
||||
if (timeout > 0 && wsgi_req->async_timeout == NULL) {
|
||||
wsgi_req->async_timeout = uwsgi_add_rb_timer(uwsgi.rb_async_timeouts, 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();
|
||||
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;
|
||||
}
|
||||
|
||||
void *async_loop(void *arg1) {
|
||||
void async_schedule_to_req_green(void) {
|
||||
#ifdef UWSGI_ROUTING
|
||||
if (uwsgi_apply_routes(uwsgi.wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
goto end;
|
||||
}
|
||||
#endif
|
||||
for(;;) {
|
||||
if (uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req) <= UWSGI_OK) {
|
||||
break;
|
||||
}
|
||||
uwsgi.wsgi_req->switches++;
|
||||
// switch after each yield
|
||||
uwsgi.schedule_to_main(uwsgi.wsgi_req);
|
||||
}
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
end:
|
||||
#endif
|
||||
async_reset_request(uwsgi.wsgi_req);
|
||||
uwsgi_close_request(uwsgi.wsgi_req);
|
||||
uwsgi.wsgi_req->async_status = UWSGI_OK;
|
||||
}
|
||||
|
||||
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 +355,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("*** WARNING *** 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 +431,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 +450,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 +470,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 +479,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 +488,36 @@ 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
|
||||
// remove from the runqueue
|
||||
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
|
||||
// remove this request from the runqueue
|
||||
runqueue_remove(current_request);
|
||||
}
|
||||
|
||||
current_request = next_async_request;
|
||||
|
||||
current_request = next_request;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
+299
-6
@@ -10,7 +10,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 +99,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 +121,190 @@ int uwsgi_buffer_append(struct uwsgi_buffer *ub, char *buf, size_t len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append_json(struct uwsgi_buffer *ub, char *buf, size_t len) {
|
||||
// need to escape \ and "
|
||||
size_t i;
|
||||
for(i=0;i<len;i++) {
|
||||
if (buf[i] == '"') {
|
||||
if (uwsgi_buffer_append(ub, "\\\"", 2)) return -1;
|
||||
}
|
||||
else if (buf[i] == '\\') {
|
||||
if (uwsgi_buffer_append(ub, "\\\\", 2)) return -1;
|
||||
}
|
||||
else {
|
||||
if (uwsgi_buffer_append(ub, buf+i, 1)) return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u16le(struct uwsgi_buffer *ub, uint16_t num) {
|
||||
uint8_t buf[2];
|
||||
buf[0] = (uint8_t) (num & 0xff);
|
||||
buf[1] = (uint8_t) ((num >> 8) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 2);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u16be(struct uwsgi_buffer *ub, uint16_t num) {
|
||||
uint8_t buf[2];
|
||||
buf[1] = (uint8_t) (num & 0xff);
|
||||
buf[0] = (uint8_t) ((num >> 8) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 2);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u24be(struct uwsgi_buffer *ub, uint32_t num) {
|
||||
uint8_t buf[3];
|
||||
buf[2] = (uint8_t) (num & 0xff);
|
||||
buf[1] = (uint8_t) ((num >> 8) & 0xff);
|
||||
buf[0] = (uint8_t) ((num >> 16) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 3);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u32be(struct uwsgi_buffer *ub, uint32_t num) {
|
||||
uint8_t buf[4];
|
||||
buf[3] = (uint8_t) (num & 0xff);
|
||||
buf[2] = (uint8_t) ((num >> 8) & 0xff);
|
||||
buf[1] = (uint8_t) ((num >> 16) & 0xff);
|
||||
buf[0] = (uint8_t) ((num >> 24) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 4);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u32le(struct uwsgi_buffer *ub, uint32_t num) {
|
||||
uint8_t buf[4];
|
||||
buf[0] = (uint8_t) (num & 0xff);
|
||||
buf[1] = (uint8_t) ((num >> 8) & 0xff);
|
||||
buf[2] = (uint8_t) ((num >> 16) & 0xff);
|
||||
buf[3] = (uint8_t) ((num >> 24) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 4);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u64be(struct uwsgi_buffer *ub, uint64_t num) {
|
||||
uint8_t buf[8];
|
||||
buf[7] = (uint8_t) (num & 0xff);
|
||||
buf[6] = (uint8_t) ((num >> 8) & 0xff);
|
||||
buf[5] = (uint8_t) ((num >> 16) & 0xff);
|
||||
buf[4] = (uint8_t) ((num >> 24) & 0xff);
|
||||
buf[3] = (uint8_t) ((num >> 32) & 0xff);
|
||||
buf[2] = (uint8_t) ((num >> 40) & 0xff);
|
||||
buf[1] = (uint8_t) ((num >> 48) & 0xff);
|
||||
buf[0] = (uint8_t) ((num >> 56) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 8);
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_buffer_append_ipv4(struct uwsgi_buffer *ub, void *addr) {
|
||||
char ip[INET_ADDRSTRLEN];
|
||||
if (!inet_ntop(AF_INET, addr, ip, INET_ADDRSTRLEN)) {
|
||||
uwsgi_error("uwsgi_buffer_append_ipv4() -> inet_ntop()");
|
||||
return -1;
|
||||
}
|
||||
return uwsgi_buffer_append(ub, ip, strlen(ip));
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_buffer_num64(struct uwsgi_buffer *ub, int64_t num) {
|
||||
char buf[sizeof(UMAX64_STR)+1];
|
||||
int ret = snprintf(buf, sizeof(UMAX64_STR)+1, "%lld", (long long) num);
|
||||
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
|
||||
return -1;
|
||||
}
|
||||
return uwsgi_buffer_append(ub, buf, ret);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append_keyval(struct uwsgi_buffer *ub, char *key, uint16_t keylen, char *val, uint16_t vallen) {
|
||||
if (uwsgi_buffer_u16le(ub, keylen)) return -1;
|
||||
if (uwsgi_buffer_append(ub, key, keylen)) return -1;
|
||||
if (uwsgi_buffer_u16le(ub, vallen)) return -1;
|
||||
return uwsgi_buffer_append(ub, val, vallen);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append_keyval32(struct uwsgi_buffer *ub, char *key, uint32_t keylen, char *val, uint32_t vallen) {
|
||||
if (uwsgi_buffer_u32be(ub, keylen)) return -1;
|
||||
if (uwsgi_buffer_append(ub, key, keylen)) return -1;
|
||||
if (uwsgi_buffer_u32be(ub, vallen)) return -1;
|
||||
return uwsgi_buffer_append(ub, val, vallen);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append_keynum(struct uwsgi_buffer *ub, char *key, uint16_t keylen, int64_t num) {
|
||||
char buf[sizeof(UMAX64_STR)+1];
|
||||
int ret = snprintf(buf, (sizeof(UMAX64_STR)+1), "%lld", (long long) num);
|
||||
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
|
||||
return -1;
|
||||
}
|
||||
if (uwsgi_buffer_u16le(ub, keylen)) return -1;
|
||||
if (uwsgi_buffer_append(ub, key, keylen)) return -1;
|
||||
if (uwsgi_buffer_u16le(ub, ret)) return -1;
|
||||
return uwsgi_buffer_append(ub, buf, ret);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append_valnum(struct uwsgi_buffer *ub, int64_t num) {
|
||||
char buf[sizeof(UMAX64_STR)+1];
|
||||
int ret = snprintf(buf, (sizeof(UMAX64_STR)+1), "%lld", (long long) num);
|
||||
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
|
||||
return -1;
|
||||
}
|
||||
if (uwsgi_buffer_u16le(ub, ret)) return -1;
|
||||
return uwsgi_buffer_append(ub, buf, ret);
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_buffer_append_keyipv4(struct uwsgi_buffer *ub, char *key, uint16_t keylen, void *addr) {
|
||||
if (uwsgi_buffer_u16le(ub, keylen)) return -1;
|
||||
if (uwsgi_buffer_append(ub, key, keylen)) return -1;
|
||||
if (uwsgi_buffer_u16le(ub, 15)) return -1;
|
||||
char *ptr = ub->buf + (ub->pos - 2);
|
||||
if (uwsgi_buffer_append_ipv4(ub, addr)) return -1;
|
||||
// fix the size
|
||||
*ptr = ((ub->buf+ub->pos) - (ptr+2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append_base64(struct uwsgi_buffer *ub, char *s, size_t len) {
|
||||
size_t b64_len = 0;
|
||||
char *b64 = uwsgi_base64_encode(s, len, &b64_len);
|
||||
if (!b64) return -1;
|
||||
int ret = uwsgi_buffer_append(ub, b64, b64_len);
|
||||
free(b64);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_buffer_destroy(struct uwsgi_buffer *ub) {
|
||||
if (ub->buf) free(ub->buf);
|
||||
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 +319,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;
|
||||
}
|
||||
|
||||
+1670
-257
File diff suppressed because it is too large
Load Diff
+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;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
|
||||
pluggable configuration system
|
||||
|
||||
*/
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_configurator *uwsgi_register_configurator(char *name, void (*func)(char *, char **)) {
|
||||
struct uwsgi_configurator *old_uc = NULL,*uc = uwsgi.configurators;
|
||||
while(uc) {
|
||||
if (!strcmp(uc->name, name)) {
|
||||
return uc;
|
||||
}
|
||||
old_uc = uc;
|
||||
uc = uc->next;
|
||||
}
|
||||
|
||||
uc = uwsgi_calloc(sizeof(struct uwsgi_configurator));
|
||||
uc->name = name;
|
||||
uc->func = func;
|
||||
|
||||
if (old_uc) {
|
||||
old_uc->next = uc;
|
||||
}
|
||||
else {
|
||||
uwsgi.configurators = uc;
|
||||
}
|
||||
|
||||
return uc;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
|
||||
cookie management functions (mainly used by the internal routing subsystem)
|
||||
|
||||
*/
|
||||
|
||||
static char *check_cookie(char *cookie, uint16_t cookie_len, char *key, uint16_t keylen, uint16_t *vallen) {
|
||||
uint16_t orig_cookie_len = cookie_len-1;
|
||||
// first lstrip white spaces
|
||||
char *ptr = cookie;
|
||||
uint16_t i;
|
||||
for(i=0;i<cookie_len;i++) {
|
||||
if (isspace((int)ptr[i])) {
|
||||
cookie++;
|
||||
cookie_len--;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// then rstrip (skipping the first char...)
|
||||
for(i=orig_cookie_len;i>0;i--) {
|
||||
if (isspace((int)ptr[i])) {
|
||||
cookie_len--;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// now search for the first equal sign
|
||||
char *equal = memchr(cookie, '=', cookie_len);
|
||||
if (!equal) return NULL;
|
||||
|
||||
if (uwsgi_strncmp(key, keylen, cookie, equal-cookie)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cookie_len -= (equal-cookie)+1;
|
||||
if (cookie_len == 0) return NULL;
|
||||
|
||||
*vallen = cookie_len;
|
||||
return equal+1;
|
||||
}
|
||||
|
||||
char *uwsgi_get_cookie(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
|
||||
uint16_t i;
|
||||
|
||||
char *cookie = wsgi_req->cookie;
|
||||
uint16_t cookie_len = 0;
|
||||
char *ptr = wsgi_req->cookie;
|
||||
//start splitting by ;
|
||||
for(i=0;i<wsgi_req->cookie_len;i++) {
|
||||
if (!cookie) {
|
||||
cookie = ptr + i;
|
||||
}
|
||||
if (ptr[i] == ';') {
|
||||
char *value = check_cookie(cookie, cookie_len, key, keylen, vallen);
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
cookie_len = 0;
|
||||
cookie = NULL;
|
||||
}
|
||||
else {
|
||||
cookie_len++;
|
||||
}
|
||||
}
|
||||
|
||||
if (cookie_len > 0) {
|
||||
char *value = check_cookie(cookie, cookie_len, key, keylen, vallen);
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
#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;
|
||||
return uc;
|
||||
}
|
||||
|
||||
void uwsgi_opt_add_cron(char *opt, char *value, void *foobar) {
|
||||
uwsgi_cron_add(value);
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
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)) {
|
||||
current_cron = current_cron->next;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
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 {
|
||||
if (uwsgi_run_command(current_cron->command, NULL, -1) >= 0) {
|
||||
uwsgi_log_verbose("[uwsgi-cron] running %s\n", current_cron->command);
|
||||
}
|
||||
}
|
||||
}
|
||||
current_cron->last_job = now;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
current_cron = current_cron->next;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+404
@@ -0,0 +1,404 @@
|
||||
#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) {
|
||||
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 && !ud->pidfile) {
|
||||
uwsgi_log("daemon \"%s\" (pid: %d) annihilated\n", ud->command, (int) diedpid);
|
||||
ud->pid = -1;
|
||||
return -1;
|
||||
}
|
||||
ud = ud->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// this function is called when a dumb daemon dies and we want to respawn it
|
||||
int uwsgi_daemon_check_pid_reload(pid_t diedpid) {
|
||||
struct uwsgi_daemon *ud = uwsgi.daemons;
|
||||
while (ud) {
|
||||
#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) {
|
||||
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
|
||||
if (ud->pidfile) {
|
||||
int checked_pid = uwsgi_check_pidfile(ud->pidfile);
|
||||
if (checked_pid <= 0) {
|
||||
uwsgi_spawn_daemon(ud);
|
||||
}
|
||||
else {
|
||||
ud->pid = checked_pid;
|
||||
uwsgi_log("[uwsgi-daemons] found valid/active pidfile for \"%s\" (pid: %d)\n", ud->command, (int) ud->pid);
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_spawn_daemon(ud);
|
||||
}
|
||||
ud->registered = 1;
|
||||
}
|
||||
ud = ud->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_detach_daemons() {
|
||||
struct uwsgi_daemon *ud = uwsgi.daemons;
|
||||
while (ud) {
|
||||
#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 than wait up to 3 seconds
|
||||
time_t timeout = uwsgi_now() + (uwsgi.reload_mercy ? uwsgi.reload_mercy : 3);
|
||||
while (!kill(ud->pid, 0)) {
|
||||
kill(-ud->pid, SIGTERM);
|
||||
sleep(1);
|
||||
if (uwsgi_now() >= timeout) {
|
||||
uwsgi_log("[uwsgi-daemons] daemon did not died 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 devnull = -1;
|
||||
int throttle = 0;
|
||||
|
||||
if (uwsgi.current_time - ud->last_spawn <= 3) {
|
||||
throttle = ud->respawns - (uwsgi.current_time - ud->last_spawn);
|
||||
}
|
||||
|
||||
pid_t pid = uwsgi_fork("uWSGI external daemon");
|
||||
if (pid < 0) {
|
||||
uwsgi_error("fork()");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pid > 0) {
|
||||
ud->pid = pid;
|
||||
ud->status = 1;
|
||||
ud->pidfile_checks = 0;
|
||||
if (ud->respawns == 0) {
|
||||
ud->born = uwsgi_now();
|
||||
}
|
||||
|
||||
ud->respawns++;
|
||||
ud->last_spawn = uwsgi_now();
|
||||
|
||||
}
|
||||
else {
|
||||
// close uwsgi sockets
|
||||
uwsgi_close_all_sockets();
|
||||
uwsgi_close_all_fds();
|
||||
|
||||
if (ud->daemonize) {
|
||||
/* refork... */
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
uwsgi_error("fork()");
|
||||
exit(1);
|
||||
}
|
||||
if (pid != 0) {
|
||||
_exit(0);
|
||||
}
|
||||
uwsgi_write_pidfile(ud->pidfile);
|
||||
}
|
||||
|
||||
if (!uwsgi.daemons_honour_stdin) {
|
||||
// /dev/null will became stdin
|
||||
devnull = open("/dev/null", O_RDONLY);
|
||||
if (devnull < 0) {
|
||||
uwsgi_error("/dev/null open()");
|
||||
exit(1);
|
||||
}
|
||||
if (devnull != 0) {
|
||||
if (dup2(devnull, 0) < 0) {
|
||||
uwsgi_error("dup2()");
|
||||
exit(1);
|
||||
}
|
||||
close(devnull);
|
||||
}
|
||||
}
|
||||
|
||||
if (setsid() < 0) {
|
||||
uwsgi_error("setsid()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!ud->pidfile) {
|
||||
#ifdef __linux__
|
||||
if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) {
|
||||
uwsgi_error("prctl()");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
if (throttle) {
|
||||
uwsgi_log("[uwsgi-daemons] throttling \"%s\" for %d seconds\n", ud->command, throttle);
|
||||
sleep(throttle);
|
||||
}
|
||||
|
||||
uwsgi_log("[uwsgi-daemons] %sspawning \"%s\"\n", ud->respawns > 0 ? "re" : "", ud->command);
|
||||
uwsgi_exec_command_with_args(ud->command);
|
||||
uwsgi_log("[uwsgi-daemons] unable to spawn \"%s\"\n", ud->command);
|
||||
|
||||
// never here;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_opt_add_daemon(char *opt, char *value, void *none) {
|
||||
|
||||
struct uwsgi_daemon *uwsgi_ud = uwsgi.daemons, *old_ud;
|
||||
char *pidfile = NULL;
|
||||
int daemonize = 0;
|
||||
int freq = 10;
|
||||
char *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")) {
|
||||
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;
|
||||
#ifdef UWSGI_SSL
|
||||
uwsgi_ud->legion = legion;
|
||||
#endif
|
||||
|
||||
uwsgi.daemons_cnt++;
|
||||
|
||||
}
|
||||
+554
-194
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;
|
||||
}
|
||||
|
||||
+775
-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);
|
||||
}
|
||||
|
||||
}
|
||||
+95
-81
@@ -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()");
|
||||
}
|
||||
|
||||
uwsgi_socket_nb(ug->internal_subscription_pipe[0]);
|
||||
uwsgi_socket_nb(ug->internal_subscription_pipe[1]);
|
||||
|
||||
if (!uwsgi.master_process)
|
||||
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,115 @@ 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();
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
// Bernstein classic hash (this is not static as it is used by other areas)
|
||||
uint32_t djb33x_hash(char *key, uint64_t keylen) {
|
||||
|
||||
register uint32_t hash = 5381;
|
||||
uint64_t i;
|
||||
|
||||
for (i = 0; i < keylen; i++) {
|
||||
hash = ((hash << 5) + hash) ^ key[i];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
// Murmur2 hash Copyright (C) Austin Appleby
|
||||
// adapted from nginx
|
||||
uint32_t murmur2_hash(char *key, uint64_t keylen) {
|
||||
|
||||
uint32_t h, k;
|
||||
uint8_t *ukey = (uint8_t *) key;
|
||||
h = 0 ^ keylen;
|
||||
while (keylen >= 4) {
|
||||
k = ukey[0];
|
||||
k |= ukey[1] << 8;
|
||||
k |= ukey[2] << 16;
|
||||
k |= ukey[3] << 24;
|
||||
|
||||
k *= 0x5bd1e995;
|
||||
k ^= k >> 24;
|
||||
k *= 0x5bd1e995;
|
||||
|
||||
h *= 0x5bd1e995;
|
||||
h ^= k;
|
||||
|
||||
ukey += 4;
|
||||
keylen -= 4;
|
||||
}
|
||||
|
||||
switch (keylen) {
|
||||
case 3:
|
||||
h ^= key[2] << 16;
|
||||
case 2:
|
||||
h ^= key[1] << 8;
|
||||
case 1:
|
||||
h ^= key[0];
|
||||
h *= 0x5bd1e995;
|
||||
}
|
||||
|
||||
h ^= h >> 13;
|
||||
h *= 0x5bd1e995;
|
||||
h ^= h >> 15;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_hash_algo *uwsgi_hash_algo_get(char *name) {
|
||||
struct uwsgi_hash_algo *uha = uwsgi.hash_algos;
|
||||
while(uha) {
|
||||
if (!strcmp(name, uha->name)) {
|
||||
return uha;
|
||||
}
|
||||
uha = uha->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
void uwsgi_hash_algo_register(char *name, uint32_t (*func)(char *, uint64_t)) {
|
||||
|
||||
struct uwsgi_hash_algo *old_uha = NULL, *uha = uwsgi.hash_algos;
|
||||
while(uha) {
|
||||
if (!strcmp(uha->name, name)) return;
|
||||
old_uha = uha;
|
||||
uha = uha->next;
|
||||
}
|
||||
|
||||
uha = uwsgi_calloc(sizeof(struct uwsgi_hash_algo));
|
||||
uha->name = name;
|
||||
uha->func = func;
|
||||
if (old_uha) {
|
||||
old_uha->next = uha;
|
||||
}
|
||||
else {
|
||||
uwsgi.hash_algos = uha;
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_hash_algo_register_all() {
|
||||
uwsgi_hash_algo_register("djb33x", djb33x_hash);
|
||||
uwsgi_hash_algo_register("murmur2", murmur2_hash);
|
||||
}
|
||||
+34
-25
@@ -1,6 +1,4 @@
|
||||
#ifdef UWSGI_INI
|
||||
|
||||
#include "uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
@@ -9,11 +7,13 @@ extern struct uwsgi_server uwsgi;
|
||||
This memory must not be freed for all the server lifecycle
|
||||
*/
|
||||
|
||||
static char *last_file = NULL;
|
||||
|
||||
void ini_rstrip(char *line) {
|
||||
|
||||
off_t i;
|
||||
|
||||
for(i = strlen(line)-1;i>=0; i--) {
|
||||
for (i = strlen(line) - 1; i >= 0; i--) {
|
||||
if (line[i] == ' ' || line[i] == '\t' || line[i] == '\r') {
|
||||
line[i] = 0;
|
||||
continue;
|
||||
@@ -27,7 +27,7 @@ char *ini_lstrip(char *line) {
|
||||
off_t i;
|
||||
char *ptr = line;
|
||||
|
||||
for(i=0;i< (int) strlen(line);i++) {
|
||||
for (i = 0; i < (int) strlen(line); i++) {
|
||||
if (line[i] == ' ' || line[i] == '\t' || line[i] == '\r') {
|
||||
ptr++;
|
||||
continue;
|
||||
@@ -43,7 +43,7 @@ char *ini_get_key(char *key) {
|
||||
off_t i;
|
||||
char *ptr = key;
|
||||
|
||||
for(i=0;i< (int) strlen(key);i++) {
|
||||
for (i = 0; i < (int) strlen(key); i++) {
|
||||
ptr++;
|
||||
if (key[i] == '=') {
|
||||
key[i] = 0;
|
||||
@@ -54,12 +54,12 @@ char *ini_get_key(char *key) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
char *ini_get_line(char *ini, off_t size) {
|
||||
char *ini_get_line(char *ini, size_t size) {
|
||||
|
||||
off_t i;
|
||||
size_t i;
|
||||
char *ptr = ini;
|
||||
|
||||
for(i=0;i<size;i++) {
|
||||
for (i = 0; i < size; i++) {
|
||||
ptr++;
|
||||
if (ini[i] == '\n') {
|
||||
ini[i] = 0;
|
||||
@@ -78,7 +78,7 @@ char *ini_get_line(char *ini, off_t size) {
|
||||
|
||||
void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
|
||||
int len = 0;
|
||||
size_t len = 0;
|
||||
char *ini;
|
||||
|
||||
char *ini_line;
|
||||
@@ -92,28 +92,39 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
char *section_asked = "uwsgi";
|
||||
char *colon;
|
||||
|
||||
|
||||
if (uwsgi_check_scheme(file)) {
|
||||
colon = uwsgi_get_last_char(file, '/');
|
||||
colon = uwsgi_get_last_char(colon, ':');
|
||||
}
|
||||
else {
|
||||
colon = uwsgi_get_last_char(file, ':');
|
||||
}
|
||||
colon = uwsgi_get_last_char(file, '/');
|
||||
colon = uwsgi_get_last_char(colon, ':');
|
||||
}
|
||||
else {
|
||||
colon = uwsgi_get_last_char(file, ':');
|
||||
}
|
||||
|
||||
if (colon) {
|
||||
colon[0] = 0;
|
||||
if (colon[1] != 0) {
|
||||
section_asked = colon+1;
|
||||
section_asked = colon + 1;
|
||||
}
|
||||
|
||||
if (colon == file) {
|
||||
file = last_file;
|
||||
}
|
||||
}
|
||||
|
||||
if (file[0] != 0) {
|
||||
uwsgi_log("[uWSGI] getting INI configuration from %s\n", file);
|
||||
if (file[0] != 0 && file != last_file) {
|
||||
uwsgi_log_initial("[uWSGI] getting INI configuration from %s\n", file);
|
||||
}
|
||||
|
||||
ini = uwsgi_open_and_read(file, &len, 1, magic_table);
|
||||
if (file != last_file) {
|
||||
if (last_file) {
|
||||
free(last_file);
|
||||
}
|
||||
last_file = uwsgi_str(file);
|
||||
}
|
||||
|
||||
while(len) {
|
||||
while (len) {
|
||||
ini_line = ini_get_line(ini, len);
|
||||
if (ini_line == NULL) {
|
||||
break;
|
||||
@@ -125,8 +136,8 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
ini_rstrip(key);
|
||||
if (key[0] != 0) {
|
||||
if (key[0] == '[') {
|
||||
section = key+1;
|
||||
section[strlen(section)-1] = 0;
|
||||
section = key + 1;
|
||||
section[strlen(section) - 1] = 0;
|
||||
}
|
||||
else if (key[0] == ';' || key[0] == '#') {
|
||||
// this is a comment
|
||||
@@ -139,7 +150,7 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
ini_rstrip(key);
|
||||
val = ini_lstrip(val);
|
||||
ini_rstrip(val);
|
||||
add_exported_option((char *)key, val, 0);
|
||||
add_exported_option((char *) key, val, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -156,5 +167,3 @@ void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+371
-171
@@ -2,104 +2,195 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct http_status_codes {
|
||||
const char key[3];
|
||||
const char *message;
|
||||
int message_size;
|
||||
};
|
||||
|
||||
/* statistically ordered */
|
||||
struct http_status_codes hsc[] = {
|
||||
{"200", "OK"},
|
||||
{"302", "Found"},
|
||||
{"404", "Not Found"},
|
||||
{"500", "Internal Server Error"},
|
||||
{"301", "Moved Permanently"},
|
||||
{"304", "Not Modified"},
|
||||
{"303", "See Other"},
|
||||
{"403", "Forbidden"},
|
||||
{"307", "Temporary Redirect"},
|
||||
{"401", "Unauthorized"},
|
||||
{"400", "Bad Request"},
|
||||
{"405", "Method Not Allowed"},
|
||||
{"408", "Request Timeout"},
|
||||
|
||||
{"100", "Continue"},
|
||||
{"101", "Switching Protocols"},
|
||||
{"201", "Created"},
|
||||
{"202", "Accepted"},
|
||||
{"203", "Non-Authoritative Information"},
|
||||
{"204", "No Content"},
|
||||
{"205", "Reset Content"},
|
||||
{"206", "Partial Content"},
|
||||
{"300", "Multiple Choices"},
|
||||
{"305", "Use Proxy"},
|
||||
{"402", "Payment Required"},
|
||||
{"406", "Not Acceptable"},
|
||||
{"407", "Proxy Authentication Required"},
|
||||
{"409", "Conflict"},
|
||||
{"410", "Gone"},
|
||||
{"411", "Length Required"},
|
||||
{"412", "Precondition Failed"},
|
||||
{"413", "Request Entity Too Large"},
|
||||
{"414", "Request-URI Too Long"},
|
||||
{"415", "Unsupported Media Type"},
|
||||
{"416", "Requested Range Not Satisfiable"},
|
||||
{"417", "Expectation Failed"},
|
||||
{"501", "Not Implemented"},
|
||||
{"502", "Bad Gateway"},
|
||||
{"503", "Service Unavailable"},
|
||||
{"504", "Gateway Timeout"},
|
||||
{"505", "HTTP Version Not Supported"},
|
||||
{"", NULL},
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
void uwsgi_init_default() {
|
||||
|
||||
uwsgi.cpus = 1;
|
||||
|
||||
uwsgi.backtrace_depth = 64;
|
||||
uwsgi.max_apps = 64;
|
||||
uwsgi.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;
|
||||
// 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.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 = "";
|
||||
|
||||
uwsgi.wait_read_hook = uwsgi_simple_wait_read_hook;
|
||||
uwsgi.wait_write_hook = uwsgi_simple_wait_write_hook;
|
||||
|
||||
uwsgi_websockets_init();
|
||||
}
|
||||
|
||||
void uwsgi_setup_reload() {
|
||||
|
||||
char env_reload_buf[11];
|
||||
char env_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 +199,33 @@ 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) {
|
||||
plugins_requested = strtok(uwsgi_str(p + 6), "_");
|
||||
while (plugins_requested) {
|
||||
uwsgi_log("[uwsgi] implicit plugin requested %s\n", plugins_requested);
|
||||
uwsgi_load_plugin(-1, plugins_requested, NULL);
|
||||
plugins_requested = strtok(NULL, "_");
|
||||
}
|
||||
}
|
||||
|
||||
plugins_requested = getenv("UWSGI_PLUGINS");
|
||||
if (plugins_requested) {
|
||||
plugins_requested = uwsgi_concat2(plugins_requested, "");
|
||||
char *p = strtok(plugins_requested, ",");
|
||||
while (p != NULL) {
|
||||
uwsgi_load_plugin(-1, p, NULL);
|
||||
p = strtok(NULL, ",");
|
||||
}
|
||||
}
|
||||
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, ",");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -143,112 +234,221 @@ 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();
|
||||
#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);
|
||||
}
|
||||
|
||||
return uwsgi.mypid;
|
||||
}
|
||||
|
||||
// fix/check related options
|
||||
void sanitize_args() {
|
||||
|
||||
if (uwsgi.async > 1) {
|
||||
uwsgi.cores = uwsgi.async;
|
||||
}
|
||||
|
||||
if (uwsgi.threads > 1) {
|
||||
uwsgi.has_threads = 1;
|
||||
uwsgi.cores = uwsgi.threads;
|
||||
}
|
||||
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
|
||||
if (!uwsgi.post_buffering) {
|
||||
uwsgi_log(" *** WARNING: you have enabled harakiri without post buffering. Slow upload could be rejected on post-unbuffered webservers *** \n");
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.write_errors_exception_only) {
|
||||
uwsgi.ignore_sigpipe = 1;
|
||||
uwsgi.ignore_write_errors = 1;
|
||||
}
|
||||
|
||||
if (uwsgi.cheaper_count == 0) uwsgi.cheaper = 0;
|
||||
|
||||
if (uwsgi.cheaper_count > 0 && uwsgi.cheaper_count >= uwsgi.numproc) {
|
||||
uwsgi_log("invalid cheaper value: must be lower than processes\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (uwsgi.cheaper && uwsgi.cheaper_count) {
|
||||
if (uwsgi.cheaper_initial) {
|
||||
if (uwsgi.cheaper_initial < uwsgi.cheaper_count) {
|
||||
uwsgi_log("warning: invalid cheaper-initial value (%d), must be equal or higher than cheaper (%d), using %d as initial number of workers\n",
|
||||
uwsgi.cheaper_initial, uwsgi.cheaper_count, uwsgi.cheaper_count);
|
||||
uwsgi.cheaper_initial = uwsgi.cheaper_count;
|
||||
}
|
||||
else if (uwsgi.cheaper_initial > uwsgi.numproc) {
|
||||
uwsgi_log("warning: invalid cheaper-initial value (%d), must be lower or equal than worker count (%d), using %d as initial number of workers\n",
|
||||
uwsgi.cheaper_initial, uwsgi.numproc, uwsgi.numproc);
|
||||
uwsgi.cheaper_initial = uwsgi.numproc;
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi.cheaper_initial = uwsgi.cheaper_count;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.auto_snapshot > 0 && uwsgi.auto_snapshot > uwsgi.numproc) {
|
||||
uwsgi_log("invalid auto-snapshot value: must be <= than processes\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME] > 0 && uwsgi.shared->options[UWSGI_OPTION_MIN_WORKER_LIFETIME] >= uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME]) {
|
||||
uwsgi_log("invalid min-worker-lifetime value (%d), must be lower than max-worker-lifetime (%d)\n",
|
||||
uwsgi.shared->options[UWSGI_OPTION_MIN_WORKER_LIFETIME], uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const char *uwsgi_http_status_msg(char *status, uint16_t *len) {
|
||||
struct http_status_codes *http_sc;
|
||||
for (http_sc = hsc; http_sc->message != NULL; http_sc++) {
|
||||
if (!strncmp(http_sc->key, status, 3)) {
|
||||
*len = http_sc->message_size;
|
||||
return http_sc->message;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+31
-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,46 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#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
|
||||
+1178
File diff suppressed because it is too large
Load Diff
+284
-142
@@ -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;
|
||||
|
||||
@@ -400,10 +497,10 @@ struct uwsgi_lock_item *uwsgi_lock_ipcsem_init(char *id) {
|
||||
exit(1);
|
||||
}
|
||||
counter++;
|
||||
semid = semget(myKey, 1, IPC_CREAT|0666);
|
||||
semid = semget(myKey, 1, IPC_CREAT | 0666);
|
||||
}
|
||||
else {
|
||||
semid = semget(IPC_PRIVATE, 1, IPC_CREAT|IPC_EXCL| 0666);
|
||||
semid = semget(IPC_PRIVATE, 1, IPC_CREAT | IPC_EXCL | 0666);
|
||||
}
|
||||
|
||||
if (semid < 0) {
|
||||
@@ -418,7 +515,7 @@ struct uwsgi_lock_item *uwsgi_lock_ipcsem_init(char *id) {
|
||||
uwsgi_error("semctl()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
return uli;
|
||||
}
|
||||
|
||||
@@ -432,9 +529,11 @@ void uwsgi_lock_ipcsem(struct uwsgi_lock_item *uli) {
|
||||
|
||||
memcpy(&semid, uli->lock_ptr, sizeof(int));
|
||||
|
||||
retry:
|
||||
if (semop(semid, &sb, 1)) {
|
||||
if (errno == EINTR) goto retry;
|
||||
uwsgi_error("semop()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_unlock_ipcsem(struct uwsgi_lock_item *uli) {
|
||||
@@ -447,16 +546,26 @@ void uwsgi_unlock_ipcsem(struct uwsgi_lock_item *uli) {
|
||||
|
||||
memcpy(&semid, uli->lock_ptr, sizeof(int));
|
||||
|
||||
retry:
|
||||
if (semop(semid, &sb, 1)) {
|
||||
if (errno == EINTR) goto retry;
|
||||
uwsgi_error("semop()");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_lock_item *uwsgi_rwlock_ipcsem_init(char *id) { return uwsgi_lock_ipcsem_init(id);}
|
||||
void uwsgi_rlock_ipcsem(struct uwsgi_lock_item *uli) { uwsgi_lock_ipcsem(uli);}
|
||||
void uwsgi_wlock_ipcsem(struct uwsgi_lock_item *uli) { uwsgi_lock_ipcsem(uli);}
|
||||
void uwsgi_rwunlock_ipcsem(struct uwsgi_lock_item *uli) { uwsgi_unlock_ipcsem(uli); }
|
||||
struct uwsgi_lock_item *uwsgi_rwlock_ipcsem_init(char *id) {
|
||||
return uwsgi_lock_ipcsem_init(id);
|
||||
}
|
||||
void uwsgi_rlock_ipcsem(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_lock_ipcsem(uli);
|
||||
}
|
||||
void uwsgi_wlock_ipcsem(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_lock_ipcsem(uli);
|
||||
}
|
||||
void uwsgi_rwunlock_ipcsem(struct uwsgi_lock_item *uli) {
|
||||
uwsgi_unlock_ipcsem(uli);
|
||||
}
|
||||
|
||||
// ipc cannot deadlock
|
||||
pid_t uwsgi_lock_ipcsem_check(struct uwsgi_lock_item *uli) {
|
||||
@@ -467,13 +576,17 @@ void uwsgi_ipcsem_clear(void) {
|
||||
|
||||
struct uwsgi_lock_item *uli = uwsgi.registered_locks;
|
||||
|
||||
if (!uwsgi.workers) goto clear;
|
||||
if (!uwsgi.workers)
|
||||
goto clear;
|
||||
|
||||
if (uwsgi.mywid == 0) goto clear;
|
||||
if (uwsgi.mywid == 0)
|
||||
goto clear;
|
||||
|
||||
if (uwsgi.master_process && getpid() == uwsgi.workers[0].pid) goto clear;
|
||||
if (uwsgi.master_process && getpid() == uwsgi.workers[0].pid)
|
||||
goto clear;
|
||||
|
||||
if (!uwsgi.master_process && uwsgi.mywid == 1) goto clear;
|
||||
if (!uwsgi.master_process && uwsgi.mywid == 1)
|
||||
goto clear;
|
||||
|
||||
return;
|
||||
|
||||
@@ -482,7 +595,7 @@ clear:
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("removing sysvipc semaphores...\n");
|
||||
#endif
|
||||
while(uli) {
|
||||
while (uli) {
|
||||
int semid = 0;
|
||||
memcpy(&semid, uli->lock_ptr, sizeof(int));
|
||||
if (semctl(semid, 0, IPC_RMID)) {
|
||||
@@ -493,11 +606,17 @@ clear:
|
||||
}
|
||||
|
||||
|
||||
pid_t uwsgi_rwlock_ipcsem_check(struct uwsgi_lock_item *uli) { return uwsgi_lock_ipcsem_check(uli); }
|
||||
pid_t uwsgi_rwlock_ipcsem_check(struct uwsgi_lock_item *uli) {
|
||||
return uwsgi_lock_ipcsem_check(uli);
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_setup_locking() {
|
||||
|
||||
int i;
|
||||
|
||||
if (uwsgi.locking_setup) return;
|
||||
|
||||
// use the fastest available locking
|
||||
if (uwsgi.lock_engine) {
|
||||
if (!strcmp(uwsgi.lock_engine, "ipcsem")) {
|
||||
@@ -514,8 +633,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 +655,53 @@ 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");
|
||||
}
|
||||
|
||||
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 +723,51 @@ int uwsgi_fcntl_lock(int fd) {
|
||||
int uwsgi_fcntl_is_locked(int fd) {
|
||||
|
||||
struct flock fl;
|
||||
fl.l_type = F_WRLCK;
|
||||
fl.l_whence = SEEK_SET;
|
||||
fl.l_start = 0;
|
||||
fl.l_len = 0;
|
||||
fl.l_pid = 0;
|
||||
fl.l_type = F_WRLCK;
|
||||
fl.l_whence = SEEK_SET;
|
||||
fl.l_start = 0;
|
||||
fl.l_len = 0;
|
||||
fl.l_pid = 0;
|
||||
|
||||
if (fcntl(fd, F_SETLK, &fl)) {
|
||||
if (fcntl(fd, F_SETLK, &fl)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_deadlock_check(pid_t diedpid) {
|
||||
struct uwsgi_lock_item *uli = uwsgi.registered_locks;
|
||||
while (uli) {
|
||||
if (!uli->can_deadlock)
|
||||
goto nextlock;
|
||||
pid_t locked_pid = 0;
|
||||
if (uli->rw) {
|
||||
locked_pid = uwsgi_rwlock_check(uli);
|
||||
}
|
||||
else {
|
||||
locked_pid = uwsgi_lock_check(uli);
|
||||
}
|
||||
if (locked_pid == diedpid) {
|
||||
uwsgi_log("[deadlock-detector] pid %d was holding lock %s (%p)\n", (int) diedpid, uli->id, uli->lock_ptr);
|
||||
if (uli->rw) {
|
||||
uwsgi_rwunlock(uli);
|
||||
}
|
||||
else {
|
||||
uwsgi_unlock(uli);
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_user_lock(int lock_num) {
|
||||
uwsgi_lock(uwsgi.user_lock[lock_num]);
|
||||
}
|
||||
|
||||
void uwsgi_user_unlock(int lock_num) {
|
||||
uwsgi_unlock(uwsgi.user_lock[lock_num]);
|
||||
}
|
||||
|
||||
+900
-414
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;
|
||||
}
|
||||
|
||||
+221
-886
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,279 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
// check if all of the workers are dead and exit uWSGI
|
||||
void uwsgi_master_check_death() {
|
||||
if (uwsgi_instance_is_dying) {
|
||||
int i;
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
if (uwsgi.workers[i].pid > 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
uwsgi_log("goodbye to uWSGI.\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
// check if all of the workers are dead, and trigger a reload
|
||||
int uwsgi_master_check_reload(char **argv) {
|
||||
if (uwsgi_instance_is_reloading) {
|
||||
int i;
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
if (uwsgi.workers[i].pid > 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
uwsgi_reload(argv);
|
||||
// never here (unless in shared library mode)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check for chain reload
|
||||
void uwsgi_master_check_chain() {
|
||||
if (!uwsgi.status.chain_reloading) return;
|
||||
if (uwsgi.status.chain_reloading > uwsgi.numproc) {
|
||||
uwsgi.status.chain_reloading = 0;
|
||||
uwsgi_log_verbose("chain reloading complete\n");
|
||||
}
|
||||
int i;
|
||||
uwsgi_block_signal(SIGHUP);
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].cursed_at == 0 && i == uwsgi.status.chain_reloading) {
|
||||
uwsgi_curse(i, SIGHUP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
uwsgi_unblock_signal(SIGHUP);
|
||||
}
|
||||
|
||||
|
||||
// special function for assuming all of the workers are dead
|
||||
void uwsgi_master_commit_status() {
|
||||
int i;
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
uwsgi.workers[i].pid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_master_check_idle() {
|
||||
|
||||
static time_t last_request_timecheck = 0;
|
||||
static uint64_t last_request_count = 0;
|
||||
int i;
|
||||
int waitpid_status;
|
||||
|
||||
if (!uwsgi.idle || uwsgi.status.is_cheap)
|
||||
return;
|
||||
|
||||
uwsgi.current_time = uwsgi_now();
|
||||
if (!last_request_timecheck)
|
||||
last_request_timecheck = uwsgi.current_time;
|
||||
|
||||
// security check, stop the check if there are busy workers
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
|
||||
if (uwsgi_worker_is_busy(i)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (last_request_count != uwsgi.workers[0].requests) {
|
||||
last_request_timecheck = uwsgi.current_time;
|
||||
last_request_count = uwsgi.workers[0].requests;
|
||||
}
|
||||
// a bit of over-engeneering to avoid clock skews
|
||||
else if (last_request_timecheck < uwsgi.current_time && (uwsgi.current_time - last_request_timecheck > uwsgi.idle)) {
|
||||
uwsgi_log("workers have been inactive for more than %d seconds (%llu-%llu)\n", uwsgi.idle, (unsigned long long) uwsgi.current_time, (unsigned long long) last_request_timecheck);
|
||||
uwsgi.status.is_cheap = 1;
|
||||
if (uwsgi.die_on_idle) {
|
||||
if (uwsgi.has_emperor) {
|
||||
char byte = 22;
|
||||
if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
|
||||
uwsgi_error("write()");
|
||||
kill_them_all(0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
kill_them_all(0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
uwsgi.workers[i].cheaped = 1;
|
||||
if (uwsgi.workers[i].pid == 0)
|
||||
continue;
|
||||
kill(uwsgi.workers[i].pid, SIGKILL);
|
||||
if (waitpid(uwsgi.workers[i].pid, &waitpid_status, 0) < 0) {
|
||||
if (errno != ECHILD)
|
||||
uwsgi_error("uwsgi_master_check_idle()/waitpid()");
|
||||
}
|
||||
}
|
||||
uwsgi_add_sockets_to_queue(uwsgi.master_queue, -1);
|
||||
uwsgi_log("cheap mode enabled: waiting for socket connection...\n");
|
||||
last_request_timecheck = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_master_check_workers_deadline() {
|
||||
int i;
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
/* first check for harakiri */
|
||||
if (uwsgi.workers[i].harakiri > 0) {
|
||||
if (uwsgi.workers[i].harakiri < (time_t) uwsgi.current_time) {
|
||||
trigger_harakiri(i);
|
||||
}
|
||||
}
|
||||
/* then user-defined harakiri */
|
||||
if (uwsgi.workers[i].user_harakiri > 0) {
|
||||
if (uwsgi.workers[i].user_harakiri < (time_t) uwsgi.current_time) {
|
||||
trigger_harakiri(i);
|
||||
}
|
||||
}
|
||||
// then for evil memory checkers
|
||||
if (uwsgi.evil_reload_on_as) {
|
||||
if ((rlim_t) uwsgi.workers[i].vsz_size >= uwsgi.evil_reload_on_as) {
|
||||
uwsgi_log("*** EVIL RELOAD ON WORKER %d ADDRESS SPACE: %lld (pid: %d) ***\n", i, (long long) uwsgi.workers[i].vsz_size, uwsgi.workers[i].pid);
|
||||
kill(uwsgi.workers[i].pid, SIGKILL);
|
||||
uwsgi.workers[i].vsz_size = 0;
|
||||
}
|
||||
}
|
||||
if (uwsgi.evil_reload_on_rss) {
|
||||
if ((rlim_t) uwsgi.workers[i].rss_size >= uwsgi.evil_reload_on_rss) {
|
||||
uwsgi_log("*** EVIL RELOAD ON WORKER %d RSS: %lld (pid: %d) ***\n", i, (long long) uwsgi.workers[i].rss_size, uwsgi.workers[i].pid);
|
||||
kill(uwsgi.workers[i].pid, SIGKILL);
|
||||
uwsgi.workers[i].rss_size = 0;
|
||||
}
|
||||
}
|
||||
// check if worker was running longer than allowed lifetime
|
||||
if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cheaped == 0 && uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME] > 0) {
|
||||
uint64_t lifetime = uwsgi_now() - uwsgi.workers[i].last_spawn;
|
||||
if (lifetime > uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME] && uwsgi.workers[i].manage_next_request == 1) {
|
||||
uwsgi_log("worker %d lifetime reached, it was running for %llu second(s)\n", i, (unsigned long long) lifetime);
|
||||
uwsgi.workers[i].manage_next_request = 0;
|
||||
kill(uwsgi.workers[i].pid, SIGWINCH);
|
||||
}
|
||||
}
|
||||
|
||||
// need to find a better way
|
||||
//uwsgi.workers[i].last_running_time = uwsgi.workers[i].running_time;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_master_check_gateways_deadline() {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ushared->gateways_cnt; i++) {
|
||||
if (ushared->gateways_harakiri[i] > 0) {
|
||||
if (ushared->gateways_harakiri[i] < (time_t) uwsgi.current_time) {
|
||||
if (ushared->gateways[i].pid > 0) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_master_check_spoolers_deadline() {
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
while (uspool) {
|
||||
if (uspool->harakiri > 0 && uspool->harakiri < (time_t) uwsgi.current_time) {
|
||||
uwsgi_log("*** HARAKIRI ON THE SPOOLER (pid: %d) ***\n", uspool->pid);
|
||||
kill(uspool->pid, SIGKILL);
|
||||
uspool->harakiri = 0;
|
||||
}
|
||||
uspool = uspool->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_master_check_spoolers_death(int diedpid) {
|
||||
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
while (uspool) {
|
||||
if (uspool->pid > 0 && diedpid == uspool->pid) {
|
||||
uwsgi_log("OOOPS the spooler is no more...trying respawn...\n");
|
||||
uspool->respawned++;
|
||||
uspool->pid = spooler_start(uspool);
|
||||
return -1;
|
||||
}
|
||||
uspool = uspool->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_master_check_emperor_death(int diedpid) {
|
||||
if (uwsgi.emperor_pid >= 0 && diedpid == uwsgi.emperor_pid) {
|
||||
uwsgi_log_verbose("!!! Emperor died !!!\n");
|
||||
uwsgi_emperor_start();
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_master_check_mules_death(int diedpid) {
|
||||
int i;
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
if (uwsgi.mules[i].pid == diedpid) {
|
||||
uwsgi_log("OOOPS mule %d (pid: %d) crippled...trying respawn...\n", i + 1, uwsgi.mules[i].pid);
|
||||
uwsgi_mule(i + 1);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_master_check_gateways_death(int diedpid) {
|
||||
int i;
|
||||
for (i = 0; i < ushared->gateways_cnt; i++) {
|
||||
if (ushared->gateways[i].pid == diedpid) {
|
||||
gateway_respawn(i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_master_check_daemons_death(int diedpid) {
|
||||
/* reload the daemons */
|
||||
if (uwsgi_daemon_check_pid_reload(diedpid)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_worker_is_busy(int wid) {
|
||||
int i;
|
||||
for(i=0;i<uwsgi.cores;i++) {
|
||||
if (uwsgi.workers[wid].cores[i].in_request) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_master_manage_events(int interesting_fd) {
|
||||
|
||||
// is a logline ?
|
||||
if (uwsgi.log_master && !uwsgi.threaded_logger) {
|
||||
// stderr log ?
|
||||
if (interesting_fd == uwsgi.shared->worker_log_pipe[0]) {
|
||||
uwsgi_master_log();
|
||||
return 0;
|
||||
}
|
||||
// req log ?
|
||||
if (uwsgi.req_log_master && interesting_fd == uwsgi.shared->worker_req_log_pipe[0]) {
|
||||
uwsgi_master_req_log();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// stats server ?
|
||||
if (uwsgi.stats && uwsgi.stats_fd > -1) {
|
||||
if (interesting_fd == uwsgi.stats_fd) {
|
||||
uwsgi_send_stats(uwsgi.stats_fd, uwsgi_master_generate_stats);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// a zerg connection ?
|
||||
if (uwsgi.zerg_server) {
|
||||
if (interesting_fd == uwsgi.zerg_server_fd) {
|
||||
uwsgi_manage_zerg(uwsgi.zerg_server_fd, 0, NULL);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// emperor event ?
|
||||
if (uwsgi.has_emperor) {
|
||||
if (interesting_fd == uwsgi.emperor_fd) {
|
||||
uwsgi_master_manage_emperor();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// wakeup from cheap mode ?
|
||||
if (uwsgi.status.is_cheap) {
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
while (uwsgi_sock) {
|
||||
if (interesting_fd == uwsgi_sock->fd) {
|
||||
uwsgi.status.is_cheap = 0;
|
||||
uwsgi_del_sockets_from_queue(uwsgi.master_queue);
|
||||
// how many worker we need to respawn ?
|
||||
int needed = uwsgi.numproc;
|
||||
// if in cheaper mode, just respawn the minimal amount
|
||||
if (uwsgi.cheaper) {
|
||||
needed = uwsgi.cheaper_count;
|
||||
}
|
||||
int i;
|
||||
for (i = 1; i <= needed; i++) {
|
||||
if (uwsgi_respawn_worker(i))
|
||||
return -1;
|
||||
}
|
||||
// here we continue instead of returning
|
||||
break;
|
||||
}
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// an SNMP request ?
|
||||
if (uwsgi.snmp_addr && interesting_fd == uwsgi.snmp_fd) {
|
||||
uwsgi_master_manage_snmp(uwsgi.snmp_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// a UDP request ?
|
||||
if (uwsgi.udp_socket && interesting_fd == uwsgi.udp_fd) {
|
||||
uwsgi_master_manage_udp(uwsgi.udp_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// check if some file monitor is ready
|
||||
// no need to lock as we are only getting registered items (and only the master can register them)
|
||||
int i;
|
||||
for (i = 0; i < ushared->files_monitored_cnt; i++) {
|
||||
if (ushared->files_monitored[i].registered) {
|
||||
if (interesting_fd == ushared->files_monitored[i].fd) {
|
||||
struct uwsgi_fmon *uf = event_queue_ack_file_monitor(uwsgi.master_queue, interesting_fd);
|
||||
// now call the file_monitor handler
|
||||
if (uf)
|
||||
uwsgi_route_signal(uf->sig);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if some timer elapsed
|
||||
// no need to lock again
|
||||
for (i = 0; i < ushared->timers_cnt; i++) {
|
||||
if (ushared->timers[i].registered) {
|
||||
if (interesting_fd == ushared->timers[i].fd) {
|
||||
struct uwsgi_timer *ut = event_queue_ack_timer(interesting_fd);
|
||||
// now call the timer handler
|
||||
if (ut)
|
||||
uwsgi_route_signal(ut->sig);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t uwsgi_signal;
|
||||
// check for worker signal
|
||||
if (interesting_fd == uwsgi.shared->worker_signal_pipe[0]) {
|
||||
ssize_t rlen = read(interesting_fd, &uwsgi_signal, 1);
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("uwsgi_master_manage_events()/read()");
|
||||
}
|
||||
else if (rlen > 0) {
|
||||
uwsgi_route_signal(uwsgi_signal);
|
||||
}
|
||||
else {
|
||||
// TODO restart workers here
|
||||
uwsgi_log_verbose("lost connection with workers !!!\n");
|
||||
close(interesting_fd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check for spooler signal
|
||||
if (uwsgi.spoolers) {
|
||||
if (interesting_fd == uwsgi.shared->spooler_signal_pipe[0]) {
|
||||
ssize_t rlen = read(interesting_fd, &uwsgi_signal, 1);
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("uwsgi_master_manage_events()/read()");
|
||||
}
|
||||
else if (rlen > 0) {
|
||||
uwsgi_route_signal(uwsgi_signal);
|
||||
}
|
||||
else {
|
||||
// TODO restart spoolers here
|
||||
uwsgi_log_verbose("lost connection with spoolers\n");
|
||||
close(interesting_fd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// check for mules signal
|
||||
if (uwsgi.mules_cnt > 0) {
|
||||
if (interesting_fd == uwsgi.shared->mule_signal_pipe[0]) {
|
||||
ssize_t rlen = read(interesting_fd, &uwsgi_signal, 1);
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("uwsgi_master_manage_events()/read()");
|
||||
}
|
||||
else if (rlen > 0) {
|
||||
uwsgi_route_signal(uwsgi_signal);
|
||||
}
|
||||
else {
|
||||
// TODO respawn mules here
|
||||
uwsgi_log_verbose("lost connection with mules\n");
|
||||
close(interesting_fd);
|
||||
}
|
||||
// return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
+723
-445
File diff suppressed because it is too large
Load Diff
+138
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
|
||||
uWSGI metrics subsystem
|
||||
|
||||
a metric is a node in a tree 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
|
||||
1.3.6.1.4.1.35156.17.4.1 = iso.org.dod.internet.private.enterprise.unbit.uwsgi.system.load_avg
|
||||
...
|
||||
|
||||
each metric is a collected value with a specific frequency (a frequency of zero means the value is re-computed every time)
|
||||
metrics are meant for numeric values signed 64 bit, but they can be exposed as:
|
||||
|
||||
gauge
|
||||
counter
|
||||
absolute
|
||||
|
||||
both 32 and 64bit, both signed and unsigned
|
||||
|
||||
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.
|
||||
|
||||
struct uwsgi_metric *um = uwsgi_register_metric("worker.1.requests", "3.1.1", UWSGI_METRIC_COUNTER, UWSGI_METRIC_PTR, &uwsgi.workers[1].requests, 0, NULL);
|
||||
prototype: struct uwsgi_metric *uwsgi_register_metric(char *name, char *oid, uint8_t value_type, uint8_t collect_way, void *ptr, uint32_t freq, void *custom);
|
||||
|
||||
value_type = UWSGI_METRIC_COUNTER/UWSGI_METRIC_GAUGE/UWSGI_METRIC_ABSOLUTE
|
||||
collect_way = UWSGI_METRIC_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
|
||||
|
||||
when freq is zero the value is recomputed whenever requested, otherwise the metrics thread compute it every time the frequency is elapsed and caches it
|
||||
|
||||
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", no_cache|force=False)
|
||||
if the second parameter is True, the value is recomputed (but if it is a metric with a cache, the cache value will not be updated accordingly, this is the job of the metric thread)
|
||||
|
||||
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)
|
||||
|
||||
*/
|
||||
|
||||
struct uwsgi_metric {
|
||||
char *name;
|
||||
char *oid;
|
||||
|
||||
// pre-computed snmp representation
|
||||
char *asn;
|
||||
size_t asn_size;
|
||||
|
||||
// ABSOLUTE/COUNTER/GAUGE
|
||||
uint8_t type;
|
||||
|
||||
// MANUAL/PTR/FUNC/FILE
|
||||
uint8_t collect_way
|
||||
|
||||
// this could be taken from a file storage and must laways be added to value when reporting (default 0)
|
||||
int64_t initial_value;
|
||||
// the value of the metric (point to a shared memory area)
|
||||
*int64_t value;
|
||||
|
||||
// a custom blob you can attach to a metric
|
||||
void *custom;
|
||||
|
||||
// the collection frequency
|
||||
uint32_t freq;
|
||||
time_t last_update;
|
||||
|
||||
// run this function to collect the value
|
||||
int64_t (*collector)(struct uwsgi_metric *);
|
||||
// take the value from this pointer to a 64bit value
|
||||
int64_t *ptr;
|
||||
// get the initial value from this file, and store each update in it
|
||||
char *filename;
|
||||
|
||||
struct uwsgi_metric *next;
|
||||
};
|
||||
|
||||
struct uwsgi_metric *uwsgi_register_metric(char *name, char *oid, uint8_t value_type, uint8_t collect_way, void *ptr, uint32_t freq, void *custom) {
|
||||
struct uwsgi_metric *old_metric=NULL,*metric=uwsgi.metric;
|
||||
|
||||
while(metric) {
|
||||
metric = metric->next;
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_metric_loop() {
|
||||
// every second scan the whole metrics tree
|
||||
time_t now = uwsgi_now();
|
||||
}
|
||||
|
||||
int64_t uwsgi_metric_get(char *name, char *oid) {
|
||||
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;
|
||||
|
||||
//
|
||||
switch(um->collect_way) {
|
||||
case UWSGI_METRIC_MANUAL:
|
||||
return um->initial_value+*um->value;
|
||||
case UWSGI_METRIC_PTR:
|
||||
return um->initial_value+*um->ptr;
|
||||
case UWSGI_METRIC_FUNC:
|
||||
case UWSGI_METRIC_FILE:
|
||||
}
|
||||
}
|
||||
+235
-213
@@ -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,54 +34,66 @@ 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);
|
||||
}
|
||||
}
|
||||
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.p[i]->post_fork) {
|
||||
uwsgi.p[i]->post_fork();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (uwsgi.mules[id-1].patch) {
|
||||
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]->mule) {
|
||||
if (uwsgi.p[i]->mule(uwsgi.mules[id - 1].patch) == 1) {
|
||||
// never here ?
|
||||
end_me(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_mule_handler();
|
||||
}
|
||||
else if (pid > 0) {
|
||||
uwsgi.mules[id-1].id = id;
|
||||
uwsgi.mules[id-1].pid = pid;
|
||||
uwsgi.mules[id - 1].id = id;
|
||||
uwsgi.mules[id - 1].pid = pid;
|
||||
uwsgi_log("spawned uWSGI mule %d (pid: %d)\n", id, (int) pid);
|
||||
}
|
||||
}
|
||||
@@ -90,7 +102,7 @@ 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 +115,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 +170,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 +184,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 +224,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 +235,236 @@ 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_signal_pipe(uwsgi.shared->mule_queue_pipe);
|
||||
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
// create the socket pipe
|
||||
create_signal_pipe(uwsgi.mules[i].signal_pipe);
|
||||
create_signal_pipe(uwsgi.mules[i].queue_pipe);
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
// create the socket pipe
|
||||
create_signal_pipe(uwsgi.mules[i].signal_pipe);
|
||||
create_signal_pipe(uwsgi.mules[i].queue_pipe);
|
||||
|
||||
uwsgi.mules[i].id = i + 1;
|
||||
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_signal_pipe(uwsgi.farms[i].queue_pipe);
|
||||
|
||||
char *p = strtok(mules_list, ",");
|
||||
while (p != NULL) {
|
||||
struct uwsgi_mule *um = get_mule_by_id(atoi(p));
|
||||
if (!um) {
|
||||
uwsgi_log("invalid mule id: %s\n", p);
|
||||
exit(1);
|
||||
}
|
||||
char *p = strtok(mules_list, ",");
|
||||
while (p != NULL) {
|
||||
struct uwsgi_mule *um = get_mule_by_id(atoi(p));
|
||||
if (!um) {
|
||||
uwsgi_log("invalid mule id: %s\n", p);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_mule_farm_new(&uwsgi.farms[i].mules, um);
|
||||
uwsgi_mule_farm_new(&uwsgi.farms[i].mules, um);
|
||||
|
||||
p = strtok(NULL, ",");
|
||||
}
|
||||
uwsgi_log("created farm %d name: %s mules:%s\n", i + 1, uwsgi.farms[i].name, strchr(farm_name->value, ':') + 1);
|
||||
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;
|
||||
farm_name = farm_name->next;
|
||||
free(farm_value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+18
-13
@@ -16,25 +16,28 @@ void uwsgi_systemd_notify(char *message) {
|
||||
iovec[1].iov_len = strlen(message);
|
||||
|
||||
iovec[2].iov_base = "\n";
|
||||
iovec[2].iov_len = 1;
|
||||
iovec[2].iov_len = 1;
|
||||
|
||||
msghdr->msg_iovlen = 3;
|
||||
|
||||
sendmsg(uwsgi.notification_fd, msghdr, 0);
|
||||
if (sendmsg(uwsgi.notification_fd, msghdr, 0) < 0) {
|
||||
uwsgi_error("sendmsg()");
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_systemd_notify_ready(void) {
|
||||
|
||||
struct msghdr *msghdr = (struct msghdr *) uwsgi.notification_object;
|
||||
struct iovec *iovec = msghdr->msg_iov;
|
||||
struct iovec *iovec = msghdr->msg_iov;
|
||||
|
||||
iovec[0].iov_base = "STATUS=uWSGI is ready\nREADY=1\n";
|
||||
iovec[0].iov_len = 30;
|
||||
iovec[0].iov_base = "STATUS=uWSGI is ready\nREADY=1\n";
|
||||
iovec[0].iov_len = 30;
|
||||
|
||||
msghdr->msg_iovlen = 1;
|
||||
|
||||
sendmsg(uwsgi.notification_fd, msghdr, 0);
|
||||
|
||||
if (sendmsg(uwsgi.notification_fd, msghdr, 0) < 0) {
|
||||
uwsgi_error("sendmsg()");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,24 +52,26 @@ void uwsgi_systemd_init(char *systemd_socket) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t len = strlen(systemd_socket);
|
||||
sd_sun = uwsgi_malloc(sizeof(struct sockaddr_un));
|
||||
memset(sd_sun, 0, sizeof(struct sockaddr_un));
|
||||
sd_sun->sun_family = AF_UNIX;
|
||||
strncpy(sd_sun->sun_path, systemd_socket, sizeof(sd_sun->sun_path));
|
||||
if (sd_sun->sun_path[0] == '@') sd_sun->sun_path[0] = 0;
|
||||
strncpy(sd_sun->sun_path, systemd_socket, UMIN(len, sizeof(sd_sun->sun_path)));
|
||||
if (sd_sun->sun_path[0] == '@')
|
||||
sd_sun->sun_path[0] = 0;
|
||||
|
||||
msghdr = uwsgi_malloc(sizeof(struct msghdr));
|
||||
memset(msghdr, 0, sizeof(struct msghdr));
|
||||
|
||||
msghdr->msg_iov = uwsgi_malloc(sizeof(struct iovec)*3);
|
||||
memset(msghdr->msg_iov, 0, sizeof(struct iovec)*3);
|
||||
msghdr->msg_iov = uwsgi_malloc(sizeof(struct iovec) * 3);
|
||||
memset(msghdr->msg_iov, 0, sizeof(struct iovec) * 3);
|
||||
|
||||
msghdr->msg_name = sd_sun;
|
||||
msghdr->msg_namelen = sizeof(struct sockaddr_un);
|
||||
msghdr->msg_namelen = sizeof(struct sockaddr_un) - (sizeof(sd_sun->sun_path) - len);
|
||||
|
||||
uwsgi.notification_object = msghdr;
|
||||
|
||||
uwsgi.notify = uwsgi_systemd_notify;
|
||||
uwsgi.notify_ready = uwsgi_systemd_notify_ready;
|
||||
|
||||
|
||||
}
|
||||
|
||||
+509
@@ -0,0 +1,509 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
/*
|
||||
|
||||
uWSGI offloading subsystem
|
||||
|
||||
steps to offload a task
|
||||
|
||||
1) allocate a uwsgi_offload_request structure (could be on stack)
|
||||
struct uwsgi_offload_request uor;
|
||||
2) prepare it for a specific engine (last argument is the takeover flag)
|
||||
uwsgi_offload_setup(my_engine, &uor, 1)
|
||||
3) run it (last argument is the waiter)
|
||||
int uwsgi_offload_run(wsgi_req, &uor, NULL);
|
||||
|
||||
between 2 and 3 you can set specific values
|
||||
|
||||
*/
|
||||
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#define uwsgi_offload_retry if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) return 0;
|
||||
#define uwsgi_offload_0r_1w(x, y) if (event_queue_del_fd(ut->queue, x, event_queue_read())) return -1;\
|
||||
if (event_queue_fd_read_to_write(ut->queue, y)) return -1;
|
||||
|
||||
void uwsgi_offload_setup(struct uwsgi_offload_engine *uoe, struct uwsgi_offload_request *uor, struct wsgi_request *wsgi_req, uint8_t takeover) {
|
||||
|
||||
memset(uor, 0, sizeof(struct uwsgi_offload_request));
|
||||
|
||||
uor->engine = uoe;
|
||||
|
||||
uor->s = wsgi_req->fd;
|
||||
uor->fd = -1;
|
||||
uor->fd2 = -1;
|
||||
// an engine could changes behaviour based on pipe anf takeover values
|
||||
uor->pipe[0] = -1;
|
||||
uor->pipe[1] = -1;
|
||||
uor->takeover = takeover;
|
||||
|
||||
}
|
||||
|
||||
static int uwsgi_offload_enqueue(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) {
|
||||
struct uwsgi_core *uc = &uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id];
|
||||
uc->offloaded_requests++;
|
||||
// round robin
|
||||
if (uc->offload_rr >= uwsgi.offload_threads) {
|
||||
uc->offload_rr = 0;
|
||||
}
|
||||
struct uwsgi_thread *ut = uwsgi.offload_thread[uc->offload_rr];
|
||||
uc->offload_rr++;
|
||||
if (write(ut->pipe[0], uor, sizeof(struct uwsgi_offload_request)) != sizeof(struct uwsgi_offload_request)) {
|
||||
if (uor->takeover) {
|
||||
wsgi_req->fd_closed = 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
transfer offload engine:
|
||||
name -> socket name
|
||||
ubuf -> data to send
|
||||
|
||||
*/
|
||||
|
||||
int u_offload_transfer_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) {
|
||||
|
||||
if (!uor->name) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uor->fd = uwsgi_connect(uor->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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
the offload task starts after having acquired the file fd
|
||||
|
||||
uor->len -> the size of the file
|
||||
uor->pos -> start writing from pos (default 0)
|
||||
|
||||
status: none
|
||||
|
||||
*/
|
||||
|
||||
static int u_offload_sendfile_do(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) {
|
||||
|
||||
if (fd == -1) {
|
||||
if (event_queue_add_fd_write(ut->queue, uor->fd2)) return -1;
|
||||
return 0;
|
||||
}
|
||||
#if defined(__linux__) || defined(__sun__)
|
||||
ssize_t len = sendfile(uor->fd2, uor->fd, &uor->pos, 128 * 1024);
|
||||
if (len > 0) {
|
||||
uor->written += len;
|
||||
if (uor->written >= uor->len) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (len < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_sendfile_do()");
|
||||
}
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
off_t sbytes = 0;
|
||||
int ret = sendfile(uor->fd, uor->fd2, uor->pos, 0, NULL, &sbytes, 0);
|
||||
// transfer finished
|
||||
if (ret == -1) {
|
||||
uor->pos += sbytes;
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_sendfile_do()");
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
off_t len = 0;
|
||||
int ret = sendfile(uor->fd, uor->fd2, uor->pos, &len, NULL, 0);
|
||||
// transfer finished
|
||||
if (ret == -1) {
|
||||
uor->pos += len;
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_sendfile_do()");
|
||||
}
|
||||
#endif
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
the offload task starts soon after the call to connect()
|
||||
|
||||
status:
|
||||
0 -> waiting for connection on fd
|
||||
1 -> sending request to fd (write event)
|
||||
2 -> start waiting for read on s and fd
|
||||
3 -> write to s
|
||||
4 -> write to fd
|
||||
*/
|
||||
static int u_offload_transfer_do(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) {
|
||||
|
||||
ssize_t rlen;
|
||||
|
||||
// setup
|
||||
if (fd == -1) {
|
||||
event_queue_add_fd_write(ut->queue, uor->fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch(uor->status) {
|
||||
// waiting for connection
|
||||
case 0:
|
||||
if (fd == uor->fd) {
|
||||
uor->status = 1;
|
||||
// ok try to send the request right now...
|
||||
return u_offload_transfer_do(ut, uor, fd);
|
||||
}
|
||||
return -1;
|
||||
// write event (or just connected)
|
||||
case 1:
|
||||
if (fd == uor->fd) {
|
||||
rlen = write(uor->fd, uor->ubuf->buf + uor->written, uor->ubuf->pos-uor->written);
|
||||
if (rlen > 0) {
|
||||
uor->written += rlen;
|
||||
if (uor->written >= (size_t)uor->ubuf->pos) {
|
||||
uor->status = 2;
|
||||
if (event_queue_add_fd_read(ut->queue, uor->s)) return -1;
|
||||
if (event_queue_fd_write_to_read(ut->queue, uor->fd)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_transfer_do() -> write()");
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
// read event from s or fd
|
||||
case 2:
|
||||
if (!uor->buf) {
|
||||
uor->buf = uwsgi_malloc(4096);
|
||||
}
|
||||
if (fd == uor->fd) {
|
||||
rlen = read(uor->fd, uor->buf, 4096);
|
||||
if (rlen > 0) {
|
||||
uor->to_write = rlen;
|
||||
uor->pos = 0;
|
||||
uwsgi_offload_0r_1w(uor->fd, uor->s)
|
||||
uor->status = 3;
|
||||
return 0;
|
||||
}
|
||||
if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_transfer_do() -> read()/fd");
|
||||
}
|
||||
}
|
||||
else if (fd == uor->s) {
|
||||
rlen = read(uor->s, uor->buf, 4096);
|
||||
if (rlen > 0) {
|
||||
uor->to_write = rlen;
|
||||
uor->pos = 0;
|
||||
uwsgi_offload_0r_1w(uor->s, uor->fd)
|
||||
uor->status = 4;
|
||||
return 0;
|
||||
}
|
||||
if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_transfer_do() -> read()/s");
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
// write event on s
|
||||
case 3:
|
||||
rlen = write(uor->s, uor->buf + uor->pos, uor->to_write);
|
||||
if (rlen > 0) {
|
||||
uor->to_write -= rlen;
|
||||
uor->pos += rlen;
|
||||
if (uor->to_write == 0) {
|
||||
if (event_queue_fd_write_to_read(ut->queue, uor->s)) return -1;
|
||||
if (event_queue_add_fd_read(ut->queue, uor->fd)) return -1;
|
||||
uor->status = 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_transfer_do() -> write()/s");
|
||||
}
|
||||
return -1;
|
||||
// write event on fd
|
||||
case 4:
|
||||
rlen = write(uor->fd, uor->buf + uor->pos, uor->to_write);
|
||||
if (rlen > 0) {
|
||||
uor->to_write -= rlen;
|
||||
uor->pos += rlen;
|
||||
if (uor->to_write == 0) {
|
||||
if (event_queue_fd_write_to_read(ut->queue, uor->fd)) return -1;
|
||||
if (event_queue_add_fd_read(ut->queue, uor->s)) return -1;
|
||||
uor->status = 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (rlen < 0) {
|
||||
uwsgi_offload_retry
|
||||
uwsgi_error("u_offload_transfer_do() -> write()/fd");
|
||||
}
|
||||
return -1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int uwsgi_offload_run(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor, int *wait) {
|
||||
|
||||
if (uor->engine->prepare_func(wsgi_req, uor)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wait) {
|
||||
if (pipe(uor->pipe)) {
|
||||
uwsgi_error("uwsgi_offload_setup()/pipe()");
|
||||
return -1;
|
||||
}
|
||||
*wait = uor->pipe[0];
|
||||
uwsgi_socket_nb(uor->pipe[0]);
|
||||
uwsgi_socket_nb(uor->pipe[1]);
|
||||
}
|
||||
|
||||
if (uor->takeover) {
|
||||
wsgi_req->fd_closed = 1;
|
||||
}
|
||||
|
||||
if (uwsgi_offload_enqueue(wsgi_req, uor)) {
|
||||
close(uor->pipe[0]);
|
||||
close(uor->pipe[1]);
|
||||
if (uor->takeover) {
|
||||
wsgi_req->fd_closed = 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
};
|
||||
|
||||
struct uwsgi_offload_engine *uwsgi_offload_engine_by_name(char *name) {
|
||||
struct uwsgi_offload_engine *uoe = uwsgi.offload_engines;
|
||||
while(uoe) {
|
||||
if (!strcmp(name, uoe->name)) {
|
||||
return uoe;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_offload_engine *uwsgi_offload_register_engine(char *name, int (*prepare_func)(struct wsgi_request *, struct uwsgi_offload_request *), int (*event_func) (struct uwsgi_thread *, struct uwsgi_offload_request *, int)) {
|
||||
|
||||
struct uwsgi_offload_engine *old_engine=NULL,*engine=uwsgi.offload_engines;
|
||||
while(engine) {
|
||||
if (!strcmp(engine->name, name)) {
|
||||
return engine;
|
||||
}
|
||||
old_engine = engine;
|
||||
engine = engine->next;
|
||||
}
|
||||
|
||||
engine = uwsgi_calloc(sizeof(struct uwsgi_offload_engine));
|
||||
engine->name = name;
|
||||
engine->prepare_func = prepare_func;
|
||||
engine->event_func = event_func;
|
||||
|
||||
if (old_engine) {
|
||||
old_engine->next = engine;
|
||||
}
|
||||
else {
|
||||
uwsgi.offload_engines = engine;
|
||||
}
|
||||
|
||||
return engine;
|
||||
}
|
||||
|
||||
void uwsgi_offload_engines_register_all() {
|
||||
uwsgi.offload_engine_sendfile = uwsgi_offload_register_engine("sendfile", u_offload_sendfile_prepare, u_offload_sendfile_do);
|
||||
uwsgi.offload_engine_transfer = uwsgi_offload_register_engine("transfer", u_offload_transfer_prepare, u_offload_transfer_do);
|
||||
}
|
||||
|
||||
int uwsgi_offload_request_sendfile_do(struct wsgi_request *wsgi_req, int fd, size_t len) {
|
||||
struct uwsgi_offload_request uor;
|
||||
uwsgi_offload_setup(uwsgi.offload_engine_sendfile, &uor, wsgi_req, 1);
|
||||
uor.fd = fd;
|
||||
uor.len = len;
|
||||
return uwsgi_offload_run(wsgi_req, &uor, NULL);
|
||||
}
|
||||
|
||||
int uwsgi_offload_request_net_do(struct wsgi_request *wsgi_req, char *socketname, struct uwsgi_buffer *ubuf) {
|
||||
struct uwsgi_offload_request uor;
|
||||
uwsgi_offload_setup(uwsgi.offload_engine_transfer, &uor, wsgi_req, 1);
|
||||
uor.name = socketname;
|
||||
uor.ubuf = ubuf;
|
||||
return uwsgi_offload_run(wsgi_req, &uor, NULL);
|
||||
}
|
||||
+92
-62
@@ -2,7 +2,29 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
static int plugin_already_loaded(const char *plugin) {
|
||||
#ifdef UWSGI_ELF
|
||||
static void uwsgi_plugin_parse_section(char *filename) {
|
||||
size_t s_len = 0;
|
||||
char *buf = uwsgi_elf_section(filename, "uwsgi", &s_len);
|
||||
if (buf) {
|
||||
char *ctx = NULL;
|
||||
char *p = strtok_r(buf, "\n", &ctx);
|
||||
while (p) {
|
||||
char *equal = strchr(p, '=');
|
||||
if (equal) {
|
||||
*equal = 0;
|
||||
if (!strcmp(p, "requires")) {
|
||||
uwsgi_load_plugin(-1, equal + 1, NULL);
|
||||
}
|
||||
}
|
||||
p = strtok_r(NULL, "\n", &ctx);
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int plugin_already_loaded(const char *plugin) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
@@ -12,7 +34,7 @@ static int plugin_already_loaded(const char *plugin) {
|
||||
uwsgi_log("%s plugin already available\n", plugin);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (uwsgi.p[i]->alias) {
|
||||
if (!strcmp(plugin, uwsgi.p[i]->alias)) {
|
||||
@@ -20,29 +42,29 @@ static int plugin_already_loaded(const char *plugin) {
|
||||
uwsgi_log("%s plugin already available\n", plugin);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0;i<uwsgi.gp_cnt;i++) {
|
||||
for (i = 0; i < uwsgi.gp_cnt; i++) {
|
||||
|
||||
if (uwsgi.gp[i]->name) {
|
||||
if (!strcmp(plugin, uwsgi.gp[i]->name)) {
|
||||
if (!strcmp(plugin, uwsgi.gp[i]->name)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%s plugin already available\n", plugin);
|
||||
uwsgi_log("%s plugin already available\n", plugin);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (uwsgi.gp[i]->alias) {
|
||||
if (!strcmp(plugin, uwsgi.gp[i]->alias)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (uwsgi.gp[i]->alias) {
|
||||
if (!strcmp(plugin, uwsgi.gp[i]->alias)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%s plugin already available\n", plugin);
|
||||
uwsgi_log("%s plugin already available\n", plugin);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -54,9 +76,8 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
|
||||
char *plugin_filename = NULL;
|
||||
|
||||
int need_free = 0;
|
||||
char *plugin_name = plugin;
|
||||
char *plugin_symbol_name_start = plugin;
|
||||
|
||||
char *plugin_name = uwsgi_strip(uwsgi_str(plugin));
|
||||
char *plugin_symbol_name_start = plugin_name;
|
||||
|
||||
struct uwsgi_plugin *up;
|
||||
char linkpath_buf[1024], linkpath[1024];
|
||||
@@ -66,7 +87,7 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
|
||||
if (colon) {
|
||||
colon[0] = 0;
|
||||
modifier = atoi(plugin_name);
|
||||
plugin_name = colon+1;
|
||||
plugin_name = colon + 1;
|
||||
colon[0] = ':';
|
||||
}
|
||||
|
||||
@@ -79,10 +100,13 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
|
||||
|
||||
// step 1: check for absolute plugin (stop if it fails)
|
||||
if (strchr(plugin_name, '/')) {
|
||||
#ifdef UWSGI_ELF
|
||||
uwsgi_plugin_parse_section(plugin_name);
|
||||
#endif
|
||||
plugin_handle = dlopen(plugin_name, RTLD_NOW | RTLD_GLOBAL);
|
||||
if (!plugin_handle) {
|
||||
if (!has_option)
|
||||
uwsgi_log( "%s\n", dlerror());
|
||||
uwsgi_log("%s\n", dlerror());
|
||||
goto end;
|
||||
}
|
||||
plugin_symbol_name_start = uwsgi_get_last_char(plugin_name, '/');
|
||||
@@ -93,8 +117,11 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
|
||||
|
||||
// step dir, check for user-supplied plugins directory
|
||||
struct uwsgi_string_list *pdir = uwsgi.plugins_dir;
|
||||
while(pdir) {
|
||||
while (pdir) {
|
||||
plugin_filename = uwsgi_concat3(pdir->value, "/", plugin_name);
|
||||
#ifdef UWSGI_ELF
|
||||
uwsgi_plugin_parse_section(plugin_filename);
|
||||
#endif
|
||||
plugin_handle = dlopen(plugin_filename, RTLD_NOW | RTLD_GLOBAL);
|
||||
if (plugin_handle) {
|
||||
plugin_abs_path = plugin_filename;
|
||||
@@ -109,19 +136,22 @@ void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
|
||||
// last step: search in compile-time plugin_dir
|
||||
if (!plugin_handle) {
|
||||
plugin_filename = uwsgi_concat3(UWSGI_PLUGIN_DIR, "/", plugin_name);
|
||||
#ifdef UWSGI_ELF
|
||||
uwsgi_plugin_parse_section(plugin_filename);
|
||||
#endif
|
||||
plugin_handle = dlopen(plugin_filename, RTLD_NOW | RTLD_GLOBAL);
|
||||
plugin_abs_path = plugin_filename;
|
||||
//free(plugin_filename);
|
||||
}
|
||||
|
||||
success:
|
||||
if (!plugin_handle) {
|
||||
if (!plugin_handle) {
|
||||
if (!has_option)
|
||||
uwsgi_log( "%s\n", dlerror());
|
||||
}
|
||||
else {
|
||||
char *plugin_entry_symbol = uwsgi_concat2n(plugin_symbol_name_start, strlen(plugin_symbol_name_start)-3, "", 0);
|
||||
up = dlsym(plugin_handle, plugin_entry_symbol);
|
||||
uwsgi_log("!!! UNABLE to load uWSGI plugin: %s !!!\n", dlerror());
|
||||
}
|
||||
else {
|
||||
char *plugin_entry_symbol = uwsgi_concat2n(plugin_symbol_name_start, strlen(plugin_symbol_name_start) - 3, "", 0);
|
||||
up = dlsym(plugin_handle, plugin_entry_symbol);
|
||||
if (!up) {
|
||||
// is it a link ?
|
||||
memset(linkpath_buf, 0, 1024);
|
||||
@@ -129,13 +159,12 @@ success:
|
||||
if ((linkpath_size = readlink(plugin_abs_path, linkpath_buf, 1023)) > 0) {
|
||||
do {
|
||||
linkpath_buf[linkpath_size] = '\0';
|
||||
strncpy(linkpath, linkpath_buf, linkpath_size+1);
|
||||
strncpy(linkpath, linkpath_buf, linkpath_size + 1);
|
||||
} while ((linkpath_size = readlink(linkpath, linkpath_buf, 1023)) > 0);
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%s\n", linkpath);
|
||||
#endif
|
||||
free(plugin_entry_symbol);
|
||||
up = dlsym(plugin_handle, plugin_entry_symbol);
|
||||
char *slash = uwsgi_get_last_char(linkpath, '/');
|
||||
if (!slash) {
|
||||
slash = linkpath;
|
||||
@@ -143,16 +172,16 @@ success:
|
||||
else {
|
||||
slash++;
|
||||
}
|
||||
plugin_entry_symbol = uwsgi_concat2n(slash, strlen(slash)-3, "",0);
|
||||
plugin_entry_symbol = uwsgi_concat2n(slash, strlen(slash) - 3, "", 0);
|
||||
up = dlsym(plugin_handle, plugin_entry_symbol);
|
||||
}
|
||||
}
|
||||
if (up) {
|
||||
if (up) {
|
||||
if (!up->name) {
|
||||
uwsgi_log("the loaded plugin (%s) has no .name attribute\n", plugin_name);
|
||||
if (dlclose(plugin_handle)) {
|
||||
uwsgi_error("dlclose()");
|
||||
}
|
||||
uwsgi_error("dlclose()");
|
||||
}
|
||||
if (need_free)
|
||||
free(plugin_name);
|
||||
if (plugin_filename)
|
||||
@@ -162,8 +191,8 @@ success:
|
||||
}
|
||||
if (plugin_already_loaded(up->name)) {
|
||||
if (dlclose(plugin_handle)) {
|
||||
uwsgi_error("dlclose()");
|
||||
}
|
||||
uwsgi_error("dlclose()");
|
||||
}
|
||||
if (need_free)
|
||||
free(plugin_name);
|
||||
if (plugin_filename)
|
||||
@@ -178,8 +207,8 @@ success:
|
||||
if (!strcmp(has_option, op->name)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
op++;
|
||||
}
|
||||
op++;
|
||||
}
|
||||
if (!found) {
|
||||
if (dlclose(plugin_handle)) {
|
||||
@@ -192,14 +221,14 @@ success:
|
||||
free(plugin_entry_symbol);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
if (modifier != -1) {
|
||||
fill_plugin_table(modifier, up);
|
||||
fill_plugin_table(modifier, up);
|
||||
up->modifier1 = modifier;
|
||||
}
|
||||
else {
|
||||
fill_plugin_table(up->modifier1, up);
|
||||
fill_plugin_table(up->modifier1, up);
|
||||
}
|
||||
if (need_free)
|
||||
free(plugin_name);
|
||||
@@ -210,10 +239,10 @@ success:
|
||||
if (up->on_load)
|
||||
up->on_load();
|
||||
return plugin_handle;
|
||||
}
|
||||
}
|
||||
if (!has_option)
|
||||
uwsgi_log( "%s\n", dlerror());
|
||||
}
|
||||
uwsgi_log("%s\n", dlerror());
|
||||
}
|
||||
|
||||
end:
|
||||
if (need_free)
|
||||
@@ -228,14 +257,14 @@ int uwsgi_try_autoload(char *option) {
|
||||
DIR *d;
|
||||
struct dirent *dp;
|
||||
// step dir, check for user-supplied plugins directory
|
||||
struct uwsgi_string_list *pdir = uwsgi.plugins_dir;
|
||||
while(pdir) {
|
||||
struct uwsgi_string_list *pdir = uwsgi.plugins_dir;
|
||||
while (pdir) {
|
||||
d = opendir(pdir->value);
|
||||
if (d) {
|
||||
while ((dp = readdir(d)) != NULL) {
|
||||
if (uwsgi_endswith(dp->d_name, "_plugin.so")) {
|
||||
char *filename = uwsgi_concat3(pdir->value, "/", dp->d_name);
|
||||
if (uwsgi_load_plugin(-1, filename, option)) {
|
||||
if (uwsgi_load_plugin(-1, filename, option)) {
|
||||
uwsgi_log("option \"%s\" found in plugin %s\n", option, filename);
|
||||
free(filename);
|
||||
closedir(d);
|
||||
@@ -248,27 +277,28 @@ int uwsgi_try_autoload(char *option) {
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
pdir = pdir->next;
|
||||
}
|
||||
pdir = pdir->next;
|
||||
}
|
||||
|
||||
// last step: search in compile-time plugin_dir
|
||||
// last step: search in compile-time plugin_dir
|
||||
d = opendir(UWSGI_PLUGIN_DIR);
|
||||
if (!d) return 0;
|
||||
if (!d)
|
||||
return 0;
|
||||
|
||||
while((dp = readdir(d)) != NULL) {
|
||||
while ((dp = readdir(d)) != NULL) {
|
||||
if (uwsgi_endswith(dp->d_name, "_plugin.so")) {
|
||||
char *filename = uwsgi_concat3(UWSGI_PLUGIN_DIR, "/", dp->d_name);
|
||||
if (uwsgi_load_plugin(-1, filename, option)) {
|
||||
uwsgi_log("option \"%s\" found in plugin %s\n", option, filename);
|
||||
free(filename);
|
||||
closedir(d);
|
||||
// add new options
|
||||
build_options();
|
||||
return 1;
|
||||
}
|
||||
char *filename = uwsgi_concat3(UWSGI_PLUGIN_DIR, "/", dp->d_name);
|
||||
if (uwsgi_load_plugin(-1, filename, option)) {
|
||||
uwsgi_log("option \"%s\" found in plugin %s\n", option, filename);
|
||||
free(filename);
|
||||
closedir(d);
|
||||
// add new options
|
||||
build_options();
|
||||
return 1;
|
||||
}
|
||||
free(filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
|
||||
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
|
||||
upload progress facilities
|
||||
|
||||
*/
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
char *uwsgi_upload_progress_create(struct wsgi_request *wsgi_req, int *fd) {
|
||||
const char *x_progress_id = "X-Progress-ID=";
|
||||
char *xpi_ptr = (char *) x_progress_id;
|
||||
uint16_t i;
|
||||
char *upload_progress_filename = NULL;
|
||||
|
||||
if (wsgi_req->uri_len <= 51)
|
||||
return NULL;
|
||||
|
||||
|
||||
for (i = 0; i < wsgi_req->uri_len; i++) {
|
||||
if (wsgi_req->uri[i] == xpi_ptr[0]) {
|
||||
if (xpi_ptr[0] == '=') {
|
||||
if (wsgi_req->uri + i + 36 <= wsgi_req->uri + wsgi_req->uri_len) {
|
||||
upload_progress_filename = wsgi_req->uri + i + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
xpi_ptr++;
|
||||
}
|
||||
else {
|
||||
xpi_ptr = (char *) x_progress_id;
|
||||
}
|
||||
}
|
||||
|
||||
// now check for valid uuid (from spec available at http://en.wikipedia.org/wiki/Universally_unique_identifier)
|
||||
if (!upload_progress_filename)
|
||||
return NULL;
|
||||
|
||||
uwsgi_log("upload progress uuid = %.*s\n", 36, upload_progress_filename);
|
||||
if (!check_hex(upload_progress_filename, 8))
|
||||
return NULL;
|
||||
if (upload_progress_filename[8] != '-')
|
||||
return NULL;
|
||||
|
||||
if (!check_hex(upload_progress_filename + 9, 4))
|
||||
return NULL;
|
||||
if (upload_progress_filename[13] != '-')
|
||||
return NULL;
|
||||
|
||||
if (!check_hex(upload_progress_filename + 14, 4))
|
||||
return NULL;
|
||||
if (upload_progress_filename[18] != '-')
|
||||
return NULL;
|
||||
|
||||
if (!check_hex(upload_progress_filename + 19, 4))
|
||||
return NULL;
|
||||
if (upload_progress_filename[23] != '-')
|
||||
return NULL;
|
||||
|
||||
if (!check_hex(upload_progress_filename + 24, 12))
|
||||
return NULL;
|
||||
|
||||
upload_progress_filename = uwsgi_concat4n(uwsgi.upload_progress, strlen(uwsgi.upload_progress), "/", 1, upload_progress_filename, 36, ".js", 3);
|
||||
// here we use O_EXCL to avoid eventual application bug in uuid generation/using
|
||||
*fd = open(upload_progress_filename, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP);
|
||||
if (*fd < 0) {
|
||||
uwsgi_error_open(upload_progress_filename);
|
||||
free(upload_progress_filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return upload_progress_filename;
|
||||
}
|
||||
|
||||
int uwsgi_upload_progress_update(struct wsgi_request *wsgi_req, int fd, size_t remains) {
|
||||
char buf[4096];
|
||||
|
||||
int ret = snprintf(buf, 4096, "{ \"state\" : \"uploading\", \"received\" : %llu, \"size\" : %llu }\r\n", (unsigned long long) (wsgi_req->post_cl - remains), (unsigned long long) wsgi_req->post_cl);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lseek(fd, 0, SEEK_SET)) {
|
||||
uwsgi_error("uwsgi_upload_progress_update()/lseek()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (write(fd, buf, ret) != ret) {
|
||||
uwsgi_error("uwsgi_upload_progress_update()/write()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fsync(fd)) {
|
||||
uwsgi_error("uwsgi_upload_progress_update()/fsync()");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uwsgi_upload_progress_destroy(char *filename, int fd) {
|
||||
close(fd);
|
||||
if (unlink(filename)) {
|
||||
uwsgi_error("uwsgi_upload_progress_destroy()/unlink()");
|
||||
}
|
||||
free(filename);
|
||||
}
|
||||
+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) {
|
||||
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);
|
||||
}
|
||||
|
||||
+572
@@ -0,0 +1,572 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_simple_wait_read_hook(int fd, int timeout) {
|
||||
struct pollfd upoll;
|
||||
timeout = timeout * 1000;
|
||||
|
||||
upoll.fd = fd;
|
||||
upoll.events = POLLIN;
|
||||
upoll.revents = 0;
|
||||
int ret = poll(&upoll, 1, timeout);
|
||||
|
||||
if (ret > 0) {
|
||||
if (upoll.revents & POLLIN) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (ret < 0) {
|
||||
uwsgi_error("uwsgi_simple_wait_read_hook()/poll()");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
seek()/rewind() language-independent implementations.
|
||||
*/
|
||||
|
||||
void uwsgi_request_body_seek(struct wsgi_request *wsgi_req, off_t pos) {
|
||||
if (wsgi_req->post_file) {
|
||||
if (pos < 0) {
|
||||
if (fseek(wsgi_req->post_file, pos, SEEK_CUR)) {
|
||||
uwsgi_error("uwsgi_request_body_seek()/fseek()");
|
||||
}
|
||||
wsgi_req->post_pos = ftell(wsgi_req->post_file);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fseek(wsgi_req->post_file, pos, SEEK_SET)) {
|
||||
uwsgi_error("uwsgi_request_body_seek()/fseek()");
|
||||
}
|
||||
wsgi_req->post_pos = ftell(wsgi_req->post_file);
|
||||
return;
|
||||
}
|
||||
|
||||
if (uwsgi.post_buffering) {
|
||||
if (pos < 0) {
|
||||
if ((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;
|
||||
}
|
||||
*rlen = -1;
|
||||
if (len == 0) {
|
||||
uwsgi_read_error0(remains);
|
||||
}
|
||||
else {
|
||||
uwsgi_read_error(remains);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
// 0 means timeout
|
||||
else if (ret == 0) {
|
||||
*rlen = 0;
|
||||
uwsgi_read_timeout(remains);
|
||||
return NULL;
|
||||
}
|
||||
*rlen = -1;
|
||||
uwsgi_read_error(remains);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return wsgi_req->post_read_buf;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
post buffering
|
||||
|
||||
*/
|
||||
|
||||
int uwsgi_postbuffer_do_in_mem(struct wsgi_request *wsgi_req) {
|
||||
|
||||
size_t remains = wsgi_req->post_cl;
|
||||
int ret;
|
||||
char *ptr = wsgi_req->post_buffering_buf;
|
||||
|
||||
while (remains > 0) {
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
|
||||
inc_harakiri(uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
}
|
||||
|
||||
ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, ptr, remains);
|
||||
if (rlen > 0) {
|
||||
remains -= rlen;
|
||||
ptr += rlen;
|
||||
continue;
|
||||
}
|
||||
if (rlen == 0) {
|
||||
uwsgi_read_error0(remains);
|
||||
return -1;
|
||||
}
|
||||
if (rlen < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
goto wait;
|
||||
}
|
||||
uwsgi_read_error(remains);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wait:
|
||||
ret = uwsgi_wait_read_req(wsgi_req);
|
||||
if (ret > 0) {
|
||||
rlen = wsgi_req->socket->proto_read_body(wsgi_req, ptr, remains);
|
||||
if (rlen > 0) {
|
||||
remains -= rlen;
|
||||
ptr += rlen;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
uwsgi_read_error(remains);
|
||||
return -1;
|
||||
}
|
||||
uwsgi_read_timeout(remains);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_postbuffer_do_in_disk(struct wsgi_request *wsgi_req) {
|
||||
|
||||
size_t post_remains = wsgi_req->post_cl;
|
||||
int ret;
|
||||
int upload_progress_fd = -1;
|
||||
char *upload_progress_filename = NULL;
|
||||
|
||||
wsgi_req->post_file = tmpfile();
|
||||
if (!wsgi_req->post_file) {
|
||||
uwsgi_error("uwsgi_postbuffer_do_in_disk()/tmpfile()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (uwsgi.upload_progress) {
|
||||
// first check for X-Progress-ID size
|
||||
// separator + 'X-Progress-ID' + '=' + uuid
|
||||
upload_progress_filename = uwsgi_upload_progress_create(wsgi_req, &upload_progress_fd);
|
||||
if (!upload_progress_filename) {
|
||||
uwsgi_log("invalid X-Progress-ID value: must be a UUID\n");
|
||||
}
|
||||
}
|
||||
|
||||
// manage buffered data and upload progress
|
||||
while (post_remains > 0) {
|
||||
|
||||
// during post buffering we need to constantly reset the harakiri
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
|
||||
inc_harakiri(uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
}
|
||||
|
||||
// we use the already available post buffering buffer to read chunks....
|
||||
size_t remains = UMIN(post_remains, uwsgi.post_buffering);
|
||||
|
||||
// first try to read data (there could be something already available
|
||||
ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_buffering_buf, remains);
|
||||
if (rlen > 0) goto write;
|
||||
if (rlen == 0) {
|
||||
uwsgi_read_error0(remains);
|
||||
goto end;
|
||||
}
|
||||
if (rlen < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
goto wait;
|
||||
}
|
||||
uwsgi_read_error(remains);
|
||||
goto end;
|
||||
}
|
||||
|
||||
wait:
|
||||
ret = uwsgi_wait_read_req(wsgi_req);
|
||||
if (ret > 0) {
|
||||
rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_buffering_buf, remains);
|
||||
if (rlen > 0) goto write;
|
||||
if (rlen == 0) {
|
||||
uwsgi_read_error0(remains);
|
||||
}
|
||||
else {
|
||||
uwsgi_read_error(remains);
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
if (ret < 0) {
|
||||
uwsgi_read_error(remains);
|
||||
goto end;
|
||||
}
|
||||
uwsgi_read_timeout(remains);
|
||||
goto end;
|
||||
|
||||
write:
|
||||
if (fwrite(wsgi_req->post_buffering_buf, rlen, 1, wsgi_req->post_file) != 1) {
|
||||
uwsgi_error("uwsgi_postbuffer_do_in_disk()/fwrite()");
|
||||
goto end;
|
||||
}
|
||||
|
||||
post_remains -= rlen;
|
||||
|
||||
if (upload_progress_filename) {
|
||||
// stop updating it on errors
|
||||
if (uwsgi_upload_progress_update(wsgi_req, upload_progress_fd, post_remains)) {
|
||||
uwsgi_upload_progress_destroy(upload_progress_filename, upload_progress_fd);
|
||||
upload_progress_filename = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
rewind(wsgi_req->post_file);
|
||||
|
||||
if (upload_progress_filename) {
|
||||
uwsgi_upload_progress_destroy(upload_progress_filename, upload_progress_fd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
end:
|
||||
if (upload_progress_filename) {
|
||||
uwsgi_upload_progress_destroy(upload_progress_filename, upload_progress_fd);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
+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;
|
||||
}
|
||||
|
||||
+1445
-72
File diff suppressed because it is too large
Load Diff
+107
-70
@@ -1,31 +1,57 @@
|
||||
#include "uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_register_rpc(char *name, uint8_t modifier1, uint8_t args, void *func) {
|
||||
int uwsgi_register_rpc(char *name, struct uwsgi_plugin *plugin, uint8_t args, void *func) {
|
||||
|
||||
struct uwsgi_rpc *urpc;
|
||||
int ret = -1;
|
||||
|
||||
if (uwsgi.mywid != 0) {
|
||||
uwsgi_log("you can register RPC functions only in the master\n");
|
||||
if (uwsgi.mywid == 0 && uwsgi.workers[0].pid != uwsgi.mypid) {
|
||||
uwsgi_log("only the master and the workers can register RPC functions\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_lock(uwsgi.rpc_table_lock);
|
||||
|
||||
if (uwsgi.shared->rpc_count < MAX_RPC) {
|
||||
urpc = &uwsgi.shared->rpc_table[uwsgi.shared->rpc_count];
|
||||
|
||||
// first check if a function is already registered
|
||||
size_t i;
|
||||
for(i=0;i<uwsgi.shared->rpc_count[uwsgi.mywid];i++) {
|
||||
int pos = (uwsgi.mywid * uwsgi.rpc_max) + i;
|
||||
urpc = &uwsgi.rpc_table[pos];
|
||||
if (!strcmp(name, urpc->name)) {
|
||||
goto already;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.shared->rpc_count[uwsgi.mywid] < uwsgi.rpc_max) {
|
||||
int pos = (uwsgi.mywid * uwsgi.rpc_max) + uwsgi.shared->rpc_count[uwsgi.mywid];
|
||||
urpc = &uwsgi.rpc_table[pos];
|
||||
uwsgi.shared->rpc_count[uwsgi.mywid]++;
|
||||
already:
|
||||
memcpy(urpc->name, name, strlen(name));
|
||||
urpc->modifier1 = modifier1;
|
||||
urpc->plugin = plugin;
|
||||
urpc->args = args;
|
||||
urpc->func = func;
|
||||
|
||||
uwsgi.shared->rpc_count++;
|
||||
urpc->shared = uwsgi.mywid == 0 ? 1 : 0;
|
||||
|
||||
ret = 0;
|
||||
uwsgi_log("registered RPC function %s\n", name);
|
||||
if (uwsgi.mywid == 0) {
|
||||
uwsgi_log("registered shared/inherited RPC function \"%s\"\n", name);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("registered RPC function \"%s\" on worker %d\n", name, uwsgi.mywid);
|
||||
}
|
||||
}
|
||||
|
||||
// implement cow
|
||||
if (uwsgi.mywid == 0) {
|
||||
int i;
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
uwsgi.shared->rpc_count[i] = uwsgi.shared->rpc_count[0];
|
||||
int pos = (i * uwsgi.rpc_max);
|
||||
memcpy(&uwsgi.rpc_table[pos], uwsgi.rpc_table, sizeof(struct uwsgi_rpc) * uwsgi.rpc_max);
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_unlock(uwsgi.rpc_table_lock);
|
||||
@@ -36,21 +62,23 @@ int uwsgi_register_rpc(char *name, uint8_t modifier1, uint8_t args, void *func)
|
||||
uint16_t uwsgi_rpc(char *name, uint8_t argc, char *argv[], uint16_t argvs[], char *output) {
|
||||
|
||||
struct uwsgi_rpc *urpc = NULL;
|
||||
int i;
|
||||
uint64_t i;
|
||||
uint16_t ret = 0;
|
||||
|
||||
for(i=0;i<uwsgi.shared->rpc_count;i++) {
|
||||
if (uwsgi.shared->rpc_table[i].name[0] != 0) {
|
||||
if (!strcmp(uwsgi.shared->rpc_table[i].name, name)) {
|
||||
urpc = &uwsgi.shared->rpc_table[i];
|
||||
int pos = (uwsgi.mywid * uwsgi.rpc_max);
|
||||
|
||||
for (i = 0; i < uwsgi.shared->rpc_count[uwsgi.mywid]; i++) {
|
||||
if (uwsgi.rpc_table[pos + i].name[0] != 0) {
|
||||
if (!strcmp(uwsgi.rpc_table[pos + i].name, name)) {
|
||||
urpc = &uwsgi.rpc_table[pos + i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (urpc) {
|
||||
if (uwsgi.p[urpc->modifier1]->rpc) {
|
||||
ret = uwsgi.p[urpc->modifier1]->rpc(urpc->func, argc, argv, argvs, output);
|
||||
if (urpc->plugin->rpc) {
|
||||
ret = urpc->plugin->rpc(urpc->func, argc, argv, argvs, output);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,85 +86,94 @@ uint16_t uwsgi_rpc(char *name, uint8_t argc, char *argv[], uint16_t argvs[], cha
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t argvs[], uint16_t *len) {
|
||||
char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t argvs[], uint16_t * len) {
|
||||
|
||||
uint8_t i;
|
||||
uint16_t ulen;
|
||||
struct uwsgi_header uh;
|
||||
struct uwsgi_header *uh = NULL;
|
||||
char *buffer = NULL;
|
||||
|
||||
|
||||
*len = 0;
|
||||
|
||||
if (node == NULL || !strcmp(node, "")) {
|
||||
if (node == NULL || !strcmp(node, "")) {
|
||||
// allocate the whole buffer
|
||||
buffer = uwsgi_malloc(65536);
|
||||
*len = uwsgi_rpc(func, argc, argv, argvs, buffer);
|
||||
buffer = uwsgi_malloc(UMAX16);
|
||||
*len = uwsgi_rpc(func, argc, argv, argvs, buffer);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// connect to node
|
||||
int fd = uwsgi_connect(node, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], 0);
|
||||
// connect to node (async way)
|
||||
int fd = uwsgi_connect(node, 0, 1);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
if (fd < 0) return NULL;
|
||||
// wait for connection;
|
||||
int ret = uwsgi.wait_write_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (ret <= 0) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// prepare a uwsgi array
|
||||
// prepare a uwsgi array
|
||||
uint16_t buffer_size = 2 + strlen(func);
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
buffer_size += 2 + argvs[i];
|
||||
}
|
||||
for (i = 0; i < argc; i++) {
|
||||
buffer_size += 2 + argvs[i];
|
||||
}
|
||||
|
||||
// allocate the whole buffer
|
||||
buffer = uwsgi_malloc(65536);
|
||||
buffer = uwsgi_malloc(4+buffer_size);
|
||||
|
||||
uh.modifier1 = 173;
|
||||
uh.pktsize = buffer_size;
|
||||
uh.modifier2 = 0;
|
||||
// set the uwsgi header
|
||||
uh = (struct uwsgi_header *) buffer;
|
||||
uh->modifier1 = 173;
|
||||
uh->pktsize = buffer_size;
|
||||
uh->modifier2 = 0;
|
||||
|
||||
// add func to the array
|
||||
char *bufptr = buffer;
|
||||
ulen = strlen(func);
|
||||
*bufptr++ = (uint8_t) (ulen & 0xff);
|
||||
*bufptr++ = (uint8_t) ((ulen >> 8) & 0xff);
|
||||
memcpy(bufptr, func, ulen);
|
||||
bufptr += ulen;
|
||||
char *bufptr = buffer + 4;
|
||||
ulen = strlen(func);
|
||||
*bufptr++ = (uint8_t) (ulen & 0xff);
|
||||
*bufptr++ = (uint8_t) ((ulen >> 8) & 0xff);
|
||||
memcpy(bufptr, func, ulen);
|
||||
bufptr += ulen;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
ulen = argvs[i];
|
||||
*bufptr++ = (uint8_t) (ulen & 0xff);
|
||||
*bufptr++ = (uint8_t) ((ulen >> 8) & 0xff);
|
||||
memcpy(bufptr, argv[i], ulen);
|
||||
bufptr += ulen;
|
||||
}
|
||||
for (i = 0; i < argc; i++) {
|
||||
ulen = argvs[i];
|
||||
*bufptr++ = (uint8_t) (ulen & 0xff);
|
||||
*bufptr++ = (uint8_t) ((ulen >> 8) & 0xff);
|
||||
memcpy(bufptr, argv[i], ulen);
|
||||
bufptr += ulen;
|
||||
}
|
||||
|
||||
if (write(fd, &uh, 4) != 4) {
|
||||
uwsgi_error("write()");
|
||||
close(fd);
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
// ok the reuqest is ready, let's send it in non blocking way
|
||||
if (uwsgi_write_true_nb(fd, buffer, buffer_size+4, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (write(fd, buffer, buffer_size) != buffer_size) {
|
||||
uwsgi_error("write()");
|
||||
close(fd);
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (uwsgi_read_response(fd, &uh, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], &buffer) < 0) {
|
||||
close(fd);
|
||||
free(buffer);
|
||||
return NULL;
|
||||
// ok time to wait for the response in non blocking way
|
||||
size_t rlen = buffer_size+4;
|
||||
if (uwsgi_read_with_realloc(fd, &buffer, &rlen, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
*len = uh.pktsize;
|
||||
*len = rlen;
|
||||
if (*len == 0) {
|
||||
free(buffer);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
return buffer;
|
||||
|
||||
error:
|
||||
close(fd);
|
||||
free(buffer);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_rpc_init() {
|
||||
uwsgi.rpc_table = uwsgi_calloc_shared((sizeof(struct uwsgi_rpc) * uwsgi.rpc_max) * (uwsgi.numproc+1));
|
||||
uwsgi.shared->rpc_count = uwsgi_calloc_shared(sizeof(uint64_t) * (uwsgi.numproc+1));
|
||||
}
|
||||
|
||||
+24
-162
@@ -1,177 +1,39 @@
|
||||
#ifdef UWSGI_SENDFILE
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
ssize_t uwsgi_sendfile(struct wsgi_request *wsgi_req) {
|
||||
|
||||
int fd = wsgi_req->sendfile_fd;
|
||||
int sockfd = wsgi_req->poll.fd;
|
||||
struct stat stat_buf;
|
||||
ssize_t sst = 0;
|
||||
|
||||
if (!wsgi_req->sendfile_fd_size) {
|
||||
|
||||
if (fstat(fd, &stat_buf)) {
|
||||
uwsgi_error("fstat()");
|
||||
goto end;
|
||||
}
|
||||
else {
|
||||
wsgi_req->sendfile_fd_size = stat_buf.st_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (wsgi_req->sendfile_fd_size) {
|
||||
|
||||
if (!wsgi_req->sendfile_fd_chunk) wsgi_req->sendfile_fd_chunk = 4096;
|
||||
|
||||
if (wsgi_req->socket->proto_sendfile) {
|
||||
sst = wsgi_req->socket->proto_sendfile(wsgi_req);
|
||||
}
|
||||
else {
|
||||
sst = uwsgi_do_sendfile(sockfd, wsgi_req->sendfile_fd, wsgi_req->sendfile_fd_size, wsgi_req->sendfile_fd_chunk, &wsgi_req->sendfile_fd_pos, uwsgi.async);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
end:
|
||||
return sst;
|
||||
}
|
||||
|
||||
ssize_t uwsgi_do_sendfile(int sockfd, int filefd, size_t filesize, size_t chunk, off_t *pos, int async) {
|
||||
// sendfile() abstraction
|
||||
ssize_t uwsgi_sendfile_do(int sockfd, int filefd, size_t pos, size_t len) {
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
|
||||
int sf_ret;
|
||||
|
||||
off_t sf_len = filesize;
|
||||
|
||||
if (async > 1) {
|
||||
sf_len = chunk;
|
||||
sf_ret = sendfile(filefd, sockfd, *pos, 0, NULL, &sf_len, 0);
|
||||
*pos += sf_len;
|
||||
}
|
||||
else {
|
||||
sf_ret = sendfile(filefd, sockfd, 0, 0, NULL, &sf_len, 0);
|
||||
}
|
||||
|
||||
if (sf_ret < 0) {
|
||||
if (errno != EAGAIN) {
|
||||
uwsgi_error("sendfile()");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return sf_len;
|
||||
off_t sf_len = len;
|
||||
int sf_ret = sendfile(filefd, sockfd, pos, len, NULL, &sf_len, 0);
|
||||
if (sf_ret == 0 || (sf_ret == -1 && errno == EAGAIN)) return sf_len;
|
||||
return -1;
|
||||
#elif defined(__APPLE__)
|
||||
int sf_ret;
|
||||
off_t sf_len = filesize;
|
||||
|
||||
if (async > 1) {
|
||||
sf_len = chunk;
|
||||
sf_ret = sendfile(filefd, sockfd, *pos, &sf_len, NULL, 0);
|
||||
*pos += sf_len;
|
||||
}
|
||||
else {
|
||||
sf_ret = sendfile(filefd, sockfd, 0, &sf_len, NULL, 0);
|
||||
}
|
||||
|
||||
if (sf_ret) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("sf_len = %d\n", sf_len);
|
||||
#endif
|
||||
uwsgi_error("sendfile()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sf_len;
|
||||
|
||||
off_t sf_len = len;
|
||||
int sf_ret = sendfile(filefd, sockfd, pos, &sf_len, NULL, 0);
|
||||
if (sf_ret == 0 || (sf_ret == -1 && errno == EAGAIN)) return sf_len;
|
||||
return -1;
|
||||
#elif defined(__linux__) || defined(__sun__)
|
||||
int sf_ret;
|
||||
size_t written = 0;
|
||||
|
||||
if (async > 1) {
|
||||
sf_ret = sendfile(sockfd, filefd, pos, chunk);
|
||||
if (sf_ret < 0) {
|
||||
uwsgi_error("sendfile()");
|
||||
return 0;
|
||||
}
|
||||
return sf_ret;
|
||||
}
|
||||
|
||||
while(written < filesize) {
|
||||
sf_ret = sendfile(sockfd, filefd, pos, filesize-written);
|
||||
if (sf_ret < 0) {
|
||||
uwsgi_error("sendfile()");
|
||||
return 0;
|
||||
}
|
||||
else if (sf_ret == 0) {
|
||||
return 0;
|
||||
}
|
||||
written+= sf_ret;
|
||||
}
|
||||
return written;
|
||||
|
||||
off_t off = pos;
|
||||
return sendfile(sockfd, filefd, &off, len);
|
||||
#else
|
||||
static size_t nosf_buf_size = 0;
|
||||
static char *nosf_buf;
|
||||
char *nosf_buf2;
|
||||
|
||||
ssize_t jlen = 0;
|
||||
ssize_t rlen = 0;
|
||||
ssize_t i = 0;
|
||||
|
||||
if (!nosf_buf) {
|
||||
nosf_buf = malloc(chunk);
|
||||
}
|
||||
else if (chunk != nosf_buf_size) {
|
||||
nosf_buf2 = realloc(nosf_buf, chunk);
|
||||
if (!nosf_buf2) {
|
||||
free(nosf_buf);
|
||||
// for platform not supporting sendfile we need to rely on boring read/write
|
||||
// generally that platforms have very low memory, so use a 8k buffer
|
||||
char buf[8192];
|
||||
if (pos > 0) {
|
||||
if (lseek(filefd, pos, SEEK_SET)) {
|
||||
uwsgi_error("uwsgi_sendfile_do()/seek()");
|
||||
return -1;
|
||||
}
|
||||
nosf_buf = nosf_buf2;
|
||||
}
|
||||
|
||||
if (!nosf_buf) {
|
||||
uwsgi_error("sendfile malloc()/realloc()");
|
||||
return 0;
|
||||
ssize_t rlen = read(filefd, buf, UMIN(len, 8192));
|
||||
if (rlen <= 0) {
|
||||
uwsgi_error("uwsgi_sendfile_do()/read()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
nosf_buf_size = chunk;
|
||||
|
||||
if (async > 1) {
|
||||
jlen = read(filefd, nosf_buf, chunk);
|
||||
if (jlen <= 0) {
|
||||
uwsgi_error("read()");
|
||||
return 0;
|
||||
}
|
||||
jlen = write(sockfd, nosf_buf, jlen);
|
||||
if (jlen <= 0) {
|
||||
uwsgi_error("write()");
|
||||
return 0;
|
||||
}
|
||||
return jlen;
|
||||
}
|
||||
|
||||
while (i < (int) filesize) {
|
||||
jlen = read(filefd, nosf_buf, chunk);
|
||||
if (jlen <= 0) {
|
||||
uwsgi_error("read()");
|
||||
break;
|
||||
}
|
||||
i += jlen;
|
||||
jlen = write(sockfd, nosf_buf, jlen);
|
||||
if (jlen <= 0) {
|
||||
uwsgi_error("write()");
|
||||
break;
|
||||
}
|
||||
rlen += jlen;
|
||||
}
|
||||
|
||||
return rlen;
|
||||
return write(sockfd, buf, rlen);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+14
-8
@@ -106,13 +106,14 @@ void uwsgi_setup_inherited_sockets() {
|
||||
//now close all the unbound fd
|
||||
for (j = 3; j < (int) uwsgi.max_fd; j++) {
|
||||
int useless = 1;
|
||||
#ifdef UWSGI_MULTICAST
|
||||
if (j == uwsgi.cluster_fd)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
if (uwsgi_fd_is_safe(j)) continue;
|
||||
|
||||
if (uwsgi.has_emperor) {
|
||||
if (j == uwsgi.emperor_fd)
|
||||
continue;
|
||||
if (j == uwsgi.emperor_fd_config)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uwsgi.shared->worker_log_pipe[0] > -1) {
|
||||
@@ -125,13 +126,18 @@ void uwsgi_setup_inherited_sockets() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uwsgi.original_log_fd > -1) {
|
||||
if (j == uwsgi.original_log_fd)
|
||||
if (uwsgi.shared->worker_req_log_pipe[0] > -1) {
|
||||
if (j == uwsgi.shared->worker_req_log_pipe[0])
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uwsgi.cache_server && uwsgi.cache_server_fd != -1) {
|
||||
if (j == uwsgi.cache_server_fd)
|
||||
if (uwsgi.shared->worker_req_log_pipe[1] > -1) {
|
||||
if (j == uwsgi.shared->worker_req_log_pipe[1])
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uwsgi.original_log_fd > -1) {
|
||||
if (j == uwsgi.original_log_fd)
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
+185
-294
@@ -4,13 +4,18 @@ extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_signal_handler(uint8_t sig) {
|
||||
|
||||
struct uwsgi_signal_entry *use = NULL;
|
||||
struct uwsgi_signal_entry *use = NULL;
|
||||
|
||||
use = &uwsgi.shared->signal_table[sig];
|
||||
int pos = (uwsgi.mywid * 256) + sig;
|
||||
|
||||
use = &uwsgi.shared->signal_table[pos];
|
||||
|
||||
if (!use->handler)
|
||||
return -1;
|
||||
|
||||
if (!uwsgi.p[use->modifier1]->signal_handler) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// check for COW
|
||||
if (uwsgi.master_process) {
|
||||
@@ -34,60 +39,57 @@ int uwsgi_signal_handler(uint8_t sig) {
|
||||
}
|
||||
}
|
||||
|
||||
// set harakiri here (if required and if i am a worker)
|
||||
|
||||
// set harakiri here (if required and if i am a worker)
|
||||
|
||||
if (uwsgi.mywid > 0) {
|
||||
uwsgi.workers[uwsgi.mywid].sig = 1;
|
||||
uwsgi.workers[uwsgi.mywid].signum = sig;
|
||||
uwsgi.workers[uwsgi.mywid].sig = 1;
|
||||
uwsgi.workers[uwsgi.mywid].signum = sig;
|
||||
uwsgi.workers[uwsgi.mywid].signals++;
|
||||
if(uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
|
||||
set_harakiri(uwsgi.shared->options[UWSGI_OPTION_HARAKIRI]);
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
|
||||
set_harakiri(uwsgi.shared->options[UWSGI_OPTION_HARAKIRI]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (uwsgi.muleid > 0) {
|
||||
uwsgi.mules[uwsgi.muleid-1].sig = 1;
|
||||
uwsgi.mules[uwsgi.muleid-1].signum = sig;
|
||||
uwsgi.mules[uwsgi.muleid-1].signals++;
|
||||
if(uwsgi.shared->options[UWSGI_OPTION_MULE_HARAKIRI] > 0) {
|
||||
set_mule_harakiri(uwsgi.shared->options[UWSGI_OPTION_MULE_HARAKIRI]);
|
||||
uwsgi.mules[uwsgi.muleid - 1].sig = 1;
|
||||
uwsgi.mules[uwsgi.muleid - 1].signum = sig;
|
||||
uwsgi.mules[uwsgi.muleid - 1].signals++;
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_MULE_HARAKIRI] > 0) {
|
||||
set_mule_harakiri(uwsgi.shared->options[UWSGI_OPTION_MULE_HARAKIRI]);
|
||||
}
|
||||
}
|
||||
else if (uwsgi.i_am_a_spooler && (getpid() == uwsgi.i_am_a_spooler->pid)) {
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
|
||||
set_spooler_harakiri(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI]);
|
||||
}
|
||||
}
|
||||
#ifdef UWSGI_SPOOLER
|
||||
else if (uwsgi.i_am_a_spooler && (getpid() == uwsgi.i_am_a_spooler->pid)) {
|
||||
if(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
|
||||
set_spooler_harakiri(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int ret = uwsgi.p[use->modifier1]->signal_handler(sig, use->handler);
|
||||
|
||||
if (uwsgi.mywid > 0) {
|
||||
uwsgi.workers[uwsgi.mywid].sig = 0;
|
||||
if(uwsgi.workers[uwsgi.mywid].harakiri > 0) {
|
||||
set_harakiri(0);
|
||||
uwsgi.workers[uwsgi.mywid].sig = 0;
|
||||
if (uwsgi.workers[uwsgi.mywid].harakiri > 0) {
|
||||
set_harakiri(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (uwsgi.muleid > 0) {
|
||||
uwsgi.mules[uwsgi.muleid-1].sig = 0;
|
||||
if(uwsgi.mules[uwsgi.muleid-1].harakiri > 0) {
|
||||
set_mule_harakiri(0);
|
||||
uwsgi.mules[uwsgi.muleid - 1].sig = 0;
|
||||
if (uwsgi.mules[uwsgi.muleid - 1].harakiri > 0) {
|
||||
set_mule_harakiri(0);
|
||||
}
|
||||
}
|
||||
#ifdef UWSGI_SPOOLER
|
||||
}
|
||||
else if (uwsgi.i_am_a_spooler && (getpid() == uwsgi.i_am_a_spooler->pid)) {
|
||||
if(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
|
||||
set_spooler_harakiri(0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
|
||||
set_spooler_harakiri(0);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int uwsgi_signal_registered(uint8_t sig) {
|
||||
|
||||
if (uwsgi.shared->signal_table[sig].handler != NULL)
|
||||
int pos = (uwsgi.mywid * 256) + sig;
|
||||
if (uwsgi.shared->signal_table[pos].handler != NULL)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@@ -97,19 +99,28 @@ int uwsgi_register_signal(uint8_t sig, char *receiver, void *handler, uint8_t mo
|
||||
|
||||
struct uwsgi_signal_entry *use = NULL;
|
||||
|
||||
if (strlen(receiver) > 63) return -1;
|
||||
if (!uwsgi.master_process) return -1;
|
||||
|
||||
if (uwsgi.mywid == 0 && uwsgi.workers[0].pid != uwsgi.mypid) {
|
||||
uwsgi_log("only the master and the workers can register signal handlers\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strlen(receiver) > 63)
|
||||
return -1;
|
||||
|
||||
uwsgi_lock(uwsgi.signal_table_lock);
|
||||
|
||||
use = &uwsgi.shared->signal_table[sig];
|
||||
int pos = (uwsgi.mywid * 256) + sig;
|
||||
use = &uwsgi.shared->signal_table[pos];
|
||||
|
||||
if (use->handler) {
|
||||
uwsgi_log("[uwsgi-signal] you cannot re-register a signal !!!\n");
|
||||
if (use->handler && uwsgi.mywid == 0) {
|
||||
uwsgi_log("[uwsgi-signal] you cannot re-register a signal as the master !!!\n");
|
||||
uwsgi_unlock(uwsgi.signal_table_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(use->receiver, receiver, strlen(receiver)+1);
|
||||
strncpy(use->receiver, receiver, strlen(receiver) + 1);
|
||||
use->handler = handler;
|
||||
use->modifier1 = modifier1;
|
||||
use->wid = uwsgi.mywid;
|
||||
@@ -121,6 +132,15 @@ int uwsgi_register_signal(uint8_t sig, char *receiver, void *handler, uint8_t mo
|
||||
uwsgi_log("[uwsgi-signal] signum %d registered (wid: %d modifier1: %d target: %s)\n", sig, uwsgi.mywid, modifier1, receiver);
|
||||
}
|
||||
|
||||
// check for cow
|
||||
if (uwsgi.mywid == 0) {
|
||||
int i;
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
int pos = (i * 256);
|
||||
memcpy(&uwsgi.shared->signal_table[pos], &uwsgi.shared->signal_table[0], sizeof(struct uwsgi_signal_entry) * 256);
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_unlock(uwsgi.signal_table_lock);
|
||||
|
||||
return 0;
|
||||
@@ -129,7 +149,7 @@ int uwsgi_register_signal(uint8_t sig, char *receiver, void *handler, uint8_t mo
|
||||
|
||||
int uwsgi_add_file_monitor(uint8_t sig, char *filename) {
|
||||
|
||||
if (strlen(filename) > (0xff-1)) {
|
||||
if (strlen(filename) > (0xff - 1)) {
|
||||
uwsgi_log("uwsgi_add_file_monitor: invalid filename length\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -140,9 +160,9 @@ int uwsgi_add_file_monitor(uint8_t sig, char *filename) {
|
||||
|
||||
// fill the fmon table, the master will use it to add items to the event queue
|
||||
memcpy(ushared->files_monitored[ushared->files_monitored_cnt].filename, filename, strlen(filename));
|
||||
ushared->files_monitored[ushared->files_monitored_cnt].registered = 0;
|
||||
ushared->files_monitored[ushared->files_monitored_cnt].registered = 0;
|
||||
ushared->files_monitored[ushared->files_monitored_cnt].sig = sig;
|
||||
|
||||
|
||||
ushared->files_monitored_cnt++;
|
||||
}
|
||||
else {
|
||||
@@ -157,89 +177,10 @@ int uwsgi_add_file_monitor(uint8_t sig, char *filename) {
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_probe *uwsgi_probe_register(struct uwsgi_probe **up, char *name, int (*func)(int, struct uwsgi_signal_probe *)) {
|
||||
|
||||
struct uwsgi_probe *uwsgi_up = *up, *old_up;
|
||||
|
||||
if (!uwsgi_up) {
|
||||
*up = uwsgi_malloc(sizeof(struct uwsgi_probe));
|
||||
uwsgi_up = *up;
|
||||
}
|
||||
else {
|
||||
while(uwsgi_up) {
|
||||
old_up = uwsgi_up;
|
||||
uwsgi_up = uwsgi_up->next;
|
||||
}
|
||||
|
||||
uwsgi_up = uwsgi_malloc(sizeof(struct uwsgi_probe));
|
||||
old_up->next = uwsgi_up;
|
||||
}
|
||||
|
||||
uwsgi_up->name = name;
|
||||
uwsgi_up->func = func;
|
||||
uwsgi_up->next = NULL;
|
||||
|
||||
uwsgi_log("registered new probe \"%s\" at %p\n", name, uwsgi_up);
|
||||
|
||||
return uwsgi_up;
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_add_probe(uint8_t sig, char *kind, char *args, int timeout, int freq) {
|
||||
|
||||
uwsgi_lock(uwsgi.probe_table_lock);
|
||||
|
||||
if (ushared->probes_cnt < MAX_PROBES) {
|
||||
|
||||
struct uwsgi_probe *up = uwsgi.probes;
|
||||
while(up) {
|
||||
if (!strcmp(up->name, kind)) {
|
||||
break;
|
||||
}
|
||||
up = up->next;
|
||||
}
|
||||
|
||||
if (!up) {
|
||||
uwsgi_log("unable to find probe \"%s\" !!!\n", kind);
|
||||
uwsgi_unlock(uwsgi.probe_table_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// fill the probe table
|
||||
ushared->probes[ushared->probes_cnt].func = up->func;
|
||||
strncpy(ushared->probes[ushared->probes_cnt].args, args, 1024-1);
|
||||
ushared->probes[ushared->probes_cnt].registered = 0;
|
||||
ushared->probes[ushared->probes_cnt].sig = sig;
|
||||
ushared->probes[ushared->probes_cnt].fd = -1;
|
||||
ushared->probes[ushared->probes_cnt].state = 0;
|
||||
ushared->probes[ushared->probes_cnt].last_event = 0;
|
||||
ushared->probes[ushared->probes_cnt].data = NULL;
|
||||
ushared->probes[ushared->probes_cnt].cycles = 0;
|
||||
ushared->probes[ushared->probes_cnt].bad = 0;
|
||||
|
||||
if (!timeout) {
|
||||
timeout = uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT];
|
||||
}
|
||||
ushared->probes[ushared->probes_cnt].timeout = timeout;
|
||||
if (!freq) {
|
||||
freq = 1;
|
||||
}
|
||||
ushared->probes[ushared->probes_cnt].freq = freq;
|
||||
ushared->probes_cnt++;
|
||||
}
|
||||
else {
|
||||
uwsgi_log("you can register max %d probes !!!\n", MAX_PROBES);
|
||||
uwsgi_unlock(uwsgi.probe_table_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_unlock(uwsgi.probe_table_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_add_timer(uint8_t sig, int secs) {
|
||||
|
||||
if (!uwsgi.master_process) return -1;
|
||||
|
||||
uwsgi_lock(uwsgi.timer_table_lock);
|
||||
|
||||
if (ushared->timers_cnt < 64) {
|
||||
@@ -262,112 +203,57 @@ int uwsgi_add_timer(uint8_t sig, int secs) {
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_opt_add_cron(char *opt, char *value, void *foobar) {
|
||||
|
||||
int i;
|
||||
|
||||
struct uwsgi_cron *old_uc, *uc = uwsgi.crons;
|
||||
if (!uc) {
|
||||
uc = uwsgi_malloc(sizeof(struct uwsgi_cron));
|
||||
uwsgi.crons = uc;
|
||||
}
|
||||
else {
|
||||
old_uc = uc;
|
||||
while(uc->next) {
|
||||
uc = uc->next;
|
||||
old_uc = uc;
|
||||
}
|
||||
|
||||
old_uc->next = uwsgi_malloc(sizeof(struct uwsgi_cron));
|
||||
uc = old_uc->next;
|
||||
}
|
||||
|
||||
memset(uc, 0, sizeof(struct uwsgi_cron));
|
||||
|
||||
if (sscanf(value, "%d %d %d %d %d %n", &uc->minute, &uc->hour, &uc->day, &uc->month, &uc->week, &i) != 5) {
|
||||
uwsgi_log("invalid cron syntax\n");
|
||||
exit(1);
|
||||
}
|
||||
uc->command = value+i;
|
||||
}
|
||||
|
||||
int uwsgi_signal_add_cron(uint8_t sig, int minute, int hour, int day, int month, int week) {
|
||||
|
||||
if (!uwsgi.master_process) return -1;
|
||||
|
||||
uwsgi_lock(uwsgi.cron_table_lock);
|
||||
|
||||
if (ushared->cron_cnt < MAX_CRONS) {
|
||||
|
||||
ushared->cron[ushared->cron_cnt].sig = sig;
|
||||
ushared->cron[ushared->cron_cnt].minute = minute;
|
||||
ushared->cron[ushared->cron_cnt].hour = hour;
|
||||
ushared->cron[ushared->cron_cnt].day = day;
|
||||
ushared->cron[ushared->cron_cnt].month = month;
|
||||
ushared->cron[ushared->cron_cnt].week = week;
|
||||
ushared->cron_cnt++;
|
||||
}
|
||||
else {
|
||||
uwsgi_log("you can register max %d cron !!!\n", MAX_CRONS);
|
||||
uwsgi_unlock(uwsgi.cron_table_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_unlock(uwsgi.cron_table_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_signal_add_rb_timer(uint8_t sig, int secs, int iterations) {
|
||||
|
||||
if (!uwsgi.master_process) return -1;
|
||||
if (!uwsgi.master_process)
|
||||
return -1;
|
||||
|
||||
uwsgi_lock(uwsgi.rb_timer_table_lock);
|
||||
uwsgi_lock(uwsgi.rb_timer_table_lock);
|
||||
|
||||
if (ushared->rb_timers_cnt < 64) {
|
||||
if (ushared->rb_timers_cnt < 64) {
|
||||
|
||||
// fill the timer table, the master will use it to add items to the event queue
|
||||
ushared->rb_timers[ushared->rb_timers_cnt].value = secs;
|
||||
ushared->rb_timers[ushared->rb_timers_cnt].registered = 0;
|
||||
ushared->rb_timers[ushared->rb_timers_cnt].iterations = iterations;
|
||||
ushared->rb_timers[ushared->rb_timers_cnt].iterations_done = 0;
|
||||
ushared->rb_timers[ushared->rb_timers_cnt].sig = sig;
|
||||
ushared->rb_timers_cnt++;
|
||||
}
|
||||
else {
|
||||
uwsgi_log("you can register max 64 rb_timers !!!\n");
|
||||
uwsgi_unlock(uwsgi.rb_timer_table_lock);
|
||||
return -1;
|
||||
}
|
||||
// fill the timer table, the master will use it to add items to the event queue
|
||||
ushared->rb_timers[ushared->rb_timers_cnt].value = secs;
|
||||
ushared->rb_timers[ushared->rb_timers_cnt].registered = 0;
|
||||
ushared->rb_timers[ushared->rb_timers_cnt].iterations = iterations;
|
||||
ushared->rb_timers[ushared->rb_timers_cnt].iterations_done = 0;
|
||||
ushared->rb_timers[ushared->rb_timers_cnt].sig = sig;
|
||||
ushared->rb_timers_cnt++;
|
||||
}
|
||||
else {
|
||||
uwsgi_log("you can register max 64 rb_timers !!!\n");
|
||||
uwsgi_unlock(uwsgi.rb_timer_table_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_unlock(uwsgi.rb_timer_table_lock);
|
||||
uwsgi_unlock(uwsgi.rb_timer_table_lock);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void create_signal_pipe(int *sigpipe) {
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sigpipe)) {
|
||||
uwsgi_error("socketpair()\n");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_socket_nb(sigpipe[0]);
|
||||
uwsgi_socket_nb(sigpipe[1]);
|
||||
uwsgi_error("socketpair()\n");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_socket_nb(sigpipe[0]);
|
||||
uwsgi_socket_nb(sigpipe[1]);
|
||||
|
||||
if (uwsgi.signal_bufsize) {
|
||||
if (setsockopt(sigpipe[0], SOL_SOCKET, SO_SNDBUF, &uwsgi.signal_bufsize, sizeof(int))) {
|
||||
uwsgi_error("setsockopt()");
|
||||
if (setsockopt(sigpipe[0], SOL_SOCKET, SO_SNDBUF, &uwsgi.signal_bufsize, sizeof(int))) {
|
||||
uwsgi_error("setsockopt()");
|
||||
}
|
||||
if (setsockopt(sigpipe[0], SOL_SOCKET, SO_RCVBUF, &uwsgi.signal_bufsize, sizeof(int))) {
|
||||
uwsgi_error("setsockopt()");
|
||||
if (setsockopt(sigpipe[0], SOL_SOCKET, SO_RCVBUF, &uwsgi.signal_bufsize, sizeof(int))) {
|
||||
uwsgi_error("setsockopt()");
|
||||
}
|
||||
|
||||
if (setsockopt(sigpipe[1], SOL_SOCKET, SO_SNDBUF, &uwsgi.signal_bufsize, sizeof(int))) {
|
||||
uwsgi_error("setsockopt()");
|
||||
if (setsockopt(sigpipe[1], SOL_SOCKET, SO_SNDBUF, &uwsgi.signal_bufsize, sizeof(int))) {
|
||||
uwsgi_error("setsockopt()");
|
||||
}
|
||||
if (setsockopt(sigpipe[1], SOL_SOCKET, SO_RCVBUF, &uwsgi.signal_bufsize, sizeof(int))) {
|
||||
uwsgi_error("setsockopt()");
|
||||
if (setsockopt(sigpipe[1], SOL_SOCKET, SO_RCVBUF, &uwsgi.signal_bufsize, sizeof(int))) {
|
||||
uwsgi_error("setsockopt()");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -379,9 +265,10 @@ int uwsgi_remote_signal_send(char *addr, uint8_t sig) {
|
||||
uh.modifier1 = 110;
|
||||
uh.pktsize = 0;
|
||||
uh.modifier2 = sig;
|
||||
|
||||
|
||||
int fd = uwsgi_connect(addr, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], 0);
|
||||
if (fd < 0) return -1;
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
if (write(fd, (char *) &uh, 4) != 4) {
|
||||
uwsgi_error("uwsgi_remote_signal_send()");
|
||||
@@ -403,23 +290,24 @@ int uwsgi_signal_send(int fd, uint8_t sig) {
|
||||
|
||||
if (write(fd, &sig, 1) != 1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &so_bufsize, &so_bufsize_len)) {
|
||||
uwsgi_error("getsockopt()");
|
||||
}
|
||||
uwsgi_log("*** SIGNAL QUEUE IS FULL: buffer size %d bytes (you can tune it with --signal-bufsize) ***\n", so_bufsize);
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &so_bufsize, &so_bufsize_len)) {
|
||||
uwsgi_error("getsockopt()");
|
||||
}
|
||||
uwsgi_log("*** SIGNAL QUEUE IS FULL: buffer size %d bytes (you can tune it with --signal-bufsize) ***\n", so_bufsize);
|
||||
}
|
||||
else {
|
||||
uwsgi_error("uwsgi_signal_send()");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_route_signal(uint8_t sig) {
|
||||
|
||||
struct uwsgi_signal_entry *use = &ushared->signal_table[sig];
|
||||
int pos = (uwsgi.mywid * 256) + sig;
|
||||
struct uwsgi_signal_entry *use = &ushared->signal_table[pos];
|
||||
int i;
|
||||
|
||||
// send to first available worker
|
||||
@@ -430,7 +318,7 @@ void uwsgi_route_signal(uint8_t sig) {
|
||||
}
|
||||
// send to all workers
|
||||
else if (!strcmp(use->receiver, "workers")) {
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
if (uwsgi_signal_send(uwsgi.workers[i].signal_pipe[0], sig)) {
|
||||
uwsgi_log("could not deliver signal %d to worker %d\n", sig, i);
|
||||
}
|
||||
@@ -438,70 +326,68 @@ void uwsgi_route_signal(uint8_t sig) {
|
||||
}
|
||||
// route to specific worker
|
||||
else if (!strncmp(use->receiver, "worker", 6)) {
|
||||
i = atoi(use->receiver+6);
|
||||
i = atoi(use->receiver + 6);
|
||||
if (i > uwsgi.numproc) {
|
||||
uwsgi_log("invalid signal target: %s\n", use->receiver);
|
||||
}
|
||||
if (uwsgi_signal_send(uwsgi.workers[i].signal_pipe[0], sig)) {
|
||||
uwsgi_log("could not deliver signal %d to worker %d\n", sig, i);
|
||||
}
|
||||
uwsgi_log("could not deliver signal %d to worker %d\n", sig, i);
|
||||
}
|
||||
}
|
||||
// route to subscribed
|
||||
else if (!strcmp(use->receiver, "subscribed")) {
|
||||
}
|
||||
// route to spooler
|
||||
#ifdef UWSGI_SPOOLER
|
||||
else if (!strcmp(use->receiver, "spooler")) {
|
||||
if (ushared->worker_signal_pipe[0] != -1) {
|
||||
if (uwsgi_signal_send(ushared->spooler_signal_pipe[0], sig)) {
|
||||
uwsgi_log("could not deliver signal %d to the spooler\n", sig);
|
||||
}
|
||||
uwsgi_log("could not deliver signal %d to the spooler\n", sig);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (!strcmp(use->receiver, "mules")) {
|
||||
for(i=0;i<uwsgi.mules_cnt;i++) {
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
if (uwsgi_signal_send(uwsgi.mules[i].signal_pipe[0], sig)) {
|
||||
uwsgi_log("could not deliver signal %d to mule %d\n", sig, i+1);
|
||||
}
|
||||
uwsgi_log("could not deliver signal %d to mule %d\n", sig, i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strncmp(use->receiver, "mule", 4)) {
|
||||
i = atoi(use->receiver+4);
|
||||
i = atoi(use->receiver + 4);
|
||||
if (i > uwsgi.mules_cnt) {
|
||||
uwsgi_log("invalid signal target: %s\n", use->receiver);
|
||||
}
|
||||
else if (i == 0) {
|
||||
if (uwsgi_signal_send(ushared->mule_signal_pipe[0], sig)) {
|
||||
uwsgi_log("could not deliver signal %d to a mule\n", sig);
|
||||
}
|
||||
uwsgi_log("could not deliver signal %d to a mule\n", sig);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (uwsgi_signal_send(uwsgi.mules[i-1].signal_pipe[0], sig)) {
|
||||
uwsgi_log("could not deliver signal %d to mule %d\n", sig, i);
|
||||
}
|
||||
if (uwsgi_signal_send(uwsgi.mules[i - 1].signal_pipe[0], sig)) {
|
||||
uwsgi_log("could not deliver signal %d to mule %d\n", sig, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strncmp(use->receiver, "farm_", 5)) {
|
||||
char *name = use->receiver+5;
|
||||
char *name = use->receiver + 5;
|
||||
struct uwsgi_farm *uf = get_farm_by_name(name);
|
||||
if (!uf) {
|
||||
uwsgi_log("unknown farm: %s\n", name);
|
||||
return;
|
||||
}
|
||||
if (uwsgi_signal_send(uf->signal_pipe[0], sig)) {
|
||||
uwsgi_log("could not deliver signal %d to farm %d (%s)\n", sig, uf->id, uf->name);
|
||||
}
|
||||
uwsgi_log("could not deliver signal %d to farm %d (%s)\n", sig, uf->id, uf->name);
|
||||
}
|
||||
}
|
||||
else if (!strncmp(use->receiver, "farm", 4)) {
|
||||
i = atoi(use->receiver+4);
|
||||
i = atoi(use->receiver + 4);
|
||||
if (i > uwsgi.farms_cnt || i <= 0) {
|
||||
uwsgi_log("invalid signal target: %s\n", use->receiver);
|
||||
}
|
||||
else {
|
||||
if (uwsgi_signal_send(uwsgi.farms[i-1].signal_pipe[0], sig)) {
|
||||
uwsgi_log("could not deliver signal %d to farm %d (%s)\n", sig, i, uwsgi.farms[i-1].name);
|
||||
}
|
||||
if (uwsgi_signal_send(uwsgi.farms[i - 1].signal_pipe[0], sig)) {
|
||||
uwsgi_log("could not deliver signal %d to farm %d (%s)\n", sig, i, uwsgi.farms[i - 1].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -512,51 +398,56 @@ void uwsgi_route_signal(uint8_t sig) {
|
||||
|
||||
}
|
||||
|
||||
uint8_t uwsgi_signal_wait(int signum) {
|
||||
int uwsgi_signal_wait(int signum) {
|
||||
|
||||
int wait_for_specific_signal = 0;
|
||||
uint8_t uwsgi_signal = 0;
|
||||
uint8_t received_signal;
|
||||
int ret;
|
||||
struct pollfd pfd[2];
|
||||
int wait_for_specific_signal = 0;
|
||||
uint8_t uwsgi_signal = 0;
|
||||
int received_signal = -1;
|
||||
int ret;
|
||||
struct pollfd pfd[2];
|
||||
|
||||
if (signum > -1) {
|
||||
wait_for_specific_signal = 1;
|
||||
}
|
||||
wait_for_specific_signal = 1;
|
||||
}
|
||||
|
||||
pfd[0].fd = uwsgi.signal_socket;
|
||||
pfd[0].events = POLLIN;
|
||||
pfd[1].fd = uwsgi.my_signal_socket;
|
||||
pfd[1].events = POLLIN;
|
||||
|
||||
pfd[0].fd = uwsgi.signal_socket;
|
||||
pfd[0].events = POLLIN;
|
||||
pfd[1].fd = uwsgi.my_signal_socket;
|
||||
pfd[1].events = POLLIN;
|
||||
cycle:
|
||||
ret = poll(pfd, 2, -1);
|
||||
if (ret > 0) {
|
||||
if (pfd[0].revents == POLLIN) {
|
||||
if (read(uwsgi.signal_socket, &received_signal, 1) != 1) {
|
||||
uwsgi_error("read()");
|
||||
}
|
||||
else {
|
||||
(void)uwsgi_signal_handler(received_signal);
|
||||
if (wait_for_specific_signal) {
|
||||
if (received_signal != uwsgi_signal) goto cycle;
|
||||
}
|
||||
}
|
||||
ret = poll(pfd, 2, -1);
|
||||
if (ret > 0) {
|
||||
if (pfd[0].revents == POLLIN) {
|
||||
if (read(uwsgi.signal_socket, &uwsgi_signal, 1) != 1) {
|
||||
uwsgi_error("read()");
|
||||
}
|
||||
else {
|
||||
(void) uwsgi_signal_handler(uwsgi_signal);
|
||||
if (wait_for_specific_signal) {
|
||||
if (signum != uwsgi_signal)
|
||||
goto cycle;
|
||||
}
|
||||
received_signal = uwsgi_signal;
|
||||
}
|
||||
}
|
||||
if (pfd[1].revents == POLLIN) {
|
||||
if (read(uwsgi.my_signal_socket, &uwsgi_signal, 1) != 1) {
|
||||
uwsgi_error("read()");
|
||||
}
|
||||
else {
|
||||
(void) uwsgi_signal_handler(uwsgi_signal);
|
||||
if (wait_for_specific_signal) {
|
||||
if (signum != uwsgi_signal)
|
||||
goto cycle;
|
||||
}
|
||||
}
|
||||
received_signal = uwsgi_signal;
|
||||
}
|
||||
if (pfd[1].revents == POLLIN) {
|
||||
if (read(uwsgi.my_signal_socket, &received_signal, 1) != 1) {
|
||||
uwsgi_error("read()");
|
||||
}
|
||||
else {
|
||||
(void)uwsgi_signal_handler(received_signal);
|
||||
if (wait_for_specific_signal) {
|
||||
if (received_signal != uwsgi_signal) goto cycle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return received_signal;
|
||||
return received_signal;
|
||||
}
|
||||
|
||||
void uwsgi_receive_signal(int fd, char *name, int id) {
|
||||
@@ -565,27 +456,27 @@ void uwsgi_receive_signal(int fd, char *name, int id) {
|
||||
|
||||
ssize_t ret = read(fd, &uwsgi_signal, 1);
|
||||
|
||||
if (ret == 0) {
|
||||
if (ret == 0) {
|
||||
goto destroy;
|
||||
}
|
||||
else if (ret < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
uwsgi_error("[uwsgi-signal] read()");
|
||||
}
|
||||
else if (ret < 0 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
|
||||
uwsgi_error("[uwsgi-signal] read()");
|
||||
goto destroy;
|
||||
}
|
||||
else if (ret > 0) {
|
||||
}
|
||||
else if (ret > 0) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log_verbose("master sent signal %d to %s %d\n", uwsgi_signal, name, id);
|
||||
uwsgi_log_verbose("master sent signal %d to %s %d\n", uwsgi_signal, name, id);
|
||||
#endif
|
||||
if (uwsgi_signal_handler(uwsgi_signal)) {
|
||||
uwsgi_log_verbose("error managing signal %d on %s %d\n", uwsgi_signal, name, id);
|
||||
}
|
||||
}
|
||||
if (uwsgi_signal_handler(uwsgi_signal)) {
|
||||
uwsgi_log_verbose("error managing signal %d on %s %d\n", uwsgi_signal, name, id);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
destroy:
|
||||
// better to kill the whole worker...
|
||||
uwsgi_log_verbose("uWSGI %s %d screams: UAAAAAAH my master disconnected: i will kill myself !!!\n", name, id);
|
||||
uwsgi_log_verbose("uWSGI %s %d screams: UAAAAAAH my master disconnected: i will kill myself !!!\n", name, id);
|
||||
end_me(0);
|
||||
|
||||
}
|
||||
|
||||
+105
-93
@@ -1,6 +1,4 @@
|
||||
#ifdef UWSGI_SNMP
|
||||
|
||||
#include "uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
@@ -249,11 +247,14 @@ static uint64_t get_uwsgi_snmp_value(uint64_t val, uint8_t * oid_t) {
|
||||
static uint64_t get_uwsgi_custom_snmp_value(uint64_t val, uint8_t * oid_t) {
|
||||
|
||||
val--;
|
||||
uwsgi_wlock(uwsgi.snmp_lock);
|
||||
if (uwsgi.shared->snmp_value[val].type) {
|
||||
*oid_t = uwsgi.shared->snmp_value[val].type;
|
||||
uwsgi_rwunlock(uwsgi.snmp_lock);
|
||||
return uwsgi.shared->snmp_value[val].val;
|
||||
}
|
||||
|
||||
uwsgi_rwunlock(uwsgi.snmp_lock);
|
||||
*oid_t = SNMP_NULL;
|
||||
return 0;
|
||||
}
|
||||
@@ -278,133 +279,144 @@ static int get_snmp_integer(uint8_t * ptr, uint64_t * val) {
|
||||
#ifdef __BIG_ENDIAN__
|
||||
for (i = 0; i < tlen; i++) {
|
||||
#else
|
||||
for (i = tlen - 1; i >= 0; i--) {
|
||||
for (i = tlen - 1; i >= 0; i--) {
|
||||
#endif
|
||||
cval[j] = ptr[1 + i];
|
||||
j++;
|
||||
}
|
||||
|
||||
return tlen + 1;
|
||||
cval[j] = ptr[1 + i];
|
||||
j++;
|
||||
}
|
||||
|
||||
static uint8_t snmp_int_to_snmp(uint64_t snmp_val, uint8_t oid_type, uint8_t * buffer) {
|
||||
uint8_t tlen;
|
||||
int i, j;
|
||||
uint8_t *ptr = (uint8_t *) &snmp_val;
|
||||
return tlen + 1;
|
||||
}
|
||||
|
||||
// check for counter, counter64 or gauge
|
||||
static uint8_t snmp_int_to_snmp(uint64_t snmp_val, uint8_t oid_type, uint8_t * buffer) {
|
||||
uint8_t tlen;
|
||||
int i, j;
|
||||
uint8_t *ptr = (uint8_t *) & snmp_val;
|
||||
|
||||
if (oid_type == SNMP_COUNTER64) {
|
||||
tlen = 8;
|
||||
}
|
||||
else if (oid_type == SNMP_NULL || oid_type == 0) {
|
||||
tlen = 0;
|
||||
}
|
||||
else {
|
||||
tlen = 4;
|
||||
}
|
||||
// check for counter, counter64 or gauge
|
||||
|
||||
buffer[0] = tlen;
|
||||
if (oid_type == SNMP_COUNTER64) {
|
||||
tlen = 8;
|
||||
}
|
||||
else if (oid_type == SNMP_NULL || oid_type == 0) {
|
||||
tlen = 0;
|
||||
}
|
||||
else {
|
||||
tlen = 4;
|
||||
}
|
||||
|
||||
j = 1;
|
||||
buffer[0] = tlen;
|
||||
|
||||
j = 1;
|
||||
#ifdef __BIG_ENDIAN__
|
||||
for (i = 0; i < tlen; i++) {
|
||||
for (i = 0; i < tlen; i++) {
|
||||
#else
|
||||
for (i = tlen - 1; i >= 0; i--) {
|
||||
for (i = tlen - 1; i >= 0; i--) {
|
||||
#endif
|
||||
buffer[j] = ptr[i];
|
||||
j++;
|
||||
}
|
||||
buffer[j] = ptr[i];
|
||||
j++;
|
||||
}
|
||||
|
||||
return tlen + 1;
|
||||
}
|
||||
return tlen + 1;
|
||||
}
|
||||
|
||||
static ssize_t build_snmp_response(uint8_t oid1, uint8_t oid2, uint8_t * buffer, int size, uint8_t * seq1, uint8_t * seq2, uint8_t * seq3) {
|
||||
uint64_t snmp_val;
|
||||
uint8_t oid_sz;
|
||||
uint8_t oid_type;
|
||||
static ssize_t build_snmp_response(uint8_t oid1, uint8_t oid2, uint8_t * buffer, int size, uint8_t * seq1, uint8_t * seq2, uint8_t * seq3) {
|
||||
uint64_t snmp_val;
|
||||
uint8_t oid_sz;
|
||||
uint8_t oid_type;
|
||||
|
||||
if (oid1 == 1) {
|
||||
snmp_val = get_uwsgi_snmp_value(oid2, &oid_type);
|
||||
}
|
||||
else if (oid1 == 2) {
|
||||
snmp_val = get_uwsgi_custom_snmp_value(oid2, &oid_type);
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
if (oid1 == 1) {
|
||||
snmp_val = get_uwsgi_snmp_value(oid2, &oid_type);
|
||||
}
|
||||
else if (oid1 == 2) {
|
||||
snmp_val = get_uwsgi_custom_snmp_value(oid2, &oid_type);
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer[size - 2] = oid_type;
|
||||
oid_sz = snmp_int_to_snmp(snmp_val, oid_type, buffer + (size - 1));
|
||||
buffer[size - 2] = oid_type;
|
||||
oid_sz = snmp_int_to_snmp(snmp_val, oid_type, buffer + (size - 1));
|
||||
|
||||
if (oid_sz < 1)
|
||||
return -1;
|
||||
if (oid_sz < 1)
|
||||
return -1;
|
||||
|
||||
oid_sz--;
|
||||
oid_sz--;
|
||||
|
||||
buffer[1] += oid_sz;
|
||||
*seq1 += oid_sz;
|
||||
*seq2 += oid_sz;
|
||||
*seq3 += oid_sz;
|
||||
buffer[1] += oid_sz;
|
||||
*seq1 += oid_sz;
|
||||
*seq2 += oid_sz;
|
||||
*seq3 += oid_sz;
|
||||
|
||||
return size + oid_sz;
|
||||
return size + oid_sz;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_opt_snmp(char *opt, char *value, void *foobar) {
|
||||
uwsgi.snmp = 1;
|
||||
if (value) {
|
||||
uwsgi.snmp_addr = value;
|
||||
uwsgi.master_process = 1;
|
||||
}
|
||||
if (value) {
|
||||
uwsgi.snmp_addr = value;
|
||||
uwsgi.master_process = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_opt_snmp_community(char *opt, char *value, void *foobar) {
|
||||
uwsgi.snmp = 1;
|
||||
uwsgi.snmp_community = value;
|
||||
uwsgi.snmp_community = value;
|
||||
}
|
||||
|
||||
int uwsgi_setup_snmp(void) {
|
||||
int snmp_fd = -1;
|
||||
int i;
|
||||
if (uwsgi.snmp) {
|
||||
if (uwsgi.snmp_community) {
|
||||
if (strlen(uwsgi.snmp_community) > 72) {
|
||||
uwsgi_log("*** warning the supplied SNMP community string will be truncated to 72 chars ***\n");
|
||||
memcpy(uwsgi.shared->snmp_community, uwsgi.snmp_community, 72);
|
||||
}
|
||||
else {
|
||||
memcpy(uwsgi.shared->snmp_community, uwsgi.snmp_community, strlen(uwsgi.snmp_community) + 1);
|
||||
}
|
||||
}
|
||||
if (uwsgi.snmp_community) {
|
||||
if (strlen(uwsgi.snmp_community) > 72) {
|
||||
uwsgi_log("*** warning the supplied SNMP community string will be truncated to 72 chars ***\n");
|
||||
memcpy(uwsgi.shared->snmp_community, uwsgi.snmp_community, 72);
|
||||
}
|
||||
else {
|
||||
memcpy(uwsgi.shared->snmp_community, uwsgi.snmp_community, strlen(uwsgi.snmp_community) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi.shared->snmp_gvalue[0].type = SNMP_COUNTER64;
|
||||
uwsgi.shared->snmp_gvalue[0].val = &uwsgi.workers[0].requests;
|
||||
uwsgi.shared->snmp_gvalue[0].type = SNMP_COUNTER64;
|
||||
uwsgi.shared->snmp_gvalue[0].val = &uwsgi.workers[0].requests;
|
||||
|
||||
for (i = 0; i < uwsgi.numproc; i++) {
|
||||
uwsgi.shared->snmp_gvalue[30 + i].type = SNMP_COUNTER64;
|
||||
uwsgi.shared->snmp_gvalue[30 + i].val = &uwsgi.workers[i + 1].requests;
|
||||
}
|
||||
for (i = 0; i < uwsgi.numproc; i++) {
|
||||
uwsgi.shared->snmp_gvalue[30 + i].type = SNMP_COUNTER64;
|
||||
uwsgi.shared->snmp_gvalue[30 + i].val = &uwsgi.workers[i + 1].requests;
|
||||
}
|
||||
|
||||
if (uwsgi.snmp_addr) {
|
||||
snmp_fd = bind_to_udp(uwsgi.snmp_addr, 0, 0);
|
||||
if (snmp_fd < 0) {
|
||||
uwsgi_log("unable to bind to udp socket. SNMP service will be disabled.\n");
|
||||
}
|
||||
else {
|
||||
uwsgi_log("SNMP server enabled on %s\n", uwsgi.snmp_addr);
|
||||
event_queue_add_fd_read(uwsgi.master_queue, snmp_fd);
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log("SNMP agent enabled.\n");
|
||||
}
|
||||
if (uwsgi.snmp_addr) {
|
||||
snmp_fd = bind_to_udp(uwsgi.snmp_addr, 0, 0);
|
||||
if (snmp_fd < 0) {
|
||||
uwsgi_log("unable to bind to udp socket. SNMP service will be disabled.\n");
|
||||
}
|
||||
else {
|
||||
uwsgi_log("SNMP server enabled on %s\n", uwsgi.snmp_addr);
|
||||
event_queue_add_fd_read(uwsgi.master_queue, snmp_fd);
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log("SNMP agent enabled.\n");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return snmp_fd;
|
||||
}
|
||||
#else
|
||||
#warning "*** SNMP support is disabled ***"
|
||||
#endif
|
||||
|
||||
void uwsgi_master_manage_snmp(int snmp_fd) {
|
||||
struct sockaddr_in udp_client;
|
||||
socklen_t udp_len = sizeof(udp_client);
|
||||
ssize_t rlen = recvfrom(snmp_fd, uwsgi.wsgi_req->buffer, uwsgi.buffer_size, 0, (struct sockaddr *) &udp_client, &udp_len);
|
||||
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("recvfrom()");
|
||||
}
|
||||
else if (rlen > 0) {
|
||||
manage_snmp(snmp_fd, (uint8_t *) uwsgi.wsgi_req->buffer, rlen, &udp_client);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+591
-420
File diff suppressed because it is too large
Load Diff
+109
-95
@@ -1,4 +1,3 @@
|
||||
#ifdef UWSGI_SPOOLER
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
@@ -13,27 +12,31 @@ static void spooler_manage_task(struct uwsgi_spooler *, char *, char *);
|
||||
static uint64_t wakeup = 0;
|
||||
|
||||
// function to allow waking up the spooler if blocked in event_wait
|
||||
void spooler_wakeup() { wakeup++; }
|
||||
void spooler_wakeup() {
|
||||
wakeup++;
|
||||
}
|
||||
|
||||
void uwsgi_opt_add_spooler(char *opt, char *directory, void *mode) {
|
||||
|
||||
int i;
|
||||
struct uwsgi_spooler *us;
|
||||
|
||||
if (access(directory, R_OK | W_OK | X_OK)) {
|
||||
uwsgi_error("[spooler directory] access()");
|
||||
exit(1);
|
||||
}
|
||||
if (access(directory, R_OK | W_OK | X_OK)) {
|
||||
uwsgi_error("[spooler directory] access()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (uwsgi.spooler_numproc > 0) {
|
||||
for(i=0;i<uwsgi.spooler_numproc;i++) {
|
||||
for (i = 0; i < uwsgi.spooler_numproc; i++) {
|
||||
us = uwsgi_new_spooler(directory);
|
||||
if (mode) us->mode = (long) mode;
|
||||
if (mode)
|
||||
us->mode = (long) mode;
|
||||
}
|
||||
}
|
||||
else {
|
||||
us = uwsgi_new_spooler(directory);
|
||||
if (mode) us->mode = (long) mode;
|
||||
us = uwsgi_new_spooler(directory);
|
||||
if (mode)
|
||||
us->mode = (long) mode;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -41,31 +44,31 @@ void uwsgi_opt_add_spooler(char *opt, char *directory, void *mode) {
|
||||
|
||||
struct uwsgi_spooler *uwsgi_new_spooler(char *dir) {
|
||||
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
|
||||
if (!uspool) {
|
||||
uwsgi.spoolers = uwsgi_calloc_shared(sizeof(struct uwsgi_spooler));
|
||||
uspool = uwsgi.spoolers;
|
||||
}
|
||||
else {
|
||||
while(uspool) {
|
||||
if (uspool->next == NULL) {
|
||||
uspool->next = uwsgi_calloc_shared(sizeof(struct uwsgi_spooler));
|
||||
uspool = uspool->next;
|
||||
break;
|
||||
}
|
||||
uspool = uspool->next;
|
||||
}
|
||||
}
|
||||
if (!uspool) {
|
||||
uwsgi.spoolers = uwsgi_calloc_shared(sizeof(struct uwsgi_spooler));
|
||||
uspool = uwsgi.spoolers;
|
||||
}
|
||||
else {
|
||||
while (uspool) {
|
||||
if (uspool->next == NULL) {
|
||||
uspool->next = uwsgi_calloc_shared(sizeof(struct uwsgi_spooler));
|
||||
uspool = uspool->next;
|
||||
break;
|
||||
}
|
||||
uspool = uspool->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (!realpath(dir, uspool->dir)) {
|
||||
uwsgi_error("[spooler] realpath()");
|
||||
exit(1);
|
||||
}
|
||||
if (!realpath(dir, uspool->dir)) {
|
||||
uwsgi_error("[spooler] realpath()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uspool->next = NULL;
|
||||
uspool->next = NULL;
|
||||
|
||||
return uspool;
|
||||
return uspool;
|
||||
}
|
||||
|
||||
|
||||
@@ -73,18 +76,18 @@ struct uwsgi_spooler *uwsgi_get_spooler_by_name(char *name) {
|
||||
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
|
||||
while(uspool) {
|
||||
while (uspool) {
|
||||
if (!strcmp(uspool->dir, name)) {
|
||||
return uspool;
|
||||
}
|
||||
uspool = uspool->next;
|
||||
}
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pid_t spooler_start(struct uwsgi_spooler *uspool) {
|
||||
|
||||
pid_t spooler_start(struct uwsgi_spooler * uspool) {
|
||||
|
||||
int i;
|
||||
|
||||
pid_t pid = uwsgi_fork("uWSGI spooler");
|
||||
@@ -93,9 +96,18 @@ pid_t spooler_start(struct uwsgi_spooler *uspool) {
|
||||
exit(1);
|
||||
}
|
||||
else if (pid == 0) {
|
||||
|
||||
signal(SIGALRM, SIG_IGN);
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
signal(SIGINT, end_me);
|
||||
signal(SIGTERM, end_me);
|
||||
// USR1 will be used to wake up the spooler
|
||||
uwsgi_unix_signal(SIGUSR1, spooler_wakeup);
|
||||
uwsgi.mywid = -1;
|
||||
signal(SIGUSR2, SIG_IGN);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGSTOP, SIG_IGN);
|
||||
signal(SIGTSTP, SIG_IGN);
|
||||
|
||||
uwsgi.mypid = getpid();
|
||||
uspool->pid = uwsgi.mypid;
|
||||
// avoid race conditions !!!
|
||||
@@ -105,24 +117,24 @@ pid_t spooler_start(struct uwsgi_spooler *uspool) {
|
||||
uwsgi_close_all_sockets();
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->post_fork) {
|
||||
uwsgi.p[i]->post_fork();
|
||||
}
|
||||
}
|
||||
if (uwsgi.p[i]->post_fork) {
|
||||
uwsgi.p[i]->post_fork();
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi.signal_socket = uwsgi.shared->spooler_signal_pipe[1];
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->spooler_init) {
|
||||
uwsgi.p[i]->spooler_init();
|
||||
}
|
||||
}
|
||||
if (uwsgi.p[i]->spooler_init) {
|
||||
uwsgi.p[i]->spooler_init();
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < uwsgi.gp_cnt; i++) {
|
||||
if (uwsgi.gp[i]->spooler_init) {
|
||||
uwsgi.gp[i]->spooler_init();
|
||||
}
|
||||
}
|
||||
for (i = 0; i < uwsgi.gp_cnt; i++) {
|
||||
if (uwsgi.gp[i]->spooler_init) {
|
||||
uwsgi.gp[i]->spooler_init();
|
||||
}
|
||||
}
|
||||
|
||||
spooler(uspool);
|
||||
}
|
||||
@@ -137,14 +149,14 @@ void destroy_spool(char *dir, char *file) {
|
||||
|
||||
if (chdir(dir)) {
|
||||
uwsgi_error("chdir()");
|
||||
uwsgi_log("[spooler] something horrible happened to the spooler. Better to kill it.\n");
|
||||
uwsgi_log("[spooler] something horrible happened to the spooler. Better to kill it.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (unlink(file)) {
|
||||
uwsgi_error("unlink()");
|
||||
uwsgi_log("[spooler] something horrible happened to the spooler. Better to kill it.\n");
|
||||
exit(1);
|
||||
uwsgi_error("unlink()");
|
||||
uwsgi_log("[spooler] something horrible happened to the spooler. Better to kill it.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -194,7 +206,7 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core
|
||||
|
||||
// now lock the file, it will no be runnable, until the lock is not removed
|
||||
// a race could come if the spooler take the file before fcntl is called
|
||||
// in such case the spooler will detect a zeroed file and will retry later
|
||||
// in such case the spooler will detect a zeroed file and will retry later
|
||||
if (uwsgi_fcntl_lock(fd)) {
|
||||
close(fd);
|
||||
uwsgi_unlock(uspool->lock);
|
||||
@@ -217,8 +229,8 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core
|
||||
}
|
||||
|
||||
if (body && body_len > 0) {
|
||||
if ((size_t)write(fd, body, body_len) != body_len) {
|
||||
goto clear;
|
||||
if ((size_t) write(fd, body, body_len) != body_len) {
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,8 +253,8 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core
|
||||
close(fd);
|
||||
|
||||
if (!uwsgi.spooler_quiet)
|
||||
uwsgi_log("[spooler] written %d bytes to file %s\n", size + body_len + 4, filename);
|
||||
|
||||
uwsgi_log("[spooler] written %lu bytes to file %s\n", (unsigned long) size + body_len + 4, filename);
|
||||
|
||||
// and here waiting threads can continue
|
||||
uwsgi_unlock(uspool->lock);
|
||||
|
||||
@@ -252,7 +264,7 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core
|
||||
*/
|
||||
|
||||
struct uwsgi_spooler *spoolers = uwsgi.spoolers;
|
||||
while(spoolers) {
|
||||
while (spoolers) {
|
||||
if (!strcmp(spoolers->dir, uspool->dir)) {
|
||||
if (spoolers->pid > 0 && spoolers->running == 0) {
|
||||
(void) kill(spoolers->pid, SIGUSR1);
|
||||
@@ -264,7 +276,7 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core
|
||||
return 1;
|
||||
|
||||
|
||||
clear:
|
||||
clear:
|
||||
uwsgi_unlock(uspool->lock);
|
||||
uwsgi_error("write()");
|
||||
if (unlink(filename)) {
|
||||
@@ -355,12 +367,6 @@ void spooler(struct uwsgi_spooler *uspool) {
|
||||
}
|
||||
wakeup = tmp_wakeup;
|
||||
|
||||
// need to recycle ?
|
||||
if (uwsgi.spooler_max_tasks > 0 && uspool->tasks >= (uint64_t)uwsgi.spooler_max_tasks) {
|
||||
uwsgi_log("[spooler %s pid: %d] maximum number of tasks reached (%d) recycling ...\n", uspool->dir, (int) uwsgi.mypid, uwsgi.spooler_max_tasks);
|
||||
end_me(0);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,17 +376,18 @@ static void spooler_scandir(struct uwsgi_spooler *uspool, char *dir) {
|
||||
struct dirent **tasklist;
|
||||
int n;
|
||||
|
||||
if (!dir) dir = uspool->dir;
|
||||
if (!dir)
|
||||
dir = uspool->dir;
|
||||
|
||||
n = scandir(dir, &tasklist, 0, versionsort);
|
||||
if (n < 0) {
|
||||
uwsgi_error("scandir()");
|
||||
return;
|
||||
}
|
||||
|
||||
while(n--) {
|
||||
|
||||
while (n--) {
|
||||
spooler_manage_task(uspool, dir, tasklist[n]->d_name);
|
||||
free(tasklist[n]);
|
||||
free(tasklist[n]);
|
||||
}
|
||||
|
||||
free(tasklist);
|
||||
@@ -393,7 +400,8 @@ static void spooler_readdir(struct uwsgi_spooler *uspool, char *dir) {
|
||||
DIR *sdir;
|
||||
struct dirent *dp;
|
||||
|
||||
if (!dir) dir = uspool->dir;
|
||||
if (!dir)
|
||||
dir = uspool->dir;
|
||||
|
||||
sdir = opendir(dir);
|
||||
if (sdir) {
|
||||
@@ -418,7 +426,8 @@ void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) {
|
||||
|
||||
int spool_fd;
|
||||
|
||||
if (!dir) dir = uspool->dir;
|
||||
if (!dir)
|
||||
dir = uspool->dir;
|
||||
|
||||
if (!strncmp("uwsgi_spoolfile_on_", task, 19) || (uwsgi.spooler_ordered && is_a_number(task))) {
|
||||
struct stat sf_lstat;
|
||||
@@ -487,16 +496,16 @@ void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) {
|
||||
|
||||
if (uwsgi_protected_read(spool_fd, spool_buf, uh.pktsize) != uh.pktsize) {
|
||||
uwsgi_error("read()");
|
||||
destroy_spool(dir, task);
|
||||
destroy_spool(dir, task);
|
||||
uwsgi_protected_close(spool_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// body available ?
|
||||
if (sf_lstat.st_size > (uh.pktsize+4)) {
|
||||
body_len = sf_lstat.st_size - (uh.pktsize+4);
|
||||
if (sf_lstat.st_size > (uh.pktsize + 4)) {
|
||||
body_len = sf_lstat.st_size - (uh.pktsize + 4);
|
||||
body = uwsgi_malloc(body_len);
|
||||
if ((size_t)uwsgi_protected_read(spool_fd, body, body_len) != body_len) {
|
||||
if ((size_t) uwsgi_protected_read(spool_fd, body, body_len) != body_len) {
|
||||
uwsgi_error("read()");
|
||||
destroy_spool(dir, task);
|
||||
uwsgi_protected_close(spool_fd);
|
||||
@@ -520,27 +529,28 @@ void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) {
|
||||
}
|
||||
|
||||
int callable_found = 0;
|
||||
for(i=0;i<256;i++) {
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->spooler) {
|
||||
time_t now = uwsgi_now();
|
||||
if(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
|
||||
set_spooler_harakiri(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI]);
|
||||
}
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
|
||||
set_spooler_harakiri(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI]);
|
||||
}
|
||||
ret = uwsgi.p[i]->spooler(task, spool_buf, uh.pktsize, body, body_len);
|
||||
if(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
|
||||
set_spooler_harakiri(0);
|
||||
}
|
||||
if (ret == 0) continue;
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) {
|
||||
set_spooler_harakiri(0);
|
||||
}
|
||||
if (ret == 0)
|
||||
continue;
|
||||
callable_found = 1;
|
||||
// increase task counter
|
||||
uspool->tasks++;
|
||||
if (ret == -2) {
|
||||
if (!uwsgi.spooler_quiet)
|
||||
uwsgi_log("[spooler %s pid: %d] done with task %s after %d seconds\n", uspool->dir, (int) uwsgi.mypid, task, uwsgi_now()-now);
|
||||
destroy_spool(dir, task);
|
||||
uwsgi_log("[spooler %s pid: %d] done with task %s after %lld seconds\n", uspool->dir, (int) uwsgi.mypid, task, (long long) uwsgi_now() - now);
|
||||
destroy_spool(dir, task);
|
||||
}
|
||||
// re-spool it
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -551,9 +561,17 @@ void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) {
|
||||
uwsgi_protected_close(spool_fd);
|
||||
uspool->running = 0;
|
||||
|
||||
|
||||
// need to recycle ?
|
||||
if (uwsgi.spooler_max_tasks > 0 && uspool->tasks >= (uint64_t) uwsgi.spooler_max_tasks) {
|
||||
uwsgi_log("[spooler %s pid: %d] maximum number of tasks reached (%d) recycling ...\n", uspool->dir, (int) uwsgi.mypid, uwsgi.spooler_max_tasks);
|
||||
end_me(0);
|
||||
}
|
||||
|
||||
|
||||
if (chdir(dir)) {
|
||||
uwsgi_error("chdir()");
|
||||
uwsgi_log("[spooler] something horrible happened to the spooler. Better to kill it.\n");
|
||||
uwsgi_error("chdir()");
|
||||
uwsgi_log("[spooler] something horrible happened to the spooler. Better to kill it.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -564,7 +582,3 @@ void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#warning "*** Spooler support is disabled ***"
|
||||
#endif
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
#ifdef UWSGI_SQLITE3
|
||||
|
||||
#include "uwsgi.h"
|
||||
#include <sqlite3.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
static int uwsgi_sqlite3_config_callback(void *magic_table, int field_count, char **fields, char **col) {
|
||||
// make a copy of the string
|
||||
if (field_count >= 2) {
|
||||
int value_len = strlen(fields[1]) + 1;
|
||||
char *value = magic_sub(fields[1], value_len, &value_len, (char **) magic_table);
|
||||
add_exported_option( uwsgi_strncopy(fields[0], strlen(fields[0])), value, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_sqlite3_config(char *file, char *magic_table[]) {
|
||||
|
||||
sqlite3 *db;
|
||||
char *err = NULL;
|
||||
char *query = "SELECT * FROM uwsgi";
|
||||
|
||||
char *colon = uwsgi_get_last_char(file, ':');
|
||||
|
||||
if (colon) {
|
||||
colon[0] = 0;
|
||||
if (colon[1] != 0) {
|
||||
query = colon+1;
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("[uWSGI] getting sqlite3 configuration from %s\n", file);
|
||||
|
||||
#ifdef sqlite3_open_v2
|
||||
if (sqlite3_open_v2(file, &db, SQLITE_OPEN_READONLY, NULL)) {
|
||||
#else
|
||||
if (sqlite3_open(file, &db)) {
|
||||
#endif
|
||||
uwsgi_log("unable to open sqlite3 db: %s\n", sqlite3_errmsg(db));
|
||||
sqlite3_close(db);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (sqlite3_exec(db, query, uwsgi_sqlite3_config_callback, (void *) magic_table, &err)) {
|
||||
uwsgi_log("sqlite3 error: %s\n", err);
|
||||
sqlite3_close(db);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sqlite3_close(db);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+516
@@ -0,0 +1,516 @@
|
||||
#include <uwsgi.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/md5.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
/*
|
||||
|
||||
ssl additional datas are retrieved via indexes.
|
||||
|
||||
You can create an index with SSL_CTX_get_ex_new_index and
|
||||
set data in it with SSL_CTX_set_ex_data
|
||||
|
||||
*/
|
||||
|
||||
void uwsgi_ssl_init(void) {
|
||||
OPENSSL_config(NULL);
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
OpenSSL_add_all_algorithms();
|
||||
uwsgi.ssl_initialized = 1;
|
||||
}
|
||||
|
||||
void uwsgi_ssl_info_cb(SSL const *ssl, int where, int ret) {
|
||||
if (where & SSL_CB_HANDSHAKE_DONE) {
|
||||
if (ssl->s3) {
|
||||
ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int uwsgi_ssl_verify_callback(int ok, X509_STORE_CTX * x509_store) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int uwsgi_ssl_session_new_cb(SSL *ssl, SSL_SESSION *sess) {
|
||||
char session_blob[4096];
|
||||
int len = i2d_SSL_SESSION(sess, NULL);
|
||||
if (len > 4096) {
|
||||
if (uwsgi.ssl_verbose) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to store session of size %d\n", len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char *p = (unsigned char *) session_blob;
|
||||
i2d_SSL_SESSION(sess, &p);
|
||||
|
||||
// ok let's write the value to the cache
|
||||
uwsgi_wlock(uwsgi.ssl_sessions_cache->lock);
|
||||
if (uwsgi_cache_set2(uwsgi.ssl_sessions_cache, (char *) sess->session_id, sess->session_id_length, session_blob, len, uwsgi.ssl_sessions_timeout, 0)) {
|
||||
if (uwsgi.ssl_verbose) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to store session of size %d in the cache\n", len);
|
||||
}
|
||||
}
|
||||
uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SSL_SESSION *uwsgi_ssl_session_get_cb(SSL *ssl, unsigned char *key, int keylen, int *copy) {
|
||||
|
||||
uint64_t valsize = 0;
|
||||
|
||||
*copy = 0;
|
||||
uwsgi_rlock(uwsgi.ssl_sessions_cache->lock);
|
||||
char *value = uwsgi_cache_get2(uwsgi.ssl_sessions_cache, (char *)key, keylen, &valsize);
|
||||
if (!value) {
|
||||
uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock);
|
||||
if (uwsgi.ssl_verbose) {
|
||||
uwsgi_log("[uwsgi-ssl] cache miss\n");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
SSL_SESSION *sess = d2i_SSL_SESSION(NULL, (const unsigned char **)&value, valsize);
|
||||
uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock);
|
||||
return sess;
|
||||
}
|
||||
|
||||
void uwsgi_ssl_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess) {
|
||||
uwsgi_wlock(uwsgi.ssl_sessions_cache->lock);
|
||||
if (uwsgi_cache_del2(uwsgi.ssl_sessions_cache, (char *) sess->session_id, sess->session_id_length, 0, 0)) {
|
||||
if (uwsgi.ssl_verbose) {
|
||||
uwsgi_log("[uwsgi-ssl] error removing cache item\n");
|
||||
}
|
||||
}
|
||||
uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock);
|
||||
}
|
||||
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
static int uwsgi_sni_cb(SSL *ssl, int *ad, void *arg) {
|
||||
const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
|
||||
if (!servername) return SSL_TLSEXT_ERR_NOACK;
|
||||
size_t servername_len = strlen(servername);
|
||||
|
||||
struct uwsgi_string_list *usl = uwsgi.sni;
|
||||
while(usl) {
|
||||
if (!uwsgi_strncmp(usl->value, usl->len, (char *)servername, servername_len)) {
|
||||
SSL_set_SSL_CTX(ssl, usl->custom_ptr);
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
struct uwsgi_regexp_list *url = uwsgi.sni_regexp;
|
||||
while(url) {
|
||||
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, (char *)servername, servername_len) >= 0) {
|
||||
SSL_set_SSL_CTX(ssl, url->custom_ptr);
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
url = url->next;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (uwsgi.sni_dir) {
|
||||
size_t sni_dir_len = strlen(uwsgi.sni_dir);
|
||||
char *sni_dir_cert = uwsgi_concat4n(uwsgi.sni_dir, sni_dir_len, "/", 1, (char *) servername, servername_len, ".crt", 4);
|
||||
char *sni_dir_key = uwsgi_concat4n(uwsgi.sni_dir, sni_dir_len, "/", 1, (char *) servername, servername_len, ".key", 4);
|
||||
char *sni_dir_client_ca = uwsgi_concat4n(uwsgi.sni_dir, sni_dir_len, "/", 1, (char *) servername, servername_len, ".ca", 3);
|
||||
if (uwsgi_file_exists(sni_dir_cert) && uwsgi_file_exists(sni_dir_key)) {
|
||||
char *client_ca = NULL;
|
||||
if (uwsgi_file_exists(sni_dir_client_ca)) {
|
||||
client_ca = sni_dir_client_ca;
|
||||
}
|
||||
usl = uwsgi_ssl_add_sni_item(uwsgi_str((char *)servername), sni_dir_cert, sni_dir_key, uwsgi.sni_dir_ciphers, client_ca);
|
||||
if (!usl) goto done;
|
||||
free(sni_dir_cert);
|
||||
free(sni_dir_key);
|
||||
free(sni_dir_client_ca);
|
||||
SSL_set_SSL_CTX(ssl, usl->custom_ptr);
|
||||
uwsgi_log("[uwsgi-sni for pid %d] added context for %s\n", (int) getpid(), servername);
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
done:
|
||||
free(sni_dir_cert);
|
||||
free(sni_dir_key);
|
||||
free(sni_dir_client_ca);
|
||||
}
|
||||
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
#endif
|
||||
|
||||
SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ciphers, char *client_ca) {
|
||||
|
||||
SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
|
||||
if (!ctx) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to initialize context \"%s\"\n", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// this part is taken from nginx and stud, removing unneeded functionality
|
||||
// stud (for me) has made the best choice on choosing DH approach
|
||||
|
||||
long ssloptions = SSL_OP_NO_SSLv2 | SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION;
|
||||
// disable compression (if possibile)
|
||||
#ifdef SSL_OP_NO_COMPRESSION
|
||||
ssloptions |= SSL_OP_NO_COMPRESSION;
|
||||
#endif
|
||||
|
||||
// release/reuse buffers as soon as possibile
|
||||
#ifdef SSL_MODE_RELEASE_BUFFERS
|
||||
SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
|
||||
#endif
|
||||
|
||||
if (SSL_CTX_use_certificate_chain_file(ctx, crt) <= 0) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to assign certificate %s for context \"%s\"\n", crt, name);
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// this part is based from stud
|
||||
BIO *bio = BIO_new_file(crt, "r");
|
||||
if (bio) {
|
||||
DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
|
||||
BIO_free(bio);
|
||||
if (dh) {
|
||||
SSL_CTX_set_tmp_dh(ctx, dh);
|
||||
DH_free(dh);
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
|
||||
#ifndef OPENSSL_NO_ECDH
|
||||
#ifdef NID_X9_62_prime256v1
|
||||
EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||||
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
|
||||
EC_KEY_free(ecdh);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) <= 0) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to assign key %s for context \"%s\"\n", key, name);
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// if ciphers are specified, prefer server ciphers
|
||||
if (ciphers && strlen(ciphers) > 0) {
|
||||
if (SSL_CTX_set_cipher_list(ctx, ciphers) == 0) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to set requested ciphers (%s) for context \"%s\"\n", ciphers, name);
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssloptions |= SSL_OP_CIPHER_SERVER_PREFERENCE;
|
||||
}
|
||||
|
||||
// set session context (if possibile), this is required for client certificate authentication
|
||||
if (name) {
|
||||
SSL_CTX_set_session_id_context(ctx, (unsigned char *) name, strlen(name));
|
||||
}
|
||||
|
||||
if (client_ca) {
|
||||
if (client_ca[0] == '!') {
|
||||
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, uwsgi_ssl_verify_callback);
|
||||
client_ca++;
|
||||
}
|
||||
else {
|
||||
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, uwsgi_ssl_verify_callback);
|
||||
}
|
||||
// in the future we should allow to set the verify depth
|
||||
SSL_CTX_set_verify_depth(ctx, 1);
|
||||
if (SSL_CTX_load_verify_locations(ctx, client_ca, NULL) == 0) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to set ssl verify locations (%s) for context \"%s\"\n", client_ca, name);
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
STACK_OF(X509_NAME) * list = SSL_load_client_CA_file(client_ca);
|
||||
if (!list) {
|
||||
uwsgi_log("unable to load client CA certificate (%s) for context \"%s\"\n", client_ca, name);
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SSL_CTX_set_client_CA_list(ctx, list);
|
||||
}
|
||||
|
||||
|
||||
SSL_CTX_set_info_callback(ctx, uwsgi_ssl_info_cb);
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
SSL_CTX_set_tlsext_servername_callback(ctx, uwsgi_sni_cb);
|
||||
#endif
|
||||
|
||||
// disable session caching by default
|
||||
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
|
||||
|
||||
if (uwsgi.ssl_sessions_use_cache) {
|
||||
|
||||
// we need to early initialize locking and caching
|
||||
uwsgi_setup_locking();
|
||||
uwsgi_cache_create_all();
|
||||
|
||||
uwsgi.ssl_sessions_cache = uwsgi_cache_by_name(uwsgi.ssl_sessions_use_cache);
|
||||
if (!uwsgi.ssl_sessions_cache) {
|
||||
// check for default cache
|
||||
if (!strcmp(uwsgi.ssl_sessions_use_cache, "true") && uwsgi.caches) {
|
||||
uwsgi.ssl_sessions_cache = uwsgi.caches;
|
||||
}
|
||||
else {
|
||||
uwsgi_log("unable to find cache \"%s\"\n", uwsgi.ssl_sessions_use_cache ? uwsgi.ssl_sessions_use_cache : "default");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!uwsgi.ssl_sessions_cache->max_items) {
|
||||
uwsgi_log("you have to enable uWSGI cache to use it as SSL session store !!!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (uwsgi.ssl_sessions_cache->blocksize < 4096) {
|
||||
uwsgi_log("cache blocksize for SSL session store must be at least 4096 bytes\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER|
|
||||
SSL_SESS_CACHE_NO_INTERNAL|
|
||||
SSL_SESS_CACHE_NO_AUTO_CLEAR);
|
||||
|
||||
#ifdef SSL_OP_NO_TICKET
|
||||
ssloptions |= SSL_OP_NO_TICKET;
|
||||
#endif
|
||||
|
||||
// just for fun
|
||||
SSL_CTX_sess_set_cache_size(ctx, 0);
|
||||
|
||||
// set the callback for ssl sessions
|
||||
SSL_CTX_sess_set_new_cb(ctx, uwsgi_ssl_session_new_cb);
|
||||
SSL_CTX_sess_set_get_cb(ctx, uwsgi_ssl_session_get_cb);
|
||||
SSL_CTX_sess_set_remove_cb(ctx, uwsgi_ssl_session_remove_cb);
|
||||
}
|
||||
|
||||
SSL_CTX_set_timeout(ctx, uwsgi.ssl_sessions_timeout);
|
||||
|
||||
SSL_CTX_set_options(ctx, ssloptions);
|
||||
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_rsa_sign(char *algo_key, char *message, size_t message_len, unsigned int *s_len) {
|
||||
|
||||
// openssl could not be initialized
|
||||
if (!uwsgi.ssl_initialized) {
|
||||
uwsgi_ssl_init();
|
||||
}
|
||||
|
||||
*s_len = 0;
|
||||
EVP_PKEY *pk = NULL;
|
||||
|
||||
char *algo = uwsgi_str(algo_key);
|
||||
char *colon = strchr(algo, ':');
|
||||
if (!colon) {
|
||||
uwsgi_log("invalid RSA signature syntax, must be: <digest>:<pemfile>\n");
|
||||
free(algo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*colon = 0;
|
||||
char *keyfile = colon + 1;
|
||||
char *signature = NULL;
|
||||
|
||||
FILE *kf = fopen(keyfile, "r");
|
||||
if (!kf) {
|
||||
uwsgi_error_open(keyfile);
|
||||
free(algo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (PEM_read_PrivateKey(kf, &pk, NULL, NULL) == 0) {
|
||||
uwsgi_log("unable to load private key: %s\n", keyfile);
|
||||
free(algo);
|
||||
fclose(kf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fclose(kf);
|
||||
|
||||
EVP_MD_CTX *ctx = EVP_MD_CTX_create();
|
||||
if (!ctx) {
|
||||
free(algo);
|
||||
EVP_PKEY_free(pk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const EVP_MD *md = EVP_get_digestbyname(algo);
|
||||
if (!md) {
|
||||
uwsgi_log("unknown digest algo: %s\n", algo);
|
||||
free(algo);
|
||||
EVP_PKEY_free(pk);
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*s_len = EVP_PKEY_size(pk);
|
||||
signature = uwsgi_malloc(*s_len);
|
||||
|
||||
if (EVP_SignInit_ex(ctx, md, NULL) == 0) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
free(signature);
|
||||
signature = NULL;
|
||||
*s_len = 0;
|
||||
goto clear;
|
||||
}
|
||||
|
||||
if (EVP_SignUpdate(ctx, message, message_len) == 0) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
free(signature);
|
||||
signature = NULL;
|
||||
*s_len = 0;
|
||||
goto clear;
|
||||
}
|
||||
|
||||
|
||||
if (EVP_SignFinal(ctx, (unsigned char *) signature, s_len, pk) == 0) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
free(signature);
|
||||
signature = NULL;
|
||||
*s_len = 0;
|
||||
goto clear;
|
||||
}
|
||||
|
||||
clear:
|
||||
free(algo);
|
||||
EVP_PKEY_free(pk);
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
return signature;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_sanitize_cert_filename(char *base, char *key, uint16_t keylen) {
|
||||
uint16_t i;
|
||||
char *filename = uwsgi_concat4n(base, strlen(base), "/", 1, key, keylen, ".pem\0", 5);
|
||||
|
||||
for (i = strlen(base) + 1; i < (strlen(base) + 1) + keylen; i++) {
|
||||
if (filename[i] >= '0' && filename[i] <= '9')
|
||||
continue;
|
||||
if (filename[i] >= 'A' && filename[i] <= 'Z')
|
||||
continue;
|
||||
if (filename[i] >= 'a' && filename[i] <= 'z')
|
||||
continue;
|
||||
if (filename[i] == '.')
|
||||
continue;
|
||||
if (filename[i] == '-')
|
||||
continue;
|
||||
if (filename[i] == '_')
|
||||
continue;
|
||||
filename[i] = '_';
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
char *uwsgi_ssl_rand(size_t len) {
|
||||
unsigned char *buf = uwsgi_calloc(len);
|
||||
if (RAND_bytes(buf, len) <= 0) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
return (char *) buf;
|
||||
}
|
||||
|
||||
char *uwsgi_sha1(char *src, size_t len, char *dst) {
|
||||
SHA_CTX sha;
|
||||
SHA1_Init(&sha);
|
||||
SHA1_Update(&sha, src, len);
|
||||
SHA1_Final((unsigned char *)dst, &sha);
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *uwsgi_md5(char *src, size_t len, char *dst) {
|
||||
MD5_CTX md5;
|
||||
MD5_Init(&md5);
|
||||
MD5_Update(&md5, src, len);
|
||||
MD5_Final((unsigned char *)dst, &md5);
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *uwsgi_sha1_2n(char *s1, size_t len1, char *s2, size_t len2, char *dst) {
|
||||
SHA_CTX sha;
|
||||
SHA1_Init(&sha);
|
||||
SHA1_Update(&sha, s1, len1);
|
||||
SHA1_Update(&sha, s2, len2);
|
||||
SHA1_Final((unsigned char *)dst, &sha);
|
||||
return dst;
|
||||
}
|
||||
|
||||
void uwsgi_opt_sni(char *opt, char *value, void *foobar) {
|
||||
char *client_ca = NULL;
|
||||
char *v = uwsgi_str(value);
|
||||
|
||||
char *space = strchr(v, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid %s syntax, must be sni_key<space>crt,key[,ciphers,client_ca]\n", opt);
|
||||
exit(1);
|
||||
}
|
||||
*space = 0;
|
||||
char *crt = space+1;
|
||||
char *key = strchr(crt, ',');
|
||||
if (!key) {
|
||||
uwsgi_log("invalid %s syntax, must be sni_key<space>crt,key[,ciphers,client_ca]\n", opt);
|
||||
exit(1);
|
||||
}
|
||||
*key = '\0'; key++;
|
||||
|
||||
char *ciphers = strchr(key, ',');
|
||||
if (ciphers) {
|
||||
*ciphers = '\0'; ciphers++;
|
||||
client_ca = strchr(ciphers, ',');
|
||||
if (client_ca) {
|
||||
*client_ca = '\0'; client_ca++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!uwsgi.ssl_initialized) {
|
||||
uwsgi_ssl_init();
|
||||
}
|
||||
|
||||
SSL_CTX *ctx = uwsgi_ssl_new_server_context(v, crt, key, ciphers, client_ca);
|
||||
if (!ctx) {
|
||||
uwsgi_log("[uwsgi-ssl] DANGER unable to initialize context for \"%s\"\n", v);
|
||||
free(v);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
if (!strcmp(opt, "sni-regexp")) {
|
||||
struct uwsgi_regexp_list *url = uwsgi_regexp_new_list(&uwsgi.sni_regexp, v);
|
||||
url->custom_ptr = ctx;
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
struct uwsgi_string_list *usl = uwsgi_string_new_list(&uwsgi.sni, v);
|
||||
usl->custom_ptr = ctx;
|
||||
#ifdef UWSGI_PCRE
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_string_list *uwsgi_ssl_add_sni_item(char *name, char *crt, char *key, char *ciphers, char *client_ca) {
|
||||
if (!uwsgi.ssl_initialized) {
|
||||
uwsgi_ssl_init();
|
||||
}
|
||||
SSL_CTX *ctx = uwsgi_ssl_new_server_context(name, crt, key, ciphers, client_ca);
|
||||
if (!ctx) {
|
||||
uwsgi_log("[uwsgi-ssl] DANGER unable to initialize context for \"%s\"\n", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_string_list *usl = uwsgi_string_new_list(&uwsgi.sni, name);
|
||||
usl->custom_ptr = ctx;
|
||||
return usl;
|
||||
}
|
||||
+658
@@ -0,0 +1,658 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_static_want_gzip(struct wsgi_request *wsgi_req, char *filename, size_t filename_len, struct stat *st) {
|
||||
// check for filename size
|
||||
if (filename_len + 4 > PATH_MAX) return 0;
|
||||
// check for supported encodings
|
||||
if (!uwsgi_contains_n(wsgi_req->encoding, wsgi_req->encoding_len, "gzip", 4) ) return 0;
|
||||
|
||||
// check for 'all'
|
||||
if (uwsgi.static_gzip_all) goto gzip;
|
||||
|
||||
// check for dirs/prefix
|
||||
struct uwsgi_string_list *usl = uwsgi.static_gzip_dir;
|
||||
while(usl) {
|
||||
if (!uwsgi_starts_with(filename, filename_len, usl->value, usl->len)) {
|
||||
goto gzip;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
// check for ext/suffix
|
||||
usl = uwsgi.static_gzip_ext;
|
||||
while(usl) {
|
||||
if (!uwsgi_strncmp(filename + (filename_len - usl->len), usl->len, usl->value, usl->len)) {
|
||||
goto gzip;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
// check for regexp
|
||||
struct uwsgi_regexp_list *url = uwsgi.static_gzip;
|
||||
while(url) {
|
||||
if (uwsgi_regexp_match(url->pattern, url->pattern_extra, filename, filename_len) >= 0) {
|
||||
goto gzip;
|
||||
}
|
||||
url = url->next;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
gzip:
|
||||
|
||||
memcpy(filename + filename_len, ".gz\0", 4);
|
||||
filename_len += 3;
|
||||
|
||||
if (stat(filename, st)) {
|
||||
filename_len -= 3;
|
||||
filename[filename_len] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int uwsgi_http_date(time_t t, char *dst) {
|
||||
|
||||
static char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
|
||||
static char *months[] = {
|
||||
"Jan", "Feb", "Mar", "Apr",
|
||||
"May", "Jun", "Jul", "Aug",
|
||||
"Sep", "Oct", "Nov", "Dec"
|
||||
};
|
||||
|
||||
struct tm *hdtm = gmtime(&t);
|
||||
|
||||
int ret = snprintf(dst, 31, "%s, %02d %s %4d %02d:%02d:%02d GMT",
|
||||
week[hdtm->tm_wday], hdtm->tm_mday, months[hdtm->tm_mon], hdtm->tm_year + 1900, hdtm->tm_hour, hdtm->tm_min, hdtm->tm_sec);
|
||||
if (ret <= 0 || ret > 31) {
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// only RFC 1123 is supported
|
||||
static time_t parse_http_date(char *date, uint16_t len) {
|
||||
|
||||
struct tm hdtm;
|
||||
|
||||
if (len != 29 && date[3] != ',')
|
||||
return 0;
|
||||
|
||||
hdtm.tm_mday = uwsgi_str2_num(date + 5);
|
||||
|
||||
switch (date[8]) {
|
||||
case 'J':
|
||||
if (date[9] == 'a') {
|
||||
hdtm.tm_mon = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (date[9] == 'u') {
|
||||
if (date[10] == 'n') {
|
||||
hdtm.tm_mon = 5;
|
||||
break;
|
||||
}
|
||||
|
||||
if (date[10] == 'l') {
|
||||
hdtm.tm_mon = 6;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
case 'F':
|
||||
hdtm.tm_mon = 1;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
if (date[9] != 'a')
|
||||
return 0;
|
||||
|
||||
if (date[10] == 'r') {
|
||||
hdtm.tm_mon = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (date[10] == 'y') {
|
||||
hdtm.tm_mon = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
case 'A':
|
||||
if (date[10] == 'r') {
|
||||
hdtm.tm_mon = 3;
|
||||
break;
|
||||
}
|
||||
if (date[10] == 'g') {
|
||||
hdtm.tm_mon = 7;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case 'S':
|
||||
hdtm.tm_mon = 8;
|
||||
break;
|
||||
|
||||
case 'O':
|
||||
hdtm.tm_mon = 9;
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
hdtm.tm_mon = 10;
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
hdtm.tm_mon = 11;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
hdtm.tm_year = uwsgi_str4_num(date + 12) - 1900;
|
||||
|
||||
hdtm.tm_hour = uwsgi_str2_num(date + 17);
|
||||
hdtm.tm_min = uwsgi_str2_num(date + 20);
|
||||
hdtm.tm_sec = uwsgi_str2_num(date + 23);
|
||||
|
||||
return timegm(&hdtm);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int uwsgi_add_expires_type(struct wsgi_request *wsgi_req, char *mime_type, int mime_type_len, struct stat *st) {
|
||||
|
||||
struct uwsgi_dyn_dict *udd = uwsgi.static_expires_type;
|
||||
time_t now = wsgi_req->start_of_request / 1000000;
|
||||
// 30+1
|
||||
char expires[31];
|
||||
|
||||
while (udd) {
|
||||
if (!uwsgi_strncmp(udd->key, udd->keylen, mime_type, mime_type_len)) {
|
||||
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
||||
int size = uwsgi_http_date(now + delta, expires);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
udd = uwsgi.static_expires_type_mtime;
|
||||
while (udd) {
|
||||
if (!uwsgi_strncmp(udd->key, udd->keylen, mime_type, mime_type_len)) {
|
||||
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
||||
int size = uwsgi_http_date(st->st_mtime + delta, expires);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
int uwsgi_add_expires(struct wsgi_request *wsgi_req, char *filename, int filename_len, struct stat *st) {
|
||||
|
||||
struct uwsgi_dyn_dict *udd = uwsgi.static_expires;
|
||||
time_t now = wsgi_req->start_of_request / 1000000;
|
||||
// 30+1
|
||||
char expires[31];
|
||||
|
||||
while (udd) {
|
||||
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, filename, filename_len) >= 0) {
|
||||
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
||||
int size = uwsgi_http_date(now + delta, expires);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
udd = uwsgi.static_expires_mtime;
|
||||
while (udd) {
|
||||
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, filename, filename_len) >= 0) {
|
||||
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
||||
int size = uwsgi_http_date(st->st_mtime + delta, expires);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_add_expires_path_info(struct wsgi_request *wsgi_req, struct stat *st) {
|
||||
|
||||
struct uwsgi_dyn_dict *udd = uwsgi.static_expires_path_info;
|
||||
time_t now = wsgi_req->start_of_request / 1000000;
|
||||
// 30+1
|
||||
char expires[31];
|
||||
|
||||
while (udd) {
|
||||
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->path_info, wsgi_req->path_info_len) >= 0) {
|
||||
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
||||
int size = uwsgi_http_date(now + delta, expires);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
udd = uwsgi.static_expires_path_info_mtime;
|
||||
while (udd) {
|
||||
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->path_info, wsgi_req->path_info_len) >= 0) {
|
||||
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
||||
int size = uwsgi_http_date(st->st_mtime + delta, expires);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_add_expires_uri(struct wsgi_request *wsgi_req, struct stat *st) {
|
||||
|
||||
struct uwsgi_dyn_dict *udd = uwsgi.static_expires_uri;
|
||||
time_t now = wsgi_req->start_of_request / 1000000;
|
||||
// 30+1
|
||||
char expires[31];
|
||||
|
||||
while (udd) {
|
||||
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->uri, wsgi_req->uri_len) >= 0) {
|
||||
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
||||
int size = uwsgi_http_date(now + delta, expires);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
udd = uwsgi.static_expires_uri_mtime;
|
||||
while (udd) {
|
||||
if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->uri, wsgi_req->uri_len) >= 0) {
|
||||
int delta = uwsgi_str_num(udd->value, udd->vallen);
|
||||
int size = uwsgi_http_date(st->st_mtime + delta, expires);
|
||||
if (size > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
char *uwsgi_get_mime_type(char *name, int namelen, size_t *size) {
|
||||
|
||||
int i;
|
||||
int count = 0;
|
||||
char *ext = NULL;
|
||||
for (i = namelen - 1; i >= 0; i--) {
|
||||
if (!isalnum((int) name[i])) {
|
||||
if (name[i] == '.') {
|
||||
ext = name + (namelen - count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!ext)
|
||||
return NULL;
|
||||
|
||||
|
||||
if (uwsgi.threads > 1)
|
||||
pthread_mutex_lock(&uwsgi.lock_static);
|
||||
|
||||
struct uwsgi_dyn_dict *udd = uwsgi.mimetypes;
|
||||
while (udd) {
|
||||
if (!uwsgi_strncmp(ext, count, udd->key, udd->keylen)) {
|
||||
udd->hits++;
|
||||
// auto optimization
|
||||
if (udd->prev) {
|
||||
if (udd->hits > udd->prev->hits) {
|
||||
struct uwsgi_dyn_dict *udd_parent = udd->prev->prev, *udd_prev = udd->prev;
|
||||
if (udd_parent) {
|
||||
udd_parent->next = udd;
|
||||
}
|
||||
|
||||
if (udd->next) {
|
||||
udd->next->prev = udd_prev;
|
||||
}
|
||||
|
||||
udd_prev->prev = udd;
|
||||
udd_prev->next = udd->next;
|
||||
|
||||
udd->prev = udd_parent;
|
||||
udd->next = udd_prev;
|
||||
|
||||
if (udd->prev == NULL) {
|
||||
uwsgi.mimetypes = udd;
|
||||
}
|
||||
}
|
||||
}
|
||||
*size = udd->vallen;
|
||||
if (uwsgi.threads > 1)
|
||||
pthread_mutex_unlock(&uwsgi.lock_static);
|
||||
return udd->value;
|
||||
}
|
||||
udd = udd->next;
|
||||
}
|
||||
|
||||
if (uwsgi.threads > 1)
|
||||
pthread_mutex_unlock(&uwsgi.lock_static);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssize_t uwsgi_append_static_path(char *dir, size_t dir_len, char *file, size_t file_len) {
|
||||
|
||||
|
||||
size_t len = dir_len;
|
||||
|
||||
if (len + 1 + file_len > PATH_MAX) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dir[len - 1] == '/') {
|
||||
memcpy(dir + len, file, file_len);
|
||||
dir[len + file_len] = 0;
|
||||
len += file_len;
|
||||
}
|
||||
else {
|
||||
dir[len] = '/';
|
||||
memcpy(dir + len + 1, file, file_len);
|
||||
dir[len + 1 + file_len] = 0;
|
||||
len += 1 + file_len;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int uwsgi_static_stat(struct wsgi_request *wsgi_req, char *filename, size_t *filename_len, struct stat *st, struct uwsgi_string_list **index) {
|
||||
|
||||
int ret = stat(filename, st);
|
||||
// if non-existant return -1
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
if (S_ISREG(st->st_mode))
|
||||
return 0;
|
||||
|
||||
// check for index
|
||||
if (S_ISDIR(st->st_mode)) {
|
||||
struct uwsgi_string_list *usl = uwsgi.static_index;
|
||||
while (usl) {
|
||||
ssize_t new_len = uwsgi_append_static_path(filename, *filename_len, usl->value, usl->len);
|
||||
if (new_len >= 0) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("checking for %s\n", filename);
|
||||
#endif
|
||||
if (uwsgi_is_file2(filename, st)) {
|
||||
*index = usl;
|
||||
*filename_len = new_len;
|
||||
return 0;
|
||||
}
|
||||
// reset to original name
|
||||
filename[*filename_len] = 0;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, size_t real_filename_len, struct stat *st) {
|
||||
|
||||
size_t mime_type_size = 0;
|
||||
char http_last_modified[49];
|
||||
int use_gzip = 0;
|
||||
|
||||
char *mime_type = uwsgi_get_mime_type(real_filename, real_filename_len, &mime_type_size);
|
||||
|
||||
// here we need to choose if we want the gzip variant;
|
||||
if (uwsgi_static_want_gzip(wsgi_req, real_filename, real_filename_len, st)) use_gzip = 1;
|
||||
|
||||
if (wsgi_req->if_modified_since_len) {
|
||||
time_t ims = parse_http_date(wsgi_req->if_modified_since, wsgi_req->if_modified_since_len);
|
||||
if (st->st_mtime <= ims) {
|
||||
uwsgi_response_prepare_headers(wsgi_req, "304 Not Modified", 16);
|
||||
return uwsgi_response_write_headers_do(wsgi_req);
|
||||
}
|
||||
}
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("[uwsgi-fileserve] file %s found\n", real_filename);
|
||||
#endif
|
||||
|
||||
|
||||
size_t fsize = st->st_size;
|
||||
if (wsgi_req->range_to) {
|
||||
fsize = wsgi_req->range_to - wsgi_req->range_from;
|
||||
if (fsize > (size_t)st->st_size) {
|
||||
fsize = st->st_size;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// reset in case of inconsistent size
|
||||
if (wsgi_req->range_from > fsize) {
|
||||
wsgi_req->range_from = 0;
|
||||
fsize = 0;
|
||||
}
|
||||
else {
|
||||
fsize -= wsgi_req->range_from;
|
||||
}
|
||||
}
|
||||
|
||||
// HTTP status
|
||||
if (fsize > 0 && (wsgi_req->range_from || wsgi_req->range_to)) {
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "206 Partial Content", 19)) return -1;
|
||||
}
|
||||
else {
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
uwsgi_add_expires(wsgi_req, real_filename, real_filename_len, st);
|
||||
uwsgi_add_expires_path_info(wsgi_req, st);
|
||||
uwsgi_add_expires_uri(wsgi_req, st);
|
||||
#endif
|
||||
|
||||
if (use_gzip) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "gzip", 4)) return -1;
|
||||
}
|
||||
|
||||
// Content-Type (if available)
|
||||
if (mime_type_size > 0 && mime_type) {
|
||||
if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_size)) return -1;
|
||||
// check for content-type related headers
|
||||
uwsgi_add_expires_type(wsgi_req, mime_type, mime_type_size, st);
|
||||
}
|
||||
|
||||
// increase static requests counter
|
||||
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].static_requests++;
|
||||
|
||||
// nginx
|
||||
if (uwsgi.file_serve_mode == 1) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "X-Accel-Redirect", 16, real_filename, real_filename_len)) return -1;
|
||||
// this is the final header (\r\n added)
|
||||
int size = uwsgi_http_date(st->st_mtime, http_last_modified);
|
||||
if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
|
||||
}
|
||||
// apache
|
||||
else if (uwsgi.file_serve_mode == 2) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "X-Sendfile", 10, real_filename, real_filename_len)) return -1;
|
||||
// this is the final header (\r\n added)
|
||||
int size = uwsgi_http_date(st->st_mtime, http_last_modified);
|
||||
if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
|
||||
}
|
||||
// raw
|
||||
else {
|
||||
// set Content-Length (to fsize NOT st->st_size)
|
||||
if (uwsgi_response_add_content_length(wsgi_req, fsize)) return -1;
|
||||
if (fsize > 0 && (wsgi_req->range_from || wsgi_req->range_to)) {
|
||||
// here use the original size !!!
|
||||
if (uwsgi_response_add_content_range(wsgi_req, wsgi_req->range_from, wsgi_req->range_to, st->st_size)) return -1;
|
||||
}
|
||||
int size = uwsgi_http_date(st->st_mtime, http_last_modified);
|
||||
if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
|
||||
|
||||
// if it is a HEAD request just skip transfer
|
||||
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) {
|
||||
wsgi_req->status = 200;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Ok, the file must be transferred from uWSGI
|
||||
// offloading will be automatically managed
|
||||
int fd = open(real_filename, O_RDONLY);
|
||||
if (fd < 0) return -1;
|
||||
// fd will be closed in the following function
|
||||
uwsgi_response_sendfile_do(wsgi_req, fd, wsgi_req->range_from, fsize);
|
||||
}
|
||||
|
||||
wsgi_req->status = 200;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_t document_root_len, char *path_info, uint16_t path_info_len, int is_a_file) {
|
||||
|
||||
struct stat st;
|
||||
char real_filename[PATH_MAX + 1];
|
||||
size_t real_filename_len = 0;
|
||||
char *filename = NULL;
|
||||
size_t filename_len = 0;
|
||||
|
||||
struct uwsgi_string_list *index = NULL;
|
||||
|
||||
if (!is_a_file) {
|
||||
filename = uwsgi_concat3n(document_root, document_root_len, "/", 1, path_info, path_info_len);
|
||||
filename_len = document_root_len + 1 + path_info_len;
|
||||
}
|
||||
else {
|
||||
filename = uwsgi_concat2n(document_root, document_root_len, "", 0);
|
||||
filename_len = document_root_len;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("[uwsgi-fileserve] checking for %s\n", filename);
|
||||
#endif
|
||||
|
||||
if (uwsgi.static_cache_paths) {
|
||||
uwsgi_rlock(uwsgi.static_cache_paths->lock);
|
||||
uint64_t item_len;
|
||||
char *item = uwsgi_cache_get2(uwsgi.static_cache_paths, filename, filename_len, &item_len);
|
||||
if (item && item_len > 0 && item_len <= PATH_MAX) {
|
||||
memcpy(real_filename, item, item_len);
|
||||
real_filename_len = item_len;
|
||||
uwsgi_rwunlock(uwsgi.static_cache_paths->lock);
|
||||
goto found;
|
||||
}
|
||||
uwsgi_rwunlock(uwsgi.static_cache_paths->lock);
|
||||
}
|
||||
|
||||
if (!realpath(filename, real_filename)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("[uwsgi-fileserve] unable to get realpath() of the static file\n");
|
||||
#endif
|
||||
free(filename);
|
||||
return -1;
|
||||
}
|
||||
real_filename_len = strlen(real_filename);
|
||||
|
||||
if (uwsgi.static_cache_paths) {
|
||||
uwsgi_wlock(uwsgi.static_cache_paths->lock);
|
||||
uwsgi_cache_set2(uwsgi.static_cache_paths, filename, filename_len, real_filename, real_filename_len, uwsgi.use_static_cache_paths, UWSGI_CACHE_FLAG_UPDATE);
|
||||
uwsgi_rwunlock(uwsgi.static_cache_paths->lock);
|
||||
}
|
||||
|
||||
found:
|
||||
free(filename);
|
||||
|
||||
if (uwsgi_starts_with(real_filename, real_filename_len, document_root, document_root_len)) {
|
||||
struct uwsgi_string_list *safe = uwsgi.static_safe;
|
||||
while(safe) {
|
||||
if (!uwsgi_starts_with(real_filename, real_filename_len, safe->value, safe->len)) {
|
||||
goto safe;
|
||||
}
|
||||
safe = safe->next;
|
||||
}
|
||||
uwsgi_log("[uwsgi-fileserve] security error: %s is not under %.*s or a safe path\n", real_filename, document_root_len, document_root);
|
||||
return -1;
|
||||
}
|
||||
|
||||
safe:
|
||||
|
||||
if (!uwsgi_static_stat(wsgi_req, real_filename, &real_filename_len, &st, &index)) {
|
||||
|
||||
if (index) {
|
||||
// if we are here the PATH_INFO need to be changed
|
||||
if (uwsgi_req_append_path_info_with_index(wsgi_req, index->value, index->len)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// skip methods other than GET and HEAD
|
||||
if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "GET", 3) && uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// check for skippable ext
|
||||
struct uwsgi_string_list *sse = uwsgi.static_skip_ext;
|
||||
while (sse) {
|
||||
if (real_filename_len >= sse->len) {
|
||||
if (!uwsgi_strncmp(real_filename + (real_filename_len - sse->len), sse->len, sse->value, sse->len)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
sse = sse->next;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
// before sending the file, we need to check if some rule applies
|
||||
if (!wsgi_req->is_routing && uwsgi_apply_routes_do(wsgi_req, NULL, 0) == UWSGI_ROUTE_BREAK) {
|
||||
return 0;
|
||||
}
|
||||
wsgi_req->routes_applied = 1;
|
||||
#endif
|
||||
|
||||
return uwsgi_real_file_serve(wsgi_req, real_filename, real_filename_len, &st);
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
+467
-110
@@ -3,15 +3,22 @@
|
||||
utility functions for fast generating json output for the stats subsystem
|
||||
*/
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_stats *uwsgi_stats_new(size_t chunk_size) {
|
||||
struct uwsgi_stats *us = uwsgi_malloc(sizeof(struct uwsgi_stats));
|
||||
us->base = uwsgi_malloc(chunk_size);
|
||||
us->base[0] = '{';
|
||||
us->base[1] = '\n';
|
||||
us->pos = 2;
|
||||
us->pos = 1;
|
||||
us->chunk = chunk_size;
|
||||
us->size = chunk_size;
|
||||
us->tabs = 1;
|
||||
us->dirty = 0;
|
||||
us->minified = uwsgi.stats_minified;
|
||||
if (!us->minified) {
|
||||
us->base[1] = '\n';
|
||||
us->pos++;
|
||||
}
|
||||
return us;
|
||||
}
|
||||
|
||||
@@ -19,9 +26,10 @@ int uwsgi_stats_symbol(struct uwsgi_stats *us, char sym) {
|
||||
char *ptr = us->base + us->pos;
|
||||
char *watermark = us->base + us->size;
|
||||
|
||||
if (ptr+1 > watermark) {
|
||||
if (ptr + 1 > watermark) {
|
||||
char *new_base = realloc(us->base, us->size + us->chunk);
|
||||
if (!new_base) return -1;
|
||||
if (!new_base)
|
||||
return -1;
|
||||
us->base = new_base;
|
||||
us->size += us->chunk;
|
||||
ptr = us->base + us->pos;
|
||||
@@ -36,6 +44,8 @@ int uwsgi_stats_symbol_nl(struct uwsgi_stats *us, char sym) {
|
||||
if (uwsgi_stats_symbol(us, sym)) {
|
||||
return -1;
|
||||
}
|
||||
if (us->minified)
|
||||
return 0;
|
||||
return uwsgi_stats_symbol(us, '\n');
|
||||
}
|
||||
|
||||
@@ -45,24 +55,33 @@ int uwsgi_stats_comma(struct uwsgi_stats *us) {
|
||||
}
|
||||
|
||||
int uwsgi_stats_apply_tabs(struct uwsgi_stats *us) {
|
||||
if (us->minified)
|
||||
return 0;
|
||||
size_t i;
|
||||
for(i=0;i<us->tabs;i++) {
|
||||
if (uwsgi_stats_symbol(us, '\t')) return -1;
|
||||
for (i = 0; i < us->tabs; i++) {
|
||||
if (uwsgi_stats_symbol(us, '\t'))
|
||||
return -1;
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_stats_object_open(struct uwsgi_stats *us) {
|
||||
if (uwsgi_stats_apply_tabs(us)) return -1;
|
||||
us->tabs++;
|
||||
if (uwsgi_stats_apply_tabs(us))
|
||||
return -1;
|
||||
if (!us->minified)
|
||||
us->tabs++;
|
||||
return uwsgi_stats_symbol_nl(us, '{');
|
||||
}
|
||||
|
||||
int uwsgi_stats_object_close(struct uwsgi_stats *us) {
|
||||
if (uwsgi_stats_symbol(us, '\n')) return -1;
|
||||
us->tabs--;
|
||||
if (uwsgi_stats_apply_tabs(us)) return -1;
|
||||
if (!us->minified) {
|
||||
if (uwsgi_stats_symbol(us, '\n'))
|
||||
return -1;
|
||||
us->tabs--;
|
||||
if (uwsgi_stats_apply_tabs(us))
|
||||
return -1;
|
||||
}
|
||||
return uwsgi_stats_symbol(us, '}');
|
||||
}
|
||||
|
||||
@@ -72,161 +91,187 @@ int uwsgi_stats_list_open(struct uwsgi_stats *us) {
|
||||
}
|
||||
|
||||
int uwsgi_stats_list_close(struct uwsgi_stats *us) {
|
||||
if (uwsgi_stats_symbol(us, '\n')) return -1;
|
||||
us->tabs--;
|
||||
if (uwsgi_stats_apply_tabs(us)) return -1;
|
||||
if (!us->minified) {
|
||||
if (uwsgi_stats_symbol(us, '\n'))
|
||||
return -1;
|
||||
us->tabs--;
|
||||
if (uwsgi_stats_apply_tabs(us))
|
||||
return -1;
|
||||
}
|
||||
return uwsgi_stats_symbol(us, ']');
|
||||
}
|
||||
|
||||
int uwsgi_stats_keyval(struct uwsgi_stats *us, char *key, char *value) {
|
||||
|
||||
if (uwsgi_stats_apply_tabs(us)) return -1;
|
||||
if (uwsgi_stats_apply_tabs(us))
|
||||
return -1;
|
||||
|
||||
char *ptr = us->base + us->pos;
|
||||
char *watermark = us->base + us->size;
|
||||
size_t available = watermark - ptr ;
|
||||
size_t available = watermark - ptr;
|
||||
|
||||
int ret = snprintf(ptr, available, "\"%s\":\"%s\"", key, value);
|
||||
if (ret < 0) return -1;
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
while (ret >= (int) available) {
|
||||
char *new_base = realloc(us->base, us->size + us->chunk);
|
||||
if (!new_base) return -1;
|
||||
if (!new_base)
|
||||
return -1;
|
||||
us->base = new_base;
|
||||
us->size += us->chunk;
|
||||
ptr = us->base + us->pos;
|
||||
watermark = us->base + us->size;
|
||||
available = watermark - ptr ;
|
||||
available = watermark - ptr;
|
||||
ret = snprintf(ptr, available, "\"%s\":\"%s\"", key, value);
|
||||
if (ret < 0) return -1;
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
us->pos += ret;
|
||||
return 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_stats_keyval_comma(struct uwsgi_stats *us, char *key, char *value) {
|
||||
int ret = uwsgi_stats_keyval(us, key, value);
|
||||
if (ret) return -1;
|
||||
if (ret)
|
||||
return -1;
|
||||
return uwsgi_stats_comma(us);
|
||||
}
|
||||
|
||||
int uwsgi_stats_keyvalnum(struct uwsgi_stats *us, char *key, char *value, unsigned long long num) {
|
||||
|
||||
if (uwsgi_stats_apply_tabs(us)) return -1;
|
||||
if (uwsgi_stats_apply_tabs(us))
|
||||
return -1;
|
||||
|
||||
char *ptr = us->base + us->pos;
|
||||
char *watermark = us->base + us->size;
|
||||
size_t available = watermark - ptr ;
|
||||
char *ptr = us->base + us->pos;
|
||||
char *watermark = us->base + us->size;
|
||||
size_t available = watermark - ptr;
|
||||
|
||||
int ret = snprintf(ptr, available, "\"%s\":\"%s%llu\"", key, value, num);
|
||||
if (ret < 0) return -1;
|
||||
while (ret >= (int) available) {
|
||||
char *new_base = realloc(us->base, us->size + us->chunk);
|
||||
if (!new_base) return -1;
|
||||
int ret = snprintf(ptr, available, "\"%s\":\"%s%llu\"", key, value, num);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
while (ret >= (int) available) {
|
||||
char *new_base = realloc(us->base, us->size + us->chunk);
|
||||
if (!new_base)
|
||||
return -1;
|
||||
us->base = new_base;
|
||||
us->size += us->chunk;
|
||||
us->size += us->chunk;
|
||||
ptr = us->base + us->pos;
|
||||
watermark = us->base + us->size;
|
||||
available = watermark - ptr ;
|
||||
ret = snprintf(ptr, available, "\"%s\":\"%s%llu\"", key, value, num);
|
||||
if (ret < 0) return -1;
|
||||
}
|
||||
watermark = us->base + us->size;
|
||||
available = watermark - ptr;
|
||||
ret = snprintf(ptr, available, "\"%s\":\"%s%llu\"", key, value, num);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
us->pos += ret;
|
||||
return 0;
|
||||
|
||||
us->pos += ret;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_stats_keyvalnum_comma(struct uwsgi_stats *us, char *key, char *value, unsigned long long num) {
|
||||
int ret = uwsgi_stats_keyvalnum(us, key, value, num);
|
||||
if (ret) return -1;
|
||||
return uwsgi_stats_comma(us);
|
||||
int ret = uwsgi_stats_keyvalnum(us, key, value, num);
|
||||
if (ret)
|
||||
return -1;
|
||||
return uwsgi_stats_comma(us);
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_stats_keyvaln(struct uwsgi_stats *us, char *key, char *value, int vallen) {
|
||||
|
||||
if (uwsgi_stats_apply_tabs(us)) return -1;
|
||||
if (uwsgi_stats_apply_tabs(us))
|
||||
return -1;
|
||||
|
||||
char *ptr = us->base + us->pos;
|
||||
char *watermark = us->base + us->size;
|
||||
size_t available = watermark - ptr ;
|
||||
char *ptr = us->base + us->pos;
|
||||
char *watermark = us->base + us->size;
|
||||
size_t available = watermark - ptr;
|
||||
|
||||
int ret = snprintf(ptr, available, "\"%s\":\"%.*s\"", key, vallen, value);
|
||||
if (ret < 0) return -1;
|
||||
while (ret >= (int) available) {
|
||||
char *new_base = realloc(us->base, us->size + us->chunk);
|
||||
if (!new_base) return -1;
|
||||
int ret = snprintf(ptr, available, "\"%s\":\"%.*s\"", key, vallen, value);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
while (ret >= (int) available) {
|
||||
char *new_base = realloc(us->base, us->size + us->chunk);
|
||||
if (!new_base)
|
||||
return -1;
|
||||
us->base = new_base;
|
||||
us->size += us->chunk;
|
||||
us->size += us->chunk;
|
||||
ptr = us->base + us->pos;
|
||||
watermark = us->base + us->size;
|
||||
available = watermark - ptr ;
|
||||
ret = snprintf(ptr, available, "\"%s\":\"%.*s\"", key, vallen, value);
|
||||
if (ret < 0) return -1;
|
||||
}
|
||||
watermark = us->base + us->size;
|
||||
available = watermark - ptr;
|
||||
ret = snprintf(ptr, available, "\"%s\":\"%.*s\"", key, vallen, value);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
us->pos += ret;
|
||||
return 0;
|
||||
|
||||
us->pos += ret;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_stats_keyvaln_comma(struct uwsgi_stats *us, char *key, char *value, int vallen) {
|
||||
int ret = uwsgi_stats_keyvaln(us, key, value, vallen);
|
||||
if (ret) return -1;
|
||||
return uwsgi_stats_comma(us);
|
||||
int ret = uwsgi_stats_keyvaln(us, key, value, vallen);
|
||||
if (ret)
|
||||
return -1;
|
||||
return uwsgi_stats_comma(us);
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_stats_key(struct uwsgi_stats *us, char *key) {
|
||||
|
||||
if (uwsgi_stats_apply_tabs(us)) return -1;
|
||||
if (uwsgi_stats_apply_tabs(us))
|
||||
return -1;
|
||||
|
||||
char *ptr = us->base + us->pos;
|
||||
char *watermark = us->base + us->size;
|
||||
size_t available = watermark - ptr ;
|
||||
char *ptr = us->base + us->pos;
|
||||
char *watermark = us->base + us->size;
|
||||
size_t available = watermark - ptr;
|
||||
|
||||
int ret = snprintf(ptr, available, "\"%s\":", key);
|
||||
if (ret < 0) return -1;
|
||||
while (ret >= (int) available) {
|
||||
char *new_base = realloc(us->base, us->size + us->chunk);
|
||||
if (!new_base) return -1;
|
||||
int ret = snprintf(ptr, available, "\"%s\":", key);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
while (ret >= (int) available) {
|
||||
char *new_base = realloc(us->base, us->size + us->chunk);
|
||||
if (!new_base)
|
||||
return -1;
|
||||
us->base = new_base;
|
||||
us->size += us->chunk;
|
||||
us->size += us->chunk;
|
||||
ptr = us->base + us->pos;
|
||||
watermark = us->base + us->size;
|
||||
available = watermark - ptr ;
|
||||
ret = snprintf(ptr, available, "\"%s\":", key);
|
||||
if (ret < 0) return -1;
|
||||
}
|
||||
watermark = us->base + us->size;
|
||||
available = watermark - ptr;
|
||||
ret = snprintf(ptr, available, "\"%s\":", key);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
us->pos += ret;
|
||||
return 0;
|
||||
us->pos += ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_stats_str(struct uwsgi_stats *us, char *str) {
|
||||
|
||||
char *ptr = us->base + us->pos;
|
||||
char *watermark = us->base + us->size;
|
||||
size_t available = watermark - ptr ;
|
||||
char *ptr = us->base + us->pos;
|
||||
char *watermark = us->base + us->size;
|
||||
size_t available = watermark - ptr;
|
||||
|
||||
int ret = snprintf(ptr, available, "\"%s\"", str);
|
||||
if (ret < 0) return -1;
|
||||
while (ret >= (int) available) {
|
||||
char *new_base = realloc(us->base, us->size + us->chunk);
|
||||
if (!new_base) return -1;
|
||||
int ret = snprintf(ptr, available, "\"%s\"", str);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
while (ret >= (int) available) {
|
||||
char *new_base = realloc(us->base, us->size + us->chunk);
|
||||
if (!new_base)
|
||||
return -1;
|
||||
us->base = new_base;
|
||||
us->size += us->chunk;
|
||||
us->size += us->chunk;
|
||||
ptr = us->base + us->pos;
|
||||
watermark = us->base + us->size;
|
||||
available = watermark - ptr ;
|
||||
ret = snprintf(ptr, available, "\"%s\"", str);
|
||||
if (ret < 0) return -1;
|
||||
}
|
||||
watermark = us->base + us->size;
|
||||
available = watermark - ptr;
|
||||
ret = snprintf(ptr, available, "\"%s\"", str);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
us->pos += ret;
|
||||
return 0;
|
||||
us->pos += ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -234,24 +279,66 @@ int uwsgi_stats_str(struct uwsgi_stats *us, char *str) {
|
||||
|
||||
int uwsgi_stats_keylong(struct uwsgi_stats *us, char *key, unsigned long long num) {
|
||||
|
||||
if (uwsgi_stats_apply_tabs(us)) return -1;
|
||||
if (uwsgi_stats_apply_tabs(us))
|
||||
return -1;
|
||||
|
||||
char *ptr = us->base + us->pos;
|
||||
char *watermark = us->base + us->size;
|
||||
size_t available = watermark - ptr;
|
||||
|
||||
int ret = snprintf(ptr, available, "\"%s\":%llu", key, num);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
while (ret >= (int) available) {
|
||||
char *new_base = realloc(us->base, us->size + us->chunk);
|
||||
if (!new_base)
|
||||
return -1;
|
||||
us->base = new_base;
|
||||
us->size += us->chunk;
|
||||
ptr = us->base + us->pos;
|
||||
watermark = us->base + us->size;
|
||||
available = watermark - ptr;
|
||||
ret = snprintf(ptr, available, "\"%s\":%llu", key, num);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
us->pos += ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_stats_keylong_comma(struct uwsgi_stats *us, char *key, unsigned long long num) {
|
||||
int ret = uwsgi_stats_keylong(us, key, num);
|
||||
if (ret)
|
||||
return -1;
|
||||
return uwsgi_stats_comma(us);
|
||||
}
|
||||
|
||||
int uwsgi_stats_keyslong(struct uwsgi_stats *us, char *key, long long num) {
|
||||
|
||||
if (uwsgi_stats_apply_tabs(us))
|
||||
return -1;
|
||||
|
||||
char *ptr = us->base + us->pos;
|
||||
char *watermark = us->base + us->size;
|
||||
size_t available = watermark - ptr ;
|
||||
size_t available = watermark - ptr;
|
||||
|
||||
int ret = snprintf(ptr, available, "\"%s\":%llu", key, num);
|
||||
if (ret < 0) return -1;
|
||||
int ret = snprintf(ptr, available, "\"%s\":%lld", key, num);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
while (ret >= (int) available) {
|
||||
char *new_base = realloc(us->base, us->size + us->chunk);
|
||||
if (!new_base) return -1;
|
||||
us->base = new_base;
|
||||
if (!new_base)
|
||||
return -1;
|
||||
us->base = new_base;
|
||||
us->size += us->chunk;
|
||||
ptr = us->base + us->pos;
|
||||
ptr = us->base + us->pos;
|
||||
watermark = us->base + us->size;
|
||||
available = watermark - ptr ;
|
||||
ret = snprintf(ptr, available, "\"%s\":%llu", key, num);
|
||||
if (ret < 0) return -1;
|
||||
available = watermark - ptr;
|
||||
ret = snprintf(ptr, available, "\"%s\":%lld", key, num);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
us->pos += ret;
|
||||
@@ -259,8 +346,278 @@ int uwsgi_stats_keylong(struct uwsgi_stats *us, char *key, unsigned long long nu
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_stats_keylong_comma(struct uwsgi_stats *us, char *key, unsigned long long num) {
|
||||
int ret = uwsgi_stats_keylong(us, key, num);
|
||||
int uwsgi_stats_keyslong_comma(struct uwsgi_stats *us, char *key, long long num) {
|
||||
int ret = uwsgi_stats_keyslong(us, key, num);
|
||||
if (ret)
|
||||
return -1;
|
||||
return uwsgi_stats_comma(us);
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_send_stats(int fd, struct uwsgi_stats *(*func) (void)) {
|
||||
|
||||
struct sockaddr_un client_src;
|
||||
socklen_t client_src_len = 0;
|
||||
|
||||
int client_fd = accept(fd, (struct sockaddr *) &client_src, &client_src_len);
|
||||
if (client_fd < 0) {
|
||||
uwsgi_error("accept()");
|
||||
return;
|
||||
}
|
||||
|
||||
if (uwsgi.stats_http) {
|
||||
if (uwsgi_send_http_stats(client_fd)) {
|
||||
close(client_fd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_stats *us = func();
|
||||
if (!us)
|
||||
goto end;
|
||||
|
||||
size_t remains = us->pos;
|
||||
off_t pos = 0;
|
||||
while (remains > 0) {
|
||||
int ret = uwsgi_waitfd_write(client_fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (ret <= 0) {
|
||||
goto end0;
|
||||
}
|
||||
ssize_t res = write(client_fd, us->base + pos, remains);
|
||||
if (res <= 0) {
|
||||
if (res < 0) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
goto end0;
|
||||
}
|
||||
pos += res;
|
||||
remains -= res;
|
||||
}
|
||||
|
||||
end0:
|
||||
free(us->base);
|
||||
free(us);
|
||||
|
||||
end:
|
||||
close(client_fd);
|
||||
}
|
||||
|
||||
struct uwsgi_stats_pusher *uwsgi_stats_pusher_get(char *name) {
|
||||
struct uwsgi_stats_pusher *usp = uwsgi.stats_pushers;
|
||||
while (usp) {
|
||||
if (!strcmp(usp->name, name)) {
|
||||
return usp;
|
||||
}
|
||||
usp = usp->next;
|
||||
}
|
||||
return usp;
|
||||
}
|
||||
|
||||
struct uwsgi_stats_pusher_instance *uwsgi_stats_pusher_add(struct uwsgi_stats_pusher *pusher, char *arg) {
|
||||
struct uwsgi_stats_pusher_instance *old_uspi = NULL, *uspi = uwsgi.stats_pusher_instances;
|
||||
while (uspi) {
|
||||
old_uspi = uspi;
|
||||
uspi = uspi->next;
|
||||
}
|
||||
|
||||
uspi = uwsgi_calloc(sizeof(struct uwsgi_stats_pusher_instance));
|
||||
uspi->pusher = pusher;
|
||||
if (arg) {
|
||||
uspi->arg = uwsgi_str(arg);
|
||||
}
|
||||
uspi->raw = pusher->raw;
|
||||
if (old_uspi) {
|
||||
old_uspi->next = uspi;
|
||||
}
|
||||
else {
|
||||
uwsgi.stats_pusher_instances = uspi;
|
||||
}
|
||||
|
||||
return uspi;
|
||||
}
|
||||
|
||||
void uwsgi_stats_pusher_loop(struct uwsgi_thread *ut) {
|
||||
void *events = event_queue_alloc(1);
|
||||
for (;;) {
|
||||
int nevents = event_queue_wait_multi(ut->queue, 1, events, 1);
|
||||
if (nevents > 0) {
|
||||
int interesting_fd = event_queue_interesting_fd(events, 0);
|
||||
char buf[4096];
|
||||
ssize_t len = read(interesting_fd, buf, 4096);
|
||||
if (len <= 0) {
|
||||
uwsgi_log("[uwsgi-stats-pusher] goodbye...\n");
|
||||
return;
|
||||
}
|
||||
uwsgi_log("[uwsgi-stats-pusher] message received from master: %.*s\n", (int) len, buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
time_t now = uwsgi_now();
|
||||
struct uwsgi_stats_pusher_instance *uspi = uwsgi.stats_pusher_instances;
|
||||
struct uwsgi_stats *us = NULL;
|
||||
while (uspi) {
|
||||
int delta = uspi->freq ? uspi->freq : uwsgi.stats_pusher_default_freq;
|
||||
if ((uspi->last_run + delta) <= now) {
|
||||
if (uspi->raw) {
|
||||
uspi->pusher->func(uspi, now, NULL, 0);
|
||||
}
|
||||
else {
|
||||
if (!us) {
|
||||
us = uwsgi_master_generate_stats();
|
||||
if (!us)
|
||||
goto next;
|
||||
}
|
||||
uspi->pusher->func(uspi, now, us->base, us->pos);
|
||||
}
|
||||
uspi->last_run = now;
|
||||
}
|
||||
next:
|
||||
uspi = uspi->next;
|
||||
}
|
||||
|
||||
if (us) {
|
||||
free(us->base);
|
||||
free(us);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_stats_pusher_setup() {
|
||||
struct uwsgi_string_list *usl = uwsgi.requested_stats_pushers;
|
||||
while (usl) {
|
||||
char *ssp = uwsgi_str(usl->value);
|
||||
struct uwsgi_stats_pusher *pusher = NULL;
|
||||
char *colon = strchr(ssp, ':');
|
||||
if (colon) {
|
||||
*colon = 0;
|
||||
}
|
||||
pusher = uwsgi_stats_pusher_get(ssp);
|
||||
if (!pusher) {
|
||||
uwsgi_log("unable to find \"%s\" stats_pusher\n", ssp);
|
||||
free(ssp);
|
||||
exit(1);
|
||||
}
|
||||
char *arg = NULL;
|
||||
if (colon) {
|
||||
arg = colon + 1;
|
||||
*colon = ':';
|
||||
}
|
||||
uwsgi_stats_pusher_add(pusher, arg);
|
||||
usl = usl->next;
|
||||
free(ssp);
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_stats_pusher *uwsgi_register_stats_pusher(char *name, void (*func) (struct uwsgi_stats_pusher_instance *, time_t, char *, size_t)) {
|
||||
|
||||
struct uwsgi_stats_pusher *pusher = uwsgi.stats_pushers, *old_pusher = NULL;
|
||||
|
||||
while (pusher) {
|
||||
old_pusher = pusher;
|
||||
pusher = pusher->next;
|
||||
}
|
||||
|
||||
pusher = uwsgi_calloc(sizeof(struct uwsgi_stats_pusher));
|
||||
pusher->name = name;
|
||||
pusher->func = func;
|
||||
|
||||
if (old_pusher) {
|
||||
old_pusher->next = pusher;
|
||||
}
|
||||
else {
|
||||
uwsgi.stats_pushers = pusher;
|
||||
}
|
||||
|
||||
return pusher;
|
||||
}
|
||||
|
||||
struct uwsgi_stats_pusher_file_conf {
|
||||
char *path;
|
||||
char *freq;
|
||||
char *separator;
|
||||
};
|
||||
|
||||
void uwsgi_stats_pusher_file(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) {
|
||||
struct uwsgi_stats_pusher_file_conf *uspic = (struct uwsgi_stats_pusher_file_conf *) uspi->data;
|
||||
if (!uspi->configured) {
|
||||
uspic = uwsgi_calloc(sizeof(struct uwsgi_stats_pusher_file_conf));
|
||||
if (uspi->arg) {
|
||||
if (uwsgi_kvlist_parse(uspi->arg, strlen(uspi->arg), ',', '=', "path", &uspic->path, "separator", &uspic->separator, "freq", &uspic->freq, NULL)) {
|
||||
free(uspi);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!uspic->path)
|
||||
uspic->path = "uwsgi.stats";
|
||||
if (!uspic->separator)
|
||||
uspic->separator = "\n\n";
|
||||
if (uspic->freq)
|
||||
uspi->freq = atoi(uspic->freq);
|
||||
uspi->configured = 1;
|
||||
uspi->data = uspic;
|
||||
}
|
||||
|
||||
int fd = open(uspic->path, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP);
|
||||
if (fd < 0) {
|
||||
uwsgi_error_open(uspic->path);
|
||||
return;
|
||||
}
|
||||
ssize_t rlen = write(fd, json, json_len);
|
||||
if (rlen != (ssize_t) json_len) {
|
||||
uwsgi_error("uwsgi_stats_pusher_file() -> write()\n");
|
||||
}
|
||||
|
||||
rlen = write(fd, uspic->separator, strlen(uspic->separator));
|
||||
if (rlen != (ssize_t) strlen(uspic->separator)) {
|
||||
uwsgi_error("uwsgi_stats_pusher_file() -> write()\n");
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void stats_dump_var(char *k, uint16_t kl, char *v, uint16_t vl, void *data) {
|
||||
struct uwsgi_stats *us = (struct uwsgi_stats *) data;
|
||||
if (us->dirty) return;
|
||||
uint16_t i;
|
||||
// replace " with '
|
||||
for(i=0;i<kl;i++) {
|
||||
if (k[i] == '"') {
|
||||
k[i] = '\'';
|
||||
}
|
||||
}
|
||||
for(i=0;i<vl;i++) {
|
||||
if (v[i] == '"') {
|
||||
v[i] = '\'';
|
||||
}
|
||||
}
|
||||
char *var = uwsgi_concat3n(k, kl, "=", 1, v,vl);
|
||||
if (uwsgi_stats_str(us, var)) {
|
||||
us->dirty = 1;
|
||||
free(var);
|
||||
return;
|
||||
}
|
||||
free(var);
|
||||
if (uwsgi_stats_comma(us)) {
|
||||
us->dirty = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int uwsgi_stats_dump_vars(struct uwsgi_stats *us, struct uwsgi_core *uc) {
|
||||
if (!uc->in_request) return 0;
|
||||
struct uwsgi_header *uh = (struct uwsgi_header *) uwsgi.workers[0].cores[0].buffer;
|
||||
uint16_t pktsize = uh->pktsize;
|
||||
if (!pktsize) return 0;
|
||||
char *dst = uwsgi.workers[0].cores[0].buffer;
|
||||
memcpy(dst, uc->buffer+4, uwsgi.buffer_size);
|
||||
// ok now check if something changed...
|
||||
if (!uc->in_request) return 0;
|
||||
if (uh->pktsize != pktsize) return 0;
|
||||
if (memcmp(dst, uc->buffer+4, uwsgi.buffer_size)) return 0;
|
||||
// nothing changed let's dump vars
|
||||
int ret = uwsgi_hooked_parse(dst, pktsize, stats_dump_var, us);
|
||||
if (ret) return -1;
|
||||
return uwsgi_stats_comma(us);
|
||||
if (us->dirty) return -1;
|
||||
if (uwsgi_stats_str(us, "")) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#include "../uwsgi.h"
|
||||
|
||||
/*
|
||||
|
||||
Storage subsystem: filesystem-like abstraction
|
||||
|
||||
struct uwsgi_storage_engine {
|
||||
char *name;
|
||||
uint16_t name_len;
|
||||
int64_t (*get)(char *, uint16_t, char *, uint64_t, uint64_t, uint64_t);
|
||||
int64_t (*set)(char *, uint16_t, char *, uint64_t, uint64_t, uint64_t);
|
||||
};
|
||||
|
||||
struct uwsgi_storage {
|
||||
char *name;
|
||||
uint16_t name_len;
|
||||
struct uwsgi_storage_engine *engine;
|
||||
};
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
struct uwsgi_storage* uwsgi_storage_by_name(char *name, uint16_t name_len) {
|
||||
if (!name_len) {
|
||||
name_len = strlen(name);
|
||||
}
|
||||
struct uwsgi_storage *s = uwsgi.virtualdisks;
|
||||
while(s) {
|
||||
if (!uwsgi_strncmp(s->name, s->name_len, name, name_len)) {
|
||||
return s;
|
||||
}
|
||||
s = s->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int64_t uwsgi_storage_get(struct uwsgi_storage *storage, char *key, uint16_t key_len, char *out_buf, uint64_t pos, uint64_t size, uint64_t flags) {
|
||||
if (!storage->get) return -1;
|
||||
return storage->get(key, key_len, out_buf, pos, size, flags);
|
||||
}
|
||||
|
||||
int64_t uwsgi_storage_set(struct uwsgi_storage *storage, char *key, uint16_t key_len, char *in_buf, uint64_t pos, uint64_t size, uint64_t flags) {
|
||||
if (!storage->set) return -1;
|
||||
return storage->set(key, key_len, out_buf, pos, size, flags);
|
||||
}
|
||||
+340
@@ -0,0 +1,340 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
// check if a string_list contains an item
|
||||
struct uwsgi_string_list *uwsgi_string_list_has_item(struct uwsgi_string_list *list, char *key, size_t keylen) {
|
||||
struct uwsgi_string_list *usl = list;
|
||||
while (usl) {
|
||||
if (keylen == usl->len) {
|
||||
if (!memcmp(key, usl->value, keylen)) {
|
||||
return usl;
|
||||
}
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// lower a string
|
||||
char *uwsgi_lower(char *str, size_t size) {
|
||||
size_t i;
|
||||
for (i = 0; i < size; i++) {
|
||||
str[i] = tolower((int) str[i]);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
// check if a string is contained in another one
|
||||
char *uwsgi_str_contains(char *str, int slen, char what) {
|
||||
|
||||
int i;
|
||||
for (i = 0; i < slen; i++) {
|
||||
if (str[i] == what) {
|
||||
return str + i;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int uwsgi_contains_n(char *s1, size_t s1_len, char *s2, size_t s2_len) {
|
||||
size_t i;
|
||||
char *ptr = s2;
|
||||
for (i = 0; i < s1_len; i++) {
|
||||
if (s1[i] == *ptr) {
|
||||
ptr++;
|
||||
if (ptr == s2 + s2_len) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ptr = s2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// fast compare 2 sized strings
|
||||
int uwsgi_strncmp(char *src, int slen, char *dst, int dlen) {
|
||||
|
||||
if (slen != dlen)
|
||||
return 1;
|
||||
|
||||
return memcmp(src, dst, dlen);
|
||||
|
||||
}
|
||||
|
||||
// fast compare 2 sized strings (case insensitive)
|
||||
int uwsgi_strnicmp(char *src, int slen, char *dst, int dlen) {
|
||||
|
||||
if (slen != dlen)
|
||||
return 1;
|
||||
|
||||
return strncasecmp(src, dst, dlen);
|
||||
|
||||
}
|
||||
|
||||
// fast sized check of initial part of a string
|
||||
int uwsgi_starts_with(char *src, int slen, char *dst, int dlen) {
|
||||
|
||||
if (slen < dlen)
|
||||
return -1;
|
||||
|
||||
return memcmp(src, dst, dlen);
|
||||
}
|
||||
|
||||
|
||||
// unsized check
|
||||
int uwsgi_startswith(char *src, char *what, int wlen) {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < wlen; i++) {
|
||||
if (src[i] != what[i])
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// concatenate strings
|
||||
char *uwsgi_concatn(int c, ...) {
|
||||
|
||||
va_list s;
|
||||
char *item;
|
||||
int j = c;
|
||||
char *buf;
|
||||
size_t len = 1;
|
||||
size_t tlen = 1;
|
||||
|
||||
va_start(s, c);
|
||||
while (j > 0) {
|
||||
item = va_arg(s, char *);
|
||||
if (item == NULL) {
|
||||
break;
|
||||
}
|
||||
len += va_arg(s, int);
|
||||
j--;
|
||||
}
|
||||
va_end(s);
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
memset(buf, 0, len);
|
||||
|
||||
j = c;
|
||||
|
||||
len = 0;
|
||||
|
||||
va_start(s, c);
|
||||
while (j > 0) {
|
||||
item = va_arg(s, char *);
|
||||
if (item == NULL) {
|
||||
break;
|
||||
}
|
||||
tlen = va_arg(s, int);
|
||||
memcpy(buf + len, item, tlen);
|
||||
len += tlen;
|
||||
j--;
|
||||
}
|
||||
va_end(s);
|
||||
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_concat2(char *one, char *two) {
|
||||
|
||||
char *buf;
|
||||
size_t len = strlen(one) + strlen(two) + 1;
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
buf[len - 1] = 0;
|
||||
|
||||
memcpy(buf, one, strlen(one));
|
||||
memcpy(buf + strlen(one), two, strlen(two));
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_concat4(char *one, char *two, char *three, char *four) {
|
||||
|
||||
char *buf;
|
||||
size_t len = strlen(one) + strlen(two) + strlen(three) + strlen(four) + 1;
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
buf[len - 1] = 0;
|
||||
|
||||
memcpy(buf, one, strlen(one));
|
||||
memcpy(buf + strlen(one), two, strlen(two));
|
||||
memcpy(buf + strlen(one) + strlen(two), three, strlen(three));
|
||||
memcpy(buf + strlen(one) + strlen(two) + strlen(three), four, strlen(four));
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_concat3(char *one, char *two, char *three) {
|
||||
|
||||
char *buf;
|
||||
size_t len = strlen(one) + strlen(two) + strlen(three) + 1;
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
buf[len - 1] = 0;
|
||||
|
||||
memcpy(buf, one, strlen(one));
|
||||
memcpy(buf + strlen(one), two, strlen(two));
|
||||
memcpy(buf + strlen(one) + strlen(two), three, strlen(three));
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_concat2n(char *one, int s1, char *two, int s2) {
|
||||
|
||||
char *buf;
|
||||
size_t len = s1 + s2 + 1;
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
buf[len - 1] = 0;
|
||||
|
||||
memcpy(buf, one, s1);
|
||||
memcpy(buf + s1, two, s2);
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_concat2nn(char *one, int s1, char *two, int s2, int *len) {
|
||||
|
||||
char *buf;
|
||||
*len = s1 + s2 + 1;
|
||||
|
||||
|
||||
buf = uwsgi_malloc(*len);
|
||||
buf[*len - 1] = 0;
|
||||
|
||||
memcpy(buf, one, s1);
|
||||
memcpy(buf + s1, two, s2);
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_concat3n(char *one, int s1, char *two, int s2, char *three, int s3) {
|
||||
|
||||
char *buf;
|
||||
size_t len = s1 + s2 + s3 + 1;
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
buf[len - 1] = 0;
|
||||
|
||||
memcpy(buf, one, s1);
|
||||
memcpy(buf + s1, two, s2);
|
||||
memcpy(buf + s1 + s2, three, s3);
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_concat4n(char *one, int s1, char *two, int s2, char *three, int s3, char *four, int s4) {
|
||||
|
||||
char *buf;
|
||||
size_t len = s1 + s2 + s3 + s4 + 1;
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
buf[len - 1] = 0;
|
||||
|
||||
memcpy(buf, one, s1);
|
||||
memcpy(buf + s1, two, s2);
|
||||
memcpy(buf + s1 + s2, three, s3);
|
||||
memcpy(buf + s1 + s2 + s3, four, s4);
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
// concat unsized strings
|
||||
char *uwsgi_concat(int c, ...) {
|
||||
|
||||
va_list s;
|
||||
char *item;
|
||||
size_t len = 1;
|
||||
int j = c;
|
||||
char *buf;
|
||||
|
||||
va_start(s, c);
|
||||
while (j > 0) {
|
||||
item = va_arg(s, char *);
|
||||
if (item == NULL) {
|
||||
break;
|
||||
}
|
||||
len += (int) strlen(item);
|
||||
j--;
|
||||
}
|
||||
va_end(s);
|
||||
|
||||
|
||||
buf = uwsgi_malloc(len);
|
||||
memset(buf, 0, len);
|
||||
|
||||
j = c;
|
||||
|
||||
len = 0;
|
||||
|
||||
va_start(s, c);
|
||||
while (j > 0) {
|
||||
item = va_arg(s, char *);
|
||||
if (item == NULL) {
|
||||
break;
|
||||
}
|
||||
memcpy(buf + len, item, strlen(item));
|
||||
len += strlen(item);
|
||||
j--;
|
||||
}
|
||||
va_end(s);
|
||||
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_strncopy(char *s, int len) {
|
||||
|
||||
char *buf;
|
||||
|
||||
buf = uwsgi_malloc(len + 1);
|
||||
buf[len] = 0;
|
||||
|
||||
memcpy(buf, s, len);
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
// this move a string back of one char and put a 0 at the end (used in uwsgi parsers for buffer reusing)
|
||||
char *uwsgi_cheap_string(char *buf, int len) {
|
||||
|
||||
int i;
|
||||
char *cheap_buf = buf - 1;
|
||||
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
*cheap_buf++ = buf[i];
|
||||
}
|
||||
|
||||
|
||||
buf[len - 1] = 0;
|
||||
|
||||
return buf - 1;
|
||||
}
|
||||
|
||||
+535
-422
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,56 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
|
||||
uWSGI timebomb
|
||||
|
||||
this is a simple thread waiting for a timeout and calling exit
|
||||
with the specified value.
|
||||
|
||||
You can use it as a last resort in async apps that could block
|
||||
normal uWSGI behaviours
|
||||
|
||||
*/
|
||||
|
||||
struct time_bomb {
|
||||
int timeout;
|
||||
int exit_code;
|
||||
};
|
||||
|
||||
static void *time_bomb(void *arg) {
|
||||
|
||||
// block all signals
|
||||
sigset_t smask;
|
||||
sigfillset(&smask);
|
||||
pthread_sigmask(SIG_BLOCK, &smask, NULL);
|
||||
|
||||
struct time_bomb *tb = (struct time_bomb *) arg;
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = tb->timeout;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
uwsgi_log_verbose("*** BOOOOOOM ***\n");
|
||||
exit(tb->exit_code);
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_time_bomb(int timeout, int exit_code) {
|
||||
|
||||
pthread_t time_bomb_thread;
|
||||
|
||||
struct time_bomb *tb = uwsgi_malloc(sizeof(struct time_bomb));
|
||||
tb->timeout = timeout;
|
||||
tb->exit_code = exit_code;
|
||||
|
||||
if (pthread_create(&time_bomb_thread, NULL, time_bomb, (void *) tb)) {
|
||||
uwsgi_error("pthread_create()");
|
||||
uwsgi_log("unable to setup the time bomb, goodbye\n");
|
||||
exit(exit_code);
|
||||
}
|
||||
else {
|
||||
uwsgi_log_verbose("Fire in the hole !!! (%d seconds to detonation)\n", timeout);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
|
||||
uWSGI transformations
|
||||
|
||||
each body chunk is passed (in chain) to every transformation
|
||||
|
||||
some of them supports streaming, other requires buffering
|
||||
|
||||
at the end of the request the "final chain" is called (and the whole chain freed)
|
||||
|
||||
Transformations (if required) could completely swallow already set headers
|
||||
|
||||
*/
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
// -1 error, 0 = no buffer, send the body, 1 = buffer
|
||||
int uwsgi_apply_transformations(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
wsgi_req->transformed_chunk = NULL;
|
||||
wsgi_req->transformed_chunk_len = 0;
|
||||
struct uwsgi_transformation *ut = wsgi_req->transformations;
|
||||
char *t_buf = buf;
|
||||
size_t t_len = len;
|
||||
uint8_t flushed = 0;
|
||||
while(ut) {
|
||||
// allocate the buffer (if needed)
|
||||
if (!ut->chunk) {
|
||||
ut->chunk = uwsgi_buffer_new(t_len);
|
||||
}
|
||||
// skip final transformations before appending data
|
||||
if (ut->is_final) goto next;
|
||||
if (uwsgi_buffer_append(ut->chunk, t_buf, t_len)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if the transformation cannot stream, continue buffering (the func will be called at the end)
|
||||
if (!ut->can_stream) return 1;
|
||||
|
||||
ut->round++;
|
||||
if (ut->func(wsgi_req, ut)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ut->flushed) flushed = 1;
|
||||
|
||||
t_buf = ut->chunk->buf;
|
||||
t_len = ut->chunk->pos;
|
||||
// we reset the buffer, so we do not waste memory
|
||||
ut->chunk->pos = 0;
|
||||
next:
|
||||
ut = ut->next;
|
||||
}
|
||||
|
||||
// if we are here we can tell the writer to send the body to the client
|
||||
// no buffering please
|
||||
if (!flushed) {
|
||||
wsgi_req->transformed_chunk = t_buf;
|
||||
wsgi_req->transformed_chunk_len = t_len;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
run all the remaining (or buffered) transformations
|
||||
|
||||
*/
|
||||
int uwsgi_apply_final_transformations(struct wsgi_request *wsgi_req) {
|
||||
struct uwsgi_transformation *ut = wsgi_req->transformations;
|
||||
wsgi_req->transformed_chunk = NULL;
|
||||
wsgi_req->transformed_chunk_len = 0;
|
||||
char *t_buf = NULL;
|
||||
size_t t_len = 0;
|
||||
uint8_t flushed = 0;
|
||||
int found_nostream = 0;
|
||||
while(ut) {
|
||||
if (!found_nostream) {
|
||||
if (!ut->can_stream) {
|
||||
found_nostream = 1;
|
||||
}
|
||||
else {
|
||||
t_buf = ut->chunk->buf;
|
||||
t_len = ut->chunk->pos;
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ut->chunk) {
|
||||
if (t_len > 0) {
|
||||
ut->chunk = uwsgi_buffer_new(t_len);
|
||||
}
|
||||
else {
|
||||
ut->chunk = uwsgi_buffer_new(uwsgi.page_size);
|
||||
}
|
||||
}
|
||||
|
||||
if (t_len > 0) {
|
||||
if (uwsgi_buffer_append(ut->chunk, t_buf, t_len)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// run the transformation
|
||||
ut->round++;
|
||||
if (ut->func(wsgi_req, ut)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ut->flushed) flushed = 1;
|
||||
|
||||
t_buf = ut->chunk->buf;
|
||||
t_len = ut->chunk->pos;
|
||||
next:
|
||||
ut = ut->next;
|
||||
}
|
||||
|
||||
// if we are here, all of the transformations are applied
|
||||
if (!flushed) {
|
||||
wsgi_req->transformed_chunk = t_buf;
|
||||
wsgi_req->transformed_chunk_len = t_len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uwsgi_free_transformations(struct wsgi_request *wsgi_req) {
|
||||
struct uwsgi_transformation *ut = wsgi_req->transformations;
|
||||
while(ut) {
|
||||
struct uwsgi_transformation *current_ut = ut;
|
||||
if (current_ut->chunk) {
|
||||
uwsgi_buffer_destroy(current_ut->chunk);
|
||||
}
|
||||
ut = ut->next;
|
||||
free(current_ut);
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_transformation *uwsgi_add_transformation(struct wsgi_request *wsgi_req, int (*func)(struct wsgi_request *, struct uwsgi_transformation *), void *data) {
|
||||
struct uwsgi_transformation *old_ut = NULL, *ut = wsgi_req->transformations;
|
||||
while(ut) {
|
||||
old_ut = ut;
|
||||
ut = ut->next;
|
||||
}
|
||||
|
||||
ut = uwsgi_malloc(sizeof(struct uwsgi_transformation));
|
||||
ut->func = func;
|
||||
ut->is_final = 0;
|
||||
ut->next = NULL;
|
||||
ut->chunk = NULL;
|
||||
ut->can_stream = 0;
|
||||
ut->data = data;
|
||||
|
||||
if (old_ut) {
|
||||
old_ut->next = ut;
|
||||
}
|
||||
else {
|
||||
wsgi_req->transformations = ut;
|
||||
}
|
||||
|
||||
return ut;
|
||||
}
|
||||
+1151
-1950
File diff suppressed because it is too large
Load Diff
+847
-533
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,359 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
/*
|
||||
|
||||
uWSGI websockets functions
|
||||
|
||||
sponsored by 20Tab S.r.l. <info@20tab.com>
|
||||
|
||||
*/
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
static struct uwsgi_buffer *uwsgi_websocket_message(char *msg, size_t len) {
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(10 + len);
|
||||
if (uwsgi_buffer_u8(ub, 0x81)) goto error;
|
||||
if (len < 126) {
|
||||
if (uwsgi_buffer_u8(ub, len)) goto error;
|
||||
}
|
||||
else if (len <= (uint16_t) 0xffff) {
|
||||
if (uwsgi_buffer_u8(ub, 126)) goto error;
|
||||
if (uwsgi_buffer_u16be(ub, len)) goto error;
|
||||
}
|
||||
else {
|
||||
if (uwsgi_buffer_u8(ub, 127)) goto error;
|
||||
if (uwsgi_buffer_u64be(ub, len)) goto error;
|
||||
}
|
||||
|
||||
if (uwsgi_buffer_append(ub, msg, len)) goto error;
|
||||
return ub;
|
||||
|
||||
error:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int uwsgi_websockets_ping(struct wsgi_request *wsgi_req) {
|
||||
if (uwsgi_response_write_body_do(wsgi_req, uwsgi.websockets_ping->buf, uwsgi.websockets_ping->pos)) {
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->websocket_last_ping = uwsgi_now();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_websockets_pong(struct wsgi_request *wsgi_req) {
|
||||
return uwsgi_response_write_body_do(wsgi_req, uwsgi.websockets_pong->buf, uwsgi.websockets_pong->pos);
|
||||
}
|
||||
|
||||
static int uwsgi_websockets_check_pingpong(struct wsgi_request *wsgi_req) {
|
||||
time_t now = uwsgi_now();
|
||||
// first round
|
||||
if (wsgi_req->websocket_last_ping == 0) {
|
||||
return uwsgi_websockets_ping(wsgi_req);
|
||||
}
|
||||
// pong not received ?
|
||||
if (wsgi_req->websocket_last_pong < wsgi_req->websocket_last_ping) {
|
||||
if (wsgi_req->websocket_last_ping - wsgi_req->websocket_last_pong > uwsgi.websockets_pong_tolerance) {
|
||||
uwsgi_log("[uwsgi-websocket] no PONG received in %d seconds !!!\n", uwsgi.websockets_pong_tolerance);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// pong received, send anther ping
|
||||
if (now - wsgi_req->websocket_last_ping >= uwsgi.websockets_ping_freq) {
|
||||
return uwsgi_websockets_ping(wsgi_req);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_websocket_send_do(struct wsgi_request *wsgi_req, char *msg, size_t len) {
|
||||
struct uwsgi_buffer *ub = uwsgi_websocket_message(msg, len);
|
||||
if (!ub) return -1;
|
||||
|
||||
ssize_t ret = uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_websocket_send(struct wsgi_request *wsgi_req, char *msg, size_t len) {
|
||||
if (wsgi_req->websocket_closed) {
|
||||
return -1;
|
||||
}
|
||||
ssize_t ret = uwsgi_websocket_send_do(wsgi_req, msg, len);
|
||||
if (ret < 0) {
|
||||
wsgi_req->websocket_closed = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void uwsgi_websocket_parse_header(struct wsgi_request *wsgi_req) {
|
||||
uint8_t byte1 = wsgi_req->websocket_buf->buf[0];
|
||||
uint8_t byte2 = wsgi_req->websocket_buf->buf[1];
|
||||
wsgi_req->websocket_opcode = byte1 & 0xf;
|
||||
wsgi_req->websocket_has_mask = byte2 >> 7;
|
||||
wsgi_req->websocket_size = byte2 & 0x7f;
|
||||
}
|
||||
|
||||
static struct uwsgi_buffer *uwsgi_websockets_parse(struct wsgi_request *wsgi_req) {
|
||||
// de-mask buffer
|
||||
uint8_t *ptr = (uint8_t *) (wsgi_req->websocket_buf->buf + (wsgi_req->websocket_pktsize - wsgi_req->websocket_size));
|
||||
size_t i;
|
||||
|
||||
if (wsgi_req->websocket_has_mask) {
|
||||
uint8_t *mask = ptr-4;
|
||||
for(i=0;i<wsgi_req->websocket_size;i++) {
|
||||
ptr[i] = ptr[i] ^ mask[i%4];
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(wsgi_req->websocket_size);
|
||||
if (uwsgi_buffer_append(ub, (char *) ptr, wsgi_req->websocket_size)) goto error;
|
||||
if (uwsgi_buffer_decapitate(wsgi_req->websocket_buf, wsgi_req->websocket_pktsize)) goto error;
|
||||
wsgi_req->websocket_phase = 0;
|
||||
wsgi_req->websocket_need = 2;
|
||||
return ub;
|
||||
error:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uwsgi_websockets_recv_pkt(struct wsgi_request *wsgi_req, int nb) {
|
||||
|
||||
int ret = -1;
|
||||
|
||||
for(;;) {
|
||||
ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->websocket_buf->buf + wsgi_req->websocket_buf->pos, wsgi_req->websocket_buf->len - wsgi_req->websocket_buf->pos);
|
||||
if (rlen > 0) return rlen;
|
||||
if (rlen == 0) return -1;
|
||||
if (rlen < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
if (nb) {
|
||||
if (uwsgi_websockets_check_pingpong(wsgi_req)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
goto wait;
|
||||
}
|
||||
uwsgi_error("uwsgi_websockets_recv_pkt()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wait:
|
||||
ret = uwsgi.wait_read_hook(wsgi_req->fd, uwsgi.websockets_ping_freq);
|
||||
if (ret > 0) {
|
||||
rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->websocket_buf->buf + wsgi_req->websocket_buf->pos, wsgi_req->websocket_buf->len - wsgi_req->websocket_buf->pos);
|
||||
if (rlen > 0) return rlen;
|
||||
if (rlen <= 0) return -1;
|
||||
}
|
||||
if (ret < 0) {
|
||||
uwsgi_error("uwsgi_websockets_recv_pkt()");
|
||||
return -1;
|
||||
}
|
||||
// send unsolicited pong
|
||||
if (uwsgi_websockets_check_pingpong(wsgi_req)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static struct uwsgi_buffer *uwsgi_websocket_recv_do(struct wsgi_request *wsgi_req, int nb) {
|
||||
if (!wsgi_req->websocket_buf) {
|
||||
// this buffer will be destroyed on connection close
|
||||
wsgi_req->websocket_buf = uwsgi_buffer_new(uwsgi.page_size);
|
||||
// need 2 byte header
|
||||
wsgi_req->websocket_need = 2;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
size_t remains = wsgi_req->websocket_buf->pos;
|
||||
// i have data;
|
||||
if (remains >= wsgi_req->websocket_need) {
|
||||
switch(wsgi_req->websocket_phase) {
|
||||
// header
|
||||
case 0:
|
||||
uwsgi_websocket_parse_header(wsgi_req);
|
||||
wsgi_req->websocket_pktsize = 2 + (wsgi_req->websocket_has_mask*4);
|
||||
if (wsgi_req->websocket_size == 126) {
|
||||
wsgi_req->websocket_need += 2;
|
||||
wsgi_req->websocket_phase = 1;
|
||||
wsgi_req->websocket_pktsize += 2;
|
||||
}
|
||||
else if (wsgi_req->websocket_size == 127) {
|
||||
wsgi_req->websocket_need += 8;
|
||||
wsgi_req->websocket_phase = 1;
|
||||
wsgi_req->websocket_pktsize += 8;
|
||||
}
|
||||
else {
|
||||
wsgi_req->websocket_phase = 2;
|
||||
}
|
||||
break;
|
||||
// size
|
||||
case 1:
|
||||
if (wsgi_req->websocket_size == 126) {
|
||||
wsgi_req->websocket_size = uwsgi_be16(wsgi_req->websocket_buf->buf+2);
|
||||
}
|
||||
else if (wsgi_req->websocket_size == 127) {
|
||||
wsgi_req->websocket_size = uwsgi_be64(wsgi_req->websocket_buf->buf+2);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[uwsgi-websocket] BUG error in websocket parser\n");
|
||||
return NULL;
|
||||
}
|
||||
if (wsgi_req->websocket_size > (uwsgi.websockets_max_size*1024)) {
|
||||
uwsgi_log("[uwsgi-websocket] invalid packet size received: %llu, max allowed: %llu\n", wsgi_req->websocket_size, uwsgi.websockets_max_size * 1024);
|
||||
return NULL;
|
||||
}
|
||||
wsgi_req->websocket_phase = 2;
|
||||
break;
|
||||
// mask check
|
||||
case 2:
|
||||
if (wsgi_req->websocket_has_mask) {
|
||||
wsgi_req->websocket_need += 4;
|
||||
wsgi_req->websocket_phase = 3;
|
||||
}
|
||||
else {
|
||||
wsgi_req->websocket_need += wsgi_req->websocket_size;
|
||||
wsgi_req->websocket_phase = 4;
|
||||
}
|
||||
break;
|
||||
// mask
|
||||
case 3:
|
||||
wsgi_req->websocket_pktsize += wsgi_req->websocket_size;
|
||||
wsgi_req->websocket_need += wsgi_req->websocket_size;
|
||||
wsgi_req->websocket_phase = 4;
|
||||
break;
|
||||
// message
|
||||
case 4:
|
||||
switch (wsgi_req->websocket_opcode) {
|
||||
// message
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
return uwsgi_websockets_parse(wsgi_req);
|
||||
// close
|
||||
case 0x8:
|
||||
return NULL;
|
||||
// ping
|
||||
case 0x9:
|
||||
if (uwsgi_websockets_pong(wsgi_req)) {
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
// pong
|
||||
case 0xA:
|
||||
wsgi_req->websocket_last_pong = uwsgi_now();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// reset the status
|
||||
wsgi_req->websocket_phase = 0;
|
||||
wsgi_req->websocket_need = 2;
|
||||
// decapitate the buffer
|
||||
if (uwsgi_buffer_decapitate(wsgi_req->websocket_buf, wsgi_req->websocket_pktsize)) return NULL;
|
||||
break;
|
||||
// oops
|
||||
default:
|
||||
uwsgi_log("[uwsgi-websocket] BUG error in websocket parser\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
// need more data
|
||||
else {
|
||||
if (uwsgi_buffer_ensure(wsgi_req->websocket_buf, uwsgi.page_size)) return NULL;
|
||||
ssize_t len = uwsgi_websockets_recv_pkt(wsgi_req, nb);
|
||||
if (len <= 0) {
|
||||
if (nb == 1 && len == 0) {
|
||||
// return an empty buffer to signal blocking event
|
||||
return uwsgi_buffer_new(0);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
// update buffer size
|
||||
wsgi_req->websocket_buf->pos+=len;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *uwsgi_websocket_recv(struct wsgi_request *wsgi_req) {
|
||||
if (wsgi_req->websocket_closed) {
|
||||
return NULL;
|
||||
}
|
||||
struct uwsgi_buffer *ub = uwsgi_websocket_recv_do(wsgi_req, 0);
|
||||
if (!ub) {
|
||||
wsgi_req->websocket_closed = 1;
|
||||
}
|
||||
return ub;
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *uwsgi_websocket_recv_nb(struct wsgi_request *wsgi_req) {
|
||||
if (wsgi_req->websocket_closed) {
|
||||
return NULL;
|
||||
}
|
||||
struct uwsgi_buffer *ub = uwsgi_websocket_recv_do(wsgi_req, 1);
|
||||
if (!ub) {
|
||||
wsgi_req->websocket_closed = 1;
|
||||
}
|
||||
return ub;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ssize_t uwsgi_websockets_simple_send(struct wsgi_request *wsgi_req, struct uwsgi_buffer *ub) {
|
||||
ssize_t len = wsgi_req->socket->proto_write(wsgi_req, ub->buf, ub->pos);
|
||||
if (wsgi_req->write_errors > 0) {
|
||||
return -1;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int uwsgi_websocket_handshake(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *origin, uint16_t origin_len) {
|
||||
#ifdef UWSGI_SSL
|
||||
char sha1[20];
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "101 Web Socket Protocol Handshake", 33)) return -1;
|
||||
if (uwsgi_response_add_header(wsgi_req, "Upgrade", 7, "WebSocket", 9)) return -1;
|
||||
if (uwsgi_response_add_header(wsgi_req, "Connection", 10, "Upgrade", 7)) return -1;
|
||||
if (origin_len > 0) {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Origin", 20, origin, origin_len)) return -1;
|
||||
}
|
||||
else {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Origin", 20, "*", 1)) return -1;
|
||||
}
|
||||
// generate websockets sha1 and encode it to base64
|
||||
if (!uwsgi_sha1_2n(key, key_len, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", 36, sha1)) return -1;
|
||||
size_t b64_len = 0;
|
||||
char *b64 = uwsgi_base64_encode(sha1, 20, &b64_len);
|
||||
if (!b64) return -1;
|
||||
|
||||
if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Accept", 20, b64, b64_len)) {
|
||||
free(b64);
|
||||
return -1;
|
||||
}
|
||||
free(b64);
|
||||
|
||||
wsgi_req->websocket_last_pong = uwsgi_now();
|
||||
|
||||
return uwsgi_response_write_headers_do(wsgi_req);
|
||||
#else
|
||||
uwsgi_log("you need to build uWSGI with SSL support to use the websocket handshake api function !!!\n");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void uwsgi_websockets_init() {
|
||||
uwsgi.websockets_pong = uwsgi_buffer_new(2);
|
||||
uwsgi_buffer_append(uwsgi.websockets_pong, "\x8A\0", 2);
|
||||
uwsgi.websockets_ping = uwsgi_buffer_new(2);
|
||||
uwsgi_buffer_append(uwsgi.websockets_ping, "\x89\0", 2);
|
||||
uwsgi.websockets_ping_freq = 30;
|
||||
uwsgi.websockets_pong_tolerance = 3;
|
||||
uwsgi.websockets_max_size = 1024;
|
||||
}
|
||||
+391
@@ -0,0 +1,391 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_response_add_content_length(struct wsgi_request *wsgi_req, uint64_t cl) {
|
||||
char buf[sizeof(UMAX64_STR)+1];
|
||||
int ret = snprintf(buf, sizeof(UMAX64_STR)+1, "%llu", (unsigned long long) cl);
|
||||
if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
return uwsgi_response_add_header(wsgi_req, "Content-Length", 14, buf, ret);
|
||||
}
|
||||
|
||||
int uwsgi_response_add_expires(struct wsgi_request *wsgi_req, uint64_t t) {
|
||||
// 30+1
|
||||
char expires[31];
|
||||
int len = uwsgi_http_date((time_t) t, expires);
|
||||
if (!len) {
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
return uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, len);
|
||||
}
|
||||
|
||||
int uwsgi_response_add_date(struct wsgi_request *wsgi_req, char *hkey, uint16_t hlen, uint64_t t) {
|
||||
// 30+1
|
||||
char d[31];
|
||||
int len = uwsgi_http_date((time_t) t, d);
|
||||
if (!len) {
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
return uwsgi_response_add_header(wsgi_req, hkey, hlen, d, len);
|
||||
}
|
||||
|
||||
int uwsgi_response_add_last_modified(struct wsgi_request *wsgi_req, uint64_t t) {
|
||||
// 30+1
|
||||
char lm[31];
|
||||
int len = uwsgi_http_date((time_t) t, lm);
|
||||
if (!len) {
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
return uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, lm, len);
|
||||
}
|
||||
|
||||
int uwsgi_response_add_content_range(struct wsgi_request *wsgi_req, uint64_t start, uint64_t end, uint64_t cl) {
|
||||
char buf[6+(sizeof(UMAX64_STR)*3)+4];
|
||||
if (end == 0) {
|
||||
end = cl-1;
|
||||
}
|
||||
int ret = snprintf(buf, 6+(sizeof(UMAX64_STR)*3)+4, "bytes %llu-%llu/%llu", (unsigned long long) start, (unsigned long long) end, (unsigned long long) cl);
|
||||
if (ret <= 0 || ret > (int) (6+(sizeof(UMAX64_STR)*3)+4)) {
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
return uwsgi_response_add_header(wsgi_req, "Content-Range", 13, buf, ret);
|
||||
}
|
||||
|
||||
int uwsgi_response_prepare_headers_int(struct wsgi_request *wsgi_req, int status) {
|
||||
char status_str[11];
|
||||
uwsgi_num2str2(status, status_str);
|
||||
return uwsgi_response_prepare_headers(wsgi_req, status_str, 3);
|
||||
}
|
||||
|
||||
// status could be NNN or NNN message
|
||||
int uwsgi_response_prepare_headers(struct wsgi_request *wsgi_req, char *status, uint16_t status_len) {
|
||||
|
||||
if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || status_len < 3 || wsgi_req->write_errors) return -1;
|
||||
|
||||
if (!wsgi_req->headers) {
|
||||
wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size);
|
||||
wsgi_req->headers->limit = UMAX16;
|
||||
}
|
||||
|
||||
// reset the buffer (could be useful for rollbacks...)
|
||||
wsgi_req->headers->pos = 0;
|
||||
struct uwsgi_buffer *hh = NULL;
|
||||
if (status_len <= 4) {
|
||||
char *new_sc = NULL;
|
||||
size_t new_sc_len = 0;
|
||||
uint16_t sc_len = 0;
|
||||
const char *sc = uwsgi_http_status_msg(status, &sc_len);
|
||||
if (sc) {
|
||||
new_sc = uwsgi_concat3n(status, 3, " ", 1, (char *)sc, sc_len);
|
||||
new_sc_len = 4+sc_len;
|
||||
}
|
||||
else {
|
||||
new_sc = uwsgi_concat2n(status, 3, " Unknown", 8);
|
||||
new_sc_len = 11;
|
||||
}
|
||||
hh = wsgi_req->socket->proto_prepare_headers(wsgi_req, new_sc, new_sc_len);
|
||||
free(new_sc);
|
||||
}
|
||||
else {
|
||||
hh = wsgi_req->socket->proto_prepare_headers(wsgi_req, status, status_len);
|
||||
}
|
||||
if (!hh) {wsgi_req->write_errors++; return -1;}
|
||||
if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error;
|
||||
uwsgi_buffer_destroy(hh);
|
||||
wsgi_req->status = uwsgi_str3_num(status);
|
||||
return 0;
|
||||
error:
|
||||
uwsgi_buffer_destroy(hh);
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
//each protocol has its header generator
|
||||
static int uwsgi_response_add_header_do(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) {
|
||||
if (!wsgi_req->headers) {
|
||||
wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size);
|
||||
wsgi_req->headers->limit = UMAX16;
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *hh = wsgi_req->socket->proto_add_header(wsgi_req, key, key_len, value, value_len);
|
||||
if (!hh) { wsgi_req->write_errors++ ; return -1;}
|
||||
if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error;
|
||||
wsgi_req->header_cnt++;
|
||||
uwsgi_buffer_destroy(hh);
|
||||
return 0;
|
||||
error:
|
||||
uwsgi_buffer_destroy(hh);
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int uwsgi_response_add_header(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) {
|
||||
|
||||
if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || wsgi_req->write_errors) return -1;
|
||||
|
||||
struct uwsgi_string_list *rh = uwsgi.remove_headers;
|
||||
while(rh) {
|
||||
if (!uwsgi_strnicmp(key, key_len, rh->value, rh->len)) {
|
||||
return 0;
|
||||
}
|
||||
rh = rh->next;
|
||||
}
|
||||
rh = wsgi_req->remove_headers;
|
||||
while(rh) {
|
||||
if (!uwsgi_strnicmp(key, key_len, rh->value, rh->len)) {
|
||||
return 0;
|
||||
}
|
||||
rh = rh->next;
|
||||
}
|
||||
|
||||
return uwsgi_response_add_header_do(wsgi_req, key, key_len, value, value_len);
|
||||
}
|
||||
|
||||
int uwsgi_response_add_header_force(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) {
|
||||
|
||||
if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || wsgi_req->write_errors) return -1;
|
||||
|
||||
return uwsgi_response_add_header_do(wsgi_req, key, key_len, value, value_len);
|
||||
}
|
||||
|
||||
int uwsgi_response_write_headers_do(struct wsgi_request *wsgi_req) {
|
||||
if (wsgi_req->headers_sent || !wsgi_req->headers || wsgi_req->response_size || wsgi_req->write_errors) {
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
struct uwsgi_string_list *ah = uwsgi.additional_headers;
|
||||
while(ah) {
|
||||
if (uwsgi_response_add_header(wsgi_req, NULL, 0, ah->value, ah->len)) return -1;
|
||||
ah = ah->next;
|
||||
}
|
||||
|
||||
ah = wsgi_req->additional_headers;
|
||||
while(ah) {
|
||||
if (uwsgi_response_add_header(wsgi_req, NULL, 0, ah->value, ah->len)) return -1;
|
||||
ah = ah->next;
|
||||
}
|
||||
|
||||
|
||||
if (wsgi_req->socket->proto_fix_headers(wsgi_req)) { wsgi_req->write_errors++ ; return -1;}
|
||||
|
||||
for(;;) {
|
||||
int ret = wsgi_req->socket->proto_write_headers(wsgi_req, wsgi_req->headers->buf, wsgi_req->headers->pos);
|
||||
if (ret < 0) {
|
||||
if (!uwsgi.ignore_write_errors) {
|
||||
uwsgi_error("uwsgi_response_write_headers_do()");
|
||||
}
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
if (ret == UWSGI_OK) {
|
||||
break;
|
||||
}
|
||||
ret = uwsgi_wait_write_req(wsgi_req);
|
||||
if (ret < 0) { wsgi_req->write_errors++; return -1;}
|
||||
if (ret == 0) {
|
||||
uwsgi_log("uwsgi_response_write_headers_do() TIMEOUT !!!\n");
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
wsgi_req->headers_size += wsgi_req->write_pos;
|
||||
// reset for the next write
|
||||
wsgi_req->write_pos = 0;
|
||||
wsgi_req->headers_sent = 1;
|
||||
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
// this is the function called by all request plugins to send chunks to the client
|
||||
int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
|
||||
if (wsgi_req->write_errors) return -1;
|
||||
|
||||
// if the transformation chain returns 1, we are in buffering mode
|
||||
if (wsgi_req->transformed_chunk_len == 0 && wsgi_req->transformations) {
|
||||
int t_ret = uwsgi_apply_transformations(wsgi_req, buf, len);
|
||||
if (t_ret == 0) {
|
||||
buf = wsgi_req->transformed_chunk;
|
||||
len = wsgi_req->transformed_chunk_len;
|
||||
// reset transformation
|
||||
wsgi_req->transformed_chunk = NULL;
|
||||
wsgi_req->transformed_chunk_len = 0;
|
||||
goto write;
|
||||
}
|
||||
if (t_ret == 1) {
|
||||
return UWSGI_OK;
|
||||
}
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
write:
|
||||
// send headers if not already sent
|
||||
if (!wsgi_req->headers_sent) {
|
||||
int ret = uwsgi_response_write_headers_do(wsgi_req);
|
||||
if (ret == UWSGI_OK) goto sendbody;
|
||||
if (ret == UWSGI_AGAIN) return UWSGI_AGAIN;
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
sendbody:
|
||||
|
||||
if (len == 0) return UWSGI_OK;
|
||||
|
||||
for(;;) {
|
||||
int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len);
|
||||
if (ret < 0) {
|
||||
if (!uwsgi.ignore_write_errors) {
|
||||
uwsgi_error("uwsgi_response_write_body_do()");
|
||||
}
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
if (ret == UWSGI_OK) {
|
||||
break;
|
||||
}
|
||||
ret = uwsgi_wait_write_req(wsgi_req);
|
||||
if (ret < 0) { wsgi_req->write_errors++; return -1;}
|
||||
if (ret == 0) {
|
||||
uwsgi_log("uwsgi_response_write_body_do() TIMEOUT !!!\n");
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
wsgi_req->response_size += wsgi_req->write_pos;
|
||||
// reset for the next write
|
||||
wsgi_req->write_pos = 0;
|
||||
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
int uwsgi_response_sendfile_do(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) {
|
||||
|
||||
int can_close = 1;
|
||||
|
||||
if (fd == wsgi_req->sendfile_fd) can_close = 0;
|
||||
|
||||
if (wsgi_req->write_errors) {
|
||||
if (can_close) close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!wsgi_req->headers_sent) {
|
||||
int ret = uwsgi_response_write_headers_do(wsgi_req);
|
||||
if (ret == UWSGI_OK) goto sendfile;
|
||||
if (ret == UWSGI_AGAIN) return UWSGI_AGAIN;
|
||||
wsgi_req->write_errors++;
|
||||
if (can_close) close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sendfile:
|
||||
|
||||
if (len == 0) {
|
||||
struct stat st;
|
||||
if (fstat(fd, &st)) {
|
||||
uwsgi_error("fstat()");
|
||||
wsgi_req->write_errors++;
|
||||
if (can_close) close(fd);
|
||||
return -1;
|
||||
}
|
||||
if (pos >= (size_t)st.st_size) {
|
||||
if (can_close) close(fd);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
len = st.st_size;
|
||||
}
|
||||
|
||||
if (wsgi_req->socket->can_offload) {
|
||||
// of we cannot close the socket (before the app will close it later)
|
||||
// let's dup it
|
||||
if (!can_close) {
|
||||
int tmp_fd = dup(fd);
|
||||
if (tmp_fd < 0) {
|
||||
uwsgi_error("uwsgi_response_sendfile_do()/dup()");
|
||||
wsgi_req->write_errors++;
|
||||
return -1;
|
||||
}
|
||||
fd = tmp_fd;
|
||||
can_close = 1;
|
||||
}
|
||||
if (!uwsgi_offload_request_sendfile_do(wsgi_req, fd, len)) {
|
||||
wsgi_req->via = UWSGI_VIA_OFFLOAD;
|
||||
wsgi_req->response_size += len;
|
||||
return 0;
|
||||
}
|
||||
wsgi_req->write_errors++;
|
||||
if (can_close) close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
wsgi_req->via = UWSGI_VIA_SENDFILE;
|
||||
|
||||
for(;;) {
|
||||
int ret = wsgi_req->socket->proto_sendfile(wsgi_req, fd, pos, len);
|
||||
if (ret < 0) {
|
||||
if (!uwsgi.ignore_write_errors) {
|
||||
uwsgi_error("uwsgi_response_sendfile_do()");
|
||||
}
|
||||
wsgi_req->write_errors++;
|
||||
if (can_close) close(fd);
|
||||
return -1;
|
||||
}
|
||||
if (ret == UWSGI_OK) {
|
||||
break;
|
||||
}
|
||||
ret = uwsgi_wait_write_req(wsgi_req);
|
||||
if (ret < 0) {
|
||||
wsgi_req->write_errors++;
|
||||
if (can_close) close(fd);
|
||||
return -1;
|
||||
}
|
||||
if (ret == 0) {
|
||||
uwsgi_log("uwsgi_response_sendfile_do() TIMEOUT !!!\n");
|
||||
wsgi_req->write_errors++;
|
||||
if (can_close) close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
wsgi_req->response_size += wsgi_req->write_pos;
|
||||
// reset for the next write
|
||||
wsgi_req->write_pos = 0;
|
||||
// close the file descriptor
|
||||
if (can_close) close(fd);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_simple_wait_write_hook(int fd, int timeout) {
|
||||
struct pollfd upoll;
|
||||
timeout = timeout * 1000;
|
||||
|
||||
upoll.fd = fd;
|
||||
upoll.events = POLLOUT;
|
||||
upoll.revents = 0;
|
||||
int ret = poll(&upoll, 1, timeout);
|
||||
|
||||
if (ret > 0) {
|
||||
if (upoll.revents & POLLOUT) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (ret < 0) {
|
||||
uwsgi_error("uwsgi_simple_wait_write_hook()/poll()");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
+116
-108
@@ -20,7 +20,7 @@ void uwsgi_xml_config(char *filename, struct wsgi_request *wsgi_req, char *magic
|
||||
|
||||
char *xml_id;
|
||||
char *xml_content;
|
||||
int xml_size = 0;
|
||||
size_t xml_size = 0;
|
||||
|
||||
if (uwsgi_check_scheme(filename)) {
|
||||
colon = uwsgi_get_last_char(filename, '/');
|
||||
@@ -36,22 +36,22 @@ void uwsgi_xml_config(char *filename, struct wsgi_request *wsgi_req, char *magic
|
||||
uwsgi_log("invalid xml id\n");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_log( "[uWSGI] using xml uwsgi id: %s\n", colon);
|
||||
uwsgi_log("[uWSGI] using xml uwsgi id: %s\n", colon);
|
||||
}
|
||||
|
||||
xml_content = uwsgi_open_and_read(filename, &xml_size, 0, magic_table);
|
||||
|
||||
doc = xmlReadMemory(xml_content, xml_size, filename, NULL, 0);
|
||||
if (doc == NULL) {
|
||||
uwsgi_log( "[uWSGI] could not parse file %s.\n", filename);
|
||||
uwsgi_log("[uWSGI] could not parse file %s.\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_log( "[uWSGI] parsing config file %s\n", filename);
|
||||
uwsgi_log_initial("[uWSGI] parsing config file %s\n", filename);
|
||||
|
||||
element = xmlDocGetRootElement(doc);
|
||||
if (element == NULL) {
|
||||
uwsgi_log( "[uWSGI] invalid xml config file.\n");
|
||||
uwsgi_log("[uWSGI] invalid xml config file.\n");
|
||||
exit(1);
|
||||
}
|
||||
if (strcmp((char *) element->name, "uwsgi")) {
|
||||
@@ -62,7 +62,7 @@ void uwsgi_xml_config(char *filename, struct wsgi_request *wsgi_req, char *magic
|
||||
xml_id = (char *) xmlGetProp(node, (const xmlChar *) "id");
|
||||
|
||||
if (colon && xml_id) {
|
||||
if ( strcmp(colon, xml_id) ) {
|
||||
if (strcmp(colon, xml_id)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -73,82 +73,82 @@ void uwsgi_xml_config(char *filename, struct wsgi_request *wsgi_req, char *magic
|
||||
}
|
||||
|
||||
if (!element) {
|
||||
uwsgi_log( "[uWSGI] invalid xml root element, <uwsgi> expected.\n");
|
||||
uwsgi_log("[uWSGI] invalid xml root element, <uwsgi> expected.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// first check for options
|
||||
for (node = element->children; node; node = node->next) {
|
||||
// first check for options
|
||||
for (node = element->children; node; node = node->next) {
|
||||
|
||||
node_mode = xmlGetProp(node, (const xmlChar *) "mode");
|
||||
if (uwsgi.mode && node_mode) {
|
||||
if (strcmp(uwsgi.mode, (char *) node_mode)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
xml_id = (char *) xmlGetProp(node, (const xmlChar *) "id");
|
||||
if (colon && xml_id) {
|
||||
if (strcmp(colon, xml_id)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (node->type == XML_CDATA_SECTION_NODE) {
|
||||
if (node->content) {
|
||||
add_exported_option((char *) "eval", strdup((char *) node->content), 0);
|
||||
}
|
||||
}
|
||||
else if (node->type == XML_ELEMENT_NODE) {
|
||||
|
||||
if (!strcmp((char *) node->name, (char *) "app")) {
|
||||
|
||||
char *mountpoint = (char *) xmlGetProp(node, (const xmlChar *) "mountpoint");
|
||||
char *domain = (char *) xmlGetProp(node, (const xmlChar *) "domain");
|
||||
|
||||
if (!node->children) {
|
||||
add_exported_option("app", strdup(""), 0);
|
||||
}
|
||||
else if (node->children && node->children->content && !node->children->next) {
|
||||
char *opt_value = strdup((char *) node->children->content);
|
||||
|
||||
if (mountpoint) {
|
||||
opt_value = uwsgi_concat3(mountpoint,"=", opt_value);
|
||||
}
|
||||
else if (domain) {
|
||||
opt_value = uwsgi_concat3(domain,"|=", opt_value);
|
||||
}
|
||||
add_exported_option("mount", opt_value, 0);
|
||||
add_exported_option("app", strdup(""), 0);
|
||||
}
|
||||
else if (node->children && node->children->next && node->children->next->children && node->children->next->children->content) {
|
||||
|
||||
char *opt_value = strdup((char *) node->children->next->children->content);
|
||||
|
||||
if (mountpoint) {
|
||||
opt_value = uwsgi_concat3(mountpoint,"=", opt_value);
|
||||
}
|
||||
else if (domain) {
|
||||
opt_value = uwsgi_concat3(domain,"|=", opt_value);
|
||||
}
|
||||
|
||||
add_exported_option("mount", opt_value, 0);
|
||||
add_exported_option("app", strdup(""), 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
if (node->children) {
|
||||
add_exported_option(strdup((char *) node->name), strdup((char *) node->children->content), 0);
|
||||
}
|
||||
else {
|
||||
add_exported_option(strdup((char *) node->name), strdup("1"), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
node_mode = xmlGetProp(node, (const xmlChar *) "mode");
|
||||
if (uwsgi.mode && node_mode) {
|
||||
if (strcmp(uwsgi.mode, (char *) node_mode)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
xml_id = (char *) xmlGetProp(node, (const xmlChar *) "id");
|
||||
if (colon && xml_id) {
|
||||
if (strcmp(colon, xml_id)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (node->type == XML_CDATA_SECTION_NODE) {
|
||||
if (node->content) {
|
||||
add_exported_option((char *) "eval", strdup((char *) node->content), 0);
|
||||
}
|
||||
}
|
||||
else if (node->type == XML_ELEMENT_NODE) {
|
||||
|
||||
if (!strcmp((char *) node->name, (char *) "app")) {
|
||||
|
||||
char *mountpoint = (char *) xmlGetProp(node, (const xmlChar *) "mountpoint");
|
||||
char *domain = (char *) xmlGetProp(node, (const xmlChar *) "domain");
|
||||
|
||||
if (!node->children) {
|
||||
add_exported_option("app", strdup(""), 0);
|
||||
}
|
||||
else if (node->children && node->children->content && !node->children->next) {
|
||||
char *opt_value = strdup((char *) node->children->content);
|
||||
|
||||
if (mountpoint) {
|
||||
opt_value = uwsgi_concat3(mountpoint, "=", opt_value);
|
||||
}
|
||||
else if (domain) {
|
||||
opt_value = uwsgi_concat3(domain, "|=", opt_value);
|
||||
}
|
||||
add_exported_option("mount", opt_value, 0);
|
||||
add_exported_option("app", strdup(""), 0);
|
||||
}
|
||||
else if (node->children && node->children->next && node->children->next->children && node->children->next->children->content) {
|
||||
|
||||
char *opt_value = strdup((char *) node->children->next->children->content);
|
||||
|
||||
if (mountpoint) {
|
||||
opt_value = uwsgi_concat3(mountpoint, "=", opt_value);
|
||||
}
|
||||
else if (domain) {
|
||||
opt_value = uwsgi_concat3(domain, "|=", opt_value);
|
||||
}
|
||||
|
||||
add_exported_option("mount", opt_value, 0);
|
||||
add_exported_option("app", strdup(""), 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
if (node->children) {
|
||||
add_exported_option(strdup((char *) node->name), strdup((char *) node->children->content), 0);
|
||||
}
|
||||
else {
|
||||
add_exported_option(strdup((char *) node->name), strdup("1"), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* We can safely free resources */
|
||||
|
||||
xmlFreeDoc(doc);
|
||||
@@ -166,17 +166,22 @@ void uwsgi_xml_config(char *filename, struct wsgi_request *wsgi_req, char *magic
|
||||
int uwsgi_xml_found_stanza = 0;
|
||||
char *uwsgi_xml_found_opt_key = NULL;
|
||||
|
||||
static void startElement(void *xml_id, const XML_Char *name, const XML_Char **attrs) {
|
||||
static void startElement(void *xml_id, const XML_Char * name, const XML_Char ** attrs) {
|
||||
|
||||
|
||||
if (!uwsgi_xml_found_stanza) {
|
||||
if (xml_id) {
|
||||
if (!attrs[0]) return;
|
||||
if (!attrs[1]) return;
|
||||
if (strcmp("id", attrs[0])) return;
|
||||
if (strcmp((char *)xml_id, attrs[1])) return;
|
||||
if (!attrs[0])
|
||||
return;
|
||||
if (!attrs[1])
|
||||
return;
|
||||
if (strcmp("id", attrs[0]))
|
||||
return;
|
||||
if (strcmp((char *) xml_id, attrs[1]))
|
||||
return;
|
||||
}
|
||||
if (!strcmp("uwsgi", name)) uwsgi_xml_found_stanza = 1;
|
||||
if (!strcmp("uwsgi", name))
|
||||
uwsgi_xml_found_stanza = 1;
|
||||
}
|
||||
else {
|
||||
uwsgi_xml_found_opt_key = (char *) name;
|
||||
@@ -186,23 +191,26 @@ static void startElement(void *xml_id, const XML_Char *name, const XML_Char **at
|
||||
|
||||
static void textElement(void *xml_id, const char *s, int len) {
|
||||
|
||||
if (!uwsgi_xml_found_stanza) return ;
|
||||
if (!uwsgi_xml_found_stanza)
|
||||
return;
|
||||
if (uwsgi_xml_found_opt_key) {
|
||||
add_exported_option(strdup(uwsgi_xml_found_opt_key), uwsgi_concat2n((char *)s, len, (char *)"", 0), 0);
|
||||
add_exported_option(strdup(uwsgi_xml_found_opt_key), uwsgi_concat2n((char *) s, len, (char *) "", 0), 0);
|
||||
uwsgi_xml_found_opt_key = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void endElement(void *xml_id, const XML_Char *name) {
|
||||
static void endElement(void *xml_id, const XML_Char * name) {
|
||||
|
||||
if (!uwsgi_xml_found_stanza) return ;
|
||||
if (!uwsgi_xml_found_stanza)
|
||||
return;
|
||||
|
||||
if (!strcmp(name, "uwsgi")) {
|
||||
uwsgi_xml_found_stanza = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!uwsgi_xml_found_opt_key) return;
|
||||
if (!uwsgi_xml_found_opt_key)
|
||||
return;
|
||||
|
||||
add_exported_option(strdup(uwsgi_xml_found_opt_key), strdup("1"), 0);
|
||||
uwsgi_xml_found_opt_key = NULL;
|
||||
@@ -212,30 +220,30 @@ void uwsgi_xml_config(char *filename, struct wsgi_request *wsgi_req, char *magic
|
||||
|
||||
char *colon;
|
||||
|
||||
char *xml_content;
|
||||
int xml_size = 0;
|
||||
char *xml_content;
|
||||
size_t xml_size = 0;
|
||||
int done = 0;
|
||||
|
||||
if (uwsgi_check_scheme(filename)) {
|
||||
colon = uwsgi_get_last_char(filename, '/');
|
||||
colon = uwsgi_get_last_char(colon, ':');
|
||||
}
|
||||
else {
|
||||
colon = uwsgi_get_last_char(filename, ':');
|
||||
}
|
||||
if (colon) {
|
||||
colon[0] = 0;
|
||||
colon++;
|
||||
if (*colon == 0) {
|
||||
uwsgi_log("invalid xml id\n");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_log( "[uWSGI] using xml uwsgi id: %s\n", colon);
|
||||
}
|
||||
if (uwsgi_check_scheme(filename)) {
|
||||
colon = uwsgi_get_last_char(filename, '/');
|
||||
colon = uwsgi_get_last_char(colon, ':');
|
||||
}
|
||||
else {
|
||||
colon = uwsgi_get_last_char(filename, ':');
|
||||
}
|
||||
if (colon) {
|
||||
colon[0] = 0;
|
||||
colon++;
|
||||
if (*colon == 0) {
|
||||
uwsgi_log("invalid xml id\n");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_log("[uWSGI] using xml uwsgi id: %s\n", colon);
|
||||
}
|
||||
|
||||
xml_content = uwsgi_open_and_read(filename, &xml_size, 0, magic_table);
|
||||
xml_content = uwsgi_open_and_read(filename, &xml_size, 0, magic_table);
|
||||
|
||||
uwsgi_log( "[uWSGI] parsing config file %s\n", filename);
|
||||
uwsgi_log("[uWSGI] parsing config file %s\n", filename);
|
||||
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
XML_SetUserData(parser, NULL);
|
||||
@@ -257,9 +265,9 @@ void uwsgi_xml_config(char *filename, struct wsgi_request *wsgi_req, char *magic
|
||||
}
|
||||
}
|
||||
|
||||
} while(!done);
|
||||
} while (!done);
|
||||
|
||||
|
||||
|
||||
// we can safely free, as we have a copy of datas
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
|
||||
+102
-96
@@ -15,7 +15,7 @@ void yaml_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] = 0;
|
||||
continue;
|
||||
@@ -26,18 +26,18 @@ void yaml_rstrip(char *line) {
|
||||
|
||||
char *yaml_lstrip(char *line) {
|
||||
|
||||
off_t i;
|
||||
char *ptr = line;
|
||||
off_t i;
|
||||
char *ptr = line;
|
||||
|
||||
for(i=0;i< (int) strlen(line);i++) {
|
||||
if (line[i] == ' ' || line[i] == '\t' || line[i] == '\r') {
|
||||
ptr++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < (int) strlen(line); i++) {
|
||||
if (line[i] == ' ' || line[i] == '\t' || line[i] == '\r') {
|
||||
ptr++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,13 +46,13 @@ int yaml_get_depth(char *line) {
|
||||
off_t i;
|
||||
int depth = 0;
|
||||
|
||||
for(i=0;i< (int) strlen(line);i++) {
|
||||
for (i = 0; i < (int) strlen(line); i++) {
|
||||
if (line[i] == ' ') {
|
||||
depth++;
|
||||
continue;
|
||||
}
|
||||
else if (line[i] == '\t' || line[i] == '\r') {
|
||||
depth+=8;
|
||||
depth += 8;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@@ -61,17 +61,17 @@ int yaml_get_depth(char *line) {
|
||||
return depth;
|
||||
}
|
||||
|
||||
char *yaml_get_line(char *yaml, off_t size) {
|
||||
char *yaml_get_line(char *yaml, size_t size) {
|
||||
|
||||
off_t i;
|
||||
size_t i;
|
||||
char *ptr = yaml;
|
||||
int comment = 0;
|
||||
|
||||
for(i=0;i<size;i++) {
|
||||
for (i = 0; i < size; i++) {
|
||||
ptr++;
|
||||
if (yaml[i] == '#') {
|
||||
yaml[i] = 0;
|
||||
comment = 1;
|
||||
comment = 1;
|
||||
}
|
||||
else if (yaml[i] == '\n') {
|
||||
yaml[i] = 0;
|
||||
@@ -96,7 +96,7 @@ char *yaml_get_line(char *yaml, off_t size) {
|
||||
|
||||
void uwsgi_yaml_config(char *file, char *magic_table[]) {
|
||||
|
||||
int len = 0;
|
||||
size_t len = 0;
|
||||
char *yaml;
|
||||
|
||||
int in_uwsgi_section = 0;
|
||||
@@ -108,101 +108,101 @@ void uwsgi_yaml_config(char *file, char *magic_table[]) {
|
||||
char *colon;
|
||||
|
||||
if (uwsgi_check_scheme(file)) {
|
||||
colon = uwsgi_get_last_char(file, '/');
|
||||
colon = uwsgi_get_last_char(colon, ':');
|
||||
}
|
||||
else {
|
||||
colon = uwsgi_get_last_char(file, ':');
|
||||
}
|
||||
colon = uwsgi_get_last_char(file, '/');
|
||||
colon = uwsgi_get_last_char(colon, ':');
|
||||
}
|
||||
else {
|
||||
colon = uwsgi_get_last_char(file, ':');
|
||||
}
|
||||
|
||||
if (colon) {
|
||||
colon[0] = 0;
|
||||
if (colon[1] != 0) {
|
||||
section_asked = colon+1;
|
||||
section_asked = colon + 1;
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("[uWSGI] getting YAML configuration from %s\n", file);
|
||||
uwsgi_log_initial("[uWSGI] getting YAML configuration from %s\n", file);
|
||||
|
||||
yaml = uwsgi_open_and_read(file, &len, 1, magic_table);
|
||||
|
||||
#ifdef UWSGI_LIBYAML
|
||||
yaml_parser_t parser;
|
||||
yaml_token_t token;
|
||||
yaml_token_t token;
|
||||
int status = 0;
|
||||
int parsing = 1;
|
||||
|
||||
if(!yaml_parser_initialize(&parser)) {
|
||||
if (!yaml_parser_initialize(&parser)) {
|
||||
uwsgi_log("unable to initialize YAML parser (libyaml)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
yaml_parser_set_input_string(&parser, (const unsigned char *)yaml, (size_t) len-1);
|
||||
yaml_parser_set_input_string(&parser, (unsigned char *) yaml, (size_t) len - 1);
|
||||
|
||||
while(parsing) {
|
||||
while (parsing) {
|
||||
if (!yaml_parser_scan(&parser, &token)) {
|
||||
uwsgi_log("error parsing YAML file: %s (%c)\n", parser.problem, yaml[parser.problem_offset]);
|
||||
exit(1);
|
||||
}
|
||||
switch(token.type) {
|
||||
case YAML_STREAM_END_TOKEN:
|
||||
switch (token.type) {
|
||||
case YAML_STREAM_END_TOKEN:
|
||||
parsing = 0;
|
||||
break;
|
||||
case YAML_KEY_TOKEN:
|
||||
status = 1;
|
||||
break;
|
||||
case YAML_VALUE_TOKEN:
|
||||
status = 2;
|
||||
break;
|
||||
case YAML_FLOW_SEQUENCE_START_TOKEN:
|
||||
case YAML_BLOCK_SEQUENCE_START_TOKEN:
|
||||
status = 3;
|
||||
break;
|
||||
case YAML_BLOCK_MAPPING_START_TOKEN:
|
||||
if (!in_uwsgi_section) {
|
||||
if (key) {
|
||||
if (!strcmp(section_asked, key)) {
|
||||
in_uwsgi_section = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YAML_BLOCK_END_TOKEN:
|
||||
if (in_uwsgi_section) {
|
||||
parsing = 0;
|
||||
break;
|
||||
case YAML_KEY_TOKEN:
|
||||
status = 1;
|
||||
break;
|
||||
case YAML_VALUE_TOKEN:
|
||||
status = 2;
|
||||
break;
|
||||
case YAML_FLOW_SEQUENCE_START_TOKEN:
|
||||
case YAML_BLOCK_SEQUENCE_START_TOKEN:
|
||||
status = 3;
|
||||
break;
|
||||
case YAML_BLOCK_MAPPING_START_TOKEN:
|
||||
if (!in_uwsgi_section) {
|
||||
if (key) {
|
||||
if (!strcmp(section_asked, key)) {
|
||||
in_uwsgi_section = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YAML_BLOCK_END_TOKEN:
|
||||
if (in_uwsgi_section) {
|
||||
parsing = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case YAML_SCALAR_TOKEN:
|
||||
case YAML_FLOW_ENTRY_TOKEN:
|
||||
case YAML_BLOCK_ENTRY_TOKEN:
|
||||
if (status == 1) {
|
||||
key = (char *) token.data.scalar.value;
|
||||
}
|
||||
else if (status == 2) {
|
||||
val = (char *) token.data.scalar.value;
|
||||
if (key && val && in_uwsgi_section) {
|
||||
add_exported_option(key, val, 0);
|
||||
}
|
||||
break;
|
||||
case YAML_SCALAR_TOKEN:
|
||||
case YAML_FLOW_ENTRY_TOKEN:
|
||||
case YAML_BLOCK_ENTRY_TOKEN:
|
||||
if (status == 1) {
|
||||
key = (char *) token.data.scalar.value;
|
||||
}
|
||||
else if (status == 2) {
|
||||
val = (char *) token.data.scalar.value;
|
||||
if (key && val && in_uwsgi_section) {
|
||||
add_exported_option(key, val, 0);
|
||||
}
|
||||
status = 0;
|
||||
}
|
||||
else if (status == 3) {
|
||||
val = (char *) token.data.scalar.value;
|
||||
if (key && val && in_uwsgi_section) {
|
||||
add_exported_option(key, val, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log("unsupported YAML token in %s block\n", section_asked);
|
||||
parsing = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
status = 0;
|
||||
}
|
||||
else if (status == 3) {
|
||||
val = (char *) token.data.scalar.value;
|
||||
if (key && val && in_uwsgi_section) {
|
||||
add_exported_option(key, val, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log("unsupported YAML token in %s block\n", section_asked);
|
||||
parsing = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
status = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
int depth;
|
||||
int current_depth = 0;
|
||||
@@ -211,7 +211,7 @@ void uwsgi_yaml_config(char *file, char *magic_table[]) {
|
||||
char *section = "";
|
||||
|
||||
|
||||
while(len) {
|
||||
while (len) {
|
||||
yaml_line = yaml_get_line(yaml, len);
|
||||
if (yaml_line == NULL) {
|
||||
break;
|
||||
@@ -219,12 +219,14 @@ void uwsgi_yaml_config(char *file, char *magic_table[]) {
|
||||
lines++;
|
||||
|
||||
// skip empty line
|
||||
if (yaml[0] == 0) goto next;
|
||||
if (yaml[0] == 0)
|
||||
goto next;
|
||||
depth = yaml_get_depth(yaml);
|
||||
if (depth <= current_depth) {
|
||||
current_depth = depth;
|
||||
// end the parsing cycle
|
||||
if (in_uwsgi_section) return;
|
||||
if (in_uwsgi_section)
|
||||
return;
|
||||
}
|
||||
else if (depth > current_depth && !in_uwsgi_section) {
|
||||
goto next;
|
||||
@@ -232,40 +234,44 @@ void uwsgi_yaml_config(char *file, char *magic_table[]) {
|
||||
|
||||
key = yaml_lstrip(yaml);
|
||||
// skip empty line
|
||||
if (key[0] == 0) goto next;
|
||||
if (key[0] == 0)
|
||||
goto next;
|
||||
|
||||
// skip list and {} defined dict
|
||||
if (key[0] == '-' || key[0] == '[' || key[0] == '{') {
|
||||
if (in_uwsgi_section) return;
|
||||
if (in_uwsgi_section)
|
||||
return;
|
||||
goto next;
|
||||
}
|
||||
|
||||
|
||||
if (!in_uwsgi_section) {
|
||||
section = strchr(key,':');
|
||||
if (!section) goto next;
|
||||
section = strchr(key, ':');
|
||||
if (!section)
|
||||
goto next;
|
||||
section[0] = 0;
|
||||
if (!strcmp(key, section_asked)) {
|
||||
in_uwsgi_section = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// get dict value
|
||||
// get dict value
|
||||
val = strstr(key, ": ");
|
||||
if (!val) {
|
||||
val = strstr(key, ":\t");
|
||||
}
|
||||
if (!val) return;
|
||||
if (!val)
|
||||
return;
|
||||
// get the right key
|
||||
val[0] = 0;
|
||||
// yeah overengeneering....
|
||||
yaml_rstrip(key);
|
||||
|
||||
val = yaml_lstrip(val+2);
|
||||
val = yaml_lstrip(val + 2);
|
||||
yaml_rstrip(val);
|
||||
|
||||
|
||||
//uwsgi_log("YAML: %s = %s\n", key, val);
|
||||
|
||||
add_exported_option((char *)key, val, 0);
|
||||
add_exported_option((char *) key, val, 0);
|
||||
}
|
||||
next:
|
||||
len -= (yaml_line - yaml);
|
||||
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
char gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 };
|
||||
|
||||
char *uwsgi_gzip_chunk(z_stream *z, uint32_t *crc32, char *buf, size_t len, size_t *dlen) {
|
||||
uwsgi_crc32(crc32, buf, len);
|
||||
return uwsgi_deflate(z, buf, len, dlen);
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *uwsgi_gzip(char *buf, size_t len) {
|
||||
z_stream z;
|
||||
struct uwsgi_buffer *ub = NULL;
|
||||
uint32_t gzip_crc32 = 0;
|
||||
char *gzipped = NULL;
|
||||
char *gzipped0 = NULL;
|
||||
size_t dlen = 0;
|
||||
size_t dlen0 = 0;
|
||||
|
||||
uwsgi_crc32(&gzip_crc32, NULL, 0);
|
||||
if (uwsgi_deflate_init(&z, NULL, 0)) return NULL;
|
||||
uwsgi_crc32(&gzip_crc32, buf, len);
|
||||
|
||||
gzipped = uwsgi_deflate(&z, buf, len, &dlen);
|
||||
if (!gzipped) goto end;
|
||||
gzipped0 = uwsgi_deflate(&z, NULL, 0, &dlen0);
|
||||
if (!gzipped0) goto end;
|
||||
|
||||
ub = uwsgi_buffer_new(10 + dlen + dlen0 + 8);
|
||||
if (uwsgi_buffer_append(ub, gzheader, 10)) goto end;
|
||||
if (uwsgi_buffer_append(ub, gzipped, dlen)) goto end;
|
||||
if (uwsgi_buffer_append(ub, gzipped0, dlen0)) goto end;
|
||||
if (uwsgi_buffer_u32le(ub, gzip_crc32)) goto end;
|
||||
if (uwsgi_buffer_u32le(ub, len)) goto end;
|
||||
end:
|
||||
if (gzipped) free(gzipped);
|
||||
if (gzipped0) free(gzipped0);
|
||||
deflateEnd(&z);
|
||||
return ub;
|
||||
}
|
||||
|
||||
int uwsgi_deflate_init(z_stream *z, char *dict, size_t dict_len) {
|
||||
z->zalloc = Z_NULL;
|
||||
z->zfree = Z_NULL;
|
||||
z->opaque = Z_NULL;
|
||||
if (deflateInit2(z, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 9, Z_DEFAULT_STRATEGY) != Z_OK) {
|
||||
//if (deflateInit(z, Z_DEFAULT_COMPRESSION)) {
|
||||
return -1;
|
||||
}
|
||||
if (dict && dict_len) {
|
||||
if (deflateSetDictionary(z, (Bytef *) dict, dict_len) != Z_OK) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_gzip_prepare(z_stream *z, char *dict, size_t dict_len, uint32_t *crc32) {
|
||||
uwsgi_crc32(crc32, NULL, 0);
|
||||
if (uwsgi_deflate_init(z, NULL, 0)) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// fix and free a gzip stream
|
||||
int uwsgi_gzip_fix(z_stream *z, uint32_t crc32, struct uwsgi_buffer *ub, size_t len) {
|
||||
size_t dlen0 = 0;
|
||||
char *gzipped0 = uwsgi_deflate(z, NULL, 0, &dlen0);
|
||||
if (!gzipped0) goto end;
|
||||
if (uwsgi_buffer_append(ub, gzipped0, dlen0)) goto end;
|
||||
free(gzipped0);
|
||||
if (uwsgi_buffer_u32le(ub, crc32)) goto end;
|
||||
if (uwsgi_buffer_u32le(ub, len)) goto end;
|
||||
deflateEnd(z);
|
||||
return 0;
|
||||
end:
|
||||
if (gzipped0) free(gzipped0);
|
||||
deflateEnd(z);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_deflate(z_stream *z, char *buf, size_t len, size_t *dlen) {
|
||||
|
||||
// calculate the amount of bytes needed for output (+30 should be enough)
|
||||
Bytef *dbuf = uwsgi_malloc(len+30);
|
||||
z->avail_in = len;
|
||||
z->next_in = (Bytef *) buf;
|
||||
z->avail_out = len+30;
|
||||
z->next_out = dbuf;
|
||||
|
||||
if (len > 0) {
|
||||
if (deflate(z, Z_SYNC_FLUSH) != Z_OK) {
|
||||
free(dbuf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (deflate(z, Z_FINISH) != Z_STREAM_END) {
|
||||
free(dbuf);
|
||||
return NULL;
|
||||
}
|
||||
deflateEnd(z);
|
||||
}
|
||||
|
||||
*dlen = (z->next_out - dbuf);
|
||||
return (char *) dbuf;
|
||||
}
|
||||
|
||||
void uwsgi_crc32(uint32_t *ctx, char *buf, size_t len) {
|
||||
if (!buf) {
|
||||
*ctx = crc32(*ctx, Z_NULL, 0);
|
||||
}
|
||||
else {
|
||||
*ctx = crc32(*ctx, (const Bytef *) buf, len);
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
{% extends "admin/base_site.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<div class="breadcrumbs">
|
||||
<a href="../">{% trans 'Home' %}</a> ›
|
||||
{% trans 'uWSGI' %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div id="content-main">
|
||||
<h1>uWSGI status</h1>
|
||||
<b>masterpid:</b> {{masterpid}}<br/>
|
||||
<b>started_on:</b> {{started_on}}<br/>
|
||||
<b>buffer size:</b> {{buffer_size}}<br/>
|
||||
<b>workers:</b> {{numproc}}<br/>
|
||||
<b>total requests:</b> {{total_requests}}<br/>
|
||||
|
||||
<br/>
|
||||
|
||||
<div class="module" style="width:860px">
|
||||
<table>
|
||||
<caption style="width:860px">workers</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="row">id</th>
|
||||
<th scope="row">pid</th>
|
||||
<th scope="row">requests</th>
|
||||
<th scope="row">running time (milliseconds)</th>
|
||||
<th scope="row">load</th>
|
||||
<th scope="row">last spawn</th>
|
||||
<th scope="row">respawn count</th>
|
||||
<th scope="row">address space (vsz)</th>
|
||||
<th scope="row">resident memory (rss)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for w in workers %}
|
||||
<tr>
|
||||
<td align="center">{{w.id}}</td>
|
||||
<td align="center">{{w.pid}}</td>
|
||||
<td align="right">{{w.requests}}</td>
|
||||
<td align="right">{{w.running_time}}</td>
|
||||
<td align="right">{{w.load|floatformat:2}} %</td>
|
||||
<td align="right">{{w.last_spawn_str}}</td>
|
||||
<td align="right">{{w.respawn_count}}</td>
|
||||
<td align="right">{{w.vsz|filesizeformat}}</td>
|
||||
<td align="right">{{w.rss|filesizeformat}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="module" style="width:860px">
|
||||
<table>
|
||||
<caption style="width:860px">spooler jobs</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="row">job filename</th>
|
||||
<th scope="row">environment</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for j in jobs %}
|
||||
<tr>
|
||||
<td align="left">{{j.file}}</td>
|
||||
<td align="left">{{j.env}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% if masterpid %}
|
||||
<br/>
|
||||
<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="reload/" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="submit" value="gracefully reload uWSGI" name="_reload"/>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user