mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-10-04 07:58:33 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
@@ -8,3 +8,39 @@ 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
|
||||
|
||||
@@ -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,5 +1,399 @@
|
||||
*** 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
|
||||
|
||||
@@ -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:
|
||||
python2.7 uwsgiconfig.py --build
|
||||
@@ -1,2 +0,0 @@
|
||||
all:
|
||||
python3.0 uwsgiconfig.py --build
|
||||
@@ -1,2 +0,0 @@
|
||||
all:
|
||||
python3.1 uwsgiconfig.py --build
|
||||
+626
-626
File diff suppressed because it is too large
Load Diff
+143
-78
@@ -1,18 +1,18 @@
|
||||
/*
|
||||
|
||||
*** uWSGI/mod_uwsgi ***
|
||||
*** uWSGI/mod_uwsgi ***
|
||||
|
||||
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.
|
||||
Copyright 2009-2011 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
|
||||
@@ -51,7 +51,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 +72,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 +84,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 +161,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 +178,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 +265,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 +283,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 +305,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 +334,58 @@ 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) ;
|
||||
vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "REMOTE_ADDR", r->connection->remote_ip, &pkt_size) ;
|
||||
|
||||
//
|
||||
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 (r->user) {
|
||||
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 +397,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 +427,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 +445,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,15 +470,22 @@ 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) {
|
||||
if (uwsgi_poll.revents & POLLIN) {
|
||||
if (uwsgi_poll.revents & POLLIN || uwsgi_poll.revents & POLLHUP) {
|
||||
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;
|
||||
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) {
|
||||
@@ -479,29 +503,27 @@ static int uwsgi_handler(request_rec *r) {
|
||||
if (r->connection->aborted) {
|
||||
close(uwsgi_poll.fd);
|
||||
apr_brigade_destroy(bb);
|
||||
free(uwsgi_vars);
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
apr_brigade_write(bb, NULL, NULL, buf, cnt);
|
||||
hret = ap_fflush(r->output_filters, bb) ;
|
||||
if (hret != APR_SUCCESS) {
|
||||
close(uwsgi_poll.fd);
|
||||
apr_brigade_destroy(bb);
|
||||
return hret;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// EOF
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi_poll.revents & POLLHUP || uwsgi_poll.revents & POLLERR || uwsgi_poll.revents & POLLNVAL) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -515,6 +537,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;
|
||||
}
|
||||
}
|
||||
@@ -522,11 +545,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) ;
|
||||
}
|
||||
|
||||
@@ -558,6 +583,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 ;
|
||||
@@ -592,7 +633,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 ;
|
||||
}
|
||||
|
||||
@@ -693,6 +734,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"),
|
||||
@@ -701,6 +764,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,459 +1,438 @@
|
||||
#ifdef UWSGI_ASYNC
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#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) {
|
||||
uwsgi_error("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)) {
|
||||
uwsgi_error("epoll_ctl()");
|
||||
close(epfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return epfd;
|
||||
struct wsgi_request *find_wsgi_req_proto_by_fd(int fd) {
|
||||
return uwsgi.async_proto_fd_table[fd];
|
||||
}
|
||||
|
||||
int async_wait(int queuefd, void *events, int nevents, int block, int timeout) {
|
||||
struct wsgi_request *find_wsgi_req_by_fd(int fd) {
|
||||
return uwsgi.async_waiting_fd_table[fd];
|
||||
}
|
||||
|
||||
int ret ;
|
||||
void runqueue_remove(struct uwsgi_async_request *u_request) {
|
||||
|
||||
if (timeout <= 0) {
|
||||
timeout = block;
|
||||
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 = time(NULL);
|
||||
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 {
|
||||
timeout = timeout*1000;
|
||||
wsgi_req->waiting_fds = uad;
|
||||
}
|
||||
|
||||
//uwsgi_log("waiting with timeout %d nevents %d\n", timeout, nevents);
|
||||
ret = epoll_wait(queuefd, (struct epoll_event *) events, nevents, timeout);
|
||||
if (ret < 0) {
|
||||
uwsgi_error("epoll_wait()");
|
||||
if (timeout > 0) {
|
||||
async_add_timeout(wsgi_req, timeout);
|
||||
}
|
||||
return ret ;
|
||||
uwsgi.async_waiting_fd_table[fd] = wsgi_req;
|
||||
event_queue_add_fd_read(uwsgi.async_queue, fd);
|
||||
|
||||
}
|
||||
|
||||
int async_add(int queuefd, int fd, int etype) {
|
||||
struct epoll_event ee;
|
||||
void async_add_timeout(struct wsgi_request *wsgi_req, int timeout) {
|
||||
|
||||
memset(&ee, 0, sizeof(struct epoll_event));
|
||||
ee.events = etype;
|
||||
ee.data.fd = fd;
|
||||
|
||||
if (epoll_ctl(queuefd, EPOLL_CTL_ADD, fd, &ee)) {
|
||||
uwsgi_error("epoll_ctl()");
|
||||
return -1;
|
||||
if (timeout > 0 && wsgi_req->async_timeout == NULL) {
|
||||
wsgi_req->async_timeout = uwsgi_add_rb_timer(uwsgi.rb_async_timeouts, time(NULL)+timeout, wsgi_req);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int async_mod(int queuefd, int fd, int etype) {
|
||||
struct epoll_event ee;
|
||||
void async_add_fd_write(struct wsgi_request *wsgi_req, int fd, int timeout) {
|
||||
|
||||
memset(&ee, 0, sizeof(struct epoll_event));
|
||||
ee.events = etype;
|
||||
ee.data.fd = fd;
|
||||
struct uwsgi_async_fd *last_uad = NULL, *uad = wsgi_req->waiting_fds;
|
||||
|
||||
if (epoll_ctl(queuefd, EPOLL_CTL_MOD, fd, &ee)) {
|
||||
uwsgi_error("epoll_ctl()");
|
||||
return -1;
|
||||
if (fd < 0) return ;
|
||||
|
||||
// find first slot
|
||||
while(uad) {
|
||||
last_uad = uad;
|
||||
uad = uad->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
uad = uwsgi_malloc(sizeof(struct uwsgi_async_fd));
|
||||
uad->fd = fd;
|
||||
uad->event = event_queue_write();
|
||||
uad->prev = last_uad;
|
||||
uad->next = NULL;
|
||||
|
||||
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)) {
|
||||
uwsgi_error("epoll_ctl()");
|
||||
return -1;
|
||||
if (last_uad) {
|
||||
last_uad->next = uad;
|
||||
}
|
||||
else {
|
||||
wsgi_req->waiting_fds = uad;
|
||||
}
|
||||
|
||||
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) {
|
||||
uwsgi_error("open()");
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
|
||||
dpev.fd = serverfd;
|
||||
dpev.events = POLLIN ;
|
||||
dpev.revents = 0;
|
||||
|
||||
if (write(dpfd, &dpev, sizeof(struct pollfd)) < 0) {
|
||||
uwsgi_error("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;
|
||||
if (timeout > 0) {
|
||||
async_add_timeout(wsgi_req, timeout);
|
||||
}
|
||||
|
||||
dv.dp_fds = (struct pollfd *) events;
|
||||
dv.dp_nfds = nevents;
|
||||
dv.dp_timeout = timeout;
|
||||
uwsgi.async_waiting_fd_table[fd] = wsgi_req;
|
||||
event_queue_add_fd_write(uwsgi.async_queue, fd);
|
||||
|
||||
//uwsgi_log("waiting with timeout %d nevents %d\n", timeout, nevents);
|
||||
ret = ioctl(queuefd, DP_POLL, &dv);
|
||||
if (ret < 0) {
|
||||
uwsgi_error("ioctl()");
|
||||
}
|
||||
return ret ;
|
||||
}
|
||||
|
||||
int async_add(int queuefd, int fd, int etype) {
|
||||
struct pollfd pl;
|
||||
|
||||
pl.fd = fd ;
|
||||
pl.events = etype ;
|
||||
pl.revents = 0 ;
|
||||
|
||||
if (write(queuefd, &pl, sizeof(struct pollfd)) < 0) {
|
||||
uwsgi_error("write()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
void async_schedule_to_req(void) {
|
||||
uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh.modifier1]->request(uwsgi.wsgi_req);
|
||||
}
|
||||
|
||||
int async_mod(int queuefd, int fd, int etype) {
|
||||
// using the same fd will overwrite existing rule
|
||||
return async_add(queuefd, fd, etype);
|
||||
}
|
||||
void *async_loop(void *arg1) {
|
||||
|
||||
int async_del(int queuefd, int fd, int etype) {
|
||||
// use POLLREMOVE to remove an fd
|
||||
return async_add(queuefd, fd, POLLREMOVE);
|
||||
}
|
||||
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;
|
||||
|
||||
#else
|
||||
int async_queue_init(int serverfd) {
|
||||
int kfd ;
|
||||
struct kevent kev;
|
||||
time_t now, last_now = 0;
|
||||
|
||||
kfd = kqueue();
|
||||
static struct uwsgi_async_request *current_request = NULL, *next_async_request = NULL;
|
||||
|
||||
if (kfd < 0) {
|
||||
uwsgi_error("kqueue()");
|
||||
return -1 ;
|
||||
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);
|
||||
}
|
||||
|
||||
EV_SET(&kev, serverfd, EVFILT_READ, EV_ADD, 0, 0, 0);
|
||||
if (kevent(kfd, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
// set a default request manager
|
||||
if (!uwsgi.schedule_to_req) uwsgi.schedule_to_req = async_schedule_to_req;
|
||||
|
||||
return kfd;
|
||||
}
|
||||
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
|
||||
|
||||
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);
|
||||
if (uwsgi.async_runqueue_cnt) {
|
||||
timeout = 0;
|
||||
}
|
||||
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) {
|
||||
uwsgi_error("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) {
|
||||
uwsgi_error("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) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
EV_SET(&kev, fd, etype, EV_ADD, 0, 0, 0);
|
||||
if (kevent(queuefd, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("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) {
|
||||
uwsgi_error("kevent()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
inline 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) ;
|
||||
|
||||
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;
|
||||
min_timeout = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts);
|
||||
if (uwsgi.async_runqueue_cnt) {
|
||||
timeout = 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) * 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) {
|
||||
uwsgi_error("write()");
|
||||
if (min_timeout) {
|
||||
timeout = min_timeout->key - time(NULL);
|
||||
if (timeout <= 0) {
|
||||
async_expire_timeouts();
|
||||
timeout = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
wsgi_req->response_size += rlen ;
|
||||
timeout = -1;
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi.async_nevents = event_queue_wait_multi(uwsgi.async_queue, timeout, events, 64);
|
||||
|
||||
// timeout ???
|
||||
if (uwsgi.async_nevents == 0) {
|
||||
async_expire_timeouts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
for(i=0;i<uwsgi.async_nevents;i++) {
|
||||
// manage events
|
||||
interesting_fd = event_queue_interesting_fd(events, i);
|
||||
|
||||
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 = time(NULL);
|
||||
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__
|
||||
if (uwsgi.numproc > 1) {
|
||||
/* re-set blocking socket */
|
||||
if (fcntl(uwsgi.wsgi_req->poll.fd, F_SETFL, uwsgi_sock->arg) < 0) {
|
||||
uwsgi_error("fcntl()");
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wsgi_req_async_recv(uwsgi.wsgi_req)) {
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
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;
|
||||
}
|
||||
wsgi_req->async_waiting_fd_monitored = 1;
|
||||
wsgi_req->async_status = UWSGI_AGAIN;
|
||||
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
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;
|
||||
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 == -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);
|
||||
}
|
||||
}
|
||||
wsgi_req = next_wsgi_req(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;
|
||||
|
||||
}
|
||||
#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,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = null
|
||||
@@ -0,0 +1,48 @@
|
||||
[uwsgi]
|
||||
xml = auto
|
||||
ini = true
|
||||
yaml = true
|
||||
json = auto
|
||||
sqlite3 = auto
|
||||
zeromq = auto
|
||||
snmp = true
|
||||
sctp = false
|
||||
spooler = true
|
||||
embedded = true
|
||||
udp = true
|
||||
multicast = true
|
||||
threading = true
|
||||
sendfile = true
|
||||
minterpreters = true
|
||||
async = true
|
||||
ldap = auto
|
||||
pcre = auto
|
||||
routing = auto
|
||||
debug = false
|
||||
unbit = false
|
||||
xml_implementation = libxml2
|
||||
yaml_implementation = auto
|
||||
malloc_implementation = libc
|
||||
extras =
|
||||
plugins =
|
||||
bin_name = uwsgi
|
||||
append_version =
|
||||
plugin_dir = .
|
||||
embedded_plugins = python, ping, cache, nagios, rrdtool, carbon, rpc, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool
|
||||
as_shared_library = false
|
||||
|
||||
locking = auto
|
||||
event = auto
|
||||
timer = auto
|
||||
filemonitor = auto
|
||||
|
||||
blacklist =
|
||||
whitelist =
|
||||
|
||||
embed_files =
|
||||
|
||||
embed_config =
|
||||
|
||||
[python]
|
||||
paste = true
|
||||
web3 = true
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embed_files = bootstrap3.py,django.zip,djapp.zip
|
||||
@@ -0,0 +1,4 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
|
||||
embed_files = embedme.py,uwsgidecorators.py
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = +,erlang
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = python, ping, cache, nagios, rpc, fastrouter, http, gevent
|
||||
@@ -0,0 +1,5 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
bin_name = libuwsgi.so
|
||||
embedded_plugins = null
|
||||
as_shared_library = true
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = lua
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
plugins = lua
|
||||
@@ -0,0 +1,5 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
plugins = python, ping, rack, psgi, cache, http, fastrouter
|
||||
plugin_dir = plugins
|
||||
embedded_plugins = null
|
||||
@@ -0,0 +1,4 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
plugin_dir = /usr/lib/uwsgi
|
||||
embedded_plugins = null
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = psgi
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = +,erlang,pyerl
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = +,lua
|
||||
@@ -0,0 +1,5 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
bin_name = libuwsgi.so
|
||||
embedded_plugins = symcall
|
||||
as_shared_library = true
|
||||
@@ -0,0 +1,31 @@
|
||||
[uwsgi]
|
||||
xml = true
|
||||
ini = true
|
||||
snmp = true
|
||||
sctp = false
|
||||
erlang = false
|
||||
spooler = true
|
||||
embedded = true
|
||||
udp = true
|
||||
multicast = true
|
||||
threading = true
|
||||
sendfile = true
|
||||
proxy = true
|
||||
minterpreters = true
|
||||
async = true
|
||||
http = true
|
||||
evdis = false
|
||||
ldap = false
|
||||
routing = false
|
||||
stackless = false
|
||||
debug = false
|
||||
unbit = false
|
||||
xml_implementation = libxml2
|
||||
plugins =
|
||||
bin_name = uwsgi
|
||||
plugin_dir = .
|
||||
embedded_plugins = python, ping, nagios, rack
|
||||
|
||||
[python]
|
||||
paste = true
|
||||
web3 = true
|
||||
@@ -0,0 +1,5 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
bin_name = pyuwsgi.so
|
||||
embedded_plugins = pyuwsgi,python,ping,cache,nagios,rpc,ugreen
|
||||
as_shared_library = true
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
inherit = default
|
||||
embedded_plugins = rack, ping, cache, nagios, rpc, fastrouter, http, ugreen
|
||||
@@ -0,0 +1,30 @@
|
||||
[uwsgi]
|
||||
xml = true
|
||||
ini = true
|
||||
yaml = true
|
||||
snmp = true
|
||||
sctp = false
|
||||
erlang = false
|
||||
spooler = false
|
||||
embedded = false
|
||||
udp = true
|
||||
multicast = false
|
||||
threading = true
|
||||
sendfile = true
|
||||
nagios = true
|
||||
proxy = true
|
||||
minterpreters = true
|
||||
async = true
|
||||
ugreen = false
|
||||
http = true
|
||||
evdis = false
|
||||
ldap = false
|
||||
routing = false
|
||||
stackless = false
|
||||
debug = false
|
||||
unbit = false
|
||||
xml_implementation = libxml2
|
||||
plugins = rack
|
||||
bin_name = uwsgi
|
||||
plugin_dir = .
|
||||
embedded_plugins =
|
||||
@@ -0,0 +1,35 @@
|
||||
[uwsgi]
|
||||
xml = true
|
||||
ini = true
|
||||
yaml = true
|
||||
json = true
|
||||
sqlite3 = false
|
||||
zeromq = false
|
||||
snmp = false
|
||||
sctp = false
|
||||
spooler = true
|
||||
embedded = true
|
||||
udp = true
|
||||
multicast = false
|
||||
threading = true
|
||||
sendfile = true
|
||||
minterpreters = true
|
||||
async = true
|
||||
evdis = false
|
||||
ldap = true
|
||||
pcre = false
|
||||
debug = false
|
||||
unbit = true
|
||||
xml_implementation = libxml2
|
||||
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,49 @@
|
||||
[uwsgi]
|
||||
xml = false
|
||||
ini = true
|
||||
yaml = false
|
||||
json = false
|
||||
sqlite3 = false
|
||||
zeromq = false
|
||||
snmp = false
|
||||
sctp = false
|
||||
spooler = true
|
||||
embedded = true
|
||||
udp = true
|
||||
multicast = false
|
||||
threading = true
|
||||
sendfile = true
|
||||
minterpreters = true
|
||||
async = true
|
||||
evdis = false
|
||||
ldap = false
|
||||
pcre = true
|
||||
routing = true
|
||||
debug = false
|
||||
unbit = false
|
||||
xml_implementation = libxml2
|
||||
yaml_implementation = auto
|
||||
malloc_implementation = libc
|
||||
extras =
|
||||
plugins =
|
||||
bin_name = uwsgi
|
||||
append_version =
|
||||
plugin_dir = .
|
||||
embedded_plugins =
|
||||
as_shared_library = false
|
||||
|
||||
locking = auto
|
||||
event = auto
|
||||
timer = auto
|
||||
filemonitor = auto
|
||||
|
||||
blacklist =
|
||||
whitelist =
|
||||
|
||||
embed_files =
|
||||
|
||||
embed_config =
|
||||
|
||||
[python]
|
||||
paste = true
|
||||
web3 = true
|
||||
@@ -0,0 +1,418 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_init_cache() {
|
||||
int i;
|
||||
|
||||
if (!uwsgi.cache_blocksize)
|
||||
uwsgi.cache_blocksize = UMAX16;
|
||||
|
||||
uwsgi.cache_hashtable = (uint64_t *) mmap(NULL, sizeof(uint64_t) * UMAX16, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (!uwsgi.cache_hashtable) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(uwsgi.cache_hashtable, 0, sizeof(uint64_t) * UMAX16);
|
||||
|
||||
uwsgi.cache_unused_stack = (uint64_t *) mmap(NULL, sizeof(uint64_t) * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (!uwsgi.cache_unused_stack) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(uwsgi.cache_unused_stack, 0, sizeof(uint64_t) * uwsgi.cache_max_items);
|
||||
|
||||
// the first cache item is always zero
|
||||
uwsgi.shared->cache_first_available_item = 1;
|
||||
uwsgi.shared->cache_unused_stack_ptr = 0;
|
||||
|
||||
//uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (uwsgi.cache_store) {
|
||||
uwsgi.cache_filesize = (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items) + (uwsgi.cache_blocksize * uwsgi.cache_max_items);
|
||||
int cache_fd;
|
||||
struct stat cst;
|
||||
|
||||
if (stat(uwsgi.cache_store, &cst)) {
|
||||
uwsgi_log("creating a new cache store file: %s\n", uwsgi.cache_store);
|
||||
cache_fd = open(uwsgi.cache_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
if (cache_fd >= 0) {
|
||||
// fill the caching store
|
||||
if (ftruncate(cache_fd, uwsgi.cache_filesize)) {
|
||||
uwsgi_log("ftruncate()");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((size_t) cst.st_size != uwsgi.cache_filesize || !S_ISREG(cst.st_mode)) {
|
||||
uwsgi_log("invalid cache store file. Please remove it or fix cache blocksize/items to match its size\n");
|
||||
exit(1);
|
||||
}
|
||||
cache_fd = open(uwsgi.cache_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
uwsgi_log("recovered cache from backing store file: %s\n", uwsgi.cache_store);
|
||||
}
|
||||
|
||||
if (cache_fd < 0) {
|
||||
uwsgi_error_open(uwsgi.cache_store);
|
||||
exit(1);
|
||||
}
|
||||
uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, uwsgi.cache_filesize, PROT_READ | PROT_WRITE, MAP_SHARED, cache_fd, 0);
|
||||
uwsgi_cache_fix();
|
||||
|
||||
}
|
||||
else {
|
||||
uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items) + (uwsgi.cache_blocksize * uwsgi.cache_max_items), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
for (i = 0; i < (int) uwsgi.cache_max_items; i++) {
|
||||
memset(&uwsgi.cache_items[i], 0, sizeof(struct uwsgi_cache_item));
|
||||
}
|
||||
}
|
||||
if (!uwsgi.cache_items) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
uwsgi.cache = mmap(NULL, uwsgi.cache_blocksize * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (!uwsgi.cache) {
|
||||
uwsgi_error("mmap()");
|
||||
exit(1);
|
||||
}
|
||||
*/
|
||||
|
||||
uwsgi.cache = ((void *) uwsgi.cache_items) + (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items);
|
||||
|
||||
uwsgi.cache_lock = uwsgi_rwlock_init("cache");
|
||||
|
||||
uwsgi_log("*** Cache subsystem initialized: %dMB (key: %llu bytes, keys: %llu bytes, data: %llu bytes) preallocated ***\n", ((uwsgi.cache_blocksize * uwsgi.cache_max_items) + (sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items)) / (1024 * 1024),
|
||||
(unsigned long long) sizeof(struct uwsgi_cache_item), (unsigned long long) sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items, (unsigned long long) uwsgi.cache_blocksize * uwsgi.cache_max_items);
|
||||
}
|
||||
|
||||
uint32_t djb33x_hash(char *key, int keylen) {
|
||||
|
||||
register uint32_t hash = 5381;
|
||||
int i;
|
||||
|
||||
for(i=0;i<keylen;i++) {
|
||||
hash = ((hash << 5) + hash) ^ key[i];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
inline uint64_t uwsgi_cache_get_index(char *key, uint16_t keylen) {
|
||||
|
||||
uint32_t hash = djb33x_hash(key, keylen);
|
||||
|
||||
int hash_key = hash % 0xffff;
|
||||
|
||||
uint64_t slot = uwsgi.cache_hashtable[hash_key];
|
||||
|
||||
struct uwsgi_cache_item *uci;
|
||||
|
||||
//uwsgi_log("found slot %d for key %d\n", slot, hash_key);
|
||||
|
||||
uci = &uwsgi.cache_items[slot];
|
||||
|
||||
// first round
|
||||
if (uci->djbhash != hash) goto cycle;
|
||||
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];
|
||||
if (uci->djbhash != hash) continue;
|
||||
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 = 0;
|
||||
struct uwsgi_cache_item *uci;
|
||||
int ret = -1;
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void uwsgi_cache_fix() {
|
||||
|
||||
uint64_t i;
|
||||
|
||||
for(i=0;i< uwsgi.cache_max_items;i++) {
|
||||
// valid record ?
|
||||
if (uwsgi.cache_items[i].keysize) {
|
||||
if (!uwsgi.cache_items[i].prev) {
|
||||
// put value in hash_table
|
||||
uwsgi.cache_hashtable[ uwsgi.cache_items[i].djbhash % 0xffff] = i;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// put this record in unused stack
|
||||
uwsgi.shared->cache_first_available_item = i;
|
||||
uwsgi.shared->cache_unused_stack_ptr++;
|
||||
uwsgi.cache_unused_stack[uwsgi.shared->cache_unused_stack_ptr] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int uwsgi_cache_set(char *key, uint16_t keylen, char *val, uint64_t vallen, uint64_t expires, uint16_t flags) {
|
||||
|
||||
uint64_t index = 0, last_index = 0 ;
|
||||
|
||||
struct uwsgi_cache_item *uci, *ucii;
|
||||
|
||||
int ret = -1;
|
||||
int slot;
|
||||
|
||||
if (!keylen || !vallen) return -1;
|
||||
|
||||
if (keylen > UWSGI_CACHE_MAX_KEY_SIZE) return -1;
|
||||
|
||||
if (uwsgi.shared->cache_first_available_item >= uwsgi.cache_max_items && !uwsgi.shared->cache_unused_stack_ptr) {
|
||||
uwsgi_log("*** DANGER cache is FULL !!! ***\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
//uwsgi_log("putting cache data in key %.*s %d\n", keylen, key, vallen);
|
||||
index = uwsgi_cache_get_index(key, keylen);
|
||||
if (!index) {
|
||||
if (uwsgi.shared->cache_unused_stack_ptr) {
|
||||
//uwsgi_log("!!! REUSING CACHE SLOT !!! (faci: %llu)\n", (unsigned long long) uwsgi.shared->cache_first_available_item);
|
||||
index = uwsgi.cache_unused_stack[uwsgi.shared->cache_unused_stack_ptr];
|
||||
uwsgi.shared->cache_unused_stack_ptr--;
|
||||
}
|
||||
else {
|
||||
index = uwsgi.shared->cache_first_available_item;
|
||||
if (uwsgi.shared->cache_first_available_item < uwsgi.cache_max_items) {
|
||||
uwsgi.shared->cache_first_available_item++;
|
||||
}
|
||||
}
|
||||
uci = &uwsgi.cache_items[index] ;
|
||||
if (expires) expires += time(NULL);
|
||||
uci->expires = expires;
|
||||
uci->djbhash = djb33x_hash(key, keylen);
|
||||
uci->hits = 0;
|
||||
uci->flags = flags;
|
||||
memcpy(uci->key, key, keylen);
|
||||
memcpy(uwsgi.cache+(index*uwsgi.cache_blocksize), val, vallen);
|
||||
|
||||
// set this as late as possibile (to reduce races risk)
|
||||
|
||||
uci->valsize = vallen;
|
||||
uci->keysize = keylen;
|
||||
ret = 0;
|
||||
// now put the value in the 16bit hashtable
|
||||
slot = uci->djbhash % 0xffff;
|
||||
|
||||
if (uwsgi.cache_hashtable[slot] == 0) {
|
||||
uwsgi.cache_hashtable[slot] = index;
|
||||
}
|
||||
else {
|
||||
//uwsgi_log("HASH COLLISION !!!!\n");
|
||||
// append to first available next
|
||||
last_index = uwsgi.cache_hashtable[slot];
|
||||
ucii = &uwsgi.cache_items[ last_index ];
|
||||
while(ucii->next) {
|
||||
last_index = ucii->next;
|
||||
ucii = &uwsgi.cache_items[ last_index ];
|
||||
}
|
||||
ucii->next = index;
|
||||
uci->prev = last_index;
|
||||
}
|
||||
}
|
||||
else if (flags & UWSGI_CACHE_FLAG_UPDATE) {
|
||||
uci = &uwsgi.cache_items[index] ;
|
||||
if (expires) {
|
||||
expires += time(NULL);
|
||||
uci->expires = expires;
|
||||
}
|
||||
memcpy(uwsgi.cache+(index*uwsgi.cache_blocksize), val, vallen);
|
||||
uci->valsize = vallen;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
end:
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* THIS PART IS HEAVILY OPTIMIZED: PERFORMANCE NOT ELEGANCE !!! */
|
||||
|
||||
void *cache_thread_loop(void *fd_ptr) {
|
||||
|
||||
int *fd_tmp = (int *) fd_ptr;
|
||||
int fd = *fd_tmp;
|
||||
int i;
|
||||
ssize_t len;
|
||||
char uwsgi_packet[UMAX16+4];
|
||||
struct uwsgi_header *uh = (struct uwsgi_header *) uwsgi_packet;
|
||||
char *val;
|
||||
uint64_t vallen;
|
||||
char *key;
|
||||
uint16_t keylen;
|
||||
struct pollfd ctl_poll;
|
||||
char *watermark;
|
||||
struct sockaddr_un ctl_sun;
|
||||
socklen_t ctl_sun_len;
|
||||
|
||||
ctl_poll.events = POLLIN;
|
||||
|
||||
for(;;) {
|
||||
ctl_sun_len = sizeof(struct sockaddr_un);
|
||||
pthread_mutex_lock(&uwsgi.cache_server_lock);
|
||||
|
||||
ctl_poll.fd = accept(fd, (struct sockaddr *) &ctl_sun, &ctl_sun_len);
|
||||
|
||||
pthread_mutex_unlock(&uwsgi.cache_server_lock);
|
||||
|
||||
if (ctl_poll.fd < 0) {
|
||||
uwsgi_error("cache accept()");
|
||||
continue;
|
||||
}
|
||||
i = 0;
|
||||
while(i < 4) {
|
||||
len = poll(&ctl_poll, 1, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (len <= 0) {
|
||||
uwsgi_error("cache poll()");
|
||||
goto clear;
|
||||
}
|
||||
len = read(ctl_poll.fd, uwsgi_packet+i, 4-i);
|
||||
if (len < 0) {
|
||||
uwsgi_error("cache read()");
|
||||
goto clear;
|
||||
}
|
||||
i+=len;
|
||||
}
|
||||
|
||||
if (uh->pktsize == 0) goto clear;
|
||||
|
||||
while(i < 4+uh->pktsize) {
|
||||
len = poll(&ctl_poll, 1, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
if (len <= 0) {
|
||||
uwsgi_error("cache poll()");
|
||||
goto clear;
|
||||
}
|
||||
len = read(ctl_poll.fd, uwsgi_packet+i, (4+uh->pktsize)-i);
|
||||
if (len < 0) {
|
||||
uwsgi_error("cache read()");
|
||||
goto clear;
|
||||
}
|
||||
i+=len;
|
||||
}
|
||||
|
||||
watermark = uwsgi_packet+4+uh->pktsize;
|
||||
|
||||
// get first parameter
|
||||
memcpy(&keylen, uwsgi_packet+4, 2);
|
||||
#ifdef __BIG_ENDIAN__
|
||||
keylen = uwsgi_swap16(keylen);
|
||||
#endif
|
||||
if (uwsgi_packet+6+keylen > watermark) goto clear;
|
||||
key = uwsgi_packet+6+keylen+2;
|
||||
memcpy(&keylen, key-2, 2);
|
||||
#ifdef __BIG_ENDIAN__
|
||||
keylen = uwsgi_swap16(keylen);
|
||||
#endif
|
||||
|
||||
if (key+keylen > watermark) goto clear;
|
||||
|
||||
val = uwsgi_cache_get(key, keylen, &vallen);
|
||||
if (val && vallen > 0) {
|
||||
if (write(ctl_poll.fd, val, vallen) < 0) {
|
||||
uwsgi_error("cache write()");
|
||||
}
|
||||
}
|
||||
|
||||
clear:
|
||||
close(ctl_poll.fd);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int uwsgi_cache_server(char *socket, int threads) {
|
||||
|
||||
int *fd = uwsgi_malloc(sizeof(int));
|
||||
|
||||
int i;
|
||||
pthread_t thread_id;
|
||||
char *tcp_port = strchr(socket, ':');
|
||||
if (tcp_port) {
|
||||
*fd = bind_to_tcp(socket, uwsgi.listen_queue, tcp_port);
|
||||
}
|
||||
else {
|
||||
*fd = bind_to_unix(socket, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
|
||||
}
|
||||
|
||||
pthread_mutex_init(&uwsgi.cache_server_lock, NULL);
|
||||
|
||||
if (threads < 1) threads = 1;
|
||||
|
||||
uwsgi_log("*** cache-optimized server enabled on fd %d (%d threads) ***\n", *fd, threads);
|
||||
|
||||
for(i=0;i<threads;i++) {
|
||||
pthread_create(&thread_id, NULL, cache_thread_loop, (void *) fd);
|
||||
}
|
||||
|
||||
return *fd;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,363 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
|
||||
#ifdef UWSGI_UDP
|
||||
|
||||
static void cluster_manage_opt(char *key, uint16_t keylen, char *value, uint16_t vallen, void *foobar) {
|
||||
|
||||
add_exported_option( uwsgi_concat2n(key, keylen, "", 0), uwsgi_concat2n(value, vallen, "", 0), 0);
|
||||
|
||||
}
|
||||
|
||||
void cluster_setup() {
|
||||
|
||||
int rlen;
|
||||
// get cluster configuration
|
||||
if (uwsgi.cluster != NULL) {
|
||||
// get multicast socket
|
||||
|
||||
uwsgi.cluster_fd = uwsgi_cluster_join(uwsgi.cluster);
|
||||
|
||||
uwsgi_log("JOINED CLUSTER: %s\n", uwsgi.cluster);
|
||||
|
||||
// ask for cluster options only if bot pre-existent options are set
|
||||
if (uwsgi.exported_opts_cnt == 1 && !uwsgi.cluster_nodes) {
|
||||
// now wait max 60 seconds and resend multicast request every 10 seconds
|
||||
for (;;) {
|
||||
uwsgi_log("asking \"%s\" uWSGI cluster for configuration data:\n", uwsgi.cluster);
|
||||
if (uwsgi_send_empty_pkt(uwsgi.cluster_fd, uwsgi.cluster, 99, 0) < 0) {
|
||||
uwsgi_log("unable to send multicast message to %s\n", uwsgi.cluster);
|
||||
continue;
|
||||
}
|
||||
waitfd:
|
||||
rlen = uwsgi_waitfd(uwsgi.cluster_fd, 10);
|
||||
if (rlen < 0) {
|
||||
break;
|
||||
}
|
||||
else if (rlen > 0) {
|
||||
// receive the packet
|
||||
char clusterbuf[4096];
|
||||
if (!uwsgi_hooked_parse_dict_dgram(uwsgi.cluster_fd, clusterbuf, 4096, 99, 1, cluster_manage_opt, NULL)) {
|
||||
uwsgi_configure(-1);
|
||||
goto options_parsed;
|
||||
}
|
||||
else {
|
||||
goto waitfd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
options_parsed:
|
||||
|
||||
if (!uwsgi.cluster_nodes)
|
||||
uwsgi_cluster_add_me();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void uwsgi_cluster_add_node(struct uwsgi_cluster_node *nucn, int type) {
|
||||
|
||||
int i;
|
||||
struct uwsgi_cluster_node *ucn;
|
||||
char *tcp_port;
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("adding node\n");
|
||||
#endif
|
||||
|
||||
tcp_port = strchr(nucn->name, ':');
|
||||
#ifndef UWSGI_ZEROMQ
|
||||
if (tcp_port == NULL) {
|
||||
#else
|
||||
char *zmq_dash = strchr(nucn->name, '-');
|
||||
if (tcp_port == NULL && zmq_dash == NULL) {
|
||||
#endif
|
||||
|
||||
fprintf(stdout, "invalid cluster node name %s\n", nucn->name);
|
||||
return;
|
||||
}
|
||||
|
||||
// first check for already present node
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
ucn = &uwsgi.shared->nodes[i];
|
||||
if (ucn->name[0] != 0) {
|
||||
if (!strcmp(ucn->name, nucn->name)) {
|
||||
ucn->status = UWSGI_NODE_OK;
|
||||
ucn->last_seen = time(NULL);
|
||||
// update requests
|
||||
ucn->requests = nucn->requests;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
ucn = &uwsgi.shared->nodes[i];
|
||||
|
||||
if (ucn->name[0] == 0) {
|
||||
memcpy(ucn->name, nucn->name, strlen(nucn->name) + 1);
|
||||
memcpy(ucn->nodename, nucn->nodename, strlen(nucn->nodename) + 1);
|
||||
ucn->workers = nucn->workers;
|
||||
ucn->ucn_addr.sin_family = AF_INET;
|
||||
if (tcp_port) {
|
||||
ucn->ucn_addr.sin_port = htons(atoi(tcp_port + 1));
|
||||
tcp_port[0] = 0;
|
||||
}
|
||||
if (nucn->name[0] == 0) {
|
||||
ucn->ucn_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
}
|
||||
else {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%s\n", nucn->name);
|
||||
#endif
|
||||
ucn->ucn_addr.sin_addr.s_addr = inet_addr(nucn->name);
|
||||
}
|
||||
|
||||
ucn->type = type;
|
||||
// here memory can be freed, as it is allocated by uwsgi_concat2n
|
||||
if (type != CLUSTER_NODE_DYNAMIC && tcp_port) {
|
||||
tcp_port[0] = ':';
|
||||
}
|
||||
ucn->last_seen = time(NULL);
|
||||
ucn->requests = nucn->requests;
|
||||
uwsgi_log("[uWSGI cluster] added node %s\n", ucn->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("unable to add node %s\n", nucn->name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int uwsgi_cluster_add_me() {
|
||||
|
||||
const char *key1 = "hostname";
|
||||
const char *key2 = "address";
|
||||
const char *key3 = "workers";
|
||||
const char *key4 = "requests";
|
||||
|
||||
char *ptrbuf;
|
||||
uint16_t ustrlen;
|
||||
char numproc[6];
|
||||
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
char uuid_zmq_str[37];
|
||||
uuid_t uuid_zmq;
|
||||
if (!uwsgi.sockets && !uwsgi.zeromq) {
|
||||
#else
|
||||
if (!uwsgi.sockets) {
|
||||
#endif
|
||||
uwsgi_log("you need to specify at least a socket to start a uWSGI cluster\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
snprintf(numproc, 6, "%d", uwsgi.numproc);
|
||||
|
||||
size_t len;
|
||||
|
||||
if (uwsgi.sockets) {
|
||||
len = 2 + strlen(key1) + 2 + strlen(uwsgi.hostname) + 2 + strlen(key2) + 2 + strlen(uwsgi.sockets->name) + 2 + strlen(key3) + 2 + strlen(numproc) + 2 + strlen(key4) + 2 + 1;
|
||||
}
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
else if (uwsgi.zeromq) {
|
||||
uuid_generate(uuid_zmq);
|
||||
uuid_unparse(uuid_zmq, uuid_zmq_str);
|
||||
len = 2 + strlen(key1) + 2 + strlen(uwsgi.hostname) + 2 + strlen(key2) + 2 + strlen(uuid_zmq_str) + 2 + strlen(key3) + 2 + strlen(numproc) + 2 + strlen(key4) + 2 + 1;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
len = 2 + strlen(key1) + 2 + strlen(uwsgi.hostname) + 2 + strlen(key3) + 2 + strlen(numproc) + 2 + strlen(key4) + 2 + 1;
|
||||
}
|
||||
char *buf = uwsgi_malloc(len);
|
||||
|
||||
ptrbuf = buf;
|
||||
|
||||
ustrlen = strlen(key1);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key1, strlen(key1));
|
||||
ptrbuf += strlen(key1);
|
||||
|
||||
ustrlen = strlen(uwsgi.hostname);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, uwsgi.hostname, strlen(uwsgi.hostname));
|
||||
ptrbuf += strlen(uwsgi.hostname);
|
||||
|
||||
|
||||
if (uwsgi.sockets && uwsgi.sockets->name) {
|
||||
ustrlen = strlen(key2);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key2, strlen(key2));
|
||||
ptrbuf += strlen(key2);
|
||||
|
||||
ustrlen = strlen(uwsgi.sockets->name);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, uwsgi.sockets->name, strlen(uwsgi.sockets->name));
|
||||
ptrbuf += strlen(uwsgi.sockets->name);
|
||||
}
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
else if (uwsgi.zeromq) {
|
||||
ustrlen = strlen(key2);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key2, strlen(key2));
|
||||
ptrbuf += strlen(key2);
|
||||
|
||||
ustrlen = strlen(uuid_zmq_str);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, uuid_zmq_str, strlen(uuid_zmq_str));
|
||||
ptrbuf += strlen(uuid_zmq_str);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
ustrlen = strlen(key3);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key3, strlen(key3));
|
||||
ptrbuf += strlen(key3);
|
||||
|
||||
ustrlen = strlen(numproc);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, numproc, strlen(numproc));
|
||||
ptrbuf += strlen(numproc);
|
||||
|
||||
ustrlen = strlen(key4);
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, key4, strlen(key4));
|
||||
ptrbuf += strlen(key4);
|
||||
|
||||
ustrlen = 1;
|
||||
*ptrbuf++ = (uint8_t) (ustrlen & 0xff);
|
||||
*ptrbuf++ = (uint8_t) ((ustrlen >> 8) & 0xff);
|
||||
memcpy(ptrbuf, "0", 1);
|
||||
ptrbuf += 1;
|
||||
|
||||
|
||||
uwsgi_string_sendto(uwsgi.cluster_fd, 95, 0, (struct sockaddr *) &uwsgi.mc_cluster_addr, sizeof(uwsgi.mc_cluster_addr), buf, len);
|
||||
|
||||
free(buf);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("add_me() successfull\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_cluster_join(char *name) {
|
||||
|
||||
int fd;
|
||||
char *cp;
|
||||
int broadcast = 0;
|
||||
|
||||
|
||||
|
||||
if (name[0] == ':') {
|
||||
fd = bind_to_udp(name, 0, 1);
|
||||
broadcast = 1;
|
||||
}
|
||||
else {
|
||||
fd = bind_to_udp(name, 1, 0);
|
||||
}
|
||||
|
||||
if (fd >= 0) {
|
||||
cp = strchr(name, ':');
|
||||
cp[0] = 0;
|
||||
uwsgi.mc_cluster_addr.sin_family = AF_INET;
|
||||
if (broadcast) {
|
||||
uwsgi.mc_cluster_addr.sin_addr.s_addr = INADDR_BROADCAST;
|
||||
}
|
||||
else {
|
||||
uwsgi.mc_cluster_addr.sin_addr.s_addr = inet_addr(name);
|
||||
}
|
||||
uwsgi.mc_cluster_addr.sin_port = htons(atoi(cp + 1));
|
||||
cp[0] = ':';
|
||||
|
||||
|
||||
// announce my presence to all the nodes
|
||||
uwsgi_string_sendto(fd, 73, 0, (struct sockaddr *) &uwsgi.mc_cluster_addr, sizeof(uwsgi.mc_cluster_addr), uwsgi.hostname, strlen(uwsgi.hostname));
|
||||
}
|
||||
else {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
return fd;
|
||||
|
||||
}
|
||||
|
||||
|
||||
char *uwsgi_cluster_best_node() {
|
||||
|
||||
int i;
|
||||
int best_node = -1;
|
||||
struct uwsgi_cluster_node *ucn;
|
||||
|
||||
for (i = 0; i < MAX_CLUSTER_NODES; i++) {
|
||||
ucn = &uwsgi.shared->nodes[i];
|
||||
if (ucn->name[0] != 0 && ucn->status == UWSGI_NODE_OK) {
|
||||
if (best_node == -1) {
|
||||
best_node = i;
|
||||
}
|
||||
else {
|
||||
if (ucn->last_choosen < uwsgi.shared->nodes[best_node].last_choosen) {
|
||||
best_node = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (best_node == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uwsgi.shared->nodes[best_node].last_choosen = time(NULL);
|
||||
return uwsgi.shared->nodes[best_node].name;
|
||||
}
|
||||
|
||||
|
||||
void manage_cluster_announce(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
|
||||
|
||||
char *tmpstr;
|
||||
struct uwsgi_cluster_node *ucn = (struct uwsgi_cluster_node *) data;
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%.*s = %.*s\n", keylen, key, vallen, val);
|
||||
#endif
|
||||
|
||||
if (!uwsgi_strncmp("hostname", 8, key, keylen)) {
|
||||
strncpy(ucn->nodename, val, UMIN(vallen, 255));
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("address", 7, key, keylen)) {
|
||||
strncpy(ucn->name, val, UMIN(vallen, 100));
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("workers", 7, key, keylen)) {
|
||||
tmpstr = uwsgi_concat2n(val, vallen, "", 0);
|
||||
ucn->workers = atoi(tmpstr);
|
||||
free(tmpstr);
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp("requests", 8, key, keylen)) {
|
||||
tmpstr = uwsgi_concat2n(val, vallen, "", 0);
|
||||
ucn->requests = strtoul(tmpstr, NULL, 0);
|
||||
free(tmpstr);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,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")]
|
||||
}
|
||||
+68
-68
@@ -17,10 +17,10 @@ sub new {
|
||||
sub run {
|
||||
my ($self, $app) = @_;
|
||||
|
||||
my $server ;
|
||||
my $server;
|
||||
|
||||
if (exists($ENV{'UWSGI_FD'})) {
|
||||
$server = IO::Socket::UNIX->new_from_fd($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);
|
||||
@@ -28,62 +28,62 @@ sub run {
|
||||
|
||||
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,
|
||||
@@ -105,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,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,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,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)
|
||||
@@ -12,4 +12,6 @@ env LOGTO=/tmp/uwsgi.log
|
||||
env BINPATH=/home/foo/uwsgi/uwsgi
|
||||
|
||||
# --no-orphans avoid workers without master
|
||||
exec $BINPATH --no-orphans --socket :3033 --uid 1001 --gid 1001 --limit-as 256 -m simple_app --logto $LOGTO -M -p 4
|
||||
# --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
|
||||
+24
-1
@@ -1,5 +1,9 @@
|
||||
require 'rubygems'
|
||||
require 'socket'
|
||||
begin
|
||||
require 'bundler/setup'
|
||||
rescue LoadError
|
||||
end
|
||||
require 'rack'
|
||||
require 'rack/content_length'
|
||||
require 'rack/rewindable_input'
|
||||
@@ -9,6 +13,7 @@ require 'optparse'
|
||||
|
||||
options = {
|
||||
:processes => 1,
|
||||
:threads => 1,
|
||||
:master => false,
|
||||
:logging => true,
|
||||
:static => true,
|
||||
@@ -19,6 +24,7 @@ options = {
|
||||
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 }
|
||||
@@ -37,6 +43,7 @@ end
|
||||
|
||||
$requests = 0
|
||||
$workers = Array.new
|
||||
$mywid = 0
|
||||
|
||||
module Rack
|
||||
|
||||
@@ -74,12 +81,14 @@ module Rack
|
||||
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
|
||||
|
||||
@@ -88,6 +97,7 @@ module Rack
|
||||
$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]})")
|
||||
@@ -107,6 +117,7 @@ module Rack
|
||||
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]})")
|
||||
@@ -118,9 +129,21 @@ module Rack
|
||||
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
|
||||
serve client, app, options
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def self.serve(client, 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+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,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
|
||||
}
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
#!./uwsgi --import decoratortest -s :3035 -M --spooler myspool --enable-threads -p 8 --spooler-ordered
|
||||
import uwsgi
|
||||
|
||||
from uwsgidecorators import *
|
||||
|
||||
from uwsgicc import app as application
|
||||
|
||||
import time
|
||||
|
||||
|
||||
# register rpc function helloworld
|
||||
@rpc("helloworld")
|
||||
def hello2():
|
||||
return "[RPC] Hello World"
|
||||
|
||||
# register signal 1
|
||||
@signal(1)
|
||||
def what_time_is_it(num):
|
||||
print(time.asctime())
|
||||
|
||||
# register signal 100
|
||||
@signal(100, target='workers')
|
||||
def what_time_is_it(num):
|
||||
print("*** I AM THE WORKER %d AT %s ***" % (uwsgi.worker_id(), time.asctime()))
|
||||
|
||||
|
||||
# a 3 seconds timer
|
||||
@timer(3)
|
||||
def salut(num):
|
||||
print("Salut !!! 3 seconds elapsed and signal %d raised" % num)
|
||||
|
||||
# a 10 seconds red black timer (executed by the spooler)
|
||||
@rbtimer(10, target='spooler')
|
||||
def tenseconds(num):
|
||||
print("red black timer !!! 10 seconds elapsed and signal %d raised" % num)
|
||||
|
||||
# monitor /tmp directory
|
||||
@filemon("/tmp")
|
||||
def tmpmodified(num):
|
||||
print("/tmp has been modified")
|
||||
|
||||
|
||||
# spool a long running task
|
||||
@spool
|
||||
def a_long_task(args):
|
||||
for i in xrange(1,10):
|
||||
print("%s = %d" % ( str(args), i))
|
||||
print(uwsgi.call('helloworld'))
|
||||
time.sleep(1)
|
||||
|
||||
# continuosly spool a long running task
|
||||
@spoolforever
|
||||
def an_infinite_task(args):
|
||||
for i in xrange(1,4):
|
||||
print("infinite: %d %s" % (i, str(args)))
|
||||
print(uwsgi.call('helloworld'))
|
||||
uwsgi.signal(100)
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
# spool a task after 5 seconds
|
||||
@spool
|
||||
def delayed_task(args):
|
||||
print("*** I am a delayed spool job. It is %s [%s]***" % (time.asctime(), str(args)))
|
||||
# send a signal to all workers
|
||||
uwsgi.signal(100)
|
||||
|
||||
@spool
|
||||
def big_body_task(args):
|
||||
print("*** managing a task with a body of %d bytes ***" % len(args['body']))
|
||||
print(args['body'].swapcase())
|
||||
|
||||
# run a task every hour
|
||||
@cron(59, -1, -1, -1, -1)
|
||||
def one_hour_passed(num):
|
||||
print("received signal %d after 1 hour" % num)
|
||||
|
||||
@thread
|
||||
def a_running_thread():
|
||||
while True:
|
||||
time.sleep(2)
|
||||
print("i am a no-args thread")
|
||||
|
||||
@thread
|
||||
def a_running_thread_with_args(who):
|
||||
while True:
|
||||
time.sleep(2)
|
||||
print("Hello %s (from arged-thread)" % who)
|
||||
|
||||
@postfork
|
||||
@thread
|
||||
def a_post_fork_thread():
|
||||
while True:
|
||||
time.sleep(3)
|
||||
if uwsgi.i_am_the_spooler():
|
||||
print("Hello from a thread in the spooler")
|
||||
else:
|
||||
print("Hello from a thread in worker %d" % uwsgi.worker_id())
|
||||
|
||||
@postfork
|
||||
def fork_happened():
|
||||
print("fork() has been called [1]")
|
||||
|
||||
@postfork
|
||||
def fork_happened2():
|
||||
if uwsgi.i_am_the_spooler():
|
||||
return
|
||||
print("worker %d is waiting for signal 100..." % uwsgi.worker_id())
|
||||
uwsgi.signal_wait(100)
|
||||
print("worker %d received signal %d" % (uwsgi.worker_id(), uwsgi.signal_received()))
|
||||
print("fork() has been called [2] wid: %d" % uwsgi.worker_id())
|
||||
|
||||
@postfork
|
||||
@lock
|
||||
def locked_func():
|
||||
print("starting locked function on worker %d" % uwsgi.worker_id())
|
||||
for i in xrange(1, 5):
|
||||
time.sleep(1)
|
||||
print("[locked %d] waiting..." % uwsgi.worker_id())
|
||||
print("done with locked function on worker %d" % uwsgi.worker_id())
|
||||
|
||||
print(uwsgi.call('helloworld'))
|
||||
spool_filename = a_long_task.spool({'foo':'bar'}, hello='world')
|
||||
print("spool filename = %s" % spool_filename)
|
||||
an_infinite_task.spool(foo='bar', priority=3)
|
||||
when = int(time.time())+5
|
||||
print("scheduling a delayed task at %d" % when)
|
||||
delayed_task.spool(foo2='bar2', at=when)
|
||||
a_running_thread()
|
||||
a_running_thread_with_args("uWSGI")
|
||||
uwsgi_source_file = open('uwsgi.c','r')
|
||||
print(big_body_task.spool(priority=9,filename='uwsgi.c',body=uwsgi_source_file.read()))
|
||||
uwsgi_source_file.close()
|
||||
@@ -56,6 +56,26 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="module" style="width:860px">
|
||||
<table>
|
||||
<caption style="width:860px">spooler jobs</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="row">job filename</th>
|
||||
<th scope="row">environment</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for j in jobs %}
|
||||
<tr>
|
||||
<td align="left">{{j.file}}</td>
|
||||
<td align="left">{{j.env}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% if masterpid %}
|
||||
<br/>
|
||||
<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="reload/" method="post">
|
||||
|
||||
@@ -14,12 +14,19 @@ def index(request):
|
||||
w['load'] = (100 * (w['running_time']/1000))/total_load
|
||||
w['last_spawn_str'] = time.ctime(w['last_spawn'])
|
||||
|
||||
jobs = []
|
||||
if 'spooler' in uwsgi.opt:
|
||||
spooler_jobs = uwsgi.spooler_jobs()
|
||||
for j in spooler_jobs:
|
||||
jobs.append({'file': j, 'env': uwsgi.parsefile(j)})
|
||||
|
||||
return render_to_response('uwsgi.html', {'masterpid': uwsgi.masterpid(),
|
||||
'started_on': time.ctime(uwsgi.started_on),
|
||||
'buffer_size': uwsgi.buffer_size,
|
||||
'total_requests': uwsgi.total_requests(),
|
||||
'numproc': uwsgi.numproc,
|
||||
'workers': workers,
|
||||
'jobs': jobs,
|
||||
}, RequestContext(request, {}))
|
||||
index = staff_member_required(index)
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
from django.template.base import TemplateDoesNotExist
|
||||
from django.template.loader import BaseLoader
|
||||
from django.conf import settings
|
||||
|
||||
try:
|
||||
import uwsgi
|
||||
on_uwsgi = True
|
||||
except:
|
||||
on_uwsgi = False
|
||||
|
||||
|
||||
|
||||
|
||||
class Loader(BaseLoader):
|
||||
|
||||
is_usable = on_uwsgi
|
||||
|
||||
def symbolize(self, name):
|
||||
return name.replace('.','_').replace('/','_').replace('-','_')
|
||||
|
||||
def load_template_source(self, template_name, template_dirs=None):
|
||||
filename = 'templates_' + self.symbolize(template_name)
|
||||
for app in settings.INSTALLED_APPS:
|
||||
try:
|
||||
symbol = "%s_%s" % (self.symbolize(app), filename)
|
||||
return (uwsgi.embedded_data(symbol), "sym://%s" % symbol)
|
||||
except:
|
||||
pass
|
||||
raise TemplateDoesNotExist(template_name)
|
||||
@@ -0,0 +1,924 @@
|
||||
#include "uwsgi.h"
|
||||
#include <glob.h>
|
||||
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
extern char **environ;
|
||||
|
||||
int emperor_queue;
|
||||
char *emperor_absolute_dir;
|
||||
|
||||
void emperor_send_stats(int);
|
||||
|
||||
struct uwsgi_instance {
|
||||
struct uwsgi_instance *ui_prev;
|
||||
struct uwsgi_instance *ui_next;
|
||||
|
||||
char name[0xff];
|
||||
pid_t pid;
|
||||
|
||||
int status;
|
||||
time_t born;
|
||||
time_t last_mod;
|
||||
time_t last_loyal;
|
||||
|
||||
uint64_t respawns;
|
||||
int use_config;
|
||||
|
||||
int pipe[2];
|
||||
int pipe_config[2];
|
||||
|
||||
char *config;
|
||||
uint32_t config_len;
|
||||
|
||||
int loyal;
|
||||
|
||||
int zerg;
|
||||
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
};
|
||||
|
||||
|
||||
struct uwsgi_instance *ui;
|
||||
|
||||
static void royal_death(int signum) {
|
||||
|
||||
|
||||
if (uwsgi.vassals_stop_hook) {
|
||||
|
||||
struct uwsgi_instance *c_ui = ui->ui_next;
|
||||
|
||||
while (c_ui) {
|
||||
uwsgi_log("running vassal stop-hook: %s %s\n", uwsgi.vassals_stop_hook, c_ui->name);
|
||||
if (setenv("UWSGI_VASSALS_DIR", emperor_absolute_dir, 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
int stop_hook_ret = uwsgi_run_command_and_wait(uwsgi.vassals_stop_hook, c_ui->name);
|
||||
uwsgi_log("%s stop-hook returned %d\n", c_ui->name, stop_hook_ret);
|
||||
c_ui = c_ui->ui_next;
|
||||
}
|
||||
}
|
||||
uwsgi_notify("The Emperor is buried.");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
void emperor_stats() {
|
||||
|
||||
struct uwsgi_instance *c_ui = ui->ui_next;
|
||||
|
||||
while (c_ui) {
|
||||
|
||||
uwsgi_log("vassal instance %s (last modified %d) status %d loyal %d zerg %d\n",c_ui->name, c_ui->last_mod, c_ui->status, c_ui->loyal, c_ui->zerg);
|
||||
|
||||
c_ui = c_ui->ui_next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_instance *emperor_get_by_fd(int fd) {
|
||||
|
||||
struct uwsgi_instance *c_ui = ui;
|
||||
|
||||
while (c_ui->ui_next) {
|
||||
c_ui = c_ui->ui_next;
|
||||
|
||||
if (c_ui->pipe[0] == fd) {
|
||||
return c_ui;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_instance *emperor_get(char *name) {
|
||||
|
||||
struct uwsgi_instance *c_ui = ui;
|
||||
|
||||
while (c_ui->ui_next) {
|
||||
c_ui = c_ui->ui_next;
|
||||
|
||||
if (!strcmp(c_ui->name, name)) {
|
||||
return c_ui;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void emperor_del(struct uwsgi_instance *c_ui) {
|
||||
|
||||
struct uwsgi_instance *parent_ui = c_ui->ui_prev;
|
||||
struct uwsgi_instance *child_ui = c_ui->ui_next;
|
||||
|
||||
parent_ui->ui_next = child_ui;
|
||||
if (child_ui) {
|
||||
child_ui->ui_prev = parent_ui;
|
||||
}
|
||||
|
||||
// this will destroy the whole uWSGI instance (and workers)
|
||||
close(c_ui->pipe[0]);
|
||||
|
||||
if (c_ui->use_config) {
|
||||
close(c_ui->pipe_config[0]);
|
||||
}
|
||||
|
||||
if (uwsgi.vassals_stop_hook) {
|
||||
uwsgi_log("running vassal stop-hook: %s %s\n", uwsgi.vassals_stop_hook, c_ui->name);
|
||||
if (setenv("UWSGI_VASSALS_DIR", emperor_absolute_dir, 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
int stop_hook_ret = uwsgi_run_command_and_wait(uwsgi.vassals_stop_hook, c_ui->name);
|
||||
uwsgi_log("%s stop-hook returned %d\n", c_ui->name, stop_hook_ret);
|
||||
}
|
||||
|
||||
uwsgi_log("removed uwsgi instance %s\n", c_ui->name);
|
||||
|
||||
if (c_ui->zerg) {
|
||||
uwsgi.emperor_broodlord_count--;
|
||||
}
|
||||
|
||||
free(c_ui);
|
||||
|
||||
}
|
||||
|
||||
void emperor_stop(struct uwsgi_instance *c_ui) {
|
||||
// remove uWSGI instance
|
||||
|
||||
if (write(c_ui->pipe[0], "\0", 1) != 1) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
|
||||
c_ui->status = 1;
|
||||
|
||||
uwsgi_log("stop the uwsgi instance %s\n", c_ui->name);
|
||||
}
|
||||
|
||||
void emperor_respawn(struct uwsgi_instance *c_ui, time_t mod) {
|
||||
|
||||
// reload the uWSGI instance
|
||||
if (c_ui->use_config) {
|
||||
if (write(c_ui->pipe[0], "\0", 1) != 1) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (write(c_ui->pipe[0], "\1", 1) != 1) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
}
|
||||
|
||||
c_ui->respawns++;
|
||||
c_ui->last_mod = mod;
|
||||
|
||||
uwsgi_log("[emperor] reload the uwsgi instance %s\n", c_ui->name);
|
||||
}
|
||||
|
||||
void emperor_add(char *name, time_t born, char *config, uint32_t config_size, uid_t uid, gid_t gid) {
|
||||
|
||||
struct uwsgi_instance *c_ui = ui;
|
||||
struct uwsgi_instance *n_ui = NULL;
|
||||
pid_t pid;
|
||||
char **vassal_argv;
|
||||
char *uef;
|
||||
char **uenvs;
|
||||
int counter;
|
||||
char *colon = NULL;
|
||||
int i;
|
||||
|
||||
usleep(uwsgi.emperor_throttle*1000);
|
||||
|
||||
if (uwsgi.emperor_tyrant) {
|
||||
if (uid == 0 || gid == 0) {
|
||||
uwsgi_log("[emperor-tyrant] invalid permissions for file %s\n", name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (c_ui->ui_next) {
|
||||
c_ui = c_ui->ui_next;
|
||||
}
|
||||
|
||||
n_ui = uwsgi_malloc(sizeof(struct uwsgi_instance));
|
||||
memset(n_ui, 0, sizeof(struct uwsgi_instance));
|
||||
|
||||
if (config) {
|
||||
n_ui->use_config = 1;
|
||||
n_ui->config = config;
|
||||
n_ui->config_len = config_size;
|
||||
}
|
||||
|
||||
c_ui->ui_next = n_ui;
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("c_ui->ui_next = %p\n", c_ui->ui_next);
|
||||
#endif
|
||||
n_ui->ui_prev = c_ui;
|
||||
|
||||
if (strchr(name,':')) {
|
||||
n_ui->zerg = 1;
|
||||
uwsgi.emperor_broodlord_count++;
|
||||
}
|
||||
|
||||
memcpy(n_ui->name, name, strlen(name));
|
||||
n_ui->born = born;
|
||||
n_ui->uid = uid;
|
||||
n_ui->gid = gid;
|
||||
n_ui->last_mod = born;
|
||||
// start without loyalty
|
||||
n_ui->last_loyal = born;
|
||||
n_ui->loyal = 0;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe)) {
|
||||
uwsgi_error("socketpair()");
|
||||
goto clear;
|
||||
}
|
||||
|
||||
event_queue_add_fd_read(emperor_queue, n_ui->pipe[0]);
|
||||
|
||||
if (n_ui->use_config) {
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe_config)) {
|
||||
uwsgi_error("socketpair()");
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO pre-start hook
|
||||
|
||||
// a new uWSGI instance will start
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
uwsgi_error("fork()")
|
||||
}
|
||||
else if (pid > 0) {
|
||||
n_ui->pid = pid;
|
||||
// close the right side of the pipe
|
||||
close(n_ui->pipe[1]);
|
||||
if (n_ui->use_config) {
|
||||
close(n_ui->pipe_config[1]);
|
||||
}
|
||||
|
||||
if (n_ui->use_config) {
|
||||
if (write(n_ui->pipe_config[0], n_ui->config, n_ui->config_len) <= 0) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
close(n_ui->pipe_config[0]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
|
||||
if (uwsgi.emperor_tyrant) {
|
||||
uwsgi_log("[emperor-tyrant] dropping privileges to %d %d for instance %s\n", (int) uid, (int) gid, name);
|
||||
if (setgid(gid)) {
|
||||
uwsgi_error("setgid()");
|
||||
exit(1);
|
||||
}
|
||||
if (setgroups(0, NULL)) {
|
||||
uwsgi_error("setgroups()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (setuid(uid)) {
|
||||
uwsgi_error("setuid()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
unsetenv("UWSGI_RELOADS");
|
||||
unsetenv("NOTIFY_SOCKET");
|
||||
|
||||
uef = uwsgi_num2str(n_ui->pipe[1]);
|
||||
if (setenv("UWSGI_EMPEROR_FD", uef, 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
exit(1);
|
||||
}
|
||||
free(uef);
|
||||
|
||||
if (n_ui->use_config) {
|
||||
uef = uwsgi_num2str(n_ui->pipe_config[1]);
|
||||
if (setenv("UWSGI_EMPEROR_FD_CONFIG", uef, 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
exit(1);
|
||||
}
|
||||
free(uef);
|
||||
}
|
||||
|
||||
uenvs = environ;
|
||||
while (*uenvs) {
|
||||
if (!strncmp(*uenvs, "UWSGI_VASSAL_", 13)) {
|
||||
char *ne = uwsgi_concat2("UWSGI_", *uenvs + 13);
|
||||
char *oe = uwsgi_concat2n(*uenvs, strchr(*uenvs, '=') - *uenvs, "", 0);
|
||||
if (unsetenv(oe)) {
|
||||
uwsgi_error("unsetenv()");
|
||||
break;
|
||||
}
|
||||
free(oe);
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("putenv %s\n", ne);
|
||||
#endif
|
||||
|
||||
if (putenv(ne)) {
|
||||
uwsgi_error("putenv()");
|
||||
}
|
||||
// do not free ne as putenv will add it to the environ
|
||||
uenvs = environ;
|
||||
continue;
|
||||
}
|
||||
uenvs++;
|
||||
}
|
||||
|
||||
// close the left side of the pipe
|
||||
close(n_ui->pipe[0]);
|
||||
|
||||
if (n_ui->use_config) {
|
||||
close(n_ui->pipe_config[0]);
|
||||
}
|
||||
|
||||
counter = 4;
|
||||
struct uwsgi_string_list *uct = uwsgi.vassals_templates;
|
||||
while(uct) {
|
||||
counter+=2;
|
||||
uct = uct->next;
|
||||
}
|
||||
|
||||
vassal_argv = uwsgi_malloc(sizeof(char *) * counter);
|
||||
// set args
|
||||
vassal_argv[0] = uwsgi.binary_path;
|
||||
|
||||
if (uwsgi.emperor_broodlord) {
|
||||
colon = strchr(name, ':');
|
||||
if (colon) {
|
||||
colon[0] = 0;
|
||||
}
|
||||
}
|
||||
if (!strcmp(name + (strlen(name) - 4), ".xml"))
|
||||
vassal_argv[1] = "--xml";
|
||||
if (!strcmp(name + (strlen(name) - 4), ".ini"))
|
||||
vassal_argv[1] = "--ini";
|
||||
if (!strcmp(name + (strlen(name) - 4), ".yml"))
|
||||
vassal_argv[1] = "--yaml";
|
||||
if (!strcmp(name + (strlen(name) - 5), ".yaml"))
|
||||
vassal_argv[1] = "--yaml";
|
||||
if (!strcmp(name + (strlen(name) - 3), ".js"))
|
||||
vassal_argv[1] = "--json";
|
||||
if (!strcmp(name + (strlen(name) - 5), ".json"))
|
||||
vassal_argv[1] = "--json";
|
||||
|
||||
if (colon) {
|
||||
colon[0] = ':';
|
||||
}
|
||||
vassal_argv[2] = name;
|
||||
counter = 3;
|
||||
uct = uwsgi.vassals_templates;
|
||||
while(uct) {
|
||||
vassal_argv[counter] = "--inherit";
|
||||
vassal_argv[counter+1] = uct->value;
|
||||
counter+=2;
|
||||
uct = uct->next;
|
||||
}
|
||||
vassal_argv[counter] = NULL;
|
||||
|
||||
// disable stdin
|
||||
int stdin_fd = open("/dev/null", O_RDONLY);
|
||||
if (stdin_fd < 0) {
|
||||
uwsgi_error_open("/dev/null");
|
||||
exit(1);
|
||||
}
|
||||
if (stdin_fd != 0) {
|
||||
if (dup2(stdin_fd, 0)) {
|
||||
uwsgi_error("dup2()");
|
||||
exit(1);
|
||||
}
|
||||
close(stdin_fd);
|
||||
}
|
||||
|
||||
// close all of the unneded fd
|
||||
for(i=3;i<(int)uwsgi.max_fd;i++) {
|
||||
if (i != n_ui->pipe[1]) {
|
||||
close(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.vassals_start_hook) {
|
||||
uwsgi_log("running vassal start-hook: %s %s\n", uwsgi.vassals_start_hook, n_ui->name);
|
||||
if (setenv("UWSGI_VASSALS_DIR", emperor_absolute_dir, 1)) {
|
||||
uwsgi_error("setenv()");
|
||||
}
|
||||
int start_hook_ret = uwsgi_run_command_and_wait(uwsgi.vassals_start_hook, n_ui->name);
|
||||
uwsgi_log("%s start-hook returned %d\n", n_ui->name, start_hook_ret);
|
||||
}
|
||||
|
||||
// start !!!
|
||||
if (execvp(vassal_argv[0], vassal_argv)) {
|
||||
uwsgi_error("execvp()");
|
||||
}
|
||||
uwsgi_log("is the uwsgi binary in your system PATH ?\n");
|
||||
// never here
|
||||
exit(UWSGI_EXILE_CODE);
|
||||
}
|
||||
|
||||
clear:
|
||||
|
||||
free(n_ui);
|
||||
c_ui->ui_next = NULL;
|
||||
|
||||
}
|
||||
|
||||
void emperor_loop() {
|
||||
|
||||
// monitor a directory
|
||||
|
||||
struct uwsgi_instance ui_base;
|
||||
struct uwsgi_instance *ui_current;
|
||||
struct stat st;
|
||||
|
||||
pid_t diedpid;
|
||||
int waitpid_status;
|
||||
int has_children = 0;
|
||||
int i_am_alone = 0;
|
||||
int simple_mode = 0;
|
||||
glob_t g;
|
||||
int i;
|
||||
struct dirent *de;
|
||||
char *amqp_port;
|
||||
int amqp_fd = -1;
|
||||
char *amqp_routing_key;
|
||||
|
||||
void *events;
|
||||
int nevents;
|
||||
int interesting_fd;
|
||||
char notification_message[64];
|
||||
struct rlimit rl;
|
||||
|
||||
uwsgi.emperor_stats_fd = -1;
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
uwsgi_unix_signal(SIGINT, royal_death);
|
||||
uwsgi_unix_signal(SIGTERM, royal_death);
|
||||
uwsgi_unix_signal(SIGQUIT, royal_death);
|
||||
uwsgi_unix_signal(SIGUSR1, emperor_stats);
|
||||
|
||||
memset(&ui_base, 0, sizeof(struct uwsgi_instance));
|
||||
|
||||
if (getrlimit(RLIMIT_NOFILE, &rl)) {
|
||||
uwsgi_error("getrlimit()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi.max_fd = rl.rlim_cur;
|
||||
|
||||
|
||||
emperor_queue = event_queue_init();
|
||||
|
||||
events = event_queue_alloc(64);
|
||||
|
||||
if (uwsgi.has_emperor) {
|
||||
uwsgi_log("*** starting uWSGI sub-Emperor ***\n");
|
||||
}
|
||||
else {
|
||||
uwsgi_log("*** starting uWSGI Emperor ***\n");
|
||||
}
|
||||
|
||||
if (uwsgi.emperor_stats) {
|
||||
char *tcp_port = strchr(uwsgi.emperor_stats, ':');
|
||||
if (tcp_port) {
|
||||
// disable deferred accept for this socket
|
||||
int current_defer_accept = uwsgi.no_defer_accept;
|
||||
uwsgi.no_defer_accept = 1;
|
||||
uwsgi.emperor_stats_fd = bind_to_tcp(uwsgi.emperor_stats, uwsgi.listen_queue, tcp_port);
|
||||
uwsgi.no_defer_accept = current_defer_accept;
|
||||
}
|
||||
else {
|
||||
uwsgi.emperor_stats_fd = bind_to_unix(uwsgi.emperor_stats, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
|
||||
}
|
||||
|
||||
event_queue_add_fd_read(emperor_queue, uwsgi.emperor_stats_fd);
|
||||
uwsgi_log("*** Emperor stats server enabled on %s fd: %d ***\n", uwsgi.emperor_stats, uwsgi.emperor_stats_fd);
|
||||
}
|
||||
|
||||
amqp_port = strchr(uwsgi.emperor_dir, ':');
|
||||
|
||||
if (amqp_port) {
|
||||
if (uwsgi.emperor_amqp_vhost == NULL) uwsgi.emperor_amqp_vhost = "/";
|
||||
if (uwsgi.emperor_amqp_username == NULL) uwsgi.emperor_amqp_username = "guest";
|
||||
if (uwsgi.emperor_amqp_password == NULL) uwsgi.emperor_amqp_password = "guest";
|
||||
reconnect:
|
||||
while(amqp_fd == -1) {
|
||||
uwsgi_log("connecting to AMQP server...\n");
|
||||
amqp_fd = uwsgi_connect(uwsgi.emperor_dir, -1, 0);
|
||||
if (amqp_fd < 0) {
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("subscribing to queue...\n");
|
||||
if (uwsgi_amqp_consume_queue(amqp_fd, uwsgi.emperor_amqp_vhost, uwsgi.emperor_amqp_username, uwsgi.emperor_amqp_password, "", "uwsgi.emperor", "fanout") < 0) {
|
||||
close(amqp_fd);
|
||||
amqp_fd = -1;
|
||||
sleep(1);
|
||||
goto reconnect;
|
||||
}
|
||||
|
||||
event_queue_add_fd_read(emperor_queue, amqp_fd);
|
||||
}
|
||||
else {
|
||||
if (!glob(uwsgi.emperor_dir, GLOB_MARK|GLOB_NOCHECK, NULL, &g)) {
|
||||
if (g.gl_pathc == 1 && g.gl_pathv[0][strlen(g.gl_pathv[0]) - 1] == '/') {
|
||||
simple_mode = 1;
|
||||
if (chdir(uwsgi.emperor_dir)) {
|
||||
uwsgi_error("chdir()");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_error("glob()");
|
||||
exit(1);
|
||||
}
|
||||
globfree(&g);
|
||||
emperor_absolute_dir = uwsgi_malloc(PATH_MAX+1);
|
||||
if (realpath(".", emperor_absolute_dir) == NULL) {
|
||||
uwsgi_error("realpath()");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
ui = &ui_base;
|
||||
|
||||
int freq = 0 ;
|
||||
|
||||
for (;;) {
|
||||
|
||||
|
||||
if (!i_am_alone) {
|
||||
diedpid = waitpid(uwsgi.emperor_pid, &waitpid_status, WNOHANG);
|
||||
if (diedpid < 0 || diedpid > 0) {
|
||||
i_am_alone = 1;
|
||||
}
|
||||
}
|
||||
|
||||
nevents = event_queue_wait_multi(emperor_queue, freq, events, 64);
|
||||
freq = 3;
|
||||
|
||||
for (i = 0; i<nevents;i++) {
|
||||
interesting_fd = event_queue_interesting_fd(events, i);
|
||||
|
||||
if (amqp_fd > -1 && interesting_fd == amqp_fd ) {
|
||||
uint64_t msgsize;
|
||||
char *config = uwsgi_amqp_consume(amqp_fd, &msgsize, &amqp_routing_key);
|
||||
|
||||
if (!config) {
|
||||
uwsgi_log("problem with RabbitMQ server, trying reconnection...\n");
|
||||
event_queue_del_fd(emperor_queue, amqp_fd, event_queue_read());
|
||||
close(amqp_fd);
|
||||
amqp_fd = -1;
|
||||
goto reconnect;
|
||||
}
|
||||
|
||||
if (amqp_routing_key) {
|
||||
uwsgi_log("AMQP routing_key = %s\n", amqp_routing_key);
|
||||
char *config_file = uwsgi_concat2("emperor://", amqp_routing_key);
|
||||
free(amqp_routing_key);
|
||||
|
||||
ui_current = emperor_get(config_file);
|
||||
|
||||
if (ui_current) {
|
||||
// ignore event if i am not loyal
|
||||
if (!ui_current->loyal) continue;
|
||||
free(ui_current->config);
|
||||
ui_current->config = config;
|
||||
ui_current->config_len = msgsize;
|
||||
if (!msgsize) {
|
||||
// SAFE
|
||||
emperor_del(ui_current);
|
||||
}
|
||||
else {
|
||||
emperor_respawn(ui_current, time(NULL));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (msgsize > 0) {
|
||||
emperor_add(config_file, time(NULL), config, msgsize, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
free(config_file);
|
||||
}
|
||||
else {
|
||||
if (msgsize) {
|
||||
if (msgsize >= 0xff) { free(config); continue; }
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%.*s\n", (int)msgsize, config);
|
||||
#endif
|
||||
char *config_file = uwsgi_concat2n(config, msgsize, "", 0);
|
||||
free(config);
|
||||
|
||||
if (strncmp(config_file, "http://", 7)) {
|
||||
if (stat(config_file, &st)) {
|
||||
free(config_file);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!S_ISREG(st.st_mode)) {
|
||||
free(config_file);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ui_current = emperor_get(config_file);
|
||||
|
||||
if (ui_current) {
|
||||
// ignore event if i am not loyal
|
||||
if (!ui_current->loyal) continue;
|
||||
emperor_respawn(ui_current, time(NULL));
|
||||
}
|
||||
else {
|
||||
emperor_add(config_file, time(NULL), NULL, 0, 0, 0);
|
||||
}
|
||||
|
||||
free(config_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (uwsgi.emperor_stats && uwsgi.emperor_stats_fd > -1 && interesting_fd == uwsgi.emperor_stats_fd) {
|
||||
emperor_send_stats(uwsgi.emperor_stats_fd);
|
||||
}
|
||||
else {
|
||||
ui_current = emperor_get_by_fd(interesting_fd);
|
||||
if (ui_current) {
|
||||
char byte;
|
||||
ssize_t rlen = read(interesting_fd, &byte, 1);
|
||||
if (rlen <= 0) {
|
||||
// SAFE
|
||||
emperor_del(ui_current);
|
||||
}
|
||||
else {
|
||||
if (byte == 17) {
|
||||
ui_current->loyal = 1;
|
||||
uwsgi_log("*** vassal %s is now loyal ***\n", ui_current->name);
|
||||
|
||||
// TODO post-start hook
|
||||
}
|
||||
else if (byte == 22) {
|
||||
emperor_stop(ui_current);
|
||||
}
|
||||
else if (byte == 30 && uwsgi.emperor_broodlord > 0 && uwsgi.emperor_broodlord_count < uwsgi.emperor_broodlord) {
|
||||
uwsgi_log("[emperor] going in broodlord mode: launching zergs for %s\n", ui_current->name);
|
||||
char *zerg_name = uwsgi_concat3(ui_current->name,":","zerg");
|
||||
emperor_add(zerg_name, time(NULL), NULL, 0, ui_current->uid, ui_current->gid);
|
||||
free(zerg_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[emperor] unrecognized vassal event on fd %d\n", interesting_fd);
|
||||
event_queue_del_fd(emperor_queue, interesting_fd, event_queue_read());
|
||||
close(interesting_fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (amqp_fd == -1) {
|
||||
if (simple_mode) {
|
||||
DIR *dir = opendir(".");
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
if (!strcmp(de->d_name + (strlen(de->d_name) - 4), ".xml") ||
|
||||
!strcmp(de->d_name + (strlen(de->d_name) - 4), ".ini") ||
|
||||
!strcmp(de->d_name + (strlen(de->d_name) - 4), ".yml") ||
|
||||
!strcmp(de->d_name + (strlen(de->d_name) - 5), ".yaml") ||
|
||||
!strcmp(de->d_name + (strlen(de->d_name) - 3), ".js") ||
|
||||
!strcmp(de->d_name + (strlen(de->d_name) - 5), ".json")
|
||||
) {
|
||||
|
||||
|
||||
if (strlen(de->d_name) >= 0xff)
|
||||
continue;
|
||||
|
||||
if (stat(de->d_name, &st))
|
||||
continue;
|
||||
|
||||
if (!S_ISREG(st.st_mode))
|
||||
continue;
|
||||
|
||||
ui_current = emperor_get(de->d_name);
|
||||
|
||||
if (ui_current) {
|
||||
// check if uid or gid are changed, in such case, sotp the instance
|
||||
if (uwsgi.emperor_tyrant) {
|
||||
if (st.st_uid != ui_current->uid || st.st_gid != ui_current->gid) {
|
||||
uwsgi_log("!!! permissions of file %s changed. stopping the instance... !!!\n");
|
||||
emperor_stop(ui_current);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// check if mtime is changed and the uWSGI instance must be reloaded
|
||||
if (st.st_mtime > ui_current->last_mod) {
|
||||
emperor_respawn(ui_current, st.st_mtime);
|
||||
}
|
||||
}
|
||||
else {
|
||||
emperor_add(de->d_name, st.st_mtime, NULL, 0, st.st_uid, st.st_gid);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
else {
|
||||
if (glob(uwsgi.emperor_dir, GLOB_MARK|GLOB_NOCHECK, NULL, &g)) {
|
||||
uwsgi_error("glob()");
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < (int) g.gl_pathc; i++) {
|
||||
if (!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 4), ".xml") ||
|
||||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 4), ".ini") ||
|
||||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 4), ".yml") ||
|
||||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 3), ".js") ||
|
||||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 5), ".json") ||
|
||||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 5), ".yaml")
|
||||
) {
|
||||
|
||||
|
||||
if (strlen(g.gl_pathv[i]) >= 0xff)
|
||||
continue;
|
||||
|
||||
if (stat(g.gl_pathv[i], &st))
|
||||
continue;
|
||||
|
||||
if (!S_ISREG(st.st_mode))
|
||||
continue;
|
||||
|
||||
ui_current = emperor_get(g.gl_pathv[i]);
|
||||
|
||||
if (ui_current) {
|
||||
// check if uid or gid are changed, in such case, sotp the instance
|
||||
if (uwsgi.emperor_tyrant) {
|
||||
if (st.st_uid != ui_current->uid || st.st_gid != ui_current->gid) {
|
||||
uwsgi_log("!!! permissions of file %s changed. stopping the instance... !!!\n");
|
||||
emperor_stop(ui_current);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// check if mtime is changed and the uWSGI instance must be reloaded
|
||||
if (st.st_mtime > ui_current->last_mod) {
|
||||
emperor_respawn(ui_current, st.st_mtime);
|
||||
}
|
||||
}
|
||||
else {
|
||||
emperor_add(g.gl_pathv[i], st.st_mtime, NULL, 0, st.st_uid, st.st_gid);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
globfree(&g);
|
||||
}
|
||||
}
|
||||
|
||||
// check for removed instances
|
||||
|
||||
ui_current = ui;
|
||||
has_children = 0;
|
||||
while (ui_current->ui_next) {
|
||||
ui_current = ui_current->ui_next;
|
||||
has_children++;
|
||||
}
|
||||
|
||||
if (uwsgi.notify) {
|
||||
if (snprintf(notification_message, 64, "The Emperor is governing %d vassals", has_children) >= 34) {
|
||||
uwsgi_notify(notification_message);
|
||||
}
|
||||
}
|
||||
|
||||
if (has_children) {
|
||||
diedpid = waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
|
||||
}
|
||||
else {
|
||||
// vacuum
|
||||
waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
|
||||
diedpid = 0;
|
||||
}
|
||||
if (diedpid < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
}
|
||||
ui_current = ui;
|
||||
while (ui_current->ui_next) {
|
||||
ui_current = ui_current->ui_next;
|
||||
// check loyalty if not in simple/glob mode
|
||||
if (amqp_fd > -1) {
|
||||
if (!ui_current->loyal && (time(NULL)-ui_current->last_loyal) > 60) {
|
||||
uwsgi_log("!!! no loyalty showed by instance %s !!!\n", ui_current->name);
|
||||
// SAFE
|
||||
emperor_del(ui_current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ui_current->status == 1) {
|
||||
if (ui_current->config) free(ui_current->config);
|
||||
// SAFE
|
||||
emperor_del(ui_current);
|
||||
break;
|
||||
}
|
||||
else if (!ui_current->use_config && strncmp(ui_current->name, "http://",7) && stat(ui_current->name, &st) && !ui_current->zerg) {
|
||||
emperor_stop(ui_current);
|
||||
}
|
||||
else if (ui_current->pid == diedpid) {
|
||||
if (ui_current->status == 0) {
|
||||
// respawn an accidentally dead instance if its exit code is not UWSGI_EXILE_CODE
|
||||
if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_EXILE_CODE) {
|
||||
// SAFE
|
||||
emperor_del(ui_current);
|
||||
}
|
||||
else {
|
||||
// UNSAFE
|
||||
emperor_add(ui_current->name, ui_current->last_mod, ui_current->config, ui_current->config_len, ui_current->uid, ui_current->gid);
|
||||
emperor_del(ui_current);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (ui_current->status == 1) {
|
||||
// remove 'marked for dead' instance
|
||||
if (ui_current->config) free(ui_current->config);
|
||||
// SAFE
|
||||
emperor_del(ui_current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define stats_send_llu(x, y) fprintf(output, x, (long long unsigned int) y)
|
||||
#define stats_send(x, y) fprintf(output, x, y)
|
||||
|
||||
void emperor_send_stats(int fd) {
|
||||
|
||||
struct sockaddr_un client_src;
|
||||
socklen_t client_src_len = 0;
|
||||
int client_fd = accept(fd, (struct sockaddr *) &client_src, &client_src_len);
|
||||
if (client_fd < 0) {
|
||||
uwsgi_error("accept()");
|
||||
return;
|
||||
}
|
||||
|
||||
FILE *output = fdopen(client_fd, "w");
|
||||
if (!output) {
|
||||
uwsgi_error("fdopen()");
|
||||
close(client_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
stats_send("{ \"version\": \"%s\",\n", UWSGI_VERSION);
|
||||
|
||||
fprintf(output,"\"pid\": %d,\n", (int)(getpid()));
|
||||
fprintf(output,"\"uid\": %d,\n", (int)(getuid()));
|
||||
fprintf(output,"\"gid\": %d,\n", (int)(getgid()));
|
||||
|
||||
char *cwd = uwsgi_get_cwd();
|
||||
stats_send("\"cwd\": \"%s\",\n", cwd);
|
||||
free(cwd);
|
||||
|
||||
stats_send("\"emperor\": \"%s\",\n", uwsgi.emperor_dir);
|
||||
|
||||
fprintf(output,"\"emperor_tyrant\": %d,\n", uwsgi.emperor_tyrant);
|
||||
|
||||
|
||||
fprintf(output, "\"vassals\": [\n");
|
||||
|
||||
struct uwsgi_instance *c_ui = ui->ui_next;
|
||||
|
||||
while (c_ui) {
|
||||
fprintf(output,"\t{");
|
||||
stats_send("\"id\": \"%s\", ", c_ui->name);
|
||||
fprintf(output,"\"pid\": %d, ", (int) c_ui->pid);
|
||||
|
||||
stats_send_llu( "\"born\": %llu, ", c_ui->born);
|
||||
stats_send_llu( "\"last_mod\": %llu, ", c_ui->last_mod);
|
||||
|
||||
fprintf(output,"\"loyal\": %d, ", c_ui->loyal);
|
||||
fprintf(output,"\"zerg\": %d, ", c_ui->zerg);
|
||||
|
||||
fprintf(output,"\"uid\": %d, ", (int)c_ui->uid);
|
||||
fprintf(output,"\"gid\": %d, ", (int)c_ui->gid);
|
||||
|
||||
stats_send_llu( "\"respawns\": %llu ", c_ui->respawns);
|
||||
c_ui = c_ui->ui_next;
|
||||
|
||||
if (c_ui) {
|
||||
fprintf(output,"},\n");
|
||||
}
|
||||
else {
|
||||
fprintf(output,"}\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fprintf(output,"]}\n");
|
||||
fclose(output);
|
||||
|
||||
}
|
||||
@@ -1,702 +0,0 @@
|
||||
#ifdef UWSGI_ERLANG
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
static void erlang_log(void);
|
||||
|
||||
PyObject *py_erlang_connect(PyObject * self, PyObject * args) {
|
||||
|
||||
char *erlang_node;
|
||||
int fd;
|
||||
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s:erlang_connect", &erlang_node)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UWSGI_SET_BLOCKING;
|
||||
fd = erl_connect(erlang_node);
|
||||
UWSGI_UNSET_BLOCKING;
|
||||
return PyInt_FromLong(fd);
|
||||
}
|
||||
|
||||
PyObject *py_erlang_recv_message(PyObject * self, PyObject * args) {
|
||||
int erfd;
|
||||
struct pollfd erpoll;
|
||||
ErlMessage emsg;
|
||||
PyObject *pyer = NULL;
|
||||
unsigned char erlang_buffer[8192];
|
||||
int eret;
|
||||
int timeout = uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT];
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i|i:erlang_recv_message", &erfd, &timeout)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (erfd < 0) {
|
||||
goto clear;
|
||||
}
|
||||
|
||||
erpoll.fd = erfd;
|
||||
erpoll.events = POLLIN;
|
||||
cycle:
|
||||
memset(&emsg, 0, sizeof(ErlMessage));
|
||||
UWSGI_SET_BLOCKING;
|
||||
if (timeout > 0) {
|
||||
eret = poll(&erpoll, 1, timeout * 1000);
|
||||
if (eret < 0) {
|
||||
uwsgi_error("poll()");
|
||||
goto clear;
|
||||
}
|
||||
else if (eret == 0) {
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
if (erl_receive_msg(erfd, erlang_buffer, 8192, &emsg) == ERL_MSG) {
|
||||
if (emsg.type == ERL_TICK) {
|
||||
goto cycle;
|
||||
}
|
||||
if (emsg.msg) {
|
||||
pyer = eterm_to_py(emsg.msg);
|
||||
}
|
||||
if (emsg.msg) {
|
||||
erl_free_compound(emsg.msg);
|
||||
}
|
||||
if (emsg.to) {
|
||||
erl_free_compound(emsg.to);
|
||||
}
|
||||
if (emsg.from) {
|
||||
erl_free_compound(emsg.from);
|
||||
}
|
||||
if (!pyer) {
|
||||
goto clear;
|
||||
}
|
||||
UWSGI_UNSET_BLOCKING;
|
||||
return pyer;
|
||||
}
|
||||
|
||||
clear:
|
||||
UWSGI_UNSET_BLOCKING;
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
|
||||
}
|
||||
|
||||
PyObject *py_erlang_send_message(PyObject * self, PyObject * args) {
|
||||
|
||||
ETERM *pymessage;
|
||||
ETERM *pid;
|
||||
int erfd;
|
||||
PyObject *ermessage, *erdest, *zero;
|
||||
|
||||
int er_number, er_serial, er_creation;
|
||||
char *er_node;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iOO|i:erlang_send_message", &erfd, &erdest, &ermessage)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (erfd < 0) {
|
||||
goto clear;
|
||||
}
|
||||
|
||||
if (!PyString_Check(erdest) && !PyDict_Check(erdest)) {
|
||||
goto clear;
|
||||
}
|
||||
|
||||
pymessage = py_to_eterm(ermessage);
|
||||
if (!pymessage) {
|
||||
goto clear;
|
||||
}
|
||||
|
||||
|
||||
if (PyString_Check(erdest)) {
|
||||
if (!erl_reg_send(erfd, PyString_AsString(erdest), pymessage)) {
|
||||
erl_err_msg("erl_reg_send()");
|
||||
goto clear2;
|
||||
}
|
||||
}
|
||||
else if (PyDict_Check(erdest)) {
|
||||
zero = PyDict_GetItemString(erdest, "node");
|
||||
if (!zero) {
|
||||
goto clear2;
|
||||
}
|
||||
if (!PyString_Check(zero)) {
|
||||
goto clear2;
|
||||
}
|
||||
er_node = PyString_AsString(zero);
|
||||
|
||||
zero = PyDict_GetItemString(erdest, "number");
|
||||
if (!zero) {
|
||||
goto clear2;
|
||||
}
|
||||
if (!PyInt_Check(zero)) {
|
||||
goto clear2;
|
||||
}
|
||||
er_number = PyInt_AsLong(zero);
|
||||
|
||||
zero = PyDict_GetItemString(erdest, "serial");
|
||||
if (!zero) {
|
||||
goto clear2;
|
||||
}
|
||||
if (!PyInt_Check(zero)) {
|
||||
goto clear2;
|
||||
}
|
||||
er_serial = PyInt_AsLong(zero);
|
||||
|
||||
zero = PyDict_GetItemString(erdest, "creation");
|
||||
if (!zero) {
|
||||
goto clear2;
|
||||
}
|
||||
if (!PyInt_Check(zero)) {
|
||||
goto clear2;
|
||||
}
|
||||
er_creation = PyInt_AsLong(zero);
|
||||
|
||||
pid = erl_mk_pid((const char *) er_node, er_number, er_serial, er_creation);
|
||||
|
||||
if (!pid) {
|
||||
goto clear2;
|
||||
}
|
||||
|
||||
if (!erl_send(erfd, pid, pymessage)) {
|
||||
erl_err_msg("erl_send()");
|
||||
erl_free_term(pid);
|
||||
goto clear2;
|
||||
}
|
||||
|
||||
erl_free_term(pid);
|
||||
}
|
||||
else {
|
||||
goto clear;
|
||||
}
|
||||
|
||||
erl_free_compound(pymessage);
|
||||
|
||||
Py_INCREF(Py_True);
|
||||
return Py_True;
|
||||
|
||||
clear2:
|
||||
erl_free_compound(pymessage);
|
||||
clear:
|
||||
PyErr_Print();
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject *py_erlang_rpc(PyObject * self, PyObject * args) {
|
||||
|
||||
int fd, timeout = uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT];
|
||||
char *emod, *efun;
|
||||
PyObject *eargs, *pyer = NULL;
|
||||
ETERM *pyargs, *rex;
|
||||
ErlMessage emsg;
|
||||
int eret;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "issO|i:erlang_rpc", &fd, &emod, &efun, &eargs, &timeout)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fd < 0) {
|
||||
goto clear;
|
||||
}
|
||||
|
||||
pyargs = py_to_eterm(eargs);
|
||||
if (!pyargs) {
|
||||
goto clear;
|
||||
}
|
||||
|
||||
|
||||
if (erl_rpc_to(fd, emod, efun, pyargs)) {
|
||||
erl_err_msg("erl_rpc_to()");
|
||||
goto clear2;
|
||||
}
|
||||
|
||||
|
||||
cycle:
|
||||
memset(&emsg, 0, sizeof(ErlMessage));
|
||||
UWSGI_SET_BLOCKING;
|
||||
eret = erl_rpc_from(fd, timeout * 1000, &emsg);
|
||||
if (eret == ERL_TICK) {
|
||||
goto cycle;
|
||||
}
|
||||
else if (eret == ERL_MSG) {
|
||||
if (emsg.msg) {
|
||||
if (ERL_IS_TUPLE(emsg.msg)) {
|
||||
rex = erl_element(1, emsg.msg);
|
||||
if (!rex) {
|
||||
goto clear2;
|
||||
}
|
||||
if (!strncmp("rex", ERL_ATOM_PTR(rex), ERL_ATOM_SIZE(rex))) {
|
||||
erl_free_term(rex);
|
||||
rex = erl_element(2, emsg.msg);
|
||||
if (!rex) {
|
||||
goto clear2;
|
||||
}
|
||||
pyer = eterm_to_py(rex);
|
||||
erl_free_term(rex);
|
||||
}
|
||||
else {
|
||||
erl_free_term(rex);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (emsg.msg) {
|
||||
erl_free_compound(emsg.msg);
|
||||
}
|
||||
if (emsg.to) {
|
||||
erl_free_compound(emsg.to);
|
||||
}
|
||||
if (emsg.from) {
|
||||
erl_free_compound(emsg.from);
|
||||
}
|
||||
if (!pyer) {
|
||||
goto clear2;
|
||||
}
|
||||
erl_free_compound(pyargs);
|
||||
UWSGI_UNSET_BLOCKING;
|
||||
return pyer;
|
||||
}
|
||||
else {
|
||||
erl_err_msg("erl_rpc_from()");
|
||||
}
|
||||
|
||||
clear2:
|
||||
UWSGI_UNSET_BLOCKING;
|
||||
erl_free_compound(pyargs);
|
||||
|
||||
clear:
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject *py_erlang_close(PyObject * self, PyObject * args) {
|
||||
|
||||
int fd;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i:erlang_close", &fd)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if (fd >= 0) {
|
||||
erl_close_connection(fd);
|
||||
}
|
||||
|
||||
Py_INCREF(Py_True);
|
||||
return Py_True;
|
||||
}
|
||||
|
||||
static PyMethodDef uwsgi_erlang_methods[] = {
|
||||
{"erlang_connect", py_erlang_connect, METH_VARARGS, ""},
|
||||
{"erlang_send_message", py_erlang_send_message, METH_VARARGS, ""},
|
||||
{"erlang_recv_message", py_erlang_recv_message, METH_VARARGS, ""},
|
||||
{"erlang_rpc", py_erlang_rpc, METH_VARARGS, ""},
|
||||
{"erlang_close", py_erlang_close, METH_VARARGS, ""},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
|
||||
int init_erlang(char *nodename, char *cookie) {
|
||||
|
||||
struct sockaddr_in e_addr;
|
||||
|
||||
char *ip;
|
||||
char *node;
|
||||
int efd;
|
||||
int rlen;
|
||||
char *cookiefile;
|
||||
char *cookiehome;
|
||||
char cookievalue[128];
|
||||
int cookiefd;
|
||||
|
||||
PyMethodDef *uwsgi_function;
|
||||
|
||||
|
||||
ip = strchr(nodename, '@');
|
||||
|
||||
if (ip == NULL) {
|
||||
uwsgi_log( "*** invalid erlang node name ***\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cookie == NULL) {
|
||||
// get the cookie from the home
|
||||
cookiehome = getenv("HOME");
|
||||
if (!cookiehome) {
|
||||
uwsgi_log( "unable to get erlang cookie from your home.\n");
|
||||
return -1;
|
||||
}
|
||||
cookiefile = malloc(strlen(cookiehome) + 1 + strlen(".erlang.cookie") + 1);
|
||||
if (!cookiefile) {
|
||||
uwsgi_error("malloc()");
|
||||
}
|
||||
cookiefile[0] = 0;
|
||||
strcat(cookiefile, cookiehome);
|
||||
strcat(cookiefile, "/.erlang.cookie");
|
||||
|
||||
cookiefd = open(cookiefile, O_RDONLY);
|
||||
if (cookiefd < 0) {
|
||||
uwsgi_error("open()");
|
||||
free(cookiefile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(cookievalue, 0, 128);
|
||||
if (read(cookiefd, cookievalue, 127) < 1) {
|
||||
uwsgi_log( "invalid cookie found in %s\n", cookiefile);
|
||||
close(cookiefd);
|
||||
free(cookiefile);
|
||||
return -1;
|
||||
}
|
||||
cookie = cookievalue;
|
||||
close(cookiefd);
|
||||
free(cookiefile);
|
||||
}
|
||||
|
||||
node = malloc((ip - nodename) + 1);
|
||||
if (node == NULL) {
|
||||
uwsgi_error("malloc()");
|
||||
return -1;
|
||||
}
|
||||
memset(node, 0, (ip - nodename) + 1);
|
||||
memcpy(node, nodename, ip - nodename);
|
||||
|
||||
erl_init(NULL, 0);
|
||||
|
||||
if (erl_connect_xinit(ip + 1, node, nodename, NULL, cookie, 0) == -1) {
|
||||
uwsgi_log( "*** unable to initialize erlang c-node ***\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
efd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (efd < 0) {
|
||||
uwsgi_error("socket()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
memset(&e_addr, 0, sizeof(struct sockaddr_in));
|
||||
e_addr.sin_family = AF_INET;
|
||||
e_addr.sin_addr.s_addr = inet_addr(ip + 1);
|
||||
|
||||
rlen = 1;
|
||||
if (setsockopt(efd, SOL_SOCKET, SO_REUSEADDR, &rlen, sizeof(rlen))) {
|
||||
uwsgi_error("setsockopt()");
|
||||
close(efd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bind(efd, (struct sockaddr *) &e_addr, sizeof(struct sockaddr_in)) < 0) {
|
||||
uwsgi_error("bind()");
|
||||
close(efd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rlen = sizeof(struct sockaddr_in);
|
||||
if (getsockname(efd, (struct sockaddr *) &e_addr, (socklen_t *) & rlen)) {
|
||||
uwsgi_error("getsockname()");
|
||||
close(efd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(efd, uwsgi.listen_queue)) {
|
||||
uwsgi_error("listen()");
|
||||
close(efd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (erl_publish(ntohs(e_addr.sin_port)) < 0) {
|
||||
uwsgi_log( "*** unable to subscribe with EPMD ***\n");
|
||||
close(efd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_log( "Erlang C-Node initialized on port %d you can access it with name %s\n", ntohs(e_addr.sin_port), nodename);
|
||||
|
||||
for (uwsgi_function = uwsgi_erlang_methods; uwsgi_function->ml_name != NULL; uwsgi_function++) {
|
||||
PyObject *func = PyCFunction_New(uwsgi_function, NULL);
|
||||
PyDict_SetItemString(uwsgi.embedded_dict, uwsgi_function->ml_name, func);
|
||||
Py_DECREF(func);
|
||||
}
|
||||
|
||||
return efd;
|
||||
|
||||
}
|
||||
|
||||
ETERM *py_to_eterm(PyObject * pobj) {
|
||||
int i;
|
||||
int count;
|
||||
PyObject *pobj2;
|
||||
ETERM *eobj = NULL;
|
||||
ETERM *eobj2 = NULL;
|
||||
ETERM **eobj3;
|
||||
|
||||
if (pobj == NULL) {
|
||||
return erl_mk_empty_list();
|
||||
}
|
||||
|
||||
if (PyString_Check(pobj)) {
|
||||
eobj = erl_mk_atom(PyString_AsString(pobj));
|
||||
}
|
||||
else if (PyInt_Check(pobj)) {
|
||||
eobj = erl_mk_int(PyInt_AsLong(pobj));
|
||||
}
|
||||
else if (PyList_Check(pobj)) {
|
||||
eobj = erl_mk_empty_list();
|
||||
for (i = PyList_Size(pobj) - 1; i >= 0; i--) {
|
||||
pobj2 = PyList_GetItem(pobj, i);
|
||||
eobj2 = py_to_eterm(pobj2);
|
||||
eobj = erl_cons(eobj2, eobj);
|
||||
}
|
||||
}
|
||||
else if (PyDict_Check(pobj)) {
|
||||
// a pid
|
||||
char *er_node;
|
||||
int er_number, er_serial, er_creation;
|
||||
pobj2 = PyDict_GetItemString(pobj, "node");
|
||||
if (!pobj2) {
|
||||
PyErr_Print();
|
||||
goto clear;
|
||||
}
|
||||
if (!PyString_Check(pobj2)) {
|
||||
goto clear;
|
||||
}
|
||||
er_node = PyString_AsString(pobj2);
|
||||
|
||||
pobj2 = PyDict_GetItemString(pobj, "number");
|
||||
if (!pobj2) {
|
||||
PyErr_Print();
|
||||
goto clear;
|
||||
}
|
||||
if (!PyInt_Check(pobj2)) {
|
||||
goto clear;
|
||||
}
|
||||
er_number = PyInt_AsLong(pobj2);
|
||||
|
||||
pobj2 = PyDict_GetItemString(pobj, "serial");
|
||||
if (!pobj2) {
|
||||
PyErr_Print();
|
||||
goto clear;
|
||||
}
|
||||
if (!PyInt_Check(pobj2)) {
|
||||
goto clear;
|
||||
}
|
||||
er_serial = PyInt_AsLong(pobj2);
|
||||
|
||||
pobj2 = PyDict_GetItemString(pobj, "creation");
|
||||
if (!pobj2) {
|
||||
PyErr_Print();
|
||||
goto clear;
|
||||
}
|
||||
if (!PyInt_Check(pobj2)) {
|
||||
goto clear;
|
||||
}
|
||||
er_creation = PyInt_AsLong(pobj2);
|
||||
|
||||
eobj = erl_mk_pid(er_node, er_number, er_serial, er_creation);
|
||||
}
|
||||
else if (PyTuple_Check(pobj)) {
|
||||
count = PyTuple_Size(pobj);
|
||||
eobj3 = malloc(sizeof(ETERM *) * count);
|
||||
for (i = 0; i < count; i++) {
|
||||
pobj2 = PyTuple_GetItem(pobj, i);
|
||||
if (!pobj2) {
|
||||
break;
|
||||
}
|
||||
eobj3[i] = py_to_eterm(pobj2);
|
||||
}
|
||||
eobj = erl_mk_tuple(eobj3, count);
|
||||
free(eobj3);
|
||||
}
|
||||
else {
|
||||
uwsgi_log( "UNMANAGED PYTHON TYPE: %s\n", pobj->ob_type->tp_name);
|
||||
}
|
||||
|
||||
clear:
|
||||
if (eobj == NULL) {
|
||||
return erl_mk_empty_list();
|
||||
}
|
||||
|
||||
return eobj;
|
||||
}
|
||||
|
||||
PyObject *eterm_to_py(ETERM * obj) {
|
||||
int i;
|
||||
int count;
|
||||
ETERM *obj2;
|
||||
PyObject *eobj = NULL;
|
||||
|
||||
if (obj == NULL) {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
switch (ERL_TYPE(obj)) {
|
||||
|
||||
case ERL_CONS:
|
||||
case ERL_NIL:
|
||||
count = erl_length(obj);
|
||||
eobj = PyList_New(0);
|
||||
for (i = 0; i < count; i++) {
|
||||
obj2 = erl_hd(obj);
|
||||
PyList_Append(eobj, eterm_to_py(obj2));
|
||||
obj = erl_tl(obj);
|
||||
}
|
||||
break;
|
||||
case ERL_TUPLE:
|
||||
eobj = PyTuple_New(erl_size(obj));
|
||||
for (i = 1; i <= erl_size(obj); i++) {
|
||||
obj2 = erl_element(i, obj);
|
||||
PyTuple_SetItem(eobj, i - 1, eterm_to_py(obj2));
|
||||
}
|
||||
break;
|
||||
case ERL_ATOM:
|
||||
eobj = PyString_FromStringAndSize(ERL_ATOM_PTR(obj), ERL_ATOM_SIZE(obj));
|
||||
break;
|
||||
case ERL_INTEGER:
|
||||
eobj = PyInt_FromLong(ERL_INT_VALUE(obj));
|
||||
break;
|
||||
case ERL_BINARY:
|
||||
uwsgi_log( "FOUND A BINARY %.*s\n", ERL_BIN_SIZE(obj), ERL_BIN_PTR(obj));
|
||||
break;
|
||||
case ERL_PID:
|
||||
eobj = PyDict_New();
|
||||
if (PyDict_SetItemString(eobj, "node", PyString_FromString(ERL_PID_NODE(obj)))) {
|
||||
PyErr_Print();
|
||||
break;
|
||||
}
|
||||
if (PyDict_SetItemString(eobj, "number", PyInt_FromLong(ERL_PID_NUMBER(obj)))) {
|
||||
PyErr_Print();
|
||||
break;
|
||||
}
|
||||
if (PyDict_SetItemString(eobj, "serial", PyInt_FromLong(ERL_PID_SERIAL(obj)))) {
|
||||
PyErr_Print();
|
||||
break;
|
||||
}
|
||||
if (PyDict_SetItemString(eobj, "creation", PyInt_FromLong(ERL_PID_CREATION(obj)))) {
|
||||
PyErr_Print();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
uwsgi_log( "UNMANAGED ETERM TYPE: %d\n", ERL_TYPE(obj));
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (eobj == NULL) {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
return eobj;
|
||||
}
|
||||
|
||||
void erlang_loop(struct wsgi_request *wsgi_req) {
|
||||
|
||||
ErlConnect econn;
|
||||
ErlMessage em;
|
||||
ETERM *eresponse;
|
||||
|
||||
PyObject *callable = PyDict_GetItemString(uwsgi.embedded_dict, "erlang_func");
|
||||
if (!callable) {
|
||||
PyErr_Print();
|
||||
uwsgi_log( "- you have not defined a uwsgi.erlang_func callable, Erlang message manager will be disabled until you define it -\n");
|
||||
}
|
||||
|
||||
PyObject *pargs = PyTuple_New(1);
|
||||
if (!pargs) {
|
||||
PyErr_Print();
|
||||
uwsgi_log( "- error preparing arg tuple for uwsgi.erlang_func callable, Erlang message manager will be disabled -\n");
|
||||
}
|
||||
|
||||
while (uwsgi.workers[uwsgi.mywid].manage_next_request) {
|
||||
|
||||
|
||||
UWSGI_CLEAR_STATUS;
|
||||
|
||||
wsgi_req->poll.fd = erl_accept(uwsgi.erlangfd, &econn);
|
||||
|
||||
if (wsgi_req->poll.fd >= 0) {
|
||||
|
||||
UWSGI_SET_ERLANGING;
|
||||
for (;;) {
|
||||
if (erl_receive_msg(wsgi_req->poll.fd, (unsigned char *) wsgi_req->buffer, uwsgi.buffer_size, &em) == ERL_MSG) {
|
||||
if (em.type == ERL_TICK)
|
||||
continue;
|
||||
|
||||
if (!callable) {
|
||||
callable = PyDict_GetItemString(uwsgi.embedded_dict, "erlang_func");
|
||||
}
|
||||
|
||||
if (!callable) {
|
||||
uwsgi_log( "- you still have not defined a uwsgi.erlang_func callable, Erlang message rejected -\n");
|
||||
}
|
||||
|
||||
PyObject *zero = eterm_to_py(em.msg);
|
||||
if (em.msg) {
|
||||
erl_free_compound(em.msg);
|
||||
}
|
||||
if (em.to) {
|
||||
erl_free_compound(em.to);
|
||||
}
|
||||
|
||||
if (!zero) {
|
||||
PyErr_Print();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (PyTuple_SetItem(pargs, 0, zero)) {
|
||||
PyErr_Print();
|
||||
continue;
|
||||
}
|
||||
|
||||
PyObject *erlang_result = PyEval_CallObject(callable, pargs);
|
||||
|
||||
//Py_DECREF(zero);
|
||||
|
||||
if (erlang_result) {
|
||||
eresponse = py_to_eterm(erlang_result);
|
||||
if (eresponse) {
|
||||
erl_send(wsgi_req->poll.fd, em.from, eresponse);
|
||||
erl_free_compound(eresponse);
|
||||
}
|
||||
Py_DECREF(erlang_result);
|
||||
}
|
||||
|
||||
if (em.from) {
|
||||
erl_free_compound(em.from);
|
||||
}
|
||||
|
||||
uwsgi.workers[0].requests++;
|
||||
uwsgi.workers[uwsgi.mywid].requests++;
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_LOGGING])
|
||||
erlang_log();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
erl_close_connection(wsgi_req->poll.fd);
|
||||
|
||||
UWSGI_UNSET_ERLANGING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void erlang_log() {
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG]) {
|
||||
get_memusage();
|
||||
}
|
||||
else {
|
||||
uwsgi.workers[uwsgi.mywid].rss_size = 0;
|
||||
uwsgi.workers[uwsgi.mywid].vsz_size = 0;
|
||||
}
|
||||
uwsgi_log( "[Erlang worker %d pid %d] request %llu done {rss: %llu vsz: %llu}\n", uwsgi.mywid, uwsgi.mypid, uwsgi.workers[uwsgi.mywid].requests, uwsgi.workers[uwsgi.mywid].rss_size, uwsgi.workers[uwsgi.mywid].vsz_size);
|
||||
}
|
||||
|
||||
#else
|
||||
#warning "*** Erlang support is disabled ***"
|
||||
#endif
|
||||
@@ -0,0 +1,883 @@
|
||||
#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_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_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_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;
|
||||
|
||||
if ( ( (ev[id].flags == EV_ERROR) || (ev[id].flags == EV_EOF) || (ev[id].flags == (EV_EOF|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
|
||||
|
||||
inline int event_queue_read() {
|
||||
return UWSGI_EVENT_IN;
|
||||
}
|
||||
|
||||
inline int event_queue_write() {
|
||||
return UWSGI_EVENT_OUT;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
use POSIX;
|
||||
|
||||
open CONFIG,'welcome.ini';
|
||||
|
||||
dup2(fileno(CONFIG), 17);
|
||||
|
||||
exec './uwsgi','--ini','fd://17';
|
||||
@@ -0,0 +1,47 @@
|
||||
require 'fiber'
|
||||
class SuspendingBody
|
||||
|
||||
def each
|
||||
for i in 1..3
|
||||
yield "number: #{i}\n"
|
||||
UWSGI.async_sleep(1)
|
||||
puts "sleep..."
|
||||
Fiber.yield
|
||||
end
|
||||
|
||||
fd = UWSGI.async_connect("81.174.68.52:80")
|
||||
UWSGI.wait_fd_write(fd, 3)
|
||||
Fiber.yield
|
||||
io = IO.new(fd)
|
||||
puts "connected"
|
||||
io.syswrite("GET /uwsgi/export/1081%3A362d695b2f25/plugins/fiber/fiber.c HTTP/1.0\r\n")
|
||||
io.syswrite("Host: projects.unbit.it\r\n")
|
||||
io.syswrite("\r\n")
|
||||
|
||||
UWSGI.wait_fd_read(fd, 3)
|
||||
Fiber.yield
|
||||
|
||||
puts "data available"
|
||||
|
||||
begin
|
||||
while body = io.sysread(fd)
|
||||
yield body
|
||||
Fiber.yield
|
||||
end
|
||||
rescue
|
||||
end
|
||||
|
||||
io.close
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class RackFoo
|
||||
|
||||
def call(env)
|
||||
[200, { 'Content-Type' => 'text/plain'}, SuspendingBody.new]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
run RackFoo.new
|
||||
@@ -0,0 +1,8 @@
|
||||
uwsgi:
|
||||
plugins: rack
|
||||
socket: 127.0.0.1:3031
|
||||
rack: fibers.ru
|
||||
post-buffering: 4096
|
||||
async: 10
|
||||
loop: fiber
|
||||
|
||||
+9
-9
@@ -4,28 +4,28 @@
|
||||
|
||||
int uwsgi_file_monitor_new() {
|
||||
|
||||
int inotify_fd ;
|
||||
int inotify_fd;
|
||||
|
||||
|
||||
|
||||
inotify_fd = inotify_init();
|
||||
|
||||
|
||||
if (inotify_fd < 0) {
|
||||
uwsgi_error("inotify_init()");
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return inotify_fd ;
|
||||
|
||||
return inotify_fd;
|
||||
}
|
||||
|
||||
int uwsgi_file_monitor_add(int fd, char *what) {
|
||||
|
||||
int inotify_watch_fd ;
|
||||
int inotify_watch_fd;
|
||||
|
||||
inotify_watch_fd = inotify_add_watch(fd, what, IN_ALL_EVENTS);
|
||||
|
||||
|
||||
if (inotify_watch_fd < 0) {
|
||||
uwsgi_error("inotify_add_watch()");
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return inotify_watch_fd;
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
from flask import Flask, request
|
||||
app = Flask(__name__)
|
||||
app.debug = True
|
||||
|
||||
@app.route('/')
|
||||
def hello_world():
|
||||
return "<form method='POST' enctype='multipart/form-data' action='/upload'><input type='text' name='pippo'/><input type='file' name='ufile'/><input type='submit' value='upload'/></form>"
|
||||
|
||||
@app.route('/upload', methods=['GET', 'POST'])
|
||||
def upload_file():
|
||||
return str(len(request.form.get('pippo', 'boh'))) + request.form.get('pippo', 'boh')
|
||||
return request.files['ufile'].read()
|
||||
@@ -0,0 +1,155 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_gateway *register_gateway(char *name, void (*loop)(int)) {
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
ug->loop(id);
|
||||
// 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->name = 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->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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// http:3:GET / HTTP/1.1:192.168.173.10:80,192.168.173.11:80,192.168.173.12:80,192.168.173.13:80
|
||||
|
||||
/*
|
||||
write(arg1);
|
||||
|
||||
wait_for_fd()
|
||||
|
||||
get_data() == 200
|
||||
*/
|
||||
@@ -0,0 +1 @@
|
||||
// uwsgi:3::192.168.173.1:3031,192.168.173.2:3031,192.168.173.3:3031,192.168.173.4:3031
|
||||
@@ -0,0 +1,27 @@
|
||||
[uwsgi]
|
||||
|
||||
master = true
|
||||
processes = 4
|
||||
threads = 8
|
||||
|
||||
; initialize 4 sockets with 4 different protocols
|
||||
socket = :3031
|
||||
socket = :3032
|
||||
socket = :3033
|
||||
socket = :3034
|
||||
|
||||
socket-protocol = 0,uwsgi
|
||||
socket-protocol = 1,http
|
||||
socket-protocol = 2,fastcgi
|
||||
socket-protocol = 3,uwsgidump
|
||||
|
||||
|
||||
; add a cache with 1000 items of 96k
|
||||
cache = 1000
|
||||
cache-blocksize = 98304
|
||||
|
||||
|
||||
log-micros = true
|
||||
|
||||
module = heavytest
|
||||
mount = /cc=uwsgicc/__init__.py
|
||||
@@ -0,0 +1,14 @@
|
||||
import uwsgi
|
||||
import werkzeug.testapp
|
||||
|
||||
uwsgi.cache_set("/cache/get", "HTTP 1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<h1>I am the uWSGI cache</h1>")
|
||||
|
||||
def app001(env, start_response):
|
||||
start_response('200 OK', [('Content-Type', 'text/html')])
|
||||
return "PATH_INFO=%s" % env['PATH_INFO']
|
||||
|
||||
def app002(env, start_response):
|
||||
start_response('200 OK', [('Content-Type', 'text/html')])
|
||||
return "requests: %d" % uwsgi.total_requests()
|
||||
|
||||
uwsgi.applications = { '':werkzeug.testapp.test_app, '/app001':app001, '/app002':app002 }
|
||||
@@ -0,0 +1,7 @@
|
||||
import uwsgi
|
||||
#uwsgi.cache_set('/', "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\nHello World from cache")
|
||||
def application(env, start_response):
|
||||
start_response('200 OK', [('Content-Type', 'text/html')])
|
||||
yield "foobar"
|
||||
yield str(env['wsgi.input'].fileno())
|
||||
yield "<h1>Hello World</h1>"
|
||||
+7
-14
@@ -6,20 +6,18 @@ import rrdtool
|
||||
|
||||
s_freq = 10
|
||||
|
||||
# this is a cron emulator done with the Spooler :)
|
||||
def rrdtool_updater(env):
|
||||
uwsgi.set_spooler_frequency(s_freq)
|
||||
rrdtool.update('../test.rrd', str(int(time.time()))+':'+str(uwsgi.total_requests()))
|
||||
uwsgi.send_to_spooler({})
|
||||
# this task will be executed every s_freq seconds
|
||||
def rrdtool_updater(sig, sec):
|
||||
rrdtool.update('test.rrd', str(int(time.time()))+':'+str(uwsgi.total_requests()))
|
||||
|
||||
|
||||
uwsgi.spooler = rrdtool_updater
|
||||
uwsgi.register_timer(0, s_freq, uwsgi.KIND_WORKER, rrdtool_updater)
|
||||
|
||||
|
||||
|
||||
def hello_world(env, start_response):
|
||||
start_response('200 Ok', [('Content-type', 'text/plain')])
|
||||
yield 'Hello world !'
|
||||
return 'Hello world !'
|
||||
|
||||
|
||||
def graph(env, start_response):
|
||||
@@ -27,12 +25,7 @@ def graph(env, start_response):
|
||||
now = int(time.time())
|
||||
graph_range = (3600*24)
|
||||
rrdtool.graph('uwsgi_graph.png', '--start', str(now - graph_range), '--end', str(now), 'DEF:urequests=test.rrd:requests:AVERAGE', 'LINE2:urequests#00FF00')
|
||||
fd = open('uwsgi_graph.png', 'r')
|
||||
# send file to browser
|
||||
return env['wsgi.file_wrapper'](fd, 4096)
|
||||
|
||||
# start the simil-cron
|
||||
uwsgi.send_to_spooler({})
|
||||
|
||||
# send file to client
|
||||
uwsgi.sendfile('uwsgi_graph.png')
|
||||
|
||||
uwsgi.applications = {'/': hello_world, '/graph':graph}
|
||||
|
||||
@@ -1,397 +0,0 @@
|
||||
#include "uwsgi.h"
|
||||
|
||||
struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_http_req {
|
||||
|
||||
pthread_t a_new_thread;
|
||||
int fd;
|
||||
struct sockaddr_in c_addr;
|
||||
socklen_t c_len;
|
||||
};
|
||||
|
||||
enum {
|
||||
uwsgi_http_method,
|
||||
uwsgi_http_uri,
|
||||
uwsgi_http_protocol,
|
||||
uwsgi_http_protocol_r,
|
||||
|
||||
uwsgi_http_header_key,
|
||||
uwsgi_http_header_key_colon,
|
||||
|
||||
uwsgi_http_header_val,
|
||||
uwsgi_http_header_val_r,
|
||||
|
||||
uwsgi_http_end
|
||||
};
|
||||
|
||||
void http_end() {
|
||||
uwsgi_log("closing uWSGI embedded HTTP server.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void http_wait_end() {
|
||||
pid_t wp_p;
|
||||
int wp_c;
|
||||
wp_p = waitpid(-1, &wp_c, 0);
|
||||
uwsgi_log("closing uWSGI embedded HTTP server.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static char *add_uwsgi_var(char *up, char *key, uint16_t keylen, char *val, uint16_t vallen, int header, char *watermark)
|
||||
{
|
||||
|
||||
int i;
|
||||
|
||||
if (!header) {
|
||||
|
||||
if ( (up + 2 + keylen + 2 + vallen) > watermark ) return up ;
|
||||
|
||||
*up++ = (unsigned char) (keylen & 0xff);
|
||||
*up++ = (unsigned char) ((keylen >> 8) & 0xff);
|
||||
|
||||
memcpy(up, key, keylen);
|
||||
up += keylen;
|
||||
} else {
|
||||
|
||||
|
||||
for (i = 0; i < keylen; i++) {
|
||||
if (key[i] == '-') {
|
||||
key[i] = '_';
|
||||
} else {
|
||||
key[i] = toupper( (int) key[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (strncmp("CONTENT_TYPE", key, keylen) && strncmp("CONTENT_LENGTH", key, keylen)) {
|
||||
if ( (up + 2 + keylen + 5 + 2 + vallen) > watermark ) return up ;
|
||||
*up++ = (unsigned char) (((uint16_t) keylen + 5) & 0xff);
|
||||
*up++ = (unsigned char) ((((uint16_t) keylen + 5) >> 8) & 0xff);
|
||||
memcpy(up, "HTTP_", 5);
|
||||
up += 5;
|
||||
} else {
|
||||
if ( (up + 2 + keylen + 2 + vallen) > watermark ) return up ;
|
||||
*up++ = (unsigned char) (keylen & 0xff);
|
||||
*up++ = (unsigned char) ((keylen >> 8) & 0xff);
|
||||
}
|
||||
|
||||
|
||||
memcpy(up, key, keylen);
|
||||
up += keylen;
|
||||
}
|
||||
|
||||
*up++ = (unsigned char) (vallen & 0xff);
|
||||
*up++ = (unsigned char) ((vallen >> 8) & 0xff);
|
||||
memcpy(up, val, vallen);
|
||||
up += vallen;
|
||||
|
||||
return up;
|
||||
}
|
||||
|
||||
static void *http_request(void *);
|
||||
|
||||
void http_loop(struct uwsgi_server * uwsgi)
|
||||
{
|
||||
|
||||
|
||||
struct uwsgi_http_req *ur;
|
||||
int ret;
|
||||
pthread_attr_t pa;
|
||||
int stat_loc ;
|
||||
|
||||
ret = pthread_attr_init(&pa);
|
||||
if (ret) {
|
||||
uwsgi_log("pthread_attr_init() = %d\n", ret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = pthread_attr_setdetachstate(&pa, PTHREAD_CREATE_DETACHED);
|
||||
if (ret) {
|
||||
uwsgi_log("pthread_attr_setdetachstate() = %d\n", ret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// ignore broken pipes;
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
if (!uwsgi->http_only) {
|
||||
signal(SIGCHLD, &http_end);
|
||||
signal(SIGINT, &http_wait_end);
|
||||
}
|
||||
else {
|
||||
signal(SIGINT, &http_end);
|
||||
}
|
||||
|
||||
uwsgi->http_server_name = malloc(256);
|
||||
if (!uwsgi->http_server_name) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(uwsgi->http_server_name, 0, 256);
|
||||
if (gethostname(uwsgi->http_server_name, 255)) {
|
||||
uwsgi_error("gethostname()");
|
||||
memcpy(uwsgi->http_server_name, "localhost", 9);
|
||||
}
|
||||
|
||||
uwsgi_log("starting HTTP loop on %s (pid: %d)\n", uwsgi->http_server_name, (int) getpid());
|
||||
for(;;) {
|
||||
|
||||
if (!uwsgi->http_only) {
|
||||
if (waitpid(-1, &stat_loc, WNOHANG) != 0) {
|
||||
http_end();
|
||||
}
|
||||
}
|
||||
ur = malloc(sizeof(struct uwsgi_http_req));
|
||||
if (!ur) {
|
||||
uwsgi_error("malloc()");
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
ur->c_len = sizeof(struct sockaddr_in) ;
|
||||
ur->fd = accept(uwsgi->http_fd, (struct sockaddr *) &ur->c_addr, &ur->c_len);
|
||||
|
||||
if (ur->fd < 0) {
|
||||
uwsgi_error("accept()");
|
||||
free(ur);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = pthread_create(&ur->a_new_thread, &pa, http_request, (void *) ur);
|
||||
if (ret) {
|
||||
uwsgi_log("pthread_create() = %d\n", ret);
|
||||
free(ur);
|
||||
// sleep a bit to allow some resource gaining
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void *http_request(void *u_h_r)
|
||||
{
|
||||
|
||||
char buf[4096];
|
||||
|
||||
char tmp_buf[4096];
|
||||
|
||||
char uwsgipkt[4096];
|
||||
|
||||
struct uwsgi_http_req *ur = (struct uwsgi_http_req *) u_h_r ;
|
||||
|
||||
int clientfd = ur->fd;
|
||||
int uwsgi_fd = -1;
|
||||
|
||||
int need_to_read = 1;
|
||||
int state = uwsgi_http_method;
|
||||
|
||||
int http_body_len = 0;
|
||||
|
||||
size_t len;
|
||||
|
||||
int i, j;
|
||||
|
||||
char HTTP_header_key[1024];
|
||||
|
||||
uint16_t ulen;
|
||||
|
||||
char *ptr = tmp_buf;
|
||||
|
||||
int qs = 0;
|
||||
|
||||
char *up = uwsgipkt;
|
||||
|
||||
char *watermark = up + 4096 ;
|
||||
char *watermark2 = tmp_buf + 4096 ;
|
||||
|
||||
int path_info_len;
|
||||
char *ip;
|
||||
|
||||
up[0] = 0;
|
||||
up[3] = 0;
|
||||
up += 4;
|
||||
|
||||
while (need_to_read) {
|
||||
len = read(clientfd, buf, 4096);
|
||||
if (len <= 0) {
|
||||
uwsgi_error("read()");
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < (int) len; i++) {
|
||||
|
||||
if (buf[i] == ' ') {
|
||||
|
||||
if (state == uwsgi_http_method) {
|
||||
|
||||
up = add_uwsgi_var(up, "REQUEST_METHOD", 14, tmp_buf, ptr - tmp_buf, 0, watermark);
|
||||
ptr = tmp_buf;
|
||||
state = uwsgi_http_uri;
|
||||
|
||||
} else if (state == uwsgi_http_uri) {
|
||||
|
||||
up = add_uwsgi_var(up, "REQUEST_URI", 11, tmp_buf, ptr - tmp_buf, 0, watermark);
|
||||
|
||||
path_info_len = ptr - tmp_buf;
|
||||
for (j = 0; j < ptr - tmp_buf; j++) {
|
||||
if (tmp_buf[j] == '?') {
|
||||
path_info_len = j;
|
||||
if (j + 1 < (ptr - tmp_buf)) {
|
||||
up = add_uwsgi_var(up, "QUERY_STRING", 12, tmp_buf + j + 1, (ptr - tmp_buf) - (j + 1), 0, watermark);
|
||||
qs = 1 ;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!qs) {
|
||||
up = add_uwsgi_var(up, "QUERY_STRING", 12, NULL, 0, 0, watermark);
|
||||
}
|
||||
up = add_uwsgi_var(up, "PATH_INFO", 9, tmp_buf, path_info_len, 0, watermark);
|
||||
|
||||
ptr = tmp_buf;
|
||||
state = uwsgi_http_protocol;
|
||||
|
||||
} else if (state == uwsgi_http_header_key_colon) {
|
||||
|
||||
if (ptr+1 > watermark2) { close(uwsgi_fd); goto clear;}
|
||||
*ptr++ = 0;
|
||||
|
||||
memset(HTTP_header_key, 0, sizeof(HTTP_header_key));
|
||||
memcpy(HTTP_header_key, tmp_buf, strlen(tmp_buf));
|
||||
ptr = tmp_buf;
|
||||
state = uwsgi_http_header_val;
|
||||
} else {
|
||||
//check for overflow
|
||||
if (ptr+1 > watermark2) { close(uwsgi_fd); goto clear;}
|
||||
*ptr++ = buf[i];
|
||||
}
|
||||
|
||||
} else if (buf[i] == '\r') {
|
||||
|
||||
if (state == uwsgi_http_protocol) {
|
||||
state = uwsgi_http_protocol_r;
|
||||
}
|
||||
if (state == uwsgi_http_header_val) {
|
||||
state = uwsgi_http_header_val_r;
|
||||
} else if (state == uwsgi_http_header_key) {
|
||||
state = uwsgi_http_end;
|
||||
}
|
||||
} else if (buf[i] == '\n') {
|
||||
|
||||
if (state == uwsgi_http_header_val_r) {
|
||||
|
||||
up = add_uwsgi_var(up, HTTP_header_key, strlen(HTTP_header_key), tmp_buf, ptr - tmp_buf, 1, watermark);
|
||||
if (!strcmp("CONTENT_LENGTH", HTTP_header_key)) {
|
||||
if (ptr+1 > watermark2) { close(uwsgi_fd); goto clear;}
|
||||
*ptr++ = 0;
|
||||
http_body_len = atoi(tmp_buf);
|
||||
}
|
||||
ptr = tmp_buf;
|
||||
state = uwsgi_http_header_key;
|
||||
} else if (state == uwsgi_http_protocol_r) {
|
||||
|
||||
up = add_uwsgi_var(up, "SERVER_PROTOCOL", 15, tmp_buf, ptr - tmp_buf, 0, watermark);
|
||||
ptr = tmp_buf;
|
||||
state = uwsgi_http_header_key;
|
||||
} else if (state == uwsgi_http_end) {
|
||||
need_to_read = 0;
|
||||
|
||||
|
||||
up = add_uwsgi_var(up, "SERVER_NAME", 11, uwsgi.http_server_name, strlen(uwsgi.http_server_name), 0, watermark);
|
||||
up = add_uwsgi_var(up, "SERVER_PORT", 11, uwsgi.http_server_port, strlen(uwsgi.http_server_port), 0, watermark);
|
||||
|
||||
up = add_uwsgi_var(up, "SCRIPT_NAME", 11, "", 0, 0, watermark);
|
||||
|
||||
ip = inet_ntoa(ur->c_addr.sin_addr);
|
||||
up = add_uwsgi_var(up, "REMOTE_ADDR", 11, ip, strlen(ip), 0, watermark);
|
||||
|
||||
//up = add_uwsgi_var(up, "REMOTE_ADDR", 11, "127.0.0.1", 9, 0, watermark);
|
||||
//up = add_uwsgi_var(up, "REMOTE_USER", 11, "unknown", 7, 0);
|
||||
|
||||
for(j=0;j<uwsgi.http_vars_cnt;j++) {
|
||||
char *separator;
|
||||
|
||||
separator = strchr(uwsgi.http_vars[j], '=');
|
||||
if (separator) {
|
||||
up = add_uwsgi_var(up, uwsgi.http_vars[j], separator - uwsgi.http_vars[j], separator + 1, strlen(separator + 1), 0, watermark);
|
||||
}
|
||||
else {
|
||||
up = add_uwsgi_var(up, uwsgi.http_vars[j], strlen(uwsgi.http_vars[j]), NULL, 0, 0, watermark);
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_fd = uwsgi_connect(uwsgi.socket_name, 10);
|
||||
if (uwsgi_fd >= 0) {
|
||||
ulen = (up - uwsgipkt) - 4;
|
||||
uwsgipkt[1] = (unsigned char) (ulen & 0xff);
|
||||
uwsgipkt[2] = (unsigned char) ((ulen >> 8) & 0xff);
|
||||
|
||||
if (write(uwsgi_fd, uwsgipkt, ulen + 4) < 0) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
|
||||
if (http_body_len > 0) {
|
||||
if (http_body_len >= (int) len - (i + 1)) {
|
||||
if (write(uwsgi_fd, buf + i + 1, len - (i + 1)) < 0) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
http_body_len -= len - (i + 1);
|
||||
} else {
|
||||
if (write(uwsgi_fd, buf + i, http_body_len) < 0) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
http_body_len = 0;
|
||||
}
|
||||
|
||||
while (http_body_len > 0) {
|
||||
int to_read = 4096;
|
||||
if (http_body_len < to_read) {
|
||||
to_read = http_body_len;
|
||||
}
|
||||
len = read(clientfd, uwsgipkt, to_read);
|
||||
if (write(uwsgi_fd, uwsgipkt, len) < 0) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
http_body_len -= len;
|
||||
}
|
||||
}
|
||||
while ((len = read(uwsgi_fd, uwsgipkt, 4096)) > 0) {
|
||||
if (write(clientfd, uwsgipkt, len) < 0) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
}
|
||||
close(uwsgi_fd);
|
||||
}
|
||||
else {
|
||||
close(uwsgi_fd);
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
} else if (buf[i] == ':') {
|
||||
|
||||
if (state == uwsgi_http_header_key) {
|
||||
state = uwsgi_http_header_key_colon;
|
||||
} else {
|
||||
//check for overflow
|
||||
if (ptr+1 > watermark2) { close(uwsgi_fd); goto clear;}
|
||||
*ptr++ = buf[i];
|
||||
}
|
||||
} else {
|
||||
|
||||
//check for overflow
|
||||
if (ptr+1 > watermark2) { close(uwsgi_fd); goto clear;}
|
||||
*ptr++ = buf[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
clear:
|
||||
close(clientfd);
|
||||
|
||||
free(ur);
|
||||
pthread_exit(NULL);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
uWSGI version <b><?=uwsgi_version()?></b><br/>
|
||||
workerd id: <b><?=uwsgi_worker_id()?></b><br/>
|
||||
master pid: <b><?=uwsgi_masterpid()?></b><br/>
|
||||
|
||||
uri: <b><?= $_SERVER['REQUEST_URI'] ?></b><br/>
|
||||
docroot: <b><?= $_SERVER['DOCUMENT_ROOT'] ?></b><br/>
|
||||
PATH_INFO: <b><?= $_SERVER['PATH_INFO'] ?></b><br/>
|
||||
|
||||
<? uwsgi_signal(17) ?>
|
||||
|
||||
<? uwsgi_setprocname("test test test"); ?>
|
||||
|
||||
rpc result:<br/>
|
||||
<? echo uwsgi_rpc("", "hello", "one", "two", "three"); ?>
|
||||
|
||||
<?
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
uwsgi_cache_update('foobar', $_POST['cache_val']);
|
||||
}
|
||||
|
||||
?>
|
||||
<form method="POST">
|
||||
<input type="text" name="cache_val" value="<?=uwsgi_cache_get('foobar')?>"/>
|
||||
<input type="submit" value="cache set" />
|
||||
</form>
|
||||
@@ -2,36 +2,33 @@
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
/*
|
||||
ini file must be read ALL into memory.
|
||||
This memory must not be freed for all the server lifecycle
|
||||
*/
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
enum {
|
||||
ini_key_start,
|
||||
ini_val_start,
|
||||
};
|
||||
/*
|
||||
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 ;
|
||||
off_t i;
|
||||
|
||||
for(i = strlen(line)-1;i>=0; i--) {
|
||||
if (line[i] == ' ' || line[i] == '\t') {
|
||||
if (line[i] == ' ' || line[i] == '\t' || line[i] == '\r') {
|
||||
line[i] = 0;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *ini_lstrip(char *line) {
|
||||
|
||||
off_t i ;
|
||||
|
||||
off_t i;
|
||||
char *ptr = line;
|
||||
|
||||
for(i=0;i< (int) strlen(line);i++) {
|
||||
if (line[i] == ' ' || line[i] == '\t') {
|
||||
if (line[i] == ' ' || line[i] == '\t' || line[i] == '\r') {
|
||||
ptr++;
|
||||
continue;
|
||||
}
|
||||
@@ -44,10 +41,10 @@ char *ini_lstrip(char *line) {
|
||||
char *ini_get_key(char *key) {
|
||||
|
||||
off_t i;
|
||||
char *ptr = key ;
|
||||
char *ptr = key;
|
||||
|
||||
for(i=0;i< (int) strlen(key);i++) {
|
||||
ptr++ ;
|
||||
ptr++;
|
||||
if (key[i] == '=') {
|
||||
key[i] = 0;
|
||||
return ptr;
|
||||
@@ -59,9 +56,9 @@ char *ini_get_key(char *key) {
|
||||
|
||||
char *ini_get_line(char *ini, off_t size) {
|
||||
|
||||
off_t i ;
|
||||
off_t i;
|
||||
char *ptr = ini;
|
||||
|
||||
|
||||
for(i=0;i<size;i++) {
|
||||
ptr++;
|
||||
if (ini[i] == '\n') {
|
||||
@@ -70,16 +67,19 @@ char *ini_get_line(char *ini, off_t size) {
|
||||
}
|
||||
}
|
||||
|
||||
// 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, struct option *long_options) {
|
||||
void uwsgi_ini_config(char *file, char *magic_table[]) {
|
||||
|
||||
int fd;
|
||||
ssize_t len;
|
||||
int len = 0;
|
||||
char *ini;
|
||||
struct stat sb;
|
||||
|
||||
char *ini_line;
|
||||
|
||||
@@ -87,48 +87,34 @@ void uwsgi_ini_config(char *file, struct option *long_options) {
|
||||
char *key;
|
||||
char *val;
|
||||
|
||||
int lines = 1 ;
|
||||
int lines = 1;
|
||||
|
||||
struct option *lopt, *aopt;
|
||||
char *section_asked = "uwsgi";
|
||||
char *colon ;
|
||||
char *colon;
|
||||
|
||||
if (uwsgi_check_scheme(file)) {
|
||||
colon = uwsgi_get_last_char(file, '/');
|
||||
colon = uwsgi_get_last_char(colon, ':');
|
||||
}
|
||||
else {
|
||||
colon = uwsgi_get_last_char(file, ':');
|
||||
}
|
||||
|
||||
colon = strchr(file, ':');
|
||||
if (colon) {
|
||||
colon[0] = 0;
|
||||
if (colon[1] != 0) {
|
||||
section_asked = colon+1 ;
|
||||
section_asked = colon+1;
|
||||
}
|
||||
}
|
||||
|
||||
fd = open(file, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
uwsgi_error("open()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (fstat(fd, &sb)) {
|
||||
uwsgi_error("fstat()");
|
||||
exit(1);
|
||||
if (file[0] != 0) {
|
||||
uwsgi_log("[uWSGI] getting INI configuration from %s\n", file);
|
||||
}
|
||||
|
||||
ini = malloc(sb.st_size+1);
|
||||
ini = uwsgi_open_and_read(file, &len, 1, magic_table);
|
||||
|
||||
if (!ini) {
|
||||
uwsgi_error("malloc()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
len = read(fd, ini, sb.st_size);
|
||||
if (len != sb.st_size) {
|
||||
uwsgi_error("read()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ini[sb.st_size+1] = 0 ;
|
||||
|
||||
while(sb.st_size) {
|
||||
ini_line = ini_get_line(ini, sb.st_size);
|
||||
while(len) {
|
||||
ini_line = ini_get_line(ini, len);
|
||||
if (ini_line == NULL) {
|
||||
break;
|
||||
}
|
||||
@@ -153,33 +139,22 @@ void uwsgi_ini_config(char *file, struct option *long_options) {
|
||||
ini_rstrip(key);
|
||||
val = ini_lstrip(val);
|
||||
ini_rstrip(val);
|
||||
lopt = long_options;
|
||||
while ((aopt = lopt)) {
|
||||
if (!aopt->name)
|
||||
break;
|
||||
if (!strcmp(key, aopt->name)) {
|
||||
if (aopt->flag) {
|
||||
*aopt->flag = aopt->val;
|
||||
}
|
||||
else {
|
||||
manage_opt(aopt->val, val);
|
||||
}
|
||||
}
|
||||
lopt++;
|
||||
}
|
||||
add_exported_option((char *)key, val, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sb.st_size -= (ini_line - ini);
|
||||
|
||||
len -= (ini_line - ini);
|
||||
ini += (ini_line - ini);
|
||||
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
if (colon) {
|
||||
colon[0] = ':';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>it.unbit.uwsgi.emperor</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/Users/roberta/uwsgi/uwsgi</string>
|
||||
<string>--emperor</string>
|
||||
<string>/Users/*/Library/uwsgi/*.{xml,ini,yml,yaml,js}</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>it.unbit.uwsgi</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/Users/roberta/uwsgi/uwsgi</string>
|
||||
<string>--socket</string>
|
||||
<string>:3032</string>
|
||||
<string>--module</string>
|
||||
<string>welcome</string>
|
||||
<string>--master</string>
|
||||
<string>--die-on-term</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -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
|
||||
@@ -1,22 +1,31 @@
|
||||
#ifdef UWSGI_LDAP
|
||||
#ifdef UWSGI_LDAP
|
||||
|
||||
#include "uwsgi.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#include <ldap.h>
|
||||
|
||||
void ldap2uwsgi(char *ldapname, char *uwsginame) {
|
||||
#ifndef LDAP_OPT_SUCCESS
|
||||
#define LDAP_OPT_SUCCESS LDAP_SUCCESS
|
||||
#endif
|
||||
|
||||
char *ptr = uwsginame ;
|
||||
#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]);
|
||||
*ptr++ = '-';
|
||||
*ptr++ = tolower( (int) ldapname[i]);
|
||||
}
|
||||
else {
|
||||
*ptr++= ldapname[i] ;
|
||||
*ptr++ = ldapname[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +33,6 @@ void ldap2uwsgi(char *ldapname, char *uwsginame) {
|
||||
}
|
||||
|
||||
int calc_ldap_name(char *name) {
|
||||
|
||||
int i;
|
||||
int counter = 0;
|
||||
|
||||
@@ -34,192 +42,204 @@ int calc_ldap_name(char *name) {
|
||||
}
|
||||
}
|
||||
|
||||
return strlen(name) + counter ;
|
||||
return strlen(name) + counter;
|
||||
}
|
||||
|
||||
void uwsgi_ldap_schema_dump_ldif(struct option *lo) {
|
||||
struct uwsgi_ldap_entry {
|
||||
int num;
|
||||
char names[1024];
|
||||
int has_arg;
|
||||
};
|
||||
|
||||
struct option *aopt, *lopt ;
|
||||
|
||||
lopt = lo;
|
||||
int i;
|
||||
int counter = 30000;
|
||||
void uwsgi_name_to_ldap(char *src, char *dst) {
|
||||
|
||||
int pythonpath_found = 0 ;
|
||||
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");
|
||||
|
||||
while( (aopt = lopt) ) {
|
||||
if (!aopt->name)
|
||||
break;
|
||||
struct uwsgi_ldap_entry *entry, *ule = get_ldap_names(&items);
|
||||
|
||||
if (aopt->val == LONG_ARGS_PYTHONPATH) {
|
||||
if (pythonpath_found) {
|
||||
goto next;
|
||||
}
|
||||
pythonpath_found = 1;
|
||||
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");
|
||||
}
|
||||
|
||||
if (aopt->flag) {
|
||||
uwsgi_log("olcAttributeTypes: ( 1.3.6.1.4.1.35156.17.4.%d NAME 'uWSGI", counter) ;
|
||||
counter++;
|
||||
}
|
||||
else {
|
||||
uwsgi_log("olcAttributeTypes: ( 1.3.6.1.4.1.35156.17.4.%d NAME 'uWSGI", aopt->val) ;
|
||||
}
|
||||
for(i=0;i< (int)strlen(aopt->name);i++) {
|
||||
if (aopt->name[i] == '-') {
|
||||
i++;
|
||||
uwsgi_log("%c", toupper( (int) aopt->name[i]));
|
||||
}
|
||||
else {
|
||||
uwsgi_log("%c", aopt->name[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (aopt->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");
|
||||
}
|
||||
next:
|
||||
lopt++;
|
||||
}
|
||||
|
||||
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") ;
|
||||
|
||||
lopt = lo;
|
||||
|
||||
uwsgi_log("olcObjectClasses: ( 1.3.6.1.4.1.35156.17.3.1 NAME 'uWSGIConfig' SUP top AUXILIARY DESC 'uWSGI configuration' MAY ( ");
|
||||
|
||||
pythonpath_found = 0;
|
||||
while( (aopt = lopt) ) {
|
||||
if (!aopt->name)
|
||||
break;
|
||||
|
||||
if (aopt->val == LONG_ARGS_PYTHONPATH) {
|
||||
if (pythonpath_found) {
|
||||
goto next2;
|
||||
}
|
||||
pythonpath_found = 1;
|
||||
else {
|
||||
uwsgi_log(" ) SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )\n");
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("uWSGI");
|
||||
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");
|
||||
|
||||
for(i=0;i< (int)strlen(aopt->name);i++) {
|
||||
if (aopt->name[i] == '-') {
|
||||
i++;
|
||||
uwsgi_log("%c", toupper( (int) aopt->name[i]));
|
||||
}
|
||||
else {
|
||||
uwsgi_log("%c", aopt->name[i]);
|
||||
}
|
||||
}
|
||||
uwsgi_log(" $ ");
|
||||
next2:
|
||||
lopt++;
|
||||
}
|
||||
|
||||
uwsgi_log("uWSGInull ))\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);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void uwsgi_opt_ldap_dump(char *opt, char *foo, void *bar) {
|
||||
|
||||
void uwsgi_ldap_schema_dump(struct option *lo) {
|
||||
|
||||
struct option *aopt, *lopt ;
|
||||
|
||||
lopt = lo;
|
||||
int i;
|
||||
int counter = 30000;
|
||||
int pythonpath_found = 0;
|
||||
int items;
|
||||
|
||||
while( (aopt = lopt) ) {
|
||||
if (!aopt->name)
|
||||
break;
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (aopt->val == LONG_ARGS_PYTHONPATH) {
|
||||
if (pythonpath_found) {
|
||||
goto next;
|
||||
}
|
||||
pythonpath_found = 1;
|
||||
}
|
||||
|
||||
if (aopt->flag) {
|
||||
uwsgi_log("attributetype ( 1.3.6.1.4.1.35156.17.4.%d NAME 'uWSGI", counter) ;
|
||||
counter++;
|
||||
}
|
||||
else {
|
||||
uwsgi_log("attributetype ( 1.3.6.1.4.1.35156.17.4.%d NAME 'uWSGI", aopt->val) ;
|
||||
}
|
||||
for(i=0;i< (int)strlen(aopt->name);i++) {
|
||||
if (aopt->name[i] == '-') {
|
||||
i++;
|
||||
uwsgi_log("%c", toupper( (int) aopt->name[i]));
|
||||
}
|
||||
else {
|
||||
uwsgi_log("%c", aopt->name[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (aopt->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");
|
||||
}
|
||||
next:
|
||||
lopt++;
|
||||
}
|
||||
|
||||
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") ;
|
||||
|
||||
lopt = lo;
|
||||
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 ( ");
|
||||
|
||||
pythonpath_found = 0;
|
||||
while( (aopt = lopt) ) {
|
||||
if (!aopt->name)
|
||||
break;
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
if (aopt->val == LONG_ARGS_PYTHONPATH) {
|
||||
if (pythonpath_found) {
|
||||
goto next2;
|
||||
}
|
||||
pythonpath_found = 1;
|
||||
}
|
||||
|
||||
uwsgi_log("uWSGI");
|
||||
|
||||
for(i=0;i< (int)strlen(aopt->name);i++) {
|
||||
if (aopt->name[i] == '-') {
|
||||
i++;
|
||||
uwsgi_log("%c", toupper( (int) aopt->name[i]));
|
||||
}
|
||||
else {
|
||||
uwsgi_log("%c", aopt->name[i]);
|
||||
}
|
||||
}
|
||||
uwsgi_log(" $ ");
|
||||
next2:
|
||||
lopt++;
|
||||
}
|
||||
|
||||
uwsgi_log("uWSGInull ))\n");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void uwsgi_ldap_config(struct uwsgi_server *uwsgi, struct option *long_options) {
|
||||
void uwsgi_ldap_config(char *url) {
|
||||
|
||||
LDAP *ldp;
|
||||
LDAPMessage *results, *entry;
|
||||
@@ -228,20 +248,13 @@ void uwsgi_ldap_config(struct uwsgi_server *uwsgi, struct option *long_options)
|
||||
char *attr;
|
||||
char *uwsgi_attr;
|
||||
|
||||
char *url = "ldap:///";
|
||||
char *url_slash;
|
||||
|
||||
int desired_version = LDAP_VERSION3;
|
||||
int ret;
|
||||
|
||||
struct option *aopt, *lopt;
|
||||
|
||||
LDAPURLDesc *ldap_url;
|
||||
|
||||
if (uwsgi->ldap) {
|
||||
url = uwsgi->ldap;
|
||||
}
|
||||
|
||||
if (!ldap_is_ldap_url(url)) {
|
||||
uwsgi_log("invalid LDAP url.\n");
|
||||
exit(1);
|
||||
@@ -251,6 +264,8 @@ void uwsgi_ldap_config(struct uwsgi_server *uwsgi, struct option *long_options)
|
||||
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, '/');
|
||||
@@ -265,21 +280,28 @@ void uwsgi_ldap_config(struct uwsgi_server *uwsgi, struct option *long_options)
|
||||
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_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);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
@@ -287,7 +309,7 @@ void uwsgi_ldap_config(struct uwsgi_server *uwsgi, struct option *long_options)
|
||||
#endif
|
||||
|
||||
free(ldap_url);
|
||||
|
||||
|
||||
if (ldap_count_entries(ldp, results) < 1) {
|
||||
uwsgi_log("no LDAP entry found\n");
|
||||
exit(1);
|
||||
@@ -295,9 +317,11 @@ void uwsgi_ldap_config(struct uwsgi_server *uwsgi, struct option *long_options)
|
||||
|
||||
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()");
|
||||
@@ -311,7 +335,7 @@ void uwsgi_ldap_config(struct uwsgi_server *uwsgi, struct option *long_options)
|
||||
#endif
|
||||
bervalues = ldap_get_values_len(ldp, entry, attr);
|
||||
if (bervalues) {
|
||||
// do not free uwsgi_val;
|
||||
// do not free uwsgi_attr/uwsgi_val;
|
||||
char *uwsgi_val = malloc( bervalues[0]->bv_len + 1 );
|
||||
if (!uwsgi_val) {
|
||||
uwsgi_error("malloc()");
|
||||
@@ -321,32 +345,25 @@ void uwsgi_ldap_config(struct uwsgi_server *uwsgi, struct option *long_options)
|
||||
memcpy(uwsgi_val, bervalues[0]->bv_val, bervalues[0]->bv_len);
|
||||
uwsgi_val[bervalues[0]->bv_len] = 0;
|
||||
|
||||
lopt = long_options;
|
||||
while ((aopt = lopt)) {
|
||||
if (!aopt->name)
|
||||
break;
|
||||
if (!strcmp(uwsgi_attr, aopt->name)) {
|
||||
if (aopt->flag) {
|
||||
*aopt->flag = aopt->val;
|
||||
}
|
||||
else {
|
||||
manage_opt(aopt->val, uwsgi_val);
|
||||
}
|
||||
}
|
||||
lopt++;
|
||||
}
|
||||
add_exported_option((char*) uwsgi_attr, uwsgi_val, 0);
|
||||
free(bervalues);
|
||||
}
|
||||
else {
|
||||
free(uwsgi_attr);
|
||||
}
|
||||
|
||||
free(bervalues);
|
||||
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
|
||||
|
||||
+773
@@ -0,0 +1,773 @@
|
||||
#include "../uwsgi.h"
|
||||
|
||||
#define AMQP_CONNECTION_HEADER "AMQP\0\0\x09\x01"
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
#define ntohll(x) x
|
||||
#else
|
||||
#define ntohll(x) ( ( (uint64_t)(ntohl( (uint32_t)((x << 32) >> 32) )) << 32) | ntohl( ((uint32_t)(x >> 32)) ) )
|
||||
#endif
|
||||
#define htonll(x) ntohll(x)
|
||||
|
||||
#define amqp_send(a, b, c) if (send(a, b, c, 0) < 0) { uwsgi_error("send()"); return -1; }
|
||||
|
||||
struct amqp_frame_header {
|
||||
|
||||
char type;
|
||||
uint16_t channel;
|
||||
uint32_t size;
|
||||
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct amqp_frame_method {
|
||||
uint16_t class_id;
|
||||
uint16_t method_id;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
static char *amqp_simple_get_frame(int, struct amqp_frame_header *);
|
||||
static char *amqp_get_method(int, uint16_t, uint16_t, uint32_t *);
|
||||
|
||||
static char *amqp_get_str(char *ptr, char *watermark) {
|
||||
|
||||
uint8_t str_size;
|
||||
|
||||
// over engeneering...
|
||||
if (ptr+1 > watermark) return NULL;
|
||||
|
||||
str_size = *ptr;
|
||||
|
||||
if (ptr+1+str_size > watermark) return NULL;
|
||||
|
||||
return ptr+1+str_size;
|
||||
}
|
||||
|
||||
|
||||
static char *amqp_get_short(char *ptr, char *watermark, uint16_t *sv) {
|
||||
|
||||
uint16_t tmp_short;
|
||||
|
||||
if (ptr+2 > watermark) return NULL;
|
||||
|
||||
memcpy(&tmp_short, ptr, 2);
|
||||
|
||||
*sv = ntohs(tmp_short);
|
||||
|
||||
return ptr+2;
|
||||
}
|
||||
|
||||
static char *amqp_get_long(char *ptr, char *watermark, uint32_t *lv) {
|
||||
|
||||
uint32_t tmp_long;
|
||||
|
||||
if (ptr+4 > watermark) return NULL;
|
||||
|
||||
memcpy(&tmp_long, ptr, 4);
|
||||
|
||||
*lv = ntohl(tmp_long);
|
||||
return ptr+4;
|
||||
}
|
||||
|
||||
static char *amqp_get_longlong(char *ptr, char *watermark, uint64_t *llv) {
|
||||
|
||||
uint64_t tmp_longlong;
|
||||
|
||||
if (ptr+8 > watermark) return NULL;
|
||||
|
||||
memcpy(&tmp_longlong, ptr, 8);
|
||||
|
||||
*llv = ntohll(tmp_longlong);
|
||||
return ptr+8;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int amqp_send_ack(int fd, uint64_t delivery_tag) {
|
||||
|
||||
uint32_t size = 4 + 8 + 1;
|
||||
|
||||
size = htonl(size);
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\1", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 60 method 80
|
||||
amqp_send(fd, "\x00\x3C\x00\x50", 4);
|
||||
|
||||
// set delivery_tag
|
||||
delivery_tag = htonll(delivery_tag);
|
||||
amqp_send(fd, &delivery_tag, 8);
|
||||
|
||||
// empty bits
|
||||
amqp_send(fd, "\0", 1);
|
||||
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *uwsgi_amqp_consume(int fd, uint64_t *msgsize, char **routing_key) {
|
||||
|
||||
uint32_t size;
|
||||
struct amqp_frame_header fh;
|
||||
uint64_t delivery_tag;
|
||||
uint64_t current_size = 0;
|
||||
char *ptr;
|
||||
char *watermark;
|
||||
uint16_t sv;
|
||||
|
||||
char *frame = amqp_get_method(fd, 60, 60, &size);
|
||||
if (!frame) return NULL;
|
||||
|
||||
ptr = frame+4;
|
||||
watermark = frame+size;
|
||||
|
||||
// consumer_tag
|
||||
ptr = amqp_get_str(ptr, watermark); if (!ptr) goto clear;
|
||||
// delivery_tag (needed for ack)
|
||||
ptr = amqp_get_longlong(ptr, watermark, &delivery_tag); if (!ptr) goto clear;
|
||||
// redelivered
|
||||
if (ptr+1 > watermark) goto clear;
|
||||
ptr++;
|
||||
// exchange
|
||||
ptr = amqp_get_str(ptr, watermark); if (!ptr) goto clear;
|
||||
// routing_key
|
||||
if (ptr+1 > watermark) goto clear;
|
||||
uint8_t rk_size = (uint8_t) *ptr;
|
||||
ptr++;
|
||||
if (ptr+rk_size > watermark) goto clear;
|
||||
|
||||
if (rk_size > 0) {
|
||||
char *rkey = uwsgi_concat2n(ptr, rk_size, "", 0);
|
||||
ptr+=rk_size;
|
||||
|
||||
*routing_key = rkey;
|
||||
}
|
||||
else {
|
||||
*routing_key = NULL;
|
||||
}
|
||||
|
||||
char *header = amqp_simple_get_frame(fd, &fh);
|
||||
if (!header) goto clear;
|
||||
|
||||
if (fh.type != 2) goto clear2;
|
||||
|
||||
ptr = header;
|
||||
watermark = ptr+fh.size;
|
||||
|
||||
// header class_id
|
||||
ptr = amqp_get_short(ptr, watermark, &sv); if (!ptr) goto clear2;
|
||||
// header weight
|
||||
ptr = amqp_get_short(ptr, watermark, &sv); if (!ptr) goto clear2;
|
||||
// message size;
|
||||
ptr = amqp_get_longlong(ptr, watermark, msgsize); if (!ptr) goto clear2;
|
||||
|
||||
free(frame);
|
||||
free(header);
|
||||
|
||||
char *fullbody = uwsgi_malloc(*msgsize);
|
||||
char *message;
|
||||
|
||||
while(current_size < *msgsize) {
|
||||
message = amqp_simple_get_frame(fd, &fh);
|
||||
if (!message) goto clear;
|
||||
|
||||
if (fh.type != 3) {
|
||||
free(message);
|
||||
goto clear3;
|
||||
}
|
||||
|
||||
if (fh.size+current_size > *msgsize) {
|
||||
free(message);
|
||||
goto clear3;
|
||||
}
|
||||
|
||||
memcpy(fullbody+current_size, message, fh.size);
|
||||
current_size+=fh.size;
|
||||
free(message);
|
||||
}
|
||||
|
||||
if (amqp_send_ack(fd, delivery_tag) < 0) {
|
||||
goto clear3;
|
||||
}
|
||||
|
||||
return fullbody;
|
||||
|
||||
clear3:
|
||||
free(fullbody);
|
||||
return NULL;
|
||||
|
||||
clear2:
|
||||
free(header);
|
||||
clear:
|
||||
free(frame);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
static int amqp_send_exchange_declare( int fd, char *exchange, char *exchange_type) {
|
||||
|
||||
uint32_t size = 4 + 2 + (1 +strlen(exchange)) + (1 +strlen(exchange_type)) + 1 + 4;
|
||||
uint8_t shortsize = strlen(exchange) ;
|
||||
|
||||
size = htonl(size);
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\1", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 40 method 10
|
||||
amqp_send(fd, "\x00\x28\x00\x0A", 4);
|
||||
|
||||
// send empty reserved
|
||||
amqp_send(fd, "\0\0", 2);
|
||||
|
||||
// set exchange name
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, exchange, shortsize);
|
||||
|
||||
// set exchange type
|
||||
shortsize = strlen(exchange_type);
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, exchange_type, shortsize);
|
||||
|
||||
// empty bits
|
||||
amqp_send(fd, "\0", 1);
|
||||
// empty table
|
||||
amqp_send(fd, "\0\0\0\0", 4);
|
||||
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int amqp_send_queue_bind( int fd, char *queue, char *exchange) {
|
||||
|
||||
uint32_t size = 4 + 2 + (1 +strlen(queue)) + (1 +strlen(exchange)) + 1 + 1 + 4;
|
||||
uint8_t shortsize = strlen(queue) ;
|
||||
|
||||
size = htonl(size);
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\1", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 50 method 20
|
||||
amqp_send(fd, "\x00\x32\x00\x14", 4);
|
||||
|
||||
// send empty reserved
|
||||
amqp_send(fd, "\0\0", 2);
|
||||
|
||||
// set queue name
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, queue, shortsize);
|
||||
|
||||
// set exchange name
|
||||
shortsize = strlen(exchange);
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, exchange, shortsize);
|
||||
|
||||
// set empty routing-key
|
||||
amqp_send(fd, "\0", 1);
|
||||
|
||||
// empty bits
|
||||
amqp_send(fd, "\0", 1);
|
||||
// empty table
|
||||
amqp_send(fd, "\0\0\0\0", 4);
|
||||
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int amqp_send_queue_consume( int fd, char *queue) {
|
||||
|
||||
uint32_t size = 4 + 2 + (1 +strlen(queue)) + 1 + 1 + 4;
|
||||
uint8_t shortsize = strlen(queue) ;
|
||||
|
||||
size = htonl(size);
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\1", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 60 method 20
|
||||
amqp_send(fd, "\x00\x3C\x00\x14", 4);
|
||||
|
||||
// send empty reserved
|
||||
amqp_send(fd, "\0\0", 2);
|
||||
|
||||
// set queue name
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, queue, shortsize);
|
||||
|
||||
// set tag name
|
||||
amqp_send(fd, "\0", 1);
|
||||
|
||||
// empty bits
|
||||
amqp_send(fd, "\0", 1);
|
||||
// empty table
|
||||
amqp_send(fd, "\0\0\0\0", 4);
|
||||
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amqp_wait_connection_start(int fd) {
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 10, 10, &size);
|
||||
|
||||
if (frame) {
|
||||
free(frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int amqp_wait_exchange_declare_ok(int fd) {
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 40, 11, &size);
|
||||
|
||||
if (frame) {
|
||||
free(frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int amqp_wait_basic_consume_ok(int fd) {
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 60, 21, &size);
|
||||
|
||||
if (frame) {
|
||||
free(frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int amqp_wait_channel_open_ok(int fd) {
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 20, 11, &size);
|
||||
|
||||
if (frame) {
|
||||
free(frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int amqp_wait_queue_bind_ok(int fd) {
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 50, 21, &size);
|
||||
|
||||
if (frame) {
|
||||
free(frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static char *amqp_wait_queue_declare_ok(int fd) {
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 50, 11, &size);
|
||||
char *queue = NULL;
|
||||
char *ptr;
|
||||
char *watermark;
|
||||
|
||||
if (frame) {
|
||||
|
||||
ptr = frame+4;
|
||||
watermark = frame+size;
|
||||
|
||||
ptr = amqp_get_str(ptr, watermark); if (!ptr) { free(frame); return NULL; }
|
||||
|
||||
queue = uwsgi_concat2n(frame+5, *(frame+4), "", 0);
|
||||
|
||||
free(frame);
|
||||
return queue;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int amqp_wait_connection_open_ok(int fd) {
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 10, 41, &size);
|
||||
|
||||
if (frame) {
|
||||
free(frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int amqp_wait_connection_tune(int fd) {
|
||||
|
||||
uint32_t size;
|
||||
char *frame = amqp_get_method(fd, 10, 30, &size);
|
||||
|
||||
uint16_t sv;
|
||||
uint32_t lv;
|
||||
char *watermark ;
|
||||
char *ptr;
|
||||
|
||||
|
||||
if (frame) {
|
||||
ptr = frame+4;
|
||||
watermark = frame+size;
|
||||
ptr = amqp_get_short(ptr, watermark, &sv); if (!ptr) { free(frame); return -1; }
|
||||
uwsgi_log("AMQP max channels: %d\n", sv);
|
||||
ptr = amqp_get_long(ptr, watermark, &lv); if (!ptr) { free(frame); return -1; }
|
||||
uwsgi_log("AMQP max frame size: %d\n", lv);
|
||||
ptr = amqp_get_short(ptr, watermark, &sv); if (!ptr) { free(frame); return -1; }
|
||||
uwsgi_log("AMQP heartbeath: %d\n", sv);
|
||||
|
||||
free(frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char *amqp_simple_get_frame(int fd, struct amqp_frame_header *fh) {
|
||||
|
||||
char *ptr = (char *) fh;
|
||||
size_t len = 0, rlen;
|
||||
|
||||
while(len < 7) {
|
||||
rlen = recv(fd, ptr, 7-len, 0);
|
||||
if (rlen <= 0) {
|
||||
uwsgi_error("recv()");
|
||||
return NULL;
|
||||
}
|
||||
len += rlen;
|
||||
ptr += rlen;
|
||||
}
|
||||
|
||||
fh->channel = ntohs(fh->channel);
|
||||
fh->size = ntohl(fh->size);
|
||||
|
||||
len = 0;
|
||||
|
||||
char *frame = uwsgi_malloc(fh->size+1);
|
||||
ptr = frame;
|
||||
|
||||
while(len < fh->size+1) {
|
||||
rlen = recv(fd, ptr, (fh->size+1)-len, 0);
|
||||
if (rlen <= 0) {
|
||||
uwsgi_error("recv()");
|
||||
return NULL;
|
||||
}
|
||||
len += rlen;
|
||||
ptr += rlen;
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
static char *amqp_get_method(int fd, uint16_t class_id, uint16_t method_id, uint32_t *size) {
|
||||
|
||||
struct amqp_frame_header fh;
|
||||
struct amqp_frame_method *fm;
|
||||
|
||||
char *frame = amqp_simple_get_frame(fd, &fh);
|
||||
if (!frame) return NULL;
|
||||
|
||||
if (fh.type != 1) goto clear;
|
||||
|
||||
fm = (struct amqp_frame_method *) frame;
|
||||
fm->class_id = ntohs(fm->class_id);
|
||||
fm->method_id = ntohs(fm->method_id);
|
||||
|
||||
if (fm->class_id != class_id) goto clear;
|
||||
if (fm->method_id != method_id) goto clear;
|
||||
|
||||
*size = fh.size;
|
||||
return frame;
|
||||
|
||||
clear:
|
||||
|
||||
free(frame);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int amqp_send_channel_open(int fd, uint16_t id) {
|
||||
|
||||
uint32_t size = 4 + 1;
|
||||
size = htonl(size);
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\1", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 20 method 10
|
||||
amqp_send(fd, "\x00\x14\x00\x0A", 4);
|
||||
|
||||
amqp_send(fd, "\0", 1);
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amqp_send_connection_open(int fd, char *vhost) {
|
||||
|
||||
uint8_t shortsize = strlen(vhost);
|
||||
uint32_t size = 4 + 1 +strlen(vhost) + 2;
|
||||
size = htonl(size);
|
||||
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\0", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 10 method 28
|
||||
amqp_send(fd, "\x00\x0A\x00\x28", 4);
|
||||
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, vhost, strlen(vhost));
|
||||
|
||||
shortsize = 0;
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int amqp_send_connection_tune_ok(int fd, uint16_t max_chan, uint32_t max_frame_size, uint16_t heartbeat) {
|
||||
|
||||
uint32_t size = 4 + 2 + 4 + 2;
|
||||
size = htonl(size);
|
||||
|
||||
max_chan = htons(max_chan);
|
||||
max_frame_size = htonl(max_frame_size);
|
||||
heartbeat = htons(heartbeat);
|
||||
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\0", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 10 method 15
|
||||
amqp_send(fd, "\x00\x0A\x00\x1F", 4);
|
||||
|
||||
amqp_send(fd, &max_chan, 2);
|
||||
amqp_send(fd, &max_frame_size, 4);
|
||||
amqp_send(fd, &heartbeat, 2);
|
||||
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int amqp_send_queue_declare(int fd, char *queue) {
|
||||
|
||||
uint32_t size = 4 + 2 + (1 +strlen(queue)) + 1 + 4;
|
||||
uint8_t shortsize = strlen(queue) ;
|
||||
|
||||
size = htonl(size);
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\1", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 50 method 10
|
||||
amqp_send(fd, "\x00\x32\x00\x0A", 4);
|
||||
|
||||
// send empty reserved
|
||||
amqp_send(fd, "\0\0", 2);
|
||||
|
||||
// set queue name
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, queue, shortsize);
|
||||
|
||||
// empty bits
|
||||
amqp_send(fd, "\0", 1);
|
||||
// empty table
|
||||
amqp_send(fd, "\0\0\0\0", 4);
|
||||
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *amqp_get_queue(int fd, char *queue) {
|
||||
|
||||
if (amqp_send_queue_declare(fd, queue) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return amqp_wait_queue_declare_ok(fd);
|
||||
}
|
||||
|
||||
|
||||
static int amqp_send_connection_start_ok(int fd, char *mech, char *sasl_response, int sasl_response_size, char *locale) {
|
||||
|
||||
uint32_t size = 4 + 4 + (1 +strlen(mech)) + (4 + sasl_response_size) + (1 + strlen(locale));
|
||||
uint8_t shortsize ;
|
||||
|
||||
size = htonl(size);
|
||||
// send type and channel
|
||||
amqp_send(fd, "\1\0\0", 3);
|
||||
// send size
|
||||
amqp_send(fd, &size, 4);
|
||||
|
||||
// send class 10 method 11
|
||||
amqp_send(fd, "\x00\x0A\x00\x0B", 4);
|
||||
|
||||
// send empty client properties
|
||||
amqp_send(fd, "\0\0\0\0", 4);
|
||||
|
||||
// send mechanism short string
|
||||
shortsize = strlen(mech);
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, mech, strlen(mech));
|
||||
|
||||
// send sasl response
|
||||
size = htonl(sasl_response_size);
|
||||
amqp_send(fd, &size, 4);
|
||||
amqp_send(fd, sasl_response, sasl_response_size);
|
||||
|
||||
// send locale
|
||||
shortsize = strlen(locale);
|
||||
amqp_send(fd, &shortsize, 1);
|
||||
amqp_send(fd, locale, strlen(locale));
|
||||
|
||||
// send frame-end
|
||||
amqp_send(fd, "\xCE", 1);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_amqp_consume_queue(int fd, char *vhost, char *username, char *password, char *queue, char *exchange, char *exchange_type) {
|
||||
|
||||
char *auth = uwsgi_concat4n("\0",1, username, strlen(username), "\0",1, password, strlen(password));
|
||||
|
||||
if (send(fd, AMQP_CONNECTION_HEADER, 8, 0) < 0) {
|
||||
uwsgi_error("send()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (amqp_wait_connection_start(fd) < 0) {
|
||||
uwsgi_log("AMQP error waiting for Connection.start\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_log("sending Connection.start-ok\n");
|
||||
if (amqp_send_connection_start_ok(fd, "PLAIN", auth, strlen(username)+strlen(password)+2, "en_US") < 0) {
|
||||
free(auth);
|
||||
uwsgi_log("AMQP error sending Connection.start-ok\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(auth);
|
||||
|
||||
if (amqp_wait_connection_tune(fd) < 0) {
|
||||
uwsgi_log("AMQP error waiting for Connection.tune\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_log("sending Connection.tune-ok\n");
|
||||
if (amqp_send_connection_tune_ok(fd, 0, 0xffff, 0) < 0) {
|
||||
uwsgi_log("AMQP error sending Connection.tune-ok\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_log("sending Connection.open\n");
|
||||
if (amqp_send_connection_open(fd, vhost) < 0) {
|
||||
uwsgi_log("AMQP error sending Connection.open\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (amqp_wait_connection_open_ok(fd) < 0) {
|
||||
uwsgi_log("AMQP error waiting for Connection.open-ok\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_log("sending Channel.open\n");
|
||||
if (amqp_send_channel_open(fd, 1) < 0) {
|
||||
uwsgi_log("AMQP error sending Channel.open\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (amqp_wait_channel_open_ok(fd) < 0) {
|
||||
uwsgi_log("AMQP error waiting for Channel.open-ok\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
queue = amqp_get_queue(fd, queue);
|
||||
if (!queue) {
|
||||
uwsgi_log("AMQP error sending Queue.declare\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (exchange) {
|
||||
if (amqp_send_exchange_declare(fd, exchange, exchange_type) < 0) {
|
||||
uwsgi_log("AMQP error sending Exchange.declare\n");
|
||||
free(queue);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (amqp_wait_exchange_declare_ok(fd) < 0) {
|
||||
uwsgi_log("AMQP error waiting for Exchange.declare-ok\n");
|
||||
free(queue);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (amqp_send_queue_bind(fd, queue, exchange) < 0) {
|
||||
uwsgi_log("AMQP error sending Queue.bind\n");
|
||||
free(queue);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (amqp_wait_queue_bind_ok(fd) < 0) {
|
||||
uwsgi_log("AMQP error waiting for Queue.bind-ok\n");
|
||||
free(queue);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (amqp_send_queue_consume(fd, queue) < 0) {
|
||||
uwsgi_log("AMQP error sending Basic.consume\n");
|
||||
free(queue);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (amqp_wait_basic_consume_ok(fd) < 0) {
|
||||
uwsgi_log("AMQP error waiting for Basic.consume-ok\n");
|
||||
free(queue);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(queue);
|
||||
|
||||
uwsgi_log("AMQP subscription done, waiting for events...\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
|
||||
common functions for various routers (fastrouter, http...)
|
||||
|
||||
*/
|
||||
static void uwsgi_corerouter_setup_sockets(char *gw_id) {
|
||||
|
||||
struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets;
|
||||
while (ugs) {
|
||||
if (!strcmp(gw_id, ugs->owner)) {
|
||||
#ifdef UWSGI_SCTP
|
||||
if (!ugs->subscription && !ugs->sctp) {
|
||||
#else
|
||||
if (!ugs->subscription) {
|
||||
#endif
|
||||
if (ugs->name[0] == '=') {
|
||||
int shared_socket = atoi(ugs->name+1);
|
||||
if (shared_socket >= 0) {
|
||||
ugs->fd = uwsgi_get_shared_socket_fd_by_num(shared_socket);
|
||||
if (ugs->fd == -1) {
|
||||
uwsgi_log("unable to use shared socket %d\n", shared_socket);
|
||||
exit(1);
|
||||
}
|
||||
ugs->name = uwsgi_getsockname(ugs->fd);
|
||||
}
|
||||
}
|
||||
else if (!uwsgi_startswith("fd://", ugs->name, 5 )) {
|
||||
int fd_socket = atoi(ugs->name+5);
|
||||
if (fd_socket >= 0) {
|
||||
ugs->fd = fd_socket;
|
||||
ugs->name = uwsgi_getsockname(ugs->fd);
|
||||
if (!ugs->name) {
|
||||
uwsgi_log("unable to use file descriptor %d as socket\n", fd_socket);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ugs->port = strchr(ugs->name, ':');
|
||||
if (ugs->fd == -1) {
|
||||
if (ugs->port) {
|
||||
ugs->fd = bind_to_tcp(ugs->name, uwsgi.listen_queue, ugs->port);
|
||||
ugs->port++;
|
||||
ugs->port_len = strlen(ugs->port);
|
||||
}
|
||||
else {
|
||||
ugs->fd = bind_to_unix(ugs->name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
// put socket in non-blocking mode
|
||||
uwsgi_socket_nb(ugs->fd);
|
||||
uwsgi_log("%s bound on %s fd %d\n", gw_id, ugs->name, ugs->fd);
|
||||
}
|
||||
else if (ugs->subscription) {
|
||||
if (ugs->fd == -1) {
|
||||
ugs->fd = bind_to_udp(ugs->name, 0, 0);
|
||||
uwsgi_socket_nb(ugs->fd);
|
||||
}
|
||||
uwsgi_log("%s subscription server bound on %s fd %d\n", gw_id, ugs->name, ugs->fd);
|
||||
}
|
||||
#ifdef UWSGI_SCTP
|
||||
else if (ugs->sctp) {
|
||||
if (ugs->fd == -1) {
|
||||
ugs->fd = bind_to_sctp(ugs->name);
|
||||
}
|
||||
uwsgi_log("%s SCTP server bound on %s fd %d\n", gw_id, ugs->name, ugs->fd);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
ugs = ugs->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void *uwsgi_corerouter_setup_event_queue(char *gw_id, int id, int nevents, int *efd, int cheap) {
|
||||
|
||||
*efd = event_queue_init();
|
||||
|
||||
struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets;
|
||||
while (ugs) {
|
||||
if (!strcmp(gw_id, ugs->owner)) {
|
||||
if (!cheap || ugs->subscription) {
|
||||
event_queue_add_fd_read(*efd, ugs->fd);
|
||||
}
|
||||
ugs->gateway = &ushared->gateways[id];
|
||||
}
|
||||
ugs = ugs->next;
|
||||
}
|
||||
|
||||
return event_queue_alloc(nevents);
|
||||
}
|
||||
|
||||
static void __attribute__ ((unused)) uwsgi_corerouter_manage_subscription(char *gw_id, int id, struct uwsgi_gateway_socket *ugs, int queue, struct uwsgi_subscribe_slot **subscriptions, int regexp, void (*parse_hook) (char *, uint16_t, char *, uint16_t, void *), int cheap, int *i_am_cheap) {
|
||||
|
||||
int i;
|
||||
struct uwsgi_subscribe_req usr;
|
||||
char bbuf[4096];
|
||||
|
||||
ssize_t len = recv(ugs->fd, bbuf, 4096, 0);
|
||||
#ifdef UWSGI_EVENT_USE_PORT
|
||||
event_queue_add_fd_read(queue, ugs->fd);
|
||||
#endif
|
||||
if (len > 0) {
|
||||
memset(&usr, 0, sizeof(struct uwsgi_subscribe_req));
|
||||
uwsgi_hooked_parse(bbuf + 4, len - 4, parse_hook, &usr);
|
||||
|
||||
// subscribe request ?
|
||||
if (bbuf[3] == 0) {
|
||||
if (uwsgi_add_subscribe_node(subscriptions, &usr, regexp) && *i_am_cheap) {
|
||||
struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets;
|
||||
while (ugs) {
|
||||
if (!strcmp(ugs->owner, gw_id) && !ugs->subscription) {
|
||||
event_queue_add_fd_read(queue, ugs->fd);
|
||||
}
|
||||
ugs = ugs->next;
|
||||
}
|
||||
*i_am_cheap = 0;
|
||||
uwsgi_log("[%s pid %d] leaving cheap mode...\n", gw_id, (int) uwsgi.mypid);
|
||||
}
|
||||
}
|
||||
//unsubscribe
|
||||
else {
|
||||
struct uwsgi_subscribe_node *node = uwsgi_get_subscribe_node_by_name(subscriptions, usr.key, usr.keylen, usr.address, usr.address_len, regexp);
|
||||
if (node && node->len) {
|
||||
if (node->death_mark == 0)
|
||||
uwsgi_log("[%s pid %d] %.*s => marking %.*s as failed\n", gw_id, (int) uwsgi.mypid, (int) usr.keylen, usr.key, (int) usr.address_len, usr.address);
|
||||
node->failcnt++;
|
||||
node->death_mark = 1;
|
||||
// check if i can remove the node
|
||||
if (node->reference == 0) {
|
||||
uwsgi_remove_subscribe_node(subscriptions, node);
|
||||
}
|
||||
if (*subscriptions == NULL && cheap && !*i_am_cheap) {
|
||||
uwsgi_gateway_go_cheap(gw_id, queue, i_am_cheap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// propagate the subscription to other nodes
|
||||
for (i = 0; i < ushared->gateways_cnt; i++) {
|
||||
if (i == id)
|
||||
continue;
|
||||
if (!strcmp(ushared->gateways[i].name, gw_id)) {
|
||||
if (send(ushared->gateways[i].internal_subscription_pipe[0], bbuf, len, 0) != len) {
|
||||
uwsgi_error("send()");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void __attribute__ ((unused)) uwsgi_corerouter_manage_internal_subscription(char *gw_id, int queue, int fd, struct uwsgi_subscribe_slot **subscriptions, int regexp, void (*parse_hook) (char *, uint16_t, char *, uint16_t, void *), int cheap, int *i_am_cheap) {
|
||||
|
||||
|
||||
struct uwsgi_subscribe_req usr;
|
||||
char bbuf[4096];
|
||||
|
||||
ssize_t len = recv(fd, bbuf, 4096, 0);
|
||||
#ifdef UWSGI_EVENT_USE_PORT
|
||||
event_queue_add_fd_read(queue, fd);
|
||||
#endif
|
||||
if (len > 0) {
|
||||
memset(&usr, 0, sizeof(struct uwsgi_subscribe_req));
|
||||
uwsgi_hooked_parse(bbuf + 4, len - 4, parse_hook, &usr);
|
||||
|
||||
// subscribe request ?
|
||||
if (bbuf[3] == 0) {
|
||||
if (uwsgi_add_subscribe_node(subscriptions, &usr, regexp) && *i_am_cheap) {
|
||||
struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets;
|
||||
while (ugs) {
|
||||
if (!strcmp(ugs->owner, gw_id) && !ugs->subscription) {
|
||||
event_queue_add_fd_read(queue, ugs->fd);
|
||||
}
|
||||
ugs = ugs->next;
|
||||
}
|
||||
*i_am_cheap = 0;
|
||||
uwsgi_log("[%s pid %d] leaving cheap mode...\n", gw_id, (int) uwsgi.mypid);
|
||||
}
|
||||
}
|
||||
//unsubscribe
|
||||
else {
|
||||
struct uwsgi_subscribe_node *node = uwsgi_get_subscribe_node_by_name(subscriptions, usr.key, usr.keylen, usr.address, usr.address_len, regexp);
|
||||
if (node && node->len) {
|
||||
if (node->death_mark == 0)
|
||||
uwsgi_log("[%s pid %d] %.*s => marking %.*s as failed\n", gw_id, (int) uwsgi.mypid, (int) usr.keylen, usr.key, (int) usr.address_len, usr.address);
|
||||
node->failcnt++;
|
||||
node->death_mark = 1;
|
||||
// check if i can remove the node
|
||||
if (node->reference == 0) {
|
||||
uwsgi_remove_subscribe_node(subscriptions, node);
|
||||
}
|
||||
if (*subscriptions == NULL && cheap && !*i_am_cheap) {
|
||||
uwsgi_gateway_go_cheap(gw_id, queue, i_am_cheap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user