mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-10-04 16:08:31 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5dc74b021 | ||
|
|
97137488f9 | ||
|
|
8cff01a1c7 | ||
|
|
3c8452313e | ||
|
|
322b130fc9 | ||
|
|
6c001c2fda | ||
|
|
5d4050817d | ||
|
|
0a1147a4f6 | ||
|
|
f92cb0e6a2 | ||
|
|
8b79c76261 | ||
|
|
0015b51262 | ||
|
|
b1dc8cd9c6 | ||
|
|
3269e2d288 | ||
|
|
71a9747d96 | ||
|
|
455d041ce4 | ||
|
|
88205f8dd1 | ||
|
|
7d9dadddf6 | ||
|
|
57e78dd76f | ||
|
|
7d0d2b33f4 | ||
|
|
03c739102d | ||
|
|
392bb8d7b1 | ||
|
|
505b35be29 | ||
|
|
fdb002ad9b | ||
|
|
557c46373f | ||
|
|
3cde8be505 | ||
|
|
c2cf1f3a62 | ||
|
|
956cb1f13c | ||
|
|
f698b558e1 | ||
|
|
ca832900a0 | ||
|
|
6a6227a8e7 | ||
|
|
8539cdb5a7 | ||
|
|
5cea1de1ba | ||
|
|
e735b9e31f | ||
|
|
9ff8f8899f | ||
|
|
d908c4ef35 | ||
|
|
207f50726d | ||
|
|
212559fcce | ||
|
|
cf480e499c | ||
|
|
f2e27f5154 | ||
|
|
d932a4feae | ||
|
|
da6e05072f | ||
|
|
13277d9d71 | ||
|
|
f17f8b337f | ||
|
|
ffb454e414 | ||
|
|
424f5a09e7 | ||
|
|
c29a6f6446 | ||
|
|
6f7edf0941 | ||
|
|
a4c4b7e8d2 | ||
|
|
837f6f3a54 | ||
|
|
13041da6bf | ||
|
|
046824dae7 | ||
|
|
269a588d9d | ||
|
|
50ae12518a | ||
|
|
a932937adf | ||
|
|
23bd924ace | ||
|
|
e8f39685cc | ||
|
|
2122bacb33 | ||
|
|
3cb3c83442 | ||
|
|
d552d5257c | ||
|
|
0aff486a73 | ||
|
|
b887f3fc27 | ||
|
|
b30e2c4ad8 | ||
|
|
040b17e5eb | ||
|
|
770114a21c | ||
|
|
2864568f09 | ||
|
|
56eaa88dd7 | ||
|
|
bb54b90640 | ||
|
|
34502eeabe | ||
|
|
ae90f29fa3 | ||
|
|
1eeda4faaa | ||
|
|
18046c976e | ||
|
|
530bf85cf9 | ||
|
|
5261a9fed5 | ||
|
|
26d0d8dfdc | ||
|
|
eddf494b07 | ||
|
|
689a4ef6d4 | ||
|
|
9398304c60 | ||
|
|
e904f9f76e | ||
|
|
5df34ecfd8 | ||
|
|
a96951880d | ||
|
|
c4425627ee | ||
|
|
7033a0b5d2 | ||
|
|
a491be3975 | ||
|
|
c664ac21bb | ||
|
|
2205c0c33d | ||
|
|
e9c54a4228 | ||
|
|
a38427944c | ||
|
|
124db58683 | ||
|
|
aa075f9aaa | ||
|
|
305f8a0667 | ||
|
|
9d8238a2bb | ||
|
|
3fccd4c5c0 | ||
|
|
1a330e49f6 | ||
|
|
7c09f294bf | ||
|
|
22c520043f | ||
|
|
859c1eed0e | ||
|
|
e942668613 | ||
|
|
169c3a7970 | ||
|
|
22892ce550 | ||
|
|
2f5132c539 | ||
|
|
d737bd0d35 | ||
|
|
665958f1f5 | ||
|
|
4bf86892ab | ||
|
|
bab89d1152 | ||
|
|
4322c3b538 | ||
|
|
9fabfd77ee | ||
|
|
94ce4187c9 | ||
|
|
e78388e287 | ||
|
|
e3014bd0dc | ||
|
|
36c79b100e | ||
|
|
f6641aeca1 | ||
|
|
278187e738 | ||
|
|
668831d437 | ||
|
|
340f1e24ae | ||
|
|
44e773f737 | ||
|
|
03aae347b0 | ||
|
|
e393f36f0a | ||
|
|
b169193723 | ||
|
|
2de9b9d5c7 | ||
|
|
bde43ee7b2 | ||
|
|
4921e676d3 | ||
|
|
b76a47231c | ||
|
|
2561d26b95 | ||
|
|
4492bf517b | ||
|
|
c195e7e8ea | ||
|
|
667b418e28 | ||
|
|
0ee7ba6aae | ||
|
|
8a656908e1 | ||
|
|
4f05d04c7f | ||
|
|
c0fcbb7b85 | ||
|
|
fe36479d5c | ||
|
|
849829d6c0 | ||
|
|
a77e9d3241 | ||
|
|
fe26d41215 | ||
|
|
4d86712d4d | ||
|
|
006197a7c3 | ||
|
|
434aeb9761 | ||
|
|
b1ca831269 | ||
|
|
8fc9b14db4 | ||
|
|
36cc5434fd | ||
|
|
70c30a62e6 | ||
|
|
56827398d1 | ||
|
|
bd5cc93872 | ||
|
|
88be144a81 | ||
|
|
8046194696 | ||
|
|
3012cb6bf9 | ||
|
|
cf74ccaaef | ||
|
|
8749053f30 | ||
|
|
8368ce0e4c | ||
|
|
c6c2157c1d | ||
|
|
4740c81280 | ||
|
|
f4f6e628b8 | ||
|
|
55239207f4 | ||
|
|
d912e951a0 | ||
|
|
b0c3184565 | ||
|
|
b3c9c5057f | ||
|
|
1c022ee01d | ||
|
|
18589d86ff | ||
|
|
5a7b5d37b4 | ||
|
|
3e2115aa21 | ||
|
|
3f4a041e07 | ||
|
|
59eb46895c | ||
|
|
2f452cc6f6 | ||
|
|
770bb1d122 | ||
|
|
4a036fb2ad | ||
|
|
2ef72ad80f | ||
|
|
c9088067d5 | ||
|
|
6f772f77c9 | ||
|
|
2430617427 | ||
|
|
28888720bd | ||
|
|
32a1ba27ba | ||
|
|
b750ee2aa3 | ||
|
|
86aa5190b1 | ||
|
|
55288af936 | ||
|
|
827d2e461b | ||
|
|
8400bcf8bc | ||
|
|
4dcfde541a | ||
|
|
cf04a87688 | ||
|
|
65f88593b8 | ||
|
|
dbdf453724 | ||
|
|
e7f157b102 | ||
|
|
d30a5a4a50 | ||
|
|
b0cfb0ca1f | ||
|
|
c150f8c793 | ||
|
|
46733c0673 | ||
|
|
772d1c8a5a | ||
|
|
3f4bbdebe5 | ||
|
|
0394977658 | ||
|
|
33c9d01baf | ||
|
|
1367ee1e40 | ||
|
|
8ddeed80cf | ||
|
|
e796a57f14 | ||
|
|
839962370a | ||
|
|
0a993c10e0 | ||
|
|
aaaef51f2a | ||
|
|
8e10efd027 | ||
|
|
13c112430d | ||
|
|
05a40e786c | ||
|
|
64e05bed38 | ||
|
|
6f39909cd4 | ||
|
|
b4e41532eb | ||
|
|
4ca33d3f88 | ||
|
|
b40cdfbe66 | ||
|
|
e775b18fd5 | ||
|
|
b1506712c9 | ||
|
|
7af2be5f1c | ||
|
|
27b1c63563 | ||
|
|
7b8fbf0f96 | ||
|
|
a748686349 | ||
|
|
e2a0173d36 | ||
|
|
4d25e05986 | ||
|
|
c2091c52eb | ||
|
|
d74928fa0f | ||
|
|
dc8bf75b73 | ||
|
|
cc5ae8bf31 | ||
|
|
f62f7f9282 | ||
|
|
c3cbcbb0d5 | ||
|
|
ec2889b202 | ||
|
|
474d04d6a1 | ||
|
|
18f535413f | ||
|
|
85ca80f7ea | ||
|
|
097d10439d | ||
|
|
209d96131d | ||
|
|
4baed7b7b8 | ||
|
|
9f02286018 | ||
|
|
1b7d3b5fe9 | ||
|
|
a6d7aa7da3 | ||
|
|
11fe76f26d | ||
|
|
1b6fdf6093 | ||
|
|
fa3badcfd0 | ||
|
|
ce1b022025 | ||
|
|
6e81548daa | ||
|
|
bb7271ec17 | ||
|
|
f6ca42a4b0 | ||
|
|
bcf5d3a480 | ||
|
|
fffe26ceac | ||
|
|
fd17bdf963 | ||
|
|
a168009382 | ||
|
|
f624f92e4d | ||
|
|
f065171aa1 | ||
|
|
b7532abcc8 | ||
|
|
59aa0308c7 | ||
|
|
6b5708a563 | ||
|
|
c1a4834624 | ||
|
|
35ce3630c6 | ||
|
|
c686912707 | ||
|
|
963964afef | ||
|
|
53666dd289 | ||
|
|
d8d292348e | ||
|
|
678726859c | ||
|
|
bedafceac3 | ||
|
|
a3635bc45f | ||
|
|
8cc8394676 | ||
|
|
e5124093ff | ||
|
|
6d1d5d6bf8 | ||
|
|
8964b45558 | ||
|
|
eb0e9e7d1a | ||
|
|
17254ee863 | ||
|
|
85fdfdd81f | ||
|
|
3d194cd8cc | ||
|
|
3cc591fd8b | ||
|
|
3bb43745b8 | ||
|
|
beb12b6804 | ||
|
|
9a9cb2f8fe | ||
|
|
6b7fed814c | ||
|
|
47e26d93c0 | ||
|
|
de51c46fd8 | ||
|
|
d342bdaf72 | ||
|
|
7ee0150e2b | ||
|
|
cd5b0e7e58 | ||
|
|
aebda4aced | ||
|
|
26b7e6aabf | ||
|
|
9b16859c33 | ||
|
|
d662bf6064 | ||
|
|
a695a27b9c | ||
|
|
e46077f576 | ||
|
|
6ec3b05ce5 | ||
|
|
f9d561993a | ||
|
|
c0b59234d0 | ||
|
|
f041509f15 | ||
|
|
06b4300d09 | ||
|
|
7bf2194a08 | ||
|
|
b6bdf37a1d | ||
|
|
4060436099 | ||
|
|
406b6098c5 | ||
|
|
a5606098aa | ||
|
|
ff9bab4b4e | ||
|
|
6e881293ff | ||
|
|
5fac82cfee | ||
|
|
83da420cfc | ||
|
|
b2abccd302 | ||
|
|
99d9e8cd67 | ||
|
|
9fe275141f | ||
|
|
8c833101d8 | ||
|
|
0c6f9faaf1 | ||
|
|
a93ff5bf1f | ||
|
|
d258c1b417 | ||
|
|
6e473a75bd | ||
|
|
433de267a6 | ||
|
|
2beca32c36 | ||
|
|
15aaddb4d3 | ||
|
|
35ddb777b4 | ||
|
|
b15a0a2d4b | ||
|
|
95bda63c40 | ||
|
|
62b24fcd2a | ||
|
|
df0406902e | ||
|
|
71d57274e5 | ||
|
|
08c6258459 | ||
|
|
9a4e950480 | ||
|
|
e2dcdba5a7 | ||
|
|
c39cf848de | ||
|
|
5ccf2254eb | ||
|
|
dd291b9b71 | ||
|
|
0515fbb2d6 | ||
|
|
6692276472 | ||
|
|
81c09a9c9c | ||
|
|
6a0a367ec3 | ||
|
|
bdf533d62b | ||
|
|
1aba0bc26c | ||
|
|
aac6e9a365 | ||
|
|
9da732d96c | ||
|
|
328ba43ed2 | ||
|
|
62d3253b02 | ||
|
|
e5ba01e707 | ||
|
|
82c25f7f8c | ||
|
|
8791866ea0 | ||
|
|
8f10b8fece | ||
|
|
0d28d210d4 | ||
|
|
2368a5a050 | ||
|
|
74a9b1b41d | ||
|
|
672c49e8eb | ||
|
|
225db32636 | ||
|
|
01541e4a50 | ||
|
|
357e260b45 | ||
|
|
a2513b1851 | ||
|
|
bbe8604054 | ||
|
|
58a33de7f7 | ||
|
|
ab7abc6a48 | ||
|
|
4986bdf202 | ||
|
|
11aaddac98 | ||
|
|
da9b2b4378 | ||
|
|
9771a98bc6 | ||
|
|
033ee5f4e9 | ||
|
|
1383163627 | ||
|
|
1d31b35c4f | ||
|
|
7b2cc757b2 | ||
|
|
68cddd1c2e | ||
|
|
b2a9fbbc5c | ||
|
|
0fcb13b9f1 | ||
|
|
938a22ce2e | ||
|
|
2df5dbfe52 | ||
|
|
feed0d0faa | ||
|
|
c8373d20a9 | ||
|
|
170267a04a | ||
|
|
bd5969db67 | ||
|
|
02256c013c | ||
|
|
89be9a0d4a | ||
|
|
4e57a6e145 | ||
|
|
784434ef3e | ||
|
|
91273b2301 | ||
|
|
2bcc85a99f | ||
|
|
b7e6da3392 | ||
|
|
d934270a27 | ||
|
|
ed5a268e1f | ||
|
|
95beaa0a86 | ||
|
|
0d3bf93c76 | ||
|
|
50fb43066a | ||
|
|
c33ec8ff56 | ||
|
|
e6afeec8af | ||
|
|
57b9bdb958 | ||
|
|
315bcb72c9 | ||
|
|
6b2460c02f | ||
|
|
35bc999a59 | ||
|
|
f00ad75e45 | ||
|
|
6bfe8e5b41 | ||
|
|
d7e8fd7d06 | ||
|
|
949a0c35d5 | ||
|
|
d193d5572f | ||
|
|
f79f7e44a7 | ||
|
|
26db55aafd | ||
|
|
9d405c6cb2 | ||
|
|
cceee511f2 | ||
|
|
e2024ed2fd | ||
|
|
add7e2ee0e | ||
|
|
0458aa8eb4 | ||
|
|
9ff6be783a | ||
|
|
14c558559b | ||
|
|
92c5dcb6f2 | ||
|
|
ae31f349f7 | ||
|
|
ce2846d04f | ||
|
|
7a6c9a5fe4 | ||
|
|
43c258ad48 | ||
|
|
8ba032adb2 | ||
|
|
1a61dfd4e0 | ||
|
|
8e150e77a8 | ||
|
|
729fa753fa | ||
|
|
bf6c552189 | ||
|
|
e9dc987a95 | ||
|
|
35d9a39100 | ||
|
|
a864c8d6ed | ||
|
|
c2df8a099e | ||
|
|
878e9cb9ba | ||
|
|
3612ea2186 | ||
|
|
81f0f93d96 | ||
|
|
c2d7b65145 | ||
|
|
6274e82cea | ||
|
|
66655c9429 | ||
|
|
f47c8553d5 | ||
|
|
f2802d3332 | ||
|
|
1a173c849f | ||
|
|
57d4cd9fc9 | ||
|
|
f6b9345716 | ||
|
|
792cd01320 | ||
|
|
03bc7d0399 | ||
|
|
ed8f0812d7 | ||
|
|
196dc45d0b | ||
|
|
f8ff906d1b | ||
|
|
bbf1b0eda5 | ||
|
|
6f811a4899 | ||
|
|
c66957d685 | ||
|
|
282b2d5ace | ||
|
|
6a73e3ae05 | ||
|
|
5856d410fd | ||
|
|
08d9de54f0 | ||
|
|
af1f98131a | ||
|
|
9cef49ec57 | ||
|
|
d60c6d50ec | ||
|
|
f3fdec2739 | ||
|
|
1a20f57b73 | ||
|
|
0fc74dac4d | ||
|
|
4117dd91fc | ||
|
|
508ca0df39 | ||
|
|
a50e356beb | ||
|
|
a0b7237083 | ||
|
|
08afa73e69 | ||
|
|
b386317921 | ||
|
|
2043127f22 | ||
|
|
c297a9415b | ||
|
|
f9f9f25a01 | ||
|
|
9001af1beb | ||
|
|
4b03f17186 | ||
|
|
3dbab36b91 | ||
|
|
056c890845 | ||
|
|
4f43cd74ad | ||
|
|
6585b7b13d | ||
|
|
e55048b574 | ||
|
|
570dcde654 | ||
|
|
3cb16ee29b | ||
|
|
bb453da5b5 | ||
|
|
1a93b68664 | ||
|
|
2ce2494a50 | ||
|
|
0a1e451289 | ||
|
|
8ef7819080 | ||
|
|
319ad13af2 | ||
|
|
fe28e90ae3 | ||
|
|
f604a0a533 | ||
|
|
4ab78d42a3 | ||
|
|
c631e7dae6 | ||
|
|
da8e88d638 | ||
|
|
4707d9250d | ||
|
|
d719960411 | ||
|
|
734818c995 | ||
|
|
a35335a820 | ||
|
|
aca4dbfbe7 | ||
|
|
b036029b32 | ||
|
|
52f3e757ed | ||
|
|
c4ce1cf7d8 | ||
|
|
48175d0759 | ||
|
|
2932168db7 | ||
|
|
e8d96b8f84 | ||
|
|
bd15fd9da1 | ||
|
|
6e98eda963 | ||
|
|
ec9bb3601e | ||
|
|
02e4840b29 | ||
|
|
d7e8523fcf | ||
|
|
41464c3bfa | ||
|
|
a3617d0b5a | ||
|
|
10ff849ebd | ||
|
|
c2f7d487d0 | ||
|
|
395cf57e21 | ||
|
|
4c854a83c9 | ||
|
|
881b3b7e0c | ||
|
|
bb28e4279b | ||
|
|
c65b8ce162 | ||
|
|
8a303b1965 | ||
|
|
adca811941 | ||
|
|
f79e9d8773 | ||
|
|
629fbf4f07 | ||
|
|
da9ce52294 | ||
|
|
205605a3c4 | ||
|
|
e39127be92 | ||
|
|
0b2458d74a | ||
|
|
9d661122bd | ||
|
|
8518747a51 | ||
|
|
2f6450a560 | ||
|
|
c72889c10f | ||
|
|
bb7456e3f8 | ||
|
|
5aff13543e | ||
|
|
c7d967d43c | ||
|
|
1a42194304 | ||
|
|
312563437c | ||
|
|
5972ac1ed7 | ||
|
|
75d4123b34 | ||
|
|
89ef4f68a9 | ||
|
|
ed72677e52 | ||
|
|
08ab27c36c | ||
|
|
af8bb8fd05 | ||
|
|
57bade7eae | ||
|
|
3c6de0e84d | ||
|
|
24e3fea334 | ||
|
|
6af77aab8b | ||
|
|
12325633ed | ||
|
|
3a108b61ee | ||
|
|
b2eaf384ac | ||
|
|
3d17ef9603 | ||
|
|
3b031872f7 | ||
|
|
e97d39f37c | ||
|
|
763f715279 | ||
|
|
af9f79f3eb | ||
|
|
01ab3e2895 | ||
|
|
7a34344632 | ||
|
|
9714cb6790 | ||
|
|
aa981d03e8 | ||
|
|
9a09164fc3 | ||
|
|
9674a81323 | ||
|
|
aba7280691 | ||
|
|
ef9908b058 | ||
|
|
4da4fb4cbd | ||
|
|
b4f8a3b179 | ||
|
|
b48a955848 | ||
|
|
5ea4e3bcc3 | ||
|
|
6732cb01a8 | ||
|
|
0b5ca736d4 | ||
|
|
a2358c6bec | ||
|
|
10775dd2ac | ||
|
|
d33d12c642 | ||
|
|
af3ccfeed4 | ||
|
|
1d64267aba | ||
|
|
9bbef9b0c5 | ||
|
|
c95ec82b03 | ||
|
|
46108a00f0 | ||
|
|
d6c3fd7771 | ||
|
|
ad783ccaf0 | ||
|
|
f58be4241f | ||
|
|
cb1d22d88b | ||
|
|
6c8453d98e | ||
|
|
061de3b037 | ||
|
|
ded065ef38 | ||
|
|
822959238c | ||
|
|
4ebb9d7b46 | ||
|
|
cc49964c43 | ||
|
|
3787d5e84a | ||
|
|
7329606a6a | ||
|
|
5facafadea | ||
|
|
d3102df2bf | ||
|
|
87860da238 | ||
|
|
4a8aa01f40 | ||
|
|
9d35067b4b | ||
|
|
1c29be3745 | ||
|
|
bf3c3a3768 | ||
|
|
b25de79ae4 | ||
|
|
ba663ef2cc | ||
|
|
19185640a5 | ||
|
|
eafe8c4fff | ||
|
|
bdd3e69024 | ||
|
|
b5a7ab3688 | ||
|
|
cc0fa8dee6 | ||
|
|
14941cc1c0 | ||
|
|
910cb3a790 | ||
|
|
355e989eea | ||
|
|
bfcd9dad25 | ||
|
|
73ed5fd7cf | ||
|
|
d21cc0970c | ||
|
|
eb8b03139d | ||
|
|
1558145985 | ||
|
|
4ea9a29e62 | ||
|
|
72c8d9cd5e | ||
|
|
fb4fc38f14 | ||
|
|
de25db9e75 | ||
|
|
4ba558430d | ||
|
|
e4711484ac | ||
|
|
5081a3f635 | ||
|
|
b31fa366a2 | ||
|
|
c1b24b390a | ||
|
|
b7461442b0 | ||
|
|
c072e9b609 | ||
|
|
5236c58255 | ||
|
|
4f5280ea2b | ||
|
|
4d1c3fcaea | ||
|
|
310acaf4cc | ||
|
|
8111acaad1 | ||
|
|
c80b10d2b2 | ||
|
|
9807192bd1 | ||
|
|
9386c97851 | ||
|
|
7f3e9b10c4 | ||
|
|
360719582b | ||
|
|
a1a6d4a248 | ||
|
|
015ea78927 | ||
|
|
ad32841aaa | ||
|
|
2a3771dccf | ||
|
|
26af8af48f | ||
|
|
5829c3a843 | ||
|
|
c723d6d9d5 | ||
|
|
2c0c9a918a | ||
|
|
8f9bc7170e | ||
|
|
ee002167d4 | ||
|
|
4ddeb26cca | ||
|
|
a1514e2eaf | ||
|
|
5d1c7ab8b0 | ||
|
|
27698e34f5 | ||
|
|
c06b4773c7 | ||
|
|
e431936a8e | ||
|
|
de3d22a401 | ||
|
|
22778d9de7 | ||
|
|
069f517b04 | ||
|
|
1017dda1ec | ||
|
|
581b4a4216 | ||
|
|
e1f00cbf96 | ||
|
|
32ad0a7b87 | ||
|
|
aa4b9b16fb | ||
|
|
73721ab73a | ||
|
|
90cc3dc389 | ||
|
|
f4f4d5a6c0 | ||
|
|
4bd2410ee7 | ||
|
|
6bc264d33b | ||
|
|
c7d1c6818b | ||
|
|
937e68bf67 | ||
|
|
434fb96be7 | ||
|
|
e2fe86027c | ||
|
|
06ca891d94 | ||
|
|
57c00c9b12 | ||
|
|
b320e1e222 | ||
|
|
c72ddc9dd8 | ||
|
|
c37a386674 | ||
|
|
ad6a79b5b7 | ||
|
|
ff733cd50b | ||
|
|
53128a2391 | ||
|
|
d01fc8804c | ||
|
|
e520d7a58f | ||
|
|
7846ea636c | ||
|
|
0025ad8329 | ||
|
|
1a1f270f4e | ||
|
|
517f4498f5 | ||
|
|
87a165477f | ||
|
|
1e657f0b77 | ||
|
|
a8e399db1e | ||
|
|
66f9607404 | ||
|
|
27319c2da3 | ||
|
|
de21abb21c | ||
|
|
94cae4ac17 | ||
|
|
3b5e1f98f5 | ||
|
|
594f67c6d7 | ||
|
|
f1b415df2f | ||
|
|
c07e0ef581 | ||
|
|
0d4f6501b0 | ||
|
|
d2cbb7eea2 | ||
|
|
f4cb3c67c1 | ||
|
|
a51877cd1d | ||
|
|
c0c3287f74 | ||
|
|
83378802af | ||
|
|
f05d712923 | ||
|
|
5b2df55b8e | ||
|
|
865ec4dd8f | ||
|
|
6ddf1afc81 | ||
|
|
7bd44f4f14 | ||
|
|
a92c2003ee | ||
|
|
97a8c5e4b6 | ||
|
|
a5aa31f13e | ||
|
|
1a0161cb6b | ||
|
|
b8c17baf7c | ||
|
|
e161ea3f0a | ||
|
|
fb827a274b | ||
|
|
7281318ef6 | ||
|
|
80be7385ed | ||
|
|
8913dda413 | ||
|
|
b8ad90104b | ||
|
|
2646109986 | ||
|
|
cf247c828a | ||
|
|
28106e624e | ||
|
|
30e8420342 | ||
|
|
99e4d55e9b | ||
|
|
f9daec9e43 | ||
|
|
68a2902ce3 | ||
|
|
4b2db3de57 | ||
|
|
c4c526df17 | ||
|
|
15ad5531b0 | ||
|
|
c0af1c1094 | ||
|
|
9b89333244 | ||
|
|
1863030078 | ||
|
|
15055ffa0d | ||
|
|
8391ce28f7 | ||
|
|
b38791a357 | ||
|
|
53ba043168 | ||
|
|
d46a8dba7b | ||
|
|
1e62afc161 | ||
|
|
03cf6e868f | ||
|
|
e1da28ccc3 | ||
|
|
4173ca36cb | ||
|
|
c393de492d | ||
|
|
f9a716d70f | ||
|
|
2e8655c203 | ||
|
|
42b7164f33 | ||
|
|
602d49b045 | ||
|
|
58a67df534 | ||
|
|
de6cc04685 | ||
|
|
33763e074d | ||
|
|
32b0f8efb6 | ||
|
|
644618963a | ||
|
|
97ac31376e | ||
|
|
e5ec0f0221 | ||
|
|
5875ddc355 | ||
|
|
f7d5f4692d | ||
|
|
d85bc64aa9 | ||
|
|
a18ed0503c | ||
|
|
77a4e3771b | ||
|
|
7523eb1cb0 | ||
|
|
46f8ee9410 | ||
|
|
f0aa9f9fd2 | ||
|
|
73d5cadd8c | ||
|
|
1a0e2076d5 | ||
|
|
6db3dab5ea | ||
|
|
20856549c1 | ||
|
|
d570845592 | ||
|
|
eed27c0aac | ||
|
|
daef139496 | ||
|
|
3690d836b0 | ||
|
|
93faeb4177 | ||
|
|
095b9154e0 | ||
|
|
f86aa55220 | ||
|
|
40f7aecbba | ||
|
|
5d9d67caa4 | ||
|
|
0f00d6fb23 | ||
|
|
61b0e68641 | ||
|
|
6ed38ced3c | ||
|
|
7a681a97b5 | ||
|
|
41008fa594 | ||
|
|
fb13084b87 | ||
|
|
3f9023281e | ||
|
|
4e21fe6607 | ||
|
|
7a95c726cd | ||
|
|
940401e0f8 | ||
|
|
86bfb20903 | ||
|
|
e21cf87285 | ||
|
|
65f1445b64 | ||
|
|
f87761d092 | ||
|
|
0c712ac28d | ||
|
|
db301531d0 | ||
|
|
4c82a72fd5 | ||
|
|
7417e582c3 | ||
|
|
e32564c7b2 | ||
|
|
798bc482dc | ||
|
|
c7e7f756bc | ||
|
|
24358701f7 | ||
|
|
f1e392c0a0 | ||
|
|
5e8d38d8bc | ||
|
|
4650d2edbb | ||
|
|
b153033514 | ||
|
|
6dcbce5eb7 | ||
|
|
4ceeab439a | ||
|
|
8b1a6be9da | ||
|
|
baeb864075 | ||
|
|
c88e1c3619 | ||
|
|
1b04df7c5e | ||
|
|
237f11dba3 | ||
|
|
313f1c2f29 | ||
|
|
f0862f3bc7 | ||
|
|
1a8850ffe5 | ||
|
|
e640f812ba | ||
|
|
75ea170472 | ||
|
|
1b14b1926e | ||
|
|
edaed7ab01 | ||
|
|
6cceece3d7 | ||
|
|
2add03edb8 | ||
|
|
7aab9bae51 | ||
|
|
46c2c1d885 | ||
|
|
544e97fac0 | ||
|
|
265a700498 | ||
|
|
a657b4b0aa | ||
|
|
ac97c8cf34 | ||
|
|
545f3ee608 | ||
|
|
fcd1a36420 | ||
|
|
47a8ab3da9 | ||
|
|
c4375a8e7a | ||
|
|
a6c5bd3bb3 | ||
|
|
d53127e8cf | ||
|
|
851dd987ab | ||
|
|
cf582af970 | ||
|
|
d0ec331b6b | ||
|
|
cc75f5f7b3 | ||
|
|
3d08b7fdd0 | ||
|
|
7a92449fc3 | ||
|
|
4b3c34469d | ||
|
|
55bf34561e | ||
|
|
7e79dc0405 | ||
|
|
d3053523ab | ||
|
|
e32185cc14 | ||
|
|
8e3e3cf27b | ||
|
|
e2cea376e8 | ||
|
|
2a27b66d96 | ||
|
|
522717ca99 | ||
|
|
5ee106170b | ||
|
|
d62f04a5a6 | ||
|
|
eefe5048b2 | ||
|
|
8f792fde2d | ||
|
|
d8ef2d8300 | ||
|
|
e69dd5cb6a | ||
|
|
8acd57d87e | ||
|
|
a42aa1a273 | ||
|
|
4b2b7ccf82 | ||
|
|
e0fa180a23 | ||
|
|
06ea1fcd1b | ||
|
|
567bcc582d | ||
|
|
844f8c71fa | ||
|
|
bddbbb93cd | ||
|
|
310cc83d36 | ||
|
|
23dcdc5863 | ||
|
|
1286e1835c | ||
|
|
613f2ed939 | ||
|
|
46108f8d0c | ||
|
|
28dcfa4131 | ||
|
|
b48597d3c3 | ||
|
|
fe4c6ba13e | ||
|
|
4049493ffd | ||
|
|
0c9b6e98f7 | ||
|
|
ce33d0be5a | ||
|
|
4f0fb90bff | ||
|
|
66eff0107a | ||
|
|
82f83e610f | ||
|
|
cf7df391ad | ||
|
|
244c9f8204 | ||
|
|
26dc19df7d | ||
|
|
7b8bff1a08 | ||
|
|
0b010124ef | ||
|
|
c7bde15f39 | ||
|
|
b941e4f2f0 | ||
|
|
536c6e7e29 | ||
|
|
dfe4abec35 | ||
|
|
693b80d7d3 | ||
|
|
c9e6475ef4 | ||
|
|
b745132ebd | ||
|
|
19686cb19f | ||
|
|
e0c0593b5b | ||
|
|
415a8af363 | ||
|
|
d44777b1b4 | ||
|
|
e3ff3037b4 | ||
|
|
7add30fd31 | ||
|
|
501cd0349b | ||
|
|
7b4e3f6601 | ||
|
|
8622c2780c | ||
|
|
13de7b6d5b | ||
|
|
53cb864f9c | ||
|
|
72f693f02a | ||
|
|
fb80e32682 | ||
|
|
1db3426ee1 | ||
|
|
a44879e384 | ||
|
|
c0075c817d | ||
|
|
177dc3322b | ||
|
|
21ef4fc89b | ||
|
|
f467643f6f | ||
|
|
3db41e7e05 | ||
|
|
73151729c6 | ||
|
|
5d9c415028 | ||
|
|
b92ed4da4e | ||
|
|
2d1a9a03d2 | ||
|
|
5d6edd2321 | ||
|
|
365f4ba83f | ||
|
|
66e30ae293 | ||
|
|
728425de19 | ||
|
|
b0af1f800b | ||
|
|
543271e856 | ||
|
|
a1564a44fa | ||
|
|
571029cfd3 | ||
|
|
579eaa630a | ||
|
|
9530c8ffe0 | ||
|
|
0d8690091b | ||
|
|
5b5e3a1ec1 | ||
|
|
869ae5e3ed | ||
|
|
d6dc8d86f8 | ||
|
|
758745be68 | ||
|
|
2adfa56d6a | ||
|
|
a4c728f5df | ||
|
|
5c06341b7f | ||
|
|
6f57902a9b | ||
|
|
a3e118893d | ||
|
|
ff2d3c29d6 | ||
|
|
59a8df85f2 | ||
|
|
e303bd182a | ||
|
|
dcef9a497c | ||
|
|
8d4fd66aaf | ||
|
|
471bd23acf | ||
|
|
ffcef81dd0 | ||
|
|
317df5d06b | ||
|
|
ad7b5efd6f | ||
|
|
891f770724 | ||
|
|
0b6d715982 | ||
|
|
76c2415516 | ||
|
|
3260faca17 | ||
|
|
feb493158c | ||
|
|
a5c1556cb7 | ||
|
|
89e640bdd9 | ||
|
|
3ade8daff8 | ||
|
|
049ea3fbed | ||
|
|
715d26beed | ||
|
|
1f5064094c | ||
|
|
7ed522dc29 | ||
|
|
2086500405 | ||
|
|
8f79409ed1 | ||
|
|
c2a3cd1476 | ||
|
|
e195a5d72c | ||
|
|
c86b757904 | ||
|
|
6800d2ac95 | ||
|
|
90fda2b4bb | ||
|
|
bf7ded9058 | ||
|
|
6615dc3a62 | ||
|
|
c35054085c | ||
|
|
fdf2bd7f96 | ||
|
|
1c10b9dfe1 | ||
|
|
6854394e5c | ||
|
|
78a0d5f432 | ||
|
|
5fe5aa70a4 | ||
|
|
e9c0c6bd0b | ||
|
|
5d12b3dc9c | ||
|
|
169a4b66db | ||
|
|
fbd6329db9 | ||
|
|
69c2e56857 | ||
|
|
18f7d1edd3 | ||
|
|
3f7cd5ff92 | ||
|
|
785e1dbf83 | ||
|
|
bc6acf8d14 | ||
|
|
3a099d0b2e | ||
|
|
f9ad5e4144 | ||
|
|
ce9f6650a0 | ||
|
|
fdeef04343 | ||
|
|
fe72ec82e1 | ||
|
|
fd0f308273 | ||
|
|
f4e9ab43cb | ||
|
|
3a141b523c | ||
|
|
2d731532be | ||
|
|
d545cd5be0 | ||
|
|
261d05d67e | ||
|
|
639995785a | ||
|
|
817e076cae | ||
|
|
713370f343 | ||
|
|
5594503a56 | ||
|
|
d57e5d46fb | ||
|
|
ee2db5fabd | ||
|
|
0c4cd6f378 | ||
|
|
8c32b9665c | ||
|
|
7405a01654 | ||
|
|
5d27691b4b | ||
|
|
19bbcfbf4c | ||
|
|
fa1064db87 | ||
|
|
850ac69ca1 | ||
|
|
943edeb30c | ||
|
|
01815a354b | ||
|
|
2f4412aca1 | ||
|
|
2782bb7594 | ||
|
|
074c1298d5 | ||
|
|
55a7911611 | ||
|
|
013ad3044d | ||
|
|
dcf4217b9d | ||
|
|
876dfc31a9 | ||
|
|
fd03bdbe00 | ||
|
|
83612649d5 | ||
|
|
3c4db7e97e | ||
|
|
088c70efdc | ||
|
|
2b19029dd0 | ||
|
|
4fb5a84378 | ||
|
|
b3107d9a25 | ||
|
|
bf32988f3e | ||
|
|
1bf3dd7bf4 | ||
|
|
07fd84f89f | ||
|
|
3a8db4a97a | ||
|
|
aea30a26f5 | ||
|
|
8f5d1cdae7 | ||
|
|
53913357e0 | ||
|
|
098416f444 | ||
|
|
c98cb09c7c | ||
|
|
bb1ef28d69 | ||
|
|
1d5b05265d | ||
|
|
d9fef3c30e | ||
|
|
e5dfb9efc3 | ||
|
|
02bab15e86 | ||
|
|
6f4ddead09 | ||
|
|
b361248ff6 | ||
|
|
e9c42ceaa5 | ||
|
|
5d7029744a | ||
|
|
1084a3afa8 | ||
|
|
ed254bffee | ||
|
|
733784d7dd | ||
|
|
cb5b26bcb4 | ||
|
|
0065152bb1 | ||
|
|
03266203fd | ||
|
|
4a5f68f9d8 | ||
|
|
83e31a1c27 | ||
|
|
0efed5ef9c | ||
|
|
cdfef1281d | ||
|
|
e00907e142 | ||
|
|
6dcbcf39e3 | ||
|
|
044579a8e0 | ||
|
|
d2b52b4663 | ||
|
|
7f75b2c02c | ||
|
|
24a3f671e5 | ||
|
|
875100e3c8 | ||
|
|
34bc7c0cfd | ||
|
|
b39a10ff7c | ||
|
|
02331904de | ||
|
|
d1a4ae694e | ||
|
|
7a5ffc1124 | ||
|
|
19c5bfb42c | ||
|
|
893bf3686b | ||
|
|
e54fa9bcd4 | ||
|
|
c1eb5ab0fe | ||
|
|
461914dde4 | ||
|
|
85662578e4 | ||
|
|
a59c0ae795 | ||
|
|
3a860155ee | ||
|
|
27553c2967 | ||
|
|
9a8ac9af3c | ||
|
|
2f5daffe99 | ||
|
|
75cd31dce4 | ||
|
|
f7150d1b41 | ||
|
|
d6a6b65338 | ||
|
|
979f6027b4 | ||
|
|
7dc059c75b | ||
|
|
b639b5974f | ||
|
|
0de08c553c | ||
|
|
80788ac695 | ||
|
|
1494c621c1 | ||
|
|
605e5b5173 | ||
|
|
4cf2213051 | ||
|
|
3aa36668e5 | ||
|
|
1c0b5b42e9 | ||
|
|
702dc44fad | ||
|
|
2cae07aa52 | ||
|
|
b5616ff25c | ||
|
|
b7b7521975 | ||
|
|
dce3263ee3 | ||
|
|
9796e05ca1 | ||
|
|
5cc0d459ec | ||
|
|
531a850a71 | ||
|
|
4c36280287 | ||
|
|
70be8eb55e | ||
|
|
f8b757b21e | ||
|
|
3a63d352bb | ||
|
|
60467705c5 | ||
|
|
eada0c09e0 | ||
|
|
8e851aa6a1 | ||
|
|
eaf7bb967d | ||
|
|
7be45c77b1 | ||
|
|
5e2b460dc8 | ||
|
|
16143e698f | ||
|
|
4259946e3b | ||
|
|
0a750d76ee | ||
|
|
e4a9f5f0dd | ||
|
|
d5b7698f89 | ||
|
|
a481e8508e | ||
|
|
a53b57497b | ||
|
|
d871357b2d | ||
|
|
2d57db55f4 | ||
|
|
bae45ce03a | ||
|
|
44cc4336f1 | ||
|
|
44f6e214fd | ||
|
|
3e46f81d2b | ||
|
|
e4532b9a50 | ||
|
|
2694be562c | ||
|
|
fadb9edd7f | ||
|
|
d85e0790de | ||
|
|
bc46c4d704 | ||
|
|
a73a010188 | ||
|
|
4e8c8ef317 | ||
|
|
e402e7805d | ||
|
|
302b8f026b | ||
|
|
630054b72a | ||
|
|
a05f459b2b | ||
|
|
207979580a | ||
|
|
f69526f8bf | ||
|
|
e249d567a1 | ||
|
|
a23ba653da | ||
|
|
0644d53572 | ||
|
|
f58f51294d | ||
|
|
86194eb93e | ||
|
|
0a89f375e6 | ||
|
|
6282178b3c | ||
|
|
8e14d68022 | ||
|
|
e86bd0c070 | ||
|
|
bf991f8892 | ||
|
|
b341678d20 | ||
|
|
5f59365d88 | ||
|
|
5130a7bb33 | ||
|
|
cc84a596d6 | ||
|
|
e67bed431a | ||
|
|
72613a9f48 | ||
|
|
c048ea0615 | ||
|
|
957ca1b7ed | ||
|
|
d80a6df039 | ||
|
|
94f9bd9d91 | ||
|
|
b480efe672 | ||
|
|
4fc306d979 | ||
|
|
56abccbdeb | ||
|
|
f218af0735 | ||
|
|
9b69c62780 | ||
|
|
eb5d67e07f | ||
|
|
e7391987b1 | ||
|
|
02cbe15575 | ||
|
|
a5a657f0d4 | ||
|
|
67567c86e0 | ||
|
|
445d02da45 | ||
|
|
4a05df41ce | ||
|
|
5c0c2f6b45 | ||
|
|
0ab55fef46 | ||
|
|
dd344bfe38 | ||
|
|
e92a889bcc | ||
|
|
419d656a83 | ||
|
|
3c3d58bfe9 | ||
|
|
1989099cc5 | ||
|
|
1446e3f0a9 | ||
|
|
00fc31289d | ||
|
|
2c463ad6af | ||
|
|
e641ae05c4 | ||
|
|
a13e0075ee | ||
|
|
e617a7b88e | ||
|
|
cbdeb4caad | ||
|
|
59314d692f | ||
|
|
3dfa56b279 | ||
|
|
920d5d7416 | ||
|
|
dcb654d7fb | ||
|
|
a563da1223 | ||
|
|
1e26cda615 | ||
|
|
97133b27ce | ||
|
|
b428bd3b87 | ||
|
|
05136e74b4 | ||
|
|
9f28a8bdf1 | ||
|
|
d9361f1fee | ||
|
|
835230b1a4 | ||
|
|
f88f51c553 | ||
|
|
1996305eb1 | ||
|
|
c7ad50e950 | ||
|
|
0ec0c29d67 | ||
|
|
75af117e8a | ||
|
|
2b04cefe4e | ||
|
|
0e41c4111a | ||
|
|
5f5d382c64 | ||
|
|
3e867fe401 | ||
|
|
153142b8b0 | ||
|
|
5562c0c047 | ||
|
|
f4a1f800ba | ||
|
|
bdbc5e5605 | ||
|
|
4104f825ff | ||
|
|
efa01ea404 | ||
|
|
982559ae66 | ||
|
|
60002e8de8 | ||
|
|
25d671e0f6 | ||
|
|
5a58281a3f | ||
|
|
c422231806 | ||
|
|
4979883fe5 | ||
|
|
8158a624d3 | ||
|
|
06403b5fce | ||
|
|
bc482652fc | ||
|
|
58aa5755e0 | ||
|
|
bca835c58a | ||
|
|
4b0f68a57a | ||
|
|
b693d73ebe | ||
|
|
dfab80447b | ||
|
|
bbde0c866a | ||
|
|
7b3514f757 | ||
|
|
6d5fb3b252 | ||
|
|
87e8f118d3 | ||
|
|
3ae78cc0a8 | ||
|
|
7ef921356f | ||
|
|
378185d997 | ||
|
|
c4b15a8509 | ||
|
|
96ef9d155b | ||
|
|
d5e6412b20 | ||
|
|
eebe757c16 | ||
|
|
43a21d32cb | ||
|
|
9f9eb5ef17 | ||
|
|
0116c62980 | ||
|
|
fae446e495 | ||
|
|
6f7054df18 | ||
|
|
0f31c21f4a | ||
|
|
bd3e234703 | ||
|
|
71bfd63623 | ||
|
|
98b89dc83c | ||
|
|
97ec789bbe | ||
|
|
14b403c046 | ||
|
|
bc01d25068 | ||
|
|
69808c34a8 | ||
|
|
273181daf5 | ||
|
|
8d2394eba1 | ||
|
|
6f5b468b11 | ||
|
|
c9e759bc14 | ||
|
|
e6d064f5c1 | ||
|
|
8f7ed02475 | ||
|
|
f7edcebbdc | ||
|
|
a19b392ba6 | ||
|
|
287df9ef86 | ||
|
|
de7be379c4 | ||
|
|
1e4d41795c | ||
|
|
e2e973a20e | ||
|
|
5d993fbfc0 | ||
|
|
a94a8ea287 | ||
|
|
55d8677a46 | ||
|
|
4004aeb54e | ||
|
|
2de2898d86 | ||
|
|
8c1b48a88d | ||
|
|
9bd3022a5e | ||
|
|
eb0ce609f0 | ||
|
|
5353eba35b | ||
|
|
4f94ceed5e | ||
|
|
cd29998b40 | ||
|
|
9aad6be26a | ||
|
|
19edee88bc | ||
|
|
42e6a7d024 | ||
|
|
1890290d05 | ||
|
|
c85231be96 | ||
|
|
0ca89771d6 | ||
|
|
d203b12464 | ||
|
|
b64690bdd6 | ||
|
|
e76c696678 | ||
|
|
f1ad2090fc | ||
|
|
f0be3c3966 | ||
|
|
8b7abc956f | ||
|
|
25a8af392b | ||
|
|
ebe1b3497e | ||
|
|
6a7246fe5a | ||
|
|
1d64e46fcd | ||
|
|
6d5e089e4e | ||
|
|
845bc1d41b | ||
|
|
007cd73ac5 | ||
|
|
651a7e4078 | ||
|
|
c3423370ec | ||
|
|
500f1e37f6 | ||
|
|
699a9bfa8e | ||
|
|
90aa7f0d0e | ||
|
|
527819703e | ||
|
|
47adc8fe48 | ||
|
|
865ad5d631 | ||
|
|
877b99c1d5 | ||
|
|
45bb124200 | ||
|
|
147af04342 | ||
|
|
b30e54bdc1 | ||
|
|
1b7484cf22 | ||
|
|
c04513f8bd | ||
|
|
c29db6ee6f | ||
|
|
0d60b001fb | ||
|
|
ea7d428c1b | ||
|
|
55ac61dbb0 | ||
|
|
048878b197 | ||
|
|
1e479de839 | ||
|
|
5b34f6c515 | ||
|
|
8fcf83769c | ||
|
|
d1ca55da55 | ||
|
|
375328623b | ||
|
|
be15137a49 | ||
|
|
43d89b2eaf | ||
|
|
d590a189ed | ||
|
|
c26861bff6 | ||
|
|
b4923deae2 | ||
|
|
20e7a65d92 | ||
|
|
fc895d105e | ||
|
|
e0e8dbe6b6 | ||
|
|
8e5834dcbb | ||
|
|
668c173969 | ||
|
|
4c19a941eb | ||
|
|
9761153ab0 | ||
|
|
140a1b1587 | ||
|
|
e5f5f40f3c | ||
|
|
2e13622ecc | ||
|
|
a4fb281859 | ||
|
|
75ba4e2220 | ||
|
|
24b17da2ea | ||
|
|
c4664fe6e3 | ||
|
|
a1ab298609 | ||
|
|
533f9f8323 | ||
|
|
6d5912f307 | ||
|
|
3d2b7c136a | ||
|
|
f25d147908 | ||
|
|
e119c8cc53 | ||
|
|
73e94350df | ||
|
|
9d8ee5aec8 | ||
|
|
c3bbd5f54f | ||
|
|
e17be93cb6 | ||
|
|
1013ca340a | ||
|
|
b87e7c0af8 | ||
|
|
615348c5a1 | ||
|
|
cae0f9bc2e | ||
|
|
93b23e3de0 | ||
|
|
eebb00d2b3 | ||
|
|
11f9b04fd1 | ||
|
|
bde996de75 | ||
|
|
552163a3bd | ||
|
|
2e6af966a9 | ||
|
|
c1775967c8 | ||
|
|
034a0a594d | ||
|
|
63a66ea82a | ||
|
|
6f155ebf17 | ||
|
|
f39d8cc5fb | ||
|
|
aecba7e710 | ||
|
|
c365eeec76 | ||
|
|
5bd06402de | ||
|
|
ec899a45d5 | ||
|
|
513c9cee3d | ||
|
|
850f2abd5c | ||
|
|
8d7940ebee | ||
|
|
195e9c398e | ||
|
|
c998d6bd1b | ||
|
|
34be14ece1 | ||
|
|
c0d6f33d54 | ||
|
|
d5210283ca | ||
|
|
545784d7af | ||
|
|
e9726b1e75 | ||
|
|
e08b2cccf9 | ||
|
|
0ba1b982d1 | ||
|
|
374c02c46e | ||
|
|
5ed59690a0 | ||
|
|
2de489f301 | ||
|
|
40a722294f | ||
|
|
9598c525cf | ||
|
|
3ed6c5e943 | ||
|
|
0f178c17ee | ||
|
|
1c963b72a3 | ||
|
|
bd1b3b8b12 | ||
|
|
f9a843dfd5 | ||
|
|
9df8f4ae2b | ||
|
|
87f649b71b | ||
|
|
3585bb0a6e | ||
|
|
750bbd64b2 | ||
|
|
19c567cef3 | ||
|
|
5024368854 | ||
|
|
3200f88363 | ||
|
|
650c77d0d1 | ||
|
|
3fa29515f2 | ||
|
|
012435747e | ||
|
|
733077a437 | ||
|
|
6b3fa74800 | ||
|
|
d673627c79 | ||
|
|
8b423d00e9 | ||
|
|
201086c854 | ||
|
|
2441cf36b3 | ||
|
|
df0f2a549e | ||
|
|
9b7cbab37c | ||
|
|
ac46cb2371 | ||
|
|
c858c88bb3 | ||
|
|
a05f5d9860 | ||
|
|
e6914b91e1 | ||
|
|
b624bd2d35 | ||
|
|
e3c9b2c0bf | ||
|
|
576a1e7cb2 | ||
|
|
55c3ba73d3 | ||
|
|
2246d30bbe | ||
|
|
789e333736 | ||
|
|
283904107f | ||
|
|
8d92261852 | ||
|
|
e8f5d82b78 | ||
|
|
0a8643155e | ||
|
|
61793201c7 | ||
|
|
41f2982074 | ||
|
|
27b86f1b79 | ||
|
|
d69892c91e | ||
|
|
296549d1bf | ||
|
|
7d2f147172 | ||
|
|
aa56f99ee2 | ||
|
|
ca82b99f42 | ||
|
|
d204a5b844 | ||
|
|
0a98550770 | ||
|
|
0c0c2736a7 | ||
|
|
27e2d984ce | ||
|
|
14eeae09b1 | ||
|
|
16eb47070d | ||
|
|
1f69f58593 | ||
|
|
1b4421e013 | ||
|
|
f13400d592 | ||
|
|
e29f0323ea | ||
|
|
15a582d046 | ||
|
|
1e01f8be17 | ||
|
|
8cc73991a3 | ||
|
|
ecce74ade5 | ||
|
|
836efaaf70 | ||
|
|
46f8e7dc00 | ||
|
|
88cd033ca6 | ||
|
|
984df3bcdf | ||
|
|
7673cdb1aa | ||
|
|
8af700ce37 | ||
|
|
ffb8752190 | ||
|
|
71fa3ab3af | ||
|
|
09501cfa74 | ||
|
|
d84ae12733 | ||
|
|
05f292abe6 | ||
|
|
a75833d322 | ||
|
|
ca3f56de5c | ||
|
|
9d75f2c9c7 | ||
|
|
a58cbf92b0 | ||
|
|
7bac76fae5 | ||
|
|
9c71b39edd | ||
|
|
52f731c6b7 | ||
|
|
735d1cb689 | ||
|
|
5a0977f412 | ||
|
|
1da1fccbc7 | ||
|
|
ca5a528818 | ||
|
|
a9ef806a37 | ||
|
|
de112b7788 | ||
|
|
ef7baba274 | ||
|
|
3a9d13b011 | ||
|
|
5b5493aab0 | ||
|
|
5f208d8f12 | ||
|
|
47c077d066 | ||
|
|
d2ac69b6c1 | ||
|
|
8860cac7dd | ||
|
|
28bcc73c70 | ||
|
|
af20c2d8f0 | ||
|
|
44213ca510 | ||
|
|
ab21a1ac00 | ||
|
|
a67f366501 | ||
|
|
b32251e5aa | ||
|
|
16e0accb74 | ||
|
|
c6ce291cbf | ||
|
|
b7525475d8 | ||
|
|
f35a36ac02 | ||
|
|
3b53f89a24 | ||
|
|
764d94e41b | ||
|
|
0292e15497 | ||
|
|
bde4ac7b2f | ||
|
|
c71fa3abd1 | ||
|
|
d2abdb5d3a | ||
|
|
1392791837 | ||
|
|
6f7d9634d5 | ||
|
|
82b95114a8 | ||
|
|
d90e701acd | ||
|
|
42993022bb | ||
|
|
29b1e46252 | ||
|
|
260cea639f | ||
|
|
208aea8aca | ||
|
|
f164d401d3 | ||
|
|
5e1c34a08b | ||
|
|
9c7b596a0d | ||
|
|
5ff34ac6d0 | ||
|
|
e304e34929 | ||
|
|
6d7848248d | ||
|
|
dbc0da0586 | ||
|
|
fecdcf9d10 | ||
|
|
bfd0ab2301 | ||
|
|
8002777e75 | ||
|
|
d57d5acb30 | ||
|
|
43e6664dd9 | ||
|
|
d0c6dff83e | ||
|
|
54b40f5978 | ||
|
|
1c59c03261 | ||
|
|
ce23fd38ab | ||
|
|
4818efa7de | ||
|
|
ea19e74229 | ||
|
|
fe353de5a8 | ||
|
|
1d89266f2e | ||
|
|
61d79394ca | ||
|
|
491f2828b5 | ||
|
|
431e05d4f4 | ||
|
|
ae6780a487 | ||
|
|
5707a70141 | ||
|
|
e9a7bd7da1 | ||
|
|
91e45daf6c | ||
|
|
9f69998075 | ||
|
|
4f6270976b | ||
|
|
328caa43f2 | ||
|
|
368408374a | ||
|
|
c3a90db493 | ||
|
|
5bc0320877 | ||
|
|
622ed620b9 | ||
|
|
1b859413de | ||
|
|
95432fd8e3 | ||
|
|
b3f3c5d7b3 | ||
|
|
02cef20462 | ||
|
|
3edebe34ae | ||
|
|
28c9b75fb5 | ||
|
|
a2735e10b7 | ||
|
|
e03d26fd63 | ||
|
|
7c4c346e64 | ||
|
|
67b3c0c4a8 | ||
|
|
dadca785e4 | ||
|
|
accebe5597 | ||
|
|
792965bedd | ||
|
|
1bb1bafe0c | ||
|
|
28c11324ca | ||
|
|
42d940c38e | ||
|
|
c1ea05b925 | ||
|
|
9435693865 | ||
|
|
14da582637 | ||
|
|
b2d4a795a1 | ||
|
|
493696705b | ||
|
|
d827c6f09a | ||
|
|
df000b0cb2 | ||
|
|
d9630a32c7 | ||
|
|
71cc6f61bd | ||
|
|
46eb832cc7 | ||
|
|
11b2e4b430 | ||
|
|
11775532ee | ||
|
|
f3388db8ba | ||
|
|
25ac86393f | ||
|
|
b3432a95e1 | ||
|
|
e34d169fa6 | ||
|
|
de84accb7a | ||
|
|
187577cbb5 | ||
|
|
72109b72d2 | ||
|
|
f6c01d11e9 | ||
|
|
d695ef4f57 | ||
|
|
16c6dcc573 | ||
|
|
3df19b286a | ||
|
|
6f1b08762d | ||
|
|
a4a379f9d6 | ||
|
|
3d3d0304bc | ||
|
|
26135018a3 | ||
|
|
4bd381bb99 | ||
|
|
cf08972e82 | ||
|
|
d57a58d1e7 | ||
|
|
f10789965e | ||
|
|
94145bd300 | ||
|
|
cdcb61d10d | ||
|
|
56146a34af | ||
|
|
991e818449 | ||
|
|
80083cba76 | ||
|
|
2c44fd5aa2 | ||
|
|
1561dd38fc | ||
|
|
8152648f66 | ||
|
|
c1507d0381 | ||
|
|
f0fb603af2 | ||
|
|
93e891153f | ||
|
|
26ece717b6 | ||
|
|
93767335ca | ||
|
|
7cbe751a39 | ||
|
|
c45df83f19 | ||
|
|
fabce61a58 | ||
|
|
5c9ccae598 | ||
|
|
6c9d7239f2 | ||
|
|
4b75e2577e | ||
|
|
08c9d942a4 | ||
|
|
3b59b4ad21 | ||
|
|
7682eec52a | ||
|
|
694517bbe7 | ||
|
|
7f443fdd05 | ||
|
|
01ab891c11 | ||
|
|
052aacfd36 | ||
|
|
80a6d2ccfb | ||
|
|
b4ce175bdf | ||
|
|
f6f52d32dc | ||
|
|
865b2de9bb | ||
|
|
4a8233a041 | ||
|
|
f856ad78a3 | ||
|
|
653267cbe6 | ||
|
|
8b53df27ab | ||
|
|
c4b7c2b58c | ||
|
|
66f82f364c | ||
|
|
6d269607d2 | ||
|
|
8370977e5b | ||
|
|
e2c335ff73 | ||
|
|
816b9d0343 | ||
|
|
2922e1ba35 | ||
|
|
c86f341d29 | ||
|
|
73cdd68283 | ||
|
|
81641686bc | ||
|
|
14c58c8e62 | ||
|
|
74b8f2587c | ||
|
|
bebe041061 | ||
|
|
2e5d3d2952 | ||
|
|
c2d155b8ff | ||
|
|
fda368ff08 | ||
|
|
19cf592e77 | ||
|
|
260cac6b59 | ||
|
|
673275e708 | ||
|
|
a6bc778c25 | ||
|
|
ef2f5879b6 | ||
|
|
ee725bf625 | ||
|
|
5388fa442c | ||
|
|
913493fd2e | ||
|
|
6d4a8c6619 | ||
|
|
4a57115336 | ||
|
|
1dd754a0d5 | ||
|
|
509b78d906 | ||
|
|
363366d012 | ||
|
|
26d4fd4e00 | ||
|
|
09ee97e775 | ||
|
|
1400a95cec | ||
|
|
5e96c4ca79 | ||
|
|
3c068b2a00 | ||
|
|
81fd7757c1 | ||
|
|
1db64b72ae | ||
|
|
ab1bed236c | ||
|
|
e503999392 | ||
|
|
2392eb7e0b | ||
|
|
c62b54f18d | ||
|
|
603d46c1ae | ||
|
|
c0e0ae551d | ||
|
|
a0a2507c05 | ||
|
|
6eed48b28d | ||
|
|
9c5d289098 | ||
|
|
42ab7f23d8 | ||
|
|
c9c2f4232e | ||
|
|
d4f23cc6bd | ||
|
|
b0db67d4d4 | ||
|
|
703cad6715 | ||
|
|
667d67460f | ||
|
|
35cf9ae328 | ||
|
|
c04131af4b | ||
|
|
9cc4db1a12 | ||
|
|
b326500913 | ||
|
|
a26579fcf5 | ||
|
|
a2b9c44433 | ||
|
|
c3b97da1d4 | ||
|
|
048cf0232a | ||
|
|
89c113bee6 | ||
|
|
6b9969a302 | ||
|
|
a6e7513d2a | ||
|
|
8a04f4810f | ||
|
|
1d9d443de0 | ||
|
|
00e5809a71 | ||
|
|
07ba4a040b | ||
|
|
7b319d230a | ||
|
|
641bc2daec | ||
|
|
fbaa30cc08 | ||
|
|
a0c2c9056b | ||
|
|
30ab5fd76b | ||
|
|
30beab4017 | ||
|
|
4ec1493b09 | ||
|
|
e7cbe9709e | ||
|
|
aacaeba525 | ||
|
|
6e4da5efb7 | ||
|
|
87443a4ff2 | ||
|
|
9746759c68 | ||
|
|
170ee2b98a | ||
|
|
938fb777dd | ||
|
|
33e1aafcd1 | ||
|
|
597ee90041 | ||
|
|
e87e54ea28 | ||
|
|
5c64c1ac3f | ||
|
|
c611cbc2ca | ||
|
|
9d051f4171 | ||
|
|
6aee788678 | ||
|
|
425a45caa7 | ||
|
|
0571601e02 | ||
|
|
c1992c8c7a | ||
|
|
bd913870c7 | ||
|
|
7a479dd47f | ||
|
|
7ae77aa58d | ||
|
|
97a4260d44 | ||
|
|
b90d711764 | ||
|
|
22de5b523e | ||
|
|
5798b824c0 | ||
|
|
4cbf6cfc33 | ||
|
|
8b55460156 | ||
|
|
a61d48a451 | ||
|
|
b9f4d57d67 | ||
|
|
92cd36d14d | ||
|
|
f74e61b126 | ||
|
|
c8b4ba2b5b | ||
|
|
0a15ba1c5b | ||
|
|
7ee5948233 | ||
|
|
85c8bcf9d2 | ||
|
|
67394c6664 | ||
|
|
66ef7d8229 | ||
|
|
3773bc69f2 | ||
|
|
912416b119 | ||
|
|
7dfe125013 | ||
|
|
87db34ef0b | ||
|
|
d4f75ab53c | ||
|
|
dc97e8fce5 | ||
|
|
b3965d9d67 | ||
|
|
7ee90d1e12 | ||
|
|
9d8b373e4f | ||
|
|
a068a7eb5b | ||
|
|
aa004c1893 | ||
|
|
9a9c149370 | ||
|
|
9e6e226e4b | ||
|
|
06c2aed0e0 | ||
|
|
df4f610cfc | ||
|
|
64249abae1 | ||
|
|
94f4be58bd | ||
|
|
35987d3741 | ||
|
|
be73e00dde | ||
|
|
a5f272f337 | ||
|
|
406691aa69 | ||
|
|
6827b3bf15 | ||
|
|
2055a1472f | ||
|
|
f4f9018068 | ||
|
|
3e82b5cd33 | ||
|
|
07036bce20 | ||
|
|
a4a7a75f29 | ||
|
|
02d6006b2f | ||
|
|
e8e5f11c66 | ||
|
|
e53a6fa4c0 | ||
|
|
c478b0a0c8 | ||
|
|
5f207e6978 | ||
|
|
a2b74d0afd | ||
|
|
b867b11de3 | ||
|
|
806765d1d3 | ||
|
|
62d2b97e17 | ||
|
|
c04e339034 | ||
|
|
927b495646 | ||
|
|
57b5392590 | ||
|
|
463030108f | ||
|
|
46dd754264 | ||
|
|
12d9641b66 | ||
|
|
6cb1203d26 | ||
|
|
23d0ec333e | ||
|
|
da579fd308 | ||
|
|
14152bc999 | ||
|
|
6c32e5f2e2 | ||
|
|
62f74f2b60 | ||
|
|
6ac7f6db7f | ||
|
|
388a836bbc | ||
|
|
f0187e8b0f | ||
|
|
c698b82c30 | ||
|
|
afb3e3636e | ||
|
|
774548f268 | ||
|
|
ee38901855 | ||
|
|
a07ecdb3e3 | ||
|
|
143c286f3b | ||
|
|
5f2f13c49e | ||
|
|
2c19a031c7 | ||
|
|
a10e67538a | ||
|
|
4387075930 | ||
|
|
6ec1eb5c90 | ||
|
|
6ac1cbe913 | ||
|
|
4923326bdd | ||
|
|
0f8ca18e0d | ||
|
|
7666e16072 | ||
|
|
a42f6e5d18 | ||
|
|
67b22ff796 | ||
|
|
28c14f4d8c | ||
|
|
7133069ee9 | ||
|
|
b752425223 | ||
|
|
c5367bb338 | ||
|
|
d1342241bd | ||
|
|
05be07aab4 | ||
|
|
7f4f16e96a | ||
|
|
f11664642f | ||
|
|
28b074b6ea | ||
|
|
f43161c939 | ||
|
|
d52b7111ea | ||
|
|
9331d1154e | ||
|
|
364a580090 | ||
|
|
f33fa5005a | ||
|
|
8029d01b8b | ||
|
|
69586a6134 | ||
|
|
7c9c50c6a9 | ||
|
|
97139a27d7 | ||
|
|
3b67033d65 | ||
|
|
ec08632a29 | ||
|
|
eea64e0178 | ||
|
|
78096fab30 | ||
|
|
86fcd13dd9 | ||
|
|
4badecdbbc | ||
|
|
8d1a0d6a13 | ||
|
|
b102b2979b | ||
|
|
393235fbfe | ||
|
|
183a109119 | ||
|
|
bcff6e0173 | ||
|
|
3bd2c3a573 | ||
|
|
afba91ad61 | ||
|
|
a34c0f5556 | ||
|
|
3fd41a3d2e | ||
|
|
1c5ba25437 | ||
|
|
f7ff6b5488 | ||
|
|
53ac53167b | ||
|
|
c4eccd0d93 | ||
|
|
7744285dc3 | ||
|
|
238c98c0bd | ||
|
|
f9a9ef5752 | ||
|
|
6e5e357a36 | ||
|
|
0c4004ed14 | ||
|
|
008cd13c4f | ||
|
|
7f3ba8324a | ||
|
|
e9002f2111 | ||
|
|
8f161909bb | ||
|
|
1eea49a010 | ||
|
|
e62679cc26 | ||
|
|
f8f9325cbc | ||
|
|
fa1dd3fbfd | ||
|
|
0288313524 | ||
|
|
df18d66319 | ||
|
|
e8eb86f998 | ||
|
|
534ff245f2 | ||
|
|
172654d409 | ||
|
|
4dea7cfb4b | ||
|
|
f7955858bf | ||
|
|
fb5a5ddadd | ||
|
|
2bacd79c43 | ||
|
|
6ca539497d | ||
|
|
78f3524fcb | ||
|
|
937b2de41b | ||
|
|
a07c79f7be | ||
|
|
9562c81590 | ||
|
|
0a37852c5f | ||
|
|
460b78857c | ||
|
|
ac0e0a9f9e | ||
|
|
740f16fe62 | ||
|
|
faa0995c9c | ||
|
|
dfff71a525 | ||
|
|
380d8cb3ea | ||
|
|
3f5aab2083 | ||
|
|
2af5ef9016 | ||
|
|
f82dbfd300 | ||
|
|
9cbf1c545d | ||
|
|
9ac598b9c3 | ||
|
|
07dd0c2c0b | ||
|
|
66b1cdd63c | ||
|
|
78980aab9e | ||
|
|
0ac813be79 | ||
|
|
b09513bb2e | ||
|
|
c3e906f1ff | ||
|
|
666c1fec75 | ||
|
|
5d86ed46a3 | ||
|
|
2ee1c3ac32 | ||
|
|
ef530650c4 | ||
|
|
fd1c7773ee | ||
|
|
520ff8465b | ||
|
|
170c66b000 | ||
|
|
c94206f7ba | ||
|
|
f9158b39d8 | ||
|
|
daba88f947 | ||
|
|
a7e4852621 | ||
|
|
8a8d029357 | ||
|
|
b9621b620a | ||
|
|
cc0d656b86 | ||
|
|
18080df77a | ||
|
|
059314e8f3 | ||
|
|
500e4e41fe | ||
|
|
8b21fb72b2 | ||
|
|
f8464ac733 | ||
|
|
ac05ad1ef5 | ||
|
|
ed5f501a19 | ||
|
|
515b9f2838 | ||
|
|
d57ddff924 | ||
|
|
0a2da2a2ce | ||
|
|
72f677bb0d | ||
|
|
e176af1702 | ||
|
|
6e748eafb9 | ||
|
|
e11f84193a | ||
|
|
ec4fbdff32 | ||
|
|
d3ced01b43 | ||
|
|
64468ae69e | ||
|
|
79d75e832f | ||
|
|
ae41506764 | ||
|
|
f0bb80b9b8 | ||
|
|
1955d63cad | ||
|
|
4b2fdb3d30 | ||
|
|
d586fe2fb3 | ||
|
|
924074175e | ||
|
|
a64cbea6e8 | ||
|
|
9ef571b4fa | ||
|
|
67666a1788 | ||
|
|
e1daf1d360 | ||
|
|
94f3b715e5 | ||
|
|
31892a69df | ||
|
|
a43bc93492 | ||
|
|
8dd9149624 | ||
|
|
e422f7311a | ||
|
|
bb093c7614 | ||
|
|
5186936c3a | ||
|
|
4269f0483f | ||
|
|
09f49bb5d6 | ||
|
|
a054f2b968 | ||
|
|
149cf74fe6 | ||
|
|
123b3fd4b1 | ||
|
|
2e18db2352 | ||
|
|
d7c2856041 | ||
|
|
07a87bdff3 | ||
|
|
fca3c51351 | ||
|
|
70db2befb5 | ||
|
|
057fcb0693 | ||
|
|
051dc77712 | ||
|
|
784191f127 | ||
|
|
3454279ac7 | ||
|
|
e335cf5e96 | ||
|
|
44277b38cd | ||
|
|
31bd3fa6c4 | ||
|
|
3104f915e5 | ||
|
|
860a017060 | ||
|
|
23f00ec864 | ||
|
|
69fd8aaa36 | ||
|
|
7ea77afb38 | ||
|
|
da577ef923 | ||
|
|
26cae83139 | ||
|
|
a8c4f6bffe | ||
|
|
eff66ef08f | ||
|
|
381da45196 | ||
|
|
43c347d20e | ||
|
|
fadee3242f | ||
|
|
27fda41398 | ||
|
|
f6f8dbecc0 | ||
|
|
902991daa4 | ||
|
|
245ab6d815 | ||
|
|
96700a49e3 | ||
|
|
b75ba73264 | ||
|
|
7d6f93d1cb | ||
|
|
9aaf36141e | ||
|
|
68c6dd13b8 | ||
|
|
8ac5176c4c | ||
|
|
fd49ba36eb | ||
|
|
047aac8426 | ||
|
|
103e7415f3 | ||
|
|
b64911d20e | ||
|
|
2f970ce585 | ||
|
|
47801964c4 | ||
|
|
da8eb4ad1b | ||
|
|
320a2b8a7f | ||
|
|
eab271e1e1 | ||
|
|
d161962db1 | ||
|
|
36a3b408cf | ||
|
|
10af04becc | ||
|
|
4db259900e | ||
|
|
fe4ba8130d | ||
|
|
4c4f92bad2 | ||
|
|
6f726d6370 | ||
|
|
c4f50fccfb | ||
|
|
7e2daed0e8 | ||
|
|
e4d3f79492 | ||
|
|
d128a958cf | ||
|
|
0024bf56be | ||
|
|
1d03fdee64 | ||
|
|
152fb9cde9 | ||
|
|
e6c5710657 | ||
|
|
df0b3f7eb5 | ||
|
|
f420bf3266 | ||
|
|
7a262159dc | ||
|
|
3dec2821f4 | ||
|
|
652a9c5825 | ||
|
|
79c30fed23 | ||
|
|
5ab8d800d8 | ||
|
|
0beb7108e4 | ||
|
|
356d59a38d | ||
|
|
87853d0ca3 | ||
|
|
c9056630b7 | ||
|
|
a4120efabe | ||
|
|
0bd017f722 | ||
|
|
5a738fba8a | ||
|
|
856fd8b00f | ||
|
|
d60d90afe3 | ||
|
|
0132c00f41 | ||
|
|
aebc637f2b | ||
|
|
d4c4643ddc | ||
|
|
aea66427f1 | ||
|
|
0376c804f9 | ||
|
|
4a99069a4e | ||
|
|
e3bbcc5c84 | ||
|
|
6fc40077be | ||
|
|
040d1a9d0b | ||
|
|
8a121ada9d | ||
|
|
373c45c7d4 | ||
|
|
3e7992d0ac | ||
|
|
4a4455cd16 | ||
|
|
444e8d2637 | ||
|
|
bcd6f7de32 | ||
|
|
5346ca68f9 | ||
|
|
ab83b1c7aa | ||
|
|
bc0eec51b4 | ||
|
|
187100f2bf | ||
|
|
2e4e23f63f | ||
|
|
6f1f990f69 | ||
|
|
75d2109254 | ||
|
|
cada9ed520 | ||
|
|
6f3fe261d0 | ||
|
|
c78c0a2798 | ||
|
|
6249c25411 | ||
|
|
36fc098c5d | ||
|
|
070e84125a | ||
|
|
aa50669237 | ||
|
|
32ab7e79ca | ||
|
|
8971539550 | ||
|
|
df52dfd31f | ||
|
|
61756d45a2 | ||
|
|
fe7a5eb5d3 | ||
|
|
e744d36fa0 | ||
|
|
2108c85f7e | ||
|
|
e2c405fe02 | ||
|
|
8668b9a614 | ||
|
|
87ae9d780e | ||
|
|
d0c071e759 | ||
|
|
1a6324e825 | ||
|
|
bee3ba73d8 | ||
|
|
8dde9c2984 | ||
|
|
094d4128dc | ||
|
|
da25f77326 | ||
|
|
c5073f7056 | ||
|
|
c461d2e6b3 | ||
|
|
6adca06764 | ||
|
|
746f645e6c | ||
|
|
e6ef84bb4b | ||
|
|
17975acb45 | ||
|
|
4b81ff61eb | ||
|
|
bf868ff636 | ||
|
|
c777a0f926 | ||
|
|
7a7f499f63 | ||
|
|
b22b46b153 | ||
|
|
bbd8ea51c0 | ||
|
|
e1969d92ab | ||
|
|
e8e8b6902c | ||
|
|
7041a9fa45 | ||
|
|
bfbca5bc96 | ||
|
|
be183bf07f | ||
|
|
f7aa451af4 | ||
|
|
53ccd3d4b8 | ||
|
|
aaa6033c2a | ||
|
|
345c8ed962 | ||
|
|
9e0c7a3bdc | ||
|
|
616ed04c79 | ||
|
|
441fb06129 | ||
|
|
4b92ba5cbe | ||
|
|
13932641e5 | ||
|
|
85752ccf2c | ||
|
|
6d9b753735 | ||
|
|
6b7e3a6429 | ||
|
|
6ef043c40a | ||
|
|
9704abd3e4 | ||
|
|
723acced71 | ||
|
|
ca43ad0a91 | ||
|
|
17e2dbf85b | ||
|
|
7e40c902e6 | ||
|
|
074d0b95d1 | ||
|
|
36c8a8c675 | ||
|
|
00a70c2ea2 | ||
|
|
2bf20631e1 | ||
|
|
74b9579531 | ||
|
|
5a152d1bae | ||
|
|
551152ade9 | ||
|
|
42c5b356f5 | ||
|
|
33bd68c44c | ||
|
|
46b715fcc3 | ||
|
|
b004168401 | ||
|
|
6cebf19468 | ||
|
|
fb73324d25 | ||
|
|
94624c7e52 | ||
|
|
c4033a5970 | ||
|
|
e66e56b593 | ||
|
|
b408423b03 | ||
|
|
c37a2d7842 | ||
|
|
da339bb3a9 | ||
|
|
f30be82926 | ||
|
|
f04aa843ff | ||
|
|
5c42c27cd4 | ||
|
|
fc744f5719 | ||
|
|
855c963fb3 | ||
|
|
dd932b0a78 | ||
|
|
e4e75a4d64 | ||
|
|
ef0464dba6 | ||
|
|
bc2b49c8e8 | ||
|
|
409ce34a0b | ||
|
|
89158b0509 | ||
|
|
86b90b8b16 | ||
|
|
fe4c88c1c5 | ||
|
|
f0f08728ab | ||
|
|
5259c803e8 | ||
|
|
c6e5e533fa | ||
|
|
21e4cc19c8 | ||
|
|
045001fd6c | ||
|
|
eadaf3407a | ||
|
|
7434d3113c | ||
|
|
ab9fade14d | ||
|
|
5be63b02e8 | ||
|
|
7694c38021 | ||
|
|
d13f7a45b9 | ||
|
|
44e8f01671 | ||
|
|
09a8104256 | ||
|
|
09d8ac2656 | ||
|
|
c5877df60c | ||
|
|
0f2fff31ee | ||
|
|
ebcdd294aa | ||
|
|
d663e10584 | ||
|
|
048299e1d3 | ||
|
|
96aaa9fa3f | ||
|
|
015f17192c | ||
|
|
f0ac801ecd | ||
|
|
f3b207c024 | ||
|
|
0379e200b6 | ||
|
|
abe6168bc3 | ||
|
|
a6aa2c31c6 | ||
|
|
f35ad319cf | ||
|
|
527ad44463 | ||
|
|
b245307f55 | ||
|
|
9285b403d9 | ||
|
|
58b72a4c80 | ||
|
|
73f706723e | ||
|
|
4d22f7171f | ||
|
|
b60e22b4e5 | ||
|
|
7310b73289 | ||
|
|
4fa61c225a | ||
|
|
63b41856e5 | ||
|
|
ed1e668240 | ||
|
|
e3a7e70180 | ||
|
|
9f0b20c8d2 | ||
|
|
68aff372ce | ||
|
|
38cfa72318 | ||
|
|
31047e1e10 | ||
|
|
bbb90296bb | ||
|
|
00c6aa2f65 | ||
|
|
720da09631 | ||
|
|
47f7c09b97 | ||
|
|
cb5704da10 | ||
|
|
c64356b231 | ||
|
|
2acd2f5224 | ||
|
|
ba251f8e3d | ||
|
|
48019f9044 | ||
|
|
d9a1f2448c | ||
|
|
553a947c2d | ||
|
|
736aedfa89 | ||
|
|
6184acc727 | ||
|
|
f0d96b03fa | ||
|
|
14bf840eef | ||
|
|
7ea08093c7 | ||
|
|
8eb8d07151 | ||
|
|
cdd95b434e | ||
|
|
82cbcea886 | ||
|
|
ea54a05fc3 | ||
|
|
eba39dcd67 | ||
|
|
d71ea1404d | ||
|
|
0f0d5b2a5f | ||
|
|
10a75ef848 | ||
|
|
4bd9bf8917 | ||
|
|
323da1299e | ||
|
|
75d08898b4 | ||
|
|
5e47796a02 | ||
|
|
0ade5aba0a | ||
|
|
f7b1ad8cb0 | ||
|
|
3bd147e687 | ||
|
|
66c99e257f | ||
|
|
8407a5921b | ||
|
|
5f36987827 | ||
|
|
ede1622368 | ||
|
|
a28dfb790e | ||
|
|
3711cbbd61 | ||
|
|
c9ef6281ff | ||
|
|
604ea6fd57 | ||
|
|
41dfcaa705 | ||
|
|
daa41d4a51 | ||
|
|
ded4450a70 | ||
|
|
cd0be56bbe | ||
|
|
0bf7b64b46 | ||
|
|
215d2e7055 | ||
|
|
2b5b0cf1bc | ||
|
|
67231da4a9 | ||
|
|
8c25b38470 | ||
|
|
08bbe0cd30 | ||
|
|
9f9f63fe2f | ||
|
|
997bd63cc3 | ||
|
|
6a566d9dca | ||
|
|
d2e743a800 | ||
|
|
2fedb175b4 | ||
|
|
6c5e25dbfe | ||
|
|
94fd3f0bfd | ||
|
|
ca169b05fb | ||
|
|
10ea1fee6e | ||
|
|
d7b8704165 | ||
|
|
0f774b840c | ||
|
|
81521a314b | ||
|
|
37ee7f8908 | ||
|
|
309648f68b | ||
|
|
5cfa65d04e | ||
|
|
e73c8194a0 | ||
|
|
00a3f6ae7f | ||
|
|
b7edaa68c8 | ||
|
|
2877ba54de | ||
|
|
f74a19a71a | ||
|
|
3da5238ee5 | ||
|
|
567dd36592 | ||
|
|
b48062a026 | ||
|
|
b039cb713f | ||
|
|
8e987ffa18 | ||
|
|
52502342e0 | ||
|
|
cb9e3c22f9 | ||
|
|
0c465775ad | ||
|
|
a5417f4963 | ||
|
|
b48076f6e4 | ||
|
|
c472eae332 | ||
|
|
918fc654f4 | ||
|
|
9097cbe10d | ||
|
|
e260873338 | ||
|
|
a7822742c0 | ||
|
|
f1316ef4bb | ||
|
|
4106931175 | ||
|
|
fb5ba40f0c | ||
|
|
854e51f0ad | ||
|
|
676b43f17d | ||
|
|
48b68e6a92 | ||
|
|
61f33721e1 | ||
|
|
5c3c46598f | ||
|
|
4358036f9e | ||
|
|
54d75d92ef | ||
|
|
b1ae57c932 | ||
|
|
2636baa33f | ||
|
|
926c739517 | ||
|
|
79fa25c4e0 | ||
|
|
02050675a8 | ||
|
|
0d5857a1bc | ||
|
|
e3a51be1f9 | ||
|
|
57cb098a6e | ||
|
|
5f285eef56 | ||
|
|
7d5cf6f318 | ||
|
|
99d305c7a1 | ||
|
|
b9cc3b6a7d | ||
|
|
e1f8c69d3d | ||
|
|
67b6fbd15b | ||
|
|
50f407eb9e | ||
|
|
b127699c0a | ||
|
|
4d74fa6759 | ||
|
|
2b9d6cb7c2 | ||
|
|
e0b67bba58 | ||
|
|
3cdf17df75 | ||
|
|
43c086494b | ||
|
|
ae26e90b3a | ||
|
|
d35a7d8725 | ||
|
|
043e7ddde4 | ||
|
|
3930960159 | ||
|
|
be12175c8a | ||
|
|
02a1847539 | ||
|
|
0235535658 | ||
|
|
3af75ca64c | ||
|
|
efbe28502d | ||
|
|
47847ee471 | ||
|
|
688ffe32a9 | ||
|
|
c6bbe01f3e | ||
|
|
002af6128c | ||
|
|
5b5c92a9d7 | ||
|
|
7d31d73fc5 | ||
|
|
c5c2c83c65 |
@@ -1,2 +1,56 @@
|
||||
d3850b52334a91d005b0fe45e1e38ba0997a1fb8 no_server mode
|
||||
2d8a617299153ed2efa6ecee7920e9d36c29e0f5 0.9.5beta1
|
||||
04722a2d0121080d14a64df097c278860db5ce8a 0.9.5rc1
|
||||
820cc64ab296dc4589ef72a33a6b804c22a0430c 0.9.5rc2
|
||||
b0db39cfad5ac6d4f00bbb3f9c57cf73206e2afb 0.9.5
|
||||
9f8b98ad1dfa51b86b13fa624c65f73523075fc4 0.9.5.1
|
||||
a83e7a482e65befcfbb0e24af8cd5d15190acdd7 0.9.6-rc1
|
||||
b8f67c6cd0d62f864db9b2b265b4e260ad7d873c 0.9.6-rc2
|
||||
35918dd4b3771158b2b57410613ef029e08bbd60 0.9.6
|
||||
5f25d1f97f9dde3e391a668c1c610a52a5db8244 0.9.6.1
|
||||
ef31fc61ac48018c464f28ebfdf865b96bf83f18 0.9.6.2
|
||||
9e100c1f085034396cec586f0c76ad3f9800d1a5 0.9.7-beta1
|
||||
ff4111eb8f55b958ec91c70163e10f3372a9b94d 0.9.7-rc1
|
||||
eb8aff2926230bb114fb90f67203440a2c534bf1 0.9.7-rc2
|
||||
311eef929ec8fd0a5dc8c16531afb7bb42d36d01 0.9.7-rc3
|
||||
4b50c04e414f1d9ab8b0b5910aba83d09ac21abb 0.9.7
|
||||
d9b9b540f7dce8cb05d2e61ca8b4d75f2ea25f62 0.9.7.1
|
||||
d9b9b540f7dce8cb05d2e61ca8b4d75f2ea25f62 0.9.7.1
|
||||
0000000000000000000000000000000000000000 0.9.7.1
|
||||
0000000000000000000000000000000000000000 0.9.7.1
|
||||
486e7760bcbc2191ddb9b4aee6c98dbd5fc4c754 0.9.7.1
|
||||
a5f13497b39269621f8f1e56e14d2cc141452e79 0.9.7.2
|
||||
d1e57707f6317f134fea7d12f6588d8690f74f3f 0.9.8-rc1
|
||||
e91bc724325e14c13b8f548c0b6a315c48a1c32a 0.9.8-rc2
|
||||
4fb424d52f226a0a087fea89709f5eb540e03f25 0.9.8-rc3
|
||||
0f1f3924ee5309a9990d9af1ffc68846e3dfb31b 0.9.8-rc4
|
||||
42efe1f329005618c8b44f901979ebcecd5216fb 0.9.8
|
||||
fd8477b6348faf16588106055ca59df1c488f76a 0.9.8.1
|
||||
7169ef1d68d3dab4737bcc3f9e082839e5a06cc1 0.9.8.2
|
||||
f4d3c4dcd7a63e21fcc9d8d567374c69935178bd 0.9.8.3
|
||||
6945ee03c7ea95eb19217ef1e1fb17d9ae26adbc 0.9.9-beta1
|
||||
fb168b0b86169219aa9b8e40f0caa6297cf34dbc 0.9.9-rc1
|
||||
6aa667612019fcff8e68af9469f73aff6fa378a8 0.9.9-rc2
|
||||
376ffd8f190623e5e2521fe9fa64bf03c31e71be 0.9.9
|
||||
7048ae11cfc8453c6bb599af3c0dfacd7ebae43c 1.0-rc1
|
||||
7a4e021ea7ba2953e474326612c3bb82d6817f0e 1.0-rc2
|
||||
4e4e781ef89ac33e71a7e92741d54549240ed156 1.0-rc3
|
||||
24f7e260ea345c2cd73e2fd8191dddbd1b039062 1.0-rc4
|
||||
043ba93dd69cf6924e98db3cb9a8759cce997367 1.0-rc5
|
||||
a2b8f25fd17ed7424d1470a287d0b3144d2a12c8 1.0-rc6
|
||||
a3ca2e8e27c5c12c44ba0cacb4de4cb51377f184 1.0-rc7
|
||||
365e2514cc19f0366365318f12a1d63113b02924 1.0-rc8
|
||||
5da6fe43a8c29056bc9442c684615e11a3699795 1.0-rc9
|
||||
af490b8c30f83bc5fb6f3837a760981474647755 1.0-rc10
|
||||
3c70927335856883283fe4db448e092cecc0ccdb 1.0
|
||||
8fe7bb792399cb6e6a24e20551f4149409660363 1.0.1
|
||||
1d1702789710ec1c20613d2490b14f70756e67ec 1.1-rc1
|
||||
901f0cb5de36ea907b26d64ac9ce54605ec531d2 1.1-rc2
|
||||
ede5c664978bb40e476e8d4a5789562928f28507 1.1-rc3
|
||||
ef99144291f06822d026e981d5d856cbec14d867 1.1-rc4
|
||||
e1568fd16b7b586cc72deb4dfccbbe64ae0b84df 1.1
|
||||
24c8fe5a26e557db41cf1cee45b8964d5885e484 1.2-rc1
|
||||
29de0fb320bc0a1ce84972f9f249360e315d3c10 1.2-rc2
|
||||
c3cdecbf2bac591336baddd14f9ac22e18d6e200 1.2
|
||||
14524da00a8b382dffb1d16a0e70cdf4a946f369 1.3-rc2
|
||||
883b946db9038372cb1d76cb1d328a3093140e7b 1.3-rc3
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
- this is a incomplete list of all the contributors of the project -
|
||||
|
||||
Roberto De Ioris, Unbit, <roberto@unbit.it>
|
||||
Riccardo Magliocchetti, Unbit, <riccardo@unbit.it>
|
||||
Yann Malet, Lincoln Loop
|
||||
Simon Litchfield
|
||||
Masahiro Honma, <hiratara@cpan.org>
|
||||
Łukasz Wróblewski <admin@nri.pl>
|
||||
Giacomo Bagnoli, Asidev
|
||||
Guido Notari, Link I.T. S.p.a.
|
||||
Marco Beri, Link I.T. S.p.a.
|
||||
Leonid Borisenko
|
||||
Cal Leeming, Simplicity Media Ltd
|
||||
Luigi Scarso
|
||||
Corey Farwell
|
||||
Charles Duffy
|
||||
Lukas Lalinsky
|
||||
Steven Fernandez
|
||||
Łukasz Mierzwa
|
||||
Roy Marples
|
||||
@@ -1,3 +1,580 @@
|
||||
*** 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] *
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
all:
|
||||
python uwsgiconfig.py --build
|
||||
|
||||
clean:
|
||||
python uwsgiconfig.py --clean
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
all:
|
||||
python2.4 uwsgiconfig.py --build
|
||||
@@ -1,2 +0,0 @@
|
||||
all:
|
||||
python2.5 uwsgiconfig.py --build
|
||||
@@ -1,2 +0,0 @@
|
||||
all:
|
||||
python2.6 uwsgiconfig.py --build
|
||||
@@ -1,2 +0,0 @@
|
||||
all:
|
||||
python3.0 uwsgiconfig.py --build
|
||||
@@ -1,2 +0,0 @@
|
||||
all:
|
||||
python3.1 uwsgiconfig.py --build
|
||||
@@ -0,0 +1,950 @@
|
||||
/*
|
||||
|
||||
*** uWSGI/mod_Ruwsgi ***
|
||||
|
||||
Copyright 2009-2010 Roger Florkowski <rflorkowski@mypublisher.com>
|
||||
Copyright 2009-2010 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.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#define MOD_UWSGI_VERSION "1.0"
|
||||
|
||||
#include "ap_config.h"
|
||||
#include "apr_version.h"
|
||||
#include "apr_lib.h"
|
||||
#include "apr_strings.h"
|
||||
#include "httpd.h"
|
||||
#include "http_core.h"
|
||||
#include "http_request.h"
|
||||
#include "http_config.h"
|
||||
#include "http_log.h"
|
||||
#include "http_protocol.h"
|
||||
#include "util_script.h"
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/uio.h>
|
||||
#include <time.h>
|
||||
#include <poll.h>
|
||||
|
||||
#define DEFAULT_TIMEOUT 60 /* default socket timeout */
|
||||
#define DEFAULT_CGIMODE 0 /* not enabled */
|
||||
|
||||
#define UNSET 0
|
||||
#define ENABLED 1
|
||||
#define DISABLED 2
|
||||
|
||||
#if APR_MAJOR_VERSION == 0
|
||||
#define apr_socket_send apr_send
|
||||
#define GET_PORT(port, addr) apr_sockaddr_port_get(&(port), addr)
|
||||
#define CREATE_SOCKET(sock, family, pool) \
|
||||
apr_socket_create(sock, family, SOCK_STREAM, pool)
|
||||
#else
|
||||
#define GET_PORT(port, addr) ((port) = (addr)->port)
|
||||
#define CREATE_SOCKET(sock, family, pool) \
|
||||
apr_socket_create(sock, family, SOCK_STREAM, APR_PROTO_TCP, pool)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
char *path;
|
||||
char *addr;
|
||||
apr_port_t port;
|
||||
} mount_entry;
|
||||
|
||||
/*
|
||||
* Configuration record. Used per-directory configuration data.
|
||||
*/
|
||||
typedef struct {
|
||||
mount_entry mount;
|
||||
int enabled; /* mod_uwsgi is enabled from this directory */
|
||||
int timeout;
|
||||
int cgi_mode;
|
||||
uint8_t modifier1;
|
||||
uint8_t modifier2;
|
||||
} uwsgi_cfg;
|
||||
|
||||
/* Server level configuration */
|
||||
typedef struct {
|
||||
apr_array_header_t *mounts;
|
||||
int timeout;
|
||||
int cgi_mode;
|
||||
} uwsgi_server_cfg;
|
||||
|
||||
module AP_MODULE_DECLARE_DATA uwsgi_module;
|
||||
|
||||
/*
|
||||
* Locate our directory configuration record for the current request.
|
||||
*/
|
||||
static uwsgi_cfg *
|
||||
our_dconfig(request_rec *r)
|
||||
{
|
||||
return (uwsgi_cfg *) ap_get_module_config(r->per_dir_config, &uwsgi_module);
|
||||
}
|
||||
|
||||
static uwsgi_server_cfg *our_sconfig(server_rec *s)
|
||||
{
|
||||
return (uwsgi_server_cfg *) ap_get_module_config(s->module_config,
|
||||
&uwsgi_module);
|
||||
}
|
||||
|
||||
static int
|
||||
mount_entry_matches(const char *url, const char *prefix,
|
||||
const char **path_info)
|
||||
{
|
||||
int i;
|
||||
for (i=0; prefix[i] != '\0'; i++) {
|
||||
if (url[i] == '\0' || url[i] != prefix[i])
|
||||
return 0;
|
||||
}
|
||||
if (url[i] == '\0' || url[i] == '/') {
|
||||
*path_info = url + i;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_translate(request_rec *r)
|
||||
{
|
||||
uwsgi_cfg *cfg = our_dconfig(r);
|
||||
|
||||
if (cfg->enabled == DISABLED) {
|
||||
return DECLINED;
|
||||
}
|
||||
|
||||
if (cfg->mount.addr != UNSET) {
|
||||
ap_assert(cfg->mount.port != UNSET);
|
||||
r->handler = "uwsgi-handler";
|
||||
r->filename = r->uri;
|
||||
return OK;
|
||||
}
|
||||
else {
|
||||
int i;
|
||||
uwsgi_server_cfg *scfg = our_sconfig(r->server);
|
||||
mount_entry *entries = (mount_entry *) scfg->mounts->elts;
|
||||
for (i = 0; i < scfg->mounts->nelts; ++i) {
|
||||
const char *path_info;
|
||||
mount_entry *mount = &entries[i];
|
||||
if (mount_entry_matches(r->uri, mount->path, &path_info)) {
|
||||
r->handler = "uwsgi-handler";
|
||||
r->path_info = apr_pstrdup(r->pool, path_info);
|
||||
r->filename = r->uri;
|
||||
ap_set_module_config(r->request_config, &uwsgi_module, mount);
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
return DECLINED;
|
||||
}
|
||||
|
||||
static int uwsgi_map_location(request_rec *r)
|
||||
{
|
||||
if (r->handler && strcmp(r->handler, "uwsgi-handler") == 0) {
|
||||
return OK; /* We don't want directory walk. */
|
||||
}
|
||||
return DECLINED;
|
||||
}
|
||||
|
||||
|
||||
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
|
||||
static void log_err(const char *file, int line, int ami, request_rec *r,
|
||||
apr_status_t status, const char *msg)
|
||||
{
|
||||
ap_log_rerror(file, line, APLOG_MODULE_INDEX, APLOG_ERR, status, r, "uwsgi: %s", msg);
|
||||
#else
|
||||
static void log_err(const char *file, int line, request_rec *r,
|
||||
apr_status_t status, const char *msg)
|
||||
{
|
||||
|
||||
ap_log_rerror(file, line, APLOG_ERR, status, r, "uwsgi: %s", msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
|
||||
static void log_debug(const char *file, int line, int ami, request_rec *r, const
|
||||
char *msg)
|
||||
{
|
||||
/*
|
||||
ap_log_rerror(file, line, APLOG_DEBUG, APR_SUCCESS, r, msg);
|
||||
ap_log_rerror(file, line, APLOG_WARNING, APR_SUCCESS, r, "uwsgi: %s", msg);
|
||||
*/
|
||||
ap_log_rerror(file, line, APLOG_MODULE_INDEX, APLOG_DEBUG, APR_SUCCESS, r, "uwsgi: %s", msg);
|
||||
#else
|
||||
static void log_debug(const char *file, int line, request_rec *r, const
|
||||
char *msg) {
|
||||
ap_log_rerror(file, line, APLOG_DEBUG, APR_SUCCESS, r, "uwsgi: %s", msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* buffered socket implementation (buckets are overkill) */
|
||||
|
||||
#define BUFFER_SIZE 8000
|
||||
|
||||
struct sockbuff {
|
||||
apr_socket_t *sock;
|
||||
char buf[BUFFER_SIZE];
|
||||
int used;
|
||||
};
|
||||
|
||||
static void binit(struct sockbuff *s, apr_socket_t *sock)
|
||||
{
|
||||
s->sock = sock;
|
||||
s->used = 0;
|
||||
}
|
||||
|
||||
static apr_status_t sendall(apr_socket_t *sock, char *buf, apr_size_t len)
|
||||
{
|
||||
apr_status_t rv;
|
||||
apr_size_t n;
|
||||
while (len > 0) {
|
||||
n = len;
|
||||
if ((rv = apr_socket_send(sock, buf, &n))) return rv;
|
||||
buf += n;
|
||||
len -= n;
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
static apr_status_t bflush(struct sockbuff *s)
|
||||
{
|
||||
apr_status_t rv;
|
||||
ap_assert(s->used >= 0 && s->used <= BUFFER_SIZE);
|
||||
if (s->used) {
|
||||
if ((rv = sendall(s->sock, s->buf, s->used))) return rv;
|
||||
s->used = 0;
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
static apr_status_t bwrite(struct sockbuff *s, char *buf, apr_size_t len)
|
||||
{
|
||||
apr_status_t rv;
|
||||
if (len >= BUFFER_SIZE - s->used) {
|
||||
if ((rv = bflush(s))) return rv;
|
||||
while (len >= BUFFER_SIZE) {
|
||||
if ((rv = sendall(s->sock, buf, BUFFER_SIZE))) return rv;
|
||||
buf += BUFFER_SIZE;
|
||||
len -= BUFFER_SIZE;
|
||||
}
|
||||
}
|
||||
if (len > 0) {
|
||||
ap_assert(len < BUFFER_SIZE - s->used);
|
||||
memcpy(s->buf + s->used, buf, len);
|
||||
s->used += len;
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
static apr_status_t bputs(struct sockbuff *s, char *buf)
|
||||
{
|
||||
return bwrite(s, buf, strlen(buf));
|
||||
}
|
||||
|
||||
static apr_status_t bputc(struct sockbuff *s, char c)
|
||||
{
|
||||
char buf[1];
|
||||
buf[0] = c;
|
||||
return bwrite(s, buf, 1);
|
||||
}
|
||||
|
||||
static apr_status_t bputh(struct sockbuff *s, unsigned short h)
|
||||
{
|
||||
return bwrite(s, (char *)&h, 2);
|
||||
}
|
||||
|
||||
#define CONFIG_VALUE(value, fallback) ((value) != UNSET ? (value) : (fallback))
|
||||
|
||||
static apr_status_t
|
||||
open_socket(apr_socket_t **sock, request_rec *r)
|
||||
{
|
||||
int timeout;
|
||||
int retries = 4;
|
||||
int sleeptime = 1;
|
||||
apr_status_t rv;
|
||||
apr_sockaddr_t *sockaddr;
|
||||
uwsgi_server_cfg *scfg = our_sconfig(r->server);
|
||||
uwsgi_cfg *cfg = our_dconfig(r);
|
||||
mount_entry *m = (mount_entry *) ap_get_module_config(r->request_config,
|
||||
&uwsgi_module);
|
||||
if (!m) {
|
||||
m = &cfg->mount;
|
||||
}
|
||||
|
||||
timeout = CONFIG_VALUE(cfg->timeout, CONFIG_VALUE(scfg->timeout,
|
||||
DEFAULT_TIMEOUT));
|
||||
rv = apr_sockaddr_info_get(&sockaddr,
|
||||
CONFIG_VALUE(m->addr, "localhost"),
|
||||
APR_UNSPEC,
|
||||
CONFIG_VALUE(m->port, 5000),
|
||||
0,
|
||||
r->pool);
|
||||
if (rv) {
|
||||
log_err(APLOG_MARK, r, rv, "apr_sockaddr_info_get() error");
|
||||
return rv;
|
||||
}
|
||||
|
||||
restart:
|
||||
*sock = NULL;
|
||||
rv = CREATE_SOCKET(sock, sockaddr->family, r->pool);
|
||||
if (rv) {
|
||||
log_err(APLOG_MARK, r, rv, "apr_socket_create() error");
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = apr_socket_timeout_set(*sock, apr_time_from_sec(timeout));
|
||||
if (rv) {
|
||||
log_err(APLOG_MARK, r, rv, "apr_socket_timeout_set() error");
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = apr_socket_connect(*sock, sockaddr);
|
||||
if (rv) {
|
||||
apr_socket_close(*sock);
|
||||
if ((APR_STATUS_IS_ECONNREFUSED(rv) |
|
||||
APR_STATUS_IS_EINPROGRESS(rv)) && retries > 0) {
|
||||
/* server may be temporarily down, retry */
|
||||
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, rv, r,
|
||||
"uwsgi: connection failed, retrying");
|
||||
apr_sleep(apr_time_from_sec(sleeptime));
|
||||
--retries;
|
||||
sleeptime *= 2;
|
||||
goto restart;
|
||||
}
|
||||
log_err(APLOG_MARK, r, rv, "uwsgi: can't connect to server");
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef APR_TCP_NODELAY
|
||||
/* disable Nagle, we don't send small packets */
|
||||
apr_socket_opt_set(*sock, APR_TCP_NODELAY, 1);
|
||||
#endif
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
/* This code is a duplicate of what's in util_script.c. We can't use
|
||||
* r->unparsed_uri because it gets changed if there was a redirect. */
|
||||
static char *original_uri(request_rec *r)
|
||||
{
|
||||
char *first, *last;
|
||||
|
||||
if (r->the_request == NULL) {
|
||||
return (char *) apr_pcalloc(r->pool, 1);
|
||||
}
|
||||
|
||||
first = r->the_request; /* use the request-line */
|
||||
|
||||
while (*first && !apr_isspace(*first)) {
|
||||
++first; /* skip over the method */
|
||||
}
|
||||
while (apr_isspace(*first)) {
|
||||
++first; /* and the space(s) */
|
||||
}
|
||||
|
||||
last = first;
|
||||
while (*last && !apr_isspace(*last)) {
|
||||
++last; /* end at next whitespace */
|
||||
}
|
||||
|
||||
return apr_pstrmemdup(r->pool, first, last - first);
|
||||
}
|
||||
|
||||
static char *lookup_name(apr_table_t *t, const char *name)
|
||||
{
|
||||
const apr_array_header_t *hdrs_arr = apr_table_elts(t);
|
||||
apr_table_entry_t *hdrs = (apr_table_entry_t *) hdrs_arr->elts;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < hdrs_arr->nelts; ++i) {
|
||||
if (hdrs[i].key == NULL)
|
||||
continue;
|
||||
|
||||
if (strcasecmp(hdrs[i].key, name) == 0)
|
||||
return hdrs[i].val;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *lookup_header(request_rec *r, const char *name)
|
||||
{
|
||||
return lookup_name(r->headers_in, name);
|
||||
}
|
||||
|
||||
static void add_header(apr_table_t *t, const char *name, const char *value)
|
||||
{
|
||||
if (name != NULL && value != NULL)
|
||||
apr_table_addn(t, name, value);
|
||||
}
|
||||
|
||||
static int find_path_info(const char *uri, const char *path_info)
|
||||
{
|
||||
int n;
|
||||
n = strlen(uri) - strlen(path_info);
|
||||
ap_assert(n >= 0);
|
||||
return n;
|
||||
}
|
||||
|
||||
static char *http2env(apr_pool_t *p, const char *name)
|
||||
{
|
||||
char *env_name = apr_pstrcat(p, "HTTP_", name, NULL);
|
||||
char *cp;
|
||||
|
||||
for (cp = env_name + 5; *cp != 0; cp++) {
|
||||
if (*cp == '-') {
|
||||
*cp = '_';
|
||||
}
|
||||
else {
|
||||
*cp = apr_toupper(*cp);
|
||||
}
|
||||
}
|
||||
|
||||
return env_name;
|
||||
}
|
||||
|
||||
static apr_status_t
|
||||
send_headers(request_rec *r, struct sockbuff *s)
|
||||
{
|
||||
int i;
|
||||
const apr_array_header_t *hdrs_arr, *env_arr;
|
||||
apr_table_entry_t *hdrs, *env;
|
||||
char *buf;
|
||||
unsigned short int n = 0;
|
||||
apr_table_t *t;
|
||||
apr_status_t rv = 0;
|
||||
apr_port_t port = 0;
|
||||
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
|
||||
GET_PORT(port, r->useragent_addr);
|
||||
#else
|
||||
GET_PORT(port, r->connection->remote_addr);
|
||||
#endif
|
||||
uwsgi_cfg *cfg = our_dconfig(r);
|
||||
|
||||
log_debug(APLOG_MARK,r, "sending headers");
|
||||
t = apr_table_make(r->pool, 40);
|
||||
if (!t)
|
||||
return APR_ENOMEM;
|
||||
|
||||
/* headers to send */
|
||||
|
||||
/* CONTENT_LENGTH must come first and always be present */
|
||||
buf = lookup_header(r, "Content-Length");
|
||||
if (buf == NULL)
|
||||
buf = "0";
|
||||
add_header(t, "CONTENT_LENGTH", buf);
|
||||
|
||||
add_header(t, "REQUEST_METHOD", (char *) r->method);
|
||||
add_header(t, "QUERY_STRING", r->args ? r->args : "");
|
||||
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
|
||||
add_header(t, "SERVER_SOFTWARE", ap_get_server_description());
|
||||
#else
|
||||
add_header(t, "SERVER_SOFTWARE", ap_get_server_version());
|
||||
#endif
|
||||
add_header(t, "SERVER_ADMIN", r->server->server_admin);
|
||||
add_header(t, "SERVER_NAME", (char *) ap_get_server_name(r));
|
||||
add_header(t, "SERVER_PORT", apr_psprintf(r->pool, "%u",ap_get_server_port(r)));
|
||||
add_header(t, "SERVER_ADDR", r->connection->local_ip);
|
||||
add_header(t, "SERVER_PROTOCOL", r->protocol);
|
||||
|
||||
add_header(t, "REQUEST_URI", original_uri(r));
|
||||
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
|
||||
add_header(t, "REMOTE_ADDR", r->useragent_ip);
|
||||
#else
|
||||
add_header(t, "REMOTE_ADDR", r->connection->remote_ip);
|
||||
#endif
|
||||
add_header(t, "REMOTE_PORT", apr_psprintf(r->pool, "%d", port));
|
||||
add_header(t, "REMOTE_USER", r->user);
|
||||
add_header(t, "DOCUMENT_ROOT", (char *) ap_document_root(r));
|
||||
|
||||
if (r->path_info) {
|
||||
int path_info_start = find_path_info(r->uri, r->path_info);
|
||||
add_header(t, "SCRIPT_NAME", apr_pstrndup(r->pool, r->uri,
|
||||
path_info_start));
|
||||
add_header(t, "PATH_INFO", r->path_info);
|
||||
}
|
||||
else {
|
||||
/* skip PATH_INFO, don't know it */
|
||||
add_header(t, "SCRIPT_NAME", r->uri);
|
||||
}
|
||||
|
||||
add_header(t, "CONTENT_TYPE", lookup_header(r, "Content-type"));
|
||||
|
||||
/* HTTP headers */
|
||||
hdrs_arr = apr_table_elts(r->headers_in);
|
||||
hdrs = (apr_table_entry_t *) hdrs_arr->elts;
|
||||
for (i = 0; i < hdrs_arr->nelts; ++i) {
|
||||
if (hdrs[i].key) {
|
||||
add_header(t, http2env(r->pool, hdrs[i].key), hdrs[i].val);
|
||||
}
|
||||
}
|
||||
|
||||
/* environment variables */
|
||||
env_arr = apr_table_elts(r->subprocess_env);
|
||||
env = (apr_table_entry_t*) env_arr->elts;
|
||||
for (i = 0; i < env_arr->nelts; ++i) {
|
||||
add_header(t, env[i].key, env[i].val);
|
||||
}
|
||||
|
||||
hdrs_arr = apr_table_elts(t);
|
||||
hdrs = (apr_table_entry_t*) hdrs_arr->elts;
|
||||
|
||||
/* calculate length of header data */
|
||||
for (i = 0; i < hdrs_arr->nelts; ++i) {
|
||||
n += strlen(hdrs[i].key);
|
||||
n += strlen(hdrs[i].val);
|
||||
n += 4; /* XXX */
|
||||
}
|
||||
log_debug(APLOG_MARK,r, apr_psprintf(r->pool, "pktheader size is %u", n));
|
||||
log_debug(APLOG_MARK,r, apr_psprintf(r->pool, "num headers %u", hdrs_arr->nelts));
|
||||
|
||||
/* write pkt header */
|
||||
rv = bputc(s, cfg->modifier1); /* marker */
|
||||
if (rv) return rv;
|
||||
rv = bputh(s, n); /* length of header data */
|
||||
if (rv) return rv;
|
||||
rv = bputc(s, cfg->modifier2); /* marker */
|
||||
if (rv) return rv;
|
||||
|
||||
/* write out headers */
|
||||
for (i = 0; i < hdrs_arr->nelts; ++i) {
|
||||
rv = bputh(s, strlen(hdrs[i].key)); /* length */
|
||||
if (rv) return rv;
|
||||
rv = bputs(s, hdrs[i].key); /* key */
|
||||
if (rv) return rv;
|
||||
rv = bputh(s, strlen(hdrs[i].val)); /* length */
|
||||
if (rv) return rv;
|
||||
rv = bputs(s, hdrs[i].val); /* data */
|
||||
if (rv) return rv;
|
||||
}
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
static apr_status_t send_request_body(request_rec *r, struct sockbuff *s)
|
||||
{
|
||||
if (ap_should_client_block(r)) {
|
||||
char buf[BUFFER_SIZE];
|
||||
apr_status_t rv;
|
||||
apr_off_t len;
|
||||
|
||||
while ((len = ap_get_client_block(r, buf, sizeof buf)) > 0) {
|
||||
if ((rv = bwrite(s, buf, len))) return rv;
|
||||
}
|
||||
if (len == -1)
|
||||
return HTTP_INTERNAL_SERVER_ERROR; /* what to return? */
|
||||
}
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
static int uwsgi_handler(request_rec *r)
|
||||
{
|
||||
apr_status_t rv = 0;
|
||||
int cgi_mode, http_status = 0;
|
||||
struct sockbuff s;
|
||||
apr_socket_t *sock;
|
||||
apr_bucket_brigade *bb = NULL;
|
||||
apr_bucket *b = NULL;
|
||||
const char *location;
|
||||
uwsgi_cfg *cfg = our_dconfig(r);
|
||||
uwsgi_server_cfg *scfg = our_sconfig(r->server);
|
||||
|
||||
if (strcmp(r->handler, "uwsgi-handler"))
|
||||
return DECLINED;
|
||||
|
||||
http_status = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR);
|
||||
if (http_status != OK)
|
||||
return http_status;
|
||||
|
||||
log_debug(APLOG_MARK, r, "connecting to server");
|
||||
|
||||
rv = open_socket(&sock, r);
|
||||
if (rv) {
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
binit(&s, sock);
|
||||
|
||||
rv = send_headers(r, &s);
|
||||
if (rv) {
|
||||
log_err(APLOG_MARK, r, rv, "error sending request headers");
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
rv = send_request_body(r, &s);
|
||||
if (rv) {
|
||||
log_err(APLOG_MARK, r, rv, "error sending request body");
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
rv = bflush(&s);
|
||||
if (rv) {
|
||||
log_err(APLOG_MARK, r, rv, "error sending request");
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
|
||||
log_debug(APLOG_MARK, r, "reading response headers");
|
||||
bb = apr_brigade_create(r->connection->pool, r->connection->bucket_alloc);
|
||||
|
||||
cgi_mode = CONFIG_VALUE(cfg->cgi_mode, CONFIG_VALUE(scfg->cgi_mode, DEFAULT_CGIMODE));
|
||||
if (!cgi_mode) {
|
||||
|
||||
/* receive implemented with http-0.9 based protocol */
|
||||
apr_interval_time_t timeout;
|
||||
char buf[4096];
|
||||
apr_pollfd_t pollfd = {r->pool, APR_POLL_SOCKET, APR_POLLIN, 0, { NULL }, NULL };
|
||||
pollfd.desc.s = sock;
|
||||
timeout = CONFIG_VALUE(cfg->timeout, CONFIG_VALUE(scfg->timeout,
|
||||
DEFAULT_TIMEOUT)) * 1000 * 1000;
|
||||
r->assbackwards = 1; /* XXX */
|
||||
|
||||
for(;;) {
|
||||
apr_int32_t nsds;
|
||||
apr_size_t len;
|
||||
|
||||
if ((rv = apr_poll(&pollfd, 1, &nsds, timeout)) == APR_TIMEUP) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: recv() timeout");
|
||||
break;
|
||||
}
|
||||
if (rv != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: poll() %s", strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
len = 4096;
|
||||
rv = apr_socket_recv(sock, buf, &len);
|
||||
if (rv == APR_SUCCESS) {
|
||||
apr_brigade_write(bb, NULL, NULL, buf, len);
|
||||
}
|
||||
else if (rv == APR_EOF) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: recv() %s", strerror(errno));
|
||||
}
|
||||
|
||||
}
|
||||
log_debug(APLOG_MARK,r, "recv finished");
|
||||
b = apr_bucket_flush_create(r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||
b = apr_bucket_eos_create(r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||
|
||||
} else {
|
||||
|
||||
/* receive implemented with http-1.x based protocol */
|
||||
b = apr_bucket_socket_create(sock, r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||
b = apr_bucket_eos_create(r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||
|
||||
rv = ap_scan_script_header_err_brigade(r, bb, NULL);
|
||||
if (rv) {
|
||||
if (rv == HTTP_INTERNAL_SERVER_ERROR) {
|
||||
log_err(APLOG_MARK, r, rv, "error reading response headers");
|
||||
}
|
||||
else {
|
||||
/* Work around an Apache bug whereby the returned status is
|
||||
* ignored and status_line is used instead. This bug is
|
||||
* present at least in 2.0.54.
|
||||
*/
|
||||
r->status_line = NULL;
|
||||
}
|
||||
apr_brigade_destroy(bb);
|
||||
return rv;
|
||||
}
|
||||
|
||||
location = apr_table_get(r->headers_out, "Location");
|
||||
|
||||
if (location && location[0] == '/' &&
|
||||
((r->status == HTTP_OK) || ap_is_HTTP_REDIRECT(r->status))) {
|
||||
|
||||
apr_brigade_destroy(bb);
|
||||
|
||||
/* Internal redirect -- fake-up a pseudo-request */
|
||||
r->status = HTTP_OK;
|
||||
|
||||
/* This redirect needs to be a GET no matter what the original
|
||||
* method was.
|
||||
*/
|
||||
r->method = apr_pstrdup(r->pool, "GET");
|
||||
r->method_number = M_GET;
|
||||
|
||||
ap_internal_redirect_handler(location, r);
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
rv = ap_pass_brigade(r->output_filters, bb);
|
||||
if (rv) {
|
||||
log_err(APLOG_MARK, r, rv, "ap_pass_brigade()");
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
|
||||
server_rec *base_server)
|
||||
{
|
||||
ap_add_version_component(p, "mod_uwsgi/" MOD_UWSGI_VERSION);
|
||||
return OK;
|
||||
}
|
||||
|
||||
static void *
|
||||
uwsgi_create_dir_config(apr_pool_t *p, char *dirspec)
|
||||
{
|
||||
uwsgi_cfg *cfg = apr_pcalloc(p, sizeof(uwsgi_cfg));
|
||||
|
||||
cfg->enabled = UNSET;
|
||||
cfg->mount.addr = UNSET;
|
||||
cfg->mount.port = UNSET;
|
||||
cfg->timeout = UNSET;
|
||||
cfg->cgi_mode = UNSET;
|
||||
cfg->modifier1 = UNSET;
|
||||
cfg->modifier2 = UNSET;
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
#define MERGE(b, n, a) (n->a == UNSET ? b->a : n->a)
|
||||
|
||||
static void *
|
||||
uwsgi_merge_dir_config(apr_pool_t *p, void *basev, void *newv)
|
||||
{
|
||||
uwsgi_cfg* cfg = apr_pcalloc(p, sizeof(uwsgi_cfg));
|
||||
uwsgi_cfg* base = basev;
|
||||
uwsgi_cfg* new = newv;
|
||||
|
||||
cfg->enabled = MERGE(base, new, enabled);
|
||||
cfg->mount.addr = MERGE(base, new, mount.addr);
|
||||
cfg->mount.port = MERGE(base, new, mount.port);
|
||||
cfg->timeout = MERGE(base, new, timeout);
|
||||
cfg->cgi_mode = MERGE(base, new, cgi_mode);
|
||||
cfg->modifier1 = MERGE(base, new, modifier1);
|
||||
cfg->modifier2 = MERGE(base, new, modifier2);
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
static void *
|
||||
uwsgi_create_server_config(apr_pool_t *p, server_rec *s)
|
||||
{
|
||||
uwsgi_server_cfg *c =
|
||||
(uwsgi_server_cfg *) apr_pcalloc(p, sizeof(uwsgi_server_cfg));
|
||||
|
||||
c->mounts = apr_array_make(p, 20, sizeof(mount_entry));
|
||||
c->timeout = UNSET;
|
||||
c->cgi_mode = UNSET;
|
||||
return c;
|
||||
}
|
||||
|
||||
static void *
|
||||
uwsgi_merge_server_config(apr_pool_t *p, void *basev, void *overridesv)
|
||||
{
|
||||
uwsgi_server_cfg *c = (uwsgi_server_cfg *)
|
||||
apr_pcalloc(p, sizeof(uwsgi_server_cfg));
|
||||
uwsgi_server_cfg *base = (uwsgi_server_cfg *) basev;
|
||||
uwsgi_server_cfg *overrides = (uwsgi_server_cfg *) overridesv;
|
||||
|
||||
c->mounts = apr_array_append(p, overrides->mounts, base->mounts);
|
||||
c->timeout = MERGE(base, overrides, timeout);
|
||||
c->cgi_mode = MERGE(base, overrides, cgi_mode);
|
||||
return c;
|
||||
}
|
||||
|
||||
static const char *
|
||||
cmd_uwsgi_mount(cmd_parms *cmd, void *dummy, const char *path, const char *addr)
|
||||
{
|
||||
int n;
|
||||
apr_status_t rv;
|
||||
char *scope_id = NULL; /* A ip6 parameter - not used here. */
|
||||
uwsgi_server_cfg *scfg = our_sconfig(cmd->server);
|
||||
mount_entry *new = apr_array_push(scfg->mounts);
|
||||
n = strlen(path);
|
||||
while (n > 0 && path[n-1] == '/') {
|
||||
n--; /* strip trailing slashes */
|
||||
}
|
||||
new->path = apr_pstrndup(cmd->pool, path, n);
|
||||
rv = apr_parse_addr_port(&new->addr, &scope_id, &new->port, addr,
|
||||
cmd->pool);
|
||||
if (rv)
|
||||
return "error parsing address:port string";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
cmd_uwsgi_server(cmd_parms *cmd, void *pcfg, const char *addr_and_port)
|
||||
{
|
||||
apr_status_t rv;
|
||||
uwsgi_cfg *cfg = pcfg;
|
||||
char *scope_id = NULL; /* A ip6 parameter - not used here. */
|
||||
|
||||
if (cmd->path == NULL)
|
||||
return "not a server command";
|
||||
|
||||
rv = apr_parse_addr_port(&cfg->mount.addr, &scope_id, &cfg->mount.port,
|
||||
addr_and_port, cmd->pool);
|
||||
if (rv)
|
||||
return "error parsing address:port string";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
cmd_uwsgi_handler(cmd_parms* cmd, void* pcfg, int flag)
|
||||
{
|
||||
uwsgi_cfg *cfg = pcfg;
|
||||
|
||||
if (cmd->path == NULL) /* server command */
|
||||
return "not a server command";
|
||||
|
||||
if (flag)
|
||||
cfg->enabled = ENABLED;
|
||||
else
|
||||
cfg->enabled = DISABLED;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
cmd_uwsgi_timeout(cmd_parms *cmd, void* pcfg, const char *strtimeout)
|
||||
{
|
||||
uwsgi_cfg *dcfg = pcfg;
|
||||
int timeout = atoi(strtimeout);
|
||||
|
||||
if (cmd->path == NULL) {
|
||||
uwsgi_server_cfg *scfg = our_sconfig(cmd->server);
|
||||
scfg->timeout = timeout;
|
||||
}
|
||||
else {
|
||||
dcfg->timeout = timeout;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
cmd_uwsgi_force_cgi_mode(cmd_parms *cmd, void *pcfg, const char *value)
|
||||
{
|
||||
int cgi_mode;
|
||||
|
||||
if (!strcmp("yes", value) || !strcmp("on", value) || !strcmp("enable", value) || !strcmp("1", value)) {
|
||||
cgi_mode = 1;
|
||||
}
|
||||
else {
|
||||
cgi_mode = 0;
|
||||
}
|
||||
|
||||
if (cmd->path == NULL) {
|
||||
uwsgi_server_cfg *scfg = our_sconfig(cmd->server);
|
||||
scfg->cgi_mode = cgi_mode;
|
||||
}
|
||||
else {
|
||||
uwsgi_cfg *dcfg = pcfg;
|
||||
dcfg->cgi_mode = cgi_mode;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
cmd_uwsgi_modifier1(cmd_parms *cmd, void *pcfg, const char *value)
|
||||
{
|
||||
uwsgi_cfg *cfg = pcfg;
|
||||
int val;
|
||||
|
||||
if (cmd->path == NULL) /* server command */
|
||||
return "not a server command";
|
||||
|
||||
val = atoi(value);
|
||||
if (val < 0 || val > 255) {
|
||||
return "ignored uWSGImodifier1. Value must be between 0 and 255";
|
||||
}
|
||||
else {
|
||||
cfg->modifier1 = (uint8_t) val;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
cmd_uwsgi_modifier2(cmd_parms *cmd, void *pcfg, const char *value)
|
||||
{
|
||||
uwsgi_cfg *cfg = pcfg;
|
||||
int val;
|
||||
|
||||
if (cmd->path == NULL) /* server command */
|
||||
return "not a server command";
|
||||
|
||||
val = atoi(value);
|
||||
if (val < 0 || val > 255) {
|
||||
return "ignored uWSGImodifier2. Value must be between 0 and 255";
|
||||
}
|
||||
else {
|
||||
cfg->modifier2 = (uint8_t) val;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const command_rec uwsgi_cmds[] = {
|
||||
AP_INIT_TAKE2("uWSGImount", cmd_uwsgi_mount, NULL, RSRC_CONF,
|
||||
"path prefix and address of UWSGI server"),
|
||||
AP_INIT_TAKE1("uWSGIserver", cmd_uwsgi_server, NULL, ACCESS_CONF,
|
||||
"Address and port of an UWSGI server (e.g. localhost:4000)"),
|
||||
AP_INIT_FLAG( "uWSGIhandler", cmd_uwsgi_handler, NULL, ACCESS_CONF,
|
||||
"On or Off to enable or disable the UWSGI handler"),
|
||||
AP_INIT_TAKE1("uWSGIserverTimeout", cmd_uwsgi_timeout, NULL, ACCESS_CONF|RSRC_CONF,
|
||||
"Timeout (in seconds) for communication with the UWSGI server."),
|
||||
AP_INIT_TAKE1("uWSGIforceCGImode", cmd_uwsgi_force_cgi_mode, NULL, ACCESS_CONF|RSRC_CONF,
|
||||
"Force uWSGI CGI mode for perfect integration with apache filter"),
|
||||
AP_INIT_TAKE1("uWSGImodifier1", cmd_uwsgi_modifier1, NULL, ACCESS_CONF,
|
||||
"Set uWSGI modifier1"),
|
||||
AP_INIT_TAKE1("uWSGImodifier2", cmd_uwsgi_modifier2, NULL, ACCESS_CONF,
|
||||
"Set uWSGI modifier2"),
|
||||
/*
|
||||
AP_INIT_TAKE12("uWSGIsocket", cmd_uwsgi_socket, NULL, RSRC_CONF|ACCESS_CONF,
|
||||
"Absolute path and optional timeout in seconds of uwsgi server socket"),
|
||||
AP_INIT_TAKE1("uWSGIsocket2", cmd_uwsgi_socket2, NULL, RSRC_CONF|ACCESS_CONF,
|
||||
"Absolute path of failover uwsgi server socket"),
|
||||
AP_INIT_TAKE1("uWSGIforceScriptName", cmd_uwsgi_force_script_name, NULL, ACCESS_CONF,
|
||||
"Fix for PATH_INFO/SCRIPT_NAME when the location has filesystem correspondence"),
|
||||
*/
|
||||
{NULL}
|
||||
};
|
||||
|
||||
static void uwsgi_register_hooks(apr_pool_t *p)
|
||||
{
|
||||
ap_hook_post_config(uwsgi_init, NULL, NULL, APR_HOOK_MIDDLE);
|
||||
ap_hook_handler(uwsgi_handler, NULL, NULL, APR_HOOK_MIDDLE);
|
||||
ap_hook_translate_name(uwsgi_translate, NULL, NULL, APR_HOOK_LAST);
|
||||
ap_hook_map_to_storage(uwsgi_map_location, NULL, NULL, APR_HOOK_FIRST);
|
||||
}
|
||||
|
||||
/* Dispatch list for API hooks */
|
||||
module AP_MODULE_DECLARE_DATA uwsgi_module = {
|
||||
STANDARD20_MODULE_STUFF,
|
||||
uwsgi_create_dir_config, /* create per-dir config structs */
|
||||
uwsgi_merge_dir_config, /* merge per-dir config structs */
|
||||
uwsgi_create_server_config, /* create per-server config structs */
|
||||
uwsgi_merge_server_config, /* merge per-server config structs */
|
||||
uwsgi_cmds, /* table of config file commands */
|
||||
uwsgi_register_hooks, /* register hooks */
|
||||
};
|
||||
|
||||
@@ -0,0 +1,397 @@
|
||||
#define APR_WANT_MEMFUNC
|
||||
#define APR_WANT_STRFUNC
|
||||
#include "apr_strings.h"
|
||||
#include "apr_hooks.h"
|
||||
#include "apr_optional_hooks.h"
|
||||
#include "apr_buckets.h"
|
||||
|
||||
#include "httpd.h"
|
||||
#include "http_config.h"
|
||||
#include "http_log.h"
|
||||
#include "http_protocol.h"
|
||||
#include "http_request.h"
|
||||
#include "util_script.h"
|
||||
|
||||
#include "mod_proxy.h"
|
||||
|
||||
|
||||
#define UWSGI_SCHEME "uwsgi"
|
||||
#define UWSGI_DEFAULT_PORT 3031
|
||||
|
||||
module AP_MODULE_DECLARE_DATA proxy_uwsgi_module;
|
||||
|
||||
|
||||
static int uwsgi_canon(request_rec *r, char *url)
|
||||
{
|
||||
char *host, sport[sizeof(":65535")];
|
||||
const char *err, *path;
|
||||
apr_port_t port = UWSGI_DEFAULT_PORT;
|
||||
|
||||
if (strncasecmp(url, UWSGI_SCHEME "://", sizeof(UWSGI_SCHEME) + 2)) {
|
||||
return DECLINED;
|
||||
}
|
||||
url += sizeof(UWSGI_SCHEME); /* Keep slashes */
|
||||
|
||||
err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
|
||||
if (err) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
"error parsing URL %s: %s", url, err);
|
||||
return HTTP_BAD_REQUEST;
|
||||
}
|
||||
|
||||
apr_snprintf(sport, sizeof(sport), ":%u", port);
|
||||
|
||||
if (ap_strchr(host, ':')) { /* if literal IPv6 address */
|
||||
host = apr_pstrcat(r->pool, "[", host, "]", NULL);
|
||||
}
|
||||
|
||||
path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
|
||||
r->proxyreq);
|
||||
if (!path) {
|
||||
return HTTP_BAD_REQUEST;
|
||||
}
|
||||
|
||||
r->filename = apr_pstrcat(r->pool, "proxy:" UWSGI_SCHEME "://", host, sport, "/",
|
||||
path, NULL);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_send(proxy_conn_rec *conn, const char *buf, apr_size_t length,
|
||||
request_rec *r)
|
||||
{
|
||||
apr_status_t rv;
|
||||
apr_size_t written;
|
||||
|
||||
while (length > 0) {
|
||||
written = length;
|
||||
if ((rv = apr_socket_send(conn->sock, buf, &written)) != APR_SUCCESS) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
|
||||
"sending data to %s:%u failed",
|
||||
conn->hostname, conn->port);
|
||||
return HTTP_SERVICE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
/* count for stats */
|
||||
conn->worker->s->transferred += written;
|
||||
buf += written;
|
||||
length -= written;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Send uwsgi header block
|
||||
*/
|
||||
static int uwsgi_send_headers(request_rec *r, proxy_conn_rec *conn)
|
||||
{
|
||||
char *buf, *ptr;
|
||||
|
||||
const apr_array_header_t *env_table;
|
||||
const apr_table_entry_t *env;
|
||||
|
||||
int j;
|
||||
|
||||
apr_size_t headerlen = 4;
|
||||
uint16_t pktsize, keylen, vallen;
|
||||
|
||||
ap_add_common_vars(r);
|
||||
ap_add_cgi_vars(r);
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
env_table = apr_table_elts(r->subprocess_env);
|
||||
env = (apr_table_entry_t *)env_table->elts;
|
||||
|
||||
for (j = 0; j < env_table->nelts; ++j) {
|
||||
headerlen += 2 + strlen(env[j].key) + 2 + strlen(env[j].val) ;
|
||||
}
|
||||
|
||||
ptr = buf = apr_palloc(r->pool, headerlen);
|
||||
|
||||
ptr+=4;
|
||||
|
||||
for (j = 0; j < env_table->nelts; ++j) {
|
||||
keylen = strlen(env[j].key);
|
||||
*ptr++= (uint8_t) (keylen & 0xff);
|
||||
*ptr++= (uint8_t) ((keylen >> 8) & 0xff);
|
||||
memcpy(ptr, env[j].key, keylen) ; ptr+=keylen;
|
||||
|
||||
vallen = strlen(env[j].val);
|
||||
*ptr++= (uint8_t) (vallen & 0xff);
|
||||
*ptr++= (uint8_t) ((vallen >> 8) & 0xff);
|
||||
memcpy(ptr, env[j].val, vallen) ; ptr+=vallen;
|
||||
}
|
||||
|
||||
pktsize = headerlen-4;
|
||||
|
||||
buf[0] = 0;
|
||||
buf[1] = (uint8_t) (pktsize & 0xff);
|
||||
buf[2] = (uint8_t) ((pktsize >> 8) & 0xff);
|
||||
buf[0] = 0;
|
||||
|
||||
return uwsgi_send(conn, buf, headerlen, r);
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_send_body(request_rec *r, proxy_conn_rec *conn)
|
||||
{
|
||||
if (ap_should_client_block(r)) {
|
||||
char *buf = apr_palloc(r->pool, AP_IOBUFSIZE);
|
||||
int status;
|
||||
apr_size_t readlen;
|
||||
|
||||
readlen = ap_get_client_block(r, buf, AP_IOBUFSIZE);
|
||||
while (readlen > 0) {
|
||||
status = uwsgi_send(conn, buf, readlen, r);
|
||||
if (status != OK) {
|
||||
return HTTP_SERVICE_UNAVAILABLE;
|
||||
}
|
||||
readlen = ap_get_client_block(r, buf, AP_IOBUFSIZE);
|
||||
}
|
||||
if (readlen == -1) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
"receiving request body failed");
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static
|
||||
apr_status_t ap_proxygetline(apr_bucket_brigade *bb, char *s, int n, request_rec *r,
|
||||
int fold, int *writen)
|
||||
{
|
||||
char *tmp_s = s;
|
||||
apr_status_t rv;
|
||||
apr_size_t len;
|
||||
|
||||
rv = ap_rgetline(&tmp_s, n, &len, r, fold, bb);
|
||||
apr_brigade_cleanup(bb);
|
||||
|
||||
if (rv == APR_SUCCESS) {
|
||||
*writen = (int) len;
|
||||
} else if (rv == APR_ENOSPC) {
|
||||
*writen = n;
|
||||
} else {
|
||||
*writen = -1;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_conf *conf)
|
||||
{
|
||||
|
||||
char buffer[HUGE_STRING_LEN];
|
||||
const char *buf;
|
||||
char *value, *end;
|
||||
int len;
|
||||
apr_status_t rc;
|
||||
conn_rec *c = r->connection;
|
||||
apr_off_t readbytes;
|
||||
apr_status_t rv;
|
||||
apr_bucket *e;
|
||||
apr_read_type_e mode = APR_NONBLOCK_READ;
|
||||
|
||||
request_rec *rp = ap_proxy_make_fake_req(backend->connection, r);
|
||||
rp->proxyreq = PROXYREQ_RESPONSE;
|
||||
|
||||
apr_bucket_brigade *bb = apr_brigade_create(r->pool, c->bucket_alloc);
|
||||
|
||||
|
||||
rc = ap_proxygetline(bb, buffer, sizeof(buffer), rp, 0, &len);
|
||||
if (len == 0) {
|
||||
rc = ap_proxygetline(bb, buffer, sizeof(buffer), rp, 0, &len);
|
||||
}
|
||||
|
||||
if (len <= 0) {
|
||||
// oops
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
backend->worker->s->read += len;
|
||||
|
||||
if (!apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
|
||||
// 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]);
|
||||
|
||||
if (keepchar != '\0') {
|
||||
buffer[12] = keepchar;
|
||||
} else {
|
||||
/* 2616 requires the space in Status-Line; the origin
|
||||
* server may have sent one but ap_rgetline_core will
|
||||
* have stripped it. */
|
||||
buffer[12] = ' ';
|
||||
buffer[13] = '\0';
|
||||
}
|
||||
r->status_line = apr_pstrdup(r->pool, &buffer[9]);
|
||||
|
||||
// start parsing headers;
|
||||
while ((len = ap_getline(buffer, sizeof(buffer), rp, 1)) > 0) {
|
||||
value = strchr(buffer, ':');
|
||||
// invalid header skip
|
||||
if (!value) continue;
|
||||
*value = '\0';
|
||||
++value;
|
||||
while (apr_isspace(*value)) ++value;
|
||||
for (end = &value[strlen(value)-1]; end > value && apr_isspace(*end); --end) *end = '\0';
|
||||
apr_table_add(r->headers_out, buffer, value);
|
||||
}
|
||||
|
||||
|
||||
if ((buf = apr_table_get(r->headers_out, "Content-Type"))) {
|
||||
ap_set_content_type(r, apr_pstrdup(r->pool, buf));
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
rv = ap_get_brigade(rp->input_filters, bb,
|
||||
AP_MODE_READBYTES, mode,
|
||||
conf->io_buffer_size);
|
||||
if (APR_STATUS_IS_EAGAIN(rv)
|
||||
|| (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb))) {
|
||||
e = apr_bucket_flush_create(c->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, e);
|
||||
if (ap_pass_brigade(r->output_filters, bb) || c->aborted) {
|
||||
break;
|
||||
}
|
||||
apr_brigade_cleanup(bb);
|
||||
mode = APR_BLOCK_READ;
|
||||
continue;
|
||||
}
|
||||
else if (rv == APR_EOF) {
|
||||
break;
|
||||
}
|
||||
else if (rv != APR_SUCCESS) {
|
||||
ap_proxy_backend_broke(r, bb);
|
||||
ap_pass_brigade(r->output_filters, bb);
|
||||
}
|
||||
|
||||
mode = APR_NONBLOCK_READ;
|
||||
apr_brigade_length(bb, 0, &readbytes);
|
||||
backend->worker->s->read += readbytes;
|
||||
ap_pass_brigade(r->output_filters, bb);
|
||||
apr_brigade_cleanup(bb);
|
||||
}
|
||||
e = apr_bucket_eos_create(c->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, e);
|
||||
ap_pass_brigade(r->output_filters, bb);
|
||||
|
||||
apr_brigade_cleanup(bb);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int uwsgi_handler(request_rec *r, proxy_worker *worker,
|
||||
proxy_server_conf *conf, char *url,
|
||||
const char *proxyname, apr_port_t proxyport)
|
||||
{
|
||||
int status;
|
||||
proxy_conn_rec *backend = NULL;
|
||||
apr_pool_t *p = r->pool;
|
||||
apr_uri_t *uri = apr_palloc(r->pool, sizeof(*uri));
|
||||
char server_portstr[32];
|
||||
|
||||
if (strncasecmp(url, UWSGI_SCHEME "://", sizeof(UWSGI_SCHEME) + 2)) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
|
||||
"declining URL %s", url);
|
||||
return DECLINED;
|
||||
}
|
||||
|
||||
// ADD PATH_INFO
|
||||
apr_table_add(r->subprocess_env, "PATH_INFO", url+strlen(worker->name));
|
||||
|
||||
|
||||
/* Create space for state information */
|
||||
status = ap_proxy_acquire_connection(UWSGI_SCHEME, &backend, worker,
|
||||
r->server);
|
||||
if (status != OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
backend->is_ssl = 0;
|
||||
|
||||
/* Step One: Determine Who To Connect To */
|
||||
status = ap_proxy_determine_connection(p, r, conf, worker, backend,
|
||||
uri, &url, proxyname, proxyport,
|
||||
server_portstr, sizeof(server_portstr));
|
||||
if (status != OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
/* Step Two: Make the Connection */
|
||||
if (ap_proxy_connect_backend(UWSGI_SCHEME, backend, worker, r->server)) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
"failed to make connection to backend: %s:%u",
|
||||
backend->hostname, backend->port);
|
||||
status = HTTP_SERVICE_UNAVAILABLE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Step Three: Create conn_rec */
|
||||
if (!backend->connection) {
|
||||
if ((status = ap_proxy_connection_create(UWSGI_SCHEME, backend,
|
||||
r->connection, r->server)) != OK)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Step Four: Process the Request */
|
||||
if ( ((status = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) != OK)
|
||||
|| ((status = uwsgi_send_headers(r, backend)) != OK)
|
||||
|| ((status = uwsgi_send_body(r, backend)) != OK)
|
||||
|| ((status = uwsgi_response(r, backend, conf)) != OK)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (backend) {
|
||||
backend->close = 1; /* always close the socket */
|
||||
ap_proxy_release_connection(UWSGI_SCHEME, backend, r->server);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static void register_hooks(apr_pool_t *p)
|
||||
{
|
||||
proxy_hook_scheme_handler(uwsgi_handler, NULL, NULL, APR_HOOK_FIRST);
|
||||
proxy_hook_canon_handler(uwsgi_canon, NULL, NULL, APR_HOOK_FIRST);
|
||||
}
|
||||
|
||||
|
||||
module AP_MODULE_DECLARE_DATA proxy_uwsgi_module = {
|
||||
STANDARD20_MODULE_STUFF,
|
||||
NULL, /* create per-directory config structure */
|
||||
NULL, /* merge per-directory config structures */
|
||||
NULL, /* create per-server config structure */
|
||||
NULL, /* merge per-server config structures */
|
||||
NULL, /* command table */
|
||||
register_hooks /* register hooks */
|
||||
};
|
||||
+197
-88
@@ -1,18 +1,18 @@
|
||||
/*
|
||||
|
||||
*** uWSGI/mod_uwsgi ***
|
||||
*** uWSGI/mod_uwsgi ***
|
||||
|
||||
Copyright 2009 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.
|
||||
Copyright 2009-2012 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.
|
||||
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
|
||||
@@ -37,11 +37,18 @@ LoadModule uwsgi_module <path_of_apache_modules>/mod_uwsgi.so
|
||||
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include "apr_strings.h"
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "httpd.h"
|
||||
#include "http_core.h"
|
||||
#include "http_protocol.h"
|
||||
#include "http_config.h"
|
||||
#include "http_log.h"
|
||||
#include "util_script.h"
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
@@ -51,7 +58,6 @@ LoadModule uwsgi_module <path_of_apache_modules>/mod_uwsgi.so
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
#define MAX_VARS 64
|
||||
#define DEFAULT_SOCK "/tmp/uwsgi.sock"
|
||||
|
||||
typedef struct {
|
||||
@@ -73,6 +79,8 @@ typedef struct {
|
||||
char script_name[256];
|
||||
char scheme[9];
|
||||
int cgi_mode ;
|
||||
int max_vars;
|
||||
int empty_remote_user;
|
||||
} uwsgi_cfg;
|
||||
|
||||
module AP_MODULE_DECLARE_DATA uwsgi_module;
|
||||
@@ -83,8 +91,18 @@ static uint16_t uwsgi_swap16(uint16_t x) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static int uwsgi_add_var(struct iovec *vec, int i, char *key, char *value, uint16_t *pkt_size) {
|
||||
static int uwsgi_add_var(struct iovec *vec, int i, request_rec *r, char *key, char *value, uint16_t *pkt_size) {
|
||||
|
||||
uwsgi_cfg *c = ap_get_module_config(r->per_dir_config, &uwsgi_module);
|
||||
|
||||
#if APR_IS_BIGENDIAN
|
||||
if (i+6 > c->max_vars) {
|
||||
#else
|
||||
if (i+4 > c->max_vars) {
|
||||
#endif
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: max number of uwsgi variables reached. consider increasing it with uWSGImaxVars directive");
|
||||
return i;
|
||||
}
|
||||
|
||||
#if APR_IS_BIGENDIAN
|
||||
char *ptr;
|
||||
@@ -150,6 +168,9 @@ static void *uwsgi_server_config(apr_pool_t *p, server_rec *s) {
|
||||
c->modifier1 = 0 ;
|
||||
c->modifier2 = 0 ;
|
||||
c->cgi_mode = 0 ;
|
||||
c->max_vars = 128;
|
||||
c->script_name[0] = 0;
|
||||
c->empty_remote_user = 1;
|
||||
|
||||
return c;
|
||||
}
|
||||
@@ -164,6 +185,14 @@ static void *uwsgi_dir_config(apr_pool_t *p, char *dir) {
|
||||
c->modifier1 = 0 ;
|
||||
c->modifier2 = 0 ;
|
||||
c->cgi_mode = 0 ;
|
||||
c->max_vars = 128;
|
||||
c->empty_remote_user = 1;
|
||||
c->script_name[0] = 0;
|
||||
if (dir) {
|
||||
if (strcmp(dir, "/")) {
|
||||
strncpy(c->script_name, dir, 255);
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
@@ -243,11 +272,8 @@ static int uwsgi_handler(request_rec *r) {
|
||||
|
||||
uwsgi_cfg *c = ap_get_module_config(r->per_dir_config, &uwsgi_module);
|
||||
|
||||
#if APR_IS_BIGENDIAN
|
||||
struct iovec uwsgi_vars[(MAX_VARS*6)+1] ;
|
||||
#else
|
||||
struct iovec uwsgi_vars[(MAX_VARS*4)+1] ;
|
||||
#endif
|
||||
struct iovec *uwsgi_vars;
|
||||
|
||||
int vecptr = 1 ;
|
||||
char pkt_header[4];
|
||||
uint16_t pkt_size = 0;
|
||||
@@ -264,7 +290,6 @@ static int uwsgi_handler(request_rec *r) {
|
||||
char uwsgi_http_status[13] ;
|
||||
int uwsgi_http_status_read = 0;
|
||||
|
||||
|
||||
apr_bucket_brigade *bb;
|
||||
|
||||
if (strcmp(r->handler, "uwsgi-handler"))
|
||||
@@ -287,7 +312,6 @@ static int uwsgi_handler(request_rec *r) {
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
|
||||
if ( (ret = timed_connect(&uwsgi_poll, (struct sockaddr *) &c->s_addr, c->addr_size, c->socket_timeout, r) ) != 0) {
|
||||
|
||||
close(uwsgi_poll.fd);
|
||||
@@ -317,68 +341,62 @@ static int uwsgi_handler(request_rec *r) {
|
||||
}
|
||||
|
||||
|
||||
#if APR_IS_BIGENDIAN
|
||||
uwsgi_vars = malloc(sizeof(struct iovec) * (c->max_vars*6)+1);
|
||||
#else
|
||||
uwsgi_vars = malloc(sizeof(struct iovec) * (c->max_vars*4)+1);
|
||||
#endif
|
||||
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "REQUEST_METHOD", (char *) r->method, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "QUERY_STRING", r->args ? r->args : "", &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "SERVER_NAME", (char *) ap_get_server_name(r), &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "SERVER_PORT", apr_psprintf(r->pool, "%u",ap_get_server_port(r)), &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "SERVER_PROTOCOL", r->protocol, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "REQUEST_URI", r->uri, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "REMOTE_ADDR", r->connection->remote_ip, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "REMOTE_USER", r->user ? r->user : "", &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "REQUEST_METHOD", (char *) r->method, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "QUERY_STRING", r->args ? r->args : "", &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "SERVER_NAME", (char *) ap_get_server_name(r), &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "SERVER_PORT", apr_psprintf(r->pool, "%u",ap_get_server_port(r)), &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "SERVER_PROTOCOL", r->protocol, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "REQUEST_URI", r->unparsed_uri, &pkt_size) ;
|
||||
#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "REMOTE_ADDR", r->useragent_ip, &pkt_size) ;
|
||||
#else
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "REMOTE_ADDR", r->connection->remote_ip, &pkt_size) ;
|
||||
#endif
|
||||
|
||||
//
|
||||
if (r->user) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "AUTH_TYPE", (char *) ap_auth_type(r), &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "REMOTE_USER", r->user, &pkt_size) ;
|
||||
}
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "DOCUMENT_ROOT", (char *) ap_document_root(r), &pkt_size) ;
|
||||
else if (c->empty_remote_user) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "REMOTE_USER", "", &pkt_size) ;
|
||||
}
|
||||
|
||||
if (ap_auth_type(r) != NULL) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "AUTH_TYPE", (char *) ap_auth_type(r), &pkt_size) ;
|
||||
}
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "DOCUMENT_ROOT", (char *) ap_document_root(r), &pkt_size) ;
|
||||
|
||||
if (c->scheme[0] != 0) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "UWSGI_SCHEME", c->scheme, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "UWSGI_SCHEME", c->scheme, &pkt_size) ;
|
||||
}
|
||||
|
||||
if (c->script_name[0] == '/') {
|
||||
if (c->script_name[1] == 0) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "SCRIPT_NAME", "", &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "PATH_INFO", r->uri, &pkt_size) ;
|
||||
}
|
||||
else {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "SCRIPT_NAME", c->script_name, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "PATH_INFO", r->uri+strlen(c->script_name), &pkt_size) ;
|
||||
}
|
||||
// SCRIPT_NAME = "/" is like SCRIPT_NAME = ""
|
||||
if (c->script_name[0] != 0 && !(c->script_name[0] == '/' && c->script_name[1] == 0)) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "SCRIPT_NAME", c->script_name, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "PATH_INFO", r->uri+strlen(c->script_name), &pkt_size) ;
|
||||
}
|
||||
else {
|
||||
if (r->path_info) {
|
||||
if (strlen(r->path_info) <= 0) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "SCRIPT_NAME", "", &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "PATH_INFO", r->uri, &pkt_size) ;
|
||||
}
|
||||
else {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "SCRIPT_NAME", apr_pstrndup(r->pool, r->uri, (strlen(r->uri) - strlen(r->path_info) )) , &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "PATH_INFO", r->path_info, &pkt_size) ;
|
||||
}
|
||||
}
|
||||
else {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "SCRIPT_NAME", "", &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "PATH_INFO", r->uri, &pkt_size) ;
|
||||
}
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "SCRIPT_NAME", "", &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "PATH_INFO", r->uri, &pkt_size) ;
|
||||
}
|
||||
|
||||
|
||||
headers = apr_table_elts(r->headers_in);
|
||||
h = (apr_table_entry_t *) headers->elts;
|
||||
|
||||
// check for max vars (a bit ugly)
|
||||
cnt = headers->nelts ;
|
||||
if (cnt + 11 > MAX_VARS) {
|
||||
cnt = MAX_VARS -11;
|
||||
}
|
||||
|
||||
for(i=0;i< cnt;i++) {
|
||||
for(i=0;i< headers->nelts;i++) {
|
||||
if (h[i].key){
|
||||
if (!strcasecmp(h[i].key, "Content-Type")) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "CONTENT_TYPE", h[i].val, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "CONTENT_TYPE", h[i].val, &pkt_size) ;
|
||||
}
|
||||
else if (!strcasecmp(h[i].key, "Content-Length")) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, "CONTENT_LENGTH", h[i].val, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "CONTENT_LENGTH", h[i].val, &pkt_size) ;
|
||||
}
|
||||
else {
|
||||
penv = apr_pstrcat(r->pool, "HTTP_", h[i].key, NULL);
|
||||
@@ -390,10 +408,17 @@ static int uwsgi_handler(request_rec *r) {
|
||||
*cp = toupper(*cp);
|
||||
}
|
||||
}
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, penv, h[i].val, &pkt_size) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, penv, h[i].val, &pkt_size) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* environment variables */
|
||||
headers = apr_table_elts(r->subprocess_env);
|
||||
h = (apr_table_entry_t*) headers->elts;
|
||||
for (i = 0; i < headers->nelts; ++i) {
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, h[i].key, h[i].val, &pkt_size) ;
|
||||
}
|
||||
|
||||
|
||||
uwsgi_vars[0].iov_base = pkt_header;
|
||||
@@ -413,11 +438,13 @@ static int uwsgi_handler(request_rec *r) {
|
||||
if (cnt < 0) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: writev() %s", strerror(errno));
|
||||
close(uwsgi_poll.fd);
|
||||
free(uwsgi_vars);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
else if (cnt != pkt_size+4) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: writev() returned wrong size");
|
||||
close(uwsgi_poll.fd);
|
||||
free(uwsgi_vars);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
@@ -429,6 +456,7 @@ static int uwsgi_handler(request_rec *r) {
|
||||
if (cnt < 0) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: read() client block failed !");
|
||||
close(uwsgi_poll.fd);
|
||||
free(uwsgi_vars);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -453,37 +481,75 @@ static int uwsgi_handler(request_rec *r) {
|
||||
if (cnt == 0) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: recv() timeout");
|
||||
apr_brigade_destroy(bb);
|
||||
free(uwsgi_vars);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
else if (cnt > 0) {
|
||||
cnt = recv(uwsgi_poll.fd, buf, 4096, 0) ;
|
||||
if (cnt < 0) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: recv() %s", strerror(errno));
|
||||
apr_brigade_destroy(bb);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
else if (cnt > 0) {
|
||||
if (!c->cgi_mode && uwsgi_http_status_read < 12) {
|
||||
if (uwsgi_http_status_read + cnt >= 12) {
|
||||
memcpy(uwsgi_http_status+uwsgi_http_status_read, buf, 12-uwsgi_http_status_read);
|
||||
r->status = atoi(uwsgi_http_status+8);
|
||||
uwsgi_http_status_read+=cnt;
|
||||
}
|
||||
else {
|
||||
memcpy(uwsgi_http_status+uwsgi_http_status_read, buf, cnt);
|
||||
uwsgi_http_status_read+=cnt;
|
||||
}
|
||||
}
|
||||
apr_brigade_write(bb, NULL, NULL, buf, cnt);
|
||||
|
||||
}
|
||||
else {
|
||||
break;
|
||||
if (uwsgi_poll.revents & POLLIN || uwsgi_poll.revents & POLLHUP) {
|
||||
cnt = recv(uwsgi_poll.fd, buf, 4096, 0) ;
|
||||
if (cnt < 0) {
|
||||
if (errno != ECONNRESET) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: recv() %s", strerror(errno));
|
||||
apr_brigade_destroy(bb);
|
||||
free(uwsgi_vars);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (cnt > 0) {
|
||||
if (!c->cgi_mode && uwsgi_http_status_read < 12) {
|
||||
if (uwsgi_http_status_read + cnt >= 12) {
|
||||
memcpy(uwsgi_http_status+uwsgi_http_status_read, buf, 12-uwsgi_http_status_read);
|
||||
r->status = atoi(uwsgi_http_status+8);
|
||||
uwsgi_http_status_read+=cnt;
|
||||
}
|
||||
else {
|
||||
memcpy(uwsgi_http_status+uwsgi_http_status_read, buf, cnt);
|
||||
uwsgi_http_status_read+=cnt;
|
||||
}
|
||||
}
|
||||
// check for client disconnect
|
||||
if (r->connection->aborted) {
|
||||
close(uwsgi_poll.fd);
|
||||
apr_brigade_destroy(bb);
|
||||
free(uwsgi_vars);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
if (!c->cgi_mode) {
|
||||
b = apr_bucket_transient_create(buf, cnt, r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||
b = apr_bucket_flush_create(r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||
if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS) {
|
||||
close(uwsgi_poll.fd);
|
||||
apr_brigade_destroy(bb);
|
||||
free(uwsgi_vars);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
apr_brigade_cleanup(bb);
|
||||
}
|
||||
else {
|
||||
apr_brigade_write(bb, NULL, NULL, buf, cnt);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// EOF
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// error
|
||||
if (uwsgi_poll.revents & POLLERR || uwsgi_poll.revents & POLLNVAL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: poll() %s", strerror(errno));
|
||||
close(uwsgi_poll.fd);
|
||||
apr_brigade_destroy(bb);
|
||||
free(uwsgi_vars);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -497,6 +563,7 @@ static int uwsgi_handler(request_rec *r) {
|
||||
|
||||
if (!c->cgi_mode) {
|
||||
if (uwsgi_http_status_read == 0) {
|
||||
free(uwsgi_vars);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -504,11 +571,13 @@ static int uwsgi_handler(request_rec *r) {
|
||||
|
||||
if (hret = ap_scan_script_header_err_brigade(r, bb, NULL)) {
|
||||
apr_brigade_destroy(bb);
|
||||
free(uwsgi_vars);
|
||||
return hret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
free(uwsgi_vars);
|
||||
return ap_pass_brigade(r->output_filters, bb) ;
|
||||
}
|
||||
|
||||
@@ -540,6 +609,22 @@ static const char * cmd_uwsgi_force_wsgi_scheme(cmd_parms *cmd, void *cfg, const
|
||||
|
||||
}
|
||||
|
||||
static const char *cmd_uwsgi_max_vars(cmd_parms *cmd, void *cfg, const char *value) {
|
||||
uwsgi_cfg *c ;
|
||||
int val ;
|
||||
|
||||
if (cfg) {
|
||||
c = cfg ;
|
||||
}
|
||||
else {
|
||||
c = ap_get_module_config(cmd->server->module_config, &uwsgi_module);
|
||||
}
|
||||
|
||||
c->max_vars = atoi(value);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char * cmd_uwsgi_modifier1(cmd_parms *cmd, void *cfg, const char *value) {
|
||||
|
||||
uwsgi_cfg *c ;
|
||||
@@ -574,7 +659,7 @@ static const char * cmd_uwsgi_force_cgi_mode(cmd_parms *cmd, void *cfg, const ch
|
||||
c = ap_get_module_config(cmd->server->module_config, &uwsgi_module);
|
||||
}
|
||||
|
||||
if (!strcmp("yes", value) || !strcmp("on", value) || !strcmp("enable", value) || !strcmp("1", value)) {
|
||||
if (!strcmp("yes", value) || !strcmp("on", value) || !strcmp("enable", value) || !strcmp("1", value) || !strcmp("true", value)) {
|
||||
c->cgi_mode = 1 ;
|
||||
}
|
||||
|
||||
@@ -675,6 +760,28 @@ static const char * cmd_uwsgi_socket(cmd_parms *cmd, void *cfg, const char *path
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
static const char * cmd_uwsgi_empty_remote_user(cmd_parms *cmd, void *cfg, const char *value) {
|
||||
|
||||
uwsgi_cfg *c ;
|
||||
|
||||
if (cfg) {
|
||||
c = cfg ;
|
||||
}
|
||||
else {
|
||||
c = ap_get_module_config(cmd->server->module_config, &uwsgi_module);
|
||||
}
|
||||
|
||||
if (!strcmp("yes", value) || !strcmp("on", value) || !strcmp("enable", value) || !strcmp("1", value) || !strcmp("true", value)) {
|
||||
c->empty_remote_user = 1;
|
||||
}
|
||||
else {
|
||||
c->empty_remote_user = 0;
|
||||
}
|
||||
|
||||
return NULL ;
|
||||
|
||||
}
|
||||
|
||||
static const command_rec uwsgi_cmds[] = {
|
||||
AP_INIT_TAKE12("uWSGIsocket", cmd_uwsgi_socket, NULL, RSRC_CONF|ACCESS_CONF, "Absolute path and optional timeout in seconds of uwsgi server socket"),
|
||||
AP_INIT_TAKE1("uWSGIsocket2", cmd_uwsgi_socket2, NULL, RSRC_CONF|ACCESS_CONF, "Absolute path of failover uwsgi server socket"),
|
||||
@@ -683,6 +790,8 @@ static const command_rec uwsgi_cmds[] = {
|
||||
AP_INIT_TAKE1("uWSGIforceScriptName", cmd_uwsgi_force_script_name, NULL, ACCESS_CONF, "Fix for PATH_INFO/SCRIPT_NAME when the location has filesystem correspondence"),
|
||||
AP_INIT_TAKE1("uWSGIforceCGImode", cmd_uwsgi_force_cgi_mode, NULL, ACCESS_CONF, "Force uWSGI CGI mode for perfect integration with apache filter"),
|
||||
AP_INIT_TAKE1("uWSGIforceWSGIscheme", cmd_uwsgi_force_wsgi_scheme, NULL, ACCESS_CONF, "Force the WSGI scheme var (set by default to \"http\")"),
|
||||
AP_INIT_TAKE1("uWSGIemptyRemoteUser", cmd_uwsgi_empty_remote_user, NULL, ACCESS_CONF, "Always include REMOTE_USER in the environment, even with an empty value (default true)"),
|
||||
AP_INIT_TAKE1("uWSGImaxVars", cmd_uwsgi_max_vars, NULL, ACCESS_CONF, "Set the maximum allowed number of uwsgi variables (default 128)"),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,454 +0,0 @@
|
||||
#ifdef UWSGI_ASYNC
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include <sys/epoll.h>
|
||||
|
||||
int async_queue_init(int serverfd) {
|
||||
int epfd ;
|
||||
struct epoll_event ee;
|
||||
|
||||
epfd = epoll_create(256);
|
||||
|
||||
if (epfd < 0) {
|
||||
perror("epoll_create()");
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
memset(&ee, 0, sizeof(struct epoll_event));
|
||||
ee.events = EPOLLIN;
|
||||
ee.data.fd = serverfd;
|
||||
|
||||
if (epoll_ctl(epfd, EPOLL_CTL_ADD, serverfd, &ee)) {
|
||||
perror("epoll_ctl()");
|
||||
close(epfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return epfd;
|
||||
}
|
||||
|
||||
int async_wait(int queuefd, void *events, int nevents, int block, int timeout) {
|
||||
|
||||
int ret ;
|
||||
|
||||
if (timeout <= 0) {
|
||||
timeout = block;
|
||||
}
|
||||
else {
|
||||
timeout = timeout*1000;
|
||||
}
|
||||
|
||||
//fprintf(stderr,"waiting with timeout %d nevents %d\n", timeout, nevents);
|
||||
ret = epoll_wait(queuefd, (struct epoll_event *) events, nevents, timeout);
|
||||
if (ret < 0) {
|
||||
perror("epoll_wait()");
|
||||
}
|
||||
return ret ;
|
||||
}
|
||||
|
||||
int async_add(int queuefd, int fd, int etype) {
|
||||
struct epoll_event ee;
|
||||
|
||||
memset(&ee, 0, sizeof(struct epoll_event));
|
||||
ee.events = etype;
|
||||
ee.data.fd = fd;
|
||||
|
||||
if (epoll_ctl(queuefd, EPOLL_CTL_ADD, fd, &ee)) {
|
||||
perror("epoll_ctl()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int async_mod(int queuefd, int fd, int etype) {
|
||||
struct epoll_event ee;
|
||||
|
||||
memset(&ee, 0, sizeof(struct epoll_event));
|
||||
ee.events = etype;
|
||||
ee.data.fd = fd;
|
||||
|
||||
if (epoll_ctl(queuefd, EPOLL_CTL_MOD, fd, &ee)) {
|
||||
perror("epoll_ctl()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int async_del(int queuefd, int fd, int etype) {
|
||||
struct epoll_event ee;
|
||||
|
||||
memset(&ee, 0, sizeof(struct epoll_event));
|
||||
ee.events = etype;
|
||||
ee.data.fd = fd;
|
||||
|
||||
if (epoll_ctl(queuefd, EPOLL_CTL_DEL, fd, &ee)) {
|
||||
perror("epoll_ctl()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(__sun__)
|
||||
|
||||
int async_queue_init(int serverfd) {
|
||||
int dpfd ;
|
||||
struct pollfd dpev;
|
||||
|
||||
dpfd = open("/dev/poll", O_RDWR);
|
||||
|
||||
if (dpfd < 0) {
|
||||
perror("open()");
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
dpev.fd = serverfd;
|
||||
dpev.events = POLLIN ;
|
||||
|
||||
if (write(dpfd, &dpev, sizeof(struct pollfd)) < 0) {
|
||||
perror("write()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return dpfd;
|
||||
}
|
||||
|
||||
int async_wait(int queuefd, void *events, int nevents, int block, int timeout) {
|
||||
|
||||
int ret ;
|
||||
struct dvpoll dv ;
|
||||
|
||||
if (timeout <= 0) {
|
||||
timeout = block;
|
||||
}
|
||||
else {
|
||||
timeout = timeout*1000;
|
||||
}
|
||||
|
||||
dv.dp_fds = (struct pollfd *) events;
|
||||
dv.dp_nfds = nevents;
|
||||
dv.dp_timeout = timeout;
|
||||
|
||||
//fprintf(stderr,"waiting with timeout %d nevents %d\n", timeout, nevents);
|
||||
ret = ioctl(queuefd, DP_POLL, &dv);
|
||||
if (ret < 0) {
|
||||
perror("ioctl()");
|
||||
}
|
||||
return ret ;
|
||||
}
|
||||
|
||||
int async_add(int queuefd, int fd, int etype) {
|
||||
struct pollfd pl;
|
||||
|
||||
pl.fd = fd ;
|
||||
pl.events = etype ;
|
||||
|
||||
if (write(queuefd, &pl, sizeof(struct pollfd))) {
|
||||
perror("write()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int async_mod(int queuefd, int fd, int etype) {
|
||||
// using the same fd will overwrite existing rule
|
||||
return async_add(queuefd, fd, etype);
|
||||
}
|
||||
|
||||
int async_del(int queuefd, int fd, int etype) {
|
||||
// to remove an fd from /dev/poll you have to simply close it
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
int async_queue_init(int serverfd) {
|
||||
int kfd ;
|
||||
struct kevent kev;
|
||||
|
||||
kfd = kqueue();
|
||||
|
||||
if (kfd < 0) {
|
||||
perror("kqueue()");
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
EV_SET(&kev, serverfd, EVFILT_READ, EV_ADD, 0, 0, 0);
|
||||
if (kevent(kfd, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
perror("kevent()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return kfd;
|
||||
}
|
||||
|
||||
int async_wait(int queuefd, void *events, int nevents, int block, int timeout) {
|
||||
|
||||
int ret;
|
||||
struct timespec ts ;
|
||||
|
||||
|
||||
if (timeout <= 0) {
|
||||
if (!block) {
|
||||
memset(&ts, 0, sizeof(struct timespec));
|
||||
ts.tv_sec = timeout ;
|
||||
ret = kevent(queuefd, NULL, 0, events, nevents, &ts);
|
||||
}
|
||||
else {
|
||||
ret = kevent(queuefd, NULL, 0, events, nevents, NULL);
|
||||
}
|
||||
}
|
||||
else {
|
||||
memset(&ts, 0, sizeof(struct timespec));
|
||||
ts.tv_sec = timeout ;
|
||||
ret = kevent(queuefd, NULL, 0, events, nevents, &ts);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
perror("kevent()");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int async_add(int queuefd, int fd, int etype) {
|
||||
struct kevent kev;
|
||||
|
||||
|
||||
EV_SET(&kev, fd, etype, EV_ADD, 0, 0, 0);
|
||||
if (kevent(queuefd, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
perror("kevent()");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int async_mod(int queuefd, int fd, int etype) {
|
||||
struct kevent kev;
|
||||
|
||||
EV_SET(&kev, fd, ASYNC_OUT, EV_DISABLE, 0, 0, 0);
|
||||
if (kevent(queuefd, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
perror("kevent()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
EV_SET(&kev, fd, etype, EV_ADD, 0, 0, 0);
|
||||
if (kevent(queuefd, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
perror("kevent()");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int async_del(int queuefd, int fd, int etype) {
|
||||
struct kevent kev;
|
||||
|
||||
EV_SET(&kev, fd, etype, EV_DELETE, 0, 0, 0);
|
||||
if (kevent(queuefd, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
perror("kevent()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct wsgi_request *next_wsgi_req(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req) {
|
||||
|
||||
uint8_t *ptr = (uint8_t *) wsgi_req ;
|
||||
|
||||
ptr += sizeof(struct wsgi_request)+(uwsgi->buffer_size-1) ;
|
||||
|
||||
return (struct wsgi_request *) ptr ;
|
||||
}
|
||||
|
||||
int async_get_timeout(struct uwsgi_server *uwsgi) {
|
||||
|
||||
|
||||
struct wsgi_request* wsgi_req = uwsgi->wsgi_requests ;
|
||||
int i ;
|
||||
time_t curtime, tdelta = 0 ;
|
||||
int ret = 0 ;
|
||||
|
||||
if (!uwsgi->async_running) return 0;
|
||||
|
||||
for(i=0;i<uwsgi->async;i++) {
|
||||
if (wsgi_req->async_status == UWSGI_AGAIN) {
|
||||
if (wsgi_req->async_timeout_expired) {
|
||||
return 0;
|
||||
}
|
||||
if (wsgi_req->async_timeout > 0) {
|
||||
if (tdelta <= 0 || tdelta > wsgi_req->async_timeout) {
|
||||
tdelta = wsgi_req->async_timeout ;
|
||||
}
|
||||
}
|
||||
}
|
||||
wsgi_req = next_wsgi_req(uwsgi, wsgi_req) ;
|
||||
}
|
||||
|
||||
curtime = time(NULL);
|
||||
|
||||
ret = tdelta - curtime ;
|
||||
if (ret > 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void async_expire_timeouts(struct uwsgi_server *uwsgi) {
|
||||
|
||||
struct wsgi_request* wsgi_req = uwsgi->wsgi_requests ;
|
||||
int i ;
|
||||
time_t deadline = time(NULL);
|
||||
|
||||
|
||||
for(i=0;i<uwsgi->async;i++) {
|
||||
if (wsgi_req->async_status == UWSGI_AGAIN && wsgi_req->async_timeout > 0) {
|
||||
if (wsgi_req->async_timeout <= deadline) {
|
||||
wsgi_req->async_timeout = 0 ;
|
||||
wsgi_req->async_timeout_expired = 1 ;
|
||||
}
|
||||
}
|
||||
wsgi_req = next_wsgi_req(uwsgi, wsgi_req) ;
|
||||
}
|
||||
}
|
||||
|
||||
struct wsgi_request *find_first_available_wsgi_req(struct uwsgi_server *uwsgi) {
|
||||
|
||||
struct wsgi_request* wsgi_req = uwsgi->wsgi_requests ;
|
||||
int i ;
|
||||
|
||||
for(i=0;i<uwsgi->async;i++) {
|
||||
if (wsgi_req->async_status == UWSGI_OK) {
|
||||
return wsgi_req ;
|
||||
}
|
||||
wsgi_req = next_wsgi_req(uwsgi, wsgi_req) ;
|
||||
}
|
||||
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
struct wsgi_request *find_wsgi_req_by_id(struct uwsgi_server *uwsgi, int async_id) {
|
||||
|
||||
uint8_t *ptr = (uint8_t *) uwsgi->wsgi_requests ;
|
||||
|
||||
ptr += (sizeof(struct wsgi_request)+(uwsgi->buffer_size-1)) * async_id ;
|
||||
|
||||
return (struct wsgi_request *) ptr ;
|
||||
}
|
||||
|
||||
struct wsgi_request *find_wsgi_req_by_fd(struct uwsgi_server *uwsgi, int fd, int etype) {
|
||||
|
||||
struct wsgi_request* wsgi_req = uwsgi->wsgi_requests ;
|
||||
int i ;
|
||||
|
||||
if (etype != -1) {
|
||||
for(i=0;i<uwsgi->async;i++) {
|
||||
if (wsgi_req->async_waiting_fd == fd && wsgi_req->async_waiting_fd_type == etype) {
|
||||
return wsgi_req ;
|
||||
}
|
||||
wsgi_req = next_wsgi_req(uwsgi, wsgi_req) ;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(i=0;i<uwsgi->async;i++) {
|
||||
if (wsgi_req->async_waiting_fd == fd) {
|
||||
return wsgi_req ;
|
||||
}
|
||||
wsgi_req = next_wsgi_req(uwsgi, wsgi_req) ;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL ;
|
||||
|
||||
}
|
||||
|
||||
void async_set_timeout(struct wsgi_request *wsgi_req, time_t timeout) {
|
||||
|
||||
wsgi_req->async_timeout = time(NULL);
|
||||
wsgi_req->async_timeout += timeout;
|
||||
wsgi_req->async_timeout_expired = 0 ;
|
||||
|
||||
}
|
||||
|
||||
void async_write_all(struct uwsgi_server *uwsgi, char *data, size_t len) {
|
||||
|
||||
struct wsgi_request *wsgi_req = uwsgi->wsgi_requests ;
|
||||
int i;
|
||||
ssize_t rlen ;
|
||||
|
||||
for(i=0;i<uwsgi->async;i++) {
|
||||
if (wsgi_req->async_status == UWSGI_PAUSED) {
|
||||
rlen = write(wsgi_req->poll.fd, data, len);
|
||||
if (rlen < 0) {
|
||||
perror("write()");
|
||||
}
|
||||
else {
|
||||
wsgi_req->response_size += rlen ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void async_unpause_all(struct uwsgi_server *uwsgi) {
|
||||
|
||||
struct wsgi_request *wsgi_req = uwsgi->wsgi_requests ;
|
||||
int i;
|
||||
|
||||
for(i=0;i<uwsgi->async;i++) {
|
||||
if (wsgi_req->async_status == UWSGI_PAUSED) {
|
||||
wsgi_req->async_status = UWSGI_AGAIN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct wsgi_request * async_loop(struct uwsgi_server *uwsgi) {
|
||||
|
||||
struct wsgi_request *wsgi_req ;
|
||||
int i ;
|
||||
|
||||
uwsgi->async_running = -1 ;
|
||||
wsgi_req = uwsgi->wsgi_requests ;
|
||||
|
||||
|
||||
for(i=0;i<uwsgi->async;i++) {
|
||||
if (wsgi_req->async_status == UWSGI_AGAIN) {
|
||||
if (wsgi_req->async_waiting_fd != -1 && !wsgi_req->async_waiting_fd_monitored) {
|
||||
// add fd to monitoring
|
||||
if (async_add(uwsgi->async_queue, wsgi_req->async_waiting_fd, wsgi_req->async_waiting_fd_type)) {
|
||||
// error adding fd to the async queue, better to close it...
|
||||
close(wsgi_req->async_waiting_fd);
|
||||
wsgi_req->async_status = UWSGI_OK ;
|
||||
return wsgi_req;
|
||||
}
|
||||
wsgi_req->async_waiting_fd_monitored = 1;
|
||||
wsgi_req->async_status = UWSGI_AGAIN;
|
||||
}
|
||||
else if (wsgi_req->async_waiting_fd == -1 && wsgi_req->async_timeout <= 0) {
|
||||
uwsgi->async_running = 0 ;
|
||||
// st global wsgi_req for python functions
|
||||
uwsgi->wsgi_req = wsgi_req ;
|
||||
wsgi_req->async_status = (*uwsgi->shared->hooks[wsgi_req->uh.modifier1]) (uwsgi, wsgi_req);
|
||||
|
||||
wsgi_req->async_switches++;
|
||||
|
||||
if (wsgi_req->async_status < UWSGI_AGAIN) {
|
||||
return wsgi_req;
|
||||
}
|
||||
}
|
||||
}
|
||||
wsgi_req = next_wsgi_req(uwsgi, wsgi_req) ;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
import struct
|
||||
import sys
|
||||
import os
|
||||
|
||||
filename = sys.argv[1]
|
||||
|
||||
size = os.path.getsize(filename)
|
||||
|
||||
f = open(filename, 'r')
|
||||
print(f.read())
|
||||
f.close()
|
||||
|
||||
print(struct.pack("<Q", size))
|
||||
@@ -0,0 +1,5 @@
|
||||
import sys
|
||||
import uwsgi
|
||||
|
||||
print("i am the bootstrap for uwsgi.SymbolsImporter")
|
||||
sys.meta_path.insert(0, uwsgi.SymbolsImporter())
|
||||
@@ -0,0 +1,4 @@
|
||||
import sys
|
||||
import uwsgi
|
||||
|
||||
sys.meta_path.insert(0, uwsgi.SymbolsZipImporter("pygments_zip"))
|
||||
@@ -0,0 +1,5 @@
|
||||
import sys
|
||||
import uwsgi
|
||||
|
||||
sys.meta_path.insert(0, uwsgi.SymbolsZipImporter("django_zip:djenv/lib/python2.6/site-packages"))
|
||||
sys.meta_path.insert(0, uwsgi.SymbolsZipImporter("djapp_zip"))
|
||||
@@ -0,0 +1,4 @@
|
||||
import sys
|
||||
import uwsgi
|
||||
|
||||
sys.meta_path.insert(0, uwsgi.ZipImporter("data://0"))
|
||||
@@ -0,0 +1,3 @@
|
||||
import uwsgi
|
||||
|
||||
print uwsgi.extract("data://0")
|
||||
@@ -0,0 +1 @@
|
||||
object file for embedded files will be put here
|
||||
@@ -0,0 +1,45 @@
|
||||
[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
|
||||
yaml_implementation = auto
|
||||
malloc_implementation = libc
|
||||
extras =
|
||||
plugins =
|
||||
bin_name = uwsgi
|
||||
append_version =
|
||||
plugin_dir = .
|
||||
embedded_plugins = %(main_plugin)s, ping, cache, nagios, rrdtool, carbon, rpc, corerouter, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool, redislog, mongodblog, router_rewrite, router_http
|
||||
as_shared_library = false
|
||||
|
||||
locking = auto
|
||||
event = auto
|
||||
timer = auto
|
||||
filemonitor = auto
|
||||
|
||||
blacklist =
|
||||
whitelist =
|
||||
|
||||
embed_files =
|
||||
|
||||
embed_config =
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = cgi
|
||||
inherit = base
|
||||
@@ -0,0 +1,4 @@
|
||||
[uwsgi]
|
||||
main_plugin =
|
||||
inherit = base
|
||||
embedded_plugins = null
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = python
|
||||
inherit = base
|
||||
@@ -0,0 +1,4 @@
|
||||
[uwsgi]
|
||||
main_plugin = python
|
||||
inherit = base
|
||||
embed_files = bootstrap3.py,django.zip,djapp.zip
|
||||
@@ -0,0 +1,5 @@
|
||||
[uwsgi]
|
||||
main_plugin = python
|
||||
inherit = base
|
||||
|
||||
embed_files = embedme.py,uwsgidecorators.py
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = erlang
|
||||
inherit = base
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = python,gevent
|
||||
inherit = base
|
||||
@@ -0,0 +1,5 @@
|
||||
[uwsgi]
|
||||
inherit = base
|
||||
bin_name = libuwsgi.so
|
||||
embedded_plugins = null
|
||||
as_shared_library = true
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = lua
|
||||
inherit = base
|
||||
@@ -0,0 +1,4 @@
|
||||
[uwsgi]
|
||||
main_plugin =
|
||||
inherit = base
|
||||
plugins = lua
|
||||
@@ -0,0 +1,5 @@
|
||||
[uwsgi]
|
||||
inherit = base
|
||||
plugins = python, ping, rack, psgi, cache, http, fastrouter
|
||||
plugin_dir = plugins
|
||||
embedded_plugins = null
|
||||
@@ -0,0 +1,4 @@
|
||||
[uwsgi]
|
||||
inherit = base
|
||||
plugin_dir = /usr/lib/uwsgi
|
||||
embedded_plugins =
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = php
|
||||
inherit = base
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = psgi
|
||||
inherit = base
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = python,erlang,pyerl
|
||||
inherit = base
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = python,lua
|
||||
inherit = base
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = pypy
|
||||
inherit = base
|
||||
@@ -0,0 +1,30 @@
|
||||
[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,5 @@
|
||||
[uwsgi]
|
||||
main_plugin = pyuwsgi
|
||||
inherit = base
|
||||
bin_name = pyuwsgi.so
|
||||
as_shared_library = true
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = rack
|
||||
inherit = base
|
||||
@@ -0,0 +1,29 @@
|
||||
[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,34 @@
|
||||
[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
|
||||
pcre = true
|
||||
routing = true
|
||||
debug = false
|
||||
unbit = true
|
||||
xml_implementation = expat
|
||||
yaml_implementation = auto
|
||||
malloc_implementation = libc
|
||||
plugins =
|
||||
bin_name = /opt/unbit/bin/uwsgi
|
||||
append_version = unbit
|
||||
plugin_dir = /opt/unbit/uwsgi_plugins
|
||||
embedded_plugins =
|
||||
|
||||
locking = auto
|
||||
event = auto
|
||||
timer = auto
|
||||
filemonitor = auto
|
||||
@@ -0,0 +1,6 @@
|
||||
[uwsgi]
|
||||
inherit = unbit
|
||||
json = false
|
||||
embedded_plugins = python
|
||||
bin_name = ../bin/uwsgi
|
||||
plugin_dir = ../bin/uwsgi_plugins
|
||||
@@ -0,0 +1,44 @@
|
||||
[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 =
|
||||
@@ -0,0 +1,18 @@
|
||||
require 'fiber'
|
||||
require 'sinatra'
|
||||
|
||||
get '/hi' do
|
||||
|
||||
class Response
|
||||
def each
|
||||
for i in 1..10
|
||||
yield "ciao<br/>"
|
||||
Fiber.yield
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Response.new
|
||||
end
|
||||
|
||||
run Sinatra::Application
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
require 'stringio'
|
||||
|
||||
hello = proc do |signum|
|
||||
puts "Hello i am signal #{signum}"
|
||||
end
|
||||
|
||||
file_changed = proc do |signum|
|
||||
puts "/tmp has been modified"
|
||||
end
|
||||
|
||||
UWSGI.register_signal(17, '', hello)
|
||||
UWSGI.register_signal(30, '', file_changed)
|
||||
|
||||
UWSGI.add_rb_timer(17 , 2)
|
||||
UWSGI.add_timer(17 , 1)
|
||||
UWSGI.add_file_monitor(30 , '/tmp')
|
||||
|
||||
puts UWSGI.signal_registered(1)
|
||||
puts UWSGI.signal_registered(17)
|
||||
|
||||
run lambda { |env|
|
||||
puts env.inspect
|
||||
UWSGI.signal(17)
|
||||
[200, {'Content-Type'=>'text/plain'}, StringIO.new("Hello World!\n")]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
require 'sinatra'
|
||||
|
||||
get '/hi' do
|
||||
"Hello World"
|
||||
end
|
||||
|
||||
run Sinatra::Application
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
require 'stringio'
|
||||
require 'uwsgidsl'
|
||||
|
||||
|
||||
|
||||
signal 17,'mule5' do |signum|
|
||||
end
|
||||
|
||||
puts UWSGI::VERSION
|
||||
puts UWSGI::NUMPROC
|
||||
puts UWSGI::HOSTNAME
|
||||
|
||||
puts UWSGI::OPT.inspect
|
||||
|
||||
timer 2 do |signum|
|
||||
puts "ciao sono un dsl ruby: #{signum} #{UWSGI::OPT.inspect}"
|
||||
end
|
||||
|
||||
timer 1,'mule1' do |signum|
|
||||
puts "1 second elapsed (signum #{signum})"
|
||||
end
|
||||
|
||||
filemon '/tmp' do |signum|
|
||||
puts "/tmp has been modified"
|
||||
end
|
||||
|
||||
cron 5,-1,-1,-1,-1 do |signum|
|
||||
puts "cron ready #{signum}"
|
||||
end
|
||||
|
||||
cron 58,-1,-1,-1,-1 do |signum|
|
||||
puts "cron ready #{signum}"
|
||||
end
|
||||
|
||||
postfork do
|
||||
puts "fork() called"
|
||||
end
|
||||
|
||||
rpc 'pippo' do
|
||||
"i am an rpc function"
|
||||
end
|
||||
|
||||
rpc 'pluto' do |x,y|
|
||||
"i am another rpc function #{x} #{y}"
|
||||
end
|
||||
|
||||
begin
|
||||
foo_func
|
||||
rescue
|
||||
end
|
||||
|
||||
puts UWSGI.cache_exists('nilkey')
|
||||
puts UWSGI.cache_exists?('nilkey')
|
||||
|
||||
UWSGI.cache_set!('foobar_key?a=1', UWSGI::OPT.inspect)
|
||||
begin
|
||||
puts UWSGI.cache_get(nil)
|
||||
rescue
|
||||
end
|
||||
puts UWSGI.cache_get('foobar_key?a=1')
|
||||
|
||||
|
||||
run lambda { |env|
|
||||
puts env.inspect
|
||||
UWSGI.setprocname("i am the uWSGI rack plugin")
|
||||
UWSGI.signal(17)
|
||||
[200, {'Content-Type'=>'text/plain'}, StringIO.new("Hello World! #{UWSGI.mem.inspect}\n")]
|
||||
}
|
||||
+74
-67
@@ -17,66 +17,73 @@ sub new {
|
||||
sub run {
|
||||
my ($self, $app) = @_;
|
||||
|
||||
my $server = IO::Socket::INET->new(LocalPort => $self->{port}, LocalAddr => $self->{host}, Listen => 100, ReuseAddr => 1);
|
||||
my $server;
|
||||
|
||||
if (exists($ENV{'UWSGI_FD'})) {
|
||||
$server = IO::Socket::UNIX->new_from_fd($ENV{'UWSGI_FD'}, '+<');
|
||||
}
|
||||
else {
|
||||
$server = IO::Socket::INET->new(LocalPort => $self->{port}, LocalAddr => $self->{host}, Listen => 100, ReuseAddr => 1);
|
||||
}
|
||||
|
||||
while ( my $client = $server->accept ) {
|
||||
|
||||
my $head = '';
|
||||
my $remains = 4 ;
|
||||
my $head = '';
|
||||
my $remains = 4;
|
||||
|
||||
while($remains) {
|
||||
$client->recv(my $buf, $remains);
|
||||
last unless $buf;
|
||||
$head.=$buf;
|
||||
$remains -= length($buf);
|
||||
}
|
||||
while($remains) {
|
||||
$client->recv(my $buf, $remains);
|
||||
last unless $buf;
|
||||
$head.=$buf;
|
||||
$remains -= length($buf);
|
||||
}
|
||||
|
||||
if (length($head) != 4) {
|
||||
$client->close ;
|
||||
next;
|
||||
}
|
||||
if (length($head) != 4) {
|
||||
$client->close;
|
||||
next;
|
||||
}
|
||||
|
||||
my ($mod1, $envsize, $mod2) = unpack('CvC', $head) ;
|
||||
my ($mod1, $envsize, $mod2) = unpack('CvC', $head);
|
||||
|
||||
unless ($envsize) {
|
||||
$client->close ;
|
||||
next;
|
||||
}
|
||||
unless ($envsize) {
|
||||
$client->close;
|
||||
next;
|
||||
}
|
||||
|
||||
$remains = $envsize ;
|
||||
my $envbuf = '' ;
|
||||
while($remains) {
|
||||
my $buf ;
|
||||
if ($remains >= 4096) {
|
||||
$client->recv($buf, 4096);
|
||||
}
|
||||
else {
|
||||
$client->recv($buf, $remains);
|
||||
}
|
||||
$remains = $envsize;
|
||||
my $envbuf = '';
|
||||
while($remains) {
|
||||
my $buf;
|
||||
if ($remains >= 4096) {
|
||||
$client->recv($buf, 4096);
|
||||
}
|
||||
else {
|
||||
$client->recv($buf, $remains);
|
||||
}
|
||||
|
||||
unless($buf) {
|
||||
$client->close ;
|
||||
next;
|
||||
}
|
||||
unless($buf) {
|
||||
$client->close;
|
||||
next;
|
||||
}
|
||||
|
||||
$envbuf.=$buf;
|
||||
$remains -= length($buf);
|
||||
}
|
||||
$envbuf.=$buf;
|
||||
$remains -= length($buf);
|
||||
}
|
||||
|
||||
if (length($envbuf) != $envsize ) {
|
||||
$client->close ;
|
||||
next;
|
||||
}
|
||||
if (length($envbuf) != $envsize ) {
|
||||
$client->close;
|
||||
next;
|
||||
}
|
||||
|
||||
my %env ;
|
||||
my %env;
|
||||
|
||||
my $i = 0;
|
||||
while($i < $envsize) {
|
||||
my $kl = unpack('v', substr($envbuf, $i, 2)) ; $i+=2;
|
||||
my $key = substr($envbuf, $i, $kl); $i+=$kl;
|
||||
my $vl = unpack('v', substr($envbuf, $i, 2)) ; $i+=2;
|
||||
$env{$key} = substr($envbuf, $i, $vl); $i+=$vl;
|
||||
}
|
||||
my $i = 0;
|
||||
while($i < $envsize) {
|
||||
my $kl = unpack('v', substr($envbuf, $i, 2)); $i+=2;
|
||||
my $key = substr($envbuf, $i, $kl); $i+=$kl;
|
||||
my $vl = unpack('v', substr($envbuf, $i, 2)); $i+=2;
|
||||
$env{$key} = substr($envbuf, $i, $vl); $i+=$vl;
|
||||
}
|
||||
|
||||
my $env = {
|
||||
%env,
|
||||
@@ -98,40 +105,40 @@ sub run {
|
||||
}
|
||||
elsif (ref $res eq 'CODE') {
|
||||
$res->(sub {
|
||||
$self->_handle_response($client, $env{'SERVER_PROTOCOL'}, $_[0]);
|
||||
});
|
||||
$self->_handle_response($client, $env{'SERVER_PROTOCOL'}, $_[0]);
|
||||
});
|
||||
}
|
||||
else {
|
||||
die "Bad response $res";
|
||||
}
|
||||
|
||||
$client->close ;
|
||||
$client->close;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
sub _handle_response {
|
||||
my ($self, $client, $protocol, $res) = @_;
|
||||
my ($self, $client, $protocol, $res) = @_;
|
||||
|
||||
$client->send($protocol.' '.$res->[0].' '.HTTP::Status::status_message( $res->[0] )."\r\n");
|
||||
$client->send($protocol.' '.$res->[0].' '.HTTP::Status::status_message( $res->[0] )."\r\n");
|
||||
|
||||
my $headers = $res->[1];
|
||||
my $hdrs = '';
|
||||
while (my ($k, $v) = splice @$headers, 0, 2) {
|
||||
$hdrs .= "$k: $v\r\n";
|
||||
}
|
||||
$hdrs .= "\r\n";
|
||||
my $headers = $res->[1];
|
||||
my $hdrs = '';
|
||||
while (my ($k, $v) = splice @$headers, 0, 2) {
|
||||
$hdrs .= "$k: $v\r\n";
|
||||
}
|
||||
$hdrs .= "\r\n";
|
||||
|
||||
$client->send($hdrs);
|
||||
$client->send($hdrs);
|
||||
|
||||
my $cb = sub { $client->send($_[0]) };
|
||||
my $body = $res->[2];
|
||||
if (defined $body) {
|
||||
Plack::Util::foreach($body, $cb);
|
||||
}
|
||||
else {
|
||||
return Plack::Util::inline_object write => $cb,close => sub { };
|
||||
}
|
||||
my $cb = sub { $client->send($_[0]) };
|
||||
my $body = $res->[2];
|
||||
if (defined $body) {
|
||||
Plack::Util::foreach($body, $cb);
|
||||
}
|
||||
else {
|
||||
return Plack::Util::inline_object write => $cb,close => sub { };
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
use POSIX;
|
||||
use IO::Socket::INET;
|
||||
use IO::Socket::INET6;
|
||||
|
||||
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);
|
||||
|
||||
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';
|
||||
@@ -0,0 +1,99 @@
|
||||
#!/bin/bash
|
||||
|
||||
# uwsgi - Use uwsgi to run python and wsgi web apps.
|
||||
#
|
||||
# chkconfig: - 85 15
|
||||
# description: Use uwsgi to run python and wsgi web apps.
|
||||
# processname: uwsgi
|
||||
|
||||
# author: Roman Vasilyev
|
||||
|
||||
# Source function library.
|
||||
. /etc/rc.d/init.d/functions
|
||||
|
||||
PATH=/opt/uwsgi:/sbin:/bin:/usr/sbin:/usr/bin
|
||||
prog=/usr/sbin/uwsgi
|
||||
|
||||
OWNER=nginx
|
||||
|
||||
NAME=uwsgi
|
||||
DESC=uwsgi
|
||||
|
||||
#DAEMON_OPTS="-s 127.0.0.1:9001 -M 4 -t 30 -A 4 -p 4 -d /var/log/uwsgi.log --pidfile /var/run/$NAME.pid --pythonpath $PYTHONPATH --module $MODULE"
|
||||
DAEMON_OPTS="-s 127.0.0.1:9001 -M 4 -t 30 -A 4 -p 16 -b 32768 -d /var/log/$NAME.log --pidfile /var/run/$NAME.pid --uid $OWNER"
|
||||
|
||||
[ -f /etc/sysconfig/uwsgi ] && . /etc/sysconfig/uwsgi
|
||||
|
||||
lockfile=/var/lock/subsys/uwsgi
|
||||
|
||||
start () {
|
||||
echo -n "Starting $DESC: "
|
||||
daemon $prog $DAEMON_OPTS
|
||||
retval=$?
|
||||
echo
|
||||
[ $retval -eq 0 ] && touch $lockfile
|
||||
return $retval
|
||||
}
|
||||
|
||||
stop () {
|
||||
echo -n "Stopping $DESC: "
|
||||
killproc $prog
|
||||
retval=$?
|
||||
echo
|
||||
[ $retval -eq 0 ] && rm -f $lockfile
|
||||
return $retval
|
||||
}
|
||||
|
||||
reload () {
|
||||
echo "Reloading $NAME"
|
||||
killproc $prog -HUP
|
||||
RETVAL=$?
|
||||
echo
|
||||
}
|
||||
|
||||
force-reload () {
|
||||
echo "Reloading $NAME"
|
||||
killproc $prog -TERM
|
||||
RETVAL=$?
|
||||
echo
|
||||
}
|
||||
|
||||
restart () {
|
||||
stop
|
||||
start
|
||||
}
|
||||
|
||||
rh_status () {
|
||||
status $prog
|
||||
}
|
||||
|
||||
rh_status_q() {
|
||||
rh_status >/dev/null 2>&1
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
rh_status_q && exit 0
|
||||
$1
|
||||
;;
|
||||
stop)
|
||||
rh_status_q || exit 0
|
||||
$1
|
||||
;;
|
||||
restart|force-reload)
|
||||
$1
|
||||
;;
|
||||
reload)
|
||||
rh_status_q || exit 7
|
||||
$1
|
||||
;;
|
||||
status)
|
||||
rh_status
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart|reload|force-reload|status}" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
exit 0
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#include <Python.h>
|
||||
|
||||
void uwsgi_cgi_load_python() {
|
||||
|
||||
Py_Initialize();
|
||||
}
|
||||
|
||||
void uwsgi_cgi_run_python(char *filename) {
|
||||
|
||||
char **e, *p;
|
||||
PyObject *k, *env_value;
|
||||
|
||||
FILE *fp = fopen(filename, "r");
|
||||
|
||||
PySys_SetArgv(1, &filename);
|
||||
|
||||
PyObject *os_module = PyImport_ImportModule("os");
|
||||
if (os_module) {
|
||||
PyObject *os_module_dict = PyModule_GetDict(os_module);
|
||||
PyObject *py_environ = PyDict_GetItemString(os_module_dict, "environ");
|
||||
if (py_environ) {
|
||||
for (e = environ; *e != NULL; e++) {
|
||||
p = strchr(*e, '=');
|
||||
if (p == NULL) continue;
|
||||
|
||||
k = PyString_FromStringAndSize(*e, (int)(p-*e));
|
||||
if (k == NULL) {
|
||||
PyErr_Print();
|
||||
continue;
|
||||
}
|
||||
|
||||
env_value = PyString_FromString(p+1);
|
||||
if (env_value == NULL) {
|
||||
PyErr_Print();
|
||||
Py_DECREF(k);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (PyObject_SetItem(py_environ, k, env_value)) {
|
||||
PyErr_Print();
|
||||
}
|
||||
|
||||
Py_DECREF(k);
|
||||
Py_DECREF(env_value);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PyRun_AnyFileEx(fp, filename, 1);
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
require 'sinatra'
|
||||
require 'socket'
|
||||
require 'json'
|
||||
|
||||
module EmperorStats
|
||||
def self.uwsgi_get_stats(server)
|
||||
parts = server.split(':')
|
||||
if parts.length > 1
|
||||
s = TCPSocket.open(parts[0], parts[1])
|
||||
else
|
||||
s = UNIXSocket.open(server)
|
||||
end
|
||||
return JSON.parse(s.read())
|
||||
end
|
||||
end
|
||||
|
||||
template = <<eof
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><%=@title%></title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="unbit">
|
||||
<link href="http://unbit.github.com/bootstrap/css/bootstrap.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */
|
||||
}
|
||||
</style>
|
||||
<link href="http://unbit.github.com/bootstrap/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a class="brand" href="#"><%=@title%></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<hr/>
|
||||
<h1>Emperor: <%=@stats['emperor']%></h1>
|
||||
<hr/>
|
||||
|
||||
<div class="row">
|
||||
<div class="span8">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>name</th><th>pid</th><th>first run</th>
|
||||
<th>last respawn</th>
|
||||
<th>last heartbeat</th>
|
||||
<th>loyal</th>
|
||||
<th>respawns</th>
|
||||
<% if @stats['emperor_tyrant'] == 1 %>
|
||||
<th>uid</th>
|
||||
<th>gid</th>
|
||||
<% end %>
|
||||
</tr>
|
||||
</thead>
|
||||
<% for vassal in @stats['vassals'] %>
|
||||
<tr>
|
||||
<td><%=vassal['id']%></td>
|
||||
<td><%=vassal['pid']%></td>
|
||||
<td><%=Time.at(vassal['first_run']).strftime("%d %b %Y %H:%M:%S")%></td>
|
||||
<td><%=Time.at(vassal['last_run']).strftime("%d %b %Y %H:%M:%S")%></td>
|
||||
<td><% if vassal['last_heartbeat'] > 0 %><%=Time.at(vassal['last_heartbeat']).strftime("%d %b %Y %H:%M:%S")%><% end %></td>
|
||||
<td><% if vassal['loyal'] > 0 %><%=Time.at(vassal['last_loyal']).strftime("%d %b %Y %H:%M:%S")%><% end %></td>
|
||||
<td><%=vassal['respawns']%></td>
|
||||
<% if @stats['emperor_tyrant'] == 1 %>
|
||||
<td><%=vassal['uid']%></td>
|
||||
<td><%=vassal['gid']%></td>
|
||||
<% end %>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="span4">
|
||||
<h3>blacklist</h3>
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr><th>name</th><th>throttle</th></tr>
|
||||
<% for bli in @stats['blacklist'] %>
|
||||
<tr>
|
||||
<td><%=bli['id']%></td>
|
||||
<td><%=bli['throttle_level']%></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script src="http://unbit.github.com/jquery-1.7.2.min.js" type="text/javascript"></script>
|
||||
<script src="http://unbit.github.com/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
|
||||
</body>
|
||||
</html>
|
||||
eof
|
||||
|
||||
get '/' do
|
||||
@stats = EmperorStats::uwsgi_get_stats(ENV['EMPEROR'])
|
||||
@title = 'uWSGI Emperor monitor'
|
||||
erb template
|
||||
end
|
||||
|
||||
run Sinatra::Application
|
||||
@@ -0,0 +1,33 @@
|
||||
# uwsgi --master --chdir /opt/graphite/webapp/graphite --module graphite_uwsgi ...
|
||||
#
|
||||
#
|
||||
# this module will update a carbon server (used by the graphite tool: http://graphite.wikidot.com/)
|
||||
# with requests count made by a Django app (and can track graphite itself as it is a Django app ;)
|
||||
#
|
||||
#
|
||||
|
||||
import os
|
||||
import uwsgi
|
||||
import time
|
||||
from django.core.handlers.wsgi import WSGIHandler
|
||||
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
|
||||
|
||||
CARBON_SERVER = "127.0.0.1:2003"
|
||||
|
||||
def update_carbon(signum):
|
||||
# connect to the carbon server
|
||||
carbon_fd = uwsgi.connect(CARBON_SERVER)
|
||||
# send data to the carbon server
|
||||
uwsgi.send(carbon_fd, "uwsgi.%s.requests %d %d\n" % (uwsgi.hostname, uwsgi.total_requests(), int(time.time())))
|
||||
# close the connection with the carbon server
|
||||
uwsgi.close(carbon_fd)
|
||||
|
||||
# register a new uwsgi signal (signum: 17)
|
||||
uwsgi.register_signal(17, '', update_carbon)
|
||||
|
||||
# attach a timer of 10 seconds to signal 17
|
||||
uwsgi.add_timer(17, 10)
|
||||
|
||||
# the Django app
|
||||
application = WSGIHandler()
|
||||
@@ -0,0 +1,15 @@
|
||||
use IO::Socket::INET;
|
||||
|
||||
my $s = IO::Socket::INET->new(PeerAddr => '127.0.0.1', PeerPort => $ARGV[0]);
|
||||
|
||||
my $mountpoint = $ARGV[1];
|
||||
my $app = $ARGV[2];
|
||||
|
||||
my $uwsgi_appid = pack('v', length('UWSGI_APPID')).'UWSGI_APPID'.pack('v', length($mountpoint)).$mountpoint;
|
||||
my $uwsgi_script = pack('v', length('UWSGI_SCRIPT')).'UWSGI_SCRIPT'.pack('v', length($app)).$app;
|
||||
|
||||
$s->send(pack('CvC', 5, length($uwsgi_appid.$uwsgi_script),0).$uwsgi_appid.$uwsgi_script);
|
||||
|
||||
while((my $cnt = $s->recv(my $buf, 4096))> 0) {
|
||||
print $buf;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import django
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.conf import settings
|
||||
import os
|
||||
import sys
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Runs this project as a uWSGI application. Requires the uwsgi binary in system path."
|
||||
|
||||
http_port = '8000'
|
||||
socket_addr = None
|
||||
|
||||
def handle(self, *args, **options):
|
||||
for arg in args:
|
||||
k,v = arg.split('=')
|
||||
if k == 'http':
|
||||
if self.http_port:
|
||||
self.http_port = v
|
||||
elif k == 'socket':
|
||||
self.http_port = None
|
||||
self.socket_addr = v
|
||||
|
||||
# load http and python plugin: first the specific version, otherwise try with the generic one
|
||||
if self.http_port:
|
||||
os.environ['UWSGI_PLUGINS'] = 'http,python%d%d:python' % (sys.version_info[0], sys.version_info[1])
|
||||
else:
|
||||
os.environ['UWSGI_PLUGINS'] = 'python%d%d:python' % (sys.version_info[0], sys.version_info[1])
|
||||
|
||||
# load the Django WSGI handler
|
||||
os.environ['UWSGI_MODULE'] = 'django.core.handlers.wsgi:WSGIHandler()'
|
||||
# DJANGO settings
|
||||
if options['settings']:
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = options['settings']
|
||||
else:
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
|
||||
|
||||
# bind the http server to the default port
|
||||
if self.http_port:
|
||||
os.environ['UWSGI_HTTP'] = ':%s' % self.http_port
|
||||
elif self.socket_addr:
|
||||
os.environ['UWSGI_SOCKET'] = self.socket_addr
|
||||
|
||||
# map admin static files
|
||||
os.environ['UWSGI_STATIC_MAP'] = '%s=%s' % (settings.ADMIN_MEDIA_PREFIX, os.path.join(django.__path__[0], 'contrib', 'admin', 'media'))
|
||||
# remove sockets/pidfile at exit
|
||||
os.environ['UWSGI_VACUUM'] = '1'
|
||||
# retrieve/set the PythonHome
|
||||
os.environ['UWSGI_PYHOME'] = sys.prefix
|
||||
# increase buffer size a bit
|
||||
os.environ['UWSGI_BUFFER_SIZE'] = '8192'
|
||||
# add threads for concurrency
|
||||
os.environ['UWSGI_THREADS'] = '8'
|
||||
# enable the master process
|
||||
os.environ['UWSGI_MASTER'] = '1'
|
||||
# use uWSGI python module aliasing to fix the PYTHONPATH
|
||||
os.environ['UWSGI_PYMODULE_ALIAS'] = '%s=./' % os.path.basename(os.getcwd())
|
||||
# exec the uwsgi binary
|
||||
os.execvp('uwsgi', ('uwsgi',))
|
||||
|
||||
def usage(self, subcomand):
|
||||
return r"""
|
||||
run this project on the uWSGI server
|
||||
|
||||
http=PORT run the embedded http server on port PORT
|
||||
socket=ADDR bind the uwsgi server on address ADDR (this will disable the http server)
|
||||
"""
|
||||
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use Crypt::OpenSSL::RSA;
|
||||
use IO::Socket::INET;
|
||||
|
||||
open PK,$ARGV[3];
|
||||
my @lines = <PK>;
|
||||
close PK;
|
||||
|
||||
$rsa_priv = Crypt::OpenSSL::RSA->new_private_key(join('',@lines));
|
||||
|
||||
my %items = {};
|
||||
|
||||
$items{'key'} = $ARGV[1];
|
||||
$items{'address'} = $ARGV[2];
|
||||
|
||||
my $uwsgi_pkt = '';
|
||||
|
||||
foreach(keys %items) {
|
||||
$uwsgi_pkt .= pack('v', length($_)).$_.pack('v', length($items{$_})).$items{$_};
|
||||
}
|
||||
|
||||
my $unix_check = time();
|
||||
|
||||
$uwsgi_pkt .= pack('v', 4).'unix'.pack('v', length($unix_check)).$unix_check;
|
||||
|
||||
my $signature = $rsa_priv->sign($uwsgi_pkt);
|
||||
|
||||
$uwsgi_pkt .= pack('v', 4).'sign'.pack('v', length($signature)).$signature;
|
||||
|
||||
|
||||
my $udp = new IO::Socket::INET(PeerAddr => $ARGV[0], Proto => 'udp');
|
||||
|
||||
$udp->send(pack('CvC', 224, length($uwsgi_pkt), 0).$uwsgi_pkt);
|
||||
|
||||
print ''.(length($uwsgi_pkt)+4).' bytes sent to '.$ARGV[0]."\n";
|
||||
@@ -0,0 +1,11 @@
|
||||
from tasksconsumer import enqueue
|
||||
|
||||
def application(env, sr):
|
||||
|
||||
sr('200 OK', [('Content-Type','text/html')])
|
||||
|
||||
enqueue(queue='fast', pippo='pluto')
|
||||
|
||||
return "Task enqueued"
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
from tasksconsumer import *
|
||||
|
||||
@queueconsumer('fast', 4)
|
||||
def fast_queue(arguments):
|
||||
print "fast", arguments
|
||||
|
||||
@queueconsumer('slow')
|
||||
def slow_queue(arguments):
|
||||
print "foobar", arguments
|
||||
@@ -0,0 +1,44 @@
|
||||
from uwsgidecorators import *
|
||||
import Queue
|
||||
from threading import Thread
|
||||
|
||||
queues = {}
|
||||
|
||||
class queueconsumer(object):
|
||||
|
||||
def __init__(self, name, num=1, **kwargs):
|
||||
self.name = name
|
||||
self.num = num
|
||||
self.queue = Queue.Queue()
|
||||
self.threads = []
|
||||
self.func = None
|
||||
queues[self.name] = self
|
||||
|
||||
|
||||
@staticmethod
|
||||
def consumer(self):
|
||||
while True:
|
||||
req = self.queue.get()
|
||||
print req
|
||||
self.func(req)
|
||||
self.queue.task_done()
|
||||
|
||||
def __call__(self, f):
|
||||
self.func = f
|
||||
for i in range(self.num):
|
||||
t = Thread(target=self.consumer,args=(self,))
|
||||
self.threads.append(t)
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
@spool
|
||||
def spooler_enqueuer(arguments):
|
||||
if 'queue' in arguments:
|
||||
queue = arguments['queue']
|
||||
queues[queue].queue.put(arguments)
|
||||
else:
|
||||
raise Exception("You have to specify a queue name")
|
||||
|
||||
|
||||
def enqueue(*args, **kwargs):
|
||||
return spooler_enqueuer.spool(*args, **kwargs)
|
||||
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use IO::Socket::INET;
|
||||
|
||||
my %items = {};
|
||||
|
||||
$items{'key'} = $ARGV[1];
|
||||
$items{'address'} = $ARGV[2];
|
||||
|
||||
my $uwsgi_pkt = '';
|
||||
|
||||
foreach(keys %items) {
|
||||
$uwsgi_pkt .= pack('v', length($_)).$_.pack('v', length($items{$_})).$items{$_};
|
||||
}
|
||||
|
||||
my $udp = new IO::Socket::INET(PeerAddr => $ARGV[0], Proto => 'udp');
|
||||
|
||||
$udp->send(pack('CvC', 224, length($uwsgi_pkt), 0).$uwsgi_pkt);
|
||||
|
||||
print ''.(length($uwsgi_pkt)+4).' bytes sent to '.$ARGV[0]."\n";
|
||||
@@ -0,0 +1,17 @@
|
||||
# uWSGI - manage uWSGI application server
|
||||
#
|
||||
|
||||
description "uWSGI"
|
||||
|
||||
start on runlevel [2345]
|
||||
stop on runlevel [!2345]
|
||||
|
||||
respawn
|
||||
|
||||
env LOGTO=/tmp/uwsgi.log
|
||||
env BINPATH=/home/foo/uwsgi/uwsgi
|
||||
|
||||
# --no-orphans avoid workers without master
|
||||
# --die-on-term could be a good idea
|
||||
exec $BINPATH --no-orphans --socket :3033 --uid 1001 --gid 1001 --limit-as 256 -w simple_app --logto $LOGTO -M -p 4
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
COMMAND=./uwsgi
|
||||
CONFIG_FILE=
|
||||
|
||||
|
||||
FIRST=0
|
||||
|
||||
for ARG in $@;do
|
||||
if [ $FIRST -eq 0 ];then
|
||||
FIRST=1
|
||||
else
|
||||
ARGS="$ARGS $ARG"
|
||||
fi
|
||||
done
|
||||
|
||||
export UWSGI_INHERIT=CONFIG_FILE
|
||||
export UWSGI_PYRUN=$1
|
||||
export UWSGI_PYARGV=$ARGS
|
||||
|
||||
exec $COMMAND
|
||||
+303
-372
@@ -1,403 +1,334 @@
|
||||
# Copyright 2009 Unbit S.a.s. <info@unbit.it>
|
||||
# see the COPYRIGHT file
|
||||
require 'rubygems'
|
||||
require 'socket'
|
||||
begin
|
||||
require 'bundler/setup'
|
||||
rescue LoadError
|
||||
end
|
||||
require 'rack'
|
||||
require 'rack/content_length'
|
||||
require 'rack/rewindable_input'
|
||||
require 'stringio'
|
||||
|
||||
$stdout.sync = true
|
||||
options = {}
|
||||
require 'optparse'
|
||||
|
||||
if Process.uid == 0
|
||||
puts "Never run uRack as root !!!"
|
||||
exit
|
||||
options = {
|
||||
:processes => 1,
|
||||
:threads => 1,
|
||||
:master => false,
|
||||
:logging => true,
|
||||
:static => true,
|
||||
:config => nil,
|
||||
:cachehack => false
|
||||
}
|
||||
|
||||
opts = OptionParser.new do |opts|
|
||||
|
||||
opts.on("-p", "--processes=nproc", Integer, '') { |p| options[:processes] = p }
|
||||
opts.on("-t", "--threads=nthreads", Integer, '') { |t| options[:threads] = t }
|
||||
opts.on("-M", "--master", '') { options[:master] = true }
|
||||
opts.on("-L", "--no-logging", '') { options[:logging] = false }
|
||||
opts.on("-S", "--no-static", '') { options[:static] = false }
|
||||
opts.on("-C", "--cache-hack", '') { options[:cachehack] = true }
|
||||
|
||||
opts.parse! ARGV
|
||||
end
|
||||
|
||||
$stderr.puts "[#{Time.new}] starting uRack"
|
||||
if ARGV[0]
|
||||
options[:config] = ARGV[0]
|
||||
end
|
||||
|
||||
def human_round(float)
|
||||
(float * (10 ** 2)).round / (10 ** 2).to_f
|
||||
end
|
||||
|
||||
unless ENV.has_key?('UNBIT_RACK_PATH')
|
||||
if File.exists?("#{ARGV.last}/config/environment.rb")
|
||||
RAILS_ROOT = String.new(ARGV.last)
|
||||
else
|
||||
RAILS_ROOT = String.new(Dir.getwd)
|
||||
end
|
||||
options[:sockname] = '/tmp/uwsgi.sock'
|
||||
options[:sock_chmod] = 0
|
||||
options[:stderr_logfile] = nil
|
||||
else
|
||||
$domain = ARGV.last.gsub('[','').gsub(']','')
|
||||
$unbit_log_base = "[uRack/Unbit on #{$domain}]"
|
||||
RAILS_ROOT = String.new(ENV['UNBIT_RACK_PATH'])
|
||||
options[:unbit] = true
|
||||
$limit_as = human_round(Process.getrlimit(Process::RLIMIT_AS)[1].to_f/1024/1024)
|
||||
puts "#{$unbit_log_base} process address space limit is #{$limit_as} MB"
|
||||
$uidsec_size = syscall(357,0,0)
|
||||
puts "#{$unbit_log_base} need #{$uidsec_size} bytes to store uidsec_struct..."
|
||||
$uidsec = '1' * $uidsec_size
|
||||
puts "#{$unbit_log_base} uidsec_struct allocated."
|
||||
end
|
||||
|
||||
|
||||
options[:environment] = (ENV['RAILS_ENV'] || "development").dup
|
||||
options[:processes] = 1
|
||||
options[:serve_file] = nil
|
||||
options[:max_input_size] = 8
|
||||
options[:unbit_debug] = false
|
||||
options[:master] = true
|
||||
options[:gc_freq] = nil
|
||||
|
||||
require 'optparse'
|
||||
|
||||
ARGV.clone.options do |opts|
|
||||
opts.on('-s', '--socket=socket', String, 'Unix socket path.', 'Default: /tmp/uwsgi.sock') { |v|
|
||||
options[:sockname] = v
|
||||
}
|
||||
opts.on('-C','--chmod','chmod to 666 the unix socket.') {
|
||||
options[:sock_chmod] = true
|
||||
}
|
||||
opts.on('-F','--serve-file','serve static file.') {
|
||||
options[:serve_file] = true
|
||||
}
|
||||
opts.on('-p', '--processes=processes', Integer, 'Number of processes to spawn.', 'Default: 1') {|v|
|
||||
options[:processes] = v
|
||||
}
|
||||
opts.on('-g', '--gc-freq=requests', Integer, 'Number of requests between GC.', 'Default: 1') {|v|
|
||||
options[:gc_freq] = v
|
||||
}
|
||||
opts.on('-d', '--daemon=logfile', 'Put processes in background.', 'Default: all processes stay in foreground') {|v|
|
||||
options[:stderr_logfile] = v
|
||||
}
|
||||
opts.on('-i', '--max-input-size=size', 'Max POST data size (in Kbyte). Bigger data goes into a temporary file.', 'Default: 8') {|v|
|
||||
options[:max_input_size] = v
|
||||
}
|
||||
opts.on('-D', '--unbit-debug', 'Enable debug-level logging.', 'Default: disabled') {|v|
|
||||
options[:unbit_debug] = true
|
||||
}
|
||||
opts.on('-M', '--master-process', 'Enable the master process manager.', 'Default: disabled') {|v|
|
||||
options[:master] = true
|
||||
}
|
||||
opts.on("-e", '--environment=name', String, 'Specifies the environment to run this server under (test/development/production).','Default: development') { |v|
|
||||
options[:environment] = v
|
||||
}
|
||||
|
||||
opts.separator ""
|
||||
|
||||
opts.parse!
|
||||
end
|
||||
|
||||
puts "[#{Time.new}] uRack: loading app [#{RAILS_ROOT}]..."
|
||||
starttime = Time.now
|
||||
require RAILS_ROOT + "/config/environment"
|
||||
|
||||
options[:app_name] = RAILS_ROOT
|
||||
|
||||
require 'socket'
|
||||
require 'rubygems'
|
||||
require 'rack'
|
||||
require 'rack/utils'
|
||||
require 'rack/content_length'
|
||||
$requests = 0
|
||||
$workers = Array.new
|
||||
$mywid = 0
|
||||
|
||||
module Rack
|
||||
module Handler
|
||||
class Unbit
|
||||
class Tempfile < ::Tempfile
|
||||
def _close
|
||||
@tmpfile.close if @tmpfile
|
||||
@data[1] = nil if @data
|
||||
@tmpfile = nil
|
||||
end
|
||||
end
|
||||
def self.run(app, options={})
|
||||
|
||||
# parse the socket options
|
||||
# note: on unbit we use the stdin as communication socket
|
||||
|
||||
server = nil
|
||||
master_pid = Process.pid
|
||||
options[:processes] ||= 1
|
||||
class RailsCachingHack
|
||||
def initialize app
|
||||
@app = app
|
||||
end
|
||||
|
||||
unless options[:unbit]
|
||||
begin
|
||||
::File.delete(options[:sockname])
|
||||
rescue
|
||||
end
|
||||
def stripuri(uri)
|
||||
uri = uri.split('/')
|
||||
uri.slice!(1)
|
||||
val = uri.join('/')
|
||||
end
|
||||
def call env
|
||||
env['PATH_INFO'] = stripuri(env['PATH_INFO']) if env['PATH_INFO']
|
||||
env['REQUEST_URI'] = stripuri(env['REQUEST_URI']) if env['REQUEST_URI']
|
||||
env['REQUEST_URI'] = '/' if env['REQUEST_URI'] == ''
|
||||
@app.call env
|
||||
end
|
||||
end
|
||||
|
||||
server = UNIXServer.new(options[:sockname])
|
||||
if options[:sock_chmod]
|
||||
::File.chmod(0666, options[:sockname])
|
||||
end
|
||||
module Handler
|
||||
class Unbit
|
||||
|
||||
if options[:stderr_logfile]
|
||||
cwd = Dir.getwd
|
||||
Process.daemon
|
||||
Dir.chdir(cwd)
|
||||
$stdout.reopen(options[:stderr_logfile],'a')
|
||||
$stderr.reopen(options[:stderr_logfile],'a')
|
||||
# log files need to be unbuffered !
|
||||
$stdout.sync = true
|
||||
$stderr.sync = true
|
||||
# pid is changed after the .daemon call
|
||||
master_pid = Process.pid
|
||||
end
|
||||
else
|
||||
server = UNIXServer.for_fd($stdin.fileno)
|
||||
end
|
||||
def self.run(app, options={})
|
||||
server = UNIXServer.for_fd(0)
|
||||
|
||||
$workers = Array.new
|
||||
can_spawn = true
|
||||
if options[:master]
|
||||
$0 = 'uRack master'
|
||||
$workers[0] = Process.pid
|
||||
ulog("master process enabled (pid: #{$workers[0]})")
|
||||
$workers[1] = Process.fork
|
||||
if $workers[1].to_i > 0
|
||||
ulog("spawned worker 1 (pid: #{$workers[1]})")
|
||||
elsif $workers[1].to_i == 0
|
||||
$0 = "uRack worker 1"
|
||||
$mywid = 1
|
||||
can_spawn = false
|
||||
end
|
||||
else
|
||||
$0 = 'uRack worker 1'
|
||||
$workers[0] = nil
|
||||
$workers[1] = Process.pid
|
||||
$mywid = 1
|
||||
ulog("spawned worker 1 (pid: #{$workers[1]})")
|
||||
end
|
||||
|
||||
if options[:master]
|
||||
$0 = "uRack #{ARGV.last}"
|
||||
pid = Process.fork
|
||||
if pid.to_i > 0
|
||||
puts "[#{Time.new}] uRack: spawned rack worker 1 (pid: #{pid})"
|
||||
$workers[1] = pid ;
|
||||
end
|
||||
end
|
||||
|
||||
# the check on master pid is necessary
|
||||
# without it the first worker will execute this part
|
||||
if options[:processes] > 1 and Process.pid == master_pid
|
||||
for p in 2..options[:processes]
|
||||
pid = Process.fork
|
||||
break if pid.to_i == 0
|
||||
puts "[#{Time.new}] uRack: spawned rack worker #{p} (pid: #{pid})"
|
||||
$workers[p] = pid ;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
# am i the master ?
|
||||
if options[:master] and Process.pid == master_pid
|
||||
Signal.trap('TERM') do
|
||||
puts "[#{Time.new}] uRack: gracefully killing uRack"
|
||||
for wid in 1..options[:processes]
|
||||
Process.kill('TERM', $workers[wid]);
|
||||
end
|
||||
exit 0;
|
||||
end
|
||||
Signal.trap('QUIT') do
|
||||
puts "[#{Time.new}] uRack: brutally killing uRack"
|
||||
for wid in 1..options[:processes]
|
||||
Process.kill('INT', $workers[wid]);
|
||||
end
|
||||
exit 0;
|
||||
end
|
||||
puts "[#{Time.new}] uRack: the master process manager is alive."
|
||||
while 1
|
||||
pid = Process.waitpid
|
||||
puts "[#{Time.new}] uRack: worker died ! (pid: #{pid})"
|
||||
newpid = Process.fork
|
||||
break if newpid.to_i == 0
|
||||
puts "[#{Time.new}] uRack: respawned rack worker (pid: #{newpid})"
|
||||
for wid in 1..options[:processes]
|
||||
if $workers[wid] == pid
|
||||
$workers[wid] = newpid
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if Process.pid != master_pid
|
||||
$0 = $0.gsub(/^uRack/,'urack')
|
||||
Signal.trap("TERM") do
|
||||
puts "[#{Time.new}] uRack: grecefully killing process #{Process.pid}..."
|
||||
if $in_request == 0
|
||||
puts "[#{Time.new}] uRack: goodbye to process #{Process.pid}"
|
||||
exit 0
|
||||
end
|
||||
$manage_next_request = nil
|
||||
end
|
||||
Signal.trap('INT') do
|
||||
puts "[#{Time.new}] uRack: brutally killing process #{Process.pid}..."
|
||||
exit 0
|
||||
end
|
||||
Signal.trap('PIPE') do
|
||||
puts "[#{Time.new}] uRack: the webserver (or the client) has closed the connection with process #{Process.pid} !!!"
|
||||
end
|
||||
end
|
||||
|
||||
max_input_size = options[:max_input_size].to_i * 1024
|
||||
requests = 0
|
||||
|
||||
null_post = StringIO.new('')
|
||||
|
||||
options[:app_name] ||= Dir.getwd
|
||||
|
||||
app = Rack::ContentLength.new(app)
|
||||
|
||||
$manage_next_request = true
|
||||
|
||||
if options[:gc_freq].to_i > 1
|
||||
GC.disable
|
||||
end
|
||||
|
||||
while $manage_next_request
|
||||
|
||||
$in_request = 0
|
||||
client = server.accept
|
||||
$in_request = 1
|
||||
|
||||
timed_out = false
|
||||
|
||||
ver, size, arg1 = client.recvfrom(4)[0].unpack('CvC')
|
||||
|
||||
vars = client.recvfrom(size)[0]
|
||||
env = Hash.new
|
||||
|
||||
i = 0
|
||||
while i < size
|
||||
kl = vars[i, 2].unpack('v')[0]
|
||||
i = i + 2
|
||||
key = vars[i, kl]
|
||||
i = i + kl
|
||||
vl = vars[i, 2].unpack('v')[0]
|
||||
i = i + 2
|
||||
value = vars[i, vl]
|
||||
i = i + vl
|
||||
env[key] = value
|
||||
end
|
||||
|
||||
rack_input = null_post
|
||||
|
||||
env.delete 'CONTENT_LENGTH' if env['CONTENT_LENGTH'] == ''
|
||||
|
||||
if env['CONTENT_LENGTH'].to_i > 0
|
||||
cl = env['CONTENT_LENGTH'].to_i
|
||||
|
||||
if cl <= max_input_size
|
||||
poststr = ''
|
||||
while poststr.size < cl
|
||||
poststr = poststr + client.recvfrom(cl-poststr.size)[0] ;
|
||||
end
|
||||
|
||||
rack_input = StringIO.new(poststr)
|
||||
else
|
||||
rack_input = Tempfile.new('UnbitRack')
|
||||
rack_input.chmod(0000)
|
||||
|
||||
bytes_read = 0
|
||||
while bytes_read < cl
|
||||
buf = client.recvfrom(4096)[0]
|
||||
rack_input.write(buf)
|
||||
bytes_read += buf.size
|
||||
end
|
||||
rack_input.rewind
|
||||
end
|
||||
end
|
||||
|
||||
env["SCRIPT_NAME"] = ""
|
||||
env.update({"rack.version" => [0,1],
|
||||
"rack.input" => rack_input,
|
||||
"rack.errors" => $stderr,
|
||||
"rack.multithread" => false,
|
||||
"rack.multiprocess" => true,
|
||||
"rack.run_once" => false,
|
||||
"rack.url_scheme" => "http"
|
||||
})
|
||||
|
||||
env["QUERY_STRING"] ||= ""
|
||||
env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
|
||||
env["REQUEST_PATH"] ||= "/"
|
||||
|
||||
|
||||
begin
|
||||
#puts env.inspect
|
||||
$start_of_request = Time.new
|
||||
status, headers, body = app.call(env)
|
||||
$speed = Time.new - $start_of_request
|
||||
|
||||
client.print "#{env["HTTP_VERSION"]} #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]}\r\n"
|
||||
headers.each {|k,vs|
|
||||
vs.split("\n").each { |v|
|
||||
client.print "#{k}: #{v}\r\n"
|
||||
}
|
||||
}
|
||||
client.print "\r\n"
|
||||
client.flush
|
||||
|
||||
body.each {|part|
|
||||
client.print part
|
||||
client.flush
|
||||
}
|
||||
rescue Errno::EPIPE
|
||||
puts "[#{Time.new}] uRack: the webserver (or the client) has closed the connection with process #{Process.pid} !!!"
|
||||
timed_out = true
|
||||
ensure
|
||||
if rack_input.respond_to? :unlink
|
||||
rack_input.unlink
|
||||
end
|
||||
unless rack_input.closed?
|
||||
rack_input.close
|
||||
end
|
||||
client.close
|
||||
requests = requests+1
|
||||
# logging
|
||||
begin
|
||||
# the syscall 356 is only available on unbit kernels
|
||||
# other systems need to use the proc file way
|
||||
# stat = ::File.open('/proc/self/stat', 'r')
|
||||
# procline = stat.readline
|
||||
# statd = procline.split /\s+/
|
||||
# stat.close
|
||||
$stderr.puts "[#{Time.new}] uRack: [#{options[:app_name]}] req: #{requests} ip: #{env['REMOTE_ADDR']} pid: #{Process.pid} as: #{human_round(syscall(356).to_f/1024/1024)} MB => #{env['REQUEST_METHOD']} #{env['REQUEST_URI']} in #{$speed} secs [#{status}]#{' TIMED OUT !!!' if timed_out}"
|
||||
rescue
|
||||
$stderr.puts "[#{Time.new}] uRack: [#{options[:app_name]}] req: #{requests} unable to get /proc/self/stat or syscall 356"
|
||||
end
|
||||
if syscall(357, $uidsec, 0) == $uidsec_size
|
||||
if $uidsec[120..123].unpack('i')[0] > 0
|
||||
$stderr.puts "[#{Time.new}] uRack: found a memory allocation error for request #{requests} (pid: #{Process.pid}). Better to kill myself..."
|
||||
$manage_next_request = nil
|
||||
end
|
||||
end
|
||||
$uidsec = '1' * $uidsec_size
|
||||
if options[:unbit_debug]
|
||||
current_as = human_round( (syscall(356).to_f/1024/1024) - $last_as )
|
||||
$stderr.puts "#{$unbit_log_base} resource status after request #{requests}: AS for this request: #{current_as} MB | OBJ for this request: #{ObjectSpace.each_object {} - $last_obj} | OBJ total: #{ObjectSpace.each_object {}}"
|
||||
$last_as = human_round(syscall(356).to_f/1024/1024) ;
|
||||
$last_obj = ObjectSpace.each_object {}
|
||||
end
|
||||
if options[:gc_freq].to_i > 1
|
||||
if requests % options[:gc_freq].to_i == 0
|
||||
$stderr.puts "[#{Time.new}] uRack: [#{options[:app_name]}] calling GC for pid #{Process.pid} after #{requests} requests."
|
||||
GC.enable ; GC.start ; GC.disable
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
puts "[#{Time.new}] uRack: goodbye to process #{Process.pid}"
|
||||
if options[:processes] > 1 and can_spawn
|
||||
for p in 2..options[:processes]
|
||||
$workers[p] = Process.fork
|
||||
if $workers[p].to_i == 0
|
||||
$0 = "uRack worker #{p}"
|
||||
$mywid = p
|
||||
break
|
||||
elsif $workers[p].to_i > 0
|
||||
ulog("spawned worker #{p} (pid: #{$workers[p]})")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# am i the master ?
|
||||
if options[:master] and Process.pid == $workers[0]
|
||||
while 1
|
||||
i_am_a_child = false
|
||||
pid = Process.waitpid
|
||||
for wid in 1..options[:processes]
|
||||
if $workers[wid] == pid
|
||||
ulog("worker #{wid} died ! (pid: #{pid})")
|
||||
$workers[wid] = Process.fork
|
||||
if $workers[wid].to_i == 0
|
||||
$0 = "uRack worker #{wid}"
|
||||
i_am_a_child = true
|
||||
$mywid = wid
|
||||
break
|
||||
elsif $workers[wid].to_i > 0
|
||||
ulog("respawned worker #{wid} (pid: #{$workers[wid]})")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
break if i_am_a_child
|
||||
end
|
||||
end
|
||||
|
||||
if options[:threads] > 2
|
||||
for t in 2..options[:threads]
|
||||
wt = Thread.new do
|
||||
ulog("spawning thread #{t} on worker #{$mywid}")
|
||||
while client = server.accept
|
||||
serve client, app, options
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
while client = server.accept
|
||||
serve client, app, options
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def self.serve(client, app, options)
|
||||
|
||||
speed = Time.now
|
||||
head, sender = client.recvfrom(4)
|
||||
|
||||
unless head
|
||||
client.close
|
||||
return
|
||||
end
|
||||
|
||||
mod1, size, mod2 = head.unpack('CvC')
|
||||
|
||||
if size == 0 or size.nil?
|
||||
client.close
|
||||
return
|
||||
end
|
||||
|
||||
vars, sender = client.recvfrom(size)
|
||||
|
||||
if vars.length != size
|
||||
client.close
|
||||
return
|
||||
end
|
||||
|
||||
env = Hash.new
|
||||
|
||||
i = 0
|
||||
while i < size
|
||||
kl = vars[i, 2].unpack('v')[0]
|
||||
i = i + 2
|
||||
key = vars[i, kl]
|
||||
i = i + kl
|
||||
vl = vars[i, 2].unpack('v')[0]
|
||||
i = i + 2
|
||||
value = vars[i, vl]
|
||||
i = i + vl
|
||||
env[key] = value
|
||||
end
|
||||
|
||||
|
||||
|
||||
env.delete "HTTP_CONTENT_LENGTH"
|
||||
env.delete "HTTP_CONTENT_TYPE"
|
||||
|
||||
env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
|
||||
env["QUERY_STRING"] ||= ""
|
||||
env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
|
||||
env["REQUEST_PATH"] ||= "/"
|
||||
env.delete "PATH_INFO" if env["PATH_INFO"] == ""
|
||||
env.delete "CONTENT_TYPE" if env["CONTENT_TYPE"] == ""
|
||||
env.delete "CONTENT_LENGTH" if env["CONTENT_LENGTH"] == ""
|
||||
|
||||
|
||||
if env["CONTENT_LENGTH"].to_i > 4096
|
||||
rack_input = Rack::RewindableInput::Tempfile.new('Rack_unbit_Input')
|
||||
rack_input.chmod(0000)
|
||||
rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
|
||||
rack_input.binmode
|
||||
rack_input.unlink
|
||||
|
||||
remains = env["CONTENT_LENGTH"].to_i
|
||||
while remains > 0
|
||||
if remains >= 4096
|
||||
buf, sender = client.recvfrom(4096)
|
||||
else
|
||||
buf, sender = client.recvfrom(remains)
|
||||
end
|
||||
|
||||
if buf.length == 0
|
||||
break
|
||||
end
|
||||
|
||||
rack_input.write( buf )
|
||||
remains -= buf.length
|
||||
end
|
||||
|
||||
elsif env["CONTENT_LENGTH"].to_i > 0
|
||||
rack_input = StringIO.new(client.recvfrom(env["CONTENT_LENGTH"].to_i)[0])
|
||||
else
|
||||
rack_input = StringIO.new('')
|
||||
end
|
||||
|
||||
rack_input.rewind
|
||||
|
||||
env.update({"rack.version" => [1,1],
|
||||
"rack.input" => rack_input,
|
||||
"rack.errors" => $stderr,
|
||||
|
||||
"rack.multithread" => false,
|
||||
"rack.multiprocess" => true,
|
||||
"rack.run_once" => false,
|
||||
|
||||
"rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http"
|
||||
})
|
||||
|
||||
app = Rack::ContentLength.new(app)
|
||||
|
||||
disconnected = false
|
||||
begin
|
||||
status, headers, body = app.call(env)
|
||||
begin
|
||||
send_headers client, env["HTTP_VERSION"] ,status, headers
|
||||
send_body client, body
|
||||
ensure
|
||||
body.close if body.respond_to? :close
|
||||
end
|
||||
rescue Errno::EPIPE, Errno::ECONNRESET
|
||||
disconnected = true
|
||||
ensure
|
||||
rack_input.close
|
||||
client.close
|
||||
end
|
||||
$requests = $requests+1
|
||||
|
||||
ulog("req: #{$requests} ip: #{env['REMOTE_ADDR']} pid: #{Process.pid} as: #{human_round(syscall(356).to_f/1024/1024)} MB => #{env['REQUEST_METHOD']} #{env['REQUEST_URI']} in #{Time.now-speed} secs [#{status}]#{' DISCONNECTED !!!' if disconnected}") if options[:logging]
|
||||
end
|
||||
|
||||
def self.send_headers(client, protocol, status, headers)
|
||||
client.print "#{protocol} #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]}\r\n"
|
||||
headers.each { |k, vs|
|
||||
vs.split("\n").each { |v|
|
||||
client.print "#{k}: #{v}\r\n"
|
||||
}
|
||||
}
|
||||
client.print "\r\n"
|
||||
client.flush
|
||||
end
|
||||
|
||||
def self.send_body(client, body)
|
||||
body.each { |part|
|
||||
client.print part
|
||||
client.flush
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def ulog(message)
|
||||
$stderr.puts "[#{Time.new}] uRack: #{message}"
|
||||
end
|
||||
|
||||
ulog("starting at #{Dir.getwd}")
|
||||
limit_as = human_round(Process.getrlimit(Process::RLIMIT_AS)[1].to_f/1024/1024)
|
||||
ulog("your process address space limit is #{limit_as} MB")
|
||||
server = Rack::Handler.get('Unbit')
|
||||
|
||||
app = Rack::Builder.new {
|
||||
if options[:serve_file]
|
||||
puts "[#{Time.new}] uRack: file serving enabled."
|
||||
use Rails::Rack::Static
|
||||
starttime = Time.now
|
||||
|
||||
app = nil
|
||||
|
||||
if options[:config]
|
||||
cfgfile = File.read(options[:config])
|
||||
if cfgfile[/^#\\(.*)/]
|
||||
opts.parse! $1.split(/\s+/)
|
||||
end
|
||||
if ActionController.const_defined?(:Dispatcher) && (ActionController::Dispatcher.instance_methods.include?(:call) || ActionController::Dispatcher.instance_methods.include?("call"))
|
||||
run ActionController::Dispatcher.new
|
||||
app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app", nil, options[:config]
|
||||
else
|
||||
# falling back to rails
|
||||
if Dir.getwd =~ /\/public\/?$/
|
||||
require '../config/environment'
|
||||
else
|
||||
require 'thin'
|
||||
run Rack::Adapter::Rails.new(:environment => ENV['RAILS_ENV'])
|
||||
require 'config/environment'
|
||||
end
|
||||
}.to_app
|
||||
|
||||
if options[:unbit]
|
||||
$after_spawn_used_as = human_round(syscall(356).to_f/1024/1024)
|
||||
$stderr.puts "#{$unbit_log_base} now you have #{$limit_as-$after_spawn_used_as} MB of address space available (used #{$after_spawn_used_as}MB after app startup)"
|
||||
app = Rack::Builder.new {
|
||||
if options[:cachehack]
|
||||
use Rack::RailsCachingHack
|
||||
end
|
||||
if options[:static]
|
||||
use Rails::Rack::Static
|
||||
end
|
||||
if ActionController.const_defined?(:Dispatcher) && (ActionController::Dispatcher.instance_methods.include?(:call) || ActionController::Dispatcher.instance_methods.include?("call"))
|
||||
run ActionController::Dispatcher.new
|
||||
else
|
||||
require 'thin'
|
||||
run Rack::Adapter::Rails.new(:environment => ENV['RAILS_ENV'])
|
||||
end
|
||||
}
|
||||
end
|
||||
secs = Time.now-starttime
|
||||
puts "[#{Time.new}] uRack: ready to serve requests after #{secs.to_i} secs (pid: #{Process.pid})"
|
||||
|
||||
if options[:unbit_debug]
|
||||
$last_as = $after_spawn_used_as ;
|
||||
$last_obj = ObjectSpace.each_object {}
|
||||
end
|
||||
|
||||
ulog("your app is ready (in #{Time.now-starttime} seconds).")
|
||||
|
||||
|
||||
server.run(app, options)
|
||||
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
import mmap
|
||||
import os
|
||||
import struct
|
||||
import array
|
||||
import time
|
||||
import sys
|
||||
from optparse import OptionParser
|
||||
|
||||
class Cache:
|
||||
|
||||
def __init__(self, filename, cache_slots, block_size=65536, sample_sleep=1):
|
||||
|
||||
self.block_size = block_size
|
||||
self.cache_slots = cache_slots
|
||||
|
||||
self.key_size = 2048
|
||||
self.item_size = 2 + 2 + 4 + 8 + 8 + 8 + 8 + 8 + self.key_size
|
||||
self.block_size_start = self.item_size * self.cache_slots
|
||||
|
||||
fd = os.open(filename, os.O_RDONLY)
|
||||
self.cache_store = mmap.mmap(fd, 0, mmap.MAP_SHARED, mmap.PROT_READ)
|
||||
|
||||
self.sample_sleep = sample_sleep
|
||||
self.samples = 0
|
||||
self.history = []
|
||||
self.cache_full = 0
|
||||
self.cache_empty = 0
|
||||
self.cache_items = 0
|
||||
self.block_sizes = 0
|
||||
|
||||
def store_read_item_block(self, position):
|
||||
pos = self.cache_store.tell()
|
||||
# uwsgi cache stores cache entries first and then the blocks
|
||||
self.cache_store.seek(self.block_size_start + (position * self.block_size))
|
||||
buf = self.cache_store.read(self.block_size)
|
||||
self.cache_store.seek(pos)
|
||||
return buf
|
||||
|
||||
def store_read_item(self, position):
|
||||
buf = self.cache_store.read(self.item_size)
|
||||
fields = struct.unpack_from('@HHIQQQQQ2048c', buf)
|
||||
key = array.array('c', fields[8:self.key_size+8]).tostring().rstrip('\x00')
|
||||
|
||||
if [x for x in key if x!= '\x00']:
|
||||
buf = self.store_read_item_block(position)
|
||||
value = array.array('c', buf).tostring().rstrip('\x00')
|
||||
else:
|
||||
value = ''
|
||||
return (position, key, value, len(value))
|
||||
|
||||
def read(self):
|
||||
data = [self.store_read_item(i) for i in range(self.cache_slots)]
|
||||
self.cache_store.seek(0)
|
||||
self.update_stats(data)
|
||||
if self.sample_sleep:
|
||||
time.sleep(self.sample_sleep)
|
||||
return data
|
||||
|
||||
def update_stats(self, data):
|
||||
# data is a list of (position, key, value, len(value)) tuples
|
||||
items = len([1 for x in data if x[3] > 0])
|
||||
self.cache_items += items
|
||||
full, empty = items == self.cache_slots, items == 0
|
||||
if full:
|
||||
self.cache_full += 1
|
||||
if empty:
|
||||
self.cache_empty += 1
|
||||
self.samples += 1
|
||||
block_sizes = sum([x[3] for x in data])
|
||||
self.block_sizes += block_sizes
|
||||
self.history.append({'full': full, 'empty': empty, 'data': data, \
|
||||
'items': items, 'block_sizes': block_sizes})
|
||||
|
||||
def dump(self):
|
||||
return {
|
||||
'samples': self.samples,
|
||||
'history': self.history,
|
||||
'cache_slots': self.cache_slots,
|
||||
'sample_sleep': self.sample_sleep,
|
||||
'cache_empty': self.cache_empty,
|
||||
'cache_full': self.cache_full,
|
||||
'cache_items': self.cache_items,
|
||||
'block_sizes': self.block_sizes,
|
||||
}
|
||||
|
||||
def show_dump(self):
|
||||
d = self.dump()
|
||||
print
|
||||
print "Recorded %d samples (%d second(s) sleep between samples)" % \
|
||||
(d['samples'], d['sample_sleep'])
|
||||
print "Cache empty %d times, full %d times, %.2f items on average" % \
|
||||
(d['cache_empty'], d['cache_full'], d['cache_items'] / d['samples'])
|
||||
print "Block size average size: %d bytes" % \
|
||||
(d['block_sizes'] / d['cache_items'] * 8)
|
||||
print "Data in cache average: %d bytes" % \
|
||||
(d['block_sizes'] / d['samples'] * 8)
|
||||
|
||||
def main(options):
|
||||
cache = Cache(options.cache_store, options.cache_slots, options.block_size,
|
||||
options.sleep_time)
|
||||
print "Recording..."
|
||||
while True:
|
||||
try:
|
||||
data = cache.read()
|
||||
except KeyboardInterrupt:
|
||||
cache.show_dump()
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = OptionParser()
|
||||
parser.add_option("-s", "--cache-slots", dest="cache_slots", type="int",
|
||||
help="Slots available in the cache, uwsgi cache option")
|
||||
parser.add_option("-c", "--cache-store", dest="cache_store", default="uwsgi.cache",
|
||||
help="The filename of the cache store, uwsgi cache-store option. Default: uwsgi.cache")
|
||||
parser.add_option("-b", "--block-size", dest="block_size", default=65536, type="int",
|
||||
help="The size of the cache block, uwsgi cache-blocksize option. Default: 65536")
|
||||
parser.add_option("-t", "--sleep-time", dest="sleep_time", default=1, type="int",
|
||||
help="The time to sleep between each sample. Default: 1")
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
if not options.cache_slots:
|
||||
parser.error('Option -s / --cache-slots is mandatory')
|
||||
main(options)
|
||||
@@ -0,0 +1,30 @@
|
||||
-module(uwsgi).
|
||||
-export([encode/1,send/3]).
|
||||
|
||||
|
||||
encode(Vars) ->
|
||||
Body = lists:map(fun(X) -> Len = length(X), lists:append( binary_to_list(<<Len:16/little-unsigned-integer>>), X) end, Vars),
|
||||
lists:flatten(Body).
|
||||
|
||||
response(Sock, Output) ->
|
||||
case gen_tcp:recv(Sock,0) of
|
||||
{ ok, Data } ->
|
||||
response(Sock, lists:append(Output, binary_to_list(Data)));
|
||||
{ error, closed } ->
|
||||
gen_tcp:close(Sock),
|
||||
Output
|
||||
end.
|
||||
|
||||
send(Host, Port, Message) ->
|
||||
{ ok, Sock } = gen_tcp:connect( Host, Port, [ binary, { active, false} ]),
|
||||
|
||||
Body = encode(Message),
|
||||
|
||||
Len = length(Body),
|
||||
|
||||
ok = gen_tcp:send(Sock, << 0, Len:16/little-unsigned-integer, 0>>),
|
||||
|
||||
ok = gen_tcp:send(Sock, Body),
|
||||
|
||||
response(Sock, []).
|
||||
|
||||
+27
-28
@@ -6,7 +6,6 @@ import java.util.Enumeration;
|
||||
import org.apache.catalina.util.IOTools;
|
||||
|
||||
public class uwsgi extends HttpServlet {
|
||||
|
||||
private String mountpoint = null;
|
||||
|
||||
public void init(ServletConfig config) throws ServletException {
|
||||
@@ -22,34 +21,34 @@ public class uwsgi extends HttpServlet {
|
||||
if (getServletConfig().getInitParameter("mountpoint") != null) {
|
||||
mountpoint = getServletConfig().getInitParameter("mountpoint");
|
||||
if (mountpoint.length() <= 1) {
|
||||
mountpoint = null ;
|
||||
mountpoint = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException {
|
||||
throws IOException, ServletException {
|
||||
uWSGIHandler(request, response);
|
||||
}
|
||||
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException {
|
||||
throws IOException, ServletException {
|
||||
uWSGIHandler(request, response);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void uWSGIHandler(HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException {
|
||||
throws IOException, ServletException {
|
||||
|
||||
Socket client = new Socket("localhost",3017);
|
||||
ByteArrayOutputStream uwsgi_request = new ByteArrayOutputStream() ;
|
||||
ByteArrayOutputStream uwsgi_request = new ByteArrayOutputStream();
|
||||
DataOutputStream wos = new DataOutputStream(uwsgi_request);
|
||||
|
||||
DataOutputStream os = new DataOutputStream(client.getOutputStream());
|
||||
DataInputStream is = new DataInputStream( client.getInputStream() );
|
||||
|
||||
|
||||
|
||||
ServletOutputStream out = response.getOutputStream();
|
||||
|
||||
boolean hasBody = false;
|
||||
@@ -104,14 +103,14 @@ public class uwsgi extends HttpServlet {
|
||||
|
||||
if (mountpoint != null) {
|
||||
wos.writeShort(swapShort( (short) 11));
|
||||
wos.writeBytes("SCRIPT_NAME");
|
||||
wos.writeShort(swapShort( (short) mountpoint.length() ) ) ;
|
||||
wos.writeBytes( mountpoint ) ;
|
||||
wos.writeBytes("SCRIPT_NAME");
|
||||
wos.writeShort(swapShort( (short) mountpoint.length() ) );
|
||||
wos.writeBytes( mountpoint );
|
||||
}
|
||||
|
||||
|
||||
|
||||
wos.writeShort(swapShort( (short) 9));
|
||||
wos.writeBytes("PATH_INFO");
|
||||
wos.writeBytes("PATH_INFO");
|
||||
if (mountpoint != null) {
|
||||
wos.writeShort(swapShort( (short) (request.getRequestURI().length() - mountpoint.length()) ) );
|
||||
wos.writeBytes( request.getRequestURI().substring(mountpoint.length()) );
|
||||
@@ -149,14 +148,14 @@ public class uwsgi extends HttpServlet {
|
||||
hasBody = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// taken from CGI servlet
|
||||
|
||||
Enumeration headers = request.getHeaderNames();
|
||||
String header = null;
|
||||
while (headers.hasMoreElements()) {
|
||||
header = null;
|
||||
header = ((String) headers.nextElement()).toUpperCase();
|
||||
header = null;
|
||||
header = ((String) headers.nextElement()).toUpperCase();
|
||||
wos.writeShort(swapShort( (short) ("HTTP_" + header.replace('-', '_')).length() ));
|
||||
wos.writeBytes("HTTP_" + header.replace('-', '_'));
|
||||
wos.writeShort(swapShort( (short) request.getHeader(header).length() ));
|
||||
@@ -175,16 +174,16 @@ public class uwsgi extends HttpServlet {
|
||||
IOTools.flow(request.getInputStream(), os);
|
||||
}
|
||||
|
||||
boolean statusParsed = false ;
|
||||
boolean statusParsed = false;
|
||||
for(;;) {
|
||||
String line = byte_readline(is) ;
|
||||
String line = byte_readline(is);
|
||||
if (line == "") {
|
||||
break;
|
||||
}
|
||||
if (statusParsed == false) {
|
||||
String[] status = line.split(" ",3);
|
||||
response.setStatus( Integer.parseInt(status[1]) );
|
||||
statusParsed = true ;
|
||||
statusParsed = true;
|
||||
}
|
||||
else {
|
||||
String[] keyval = line.split(": ",2);
|
||||
@@ -200,7 +199,7 @@ public class uwsgi extends HttpServlet {
|
||||
byte cb[] = new byte[4096];
|
||||
int len = 0;
|
||||
for(;;) {
|
||||
len = is.read(cb,0,4096) ;
|
||||
len = is.read(cb,0,4096);
|
||||
if ( len > 0) {
|
||||
out.write(cb,0,len);
|
||||
}
|
||||
@@ -208,7 +207,7 @@ public class uwsgi extends HttpServlet {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -218,19 +217,19 @@ public class uwsgi extends HttpServlet {
|
||||
for(;;) {
|
||||
byte b = is.readByte();
|
||||
if (b == 10) {
|
||||
break ;
|
||||
break;
|
||||
}
|
||||
line.write(b) ;
|
||||
line.write(b);
|
||||
}
|
||||
|
||||
return line.toString("ASCII").replaceAll("\\n","").replaceAll("\\r","");
|
||||
}
|
||||
|
||||
private short swapShort(short x) {
|
||||
|
||||
short tmp1 = (short) (x>>8) ;
|
||||
short tmp2 = (short) (x<<8) ;
|
||||
return (short) (tmp1 | tmp2) ;
|
||||
|
||||
short tmp1 = (short) (x>>8);
|
||||
short tmp2 = (short) (x<<8);
|
||||
return (short) (tmp1 | tmp2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-1
@@ -1,13 +1,18 @@
|
||||
require 'socket'
|
||||
require 'rack/content_length'
|
||||
require 'rack/rewindable_input'
|
||||
require 'stringio'
|
||||
|
||||
module Rack
|
||||
module Handler
|
||||
class Uwsgi
|
||||
|
||||
def self.run(app, options={})
|
||||
server = TCPServer.new(options[:Host], options[:Port])
|
||||
if ENV['UWSGI_FD']
|
||||
server = UNIXServer.for_fd(ENV['UWSGI_FD'].to_i)
|
||||
else
|
||||
server = TCPServer.new(options[:Host], options[:Port])
|
||||
end
|
||||
while client = server.accept
|
||||
serve client, app
|
||||
end
|
||||
|
||||
+65
-65
@@ -2,8 +2,8 @@
|
||||
|
||||
*** uWSGI cgi client ***
|
||||
|
||||
to compile:
|
||||
gcc -Wall -o uwsgi_client.cgi uwsgi_client.c
|
||||
to compile:
|
||||
gcc -Wall -o uwsgi_client.cgi uwsgi_client.c
|
||||
|
||||
*/
|
||||
|
||||
@@ -18,79 +18,79 @@ to compile:
|
||||
#define UWSGI_SOCK "/tmp/uwsgi.sock"
|
||||
|
||||
int main() {
|
||||
extern char **environ;
|
||||
char *env ;
|
||||
struct sockaddr_un s_addr ;
|
||||
int uwsgi_socket ;
|
||||
int res, cnt;
|
||||
char *place_holder;
|
||||
|
||||
unsigned short len ;
|
||||
char message[4096];
|
||||
char *mptr;
|
||||
extern char **environ;
|
||||
char *env;
|
||||
struct sockaddr_un s_addr;
|
||||
int uwsgi_socket;
|
||||
int res, cnt;
|
||||
char *place_holder;
|
||||
|
||||
unsigned short len;
|
||||
char message[4096];
|
||||
char *mptr;
|
||||
char *content_length;
|
||||
|
||||
memset(&s_addr, 0, sizeof(struct sockaddr_un)) ;
|
||||
memset(&s_addr, 0, sizeof(struct sockaddr_un));
|
||||
|
||||
s_addr.sun_family = AF_UNIX;
|
||||
strcpy(s_addr.sun_path, UWSGI_SOCK);
|
||||
s_addr.sun_family = AF_UNIX;
|
||||
strcpy(s_addr.sun_path, UWSGI_SOCK);
|
||||
|
||||
uwsgi_socket = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (uwsgi_socket < 0) {
|
||||
perror("socket()");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_socket = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (uwsgi_socket < 0) {
|
||||
perror("socket()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (connect(uwsgi_socket, (struct sockaddr *) &s_addr, strlen(UWSGI_SOCK) + ( (void *)&s_addr.sun_path - (void *)&s_addr) ) != 0) {
|
||||
perror("connect()");
|
||||
exit(1);
|
||||
}
|
||||
if (connect(uwsgi_socket, (struct sockaddr *) &s_addr, strlen(UWSGI_SOCK) + ( (void *)&s_addr.sun_path - (void *)&s_addr) ) != 0) {
|
||||
perror("connect()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(message, 0, 4096);
|
||||
memset(message, 0, 4096);
|
||||
|
||||
mptr = message+4;
|
||||
mptr = message+4;
|
||||
|
||||
if (**environ) {
|
||||
while( (env = *environ) ) {
|
||||
place_holder = strchr(env,'=');
|
||||
// key
|
||||
len = place_holder-env ;
|
||||
memcpy(mptr, &len, 2);
|
||||
mptr+=2;
|
||||
memcpy(mptr, env, len);
|
||||
mptr+=len ;
|
||||
// value
|
||||
len = (unsigned short) (env+strlen(env) - (place_holder+1)) ;
|
||||
memcpy(mptr, &len, 2);
|
||||
mptr+=2;
|
||||
memcpy(mptr, place_holder+1, len);
|
||||
mptr+= len ;
|
||||
*environ++;
|
||||
}
|
||||
}
|
||||
|
||||
message[0] = 0;
|
||||
len = (mptr-message)-4 ;
|
||||
memcpy(message+1, &len, 2) ;
|
||||
message[3] = 0 ;
|
||||
|
||||
res = send(uwsgi_socket, message, mptr-message, 0);
|
||||
|
||||
if ( (content_length = getenv("CONTENT_LENGTH")) != NULL) {
|
||||
if (atoi(content_length) > 0) {
|
||||
while( (cnt = read(0, message, 4096)) ) {
|
||||
send(uwsgi_socket, message, cnt, 0) ;
|
||||
}
|
||||
if (**environ) {
|
||||
while( (env = *environ) ) {
|
||||
place_holder = strchr(env,'=');
|
||||
// key
|
||||
len = place_holder-env;
|
||||
memcpy(mptr, &len, 2);
|
||||
mptr+=2;
|
||||
memcpy(mptr, env, len);
|
||||
mptr+=len;
|
||||
// value
|
||||
len = (unsigned short) (env+strlen(env) - (place_holder+1));
|
||||
memcpy(mptr, &len, 2);
|
||||
mptr+=2;
|
||||
memcpy(mptr, place_holder+1, len);
|
||||
mptr+= len;
|
||||
*environ++;
|
||||
}
|
||||
}
|
||||
|
||||
if (res == mptr-message) {
|
||||
while( (res = recv(uwsgi_socket, message, 4096,0)) ) {
|
||||
write(1, message, res) ;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
message[0] = 0;
|
||||
len = (mptr-message)-4;
|
||||
memcpy(message+1, &len, 2);
|
||||
message[3] = 0;
|
||||
|
||||
res = send(uwsgi_socket, message, mptr-message, 0);
|
||||
|
||||
if ( (content_length = getenv("CONTENT_LENGTH")) != NULL) {
|
||||
if (atoi(content_length) > 0) {
|
||||
while( (cnt = read(0, message, 4096)) ) {
|
||||
send(uwsgi_socket, message, cnt, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (res == mptr-message) {
|
||||
while( (res = recv(uwsgi_socket, message, 4096,0)) ) {
|
||||
write(1, message, res);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
*** uWSGI cgi client ***
|
||||
|
||||
to compile:
|
||||
gcc -Wall -o uwsgi_client.cgi uwsgi_dynamic_client.c
|
||||
to compile:
|
||||
gcc -Wall -o uwsgi_client.cgi uwsgi_dynamic_client.c
|
||||
|
||||
*/
|
||||
|
||||
@@ -19,77 +19,77 @@ to compile:
|
||||
#define UWSGI_SCRIPT "myapp_wsgi"
|
||||
|
||||
int main() {
|
||||
extern char **environ;
|
||||
char *env ;
|
||||
struct sockaddr_un s_addr ;
|
||||
int uwsgi_socket ;
|
||||
int res, cnt;
|
||||
char *place_holder;
|
||||
|
||||
unsigned short len ;
|
||||
char message[4096];
|
||||
char *mptr;
|
||||
extern char **environ;
|
||||
char *env;
|
||||
struct sockaddr_un s_addr;
|
||||
int uwsgi_socket;
|
||||
int res, cnt;
|
||||
char *place_holder;
|
||||
|
||||
memset(&s_addr, 0, sizeof(struct sockaddr_un)) ;
|
||||
unsigned short len;
|
||||
char message[4096];
|
||||
char *mptr;
|
||||
|
||||
s_addr.sun_family = AF_UNIX;
|
||||
strcpy(s_addr.sun_path, UWSGI_SOCK);
|
||||
memset(&s_addr, 0, sizeof(struct sockaddr_un));
|
||||
|
||||
uwsgi_socket = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (uwsgi_socket < 0) {
|
||||
perror("socket()");
|
||||
exit(1);
|
||||
}
|
||||
s_addr.sun_family = AF_UNIX;
|
||||
strcpy(s_addr.sun_path, UWSGI_SOCK);
|
||||
|
||||
if (connect(uwsgi_socket, (struct sockaddr *) &s_addr, strlen(UWSGI_SOCK) + ( (void *)&s_addr.sun_path - (void *)&s_addr) ) != 0) {
|
||||
perror("connect()");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_socket = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (uwsgi_socket < 0) {
|
||||
perror("socket()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(message, 0, 4096);
|
||||
if (connect(uwsgi_socket, (struct sockaddr *) &s_addr, strlen(UWSGI_SOCK) + ( (void *)&s_addr.sun_path - (void *)&s_addr) ) != 0) {
|
||||
perror("connect()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
mptr = message+4;
|
||||
if (setenv("UWSGI_SCRIPT", UWSGI_SCRIPT, 1) != 0) {
|
||||
perror("setenv()");
|
||||
exit(1);
|
||||
}
|
||||
if (**environ) {
|
||||
while( (env = *environ) ) {
|
||||
place_holder = strchr(env,'=');
|
||||
// key
|
||||
len = place_holder-env ;
|
||||
memcpy(mptr, &len, 2);
|
||||
mptr+=2;
|
||||
memcpy(mptr, env, len);
|
||||
mptr+=len ;
|
||||
// value
|
||||
len = (unsigned short) (env+strlen(env) - (place_holder+1)) ;
|
||||
memcpy(mptr, &len, 2);
|
||||
mptr+=2;
|
||||
memcpy(mptr, place_holder+1, len);
|
||||
mptr+= len ;
|
||||
*environ++;
|
||||
}
|
||||
}
|
||||
memset(message, 0, 4096);
|
||||
|
||||
message[0] = 0;
|
||||
len = (mptr-message)-4 ;
|
||||
memcpy(message+1, &len, 2) ;
|
||||
message[3] = 0 ;
|
||||
mptr = message+4;
|
||||
if (setenv("UWSGI_SCRIPT", UWSGI_SCRIPT, 1) != 0) {
|
||||
perror("setenv()");
|
||||
exit(1);
|
||||
}
|
||||
if (**environ) {
|
||||
while( (env = *environ) ) {
|
||||
place_holder = strchr(env,'=');
|
||||
// key
|
||||
len = place_holder-env;
|
||||
memcpy(mptr, &len, 2);
|
||||
mptr+=2;
|
||||
memcpy(mptr, env, len);
|
||||
mptr+=len;
|
||||
// value
|
||||
len = (unsigned short) (env+strlen(env) - (place_holder+1));
|
||||
memcpy(mptr, &len, 2);
|
||||
mptr+=2;
|
||||
memcpy(mptr, place_holder+1, len);
|
||||
mptr+= len;
|
||||
*environ++;
|
||||
}
|
||||
}
|
||||
|
||||
res = send(uwsgi_socket, message, mptr-message, 0);
|
||||
message[0] = 0;
|
||||
len = (mptr-message)-4;
|
||||
memcpy(message+1, &len, 2);
|
||||
message[3] = 0;
|
||||
|
||||
while( (cnt = read(0, message, 4096)) ) {
|
||||
send(uwsgi_socket, message, cnt, 0) ;
|
||||
}
|
||||
res = send(uwsgi_socket, message, mptr-message, 0);
|
||||
|
||||
while( (cnt = read(0, message, 4096)) ) {
|
||||
send(uwsgi_socket, message, cnt, 0);
|
||||
}
|
||||
|
||||
if (res == mptr-message) {
|
||||
while( (res = recv(uwsgi_socket, message, 4096,0)) ) {
|
||||
write(1, message, res);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
if (res == mptr-message) {
|
||||
while( (res = recv(uwsgi_socket, message, 4096,0)) ) {
|
||||
write(1, message, res) ;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
require 'sinatra'
|
||||
require 'socket'
|
||||
require 'json'
|
||||
|
||||
module USubscribers
|
||||
def self.uwsgi_get_stats(server)
|
||||
parts = server.split(':')
|
||||
if parts.length > 1
|
||||
s = TCPSocket.open(parts[0], parts[1])
|
||||
else
|
||||
s = UNIXSocket.open(server)
|
||||
end
|
||||
return JSON.parse(s.read())
|
||||
end
|
||||
end
|
||||
|
||||
template = <<eof
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><%=@title%></title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="unbit">
|
||||
<link href="http://unbit.github.com/bootstrap/css/bootstrap.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */
|
||||
}
|
||||
</style>
|
||||
<link href="http://unbit.github.com/bootstrap/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a class="brand" href="#"><%=@title%></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% for server in @servers.keys %>
|
||||
<div class="container">
|
||||
<hr/>
|
||||
<h1>SubscriptionServer: <%=server%></h1>
|
||||
<hr/>
|
||||
|
||||
<div class="row">
|
||||
<% for pool in @servers[server] %>
|
||||
<div class="span6">
|
||||
<h3><%=pool['key']%> (<%=pool['hits']%> hits)</h3>
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>node</th><th>load</th><th>requests</th>
|
||||
<th>last check</th>
|
||||
<th>fail count</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<% for node in pool['nodes'] %>
|
||||
<tr>
|
||||
<td><%=node['name']%></td><td><%=node['load']%></td><td><%=node['requests']%></td>
|
||||
<td><%=Time.at(node['last_check']).strftime("%d-%m-%Y %H:%M:%S")%></td>
|
||||
<td><%=node['failcnt']%></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<% end %>
|
||||
|
||||
<script src="http://unbit.github.com/jquery-1.7.2.min.js" type="text/javascript"></script>
|
||||
<script src="http://unbit.github.com/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
|
||||
</body>
|
||||
</html>
|
||||
eof
|
||||
|
||||
get '/' do
|
||||
@servers = {}
|
||||
for server in ENV['U_SERVERS'].split(',')
|
||||
stats = USubscribers::uwsgi_get_stats(server)
|
||||
if stats
|
||||
@servers[server] = stats['subscriptions']
|
||||
end
|
||||
end
|
||||
@title = 'uWSGI subscriptions viewer'
|
||||
erb template
|
||||
end
|
||||
|
||||
run Sinatra::Application
|
||||
@@ -0,0 +1,14 @@
|
||||
service uwsgi
|
||||
{
|
||||
disable = no
|
||||
id = uwsgi-000
|
||||
type = UNLISTED
|
||||
socket_type = stream
|
||||
server = /root/uwsgi/uwsgi
|
||||
server_args = --chdir /root/uwsgi/ --module welcome --logto /tmp/uwsgi.log
|
||||
port = 3031
|
||||
bind = 127.0.0.1
|
||||
user = root
|
||||
wait = yes
|
||||
}
|
||||
|
||||
+469
@@ -0,0 +1,469 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_async_init() {
|
||||
int i;
|
||||
|
||||
uwsgi.async_queue = event_queue_init();
|
||||
|
||||
if (uwsgi.async_queue < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_add_sockets_to_queue(uwsgi.async_queue, -1);
|
||||
|
||||
uwsgi.rb_async_timeouts = uwsgi_init_rb_timer();
|
||||
|
||||
uwsgi.async_queue_unused = uwsgi_malloc(sizeof(struct wsgi_request *) * uwsgi.async);
|
||||
|
||||
for (i = 0; i < uwsgi.async; i++) {
|
||||
uwsgi.async_queue_unused[i] = &uwsgi.workers[uwsgi.mywid].cores[i].req;
|
||||
}
|
||||
|
||||
uwsgi.async_queue_unused_ptr = uwsgi.async - 1;
|
||||
|
||||
}
|
||||
|
||||
struct wsgi_request *find_wsgi_req_proto_by_fd(int fd) {
|
||||
return uwsgi.async_proto_fd_table[fd];
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
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 (u_request == uwsgi.async_runqueue_last) {
|
||||
uwsgi.async_runqueue_last = parent;
|
||||
}
|
||||
|
||||
free(u_request);
|
||||
|
||||
uwsgi.async_runqueue_cnt--;
|
||||
}
|
||||
|
||||
void runqueue_push(struct wsgi_request *wsgi_req) {
|
||||
|
||||
struct uwsgi_async_request *uar;
|
||||
|
||||
if (uwsgi.async_runqueue == NULL) {
|
||||
// empty runqueue, create a new one
|
||||
uwsgi.async_runqueue = uwsgi_malloc(sizeof(struct uwsgi_async_request));
|
||||
uwsgi.async_runqueue->next = NULL;
|
||||
uwsgi.async_runqueue->prev = NULL;
|
||||
uwsgi.async_runqueue->wsgi_req = wsgi_req;
|
||||
uwsgi.async_runqueue_last = uwsgi.async_runqueue;
|
||||
}
|
||||
else {
|
||||
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++;
|
||||
|
||||
}
|
||||
|
||||
struct wsgi_request *find_first_available_wsgi_req() {
|
||||
|
||||
struct wsgi_request *wsgi_req;
|
||||
|
||||
if (uwsgi.async_queue_unused_ptr < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wsgi_req = uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr];
|
||||
uwsgi.async_queue_unused_ptr--;
|
||||
return wsgi_req;
|
||||
}
|
||||
|
||||
void async_expire_timeouts() {
|
||||
|
||||
struct wsgi_request *wsgi_req;
|
||||
time_t current_time = uwsgi_now();
|
||||
struct uwsgi_async_fd *uaf = NULL, *current_uaf;
|
||||
|
||||
struct uwsgi_rb_timer *urbt;
|
||||
|
||||
for(;;) {
|
||||
|
||||
urbt = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts);
|
||||
|
||||
if (urbt == NULL) return;
|
||||
|
||||
if (urbt->key <= current_time) {
|
||||
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
|
||||
runqueue_push(wsgi_req);
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void 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 ;
|
||||
|
||||
// find first slot
|
||||
while(uad) {
|
||||
last_uad = uad;
|
||||
uad = uad->next;
|
||||
}
|
||||
|
||||
uad = uwsgi_malloc(sizeof(struct uwsgi_async_fd));
|
||||
uad->fd = fd;
|
||||
uad->event = event_queue_read();
|
||||
uad->prev = last_uad;
|
||||
uad->next = NULL;
|
||||
|
||||
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_read(uwsgi.async_queue, fd);
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void async_add_fd_write(struct wsgi_request *wsgi_req, int fd, int timeout) {
|
||||
|
||||
struct uwsgi_async_fd *last_uad = NULL, *uad = wsgi_req->waiting_fds;
|
||||
|
||||
if (fd < 0) return ;
|
||||
|
||||
// find first slot
|
||||
while(uad) {
|
||||
last_uad = uad;
|
||||
uad = uad->next;
|
||||
}
|
||||
|
||||
uad = uwsgi_malloc(sizeof(struct uwsgi_async_fd));
|
||||
uad->fd = fd;
|
||||
uad->event = event_queue_write();
|
||||
uad->prev = last_uad;
|
||||
uad->next = NULL;
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
void async_schedule_to_req(void) {
|
||||
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh.modifier1]->request(uwsgi.wsgi_req);
|
||||
}
|
||||
|
||||
void *async_loop(void *arg1) {
|
||||
|
||||
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;
|
||||
|
||||
static struct uwsgi_async_request *current_request = NULL, *next_async_request = NULL;
|
||||
|
||||
void *events = event_queue_alloc(64);
|
||||
struct uwsgi_socket *uwsgi_sock;
|
||||
|
||||
uwsgi.async_runqueue = NULL;
|
||||
uwsgi.async_runqueue_cnt = 0;
|
||||
|
||||
if (uwsgi.signal_socket > -1) {
|
||||
event_queue_add_fd_read(uwsgi.async_queue, uwsgi.signal_socket);
|
||||
event_queue_add_fd_read(uwsgi.async_queue, uwsgi.my_signal_socket);
|
||||
}
|
||||
|
||||
// set a default request manager
|
||||
if (!uwsgi.schedule_to_req) uwsgi.schedule_to_req = async_schedule_to_req;
|
||||
|
||||
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
|
||||
|
||||
if (uwsgi.async_runqueue_cnt) {
|
||||
timeout = 0;
|
||||
}
|
||||
else {
|
||||
min_timeout = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts);
|
||||
if (uwsgi.async_runqueue_cnt) {
|
||||
timeout = 0;
|
||||
}
|
||||
if (min_timeout) {
|
||||
timeout = min_timeout->key - uwsgi_now();
|
||||
if (timeout <= 0) {
|
||||
async_expire_timeouts();
|
||||
timeout = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
timeout = -1;
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi.async_nevents = event_queue_wait_multi(uwsgi.async_queue, timeout, events, 64);
|
||||
|
||||
// timeout ???
|
||||
if (uwsgi.async_nevents == 0) {
|
||||
async_expire_timeouts();
|
||||
}
|
||||
|
||||
|
||||
for(i=0;i<uwsgi.async_nevents;i++) {
|
||||
// manage events
|
||||
interesting_fd = event_queue_interesting_fd(events, i);
|
||||
|
||||
if (uwsgi.signal_socket > -1 && (interesting_fd == uwsgi.signal_socket || interesting_fd == uwsgi.my_signal_socket)) {
|
||||
uwsgi_receive_signal(interesting_fd, "worker", uwsgi.mywid);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
is_a_new_connection = 0;
|
||||
|
||||
// new request coming in ?
|
||||
|
||||
uwsgi_sock = uwsgi.sockets;
|
||||
while(uwsgi_sock) {
|
||||
|
||||
if (interesting_fd == uwsgi_sock->fd) {
|
||||
|
||||
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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
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++;
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
|
||||
break;
|
||||
}
|
||||
|
||||
if (uwsgi.wsgi_req->do_not_add_to_async_queue) {
|
||||
runqueue_push(uwsgi.wsgi_req);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
if (!is_a_new_connection) {
|
||||
// proto event
|
||||
uwsgi.wsgi_req = find_wsgi_req_proto_by_fd(interesting_fd);
|
||||
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;
|
||||
// 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
|
||||
uwsgi.async_proto_fd_table[interesting_fd] = NULL;
|
||||
// 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;
|
||||
}
|
||||
// re-add timer
|
||||
async_add_timeout(uwsgi.wsgi_req, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// app event
|
||||
uwsgi.wsgi_req = find_wsgi_req_by_fd(interesting_fd);
|
||||
// unknown fd, remove it (for safety)
|
||||
if (uwsgi.wsgi_req == NULL) {
|
||||
close(interesting_fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
uwsgi.wsgi_req->async_ready_fd = 1;
|
||||
uwsgi.wsgi_req->async_last_ready_fd = interesting_fd;
|
||||
|
||||
// put the request in the runqueue again
|
||||
runqueue_push(uwsgi.wsgi_req);
|
||||
}
|
||||
}
|
||||
|
||||
// event queue managed, give cpu to runqueue
|
||||
if (!current_request)
|
||||
current_request = uwsgi.async_runqueue;
|
||||
|
||||
if (uwsgi.async_runqueue_cnt) {
|
||||
|
||||
uwsgi.wsgi_req = current_request->wsgi_req;
|
||||
|
||||
uwsgi.schedule_to_req();
|
||||
uwsgi.wsgi_req->switches++;
|
||||
|
||||
next_async_request = current_request->next;
|
||||
// request ended ?
|
||||
if (uwsgi.wsgi_req->async_status <= UWSGI_OK) {
|
||||
// remove all the monitored fds and timeout
|
||||
while(uwsgi.wsgi_req->waiting_fds) {
|
||||
#ifndef UWSGI_EVENT_USE_PORT
|
||||
event_queue_del_fd(uwsgi.async_queue, uwsgi.wsgi_req->waiting_fds->fd, uwsgi.wsgi_req->waiting_fds->event);
|
||||
#endif
|
||||
tmp_uaf = uwsgi.wsgi_req->waiting_fds;
|
||||
uwsgi.async_waiting_fd_table[tmp_uaf->fd] = NULL;
|
||||
uwsgi.wsgi_req->waiting_fds = tmp_uaf->next;
|
||||
free(tmp_uaf);
|
||||
}
|
||||
uwsgi.wsgi_req->waiting_fds = NULL;
|
||||
if (uwsgi.wsgi_req->async_timeout) {
|
||||
rb_erase(&uwsgi.wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts);
|
||||
free(uwsgi.wsgi_req->async_timeout);
|
||||
uwsgi.wsgi_req->async_timeout = NULL;
|
||||
}
|
||||
|
||||
// remove from the list
|
||||
runqueue_remove(current_request);
|
||||
|
||||
uwsgi_close_request(uwsgi.wsgi_req);
|
||||
|
||||
// push wsgi_request in the unused stack
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
|
||||
|
||||
}
|
||||
else if (uwsgi.wsgi_req->waiting_fds || uwsgi.wsgi_req->async_timeout) {
|
||||
// remove this request from suspended list
|
||||
runqueue_remove(current_request);
|
||||
}
|
||||
|
||||
current_request = next_async_request;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_buffer *uwsgi_buffer_new(size_t len) {
|
||||
struct uwsgi_buffer *ub = uwsgi_calloc(sizeof(struct uwsgi_buffer));
|
||||
|
||||
if (len) {
|
||||
ub->buf = uwsgi_malloc(len);
|
||||
ub->len = len;
|
||||
}
|
||||
return ub;
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_buffer_append(struct uwsgi_buffer *ub, char *buf, size_t len) {
|
||||
|
||||
size_t remains = ub->len - ub->pos;
|
||||
|
||||
if (len > remains) {
|
||||
size_t chunk_size = UMAX(len, (size_t) uwsgi.page_size);
|
||||
char *new_buf = realloc(ub->buf, ub->len + chunk_size);
|
||||
if (!new_buf) {
|
||||
uwsgi_error("realloc()");
|
||||
return -1;
|
||||
}
|
||||
ub->buf = new_buf;
|
||||
ub->len += chunk_size;
|
||||
}
|
||||
|
||||
memcpy(ub->buf + ub->pos, buf, len);
|
||||
ub->pos += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uwsgi_buffer_destroy(struct uwsgi_buffer *ub) {
|
||||
if (ub->buf) free(ub->buf);
|
||||
free(ub);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_send(struct uwsgi_buffer *ub, int fd) {
|
||||
size_t remains = ub->pos;
|
||||
char *ptr = ub->buf;
|
||||
|
||||
while(remains > 0) {
|
||||
int ret = uwsgi_waitfd_write(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (ret > 0) {
|
||||
ssize_t len = write(fd, ptr, remains);
|
||||
if (len > 0) {
|
||||
ptr += len;
|
||||
remains -= len;
|
||||
}
|
||||
else if (len == 0) {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
uwsgi_error("write()");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (ret == 0) {
|
||||
uwsgi_log("timeout while sending buffer !!!\n");
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
+443
@@ -0,0 +1,443 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_init_cache() {
|
||||
int i;
|
||||
|
||||
if (!uwsgi.cache_blocksize)
|
||||
uwsgi.cache_blocksize = UMAX16;
|
||||
|
||||
uwsgi.cache_hashtable = (uint64_t *) mmap(NULL, sizeof(uint64_t) * UMAX16, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (!uwsgi.cache_hashtable) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(uwsgi.cache_hashtable, 0, sizeof(uint64_t) * UMAX16);
|
||||
|
||||
uwsgi.cache_unused_stack = (uint64_t *) mmap(NULL, sizeof(uint64_t) * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (!uwsgi.cache_unused_stack) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(uwsgi.cache_unused_stack, 0, sizeof(uint64_t) * uwsgi.cache_max_items);
|
||||
|
||||
// the first cache item is always zero
|
||||
uwsgi.shared->cache_first_available_item = 1;
|
||||
uwsgi.shared->cache_unused_stack_ptr = 0;
|
||||
|
||||
//uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (uwsgi.cache_store) {
|
||||
uwsgi.cache_filesize = (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items) + (uwsgi.cache_blocksize * uwsgi.cache_max_items);
|
||||
int cache_fd;
|
||||
struct stat cst;
|
||||
|
||||
if (stat(uwsgi.cache_store, &cst)) {
|
||||
uwsgi_log("creating a new cache store file: %s\n", uwsgi.cache_store);
|
||||
cache_fd = open(uwsgi.cache_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
if (cache_fd >= 0) {
|
||||
// fill the caching store
|
||||
if (ftruncate(cache_fd, uwsgi.cache_filesize)) {
|
||||
uwsgi_log("ftruncate()");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((size_t) cst.st_size != uwsgi.cache_filesize || !S_ISREG(cst.st_mode)) {
|
||||
uwsgi_log("invalid cache store file. Please remove it or fix cache blocksize/items to match its size\n");
|
||||
exit(1);
|
||||
}
|
||||
cache_fd = open(uwsgi.cache_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
uwsgi_log("recovered cache from backing store file: %s\n", uwsgi.cache_store);
|
||||
}
|
||||
|
||||
if (cache_fd < 0) {
|
||||
uwsgi_error_open(uwsgi.cache_store);
|
||||
exit(1);
|
||||
}
|
||||
uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, uwsgi.cache_filesize, PROT_READ | PROT_WRITE, MAP_SHARED, cache_fd, 0);
|
||||
uwsgi_cache_fix();
|
||||
|
||||
}
|
||||
else {
|
||||
uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items) + (uwsgi.cache_blocksize * uwsgi.cache_max_items), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
for (i = 0; i < (int) uwsgi.cache_max_items; i++) {
|
||||
memset(&uwsgi.cache_items[i], 0, sizeof(struct uwsgi_cache_item));
|
||||
}
|
||||
}
|
||||
if (!uwsgi.cache_items) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
uwsgi.cache = mmap(NULL, uwsgi.cache_blocksize * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (!uwsgi.cache) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
*/
|
||||
|
||||
uwsgi.cache = ((void *) uwsgi.cache_items) + (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items);
|
||||
|
||||
uwsgi.cache_lock = uwsgi_rwlock_init("cache");
|
||||
|
||||
uwsgi_log("*** Cache subsystem initialized: %dMB (key: %llu bytes, keys: %llu bytes, data: %llu bytes) preallocated ***\n", ((uwsgi.cache_blocksize * uwsgi.cache_max_items) + (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items)) / (1024 * 1024),
|
||||
(unsigned long long) sizeof(struct uwsgi_cache_item), (unsigned long long) sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items, (unsigned long long) uwsgi.cache_blocksize * uwsgi.cache_max_items);
|
||||
}
|
||||
|
||||
uint32_t djb33x_hash(char *key, int keylen) {
|
||||
|
||||
register uint32_t hash = 5381;
|
||||
int i;
|
||||
|
||||
for(i=0;i<keylen;i++) {
|
||||
hash = ((hash << 5) + hash) ^ key[i];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
static inline uint64_t uwsgi_cache_get_index(char *key, uint16_t keylen) {
|
||||
|
||||
uint32_t hash = djb33x_hash(key, keylen);
|
||||
|
||||
int hash_key = hash % 0xffff;
|
||||
|
||||
uint64_t slot = uwsgi.cache_hashtable[hash_key];
|
||||
|
||||
struct uwsgi_cache_item *uci;
|
||||
uint64_t rounds = 0;
|
||||
|
||||
//uwsgi_log("found slot %d for key %d\n", slot, hash_key);
|
||||
|
||||
uci = &uwsgi.cache_items[slot];
|
||||
|
||||
// first round
|
||||
if (uci->djbhash != hash) return 0;
|
||||
if (uci->keysize != keylen) goto cycle;
|
||||
if (memcmp(uci->key, key, keylen)) goto cycle;
|
||||
|
||||
return slot;
|
||||
|
||||
cycle:
|
||||
while(uci->next) {
|
||||
slot = uci->next;
|
||||
uci = &uwsgi.cache_items[slot];
|
||||
rounds++;
|
||||
if (rounds > uwsgi.cache_max_items) {
|
||||
uwsgi_log("ALARM !!! cache-loop (and potential deadlock) detected slot = %llu prev = %llu next = %llu\n", uci->next, slot, uci->prev, uci->next);
|
||||
// terrible case: the whole uWSGI stack can deadlock, leaving only the master alive
|
||||
// if the master is avalable, trigger a brutal reload
|
||||
if (uwsgi.master_process) {
|
||||
kill(uwsgi.workers[0].pid, SIGTERM);
|
||||
}
|
||||
// otherwise kill the current worker (could be pretty useless...)
|
||||
else {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (uci->djbhash != hash) return 0;
|
||||
if (uci->keysize != keylen) continue;
|
||||
if (!memcmp(uci->key, key, keylen)) return slot;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t uwsgi_cache_exists(char *key, uint16_t keylen) {
|
||||
|
||||
return uwsgi_cache_get_index(key, keylen);
|
||||
}
|
||||
|
||||
char *uwsgi_cache_get(char *key, uint16_t keylen, uint64_t *valsize) {
|
||||
|
||||
uint64_t index = uwsgi_cache_get_index(key, keylen);
|
||||
|
||||
if (index) {
|
||||
if (uwsgi.cache_items[index].flags & UWSGI_CACHE_FLAG_UNGETTABLE) return NULL;
|
||||
*valsize = uwsgi.cache_items[index].valsize;
|
||||
uwsgi.cache_items[index].hits++;
|
||||
return uwsgi.cache+(index*uwsgi.cache_blocksize);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int uwsgi_cache_del(char *key, uint16_t keylen, uint64_t index) {
|
||||
|
||||
struct uwsgi_cache_item *uci;
|
||||
int ret = -1;
|
||||
|
||||
if (!index)
|
||||
index = uwsgi_cache_get_index(key, keylen);
|
||||
|
||||
if (index) {
|
||||
uci = &uwsgi.cache_items[index] ;
|
||||
uci->keysize = 0;
|
||||
uci->valsize = 0;
|
||||
uwsgi.shared->cache_unused_stack_ptr++;
|
||||
uwsgi.cache_unused_stack[uwsgi.shared->cache_unused_stack_ptr] = index;
|
||||
// try to return to initial condition...
|
||||
if (index == uwsgi.shared->cache_first_available_item-1) {
|
||||
uwsgi.shared->cache_first_available_item--;
|
||||
//uwsgi_log("FACI: %llu STACK PTR: %llu\n", (unsigned long long) uwsgi.shared->cache_first_available_item, (unsigned long long) uwsgi.shared->cache_unused_stack_ptr);
|
||||
}
|
||||
ret = 0;
|
||||
// relink collisioned entry
|
||||
if (uci->prev) {
|
||||
uwsgi.cache_items[uci->prev].next = uci->next;
|
||||
}
|
||||
else {
|
||||
// set next as the new entry point (could be 0)
|
||||
uwsgi.cache_hashtable[uci->djbhash % 0xffff] = uci->next;
|
||||
}
|
||||
|
||||
if (uci->next) {
|
||||
uwsgi.cache_items[uci->next].prev = uci->prev;
|
||||
}
|
||||
|
||||
if (!uci->prev && !uci->next) {
|
||||
// reset hashtable entry
|
||||
//uwsgi_log("!!! resetted hashtable entry !!!\n");
|
||||
uwsgi.cache_hashtable[uci->djbhash % 0xffff] = 0;
|
||||
}
|
||||
uci->djbhash = 0;
|
||||
uci->prev = 0;
|
||||
uci->next = 0;
|
||||
uci->expires = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void uwsgi_cache_fix() {
|
||||
|
||||
uint64_t i;
|
||||
|
||||
for(i=0;i< uwsgi.cache_max_items;i++) {
|
||||
// valid record ?
|
||||
if (uwsgi.cache_items[i].keysize) {
|
||||
if (!uwsgi.cache_items[i].prev) {
|
||||
// put value in hash_table
|
||||
uwsgi.cache_hashtable[ uwsgi.cache_items[i].djbhash % 0xffff] = i;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// put this record in unused stack
|
||||
uwsgi.shared->cache_first_available_item = i;
|
||||
uwsgi.shared->cache_unused_stack_ptr++;
|
||||
uwsgi.cache_unused_stack[uwsgi.shared->cache_unused_stack_ptr] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int uwsgi_cache_set(char *key, uint16_t keylen, char *val, uint64_t vallen, uint64_t expires, uint16_t flags) {
|
||||
|
||||
uint64_t index = 0, last_index = 0 ;
|
||||
|
||||
struct uwsgi_cache_item *uci, *ucii;
|
||||
|
||||
int ret = -1;
|
||||
int slot;
|
||||
|
||||
if (!keylen || !vallen) return -1;
|
||||
|
||||
if (keylen > UWSGI_CACHE_MAX_KEY_SIZE) return -1;
|
||||
|
||||
if (uwsgi.shared->cache_first_available_item >= uwsgi.cache_max_items && !uwsgi.shared->cache_unused_stack_ptr) {
|
||||
uwsgi_log("*** DANGER cache is FULL !!! ***\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
//uwsgi_log("putting cache data in key %.*s %d\n", keylen, key, vallen);
|
||||
index = uwsgi_cache_get_index(key, keylen);
|
||||
if (!index) {
|
||||
if (uwsgi.shared->cache_unused_stack_ptr) {
|
||||
//uwsgi_log("!!! REUSING CACHE SLOT !!! (faci: %llu)\n", (unsigned long long) uwsgi.shared->cache_first_available_item);
|
||||
index = uwsgi.cache_unused_stack[uwsgi.shared->cache_unused_stack_ptr];
|
||||
uwsgi.shared->cache_unused_stack_ptr--;
|
||||
}
|
||||
else {
|
||||
index = uwsgi.shared->cache_first_available_item;
|
||||
if (uwsgi.shared->cache_first_available_item < uwsgi.cache_max_items) {
|
||||
uwsgi.shared->cache_first_available_item++;
|
||||
}
|
||||
}
|
||||
uci = &uwsgi.cache_items[index] ;
|
||||
if (expires) expires += uwsgi_now();
|
||||
uci->expires = expires;
|
||||
uci->djbhash = djb33x_hash(key, keylen);
|
||||
uci->hits = 0;
|
||||
uci->flags = flags;
|
||||
memcpy(uci->key, key, keylen);
|
||||
memcpy(uwsgi.cache+(index*uwsgi.cache_blocksize), val, vallen);
|
||||
|
||||
// set this as late as possibile (to reduce races risk)
|
||||
|
||||
uci->valsize = vallen;
|
||||
uci->keysize = keylen;
|
||||
ret = 0;
|
||||
// now put the value in the 16bit hashtable
|
||||
slot = uci->djbhash % 0xffff;
|
||||
// reset values
|
||||
uci->prev = 0;
|
||||
uci->next = 0;
|
||||
|
||||
if (uwsgi.cache_hashtable[slot] == 0) {
|
||||
uwsgi.cache_hashtable[slot] = index;
|
||||
}
|
||||
else {
|
||||
//uwsgi_log("HASH COLLISION !!!!\n");
|
||||
// append to first available next
|
||||
last_index = uwsgi.cache_hashtable[slot];
|
||||
ucii = &uwsgi.cache_items[ last_index ];
|
||||
while(ucii->next) {
|
||||
last_index = ucii->next;
|
||||
ucii = &uwsgi.cache_items[ last_index ];
|
||||
}
|
||||
ucii->next = index;
|
||||
uci->prev = last_index;
|
||||
}
|
||||
}
|
||||
else if (flags & UWSGI_CACHE_FLAG_UPDATE) {
|
||||
uci = &uwsgi.cache_items[index] ;
|
||||
if (expires) {
|
||||
expires += uwsgi_now();
|
||||
uci->expires = expires;
|
||||
}
|
||||
memcpy(uwsgi.cache+(index*uwsgi.cache_blocksize), val, vallen);
|
||||
uci->valsize = vallen;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
end:
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* THIS PART IS HEAVILY OPTIMIZED: PERFORMANCE NOT ELEGANCE !!! */
|
||||
|
||||
void *cache_thread_loop(void *fd_ptr) {
|
||||
|
||||
int *fd_tmp = (int *) fd_ptr;
|
||||
int fd = *fd_tmp;
|
||||
int i;
|
||||
ssize_t len;
|
||||
char uwsgi_packet[UMAX16+4];
|
||||
struct uwsgi_header *uh = (struct uwsgi_header *) uwsgi_packet;
|
||||
char *val;
|
||||
uint64_t vallen;
|
||||
char *key;
|
||||
uint16_t keylen;
|
||||
struct pollfd ctl_poll;
|
||||
char *watermark;
|
||||
struct sockaddr_un ctl_sun;
|
||||
socklen_t ctl_sun_len;
|
||||
|
||||
ctl_poll.events = POLLIN;
|
||||
|
||||
for(;;) {
|
||||
ctl_sun_len = sizeof(struct sockaddr_un);
|
||||
pthread_mutex_lock(&uwsgi.cache_server_lock);
|
||||
|
||||
ctl_poll.fd = accept(fd, (struct sockaddr *) &ctl_sun, &ctl_sun_len);
|
||||
|
||||
pthread_mutex_unlock(&uwsgi.cache_server_lock);
|
||||
|
||||
if (ctl_poll.fd < 0) {
|
||||
uwsgi_error("cache accept()");
|
||||
continue;
|
||||
}
|
||||
i = 0;
|
||||
while(i < 4) {
|
||||
len = poll(&ctl_poll, 1, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (len <= 0) {
|
||||
uwsgi_error("cache poll()");
|
||||
goto clear;
|
||||
}
|
||||
len = read(ctl_poll.fd, uwsgi_packet+i, 4-i);
|
||||
if (len < 0) {
|
||||
uwsgi_error("cache read()");
|
||||
goto clear;
|
||||
}
|
||||
i+=len;
|
||||
}
|
||||
|
||||
if (uh->pktsize == 0) goto clear;
|
||||
|
||||
while(i < 4+uh->pktsize) {
|
||||
len = poll(&ctl_poll, 1, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (len <= 0) {
|
||||
uwsgi_error("cache poll()");
|
||||
goto clear;
|
||||
}
|
||||
len = read(ctl_poll.fd, uwsgi_packet+i, (4+uh->pktsize)-i);
|
||||
if (len < 0) {
|
||||
uwsgi_error("cache read()");
|
||||
goto clear;
|
||||
}
|
||||
i+=len;
|
||||
}
|
||||
|
||||
watermark = uwsgi_packet+4+uh->pktsize;
|
||||
|
||||
// get first parameter
|
||||
memcpy(&keylen, uwsgi_packet+4, 2);
|
||||
#ifdef __BIG_ENDIAN__
|
||||
keylen = uwsgi_swap16(keylen);
|
||||
#endif
|
||||
if (uwsgi_packet+6+keylen > watermark) goto clear;
|
||||
key = uwsgi_packet+6+keylen+2;
|
||||
memcpy(&keylen, key-2, 2);
|
||||
#ifdef __BIG_ENDIAN__
|
||||
keylen = uwsgi_swap16(keylen);
|
||||
#endif
|
||||
|
||||
if (key+keylen > watermark) goto clear;
|
||||
|
||||
val = uwsgi_cache_get(key, keylen, &vallen);
|
||||
if (val && vallen > 0) {
|
||||
if (write(ctl_poll.fd, val, vallen) < 0) {
|
||||
uwsgi_error("cache write()");
|
||||
}
|
||||
}
|
||||
|
||||
clear:
|
||||
close(ctl_poll.fd);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int uwsgi_cache_server(char *socket, int threads) {
|
||||
|
||||
int *fd = uwsgi_malloc(sizeof(int));
|
||||
|
||||
int i;
|
||||
pthread_t thread_id;
|
||||
char *tcp_port = strchr(socket, ':');
|
||||
if (tcp_port) {
|
||||
*fd = bind_to_tcp(socket, uwsgi.listen_queue, tcp_port);
|
||||
}
|
||||
else {
|
||||
*fd = bind_to_unix(socket, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
|
||||
}
|
||||
|
||||
pthread_mutex_init(&uwsgi.cache_server_lock, NULL);
|
||||
|
||||
if (threads < 1) threads = 1;
|
||||
|
||||
uwsgi_log("*** cache-optimized server enabled on fd %d (%d threads) ***\n", *fd, threads);
|
||||
|
||||
for(i=0;i<threads;i++) {
|
||||
pthread_create(&thread_id, NULL, cache_thread_loop, (void *) fd);
|
||||
}
|
||||
|
||||
return *fd;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
// in the future we will need to use the best clock source for each os/system
|
||||
time_t uwsgi_now() {
|
||||
return uwsgi.clock->seconds();
|
||||
}
|
||||
|
||||
uint64_t uwsgi_micros() {
|
||||
return uwsgi.clock->microseconds();
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_register_clock(struct uwsgi_clock *clock) {
|
||||
struct uwsgi_clock *clocks = uwsgi.clocks;
|
||||
|
||||
clock->next = NULL;
|
||||
|
||||
if (!clocks) {
|
||||
uwsgi.clocks = clock;
|
||||
return;
|
||||
}
|
||||
|
||||
while(clocks) {
|
||||
if (!clocks->next) {
|
||||
clocks->next = clock;
|
||||
return;
|
||||
}
|
||||
clocks = clocks->next;
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_set_clock(char *name) {
|
||||
struct uwsgi_clock *clocks = uwsgi.clocks;
|
||||
while(clocks) {
|
||||
if (!strcmp(name, clocks->name)) {
|
||||
uwsgi.clock = clocks;
|
||||
return;
|
||||
}
|
||||
clocks = clocks->next;
|
||||
}
|
||||
|
||||
uwsgi_log("unable to set \"%s\" clock\n", name);
|
||||
exit(1);
|
||||
}
|
||||
+464
@@ -0,0 +1,464 @@
|
||||
#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;
|
||||
}
|
||||
+1376
File diff suppressed because it is too large
Load Diff
+935
@@ -0,0 +1,935 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#ifdef UWSGI_EVENT_USE_PORT
|
||||
|
||||
#include <port.h>
|
||||
|
||||
#define UWSGI_EVENT_IN POLLIN
|
||||
#define UWSGI_EVENT_OUT POLLOUT
|
||||
|
||||
int event_queue_init() {
|
||||
|
||||
int port = port_create();
|
||||
|
||||
if (port < 0) {
|
||||
uwsgi_error("port_create()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
int event_queue_del_fd(int eq, int fd, int event) {
|
||||
|
||||
if (port_dissociate(eq, PORT_SOURCE_FD, fd)) {
|
||||
uwsgi_error("port_disassociate");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int event_queue_fd_write_to_read(int eq, int fd) {
|
||||
|
||||
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, NULL)) {
|
||||
uwsgi_error("port_associate");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
|
||||
}
|
||||
|
||||
int event_queue_fd_read_to_write(int eq, int fd) {
|
||||
|
||||
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLOUT, NULL)) {
|
||||
uwsgi_error("port_associate");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int event_queue_interesting_fd_has_error(void *events, int id) {
|
||||
port_event_t *pe = (port_event_t *) events;
|
||||
if (pe[id].portev_events == POLLHUP || pe[id].portev_events == POLLERR) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int event_queue_add_fd_read(int eq, int fd) {
|
||||
|
||||
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, NULL)) {
|
||||
uwsgi_error("port_associate");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int event_queue_add_fd_write(int eq, int fd) {
|
||||
|
||||
if (port_associate(eq, PORT_SOURCE_FD, fd, POLLOUT, NULL)) {
|
||||
uwsgi_error("port_associate");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
void *event_queue_alloc(int nevents) {
|
||||
|
||||
return uwsgi_malloc(sizeof(port_event_t) * nevents);
|
||||
}
|
||||
|
||||
int event_queue_interesting_fd(void *events, int id) {
|
||||
port_event_t *pe = (port_event_t *) events;
|
||||
if (pe[id].portev_source == PORT_SOURCE_FILE || pe[id].portev_source == PORT_SOURCE_TIMER) {
|
||||
return (long) pe[id].portev_user;
|
||||
}
|
||||
|
||||
return (int) pe[id].portev_object;
|
||||
}
|
||||
|
||||
int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
|
||||
|
||||
int ret;
|
||||
uint_t nget = 1;
|
||||
timespec_t ts;
|
||||
port_event_t *pe;
|
||||
|
||||
if (timeout >= 0) {
|
||||
ts.tv_sec = timeout;
|
||||
ts.tv_nsec = 0;
|
||||
ret = port_getn(eq, events, nevents, &nget, &ts);
|
||||
}
|
||||
else {
|
||||
ret = port_getn(eq, events, nevents, &nget, NULL);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
if (errno != ETIME) {
|
||||
uwsgi_error("port_getn()");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
pe = (port_event_t *) events;
|
||||
|
||||
return nget;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int event_queue_wait(int eq, int timeout, int *interesting_fd) {
|
||||
|
||||
int ret;
|
||||
port_event_t pe;
|
||||
timespec_t ts;
|
||||
|
||||
if (timeout > 0) {
|
||||
ts.tv_sec = timeout;
|
||||
ts.tv_nsec = 0;
|
||||
ret = port_get(eq, &pe, &ts);
|
||||
}
|
||||
else {
|
||||
ret = port_get(eq, &pe, NULL);
|
||||
}
|
||||
if (ret < 0) {
|
||||
if (errno != ETIME) {
|
||||
uwsgi_error("port_get()");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pe.portev_source == PORT_SOURCE_FD) {
|
||||
// event must be readded (damn Oracle/Sun why the fu*k you made such a horrible choice ???? why not adding a ONESHOT flag ???)
|
||||
if (port_associate(eq, pe.portev_source, pe.portev_object, pe.portev_events, NULL)) {
|
||||
uwsgi_error("port_associate");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (pe.portev_source == PORT_SOURCE_FILE || pe.portev_source == PORT_SOURCE_TIMER) {
|
||||
*interesting_fd = (long) pe.portev_user;
|
||||
}
|
||||
else {
|
||||
*interesting_fd = (int) pe.portev_object;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef UWSGI_EVENT_USE_EPOLL
|
||||
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#define UWSGI_EVENT_IN EPOLLIN
|
||||
#define UWSGI_EVENT_OUT EPOLLOUT
|
||||
|
||||
int event_queue_init() {
|
||||
|
||||
int epfd;
|
||||
|
||||
|
||||
epfd = epoll_create(256);
|
||||
|
||||
if (epfd < 0) {
|
||||
uwsgi_error("epoll_create()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return epfd;
|
||||
}
|
||||
|
||||
|
||||
int event_queue_add_fd_read(int eq, int fd) {
|
||||
|
||||
struct epoll_event ee;
|
||||
|
||||
memset(&ee, 0, sizeof(struct epoll_event));
|
||||
ee.events = EPOLLIN;
|
||||
ee.data.fd = fd;
|
||||
|
||||
if (epoll_ctl(eq, EPOLL_CTL_ADD, fd, &ee)) {
|
||||
uwsgi_error("epoll_ctl()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int event_queue_fd_write_to_read(int eq, int fd) {
|
||||
|
||||
struct epoll_event ee;
|
||||
|
||||
memset(&ee, 0, sizeof(struct epoll_event));
|
||||
ee.events = EPOLLIN;
|
||||
ee.data.fd = fd;
|
||||
|
||||
if (epoll_ctl(eq, EPOLL_CTL_MOD, fd, &ee)) {
|
||||
uwsgi_error("epoll_ctl()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int event_queue_fd_read_to_write(int eq, int fd) {
|
||||
|
||||
struct epoll_event ee;
|
||||
|
||||
memset(&ee, 0, sizeof(struct epoll_event));
|
||||
ee.events = EPOLLOUT;
|
||||
ee.data.fd = fd;
|
||||
|
||||
if (epoll_ctl(eq, EPOLL_CTL_MOD, fd, &ee)) {
|
||||
uwsgi_error("epoll_ctl()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
int event_queue_del_fd(int eq, int fd, int event) {
|
||||
|
||||
struct epoll_event ee;
|
||||
|
||||
memset(&ee, 0, sizeof(struct epoll_event));
|
||||
ee.data.fd = fd;
|
||||
ee.events = event;
|
||||
|
||||
if (epoll_ctl(eq, EPOLL_CTL_DEL, fd, &ee)) {
|
||||
uwsgi_error("epoll_ctl()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int event_queue_add_fd_write(int eq, int fd) {
|
||||
|
||||
struct epoll_event ee;
|
||||
|
||||
memset(&ee, 0, sizeof(struct epoll_event));
|
||||
ee.events = EPOLLOUT;
|
||||
ee.data.fd = fd;
|
||||
|
||||
if (epoll_ctl(eq, EPOLL_CTL_ADD, fd, &ee)) {
|
||||
uwsgi_error("epoll_ctl()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
void *event_queue_alloc(int nevents) {
|
||||
|
||||
return uwsgi_malloc(sizeof(struct epoll_event) * nevents);
|
||||
}
|
||||
|
||||
int event_queue_interesting_fd(void *events, int id) {
|
||||
struct epoll_event *ee = (struct epoll_event *) events;
|
||||
return ee[id].data.fd;
|
||||
}
|
||||
|
||||
int event_queue_interesting_fd_has_error(void *events, int id) {
|
||||
struct epoll_event *ee = (struct epoll_event *) events;
|
||||
if (ee[id].events == EPOLLHUP || ee[id].events == EPOLLERR || (ee[id].events == (EPOLLERR|EPOLLHUP))) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
|
||||
|
||||
int ret;
|
||||
|
||||
if (timeout > 0) {
|
||||
timeout = timeout*1000;
|
||||
}
|
||||
|
||||
ret = epoll_wait(eq, (struct epoll_event *) events, nevents, timeout);
|
||||
if (ret < 0) {
|
||||
if (errno != EINTR)
|
||||
uwsgi_error("epoll_wait()");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int event_queue_wait(int eq, int timeout, int *interesting_fd) {
|
||||
|
||||
int ret;
|
||||
struct epoll_event ee;
|
||||
|
||||
if (timeout > 0) {
|
||||
timeout = timeout*1000;
|
||||
}
|
||||
|
||||
ret = epoll_wait(eq, &ee, 1, timeout);
|
||||
if (ret < 0) {
|
||||
if (errno != EINTR)
|
||||
uwsgi_error("epoll_wait()");
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
*interesting_fd = ee.data.fd;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_EVENT_USE_KQUEUE
|
||||
|
||||
#define UWSGI_EVENT_IN EVFILT_READ
|
||||
#define UWSGI_EVENT_OUT EVFILT_WRITE
|
||||
|
||||
int event_queue_init() {
|
||||
|
||||
int kfd = kqueue();
|
||||
|
||||
if (kfd < 0) {
|
||||
uwsgi_error("kqueue()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return kfd;
|
||||
}
|
||||
|
||||
int event_queue_fd_write_to_read(int eq, int fd) {
|
||||
|
||||
struct kevent kev;
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
EV_SET(&kev, fd, EVFILT_WRITE, EV_DISABLE, 0, 0, 0);
|
||||
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
|
||||
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int event_queue_fd_read_to_write(int eq, int fd) {
|
||||
|
||||
struct kevent kev;
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
EV_SET(&kev, fd, EVFILT_READ, EV_DISABLE, 0, 0, 0);
|
||||
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
EV_SET(&kev, fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
|
||||
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
int event_queue_del_fd(int eq, int fd, int event) {
|
||||
|
||||
struct kevent kev;
|
||||
|
||||
EV_SET(&kev, fd, event, EV_DELETE, 0, 0, 0);
|
||||
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int event_queue_add_fd_read(int eq, int fd) {
|
||||
|
||||
struct kevent kev;
|
||||
|
||||
EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
|
||||
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int event_queue_add_fd_write(int eq, int fd) {
|
||||
|
||||
struct kevent kev;
|
||||
|
||||
EV_SET(&kev, fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
|
||||
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *event_queue_alloc(int nevents) {
|
||||
|
||||
return uwsgi_malloc(sizeof(struct kevent) * nevents);
|
||||
}
|
||||
|
||||
int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
|
||||
|
||||
int ret;
|
||||
struct timespec ts;
|
||||
|
||||
if (timeout < 0) {
|
||||
ret = kevent(eq, NULL, 0, events, nevents, NULL);
|
||||
}
|
||||
else {
|
||||
memset(&ts, 0, sizeof(struct timespec));
|
||||
ts.tv_sec = timeout;
|
||||
ret = kevent(eq, NULL, 0, (struct kevent *)events, nevents, &ts);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
if (errno != EINTR)
|
||||
uwsgi_error("kevent()");
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int event_queue_interesting_fd(void *events, int id) {
|
||||
|
||||
struct kevent *ev = (struct kevent *) events;
|
||||
return ev[id].ident;
|
||||
}
|
||||
|
||||
int event_queue_interesting_fd_has_error(void *events, int id) {
|
||||
struct kevent *ev = (struct kevent *) events;
|
||||
|
||||
// DO NOT CHECK FOR EOF !!!
|
||||
if ( ev[id].flags & EV_ERROR ) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int event_queue_wait(int eq, int timeout, int *interesting_fd) {
|
||||
|
||||
int ret;
|
||||
struct timespec ts;
|
||||
struct kevent ev;
|
||||
|
||||
if (timeout <= 0) {
|
||||
ret = kevent(eq, NULL, 0, &ev, 1, NULL);
|
||||
}
|
||||
else {
|
||||
memset(&ts, 0, sizeof(struct timespec));
|
||||
ts.tv_sec = timeout;
|
||||
ret = kevent(eq, NULL, 0, &ev, 1, &ts);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
if (errno != EINTR)
|
||||
uwsgi_error("kevent()");
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
*interesting_fd = ev.ident;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_EVENT_FILEMONITOR_USE_NONE
|
||||
int event_queue_add_file_monitor(int eq, char *filename, int *id) { return -1;}
|
||||
struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {return NULL;}
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_EVENT_FILEMONITOR_USE_PORT
|
||||
int event_queue_add_file_monitor(int eq, char *filename, int *id) {
|
||||
|
||||
struct file_obj fo;
|
||||
struct stat st;
|
||||
static int fmon_id = 0xffffee00;
|
||||
|
||||
if (stat(filename, &st)) {
|
||||
uwsgi_error("stat()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fo.fo_name = filename;
|
||||
fo.fo_atime = st.st_atim;
|
||||
fo.fo_mtime = st.st_mtim;
|
||||
fo.fo_ctime = st.st_ctim;
|
||||
|
||||
fmon_id++;
|
||||
if (port_associate(eq, PORT_SOURCE_FILE, (uintptr_t) &fo, FILE_MODIFIED|FILE_ATTRIB, (void *) (long) fmon_id)) {
|
||||
uwsgi_error("port_associate()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
*id = fmon_id;
|
||||
|
||||
uwsgi_log("added new file to monitor %s [%d]\n", filename, *id);
|
||||
|
||||
return *id;
|
||||
}
|
||||
|
||||
struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
|
||||
|
||||
int i;
|
||||
struct file_obj fo;
|
||||
struct stat st;
|
||||
|
||||
for(i=0;i<ushared->files_monitored_cnt;i++) {
|
||||
if (ushared->files_monitored[i].registered) {
|
||||
if (ushared->files_monitored[i].fd == id) {
|
||||
if (stat(ushared->files_monitored[i].filename, &st)) {
|
||||
uwsgi_error("stat()");
|
||||
return NULL;
|
||||
}
|
||||
fo.fo_name = ushared->files_monitored[i].filename;
|
||||
fo.fo_atime = st.st_atim;
|
||||
fo.fo_mtime = st.st_mtim;
|
||||
fo.fo_ctime = st.st_ctim;
|
||||
if (port_associate(eq, PORT_SOURCE_FILE, (uintptr_t) &fo, FILE_MODIFIED|FILE_ATTRIB, (void *)(long)id)) {
|
||||
uwsgi_error("port_associate()");
|
||||
return NULL;
|
||||
}
|
||||
return &ushared->files_monitored[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef UWSGI_EVENT_FILEMONITOR_USE_KQUEUE
|
||||
int event_queue_add_file_monitor(int eq, char *filename, int *id) {
|
||||
|
||||
struct kevent kev;
|
||||
|
||||
int fd = open(filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
uwsgi_error_open(filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD|EV_CLEAR, NOTE_WRITE|NOTE_DELETE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_RENAME|NOTE_REVOKE, 0, 0);
|
||||
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*id = fd;
|
||||
|
||||
uwsgi_log("added new file to monitor %s\n", filename);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
|
||||
|
||||
int i;
|
||||
|
||||
for(i=0;i<ushared->files_monitored_cnt;i++) {
|
||||
if (ushared->files_monitored[i].registered) {
|
||||
if (ushared->files_monitored[i].fd == id) {
|
||||
return &ushared->files_monitored[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_EVENT_FILEMONITOR_USE_INOTIFY
|
||||
|
||||
|
||||
#ifdef OBSOLETE_LINUX_KERNEL
|
||||
int event_queue_add_file_monitor(int eq, char *filename, int *id) {
|
||||
return -1;
|
||||
}
|
||||
struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
#include <sys/inotify.h>
|
||||
|
||||
int event_queue_add_file_monitor(int eq, char *filename, int *id) {
|
||||
|
||||
int ifd = -1;
|
||||
int i;
|
||||
int add_to_queue = 0;
|
||||
|
||||
for (i=0;i<ushared->files_monitored_cnt;i++) {
|
||||
if (ushared->files_monitored[i].registered) {
|
||||
ifd = ushared->files_monitored[0].fd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ifd == -1) {
|
||||
ifd = inotify_init();
|
||||
if (ifd < 0) {
|
||||
uwsgi_error("inotify_init()");
|
||||
return -1;
|
||||
}
|
||||
add_to_queue = 1;
|
||||
}
|
||||
|
||||
*id = inotify_add_watch(ifd, filename, IN_ATTRIB|IN_CREATE|IN_DELETE|IN_DELETE_SELF|IN_MODIFY|IN_MOVE_SELF|IN_MOVED_FROM|IN_MOVED_TO);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("added watch %d for filename %s\n", *id, filename);
|
||||
#endif
|
||||
|
||||
if (add_to_queue) {
|
||||
return event_queue_add_fd_read(eq, ifd);
|
||||
}
|
||||
else {
|
||||
return ifd;
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
|
||||
|
||||
ssize_t rlen = 0;
|
||||
struct inotify_event ie, *bie, *iie;
|
||||
int i,j;
|
||||
int items = 0;
|
||||
|
||||
unsigned int isize = sizeof(struct inotify_event);
|
||||
struct uwsgi_fmon *uf = NULL;
|
||||
|
||||
if (ioctl(id, FIONREAD, &isize) < 0) {
|
||||
uwsgi_error("ioctl()");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (isize > sizeof(struct inotify_event)) {
|
||||
bie = uwsgi_malloc(isize);
|
||||
rlen = read(id, bie, isize);
|
||||
}
|
||||
else {
|
||||
rlen = read(id, &ie, sizeof(struct inotify_event));
|
||||
bie = &ie;
|
||||
}
|
||||
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("read()");
|
||||
}
|
||||
else {
|
||||
items = isize/(sizeof(struct inotify_event));
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("inotify returned %d items\n", items);
|
||||
#endif
|
||||
for(j=0;j<items;j++) {
|
||||
iie = &bie[j];
|
||||
for(i=0;i<ushared->files_monitored_cnt;i++) {
|
||||
if (ushared->files_monitored[i].registered) {
|
||||
if (ushared->files_monitored[i].fd == id && ushared->files_monitored[i].id == iie->wd) {
|
||||
uf = &ushared->files_monitored[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (items > 1) {
|
||||
free(bie);
|
||||
}
|
||||
|
||||
return uf;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_EVENT_TIMER_USE_TIMERFD
|
||||
|
||||
#ifndef UWSGI_EVENT_TIMER_USE_TIMERFD_NOINC
|
||||
#include <sys/timerfd.h>
|
||||
#endif
|
||||
|
||||
#ifndef TFD_CLOEXEC
|
||||
|
||||
// timerfd support
|
||||
|
||||
enum
|
||||
{
|
||||
TFD_CLOEXEC = 02000000,
|
||||
#define TFD_CLOEXEC TFD_CLOEXEC
|
||||
TFD_NONBLOCK = 04000
|
||||
#define TFD_NONBLOCK TFD_NONBLOCK
|
||||
};
|
||||
|
||||
|
||||
/* Bits to be set in the FLAGS parameter of `timerfd_settime'. */
|
||||
enum
|
||||
{
|
||||
TFD_TIMER_ABSTIME = 1 << 0
|
||||
#define TFD_TIMER_ABSTIME TFD_TIMER_ABSTIME
|
||||
};
|
||||
|
||||
|
||||
static int timerfd_create (clockid_t __clock_id, int __flags) {
|
||||
#ifdef __amd64__
|
||||
return syscall(283, __clock_id, __flags);
|
||||
#elif defined(__i386__)
|
||||
return syscall(322, __clock_id, __flags);
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int timerfd_settime (int __ufd, int __flags,
|
||||
__const struct itimerspec *__utmr,
|
||||
struct itimerspec *__otmr) {
|
||||
#ifdef __amd64__
|
||||
return syscall(286, __ufd, __flags, __utmr, __otmr);
|
||||
#elif defined(__i386__)
|
||||
return syscall(325, __ufd, __flags, __utmr, __otmr);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int event_queue_add_timer(int eq, int *id, int sec) {
|
||||
|
||||
struct itimerspec it;
|
||||
int tfd = timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC);
|
||||
|
||||
if (tfd < 0) {
|
||||
uwsgi_error("timerfd_create()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
it.it_value.tv_sec = sec;
|
||||
it.it_value.tv_nsec = 0;
|
||||
|
||||
it.it_interval.tv_sec = sec;
|
||||
it.it_interval.tv_nsec = 0;
|
||||
|
||||
if (timerfd_settime(tfd, 0, &it, NULL)) {
|
||||
uwsgi_error("timerfd_settime()");
|
||||
close(tfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*id = tfd;
|
||||
return event_queue_add_fd_read(eq, tfd);
|
||||
}
|
||||
|
||||
struct uwsgi_timer *event_queue_ack_timer(int id) {
|
||||
|
||||
int i;
|
||||
ssize_t rlen;
|
||||
uint64_t counter;
|
||||
struct uwsgi_timer *ut = NULL;
|
||||
|
||||
for(i=0;i<ushared->timers_cnt;i++) {
|
||||
if (ushared->timers[i].registered) {
|
||||
if (ushared->timers[i].id == id) {
|
||||
ut = &ushared->timers[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rlen = read(id, &counter, sizeof(uint64_t));
|
||||
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("read()");
|
||||
}
|
||||
|
||||
return ut;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_EVENT_TIMER_USE_NONE
|
||||
int event_queue_add_timer(int eq, int *id, int sec) { return -1; }
|
||||
struct uwsgi_timer *event_queue_ack_timer(int id) { return NULL;}
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_EVENT_TIMER_USE_PORT
|
||||
int event_queue_add_timer(int eq, int *id, int sec) {
|
||||
|
||||
static int timer_id = 0xffffff00;
|
||||
port_notify_t pnotif;
|
||||
struct sigevent sigev;
|
||||
itimerspec_t it;
|
||||
timer_t tid;
|
||||
|
||||
timer_id++;
|
||||
|
||||
pnotif.portnfy_port = eq;
|
||||
pnotif.portnfy_user = (void *) (long) timer_id;
|
||||
|
||||
sigev.sigev_notify = SIGEV_PORT;
|
||||
sigev.sigev_value.sival_ptr = &pnotif;
|
||||
|
||||
if (timer_create(CLOCK_REALTIME, &sigev, &tid) < 0) {
|
||||
uwsgi_error("timer_create()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
it.it_value.tv_sec = sec;
|
||||
it.it_value.tv_nsec = 0;
|
||||
|
||||
it.it_interval.tv_sec = sec;
|
||||
it.it_interval.tv_nsec = 0;
|
||||
|
||||
if (timer_settime(tid, 0, &it, NULL) < 0) {
|
||||
uwsgi_error("timer_settime()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*id = timer_id;
|
||||
|
||||
return *id;
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_timer *event_queue_ack_timer(int id) {
|
||||
|
||||
int i;
|
||||
struct uwsgi_timer *ut = NULL;
|
||||
|
||||
for(i=0;i<uwsgi.shared->timers_cnt;i++) {
|
||||
if (uwsgi.shared->timers[i].registered) {
|
||||
if (uwsgi.shared->timers[i].id == id) {
|
||||
ut = &uwsgi.shared->timers[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ut;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef UWSGI_EVENT_TIMER_USE_KQUEUE
|
||||
int event_queue_add_timer(int eq, int *id, int sec) {
|
||||
|
||||
static int timer_id = 0xffffff00;
|
||||
struct kevent kev;
|
||||
|
||||
*id = timer_id ;
|
||||
timer_id++;
|
||||
|
||||
EV_SET(&kev, *id, EVFILT_TIMER, EV_ADD, 0, sec*1000, 0);
|
||||
if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return *id;
|
||||
}
|
||||
|
||||
struct uwsgi_timer *event_queue_ack_timer(int id) {
|
||||
|
||||
int i;
|
||||
struct uwsgi_timer *ut = NULL;
|
||||
|
||||
for(i=0;i<uwsgi.shared->timers_cnt;i++) {
|
||||
if (uwsgi.shared->timers[i].registered) {
|
||||
if (uwsgi.shared->timers[i].id == id) {
|
||||
ut = &uwsgi.shared->timers[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ut;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
int event_queue_read() {
|
||||
return UWSGI_EVENT_IN;
|
||||
}
|
||||
|
||||
int event_queue_write() {
|
||||
return UWSGI_EVENT_OUT;
|
||||
}
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_gateway *register_gateway(char *name, void (*loop)(int, void *), void *data) {
|
||||
|
||||
struct uwsgi_gateway *ug;
|
||||
int num=1,i;
|
||||
|
||||
if (ushared->gateways_cnt >= MAX_GATEWAYS) {
|
||||
uwsgi_log("you can register max %d gateways\n", MAX_GATEWAYS);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(i=0;i<ushared->gateways_cnt;i++) {
|
||||
if (!strcmp(name, ushared->gateways[i].name)) {
|
||||
num++;
|
||||
}
|
||||
}
|
||||
|
||||
char *fullname = uwsgi_concat3(name, " ", uwsgi_num2str(num));
|
||||
|
||||
ug = &ushared->gateways[ushared->gateways_cnt];
|
||||
ug->pid = 0;
|
||||
ug->name = name;
|
||||
ug->loop = loop;
|
||||
ug->num = num;
|
||||
ug->fullname = fullname;
|
||||
ug->data = data;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, ug->internal_subscription_pipe)) {
|
||||
uwsgi_error("socketpair()");
|
||||
}
|
||||
|
||||
if (!uwsgi.master_process)
|
||||
gateway_respawn(ushared->gateways_cnt);
|
||||
|
||||
ushared->gateways_cnt++;
|
||||
|
||||
|
||||
return ug;
|
||||
}
|
||||
|
||||
void gateway_respawn(int id) {
|
||||
|
||||
pid_t gw_pid;
|
||||
struct uwsgi_gateway *ug = &ushared->gateways[id];
|
||||
|
||||
if (uwsgi.master_process)
|
||||
uwsgi.shared->gateways_harakiri[id] = 0;
|
||||
|
||||
gw_pid = uwsgi_fork(ug->fullname);
|
||||
if (gw_pid < 0) {
|
||||
uwsgi_error("fork()");
|
||||
return;
|
||||
}
|
||||
|
||||
if (gw_pid == 0) {
|
||||
uwsgi_fixup_fds(0, 0, ug);
|
||||
if (uwsgi.master_as_root) uwsgi_as_root();
|
||||
#ifdef __linux__
|
||||
if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0,0,0)) {
|
||||
uwsgi_error("prctl()");
|
||||
}
|
||||
#endif
|
||||
uwsgi.mypid = getpid();
|
||||
signal(SIGALRM, SIG_IGN);
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
signal(SIGINT, end_me);
|
||||
signal(SIGTERM, end_me);
|
||||
signal(SIGUSR1, SIG_IGN);
|
||||
signal(SIGUSR2, SIG_IGN);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGSTOP, SIG_IGN);
|
||||
signal(SIGTSTP, SIG_IGN);
|
||||
|
||||
ug->loop(id, ug->data);
|
||||
// never here !!! (i hope)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ug->pid = gw_pid;
|
||||
ug->respawns++;
|
||||
if (ug->respawns == 1) {
|
||||
uwsgi_log( "spawned %s %d (pid: %d)\n", ug->name, ug->num, (int) gw_pid);
|
||||
}
|
||||
else {
|
||||
uwsgi_log( "respawned %s %d (pid: %d)\n", ug->name, ug->num, (int) gw_pid);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_gateway_socket *uwsgi_new_gateway_socket(char *name, char *owner) {
|
||||
|
||||
struct uwsgi_gateway_socket *uwsgi_sock = uwsgi.gateway_sockets, *old_uwsgi_sock;
|
||||
|
||||
if (!uwsgi_sock) {
|
||||
uwsgi.gateway_sockets = uwsgi_malloc(sizeof(struct uwsgi_gateway_socket));
|
||||
uwsgi_sock = uwsgi.gateway_sockets;
|
||||
}
|
||||
else {
|
||||
while(uwsgi_sock) {
|
||||
old_uwsgi_sock = uwsgi_sock;
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
uwsgi_sock = uwsgi_malloc(sizeof(struct uwsgi_gateway_socket));
|
||||
old_uwsgi_sock->next = uwsgi_sock;
|
||||
}
|
||||
|
||||
memset(uwsgi_sock, 0, sizeof(struct uwsgi_gateway_socket));
|
||||
uwsgi_sock->fd = -1;
|
||||
uwsgi_sock->shared = 0;
|
||||
uwsgi_sock->name = name;
|
||||
uwsgi_sock->name_len = strlen(name);
|
||||
uwsgi_sock->owner = owner;
|
||||
|
||||
return uwsgi_sock;
|
||||
}
|
||||
|
||||
struct uwsgi_gateway_socket *uwsgi_new_gateway_socket_from_fd(int fd, char *owner) {
|
||||
|
||||
struct uwsgi_gateway_socket *uwsgi_sock = uwsgi.gateway_sockets, *old_uwsgi_sock;
|
||||
|
||||
if (!uwsgi_sock) {
|
||||
uwsgi.gateway_sockets = uwsgi_malloc(sizeof(struct uwsgi_gateway_socket));
|
||||
uwsgi_sock = uwsgi.gateway_sockets;
|
||||
}
|
||||
else {
|
||||
while(uwsgi_sock) {
|
||||
old_uwsgi_sock = uwsgi_sock;
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
uwsgi_sock = uwsgi_malloc(sizeof(struct uwsgi_gateway_socket));
|
||||
old_uwsgi_sock->next = uwsgi_sock;
|
||||
}
|
||||
|
||||
memset(uwsgi_sock, 0, sizeof(struct uwsgi_gateway_socket));
|
||||
uwsgi_sock->fd = fd;
|
||||
uwsgi_sock->name = uwsgi_getsockname(fd);
|
||||
uwsgi_sock->name_len = strlen(uwsgi_sock->name);
|
||||
uwsgi_sock->owner = owner;
|
||||
|
||||
return uwsgi_sock;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_gateway_go_cheap(char *gw_id, int queue, int *i_am_cheap) {
|
||||
|
||||
uwsgi_log("[%s pid %d] no more nodes available. Going cheap...\n", gw_id, (int) uwsgi.mypid);
|
||||
struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets;
|
||||
while (ugs) {
|
||||
if (!strcmp(ugs->owner, gw_id) && !ugs->subscription) {
|
||||
event_queue_del_fd(queue, ugs->fd, event_queue_read());
|
||||
}
|
||||
ugs = ugs->next;
|
||||
}
|
||||
*i_am_cheap = 1;
|
||||
}
|
||||
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
#ifdef UWSGI_INI
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/*
|
||||
ini file must be read ALL into memory.
|
||||
This memory must not be freed for all the server lifecycle
|
||||
*/
|
||||
|
||||
void ini_rstrip(char *line) {
|
||||
|
||||
off_t i;
|
||||
|
||||
for(i = strlen(line)-1;i>=0; i--) {
|
||||
if (line[i] == ' ' || line[i] == '\t' || line[i] == '\r') {
|
||||
line[i] = 0;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char *ini_lstrip(char *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;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
char *ini_get_key(char *key) {
|
||||
|
||||
off_t i;
|
||||
char *ptr = key;
|
||||
|
||||
for(i=0;i< (int) strlen(key);i++) {
|
||||
ptr++;
|
||||
if (key[i] == '=') {
|
||||
key[i] = 0;
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
char *ini_get_line(char *ini, off_t size) {
|
||||
|
||||
off_t i;
|
||||
char *ptr = ini;
|
||||
|
||||
for(i=0;i<size;i++) {
|
||||
ptr++;
|
||||
if (ini[i] == '\n') {
|
||||
ini[i] = 0;
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
// check if it is a stupid file without \n at the end
|
||||
if (ptr > ini) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
|
||||
int len = 0;
|
||||
char *ini;
|
||||
|
||||
char *ini_line;
|
||||
|
||||
char *section = "";
|
||||
char *key;
|
||||
char *val;
|
||||
|
||||
int lines = 1;
|
||||
|
||||
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, ':');
|
||||
}
|
||||
|
||||
if (colon) {
|
||||
colon[0] = 0;
|
||||
if (colon[1] != 0) {
|
||||
section_asked = colon+1;
|
||||
}
|
||||
}
|
||||
|
||||
if (file[0] != 0) {
|
||||
uwsgi_log("[uWSGI] getting INI configuration from %s\n", file);
|
||||
}
|
||||
|
||||
ini = uwsgi_open_and_read(file, &len, 1, magic_table);
|
||||
|
||||
while(len) {
|
||||
ini_line = ini_get_line(ini, len);
|
||||
if (ini_line == NULL) {
|
||||
break;
|
||||
}
|
||||
lines++;
|
||||
|
||||
// skip empty line
|
||||
key = ini_lstrip(ini);
|
||||
ini_rstrip(key);
|
||||
if (key[0] != 0) {
|
||||
if (key[0] == '[') {
|
||||
section = key+1;
|
||||
section[strlen(section)-1] = 0;
|
||||
}
|
||||
else if (key[0] == ';' || key[0] == '#') {
|
||||
// this is a comment
|
||||
}
|
||||
else {
|
||||
// val is always valid, but (obviously) can be ignored
|
||||
val = ini_get_key(key);
|
||||
|
||||
if (!strcmp(section, section_asked)) {
|
||||
ini_rstrip(key);
|
||||
val = ini_lstrip(val);
|
||||
ini_rstrip(val);
|
||||
add_exported_option((char *)key, val, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
len -= (ini_line - ini);
|
||||
ini += (ini_line - ini);
|
||||
|
||||
}
|
||||
|
||||
if (colon) {
|
||||
colon[0] = ':';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+282
@@ -0,0 +1,282 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_init_default() {
|
||||
|
||||
uwsgi.cpus = 1;
|
||||
|
||||
uwsgi.backtrace_depth = 64;
|
||||
uwsgi.max_apps = 64;
|
||||
|
||||
uwsgi.master_queue = -1;
|
||||
|
||||
uwsgi.signal_socket = -1;
|
||||
uwsgi.my_signal_socket = -1;
|
||||
uwsgi.cache_server_fd = -1;
|
||||
uwsgi.stats_fd = -1;
|
||||
|
||||
uwsgi.original_log_fd = -1;
|
||||
|
||||
uwsgi.emperor_fd_config = -1;
|
||||
// default emperor scan frequency
|
||||
uwsgi.emperor_freq = 3;
|
||||
uwsgi.emperor_throttle = 1000;
|
||||
uwsgi.emperor_heartbeat = 30;
|
||||
// max 3 minutes throttling
|
||||
uwsgi.emperor_max_throttle = 1000 * 180;
|
||||
uwsgi.emperor_pid = -1;
|
||||
|
||||
uwsgi.subscribe_freq = 10;
|
||||
uwsgi.subscription_tolerance = 17;
|
||||
|
||||
uwsgi.cluster_fd = -1;
|
||||
uwsgi.cores = 1;
|
||||
uwsgi.threads = 1;
|
||||
|
||||
uwsgi.default_app = -1;
|
||||
|
||||
uwsgi.buffer_size = 4096;
|
||||
uwsgi.numproc = 1;
|
||||
|
||||
uwsgi.forkbomb_delay = 2;
|
||||
|
||||
uwsgi.async = 1;
|
||||
uwsgi.listen_queue = 100;
|
||||
|
||||
uwsgi.cheaper_overload = 3;
|
||||
|
||||
uwsgi.log_master_bufsize = 8192;
|
||||
|
||||
uwsgi.max_vars = MAX_VARS;
|
||||
uwsgi.vec_size = 4 + 1 + (4 * MAX_VARS);
|
||||
|
||||
uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] = 4;
|
||||
uwsgi.shared->options[UWSGI_OPTION_LOGGING] = 1;
|
||||
|
||||
#ifdef UWSGI_SPOOLER
|
||||
uwsgi.shared->spooler_frequency = 30;
|
||||
|
||||
uwsgi.shared->spooler_signal_pipe[0] = -1;
|
||||
uwsgi.shared->spooler_signal_pipe[1] = -1;
|
||||
#endif
|
||||
uwsgi.shared->mule_signal_pipe[0] = -1;
|
||||
uwsgi.shared->mule_signal_pipe[1] = -1;
|
||||
|
||||
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;
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
// 1 day of tolerance
|
||||
uwsgi.subscriptions_sign_check_tolerance = 3600 * 24;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_setup_reload() {
|
||||
|
||||
char env_reload_buf[11];
|
||||
|
||||
char *env_reloads = getenv("UWSGI_RELOADS");
|
||||
if (env_reloads) {
|
||||
//convert env value to int
|
||||
uwsgi.reloads = atoi(env_reloads);
|
||||
uwsgi.reloads++;
|
||||
//convert reloads to string
|
||||
int rlen = snprintf(env_reload_buf, 10, "%u", uwsgi.reloads);
|
||||
if (rlen > 0) {
|
||||
env_reload_buf[rlen] = 0;
|
||||
if (setenv("UWSGI_RELOADS", env_reload_buf, 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
}
|
||||
uwsgi.is_a_reload = 1;
|
||||
}
|
||||
else {
|
||||
if (setenv("UWSGI_RELOADS", "0", 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_autoload_plugins_by_name(char *argv_zero) {
|
||||
|
||||
char *plugins_requested = NULL;
|
||||
|
||||
char *original_proc_name = getenv("UWSGI_ORIGINAL_PROC_NAME");
|
||||
if (!original_proc_name) {
|
||||
// here we use argv[0];
|
||||
original_proc_name = argv_zero;
|
||||
setenv("UWSGI_ORIGINAL_PROC_NAME", original_proc_name, 1);
|
||||
}
|
||||
char *p = strrchr(original_proc_name, '/');
|
||||
if (p == NULL)
|
||||
p = original_proc_name;
|
||||
p = strstr(p, "uwsgi_");
|
||||
if (p != NULL) {
|
||||
plugins_requested = strtok(uwsgi_str(p + 6), "_");
|
||||
while (plugins_requested) {
|
||||
uwsgi_log("[uwsgi] implicit plugin requested %s\n", plugins_requested);
|
||||
uwsgi_load_plugin(-1, plugins_requested, NULL);
|
||||
plugins_requested = strtok(NULL, "_");
|
||||
}
|
||||
}
|
||||
|
||||
plugins_requested = getenv("UWSGI_PLUGINS");
|
||||
if (plugins_requested) {
|
||||
plugins_requested = uwsgi_concat2(plugins_requested, "");
|
||||
char *p = strtok(plugins_requested, ",");
|
||||
while (p != NULL) {
|
||||
uwsgi_load_plugin(-1, p, NULL);
|
||||
p = strtok(NULL, ",");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_commandline_config() {
|
||||
int i;
|
||||
|
||||
uwsgi.option_index = -1;
|
||||
|
||||
char *optname;
|
||||
while ((i = getopt_long(uwsgi.argc, uwsgi.argv, uwsgi.short_options, uwsgi.long_options, &uwsgi.option_index)) != -1) {
|
||||
|
||||
if (i == '?') {
|
||||
uwsgi_log("getopt_long() error\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (uwsgi.option_index > -1) {
|
||||
optname = (char *) uwsgi.long_options[uwsgi.option_index].name;
|
||||
}
|
||||
else {
|
||||
optname = uwsgi_get_optname_by_index(i);
|
||||
}
|
||||
if (!optname) {
|
||||
uwsgi_log("unable to parse command line options\n");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi.option_index = -1;
|
||||
add_exported_option(optname, optarg, 0);
|
||||
}
|
||||
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("optind:%d argc:%d\n", optind, uwsgi.argc);
|
||||
#endif
|
||||
|
||||
if (optind < uwsgi.argc) {
|
||||
for (i = optind; i < uwsgi.argc; i++) {
|
||||
char *lazy = uwsgi.argv[i];
|
||||
if (lazy[0] != '[') {
|
||||
uwsgi_opt_load(NULL, lazy, NULL);
|
||||
// manage magic mountpoint
|
||||
int magic = 0;
|
||||
int j;
|
||||
for (j = 0; j < uwsgi.gp_cnt; j++) {
|
||||
if (uwsgi.gp[j]->magic) {
|
||||
if (uwsgi.gp[j]->magic(NULL, lazy)) {
|
||||
magic = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!magic) {
|
||||
for (j = 0; j < 256; j++) {
|
||||
if (uwsgi.p[j]->magic) {
|
||||
if (uwsgi.p[j]->magic(NULL, lazy)) {
|
||||
magic = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_setup_workers() {
|
||||
int i,j;
|
||||
// allocate shared memory for workers + master
|
||||
uwsgi.workers = (struct uwsgi_worker *) uwsgi_calloc_shared(sizeof(struct uwsgi_worker) * (uwsgi.numproc + 1 + uwsgi.grunt));
|
||||
|
||||
for (i = 0; i <= uwsgi.numproc; i++) {
|
||||
// allocate memory for apps
|
||||
uwsgi.workers[i].apps = (struct uwsgi_app *) uwsgi_calloc_shared(sizeof(struct uwsgi_app) * uwsgi.max_apps);
|
||||
|
||||
// allocate memory for cores
|
||||
uwsgi.workers[i].cores = (struct uwsgi_core *) uwsgi_calloc_shared(sizeof(struct uwsgi_core) * uwsgi.cores);
|
||||
|
||||
// this is a trick for avoiding too much memory areas
|
||||
void *ts = uwsgi_calloc_shared(sizeof(void *) * uwsgi.max_apps * uwsgi.cores);
|
||||
void *buffers = uwsgi_malloc_shared(uwsgi.buffer_size * uwsgi.cores);
|
||||
void *hvec = uwsgi_malloc_shared(sizeof(struct iovec) * uwsgi.vec_size * uwsgi.cores);
|
||||
void *post_buf = NULL;
|
||||
if (uwsgi.post_buffering > 0)
|
||||
post_buf = uwsgi_malloc_shared(uwsgi.post_buffering_bufsize * uwsgi.cores);
|
||||
|
||||
|
||||
for (j = 0; j < uwsgi.cores; j++) {
|
||||
// allocate shared memory for thread states (required for some language, like python)
|
||||
uwsgi.workers[i].cores[j].ts = ts + ((sizeof(void *) * uwsgi.max_apps) * j);
|
||||
// raw per-request buffer
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
#ifdef UWSGI_JSON
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#include <jansson.h>
|
||||
|
||||
|
||||
/*
|
||||
I really love the jansson library...
|
||||
*/
|
||||
|
||||
void uwsgi_json_config(char *file, char *magic_table[]) {
|
||||
|
||||
int len = 0;
|
||||
char *json_data;
|
||||
|
||||
|
||||
const char *key;
|
||||
|
||||
json_t *root;
|
||||
json_error_t error;
|
||||
json_t *config;
|
||||
json_t *config_value, *config_array_item;
|
||||
|
||||
void *config_iter;
|
||||
|
||||
char *object_asked = "uwsgi";
|
||||
char *colon;
|
||||
int i;
|
||||
|
||||
if (uwsgi_check_scheme(file)) {
|
||||
colon = uwsgi_get_last_char(file, '/');
|
||||
colon = uwsgi_get_last_char(colon, ':');
|
||||
}
|
||||
else {
|
||||
colon = uwsgi_get_last_char(file, ':');
|
||||
}
|
||||
|
||||
if (colon) {
|
||||
colon[0] = 0;
|
||||
if (colon[1] != 0) {
|
||||
object_asked = colon+1;
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("[uWSGI] getting JSON configuration from %s\n", file);
|
||||
|
||||
json_data = uwsgi_open_and_read(file, &len, 1, magic_table);
|
||||
|
||||
#ifdef JANSSON_MAJOR_VERSION
|
||||
root = json_loads(json_data, 0, &error);
|
||||
#else
|
||||
root = json_loads(json_data, &error);
|
||||
#endif
|
||||
|
||||
if (!root) {
|
||||
uwsgi_log("error parsing JSON data: line %d %s\n", error.line, error.text);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
config = json_object_get(root, object_asked);
|
||||
|
||||
if (!json_is_object(config)) {
|
||||
uwsgi_log("you must define a object named %s in your JSON data\n", object_asked);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
config_iter = json_object_iter(config);
|
||||
|
||||
while(config_iter) {
|
||||
key = json_object_iter_key(config_iter);
|
||||
config_value = json_object_iter_value(config_iter);
|
||||
|
||||
if (json_is_string(config_value)) {
|
||||
add_exported_option((char *)key, (char *) json_string_value(config_value), 0);
|
||||
}
|
||||
else if (json_is_true(config_value)) {
|
||||
add_exported_option((char *)key, strdup("1"), 0);
|
||||
}
|
||||
else if (json_is_false(config_value) || json_is_null(config_value)) {
|
||||
add_exported_option((char *)key, strdup("0"), 0);
|
||||
}
|
||||
else if (json_is_integer(config_value)) {
|
||||
add_exported_option((char *)key, uwsgi_num2str(json_integer_value(config_value)), 0);
|
||||
}
|
||||
else if (json_is_array(config_value)) {
|
||||
for(i=0;i<(int)json_array_size(config_value);i++) {
|
||||
config_array_item = json_array_get(config_value, i);
|
||||
if (json_is_string(config_array_item)) {
|
||||
add_exported_option((char *)key, (char *) json_string_value(config_array_item), 0);
|
||||
}
|
||||
else if (json_is_true(config_array_item)) {
|
||||
add_exported_option((char *)key, strdup("1"), 0);
|
||||
}
|
||||
else if (json_is_false(config_array_item) || json_is_null(config_array_item)) {
|
||||
add_exported_option((char *)key, strdup("0"), 0);
|
||||
}
|
||||
else if (json_is_integer(config_array_item)) {
|
||||
add_exported_option((char *)key, uwsgi_num2str(json_integer_value(config_array_item)), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config_iter = json_object_iter_next(config, config_iter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+369
@@ -0,0 +1,369 @@
|
||||
#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
|
||||
+631
@@ -0,0 +1,631 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
static struct uwsgi_lock_item *uwsgi_register_lock(char *id, int rw) {
|
||||
|
||||
struct uwsgi_lock_item *uli = uwsgi.registered_locks;
|
||||
if (!uli) {
|
||||
uwsgi.registered_locks = uwsgi_malloc_shared(sizeof(struct uwsgi_lock_item));
|
||||
uwsgi.registered_locks->id = id;
|
||||
uwsgi.registered_locks->pid = 0;
|
||||
if (rw) {
|
||||
uwsgi.registered_locks->lock_ptr = uwsgi_malloc_shared(uwsgi.rwlock_size);
|
||||
}
|
||||
else {
|
||||
uwsgi.registered_locks->lock_ptr = uwsgi_malloc_shared(uwsgi.lock_size);
|
||||
}
|
||||
uwsgi.registered_locks->rw = rw;
|
||||
uwsgi.registered_locks->next = NULL;
|
||||
return uwsgi.registered_locks;
|
||||
}
|
||||
|
||||
while(uli) {
|
||||
if (!uli->next) {
|
||||
uli->next = uwsgi_malloc_shared(sizeof(struct uwsgi_lock_item));
|
||||
if (rw) {
|
||||
uli->next->lock_ptr = uwsgi_malloc_shared(uwsgi.rwlock_size);
|
||||
}
|
||||
else {
|
||||
uli->next->lock_ptr = uwsgi_malloc_shared(uwsgi.lock_size);
|
||||
}
|
||||
uli->next->id = id;
|
||||
uli->next->pid = 0;
|
||||
uli->next->rw = rw;
|
||||
uli->next->next = NULL;
|
||||
return uli->next;
|
||||
}
|
||||
uli = uli->next;
|
||||
}
|
||||
|
||||
uwsgi_log("*** DANGER: unable to allocate lock %s ***\n", id);
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
#ifdef UWSGI_LOCK_USE_MUTEX
|
||||
|
||||
#ifdef EOWNERDEAD
|
||||
#define UWSGI_LOCK_ENGINE_NAME "pthread robust mutexes"
|
||||
int uwsgi_pthread_robust_mutexes_enabled = 1;
|
||||
#else
|
||||
#define UWSGI_LOCK_ENGINE_NAME "pthread mutexes"
|
||||
#endif
|
||||
|
||||
#define UWSGI_LOCK_SIZE sizeof(pthread_mutex_t)
|
||||
|
||||
#ifdef OBSOLETE_LINUX_KERNEL
|
||||
#define UWSGI_RWLOCK_SIZE sizeof(pthread_mutex_t)
|
||||
#else
|
||||
#define UWSGI_RWLOCK_SIZE sizeof(pthread_rwlock_t)
|
||||
#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);
|
||||
|
||||
#ifdef EOWNERDEAD
|
||||
retry:
|
||||
#endif
|
||||
if (pthread_mutexattr_init(&attr)) {
|
||||
uwsgi_log("unable to allocate mutexattr structure\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) {
|
||||
uwsgi_log("unable to share mutex\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef EOWNERDEAD
|
||||
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);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pthread_mutex_init((pthread_mutex_t *) uli->lock_ptr, &attr)) {
|
||||
#ifdef EOWNERDEAD
|
||||
if (uwsgi_pthread_robust_mutexes_enabled) {
|
||||
uwsgi_log("!!! it looks like your kernel does not support pthread robust mutexes !!!\n");
|
||||
uwsgi_log("!!! falling back to standard pthread mutexes !!!\n");
|
||||
uwsgi_pthread_robust_mutexes_enabled = 0;
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
goto retry;
|
||||
}
|
||||
#endif
|
||||
uwsgi_log("unable to initialize mutex\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
|
||||
#ifdef EOWNERDEAD
|
||||
if (!uwsgi_pthread_robust_mutexes_enabled) {
|
||||
uli->can_deadlock = 1;
|
||||
}
|
||||
#else
|
||||
uli->can_deadlock = 1;
|
||||
#endif
|
||||
|
||||
return uli;
|
||||
}
|
||||
|
||||
pid_t uwsgi_lock_fast_check(struct uwsgi_lock_item *uli) {
|
||||
|
||||
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) {
|
||||
#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);
|
||||
return 0;
|
||||
}
|
||||
return uli->pid;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_lock_fast(struct uwsgi_lock_item *uli) {
|
||||
|
||||
#ifdef EOWNERDEAD
|
||||
if (pthread_mutex_lock((pthread_mutex_t *) uli->lock_ptr) == EOWNERDEAD) {
|
||||
uwsgi_log("[deadlock-detector] a process holding a robust mutex died. recovering...\n");
|
||||
pthread_mutex_consistent_np((pthread_mutex_t *) uli->lock_ptr);
|
||||
}
|
||||
#else
|
||||
pthread_mutex_lock((pthread_mutex_t *) uli->lock_ptr);
|
||||
#endif
|
||||
uli->pid = uwsgi.mypid;
|
||||
}
|
||||
|
||||
void uwsgi_unlock_fast(struct uwsgi_lock_item *uli) {
|
||||
|
||||
pthread_mutex_unlock((pthread_mutex_t *) uli->lock_ptr);
|
||||
uli->pid = 0;
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_rlock_fast(struct uwsgi_lock_item *uli) {
|
||||
#ifdef OBSOLETE_LINUX_KERNEL
|
||||
uwsgi_lock_fast(uli);
|
||||
#else
|
||||
pthread_rwlock_rdlock((pthread_rwlock_t *) uli->lock_ptr);
|
||||
uli->pid = uwsgi.mypid;
|
||||
#endif
|
||||
}
|
||||
|
||||
void uwsgi_wlock_fast(struct uwsgi_lock_item *uli) {
|
||||
#ifdef OBSOLETE_LINUX_KERNEL
|
||||
uwsgi_lock_fast(uli);
|
||||
#else
|
||||
pthread_rwlock_wrlock((pthread_rwlock_t *) uli->lock_ptr);
|
||||
uli->pid = uwsgi.mypid;
|
||||
#endif
|
||||
}
|
||||
|
||||
void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) {
|
||||
#ifdef OBSOLETE_LINUX_KERNEL
|
||||
uwsgi_unlock_fast(uli);
|
||||
#else
|
||||
pthread_rwlock_unlock((pthread_rwlock_t *) uli->lock_ptr);
|
||||
uli->pid = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
struct uwsgi_lock_item *uwsgi_rwlock_fast_init(char *id) {
|
||||
|
||||
#ifdef OBSOLETE_LINUX_KERNEL
|
||||
return uwsgi_lock_fast_init(id);
|
||||
#else
|
||||
|
||||
pthread_rwlockattr_t attr;
|
||||
|
||||
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_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);
|
||||
}
|
||||
|
||||
pthread_rwlockattr_destroy(&attr);
|
||||
|
||||
uli->can_deadlock = 1;
|
||||
|
||||
return uli;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#elif defined(UWSGI_LOCK_USE_UMTX)
|
||||
|
||||
/* Warning: FreeBSD is still not ready for process-shared UMTX */
|
||||
|
||||
#include <machine/atomic.h>
|
||||
#include <sys/umtx.h>
|
||||
|
||||
#define UWSGI_LOCK_SIZE sizeof(struct umtx)
|
||||
#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_lock_fast_init(char *id) {
|
||||
struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0);
|
||||
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() );
|
||||
uli->pid = uwsgi.mypid;
|
||||
}
|
||||
|
||||
void uwsgi_unlock_fast(struct uwsgi_lock_item *uli) {
|
||||
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() );
|
||||
return 0;
|
||||
}
|
||||
return uli->pid;
|
||||
}
|
||||
|
||||
pid_t uwsgi_rwlock_fast_check(struct uwsgi_lock_item *uli) { return uwsgi_lock_fast_check(uli); }
|
||||
|
||||
#elif defined(UWSGI_LOCK_USE_POSIX_SEM)
|
||||
|
||||
#define UWSGI_LOCK_SIZE sizeof(sem_t)
|
||||
#define UWSGI_RWLOCK_SIZE sizeof(sem_t)
|
||||
#define UWSGI_LOCK_ENGINE_NAME "POSIX semaphores"
|
||||
|
||||
#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);
|
||||
uli->can_deadlock = 1;
|
||||
return uli;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void uwsgi_unlock_fast(struct uwsgi_lock_item *uli) {
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
#define UWSGI_LOCK_ENGINE_NAME "OSX spinlocks"
|
||||
#define UWSGI_LOCK_SIZE sizeof(OSSpinLock)
|
||||
#define UWSGI_RWLOCK_SIZE sizeof(OSSpinLock)
|
||||
|
||||
|
||||
struct uwsgi_lock_item *uwsgi_lock_fast_init(char *id) {
|
||||
|
||||
struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0);
|
||||
memset(uli->lock_ptr, 0, UWSGI_LOCK_SIZE);
|
||||
uli->can_deadlock = 1;
|
||||
return uli;
|
||||
}
|
||||
|
||||
void uwsgi_lock_fast(struct uwsgi_lock_item *uli) {
|
||||
|
||||
OSSpinLockLock((OSSpinLock *) uli->lock_ptr);
|
||||
uli->pid = uwsgi.mypid;
|
||||
}
|
||||
|
||||
void uwsgi_unlock_fast(struct uwsgi_lock_item *uli) {
|
||||
|
||||
OSSpinLockUnlock((OSSpinLock *) uli->lock_ptr);
|
||||
uli->pid = 0;
|
||||
}
|
||||
|
||||
pid_t uwsgi_lock_fast_check(struct uwsgi_lock_item *uli) {
|
||||
if (OSSpinLockTry((OSSpinLock *) uli->lock_ptr)) {
|
||||
OSSpinLockUnlock((OSSpinLock *) uli->lock_ptr);
|
||||
return 0;
|
||||
}
|
||||
return uli->pid;
|
||||
}
|
||||
|
||||
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);}
|
||||
|
||||
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); }
|
||||
|
||||
#else
|
||||
|
||||
#define uwsgi_lock_fast_init uwsgi_lock_ipcsem_init
|
||||
#define uwsgi_lock_fast_check uwsgi_lock_ipcsem_check
|
||||
#define uwsgi_lock_fast uwsgi_lock_ipcsem
|
||||
#define uwsgi_unlock_fast uwsgi_unlock_ipcsem
|
||||
|
||||
#define uwsgi_rwlock_fast_init uwsgi_rwlock_ipcsem_init
|
||||
#define uwsgi_rwlock_fast_check uwsgi_rwlock_ipcsem_check
|
||||
|
||||
#define uwsgi_rlock_fast uwsgi_rlock_ipcsem
|
||||
#define uwsgi_wlock_fast uwsgi_wlock_ipcsem
|
||||
#define uwsgi_rwunlock_fast uwsgi_rwunlock_ipcsem
|
||||
|
||||
#define UWSGI_LOCK_SIZE sizeof(int)
|
||||
#define UWSGI_RWLOCK_SIZE sizeof(int)
|
||||
|
||||
#define UWSGI_LOCK_ENGINE_NAME "ipcsem"
|
||||
|
||||
#define UWSGI_IPCSEM_ATEXIT 1
|
||||
|
||||
#endif
|
||||
|
||||
struct uwsgi_lock_item *uwsgi_lock_ipcsem_init(char *id) {
|
||||
|
||||
// used by ftok
|
||||
static int counter = 1;
|
||||
union semun {
|
||||
int val;
|
||||
struct semid_ds *buf;
|
||||
ushort *array;
|
||||
} semu ;
|
||||
int semid;
|
||||
key_t myKey;
|
||||
|
||||
struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0);
|
||||
|
||||
if (uwsgi.ftok) {
|
||||
myKey = ftok(uwsgi.ftok, counter);
|
||||
if (myKey < 0) {
|
||||
uwsgi_error("ftok()");
|
||||
exit(1);
|
||||
}
|
||||
counter++;
|
||||
semid = semget(myKey, 1, IPC_CREAT|0666);
|
||||
}
|
||||
else {
|
||||
semid = semget(IPC_PRIVATE, 1, IPC_CREAT|IPC_EXCL| 0666);
|
||||
}
|
||||
|
||||
if (semid < 0) {
|
||||
uwsgi_error("semget()");
|
||||
exit(1);
|
||||
}
|
||||
// do this now, to allows triggering of atexit hook in case of problems
|
||||
memcpy(uli->lock_ptr, &semid, sizeof(int));
|
||||
|
||||
semu.val = 1;
|
||||
if (semctl(semid, 0, SETVAL, semu)) {
|
||||
uwsgi_error("semctl()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return uli;
|
||||
}
|
||||
|
||||
void uwsgi_lock_ipcsem(struct uwsgi_lock_item *uli) {
|
||||
|
||||
int semid;
|
||||
struct sembuf sb;
|
||||
sb.sem_num = 0;
|
||||
sb.sem_op = -1;
|
||||
sb.sem_flg = SEM_UNDO;
|
||||
|
||||
memcpy(&semid, uli->lock_ptr, sizeof(int));
|
||||
|
||||
if (semop(semid, &sb, 1)) {
|
||||
uwsgi_error("semop()");
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_unlock_ipcsem(struct uwsgi_lock_item *uli) {
|
||||
|
||||
int semid;
|
||||
struct sembuf sb;
|
||||
sb.sem_num = 0;
|
||||
sb.sem_op = 1;
|
||||
sb.sem_flg = SEM_UNDO;
|
||||
|
||||
memcpy(&semid, uli->lock_ptr, sizeof(int));
|
||||
|
||||
if (semop(semid, &sb, 1)) {
|
||||
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); }
|
||||
|
||||
// ipc cannot deadlock
|
||||
pid_t uwsgi_lock_ipcsem_check(struct uwsgi_lock_item *uli) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uwsgi_ipcsem_clear(void) {
|
||||
|
||||
struct uwsgi_lock_item *uli = uwsgi.registered_locks;
|
||||
|
||||
if (!uwsgi.workers) goto clear;
|
||||
|
||||
if (uwsgi.mywid == 0) goto clear;
|
||||
|
||||
if (uwsgi.master_process && getpid() == uwsgi.workers[0].pid) goto clear;
|
||||
|
||||
if (!uwsgi.master_process && uwsgi.mywid == 1) goto clear;
|
||||
|
||||
return;
|
||||
|
||||
clear:
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("removing sysvipc semaphores...\n");
|
||||
#endif
|
||||
while(uli) {
|
||||
int semid = 0;
|
||||
memcpy(&semid, uli->lock_ptr, sizeof(int));
|
||||
if (semctl(semid, 0, IPC_RMID)) {
|
||||
uwsgi_error("semctl()");
|
||||
}
|
||||
uli = uli->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pid_t uwsgi_rwlock_ipcsem_check(struct uwsgi_lock_item *uli) { return uwsgi_lock_ipcsem_check(uli); }
|
||||
|
||||
|
||||
void uwsgi_setup_locking() {
|
||||
|
||||
// use the fastest available locking
|
||||
if (uwsgi.lock_engine) {
|
||||
if (!strcmp(uwsgi.lock_engine, "ipcsem")) {
|
||||
uwsgi_log_initial("lock engine: ipcsem\n");
|
||||
atexit(uwsgi_ipcsem_clear);
|
||||
uwsgi.lock_ops.lock_init = uwsgi_lock_ipcsem_init;
|
||||
uwsgi.lock_ops.lock_check = uwsgi_lock_ipcsem_check;
|
||||
uwsgi.lock_ops.lock = uwsgi_lock_ipcsem;
|
||||
uwsgi.lock_ops.unlock = uwsgi_unlock_ipcsem;
|
||||
uwsgi.lock_ops.rwlock_init = uwsgi_rwlock_ipcsem_init;
|
||||
uwsgi.lock_ops.rwlock_check = uwsgi_rwlock_ipcsem_check;
|
||||
uwsgi.lock_ops.rlock = uwsgi_rlock_ipcsem;
|
||||
uwsgi.lock_ops.wlock = uwsgi_wlock_ipcsem;
|
||||
uwsgi.lock_ops.rwunlock = uwsgi_rwunlock_ipcsem;
|
||||
uwsgi.lock_size = 8;
|
||||
uwsgi.rwlock_size = 8;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log_initial("lock engine: %s\n", UWSGI_LOCK_ENGINE_NAME);
|
||||
#ifdef UWSGI_IPCSEM_ATEXIT
|
||||
atexit(uwsgi_ipcsem_clear);
|
||||
#endif
|
||||
uwsgi.lock_ops.lock_init = uwsgi_lock_fast_init;
|
||||
uwsgi.lock_ops.lock_check = uwsgi_lock_fast_check;
|
||||
uwsgi.lock_ops.lock = uwsgi_lock_fast;
|
||||
uwsgi.lock_ops.unlock = uwsgi_unlock_fast;
|
||||
uwsgi.lock_ops.rwlock_init = uwsgi_rwlock_fast_init;
|
||||
uwsgi.lock_ops.rwlock_check = uwsgi_rwlock_fast_check;
|
||||
uwsgi.lock_ops.rlock = uwsgi_rlock_fast;
|
||||
uwsgi.lock_ops.wlock = uwsgi_wlock_fast;
|
||||
uwsgi.lock_ops.rwunlock = uwsgi_rwunlock_fast;
|
||||
uwsgi.lock_size = UWSGI_LOCK_SIZE;
|
||||
uwsgi.rwlock_size = UWSGI_RWLOCK_SIZE;
|
||||
|
||||
// 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)));
|
||||
}
|
||||
|
||||
// event queue lock (mitigate same event on multiple queues)
|
||||
if (uwsgi.threads > 1) {
|
||||
pthread_mutex_init(&uwsgi.thunder_mutex, NULL);
|
||||
}
|
||||
|
||||
if (uwsgi.master_process) {
|
||||
// signal table lock
|
||||
uwsgi.signal_table_lock = uwsgi_lock_init("signal");
|
||||
|
||||
// fmon table lock
|
||||
uwsgi.fmon_table_lock = uwsgi_lock_init("filemon");
|
||||
|
||||
// timer table lock
|
||||
uwsgi.timer_table_lock = uwsgi_lock_init("timer");
|
||||
|
||||
// probe table lock
|
||||
uwsgi.probe_table_lock = uwsgi_lock_init("probe");
|
||||
|
||||
// rb_timer table lock
|
||||
uwsgi.rb_timer_table_lock = uwsgi_lock_init("rbtimer");
|
||||
|
||||
// cron table lock
|
||||
uwsgi.cron_table_lock = uwsgi_lock_init("cron");
|
||||
}
|
||||
|
||||
uwsgi.rpc_table_lock = uwsgi_lock_init("rpc");
|
||||
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_fcntl_lock(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;
|
||||
|
||||
int ret = fcntl(fd, F_SETLKW, &fl);
|
||||
if (ret < 0)
|
||||
uwsgi_error("fcntl()");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (fcntl(fd, F_SETLK, &fl)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_deadlock_check(pid_t diedpid) {
|
||||
struct uwsgi_lock_item *uli = uwsgi.registered_locks;
|
||||
while (uli) {
|
||||
if (!uli->can_deadlock)
|
||||
goto nextlock;
|
||||
pid_t locked_pid = 0;
|
||||
if (uli->rw) {
|
||||
locked_pid = uwsgi_rwlock_check(uli);
|
||||
}
|
||||
else {
|
||||
locked_pid = uwsgi_lock_check(uli);
|
||||
}
|
||||
if (locked_pid == diedpid) {
|
||||
uwsgi_log("[deadlock-detector] pid %d was holding lock %s (%p)\n", (int) diedpid, uli->id, uli->lock_ptr);
|
||||
if (uli->rw) {
|
||||
uwsgi_rwunlock(uli);
|
||||
}
|
||||
else {
|
||||
uwsgi_unlock(uli);
|
||||
}
|
||||
}
|
||||
nextlock:
|
||||
uli = uli->next;
|
||||
}
|
||||
|
||||
}
|
||||
+1009
File diff suppressed because it is too large
Load Diff
+122
@@ -0,0 +1,122 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct wsgi_request *threaded_current_wsgi_req() {
|
||||
return pthread_getspecific(uwsgi.tur_key);
|
||||
}
|
||||
struct wsgi_request *simple_current_wsgi_req() {
|
||||
return uwsgi.wsgi_req;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_register_loop(char *name, void *loop) {
|
||||
|
||||
if (uwsgi.loops_cnt >= MAX_LOOPS) {
|
||||
uwsgi_log("you can define %d loops at max\n", MAX_LOOPS);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi.loops[uwsgi.loops_cnt].name = name;
|
||||
uwsgi.loops[uwsgi.loops_cnt].loop = loop;
|
||||
uwsgi.loops_cnt++;
|
||||
}
|
||||
|
||||
void *uwsgi_get_loop(char *name) {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < uwsgi.loops_cnt; i++) {
|
||||
if (!strcmp(name, uwsgi.loops[i].name)) {
|
||||
return uwsgi.loops[i].loop;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *simple_loop(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// initialize the main event queue to monitor sockets
|
||||
int main_queue = event_queue_init();
|
||||
|
||||
uwsgi_add_sockets_to_queue(main_queue, core_id);
|
||||
|
||||
if (uwsgi.signal_socket > -1) {
|
||||
event_queue_add_fd_read(main_queue, uwsgi.signal_socket);
|
||||
event_queue_add_fd_read(main_queue, uwsgi.my_signal_socket);
|
||||
}
|
||||
|
||||
|
||||
// ok we are ready, let's start managing requests and signals
|
||||
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
|
||||
|
||||
wsgi_req_setup(wsgi_req, core_id, NULL);
|
||||
|
||||
if (wsgi_req_accept(main_queue, wsgi_req)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (wsgi_req_recv(wsgi_req)) {
|
||||
uwsgi_destroy_request(wsgi_req);
|
||||
continue;
|
||||
}
|
||||
|
||||
uwsgi_close_request(wsgi_req);
|
||||
}
|
||||
|
||||
// end of the loop
|
||||
if (uwsgi.workers[uwsgi.mywid].destroy && uwsgi.workers[0].pid > 0) {
|
||||
#ifdef __APPLE__
|
||||
kill(uwsgi.workers[0].pid, SIGTERM);
|
||||
#else
|
||||
if (uwsgi.propagate_touch) {
|
||||
kill(uwsgi.workers[0].pid, SIGHUP);
|
||||
}
|
||||
else {
|
||||
gracefully_kill(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
+1593
File diff suppressed because it is too large
Load Diff
+1105
File diff suppressed because it is too large
Load Diff
+448
@@ -0,0 +1,448 @@
|
||||
/*
|
||||
|
||||
uWSGI mules are very simple workers only managing signals or running custom code in background.
|
||||
|
||||
By default they born in signal-only mode, but if you patch them (passing the script/code to run) they will became fully customized daemons.
|
||||
|
||||
*/
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_mule_handler(void);
|
||||
|
||||
void mule_send_msg(int fd, char *message, size_t len) {
|
||||
|
||||
socklen_t so_bufsize_len = sizeof(int);
|
||||
int so_bufsize = 0;
|
||||
|
||||
if (write(fd, message, len) != (ssize_t) len) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &so_bufsize, &so_bufsize_len)) {
|
||||
uwsgi_error("getsockopt()");
|
||||
}
|
||||
uwsgi_log("*** MULE MSG QUEUE IS FULL: buffer size %d bytes (you can tune it with --signal-bufsize) ***\n", so_bufsize);
|
||||
}
|
||||
else {
|
||||
uwsgi_error("mule_send_msg()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_mule(int id) {
|
||||
|
||||
int i;
|
||||
|
||||
pid_t pid = uwsgi_fork(uwsgi.mules[id-1].name);
|
||||
if (pid == 0) {
|
||||
#ifdef __linux__
|
||||
if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0,0,0)) {
|
||||
uwsgi_error("prctl()");
|
||||
}
|
||||
#endif
|
||||
uwsgi.muleid = id;
|
||||
// avoid race conditions
|
||||
uwsgi.mules[id-1].id = id;
|
||||
uwsgi.mules[id-1].pid = getpid();
|
||||
|
||||
uwsgi_fixup_fds(0, id, NULL);
|
||||
|
||||
uwsgi.my_signal_socket = uwsgi.mules[id-1].signal_pipe[1];
|
||||
uwsgi.signal_socket = uwsgi.shared->mule_signal_pipe[1];
|
||||
|
||||
uwsgi_close_all_sockets();
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->master_fixup) {
|
||||
uwsgi.p[i]->master_fixup(1);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->post_fork) {
|
||||
uwsgi.p[i]->post_fork();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (uwsgi.mules[id-1].patch) {
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->mule) {
|
||||
if (uwsgi.p[i]->mule(uwsgi.mules[id-1].patch) == 1) {
|
||||
// never here
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_mule_handler();
|
||||
}
|
||||
else if (pid > 0) {
|
||||
uwsgi.mules[id-1].id = id;
|
||||
uwsgi.mules[id-1].pid = pid;
|
||||
uwsgi_log("spawned uWSGI mule %d (pid: %d)\n", id, (int) pid);
|
||||
}
|
||||
}
|
||||
|
||||
int uwsgi_farm_has_mule(struct uwsgi_farm *farm, int muleid) {
|
||||
|
||||
struct uwsgi_mule_farm *umf = farm->mules;
|
||||
|
||||
while(umf) {
|
||||
if (umf->mule->id == muleid) {
|
||||
return 1;
|
||||
}
|
||||
umf = umf->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int farm_has_signaled(int fd) {
|
||||
|
||||
int i;
|
||||
for(i=0;i<uwsgi.farms_cnt;i++) {
|
||||
struct uwsgi_mule_farm *umf = uwsgi.farms[i].mules;
|
||||
while(umf) {
|
||||
if (umf->mule->id == uwsgi.muleid && uwsgi.farms[i].signal_pipe[1] == fd) {
|
||||
return 1;
|
||||
}
|
||||
umf = umf->next;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int farm_has_msg(int fd) {
|
||||
|
||||
int i;
|
||||
for(i=0;i<uwsgi.farms_cnt;i++) {
|
||||
struct uwsgi_mule_farm *umf = uwsgi.farms[i].mules;
|
||||
while(umf) {
|
||||
if (umf->mule->id == uwsgi.muleid && uwsgi.farms[i].queue_pipe[1] == fd) {
|
||||
return 1;
|
||||
}
|
||||
umf = umf->next;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_mule_add_farm_to_queue(int queue) {
|
||||
|
||||
int i;
|
||||
for(i=0;i<uwsgi.farms_cnt;i++) {
|
||||
if (uwsgi_farm_has_mule(&uwsgi.farms[i], uwsgi.muleid)) {
|
||||
event_queue_add_fd_read(queue, uwsgi.farms[i].signal_pipe[1]);
|
||||
event_queue_add_fd_read(queue, uwsgi.farms[i].queue_pipe[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_mule_handler() {
|
||||
|
||||
ssize_t len;
|
||||
uint8_t uwsgi_signal;
|
||||
int rlen;
|
||||
int interesting_fd;
|
||||
|
||||
// this must be configurable
|
||||
char message[65536];
|
||||
|
||||
int mule_queue = event_queue_init();
|
||||
|
||||
event_queue_add_fd_read(mule_queue, uwsgi.signal_socket);
|
||||
event_queue_add_fd_read(mule_queue, uwsgi.my_signal_socket);
|
||||
event_queue_add_fd_read(mule_queue, uwsgi.mules[uwsgi.muleid-1].queue_pipe[1]);
|
||||
event_queue_add_fd_read(mule_queue, uwsgi.shared->mule_queue_pipe[1]);
|
||||
|
||||
uwsgi_mule_add_farm_to_queue(mule_queue);
|
||||
|
||||
for(;;) {
|
||||
rlen = event_queue_wait(mule_queue, -1, &interesting_fd);
|
||||
if (rlen <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (interesting_fd == uwsgi.signal_socket || interesting_fd == uwsgi.my_signal_socket || farm_has_signaled(interesting_fd)) {
|
||||
len = read(interesting_fd, &uwsgi_signal, 1);
|
||||
if (len <= 0) {
|
||||
uwsgi_log_verbose("uWSGI mule %d braying: my master died, i will follow him...\n", uwsgi.muleid);
|
||||
end_me(0);
|
||||
}
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log_verbose("master sent signal %d to mule %d\n", uwsgi_signal, uwsgi.muleid);
|
||||
#endif
|
||||
if (uwsgi_signal_handler(uwsgi_signal)) {
|
||||
uwsgi_log_verbose("error managing signal %d on mule %d\n", uwsgi_signal, uwsgi.muleid);
|
||||
}
|
||||
}
|
||||
else if (interesting_fd == uwsgi.mules[uwsgi.muleid-1].queue_pipe[1] || interesting_fd == uwsgi.shared->mule_queue_pipe[1] || farm_has_msg(interesting_fd)) {
|
||||
len = read(interesting_fd, message, 65536);
|
||||
if (len < 0) {
|
||||
uwsgi_error("read()");
|
||||
}
|
||||
else {
|
||||
int i,found = 0;
|
||||
for(i=0;i<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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_mule *get_mule_by_id(int id) {
|
||||
|
||||
int i;
|
||||
|
||||
for(i=0;i<uwsgi.mules_cnt;i++) {
|
||||
if (uwsgi.mules[i].id == id) {
|
||||
return &uwsgi.mules[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_farm *get_farm_by_name(char *name) {
|
||||
|
||||
int i;
|
||||
|
||||
for(i=0;i<uwsgi.farms_cnt;i++) {
|
||||
if (!strcmp(uwsgi.farms[i].name, name)) {
|
||||
return &uwsgi.farms[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_mule_farm *uwsgi_mule_farm_new(struct uwsgi_mule_farm **umf, struct uwsgi_mule *um) {
|
||||
|
||||
struct uwsgi_mule_farm *uwsgi_mf = *umf, *old_umf;
|
||||
|
||||
if (!uwsgi_mf) {
|
||||
*umf = uwsgi_malloc(sizeof(struct uwsgi_mule_farm));
|
||||
uwsgi_mf = *umf;
|
||||
}
|
||||
else {
|
||||
while(uwsgi_mf) {
|
||||
old_umf = uwsgi_mf;
|
||||
uwsgi_mf = uwsgi_mf->next;
|
||||
}
|
||||
|
||||
uwsgi_mf = uwsgi_malloc(sizeof(struct uwsgi_mule_farm));
|
||||
old_umf->next = uwsgi_mf;
|
||||
}
|
||||
|
||||
uwsgi_mf->mule = um;
|
||||
uwsgi_mf->next = NULL;
|
||||
|
||||
return uwsgi_mf;
|
||||
}
|
||||
|
||||
ssize_t uwsgi_mule_get_msg(int manage_signals, int manage_farms, char *message, size_t buffer_size, int timeout) {
|
||||
|
||||
ssize_t len = 0;
|
||||
struct pollfd *mulepoll;
|
||||
int count = 4;
|
||||
int farms_count = 0;
|
||||
uint8_t uwsgi_signal;
|
||||
int i;
|
||||
|
||||
if (uwsgi.muleid == 0) return -1;
|
||||
|
||||
if (manage_signals) count = 2;
|
||||
|
||||
if (!manage_farms) goto next;
|
||||
|
||||
for(i=0;i<uwsgi.farms_cnt;i++) {
|
||||
if (uwsgi_farm_has_mule(&uwsgi.farms[i], uwsgi.muleid)) farms_count++;
|
||||
}
|
||||
next:
|
||||
|
||||
if (timeout > -1) timeout = timeout*1000;
|
||||
|
||||
mulepoll = uwsgi_malloc(sizeof(struct pollfd) * (count+farms_count));
|
||||
|
||||
mulepoll[0].fd = uwsgi.mules[uwsgi.muleid-1].queue_pipe[1];
|
||||
mulepoll[0].events = POLLIN;
|
||||
mulepoll[1].fd = uwsgi.shared->mule_queue_pipe[1];
|
||||
mulepoll[1].events = POLLIN;
|
||||
if (count > 2) {
|
||||
mulepoll[2].fd = uwsgi.signal_socket;
|
||||
mulepoll[2].events = POLLIN;
|
||||
mulepoll[3].fd = uwsgi.my_signal_socket;
|
||||
mulepoll[3].events = POLLIN;
|
||||
}
|
||||
|
||||
if (farms_count > 0) {
|
||||
int tmp_cnt = 0;
|
||||
for(i=0;i<uwsgi.farms_cnt;i++) {
|
||||
if (uwsgi_farm_has_mule(&uwsgi.farms[i], uwsgi.muleid)) {
|
||||
mulepoll[count+tmp_cnt].fd = uwsgi.farms[i].queue_pipe[1];
|
||||
mulepoll[count+tmp_cnt].events = POLLIN;
|
||||
tmp_cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ret = poll(mulepoll, count+farms_count, timeout);
|
||||
if (ret <= 0) {
|
||||
uwsgi_error("poll");
|
||||
}
|
||||
else {
|
||||
if (mulepoll[0].revents & POLLIN) {
|
||||
len = read(uwsgi.mules[uwsgi.muleid-1].queue_pipe[1], message, buffer_size);
|
||||
}
|
||||
else if (mulepoll[1].revents & POLLIN) {
|
||||
len = read(uwsgi.shared->mule_queue_pipe[1], message, buffer_size);
|
||||
}
|
||||
else {
|
||||
if (count > 2) {
|
||||
int interesting_fd = -1;
|
||||
if (mulepoll[2].revents & POLLIN) {
|
||||
interesting_fd = mulepoll[2].fd;
|
||||
}
|
||||
else if (mulepoll[3].revents & POLLIN) {
|
||||
interesting_fd = mulepoll[3].fd;
|
||||
}
|
||||
|
||||
if (interesting_fd > -1) {
|
||||
len = read(interesting_fd, &uwsgi_signal, 1);
|
||||
if (len <= 0) {
|
||||
uwsgi_log_verbose("uWSGI mule %d braying: my master died, i will follow him...\n", uwsgi.muleid);
|
||||
end_me(0);
|
||||
}
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log_verbose("master sent signal %d to mule %d\n", uwsgi_signal, uwsgi.muleid);
|
||||
#endif
|
||||
if (uwsgi_signal_handler(uwsgi_signal)) {
|
||||
uwsgi_log_verbose("error managing signal %d on mule %d\n", uwsgi_signal, uwsgi.mywid);
|
||||
}
|
||||
// set the error condition
|
||||
len = -1;
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
|
||||
// read messages in the farm
|
||||
for(i=0;i<farms_count;i++) {
|
||||
if (mulepoll[count+i].revents & POLLIN) {
|
||||
len = read(mulepoll[count+i].fd, message, buffer_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (len < 0) {
|
||||
uwsgi_error("read()");
|
||||
goto clear;
|
||||
}
|
||||
|
||||
clear:
|
||||
free(mulepoll);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_opt_add_mule(char *opt, char *value, void *foobar) {
|
||||
|
||||
uwsgi.mules_cnt++;
|
||||
uwsgi_string_new_list(&uwsgi.mules_patches, value);
|
||||
}
|
||||
|
||||
void uwsgi_opt_add_mules(char *opt, char *value, void *foobar) {
|
||||
int i;
|
||||
|
||||
for(i=0;i<atoi(value);i++) {
|
||||
uwsgi.mules_cnt++;
|
||||
uwsgi_string_new_list(&uwsgi.mules_patches, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_opt_add_farm(char *opt, char *value, void *foobar) {
|
||||
uwsgi.farms_cnt++;
|
||||
uwsgi_string_new_list(&uwsgi.farms_list, value);
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_setup_mules_and_farms() {
|
||||
int i;
|
||||
if (uwsgi.mules_cnt > 0) {
|
||||
uwsgi.mules = (struct uwsgi_mule *) uwsgi_calloc_shared(sizeof(struct uwsgi_mule) * uwsgi.mules_cnt);
|
||||
|
||||
create_signal_pipe(uwsgi.shared->mule_signal_pipe);
|
||||
create_signal_pipe(uwsgi.shared->mule_queue_pipe);
|
||||
|
||||
for (i = 0; i < uwsgi.mules_cnt; i++) {
|
||||
// create the socket pipe
|
||||
create_signal_pipe(uwsgi.mules[i].signal_pipe);
|
||||
create_signal_pipe(uwsgi.mules[i].queue_pipe);
|
||||
|
||||
uwsgi.mules[i].id = i + 1;
|
||||
|
||||
snprintf(uwsgi.mules[i].name, 0xff, "uWSGI mule %d", i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.farms_cnt > 0) {
|
||||
uwsgi.farms = (struct uwsgi_farm *) uwsgi_calloc_shared(sizeof(struct uwsgi_farm) * uwsgi.farms_cnt);
|
||||
|
||||
struct uwsgi_string_list *farm_name = uwsgi.farms_list;
|
||||
for (i = 0; i < uwsgi.farms_cnt; i++) {
|
||||
|
||||
char *farm_value = uwsgi_str(farm_name->value);
|
||||
|
||||
char *mules_list = strchr(farm_value, ':');
|
||||
if (!mules_list) {
|
||||
uwsgi_log("invalid farm value (%s) must be in the form name:mule[,muleN].\n", farm_value);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
mules_list[0] = 0;
|
||||
mules_list++;
|
||||
|
||||
strncpy(uwsgi.farms[i].name, farm_value, 0xff);
|
||||
|
||||
// create the socket pipe
|
||||
create_signal_pipe(uwsgi.farms[i].signal_pipe);
|
||||
create_signal_pipe(uwsgi.farms[i].queue_pipe);
|
||||
|
||||
char *p = strtok(mules_list, ",");
|
||||
while (p != NULL) {
|
||||
struct uwsgi_mule *um = get_mule_by_id(atoi(p));
|
||||
if (!um) {
|
||||
uwsgi_log("invalid mule id: %s\n", p);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_mule_farm_new(&uwsgi.farms[i].mules, um);
|
||||
|
||||
p = strtok(NULL, ",");
|
||||
}
|
||||
uwsgi_log("created farm %d name: %s mules:%s\n", i + 1, uwsgi.farms[i].name, strchr(farm_name->value, ':') + 1);
|
||||
|
||||
farm_name = farm_name->next;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
|
||||
|
||||
void uwsgi_systemd_notify(char *message) {
|
||||
|
||||
struct msghdr *msghdr = (struct msghdr *) uwsgi.notification_object;
|
||||
struct iovec *iovec = msghdr->msg_iov;
|
||||
|
||||
iovec[0].iov_base = "STATUS=";
|
||||
iovec[0].iov_len = 7;
|
||||
|
||||
iovec[1].iov_base = message;
|
||||
iovec[1].iov_len = strlen(message);
|
||||
|
||||
iovec[2].iov_base = "\n";
|
||||
iovec[2].iov_len = 1;
|
||||
|
||||
msghdr->msg_iovlen = 3;
|
||||
|
||||
sendmsg(uwsgi.notification_fd, msghdr, 0);
|
||||
}
|
||||
|
||||
void uwsgi_systemd_notify_ready(void) {
|
||||
|
||||
struct msghdr *msghdr = (struct msghdr *) uwsgi.notification_object;
|
||||
struct iovec *iovec = msghdr->msg_iov;
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_systemd_init(char *systemd_socket) {
|
||||
|
||||
struct sockaddr_un *sd_sun;
|
||||
struct msghdr *msghdr;
|
||||
|
||||
uwsgi.notification_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if (uwsgi.notification_fd < 0) {
|
||||
uwsgi_error("socket()");
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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_name = sd_sun;
|
||||
msghdr->msg_namelen = sizeof(struct sockaddr_un);
|
||||
|
||||
uwsgi.notification_object = msghdr;
|
||||
|
||||
uwsgi.notify = uwsgi_systemd_notify;
|
||||
uwsgi.notify_ready = uwsgi_systemd_notify_ready;
|
||||
|
||||
}
|
||||
+307
@@ -0,0 +1,307 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#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 *p = strtok(buf, "\n");
|
||||
while(p) {
|
||||
char *equal = strchr(p, '=');
|
||||
if (equal) {
|
||||
*equal = 0;
|
||||
if (!strcmp(p, "requires")) {
|
||||
uwsgi_load_plugin(-1, equal+1, NULL);
|
||||
}
|
||||
}
|
||||
p = strtok(NULL, "\n");
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int plugin_already_loaded(const char *plugin) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->name) {
|
||||
if (!strcmp(plugin, uwsgi.p[i]->name)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%s plugin already available\n", plugin);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (uwsgi.p[i]->alias) {
|
||||
if (!strcmp(plugin, uwsgi.p[i]->alias)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%s plugin already available\n", plugin);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0;i<uwsgi.gp_cnt;i++) {
|
||||
|
||||
if (uwsgi.gp[i]->name) {
|
||||
if (!strcmp(plugin, uwsgi.gp[i]->name)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%s plugin already available\n", plugin);
|
||||
#endif
|
||||
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);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) {
|
||||
|
||||
void *plugin_handle = NULL;
|
||||
char *plugin_abs_path = NULL;
|
||||
char *plugin_filename = NULL;
|
||||
|
||||
int need_free = 0;
|
||||
char *plugin_name = plugin;
|
||||
char *plugin_symbol_name_start = plugin;
|
||||
|
||||
|
||||
struct uwsgi_plugin *up;
|
||||
char linkpath_buf[1024], linkpath[1024];
|
||||
int linkpath_size;
|
||||
|
||||
char *colon = strchr(plugin_name, ':');
|
||||
if (colon) {
|
||||
colon[0] = 0;
|
||||
modifier = atoi(plugin_name);
|
||||
plugin_name = colon+1;
|
||||
colon[0] = ':';
|
||||
}
|
||||
|
||||
if (!uwsgi_endswith(plugin_name, "_plugin.so")) {
|
||||
plugin_name = uwsgi_concat2(plugin_name, "_plugin.so");
|
||||
need_free = 1;
|
||||
}
|
||||
|
||||
plugin_symbol_name_start = plugin_name;
|
||||
|
||||
// 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());
|
||||
goto end;
|
||||
}
|
||||
plugin_symbol_name_start = uwsgi_get_last_char(plugin_name, '/');
|
||||
plugin_symbol_name_start++;
|
||||
plugin_abs_path = plugin_name;
|
||||
goto success;
|
||||
}
|
||||
|
||||
// step dir, check for user-supplied plugins directory
|
||||
struct uwsgi_string_list *pdir = uwsgi.plugins_dir;
|
||||
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;
|
||||
//free(plugin_filename);
|
||||
goto success;
|
||||
}
|
||||
free(plugin_filename);
|
||||
plugin_filename = NULL;
|
||||
pdir = pdir->next;
|
||||
}
|
||||
|
||||
// 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 (!has_option)
|
||||
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);
|
||||
memset(linkpath, 0, 1024);
|
||||
if ((linkpath_size = readlink(plugin_abs_path, linkpath_buf, 1023)) > 0) {
|
||||
do {
|
||||
linkpath_buf[linkpath_size] = '\0';
|
||||
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;
|
||||
}
|
||||
else {
|
||||
slash++;
|
||||
}
|
||||
plugin_entry_symbol = uwsgi_concat2n(slash, strlen(slash)-3, "",0);
|
||||
up = dlsym(plugin_handle, plugin_entry_symbol);
|
||||
}
|
||||
}
|
||||
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()");
|
||||
}
|
||||
if (need_free)
|
||||
free(plugin_name);
|
||||
if (plugin_filename)
|
||||
free(plugin_filename);
|
||||
free(plugin_entry_symbol);
|
||||
return NULL;
|
||||
}
|
||||
if (plugin_already_loaded(up->name)) {
|
||||
if (dlclose(plugin_handle)) {
|
||||
uwsgi_error("dlclose()");
|
||||
}
|
||||
if (need_free)
|
||||
free(plugin_name);
|
||||
if (plugin_filename)
|
||||
free(plugin_filename);
|
||||
free(plugin_entry_symbol);
|
||||
return NULL;
|
||||
}
|
||||
if (has_option) {
|
||||
struct uwsgi_option *op = up->options;
|
||||
int found = 0;
|
||||
while (op && op->name) {
|
||||
if (!strcmp(has_option, op->name)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
op++;
|
||||
}
|
||||
if (!found) {
|
||||
if (dlclose(plugin_handle)) {
|
||||
uwsgi_error("dlclose()");
|
||||
}
|
||||
if (need_free)
|
||||
free(plugin_name);
|
||||
if (plugin_filename)
|
||||
free(plugin_filename);
|
||||
free(plugin_entry_symbol);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
if (modifier != -1) {
|
||||
fill_plugin_table(modifier, up);
|
||||
up->modifier1 = modifier;
|
||||
}
|
||||
else {
|
||||
fill_plugin_table(up->modifier1, up);
|
||||
}
|
||||
if (need_free)
|
||||
free(plugin_name);
|
||||
if (plugin_filename)
|
||||
free(plugin_filename);
|
||||
free(plugin_entry_symbol);
|
||||
|
||||
if (up->on_load)
|
||||
up->on_load();
|
||||
return plugin_handle;
|
||||
}
|
||||
if (!has_option)
|
||||
uwsgi_log( "%s\n", dlerror());
|
||||
}
|
||||
|
||||
end:
|
||||
if (need_free)
|
||||
free(plugin_name);
|
||||
if (plugin_filename)
|
||||
free(plugin_filename);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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) {
|
||||
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)) {
|
||||
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);
|
||||
}
|
||||
pdir = pdir->next;
|
||||
}
|
||||
|
||||
// last step: search in compile-time plugin_dir
|
||||
d = opendir(UWSGI_PLUGIN_DIR);
|
||||
if (!d) return 0;
|
||||
|
||||
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;
|
||||
}
|
||||
free(filename);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
+2053
File diff suppressed because it is too large
Load Diff
+186
@@ -0,0 +1,186 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_init_queue() {
|
||||
if (!uwsgi.queue_blocksize)
|
||||
uwsgi.queue_blocksize = 8192;
|
||||
|
||||
if ((uwsgi.queue_blocksize * uwsgi.queue_size) % uwsgi.page_size != 0) {
|
||||
uwsgi_log("invalid queue size/blocksize %llu: must be a multiple of memory page size (%d bytes)\n", (unsigned long long) uwsgi.queue_blocksize, uwsgi.page_size);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (uwsgi.queue_store) {
|
||||
uwsgi.queue_filesize = uwsgi.queue_blocksize * uwsgi.queue_size + 16;
|
||||
int queue_fd;
|
||||
struct stat qst;
|
||||
|
||||
if (stat(uwsgi.queue_store, &qst)) {
|
||||
uwsgi_log("creating a new queue store file: %s\n", uwsgi.queue_store);
|
||||
queue_fd = open(uwsgi.queue_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
if (queue_fd >= 0) {
|
||||
// fill the queue store
|
||||
if (ftruncate(queue_fd, uwsgi.queue_filesize)) {
|
||||
uwsgi_log("ftruncate()");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((size_t) qst.st_size != uwsgi.queue_filesize || !S_ISREG(qst.st_mode)) {
|
||||
uwsgi_log("invalid queue store file. Please remove it or fix queue blocksize/items to match its size\n");
|
||||
exit(1);
|
||||
}
|
||||
queue_fd = open(uwsgi.queue_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
uwsgi_log("recovered queue from backing store file: %s\n", uwsgi.queue_store);
|
||||
}
|
||||
|
||||
if (queue_fd < 0) {
|
||||
uwsgi_error_open(uwsgi.queue_store);
|
||||
exit(1);
|
||||
}
|
||||
uwsgi.queue = mmap(NULL, uwsgi.queue_filesize, PROT_READ | PROT_WRITE, MAP_SHARED, queue_fd, 0);
|
||||
|
||||
// fix header
|
||||
uwsgi.queue_header = uwsgi.queue;
|
||||
uwsgi.queue+=16;
|
||||
}
|
||||
else {
|
||||
uwsgi.queue = mmap(NULL, (uwsgi.queue_blocksize * uwsgi.queue_size)+16, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
// fix header
|
||||
uwsgi.queue_header = uwsgi.queue;
|
||||
uwsgi.queue+=16;
|
||||
uwsgi.queue_header->pos = 0;
|
||||
uwsgi.queue_header->pull_pos = 0;
|
||||
}
|
||||
if (!uwsgi.queue) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
uwsgi.queue_lock = uwsgi_rwlock_init("queue");
|
||||
|
||||
uwsgi_log("*** Queue subsystem initialized: %dMB preallocated ***\n", (uwsgi.queue_blocksize * uwsgi.queue_size) / (1024 * 1024));
|
||||
}
|
||||
|
||||
char *uwsgi_queue_get(uint64_t index, uint64_t *size) {
|
||||
|
||||
struct uwsgi_queue_item *uqi;
|
||||
char *ptr = (char *) uwsgi.queue;
|
||||
|
||||
if (index >= uwsgi.queue_size) return NULL;
|
||||
|
||||
ptr = ptr + (uwsgi.queue_blocksize*index);
|
||||
|
||||
uqi = (struct uwsgi_queue_item *) ptr;
|
||||
|
||||
*size = uqi->size;
|
||||
|
||||
return ptr + sizeof(struct uwsgi_queue_item);
|
||||
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_queue_pop(uint64_t *size) {
|
||||
|
||||
struct uwsgi_queue_item *uqi;
|
||||
char *ptr = (char *) uwsgi.queue;
|
||||
|
||||
if (uwsgi.queue_header->pos == 0) {
|
||||
uwsgi.queue_header->pos = uwsgi.queue_size-1;
|
||||
}
|
||||
else {
|
||||
uwsgi.queue_header->pos--;
|
||||
}
|
||||
|
||||
ptr = ptr + (uwsgi.queue_blocksize*uwsgi.queue_header->pos);
|
||||
uqi = (struct uwsgi_queue_item *) ptr;
|
||||
|
||||
if (!uqi->size) return NULL;
|
||||
|
||||
*size = uqi->size;
|
||||
// remove item
|
||||
uqi->size = 0;
|
||||
|
||||
return ptr + sizeof(struct uwsgi_queue_item);
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_queue_pull(uint64_t *size) {
|
||||
|
||||
struct uwsgi_queue_item *uqi;
|
||||
char *ptr = (char *) uwsgi.queue;
|
||||
|
||||
ptr = ptr + (uwsgi.queue_blocksize*uwsgi.queue_header->pull_pos);
|
||||
uqi = (struct uwsgi_queue_item *) ptr;
|
||||
|
||||
if (!uqi->size) return NULL;
|
||||
|
||||
*size = uqi->size;
|
||||
|
||||
uwsgi.queue_header->pull_pos++;
|
||||
|
||||
if (uwsgi.queue_header->pull_pos >= uwsgi.queue_size) uwsgi.queue_header->pull_pos = 0;
|
||||
|
||||
// remove item
|
||||
uqi->size = 0;
|
||||
|
||||
return ptr + sizeof(struct uwsgi_queue_item);
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_queue_push(char *message, uint64_t size) {
|
||||
|
||||
struct uwsgi_queue_item *uqi;
|
||||
char *ptr = (char *) uwsgi.queue;
|
||||
|
||||
if (size > uwsgi.queue_blocksize + sizeof(struct uwsgi_queue_item))
|
||||
return 0;
|
||||
|
||||
if (!size) return 0;
|
||||
|
||||
ptr = ptr + (uwsgi.queue_blocksize*uwsgi.queue_header->pos);
|
||||
uqi = (struct uwsgi_queue_item *) ptr;
|
||||
|
||||
ptr += sizeof(struct uwsgi_queue_item);
|
||||
|
||||
uqi->size = size;
|
||||
uqi->ts = uwsgi_now();
|
||||
memcpy(ptr, message, size);
|
||||
|
||||
uwsgi.queue_header->pos++;
|
||||
|
||||
if (uwsgi.queue_header->pos >= uwsgi.queue_size) uwsgi.queue_header->pos = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int uwsgi_queue_set(uint64_t pos, char *message, uint64_t size) {
|
||||
|
||||
struct uwsgi_queue_item *uqi;
|
||||
char *ptr = (char *) uwsgi.queue;
|
||||
|
||||
if (size > uwsgi.queue_blocksize + sizeof(struct uwsgi_queue_item))
|
||||
return 0;
|
||||
|
||||
if (!size) return 0;
|
||||
|
||||
if (pos >= uwsgi.queue_size) return 0;
|
||||
|
||||
ptr = ptr + (uwsgi.queue_blocksize*pos);
|
||||
uqi = (struct uwsgi_queue_item *) ptr;
|
||||
|
||||
ptr += sizeof(struct uwsgi_queue_item);
|
||||
|
||||
uqi->size = size;
|
||||
uqi->ts = uwsgi_now();
|
||||
memcpy(ptr, message, size);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
|
||||
uWSGI timers implementation
|
||||
|
||||
based on Linux hrtimers and nginx timeout management.
|
||||
|
||||
rbtree with allowed duplicate keys is used
|
||||
|
||||
*/
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
struct rb_root *uwsgi_init_rb_timer() {
|
||||
|
||||
struct rb_root *u_rb_root = uwsgi_malloc(sizeof(struct rb_root));
|
||||
|
||||
u_rb_root->rb_node = NULL;
|
||||
|
||||
return u_rb_root;
|
||||
}
|
||||
|
||||
struct uwsgi_rb_timer *uwsgi_min_rb_timer(struct rb_root *root) {
|
||||
|
||||
struct rb_node *node = root->rb_node;
|
||||
|
||||
if (node == NULL) return NULL;
|
||||
|
||||
while(node->rb_left != NULL) {
|
||||
node = node->rb_left;
|
||||
}
|
||||
|
||||
return ((struct uwsgi_rb_timer *) node);
|
||||
}
|
||||
|
||||
struct uwsgi_rb_timer *uwsgi_add_rb_timer(struct rb_root *root, time_t key, void *data) {
|
||||
|
||||
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;
|
||||
|
||||
memset(urbt, 0, sizeof(struct uwsgi_rb_timer));
|
||||
|
||||
urbt->key = key;
|
||||
urbt->data = data;
|
||||
|
||||
while(*p) {
|
||||
parent = *p;
|
||||
|
||||
current_rb_timer = (struct uwsgi_rb_timer *) parent;
|
||||
|
||||
if (key <= current_rb_timer->key) {
|
||||
p = &(*p)->rb_left;
|
||||
}
|
||||
else {
|
||||
p = &(*p)->rb_right;
|
||||
}
|
||||
}
|
||||
|
||||
rb_link_node((struct rb_node *) urbt, parent, p);
|
||||
|
||||
rb_insert_color((struct rb_node *) urbt, root);
|
||||
|
||||
return urbt;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
#ifdef UWSGI_PCRE
|
||||
#include "uwsgi.h"
|
||||
|
||||
int uwsgi_regexp_build(char *re, pcre **pattern, pcre_extra **pattern_extra) {
|
||||
|
||||
const char *errstr;
|
||||
int erroff;
|
||||
|
||||
*pattern = pcre_compile( (const char *)re, 0, &errstr, &erroff, NULL);
|
||||
if (!*pattern) {
|
||||
uwsgi_log("pcre error: %s at offset %d\n", errstr, erroff);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*pattern_extra = (pcre_extra *) pcre_study((const pcre*)*pattern, 0, &errstr);
|
||||
if (*pattern_extra == NULL && errstr != NULL) {
|
||||
pcre_free(*pattern);
|
||||
uwsgi_log("pcre (study) error: %s\n", errstr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_regexp_match(pcre *pattern, pcre_extra *pattern_extra, char *subject, int length) {
|
||||
|
||||
return pcre_exec((const pcre*)pattern, (const pcre_extra *)pattern_extra, subject, length, 0, 0, NULL, 0 );
|
||||
}
|
||||
|
||||
int uwsgi_regexp_match_ovec(pcre *pattern, pcre_extra *pattern_extra, char *subject, int length, int *ovec, int n ) {
|
||||
|
||||
if (n > 0) {
|
||||
return pcre_exec((const pcre*)pattern, (const pcre_extra *)pattern_extra, subject, length, 0, 0, ovec, (n+1)*3 );
|
||||
}
|
||||
return pcre_exec((const pcre*)pattern, (const pcre_extra *)pattern_extra, subject, length, 0, 0, NULL, 0 );
|
||||
}
|
||||
|
||||
int uwsgi_regexp_ovector(pcre *pattern, pcre_extra *pattern_extra) {
|
||||
|
||||
int n;
|
||||
|
||||
if (pcre_fullinfo((const pcre*)pattern, (const pcre_extra *)pattern_extra, PCRE_INFO_CAPTURECOUNT, &n))
|
||||
return 0;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
char *uwsgi_regexp_apply_ovec(char *src, int src_n, char *dst, int dst_n, int *ovector, int n) {
|
||||
|
||||
int i;
|
||||
int dollar = 0;
|
||||
|
||||
char *res = uwsgi_malloc( dst_n + (src_n * n) + 1);
|
||||
char *ptr = res;
|
||||
|
||||
for(i=0;i<dst_n;i++) {
|
||||
if (dollar) {
|
||||
if (isdigit((int)dst[i])) {
|
||||
int pos = (dst[i] - 48);
|
||||
if (pos <= n) {
|
||||
pos = pos * 2;
|
||||
memcpy(ptr, src + ovector[pos], ovector[pos+1]-ovector[pos]);
|
||||
ptr+=ovector[pos+1]-ovector[pos];
|
||||
}
|
||||
}
|
||||
else {
|
||||
*ptr++= dst[i];
|
||||
}
|
||||
dollar = 0;
|
||||
}
|
||||
else {
|
||||
if (dst[i] == '$') {
|
||||
dollar = 1;
|
||||
}
|
||||
else {
|
||||
*ptr++= dst[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*ptr++= 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
#ifdef UWSGI_ROUTING
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_apply_routes(struct wsgi_request *wsgi_req) {
|
||||
|
||||
struct uwsgi_route *routes = uwsgi.routes;
|
||||
|
||||
if (!routes) return UWSGI_ROUTE_CONTINUE;
|
||||
|
||||
if (uwsgi_parse_vars(wsgi_req)) {
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
|
||||
while(routes) {
|
||||
char **subject = (char **) (((char *)(wsgi_req))+routes->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+routes->subject_len);
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("route subject = %.*s\n", *subject_len, *subject);
|
||||
#endif
|
||||
int n = uwsgi_regexp_match_ovec(routes->pattern, routes->pattern_extra, *subject, *subject_len, routes->ovector, routes->ovn);
|
||||
if (n>= 0) {
|
||||
int ret = routes->func(wsgi_req, routes);
|
||||
if (ret != UWSGI_ROUTE_NEXT) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
routes = routes->next;
|
||||
}
|
||||
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
}
|
||||
|
||||
int uwsgi_apply_routes_fast(struct wsgi_request *wsgi_req, char *uri, int len) {
|
||||
|
||||
struct uwsgi_route *routes = uwsgi.routes;
|
||||
|
||||
if (!routes) return UWSGI_ROUTE_CONTINUE;
|
||||
|
||||
while(routes) {
|
||||
int n = uwsgi_regexp_match_ovec(routes->pattern, routes->pattern_extra, uri, len, routes->ovector, routes->ovn);
|
||||
if (n>= 0) {
|
||||
int ret = routes->func(wsgi_req, routes);
|
||||
if (ret != UWSGI_ROUTE_NEXT) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
routes = routes->next;
|
||||
}
|
||||
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_opt_add_route(char *opt, char *value, void *foobar) {
|
||||
|
||||
char *route = uwsgi_str(value);
|
||||
|
||||
char *space = strchr(route, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid route syntax\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
*space = 0;
|
||||
|
||||
struct uwsgi_route *ur = uwsgi.routes;
|
||||
if (!ur) {
|
||||
uwsgi.routes = uwsgi_calloc(sizeof(struct uwsgi_route));
|
||||
ur = uwsgi.routes;
|
||||
}
|
||||
else {
|
||||
while(ur) {
|
||||
if (!ur->next) {
|
||||
ur->next = uwsgi_calloc(sizeof(struct uwsgi_route));
|
||||
ur = ur->next;
|
||||
break;
|
||||
}
|
||||
ur = ur->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcmp(foobar, "http_host")) {
|
||||
ur->subject = offsetof(struct wsgi_request, host);
|
||||
ur->subject_len = offsetof(struct wsgi_request, host_len);
|
||||
}
|
||||
else if (!strcmp(foobar, "request_uri")) {
|
||||
ur->subject = offsetof(struct wsgi_request, uri);
|
||||
ur->subject_len = offsetof(struct wsgi_request, uri_len);
|
||||
}
|
||||
else if (!strcmp(foobar, "query_string")) {
|
||||
ur->subject = offsetof(struct wsgi_request, query_string);
|
||||
ur->subject_len = offsetof(struct wsgi_request, query_string_len);
|
||||
}
|
||||
else {
|
||||
ur->subject = offsetof(struct wsgi_request, path_info);
|
||||
ur->subject_len = offsetof(struct wsgi_request, path_info_len);
|
||||
}
|
||||
|
||||
if (uwsgi_regexp_build(route, &ur->pattern, &ur->pattern_extra)) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ur->ovn = uwsgi_regexp_ovector(ur->pattern, ur->pattern_extra);
|
||||
if (ur->ovn > 0) {
|
||||
ur->ovector = uwsgi_calloc(sizeof(int) * (3 * (ur->ovn + 1)) );
|
||||
}
|
||||
|
||||
char *command = space+1;
|
||||
|
||||
char *colon = strchr(command, ':');
|
||||
if (!colon) {
|
||||
uwsgi_log("invalid route syntax\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
*colon = 0;
|
||||
|
||||
struct uwsgi_router *r = uwsgi.routers;
|
||||
while(r) {
|
||||
if (!strcmp(r->name, command)) {
|
||||
if (r->func(ur, colon+1) == 0) {
|
||||
// apply is_last
|
||||
struct uwsgi_route *last_ur = ur;
|
||||
ur = uwsgi.routes;
|
||||
while(ur) {
|
||||
if (ur->func == last_ur->func) {
|
||||
ur->is_last = 0;
|
||||
}
|
||||
ur = ur->next;
|
||||
}
|
||||
last_ur->is_last = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
r = r->next;
|
||||
}
|
||||
|
||||
uwsgi_log("unable to register route \"%s\"\n", value);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct uwsgi_router *uwsgi_register_router(char *name, int (*func)(struct uwsgi_route *, char *)) {
|
||||
|
||||
struct uwsgi_router *ur = uwsgi.routers;
|
||||
if (!ur) {
|
||||
uwsgi.routers = uwsgi_calloc(sizeof(struct uwsgi_router));
|
||||
uwsgi.routers->name = name;
|
||||
uwsgi.routers->func = func;
|
||||
return uwsgi.routers;
|
||||
}
|
||||
|
||||
while(ur) {
|
||||
if (!ur->next) {
|
||||
ur->next = uwsgi_calloc(sizeof(struct uwsgi_router));
|
||||
ur->next->name = name;
|
||||
ur->next->func = func;
|
||||
return ur->next;
|
||||
}
|
||||
ur = ur->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
#endif
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_register_rpc(char *name, uint8_t modifier1, uint8_t args, void *func) {
|
||||
|
||||
struct uwsgi_rpc *urpc;
|
||||
int ret = -1;
|
||||
|
||||
if (uwsgi.mywid != 0) {
|
||||
uwsgi_log("you can register RPC functions only in the master\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];
|
||||
|
||||
memcpy(urpc->name, name, strlen(name));
|
||||
urpc->modifier1 = modifier1;
|
||||
urpc->args = args;
|
||||
urpc->func = func;
|
||||
|
||||
uwsgi.shared->rpc_count++;
|
||||
|
||||
ret = 0;
|
||||
uwsgi_log("registered RPC function %s\n", name);
|
||||
}
|
||||
|
||||
uwsgi_unlock(uwsgi.rpc_table_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t uwsgi_rpc(char *name, uint8_t argc, char *argv[], uint16_t argvs[], char *output) {
|
||||
|
||||
struct uwsgi_rpc *urpc = NULL;
|
||||
int 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];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (urpc) {
|
||||
if (uwsgi.p[urpc->modifier1]->rpc) {
|
||||
ret = uwsgi.p[urpc->modifier1]->rpc(urpc->func, argc, argv, argvs, output);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t argvs[], uint16_t *len) {
|
||||
|
||||
uint8_t i;
|
||||
uint16_t ulen;
|
||||
struct uwsgi_header uh;
|
||||
char *buffer = NULL;
|
||||
|
||||
*len = 0;
|
||||
|
||||
if (node == NULL || !strcmp(node, "")) {
|
||||
// allocate the whole buffer
|
||||
buffer = uwsgi_malloc(65536);
|
||||
*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);
|
||||
|
||||
if (fd < 0) return NULL;
|
||||
|
||||
// prepare a uwsgi array
|
||||
uint16_t buffer_size = 2 + strlen(func);
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
buffer_size += 2 + argvs[i];
|
||||
}
|
||||
|
||||
// allocate the whole buffer
|
||||
buffer = uwsgi_malloc(65536);
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
*len = uh.pktsize;
|
||||
if (*len == 0) {
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
return buffer;
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user