mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-10-04 16:08:31 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7604c67018 | ||
|
|
afc962709f | ||
|
|
c11e0654a0 | ||
|
|
6e4f47cc76 | ||
|
|
20c9f0ef40 | ||
|
|
ef3c8a5bd9 | ||
|
|
76d0438fee | ||
|
|
18fd338908 | ||
|
|
2b35e95706 | ||
|
|
4761146599 | ||
|
|
3924cc639e | ||
|
|
5f09de0469 | ||
|
|
4f0e3fb79f | ||
|
|
05b6baf173 | ||
|
|
149823aac4 | ||
|
|
85d86dc10e | ||
|
|
e97d921909 | ||
|
|
c5e20bf4da | ||
|
|
a09d25ccaa | ||
|
|
bf01cea062 | ||
|
|
b6459be3e4 | ||
|
|
d42788c17b | ||
|
|
872730c116 | ||
|
|
6fce0aee84 | ||
|
|
e3d8a02614 | ||
|
|
b58696399e | ||
|
|
519c9f58b3 | ||
|
|
2c77c5c639 | ||
|
|
fb9e5a1891 | ||
|
|
5aa7d1a79f | ||
|
|
bc3442ba29 | ||
|
|
3061e36089 | ||
|
|
4f8c41cf61 | ||
|
|
b0065c379e | ||
|
|
57f71c974d | ||
|
|
b820fefbbd | ||
|
|
5f759f0d26 | ||
|
|
f7eb9ed1cd | ||
|
|
3a82732b19 | ||
|
|
d74e826f71 | ||
|
|
c846a9b388 | ||
|
|
001e4b6e39 | ||
|
|
a51a396f47 | ||
|
|
17965ea870 | ||
|
|
8a032b41ec | ||
|
|
a489cfc2c1 | ||
|
|
3b32672ff9 | ||
|
|
858131ba57 | ||
|
|
8a8d2f8675 | ||
|
|
9d37725323 | ||
|
|
e973492267 | ||
|
|
105a68bce9 | ||
|
|
0587a0ca53 | ||
|
|
d4b259d5e0 | ||
|
|
9e591c587f | ||
|
|
e7cce7b785 | ||
|
|
3285b224c2 | ||
|
|
e4a4942980 | ||
|
|
6f671936fc | ||
|
|
7d1d992d58 | ||
|
|
2bba4cf15a | ||
|
|
930f71c562 | ||
|
|
959bb11f77 | ||
|
|
13d8505738 | ||
|
|
93fe463ca8 | ||
|
|
5c64c21745 | ||
|
|
f825ab542d | ||
|
|
e744aef144 | ||
|
|
4ded485a8e | ||
|
|
2ce5ec3986 | ||
|
|
af95f90fb0 | ||
|
|
7989dc748b | ||
|
|
f85f3e8178 | ||
|
|
97809192c8 | ||
|
|
5f74e6d964 | ||
|
|
ae87fdd0f7 | ||
|
|
36c44c83af | ||
|
|
48e13bfc65 | ||
|
|
16cd55637d | ||
|
|
39cf2887c4 | ||
|
|
671bf8a258 | ||
|
|
89a8ceea81 | ||
|
|
6699f4046e | ||
|
|
88474b3d96 | ||
|
|
32b6463d06 | ||
|
|
63cc29a61d | ||
|
|
d58f79eeab | ||
|
|
7b24d2f5de | ||
|
|
a93db73d0c | ||
|
|
c118c75bfe | ||
|
|
624631d443 | ||
|
|
b681eab385 | ||
|
|
91dfe779ff | ||
|
|
0ad50711c0 | ||
|
|
df6ed26479 | ||
|
|
d08778b39c | ||
|
|
0c8c2932cf | ||
|
|
131bd7da2f | ||
|
|
d247424442 | ||
|
|
332fab2150 | ||
|
|
62d74951db | ||
|
|
839638a0ad | ||
|
|
536ae8d013 | ||
|
|
367c4b9bab | ||
|
|
3965c01880 | ||
|
|
7e4341a7cd | ||
|
|
8c118c8f62 | ||
|
|
5d76b63fac | ||
|
|
b0159ea23b | ||
|
|
d3493df032 | ||
|
|
757c76b569 | ||
|
|
30eebfd335 | ||
|
|
c5d7d30439 | ||
|
|
04bc3e117d | ||
|
|
3480c30674 | ||
|
|
a7e6dfc469 | ||
|
|
5e276b43ad | ||
|
|
9e6a21602a | ||
|
|
952c4ce854 | ||
|
|
951f24e711 | ||
|
|
7bda4c9b63 | ||
|
|
1b25516ced | ||
|
|
b3020e60f9 | ||
|
|
808d37f33a | ||
|
|
8c8a7f77d1 | ||
|
|
3f601af740 | ||
|
|
7b901ab81e | ||
|
|
930eb1e6aa | ||
|
|
77e5931da7 | ||
|
|
3e6ddbb3d5 | ||
|
|
623bce274a | ||
|
|
6c986f8082 | ||
|
|
10a02064ba | ||
|
|
774f5a81a5 | ||
|
|
e270593cc0 | ||
|
|
b559354845 | ||
|
|
46a2fefb04 | ||
|
|
c6c9baa7b5 | ||
|
|
c37710f4c2 | ||
|
|
943c20b88c | ||
|
|
a442614db0 | ||
|
|
5830af37ba | ||
|
|
de4c563169 | ||
|
|
77f008e24c | ||
|
|
df0bd832b4 | ||
|
|
07c42c262f | ||
|
|
cb131836ae | ||
|
|
2c6855a969 | ||
|
|
79ca1940de | ||
|
|
d46879dca9 | ||
|
|
9b889f7b77 | ||
|
|
1128d09187 | ||
|
|
d3d4d04fac | ||
|
|
4a554db63b | ||
|
|
8b799b4f9f | ||
|
|
ef17013945 | ||
|
|
a225d53825 | ||
|
|
d4298469ba | ||
|
|
395de489b8 | ||
|
|
6e6efc5605 | ||
|
|
ce260ecbb6 | ||
|
|
e143e25b3c | ||
|
|
e9a58bac46 | ||
|
|
1448fbc5a3 | ||
|
|
b801f839fc | ||
|
|
bcb8321480 | ||
|
|
5cd9e64073 | ||
|
|
d878b65401 | ||
|
|
ded149fc80 | ||
|
|
f041d1095d | ||
|
|
886842de12 | ||
|
|
b4915f778e | ||
|
|
a25e02bbb3 | ||
|
|
16aec7c44b | ||
|
|
42dfa20f27 | ||
|
|
2092050f00 | ||
|
|
b5a0434710 | ||
|
|
2737cd5c35 | ||
|
|
7a29d9649c | ||
|
|
27cc164ebe | ||
|
|
40be8fc916 | ||
|
|
f219afc6e0 | ||
|
|
f20f72ceb1 | ||
|
|
6555c2804c | ||
|
|
c05082a8e4 | ||
|
|
62dab40a22 | ||
|
|
02e68ae578 | ||
|
|
ba1fb72427 | ||
|
|
df9a76a171 | ||
|
|
98e7e0845d | ||
|
|
6c9f73ae7f | ||
|
|
b12658102d | ||
|
|
c51b74a32b | ||
|
|
b0e6d19d5c | ||
|
|
7ff3584ad7 | ||
|
|
57b6d1f51b | ||
|
|
1646f9c199 | ||
|
|
260b49c3f6 | ||
|
|
58af067bef | ||
|
|
d1285c6dc4 | ||
|
|
d4e9f3a2d4 | ||
|
|
a15de85811 | ||
|
|
4b09ead07d | ||
|
|
338aca9da5 | ||
|
|
3f0b9390d9 | ||
|
|
e14b189c77 | ||
|
|
cabb179a84 | ||
|
|
ad9b48b69e | ||
|
|
08443d5463 | ||
|
|
5d11a5cd77 | ||
|
|
3aba97745c | ||
|
|
0b596bdf42 | ||
|
|
4c4b08c36f | ||
|
|
1f0827abc8 | ||
|
|
2ea67c67df | ||
|
|
8eebc9f400 | ||
|
|
2ad6a1c8e8 | ||
|
|
d39d0e8403 | ||
|
|
2838fffbde | ||
|
|
45bc51541a | ||
|
|
3427a17191 | ||
|
|
0cf61abf9d | ||
|
|
53fde5fcdd | ||
|
|
e81f068e4b | ||
|
|
aaee226183 | ||
|
|
d7bba38d7a | ||
|
|
18fa1172db | ||
|
|
9e95312169 | ||
|
|
216aff3820 | ||
|
|
eae335a43e | ||
|
|
e0cf245a0e | ||
|
|
d463f9e7d9 | ||
|
|
06c62033dd | ||
|
|
72ea5ab54a | ||
|
|
843a3b18ad | ||
|
|
37acca060b | ||
|
|
a0ff5b91b8 | ||
|
|
ea19e1e67b | ||
|
|
c20e3fb1a8 | ||
|
|
a57c2997f4 | ||
|
|
3d051e5d79 | ||
|
|
3b0d18c1ec | ||
|
|
89e04c5d17 | ||
|
|
84ea262203 | ||
|
|
15fa2be4ee | ||
|
|
f18ceea9bf | ||
|
|
e4a993ac31 | ||
|
|
cf2c20418c | ||
|
|
d155197d98 | ||
|
|
fbc1551112 | ||
|
|
b3bba48d1a | ||
|
|
18972d95a8 | ||
|
|
8aa8d6070b | ||
|
|
3f0e9f899a | ||
|
|
00bf0aa713 | ||
|
|
60675724d3 | ||
|
|
b45deb780d | ||
|
|
24e144268b | ||
|
|
b870b8c6d8 | ||
|
|
62be7482d4 | ||
|
|
0c8f473e6f | ||
|
|
8b19fd3f94 | ||
|
|
7553ce3a48 | ||
|
|
9ff67391c0 | ||
|
|
4f4f9b93aa | ||
|
|
51a8f31f17 | ||
|
|
32b7126836 | ||
|
|
4d43a66581 | ||
|
|
0f95ef6d5a | ||
|
|
c0c43a7d47 | ||
|
|
4361ef2dc6 | ||
|
|
b7298aba85 |
@@ -7,6 +7,7 @@
|
||||
|
||||
/uwsgi
|
||||
/uwsgibuild.*
|
||||
/core/config_py.c
|
||||
|
||||
/t/ring/target
|
||||
|
||||
|
||||
@@ -25,3 +25,6 @@ Mingli Yuan
|
||||
Natanael Copa
|
||||
Roberto Leandrini
|
||||
Ryan Petrello
|
||||
Danila Shtan <danila@shtan.ru>
|
||||
Ævar Arnfjörð Bjarmason
|
||||
Yu Zhao (getcwd)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
*** mod_proxy_uwsgi ***
|
||||
|
||||
Copyright 2009-2013 Unbit S.a.s. <info@unbit.it>
|
||||
Copyright 2009-2014 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
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
*** uWSGI/mod_uwsgi ***
|
||||
|
||||
Copyright 2009-2013 Unbit S.a.s. <info@unbit.it>
|
||||
Copyright 2009-2014 Unbit S.a.s. <info@unbit.it>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = python,asyncio,greenlet
|
||||
inherit = base
|
||||
@@ -1,4 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = python,gevent
|
||||
inherit = base
|
||||
debug = false
|
||||
|
||||
+4
-4
@@ -18,18 +18,18 @@ void uwsgi_alarm_init_log(struct uwsgi_alarm_instance *uai) {
|
||||
void uwsgi_alarm_func_log(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
|
||||
if (msg[len-1] != '\n') {
|
||||
if (uai->arg && strlen(uai->arg) > 0) {
|
||||
uwsgi_log_alarm("] %s %.*s\n", uai->arg, len, msg);
|
||||
uwsgi_log_verbose("ALARM: %s %.*s\n", uai->arg, len, msg);
|
||||
}
|
||||
else {
|
||||
uwsgi_log_alarm("] %.*s\n", len, msg);
|
||||
uwsgi_log_verbose("ALARM: %.*s\n", len, msg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (uai->arg && strlen(uai->arg) > 0) {
|
||||
uwsgi_log_alarm("] %s %.*s", uai->arg, len, msg);
|
||||
uwsgi_log_verbose("ALARM: %s %.*s", uai->arg, len, msg);
|
||||
}
|
||||
else {
|
||||
uwsgi_log_alarm("] %.*s", len, msg);
|
||||
uwsgi_log_verbose("ALARM: %.*s", len, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -387,6 +387,23 @@ end:
|
||||
|
||||
}
|
||||
|
||||
static int uwsgi_async_wait_milliseconds_hook(int timeout) {
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
timeout = timeout / 1000;
|
||||
if (!timeout) timeout = 1;
|
||||
async_add_timeout(wsgi_req, timeout);
|
||||
wsgi_req->async_force_again = 1;
|
||||
if (uwsgi.schedule_to_main) {
|
||||
uwsgi.schedule_to_main(wsgi_req);
|
||||
}
|
||||
if (wsgi_req->async_timed_out) {
|
||||
wsgi_req->async_timed_out = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void async_loop() {
|
||||
|
||||
if (uwsgi.async < 2) {
|
||||
@@ -414,6 +431,7 @@ void async_loop() {
|
||||
uwsgi.wait_write_hook = async_wait_fd_write;
|
||||
uwsgi.wait_read_hook = async_wait_fd_read;
|
||||
uwsgi.wait_read2_hook = async_wait_fd_read2;
|
||||
uwsgi.wait_milliseconds_hook = uwsgi_async_wait_milliseconds_hook;
|
||||
|
||||
if (uwsgi.signal_socket > -1) {
|
||||
event_queue_add_fd_read(uwsgi.async_queue, uwsgi.signal_socket);
|
||||
|
||||
+242
-117
@@ -32,7 +32,7 @@ static uint64_t uwsgi_cache_find_free_blocks(struct uwsgi_cache *uc, uint64_t ne
|
||||
// which is the first free bit?
|
||||
uint64_t bitmap_byte = 0;
|
||||
uint8_t bitmap_bit = 0;
|
||||
|
||||
|
||||
if (uc->blocks_bitmap_pos > 0) {
|
||||
bitmap_byte = uc->blocks_bitmap_pos/8;
|
||||
bitmap_bit = uc->blocks_bitmap_pos % 8;
|
||||
@@ -45,6 +45,8 @@ static uint64_t uwsgi_cache_find_free_blocks(struct uwsgi_cache *uc, uint64_t ne
|
||||
uint64_t j;
|
||||
uint64_t found = 0;
|
||||
uint64_t need_to_scan = uc->blocks_bitmap_size;
|
||||
// we make an addition round for the corner case of a single byte map not starting from 0
|
||||
if (bitmap_bit > 0) need_to_scan++;
|
||||
j = bitmap_byte;
|
||||
//uwsgi_log("start scanning %llu bytes starting from %llu need: %llu\n", (unsigned long long) need_to_scan, (unsigned long long) bitmap_byte, (unsigned long long) needed_blocks);
|
||||
while(need_to_scan) {
|
||||
@@ -73,7 +75,9 @@ static uint64_t uwsgi_cache_find_free_blocks(struct uwsgi_cache *uc, uint64_t ne
|
||||
}
|
||||
found++;
|
||||
if (found == needed_blocks) {
|
||||
//printf("found %llu consecutive bit starting from byte %llu\n", found, base);
|
||||
#ifdef UWSGI_DEBUG
|
||||
printf("found %llu consecutive bit starting from byte %llu\n", (unsigned long long) found, (unsigned long long) base);
|
||||
#endif
|
||||
return ((base*8) + base_bit);
|
||||
}
|
||||
}
|
||||
@@ -82,12 +86,14 @@ static uint64_t uwsgi_cache_find_free_blocks(struct uwsgi_cache *uc, uint64_t ne
|
||||
}
|
||||
j++;
|
||||
need_to_scan--;
|
||||
// check for overlap
|
||||
if (j >= need_to_scan) {
|
||||
// check for overlap (that is not supported)
|
||||
if (j >= uc->blocks_bitmap_size) {
|
||||
j = 0;
|
||||
found = 0;
|
||||
base = 0xffffffffffffffffLLU;
|
||||
base_bit = 0;
|
||||
// we use bitmap_bit only at the first round
|
||||
bitmap_bit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,19 +108,27 @@ static uint64_t cache_mark_blocks(struct uwsgi_cache *uc, uint64_t index, uint64
|
||||
|
||||
uint64_t first_byte = index/8;
|
||||
uint8_t first_byte_bit = index % 8;
|
||||
uint64_t last_byte = (index+needed_blocks)/8;
|
||||
uint8_t last_byte_bit = (index+needed_blocks) % 8;
|
||||
// offset starts with 0, so actual last bit is index + needed_blocks - 1
|
||||
uint64_t last_byte = (index + needed_blocks - 1) / 8;
|
||||
uint8_t last_byte_bit = (index + needed_blocks - 1) % 8;
|
||||
|
||||
uint64_t needed_bytes = (last_byte - first_byte) + 1;
|
||||
|
||||
//uwsgi_log("%llu %u %llu %u\n", first_byte, first_byte_bit, last_byte, last_byte_bit);
|
||||
|
||||
uint8_t mask = 0xff >> first_byte_bit;
|
||||
|
||||
if (needed_bytes == 1) {
|
||||
// kinda hacky, but it does the job
|
||||
mask >>= (7 - last_byte_bit);
|
||||
mask <<= (7 - last_byte_bit);
|
||||
}
|
||||
|
||||
uc->blocks_bitmap[first_byte] |= mask;
|
||||
|
||||
uint64_t needed_bytes = (last_byte - first_byte)+1;
|
||||
|
||||
if (needed_bytes > 1) {
|
||||
mask = 0xff << (8 - last_byte_bit);
|
||||
uc->blocks_bitmap[last_byte-1] |= mask;
|
||||
mask = 0xff << (7 - last_byte_bit);
|
||||
uc->blocks_bitmap[last_byte] |= mask;
|
||||
}
|
||||
|
||||
if (needed_bytes > 2) {
|
||||
@@ -130,19 +144,28 @@ static void cache_unmark_blocks(struct uwsgi_cache *uc, uint64_t index, uint64_t
|
||||
|
||||
uint64_t first_byte = index/8;
|
||||
uint8_t first_byte_bit = index % 8;
|
||||
uint64_t last_byte = (index+needed_blocks)/8;
|
||||
uint8_t last_byte_bit = (index+needed_blocks) % 8;
|
||||
// offset starts with 0, so actual last bit is index + needed_blocks - 1
|
||||
uint64_t last_byte = (index + needed_blocks - 1)/8;
|
||||
uint8_t last_byte_bit = (index + needed_blocks - 1) % 8;
|
||||
|
||||
// here we use XOR (0+0 = 0 | 1+0 = 1 | 0+1 = 1| 1+1 = 0|
|
||||
uint64_t needed_bytes = (last_byte - first_byte) + 1;
|
||||
|
||||
uint8_t mask = 0xff >> first_byte_bit;
|
||||
uc->blocks_bitmap[first_byte] ^= mask;
|
||||
uint8_t mask = 0xff >> first_byte_bit;
|
||||
|
||||
uint64_t needed_bytes = (last_byte - first_byte)+1;
|
||||
if (needed_bytes == 1) {
|
||||
// kinda hacky, but it does the job
|
||||
mask >>= (7 - last_byte_bit);
|
||||
mask <<= (7 - last_byte_bit);
|
||||
}
|
||||
|
||||
// here we use AND (0+0 = 0 | 1+0 = 0 | 0+1 = 0| 1+1 = 1)
|
||||
// 0 in mask means "unmark", 1 in mask means "do not change"
|
||||
// so we need to invert the mask
|
||||
uc->blocks_bitmap[first_byte] &= ~mask;
|
||||
|
||||
if (needed_bytes > 1) {
|
||||
mask = 0xff << (8 - last_byte_bit);
|
||||
uc->blocks_bitmap[last_byte-1] ^= mask;
|
||||
mask = 0xff << (7 - last_byte_bit);
|
||||
uc->blocks_bitmap[last_byte] &= ~mask;
|
||||
}
|
||||
|
||||
if (needed_bytes > 2) {
|
||||
@@ -283,16 +306,24 @@ next2:
|
||||
void uwsgi_cache_init(struct uwsgi_cache *uc) {
|
||||
|
||||
uc->hashtable = uwsgi_calloc_shared(sizeof(uint64_t) * uc->hashsize);
|
||||
uc->unused_blocks_stack = uwsgi_calloc_shared(sizeof(uint64_t) * uc->blocks);
|
||||
// the first cache item is always zero
|
||||
uc->first_available_block = 1;
|
||||
uc->unused_blocks_stack = uwsgi_calloc_shared(sizeof(uint64_t) * uc->max_items);
|
||||
uc->unused_blocks_stack_ptr = 0;
|
||||
uc->filesize = ( (sizeof(struct uwsgi_cache_item)+uc->keysize) * uc->max_items) + (uc->blocksize * uc->blocks);
|
||||
|
||||
uint64_t i;
|
||||
for (i = 1; i < uc->max_items; i++) {
|
||||
uc->unused_blocks_stack_ptr++;
|
||||
uc->unused_blocks_stack[uc->unused_blocks_stack_ptr] = i;
|
||||
}
|
||||
|
||||
if (uc->use_blocks_bitmap) {
|
||||
uc->blocks_bitmap_size = uc->blocks/8;
|
||||
if (uc->blocks % 8 > 0) uc->blocks_bitmap_size++;
|
||||
uint8_t m = uc->blocks % 8;
|
||||
if (m > 0) uc->blocks_bitmap_size++;
|
||||
uc->blocks_bitmap = uwsgi_calloc_shared(uc->blocks_bitmap_size);
|
||||
if (m > 0) {
|
||||
uc->blocks_bitmap[uc->blocks_bitmap_size-1] = 0xff >> m;
|
||||
}
|
||||
}
|
||||
|
||||
//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);
|
||||
@@ -361,7 +392,7 @@ void uwsgi_cache_init(struct uwsgi_cache *uc) {
|
||||
uc->name,
|
||||
(unsigned long long) uc->filesize / (1024 * 1024),
|
||||
(unsigned long long) sizeof(struct uwsgi_cache_item)+uc->keysize,
|
||||
(unsigned long long) ((sizeof(struct uwsgi_cache_item)+uc->keysize) * uc->max_items), (unsigned long long) (uc->blocksize * uc->max_items),
|
||||
(unsigned long long) ((sizeof(struct uwsgi_cache_item)+uc->keysize) * uc->max_items), (unsigned long long) (uc->blocksize * uc->blocks),
|
||||
(unsigned long long) uc->blocks_bitmap_size);
|
||||
|
||||
uwsgi_cache_setup_nodes(uc);
|
||||
@@ -441,6 +472,38 @@ uint32_t uwsgi_cache_exists2(struct uwsgi_cache *uc, char *key, uint16_t keylen)
|
||||
return uwsgi_cache_get_index(uc, key, keylen);
|
||||
}
|
||||
|
||||
static void lru_remove_item(struct uwsgi_cache *uc, uint64_t index)
|
||||
{
|
||||
struct uwsgi_cache_item *prev, *next, *curr = cache_item(index);
|
||||
|
||||
if (curr->next) {
|
||||
next = cache_item(curr->next);
|
||||
next->prev = curr->prev;
|
||||
} else
|
||||
uc->lru_tail = curr->prev;
|
||||
|
||||
if (curr->prev) {
|
||||
prev = cache_item(curr->prev);
|
||||
prev->next = curr->next;
|
||||
} else
|
||||
uc->lru_head = curr->next;
|
||||
}
|
||||
|
||||
static void lru_add_item(struct uwsgi_cache *uc, uint64_t index)
|
||||
{
|
||||
struct uwsgi_cache_item *prev, *curr = cache_item(index);
|
||||
|
||||
if (uc->lru_tail) {
|
||||
prev = cache_item(uc->lru_tail);
|
||||
prev->next = index;
|
||||
} else
|
||||
uc->lru_head = index;
|
||||
|
||||
curr->next = 0;
|
||||
curr->prev = uc->lru_tail;
|
||||
uc->lru_tail = index;
|
||||
}
|
||||
|
||||
char *uwsgi_cache_get2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint64_t * valsize) {
|
||||
|
||||
uint64_t index = uwsgi_cache_get_index(uc, key, keylen);
|
||||
@@ -450,6 +513,10 @@ char *uwsgi_cache_get2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint6
|
||||
if (uci->flags & UWSGI_CACHE_FLAG_UNGETTABLE)
|
||||
return NULL;
|
||||
*valsize = uci->valsize;
|
||||
if (uc->purge_lru) {
|
||||
lru_remove_item(uc, index);
|
||||
lru_add_item(uc, index);
|
||||
}
|
||||
uci->hits++;
|
||||
uc->hits++;
|
||||
return uc->data + (uci->first_block * uc->blocksize);
|
||||
@@ -489,6 +556,10 @@ char *uwsgi_cache_get3(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint6
|
||||
*valsize = uci->valsize;
|
||||
if (expires)
|
||||
*expires = uci->expires;
|
||||
if (uc->purge_lru) {
|
||||
lru_remove_item(uc, index);
|
||||
lru_add_item(uc, index);
|
||||
}
|
||||
uci->hits++;
|
||||
uc->hits++;
|
||||
return uc->data + (uci->first_block * uc->blocksize);
|
||||
@@ -523,50 +594,56 @@ char *uwsgi_cache_get4(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint6
|
||||
|
||||
int uwsgi_cache_del2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint64_t index, uint16_t flags) {
|
||||
|
||||
|
||||
struct uwsgi_cache_item *uci;
|
||||
int ret = -1;
|
||||
|
||||
if (!index)
|
||||
index = uwsgi_cache_get_index(uc, key, keylen);
|
||||
if (!index) index = uwsgi_cache_get_index(uc, key, keylen);
|
||||
|
||||
if (index) {
|
||||
uci = cache_item(index);
|
||||
if (uci->keysize > 0) {
|
||||
// unmark blocks
|
||||
if (uc->blocks_bitmap) cache_unmark_blocks(uc, uci->first_block, uci->valsize);
|
||||
// put back the block in unused stack
|
||||
uc->unused_blocks_stack_ptr++;
|
||||
uc->unused_blocks_stack[uc->unused_blocks_stack_ptr] = index;
|
||||
|
||||
// unlink prev and next (if any)
|
||||
if (uci->prev) {
|
||||
struct uwsgi_cache_item *ucii = cache_item(uci->prev);
|
||||
ucii->next = uci->next;
|
||||
}
|
||||
else {
|
||||
// set next as the new entry point (could be 0)
|
||||
uc->hashtable[uci->hash % uc->hashsize] = uci->next;
|
||||
}
|
||||
|
||||
if (uci->next) {
|
||||
struct uwsgi_cache_item *ucii = cache_item(uci->next);
|
||||
ucii->prev = uci->prev;
|
||||
}
|
||||
|
||||
if (!uci->prev && !uci->next) {
|
||||
// reset hashtable entry
|
||||
uc->hashtable[uci->hash % uc->hashsize] = 0;
|
||||
}
|
||||
|
||||
if (uc->purge_lru)
|
||||
lru_remove_item(uc, index);
|
||||
|
||||
uc->n_items--;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
uci->keysize = 0;
|
||||
uci->valsize = 0;
|
||||
uc->unused_blocks_stack_ptr++;
|
||||
uc->unused_blocks_stack[uc->unused_blocks_stack_ptr] = index;
|
||||
// unmark blocks
|
||||
if (uc->blocks_bitmap) {
|
||||
cache_unmark_blocks(uc, uci->first_block, uci->valsize);
|
||||
}
|
||||
ret = 0;
|
||||
// relink collisioned entry
|
||||
if (uci->prev) {
|
||||
struct uwsgi_cache_item *ucii = cache_item(uci->prev);
|
||||
ucii->next = uci->next;
|
||||
}
|
||||
else {
|
||||
// set next as the new entry point (could be 0)
|
||||
uc->hashtable[uci->hash % uc->hashsize] = uci->next;
|
||||
}
|
||||
|
||||
if (uci->next) {
|
||||
struct uwsgi_cache_item *ucii = cache_item(uci->next);
|
||||
ucii->prev = uci->prev;
|
||||
}
|
||||
|
||||
if (!uci->prev && !uci->next) {
|
||||
// reset hashtable entry
|
||||
//uwsgi_log("!!! resetted hashtable entry !!!\n");
|
||||
uc->hashtable[uci->hash % uc->hashsize] = 0;
|
||||
}
|
||||
uci->hash = 0;
|
||||
uci->prev = 0;
|
||||
uci->next = 0;
|
||||
uci->expires = 0;
|
||||
|
||||
uc->n_items--;
|
||||
|
||||
if (uc->use_last_modified) {
|
||||
uc->last_modified_at = uwsgi_now();
|
||||
}
|
||||
@@ -584,7 +661,10 @@ void uwsgi_cache_fix(struct uwsgi_cache *uc) {
|
||||
uint64_t i;
|
||||
unsigned long long restored = 0;
|
||||
|
||||
for (i = 0; i < uc->max_items; i++) {
|
||||
// reset unused blocks
|
||||
uc->unused_blocks_stack_ptr = 0;
|
||||
|
||||
for (i = 1; i < uc->max_items; i++) {
|
||||
// valid record ?
|
||||
struct uwsgi_cache_item *uci = cache_item(i);
|
||||
if (uci->keysize) {
|
||||
@@ -596,7 +676,6 @@ void uwsgi_cache_fix(struct uwsgi_cache *uc) {
|
||||
}
|
||||
else {
|
||||
// put this record in unused stack
|
||||
uc->first_available_block = i;
|
||||
uc->unused_blocks_stack_ptr++;
|
||||
uc->unused_blocks_stack[uc->unused_blocks_stack_ptr] = i;
|
||||
}
|
||||
@@ -613,7 +692,6 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
|
||||
struct uwsgi_cache_item *uci, *ucii;
|
||||
|
||||
// used to reset key allocation in bitmap mode
|
||||
uint8_t rollback_mode = 0;
|
||||
|
||||
int ret = -1;
|
||||
time_t now = 0;
|
||||
@@ -631,56 +709,53 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
|
||||
//uwsgi_log("putting cache data in key %.*s %d\n", keylen, key, vallen);
|
||||
index = uwsgi_cache_get_index(uc, key, keylen);
|
||||
if (!index) {
|
||||
if (uc->first_available_block >= uc->max_items && !uc->unused_blocks_stack_ptr) {
|
||||
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
|
||||
uc->full++;
|
||||
goto end;
|
||||
}
|
||||
if (uc->unused_blocks_stack_ptr) {
|
||||
//uwsgi_log("!!! REUSING CACHE SLOT !!! (faci: %llu)\n", (unsigned long long) uwsgi.shared->cache_first_available_block);
|
||||
index = uc->unused_blocks_stack[uc->unused_blocks_stack_ptr];
|
||||
uc->unused_blocks_stack_ptr--;
|
||||
}
|
||||
else {
|
||||
rollback_mode = 1;
|
||||
index = uc->first_available_block;
|
||||
if (uc->first_available_block < uc->max_items) {
|
||||
rollback_mode = 2;
|
||||
uc->first_available_block++;
|
||||
if (!uc->unused_blocks_stack_ptr) {
|
||||
if (!uc->ignore_full) {
|
||||
if (uc->purge_lru)
|
||||
uwsgi_log("LRU item will be purged from cache \"%s\"\n", uc->name);
|
||||
else
|
||||
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
|
||||
}
|
||||
uc->full++;
|
||||
if (uc->purge_lru && uc->lru_head)
|
||||
uwsgi_cache_del2(uc, NULL, 0, uc->lru_head, UWSGI_CACHE_FLAG_LOCAL);
|
||||
if (!uc->unused_blocks_stack_ptr)
|
||||
goto end;
|
||||
}
|
||||
|
||||
index = uc->unused_blocks_stack[uc->unused_blocks_stack_ptr];
|
||||
uc->unused_blocks_stack_ptr--;
|
||||
|
||||
uci = cache_item(index);
|
||||
if (!uc->blocks_bitmap) {
|
||||
uci->first_block = index;
|
||||
}
|
||||
else {
|
||||
uci->first_block = uwsgi_cache_find_free_blocks(uc, vallen);
|
||||
//uwsgi_log("first block = %llu\n", uci->first_block);
|
||||
if (uci->first_block == 0xffffffffffffffffLLU) {
|
||||
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
|
||||
if (!uc->ignore_full)
|
||||
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
|
||||
uc->full++;
|
||||
if (rollback_mode == 0) {
|
||||
uc->unused_blocks_stack_ptr++;
|
||||
}
|
||||
else if (rollback_mode == 2) {
|
||||
uc->first_available_block--;
|
||||
}
|
||||
uc->unused_blocks_stack_ptr++;
|
||||
goto end;
|
||||
}
|
||||
// mark used blocks;
|
||||
uint64_t needed_blocks = cache_mark_blocks(uc, uci->first_block, vallen);
|
||||
// optimize the scan
|
||||
if (uc->blocks_bitmap_pos + (needed_blocks+1) > uc->blocks) {
|
||||
if (uc->blocks_bitmap_pos + needed_blocks > uc->blocks) {
|
||||
uc->blocks_bitmap_pos = 0;
|
||||
}
|
||||
else {
|
||||
uc->blocks_bitmap_pos = uci->first_block + needed_blocks + 1;
|
||||
uc->blocks_bitmap_pos = uci->first_block + needed_blocks;
|
||||
}
|
||||
}
|
||||
if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) {
|
||||
if (uc->purge_lru)
|
||||
lru_add_item(uc, index);
|
||||
else if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) {
|
||||
now = uwsgi_now();
|
||||
expires += now;
|
||||
if (!uc->next_scan || uc->next_scan > expires)
|
||||
uc->next_scan = expires;
|
||||
}
|
||||
uci->expires = expires;
|
||||
uci->hash = uc->hash->func(key, keylen);
|
||||
@@ -745,9 +820,16 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
|
||||
}
|
||||
else if (flags & UWSGI_CACHE_FLAG_UPDATE) {
|
||||
uci = cache_item(index);
|
||||
if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE) && !(flags & UWSGI_CACHE_FLAG_FIXEXPIRE)) {
|
||||
now = uwsgi_now();
|
||||
expires += now;
|
||||
if (!(flags & UWSGI_CACHE_FLAG_FIXEXPIRE)) {
|
||||
if (uc->purge_lru) {
|
||||
lru_remove_item(uc, index);
|
||||
lru_add_item(uc, index);
|
||||
} else if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) {
|
||||
now = uwsgi_now();
|
||||
expires += now;
|
||||
if (!uc->next_scan || uc->next_scan > expires)
|
||||
uc->next_scan = expires;
|
||||
}
|
||||
uci->expires = expires;
|
||||
}
|
||||
if (uc->blocks_bitmap) {
|
||||
@@ -755,7 +837,8 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
|
||||
uint64_t old_first_block = uci->first_block;
|
||||
uci->first_block = uwsgi_cache_find_free_blocks(uc, vallen);
|
||||
if (uci->first_block == 0xffffffffffffffffLLU) {
|
||||
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
|
||||
if (!uc->ignore_full)
|
||||
uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name);
|
||||
uc->full++;
|
||||
uci->first_block = old_first_block;
|
||||
goto end;
|
||||
@@ -763,14 +846,14 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v
|
||||
// mark used blocks;
|
||||
uint64_t needed_blocks = cache_mark_blocks(uc, uci->first_block, vallen);
|
||||
// optimize the scan
|
||||
if (uc->blocks_bitmap_pos + (needed_blocks+1) > uc->blocks) {
|
||||
if (uc->blocks_bitmap_pos + needed_blocks > uc->blocks) {
|
||||
uc->blocks_bitmap_pos = 0;
|
||||
}
|
||||
else {
|
||||
uc->blocks_bitmap_pos = uci->first_block + needed_blocks + 1;
|
||||
uc->blocks_bitmap_pos = uci->first_block + needed_blocks;
|
||||
}
|
||||
// unmark the old blocks
|
||||
cache_unmark_blocks(uc, uci->first_block, uci->valsize);
|
||||
cache_unmark_blocks(uc, old_first_block, uci->valsize);
|
||||
}
|
||||
if ( !(flags & UWSGI_CACHE_FLAG_MATH)) {
|
||||
memcpy(((char *) uc->data) + (uci->first_block * uc->blocksize), val, vallen);
|
||||
@@ -965,39 +1048,66 @@ void *cache_udp_server_loop(void *ucache) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint64_t cache_sweeper_free_items(struct uwsgi_cache *uc) {
|
||||
uint64_t i;
|
||||
uint64_t freed_items = 0;
|
||||
|
||||
if (uc->no_expire || uc->purge_lru)
|
||||
return 0;
|
||||
|
||||
uwsgi_rlock(uc->lock);
|
||||
if (!uc->next_scan || uc->next_scan > (uint64_t)uwsgi.current_time) {
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
return 0;
|
||||
}
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
|
||||
// skip the first slot
|
||||
for (i = 1; i < uc->max_items; i++) {
|
||||
struct uwsgi_cache_item *uci = cache_item(i);
|
||||
|
||||
uwsgi_wlock(uc->lock);
|
||||
// we reset next scan time first, then we find the least
|
||||
// expiration time from those that are NOT expired yet.
|
||||
if (i == 1)
|
||||
uc->next_scan = 0;
|
||||
|
||||
if (uci->expires) {
|
||||
if (uci->expires <= (uint64_t)uwsgi.current_time) {
|
||||
uwsgi_cache_del2(uc, NULL, 0, i, UWSGI_CACHE_FLAG_LOCAL);
|
||||
freed_items++;
|
||||
} else if (!uc->next_scan || uc->next_scan > uci->expires) {
|
||||
uc->next_scan = uci->expires;
|
||||
}
|
||||
}
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
}
|
||||
|
||||
return freed_items;
|
||||
}
|
||||
|
||||
static void *cache_sweeper_loop(void *ucache) {
|
||||
|
||||
uint64_t i;
|
||||
// block all signals
|
||||
sigset_t smask;
|
||||
sigfillset(&smask);
|
||||
pthread_sigmask(SIG_BLOCK, &smask, NULL);
|
||||
|
||||
struct uwsgi_cache *uc = (struct uwsgi_cache *) ucache;
|
||||
|
||||
if (!uwsgi.cache_expire_freq)
|
||||
uwsgi.cache_expire_freq = 3;
|
||||
|
||||
// remove expired cache items TODO use rb_tree timeouts
|
||||
for (;;) {
|
||||
struct uwsgi_cache *uc;
|
||||
|
||||
for (uc = (struct uwsgi_cache *)ucache; uc; uc = uc->next) {
|
||||
uint64_t freed_items = cache_sweeper_free_items(uc);
|
||||
if (uwsgi.cache_report_freed_items && freed_items)
|
||||
uwsgi_log("freed %llu items for cache \"%s\"\n", (unsigned long long)freed_items, uc->name);
|
||||
}
|
||||
|
||||
sleep(uwsgi.cache_expire_freq);
|
||||
uint64_t freed_items = 0;
|
||||
// skip the first slot
|
||||
for (i = 1; i < uc->max_items; i++) {
|
||||
uwsgi_wlock(uc->lock);
|
||||
struct uwsgi_cache_item *uci = cache_item(i);
|
||||
if (uci->expires) {
|
||||
if (uci->expires < (uint64_t) uwsgi.current_time) {
|
||||
uwsgi_cache_del2(uc, NULL, 0, i, UWSGI_CACHE_FLAG_LOCAL);
|
||||
freed_items++;
|
||||
}
|
||||
}
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
}
|
||||
if (uwsgi.cache_report_freed_items && freed_items > 0) {
|
||||
uwsgi_log("freed %llu items for cache \"%s\"\n", (unsigned long long) freed_items, uc->name);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1017,16 +1127,21 @@ void uwsgi_cache_sync_all() {
|
||||
|
||||
void uwsgi_cache_start_sweepers() {
|
||||
struct uwsgi_cache *uc = uwsgi.caches;
|
||||
|
||||
if (uwsgi.cache_no_expire)
|
||||
return;
|
||||
|
||||
while(uc) {
|
||||
pthread_t cache_sweeper;
|
||||
if (!uwsgi.cache_no_expire && !uc->no_expire) {
|
||||
if (pthread_create(&cache_sweeper, NULL, cache_sweeper_loop, (void *) uc)) {
|
||||
if (!uc->no_expire && !uc->purge_lru) {
|
||||
if (pthread_create(&cache_sweeper, NULL, cache_sweeper_loop, uwsgi.caches)) {
|
||||
uwsgi_error("pthread_create()");
|
||||
uwsgi_log("unable to run the sweeper for cache \"%s\" !!!\n", uc->name);
|
||||
uwsgi_log("unable to run the sweeper!!!\n");
|
||||
}
|
||||
else {
|
||||
uwsgi_log("sweeper thread enabled for cache \"%s\"\n", uc->name);
|
||||
uwsgi_log("sweeper thread enabled\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
uc = uc->next;
|
||||
}
|
||||
@@ -1103,6 +1218,8 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
|
||||
char *c_bitmap = NULL;
|
||||
char *c_use_last_modified = NULL;
|
||||
char *c_math_initial = NULL;
|
||||
char *c_ignore_full = NULL;
|
||||
char *c_purge_lru = NULL;
|
||||
|
||||
if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=',
|
||||
"name", &c_name,
|
||||
@@ -1130,6 +1247,8 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
|
||||
"bitmap", &c_bitmap,
|
||||
"lastmod", &c_use_last_modified,
|
||||
"math_initial", &c_math_initial,
|
||||
"ignore_full", &c_ignore_full,
|
||||
"purge_lru", &c_purge_lru,
|
||||
NULL)) {
|
||||
uwsgi_log("unable to parse cache definition\n");
|
||||
exit(1);
|
||||
@@ -1177,6 +1296,7 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
|
||||
uc->max_item_size = uc->blocksize * uc->blocks;
|
||||
}
|
||||
if (c_use_last_modified) uc->use_last_modified = 1;
|
||||
if (c_ignore_full) uc->ignore_full = 1;
|
||||
|
||||
if (c_math_initial) uc->math_initial = strtol(c_math_initial, NULL, 10);
|
||||
|
||||
@@ -1211,6 +1331,8 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) {
|
||||
}
|
||||
}
|
||||
|
||||
if (c_purge_lru)
|
||||
uc->purge_lru = 1;
|
||||
}
|
||||
|
||||
uwsgi_cache_init(uc);
|
||||
@@ -1466,7 +1588,10 @@ char *uwsgi_cache_magic_get(char *key, uint16_t keylen, uint64_t *vallen, uint64
|
||||
|
||||
// we have a local cache !!!
|
||||
if (uc) {
|
||||
uwsgi_rlock(uc->lock);
|
||||
if (uc->purge_lru)
|
||||
uwsgi_wlock(uc->lock);
|
||||
else
|
||||
uwsgi_rlock(uc->lock);
|
||||
char *value = uwsgi_cache_get3(uc, key, keylen, vallen, expires);
|
||||
if (!value) {
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
@@ -1788,7 +1913,7 @@ int uwsgi_cache_magic_clear(char *cache) {
|
||||
if (uc) {
|
||||
uint64_t i;
|
||||
uwsgi_wlock(uc->lock);
|
||||
for (i = 1; i < uwsgi.caches->max_items; i++) {
|
||||
for (i = 1; i < uc->max_items; i++) {
|
||||
if (uwsgi_cache_del2(uc, NULL, 0, i, 0)) {
|
||||
uwsgi_rwunlock(uc->lock);
|
||||
return -1;
|
||||
|
||||
+18
-1
@@ -81,6 +81,22 @@ int uwsgi_logic_opt_for_glob(char *key, char *value) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int uwsgi_logic_opt_for_readline(char *key, char *value) {
|
||||
|
||||
char line[1024];
|
||||
|
||||
FILE *fh = fopen(uwsgi.logic_opt_data, "r");
|
||||
if (fh) {
|
||||
while (fgets(line, 1024, fh)) {
|
||||
add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi_chomp(uwsgi_str(line))), 0);
|
||||
}
|
||||
fclose(fh);
|
||||
return 1;
|
||||
}
|
||||
uwsgi_error_open(uwsgi.logic_opt_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_logic_opt_for_times(char *key, char *value) {
|
||||
|
||||
int num = atoi(uwsgi.logic_opt_data);
|
||||
@@ -384,7 +400,8 @@ void add_exported_option_do(char *key, char *value, int configured, int placehol
|
||||
if (uwsgi.logic_opt_running)
|
||||
goto add;
|
||||
|
||||
if (!strcmp(key, "end") || !strcmp(key, "endfor") || !strcmp(key, "endif")) {
|
||||
if (!strcmp(key, "end") || !strcmp(key, "endfor") || !strcmp(key, "endif")
|
||||
|| !strcmp(key, "end-if") || !strcmp(key, "end-for")) {
|
||||
if (uwsgi.logic_opt_data) {
|
||||
free(uwsgi.logic_opt_data);
|
||||
}
|
||||
|
||||
+60
-15
@@ -55,7 +55,7 @@ void uwsgi_daemons_smart_check() {
|
||||
if (ud->pid > 0) {
|
||||
if (!kill(ud->pid, 0)) {
|
||||
uwsgi_log("[uwsgi_daemons] stopping legion \"%s\" daemon: %s (pid: %d)\n", ud->legion, ud->command, ud->pid);
|
||||
kill(-ud->pid, ud->stop_signal);
|
||||
kill(-(ud->pid), ud->stop_signal);
|
||||
}
|
||||
else {
|
||||
// pid already died
|
||||
@@ -237,12 +237,12 @@ void uwsgi_detach_daemons() {
|
||||
time_t timeout = uwsgi_now() + (uwsgi.reload_mercy ? uwsgi.reload_mercy : 3);
|
||||
int waitpid_status;
|
||||
while (!kill(ud->pid, 0)) {
|
||||
kill(-ud->pid, ud->stop_signal);
|
||||
kill(-(ud->pid), ud->stop_signal);
|
||||
sleep(1);
|
||||
waitpid(-ud->pid, &waitpid_status, WNOHANG);
|
||||
waitpid(ud->pid, &waitpid_status, WNOHANG);
|
||||
if (uwsgi_now() >= timeout) {
|
||||
uwsgi_log("[uwsgi-daemons] daemon did not die in time, killing (pid: %d): %s\n", (int) ud->pid, ud->command);
|
||||
kill(-ud->pid, SIGKILL);
|
||||
kill(-(ud->pid), SIGKILL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -253,18 +253,19 @@ void uwsgi_detach_daemons() {
|
||||
}
|
||||
}
|
||||
|
||||
static int daemon_spawn(void *);
|
||||
|
||||
void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
|
||||
|
||||
// skip unregistered daemons
|
||||
if (!ud->registered) return;
|
||||
|
||||
int throttle = 0;
|
||||
ud->throttle = 0;
|
||||
|
||||
if (uwsgi.current_time - ud->last_spawn <= 3) {
|
||||
throttle = ud->respawns - (uwsgi.current_time - ud->last_spawn);
|
||||
ud->throttle = ud->respawns - (uwsgi.current_time - ud->last_spawn);
|
||||
// if ud->respawns == 0 then we can end up with throttle < 0
|
||||
if (throttle <= 0) throttle = 1;
|
||||
if (ud->throttle <= 0) ud->throttle = 1;
|
||||
}
|
||||
|
||||
pid_t pid = uwsgi_fork("uWSGI external daemon");
|
||||
@@ -291,6 +292,50 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
|
||||
uwsgi_close_all_sockets();
|
||||
uwsgi_close_all_fds();
|
||||
|
||||
#if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL) && defined(CLONE_NEWPID)
|
||||
if (ud->ns_pid) {
|
||||
// we need to create a new session
|
||||
if (setsid() < 0) {
|
||||
uwsgi_error("setsid()");
|
||||
exit(1);
|
||||
}
|
||||
// avoid the need to set stop_signal in attach-daemon2
|
||||
signal(SIGTERM, end_me);
|
||||
|
||||
char stack[PTHREAD_STACK_MIN];
|
||||
pid_t pid = clone((int (*)(void *))daemon_spawn, stack + PTHREAD_STACK_MIN, SIGCHLD | CLONE_NEWPID, (void *) ud);
|
||||
if (pid > 0) {
|
||||
|
||||
#ifdef PR_SET_PDEATHSIG
|
||||
if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) {
|
||||
uwsgi_error("uwsgi_spawn_daemon()/prctl()");
|
||||
}
|
||||
#endif
|
||||
// block all signals except SIGTERM
|
||||
sigset_t smask;
|
||||
sigfillset(&smask);
|
||||
sigdelset(&smask, SIGTERM);
|
||||
sigprocmask(SIG_BLOCK, &smask, NULL);
|
||||
int status;
|
||||
if (waitpid(pid, &status, 0) < 0) {
|
||||
uwsgi_error("uwsgi_spawn_daemon()/waitpid()");
|
||||
}
|
||||
_exit(0);
|
||||
}
|
||||
uwsgi_error("uwsgi_spawn_daemon()/clone()");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
daemon_spawn((void *) ud);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int daemon_spawn(void *arg) {
|
||||
|
||||
struct uwsgi_daemon *ud = (struct uwsgi_daemon *) arg;
|
||||
|
||||
if (ud->gid) {
|
||||
if (setgid(ud->gid)) {
|
||||
uwsgi_error("uwsgi_spawn_daemon()/setgid()");
|
||||
@@ -307,7 +352,7 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
|
||||
|
||||
if (ud->daemonize) {
|
||||
/* refork... */
|
||||
pid = fork();
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
uwsgi_error("fork()");
|
||||
exit(1);
|
||||
@@ -329,7 +374,7 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
|
||||
}
|
||||
|
||||
if (!ud->pidfile) {
|
||||
#ifdef __linux__
|
||||
#ifdef PR_SET_PDEATHSIG
|
||||
if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) {
|
||||
uwsgi_error("prctl()");
|
||||
}
|
||||
@@ -337,9 +382,9 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
|
||||
}
|
||||
|
||||
|
||||
if (throttle) {
|
||||
uwsgi_log("[uwsgi-daemons] throttling \"%s\" for %d seconds\n", ud->command, throttle);
|
||||
sleep((unsigned int) throttle);
|
||||
if (ud->throttle) {
|
||||
uwsgi_log("[uwsgi-daemons] throttling \"%s\" for %d seconds\n", ud->command, ud->throttle);
|
||||
sleep((unsigned int) ud->throttle);
|
||||
}
|
||||
|
||||
uwsgi_log("[uwsgi-daemons] %sspawning \"%s\" (uid: %d gid: %d)\n", ud->respawns > 0 ? "re" : "", ud->command, (int) getuid(), (int) getgid());
|
||||
@@ -348,9 +393,6 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
|
||||
|
||||
// never here;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -454,6 +496,7 @@ void uwsgi_opt_add_daemon2(char *opt, char *value, void *none) {
|
||||
char *d_stdin = NULL;
|
||||
char *d_uid = NULL;
|
||||
char *d_gid = NULL;
|
||||
char *d_ns_pid = NULL;
|
||||
|
||||
char *arg = uwsgi_str(value);
|
||||
|
||||
@@ -474,6 +517,7 @@ void uwsgi_opt_add_daemon2(char *opt, char *value, void *none) {
|
||||
"stdin", &d_stdin,
|
||||
"uid", &d_uid,
|
||||
"gid", &d_gid,
|
||||
"ns_pid", &d_ns_pid,
|
||||
NULL)) {
|
||||
uwsgi_log("invalid --%s keyval syntax\n", opt);
|
||||
exit(1);
|
||||
@@ -519,6 +563,7 @@ void uwsgi_opt_add_daemon2(char *opt, char *value, void *none) {
|
||||
#ifdef UWSGI_SSL
|
||||
uwsgi_ud->legion = d_legion;
|
||||
#endif
|
||||
uwsgi_ud->ns_pid = d_ns_pid ? 1 : 0;
|
||||
|
||||
if (d_touch) {
|
||||
size_t i,rlen = 0;
|
||||
|
||||
+253
-42
@@ -18,6 +18,8 @@ int emperor_throttle_level;
|
||||
|
||||
struct uwsgi_instance *ui;
|
||||
|
||||
time_t on_royal_death = 0;
|
||||
|
||||
/*
|
||||
|
||||
blacklist subsystem
|
||||
@@ -37,6 +39,70 @@ struct uwsgi_emperor_blacklist_item {
|
||||
|
||||
struct uwsgi_emperor_blacklist_item *emperor_blacklist;
|
||||
|
||||
/*
|
||||
this should be placed in core/socket.c but we realized it was needed
|
||||
only after 2.0 so we cannot change uwsgi.h
|
||||
|
||||
basically it is a stripped down bind_to_tcp/bind_to_unix with rollback
|
||||
*/
|
||||
static int on_demand_bind(char *socket_name) {
|
||||
union uwsgi_sockaddr us;
|
||||
socklen_t addr_len = sizeof(struct sockaddr_un);
|
||||
char *is_tcp = strchr(socket_name, ':');
|
||||
int af_family = is_tcp ? AF_INET : AF_UNIX;
|
||||
int fd = socket(af_family, SOCK_STREAM, 0);
|
||||
if (fd < 0) return -1;
|
||||
|
||||
memset(&us, 0, sizeof(union uwsgi_sockaddr));
|
||||
|
||||
if (is_tcp) {
|
||||
int reuse = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
us.sa_in.sin_family = AF_INET;
|
||||
us.sa_in.sin_port = htons(atoi(is_tcp+1));
|
||||
*is_tcp = 0;
|
||||
if (socket_name[0] != 0) {
|
||||
us.sa_in.sin_addr.s_addr = inet_addr(socket_name);
|
||||
}
|
||||
else {
|
||||
us.sa_in.sin_addr.s_addr = INADDR_ANY;
|
||||
}
|
||||
*is_tcp = ':';
|
||||
addr_len = sizeof(struct sockaddr_in);
|
||||
}
|
||||
else {
|
||||
if (unlink(socket_name) != 0 && errno != ENOENT) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
us.sa_un.sun_family = AF_UNIX;
|
||||
memcpy(us.sa_un.sun_path, socket_name, UMIN(strlen(socket_name), 102));
|
||||
addr_len = strlen(socket_name) + ((void *) us.sa_un.sun_path - (void *) &us.sa_un);
|
||||
}
|
||||
|
||||
if (bind(fd, (struct sockaddr *) &us, addr_len) != 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!is_tcp) {
|
||||
if (chmod(socket_name, 0666)) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (listen(fd, uwsgi.listen_queue) != 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
return fd;
|
||||
|
||||
error:
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct uwsgi_emperor_blacklist_item *uwsgi_emperor_blacklist_check(char *id) {
|
||||
struct uwsgi_emperor_blacklist_item *uebi = emperor_blacklist;
|
||||
while (uebi) {
|
||||
@@ -155,7 +221,7 @@ static char *emperor_check_on_demand_socket(char *filename) {
|
||||
if (fd < 0) return NULL;
|
||||
char *ret = uwsgi_read_fd(fd, &len, 1);
|
||||
close(fd);
|
||||
// change the first non prinabel character to 0
|
||||
// change the first non printable character to 0
|
||||
size_t i;
|
||||
for(i=0;i<len;i++) {
|
||||
if (ret[i] < 32) {
|
||||
@@ -482,6 +548,10 @@ void uwsgi_register_imperial_monitor(char *name, void (*init) (struct uwsgi_empe
|
||||
// the sad death of an Emperor
|
||||
static void royal_death(int signum) {
|
||||
|
||||
if (on_royal_death) {
|
||||
uwsgi_log("[emperor] *** RAGNAROK ALREADY EVOKED (mercyless in %d seconds)***\n", uwsgi.reload_mercy - (uwsgi_now() - on_royal_death));
|
||||
return;
|
||||
}
|
||||
|
||||
struct uwsgi_instance *c_ui = ui->ui_next;
|
||||
|
||||
@@ -502,8 +572,14 @@ static void royal_death(int signum) {
|
||||
}
|
||||
|
||||
uwsgi_log("[emperor] *** RAGNAROK EVOKED ***\n");
|
||||
uwsgi_notify("The Emperor is buried.");
|
||||
exit(0);
|
||||
|
||||
while (c_ui) {
|
||||
emperor_stop(c_ui);
|
||||
c_ui = c_ui->ui_next;
|
||||
}
|
||||
|
||||
if (!uwsgi.reload_mercy) uwsgi.reload_mercy = 30;
|
||||
on_royal_death = uwsgi_now();
|
||||
}
|
||||
|
||||
// massive reload of vassals
|
||||
@@ -617,16 +693,39 @@ void emperor_del(struct uwsgi_instance *c_ui) {
|
||||
free(c_ui->socket_name);
|
||||
}
|
||||
|
||||
if (c_ui->on_demand_fd != -1) {
|
||||
close(c_ui->on_demand_fd);
|
||||
}
|
||||
|
||||
free(c_ui);
|
||||
|
||||
}
|
||||
|
||||
void emperor_back_to_ondemand(struct uwsgi_instance *c_ui) {
|
||||
if (c_ui->status > 0) return;
|
||||
|
||||
// remove uWSGI instance
|
||||
|
||||
if (c_ui->pid != -1) {
|
||||
if (write(c_ui->pipe[0], "\0", 1) != 1) {
|
||||
uwsgi_error("emperor_stop()/write()");
|
||||
}
|
||||
}
|
||||
|
||||
c_ui->status = 2;
|
||||
c_ui->cursed_at = uwsgi_now();
|
||||
|
||||
uwsgi_log_verbose("[emperor] bringing back instance %s to on-demand mode\n", c_ui->name);
|
||||
}
|
||||
|
||||
void emperor_stop(struct uwsgi_instance *c_ui) {
|
||||
if (c_ui->status == 1) return;
|
||||
// remove uWSGI instance
|
||||
|
||||
if (write(c_ui->pipe[0], "\0", 1) != 1) {
|
||||
uwsgi_error("emperor_stop()/write()");
|
||||
if (c_ui->pid != -1) {
|
||||
if (write(c_ui->pipe[0], "\0", 1) != 1) {
|
||||
uwsgi_error("emperor_stop()/write()");
|
||||
}
|
||||
}
|
||||
|
||||
c_ui->status = 1;
|
||||
@@ -639,38 +738,55 @@ void emperor_curse(struct uwsgi_instance *c_ui) {
|
||||
if (c_ui->status == 1) return;
|
||||
// curse uWSGI instance
|
||||
|
||||
c_ui->status = 1;
|
||||
// take in account on-demand mode
|
||||
if (c_ui->status == 0) c_ui->status = 1;
|
||||
c_ui->cursed_at = uwsgi_now();
|
||||
|
||||
uwsgi_log_verbose("[emperor] curse the uwsgi instance %s (pid: %d)\n", c_ui->name, (int) c_ui->pid);
|
||||
|
||||
}
|
||||
|
||||
// send configuration (if required to the vassal)
|
||||
static void emperor_push_config(struct uwsgi_instance *c_ui) {
|
||||
struct uwsgi_header uh;
|
||||
|
||||
if (c_ui->use_config) {
|
||||
uh.modifier1 = 115;
|
||||
uh.pktsize = c_ui->config_len;
|
||||
uh.modifier2 = 0;
|
||||
if (write(c_ui->pipe_config[0], &uh, 4) != 4) {
|
||||
uwsgi_error("[uwsgi-emperor] write() header config");
|
||||
}
|
||||
else {
|
||||
if (write(c_ui->pipe_config[0], c_ui->config, c_ui->config_len) != (long) c_ui->config_len) {
|
||||
uwsgi_error("[uwsgi-emperor] write() config");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void emperor_respawn(struct uwsgi_instance *c_ui, time_t mod) {
|
||||
|
||||
struct uwsgi_header uh;
|
||||
// if the vassal is being destroyed, do not honour respawns
|
||||
if (c_ui->status > 0) return;
|
||||
|
||||
// check if we are in on_demand mode (the respawn will be ignored)
|
||||
if (c_ui->pid == -1 && c_ui->on_demand_fd > -1) {
|
||||
c_ui->last_mod = mod;
|
||||
uwsgi_log_verbose("[emperor] updated configuration for \"on demand\" instance %s\n", c_ui->name);
|
||||
return;
|
||||
}
|
||||
|
||||
// reload the uWSGI instance
|
||||
if (write(c_ui->pipe[0], "\1", 1) != 1) {
|
||||
// the vassal could be already dead, better to curse it
|
||||
uwsgi_error("emperor_respawn/write()");
|
||||
emperor_curse(c_ui);
|
||||
return;
|
||||
}
|
||||
|
||||
// push the config to the config pipe (if needed)
|
||||
if (c_ui->use_config) {
|
||||
uh.modifier1 = 115;
|
||||
uh.pktsize = c_ui->config_len;
|
||||
uh.modifier2 = 0;
|
||||
if (write(c_ui->pipe_config[0], &uh, 4) != 4) {
|
||||
uwsgi_error("[uwsgi-emperor] write() header config");
|
||||
}
|
||||
else {
|
||||
if (write(c_ui->pipe_config[0], c_ui->config, c_ui->config_len) != (long) c_ui->config_len) {
|
||||
uwsgi_error("[uwsgi-emperor] write() config");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emperor_push_config(c_ui);
|
||||
|
||||
c_ui->respawns++;
|
||||
c_ui->last_mod = mod;
|
||||
@@ -782,21 +898,12 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha
|
||||
}
|
||||
|
||||
n_ui->pid = -1;
|
||||
n_ui->pipe[0] = -1;
|
||||
n_ui->pipe[1] = -1;
|
||||
|
||||
// ok here we check if we need to bind to the specified socket or continue with the activation
|
||||
if (socket_name) {
|
||||
char *tcp_port = strchr(socket_name, ':');
|
||||
if (tcp_port) {
|
||||
// disable deferred accept for this socket
|
||||
int current_defer_accept = uwsgi.no_defer_accept;
|
||||
uwsgi.no_defer_accept = 1;
|
||||
n_ui->on_demand_fd = bind_to_tcp(socket_name, uwsgi.listen_queue, tcp_port);
|
||||
uwsgi.no_defer_accept = current_defer_accept;
|
||||
}
|
||||
else {
|
||||
n_ui->on_demand_fd = bind_to_unix(socket_name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
|
||||
}
|
||||
|
||||
n_ui->on_demand_fd = on_demand_bind(socket_name);
|
||||
if (n_ui->on_demand_fd < 0) {
|
||||
uwsgi_error("emperor_add()/bind()");
|
||||
free(n_ui);
|
||||
@@ -826,6 +933,7 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
|
||||
uwsgi_error("socketpair()");
|
||||
return -1;
|
||||
}
|
||||
uwsgi_socket_nb(n_ui->pipe[0]);
|
||||
|
||||
event_queue_add_fd_read(uwsgi.emperor_queue, n_ui->pipe[0]);
|
||||
|
||||
@@ -834,6 +942,7 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
|
||||
uwsgi_error("socketpair()");
|
||||
return -1;
|
||||
}
|
||||
uwsgi_socket_nb(n_ui->pipe_config[0]);
|
||||
}
|
||||
|
||||
if (n_ui->zerg) {
|
||||
@@ -861,11 +970,14 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) {
|
||||
n_ui->pid = pid;
|
||||
// close the right side of the pipe
|
||||
close(n_ui->pipe[1]);
|
||||
/* THE ON-DEMAND file descriptir is left mapped to the emperor to allow fast-respawn
|
||||
// TODO add an option to force closing it
|
||||
// close the "on demand" socket
|
||||
if (n_ui->on_demand_fd > -1) {
|
||||
close(n_ui->on_demand_fd);
|
||||
n_ui->on_demand_fd = -1;
|
||||
}
|
||||
*/
|
||||
if (n_ui->use_config) {
|
||||
close(n_ui->pipe_config[1]);
|
||||
}
|
||||
@@ -1440,6 +1552,17 @@ int uwsgi_emperor_scanner_event(int fd) {
|
||||
|
||||
}
|
||||
|
||||
static void emperor_wakeup(int sn) {}
|
||||
|
||||
static void emperor_cleanup() {
|
||||
uwsgi_log_verbose("[uwsgi-emperor] cleaning up blacklist ...\n");
|
||||
struct uwsgi_instance *ui_current = ui;
|
||||
while (ui_current->ui_next) {
|
||||
uwsgi_emperor_blacklist_remove(ui_current->name);
|
||||
ui_current = ui_current->ui_next;
|
||||
}
|
||||
}
|
||||
|
||||
void emperor_loop() {
|
||||
|
||||
// monitor a directory
|
||||
@@ -1468,11 +1591,13 @@ void emperor_loop() {
|
||||
}
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGWINCH, emperor_wakeup);
|
||||
uwsgi_unix_signal(SIGINT, royal_death);
|
||||
uwsgi_unix_signal(SIGTERM, royal_death);
|
||||
uwsgi_unix_signal(SIGQUIT, royal_death);
|
||||
uwsgi_unix_signal(SIGUSR1, emperor_stats);
|
||||
uwsgi_unix_signal(SIGHUP, emperor_massive_reload);
|
||||
uwsgi_unix_signal(SIGURG, emperor_cleanup);
|
||||
|
||||
memset(&ui_base, 0, sizeof(struct uwsgi_instance));
|
||||
|
||||
@@ -1520,8 +1645,47 @@ void emperor_loop() {
|
||||
|
||||
int freq = 0;
|
||||
|
||||
uwsgi_hooks_run(uwsgi.hook_emperor_start, "emperor-start", 1);
|
||||
|
||||
// signal parent-Emperor about my loyalty
|
||||
if (uwsgi.has_emperor && !uwsgi.loyal) {
|
||||
uwsgi_log("announcing my loyalty to the Emperor...\n");
|
||||
char byte = 17;
|
||||
if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
|
||||
uwsgi_error("write()");
|
||||
}
|
||||
uwsgi.loyal = 1;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
|
||||
if (on_royal_death) {
|
||||
if (!ui->ui_next) break;
|
||||
if (uwsgi_now() - on_royal_death >= uwsgi.reload_mercy) {
|
||||
ui_current = ui->ui_next;
|
||||
while (ui_current) {
|
||||
uwsgi_log_verbose("[emperor] NO MERCY for vassal %s !!!\n", ui_current->name);
|
||||
if (kill(ui_current->pid, SIGKILL) < 0) {
|
||||
uwsgi_error("[emperor] kill()");
|
||||
emperor_del(ui_current);
|
||||
break;
|
||||
}
|
||||
ui_current = ui_current->ui_next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ui_current = ui->ui_next;
|
||||
while (ui_current) {
|
||||
struct uwsgi_instance *dead_vassal = ui_current;
|
||||
ui_current = ui_current->ui_next;
|
||||
pid_t dead_pid = waitpid(dead_vassal->pid, &waitpid_status, WNOHANG);
|
||||
if (dead_pid > 0 || dead_pid < 0) {
|
||||
emperor_del(dead_vassal);
|
||||
}
|
||||
}
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!i_am_alone) {
|
||||
diedpid = waitpid(uwsgi.emperor_pid, &waitpid_status, WNOHANG);
|
||||
@@ -1553,6 +1717,10 @@ void emperor_loop() {
|
||||
if (rlen <= 0) {
|
||||
// SAFE
|
||||
event_queue_del_fd(uwsgi.emperor_queue, interesting_fd, event_queue_read());
|
||||
if (ui_current->status > 0) {
|
||||
// temporarily set frequency to a low value , so we can eventually fast-restart the instance
|
||||
freq = ui_current->status;
|
||||
}
|
||||
emperor_curse(ui_current);
|
||||
}
|
||||
else {
|
||||
@@ -1569,7 +1737,13 @@ void emperor_loop() {
|
||||
ui_current->last_heartbeat = uwsgi_now();
|
||||
}
|
||||
else if (byte == 22) {
|
||||
emperor_stop(ui_current);
|
||||
// command 22 changes meaning when in "on_demand" mode
|
||||
if (ui_current->on_demand_fd != -1) {
|
||||
emperor_back_to_ondemand(ui_current);
|
||||
}
|
||||
else {
|
||||
emperor_stop(ui_current);
|
||||
}
|
||||
}
|
||||
else if (byte == 30 && uwsgi.emperor_broodlord > 0 && uwsgi.emperor_broodlord_count < uwsgi.emperor_broodlord) {
|
||||
uwsgi_log_verbose("[emperor] going in broodlord mode: launching zergs for %s\n", ui_current->name);
|
||||
@@ -1588,6 +1762,9 @@ void emperor_loop() {
|
||||
ui_current->last_ready = uwsgi_now();
|
||||
uwsgi_log_verbose("[emperor] vassal %s has been spawned\n", ui_current->name);
|
||||
}
|
||||
else if (byte == 2) {
|
||||
emperor_push_config(ui_current);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1612,13 +1789,18 @@ void emperor_loop() {
|
||||
ui_current = ui->ui_next;
|
||||
while (ui_current) {
|
||||
if (ui_current->last_heartbeat > 0) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%d %d %d %d\n", ui_current->last_heartbeat, uwsgi.emperor_heartbeat, ui_current->last_heartbeat + uwsgi.emperor_heartbeat, uwsgi_now());
|
||||
#endif
|
||||
if ((ui_current->last_heartbeat + uwsgi.emperor_heartbeat) < uwsgi_now()) {
|
||||
uwsgi_log("[emperor] vassal %s sent no heartbeat in last %d seconds, brutally respawning it...\n", ui_current->name, uwsgi.emperor_heartbeat);
|
||||
// set last_heartbeat to 0 avoiding races
|
||||
ui_current->last_heartbeat = 0;
|
||||
if (ui_current->pid > 0) {
|
||||
if (kill(ui_current->pid, SIGKILL)) {
|
||||
if (kill(ui_current->pid, SIGKILL) < 0) {
|
||||
uwsgi_error("[emperor] kill()");
|
||||
emperor_del(ui_current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1626,6 +1808,8 @@ void emperor_loop() {
|
||||
ui_current = ui_current->ui_next;
|
||||
}
|
||||
|
||||
|
||||
recheck:
|
||||
// check for removed instances
|
||||
ui_current = ui;
|
||||
has_children = 0;
|
||||
@@ -1670,7 +1854,7 @@ void emperor_loop() {
|
||||
while (ui_current->ui_next) {
|
||||
ui_current = ui_current->ui_next;
|
||||
time_t now = uwsgi_now();
|
||||
if (ui_current->pid == diedpid) {
|
||||
if (diedpid > 0 && 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) {
|
||||
@@ -1681,6 +1865,8 @@ void emperor_loop() {
|
||||
// UNSAFE
|
||||
emperor_add(ui_current->scanner, ui_current->name, ui_current->last_mod, ui_current->config, ui_current->config_len, ui_current->uid, ui_current->gid, ui_current->socket_name);
|
||||
emperor_del(ui_current);
|
||||
// temporarily set frequency to 0, so we can eventually fast-restart the instance
|
||||
freq = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1690,21 +1876,47 @@ void emperor_loop() {
|
||||
free(ui_current->config);
|
||||
// SAFE
|
||||
emperor_del(ui_current);
|
||||
// temporarily set frequency to 0, so we can eventually fast-restart the instance
|
||||
freq = 0;
|
||||
break;
|
||||
}
|
||||
// back to on_demand mode ...
|
||||
else if (ui_current->status == 2) {
|
||||
event_queue_add_fd_read(uwsgi.emperor_queue, ui_current->on_demand_fd);
|
||||
ui_current->pid = -1;
|
||||
ui_current->status = 0;
|
||||
ui_current->cursed_at = 0;
|
||||
uwsgi_log("[uwsgi-emperor] %s -> back to \"on demand\" mode, waiting for connections on socket \"%s\" ...\n", ui_current->name, ui_current->socket_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (ui_current->cursed_at > 0 && now - ui_current->cursed_at >= uwsgi.emperor_curse_tolerance) {
|
||||
ui_current->cursed_at = now;
|
||||
if (kill(ui_current->pid, SIGKILL)) {
|
||||
uwsgi_error("[emperor] kill");
|
||||
else if (ui_current->cursed_at > 0) {
|
||||
if (ui_current->pid == -1) {
|
||||
emperor_del(ui_current);
|
||||
break;
|
||||
}
|
||||
else if (now - ui_current->cursed_at >= uwsgi.emperor_curse_tolerance) {
|
||||
ui_current->cursed_at = now;
|
||||
if (kill(ui_current->pid, SIGKILL) < 0) {
|
||||
uwsgi_error("[emperor] kill()");
|
||||
// delete the vassal, something is seriously wrong better to not leak memory...
|
||||
emperor_del(ui_current);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if waitpid returned an item, let's check for another (potential) one
|
||||
if (diedpid > 0) goto recheck;
|
||||
|
||||
|
||||
}
|
||||
|
||||
uwsgi_log_verbose("The Emperor is buried.\n");
|
||||
uwsgi_notify("The Emperor is buried.");
|
||||
exit(0);
|
||||
|
||||
}
|
||||
|
||||
void emperor_send_stats(int fd) {
|
||||
@@ -1995,7 +2207,6 @@ next:
|
||||
uwsgi.has_emperor = 1;
|
||||
uwsgi.emperor_fd = atoi(emperor_env);
|
||||
uwsgi.master_process = 1;
|
||||
uwsgi.no_orphans = 1;
|
||||
uwsgi_log("*** has_emperor mode detected (fd: %d) ***\n", uwsgi.emperor_fd);
|
||||
|
||||
if (getenv("UWSGI_EMPEROR_FD_CONFIG")) {
|
||||
|
||||
@@ -48,6 +48,14 @@ static void subscriptions_blocker() {
|
||||
}
|
||||
}
|
||||
|
||||
static void emperor_rescan() {
|
||||
if (uwsgi.emperor_pid > 0) {
|
||||
if (kill(uwsgi.emperor_pid, SIGWINCH)) {
|
||||
uwsgi_error("emperor_rescan()/kill()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
this is called as soon as possibile allowing plugins (or hooks) to override it
|
||||
@@ -74,6 +82,7 @@ void uwsgi_master_fifo_prepare() {
|
||||
uwsgi_fifo_table['+'] = uwsgi_cheaper_increase;
|
||||
uwsgi_fifo_table['c'] = uwsgi_chain_reload;
|
||||
uwsgi_fifo_table['C'] = uwsgi_go_cheap;
|
||||
uwsgi_fifo_table['E'] = emperor_rescan;
|
||||
uwsgi_fifo_table['f'] = uwsgi_refork_master;
|
||||
uwsgi_fifo_table['l'] = uwsgi_log_reopen;
|
||||
uwsgi_fifo_table['L'] = uwsgi_log_rotate;
|
||||
|
||||
+137
-162
@@ -8,207 +8,182 @@ extern struct uwsgi_server uwsgi;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
void uwsgi_fsmon_setup() {
|
||||
struct uwsgi_string_list *usl = uwsgi.fs_reload;
|
||||
while(usl) {
|
||||
if (uwsgi_register_fsmon(usl)) {
|
||||
uwsgi_log("[uwsgi-fsmon] unable to register monitor for \"%s\"\n", usl->value);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[uwsgi-fsmon] registered monitor for \"%s\"\n", usl->value);
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
usl = uwsgi.fs_brutal_reload;
|
||||
while(usl) {
|
||||
if (uwsgi_register_fsmon(usl)) {
|
||||
uwsgi_log("[uwsgi-fsmon] unable to register monitor for \"%s\"\n", usl->value);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[uwsgi-fsmon] registered monitor for \"%s\"\n", usl->value);
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
usl = uwsgi.fs_signal;
|
||||
while(usl) {
|
||||
char *copy = uwsgi_str(usl->value);
|
||||
char *space = strchr(copy, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("[uwsgi-fsmon] invalid syntax: \"%s\"\n", usl->value);
|
||||
free(copy);
|
||||
goto next;
|
||||
}
|
||||
*space = 0;
|
||||
usl->value = copy;
|
||||
usl->len = strlen(copy);
|
||||
usl->custom_ptr = space+1;
|
||||
if (uwsgi_register_fsmon(usl)) {
|
||||
uwsgi_log("[uwsgi-fsmon] unable to register monitor for \"%s\"\n", usl->value);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[uwsgi-fsmon] registered monitor for \"%s\"\n", usl->value);
|
||||
}
|
||||
next:
|
||||
usl = usl->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_register_fsmon(struct uwsgi_string_list *usl) {
|
||||
static int fsmon_add(struct uwsgi_fsmon *fs) {
|
||||
#ifdef UWSGI_EVENT_FILEMONITOR_USE_INOTIFY
|
||||
#ifndef OBSOLETE_LINUX_KERNEL
|
||||
static int inotify_fd = -1;
|
||||
if (inotify_fd == -1) {
|
||||
inotify_fd = inotify_init();
|
||||
if (inotify_fd < 0) {
|
||||
uwsgi_error("uwsgi_register_fsmon()/inotify_init()");
|
||||
uwsgi_error("fsmon_add()/inotify_init()");
|
||||
return -1;
|
||||
}
|
||||
if (event_queue_add_fd_read(uwsgi.master_queue, inotify_fd)) {
|
||||
uwsgi_error("uwsgi_register_fsmon()/event_queue_add_fd_read()");
|
||||
uwsgi_error("fsmon_add()/event_queue_add_fd_read()");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
int wd = inotify_add_watch(inotify_fd, usl->value, IN_ATTRIB | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_MOVED_FROM | IN_MOVED_TO);
|
||||
int wd = inotify_add_watch(inotify_fd, fs->path, IN_ATTRIB | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_MOVED_FROM | IN_MOVED_TO);
|
||||
if (wd < 0) {
|
||||
uwsgi_error("uwsgi_register_fsmon()/inotify_add_watch()");
|
||||
uwsgi_error("fsmon_add()/inotify_add_watch()");
|
||||
return -1;
|
||||
}
|
||||
usl->custom = inotify_fd;
|
||||
usl->custom2 = wd;
|
||||
fs->fd = inotify_fd;
|
||||
fs->id = wd;
|
||||
return 0;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef UWSGI_EVENT_FILEMONITOR_USE_KQUEUE
|
||||
struct kevent kev;
|
||||
int fd = open(usl->value, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
uwsgi_error_open(usl->value);
|
||||
uwsgi_error("uwsgi_register_fsmon()/open()");
|
||||
return -1;
|
||||
}
|
||||
struct kevent kev;
|
||||
int fd = open(fs->path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
uwsgi_error_open(fs->path);
|
||||
uwsgi_error("fsmon_add()/open()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE | NOTE_DELETE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE, 0, 0);
|
||||
if (kevent(uwsgi.master_queue, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("uwsgi_register_fsmon()/kevent()");
|
||||
return -1;
|
||||
}
|
||||
usl->custom = fd;
|
||||
usl->custom2 = fd;
|
||||
EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE | NOTE_DELETE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE, 0, 0);
|
||||
if (kevent(uwsgi.master_queue, &kev, 1, NULL, 0, NULL) < 0) {
|
||||
uwsgi_error("fsmon_add()/kevent()");
|
||||
return -1;
|
||||
}
|
||||
fs->fd = fd;
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
uwsgi_log("[uwsgi-fsmon] filesystem monitoring interface not available in this platform !!!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct uwsgi_string_list *uwsgi_fsmon_ack(int interesting_fd) {
|
||||
int found_fd = -1;
|
||||
struct uwsgi_string_list *usl = uwsgi.fs_reload;
|
||||
while(usl) {
|
||||
if ((int)usl->custom == interesting_fd) {
|
||||
found_fd = usl->custom;
|
||||
goto found;
|
||||
}
|
||||
usl = usl->next;
|
||||
static void fsmon_reload(struct uwsgi_fsmon *fs) {
|
||||
uwsgi_block_signal(SIGHUP);
|
||||
grace_them_all(0);
|
||||
uwsgi_unblock_signal(SIGHUP);
|
||||
}
|
||||
|
||||
static void fsmon_brutal_reload(struct uwsgi_fsmon *fs) {
|
||||
if (uwsgi.die_on_term) {
|
||||
uwsgi_block_signal(SIGQUIT);
|
||||
reap_them_all(0);
|
||||
uwsgi_unblock_signal(SIGQUIT);
|
||||
}
|
||||
usl = uwsgi.fs_brutal_reload;
|
||||
while(usl) {
|
||||
if ((int)usl->custom == interesting_fd) {
|
||||
found_fd = usl->custom;
|
||||
goto found;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
usl = uwsgi.fs_signal;
|
||||
while(usl) {
|
||||
if ((int)usl->custom == interesting_fd) {
|
||||
found_fd = usl->custom;
|
||||
goto found;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
found:
|
||||
if (found_fd == -1) return NULL;
|
||||
else {
|
||||
uwsgi_block_signal(SIGTERM);
|
||||
reap_them_all(0);
|
||||
uwsgi_unblock_signal(SIGTERM);
|
||||
}
|
||||
}
|
||||
|
||||
static void fsmon_signal(struct uwsgi_fsmon *fs) {
|
||||
uwsgi_route_signal(atoi((char *) fs->data));
|
||||
}
|
||||
|
||||
void uwsgi_fsmon_setup() {
|
||||
struct uwsgi_string_list *usl = NULL;
|
||||
uwsgi_foreach(usl, uwsgi.fs_reload) {
|
||||
uwsgi_register_fsmon(usl->value, fsmon_reload, NULL);
|
||||
}
|
||||
uwsgi_foreach(usl, uwsgi.fs_brutal_reload) {
|
||||
uwsgi_register_fsmon(usl->value, fsmon_brutal_reload, NULL);
|
||||
}
|
||||
uwsgi_foreach(usl, uwsgi.fs_signal) {
|
||||
char *copy = uwsgi_str(usl->value);
|
||||
char *space = strchr(copy, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("[uwsgi-fsmon] invalid syntax: \"%s\"\n", usl->value);
|
||||
free(copy);
|
||||
continue;
|
||||
}
|
||||
*space = 0;
|
||||
uwsgi_register_fsmon(copy, fsmon_signal, space + 1);
|
||||
}
|
||||
|
||||
struct uwsgi_fsmon *fs = uwsgi.fsmon;
|
||||
while (fs) {
|
||||
if (fsmon_add(fs)) {
|
||||
uwsgi_log("[uwsgi-fsmon] unable to register monitor for \"%s\"\n", fs->path);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[uwsgi-fsmon] registered monitor for \"%s\"\n", fs->path);
|
||||
}
|
||||
fs = fs->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_fsmon *uwsgi_register_fsmon(char *path, void (*func) (struct uwsgi_fsmon *), void *data) {
|
||||
struct uwsgi_fsmon *old_fs = NULL, *fs = uwsgi.fsmon;
|
||||
while(fs) {
|
||||
old_fs = fs;
|
||||
fs = fs->next;
|
||||
}
|
||||
|
||||
fs = uwsgi_calloc(sizeof(struct uwsgi_fsmon));
|
||||
fs->path = path;
|
||||
fs->func = func;
|
||||
fs->data = data;
|
||||
|
||||
if (old_fs) {
|
||||
old_fs->next = fs;
|
||||
}
|
||||
else {
|
||||
uwsgi.fsmon = fs;
|
||||
}
|
||||
|
||||
return fs;
|
||||
}
|
||||
|
||||
static struct uwsgi_fsmon *uwsgi_fsmon_ack(int interesting_fd) {
|
||||
struct uwsgi_fsmon *found_fs = NULL;
|
||||
struct uwsgi_fsmon *fs = uwsgi.fsmon;
|
||||
while (fs) {
|
||||
if (fs->fd == interesting_fd) {
|
||||
found_fs = fs;
|
||||
break;
|
||||
}
|
||||
fs = fs->next;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_EVENT_FILEMONITOR_USE_INOTIFY
|
||||
#ifndef OBSOLETE_LINUX_KERNEL
|
||||
if (!found_fs)
|
||||
return NULL;
|
||||
found_fs = NULL;
|
||||
unsigned int isize = 0;
|
||||
if (ioctl(found_fd, FIONREAD, &isize) < 0) {
|
||||
uwsgi_error("uwsgi_fsmon_ack()/ioctl()");
|
||||
return 0;
|
||||
}
|
||||
if (isize == 0) return NULL;
|
||||
if (ioctl(interesting_fd, FIONREAD, &isize) < 0) {
|
||||
uwsgi_error("uwsgi_fsmon_ack()/ioctl()");
|
||||
return NULL;
|
||||
}
|
||||
if (isize == 0)
|
||||
return NULL;
|
||||
struct inotify_event *ie = uwsgi_malloc(isize);
|
||||
// read from the inotify descriptor
|
||||
ssize_t len = read(found_fd, ie, isize);
|
||||
if (len < 0) { free(ie); uwsgi_error("uwsgi_fsmon_ack()/read()"); return NULL;}
|
||||
found_fd = ie->wd;
|
||||
ssize_t len = read(interesting_fd, ie, isize);
|
||||
if (len < 0) {
|
||||
free(ie);
|
||||
uwsgi_error("uwsgi_fsmon_ack()/read()");
|
||||
return NULL;
|
||||
}
|
||||
fs = uwsgi.fsmon;
|
||||
while (fs) {
|
||||
if (fs->fd == interesting_fd && fs->id == ie->wd) {
|
||||
found_fs = fs;
|
||||
break;
|
||||
}
|
||||
fs = fs->next;
|
||||
}
|
||||
free(ie);
|
||||
#endif
|
||||
#endif
|
||||
// search for the item id and print it
|
||||
usl = uwsgi.fs_reload;
|
||||
while(usl) {
|
||||
if ((int)usl->custom2 == found_fd) {
|
||||
uwsgi_log("[uwsgi-fsmon] \"%s\" has been modified\n", usl->value);
|
||||
return uwsgi.fs_reload;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
usl = uwsgi.fs_brutal_reload;
|
||||
while(usl) {
|
||||
if ((int)usl->custom2 == found_fd) {
|
||||
uwsgi_log("[uwsgi-fsmon] \"%s\" has been modified\n", usl->value);
|
||||
return uwsgi.fs_brutal_reload;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
usl = uwsgi.fs_signal;
|
||||
while(usl) {
|
||||
if ((int)usl->custom2 == found_fd) {
|
||||
uwsgi_log("[uwsgi-fsmon] \"%s\" has been modified\n", usl->value);
|
||||
return usl;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return found_fs;
|
||||
}
|
||||
|
||||
int uwsgi_fsmon_event(int interesting_fd) {
|
||||
|
||||
struct uwsgi_string_list *usl = uwsgi_fsmon_ack(interesting_fd);
|
||||
struct uwsgi_fsmon *fs = uwsgi_fsmon_ack(interesting_fd);
|
||||
if (!fs)
|
||||
return 0;
|
||||
|
||||
if (!usl) return 0;
|
||||
|
||||
if (usl == uwsgi.fs_reload) {
|
||||
uwsgi_block_signal(SIGHUP);
|
||||
grace_them_all(0);
|
||||
uwsgi_unblock_signal(SIGHUP);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (usl == uwsgi.fs_brutal_reload) {
|
||||
if (uwsgi.die_on_term) {
|
||||
uwsgi_block_signal(SIGQUIT);
|
||||
reap_them_all(0);
|
||||
uwsgi_unblock_signal(SIGQUIT);
|
||||
}
|
||||
else {
|
||||
uwsgi_block_signal(SIGTERM);
|
||||
reap_them_all(0);
|
||||
uwsgi_unblock_signal(SIGTERM);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// fallback to signal
|
||||
uwsgi_route_signal(atoi(usl->custom_ptr));
|
||||
uwsgi_log_verbose("[uwsgi-fsmon] detected event on \"%s\"\n", fs->path);
|
||||
fs->func(fs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -92,6 +92,8 @@ void gateway_respawn(int id) {
|
||||
signal(SIGSTOP, SIG_IGN);
|
||||
signal(SIGTSTP, SIG_IGN);
|
||||
|
||||
uwsgi_hooks_run(uwsgi.hook_as_gateway, "as-gateway", 1);
|
||||
|
||||
if (ug->gid) {
|
||||
uwsgi_log("%s %d setgid() to %d\n", ug->name, ug->num, (int) ug->gid);
|
||||
if (setgid(ug->gid)) {
|
||||
|
||||
+121
@@ -47,6 +47,18 @@ void uwsgi_register_hook(char *name, int (*func)(char *)) {
|
||||
}
|
||||
}
|
||||
|
||||
static int uwsgi_hook_alarm(char *arg) {
|
||||
char *space = strchr(arg,' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid alarm hook syntax, must be: <alarm> <msg>\n");
|
||||
return -1;
|
||||
}
|
||||
*space = 0;
|
||||
uwsgi_alarm_trigger(arg, space+1, strlen(space+1));
|
||||
*space = ' ';
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_hook_chdir(char *arg) {
|
||||
int ret = chdir(arg);
|
||||
if (ret) {
|
||||
@@ -154,6 +166,17 @@ static int uwsgi_hook_write(char *arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_hook_creat(char *arg) {
|
||||
int fd = open(arg, O_WRONLY|O_CREAT|O_TRUNC, 0666);
|
||||
if (fd < 0) {
|
||||
uwsgi_error_open(arg);
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_hook_append(char *arg) {
|
||||
char *space = strchr(arg, ' ');
|
||||
if (!space) {
|
||||
@@ -262,6 +285,20 @@ static int uwsgi_hook_chmod(char *arg) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int uwsgi_hook_sticky(char *arg) {
|
||||
struct stat st;
|
||||
if (stat(arg, &st)) {
|
||||
uwsgi_error("uwsgi_hook_sticky()/stat()");
|
||||
return -1;
|
||||
}
|
||||
if (chmod(arg, st.st_mode | S_ISVTX)) {
|
||||
uwsgi_error("uwsgi_hook_sticky()/chmod()");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_hook_chown(char *arg) {
|
||||
char *space = strchr(arg, ' ');
|
||||
if (!space) {
|
||||
@@ -342,6 +379,9 @@ static int uwsgi_hook_chown2(char *arg) {
|
||||
}
|
||||
|
||||
|
||||
#ifdef __sun__
|
||||
extern int sethostname(char *, int);
|
||||
#endif
|
||||
static int uwsgi_hook_hostname(char *arg) {
|
||||
#ifdef __CYGWIN__
|
||||
return -1;
|
||||
@@ -445,6 +485,60 @@ static int uwsgi_hook_callret(char *arg) {
|
||||
return func();
|
||||
}
|
||||
|
||||
static int uwsgi_hook_rpc(char *arg) {
|
||||
|
||||
int ret = -1;
|
||||
size_t i, argc = 0;
|
||||
char **rargv = uwsgi_split_quoted(arg, strlen(arg), " \t", &argc);
|
||||
if (!argc) goto end;
|
||||
if (argc > 256) goto destroy;
|
||||
|
||||
char *argv[256];
|
||||
uint16_t argvs[256];
|
||||
|
||||
char *node = NULL;
|
||||
char *func = rargv[0];
|
||||
|
||||
char *at = strchr(func, '@');
|
||||
if (at) {
|
||||
*at = 0;
|
||||
node = at + 1;
|
||||
}
|
||||
|
||||
for(i=0;i<(argc-1);i++) {
|
||||
size_t a_len = strlen(rargv[i+1]);
|
||||
if (a_len > 0xffff) goto destroy;
|
||||
argv[i] = rargv[i+1] ;
|
||||
argvs[i] = a_len;
|
||||
}
|
||||
|
||||
uint64_t size = 0;
|
||||
// response must be always freed
|
||||
char *response = uwsgi_do_rpc(node, func, argc-1, argv, argvs, &size);
|
||||
if (response) {
|
||||
if (at) *at = '@';
|
||||
uwsgi_log("[rpc result from \"%s\"] %.*s\n", rargv[0], size, response);
|
||||
free(response);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
destroy:
|
||||
for(i=0;i<argc;i++) {
|
||||
free(rargv[i]);
|
||||
}
|
||||
end:
|
||||
free(rargv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int uwsgi_hook_retryrpc(char *arg) {
|
||||
for(;;) {
|
||||
int ret = uwsgi_hook_rpc(arg);
|
||||
if (!ret) break;
|
||||
sleep(2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uwsgi_register_base_hooks() {
|
||||
uwsgi_register_hook("cd", uwsgi_hook_chdir);
|
||||
@@ -456,8 +550,13 @@ void uwsgi_register_base_hooks() {
|
||||
uwsgi_register_hook("chown", uwsgi_hook_chown);
|
||||
uwsgi_register_hook("chown2", uwsgi_hook_chown2);
|
||||
|
||||
uwsgi_register_hook("sticky", uwsgi_hook_sticky);
|
||||
|
||||
uwsgi_register_hook("exec", uwsgi_hook_exec);
|
||||
|
||||
uwsgi_register_hook("create", uwsgi_hook_creat);
|
||||
uwsgi_register_hook("creat", uwsgi_hook_creat);
|
||||
|
||||
uwsgi_register_hook("write", uwsgi_hook_write);
|
||||
uwsgi_register_hook("writen", uwsgi_hook_writen);
|
||||
uwsgi_register_hook("append", uwsgi_hook_append);
|
||||
@@ -476,9 +575,15 @@ void uwsgi_register_base_hooks() {
|
||||
|
||||
uwsgi_register_hook("hostname", uwsgi_hook_hostname);
|
||||
|
||||
uwsgi_register_hook("alarm", uwsgi_hook_alarm);
|
||||
|
||||
uwsgi_register_hook("rpc", uwsgi_hook_rpc);
|
||||
uwsgi_register_hook("retryrpc", uwsgi_hook_retryrpc);
|
||||
|
||||
// for testing
|
||||
uwsgi_register_hook("exit", uwsgi_hook_exit);
|
||||
uwsgi_register_hook("print", uwsgi_hook_print);
|
||||
uwsgi_register_hook("log", uwsgi_hook_print);
|
||||
}
|
||||
|
||||
void uwsgi_hooks_run(struct uwsgi_string_list *l, char *phase, int fatal) {
|
||||
@@ -513,6 +618,22 @@ void uwsgi_hooks_run(struct uwsgi_string_list *l, char *phase, int fatal) {
|
||||
|
||||
int ret = uh->func(colon+1);
|
||||
if (fatal && ret != 0) {
|
||||
uwsgi_log_verbose("FATAL hook failed, destroying instance\n");
|
||||
if (uwsgi.master_process) {
|
||||
if (uwsgi.workers) {
|
||||
if (uwsgi.workers[0].pid == getpid()) {
|
||||
kill_them_all(0);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (kill(uwsgi.workers[0].pid, SIGINT)) {
|
||||
uwsgi_error("uwsgi_hooks_run()/kill()");
|
||||
exit(1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -123,7 +123,7 @@ void uwsgi_init_default() {
|
||||
// a workers hould be running for at least 10 seconds
|
||||
uwsgi.min_worker_lifetime = 10;
|
||||
|
||||
uwsgi.shared->spooler_frequency = 30;
|
||||
uwsgi.spooler_frequency = 30;
|
||||
|
||||
uwsgi.shared->spooler_signal_pipe[0] = -1;
|
||||
uwsgi.shared->spooler_signal_pipe[1] = -1;
|
||||
@@ -183,6 +183,8 @@ void uwsgi_init_default() {
|
||||
|
||||
uwsgi.master_fifo_fd = -1;
|
||||
uwsgi_master_fifo_prepare();
|
||||
|
||||
uwsgi.notify_socket_fd = -1;
|
||||
}
|
||||
|
||||
void uwsgi_setup_reload() {
|
||||
|
||||
@@ -517,12 +517,28 @@ fallback:
|
||||
goto end;
|
||||
}
|
||||
|
||||
// is it a potential virtual file (/proc, /sys...) ?
|
||||
int is_virtual = 0;
|
||||
if (sb.st_size == 0) {
|
||||
is_virtual = 1;
|
||||
sb.st_size = 4096;
|
||||
}
|
||||
|
||||
buffer = uwsgi_malloc(sb.st_size + add_zero);
|
||||
|
||||
len = read(fd, buffer, sb.st_size);
|
||||
if (len != sb.st_size) {
|
||||
uwsgi_error("read()");
|
||||
exit(1);
|
||||
if (!is_virtual) {
|
||||
if (len != sb.st_size) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (len >= 0) {
|
||||
sb.st_size = len;
|
||||
}
|
||||
else {
|
||||
uwsgi_error("read()");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
@@ -535,7 +551,46 @@ fallback:
|
||||
end:
|
||||
|
||||
if (magic_table) {
|
||||
|
||||
// here we inject blobs
|
||||
struct uwsgi_string_list *usl = NULL;
|
||||
if (uwsgi.inject_before || uwsgi.inject_after) {
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
|
||||
uwsgi_foreach(usl, uwsgi.inject_before) {
|
||||
size_t rlen = 0;
|
||||
char *before = uwsgi_open_and_read(usl->value, &rlen, 0, NULL);
|
||||
if (uwsgi_buffer_append(ub, before, rlen)) {
|
||||
uwsgi_log("unable to inject data in the config file\n");
|
||||
exit(1);
|
||||
}
|
||||
free(before);
|
||||
}
|
||||
if (uwsgi_buffer_append(ub, buffer, *size - add_zero)) {
|
||||
uwsgi_log("unable to inject data in the config file\n");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_foreach(usl, uwsgi.inject_after) {
|
||||
size_t rlen = 0;
|
||||
char *after = uwsgi_open_and_read(usl->value, &rlen, 0, NULL);
|
||||
if (uwsgi_buffer_append(ub, after, rlen)) {
|
||||
uwsgi_log("unable to inject data in the config file\n");
|
||||
exit(1);
|
||||
}
|
||||
free(after);
|
||||
}
|
||||
if (add_zero) {
|
||||
if (uwsgi_buffer_append(ub, "\0", 1)) {
|
||||
uwsgi_log("unable to inject data in the config file\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
*size = ub->pos;
|
||||
// free resources
|
||||
free(buffer);
|
||||
buffer = ub->buf;
|
||||
// aboid destroying buffer
|
||||
ub->buf = NULL;
|
||||
uwsgi_buffer_destroy(ub);
|
||||
}
|
||||
magic_buf = magic_sub(buffer, *size, size, magic_table);
|
||||
free(buffer);
|
||||
return magic_buf;
|
||||
@@ -912,6 +967,7 @@ int uwsgi_read_nb(int fd, char *buf, size_t remains, int timeout) {
|
||||
ssize_t uwsgi_read_true_nb(int fd, char *buf, size_t len, int timeout) {
|
||||
int ret;
|
||||
|
||||
errno = 0;
|
||||
ssize_t rlen = read(fd, buf, len);
|
||||
if (rlen > 0) {
|
||||
return rlen;
|
||||
@@ -922,8 +978,10 @@ ssize_t uwsgi_read_true_nb(int fd, char *buf, size_t len, int timeout) {
|
||||
}
|
||||
return -1;
|
||||
wait:
|
||||
errno = 0;
|
||||
ret = uwsgi.wait_read_hook(fd, timeout);
|
||||
if (ret > 0) {
|
||||
errno = 0;
|
||||
rlen = read(fd, buf, len);
|
||||
if (rlen > 0) {
|
||||
return rlen;
|
||||
|
||||
+118
-1
@@ -4,7 +4,124 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#ifdef UWSGI_JSON_YAJL
|
||||
#if defined(UWSGI_JSON_YAJL_OLD)
|
||||
#include <yajl/yajl_parse.h>
|
||||
|
||||
struct uwsgi_yajl_old_state {
|
||||
char *object;
|
||||
char *key;
|
||||
int in_object;
|
||||
int is_array;
|
||||
};
|
||||
|
||||
static int uwsgi_yajl_cb_null(void *ctx) {
|
||||
struct uwsgi_yajl_old_state *uyos = (struct uwsgi_yajl_old_state *) ctx;
|
||||
if (!uyos->key) return 1;
|
||||
add_exported_option(uyos->key, strdup("0"), 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int uwsgi_yajl_cb_boolean(void *ctx, int b) {
|
||||
struct uwsgi_yajl_old_state *uyos = (struct uwsgi_yajl_old_state *) ctx;
|
||||
if (!uyos->key) return 1;
|
||||
if (b) {
|
||||
add_exported_option(uyos->key, strdup("1"), 0);
|
||||
}
|
||||
else {
|
||||
add_exported_option(uyos->key, strdup("0"), 0);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int uwsgi_yajl_cb_integer(void *ctx, long n) {
|
||||
struct uwsgi_yajl_old_state *uyos = (struct uwsgi_yajl_old_state *) ctx;
|
||||
if (!uyos->key) return 1;
|
||||
add_exported_option(uyos->key, uwsgi_64bit2str((int64_t) n), 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int uwsgi_yajl_cb_double(void *ctx, double n) {
|
||||
return uwsgi_yajl_cb_integer(ctx, (long) n);
|
||||
}
|
||||
|
||||
static int uwsgi_yajl_cb_string(void *ctx, const unsigned char *s, unsigned int s_len) {
|
||||
struct uwsgi_yajl_old_state *uyos = (struct uwsgi_yajl_old_state *) ctx;
|
||||
if (!uyos->key) return 1;
|
||||
add_exported_option(uyos->key, uwsgi_concat2n((char *)s, (size_t)s_len, "", 0), 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int uwsgi_yajl_cb_number(void *ctx, const char *n, unsigned int n_len) {
|
||||
return uwsgi_yajl_cb_string(ctx, (const unsigned char *)n, n_len);
|
||||
}
|
||||
|
||||
static int uwsgi_yajl_cb_map_key(void *ctx, const unsigned char *s, unsigned int s_len) {
|
||||
struct uwsgi_yajl_old_state *uyos = (struct uwsgi_yajl_old_state *) ctx;
|
||||
if (!uyos->in_object) {
|
||||
if (!uwsgi_strncmp(uyos->object, strlen(uyos->object), (char *)s, (size_t)s_len)) {
|
||||
uyos->in_object = 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
uyos->key = uwsgi_concat2n((char *)s, (size_t)s_len, "", 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static yajl_callbacks callbacks = {
|
||||
.yajl_null = uwsgi_yajl_cb_null,
|
||||
.yajl_boolean = uwsgi_yajl_cb_boolean,
|
||||
.yajl_integer = uwsgi_yajl_cb_integer,
|
||||
.yajl_double = uwsgi_yajl_cb_double,
|
||||
.yajl_number = uwsgi_yajl_cb_number,
|
||||
.yajl_string = uwsgi_yajl_cb_string,
|
||||
.yajl_start_map = NULL,
|
||||
.yajl_map_key = uwsgi_yajl_cb_map_key,
|
||||
.yajl_end_map = NULL,
|
||||
.yajl_start_array = NULL,
|
||||
.yajl_end_array = NULL,
|
||||
};
|
||||
|
||||
void uwsgi_json_config(char *file, char *magic_table[]) {
|
||||
size_t len = 0;
|
||||
|
||||
char *object_asked = "uwsgi";
|
||||
char *colon;
|
||||
|
||||
if (uwsgi_check_scheme(file)) {
|
||||
colon = uwsgi_get_last_char(file, '/');
|
||||
colon = uwsgi_get_last_char(colon, ':');
|
||||
}
|
||||
else {
|
||||
colon = uwsgi_get_last_char(file, ':');
|
||||
}
|
||||
|
||||
if (colon) {
|
||||
colon[0] = 0;
|
||||
if (colon[1] != 0) {
|
||||
object_asked = colon + 1;
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_yajl_old_state uyos;
|
||||
memset(&uyos, 0, sizeof(struct uwsgi_yajl_old_state));
|
||||
uyos.object = object_asked;
|
||||
uwsgi_log_initial("[uWSGI] getting JSON configuration from %s\n", file);
|
||||
|
||||
char *json_data = uwsgi_open_and_read(file, &len, 1, magic_table);
|
||||
|
||||
yajl_handle hand = yajl_alloc(&callbacks, NULL, NULL, &uyos);
|
||||
|
||||
yajl_status s = yajl_parse(hand, (const unsigned char *)json_data, len);
|
||||
if (s != yajl_status_ok) {
|
||||
uwsgi_log("%s\n", yajl_get_error(hand, 1, (const unsigned char *)json_data, len));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#elif defined(UWSGI_JSON_YAJL)
|
||||
#include <yajl/yajl_tree.h>
|
||||
|
||||
void uwsgi_json_config(char *file, char *magic_table[]) {
|
||||
|
||||
+57
-10
@@ -279,9 +279,12 @@ static void legions_check_nodes_step2() {
|
||||
// go on if i am not an arbiter
|
||||
else if (ul->valor > 0) {
|
||||
// no potential Lord is available, i will propose myself
|
||||
best_valor = ul->valor;
|
||||
memcpy(best_uuid, ul->uuid, 36);
|
||||
i_am_the_best = 1;
|
||||
// but only if i am not suspended...
|
||||
if (uwsgi_now() > ul->suspended_til) {
|
||||
best_valor = ul->valor;
|
||||
memcpy(best_uuid, ul->uuid, 36);
|
||||
i_am_the_best = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// empty lord
|
||||
@@ -337,13 +340,20 @@ static void legions_check_nodes_step2() {
|
||||
}
|
||||
if (i_am_the_best) {
|
||||
if (!ul->i_am_the_lord) {
|
||||
uwsgi_log("[uwsgi-legion] i am now the Lord of the Legion %s\n", ul->legion);
|
||||
// triggering lord hooks
|
||||
uwsgi_log("[uwsgi-legion] attempting to become the Lord of the Legion %s\n", ul->legion);
|
||||
struct uwsgi_string_list *usl = ul->lord_hooks;
|
||||
while (usl) {
|
||||
int ret = uwsgi_legion_action_call("lord", ul, usl);
|
||||
if (ret) {
|
||||
uwsgi_log("[uwsgi-legion] ERROR, lord hook returned: %d\n", ret);
|
||||
if (uwsgi.legion_death_on_lord_error) {
|
||||
ul->dead = 1;
|
||||
uwsgi_legion_announce(ul);
|
||||
ul->suspended_til = uwsgi_now() + uwsgi.legion_death_on_lord_error;
|
||||
uwsgi_log("[uwsgi-legion] suspending myself from Legion \"%s\" for %d seconds\n", ul->legion, uwsgi.legion_death_on_lord_error);
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
@@ -356,6 +366,7 @@ static void legions_check_nodes_step2() {
|
||||
else {
|
||||
ul->lord_scroll_len = 0;
|
||||
}
|
||||
uwsgi_log("[uwsgi-legion] i am now the Lord of the Legion %s\n", ul->legion);
|
||||
ul->i_am_the_lord = uwsgi_now();
|
||||
// trick: reduce the time needed by the old lord to unlord itself
|
||||
uwsgi_legion_announce(ul);
|
||||
@@ -400,7 +411,7 @@ static void legions_check_nodes_step2() {
|
||||
}
|
||||
ul->last_warning = uwsgi_now();
|
||||
}
|
||||
|
||||
next:
|
||||
ul = ul->next;
|
||||
}
|
||||
}
|
||||
@@ -496,8 +507,15 @@ static void *legion_loop(void *foobar) {
|
||||
last_round = now;
|
||||
// wait for event
|
||||
int interesting_fd = -1;
|
||||
if (uwsgi_instance_is_reloading || uwsgi_instance_is_dying) return NULL;
|
||||
int rlen = event_queue_wait(uwsgi.legion_queue, timeout, &interesting_fd);
|
||||
|
||||
if (rlen < 0 && errno != EINTR) {
|
||||
if (uwsgi_instance_is_reloading || uwsgi_instance_is_dying) return NULL;
|
||||
uwsgi_nuclear_blast();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
now = uwsgi_now();
|
||||
if (timeout == 0 || rlen == 0 || (now - last_round) >= timeout) {
|
||||
struct uwsgi_legion *legions = uwsgi.legions;
|
||||
@@ -591,6 +609,8 @@ static void *legion_loop(void *foobar) {
|
||||
// check if the node is already accounted
|
||||
struct uwsgi_legion_node *node = uwsgi_legion_get_node(ul, legion_msg.valor, legion_msg.name, legion_msg.name_len, legion_msg.uuid);
|
||||
if (!node) {
|
||||
// if a lord hook election fails, a node can announce itself as dead for long time...
|
||||
if (legion_msg.dead) continue;
|
||||
// add the new node
|
||||
uwsgi_wlock(ul->lock);
|
||||
node = uwsgi_legion_add_node(ul, legion_msg.valor, legion_msg.name, legion_msg.name_len, legion_msg.uuid);
|
||||
@@ -648,7 +668,12 @@ int uwsgi_legion_action_call(char *phase, struct uwsgi_legion *ul, struct uwsgi_
|
||||
return -1;
|
||||
}
|
||||
|
||||
uwsgi_log("[uwsgi-legion] (phase: %s legion: %s) calling %s\n", phase, ul->legion, usl->value);
|
||||
if (ula->log_msg) {
|
||||
uwsgi_log("[uwsgi-legion] (phase: %s legion: %s) %s\n", phase, ul->legion, ula->log_msg);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[uwsgi-legion] (phase: %s legion: %s) calling %s\n", phase, ul->legion, usl->value);
|
||||
}
|
||||
return ula->func(ul, usl->value + usl->custom);
|
||||
}
|
||||
|
||||
@@ -667,6 +692,18 @@ static int legion_action_log(struct uwsgi_legion *ul, char *arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int legion_action_alarm(struct uwsgi_legion *ul, char *arg) {
|
||||
char *space = strchr(arg,' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid alarm action syntax, must be: <alarm> <msg>\n");
|
||||
return -1;
|
||||
}
|
||||
*space = 0;
|
||||
uwsgi_alarm_trigger(arg, space+1, strlen(space+1));
|
||||
*space = ' ';
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uwsgi_start_legions() {
|
||||
pthread_t legion_loop_t;
|
||||
|
||||
@@ -675,8 +712,10 @@ void uwsgi_start_legions() {
|
||||
|
||||
// register embedded actions
|
||||
uwsgi_legion_action_register("cmd", legion_action_cmd);
|
||||
uwsgi_legion_action_register("exec", legion_action_cmd);
|
||||
uwsgi_legion_action_register("signal", legion_action_signal);
|
||||
uwsgi_legion_action_register("log", legion_action_log);
|
||||
uwsgi_legion_action_register("alarm", legion_action_alarm);
|
||||
|
||||
uwsgi.legion_queue = event_queue_init();
|
||||
struct uwsgi_legion *legion = uwsgi.legions;
|
||||
@@ -736,6 +775,11 @@ void uwsgi_legion_add(struct uwsgi_legion *ul) {
|
||||
}
|
||||
|
||||
int uwsgi_legion_announce(struct uwsgi_legion *ul) {
|
||||
time_t now = uwsgi_now();
|
||||
|
||||
if (now <= ul->suspended_til) return 0;
|
||||
ul->suspended_til = 0;
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(4096);
|
||||
unsigned char *encrypted = NULL;
|
||||
|
||||
@@ -743,7 +787,7 @@ int uwsgi_legion_announce(struct uwsgi_legion *ul) {
|
||||
goto err;
|
||||
if (uwsgi_buffer_append_keynum(ub, "valor", 5, ul->valor))
|
||||
goto err;
|
||||
if (uwsgi_buffer_append_keynum(ub, "unix", 4, uwsgi_now()))
|
||||
if (uwsgi_buffer_append_keynum(ub, "unix", 4, now))
|
||||
goto err;
|
||||
if (uwsgi_buffer_append_keynum(ub, "lord", 4, ul->i_am_the_lord ? ul->i_am_the_lord : 0))
|
||||
goto err;
|
||||
@@ -1115,10 +1159,11 @@ struct uwsgi_legion_action *uwsgi_legion_action_get(char *name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void uwsgi_legion_action_register(char *name, int (*func) (struct uwsgi_legion *, char *)) {
|
||||
if (uwsgi_legion_action_get(name)) {
|
||||
struct uwsgi_legion_action *uwsgi_legion_action_register(char *name, int (*func) (struct uwsgi_legion *, char *)) {
|
||||
struct uwsgi_legion_action *found_ula = uwsgi_legion_action_get(name);
|
||||
if (found_ula) {
|
||||
uwsgi_log("[uwsgi-legion] action \"%s\" is already registered !!!\n", name);
|
||||
return;
|
||||
return found_ula;
|
||||
}
|
||||
|
||||
struct uwsgi_legion_action *old_ula = NULL, *ula = uwsgi.legion_actions;
|
||||
@@ -1137,6 +1182,8 @@ void uwsgi_legion_action_register(char *name, int (*func) (struct uwsgi_legion *
|
||||
else {
|
||||
uwsgi.legion_actions = ula;
|
||||
}
|
||||
|
||||
return ula;
|
||||
}
|
||||
|
||||
void uwsgi_legion_announce_death(void) {
|
||||
|
||||
+10
-4
@@ -477,13 +477,19 @@ void uwsgi_check_logrotate(void) {
|
||||
|
||||
int need_rotation = 0;
|
||||
int need_reopen = 0;
|
||||
off_t logsize;
|
||||
|
||||
if (uwsgi.log_master) {
|
||||
uwsgi.shared->logsize = lseek(uwsgi.original_log_fd, 0, SEEK_CUR);
|
||||
logsize = lseek(uwsgi.original_log_fd, 0, SEEK_CUR);
|
||||
}
|
||||
else {
|
||||
uwsgi.shared->logsize = lseek(2, 0, SEEK_CUR);
|
||||
logsize = lseek(2, 0, SEEK_CUR);
|
||||
}
|
||||
if (logsize < 0) {
|
||||
uwsgi_error("uwsgi_check_logrotate()/lseek()");
|
||||
return;
|
||||
}
|
||||
uwsgi.shared->logsize = logsize;
|
||||
|
||||
if (uwsgi.log_maxsize > 0 && (uint64_t) uwsgi.shared->logsize > uwsgi.log_maxsize) {
|
||||
need_rotation = 1;
|
||||
@@ -917,7 +923,7 @@ struct uwsgi_logger *uwsgi_get_logger_from_id(char *id) {
|
||||
struct uwsgi_logger *ul = uwsgi.choosen_logger;
|
||||
|
||||
while (ul) {
|
||||
if (!strcmp(ul->id, id)) {
|
||||
if (ul->id && !strcmp(ul->id, id)) {
|
||||
return ul;
|
||||
}
|
||||
ul = ul->next;
|
||||
@@ -1116,7 +1122,7 @@ static ssize_t uwsgi_lf_ltime(struct wsgi_request * wsgi_req, char **buf) {
|
||||
}
|
||||
|
||||
static ssize_t uwsgi_lf_ftime(struct wsgi_request * wsgi_req, char **buf) {
|
||||
if (!uwsgi.log_strftime) {
|
||||
if (!uwsgi.logformat_strftime || !uwsgi.log_strftime) {
|
||||
return uwsgi_lf_ltime(wsgi_req, buf);
|
||||
}
|
||||
*buf = uwsgi_malloc(64);
|
||||
|
||||
+35
-1
@@ -242,6 +242,17 @@ static void master_check_listen_queue() {
|
||||
if (uwsgi_sock->queue > 0 && uwsgi_sock->queue >= uwsgi_sock->max_queue) {
|
||||
uwsgi_log_verbose("*** uWSGI listen queue of socket \"%s\" (fd: %d) full !!! (%llu/%llu) ***\n", uwsgi_sock->name, uwsgi_sock->fd, (unsigned long long) uwsgi_sock->queue, (unsigned long long) uwsgi_sock->max_queue);
|
||||
}
|
||||
|
||||
if (uwsgi.alarm_backlog) {
|
||||
char buf[1024];
|
||||
int ret = snprintf(buf, 1024, "listen queue of socket \"%s\" (fd: %d) full !!! (%llu/%llu)", uwsgi_sock->name, uwsgi_sock->fd, (unsigned long long) uwsgi_sock->queue, (unsigned long long) uwsgi_sock->max_queue);
|
||||
if (ret > 0 && ret < 1024) {
|
||||
struct uwsgi_string_list *usl = NULL;
|
||||
uwsgi_foreach(usl, uwsgi.alarm_backlog) {
|
||||
uwsgi_alarm_trigger(usl->value, buf, ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
@@ -323,6 +334,12 @@ int master_loop(char **argv, char **environ) {
|
||||
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.master_fifo_fd);
|
||||
}
|
||||
|
||||
if (uwsgi.notify_socket) {
|
||||
uwsgi.notify_socket_fd = bind_to_unix_dgram(uwsgi.notify_socket);
|
||||
uwsgi_log("notification socket enabled on %s (fd: %d)\n", uwsgi.notify_socket, uwsgi.notify_socket_fd);
|
||||
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.notify_socket_fd);
|
||||
}
|
||||
|
||||
if (uwsgi.spoolers) {
|
||||
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->spooler_signal_pipe[0]);
|
||||
}
|
||||
@@ -508,6 +525,16 @@ int master_loop(char **argv, char **environ) {
|
||||
}
|
||||
ud = ud->next;
|
||||
}
|
||||
// hook touches
|
||||
uwsgi_foreach(usl, uwsgi.hook_touch) {
|
||||
char *space = strchr(usl->value, ' ');
|
||||
if (space) {
|
||||
*space = 0;
|
||||
usl->len = strlen(usl->value);
|
||||
uwsgi_string_new_list((struct uwsgi_string_list **)&usl->custom_ptr, space+1);
|
||||
}
|
||||
}
|
||||
uwsgi_check_touches(uwsgi.hook_touch);
|
||||
|
||||
// fsmon
|
||||
uwsgi_fsmon_setup();
|
||||
@@ -555,6 +582,7 @@ int master_loop(char **argv, char **environ) {
|
||||
}
|
||||
|
||||
// here really starts the master loop
|
||||
uwsgi_hooks_run(uwsgi.hook_master_start, "master-start", 1);
|
||||
|
||||
for (;;) {
|
||||
//uwsgi_log("uwsgi.ready_to_reload %d %d\n", uwsgi.ready_to_reload, uwsgi.numproc);
|
||||
@@ -807,7 +835,7 @@ int master_loop(char **argv, char **environ) {
|
||||
touched = uwsgi_check_touches(ud->touch);
|
||||
if (touched) {
|
||||
uwsgi_log_verbose("*** %s has been touched... reloading daemon \"%s\" (pid: %d) !!! ***\n", touched, ud->command, (int) ud->pid);
|
||||
if (kill(ud->pid, ud->stop_signal)) {
|
||||
if (kill(-ud->pid, ud->stop_signal)) {
|
||||
uwsgi_error("[uwsgi-daemon/touch] kill()");
|
||||
}
|
||||
}
|
||||
@@ -815,6 +843,12 @@ int master_loop(char **argv, char **environ) {
|
||||
ud = ud->next;
|
||||
}
|
||||
|
||||
// hook touches
|
||||
touched = uwsgi_check_touches(uwsgi.hook_touch);
|
||||
if (touched) {
|
||||
uwsgi_hooks_run((struct uwsgi_string_list *) touched, "touch", 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// allows the KILL signal to be delivered;
|
||||
|
||||
@@ -22,6 +22,10 @@ int uwsgi_master_manage_events(int interesting_fd) {
|
||||
return uwsgi_master_fifo_manage(uwsgi.master_fifo_fd);
|
||||
}
|
||||
|
||||
if (uwsgi.notify_socket_fd > -1 && interesting_fd == uwsgi.notify_socket_fd) {
|
||||
return uwsgi_notify_socket_manage(interesting_fd);
|
||||
}
|
||||
|
||||
// stats server ?
|
||||
if (uwsgi.stats && uwsgi.stats_fd > -1) {
|
||||
if (interesting_fd == uwsgi.stats_fd) {
|
||||
|
||||
+35
-10
@@ -43,13 +43,6 @@ void uwsgi_destroy_processes() {
|
||||
|
||||
uwsgi_signal_spoolers(SIGKILL);
|
||||
|
||||
if (uwsgi.emperor_pid >= 0) {
|
||||
kill(uwsgi.emperor_pid, SIGKILL);
|
||||
waitpid(uwsgi.emperor_pid, &waitpid_status, 0);
|
||||
uwsgi_log("The Emperor has been buried (pid: %d)\n", (int) uwsgi.emperor_pid);
|
||||
}
|
||||
|
||||
|
||||
uwsgi_detach_daemons();
|
||||
|
||||
for (i = 0; i < ushared->gateways_cnt; i++) {
|
||||
@@ -68,6 +61,26 @@ void uwsgi_destroy_processes() {
|
||||
uwsgi_log("mule %d has been buried (pid: %d)\n", i, (int) uwsgi.mules[i].pid);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.emperor_pid > 0) {
|
||||
kill(uwsgi.emperor_pid, SIGINT);
|
||||
time_t timeout = uwsgi_now() + (uwsgi.reload_mercy ? uwsgi.reload_mercy : 3);
|
||||
// increase timeout for being more tolerant
|
||||
timeout+=2;
|
||||
int waitpid_status;
|
||||
while (uwsgi_now() < timeout) {
|
||||
pid_t diedpid = waitpid(uwsgi.emperor_pid, &waitpid_status, WNOHANG);
|
||||
if (diedpid == uwsgi.emperor_pid) {
|
||||
goto nomoremperor;
|
||||
}
|
||||
uwsgi_log("waiting for Emperor death...\n");
|
||||
sleep(1);
|
||||
}
|
||||
kill(uwsgi.emperor_pid, SIGKILL);
|
||||
waitpid(uwsgi.emperor_pid, &waitpid_status, 0);
|
||||
nomoremperor:
|
||||
uwsgi_log("The Emperor has been buried (pid: %d)\n", (int) uwsgi.emperor_pid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -399,14 +412,23 @@ void uwsgi_reload(char **argv) {
|
||||
uwsgi_log("fork()'ing uWSGI...\n");
|
||||
}
|
||||
|
||||
// ask for configuration (if needed)
|
||||
if (uwsgi.has_emperor && uwsgi.emperor_fd_config > -1) {
|
||||
char byte = 2;
|
||||
if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
|
||||
uwsgi_error("uwsgi_reload()/write()");
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_log("chdir() to %s\n", uwsgi.cwd);
|
||||
if (chdir(uwsgi.cwd)) {
|
||||
uwsgi_error("chdir()");
|
||||
uwsgi_error("uwsgi_reload()/chdir()");
|
||||
}
|
||||
|
||||
/* check fd table (a module can obviosly open some fd on initialization...) */
|
||||
uwsgi_log("closing all non-uwsgi socket fds > 2 (max_fd = %d)...\n", (int) uwsgi.max_fd);
|
||||
for (i = 3; i < (int) uwsgi.max_fd; i++) {
|
||||
if (uwsgi.close_on_exec2) fcntl(i, F_SETFD, 0);
|
||||
|
||||
if (uwsgi_fd_is_safe(i)) continue;
|
||||
|
||||
@@ -545,9 +567,10 @@ void uwsgi_fixup_fds(int wid, int muleid, struct uwsgi_gateway *ug) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (uwsgi.shared->spooler_signal_pipe[0] != -1)
|
||||
close(uwsgi.shared->spooler_signal_pipe[0]);
|
||||
if (uwsgi.i_am_a_spooler && uwsgi.i_am_a_spooler->pid != getpid()) {
|
||||
if (uwsgi.shared->spooler_signal_pipe[0] != -1)
|
||||
close(uwsgi.shared->spooler_signal_pipe[0]);
|
||||
if (uwsgi.shared->spooler_signal_pipe[1] != -1)
|
||||
close(uwsgi.shared->spooler_signal_pipe[1]);
|
||||
}
|
||||
@@ -587,6 +610,8 @@ void uwsgi_fixup_fds(int wid, int muleid, struct uwsgi_gateway *ug) {
|
||||
|
||||
if (uwsgi.master_fifo_fd > -1) close(uwsgi.master_fifo_fd);
|
||||
|
||||
if (uwsgi.notify_socket_fd > -1) close(uwsgi.notify_socket_fd);
|
||||
|
||||
#ifdef __linux__
|
||||
for(i=0;i<uwsgi.setns_fds_count;i++) {
|
||||
close(uwsgi.setns_fds[i]);
|
||||
|
||||
+2
-2
@@ -330,10 +330,10 @@ next:
|
||||
}
|
||||
|
||||
int ret = poll(mulepoll, count + farms_count, timeout);
|
||||
if (ret <= 0) {
|
||||
if (ret < 0) {
|
||||
uwsgi_error("poll");
|
||||
}
|
||||
else {
|
||||
else if (ret > 0 ) {
|
||||
if (mulepoll[0].revents & POLLIN) {
|
||||
len = read(uwsgi.mules[uwsgi.muleid - 1].queue_pipe[1], message, buffer_size);
|
||||
}
|
||||
|
||||
@@ -75,3 +75,39 @@ void uwsgi_systemd_init(char *systemd_socket) {
|
||||
uwsgi.notify_ready = uwsgi_systemd_notify_ready;
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_notify_socket_manage(int fd) {
|
||||
char buf[8192];
|
||||
ssize_t rlen = read(fd, buf, 8192);
|
||||
if (rlen < 0) {
|
||||
if (uwsgi_is_again()) return 0;
|
||||
uwsgi_error("uwsgi_notify_socket_manage()/read()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (rlen > 0) {
|
||||
uwsgi_log_verbose("[notify-socket] %.*s\n", rlen, buf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_notify_msg(char *dst, char *msg, size_t len) {
|
||||
static int notify_fd = -1;
|
||||
if (notify_fd < 0) {
|
||||
notify_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if (notify_fd < 0) {
|
||||
uwsgi_error("uwsgi_notify_msg()/socket()");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
struct sockaddr_un un_addr;
|
||||
memset(&un_addr, 0, sizeof(struct sockaddr_un));
|
||||
un_addr.sun_family = AF_UNIX;
|
||||
// use 102 as the magic number
|
||||
strncat(un_addr.sun_path, dst, 102);
|
||||
if (sendto(notify_fd, msg, len, 0, (struct sockaddr *) &un_addr, sizeof(un_addr)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -237,6 +237,7 @@ static void uwsgi_offload_loop(struct uwsgi_thread *ut) {
|
||||
void *events = event_queue_alloc(uwsgi.offload_threads_events);
|
||||
|
||||
for (;;) {
|
||||
// TODO make timeout tunable
|
||||
int nevents = event_queue_wait_multi(ut->queue, -1, events, uwsgi.offload_threads_events);
|
||||
for (i = 0; i < nevents; i++) {
|
||||
int interesting_fd = event_queue_interesting_fd(events, i);
|
||||
@@ -456,6 +457,13 @@ static int u_offload_transfer_do(struct uwsgi_thread *ut, struct uwsgi_offload_r
|
||||
// write event (or just connected)
|
||||
case 1:
|
||||
if (fd == uor->fd) {
|
||||
// maybe we want only a connection...
|
||||
if (uor->ubuf->pos == 0) {
|
||||
uor->status = 2;
|
||||
if (event_queue_add_fd_read(ut->queue, uor->s)) return -1;
|
||||
if (event_queue_fd_write_to_read(ut->queue, uor->fd)) return -1;
|
||||
return 0;
|
||||
}
|
||||
rlen = write(uor->fd, uor->ubuf->buf + uor->written, uor->ubuf->pos-uor->written);
|
||||
if (rlen > 0) {
|
||||
uor->written += rlen;
|
||||
|
||||
+40
-1
@@ -312,6 +312,7 @@ int uwsgi_apply_error_routes(struct wsgi_request *wsgi_req) {
|
||||
|
||||
int uwsgi_apply_response_routes(struct wsgi_request *wsgi_req) {
|
||||
|
||||
|
||||
if (!uwsgi.response_routes) return 0;
|
||||
if (wsgi_req->response_routes_applied) return 0;
|
||||
|
||||
@@ -942,6 +943,20 @@ static int uwsgi_router_clearheaders(struct uwsgi_route *ur, char *arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// disable headers
|
||||
static int uwsgi_router_disableheaders_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
wsgi_req->headers_sent = 1;
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
static int uwsgi_router_disableheaders(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_disableheaders_func;
|
||||
ur->data = arg;
|
||||
ur->data_len = strlen(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// signal route
|
||||
static int uwsgi_router_signal_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
|
||||
@@ -1144,6 +1159,26 @@ static int uwsgi_router_setscheme(struct uwsgi_route *ur, char *arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// setmodifiers
|
||||
static int uwsgi_router_setmodifier1_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
wsgi_req->uh->modifier1 = ur->custom;
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
static int uwsgi_router_setmodifier1(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_setmodifier1_func;
|
||||
ur->custom = atoi(arg);
|
||||
return 0;
|
||||
}
|
||||
static int uwsgi_router_setmodifier2_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
wsgi_req->uh->modifier2 = ur->custom;
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
static int uwsgi_router_setmodifier2(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_setmodifier2_func;
|
||||
ur->custom = atoi(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// setuser route
|
||||
static int uwsgi_router_setuser_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
@@ -1669,7 +1704,7 @@ static char *uwsgi_route_var_mime(struct wsgi_request *wsgi_req, char *key, uint
|
||||
char *var_value = uwsgi_get_var(wsgi_req, key, keylen, &var_vallen);
|
||||
if (var_value) {
|
||||
size_t mime_type_len = 0;
|
||||
char *ret = uwsgi_get_mime_type(key, keylen, &mime_type_len);
|
||||
ret = uwsgi_get_mime_type(var_value, var_vallen, &mime_type_len);
|
||||
if (ret) *vallen = mime_type_len;
|
||||
}
|
||||
return ret;
|
||||
@@ -1736,6 +1771,7 @@ void uwsgi_register_embedded_routers() {
|
||||
uwsgi_register_router("remheader", uwsgi_router_remheader);
|
||||
uwsgi_register_router("clearheaders", uwsgi_router_clearheaders);
|
||||
uwsgi_register_router("resetheaders", uwsgi_router_clearheaders);
|
||||
uwsgi_register_router("disableheaders", uwsgi_router_disableheaders);
|
||||
uwsgi_register_router("signal", uwsgi_router_signal);
|
||||
uwsgi_register_router("send", uwsgi_router_send);
|
||||
uwsgi_register_router("send-crnl", uwsgi_router_send_crnl);
|
||||
@@ -1753,6 +1789,9 @@ void uwsgi_register_embedded_routers() {
|
||||
uwsgi_register_router("setprocname", uwsgi_router_setprocname);
|
||||
uwsgi_register_router("alarm", uwsgi_router_alarm);
|
||||
|
||||
uwsgi_register_router("setmodifier1", uwsgi_router_setmodifier1);
|
||||
uwsgi_register_router("setmodifier2", uwsgi_router_setmodifier2);
|
||||
|
||||
uwsgi_register_router("+", uwsgi_router_simple_math_plus);
|
||||
uwsgi_register_router("-", uwsgi_router_simple_math_minus);
|
||||
uwsgi_register_router("*", uwsgi_router_simple_math_multiply);
|
||||
|
||||
+5
-1
@@ -104,8 +104,12 @@ char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t
|
||||
|
||||
if (node == NULL || !strcmp(node, "")) {
|
||||
// allocate the whole buffer
|
||||
if (!uwsgi.rpc_table) {
|
||||
uwsgi_log("local rpc subsystem is still not initialized !!!\n");
|
||||
return NULL;
|
||||
}
|
||||
*len = uwsgi_rpc(func, argc, argv, argvs, &buffer);
|
||||
if (*buffer)
|
||||
if (buffer)
|
||||
return buffer;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+12
-10
@@ -269,20 +269,22 @@ int uwsgi_remote_signal_send(char *addr, uint8_t sig) {
|
||||
uh.pktsize = 0;
|
||||
uh.modifier2 = sig;
|
||||
|
||||
int fd = uwsgi_connect(addr, uwsgi.socket_timeout, 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
int fd = uwsgi_connect(addr, 0, 1);
|
||||
if (fd < 0) return -1;
|
||||
|
||||
if (write(fd, (char *) &uh, 4) != 4) {
|
||||
uwsgi_error("uwsgi_remote_signal_send()");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
// wait for connection
|
||||
if (uwsgi.wait_write_hook(fd, uwsgi.socket_timeout) <= 0) goto end;
|
||||
|
||||
int ret = uwsgi_read_response(fd, &uh, uwsgi.socket_timeout, NULL);
|
||||
if (uwsgi_write_true_nb(fd, (char *) &uh, 4, uwsgi.socket_timeout)) goto end;
|
||||
|
||||
if (uwsgi_read_whole_true_nb(fd, (char *) &uh, 4, uwsgi.socket_timeout)) goto end;
|
||||
close(fd);
|
||||
return ret;
|
||||
|
||||
return uh.modifier2;
|
||||
|
||||
end:
|
||||
close(fd);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
+61
-90
@@ -76,18 +76,66 @@ char *uwsgi_getsockname(int fd) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int create_server_socket(int domain, int type) {
|
||||
int serverfd = socket(domain, type, 0);
|
||||
if (serverfd < 0) {
|
||||
uwsgi_error("socket()");
|
||||
uwsgi_nuclear_blast();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (uwsgi.close_on_exec2 && fcntl(serverfd, F_SETFD, FD_CLOEXEC) < 0)
|
||||
uwsgi_error("fcntl()");
|
||||
|
||||
if (domain != AF_UNIX) {
|
||||
int reuse = 1;
|
||||
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) {
|
||||
uwsgi_error("SO_REUSEADDR setsockopt()");
|
||||
uwsgi_nuclear_blast();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == SOCK_STREAM) {
|
||||
if (uwsgi.so_sndbuf) {
|
||||
socklen_t sndbuf = (socklen_t) uwsgi.so_sndbuf;
|
||||
if (setsockopt(serverfd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(socklen_t)) < 0) {
|
||||
uwsgi_error("SO_SNDBUF setsockopt()");
|
||||
uwsgi_nuclear_blast();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.so_rcvbuf) {
|
||||
socklen_t rcvbuf = (socklen_t) uwsgi.so_rcvbuf;
|
||||
if (setsockopt(serverfd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(socklen_t)) < 0) {
|
||||
uwsgi_error("SO_RCVBUF setsockopt()");
|
||||
uwsgi_nuclear_blast();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
long somaxconn = uwsgi_num_from_file("/proc/sys/net/core/somaxconn", 1);
|
||||
if (somaxconn > 0 && uwsgi.listen_queue > somaxconn) {
|
||||
uwsgi_log("Listen queue size is greater than the system max net.core.somaxconn (%li).\n", somaxconn);
|
||||
uwsgi_nuclear_blast();
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return serverfd;
|
||||
}
|
||||
|
||||
int bind_to_unix_dgram(char *socket_name) {
|
||||
|
||||
int serverfd;
|
||||
struct sockaddr_un *uws_addr;
|
||||
socklen_t len;
|
||||
|
||||
serverfd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if (serverfd < 0) {
|
||||
uwsgi_error("socket()");
|
||||
uwsgi_nuclear_blast();
|
||||
return -1;
|
||||
}
|
||||
serverfd = create_server_socket(AF_UNIX, SOCK_DGRAM);
|
||||
if (serverfd < 0) return -1;
|
||||
|
||||
if (unlink(socket_name) != 0 && errno != ENOENT) {
|
||||
uwsgi_error("error removing unix socket, unlink()");
|
||||
@@ -140,15 +188,11 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst
|
||||
}
|
||||
|
||||
memset(uws_addr, 0, sizeof(struct sockaddr_un));
|
||||
serverfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (serverfd < 0) {
|
||||
uwsgi_error("socket()");
|
||||
uwsgi_nuclear_blast();
|
||||
return -1;
|
||||
}
|
||||
serverfd = create_server_socket(AF_UNIX, SOCK_STREAM);
|
||||
if (serverfd < 0) return -1;
|
||||
if (abstract_socket == 0) {
|
||||
if (unlink(socket_name) != 0 && errno != ENOENT) {
|
||||
uwsgi_error("unlink()");
|
||||
uwsgi_error("error removing unix socket, unlink()");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,24 +200,6 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst
|
||||
uwsgi_log("setting abstract socket mode (warning: only Linux supports this)\n");
|
||||
}
|
||||
|
||||
if (uwsgi.so_sndbuf) {
|
||||
socklen_t sndbuf = (socklen_t) uwsgi.so_sndbuf;
|
||||
if (setsockopt(serverfd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(socklen_t)) < 0) {
|
||||
uwsgi_error("SO_SNDBUF setsockopt()");
|
||||
uwsgi_nuclear_blast();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.so_rcvbuf) {
|
||||
socklen_t rcvbuf = (socklen_t) uwsgi.so_rcvbuf;
|
||||
if (setsockopt(serverfd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(socklen_t)) < 0) {
|
||||
uwsgi_error("SO_RCVBUF setsockopt()");
|
||||
uwsgi_nuclear_blast();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
uws_addr->sun_family = AF_UNIX;
|
||||
if (socket_name[0] == '@') {
|
||||
memcpy(uws_addr->sun_path + abstract_socket, socket_name + 1, UMIN(strlen(socket_name + 1), 101));
|
||||
@@ -203,15 +229,6 @@ int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abst
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
long somaxconn = uwsgi_num_from_file("/proc/sys/net/core/somaxconn", 1);
|
||||
if (somaxconn > 0 && uwsgi.listen_queue > somaxconn) {
|
||||
uwsgi_log("Listen queue size is greater than the system max net.core.somaxconn (%li).\n", somaxconn);
|
||||
uwsgi_nuclear_blast();
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (listen(serverfd, listen_queue) != 0) {
|
||||
uwsgi_error("listen()");
|
||||
uwsgi_nuclear_blast();
|
||||
@@ -243,7 +260,6 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
|
||||
struct sockaddr_in uws_addr;
|
||||
char *udp_port;
|
||||
int bcast = 1;
|
||||
int reuse = 1;
|
||||
|
||||
struct ip_mreq mc;
|
||||
|
||||
@@ -288,15 +304,8 @@ int bind_to_udp(char *socket_name, int multicast, int broadcast) {
|
||||
}
|
||||
|
||||
|
||||
serverfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (serverfd < 0) {
|
||||
uwsgi_error("socket()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) {
|
||||
uwsgi_error("setsockopt()");
|
||||
}
|
||||
serverfd = create_server_socket(AF_INET, SOCK_DGRAM);
|
||||
if (serverfd < 0) return -1;
|
||||
|
||||
if (multicast) {
|
||||
// if multicast is enabled remember to bind to INADDR_ANY
|
||||
@@ -649,7 +658,6 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
|
||||
#else
|
||||
struct sockaddr_in uws_addr;
|
||||
#endif
|
||||
int reuse = 1;
|
||||
int family = AF_INET;
|
||||
socklen_t addr_len = sizeof(struct sockaddr_in);
|
||||
|
||||
@@ -667,37 +675,9 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
|
||||
#endif
|
||||
|
||||
|
||||
serverfd = socket(family, SOCK_STREAM, 0);
|
||||
if (serverfd < 0) {
|
||||
uwsgi_error("socket()");
|
||||
uwsgi_nuclear_blast();
|
||||
return -1;
|
||||
}
|
||||
serverfd = create_server_socket(family, SOCK_STREAM);
|
||||
if (serverfd < 0) return -1;
|
||||
|
||||
if (uwsgi.so_sndbuf) {
|
||||
socklen_t sndbuf = (socklen_t) uwsgi.so_sndbuf;
|
||||
if (setsockopt(serverfd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(socklen_t)) < 0) {
|
||||
uwsgi_error("SO_SNDBUF setsockopt()");
|
||||
uwsgi_nuclear_blast();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.so_rcvbuf) {
|
||||
socklen_t rcvbuf = (socklen_t) uwsgi.so_rcvbuf;
|
||||
if (setsockopt(serverfd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(socklen_t)) < 0) {
|
||||
uwsgi_error("SO_RCVBUF setsockopt()");
|
||||
uwsgi_nuclear_blast();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) {
|
||||
uwsgi_error("SO_REUSEADDR setsockopt()");
|
||||
uwsgi_nuclear_blast();
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
#ifndef IP_FREEBIND
|
||||
#define IP_FREEBIND 15
|
||||
@@ -781,15 +761,6 @@ int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
long somaxconn = uwsgi_num_from_file("/proc/sys/net/core/somaxconn", 1);
|
||||
if (somaxconn > 0 && uwsgi.listen_queue > somaxconn) {
|
||||
uwsgi_log("Listen queue size is greater than the system max net.core.somaxconn (%li).\n", somaxconn);
|
||||
uwsgi_nuclear_blast();
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (listen(serverfd, listen_queue) != 0) {
|
||||
uwsgi_error("listen()");
|
||||
uwsgi_nuclear_blast();
|
||||
|
||||
+113
-30
@@ -72,12 +72,12 @@ struct uwsgi_spooler *uwsgi_new_spooler(char *dir) {
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_spooler *uwsgi_get_spooler_by_name(char *name) {
|
||||
struct uwsgi_spooler *uwsgi_get_spooler_by_name(char *name, size_t name_len) {
|
||||
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
|
||||
while (uspool) {
|
||||
if (!strcmp(uspool->dir, name)) {
|
||||
if (!uwsgi_strncmp(uspool->dir, strlen(uspool->dir), name, name_len)) {
|
||||
return uspool;
|
||||
}
|
||||
uspool = uspool->next;
|
||||
@@ -167,47 +167,127 @@ void destroy_spool(char *dir, char *file) {
|
||||
|
||||
}
|
||||
|
||||
struct spooler_req {
|
||||
char *spooler;
|
||||
size_t spooler_len;
|
||||
char *priority;
|
||||
size_t priority_len;
|
||||
time_t at;
|
||||
};
|
||||
|
||||
int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core_id, char *buffer, int size, char *priority, time_t at, char *body, size_t body_len) {
|
||||
static void spooler_req_parser_hook(char *key, uint16_t key_len, char *value, uint16_t value_len, void *data) {
|
||||
struct spooler_req *sr = (struct spooler_req *) data;
|
||||
if (!uwsgi_strncmp(key, key_len, "spooler", 7)) {
|
||||
sr->spooler = value;
|
||||
sr->spooler_len = value_len;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp(key, key_len, "priority", 8)) {
|
||||
sr->priority = value;
|
||||
sr->priority_len = value_len;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!uwsgi_strncmp(key, key_len, "at", 2)) {
|
||||
// at can be a float...
|
||||
char *dot = memchr(value, '.', value_len);
|
||||
if (dot) {
|
||||
value_len = dot - value;
|
||||
}
|
||||
sr->at = uwsgi_str_num(value, value_len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
char *uwsgi_spool_request(struct wsgi_request *wsgi_req, char *buf, size_t len, char *body, size_t body_len) {
|
||||
|
||||
struct timeval tv;
|
||||
int fd;
|
||||
struct uwsgi_header uh;
|
||||
static uint64_t internal_counter = 0;
|
||||
int core_id = 0;
|
||||
int fd = -1;
|
||||
struct spooler_req sr;
|
||||
|
||||
if (len > 0xffff) {
|
||||
uwsgi_log("[uwsgi-spooler] args buffer is limited to 64k, use the 'body' for bigger values\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// parse the request buffer
|
||||
memset(&sr, 0, sizeof(struct spooler_req));
|
||||
uwsgi_hooked_parse(buf, len, spooler_req_parser_hook, &sr);
|
||||
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
if (!uspool) {
|
||||
uspool = uwsgi.spoolers;
|
||||
uwsgi_log("[uwsgi-spooler] no spooler available\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// if it is a number, get the spooler by id instead of by name
|
||||
if (sr.spooler && sr.spooler_len) {
|
||||
uspool = uwsgi_get_spooler_by_name(sr.spooler, sr.spooler_len);
|
||||
if (!uspool) {
|
||||
uwsgi_log("[uwsgi-spooler] unable to find spooler \"%.*s\"\n", sr.spooler_len, sr.spooler);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (wsgi_req) {
|
||||
core_id = wsgi_req->async_id;
|
||||
}
|
||||
|
||||
// this lock is for threads, the pid value in filename will avoid multiprocess races
|
||||
uwsgi_lock(uspool->lock);
|
||||
|
||||
// we increase it even if the request fails
|
||||
internal_counter++;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
if (priority) {
|
||||
if (snprintf(filename, 1024, "%s/%s", uspool->dir, priority) <= 0) {
|
||||
char *filename = NULL;
|
||||
size_t filename_len = 0;
|
||||
|
||||
if (sr.priority && sr.priority_len) {
|
||||
filename_len = strlen(uspool->dir) + sr.priority_len + strlen(uwsgi.hostname) + 256;
|
||||
filename = uwsgi_malloc(filename_len);
|
||||
int ret = snprintf(filename, filename_len, "%s/%.*s", uspool->dir, (int) sr.priority_len, sr.priority);
|
||||
if (ret <= 0 || ret >= (int) filename_len) {
|
||||
uwsgi_log("[uwsgi-spooler] error generating spooler filename\n");
|
||||
free(filename);
|
||||
uwsgi_unlock(uspool->lock);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
// no need to check for errors...
|
||||
(void) mkdir(filename, 0777);
|
||||
|
||||
if (snprintf(filename, 1024, "%s/%s/uwsgi_spoolfile_on_%s_%d_%d_%d_%llu_%llu", uspool->dir, priority, uwsgi.hostname, (int) getpid(), rn, core_id, (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec) <= 0) {
|
||||
ret = snprintf(filename, filename_len, "%s/%.*s/uwsgi_spoolfile_on_%s_%d_%llu_%d_%llu_%llu", uspool->dir, (int)sr.priority_len, sr.priority, uwsgi.hostname, (int) getpid(), (unsigned long long) internal_counter, core_id,
|
||||
(unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec);
|
||||
if (ret <= 0 || ret >=(int) filename_len) {
|
||||
uwsgi_log("[uwsgi-spooler] error generating spooler filename\n");
|
||||
free(filename);
|
||||
uwsgi_unlock(uspool->lock);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (snprintf(filename, 1024, "%s/uwsgi_spoolfile_on_%s_%d_%d_%d_%llu_%llu", uspool->dir, uwsgi.hostname, (int) getpid(), rn, core_id, (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec) <= 0) {
|
||||
filename_len = strlen(uspool->dir) + strlen(uwsgi.hostname) + 256;
|
||||
filename = uwsgi_malloc(filename_len);
|
||||
int ret = snprintf(filename, filename_len, "%s/uwsgi_spoolfile_on_%s_%d_%llu_%d_%llu_%llu", uspool->dir, uwsgi.hostname, (int) getpid(), (unsigned long long) internal_counter, core_id,
|
||||
(unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec);
|
||||
if (ret <= 0 || ret >= (int) filename_len) {
|
||||
uwsgi_log("[uwsgi-spooler] error generating spooler filename\n");
|
||||
free(filename);
|
||||
uwsgi_unlock(uspool->lock);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
fd = open(filename, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0) {
|
||||
uwsgi_error_open(filename);
|
||||
free(filename);
|
||||
uwsgi_unlock(uspool->lock);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// now lock the file, it will no be runnable, until the lock is not removed
|
||||
@@ -215,13 +295,15 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core
|
||||
// in such case the spooler will detect a zeroed file and will retry later
|
||||
if (uwsgi_fcntl_lock(fd)) {
|
||||
close(fd);
|
||||
free(filename);
|
||||
uwsgi_unlock(uspool->lock);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct uwsgi_header uh;
|
||||
uh.modifier1 = 17;
|
||||
uh.modifier2 = 0;
|
||||
uh.pktsize = (uint16_t) size;
|
||||
uh.pktsize = (uint16_t) len;
|
||||
#ifdef __BIG_ENDIAN__
|
||||
uh.pktsize = uwsgi_swap16(uh.pktsize);
|
||||
#endif
|
||||
@@ -231,7 +313,7 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core
|
||||
goto clear;
|
||||
}
|
||||
|
||||
if (write(fd, buffer, size) != size) {
|
||||
if (write(fd, buf, len) != (ssize_t) len) {
|
||||
uwsgi_log("[spooler] unable to write args for %s\n", filename);
|
||||
goto clear;
|
||||
}
|
||||
@@ -243,28 +325,28 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core
|
||||
}
|
||||
}
|
||||
|
||||
if (at > 0) {
|
||||
if (sr.at > 0) {
|
||||
#ifdef __UCLIBC__
|
||||
struct timespec ts[2];
|
||||
ts[0].tv_sec = at;
|
||||
ts[0].tv_sec = sr.at;
|
||||
ts[0].tv_nsec = 0;
|
||||
ts[1].tv_sec = at;
|
||||
ts[1].tv_sec = sr.at;
|
||||
ts[1].tv_nsec = 0;
|
||||
if (futimens(fd, ts)) {
|
||||
uwsgi_error("futimens()");
|
||||
uwsgi_error("uwsgi_spooler_request()/futimens()");
|
||||
}
|
||||
#else
|
||||
struct timeval tv[2];
|
||||
tv[0].tv_sec = at;
|
||||
tv[0].tv_sec = sr.at;
|
||||
tv[0].tv_usec = 0;
|
||||
tv[1].tv_sec = at;
|
||||
tv[1].tv_sec = sr.at;
|
||||
tv[1].tv_usec = 0;
|
||||
#ifdef __sun__
|
||||
if (futimesat(fd, NULL, tv)) {
|
||||
#else
|
||||
if (futimes(fd, tv)) {
|
||||
#endif
|
||||
uwsgi_error("futimes()");
|
||||
uwsgi_error("uwsgi_spooler_request()/futimes()");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -273,7 +355,7 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core
|
||||
close(fd);
|
||||
|
||||
if (!uwsgi.spooler_quiet)
|
||||
uwsgi_log("[spooler] written %lu bytes to file %s\n", (unsigned long) size + body_len + 4, filename);
|
||||
uwsgi_log("[spooler] written %lu bytes to file %s\n", (unsigned long) len + body_len + 4, filename);
|
||||
|
||||
// and here waiting threads can continue
|
||||
uwsgi_unlock(uspool->lock);
|
||||
@@ -293,18 +375,19 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core
|
||||
spoolers = spoolers->next;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return filename;
|
||||
|
||||
|
||||
clear:
|
||||
uwsgi_unlock(uspool->lock);
|
||||
uwsgi_error("write()");
|
||||
uwsgi_error("uwsgi_spool_request()/write()");
|
||||
if (unlink(filename)) {
|
||||
uwsgi_error("unlink()");
|
||||
uwsgi_error("uwsgi_spool_request()/unlink()");
|
||||
}
|
||||
free(filename);
|
||||
// unlock the file too
|
||||
close(fd);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -367,7 +450,7 @@ void spooler(struct uwsgi_spooler *uspool) {
|
||||
spooler_readdir(uspool, NULL);
|
||||
}
|
||||
|
||||
int timeout = uwsgi.shared->spooler_frequency;
|
||||
int timeout = uwsgi.shared->spooler_frequency ? uwsgi.shared->spooler_frequency : uwsgi.spooler_frequency;
|
||||
if (wakeup > 0) {
|
||||
timeout = 0;
|
||||
}
|
||||
|
||||
+116
-16
@@ -95,15 +95,38 @@ static int uwsgi_sni_cb(SSL *ssl, int *ad, void *arg) {
|
||||
const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
|
||||
if (!servername) return SSL_TLSEXT_ERR_NOACK;
|
||||
size_t servername_len = strlen(servername);
|
||||
// reduce DOS attempts
|
||||
int count = 5;
|
||||
|
||||
struct uwsgi_string_list *usl = uwsgi.sni;
|
||||
while(usl) {
|
||||
if (!uwsgi_strncmp(usl->value, usl->len, (char *)servername, servername_len)) {
|
||||
SSL_set_SSL_CTX(ssl, usl->custom_ptr);
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
while(count > 0) {
|
||||
struct uwsgi_string_list *usl = uwsgi.sni;
|
||||
while(usl) {
|
||||
if (!uwsgi_strncmp(usl->value, usl->len, (char *)servername, servername_len)) {
|
||||
SSL_set_SSL_CTX(ssl, (SSL_CTX *) usl->custom_ptr);
|
||||
// the following steps are taken from nginx
|
||||
SSL_set_verify(ssl, SSL_CTX_get_verify_mode((SSL_CTX *)usl->custom_ptr),
|
||||
SSL_CTX_get_verify_callback((SSL_CTX *)usl->custom_ptr));
|
||||
SSL_set_verify_depth(ssl, SSL_CTX_get_verify_depth((SSL_CTX *)usl->custom_ptr));
|
||||
#ifdef SSL_CTRL_CLEAR_OPTIONS
|
||||
SSL_clear_options(ssl, SSL_get_options(ssl) & ~SSL_CTX_get_options((SSL_CTX *)usl->custom_ptr));
|
||||
#endif
|
||||
SSL_set_options(ssl, SSL_CTX_get_options((SSL_CTX *)usl->custom_ptr));
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
if (!uwsgi.subscription_dotsplit) break;
|
||||
char *next = memchr(servername+1, '.', servername_len-1);
|
||||
if (next) {
|
||||
servername_len -= next - servername;
|
||||
servername = next;
|
||||
count--;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (uwsgi.subscription_dotsplit) goto end;
|
||||
|
||||
#ifdef UWSGI_PCRE
|
||||
struct uwsgi_regexp_list *url = uwsgi.sni_regexp;
|
||||
@@ -126,7 +149,7 @@ static int uwsgi_sni_cb(SSL *ssl, int *ad, void *arg) {
|
||||
if (uwsgi_file_exists(sni_dir_client_ca)) {
|
||||
client_ca = sni_dir_client_ca;
|
||||
}
|
||||
usl = uwsgi_ssl_add_sni_item(uwsgi_str((char *)servername), sni_dir_cert, sni_dir_key, uwsgi.sni_dir_ciphers, client_ca);
|
||||
struct uwsgi_string_list *usl = uwsgi_ssl_add_sni_item(uwsgi_str((char *)servername), sni_dir_cert, sni_dir_key, uwsgi.sni_dir_ciphers, client_ca);
|
||||
if (!usl) goto done;
|
||||
free(sni_dir_cert);
|
||||
free(sni_dir_key);
|
||||
@@ -139,13 +162,39 @@ done:
|
||||
free(sni_dir_key);
|
||||
free(sni_dir_client_ca);
|
||||
}
|
||||
|
||||
end:
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
#endif
|
||||
|
||||
char *uwsgi_write_pem_to_file(char *name, char *buf, size_t len, char *ext) {
|
||||
if (!uwsgi.ssl_tmp_dir) return NULL;
|
||||
char *filename = uwsgi_concat4(uwsgi.ssl_tmp_dir, "/", name, ext);
|
||||
int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR);
|
||||
if (fd < 0) {
|
||||
uwsgi_error_open(filename);
|
||||
free(filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (write(fd, buf, len) != (ssize_t) len) {
|
||||
uwsgi_log("unable to write pem data in file %s\n", filename);
|
||||
uwsgi_error("uwsgi_write_pem_to_file()/write()");
|
||||
free(filename);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return filename;
|
||||
}
|
||||
|
||||
SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ciphers, char *client_ca) {
|
||||
|
||||
int crt_need_free = 0;
|
||||
int key_need_free = 0;
|
||||
int client_ca_need_free = 0;
|
||||
|
||||
SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
|
||||
if (!ctx) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to initialize context \"%s\"\n", name);
|
||||
@@ -165,11 +214,27 @@ SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ci
|
||||
#ifdef SSL_MODE_RELEASE_BUFFERS
|
||||
SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
|
||||
#endif
|
||||
|
||||
/*
|
||||
we need to support both file-based certs and stream based
|
||||
as dealing with openssl memory bio for keys is really overkill,
|
||||
we store them in a tmp directory
|
||||
*/
|
||||
|
||||
if (uwsgi.ssl_tmp_dir && !uwsgi_starts_with(crt, strlen(crt), "-----BEGIN ", 11)) {
|
||||
crt = uwsgi_write_pem_to_file(name, crt, strlen(crt), ".crt");
|
||||
if (!crt) {
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
crt_need_free = 1;
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_certificate_chain_file(ctx, crt) <= 0) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to assign certificate %s for context \"%s\"\n", crt, name);
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
uwsgi_log("[uwsgi-ssl] unable to assign certificate %s for context \"%s\"\n", crt, name);
|
||||
SSL_CTX_free(ctx);
|
||||
if (crt_need_free) free(crt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// this part is based from stud
|
||||
@@ -178,26 +243,43 @@ SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ci
|
||||
DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
|
||||
BIO_free(bio);
|
||||
if (dh) {
|
||||
SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
|
||||
SSL_CTX_set_tmp_dh(ctx, dh);
|
||||
DH_free(dh);
|
||||
}
|
||||
}
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
|
||||
#ifndef OPENSSL_NO_ECDH
|
||||
#ifdef NID_X9_62_prime256v1
|
||||
EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||||
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
|
||||
EC_KEY_free(ecdh);
|
||||
EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||||
if (ecdh) {
|
||||
SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE);
|
||||
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
|
||||
EC_KEY_free(ecdh);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (crt_need_free) free(crt);
|
||||
|
||||
if (uwsgi.ssl_tmp_dir && !uwsgi_starts_with(key, strlen(key), "-----BEGIN ", 11)) {
|
||||
key = uwsgi_write_pem_to_file(name, key, strlen(key), ".key");
|
||||
if (!key) {
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
key_need_free = 1;
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) <= 0) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to assign key %s for context \"%s\"\n", key, name);
|
||||
SSL_CTX_free(ctx);
|
||||
if (key_need_free) free(key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (key_need_free) free(key);
|
||||
|
||||
// if ciphers are specified, prefer server ciphers
|
||||
if (ciphers && strlen(ciphers) > 0) {
|
||||
@@ -225,19 +307,37 @@ SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ci
|
||||
}
|
||||
// in the future we should allow to set the verify depth
|
||||
SSL_CTX_set_verify_depth(ctx, 1);
|
||||
|
||||
if (uwsgi.ssl_tmp_dir && !uwsgi_starts_with(client_ca, strlen(client_ca), "-----BEGIN ", 11)) {
|
||||
if (!name) {
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
client_ca = uwsgi_write_pem_to_file(name, client_ca, strlen(client_ca), ".ca");
|
||||
if (!client_ca) {
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
client_ca_need_free = 1;
|
||||
}
|
||||
|
||||
if (SSL_CTX_load_verify_locations(ctx, client_ca, NULL) == 0) {
|
||||
uwsgi_log("[uwsgi-ssl] unable to set ssl verify locations (%s) for context \"%s\"\n", client_ca, name);
|
||||
SSL_CTX_free(ctx);
|
||||
if (client_ca_need_free) free(client_ca);
|
||||
return NULL;
|
||||
}
|
||||
STACK_OF(X509_NAME) * list = SSL_load_client_CA_file(client_ca);
|
||||
if (!list) {
|
||||
uwsgi_log("unable to load client CA certificate (%s) for context \"%s\"\n", client_ca, name);
|
||||
SSL_CTX_free(ctx);
|
||||
if (client_ca_need_free) free(client_ca);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SSL_CTX_set_client_CA_list(ctx, list);
|
||||
|
||||
if (client_ca_need_free) free(client_ca);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -578,7 +578,7 @@ static void stats_dump_var(char *k, uint16_t kl, char *v, uint16_t vl, void *dat
|
||||
|
||||
int uwsgi_stats_dump_vars(struct uwsgi_stats *us, struct uwsgi_core *uc) {
|
||||
if (!uc->in_request) return 0;
|
||||
struct uwsgi_header *uh = (struct uwsgi_header *) uwsgi.workers[0].cores[0].buffer;
|
||||
struct uwsgi_header *uh = (struct uwsgi_header *) uc->buffer;
|
||||
uint16_t pktsize = uh->pktsize;
|
||||
if (!pktsize) return 0;
|
||||
char *dst = uwsgi.workers[0].cores[0].buffer;
|
||||
|
||||
+437
-325
@@ -23,46 +23,52 @@ extern struct uwsgi_server uwsgi;
|
||||
#ifdef UWSGI_SSL
|
||||
static void uwsgi_subscription_sni_check(struct uwsgi_subscribe_slot *current_slot, struct uwsgi_subscribe_req *usr) {
|
||||
if (usr->sni_key_len > 0 && usr->sni_crt_len > 0) {
|
||||
if (!current_slot->sni_enabled) {
|
||||
char *sni_key = uwsgi_concat2n(usr->sni_key, usr->sni_key_len, "", 0);
|
||||
char *sni_crt = uwsgi_concat2n(usr->sni_crt, usr->sni_crt_len, "", 0);
|
||||
char *sni_ca = NULL;
|
||||
if (usr->sni_ca_len > 0) {
|
||||
sni_ca = uwsgi_concat2n(usr->sni_ca, usr->sni_ca_len, "", 0);
|
||||
}
|
||||
char *servername = NULL;
|
||||
char *colon = memchr(current_slot->key, ':', current_slot->keylen);
|
||||
if (colon) {
|
||||
servername = uwsgi_concat2n(current_slot->key, colon-current_slot->key, "", 0);
|
||||
}
|
||||
else {
|
||||
servername = uwsgi_concat2n(current_slot->key, current_slot->keylen, "", 0);
|
||||
}
|
||||
if (uwsgi_ssl_add_sni_item(servername, sni_crt, sni_key, uwsgi.sni_dir_ciphers , sni_ca)) {
|
||||
current_slot->sni_enabled = 1;
|
||||
}
|
||||
if (sni_key) free(sni_key);
|
||||
if (sni_crt) free(sni_crt);
|
||||
if (sni_ca) free(sni_ca);
|
||||
}
|
||||
}
|
||||
if (!current_slot->sni_enabled) {
|
||||
char *sni_key = uwsgi_concat2n(usr->sni_key, usr->sni_key_len, "", 0);
|
||||
char *sni_crt = uwsgi_concat2n(usr->sni_crt, usr->sni_crt_len, "", 0);
|
||||
char *sni_ca = NULL;
|
||||
if (usr->sni_ca_len > 0) {
|
||||
sni_ca = uwsgi_concat2n(usr->sni_ca, usr->sni_ca_len, "", 0);
|
||||
}
|
||||
char *servername = NULL;
|
||||
char *colon = memchr(current_slot->key, ':', current_slot->keylen);
|
||||
if (colon) {
|
||||
servername = uwsgi_concat2n(current_slot->key, colon - current_slot->key, "", 0);
|
||||
}
|
||||
else {
|
||||
servername = uwsgi_concat2n(current_slot->key, current_slot->keylen, "", 0);
|
||||
}
|
||||
if (uwsgi_ssl_add_sni_item(servername, sni_crt, sni_key, uwsgi.sni_dir_ciphers, sni_ca)) {
|
||||
current_slot->sni_enabled = 1;
|
||||
}
|
||||
if (sni_key)
|
||||
free(sni_key);
|
||||
if (sni_crt)
|
||||
free(sni_crt);
|
||||
if (sni_ca)
|
||||
free(sni_ca);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int uwsgi_subscription_credentials_check(struct uwsgi_subscribe_slot *slot, struct uwsgi_subscribe_req *usr) {
|
||||
struct uwsgi_string_list *usl = NULL;
|
||||
uwsgi_foreach(usl, uwsgi.subscriptions_credentials_check_dir) {
|
||||
char *filename = uwsgi_concat2n(usl->value, usl->len, slot->key, slot->keylen);
|
||||
struct stat st;
|
||||
int ret = stat(filename, &st);
|
||||
free(filename);
|
||||
if (ret != 0) continue;
|
||||
if (st.st_uid != usr->uid) continue;
|
||||
if (st.st_gid != usr->gid) continue;
|
||||
// accepted...
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
struct uwsgi_string_list *usl = NULL;
|
||||
uwsgi_foreach(usl, uwsgi.subscriptions_credentials_check_dir) {
|
||||
char *filename = uwsgi_concat2n(usl->value, usl->len, slot->key, slot->keylen);
|
||||
struct stat st;
|
||||
int ret = stat(filename, &st);
|
||||
free(filename);
|
||||
if (ret != 0)
|
||||
continue;
|
||||
if (st.st_uid != usr->uid)
|
||||
continue;
|
||||
if (st.st_gid != usr->gid)
|
||||
continue;
|
||||
// accepted...
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct uwsgi_subscribe_slot *uwsgi_get_subscribe_slot(struct uwsgi_subscribe_slot **slot, char *key, uint16_t keylen) {
|
||||
@@ -346,7 +352,7 @@ int uwsgi_remove_subscribe_node(struct uwsgi_subscribe_slot **slot, struct uwsgi
|
||||
// first check if i am the only node
|
||||
if ((!prev_slot && !next_slot) || next_slot == node_slot) {
|
||||
#ifdef UWSGI_SSL
|
||||
if (uwsgi.subscriptions_sign_check_dir) {
|
||||
if (node_slot->sign_ctx) {
|
||||
EVP_PKEY_free(node_slot->sign_public_key);
|
||||
EVP_MD_CTX_destroy(node_slot->sign_ctx);
|
||||
}
|
||||
@@ -375,7 +381,7 @@ int uwsgi_remove_subscribe_node(struct uwsgi_subscribe_slot **slot, struct uwsgi
|
||||
}
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
if (uwsgi.subscriptions_sign_check_dir) {
|
||||
if (node_slot->sign_ctx) {
|
||||
EVP_PKEY_free(node_slot->sign_public_key);
|
||||
EVP_MD_CTX_destroy(node_slot->sign_ctx);
|
||||
}
|
||||
@@ -388,6 +394,11 @@ end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
static int subscription_new_sign_ctx(struct uwsgi_subscribe_slot *, struct uwsgi_subscribe_req *);
|
||||
static int subscription_is_safe(struct uwsgi_subscribe_req *);
|
||||
#endif
|
||||
|
||||
struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slot **slot, struct uwsgi_subscribe_req *usr) {
|
||||
|
||||
struct uwsgi_subscribe_slot *current_slot = uwsgi_get_subscribe_slot(slot, usr->key, usr->keylen), *old_slot = NULL, *a_slot;
|
||||
@@ -396,13 +407,6 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
|
||||
if (usr->address_len > 0xff || usr->address_len == 0)
|
||||
return NULL;
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
if (uwsgi.subscriptions_sign_check_dir) {
|
||||
if (usr->sign_len == 0 || usr->base_len == 0)
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (current_slot) {
|
||||
#ifdef UWSGI_SSL
|
||||
if (uwsgi.subscriptions_sign_check_dir && !uwsgi_subscription_sign_check(current_slot, usr)) {
|
||||
@@ -419,10 +423,12 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
|
||||
if (!uwsgi_strncmp(node->name, node->len, usr->address, usr->address_len)) {
|
||||
#ifdef UWSGI_SSL
|
||||
// this should avoid sending sniffed packets...
|
||||
if (uwsgi.subscriptions_sign_check_dir && usr->unix_check <= node->unix_check) {
|
||||
if (current_slot->sign_ctx && !subscription_is_safe(usr) && usr->unix_check <= node->unix_check) {
|
||||
uwsgi_log("[uwsgi-subscription for pid %d] invalid (sniffed ?) packet sent for slot: %.*s node: %.*s unix_check: %lu\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address, (unsigned long) usr->unix_check);
|
||||
return NULL;
|
||||
}
|
||||
// eventually the packet could be upgraded to sni...
|
||||
uwsgi_subscription_sni_check(current_slot, usr);
|
||||
#endif
|
||||
// remove death mark and update cores and load
|
||||
node->death_mark = 0;
|
||||
@@ -440,12 +446,12 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
|
||||
}
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
if (uwsgi.subscriptions_sign_check_dir && usr->unix_check < (uwsgi_now() - (time_t) uwsgi.subscriptions_sign_check_tolerance)) {
|
||||
if (current_slot->sign_ctx && !subscription_is_safe(usr) && usr->unix_check < (uwsgi_now() - (time_t) uwsgi.subscriptions_sign_check_tolerance)) {
|
||||
uwsgi_log("[uwsgi-subscription for pid %d] invalid (sniffed ?) packet sent for slot: %.*s node: %.*s unix_check: %lu\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address, (unsigned long) usr->unix_check);
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
// check here as we are sure the node will be added
|
||||
uwsgi_subscription_sni_check(current_slot, usr);
|
||||
uwsgi_subscription_sni_check(current_slot, usr);
|
||||
#endif
|
||||
|
||||
node = uwsgi_malloc(sizeof(struct uwsgi_subscribe_node));
|
||||
@@ -469,6 +475,11 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
|
||||
node->pid = usr->pid;
|
||||
node->uid = usr->uid;
|
||||
node->gid = usr->gid;
|
||||
node->notify[0] = 0;
|
||||
if (usr->notify_len > 0 && usr->notify_len < 102) {
|
||||
memcpy(node->notify, usr->notify, usr->notify_len);
|
||||
node->notify[usr->notify_len] = 0;
|
||||
}
|
||||
node->last_check = uwsgi_now();
|
||||
node->slot = current_slot;
|
||||
memcpy(node->name, usr->address, usr->address_len);
|
||||
@@ -476,54 +487,28 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
|
||||
old_node->next = node;
|
||||
}
|
||||
node->next = NULL;
|
||||
|
||||
uwsgi_log("[uwsgi-subscription for pid %d] %.*s => new node: %.*s\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address);
|
||||
if (node->notify[0]) {
|
||||
char buf[1024];
|
||||
int ret = snprintf(buf, 1024, "[subscription ack] %.*s => new node: %.*s", usr->keylen, usr->key, usr->address_len, usr->address);
|
||||
if (ret > 0 && ret < 1024)
|
||||
uwsgi_notify_msg(node->notify, buf, ret);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
else {
|
||||
current_slot = uwsgi_malloc(sizeof(struct uwsgi_subscribe_slot));
|
||||
#ifdef UWSGI_SSL
|
||||
FILE *kf = NULL;
|
||||
if (uwsgi.subscriptions_sign_check_dir) {
|
||||
if (usr->unix_check < (uwsgi_now() - (time_t) uwsgi.subscriptions_sign_check_tolerance)) {
|
||||
uwsgi_log("[uwsgi-subscription for pid %d] invalid (sniffed ?) packet sent for slot: %.*s node: %.*s unix_check: %lu\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address, (unsigned long) usr->unix_check);
|
||||
return NULL;
|
||||
}
|
||||
char *keyfile = uwsgi_sanitize_cert_filename(uwsgi.subscriptions_sign_check_dir, usr->key, usr->keylen);
|
||||
kf = fopen(keyfile, "r");
|
||||
free(keyfile);
|
||||
if (!kf)
|
||||
return NULL;
|
||||
|
||||
current_slot->sign_ctx = NULL;
|
||||
if (uwsgi.subscriptions_sign_check_dir && !subscription_new_sign_ctx(current_slot, usr)) {
|
||||
free(current_slot);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
current_slot = uwsgi_malloc(sizeof(struct uwsgi_subscribe_slot));
|
||||
uint32_t hash = djb33x_hash(usr->key, usr->keylen);
|
||||
int hash_key = hash % 0xffff;
|
||||
current_slot->hash = hash_key;
|
||||
#ifdef UWSGI_SSL
|
||||
if (uwsgi.subscriptions_sign_check_dir) {
|
||||
current_slot->sign_public_key = PEM_read_PUBKEY(kf, NULL, NULL, NULL);
|
||||
fclose(kf);
|
||||
if (!current_slot->sign_public_key) {
|
||||
uwsgi_log("unable to load public key for %.*s\n", usr->keylen, usr->key);
|
||||
free(current_slot);
|
||||
return NULL;
|
||||
}
|
||||
current_slot->sign_ctx = EVP_MD_CTX_create();
|
||||
if (!current_slot->sign_ctx) {
|
||||
uwsgi_log("unable to initialize EVP context for %.*s\n", usr->keylen, usr->key);
|
||||
EVP_PKEY_free(current_slot->sign_public_key);
|
||||
free(current_slot);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!uwsgi_subscription_sign_check(current_slot, usr)) {
|
||||
EVP_PKEY_free(current_slot->sign_public_key);
|
||||
EVP_MD_CTX_destroy(current_slot->sign_ctx);
|
||||
free(current_slot);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
current_slot->keylen = usr->keylen;
|
||||
memcpy(current_slot->key, usr->key, usr->keylen);
|
||||
if (uwsgi.subscriptions_credentials_check_dir) {
|
||||
@@ -561,6 +546,11 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
|
||||
current_slot->nodes->pid = usr->pid;
|
||||
current_slot->nodes->uid = usr->uid;
|
||||
current_slot->nodes->gid = usr->gid;
|
||||
current_slot->nodes->notify[0] = 0;
|
||||
if (usr->notify_len > 0 && usr->notify_len < 102) {
|
||||
memcpy(current_slot->nodes->notify, usr->notify, usr->notify_len);
|
||||
current_slot->nodes->notify[usr->notify_len] = 0;
|
||||
}
|
||||
memcpy(current_slot->nodes->name, usr->address, usr->address_len);
|
||||
current_slot->nodes->last_check = uwsgi_now();
|
||||
|
||||
@@ -587,98 +577,153 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo
|
||||
|
||||
uwsgi_log("[uwsgi-subscription for pid %d] new pool: %.*s (hash key: %d)\n", (int) uwsgi.mypid, usr->keylen, usr->key, current_slot->hash);
|
||||
uwsgi_log("[uwsgi-subscription for pid %d] %.*s => new node: %.*s\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address);
|
||||
|
||||
if (current_slot->nodes->notify[0]) {
|
||||
char buf[1024];
|
||||
int ret = snprintf(buf, 1024, "[subscription ack] %.*s => new node: %.*s", usr->keylen, usr->key, usr->address_len, usr->address);
|
||||
if (ret > 0 && ret < 1024)
|
||||
uwsgi_notify_msg(current_slot->nodes->notify, buf, ret);
|
||||
}
|
||||
return current_slot->nodes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void send_subscription(char *host, char *message, uint16_t message_size) {
|
||||
static void send_subscription(int sfd, char *host, char *message, uint16_t message_size) {
|
||||
|
||||
int fd;
|
||||
struct sockaddr_in udp_addr;
|
||||
struct sockaddr_un un_addr;
|
||||
ssize_t ret;
|
||||
int fd = sfd;
|
||||
struct sockaddr_in udp_addr;
|
||||
struct sockaddr_un un_addr;
|
||||
ssize_t ret;
|
||||
|
||||
char *udp_port = strchr(host, ':');
|
||||
if (udp_port) {
|
||||
udp_port[0] = 0;
|
||||
char *udp_port = strchr(host, ':');
|
||||
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
uwsgi_error("send_subscription()/socket()");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&udp_addr, 0, sizeof(struct sockaddr_in));
|
||||
udp_addr.sin_family = AF_INET;
|
||||
udp_addr.sin_port = htons(atoi(udp_port + 1));
|
||||
udp_addr.sin_addr.s_addr = inet_addr(host);
|
||||
}
|
||||
else {
|
||||
fd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
uwsgi_error("send_subscription()/socket()");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&un_addr, 0, sizeof(struct sockaddr_un));
|
||||
un_addr.sun_family = AF_UNIX;
|
||||
// use 102 as the magic number
|
||||
strncat(un_addr.sun_path, host, 102);
|
||||
|
||||
}
|
||||
|
||||
if (udp_port) {
|
||||
ret = sendto(fd, message, message_size, 0, (struct sockaddr *) &udp_addr, sizeof(udp_addr));
|
||||
udp_port[0] = ':';
|
||||
}
|
||||
else {
|
||||
if (uwsgi.subscriptions_use_credentials) {
|
||||
// could be useless as internally the socket could add them automagically
|
||||
ret = uwsgi_pass_cred2(fd, message, message_size, (struct sockaddr *) &un_addr, sizeof(un_addr));
|
||||
if (fd == -1) {
|
||||
if (udp_port) {
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
}
|
||||
else {
|
||||
ret = sendto(fd, message, message_size, 0, (struct sockaddr *) &un_addr, sizeof(un_addr));
|
||||
fd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
}
|
||||
if (fd < 0) {
|
||||
uwsgi_error("send_subscription()/socket()");
|
||||
return;
|
||||
}
|
||||
uwsgi_socket_nb(fd);
|
||||
}
|
||||
else if (fd == -2) {
|
||||
static int unix_fd = -1;
|
||||
static int inet_fd = -1;
|
||||
if (udp_port) {
|
||||
if (inet_fd == -1) {
|
||||
inet_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (inet_fd < 0) {
|
||||
uwsgi_error("send_subscription()/socket()");
|
||||
return;
|
||||
}
|
||||
uwsgi_socket_nb(inet_fd);
|
||||
}
|
||||
fd = inet_fd;
|
||||
}
|
||||
else {
|
||||
if (unix_fd == -1) {
|
||||
unix_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if (unix_fd < 0) {
|
||||
uwsgi_error("send_subscription()/socket()");
|
||||
return;
|
||||
}
|
||||
uwsgi_socket_nb(unix_fd);
|
||||
}
|
||||
fd = unix_fd;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
uwsgi_error("send_subscription()/sendto()");
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8_t modifier1, uint8_t modifier2, uint8_t cmd, char *socket_name, char *sign, char *sni_key, char *sni_crt, char *sni_ca) {
|
||||
|
||||
if (socket_name == NULL && !uwsgi.sockets)
|
||||
return;
|
||||
|
||||
if (!socket_name) {
|
||||
socket_name = uwsgi.sockets->name;
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(4096);
|
||||
if (udp_port) {
|
||||
udp_port[0] = 0;
|
||||
memset(&udp_addr, 0, sizeof(struct sockaddr_in));
|
||||
udp_addr.sin_family = AF_INET;
|
||||
udp_addr.sin_port = htons(atoi(udp_port + 1));
|
||||
udp_addr.sin_addr.s_addr = inet_addr(host);
|
||||
ret = sendto(fd, message, message_size, 0, (struct sockaddr *) &udp_addr, sizeof(udp_addr));
|
||||
udp_port[0] = ':';
|
||||
}
|
||||
else {
|
||||
memset(&un_addr, 0, sizeof(struct sockaddr_un));
|
||||
un_addr.sun_family = AF_UNIX;
|
||||
// use 102 as the magic number
|
||||
strncat(un_addr.sun_path, host, 102);
|
||||
if (uwsgi.subscriptions_use_credentials) {
|
||||
// could be useless as internally the socket could add them automagically
|
||||
ret = uwsgi_pass_cred2(fd, message, message_size, (struct sockaddr *) &un_addr, sizeof(un_addr));
|
||||
}
|
||||
else {
|
||||
ret = sendto(fd, message, message_size, 0, (struct sockaddr *) &un_addr, sizeof(un_addr));
|
||||
}
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
uwsgi_error("send_subscription()/sendto()");
|
||||
}
|
||||
|
||||
if (sfd == -1)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static struct uwsgi_buffer *uwsgi_subscription_ub(char *key, size_t keysize, uint8_t modifier1, uint8_t modifier2, uint8_t cmd, char *socket_name, char *sign, char *sni_key, char *sni_crt, char *sni_ca) {
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(4096);
|
||||
|
||||
// make space for uwsgi header
|
||||
ub->pos = 4;
|
||||
|
||||
if (uwsgi_buffer_append_keyval(ub, "key", 3, key, keysize)) goto end;
|
||||
if (uwsgi_buffer_append_keyval(ub, "address", 7, socket_name, strlen(socket_name))) goto end;
|
||||
if (uwsgi_buffer_append_keynum(ub, "modifier1", 9, modifier1)) goto end;
|
||||
if (uwsgi_buffer_append_keynum(ub, "modifier2", 9, modifier2)) goto end;
|
||||
if (uwsgi_buffer_append_keynum(ub, "cores", 5, uwsgi.numproc * uwsgi.cores)) goto end;
|
||||
if (uwsgi_buffer_append_keynum(ub, "load", 4, uwsgi.shared->load)) goto end;
|
||||
if (uwsgi_buffer_append_keyval(ub, "key", 3, key, keysize))
|
||||
goto end;
|
||||
if (uwsgi_buffer_append_keyval(ub, "address", 7, socket_name, strlen(socket_name)))
|
||||
goto end;
|
||||
if (uwsgi_buffer_append_keynum(ub, "modifier1", 9, modifier1))
|
||||
goto end;
|
||||
if (uwsgi_buffer_append_keynum(ub, "modifier2", 9, modifier2))
|
||||
goto end;
|
||||
if (uwsgi_buffer_append_keynum(ub, "cores", 5, uwsgi.numproc * uwsgi.cores))
|
||||
goto end;
|
||||
if (uwsgi_buffer_append_keynum(ub, "load", 4, uwsgi.shared->load))
|
||||
goto end;
|
||||
if (uwsgi.auto_weight) {
|
||||
if (uwsgi_buffer_append_keynum(ub, "weight", 6, uwsgi.numproc * uwsgi.cores )) goto end;
|
||||
if (uwsgi_buffer_append_keynum(ub, "weight", 6, uwsgi.numproc * uwsgi.cores))
|
||||
goto end;
|
||||
}
|
||||
else {
|
||||
if (uwsgi_buffer_append_keynum(ub, "weight", 6, uwsgi.weight )) goto end;
|
||||
if (uwsgi_buffer_append_keynum(ub, "weight", 6, uwsgi.weight))
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (sni_key) {
|
||||
if (uwsgi_buffer_append_keyval(ub, "sni_key", 7, sni_key, strlen(sni_key)))
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (sni_crt) {
|
||||
if (uwsgi_buffer_append_keyval(ub, "sni_crt", 7, sni_crt, strlen(sni_crt)))
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (sni_ca) {
|
||||
if (uwsgi_buffer_append_keyval(ub, "sni_ca", 6, sni_ca, strlen(sni_ca)))
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (uwsgi.subscription_notify_socket) {
|
||||
if (uwsgi_buffer_append_keyval(ub, "notify", 6, uwsgi.subscription_notify_socket, strlen(uwsgi.subscription_notify_socket)))
|
||||
goto end;
|
||||
}
|
||||
else if (uwsgi.notify_socket_fd > -1 && uwsgi.notify_socket) {
|
||||
if (uwsgi_buffer_append_keyval(ub, "notify", 6, uwsgi.notify_socket, strlen(uwsgi.notify_socket)))
|
||||
goto end;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
if (sign) {
|
||||
if (uwsgi_buffer_append_keynum(ub, "unix", 4, (uwsgi_now() + (time_t) cmd) )) goto end;
|
||||
if (uwsgi_buffer_append_keynum(ub, "unix", 4, (uwsgi_now() + (time_t) cmd)))
|
||||
goto end;
|
||||
|
||||
unsigned int signature_len = 0;
|
||||
char *signature = uwsgi_rsa_sign(sign, ub->buf + 4, ub->pos - 4, &signature_len);
|
||||
@@ -692,29 +737,98 @@ void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sni_key) {
|
||||
if (uwsgi_buffer_append_keyval(ub, "sni_key", 7, sni_key, strlen(sni_key))) goto end;
|
||||
}
|
||||
|
||||
if (sni_crt) {
|
||||
if (uwsgi_buffer_append_keyval(ub, "sni_crt", 7, sni_crt, strlen(sni_crt))) goto end;
|
||||
}
|
||||
|
||||
if (sni_ca) {
|
||||
if (uwsgi_buffer_append_keyval(ub, "sni_ca", 6, sni_ca, strlen(sni_ca))) goto end;
|
||||
}
|
||||
|
||||
// add uwsgi header
|
||||
if (uwsgi_buffer_set_uh(ub, 224, cmd)) goto end;
|
||||
if (uwsgi_buffer_set_uh(ub, 224, cmd))
|
||||
goto end;
|
||||
|
||||
return ub;
|
||||
|
||||
send_subscription(udp_address, ub->buf, ub->pos);
|
||||
end:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void uwsgi_send_subscription_from_fd(int fd, char *udp_address, char *key, size_t keysize, uint8_t modifier1, uint8_t modifier2, uint8_t cmd, char *socket_name, char *sign, char *sni_key, char *sni_crt, char *sni_ca) {
|
||||
|
||||
if (socket_name == NULL && !uwsgi.sockets)
|
||||
return;
|
||||
|
||||
if (!socket_name) {
|
||||
socket_name = uwsgi.sockets->name;
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_subscription_ub(key, keysize, modifier1, modifier2, cmd, socket_name, sign, sni_key, sni_crt, sni_ca);
|
||||
|
||||
if (!ub)
|
||||
return;
|
||||
|
||||
send_subscription(fd, udp_address, ub->buf, ub->pos);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8_t modifier1, uint8_t modifier2, uint8_t cmd, char *socket_name, char *sign, char *sni_key, char *sni_crt, char *sni_ca) {
|
||||
uwsgi_send_subscription_from_fd(-1, udp_address, key, keysize, modifier1, modifier2, cmd, socket_name, sign, sni_key, sni_crt, sni_ca);
|
||||
}
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
static int subscription_is_safe(struct uwsgi_subscribe_req *usr) {
|
||||
struct uwsgi_string_list *usl = NULL;
|
||||
uwsgi_foreach(usl, uwsgi.subscriptions_sign_skip_uid) {
|
||||
if (usl->custom == 0) {
|
||||
usl->custom = atoi(usl->value);
|
||||
}
|
||||
if (usr->uid > 0 && usr->uid == (uid_t) usl->custom) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int subscription_new_sign_ctx(struct uwsgi_subscribe_slot *slot, struct uwsgi_subscribe_req *usr) {
|
||||
if (subscription_is_safe(usr)) return 1;
|
||||
|
||||
if (usr->sign_len == 0 || usr->base_len == 0)
|
||||
return 0;
|
||||
|
||||
if (usr->unix_check < (uwsgi_now() - (time_t) uwsgi.subscriptions_sign_check_tolerance)) {
|
||||
uwsgi_log("[uwsgi-subscription for pid %d] invalid (sniffed ?) packet sent for slot: %.*s node: %.*s unix_check: %lu\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address, (unsigned long) usr->unix_check);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *keyfile = uwsgi_sanitize_cert_filename(uwsgi.subscriptions_sign_check_dir, usr->key, usr->keylen);
|
||||
FILE *kf = fopen(keyfile, "r");
|
||||
free(keyfile);
|
||||
if (!kf) return 0;
|
||||
slot->sign_public_key = PEM_read_PUBKEY(kf, NULL, NULL, NULL);
|
||||
fclose(kf);
|
||||
if (!slot->sign_public_key) {
|
||||
uwsgi_log("unable to load public key for %.*s\n", usr->keylen, usr->key);
|
||||
return 0;
|
||||
}
|
||||
slot->sign_ctx = EVP_MD_CTX_create();
|
||||
if (!slot->sign_ctx) {
|
||||
uwsgi_log("unable to initialize EVP context for %.*s\n", usr->keylen, usr->key);
|
||||
EVP_PKEY_free(slot->sign_public_key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!uwsgi_subscription_sign_check(slot, usr)) {
|
||||
EVP_PKEY_free(slot->sign_public_key);
|
||||
EVP_MD_CTX_destroy(slot->sign_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
int uwsgi_subscription_sign_check(struct uwsgi_subscribe_slot *slot, struct uwsgi_subscribe_req *usr) {
|
||||
if (subscription_is_safe(usr)) return 1;
|
||||
|
||||
if (usr->sign_len == 0 || usr->base_len == 0)
|
||||
return 0;
|
||||
|
||||
if (!slot->sign_ctx) {
|
||||
if (!subscription_new_sign_ctx(slot, usr)) return 0;
|
||||
}
|
||||
|
||||
if (EVP_VerifyInit_ex(slot->sign_ctx, uwsgi.subscriptions_sign_check_md, NULL) == 0) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
@@ -756,133 +870,133 @@ struct uwsgi_subscribe_slot **uwsgi_subscription_init_ht() {
|
||||
|
||||
void uwsgi_subscribe(char *subscription, uint8_t cmd) {
|
||||
|
||||
size_t subfile_size;
|
||||
size_t i;
|
||||
char *key = NULL;
|
||||
int keysize = 0;
|
||||
char *modifier1 = NULL;
|
||||
int modifier1_len = 0;
|
||||
char *socket_name = NULL;
|
||||
char *udp_address = subscription;
|
||||
char *udp_port = NULL;
|
||||
char *subscription_key = NULL;
|
||||
char *sign = NULL;
|
||||
size_t subfile_size;
|
||||
size_t i;
|
||||
char *key = NULL;
|
||||
int keysize = 0;
|
||||
char *modifier1 = NULL;
|
||||
int modifier1_len = 0;
|
||||
char *socket_name = NULL;
|
||||
char *udp_address = subscription;
|
||||
char *udp_port = NULL;
|
||||
char *subscription_key = NULL;
|
||||
char *sign = NULL;
|
||||
|
||||
// check for explicit socket_name
|
||||
char *equal = strchr(subscription, '=');
|
||||
if (equal) {
|
||||
socket_name = subscription;
|
||||
if (socket_name[0] == '=') {
|
||||
equal = strchr(socket_name + 1, '=');
|
||||
if (!equal)
|
||||
return;
|
||||
*equal = '\0';
|
||||
struct uwsgi_socket *us = uwsgi_get_shared_socket_by_num(atoi(socket_name + 1));
|
||||
if (!us)
|
||||
return;
|
||||
socket_name = us->name;
|
||||
}
|
||||
*equal = '\0';
|
||||
udp_address = equal + 1;
|
||||
}
|
||||
// check for explicit socket_name
|
||||
char *equal = strchr(subscription, '=');
|
||||
if (equal) {
|
||||
socket_name = subscription;
|
||||
if (socket_name[0] == '=') {
|
||||
equal = strchr(socket_name + 1, '=');
|
||||
if (!equal)
|
||||
return;
|
||||
*equal = '\0';
|
||||
struct uwsgi_socket *us = uwsgi_get_shared_socket_by_num(atoi(socket_name + 1));
|
||||
if (!us)
|
||||
return;
|
||||
socket_name = us->name;
|
||||
}
|
||||
*equal = '\0';
|
||||
udp_address = equal + 1;
|
||||
}
|
||||
|
||||
// check for unix socket
|
||||
if (udp_address[0] != '/') {
|
||||
udp_port = strchr(udp_address, ':');
|
||||
if (!udp_port) {
|
||||
if (equal)
|
||||
*equal = '=';
|
||||
return;
|
||||
}
|
||||
subscription_key = strchr(udp_port + 1, ':');
|
||||
}
|
||||
else {
|
||||
subscription_key = strchr(udp_address + 1, ':');
|
||||
}
|
||||
// check for unix socket
|
||||
if (udp_address[0] != '/') {
|
||||
udp_port = strchr(udp_address, ':');
|
||||
if (!udp_port) {
|
||||
if (equal)
|
||||
*equal = '=';
|
||||
return;
|
||||
}
|
||||
subscription_key = strchr(udp_port + 1, ':');
|
||||
}
|
||||
else {
|
||||
subscription_key = strchr(udp_address + 1, ':');
|
||||
}
|
||||
|
||||
if (!subscription_key) {
|
||||
if (equal)
|
||||
*equal = '=';
|
||||
return;
|
||||
}
|
||||
if (!subscription_key) {
|
||||
if (equal)
|
||||
*equal = '=';
|
||||
return;
|
||||
}
|
||||
|
||||
udp_address = uwsgi_concat2n(udp_address, subscription_key - udp_address, "", 0);
|
||||
udp_address = uwsgi_concat2n(udp_address, subscription_key - udp_address, "", 0);
|
||||
|
||||
if (subscription_key[1] == '@') {
|
||||
if (!uwsgi_file_exists(subscription_key + 2))
|
||||
goto clear;
|
||||
char *lines = uwsgi_open_and_read(subscription_key + 2, &subfile_size, 1, NULL);
|
||||
if (subfile_size > 0) {
|
||||
key = lines;
|
||||
for (i = 0; i < subfile_size; i++) {
|
||||
if (lines[i] == 0) {
|
||||
if (keysize > 0) {
|
||||
if (key[0] != '#' && key[0] != '\n') {
|
||||
modifier1 = strchr(key, ',');
|
||||
if (modifier1) {
|
||||
modifier1[0] = 0;
|
||||
modifier1++;
|
||||
modifier1_len = strlen(modifier1);
|
||||
keysize = strlen(key);
|
||||
}
|
||||
uwsgi_send_subscription(udp_address, key, keysize, uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign, NULL, NULL, NULL);
|
||||
modifier1 = NULL;
|
||||
modifier1_len = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (lines[i] == '\n') {
|
||||
if (keysize > 0) {
|
||||
if (key[0] != '#' && key[0] != '\n') {
|
||||
lines[i] = 0;
|
||||
modifier1 = strchr(key, ',');
|
||||
if (modifier1) {
|
||||
modifier1[0] = 0;
|
||||
modifier1++;
|
||||
modifier1_len = strlen(modifier1);
|
||||
keysize = strlen(key);
|
||||
}
|
||||
uwsgi_send_subscription(udp_address, key, keysize, uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign, NULL, NULL, NULL);
|
||||
modifier1 = NULL;
|
||||
modifier1_len = 0;
|
||||
lines[i] = '\n';
|
||||
}
|
||||
}
|
||||
key = lines + i + 1;
|
||||
keysize = 0;
|
||||
continue;
|
||||
}
|
||||
keysize++;
|
||||
}
|
||||
}
|
||||
free(lines);
|
||||
}
|
||||
else {
|
||||
modifier1 = strchr(subscription_key + 1, ',');
|
||||
if (modifier1) {
|
||||
modifier1[0] = 0;
|
||||
modifier1++;
|
||||
if (!uwsgi_file_exists(subscription_key + 2))
|
||||
goto clear;
|
||||
char *lines = uwsgi_open_and_read(subscription_key + 2, &subfile_size, 1, NULL);
|
||||
if (subfile_size > 0) {
|
||||
key = lines;
|
||||
for (i = 0; i < subfile_size; i++) {
|
||||
if (lines[i] == 0) {
|
||||
if (keysize > 0) {
|
||||
if (key[0] != '#' && key[0] != '\n') {
|
||||
modifier1 = strchr(key, ',');
|
||||
if (modifier1) {
|
||||
modifier1[0] = 0;
|
||||
modifier1++;
|
||||
modifier1_len = strlen(modifier1);
|
||||
keysize = strlen(key);
|
||||
}
|
||||
uwsgi_send_subscription(udp_address, key, keysize, uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign, NULL, NULL, NULL);
|
||||
modifier1 = NULL;
|
||||
modifier1_len = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (lines[i] == '\n') {
|
||||
if (keysize > 0) {
|
||||
if (key[0] != '#' && key[0] != '\n') {
|
||||
lines[i] = 0;
|
||||
modifier1 = strchr(key, ',');
|
||||
if (modifier1) {
|
||||
modifier1[0] = 0;
|
||||
modifier1++;
|
||||
modifier1_len = strlen(modifier1);
|
||||
keysize = strlen(key);
|
||||
}
|
||||
uwsgi_send_subscription(udp_address, key, keysize, uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign, NULL, NULL, NULL);
|
||||
modifier1 = NULL;
|
||||
modifier1_len = 0;
|
||||
lines[i] = '\n';
|
||||
}
|
||||
}
|
||||
key = lines + i + 1;
|
||||
keysize = 0;
|
||||
continue;
|
||||
}
|
||||
keysize++;
|
||||
}
|
||||
}
|
||||
free(lines);
|
||||
}
|
||||
else {
|
||||
modifier1 = strchr(subscription_key + 1, ',');
|
||||
if (modifier1) {
|
||||
modifier1[0] = 0;
|
||||
modifier1++;
|
||||
|
||||
sign = strchr(modifier1 + 1, ',');
|
||||
if (sign) {
|
||||
*sign = 0;
|
||||
sign++;
|
||||
}
|
||||
modifier1_len = strlen(modifier1);
|
||||
}
|
||||
sign = strchr(modifier1 + 1, ',');
|
||||
if (sign) {
|
||||
*sign = 0;
|
||||
sign++;
|
||||
}
|
||||
modifier1_len = strlen(modifier1);
|
||||
}
|
||||
|
||||
uwsgi_send_subscription(udp_address, subscription_key + 1, strlen(subscription_key + 1), uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign, NULL, NULL, NULL);
|
||||
if (modifier1)
|
||||
modifier1[-1] = ',';
|
||||
if (sign)
|
||||
sign[-1] = ',';
|
||||
}
|
||||
uwsgi_send_subscription(udp_address, subscription_key + 1, strlen(subscription_key + 1), uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign, NULL, NULL, NULL);
|
||||
if (modifier1)
|
||||
modifier1[-1] = ',';
|
||||
if (sign)
|
||||
sign[-1] = ',';
|
||||
}
|
||||
|
||||
clear:
|
||||
if (equal)
|
||||
*equal = '=';
|
||||
free(udp_address);
|
||||
if (equal)
|
||||
*equal = '=';
|
||||
free(udp_address);
|
||||
|
||||
}
|
||||
|
||||
@@ -901,27 +1015,16 @@ void uwsgi_subscribe2(char *arg, uint8_t cmd) {
|
||||
char *s2_sni_crt = NULL;
|
||||
char *s2_sni_ca = NULL;
|
||||
|
||||
if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=',
|
||||
"server", &s2_server,
|
||||
"key", &s2_key,
|
||||
"socket", &s2_socket,
|
||||
"addr", &s2_addr,
|
||||
"weight", &s2_weight,
|
||||
"modifier1", &s2_modifier1,
|
||||
"modifier2", &s2_modifier2,
|
||||
"sign", &s2_sign,
|
||||
"check", &s2_check,
|
||||
"sni_key", &s2_sni_key,
|
||||
"sni_crt", &s2_sni_crt,
|
||||
"sni_ca", &s2_sni_ca,
|
||||
NULL)) {
|
||||
if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=', "server", &s2_server, "key", &s2_key, "socket", &s2_socket, "addr", &s2_addr, "weight", &s2_weight, "modifier1", &s2_modifier1, "modifier2", &s2_modifier2, "sign", &s2_sign, "check", &s2_check, "sni_key", &s2_sni_key, "sni_crt", &s2_sni_crt, "sni_ca", &s2_sni_ca, NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s2_server || !s2_key) goto end;
|
||||
if (!s2_server || !s2_key)
|
||||
goto end;
|
||||
|
||||
if (s2_check) {
|
||||
if (uwsgi_file_exists(s2_check)) goto end;
|
||||
if (uwsgi_file_exists(s2_check))
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (s2_weight) {
|
||||
@@ -951,39 +1054,48 @@ void uwsgi_subscribe2(char *arg, uint8_t cmd) {
|
||||
|
||||
uwsgi_send_subscription(s2_server, s2_key, strlen(s2_key), modifier1, modifier2, cmd, s2_addr, s2_sign, s2_sni_key, s2_sni_crt, s2_sni_ca);
|
||||
end:
|
||||
if (s2_server) free(s2_server);
|
||||
if (s2_key) free(s2_key);
|
||||
if (s2_socket) free(s2_socket);
|
||||
if (s2_addr) free(s2_addr);
|
||||
if (s2_weight) free(s2_weight);
|
||||
if (s2_modifier1) free(s2_modifier1);
|
||||
if (s2_modifier2) free(s2_modifier2);
|
||||
if (s2_sign) free(s2_sign);
|
||||
if (s2_check) free(s2_check);
|
||||
if (s2_server)
|
||||
free(s2_server);
|
||||
if (s2_key)
|
||||
free(s2_key);
|
||||
if (s2_socket)
|
||||
free(s2_socket);
|
||||
if (s2_addr)
|
||||
free(s2_addr);
|
||||
if (s2_weight)
|
||||
free(s2_weight);
|
||||
if (s2_modifier1)
|
||||
free(s2_modifier1);
|
||||
if (s2_modifier2)
|
||||
free(s2_modifier2);
|
||||
if (s2_sign)
|
||||
free(s2_sign);
|
||||
if (s2_check)
|
||||
free(s2_check);
|
||||
}
|
||||
|
||||
void uwsgi_subscribe_all(uint8_t cmd, int verbose) {
|
||||
|
||||
if (uwsgi.subscriptions_blocked) return;
|
||||
if (uwsgi.subscriptions_blocked)
|
||||
return;
|
||||
// -- subscribe
|
||||
struct uwsgi_string_list *subscriptions = uwsgi.subscriptions;
|
||||
while (subscriptions) {
|
||||
while (subscriptions) {
|
||||
if (verbose) {
|
||||
uwsgi_log("%s %s\n", cmd ? "unsubscribing from" : "subscribing to", subscriptions->value);
|
||||
uwsgi_log("%s %s\n", cmd ? "unsubscribing from" : "subscribing to", subscriptions->value);
|
||||
}
|
||||
uwsgi_subscribe(subscriptions->value, cmd);
|
||||
subscriptions = subscriptions->next;
|
||||
}
|
||||
uwsgi_subscribe(subscriptions->value, cmd);
|
||||
subscriptions = subscriptions->next;
|
||||
}
|
||||
|
||||
// --subscribe2
|
||||
subscriptions = uwsgi.subscriptions2;
|
||||
while (subscriptions) {
|
||||
if (verbose) {
|
||||
uwsgi_log("%s %s\n", cmd ? "unsubscribing from" : "subscribing to", subscriptions->value);
|
||||
}
|
||||
uwsgi_subscribe2(subscriptions->value, cmd);
|
||||
subscriptions = subscriptions->next;
|
||||
}
|
||||
while (subscriptions) {
|
||||
if (verbose) {
|
||||
uwsgi_log("%s %s\n", cmd ? "unsubscribing from" : "subscribing to", subscriptions->value);
|
||||
}
|
||||
uwsgi_subscribe2(subscriptions->value, cmd);
|
||||
subscriptions = subscriptions->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
+51
-32
@@ -754,7 +754,11 @@ void uwsgi_as_root() {
|
||||
}
|
||||
|
||||
if (uwsgi.logfile_chown) {
|
||||
if (fchown(2, uwsgi.uid, uwsgi.gid)) {
|
||||
int log_fd = 2;
|
||||
if (uwsgi.log_master && uwsgi.original_log_fd > -1) {
|
||||
log_fd = uwsgi.original_log_fd;
|
||||
}
|
||||
if (fchown(log_fd, uwsgi.uid, uwsgi.gid)) {
|
||||
uwsgi_error("fchown()");
|
||||
exit(1);
|
||||
}
|
||||
@@ -978,19 +982,44 @@ nonroot:
|
||||
}
|
||||
}
|
||||
|
||||
static void close_and_free_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
// close the connection with the client
|
||||
if (!wsgi_req->fd_closed) {
|
||||
// NOTE, if we close the socket before receiving eventually sent data, socket layer will send a RST
|
||||
wsgi_req->socket->proto_close(wsgi_req);
|
||||
}
|
||||
|
||||
if (wsgi_req->post_file) {
|
||||
fclose(wsgi_req->post_file);
|
||||
}
|
||||
|
||||
if (wsgi_req->post_read_buf) {
|
||||
free(wsgi_req->post_read_buf);
|
||||
}
|
||||
|
||||
if (wsgi_req->post_readline_buf) {
|
||||
free(wsgi_req->post_readline_buf);
|
||||
}
|
||||
|
||||
if (wsgi_req->proto_parser_buf) {
|
||||
free(wsgi_req->proto_parser_buf);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// destroy a request
|
||||
void uwsgi_destroy_request(struct wsgi_request *wsgi_req) {
|
||||
|
||||
wsgi_req->socket->proto_close(wsgi_req);
|
||||
close_and_free_request(wsgi_req);
|
||||
|
||||
int foo;
|
||||
if (uwsgi.threads > 1) {
|
||||
// now the thread can die...
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &foo);
|
||||
}
|
||||
|
||||
memset(wsgi_req, 0, sizeof(struct wsgi_request));
|
||||
if (uwsgi.threads > 1) {
|
||||
// now the thread can die...
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &foo);
|
||||
}
|
||||
|
||||
memset(wsgi_req, 0, sizeof(struct wsgi_request));
|
||||
|
||||
}
|
||||
|
||||
@@ -1049,27 +1078,8 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
|
||||
uwsgi_apply_final_routes(wsgi_req);
|
||||
#endif
|
||||
|
||||
// close the connection with the client
|
||||
if (!wsgi_req->fd_closed) {
|
||||
// NOTE, if we close the socket before receiving eventually sent data, socket layer will send a RST
|
||||
wsgi_req->socket->proto_close(wsgi_req);
|
||||
}
|
||||
|
||||
if (wsgi_req->post_file) {
|
||||
fclose(wsgi_req->post_file);
|
||||
}
|
||||
|
||||
if (wsgi_req->post_read_buf) {
|
||||
free(wsgi_req->post_read_buf);
|
||||
}
|
||||
|
||||
if (wsgi_req->post_readline_buf) {
|
||||
free(wsgi_req->post_readline_buf);
|
||||
}
|
||||
|
||||
if (wsgi_req->proto_parser_buf) {
|
||||
free(wsgi_req->proto_parser_buf);
|
||||
}
|
||||
// close socket and free parsers-allocated memory
|
||||
close_and_free_request(wsgi_req);
|
||||
|
||||
// after_request hook
|
||||
if (!wsgi_req->is_raw && uwsgi.p[wsgi_req->uh->modifier1]->after_request)
|
||||
@@ -1432,7 +1442,7 @@ void uwsgi_heartbeat() {
|
||||
return;
|
||||
|
||||
time_t now = uwsgi_now();
|
||||
if (uwsgi.next_heartbeat < now) {
|
||||
if (uwsgi.next_heartbeat <= now) {
|
||||
char byte = 26;
|
||||
if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
|
||||
uwsgi_error("write()");
|
||||
@@ -1456,7 +1466,15 @@ int wsgi_req_accept(int queue, struct wsgi_request *wsgi_req) {
|
||||
// heartbeat
|
||||
// in multithreaded mode we are now locked
|
||||
if (uwsgi.has_emperor && uwsgi.heartbeat) {
|
||||
time_t now = uwsgi_now();
|
||||
// overengineering ... (reduce skew problems)
|
||||
timeout = uwsgi.heartbeat;
|
||||
if (!uwsgi.next_heartbeat) {
|
||||
uwsgi.next_heartbeat = now;
|
||||
}
|
||||
if (uwsgi.next_heartbeat >= now) {
|
||||
timeout = uwsgi.next_heartbeat - now;
|
||||
}
|
||||
}
|
||||
|
||||
// need edge trigger ?
|
||||
@@ -1479,7 +1497,7 @@ int wsgi_req_accept(int queue, struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
|
||||
// check for heartbeat
|
||||
if (timeout > 0) {
|
||||
if (uwsgi.has_emperor && uwsgi.heartbeat) {
|
||||
uwsgi_heartbeat();
|
||||
// no need to continue if timed-out
|
||||
if (ret == 0) {
|
||||
@@ -4182,7 +4200,8 @@ char *uwsgi_str_to_hex(char *src, size_t slen) {
|
||||
char *ptr = dst;
|
||||
size_t i;
|
||||
for (i = 0; i < slen; i++) {
|
||||
memcpy(ptr, uwsgi_hex_table[(int) src[i]], 2);
|
||||
uint8_t pos = (uint8_t) src[i];
|
||||
memcpy(ptr, uwsgi_hex_table[pos], 2);
|
||||
ptr += 2;
|
||||
}
|
||||
return dst;
|
||||
|
||||
+84
-13
@@ -2,7 +2,7 @@
|
||||
|
||||
*** uWSGI ***
|
||||
|
||||
Copyright (C) 2009-2013 Unbit S.a.s. <info@unbit.it>
|
||||
Copyright (C) 2009-2014 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
|
||||
@@ -104,6 +104,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"for", required_argument, 0, "(opt logic) for cycle", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for, UWSGI_OPT_IMMEDIATE},
|
||||
{"for-glob", required_argument, 0, "(opt logic) for cycle (expand glob)", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for_glob, UWSGI_OPT_IMMEDIATE},
|
||||
{"for-times", required_argument, 0, "(opt logic) for cycle (expand the specified num to a list starting from 1)", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for_times, UWSGI_OPT_IMMEDIATE},
|
||||
{"for-readline", required_argument, 0, "(opt logic) for cycle (expand the specified file to a list of lines)", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for_readline, UWSGI_OPT_IMMEDIATE},
|
||||
{"endfor", optional_argument, 0, "(opt logic) end for cycle", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE},
|
||||
{"end-for", optional_argument, 0, "(opt logic) end for cycle", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE},
|
||||
|
||||
@@ -150,6 +151,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
|
||||
{"inherit", required_argument, 0, "use the specified file as config template", uwsgi_opt_load, NULL, 0},
|
||||
{"include", required_argument, 0, "include the specified file as immediate configuration", uwsgi_opt_load, NULL, UWSGI_OPT_IMMEDIATE},
|
||||
{"inject-before", required_argument, 0, "inject a text file before the config file (advanced templating)", uwsgi_opt_add_string_list, &uwsgi.inject_before, UWSGI_OPT_IMMEDIATE},
|
||||
{"inject-after", required_argument, 0, "inject a text file after the config file (advanced templating)", uwsgi_opt_add_string_list, &uwsgi.inject_after, UWSGI_OPT_IMMEDIATE},
|
||||
{"daemonize", required_argument, 'd', "daemonize uWSGI", uwsgi_opt_set_str, &uwsgi.daemonize, 0},
|
||||
{"daemonize2", required_argument, 0, "daemonize uWSGI after app loading", uwsgi_opt_set_str, &uwsgi.daemonize2, 0},
|
||||
{"stop", required_argument, 0, "stop an instance", uwsgi_opt_pidfile_signal, (void *) SIGINT, UWSGI_OPT_IMMEDIATE},
|
||||
@@ -299,6 +302,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"spooler-quiet", no_argument, 0, "do not be verbose with spooler tasks", uwsgi_opt_true, &uwsgi.spooler_quiet, 0},
|
||||
{"spooler-max-tasks", required_argument, 0, "set the maximum number of tasks to run before recycling a spooler", uwsgi_opt_set_int, &uwsgi.spooler_max_tasks, 0},
|
||||
{"spooler-harakiri", required_argument, 0, "set harakiri timeout for spooler tasks", uwsgi_opt_set_int, &uwsgi.harakiri_options.spoolers, 0},
|
||||
{"spooler-frequency", required_argument, 0, "set spooler frequency", uwsgi_opt_set_int, &uwsgi.spooler_frequency, 0},
|
||||
{"spooler-freq", required_argument, 0, "set spooler frequency", uwsgi_opt_set_int, &uwsgi.spooler_frequency, 0},
|
||||
|
||||
{"mule", optional_argument, 0, "add a mule", uwsgi_opt_add_mule, NULL, UWSGI_OPT_MASTER},
|
||||
{"mules", required_argument, 0, "add the specified number of mules", uwsgi_opt_add_mules, NULL, UWSGI_OPT_MASTER},
|
||||
@@ -385,6 +390,11 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"hook-accepting-once", required_argument, 0, "run the specified hook after each worker enter the accepting phase (once per-instance)", uwsgi_opt_add_string_list, &uwsgi.hook_accepting_once, 0},
|
||||
{"hook-accepting1-once", required_argument, 0, "run the specified hook after the first worker enters the accepting phase (once per instance)", uwsgi_opt_add_string_list, &uwsgi.hook_accepting1_once, 0},
|
||||
|
||||
{"hook-master-start", required_argument, 0, "run the specified hook when the Master starts", uwsgi_opt_add_string_list, &uwsgi.hook_master_start, 0},
|
||||
|
||||
{"hook-touch", required_argument, 0, "run the specified hook when the specified file is touched (syntax: <file> <action>)", uwsgi_opt_add_string_list, &uwsgi.hook_touch, 0},
|
||||
|
||||
{"hook-emperor-start", required_argument, 0, "run the specified hook when the Emperor starts", uwsgi_opt_add_string_list, &uwsgi.hook_emperor_start, 0},
|
||||
{"hook-emperor-stop", required_argument, 0, "run the specified hook when the Emperor send a stop message", uwsgi_opt_add_string_list, &uwsgi.hook_emperor_stop, 0},
|
||||
{"hook-emperor-reload", required_argument, 0, "run the specified hook when the Emperor send a reload message", uwsgi_opt_add_string_list, &uwsgi.hook_emperor_reload, 0},
|
||||
{"hook-emperor-lost", required_argument, 0, "run the specified hook when the Emperor connection is lost", uwsgi_opt_add_string_list, &uwsgi.hook_emperor_lost, 0},
|
||||
@@ -394,6 +404,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
|
||||
{"hook-as-mule", required_argument, 0, "run the specified hook in each mule", uwsgi_opt_add_string_list, &uwsgi.hook_as_mule, 0},
|
||||
|
||||
{"hook-as-gateway", required_argument, 0, "run the specified hook in each gateway", uwsgi_opt_add_string_list, &uwsgi.hook_as_gateway, 0},
|
||||
|
||||
{"after-request-hook", required_argument, 0, "run the specified function/symbol after each request", uwsgi_opt_add_string_list, &uwsgi.after_request_hooks, 0},
|
||||
{"after-request-call", required_argument, 0, "run the specified function/symbol after each request", uwsgi_opt_add_string_list, &uwsgi.after_request_hooks, 0},
|
||||
|
||||
@@ -543,6 +555,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"metric", required_argument, 0, "add a custom metric", uwsgi_opt_add_string_list, &uwsgi.additional_metrics, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
|
||||
{"metric-threshold", required_argument, 0, "add a metric threshold/alarm", uwsgi_opt_add_string_list, &uwsgi.metrics_threshold, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
|
||||
{"metric-alarm", required_argument, 0, "add a metric threshold/alarm", uwsgi_opt_add_string_list, &uwsgi.metrics_threshold, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
|
||||
{"alarm-metric", required_argument, 0, "add a metric threshold/alarm", uwsgi_opt_add_string_list, &uwsgi.metrics_threshold, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
|
||||
{"metrics-dir", required_argument, 0, "export metrics as text files to the specified directory", uwsgi_opt_set_str, &uwsgi.metrics_dir, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
|
||||
{"metrics-dir-restore", no_argument, 0, "restore last value taken from the metrics dir", uwsgi_opt_true, &uwsgi.metrics_dir_restore, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
|
||||
{"metric-dir", required_argument, 0, "export metrics as text files to the specified directory", uwsgi_opt_set_str, &uwsgi.metrics_dir, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER},
|
||||
@@ -563,12 +576,16 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
|
||||
{"master-fifo", required_argument, 0, "enable the master fifo", uwsgi_opt_add_string_list, &uwsgi.master_fifo, UWSGI_OPT_MASTER},
|
||||
|
||||
{"notify-socket", required_argument, 0, "enable the notification socket", uwsgi_opt_set_str, &uwsgi.notify_socket, UWSGI_OPT_MASTER},
|
||||
{"subscription-notify-socket", required_argument, 0, "set the notification socket for subscriptions", uwsgi_opt_set_str, &uwsgi.subscription_notify_socket, UWSGI_OPT_MASTER},
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
{"legion", required_argument, 0, "became a member of a legion", uwsgi_opt_legion, NULL, UWSGI_OPT_MASTER},
|
||||
{"legion-mcast", required_argument, 0, "became a member of a legion (shortcut for multicast)", uwsgi_opt_legion_mcast, NULL, UWSGI_OPT_MASTER},
|
||||
{"legion-node", required_argument, 0, "add a node to a legion", uwsgi_opt_legion_node, NULL, UWSGI_OPT_MASTER},
|
||||
{"legion-freq", required_argument, 0, "set the frequency of legion packets", uwsgi_opt_set_int, &uwsgi.legion_freq, UWSGI_OPT_MASTER},
|
||||
{"legion-tolerance", required_argument, 0, "set the tolerance of legion subsystem", uwsgi_opt_set_int, &uwsgi.legion_tolerance, UWSGI_OPT_MASTER},
|
||||
{"legion-death-on-lord-error", required_argument, 0, "declare itself as a dead node for the specified amount of seconds if one of the lord hooks fails", uwsgi_opt_set_int, &uwsgi.legion_death_on_lord_error, UWSGI_OPT_MASTER},
|
||||
{"legion-skew-tolerance", required_argument, 0, "set the clock skew tolerance of legion subsystem (default 30 seconds)", uwsgi_opt_set_int, &uwsgi.legion_skew_tolerance, UWSGI_OPT_MASTER},
|
||||
{"legion-lord", required_argument, 0, "action to call on Lord election", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER},
|
||||
{"legion-unlord", required_argument, 0, "action to call on Lord dismiss", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER},
|
||||
@@ -583,6 +600,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"legion-scroll-list-max-size", required_argument, 0, "set max size of legion scroll list buffer", uwsgi_opt_set_64bit, &uwsgi.legion_scroll_list_max_size, 0},
|
||||
{"subscriptions-sign-check", required_argument, 0, "set digest algorithm and certificate directory for secured subscription system", uwsgi_opt_scd, NULL, UWSGI_OPT_MASTER},
|
||||
{"subscriptions-sign-check-tolerance", required_argument, 0, "set the maximum tolerance (in seconds) of clock skew for secured subscription system", uwsgi_opt_set_int, &uwsgi.subscriptions_sign_check_tolerance, UWSGI_OPT_MASTER},
|
||||
{"subscriptions-sign-skip-uid", required_argument, 0, "skip signature check for the specified uid when using unix sockets credentials", uwsgi_opt_add_string_list, &uwsgi.subscriptions_sign_skip_uid, UWSGI_OPT_MASTER},
|
||||
#endif
|
||||
{"subscriptions-credentials-check", required_argument, 0, "add a directory to search for subscriptions key credentials", uwsgi_opt_add_string_list, &uwsgi.subscriptions_credentials_check_dir, UWSGI_OPT_MASTER},
|
||||
{"subscriptions-use-credentials", no_argument, 0, "enable management of SCM_CREDENTIALS in subscriptions UNIX sockets", uwsgi_opt_true, &uwsgi.subscriptions_use_credentials, 0},
|
||||
@@ -595,6 +613,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"subscribe-freq", required_argument, 0, "send subscription announce at the specified interval", uwsgi_opt_set_int, &uwsgi.subscribe_freq, 0},
|
||||
{"subscription-tolerance", required_argument, 0, "set tolerance for subscription servers", uwsgi_opt_set_int, &uwsgi.subscription_tolerance, 0},
|
||||
{"unsubscribe-on-graceful-reload", no_argument, 0, "force unsubscribe request even during graceful reload", uwsgi_opt_true, &uwsgi.unsubscribe_on_graceful_reload, 0},
|
||||
{"start-unsubscribed", no_argument, 0, "configure subscriptions but do not send them (useful with master fifo)", uwsgi_opt_true, &uwsgi.subscriptions_blocked, 0},
|
||||
{"snmp", optional_argument, 0, "enable the embedded snmp server", uwsgi_opt_snmp, NULL, 0},
|
||||
{"snmp-community", required_argument, 0, "set the snmp community string", uwsgi_opt_snmp_community, NULL, 0},
|
||||
#ifdef UWSGI_SSL
|
||||
@@ -610,6 +629,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
#ifdef UWSGI_PCRE
|
||||
{"sni-regexp", required_argument, 0, "add an SNI-governed SSL context (the key is a regexp)", uwsgi_opt_sni, NULL, 0},
|
||||
#endif
|
||||
{"ssl-tmp-dir", required_argument, 0, "store ssl-related temp files in the specified directory", uwsgi_opt_set_str, &uwsgi.ssl_tmp_dir, 0},
|
||||
#endif
|
||||
{"check-interval", required_argument, 0, "set the interval (in seconds) of master checks", uwsgi_opt_set_int, &uwsgi.master_interval, UWSGI_OPT_MASTER},
|
||||
{"forkbomb-delay", required_argument, 0, "sleep for the specified number of seconds when a forkbomb is detected", uwsgi_opt_set_int, &uwsgi.forkbomb_delay, UWSGI_OPT_MASTER},
|
||||
@@ -656,6 +676,12 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"alarm-fd", required_argument, 0, "raise the specified alarm when an fd is read for read (by default it reads 1 byte, set 8 for eventfd)", uwsgi_opt_add_string_list, &uwsgi.alarm_fd_list, UWSGI_OPT_MASTER},
|
||||
{"alarm-segfault", required_argument, 0, "raise the specified alarm when the segmentation fault handler is executed", uwsgi_opt_add_string_list, &uwsgi.alarm_segfault, UWSGI_OPT_MASTER},
|
||||
{"segfault-alarm", required_argument, 0, "raise the specified alarm when the segmentation fault handler is executed", uwsgi_opt_add_string_list, &uwsgi.alarm_segfault, UWSGI_OPT_MASTER},
|
||||
{"alarm-backlog", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER},
|
||||
{"backlog-alarm", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER},
|
||||
{"lq-alarm", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER},
|
||||
{"alarm-lq", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER},
|
||||
{"alarm-listen-queue", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER},
|
||||
{"listen-queue-alarm", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER},
|
||||
#ifdef UWSGI_PCRE
|
||||
{"log-alarm", required_argument, 0, "raise the specified alarm when a log line matches the specified regexp, syntax: <alarm>[,alarm...] <regexp>", uwsgi_opt_add_string_list, &uwsgi.alarm_logs_list, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
|
||||
{"alarm-log", required_argument, 0, "raise the specified alarm when a log line matches the specified regexp, syntax: <alarm>[,alarm...] <regexp>", uwsgi_opt_add_string_list, &uwsgi.alarm_logs_list, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER},
|
||||
@@ -861,7 +887,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"disable-sendfile", no_argument, 0, "disable sendfile() and rely on boring read()/write()", uwsgi_opt_true, &uwsgi.disable_sendfile, 0},
|
||||
|
||||
{"check-cache", optional_argument, 0, "check for response data in the specified cache (empty for default cache)", uwsgi_opt_set_str, &uwsgi.use_check_cache, 0},
|
||||
{"close-on-exec", no_argument, 0, "set close-on-exec on sockets (could be required for spawning processes in requests)", uwsgi_opt_true, &uwsgi.close_on_exec, 0},
|
||||
{"close-on-exec", no_argument, 0, "set close-on-exec on connection sockets (could be required for spawning processes in requests)", uwsgi_opt_true, &uwsgi.close_on_exec, 0},
|
||||
{"close-on-exec2", no_argument, 0, "set close-on-exec on server sockets (could be required for spawning processes in requests)", uwsgi_opt_true, &uwsgi.close_on_exec2, 0},
|
||||
{"mode", required_argument, 0, "set uWSGI custom mode", uwsgi_opt_set_str, &uwsgi.mode, 0},
|
||||
{"env", required_argument, 0, "set environment variable", uwsgi_opt_set_env, NULL, 0},
|
||||
{"envdir", required_argument, 0, "load a daemontools compatible envdir", uwsgi_opt_add_string_list, &uwsgi.envdirs, 0},
|
||||
@@ -999,6 +1026,17 @@ void config_magic_table_fill(char *filename, char **magic_table) {
|
||||
magic_table['b'] = uwsgi.binary_path;
|
||||
magic_table['p'] = fullname;
|
||||
|
||||
// compute filename hash
|
||||
uint32_t hash = djb33x_hash(magic_table['p'], strlen(magic_table['p']));
|
||||
char *hex = uwsgi_str_to_hex((char *)&hash, 4);
|
||||
magic_table['j'] = uwsgi_concat2n(hex, 8, "", 0);
|
||||
free(hex);
|
||||
|
||||
struct stat st;
|
||||
if (!lstat(fullname, &st)) {
|
||||
magic_table['i'] = uwsgi_num2str(st.st_ino);
|
||||
}
|
||||
|
||||
magic_table['s'] = uwsgi_get_last_char(fullname, '/') + 1;
|
||||
|
||||
magic_table['d'] = uwsgi_concat2n(magic_table['p'], magic_table['s'] - magic_table['p'], "", 0);
|
||||
@@ -1071,6 +1109,8 @@ reuse:
|
||||
magic_table['E'] = magic_table['e'];
|
||||
magic_table['N'] = magic_table['n'];
|
||||
magic_table['X'] = magic_table['x'];
|
||||
magic_table['I'] = magic_table['i'];
|
||||
magic_table['J'] = magic_table['j'];
|
||||
uwsgi.magic_table_first_round = 1;
|
||||
}
|
||||
|
||||
@@ -1876,6 +1916,17 @@ int main(int argc, char *argv[], char *envp[]) {
|
||||
return uwsgi_run();
|
||||
}
|
||||
|
||||
static char *uwsgi_at_file_read(char *filename) {
|
||||
size_t size = 0;
|
||||
char *buffer = uwsgi_open_and_read(filename, &size, 1, NULL);
|
||||
if (size > 1) {
|
||||
if (buffer[size-2] == '\n' || buffer[size-2] == '\r') {
|
||||
buffer[size-2] = 0;
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void uwsgi_setup(int argc, char *argv[], char *envp[]) {
|
||||
#ifdef UWSGI_AS_SHARED_LIBRARY
|
||||
#ifdef __APPLE__
|
||||
@@ -2073,7 +2124,7 @@ void uwsgi_setup(int argc, char *argv[], char *envp[]) {
|
||||
uwsgi_apply_config_pass('$', (char *(*)(char *)) getenv);
|
||||
|
||||
// third pass: FILEs
|
||||
uwsgi_apply_config_pass('@', uwsgi_simple_file_read);
|
||||
uwsgi_apply_config_pass('@', uwsgi_at_file_read);
|
||||
|
||||
// last pass: REFERENCEs
|
||||
uwsgi_apply_config_pass('%', uwsgi_manage_placeholder);
|
||||
@@ -2147,7 +2198,7 @@ void uwsgi_setup(int argc, char *argv[], char *envp[]) {
|
||||
uwsgi_opt_flock(NULL, uwsgi.flock_wait2, NULL);
|
||||
|
||||
// setup master logging
|
||||
if (uwsgi.log_master && !uwsgi.daemonize2)
|
||||
if (uwsgi.log_master && !uwsgi.daemonize2 && !uwsgi.logto2)
|
||||
uwsgi_setup_log_master();
|
||||
|
||||
// setup offload engines
|
||||
@@ -2430,6 +2481,7 @@ int uwsgi_start(void *v_argv) {
|
||||
if (uwsgi.logto2) {
|
||||
if (!uwsgi.is_a_reload || uwsgi.log_reopen) {
|
||||
logto(uwsgi.logto2);
|
||||
uwsgi_setup_log_master();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2732,7 +2784,11 @@ int uwsgi_start(void *v_argv) {
|
||||
!uwsgi.command_mode &&
|
||||
!uwsgi.daemons_cnt &&
|
||||
!uwsgi.crons &&
|
||||
!uwsgi.spoolers &&
|
||||
!uwsgi.emperor_proxy
|
||||
#ifdef __linux__
|
||||
&& !uwsgi.setns_socket
|
||||
#endif
|
||||
#ifdef UWSGI_SSL
|
||||
&& !uwsgi.legions
|
||||
#endif
|
||||
@@ -2887,7 +2943,7 @@ unsafe:
|
||||
}
|
||||
|
||||
// initialize locks and socket as soon as possible, as the master could enqueue tasks
|
||||
if (uwsgi.spoolers != NULL && (uwsgi.sockets || uwsgi.loop)) {
|
||||
if (uwsgi.spoolers != NULL) {
|
||||
create_signal_pipe(uwsgi.shared->spooler_signal_pipe);
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
while (uspool) {
|
||||
@@ -3025,15 +3081,13 @@ next:
|
||||
|
||||
|
||||
|
||||
if (uwsgi.spoolers != NULL && (uwsgi.sockets || uwsgi.loop)) {
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
while (uspool) {
|
||||
if (uspool->mode == UWSGI_SPOOLER_EXTERNAL)
|
||||
goto next2;
|
||||
uspool->pid = spooler_start(uspool);
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
while (uspool) {
|
||||
if (uspool->mode == UWSGI_SPOOLER_EXTERNAL)
|
||||
goto next2;
|
||||
uspool->pid = spooler_start(uspool);
|
||||
next2:
|
||||
uspool = uspool->next;
|
||||
}
|
||||
uspool = uspool->next;
|
||||
}
|
||||
|
||||
if (!uwsgi.master_process) {
|
||||
@@ -3109,6 +3163,16 @@ int uwsgi_run() {
|
||||
//from now on the process is a real worker
|
||||
}
|
||||
|
||||
#if defined(__linux__) && defined(PR_SET_PDEATHSIG)
|
||||
// avoid workers running without master at all costs !!! (dangerous)
|
||||
if (uwsgi.master_process && uwsgi.no_orphans) {
|
||||
if (prctl(PR_SET_PDEATHSIG, SIGKILL)) {
|
||||
uwsgi_error("uwsgi_run()/prctl()");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// eventually maps (or disable) sockets for the worker
|
||||
uwsgi_map_sockets();
|
||||
|
||||
@@ -3600,6 +3664,13 @@ void uwsgi_init_all_apps() {
|
||||
if (uwsgi.need_app) {
|
||||
if (!uwsgi.lazy)
|
||||
uwsgi_log("*** no app loaded. GAME OVER ***\n");
|
||||
if (uwsgi.lazy_apps) {
|
||||
if (uwsgi.master_process) {
|
||||
if (kill(uwsgi.workers[0].pid, SIGINT)) {
|
||||
uwsgi_error("kill()");
|
||||
}
|
||||
}
|
||||
}
|
||||
exit(UWSGI_FAILED_APP_CODE);
|
||||
}
|
||||
else {
|
||||
|
||||
+9
-7
@@ -1,4 +1,4 @@
|
||||
#include "uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#define REQ_DATA wsgi_req->method_len, wsgi_req->method, wsgi_req->uri_len, wsgi_req->uri, wsgi_req->remote_addr_len, wsgi_req->remote_addr
|
||||
|
||||
static struct uwsgi_buffer *uwsgi_websocket_message(struct wsgi_request *wsgi_req, char *msg, size_t len, uint8_t opcode) {
|
||||
struct uwsgi_buffer *ub = wsgi_req->websocket_send_buf;
|
||||
if (!ub) {
|
||||
@@ -61,7 +63,7 @@ static int uwsgi_websockets_check_pingpong(struct wsgi_request *wsgi_req) {
|
||||
// pong not received ?
|
||||
if (wsgi_req->websocket_last_pong < wsgi_req->websocket_last_ping) {
|
||||
if (wsgi_req->websocket_last_ping - wsgi_req->websocket_last_pong > uwsgi.websockets_pong_tolerance) {
|
||||
uwsgi_log("[uwsgi-websocket] no PONG received in %d seconds !!!\n", uwsgi.websockets_pong_tolerance);
|
||||
uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) no PONG received in %d seconds !!!\n", REQ_DATA, uwsgi.websockets_pong_tolerance);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -189,7 +191,7 @@ static ssize_t uwsgi_websockets_recv_pkt(struct wsgi_request *wsgi_req, int nb)
|
||||
}
|
||||
goto wait;
|
||||
}
|
||||
uwsgi_error("uwsgi_websockets_recv_pkt()");
|
||||
uwsgi_req_error("uwsgi_websockets_recv_pkt()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -201,7 +203,7 @@ wait:
|
||||
if (rlen <= 0) return -1;
|
||||
}
|
||||
if (ret < 0) {
|
||||
uwsgi_error("uwsgi_websockets_recv_pkt()");
|
||||
uwsgi_req_error("uwsgi_websockets_recv_pkt()");
|
||||
return -1;
|
||||
}
|
||||
// send unsolicited pong
|
||||
@@ -254,11 +256,11 @@ static struct uwsgi_buffer *uwsgi_websocket_recv_do(struct wsgi_request *wsgi_re
|
||||
wsgi_req->websocket_size = uwsgi_be64(wsgi_req->websocket_buf->buf+2);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[uwsgi-websocket] BUG error in websocket parser\n");
|
||||
uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) BUG error in websocket parser\n", REQ_DATA);
|
||||
return NULL;
|
||||
}
|
||||
if (wsgi_req->websocket_size > (uwsgi.websockets_max_size*1024)) {
|
||||
uwsgi_log("[uwsgi-websocket] invalid packet size received: %llu, max allowed: %llu\n", wsgi_req->websocket_size, uwsgi.websockets_max_size * 1024);
|
||||
uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) invalid packet size received: %llu, max allowed: %llu\n", REQ_DATA, wsgi_req->websocket_size, uwsgi.websockets_max_size * 1024);
|
||||
return NULL;
|
||||
}
|
||||
wsgi_req->websocket_phase = 2;
|
||||
@@ -312,7 +314,7 @@ static struct uwsgi_buffer *uwsgi_websocket_recv_do(struct wsgi_request *wsgi_re
|
||||
break;
|
||||
// oops
|
||||
default:
|
||||
uwsgi_log("[uwsgi-websocket] BUG error in websocket parser\n");
|
||||
uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) BUG error in websocket parser\n", REQ_DATA);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
+31
-23
@@ -82,12 +82,14 @@ int uwsgi_response_prepare_headers(struct wsgi_request *wsgi_req, char *status,
|
||||
wsgi_req->status = uwsgi_str3_num(status);
|
||||
#ifdef UWSGI_ROUTING
|
||||
// apply error routes
|
||||
if (uwsgi_apply_error_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
// from now on ignore write body requests...
|
||||
wsgi_req->ignore_body = 1;
|
||||
return -1;
|
||||
if (wsgi_req->is_error_routing == 0) {
|
||||
if (uwsgi_apply_error_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
// from now on ignore write body requests...
|
||||
wsgi_req->ignore_body = 1;
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->is_error_routing = 0;
|
||||
}
|
||||
wsgi_req->is_error_routing = 0;
|
||||
#endif
|
||||
if (status_len <= 4) {
|
||||
char *new_sc = NULL;
|
||||
@@ -186,12 +188,14 @@ static int uwsgi_response_write_headers_do0(struct wsgi_request *wsgi_req) {
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
// apply response routes
|
||||
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
// from now on ignore write body requests...
|
||||
wsgi_req->ignore_body = 1;
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->is_response_routing = 0;
|
||||
if (wsgi_req->is_response_routing == 0) {
|
||||
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
// from now on ignore write body requests...
|
||||
wsgi_req->ignore_body = 1;
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->is_response_routing = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct uwsgi_string_list *ah = uwsgi.additional_headers;
|
||||
@@ -352,12 +356,14 @@ int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_
|
||||
// special case here, we could need to set transformations before
|
||||
if (!wsgi_req->headers_sent) {
|
||||
// apply response routes
|
||||
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
// from now on ignore write body requests...
|
||||
wsgi_req->ignore_body = 1;
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->is_response_routing = 0;
|
||||
if (wsgi_req->is_response_routing == 0) {
|
||||
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
// from now on ignore write body requests...
|
||||
wsgi_req->ignore_body = 1;
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->is_response_routing = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -435,12 +441,14 @@ int uwsgi_response_writev_body_do(struct wsgi_request *wsgi_req, struct iovec *i
|
||||
// special case here, we could need to set transformations before
|
||||
if (!wsgi_req->headers_sent) {
|
||||
// apply response routes
|
||||
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
// from now on ignore write body requests...
|
||||
wsgi_req->ignore_body = 1;
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->is_response_routing = 0;
|
||||
if (wsgi_req->is_response_routing == 0) {
|
||||
if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
// from now on ignore write body requests...
|
||||
wsgi_req->ignore_body = 1;
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->is_response_routing = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,378 @@
|
||||
#include "../python/uwsgi_python.h"
|
||||
|
||||
/*
|
||||
|
||||
python >= 3.4 asyncio (PEP 3156) loop engine
|
||||
|
||||
EXPERIMENTAL !!!
|
||||
|
||||
Author: Roberto De Ioris
|
||||
|
||||
*/
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
extern struct uwsgi_python up;
|
||||
|
||||
static struct uwsgi_asyncio {
|
||||
PyObject *mod;
|
||||
PyObject *loop;
|
||||
PyObject *request;
|
||||
PyObject *hook_fd;
|
||||
PyObject *hook_timeout;
|
||||
PyObject *hook_fix;
|
||||
} uasyncio;
|
||||
|
||||
#define free_req_queue uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = wsgi_req
|
||||
|
||||
static void uwsgi_opt_setup_asyncio(char *opt, char *value, void *null) {
|
||||
|
||||
// set async mode
|
||||
uwsgi_opt_set_int(opt, value, &uwsgi.async);
|
||||
if (uwsgi.socket_timeout < 30) {
|
||||
uwsgi.socket_timeout = 30;
|
||||
}
|
||||
// set loop engine
|
||||
uwsgi.loop = "asyncio";
|
||||
|
||||
}
|
||||
|
||||
static struct uwsgi_option asyncio_options[] = {
|
||||
{"asyncio", required_argument, 0, "a shortcut enabling asyncio loop engine with the specified number of async cores and optimal parameters", uwsgi_opt_setup_asyncio, NULL, UWSGI_OPT_THREADS},
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
|
||||
};
|
||||
|
||||
static void gil_asyncio_get() {
|
||||
pthread_setspecific(up.upt_gil_key, (void *) PyGILState_Ensure());
|
||||
}
|
||||
|
||||
static void gil_asyncio_release() {
|
||||
PyGILState_Release((PyGILState_STATE) pthread_getspecific(up.upt_gil_key));
|
||||
}
|
||||
|
||||
static int uwsgi_asyncio_wait_read_hook(int fd, int timeout) {
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
if (PyObject_CallMethod(uasyncio.loop, "add_reader", "iOl", fd, uasyncio.hook_fd,(long) wsgi_req) == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
PyObject *ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOl", timeout, uasyncio.hook_timeout, (long)wsgi_req);
|
||||
if (!ob_timeout) {
|
||||
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", fd) == NULL) PyErr_Print();
|
||||
goto error;
|
||||
}
|
||||
// back to loop
|
||||
if (uwsgi.schedule_to_main) uwsgi.schedule_to_main(wsgi_req);
|
||||
// back from loop
|
||||
|
||||
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", fd) == NULL) PyErr_Print();
|
||||
if (PyObject_CallMethod(ob_timeout, "cancel", NULL) == NULL) PyErr_Print();
|
||||
|
||||
Py_DECREF(ob_timeout);
|
||||
|
||||
if (wsgi_req->async_timed_out) return 0;
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
PyErr_Print();
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int uwsgi_asyncio_wait_write_hook(int fd, int timeout) {
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
if (PyObject_CallMethod(uasyncio.loop, "add_writer", "iOl", fd, uasyncio.hook_fd,(long) wsgi_req) == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
PyObject *ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOl", timeout, uasyncio.hook_timeout, (long)wsgi_req);
|
||||
if (!ob_timeout) {
|
||||
if (PyObject_CallMethod(uasyncio.loop, "remove_writer", "i", fd) == NULL) PyErr_Print();
|
||||
goto error;
|
||||
}
|
||||
// back to loop
|
||||
if (uwsgi.schedule_to_main) {
|
||||
uwsgi.schedule_to_main(wsgi_req);
|
||||
}
|
||||
// back from loop
|
||||
|
||||
if (PyObject_CallMethod(uasyncio.loop, "remove_writer", "i", fd) == NULL) PyErr_Print();
|
||||
if (PyObject_CallMethod(ob_timeout, "cancel", NULL) == NULL) PyErr_Print();
|
||||
|
||||
Py_DECREF(ob_timeout);
|
||||
|
||||
if (wsgi_req->async_timed_out) return 0;
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
PyErr_Print();
|
||||
return -1;
|
||||
}
|
||||
|
||||
static PyObject *py_uwsgi_asyncio_request(PyObject *self, PyObject *args) {
|
||||
long wsgi_req_ptr = 0;
|
||||
int timed_out = 0;
|
||||
if (!PyArg_ParseTuple(args, "l|i:uwsgi_asyncio_request", &wsgi_req_ptr, &timed_out)) {
|
||||
uwsgi_log_verbose("[BUG] invalid arguments for asyncio callback !!!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct wsgi_request *wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
|
||||
PyObject *ob_timeout = (PyObject *) wsgi_req->async_timeout;
|
||||
if (PyObject_CallMethod(ob_timeout, "cancel", NULL) == NULL) PyErr_Print();
|
||||
Py_DECREF(ob_timeout);
|
||||
// avoid mess when closing the request
|
||||
wsgi_req->async_timeout = NULL;
|
||||
|
||||
if (timed_out > 0) {
|
||||
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) PyErr_Print();
|
||||
goto end;
|
||||
}
|
||||
|
||||
int status = wsgi_req->socket->proto(wsgi_req);
|
||||
if (status > 0) {
|
||||
ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOli", uwsgi.socket_timeout, uasyncio.request, wsgi_req_ptr, 1);
|
||||
if (!ob_timeout) {
|
||||
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) PyErr_Print();
|
||||
goto end;
|
||||
}
|
||||
// trick for reference counting
|
||||
wsgi_req->async_timeout = (struct uwsgi_rb_timer *) ob_timeout;
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) {
|
||||
PyErr_Print();
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (status == 0) {
|
||||
// we call this two time... overengineering :(
|
||||
uwsgi.async_proto_fd_table[wsgi_req->fd] = NULL;
|
||||
uwsgi.schedule_to_req();
|
||||
goto again;
|
||||
}
|
||||
|
||||
end:
|
||||
uwsgi.async_proto_fd_table[wsgi_req->fd] = NULL;
|
||||
uwsgi_close_request(uwsgi.wsgi_req);
|
||||
free_req_queue;
|
||||
again:
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *py_uwsgi_asyncio_accept(PyObject *self, PyObject *args) {
|
||||
long uwsgi_sock_ptr = 0;
|
||||
if (!PyArg_ParseTuple(args, "l:uwsgi_asyncio_accept", &uwsgi_sock_ptr)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wsgi_request *wsgi_req = find_first_available_wsgi_req();
|
||||
|
||||
if (wsgi_req == NULL) {
|
||||
uwsgi_async_queue_is_full(uwsgi_now());
|
||||
goto end;
|
||||
}
|
||||
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
struct uwsgi_socket *uwsgi_sock = (struct uwsgi_socket *) uwsgi_sock_ptr;
|
||||
|
||||
// fill wsgi_request structure
|
||||
wsgi_req_setup(wsgi_req, wsgi_req->async_id, uwsgi_sock );
|
||||
|
||||
// mark core as used
|
||||
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 1;
|
||||
|
||||
// accept the connection (since uWSGI 1.5 all of the sockets are non-blocking)
|
||||
if (wsgi_req_simple_accept(wsgi_req, uwsgi_sock->fd)) {
|
||||
// in case of errors (or thundering herd, just reset it)
|
||||
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 0;
|
||||
free_req_queue;
|
||||
goto end;
|
||||
}
|
||||
|
||||
wsgi_req->start_of_request = uwsgi_micros();
|
||||
wsgi_req->start_of_request_in_sec = wsgi_req->start_of_request/1000000;
|
||||
|
||||
// enter harakiri mode
|
||||
if (uwsgi.harakiri_options.workers > 0) {
|
||||
set_harakiri(uwsgi.harakiri_options.workers);
|
||||
}
|
||||
|
||||
uwsgi.async_proto_fd_table[wsgi_req->fd] = wsgi_req;
|
||||
|
||||
// add callback for protocol
|
||||
if (PyObject_CallMethod(uasyncio.loop, "add_reader", "iOl", wsgi_req->fd, uasyncio.request, (long) wsgi_req) == NULL) {
|
||||
free_req_queue;
|
||||
PyErr_Print();
|
||||
}
|
||||
|
||||
// add timeout
|
||||
PyObject *ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOli", uwsgi.socket_timeout, uasyncio.request, (long)wsgi_req, 1);
|
||||
if (!ob_timeout) {
|
||||
if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) PyErr_Print();
|
||||
free_req_queue;
|
||||
}
|
||||
else {
|
||||
// trick for reference counting
|
||||
wsgi_req->async_timeout = (struct uwsgi_rb_timer *) ob_timeout;
|
||||
}
|
||||
end:
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_asyncio_hook_fd(PyObject *self, PyObject *args) {
|
||||
long wsgi_req_ptr = 0;
|
||||
if (!PyArg_ParseTuple(args, "l:uwsgi_asyncio_hook_fd", &wsgi_req_ptr)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
|
||||
uwsgi.schedule_to_req();
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_asyncio_hook_timeout(PyObject *self, PyObject *args) {
|
||||
long wsgi_req_ptr = 0;
|
||||
if (!PyArg_ParseTuple(args, "l", &wsgi_req_ptr)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
|
||||
uwsgi.wsgi_req->async_timed_out = 1;
|
||||
uwsgi.schedule_to_req();
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_asyncio_hook_fix(PyObject *self, PyObject *args) {
|
||||
long wsgi_req_ptr = 0;
|
||||
if (!PyArg_ParseTuple(args, "l", &wsgi_req_ptr)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr;
|
||||
uwsgi.schedule_to_req();
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
PyMethodDef uwsgi_asyncio_accept_def[] = { {"uwsgi_asyncio_accept", py_uwsgi_asyncio_accept, METH_VARARGS, ""} };
|
||||
PyMethodDef uwsgi_asyncio_request_def[] = { {"uwsgi_asyncio_request", py_uwsgi_asyncio_request, METH_VARARGS, ""} };
|
||||
PyMethodDef uwsgi_asyncio_hook_fd_def[] = { {"uwsgi_asyncio_hook_fd", py_uwsgi_asyncio_hook_fd, METH_VARARGS, ""} };
|
||||
PyMethodDef uwsgi_asyncio_hook_timeout_def[] = { {"uwsgi_asyncio_hook_timeout", py_uwsgi_asyncio_hook_timeout, METH_VARARGS, ""} };
|
||||
PyMethodDef uwsgi_asyncio_hook_fix_def[] = { {"uwsgi_asyncio_hook_fix", py_uwsgi_asyncio_hook_fix, METH_VARARGS, ""} };
|
||||
|
||||
static void uwsgi_asyncio_schedule_fix(struct wsgi_request *wsgi_req) {
|
||||
PyObject *cb = PyObject_CallMethod(uasyncio.loop, "call_soon", "Ol", uasyncio.hook_fix, (long) wsgi_req);
|
||||
if (!cb) goto error;
|
||||
Py_DECREF(cb);
|
||||
return;
|
||||
|
||||
error:
|
||||
PyErr_Print();
|
||||
}
|
||||
|
||||
static void asyncio_loop() {
|
||||
|
||||
if (!uwsgi.has_threads && uwsgi.mywid == 1) {
|
||||
uwsgi_log("!!! Running asyncio without threads IS NOT recommended, enable them with --enable-threads !!!\n");
|
||||
}
|
||||
|
||||
if (uwsgi.socket_timeout < 30) {
|
||||
uwsgi_log("!!! Running asyncio with a socket-timeout lower than 30 seconds is not recommended, tune it with --socket-timeout !!!\n");
|
||||
}
|
||||
|
||||
if (!uwsgi.async_waiting_fd_table)
|
||||
uwsgi.async_waiting_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
|
||||
if (!uwsgi.async_proto_fd_table)
|
||||
uwsgi.async_proto_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
|
||||
|
||||
// get the GIL
|
||||
UWSGI_GET_GIL
|
||||
|
||||
up.gil_get = gil_asyncio_get;
|
||||
up.gil_release = gil_asyncio_release;
|
||||
|
||||
uwsgi.wait_write_hook = uwsgi_asyncio_wait_write_hook;
|
||||
uwsgi.wait_read_hook = uwsgi_asyncio_wait_read_hook;
|
||||
|
||||
uwsgi.schedule_fix = uwsgi_asyncio_schedule_fix;
|
||||
|
||||
if (uwsgi.async < 2) {
|
||||
uwsgi_log("the asyncio loop engine requires async mode (--async <n>)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!uwsgi.schedule_to_main) {
|
||||
uwsgi_log("*** DANGER *** asyncio mode without coroutine/greenthread engine loaded !!!\n");
|
||||
}
|
||||
|
||||
PyObject *asyncio = PyImport_ImportModule("asyncio");
|
||||
if (!asyncio) uwsgi_pyexit;
|
||||
|
||||
uasyncio.mod = asyncio;
|
||||
|
||||
uasyncio.loop = PyObject_CallMethod(asyncio, "get_event_loop", NULL);
|
||||
if (!uasyncio.loop) uwsgi_pyexit;
|
||||
|
||||
// main greenlet waiting for connection (one greenlet per-socket)
|
||||
PyObject *asyncio_accept = PyCFunction_New(uwsgi_asyncio_accept_def, NULL);
|
||||
Py_INCREF(asyncio_accept);
|
||||
|
||||
uasyncio.request = PyCFunction_New(uwsgi_asyncio_request_def, NULL);
|
||||
if (!uasyncio.request) uwsgi_pyexit;
|
||||
|
||||
uasyncio.hook_fd = PyCFunction_New(uwsgi_asyncio_hook_fd_def, NULL);
|
||||
if (!uasyncio.hook_fd) uwsgi_pyexit;
|
||||
uasyncio.hook_timeout = PyCFunction_New(uwsgi_asyncio_hook_timeout_def, NULL);
|
||||
if (!uasyncio.hook_timeout) uwsgi_pyexit;
|
||||
uasyncio.hook_fix = PyCFunction_New(uwsgi_asyncio_hook_fix_def, NULL);
|
||||
if (!uasyncio.hook_fix) uwsgi_pyexit;
|
||||
|
||||
Py_INCREF(uasyncio.request);
|
||||
Py_INCREF(uasyncio.hook_fd);
|
||||
Py_INCREF(uasyncio.hook_timeout);
|
||||
Py_INCREF(uasyncio.hook_fix);
|
||||
|
||||
// call add_handler on each socket
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
while(uwsgi_sock) {
|
||||
if (PyObject_CallMethod(uasyncio.loop, "add_reader", "iOi", uwsgi_sock->fd, asyncio_accept, (long) uwsgi_sock) == NULL) {
|
||||
uwsgi_pyexit;
|
||||
}
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
if (PyObject_CallMethod(uasyncio.loop, "run_forever", NULL) == NULL) {
|
||||
uwsgi_pyexit;
|
||||
}
|
||||
|
||||
// never here ?
|
||||
}
|
||||
|
||||
static void asyncio_init() {
|
||||
uwsgi_register_loop( (char *) "asyncio", asyncio_loop);
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_plugin asyncio_plugin = {
|
||||
.name = "asyncio",
|
||||
.options = asyncio_options,
|
||||
.on_load = asyncio_init,
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
from distutils import sysconfig
|
||||
|
||||
NAME='asyncio'
|
||||
CFLAGS = ['-I' + sysconfig.get_python_inc(), '-I' + sysconfig.get_python_inc(plat_specific=True)]
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
|
||||
GCC_LIST = ['asyncio']
|
||||
+217
-132
@@ -2,6 +2,8 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
#define kill_on_error if (!uc.do_not_kill_on_error) { if (kill(cgi_pid, SIGKILL)) uwsgi_error("kill()");}
|
||||
|
||||
struct uwsgi_cgi {
|
||||
struct uwsgi_dyn_dict *mountpoint;
|
||||
struct uwsgi_dyn_dict *helpers;
|
||||
@@ -16,6 +18,8 @@ struct uwsgi_cgi {
|
||||
int has_mountpoints;
|
||||
struct uwsgi_dyn_dict *default_cgi;
|
||||
int path_info;
|
||||
int do_not_kill_on_error;
|
||||
int async_max_attempts;
|
||||
} uc ;
|
||||
|
||||
static void uwsgi_opt_add_cgi(char *opt, char *value, void *foobar) {
|
||||
@@ -62,6 +66,9 @@ struct uwsgi_option uwsgi_cgi_options[] = {
|
||||
|
||||
{"cgi-path-info", no_argument, 0, "disable PATH_INFO management in cgi scripts", uwsgi_opt_true, &uc.path_info, 0},
|
||||
|
||||
{"cgi-do-not-kill-on-error", no_argument, 0, "do not send SIGKILL to cgi script on errors", uwsgi_opt_true, &uc.do_not_kill_on_error, 0},
|
||||
{"cgi-async-max-attempts", no_argument, 0, "max waitpid() attempts in cgi async mode (default 10)", uwsgi_opt_set_int, &uc.async_max_attempts, 0},
|
||||
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
|
||||
};
|
||||
@@ -179,78 +186,154 @@ static char *uwsgi_cgi_get_helper(char *filename) {
|
||||
|
||||
}
|
||||
|
||||
static int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
|
||||
size_t i;
|
||||
/*
|
||||
start reading each line until Status or Location are found
|
||||
-1 error
|
||||
0 not found
|
||||
1 found
|
||||
*/
|
||||
static int uwsgi_cgi_check_status(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
char *key = buf, *value = NULL;
|
||||
size_t header_size = 0;
|
||||
int status_sent = 0;
|
||||
size_t i;
|
||||
|
||||
for(i=0;i<len;i++) {
|
||||
// end of a line
|
||||
if (buf[i] == '\n') {
|
||||
// end of headers
|
||||
if (key == NULL) {
|
||||
i++;
|
||||
goto send_body;
|
||||
// end of a line
|
||||
if (buf[i] == '\n') {
|
||||
// end of headers
|
||||
if (key == NULL) {
|
||||
// Default status
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("setting default Status header\n");
|
||||
#endif
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1;
|
||||
return 1;
|
||||
}
|
||||
// invalid header
|
||||
else if (value == NULL) {
|
||||
return -1;
|
||||
// invalid header
|
||||
else if (value == NULL) return -1;
|
||||
header_size = (buf+i) - key;
|
||||
// security check
|
||||
if (buf+i > buf) {
|
||||
// remove \r
|
||||
if ((buf[i-1]) == '\r') {
|
||||
header_size--;
|
||||
}
|
||||
}
|
||||
|
||||
// enough space for Status ?
|
||||
if (header_size >= 11) {
|
||||
// "Status: NNN"
|
||||
if (!strncasecmp("Status: ", key, 8)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("found Status header: %.*s\n", header_size, key);
|
||||
#endif
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, key+8, header_size - 8)) return -1;
|
||||
return 1;
|
||||
}
|
||||
// Location: X
|
||||
if (!strncasecmp("Location: ", key, 10)) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("found Location header: %.*s\n", header_size, key);
|
||||
#endif
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "302 Found", 9)) return -1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
header_size = (buf+i) - key;
|
||||
// security check
|
||||
if (buf+i > buf) {
|
||||
if ((buf[i-1]) == '\r') {
|
||||
header_size--;
|
||||
|
||||
key = NULL;
|
||||
value = NULL;
|
||||
}
|
||||
else if (buf[i] == ':') {
|
||||
value = buf+i;
|
||||
}
|
||||
else if (buf[i] != '\r') {
|
||||
if (key == NULL) key = buf + i;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// no Status/Location found
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, int fd, char *buf, size_t blen) {
|
||||
|
||||
size_t i;
|
||||
size_t header_size = 0;
|
||||
int status_sent = 0;
|
||||
size_t remains = blen;
|
||||
char *ptr = buf;
|
||||
size_t len = 0;
|
||||
|
||||
while(remains > 0) {
|
||||
ssize_t rlen = uwsgi_read_true_nb(fd, ptr, remains, uc.timeout);
|
||||
if (rlen < 0) {
|
||||
if (!errno) return 1;
|
||||
return -1;
|
||||
}
|
||||
// timed out
|
||||
if (rlen == 0) return -1;
|
||||
remains -= rlen;
|
||||
len += rlen;
|
||||
ptr += rlen;
|
||||
|
||||
// Search for Status/Location headers
|
||||
if (!status_sent) {
|
||||
status_sent = uwsgi_cgi_check_status(wsgi_req, buf, len);
|
||||
if (status_sent < 0) return -1;
|
||||
// need more data ?
|
||||
if (status_sent == 0) continue;
|
||||
}
|
||||
|
||||
// send headers
|
||||
char *key = buf;
|
||||
char *value = NULL;
|
||||
|
||||
for(i=0;i<len;i++) {
|
||||
// end of a line
|
||||
if (buf[i] == '\n') {
|
||||
// end of headers
|
||||
if (key == NULL) {
|
||||
i++;
|
||||
goto send_body;
|
||||
}
|
||||
// invalid header
|
||||
else if (value == NULL) {
|
||||
return -1;
|
||||
}
|
||||
header_size = (buf+i) - key;
|
||||
// security check
|
||||
if (buf+i > buf) {
|
||||
if ((buf[i-1]) == '\r') {
|
||||
header_size--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("found CGI header: %.*s\n", header_size, key);
|
||||
uwsgi_log("found CGI header: %.*s\n", header_size, key);
|
||||
#endif
|
||||
|
||||
if (status_sent == 0) {
|
||||
// "Status: NNN"
|
||||
// Ignore "Status: NNN" header
|
||||
if (header_size >= 11) {
|
||||
if (!strncasecmp("Status: ", key, 8)) {
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, key+8, header_size - 8)) return -1;
|
||||
status_sent = 1;
|
||||
key = NULL;
|
||||
value = NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi_response_add_header(wsgi_req, NULL, 0, key, header_size);
|
||||
key = NULL;
|
||||
value = NULL;
|
||||
}
|
||||
|
||||
// default status
|
||||
if (status_sent == 0) {
|
||||
|
||||
// Location: X
|
||||
if (header_size >= 11) {
|
||||
if (!strncasecmp("Location: ", key, 10)) {
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "302 Found", 9)) return -1;
|
||||
status_sent = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (status_sent == 0) {
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1;
|
||||
status_sent = 1;
|
||||
}
|
||||
else if (buf[i] == ':') {
|
||||
value = buf+i;
|
||||
}
|
||||
|
||||
uwsgi_response_add_header(wsgi_req, NULL, 0, key, header_size);
|
||||
|
||||
key = NULL;
|
||||
value = NULL;
|
||||
}
|
||||
else if (buf[i] == ':') {
|
||||
value = buf+i;
|
||||
}
|
||||
else if (buf[i] != '\r') {
|
||||
if (key == NULL) {
|
||||
key = buf + i;
|
||||
else if (buf[i] != '\r') {
|
||||
if (key == NULL) {
|
||||
key = buf + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -552,7 +635,6 @@ static int uwsgi_cgi_run(struct wsgi_request *wsgi_req, char *docroot, size_t do
|
||||
int post_pipe[2];
|
||||
int nargs = 0;
|
||||
int waitpid_status;
|
||||
ssize_t len;
|
||||
int i;
|
||||
char **argv;
|
||||
|
||||
@@ -590,126 +672,96 @@ static int uwsgi_cgi_run(struct wsgi_request *wsgi_req, char *docroot, size_t do
|
||||
close(cgi_pipe[1]);
|
||||
close(post_pipe[0]);
|
||||
|
||||
uwsgi_socket_nb(cgi_pipe[0]);
|
||||
uwsgi_socket_nb(post_pipe[1]);
|
||||
|
||||
// ok start sending post data...
|
||||
size_t remains = wsgi_req->post_cl;
|
||||
while(remains > 0) {
|
||||
ssize_t rlen = 0;
|
||||
char *buf = uwsgi_request_body_read(wsgi_req, 8192, &rlen);
|
||||
if (!buf) {
|
||||
close(post_pipe[1]);
|
||||
goto clear2;
|
||||
}
|
||||
if (buf == uwsgi.empty) break;
|
||||
// write data to the node
|
||||
if (uwsgi_write_true_nb(post_pipe[1], buf, rlen, uc.timeout)) {
|
||||
close(post_pipe[1]);
|
||||
goto clear2;
|
||||
}
|
||||
remains -= rlen;
|
||||
}
|
||||
|
||||
close(post_pipe[1]);
|
||||
// wait for data
|
||||
char *headers_buf = uwsgi_malloc(uc.buffer_size);
|
||||
char *ptr = headers_buf;
|
||||
remains = uc.buffer_size;
|
||||
int completed = 0;
|
||||
while(remains > 0) {
|
||||
int ret = uwsgi.wait_read_hook(cgi_pipe[0], uc.timeout);
|
||||
if (ret > 0) {
|
||||
len = read(cgi_pipe[0], ptr, remains);
|
||||
if (len > 0) {
|
||||
ptr+=len;
|
||||
remains -= len;
|
||||
}
|
||||
else if (len == 0) {
|
||||
completed = 1;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
uwsgi_error("read()");
|
||||
goto clear;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (ret == 0) {
|
||||
uwsgi_log("CGI timeout !!!\n");
|
||||
goto clear;
|
||||
}
|
||||
break;
|
||||
}
|
||||
char *buf = uwsgi_malloc(uc.buffer_size);
|
||||
|
||||
if (uwsgi_cgi_parse(wsgi_req, headers_buf, uc.buffer_size-remains)) {
|
||||
uwsgi_log("invalid CGI output !!!\n");
|
||||
int completed = uwsgi_cgi_parse(wsgi_req, cgi_pipe[0], buf, uc.buffer_size);
|
||||
if (completed < 0) {
|
||||
uwsgi_log("invalid CGI response !!!\n");
|
||||
kill_on_error
|
||||
goto clear;
|
||||
}
|
||||
|
||||
while (!completed) {
|
||||
int ret = uwsgi.wait_read_hook(cgi_pipe[0], uc.timeout);
|
||||
if (ret > 0) {
|
||||
len = read(cgi_pipe[0], headers_buf, uc.buffer_size);
|
||||
if (len > 0) {
|
||||
uwsgi_response_write_body_do(wsgi_req, headers_buf, len);
|
||||
}
|
||||
// end of output
|
||||
else if (len == 0) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
uwsgi_error("read()");
|
||||
ssize_t rlen = uwsgi_read_true_nb(cgi_pipe[0], buf, uc.buffer_size, uc.timeout);
|
||||
if (rlen > 0) {
|
||||
if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) {
|
||||
kill_on_error
|
||||
goto clear;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (ret == 0) {
|
||||
uwsgi_log("CGI timeout !!!\n");
|
||||
goto clear;
|
||||
}
|
||||
break;
|
||||
else if (rlen == 0) {
|
||||
uwsgi_log("CGI timeout !!!\n");
|
||||
kill_on_error
|
||||
goto clear;
|
||||
}
|
||||
else {
|
||||
if (errno) {
|
||||
uwsgi_req_error("error reading CGI response\n");
|
||||
kill_on_error
|
||||
}
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
|
||||
clear:
|
||||
free(headers_buf);
|
||||
free(buf);
|
||||
clear2:
|
||||
close(cgi_pipe[0]);
|
||||
close(post_pipe[1]);
|
||||
|
||||
// now wait for process exit/death
|
||||
if (waitpid(cgi_pid, &waitpid_status, 0) < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
// in async mode we need a trick...
|
||||
if (uwsgi.async > 1) {
|
||||
pid_t diedpid = waitpid(cgi_pid, &waitpid_status, WNOHANG);
|
||||
if (diedpid < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
}
|
||||
else if (diedpid == 0) {
|
||||
// pass the pid of the cgi to async_plagued (the after request hook will clear the process)
|
||||
wsgi_req->async_plagued = (int) cgi_pid;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (waitpid(cgi_pid, &waitpid_status, 0) < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
}
|
||||
}
|
||||
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
// close all the fd except wsgi_req->poll.fd and 2;
|
||||
|
||||
for(i=0;i< (int)uwsgi.max_fd;i++) {
|
||||
if (post_pipe[0] == i) {
|
||||
continue;
|
||||
}
|
||||
if (wsgi_req->post_file) {
|
||||
if (fileno(wsgi_req->post_file) == i) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (i != wsgi_req->fd && i != 2 && i != cgi_pipe[1]) {
|
||||
close(i);
|
||||
}
|
||||
}
|
||||
|
||||
// now map wsgi_req->poll.fd (or async_post) to 0 & cgi_pipe[1] to 1
|
||||
if (post_pipe[0] != 0) {
|
||||
dup2(post_pipe[0], 0);
|
||||
close(post_pipe[0]);
|
||||
}
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("mapping cgi_pipe %d to 1\n", cgi_pipe[1]);
|
||||
#endif
|
||||
dup2(post_pipe[0], 0);
|
||||
close(post_pipe[0]);
|
||||
|
||||
dup2(cgi_pipe[1],1);
|
||||
|
||||
close(cgi_pipe[1]);
|
||||
|
||||
// close all the fd > 2
|
||||
for(i=3;i<(int)uwsgi.max_fd;i++) {
|
||||
close(i);
|
||||
}
|
||||
|
||||
// fill cgi env
|
||||
for(i=0;i<wsgi_req->var_cnt;i++) {
|
||||
// no need to free the putenv() memory
|
||||
@@ -873,6 +925,39 @@ clear2:
|
||||
|
||||
|
||||
static void uwsgi_cgi_after_request(struct wsgi_request *wsgi_req) {
|
||||
if (wsgi_req->async_plagued > 0) {
|
||||
int waitpid_status;
|
||||
pid_t cgi_pid = (pid_t) wsgi_req->async_plagued;
|
||||
int max_attempts = uc.async_max_attempts;
|
||||
if (!max_attempts) max_attempts = 10;
|
||||
while(max_attempts) {
|
||||
pid_t diedpid = waitpid(cgi_pid, &waitpid_status, WNOHANG);
|
||||
if (diedpid < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
break;
|
||||
}
|
||||
else if (diedpid == 0) {
|
||||
int ret = uwsgi.wait_milliseconds_hook(1000);
|
||||
if (ret < 0) {
|
||||
kill_on_error
|
||||
if (waitpid(cgi_pid, &waitpid_status, 0) < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
max_attempts--;
|
||||
}
|
||||
if (max_attempts == 0) {
|
||||
kill_on_error
|
||||
if (waitpid(cgi_pid, &waitpid_status, 0) < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log_request(wsgi_req);
|
||||
}
|
||||
|
||||
|
||||
@@ -201,9 +201,11 @@ int cheaper_busyness_algo(int can_spawn) {
|
||||
}
|
||||
|
||||
avg_busyness = (active_workers ? total_busyness / active_workers : 0);
|
||||
uwsgi_wlock(uwsgi.metrics_lock);
|
||||
uwsgi_cheaper_busyness_global.total_avg_busyness = avg_busyness;
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
if (uwsgi.has_metrics) {
|
||||
uwsgi_wlock(uwsgi.metrics_lock);
|
||||
uwsgi_cheaper_busyness_global.total_avg_busyness = avg_busyness;
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
}
|
||||
|
||||
if (uwsgi_cheaper_busyness_global.verbose)
|
||||
uwsgi_log("[busyness] %ds average busyness of %d worker(s) is at %d%%\n",
|
||||
|
||||
@@ -41,8 +41,11 @@ struct corerouter_peer *uwsgi_cr_peer_add(struct corerouter_session *cs) {
|
||||
peers->session = cs;
|
||||
peers->fd = -1;
|
||||
// create input buffer
|
||||
peers->in = uwsgi_buffer_new(uwsgi.page_size);
|
||||
size_t bufsize = cs->corerouter->buffer_size;
|
||||
if (!bufsize) bufsize = uwsgi.page_size;
|
||||
peers->in = uwsgi_buffer_new(bufsize);
|
||||
// add timeout
|
||||
peers->current_timeout = cs->corerouter->socket_timeout;
|
||||
peers->timeout = cr_add_timeout(cs->corerouter, peers);
|
||||
peers->prev = old_peers;
|
||||
|
||||
@@ -284,6 +287,10 @@ void corerouter_manage_subscription(char *key, uint16_t keylen, char *val, uint1
|
||||
usr->sni_ca = val;
|
||||
usr->sni_ca_len = vallen;
|
||||
}
|
||||
else if (!uwsgi_strncmp("notify", 6, key, keylen)) {
|
||||
usr->notify = val;
|
||||
usr->notify_len = vallen;
|
||||
}
|
||||
}
|
||||
|
||||
void corerouter_close_peer(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) {
|
||||
@@ -562,7 +569,9 @@ struct corerouter_session *corerouter_alloc_session(struct uwsgi_corerouter *ucr
|
||||
|
||||
struct corerouter_peer *peer = uwsgi_calloc(sizeof(struct corerouter_peer));
|
||||
// main_peer has only input buffer as output buffer is taken from backend peers
|
||||
peer->in = uwsgi_buffer_new(uwsgi.page_size);
|
||||
size_t bufsize = ucr->buffer_size;
|
||||
if (!bufsize) bufsize = uwsgi.page_size;
|
||||
peer->in = uwsgi_buffer_new(bufsize);
|
||||
|
||||
ucr->cr_table[new_connection] = peer;
|
||||
cs->main_peer = peer;
|
||||
@@ -574,8 +583,8 @@ struct corerouter_session *corerouter_alloc_session(struct uwsgi_corerouter *ucr
|
||||
cs->corerouter = ucr;
|
||||
cs->ugs = ugs;
|
||||
|
||||
// set initial timeout
|
||||
peer->timeout = cr_add_timeout(ucr, ucr->cr_table[new_connection]);
|
||||
// set initial timeout (could be overridden)
|
||||
peer->current_timeout = ucr->socket_timeout;
|
||||
|
||||
ucr->active_sessions++;
|
||||
|
||||
@@ -614,6 +623,10 @@ struct corerouter_session *corerouter_alloc_session(struct uwsgi_corerouter *ucr
|
||||
corerouter_close_session(ucr, cs);
|
||||
cs = NULL;
|
||||
}
|
||||
else {
|
||||
// truly set the timeout
|
||||
peer->timeout = cr_add_timeout(ucr, ucr->cr_table[new_connection]);
|
||||
}
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
+11
-4
@@ -3,12 +3,12 @@
|
||||
#define COREROUTER_STATUS_RECV_HDR 2
|
||||
#define COREROUTER_STATUS_RESPONSE 3
|
||||
|
||||
#define cr_add_timeout(u, x) uwsgi_add_rb_timer(u->timeouts, uwsgi_now()+u->socket_timeout, x)
|
||||
#define cr_add_timeout_fast(u, x, t) uwsgi_add_rb_timer(u->timeouts, t+u->socket_timeout, x)
|
||||
#define cr_add_timeout(u, x) uwsgi_add_rb_timer(u->timeouts, uwsgi_now()+x->current_timeout, x)
|
||||
#define cr_add_timeout_fast(u, x, t) uwsgi_add_rb_timer(u->timeouts, t+x->current_timeout, x)
|
||||
#define cr_del_timeout(u, x) uwsgi_del_rb_timer(u->timeouts, x->timeout); free(x->timeout);
|
||||
|
||||
#define uwsgi_cr_error(x, y) uwsgi_log("[uwsgi-%s client_addr: %s client_port: %s] %s: %s [%s line %d]\n", x->session->corerouter->short_name, x->session->client_address, x->session->client_port, y, strerror(errno), __FILE__, __LINE__)
|
||||
#define uwsgi_cr_log(x, y, ...) uwsgi_log("[uwsgi-%s client_addr: %s client_port: %s]" y, x->session->corerouter->short_name, x->session->client_address, x->session->client_port, __VA_ARGS__)
|
||||
#define uwsgi_cr_error(x, y) uwsgi_log("[uwsgi-%s key: %.*s client_addr: %s client_port: %s] %s: %s [%s line %d]\n", x->session->corerouter->short_name, (x == x->session->main_peer) ? (x->session->peers ? x->session->peers->key_len: 0) : x->key_len, (x == x->session->main_peer) ? (x->session->peers ? x->session->peers->key: "") : x->key, x->session->client_address, x->session->client_port, y, strerror(errno), __FILE__, __LINE__)
|
||||
#define uwsgi_cr_log(x, y, ...) uwsgi_log("[uwsgi-%s key: %.*s client_addr: %s client_port: %s]" y, x->session->corerouter->short_name, (x == x->session->main_peer) ? (x->session->peers ? x->session->peers->key_len: 0) : x->key_len, (x == x->session->main_peer) ? (x->session->peers ? x->session->peers->key: "") : x->key, x->session->client_address, x->session->client_port, __VA_ARGS__)
|
||||
|
||||
#define cr_try_again if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {\
|
||||
errno = EINPROGRESS;\
|
||||
@@ -188,6 +188,8 @@ struct corerouter_peer {
|
||||
|
||||
struct corerouter_peer *prev;
|
||||
struct corerouter_peer *next;
|
||||
|
||||
int current_timeout;
|
||||
};
|
||||
|
||||
struct uwsgi_corerouter {
|
||||
@@ -265,6 +267,11 @@ struct uwsgi_corerouter {
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
|
||||
struct uwsgi_string_list *resubscribe;
|
||||
char *resubscribe_bind;
|
||||
|
||||
size_t buffer_size;
|
||||
|
||||
};
|
||||
|
||||
// a session is started when a client connect to the router
|
||||
|
||||
@@ -154,10 +154,6 @@ void uwsgi_corerouter_manage_subscription(struct uwsgi_corerouter *ucr, int id,
|
||||
if (node && node->len) {
|
||||
#ifdef UWSGI_SSL
|
||||
if (uwsgi.subscriptions_sign_check_dir) {
|
||||
if (usr.sign_len == 0 || usr.base_len == 0)
|
||||
return;
|
||||
if (usr.unix_check <= node->unix_check)
|
||||
return;
|
||||
if (!uwsgi_subscription_sign_check(node->slot, &usr)) {
|
||||
return;
|
||||
}
|
||||
@@ -187,6 +183,51 @@ void uwsgi_corerouter_manage_subscription(struct uwsgi_corerouter *ucr, int id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// resubscribe if needed ?
|
||||
if (ucr->resubscribe) {
|
||||
static char *address = NULL;
|
||||
if (!address) {
|
||||
struct uwsgi_gateway_socket *augs = uwsgi.gateway_sockets;
|
||||
while (augs) {
|
||||
if (!strcmp(ucr->name, augs->owner)) {
|
||||
if (!augs->subscription) {
|
||||
address = augs->name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
augs = augs->next;
|
||||
}
|
||||
}
|
||||
struct uwsgi_string_list *usl = NULL;
|
||||
char *sni_key = NULL;
|
||||
char *sni_cert = NULL;
|
||||
char *sni_ca = NULL;
|
||||
if (usr.sni_key_len) {
|
||||
sni_key = uwsgi_concat2n(usr.sni_key, usr.sni_key_len, "", 0);
|
||||
}
|
||||
if (usr.sni_crt_len) {
|
||||
sni_cert = uwsgi_concat2n(usr.sni_crt, usr.sni_crt_len, "", 0);
|
||||
}
|
||||
if (usr.sni_ca_len) {
|
||||
sni_ca = uwsgi_concat2n(usr.sni_ca, usr.sni_ca_len, "", 0);
|
||||
}
|
||||
uwsgi_foreach(usl, ucr->resubscribe) {
|
||||
if (ucr->resubscribe_bind) {
|
||||
static int rfd = -1;
|
||||
if (rfd == -1) {
|
||||
rfd = bind_to_udp(ucr->resubscribe_bind, 0, 0);
|
||||
}
|
||||
uwsgi_send_subscription_from_fd(rfd, usl->value, usr.key, usr.keylen, usr.modifier1, usr.modifier2, bbuf[3], address, NULL, sni_key, sni_cert, sni_ca);
|
||||
}
|
||||
else {
|
||||
uwsgi_send_subscription_from_fd(-2, usl->value, usr.key, usr.keylen, usr.modifier1, usr.modifier2, bbuf[3], address, NULL, sni_key, sni_cert, sni_ca);
|
||||
}
|
||||
}
|
||||
if (sni_key) free(sni_key);
|
||||
if (sni_cert) free(sni_cert);
|
||||
if (sni_ca) free(sni_ca);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -65,8 +65,11 @@ int uwsgi_cr_map_use_subscription_dotsplit(struct uwsgi_corerouter *ucr, struct
|
||||
|
||||
char *name = peer->key;
|
||||
uint16_t name_len = peer->key_len;
|
||||
// max 5 split, reduce DOS attempts
|
||||
int count = 5;
|
||||
|
||||
split:
|
||||
if (!count) return 0;
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("trying with %.*s\n", name_len, name);
|
||||
#endif
|
||||
@@ -76,6 +79,7 @@ split:
|
||||
if (next) {
|
||||
name_len -= next - name;
|
||||
name = next;
|
||||
count--;
|
||||
goto split;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-15
@@ -386,21 +386,9 @@ static void coroae_loop() {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
perl_eval_pv("use Coro;", 0);
|
||||
if (SvTRUE(ERRSV)) {
|
||||
uwsgi_log("unable to load Coro module\n");
|
||||
exit(1);
|
||||
}
|
||||
perl_eval_pv("use AnyEvent;", 0);
|
||||
if (SvTRUE(ERRSV)) {
|
||||
uwsgi_log("unable to load AnyEvent module\n");
|
||||
exit(1);
|
||||
}
|
||||
perl_eval_pv("use Coro::AnyEvent;", 0);
|
||||
if (SvTRUE(ERRSV)) {
|
||||
uwsgi_log("unable to load Coro::AnyEvent module\n");
|
||||
exit(1);
|
||||
}
|
||||
perl_eval_pv("use Coro;", 1);
|
||||
perl_eval_pv("use AnyEvent;", 1);
|
||||
perl_eval_pv("use Coro::AnyEvent;", 1);
|
||||
|
||||
uwsgi.current_wsgi_req = coroae_current_wsgi_req;
|
||||
uwsgi.wait_write_hook = coroae_wait_fd_write;
|
||||
|
||||
@@ -10,6 +10,10 @@ struct uwsgi_emperor_mongodb_state {
|
||||
char *address;
|
||||
char *collection;
|
||||
char *json;
|
||||
char *database;
|
||||
char *username;
|
||||
char *password;
|
||||
char *predigest;
|
||||
};
|
||||
|
||||
|
||||
@@ -20,7 +24,7 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
|
||||
try {
|
||||
|
||||
// requested fields
|
||||
mongo::BSONObj p = BSON( "name" << 1 << "config" << 1 << "ts" << 1 << "uid" << 1 << "gid" << 1 );
|
||||
mongo::BSONObj p = BSON( "name" << 1 << "config" << 1 << "ts" << 1 << "uid" << 1 << "gid" << 1 << "socket" << 1 );
|
||||
mongo::BSONObj q = mongo::fromjson(uems->json);
|
||||
// the connection object (will be automatically destroyed at each cycle)
|
||||
mongo::DBClientConnection c;
|
||||
@@ -29,9 +33,17 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
|
||||
// connect
|
||||
c.connect(uems->address);
|
||||
|
||||
if (uems->database && uems->username && uems->password) {
|
||||
std::string err;
|
||||
if (c.auth(uems->database, uems->username, uems->password, err, uems->predigest ? false : true) == false) {
|
||||
uwsgi_log_verbose("[emperor-mongodb] unabel to authenticate to db %s: %s\n", uems->database, err.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// run the query
|
||||
std::auto_ptr<mongo::DBClientCursor> cursor = c.query(uems->collection, q, 0, 0, &p);
|
||||
while( cursor->more() ) {
|
||||
while(cursor.get() && cursor->more() ) {
|
||||
mongo::BSONObj p = cursor->next();
|
||||
|
||||
// checking for an empty string is not required, but we reduce the load
|
||||
@@ -40,6 +52,7 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
|
||||
if (strlen(name) == 0) continue;
|
||||
|
||||
const char *config = p.getStringField("config");
|
||||
if (strlen(config) == 0) config = NULL;
|
||||
|
||||
time_t vassal_ts = 0;
|
||||
// ts must be a Date object !!!
|
||||
@@ -61,6 +74,7 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
|
||||
}
|
||||
|
||||
const char *socket_name = p.getStringField("socket");
|
||||
if (strlen(socket_name) == 0) socket_name = NULL;
|
||||
|
||||
uwsgi_emperor_simple_do(ues, (char *) name, (char *) config, vassal_ts/1000, vassal_uid, vassal_gid, (char *) socket_name);
|
||||
}
|
||||
@@ -76,6 +90,7 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues
|
||||
b.append("name", c_ui->name);
|
||||
mongo::BSONObj q2 = b.obj();
|
||||
cursor = c.query(uems->collection, q2, 0, 0, &p);
|
||||
if (!cursor.get()) return;
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("JSON: %s\n", q2.toString().c_str());
|
||||
#endif
|
||||
@@ -121,3 +136,40 @@ done:
|
||||
uwsgi_log("[emperor] enabled emperor MongoDB monitor for %s on collection %s\n", uems->address, uems->collection);
|
||||
}
|
||||
|
||||
// setup a new mongodb imperial monitor (keyval based)
|
||||
extern "C" void uwsgi_imperial_monitor_mongodb_init2(struct uwsgi_emperor_scanner *ues) {
|
||||
|
||||
// allocate a new state
|
||||
ues->data = uwsgi_calloc(sizeof(struct uwsgi_emperor_mongodb_state));
|
||||
size_t arg_len = strlen(ues->arg);
|
||||
struct uwsgi_emperor_mongodb_state *uems = (struct uwsgi_emperor_mongodb_state *) ues->data;
|
||||
|
||||
// parse args/ set defaults
|
||||
uems->address = (char *) "127.0.0.1:27017";
|
||||
uems->collection = (char *) "uwsgi.emperor.vassals";
|
||||
uems->json = (char *) "";
|
||||
char *args = NULL;
|
||||
if (arg_len <= 11) goto done;
|
||||
args = ues->arg+11;
|
||||
if (uwsgi_kvlist_parse(args, strlen(args), ',', '=',
|
||||
"addr", &uems->address,
|
||||
"address", &uems->address,
|
||||
"server", &uems->address,
|
||||
"collection", &uems->collection,
|
||||
"coll", &uems->collection,
|
||||
"json", &uems->json,
|
||||
"database", &uems->database,
|
||||
"db", &uems->database,
|
||||
"username", &uems->username,
|
||||
"password", &uems->password,
|
||||
"predigest", &uems->predigest,
|
||||
NULL)) {
|
||||
|
||||
uwsgi_log("[emperor-mongodb] invalid keyval syntax !\n");
|
||||
exit(1);
|
||||
}
|
||||
done:
|
||||
uwsgi_log("[emperor] enabled emperor MongoDB monitor for %s on collection %s\n", uems->address, uems->collection);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
|
||||
void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *);
|
||||
void uwsgi_imperial_monitor_mongodb_init(struct uwsgi_emperor_scanner *);
|
||||
void uwsgi_imperial_monitor_mongodb_init2(struct uwsgi_emperor_scanner *);
|
||||
|
||||
void emperor_mongodb_init(void) {
|
||||
uwsgi_register_imperial_monitor("mongodb", uwsgi_imperial_monitor_mongodb_init, uwsgi_imperial_monitor_mongodb);
|
||||
uwsgi_register_imperial_monitor("mongodb2", uwsgi_imperial_monitor_mongodb_init2, uwsgi_imperial_monitor_mongodb);
|
||||
}
|
||||
|
||||
struct uwsgi_plugin emperor_mongodb_plugin = {
|
||||
|
||||
@@ -37,7 +37,7 @@ static struct uwsgi_option fastrouter_options[] = {
|
||||
{"fastrouter-events", required_argument, 0, "set the maximum number of concurrent events", uwsgi_opt_set_int, &ufr.cr.nevents, 0},
|
||||
{"fastrouter-quiet", required_argument, 0, "do not report failed connections to instances", uwsgi_opt_true, &ufr.cr.quiet, 0},
|
||||
{"fastrouter-cheap", no_argument, 0, "run the fastrouter in cheap mode", uwsgi_opt_true, &ufr.cr.cheap, 0},
|
||||
{"fastrouter-subscription-server", required_argument, 0, "run the fastrouter subscription server on the spcified address", uwsgi_opt_corerouter_ss, &ufr, 0},
|
||||
{"fastrouter-subscription-server", required_argument, 0, "run the fastrouter subscription server on the specified address", uwsgi_opt_corerouter_ss, &ufr, 0},
|
||||
{"fastrouter-subscription-slot", required_argument, 0, "*** deprecated ***", uwsgi_opt_deprecated, (void *) "useless thanks to the new implementation", 0},
|
||||
|
||||
{"fastrouter-timeout", required_argument, 0, "set fastrouter timeout", uwsgi_opt_set_int, &ufr.cr.socket_timeout, 0},
|
||||
@@ -48,6 +48,13 @@ static struct uwsgi_option fastrouter_options[] = {
|
||||
{"fastrouter-stats-server", required_argument, 0, "run the fastrouter stats server", uwsgi_opt_set_str, &ufr.cr.stats_server, 0},
|
||||
{"fastrouter-ss", required_argument, 0, "run the fastrouter stats server", uwsgi_opt_set_str, &ufr.cr.stats_server, 0},
|
||||
{"fastrouter-harakiri", required_argument, 0, "enable fastrouter harakiri", uwsgi_opt_set_int, &ufr.cr.harakiri, 0},
|
||||
|
||||
{"fastrouter-uid", required_argument, 0, "drop fastrouter privileges to the specified uid", uwsgi_opt_uid, &ufr.cr.uid, 0 },
|
||||
{"fastrouter-gid", required_argument, 0, "drop fastrouter privileges to the specified gid", uwsgi_opt_gid, &ufr.cr.gid, 0 },
|
||||
{"fastrouter-resubscribe", required_argument, 0, "forward subscriptions to the specified subscription server", uwsgi_opt_add_string_list, &ufr.cr.resubscribe, 0},
|
||||
{"fastrouter-resubscribe-bind", required_argument, 0, "bind to the specified address when re-subscribing", uwsgi_opt_set_str, &ufr.cr.resubscribe_bind, 0},
|
||||
|
||||
{"fastrouter-buffer-size", required_argument, 0, "set internal buffer size (default: page size)", uwsgi_opt_set_64bit, &ufr.cr.buffer_size, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
};
|
||||
|
||||
|
||||
@@ -24,6 +24,9 @@ else:
|
||||
CFLAGS.append('-I' + archdir)
|
||||
CFLAGS.append('-I' + archdir + '/' + arch)
|
||||
CFLAGS.append('-I' + includedir + '/' + arch)
|
||||
archdir2 = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['rubyarchhdrdir']\"" % rbconfig).read().rstrip()
|
||||
if archdir2:
|
||||
CFLAGS.append('-I' + archdir2)
|
||||
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
|
||||
@@ -8,18 +8,20 @@ struct uwsgi_geoip {
|
||||
char *city_db;
|
||||
GeoIP *country;
|
||||
GeoIP *city;
|
||||
int use_disk;
|
||||
|
||||
} ugeoip;
|
||||
|
||||
struct uwsgi_option uwsgi_geoip_options[] = {
|
||||
{"geoip-country", required_argument, 0, "load the specified geoip country database", uwsgi_opt_set_str, &ugeoip.country_db, 0},
|
||||
{"geoip-city", required_argument, 0, "load the specified geoip city database", uwsgi_opt_set_str, &ugeoip.city_db, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, 0 }
|
||||
{"geoip-use-disk", no_argument, 0, "do not cache geoip databases in memory", uwsgi_opt_true, &ugeoip.use_disk, 0},
|
||||
UWSGI_END_OF_OPTIONS
|
||||
};
|
||||
|
||||
static int uwsgi_geoip_init() {
|
||||
if (ugeoip.country_db) {
|
||||
ugeoip.country = GeoIP_open(ugeoip.country_db, GEOIP_MEMORY_CACHE);
|
||||
ugeoip.country = GeoIP_open(ugeoip.country_db, ugeoip.use_disk ? GEOIP_STANDARD : GEOIP_MEMORY_CACHE);
|
||||
if (!ugeoip.country) {
|
||||
uwsgi_log("unable to open GeoIP country database: %s\n", ugeoip.country_db);
|
||||
exit(1);
|
||||
@@ -27,7 +29,7 @@ static int uwsgi_geoip_init() {
|
||||
}
|
||||
|
||||
if (ugeoip.city_db) {
|
||||
ugeoip.city = GeoIP_open(ugeoip.city_db, GEOIP_MEMORY_CACHE);
|
||||
ugeoip.city = GeoIP_open(ugeoip.city_db, ugeoip.use_disk ? GEOIP_STANDARD : GEOIP_MEMORY_CACHE);
|
||||
if (!ugeoip.city) {
|
||||
uwsgi_log("unable to open GeoIP city database: %s\n", ugeoip.city_db);
|
||||
exit(1);
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
extern struct uwsgi_server uwsgi;
|
||||
extern struct uwsgi_python up;
|
||||
|
||||
#define is_not_python(x) strcmp(uwsgi.p[x]->name, "python")
|
||||
|
||||
struct ugreenlet {
|
||||
int enabled;
|
||||
PyObject *callable;
|
||||
@@ -69,7 +71,7 @@ static void greenlet_schedule_to_req() {
|
||||
}
|
||||
|
||||
// call it in the main core
|
||||
if (uwsgi.p[modifier1]->suspend) {
|
||||
if (is_not_python(modifier1) && uwsgi.p[modifier1]->suspend) {
|
||||
uwsgi.p[modifier1]->suspend(NULL);
|
||||
}
|
||||
|
||||
@@ -81,7 +83,7 @@ static void greenlet_schedule_to_req() {
|
||||
}
|
||||
Py_DECREF(ret);
|
||||
|
||||
if (uwsgi.p[modifier1]->resume) {
|
||||
if (is_not_python(modifier1) && uwsgi.p[modifier1]->resume) {
|
||||
uwsgi.p[modifier1]->resume(NULL);
|
||||
}
|
||||
|
||||
@@ -93,7 +95,7 @@ static void greenlet_schedule_to_main(struct wsgi_request *wsgi_req) {
|
||||
// ensure gil
|
||||
UWSGI_GET_GIL
|
||||
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->suspend) {
|
||||
if (is_not_python(wsgi_req->uh->modifier1) && uwsgi.p[wsgi_req->uh->modifier1]->suspend) {
|
||||
uwsgi.p[wsgi_req->uh->modifier1]->suspend(wsgi_req);
|
||||
}
|
||||
PyObject *ret = PyGreenlet_Switch(ugl.main, NULL, NULL);
|
||||
@@ -103,7 +105,7 @@ static void greenlet_schedule_to_main(struct wsgi_request *wsgi_req) {
|
||||
exit(1);
|
||||
}
|
||||
Py_DECREF(ret);
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->resume) {
|
||||
if (is_not_python(wsgi_req->uh->modifier1) && uwsgi.p[wsgi_req->uh->modifier1]->resume) {
|
||||
uwsgi.p[wsgi_req->uh->modifier1]->resume(wsgi_req);
|
||||
}
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
@@ -132,6 +134,10 @@ static void greenlet_init_apps(void) {
|
||||
|
||||
|
||||
PyGreenlet_Import();
|
||||
if (PyErr_Occurred()){
|
||||
PyErr_Print();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ugl.gl = uwsgi_malloc( sizeof(PyGreenlet *) * uwsgi.async );
|
||||
ugl.main = PyGreenlet_GetCurrent();
|
||||
|
||||
@@ -79,6 +79,11 @@ static void uwsgi_gridfs_do(struct wsgi_request *wsgi_req, struct uwsgi_gridfs_m
|
||||
}
|
||||
uwsgi_response_add_content_length(wsgi_req, gfile.getContentLength());
|
||||
|
||||
char http_last_modified[49];
|
||||
time_t t = gfile.getUploadDate().toTimeT();
|
||||
int size = uwsgi_http_date(t, http_last_modified);
|
||||
uwsgi_response_add_header(wsgi_req, (char *)"Last-Modified", 13, http_last_modified, size);
|
||||
|
||||
if (ugm->etag) {
|
||||
std::string g_md5 = gfile.getMD5();
|
||||
if (!g_md5.empty()) {
|
||||
|
||||
@@ -40,6 +40,10 @@ struct uwsgi_http {
|
||||
size_t spdy3_settings_size;
|
||||
#endif
|
||||
|
||||
int server_name_as_http_host;
|
||||
|
||||
int headers_timeout;
|
||||
int connect_timeout;
|
||||
};
|
||||
|
||||
struct http_session {
|
||||
|
||||
+128
-45
@@ -54,45 +54,62 @@ struct uwsgi_option http_options[] = {
|
||||
{"http-ss", required_argument, 0, "run the http router stats server", uwsgi_opt_set_str, &uhttp.cr.stats_server, 0},
|
||||
{"http-harakiri", required_argument, 0, "enable http router harakiri", uwsgi_opt_set_int, &uhttp.cr.harakiri, 0},
|
||||
{"http-stud-prefix", required_argument, 0, "expect a stud prefix (1byte family + 4/16 bytes address) on connections from the specified address", uwsgi_opt_add_addr_list, &uhttp.stud_prefix, 0},
|
||||
{"http-uid", required_argument, 0, "drop http routr privileges to the specified uid", uwsgi_opt_uid, &uhttp.cr.uid, 0 },
|
||||
{"http-gid", required_argument, 0, "drop http routr privileges to the specified gid", uwsgi_opt_gid, &uhttp.cr.gid, 0 },
|
||||
{"http-uid", required_argument, 0, "drop http router privileges to the specified uid", uwsgi_opt_uid, &uhttp.cr.uid, 0 },
|
||||
{"http-gid", required_argument, 0, "drop http router privileges to the specified gid", uwsgi_opt_gid, &uhttp.cr.gid, 0 },
|
||||
{"http-resubscribe", required_argument, 0, "forward subscriptions to the specified subscription server", uwsgi_opt_add_string_list, &uhttp.cr.resubscribe, 0},
|
||||
{"http-buffer-size", required_argument, 0, "set internal buffer size (default: page size)", uwsgi_opt_set_64bit, &uhttp.cr.buffer_size, 0},
|
||||
|
||||
{"http-server-name-as-http-host", required_argument, 0, "force SERVER_NAME to HTTP_HOST", uwsgi_opt_true, &uhttp.server_name_as_http_host, 0},
|
||||
{"http-headers-timeout", required_argument, 0, "set internal http socket timeout for headers", uwsgi_opt_set_int, &uhttp.headers_timeout, 0},
|
||||
{"http-connect-timeout", required_argument, 0, "set internal http socket timeout for backend connections", uwsgi_opt_set_int, &uhttp.connect_timeout, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
};
|
||||
|
||||
int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, uint16_t hhlen) {
|
||||
static void http_set_timeout(struct corerouter_peer *peer, int timeout) {
|
||||
if (peer->current_timeout == timeout) return;
|
||||
peer->current_timeout = timeout;
|
||||
peer->timeout = corerouter_reset_timeout(peer->session->corerouter, peer);
|
||||
}
|
||||
|
||||
static char * http_header_to_cgi(char *hh, size_t hhlen, size_t *keylen, size_t *vallen, int *has_prefix) {
|
||||
size_t i;
|
||||
char *val = hh;
|
||||
int status = 0;
|
||||
for (i = 0; i < hhlen; i++) {
|
||||
if (!status) {
|
||||
hh[i] = toupper((int) hh[i]);
|
||||
if (hh[i] == '-')
|
||||
hh[i] = '_';
|
||||
if (hh[i] == ':') {
|
||||
status = 1;
|
||||
*keylen = i;
|
||||
}
|
||||
}
|
||||
else if (status == 1 && hh[i] != ' ') {
|
||||
status = 2;
|
||||
val += i;
|
||||
*vallen+=1;
|
||||
}
|
||||
else if (status == 2) {
|
||||
*vallen+=1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(*keylen))
|
||||
return NULL;
|
||||
|
||||
if (uwsgi_strncmp("CONTENT_LENGTH", 14, hh, *keylen) && uwsgi_strncmp("CONTENT_TYPE", 12, hh, *keylen)) {
|
||||
*has_prefix = 0x02;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, size_t keylen, char *val, size_t vallen, int prefix) {
|
||||
|
||||
struct uwsgi_buffer *out = peer->out;
|
||||
struct http_session *hr = (struct http_session *) peer->session;
|
||||
|
||||
int i;
|
||||
int status = 0;
|
||||
char *val = hh;
|
||||
uint16_t keylen = 0, vallen = 0;
|
||||
int prefix = 0;
|
||||
|
||||
for (i = 0; i < hhlen; i++) {
|
||||
if (!status) {
|
||||
hh[i] = toupper((int) hh[i]);
|
||||
if (hh[i] == '-')
|
||||
hh[i] = '_';
|
||||
if (hh[i] == ':') {
|
||||
status = 1;
|
||||
keylen = i;
|
||||
}
|
||||
}
|
||||
else if (status == 1 && hh[i] != ' ') {
|
||||
status = 2;
|
||||
val += i;
|
||||
vallen++;
|
||||
}
|
||||
else if (status == 2) {
|
||||
vallen++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!keylen)
|
||||
return -1;
|
||||
|
||||
if (hr->websockets) {
|
||||
if (!uwsgi_strncmp("UPGRADE", 7, hh, keylen)) {
|
||||
if (!uwsgi_strnicmp(val, vallen, "websocket", 9)) {
|
||||
@@ -120,6 +137,7 @@ int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, uint16_t hhlen
|
||||
if (!uwsgi_strncmp("HOST", 4, hh, keylen)) {
|
||||
peer->key = val;
|
||||
peer->key_len = vallen;
|
||||
if (uhttp.server_name_as_http_host && uwsgi_buffer_append_keyval(out, "SERVER_NAME", 11, peer->key, peer->key_len)) return -1;
|
||||
}
|
||||
|
||||
else if (!uwsgi_strncmp("CONTENT_LENGTH", 14, hh, keylen)) {
|
||||
@@ -146,11 +164,7 @@ int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, uint16_t hhlen
|
||||
#endif
|
||||
|
||||
done:
|
||||
|
||||
if (uwsgi_strncmp("CONTENT_TYPE", 12, hh, keylen) && uwsgi_strncmp("CONTENT_LENGTH", 14, hh, keylen)) {
|
||||
keylen += 5;
|
||||
prefix = 1;
|
||||
}
|
||||
if (prefix) keylen += 5;
|
||||
|
||||
if (uwsgi_buffer_u16le(out, keylen)) return -1;
|
||||
|
||||
@@ -158,7 +172,7 @@ done:
|
||||
if (uwsgi_buffer_append(out, "HTTP_", 5)) return -1;
|
||||
}
|
||||
|
||||
if (uwsgi_buffer_append(out, hh, keylen - (prefix * 5))) return -1;
|
||||
if (uwsgi_buffer_append(out, hh, keylen - (prefix ? 5 : 0))) return -1;
|
||||
|
||||
if (uwsgi_buffer_u16le(out, vallen)) return -1;
|
||||
if (uwsgi_buffer_append(out, val, vallen)) return -1;
|
||||
@@ -294,7 +308,7 @@ int http_headers_parse(struct corerouter_peer *peer) {
|
||||
if (uwsgi_buffer_append_keyval(out, "SCRIPT_NAME", 11, "", 0)) return -1;
|
||||
|
||||
// SERVER_NAME
|
||||
if (uwsgi_buffer_append_keyval(out, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len)) return -1;
|
||||
if (!uhttp.server_name_as_http_host && uwsgi_buffer_append_keyval(out, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len)) return -1;
|
||||
peer->key = uwsgi.hostname;
|
||||
peer->key_len = uwsgi.hostname_len;
|
||||
|
||||
@@ -320,6 +334,8 @@ int http_headers_parse(struct corerouter_peer *peer) {
|
||||
//HEADERS
|
||||
base = ptr;
|
||||
|
||||
struct uwsgi_string_list *headers = NULL, *usl = NULL;
|
||||
|
||||
while (ptr < watermark) {
|
||||
if (*ptr == '\r') {
|
||||
if (ptr + 1 >= watermark)
|
||||
@@ -340,13 +356,53 @@ int http_headers_parse(struct corerouter_peer *peer) {
|
||||
hr->send_expect_100 = 1;
|
||||
}
|
||||
}
|
||||
if (http_add_uwsgi_header(peer, base, ptr - base)) return -1;
|
||||
|
||||
size_t key_len = 0, value_len = 0;
|
||||
int has_prefix = 0;
|
||||
// last line, do not waste time
|
||||
if (ptr - base == 0) break;
|
||||
char *value = http_header_to_cgi(base, ptr - base, &key_len, &value_len, &has_prefix);
|
||||
if (!value) goto clear;
|
||||
usl = uwsgi_string_list_has_item(headers, base, key_len);
|
||||
// there is already a HTTP header with the same name, let's merge them
|
||||
if (usl) {
|
||||
char *old_value = usl->custom_ptr;
|
||||
usl->custom_ptr = uwsgi_concat3n(old_value, (size_t) usl->custom, ", ", 2, value, value_len);
|
||||
usl->custom += 2 + value_len;
|
||||
if (usl->custom2 & 0x01) free(old_value);
|
||||
usl->custom2 |= 0x01;
|
||||
}
|
||||
else {
|
||||
// add an entry
|
||||
usl = uwsgi_string_new_list(&headers, NULL);
|
||||
usl->value = base;
|
||||
usl->len = key_len;
|
||||
usl->custom_ptr = value;
|
||||
usl->custom = value_len;
|
||||
usl->custom2 = has_prefix;
|
||||
}
|
||||
ptr++;
|
||||
base = ptr + 1;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
usl = headers;
|
||||
int broken = 0;
|
||||
while(usl) {
|
||||
if (!broken) {
|
||||
if (http_add_uwsgi_header(peer, usl->value, usl->len, usl->custom_ptr, (size_t) usl->custom, usl->custom2 & 0x02)) broken = 1;
|
||||
}
|
||||
if (usl->custom2 & 0x01) {
|
||||
free(usl->custom_ptr);
|
||||
}
|
||||
struct uwsgi_string_list *tmp_usl = usl;
|
||||
usl = usl->next;
|
||||
free(tmp_usl);
|
||||
}
|
||||
|
||||
if (broken) return -1;
|
||||
|
||||
struct uwsgi_string_list *hv = uhttp.http_vars;
|
||||
while (hv) {
|
||||
char *equal = strchr(hv->value, '=');
|
||||
@@ -358,6 +414,18 @@ int http_headers_parse(struct corerouter_peer *peer) {
|
||||
|
||||
return 0;
|
||||
|
||||
clear:
|
||||
usl = headers;
|
||||
while(usl) {
|
||||
if (usl->custom2 & 0x01) {
|
||||
free(usl->custom_ptr);
|
||||
}
|
||||
struct uwsgi_string_list *tmp_usl = usl;
|
||||
usl = usl->next;
|
||||
free(tmp_usl);
|
||||
}
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -441,6 +509,7 @@ ssize_t hr_write(struct corerouter_peer *main_peer) {
|
||||
return 0;
|
||||
}
|
||||
if (main_peer->session->connect_peer_after_write) {
|
||||
http_set_timeout(main_peer->session->connect_peer_after_write, uhttp.connect_timeout);
|
||||
cr_connect(main_peer->session->connect_peer_after_write, hr_instance_connected);
|
||||
main_peer->session->connect_peer_after_write = NULL;
|
||||
return len;
|
||||
@@ -454,6 +523,9 @@ ssize_t hr_write(struct corerouter_peer *main_peer) {
|
||||
ssize_t hr_instance_connected(struct corerouter_peer* peer) {
|
||||
|
||||
cr_peer_connected(peer, "hr_instance_connected()");
|
||||
|
||||
// set the default timeout
|
||||
http_set_timeout(peer, uhttp.cr.socket_timeout);
|
||||
|
||||
// we are connected, we cannot retry anymore
|
||||
peer->can_retry = 0;
|
||||
@@ -518,10 +590,7 @@ ssize_t hr_instance_read(struct corerouter_peer *peer) {
|
||||
hr->has_gzip = 0;
|
||||
#endif
|
||||
if (uhttp.keepalive > 1) {
|
||||
int orig_timeout = peer->session->corerouter->socket_timeout;
|
||||
peer->session->corerouter->socket_timeout = uhttp.keepalive;
|
||||
peer->session->main_peer->timeout = corerouter_reset_timeout(peer->session->corerouter, peer->session->main_peer);
|
||||
peer->session->corerouter->socket_timeout = orig_timeout;
|
||||
http_set_timeout(peer->session->main_peer, uhttp.keepalive);
|
||||
}
|
||||
}
|
||||
#ifdef UWSGI_ZLIB
|
||||
@@ -650,6 +719,9 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ensure the headers timeout is honoured
|
||||
http_set_timeout(main_peer, uhttp.headers_timeout);
|
||||
|
||||
// read until \r\n\r\n is found
|
||||
size_t j;
|
||||
size_t len = main_peer->in->pos;
|
||||
@@ -739,6 +811,10 @@ ssize_t http_parse(struct corerouter_peer *main_peer) {
|
||||
hr->raw_body = 1;
|
||||
}
|
||||
new_peer->can_retry = 1;
|
||||
// reset main timeout
|
||||
http_set_timeout(main_peer, uhttp.cr.socket_timeout);
|
||||
// set peer timeout
|
||||
http_set_timeout(new_peer, uhttp.connect_timeout);
|
||||
cr_connect(new_peer, hr_instance_connected);
|
||||
break;
|
||||
}
|
||||
@@ -825,12 +901,17 @@ static int hr_retry(struct corerouter_peer *peer) {
|
||||
|
||||
retry:
|
||||
// start async connect (again)
|
||||
http_set_timeout(peer, uhttp.connect_timeout);
|
||||
cr_connect(peer, hr_instance_connected);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int http_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket *ugs, struct corerouter_session *cs, struct sockaddr *sa, socklen_t s_len) {
|
||||
|
||||
if (!uhttp.headers_timeout) uhttp.headers_timeout = uhttp.cr.socket_timeout;
|
||||
if (!uhttp.connect_timeout) uhttp.connect_timeout = uhttp.cr.socket_timeout;
|
||||
|
||||
// set the retry hook
|
||||
cs->retry = hr_retry;
|
||||
struct http_session *hr = (struct http_session *) cs;
|
||||
@@ -840,6 +921,9 @@ int http_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket
|
||||
// default hook
|
||||
cs->main_peer->last_hook_read = hr_read;
|
||||
|
||||
// headers timeout
|
||||
cs->main_peer->current_timeout = uhttp.headers_timeout;
|
||||
|
||||
if (uhttp.raw_body) {
|
||||
hr->raw_body = 1;
|
||||
}
|
||||
@@ -901,7 +985,6 @@ int http_init() {
|
||||
uhttp.cr.socket_num = 0;
|
||||
}
|
||||
uwsgi_corerouter_init((struct uwsgi_corerouter *) &uhttp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+46
-5
@@ -180,8 +180,10 @@ struct uwsgi_buffer *spdy_http_to_spdy(char *buf, size_t len, uint32_t *hh) {
|
||||
if (!key) return ub;
|
||||
|
||||
uint32_t h_len = 0;
|
||||
|
||||
// headers (key lowercase...)
|
||||
// merge header values and ensure keys are all lowercase
|
||||
struct uwsgi_string_list *hr=NULL, *usl=NULL;
|
||||
char *line_value;
|
||||
size_t line_key_len, line_value_len;
|
||||
for(i=next;i<len;i++) {
|
||||
if (key) {
|
||||
if (buf[i] == '\r' || buf[i] == '\n') {
|
||||
@@ -192,10 +194,37 @@ struct uwsgi_buffer *spdy_http_to_spdy(char *buf, size_t len, uint32_t *hh) {
|
||||
// tolower !!!
|
||||
size_t j;
|
||||
for(j=0;j<h_len;j++) {
|
||||
key[j] = tolower((int) key[j]);
|
||||
// don't lowercase values, only keys
|
||||
if (key[j] == ':') break;
|
||||
key[j] = tolower((int) key[j]);
|
||||
}
|
||||
line_key_len = colon - key;
|
||||
key[line_key_len] = 0;
|
||||
line_value_len = h_len - 2 - line_key_len;
|
||||
line_value = uwsgi_strncopy(colon+2, line_value_len);
|
||||
if (hr) {
|
||||
// check if we already store values for this key
|
||||
usl = uwsgi_string_list_has_item(hr, key, line_key_len);
|
||||
if (usl) {
|
||||
// we have this key, append new value
|
||||
char *oldval = usl->custom_ptr;
|
||||
usl->custom_ptr = uwsgi_concat3n(usl->custom_ptr, usl->custom, "\0", 1, line_value, line_value_len);
|
||||
usl->custom = usl->custom + 1 + line_value_len;
|
||||
free(oldval);
|
||||
}
|
||||
else {
|
||||
// this key is new
|
||||
usl = uwsgi_string_new_list(&hr, key);
|
||||
usl->custom_ptr = line_value;
|
||||
usl->custom = line_value_len;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// this is first key
|
||||
usl = uwsgi_string_new_list(&hr, key);
|
||||
usl->custom_ptr = line_value;
|
||||
usl->custom = line_value_len;
|
||||
}
|
||||
if (uwsgi_buffer_append_keyval32(ub, key, colon-key, colon+2, h_len-((colon-key)+2))) goto end;
|
||||
*hh+=1;
|
||||
key = NULL;
|
||||
h_len = 0;
|
||||
}
|
||||
@@ -210,6 +239,18 @@ struct uwsgi_buffer *spdy_http_to_spdy(char *buf, size_t len, uint32_t *hh) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// append all merged header lines to buffer and free memory
|
||||
struct uwsgi_string_list *ohr;
|
||||
while (hr) {
|
||||
if (uwsgi_buffer_append_keyval32(ub, hr->value, hr->len, hr->custom_ptr, hr->custom)) goto end;
|
||||
*hh+=1;
|
||||
ohr = hr;
|
||||
hr = hr->next;
|
||||
free(ohr->custom_ptr);
|
||||
free(ohr);
|
||||
}
|
||||
|
||||
return ub;
|
||||
|
||||
end:
|
||||
|
||||
@@ -28,7 +28,10 @@ static ssize_t uwsgi_pipe_logger(struct uwsgi_logger *ul, char *message, size_t
|
||||
}
|
||||
else {
|
||||
// child
|
||||
setsid();
|
||||
if (setsid() < 0) {
|
||||
uwsgi_error("setsid()");
|
||||
exit(1);
|
||||
}
|
||||
close(pipefd[1]);
|
||||
dup2(pipefd[0], STDIN_FILENO);
|
||||
close(pipefd[0]);
|
||||
|
||||
+46
-33
@@ -102,6 +102,10 @@ static int uwsgi_mongrel2_json_parse(json_t * root, struct wsgi_request *wsgi_re
|
||||
}
|
||||
}
|
||||
|
||||
if ((json_val = uwsgi_mongrel2_json_get_string(root, "URL_SCHEME"))) {
|
||||
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "UWSGI_SCHEME", 12, json_val, strlen(json_val));
|
||||
}
|
||||
|
||||
if ((json_val = uwsgi_mongrel2_json_get_string(root, "host"))) {
|
||||
char *colon = strchr(json_val, ':');
|
||||
if (colon) {
|
||||
@@ -210,6 +214,9 @@ static int uwsgi_mongrel2_tnetstring_parse(struct wsgi_request *wsgi_req, char *
|
||||
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, val, vallen);
|
||||
}
|
||||
}
|
||||
else if (!uwsgi_strncmp("URL_SCHEME", 10, key, keylen)) {
|
||||
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "UWSGI_SCHEME", 12, val, vallen);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// add header
|
||||
@@ -299,6 +306,13 @@ void uwsgi_proto_zeromq_thread_fixup(struct uwsgi_socket *uwsgi_sock, int async_
|
||||
|
||||
// fake function, the body is in a file or completely in memory
|
||||
ssize_t uwsgi_proto_zeromq_read_body(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
size_t remains = wsgi_req->post_cl - wsgi_req->proto_parser_status;
|
||||
if (remains > 0) {
|
||||
if (len > remains) len = remains;
|
||||
memcpy(buf, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_buf_size + wsgi_req->proto_parser_status, len);
|
||||
wsgi_req->proto_parser_status += len;
|
||||
return len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -410,7 +424,8 @@ int uwsgi_proto_zeromq_accept(struct wsgi_request *wsgi_req, int fd) {
|
||||
}
|
||||
|
||||
// pre-build the mongrel2 response_header
|
||||
wsgi_req->proto_parser_buf = uwsgi_malloc(req_uuid_len + 1 + 11 + 1 + req_id_len + 1 + 1);
|
||||
wsgi_req->proto_parser_buf_size = req_uuid_len + 1 + 11 + 1 + req_id_len + 1 + 1;
|
||||
wsgi_req->proto_parser_buf = uwsgi_malloc(wsgi_req->proto_parser_buf_size);
|
||||
memcpy(wsgi_req->proto_parser_buf, req_uuid, req_uuid_len);
|
||||
((char *) wsgi_req->proto_parser_buf)[req_uuid_len] = ' ';
|
||||
resp_id_len = uwsgi_num2str2(req_id_len, wsgi_req->proto_parser_buf + req_uuid_len + 1);
|
||||
@@ -422,13 +437,22 @@ int uwsgi_proto_zeromq_accept(struct wsgi_request *wsgi_req, int fd) {
|
||||
wsgi_req->proto_parser_pos = (uint64_t) req_uuid_len + 1 + resp_id_len + 1 + req_id_len + 1 + 1;
|
||||
|
||||
// handle post data (in memory)
|
||||
// reallocate wsgi_req->proto_parser_buf and change its size to be able to store request body
|
||||
// the parser status holds the current position for read_body hook
|
||||
if (wsgi_req->post_cl > 0 && !wsgi_req->post_file) {
|
||||
if (uwsgi_netstring(post_data, message_size - (post_data - message_ptr), &message_ptr, &wsgi_req->post_cl)) {
|
||||
char *tmp = realloc(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf_size + wsgi_req->post_cl);
|
||||
if (!tmp) {
|
||||
uwsgi_error("realloc()");
|
||||
exit(1);
|
||||
}
|
||||
wsgi_req->proto_parser_buf = tmp;
|
||||
// status is an offset...
|
||||
wsgi_req->proto_parser_status = 0;
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("post_size: %d\n", wsgi_req->post_cl);
|
||||
#endif
|
||||
wsgi_req->post_read_buf = uwsgi_malloc(wsgi_req->post_cl);
|
||||
memcpy(wsgi_req->post_read_buf, message_ptr, wsgi_req->post_cl);
|
||||
memcpy(wsgi_req->proto_parser_buf + wsgi_req->proto_parser_buf_size, message_ptr, wsgi_req->post_cl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,33 +476,7 @@ retry:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void uwsgi_proto_zeromq_close(struct wsgi_request *wsgi_req) {
|
||||
zmq_msg_t reply;
|
||||
|
||||
// check for already freed wsgi_req->proto_parser_buf/wsgi_req->proto_parser_pos
|
||||
if (!wsgi_req->proto_parser_pos)
|
||||
return;
|
||||
|
||||
// no need to pass a free function (the buffer will be freed during cloe_request)
|
||||
zmq_msg_init_data(&reply, wsgi_req->proto_parser_buf, wsgi_req->proto_parser_pos, NULL, NULL);
|
||||
if (uwsgi.threads > 1)
|
||||
pthread_mutex_lock(&wsgi_req->socket->lock);
|
||||
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0)
|
||||
if (zmq_sendmsg(wsgi_req->socket->pub, &reply, 0)) {
|
||||
uwsgi_error("uwsgi_proto_zeromq_close()/zmq_sendmsg()");
|
||||
#else
|
||||
if (zmq_send(wsgi_req->socket->pub, &reply, 0)) {
|
||||
uwsgi_error("uwsgi_proto_zeromq_close()/zmq_send()");
|
||||
#endif
|
||||
}
|
||||
if (uwsgi.threads > 1)
|
||||
pthread_mutex_unlock(&wsgi_req->socket->lock);
|
||||
zmq_msg_close(&reply);
|
||||
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_proto_zeromq_write(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
static int uwsgi_proto_zeromq_write_do(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
zmq_msg_t reply;
|
||||
|
||||
if (zmq_msg_init_size(&reply, wsgi_req->proto_parser_pos + len)) {
|
||||
@@ -489,7 +487,8 @@ int uwsgi_proto_zeromq_write(struct wsgi_request *wsgi_req, char *buf, size_t le
|
||||
|
||||
char *zmq_body = zmq_msg_data(&reply);
|
||||
memcpy(zmq_body, wsgi_req->proto_parser_buf, wsgi_req->proto_parser_pos);
|
||||
memcpy(zmq_body + wsgi_req->proto_parser_pos, buf, len);
|
||||
if (len > 0)
|
||||
memcpy(zmq_body + wsgi_req->proto_parser_pos, buf, len);
|
||||
|
||||
if (uwsgi.threads > 1)
|
||||
pthread_mutex_lock(&wsgi_req->socket->lock);
|
||||
@@ -510,6 +509,18 @@ int uwsgi_proto_zeromq_write(struct wsgi_request *wsgi_req, char *buf, size_t le
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
int uwsgi_proto_zeromq_write(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
int ret = uwsgi_proto_zeromq_write_do(wsgi_req, buf, len);
|
||||
if (ret == UWSGI_OK) {
|
||||
wsgi_req->write_pos += len;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void uwsgi_proto_zeromq_close(struct wsgi_request *wsgi_req) {
|
||||
uwsgi_proto_zeromq_write_do(wsgi_req, "", 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
we have a problem... recent Mongrel2 releases introduced a ring buffer that limit the amount of messages we can send (or better, the amount of
|
||||
@@ -532,7 +543,7 @@ int uwsgi_proto_zeromq_sendfile(struct wsgi_request *wsgi_req, int fd, size_t po
|
||||
return -1;
|
||||
}
|
||||
wsgi_req->write_pos += rlen;
|
||||
if (uwsgi_proto_zeromq_write(wsgi_req, tmp_buf, rlen) < 0) {
|
||||
if (uwsgi_proto_zeromq_write_do(wsgi_req, tmp_buf, rlen) < 0) {
|
||||
free(tmp_buf);
|
||||
return -1;
|
||||
}
|
||||
@@ -574,6 +585,7 @@ static void mongrel2_register_proto() {
|
||||
static void mongrel2_connect() {
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
while(uwsgi_sock) {
|
||||
if (uwsgi_sock->proto != uwsgi_proto_zeromq_parser) goto next;
|
||||
uwsgi_sock->ctx = zmq_init(1);
|
||||
if (!uwsgi_sock->ctx) {
|
||||
uwsgi_error("mongrel2_connect()/zmq_init()");
|
||||
@@ -581,7 +593,7 @@ static void mongrel2_connect() {
|
||||
}
|
||||
char *responder = strchr(uwsgi_sock->name, ',');
|
||||
if (!responder) {
|
||||
uwsgi_log("invalid zeromq address\n");
|
||||
uwsgi_log("invalid zeromq address: %s\n", uwsgi_sock->name);
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_sock->receiver = uwsgi_concat2n(uwsgi_sock->name, responder - uwsgi_sock->name, "", 0);
|
||||
@@ -653,6 +665,7 @@ static void mongrel2_connect() {
|
||||
#else
|
||||
uwsgi_sock->recv_flag = ZMQ_NOBLOCK;
|
||||
#endif
|
||||
next:
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#include "php.h"
|
||||
#include "SAPI.h"
|
||||
#include "php_main.h"
|
||||
#include "php_variables.h"
|
||||
|
||||
#include "ext/standard/php_smart_str.h"
|
||||
#include "ext/standard/info.h"
|
||||
|
||||
#include "ext/session/php_session.h"
|
||||
|
||||
#include <uwsgi.h>
|
||||
|
||||
+24
-14
@@ -1,12 +1,4 @@
|
||||
#include "php.h"
|
||||
#include "SAPI.h"
|
||||
#include "php_main.h"
|
||||
#include "php_variables.h"
|
||||
|
||||
#include "ext/standard/php_smart_str.h"
|
||||
#include "ext/standard/info.h"
|
||||
|
||||
#include "../../uwsgi.h"
|
||||
#include "common.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
@@ -31,6 +23,9 @@ struct uwsgi_php {
|
||||
int dump_config;
|
||||
char *server_software;
|
||||
size_t server_software_len;
|
||||
|
||||
struct uwsgi_string_list *exec_before;
|
||||
struct uwsgi_string_list *exec_after;
|
||||
} uphp;
|
||||
|
||||
void uwsgi_opt_php_ini(char *opt, char *value, void *foobar) {
|
||||
@@ -59,8 +54,11 @@ struct uwsgi_option uwsgi_php_options[] = {
|
||||
#endif
|
||||
{"php-var", required_argument, 0, "add/overwrite a CGI variable at each request", uwsgi_opt_add_string_list, &uphp.vars, 0},
|
||||
{"php-dump-config", no_argument, 0, "dump php config (if modified via --php-set or append options)", uwsgi_opt_true, &uphp.dump_config, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
|
||||
{"php-exec-before", required_argument, 0, "run specified php code before the requested script", uwsgi_opt_add_string_list, &uphp.exec_before, 0},
|
||||
{"php-exec-begin", required_argument, 0, "run specified php code before the requested script", uwsgi_opt_add_string_list, &uphp.exec_before, 0},
|
||||
{"php-exec-after", required_argument, 0, "run specified php code after the requested script", uwsgi_opt_add_string_list, &uphp.exec_after, 0},
|
||||
{"php-exec-end", required_argument, 0, "run specified php code after the requested script", uwsgi_opt_add_string_list, &uphp.exec_after, 0},
|
||||
UWSGI_END_OF_OPTIONS
|
||||
};
|
||||
|
||||
|
||||
@@ -227,8 +225,9 @@ void uwsgi_php_set(char *opt) {
|
||||
uwsgi_sapi_module.ini_entries[uphp.ini_size] = 0;
|
||||
}
|
||||
|
||||
// future implementation...
|
||||
extern ps_module ps_mod_uwsgi;
|
||||
PHP_MINIT_FUNCTION(uwsgi_php_minit) {
|
||||
php_session_register_module(&ps_mod_uwsgi);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@@ -335,7 +334,7 @@ PHP_FUNCTION(uwsgi_cache_set) {
|
||||
RETURN_NULL();
|
||||
}
|
||||
|
||||
if (uwsgi_cache_magic_set(key, keylen, value, vallen, expires, 0, cache)) {
|
||||
if (!uwsgi_cache_magic_set(key, keylen, value, vallen, expires, 0, cache)) {
|
||||
RETURN_TRUE;
|
||||
}
|
||||
RETURN_NULL();
|
||||
@@ -357,7 +356,7 @@ PHP_FUNCTION(uwsgi_cache_update) {
|
||||
RETURN_NULL();
|
||||
}
|
||||
|
||||
if (uwsgi_cache_magic_set(key, keylen, value, vallen, expires, UWSGI_CACHE_FLAG_UPDATE, cache)) {
|
||||
if (!uwsgi_cache_magic_set(key, keylen, value, vallen, expires, UWSGI_CACHE_FLAG_UPDATE, cache)) {
|
||||
RETURN_TRUE;
|
||||
}
|
||||
RETURN_NULL();
|
||||
@@ -890,8 +889,19 @@ secure3:
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct uwsgi_string_list *usl=NULL;
|
||||
|
||||
uwsgi_foreach(usl, uphp.exec_before) {
|
||||
if (zend_eval_string_ex(usl->value, NULL, "uWSGI php exec before", 1 TSRMLS_CC) == FAILURE) goto end;
|
||||
}
|
||||
|
||||
php_execute_script(&file_handle TSRMLS_CC);
|
||||
|
||||
uwsgi_foreach(usl, uphp.exec_after) {
|
||||
if (zend_eval_string_ex(usl->value, NULL, "uWSGI php exec after", 1 TSRMLS_CC) == FAILURE) goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
php_request_shutdown(NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
#include "common.h"
|
||||
|
||||
PS_OPEN_FUNC(uwsgi) {
|
||||
PS_SET_MOD_DATA((char *)save_path);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
PS_CLOSE_FUNC(uwsgi) {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
PS_READ_FUNC(uwsgi) {
|
||||
char *cache = PS_GET_MOD_DATA();
|
||||
uint64_t valsize = 0;
|
||||
char *value = uwsgi_cache_magic_get((char *)key, strlen(key), &valsize, NULL, cache);
|
||||
if (!value) return FAILURE;
|
||||
char *new_val = emalloc(valsize);
|
||||
memcpy(new_val, value, valsize);
|
||||
free(value);
|
||||
*val = new_val;
|
||||
*vallen = valsize;
|
||||
return SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
PS_WRITE_FUNC(uwsgi) {
|
||||
char *cache = PS_GET_MOD_DATA();
|
||||
if (vallen == 0) return SUCCESS;
|
||||
if (!uwsgi_cache_magic_set((char *)key, strlen(key), (char *)val, vallen, 0, UWSGI_CACHE_FLAG_UPDATE, cache)) {
|
||||
return SUCCESS;
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
PS_DESTROY_FUNC(uwsgi) {
|
||||
char *cache = PS_GET_MOD_DATA();
|
||||
if (!uwsgi_cache_magic_del((char *)key, strlen(key), cache)) {
|
||||
return SUCCESS;
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
PS_GC_FUNC(uwsgi) {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
ps_module ps_mod_uwsgi = {
|
||||
PS_MOD(uwsgi)
|
||||
};
|
||||
|
||||
@@ -25,4 +25,4 @@ phplibdir = os.environ.get('UWSGICONFIG_PHPLIBDIR')
|
||||
if phplibdir:
|
||||
LIBS.append('-Wl,-rpath=%s' % phplibdir)
|
||||
|
||||
GCC_LIST = ['php_plugin']
|
||||
GCC_LIST = ['php_plugin', 'session']
|
||||
|
||||
@@ -65,6 +65,8 @@ struct uwsgi_perl {
|
||||
int shell_oneshot;
|
||||
|
||||
CV *spooler;
|
||||
|
||||
int no_plack;
|
||||
};
|
||||
|
||||
void init_perl_embedded_module(void);
|
||||
@@ -84,3 +86,4 @@ void uwsgi_perl_run_hook(SV *);
|
||||
void uwsgi_perl_exec(char *);
|
||||
|
||||
void uwsgi_perl_check_auto_reload(void);
|
||||
void uwsgi_psgi_preinit_apps(void);
|
||||
|
||||
+134
-72
@@ -54,7 +54,7 @@ XS(XS_psgix_logger) {
|
||||
psgi_check_args(1);
|
||||
HV *hv_args = (HV *) (SvRV(ST(0)));
|
||||
if (!hv_exists(hv_args, "level", 5) || !hv_exists(hv_args, "message", 7)) {
|
||||
Perl_croak(aTHX_ "psgix.logger requires bot level and message items");
|
||||
Perl_croak(aTHX_ "psgix.logger requires both level and message items");
|
||||
}
|
||||
char *level = SvPV_nolen(*(hv_fetch(hv_args, "level", 5, 0)));
|
||||
char *message = SvPV_nolen(*(hv_fetch(hv_args, "message", 7, 0)));
|
||||
@@ -107,11 +107,67 @@ XS(XS_input_read) {
|
||||
SV *read_buf = ST(1);
|
||||
unsigned long arg_len = SvIV(ST(2));
|
||||
|
||||
long offset = 0;
|
||||
if (items > 3) {
|
||||
offset = (long) SvIV(ST(3));
|
||||
}
|
||||
|
||||
ssize_t rlen = 0;
|
||||
|
||||
char *buf = uwsgi_request_body_read(wsgi_req, arg_len, &rlen);
|
||||
if (buf) {
|
||||
sv_setpvn(read_buf, buf, rlen);
|
||||
if (rlen > 0 && offset != 0) {
|
||||
STRLEN orig_len;
|
||||
// get data from original string
|
||||
char *orig = SvPV(read_buf, orig_len);
|
||||
size_t new_size = orig_len;
|
||||
// still valid ?
|
||||
if (offset > 0) {
|
||||
// if the new string is bigger than the old one, allocate a bigger chunk
|
||||
if ((size_t) rlen + offset > orig_len) {
|
||||
new_size = rlen + offset;
|
||||
}
|
||||
// if offset is bigger than orig_len, pad with "\0", so we use (slower) calloc
|
||||
char *new_buf = uwsgi_calloc(new_size);
|
||||
// put back older value
|
||||
memcpy(new_buf, orig, orig_len);
|
||||
// put the new value
|
||||
memcpy(new_buf + offset, buf, rlen);
|
||||
sv_setpvn(read_buf, new_buf, new_size);
|
||||
// free the new value
|
||||
free(new_buf);
|
||||
}
|
||||
// negative (a little bit more complex)
|
||||
else {
|
||||
long orig_offset = 0;
|
||||
// first of all get the new orig_len;
|
||||
offset = abs(offset);
|
||||
if (offset > (long) orig_len) {
|
||||
new_size = offset;
|
||||
orig_offset = offset - orig_len;
|
||||
offset = 0;
|
||||
}
|
||||
else {
|
||||
offset = orig_len - offset;
|
||||
}
|
||||
|
||||
if ((size_t) rlen + offset > new_size) {
|
||||
new_size = rlen + offset;
|
||||
}
|
||||
|
||||
char *new_buf = uwsgi_calloc(new_size);
|
||||
// put back older value
|
||||
memcpy(new_buf + orig_offset, orig, orig_len);
|
||||
// put the new value
|
||||
memcpy(new_buf + offset, buf, rlen);
|
||||
sv_setpvn(read_buf, new_buf, new_size);
|
||||
// free the new value
|
||||
free(new_buf);
|
||||
}
|
||||
}
|
||||
else {
|
||||
sv_setpvn(read_buf, buf, rlen);
|
||||
}
|
||||
goto ret;
|
||||
}
|
||||
|
||||
@@ -171,20 +227,6 @@ XS(XS_error_print) {
|
||||
XSRETURN(0);
|
||||
}
|
||||
|
||||
XS(XS_uwsgi_stacktrace) {
|
||||
|
||||
dXSARGS;
|
||||
|
||||
psgi_check_args(0);
|
||||
uwsgi_log("%s", SvPV_nolen(ERRSV));
|
||||
uwsgi_log("*** uWSGI perl stacktrace ***\n");
|
||||
SV *ret = perl_eval_pv("Devel::StackTrace->new->as_string;", 0);
|
||||
uwsgi_log("%s", SvPV_nolen(ret));
|
||||
uwsgi_log("*** end of perl stacktrace ***\n\n");
|
||||
XSRETURN(0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* automatically generated */
|
||||
|
||||
@@ -197,6 +239,7 @@ xs_init(pTHX)
|
||||
{
|
||||
char *file = __FILE__;
|
||||
dXSUB_SYS;
|
||||
HV *stash;
|
||||
|
||||
/* DynaLoader is a special case */
|
||||
newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
|
||||
@@ -218,13 +261,16 @@ xs_init(pTHX)
|
||||
newXS("uwsgi::streaming::write", XS_streaming_write, "uwsgi::streaming");
|
||||
newXS("uwsgi::streaming::close", XS_streaming_close, "uwsgi::streaming");
|
||||
|
||||
newXS("uwsgi::stacktrace", XS_uwsgi_stacktrace, "uwsgi");
|
||||
|
||||
|
||||
uperl.tmp_streaming_stash[uperl.tmp_current_i] = gv_stashpv("uwsgi::streaming", 0);
|
||||
|
||||
nonworker:
|
||||
|
||||
stash = gv_stashpv("uwsgi", 1);
|
||||
newCONSTSUB(stash, "VERSION", newSVpv(UWSGI_VERSION, 0));
|
||||
newCONSTSUB(stash, "SPOOL_OK", newSViv(-2));
|
||||
newCONSTSUB(stash, "SPOOL_RETRY", newSViv(-1));
|
||||
newCONSTSUB(stash, "SPOOL_IGNORE", newSViv(0));
|
||||
|
||||
init_perl_embedded_module();
|
||||
|
||||
}
|
||||
@@ -267,9 +313,6 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
|
||||
|
||||
char *app_name = uwsgi_concat2n(app, app_len, "", 0);
|
||||
|
||||
size_t size;
|
||||
char *buf = uwsgi_open_and_read(app_name, &size, 1, NULL);
|
||||
|
||||
if (uwsgi_file_exists(app_name)) {
|
||||
// prepare for $0 (if the file is local)
|
||||
uperl.embedding[1] = app_name;
|
||||
@@ -322,43 +365,35 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
|
||||
|
||||
uperl.tmp_current_i = i;
|
||||
|
||||
|
||||
if (uperl.locallib) {
|
||||
uwsgi_log("using %s as local::lib directory\n", uperl.locallib);
|
||||
uperl.embedding[1] = uwsgi_concat2("-Mlocal::lib=", uperl.locallib);
|
||||
uperl.embedding[2] = app_name;
|
||||
if (perl_parse(interpreters[i], xs_init, 3, uperl.embedding, NULL)) {
|
||||
// what to do here ? i hope no-one will use threads with dynamic apps... but clear the whole stuff...
|
||||
free(uperl.embedding[1]);
|
||||
uperl.embedding[1] = app_name;
|
||||
free(callables);
|
||||
uwsgi_perl_free_stashes();
|
||||
goto clear;
|
||||
}
|
||||
free(uperl.embedding[1]);
|
||||
uperl.embedding[1] = app_name;
|
||||
}
|
||||
else {
|
||||
if (perl_parse(interpreters[i], xs_init, 2, uperl.embedding, NULL)) {
|
||||
// We need to initialize the interpreter to execute
|
||||
// our xs_init hook, but we're *not* calling it with
|
||||
// uperl.embedding as an argument so we won't execute
|
||||
// BEGIN blocks in app_name twice.
|
||||
{
|
||||
char *perl_e_arg = uwsgi_concat2("#line 0 ", app_name);
|
||||
char *perl_init_arg[] = { "", "-e", perl_e_arg };
|
||||
if (perl_parse(interpreters[i], xs_init, 3, perl_init_arg, NULL)) {
|
||||
// what to do here ? i hope no-one will use threads with dynamic apps... but clear the whole stuff...
|
||||
free(callables);
|
||||
free(perl_e_arg);
|
||||
uwsgi_perl_free_stashes();
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
|
||||
perl_eval_pv("use IO::Handle;", 0);
|
||||
perl_eval_pv("use IO::File;", 0);
|
||||
perl_eval_pv("use IO::Socket;", 0);
|
||||
perl_eval_pv("use Scalar::Util;", 0);
|
||||
if (!uperl.no_die_catch) {
|
||||
perl_eval_pv("use Devel::StackTrace;", 0);
|
||||
if (!SvTRUE(ERRSV)) {
|
||||
uperl.stacktrace_available = 1;
|
||||
perl_eval_pv("$SIG{__DIE__} = \\&uwsgi::stacktrace;", 0);
|
||||
} else {
|
||||
free(perl_e_arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (uperl.locallib) {
|
||||
uwsgi_log("using %s as local::lib directory\n", uperl.locallib);
|
||||
char *local_lib_use = uwsgi_concat3("use local::lib qw(", uperl.locallib, ");");
|
||||
perl_eval_pv(local_lib_use, 1);
|
||||
free(local_lib_use);
|
||||
}
|
||||
perl_eval_pv("use IO::Handle;", 1);
|
||||
perl_eval_pv("use IO::File;", 1);
|
||||
perl_eval_pv("use IO::Socket;", 1);
|
||||
perl_eval_pv("use Scalar::Util;", 1);
|
||||
|
||||
if (uperl.argv_items || uperl.argv_item) {
|
||||
AV *uperl_argv = GvAV(PL_argvgv);
|
||||
if (uperl.argv_items) {
|
||||
@@ -375,12 +410,32 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SV *dollar_zero = get_sv("0", GV_ADD);
|
||||
sv_setsv(dollar_zero, newSVpv(app, app_len));
|
||||
|
||||
callables[i] = perl_eval_pv(uwsgi_concat4("#line 1 ", app_name, "\n", buf), 0);
|
||||
if (!callables[i]) {
|
||||
SV *has_plack = NULL;
|
||||
if (!uperl.no_plack) {
|
||||
has_plack = perl_eval_pv("use Plack::Util;", 0);
|
||||
}
|
||||
|
||||
if (!has_plack || SvTRUE(ERRSV)) {
|
||||
if (!uperl.no_plack) {
|
||||
uwsgi_log("Plack::Util is not installed, using \"do\" instead of \"load_psgi\"\n");
|
||||
}
|
||||
char *code = uwsgi_concat3("my $app = do '", app_name, "'; if ( !$app && ( my $error = $@ || $! )) { die $error; }; $app");
|
||||
callables[i] = perl_eval_pv(code, 0);
|
||||
free(code);
|
||||
}
|
||||
else {
|
||||
char *code = uwsgi_concat3("Plack::Util::load_psgi '", app_name , "';");
|
||||
callables[i] = perl_eval_pv(code, 0);
|
||||
free(code);
|
||||
}
|
||||
|
||||
if (!callables[i] || SvTYPE(callables[i]) == SVt_NULL || SvTRUE(ERRSV)) {
|
||||
if (SvTRUE(ERRSV)) {
|
||||
uwsgi_log("%s", SvPV_nolen(ERRSV));
|
||||
}
|
||||
uwsgi_log("unable to find PSGI function entry point.\n");
|
||||
// what to do here ? i hope no-one will use threads with dynamic apps...
|
||||
free(callables);
|
||||
@@ -388,18 +443,16 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
|
||||
goto clear;
|
||||
}
|
||||
|
||||
if (!uperl.no_die_catch) {
|
||||
perl_eval_pv("use Devel::StackTrace; $SIG{__DIE__} = sub { print Devel::StackTrace->new()->as_string() };", 0);
|
||||
if(SvTRUE(ERRSV)) {
|
||||
uwsgi_log("%s", SvPV_nolen(ERRSV));
|
||||
}
|
||||
}
|
||||
|
||||
PERL_SET_CONTEXT(interpreters[0]);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
if(SvTRUE(ERRSV)) {
|
||||
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
|
||||
free(callables);
|
||||
uwsgi_perl_free_stashes();
|
||||
goto clear;
|
||||
}
|
||||
|
||||
if (uwsgi_apps_cnt >= uwsgi.max_apps) {
|
||||
uwsgi_log("ERROR: you cannot load more than %d apps in a worker\n", uwsgi.max_apps);
|
||||
goto clear;
|
||||
@@ -456,6 +509,19 @@ clear2:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void uwsgi_psgi_preinit_apps() {
|
||||
if (uperl.exec) {
|
||||
PERL_SET_CONTEXT(uperl.main[0]);
|
||||
perl_parse(uperl.main[0], xs_init, 3, uperl.embedding, NULL);
|
||||
struct uwsgi_string_list *usl;
|
||||
uwsgi_foreach(usl, uperl.exec) {
|
||||
SV *dollar_zero = get_sv("0", GV_ADD);
|
||||
sv_setsv(dollar_zero, newSVpv(usl->value, usl->len));
|
||||
uwsgi_perl_exec(usl->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_psgi_app() {
|
||||
|
||||
if (uperl.psgi) {
|
||||
@@ -463,15 +529,11 @@ void uwsgi_psgi_app() {
|
||||
init_psgi_app(NULL, uperl.psgi, strlen(uperl.psgi), uperl.main);
|
||||
}
|
||||
// create a perl environment (if needed)
|
||||
else if (uperl.exec || uperl.shell) {
|
||||
else if (!uperl.exec && uperl.shell) {
|
||||
PERL_SET_CONTEXT(uperl.main[0]);
|
||||
perl_parse(uperl.main[0], xs_init, 2, uperl.embedding, NULL);
|
||||
perl_parse(uperl.main[0], xs_init, 3, uperl.embedding, NULL);
|
||||
}
|
||||
|
||||
struct uwsgi_string_list *usl;
|
||||
uwsgi_foreach(usl, uperl.exec) {
|
||||
uwsgi_perl_exec(usl->value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -480,7 +542,7 @@ int uwsgi_perl_mule(char *opt) {
|
||||
if (uwsgi_endswith(opt, ".pl")) {
|
||||
PERL_SET_CONTEXT(uperl.main[0]);
|
||||
uperl.embedding[1] = opt;
|
||||
if (perl_parse(uperl.main[0], xs_init, 2, uperl.embedding, NULL)) {
|
||||
if (perl_parse(uperl.main[0], xs_init, 3, uperl.embedding, NULL)) {
|
||||
return 0;
|
||||
}
|
||||
perl_run(uperl.main[0]);
|
||||
@@ -495,6 +557,6 @@ int uwsgi_perl_mule(char *opt) {
|
||||
void uwsgi_perl_exec(char *filename) {
|
||||
size_t size = 0;
|
||||
char *buf = uwsgi_open_and_read(filename, &size, 1, NULL);
|
||||
perl_eval_pv(buf, 0);
|
||||
perl_eval_pv(buf, 1);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ struct uwsgi_option uwsgi_perl_options[] = {
|
||||
|
||||
{"plshell", optional_argument, 0, "run a perl interactive shell", uwsgi_opt_plshell, NULL, 0},
|
||||
{"plshell-oneshot", no_argument, 0, "run a perl interactive shell (one shot)", uwsgi_opt_plshell, NULL, 0},
|
||||
|
||||
{"perl-no-plack", no_argument, 0, "force the use of do instead of Plack::Util::load_psgi", uwsgi_opt_true, &uperl.no_plack, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
|
||||
};
|
||||
@@ -705,6 +707,8 @@ void uwsgi_perl_post_fork() {
|
||||
|
||||
struct uwsgi_string_list *usl;
|
||||
uwsgi_foreach(usl, uperl.exec_post_fork) {
|
||||
SV *dollar_zero = get_sv("0", GV_ADD);
|
||||
sv_setsv(dollar_zero, newSVpv(usl->value, usl->len));
|
||||
uwsgi_perl_exec(usl->value);
|
||||
}
|
||||
|
||||
@@ -950,6 +954,7 @@ struct uwsgi_plugin psgi_plugin = {
|
||||
.init = uwsgi_perl_init,
|
||||
.options = uwsgi_perl_options,
|
||||
|
||||
.preinit_apps = uwsgi_psgi_preinit_apps,
|
||||
.init_apps = uwsgi_psgi_app,
|
||||
.mount_app = uwsgi_perl_mount_app,
|
||||
|
||||
|
||||
@@ -897,6 +897,85 @@ XS(XS_chunked_read_nb) {
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_spool) {
|
||||
|
||||
dXSARGS;
|
||||
psgi_check_args(1);
|
||||
|
||||
SV *arg = ST(0);
|
||||
HV *env = NULL;
|
||||
|
||||
char *body = NULL;
|
||||
STRLEN body_len = 0;
|
||||
|
||||
if (SvROK(arg)) {
|
||||
env = (HV *) SvRV(arg);
|
||||
}
|
||||
else {
|
||||
croak("spool argument must be a hashref");
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
|
||||
if (SvTYPE(env) != SVt_PVHV) {
|
||||
croak("spool argument must be a hashref");
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
|
||||
if (hv_exists(env, "body", 4)) {
|
||||
SV **body_sv = hv_fetch(env, "body", 4, 0);
|
||||
body = SvPV(*body_sv, body_len);
|
||||
(void)hv_delete(env, "body", 4, 0);
|
||||
}
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
|
||||
|
||||
HE *he;
|
||||
hv_iterinit(env);
|
||||
while((he = hv_iternext(env))) {
|
||||
I32 klen;
|
||||
STRLEN vlen;
|
||||
char *key = hv_iterkey(he, &klen);
|
||||
char *value = SvPV(hv_iterval(env, he), vlen);
|
||||
if (uwsgi_buffer_append_keyval(ub, key, klen, value, vlen)) {
|
||||
croak("unable to serialize hash to spool file");
|
||||
uwsgi_buffer_destroy(ub);
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
}
|
||||
|
||||
char *filename = uwsgi_spool_request(current_wsgi_req(), ub->buf, ub->pos, body, body_len);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
if (filename) {
|
||||
ST(0) = newSVpv(filename, strlen(filename));
|
||||
free(filename);
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
croak("unable to spool request");
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
|
||||
XS(XS_add_var) {
|
||||
dXSARGS;
|
||||
psgi_check_args(2);
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
STRLEN keylen;
|
||||
char *key = SvPV(ST(0), keylen);
|
||||
|
||||
STRLEN vallen;
|
||||
char *val = SvPV(ST(1), vallen);
|
||||
|
||||
if (!uwsgi_req_append(wsgi_req, key, keylen, val, vallen)) {
|
||||
croak("unable to add request var, check your buffer size");
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
|
||||
XSRETURN_YES;
|
||||
|
||||
}
|
||||
|
||||
void init_perl_embedded_module() {
|
||||
psgi_xs(reload);
|
||||
|
||||
@@ -957,4 +1036,8 @@ void init_perl_embedded_module() {
|
||||
psgi_xs(sharedarea_wait);
|
||||
|
||||
psgi_xs(spooler);
|
||||
psgi_xs(spool);
|
||||
|
||||
psgi_xs(add_var);
|
||||
|
||||
}
|
||||
|
||||
+41
-25
@@ -16,12 +16,15 @@ struct uwsgi_pypy {
|
||||
char *home;
|
||||
char *wsgi;
|
||||
char *wsgi_file;
|
||||
char *paste;
|
||||
struct uwsgi_string_list *eval;
|
||||
struct uwsgi_string_list *eval_post_fork;
|
||||
struct uwsgi_string_list *exec;
|
||||
struct uwsgi_string_list *exec_post_fork;
|
||||
|
||||
struct uwsgi_string_list *pp;
|
||||
|
||||
pthread_mutex_t attach_thread_lock;
|
||||
} upypy;
|
||||
|
||||
// the functions exposed by libpypy-c
|
||||
@@ -32,8 +35,10 @@ void (*u_pypy_thread_attach)(void);
|
||||
void (*u_pypy_init_threads)(void);
|
||||
|
||||
// the hooks you can override with pypy
|
||||
void (*uwsgi_pypy_hook_execute_source)(char *);
|
||||
void (*uwsgi_pypy_hook_loader)(char *);
|
||||
void (*uwsgi_pypy_hook_file_loader)(char *);
|
||||
void (*uwsgi_pypy_hook_paste_loader)(char *);
|
||||
void (*uwsgi_pypy_hook_pythonpath)(char *);
|
||||
void (*uwsgi_pypy_hook_request)(void *, int);
|
||||
void (*uwsgi_pypy_post_fork_hook)(void);
|
||||
@@ -182,23 +187,21 @@ ready:
|
||||
|
||||
static void uwsgi_pypy_preinit_apps() {
|
||||
|
||||
struct uwsgi_string_list *usl = upypy.eval;
|
||||
while(usl) {
|
||||
if (u_pypy_execute_source(usl->value)) {
|
||||
exit(1);
|
||||
}
|
||||
usl = usl->next;
|
||||
if (!uwsgi_pypy_hook_execute_source) {
|
||||
uwsgi_log("*** WARNING your pypy setup code does not expose a callback for \"execute_source\" ***\n");
|
||||
return;
|
||||
}
|
||||
|
||||
usl = upypy.exec;
|
||||
while(usl) {
|
||||
struct uwsgi_string_list *usl = NULL;
|
||||
uwsgi_foreach(usl, upypy.eval) {
|
||||
uwsgi_pypy_hook_execute_source(usl->value);
|
||||
}
|
||||
|
||||
uwsgi_foreach(usl, upypy.exec) {
|
||||
size_t rlen = 0;
|
||||
char *buffer = uwsgi_open_and_read(usl->value, &rlen, 1, NULL);
|
||||
if (u_pypy_execute_source(buffer)) {
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_pypy_hook_execute_source(buffer);
|
||||
free(buffer);
|
||||
usl = usl->next;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,6 +234,10 @@ static void uwsgi_pypy_init_apps() {
|
||||
if (uwsgi_pypy_hook_file_loader && upypy.wsgi_file) {
|
||||
uwsgi_pypy_hook_file_loader(upypy.wsgi_file);
|
||||
}
|
||||
|
||||
if (uwsgi_pypy_hook_paste_loader && upypy.paste) {
|
||||
uwsgi_pypy_hook_paste_loader(upypy.paste);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -240,12 +247,20 @@ static void uwsgi_pypy_atexit() {
|
||||
}
|
||||
*/
|
||||
|
||||
static void uwsgi_opt_pypy_ini_paste(char *opt, char *value, void *foobar) {
|
||||
uwsgi_opt_load_ini(opt, value, NULL);
|
||||
upypy.paste = value;
|
||||
}
|
||||
|
||||
|
||||
static struct uwsgi_option uwsgi_pypy_options[] = {
|
||||
{"pypy-lib", required_argument, 0, "set the path/name of the pypy library", uwsgi_opt_set_str, &upypy.lib, 0},
|
||||
{"pypy-setup", required_argument, 0, "set the path of the python setup script", uwsgi_opt_set_str, &upypy.setup, 0},
|
||||
{"pypy-home", required_argument, 0, "set the home of pypy library", uwsgi_opt_set_str, &upypy.home, 0},
|
||||
{"pypy-wsgi", required_argument, 0, "load a WSGI module", uwsgi_opt_set_str, &upypy.wsgi, 0},
|
||||
{"pypy-wsgi-file", required_argument, 0, "load a WSGI/mod_wsgi file", uwsgi_opt_set_str, &upypy.wsgi_file, 0},
|
||||
{"pypy-ini-paste", required_argument, 0, "load a paste.deploy config file containing uwsgi section", uwsgi_opt_pypy_ini_paste, NULL, UWSGI_OPT_IMMEDIATE},
|
||||
{"pypy-paste", required_argument, 0, "load a paste.deploy config file", uwsgi_opt_set_str, &upypy.paste, 0},
|
||||
{"pypy-eval", required_argument, 0, "evaluate pypy code before fork()", uwsgi_opt_add_string_list, &upypy.eval, 0},
|
||||
{"pypy-eval-post-fork", required_argument, 0, "evaluate pypy code soon after fork()", uwsgi_opt_add_string_list, &upypy.eval_post_fork, 0},
|
||||
{"pypy-exec", required_argument, 0, "execute pypy code from file before fork()", uwsgi_opt_add_string_list, &upypy.exec, 0},
|
||||
@@ -264,7 +279,9 @@ static void uwsgi_pypy_enable_threads() {
|
||||
|
||||
static void uwsgi_pypy_init_thread() {
|
||||
if (u_pypy_thread_attach) {
|
||||
pthread_mutex_lock(&upypy.attach_thread_lock);
|
||||
u_pypy_thread_attach();
|
||||
pthread_mutex_unlock(&upypy.attach_thread_lock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,22 +303,16 @@ static uint64_t uwsgi_pypy_rpc(void *func, uint8_t argc, char **argv, uint16_t a
|
||||
}
|
||||
|
||||
static void uwsgi_pypy_post_fork() {
|
||||
struct uwsgi_string_list *usl = upypy.eval_post_fork;
|
||||
while(usl) {
|
||||
if (u_pypy_execute_source(usl->value)) {
|
||||
exit(1);
|
||||
}
|
||||
usl = usl->next;
|
||||
pthread_mutex_init(&upypy.attach_thread_lock, NULL);
|
||||
struct uwsgi_string_list *usl = NULL;
|
||||
uwsgi_foreach(usl, upypy.eval_post_fork) {
|
||||
uwsgi_pypy_hook_execute_source(usl->value);
|
||||
}
|
||||
usl = upypy.exec_post_fork;
|
||||
while(usl) {
|
||||
uwsgi_foreach(usl, upypy.exec_post_fork) {
|
||||
size_t rlen = 0;
|
||||
char *buffer = uwsgi_open_and_read(usl->value, &rlen, 1, NULL);
|
||||
if (u_pypy_execute_source(buffer)) {
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_pypy_hook_execute_source(buffer);
|
||||
free(buffer);
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
if (uwsgi_pypy_post_fork_hook) {
|
||||
@@ -318,10 +329,15 @@ static void uwsgi_pypy_onload() {
|
||||
|
||||
static int uwsgi_pypy_mule(char *opt) {
|
||||
|
||||
if (!uwsgi_pypy_hook_execute_source) {
|
||||
uwsgi_log("!!! no \"execute_source\" callback in your pypy setup code !!!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (uwsgi_endswith(opt, ".py")) {
|
||||
size_t rlen = 0;
|
||||
char *buffer = uwsgi_open_and_read(opt, &rlen, 1, NULL);
|
||||
u_pypy_execute_source(buffer);
|
||||
uwsgi_pypy_hook_execute_source(buffer);
|
||||
free(buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -24,8 +24,10 @@ ssize_t read(int, void *, size_t);
|
||||
ssize_t write(int, const void *, size_t);
|
||||
int close(int);
|
||||
|
||||
void (*uwsgi_pypy_hook_execute_source)(char *);
|
||||
void (*uwsgi_pypy_hook_loader)(char *);
|
||||
void (*uwsgi_pypy_hook_file_loader)(char *);
|
||||
void (*uwsgi_pypy_hook_paste_loader)(char *);
|
||||
void (*uwsgi_pypy_hook_pythonpath)(char *);
|
||||
void (*uwsgi_pypy_hook_request)(struct wsgi_request *);
|
||||
void (*uwsgi_pypy_post_fork_hook)(void);
|
||||
@@ -276,6 +278,14 @@ wsgi_application = None
|
||||
if len(sys.argv) == 0:
|
||||
sys.argv.insert(0, ffi.string(lib.uwsgi_binary_path()))
|
||||
|
||||
"""
|
||||
execute source, we expose it as cffi callback to avoid deadlocks
|
||||
after GIL initialization
|
||||
"""
|
||||
@ffi.callback("void(char *)")
|
||||
def uwsgi_pypy_execute_source(s):
|
||||
source = ffi.string(s)
|
||||
exec(source)
|
||||
|
||||
"""
|
||||
load a wsgi module
|
||||
@@ -304,6 +314,25 @@ def uwsgi_pypy_file_loader(filename):
|
||||
mod = imp.load_source('uwsgi_file_wsgi', w)
|
||||
wsgi_application = getattr(mod, c)
|
||||
|
||||
"""
|
||||
load a .ini paste app
|
||||
"""
|
||||
@ffi.callback("void(char *)")
|
||||
def uwsgi_pypy_paste_loader(config):
|
||||
global wsgi_application
|
||||
c = ffi.string(config)
|
||||
if c.startswith('config:'):
|
||||
c = c[7:]
|
||||
if c[0] != '/':
|
||||
c = os.getcwd() + '/' + c
|
||||
try:
|
||||
from paste.script.util.logging_config import fileConfig
|
||||
fileConfig(c)
|
||||
except ImportError:
|
||||
print "PyPy WARNING: unable to load paste.script.util.logging_config"
|
||||
from paste.deploy import loadapp
|
||||
wsgi_application = loadapp('config:%s' % c)
|
||||
|
||||
"""
|
||||
.post_fork_hook
|
||||
"""
|
||||
@@ -460,8 +489,10 @@ def uwsgi_pypy_wsgi_handler(wsgi_req):
|
||||
if hasattr(response, 'close'):
|
||||
response.close()
|
||||
|
||||
lib.uwsgi_pypy_hook_execute_source = uwsgi_pypy_execute_source
|
||||
lib.uwsgi_pypy_hook_loader = uwsgi_pypy_loader
|
||||
lib.uwsgi_pypy_hook_file_loader = uwsgi_pypy_file_loader
|
||||
lib.uwsgi_pypy_hook_paste_loader = uwsgi_pypy_paste_loader
|
||||
lib.uwsgi_pypy_hook_pythonpath = uwsgi_pypy_pythonpath
|
||||
lib.uwsgi_pypy_hook_request = uwsgi_pypy_wsgi_handler
|
||||
lib.uwsgi_pypy_post_fork_hook = uwsgi_pypy_post_fork_hook
|
||||
|
||||
@@ -197,6 +197,12 @@ int uwsgi_python_init() {
|
||||
uwsgi_log_initial("Python version: %.*s %s\n", pyversion-Py_GetVersion(), Py_GetVersion(), Py_GetCompiler()+1);
|
||||
}
|
||||
|
||||
if (Py_IsInitialized()) {
|
||||
uwsgi_log("--- Python VM already initialized ---\n");
|
||||
PyGILState_Ensure();
|
||||
goto ready;
|
||||
}
|
||||
|
||||
if (up.home != NULL) {
|
||||
#ifdef PYTHREE
|
||||
// check for PEP 405 virtualenv (starting from python 3.3)
|
||||
@@ -251,6 +257,8 @@ pep405:
|
||||
|
||||
Py_Initialize();
|
||||
|
||||
ready:
|
||||
|
||||
if (!uwsgi.has_threads) {
|
||||
uwsgi_log_initial("*** Python threads support is disabled. You can enable it with --enable-threads ***\n");
|
||||
}
|
||||
@@ -1616,25 +1624,25 @@ int uwsgi_python_spooler(char *filename, char *buf, uint16_t len, char *body, si
|
||||
return 0;
|
||||
}
|
||||
|
||||
int retval = -1;
|
||||
PyObject *spool_dict = PyDict_New();
|
||||
PyObject *pyargs, *ret;
|
||||
PyObject *pyargs = PyTuple_New(1);
|
||||
PyObject *ret = NULL;
|
||||
|
||||
PyObject *value = PyString_FromString(filename);
|
||||
PyDict_SetItemString(spool_dict, "spooler_task_name", value);
|
||||
Py_DECREF(value);
|
||||
|
||||
if (uwsgi_hooked_parse(buf, len, uwsgi_python_add_item, spool_dict)) {
|
||||
Py_DECREF(spool_dict);
|
||||
// malformed packet, destroy it
|
||||
UWSGI_RELEASE_GIL;
|
||||
return -2;
|
||||
retval = -2;
|
||||
goto clear;
|
||||
}
|
||||
|
||||
pyargs = PyTuple_New(1);
|
||||
|
||||
PyObject *zero = PyString_FromString(filename);
|
||||
PyDict_SetItemString(spool_dict, "spooler_task_name", zero);
|
||||
Py_DECREF(zero);
|
||||
|
||||
if (body && body_len > 0) {
|
||||
PyDict_SetItemString(spool_dict, "body", PyString_FromStringAndSize(body, body_len));
|
||||
PyObject *value = PyString_FromStringAndSize(body, body_len);
|
||||
PyDict_SetItemString(spool_dict, "body", value);
|
||||
Py_DECREF(value);
|
||||
}
|
||||
PyTuple_SetItem(pyargs, 0, spool_dict);
|
||||
|
||||
@@ -1642,32 +1650,25 @@ int uwsgi_python_spooler(char *filename, char *buf, uint16_t len, char *body, si
|
||||
|
||||
if (ret) {
|
||||
if (!PyInt_Check(ret)) {
|
||||
Py_DECREF(ret);
|
||||
Py_DECREF(spool_dict);
|
||||
Py_DECREF(pyargs);
|
||||
// error, retry
|
||||
UWSGI_RELEASE_GIL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int retval = (int) PyInt_AsLong(ret);
|
||||
Py_DECREF(ret);
|
||||
Py_DECREF(spool_dict);
|
||||
Py_DECREF(pyargs);
|
||||
UWSGI_RELEASE_GIL;
|
||||
return retval;
|
||||
|
||||
retval = -1; // error, retry
|
||||
} else {
|
||||
retval = (int) PyInt_AsLong(ret);
|
||||
}
|
||||
goto clear;
|
||||
}
|
||||
|
||||
|
||||
if (PyErr_Occurred())
|
||||
PyErr_Print();
|
||||
|
||||
Py_DECREF(spool_dict);
|
||||
Py_DECREF(pyargs);
|
||||
|
||||
// error, retry
|
||||
retval = -1;
|
||||
|
||||
clear:
|
||||
Py_XDECREF(ret);
|
||||
Py_XDECREF(pyargs);
|
||||
Py_XDECREF(spool_dict);
|
||||
UWSGI_RELEASE_GIL;
|
||||
return -1;
|
||||
return retval;
|
||||
}
|
||||
|
||||
void uwsgi_python_resume(struct wsgi_request *wsgi_req) {
|
||||
@@ -1802,15 +1803,13 @@ static void uwsgi_python_harakiri(int wid) {
|
||||
if (fd < 1)
|
||||
goto exit;
|
||||
|
||||
int ret = uwsgi_waitfd(fd, uwsgi.socket_timeout);
|
||||
if (ret <= 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
ssize_t len = read(fd, buf, 8192);
|
||||
if (len <= 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
uwsgi_log("%.*s", (int) len, buf);
|
||||
for(;;) {
|
||||
int ret = uwsgi_waitfd(fd, uwsgi.socket_timeout);
|
||||
if (ret <= 0) goto cleanup;
|
||||
ssize_t len = read(fd, buf, 8192);
|
||||
if (len <= 0) goto cleanup;
|
||||
uwsgi_log("%.*s", (int) len, buf);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
close(fd);
|
||||
|
||||
@@ -114,7 +114,6 @@ void *uwsgi_python_tracebacker_thread(void *foobar) {
|
||||
}
|
||||
PyObject *frame = PyIter_Next(frames_iter);
|
||||
while(frame) {
|
||||
|
||||
PyObject *thread_id = PyTuple_GetItem(frame, 0);
|
||||
if (!thread_id) goto next2;
|
||||
|
||||
|
||||
+76
-112
@@ -4,6 +4,29 @@ extern struct uwsgi_server uwsgi;
|
||||
extern struct uwsgi_python up;
|
||||
extern struct uwsgi_plugin python_plugin;
|
||||
|
||||
static PyObject *py_uwsgi_add_var(PyObject * self, PyObject * args) {
|
||||
char *key = NULL;
|
||||
Py_ssize_t keylen = 0;
|
||||
char *val = NULL;
|
||||
Py_ssize_t vallen = 0;
|
||||
struct wsgi_request *wsgi_req = py_current_wsgi_req();
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s#s#", &key, &keylen, &val, &vallen)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!uwsgi_req_append(wsgi_req, key, keylen, val, vallen)) {
|
||||
return PyErr_Format(PyExc_ValueError, "unable to add request var, check your buffer size");
|
||||
}
|
||||
|
||||
Py_INCREF(Py_True);
|
||||
return Py_True;
|
||||
}
|
||||
|
||||
static PyObject *py_uwsgi_micros(PyObject * self, PyObject * args) {
|
||||
return PyLong_FromUnsignedLongLong(uwsgi_micros());
|
||||
}
|
||||
|
||||
static PyObject *py_uwsgi_signal_wait(PyObject * self, PyObject * args) {
|
||||
|
||||
struct wsgi_request *wsgi_req = py_current_wsgi_req();
|
||||
@@ -1289,7 +1312,7 @@ PyObject *py_uwsgi_mule_get_msg(PyObject * self, PyObject * args, PyObject *kwar
|
||||
int timeout = -1;
|
||||
int manage_signals = 1, manage_farms = 1;
|
||||
|
||||
static char *kwlist[] = {"signals", "buffer_size", "timeout", "farms", NULL};
|
||||
static char *kwlist[] = {"signals", "farms", "buffer_size", "timeout", NULL};
|
||||
|
||||
if (uwsgi.muleid == 0) {
|
||||
return PyErr_Format(PyExc_ValueError, "you can receive mule messages only in a mule !!!");
|
||||
@@ -1745,25 +1768,13 @@ PyObject *py_uwsgi_send_spool(PyObject * self, PyObject * args, PyObject *kw) {
|
||||
PyObject *spool_dict, *spool_vars;
|
||||
PyObject *zero, *key, *val;
|
||||
uint16_t keysize, valsize;
|
||||
char *cur_buf;
|
||||
int i;
|
||||
char spool_filename[1024];
|
||||
struct wsgi_request *wsgi_req = py_current_wsgi_req();
|
||||
char *priority = NULL;
|
||||
long numprio = 0;
|
||||
time_t at = 0;
|
||||
char *body = NULL;
|
||||
size_t body_len= 0;
|
||||
|
||||
// this is a counter for non-request-related tasks (like threads or greenlet)
|
||||
static int internal_counter = 0xffff;
|
||||
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
|
||||
spool_dict = PyTuple_GetItem(args, 0);
|
||||
|
||||
if (spool_dict) {
|
||||
|
||||
if (!PyDict_Check(spool_dict)) {
|
||||
return PyErr_Format(PyExc_ValueError, "The argument of spooler callable must be a dictionary");
|
||||
}
|
||||
@@ -1774,46 +1785,10 @@ PyObject *py_uwsgi_send_spool(PyObject * self, PyObject * args, PyObject *kw) {
|
||||
spool_dict = kw;
|
||||
}
|
||||
|
||||
|
||||
if (!spool_dict) {
|
||||
return PyErr_Format(PyExc_ValueError, "The argument of spooler callable must be a dictionary");
|
||||
}
|
||||
|
||||
// TODO if "spooler" is a num, get the spooler by id, otherwise get it by directory
|
||||
PyObject *py_spooler = uwsgi_py_dict_get(spool_dict, "spooler");
|
||||
if (py_spooler) {
|
||||
if (PyString_Check(py_spooler)) {
|
||||
uspool = uwsgi_get_spooler_by_name(PyString_AsString(py_spooler));
|
||||
if (!uspool) {
|
||||
return PyErr_Format(PyExc_ValueError, "Unknown spooler requested");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *pyprio = uwsgi_py_dict_get(spool_dict, "priority");
|
||||
if (pyprio) {
|
||||
if (PyInt_Check(pyprio)) {
|
||||
numprio = PyInt_AsLong(pyprio);
|
||||
uwsgi_py_dict_del(spool_dict, "priority");
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *pyat = uwsgi_py_dict_get(spool_dict, "at");
|
||||
if (pyat) {
|
||||
if (PyInt_Check(pyat)) {
|
||||
at = (time_t) PyInt_AsLong(pyat);
|
||||
uwsgi_py_dict_del(spool_dict, "at");
|
||||
}
|
||||
else if (PyLong_Check(pyat)) {
|
||||
at = (time_t) PyLong_AsLong(pyat);
|
||||
uwsgi_py_dict_del(spool_dict, "at");
|
||||
}
|
||||
else if (PyFloat_Check(pyat)) {
|
||||
at = (time_t) PyFloat_AsDouble(pyat);
|
||||
uwsgi_py_dict_del(spool_dict, "at");
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *pybody = uwsgi_py_dict_get(spool_dict, "body");
|
||||
if (pybody) {
|
||||
if (PyString_Check(pybody)) {
|
||||
@@ -1830,9 +1805,8 @@ PyObject *py_uwsgi_send_spool(PyObject * self, PyObject * args, PyObject *kw) {
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
char *spool_buffer = uwsgi_malloc(UMAX16);
|
||||
|
||||
cur_buf = spool_buffer;
|
||||
int i;
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
|
||||
|
||||
for (i = 0; i < PyList_Size(spool_vars); i++) {
|
||||
zero = PyList_GetItem(spool_vars, i);
|
||||
@@ -1841,98 +1815,84 @@ PyObject *py_uwsgi_send_spool(PyObject * self, PyObject * args, PyObject *kw) {
|
||||
key = PyTuple_GetItem(zero, 0);
|
||||
val = PyTuple_GetItem(zero, 1);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("ob_type %s %s\n", key->ob_type->tp_name, val->ob_type->tp_name);
|
||||
#endif
|
||||
|
||||
if (PyString_Check(key) && PyString_Check(val)) {
|
||||
|
||||
if (PyString_Check(key)) {
|
||||
|
||||
keysize = PyString_Size(key);
|
||||
valsize = PyString_Size(val);
|
||||
if (cur_buf + keysize + 2 + valsize + 2 <= spool_buffer + UMAX16) {
|
||||
|
||||
*cur_buf++ = (uint8_t) (keysize & 0xff);
|
||||
*cur_buf++ = (uint8_t) ((keysize >> 8) & 0xff);
|
||||
|
||||
memcpy(cur_buf, PyString_AsString(key), keysize);
|
||||
cur_buf += keysize;
|
||||
|
||||
*cur_buf++ = (uint8_t) (valsize & 0xff);
|
||||
*cur_buf++ = (uint8_t) ((valsize >> 8) & 0xff);
|
||||
|
||||
memcpy(cur_buf, PyString_AsString(val), valsize);
|
||||
cur_buf += valsize;
|
||||
|
||||
if (PyString_Check(val)) {
|
||||
valsize = PyString_Size(val);
|
||||
if (uwsgi_buffer_append_keyval(ub, PyString_AsString(key), keysize, PyString_AsString(val), valsize)) {
|
||||
Py_DECREF(zero);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Py_DECREF(zero);
|
||||
free(spool_buffer);
|
||||
return PyErr_Format(PyExc_ValueError, "spooler packet cannot be more than %d bytes", UMAX16);
|
||||
#ifdef PYTHREE
|
||||
PyObject *str = PyObject_Bytes(val);
|
||||
#else
|
||||
PyObject *str = PyObject_Str(val);
|
||||
#endif
|
||||
if (!str) {
|
||||
Py_DECREF(zero);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
goto error;
|
||||
}
|
||||
if (uwsgi_buffer_append_keyval(ub, PyString_AsString(key), keysize, PyString_AsString(str), PyString_Size(str))) {
|
||||
Py_DECREF(zero);
|
||||
Py_DECREF(str);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(str);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Py_DECREF(zero);
|
||||
free(spool_buffer);
|
||||
return PyErr_Format(PyExc_ValueError, "spooler callable dictionary must contains only strings");
|
||||
uwsgi_buffer_destroy(ub);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else {
|
||||
free(spool_buffer);
|
||||
Py_DECREF(zero);
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
uwsgi_buffer_destroy(ub);
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(zero);
|
||||
}
|
||||
else {
|
||||
free(spool_buffer);
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
uwsgi_buffer_destroy(ub);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (numprio) {
|
||||
priority = uwsgi_num2str(numprio);
|
||||
}
|
||||
|
||||
int async_id;
|
||||
|
||||
if (wsgi_req) {
|
||||
async_id = wsgi_req->async_id;
|
||||
}
|
||||
else {
|
||||
// the GIL is protecting this counter...
|
||||
async_id = internal_counter;
|
||||
internal_counter++;
|
||||
}
|
||||
|
||||
UWSGI_RELEASE_GIL
|
||||
|
||||
i = spool_request(uspool, spool_filename, uwsgi.workers[0].requests + 1, async_id, spool_buffer, cur_buf - spool_buffer, priority, at, body, body_len);
|
||||
char *filename = uwsgi_spool_request(wsgi_req, ub->buf, ub->pos, body, body_len);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
|
||||
UWSGI_GET_GIL
|
||||
|
||||
|
||||
if (pybody) {
|
||||
Py_DECREF(pybody);
|
||||
}
|
||||
|
||||
if (priority) {
|
||||
free(priority);
|
||||
}
|
||||
|
||||
free(spool_buffer);
|
||||
|
||||
|
||||
Py_DECREF(spool_vars);
|
||||
|
||||
if (i > 0) {
|
||||
char *slash = uwsgi_get_last_char(spool_filename, '/');
|
||||
if (slash) {
|
||||
return PyString_FromString(slash+1);
|
||||
}
|
||||
return PyString_FromString(spool_filename);
|
||||
if (filename) {
|
||||
PyObject *ret = PyString_FromString(filename);
|
||||
free(filename);
|
||||
return ret;
|
||||
}
|
||||
return PyErr_Format(PyExc_ValueError, "unable to spool job");
|
||||
error:
|
||||
#ifdef PYTHREE
|
||||
return PyErr_Format(PyExc_ValueError, "spooler callable dictionary must contains only bytes");
|
||||
#else
|
||||
return PyErr_Format(PyExc_ValueError, "spooler callable dictionary must contains only strings");
|
||||
#endif
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_spooler_pid(PyObject * self, PyObject * args) {
|
||||
@@ -2480,6 +2440,10 @@ static PyMethodDef uwsgi_advanced_methods[] = {
|
||||
|
||||
{"ready_fd", py_uwsgi_ready_fd, METH_VARARGS, ""},
|
||||
|
||||
{"add_var", py_uwsgi_add_var, METH_VARARGS, ""},
|
||||
|
||||
{"micros", py_uwsgi_micros, METH_VARARGS, ""},
|
||||
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
|
||||
@@ -21,12 +21,13 @@ int uwsgi_python_send_body(struct wsgi_request *wsgi_req, PyObject *chunk) {
|
||||
char *content = NULL;
|
||||
size_t content_len = 0;
|
||||
|
||||
if (!up.wsgi_accept_buffer && !wsgi_req->is_raw) goto strict;
|
||||
#if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER)
|
||||
Py_buffer pbuf;
|
||||
int has_buffer = 0;
|
||||
#endif
|
||||
|
||||
if (!up.wsgi_accept_buffer && !wsgi_req->is_raw) goto strict;
|
||||
|
||||
#if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER)
|
||||
if (PyObject_CheckBuffer(chunk)) {
|
||||
if (!PyObject_GetBuffer(chunk, &pbuf, PyBUF_SIMPLE)) {
|
||||
|
||||
+30
-68
@@ -932,35 +932,36 @@ static VALUE uwsgi_ruby_signal(int argc, VALUE *argv, VALUE *class) {
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
int rack_uwsgi_build_spool(VALUE rbkey, VALUE rbval, VALUE argv) {
|
||||
char **sa = (char **) argv;
|
||||
static int rack_uwsgi_build_spool(VALUE rbkey, VALUE rbval, VALUE argv) {
|
||||
struct uwsgi_buffer *ub = (struct uwsgi_buffer *) argv;
|
||||
|
||||
char *cur_buf = sa[0];
|
||||
char *watermark = sa[1];
|
||||
|
||||
if (TYPE(rbkey) != T_STRING || TYPE(rbval) != T_STRING) {
|
||||
if (TYPE(rbkey) != T_STRING) {
|
||||
rb_raise(rb_eRuntimeError, "spool hash must contains only strings");
|
||||
return ST_STOP;
|
||||
}
|
||||
|
||||
char *key = RSTRING_PTR(rbkey); uint16_t keylen = RSTRING_LEN(rbkey);
|
||||
char *val = RSTRING_PTR(rbval); uint16_t vallen = RSTRING_LEN(rbval);
|
||||
|
||||
if (cur_buf + (2+keylen+2+vallen) > watermark) {
|
||||
rb_raise(rb_eRuntimeError, "spool hash size can be no more than 64K");
|
||||
return ST_STOP;
|
||||
if (TYPE(rbval) == T_STRING) {
|
||||
char *val = RSTRING_PTR(rbval); uint16_t vallen = RSTRING_LEN(rbval);
|
||||
if (uwsgi_buffer_append_keyval(ub, key, keylen, val, vallen)) {
|
||||
rb_raise(rb_eRuntimeError, "error building the spool packet");
|
||||
return ST_STOP;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//VALUE str = rb_any_to_s(rbval);
|
||||
VALUE str = rb_funcall( rbval, rb_intern("to_s"), 0);
|
||||
if (!str) {
|
||||
rb_raise(rb_eRuntimeError, "error building the spool packet");
|
||||
return ST_STOP;
|
||||
}
|
||||
char *val = RSTRING_PTR(str); uint16_t vallen = RSTRING_LEN(str);
|
||||
if (uwsgi_buffer_append_keyval(ub, key, keylen, val, vallen)) {
|
||||
rb_raise(rb_eRuntimeError, "error building the spool packet");
|
||||
return ST_STOP;
|
||||
}
|
||||
}
|
||||
|
||||
*cur_buf++ = (uint8_t) (keylen & 0xff);
|
||||
*cur_buf++ = (uint8_t) ((keylen >> 8) & 0xff);
|
||||
memcpy(cur_buf, key, keylen); cur_buf += keylen;
|
||||
|
||||
*cur_buf++ = (uint8_t) (vallen & 0xff);
|
||||
*cur_buf++ = (uint8_t) ((vallen >> 8) & 0xff);
|
||||
memcpy(cur_buf, val, vallen); cur_buf += vallen;
|
||||
|
||||
// fix the ptr
|
||||
sa[0] = cur_buf;
|
||||
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
@@ -968,38 +969,12 @@ int rack_uwsgi_build_spool(VALUE rbkey, VALUE rbval, VALUE argv) {
|
||||
|
||||
static VALUE rack_uwsgi_send_spool(VALUE *class, VALUE args) {
|
||||
|
||||
char spool_filename[1024];
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
char *priority = NULL;
|
||||
long numprio = 0;
|
||||
time_t at = 0;
|
||||
char *body = NULL;
|
||||
size_t body_len= 0;
|
||||
|
||||
Check_Type(args, T_HASH);
|
||||
|
||||
// priority
|
||||
#ifdef RUBY19
|
||||
VALUE rbprio = rb_hash_lookup(args, rb_str_new2("priority"));
|
||||
#else
|
||||
VALUE rbprio = rb_hash_aref(args, rb_str_new2("priority"));
|
||||
#endif
|
||||
if (TYPE(rbprio) == T_FIXNUM) {
|
||||
numprio = NUM2INT(rbprio);
|
||||
rb_hash_delete(args, rb_str_new2("priority"));
|
||||
}
|
||||
|
||||
// at
|
||||
#ifdef RUBY19
|
||||
VALUE rbat = rb_hash_lookup(args, rb_str_new2("at"));
|
||||
#else
|
||||
VALUE rbat = rb_hash_aref(args, rb_str_new2("at"));
|
||||
#endif
|
||||
if (TYPE(rbat) == T_FIXNUM) {
|
||||
at = NUM2INT(rbat);
|
||||
rb_hash_delete(args, rb_str_new2("at"));
|
||||
}
|
||||
|
||||
// body
|
||||
#ifdef RUBY19
|
||||
VALUE rbbody = rb_hash_lookup(args, rb_str_new2("body"));
|
||||
@@ -1012,31 +987,18 @@ static VALUE rack_uwsgi_send_spool(VALUE *class, VALUE args) {
|
||||
rb_hash_delete(args, rb_str_new2("body"));
|
||||
}
|
||||
|
||||
char *spool_buffer = uwsgi_malloc(UMAX16);
|
||||
char *argv[2];
|
||||
argv[0] = spool_buffer;
|
||||
argv[1] = spool_buffer + UMAX16 ;
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
|
||||
|
||||
rb_hash_foreach(args, rack_uwsgi_build_spool, (VALUE) argv);
|
||||
rb_hash_foreach(args, rack_uwsgi_build_spool, (VALUE) ub);
|
||||
|
||||
if (numprio) {
|
||||
priority = uwsgi_num2str((int)numprio);
|
||||
}
|
||||
char *filename = uwsgi_spool_request(wsgi_req, ub->buf, ub->pos, body, body_len);
|
||||
|
||||
int ret = spool_request(uwsgi.spoolers, spool_filename, (int)(uwsgi.workers[0].requests + 1), wsgi_req->async_id, spool_buffer, (int)(argv[0] - spool_buffer), priority, at, body, body_len);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
|
||||
if (priority) {
|
||||
free(priority);
|
||||
}
|
||||
|
||||
free(spool_buffer);
|
||||
|
||||
if (ret > 0) {
|
||||
char *slash = uwsgi_get_last_char(spool_filename, '/');
|
||||
if (slash) {
|
||||
return rb_str_new2(slash+1);
|
||||
}
|
||||
return rb_str_new2(spool_filename);
|
||||
if (filename) {
|
||||
VALUE ret = rb_str_new2(filename);
|
||||
free(filename);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rb_raise(rb_eRuntimeError, "unable to spool job");
|
||||
|
||||
@@ -459,6 +459,10 @@ static void rack_hack_dollar_zero(VALUE name, ID id) {
|
||||
rb_obj_taint(ur.dollar_zero);
|
||||
}
|
||||
|
||||
#ifndef RUBY19
|
||||
void Init_stack(VALUE*);
|
||||
#endif
|
||||
|
||||
int uwsgi_rack_init(){
|
||||
|
||||
#ifdef RUBY19
|
||||
@@ -483,14 +487,16 @@ int uwsgi_rack_init(){
|
||||
uwsgi_log("*** if you get errors about rubygems.rb, you can:\n");
|
||||
uwsgi_log("*** 1) add a directory to the libdir search path using --ruby-libdir ***\n");
|
||||
uwsgi_log("*** 2) force the RUBY_EXEC_PREFIX with --chdir ***\n");
|
||||
#ifdef UWSGI_RUBY_LIBDIR
|
||||
uwsgi_string_new_list(&ur.libdir, UWSGI_RUBY_LIBDIR);
|
||||
#endif
|
||||
#ifdef UWSGI_RUBY_ARCHDIR
|
||||
uwsgi_string_new_list(&ur.libdir, UWSGI_RUBY_ARCHDIR);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_RUBY_LIBDIR
|
||||
uwsgi_string_new_list(&ur.libdir, UWSGI_RUBY_LIBDIR);
|
||||
#endif
|
||||
#ifdef UWSGI_RUBY_ARCHDIR
|
||||
uwsgi_string_new_list(&ur.libdir, UWSGI_RUBY_ARCHDIR);
|
||||
#endif
|
||||
|
||||
ruby_init();
|
||||
struct uwsgi_string_list *usl = ur.libdir;
|
||||
while(usl) {
|
||||
@@ -501,6 +507,8 @@ int uwsgi_rack_init(){
|
||||
ruby_options(argc, argv);
|
||||
#else
|
||||
ruby_init();
|
||||
VALUE dummy;
|
||||
Init_stack(&dummy);
|
||||
ruby_init_loadpath();
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "../../uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
#include <ruby.h>
|
||||
|
||||
|
||||
@@ -30,10 +30,12 @@ else:
|
||||
CFLAGS.append('-I' + includedir)
|
||||
archdir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['archdir']\"" % rbconfig).read().rstrip()
|
||||
arch = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['arch']\"" % rbconfig).read().rstrip()
|
||||
archdir2 = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['rubyarchhdrdir']\"" % rbconfig).read().rstrip()
|
||||
CFLAGS.append('-I' + archdir)
|
||||
CFLAGS.append('-I' + archdir + '/' + arch)
|
||||
CFLAGS.append('-I' + includedir + '/' + arch)
|
||||
|
||||
if archdir2:
|
||||
CFLAGS.append('-I' + archdir2)
|
||||
|
||||
LDFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['LDFLAGS']\"" % rbconfig).read().rstrip().split()
|
||||
libpath = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['libdir']\"" % rbconfig).read().rstrip()
|
||||
|
||||
@@ -56,6 +56,8 @@ static struct uwsgi_option rawrouter_options[] = {
|
||||
|
||||
{"rawrouter-xclient", no_argument, 0, "use the xclient protocol to pass the client addres", uwsgi_opt_true, &urr.xclient, 0},
|
||||
|
||||
{"rawrouter-buffer-size", required_argument, 0, "set internal buffer size (default: page size)", uwsgi_opt_set_64bit, &urr.cr.buffer_size, 0},
|
||||
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
};
|
||||
|
||||
|
||||
@@ -24,6 +24,9 @@ else:
|
||||
CFLAGS.append('-I' + archdir)
|
||||
CFLAGS.append('-I' + archdir + '/' + arch)
|
||||
CFLAGS.append('-I' + includedir + '/' + arch)
|
||||
archdir2 = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['rubyarchhdrdir']\"" % rbconfig).read().rstrip()
|
||||
if archdir2:
|
||||
CFLAGS.append('-I' + archdir2)
|
||||
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
|
||||
@@ -13,6 +13,26 @@ pthread_mutex_t ur_basicauth_crypt_mutex;
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
static char *htpasswd_check_sha1(char *pwd) {
|
||||
#ifdef UWSGI_SSL
|
||||
char sha1[20];
|
||||
uwsgi_sha1(pwd, strlen(pwd), sha1);
|
||||
|
||||
size_t len = 0;
|
||||
char *b64 = uwsgi_base64_encode(sha1, 20, &len);
|
||||
if (!b64) return NULL;
|
||||
|
||||
// we add a new line for being fgets-friendly
|
||||
char *crypted = uwsgi_concat3n("{SHA}", 5, b64, len, "\n", 1);
|
||||
free(b64);
|
||||
return crypted;
|
||||
|
||||
#else
|
||||
uwsgi_log("*** WARNING, rebuild uWSGI with SSL support for htpasswd sha1 feature ***\n");
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint16_t htpasswd_check(char *filename, char *auth) {
|
||||
|
||||
char line[1024];
|
||||
@@ -25,11 +45,23 @@ static uint16_t htpasswd_check(char *filename, char *auth) {
|
||||
return 0;
|
||||
}
|
||||
while(fgets(line, 1024, htpasswd)) {
|
||||
char *crypted = NULL;
|
||||
int need_free = 0;
|
||||
char *colon2 = strchr(line, ':');
|
||||
if (!colon2) break;
|
||||
|
||||
char *cpwd = colon2+1;
|
||||
size_t clen = strlen(cpwd);
|
||||
|
||||
// now we check which algo to use
|
||||
// {SHA} ?
|
||||
if (!uwsgi_starts_with(cpwd, clen, "{SHA}", 5)) {
|
||||
crypted = htpasswd_check_sha1(colon+1);
|
||||
if (crypted) need_free = 1;
|
||||
goto check;
|
||||
}
|
||||
|
||||
|
||||
if (clen < 13) break;
|
||||
|
||||
if (clen > 13) cpwd[13] = 0;
|
||||
@@ -39,20 +71,24 @@ static uint16_t htpasswd_check(char *filename, char *auth) {
|
||||
cd.initialized = 0;
|
||||
// we do as nginx here
|
||||
cd.current_salt[0] = ~cpwd[0];
|
||||
char *crypted = crypt_r( colon+1, cpwd, &cd);
|
||||
crypted = crypt_r( colon+1, cpwd, &cd);
|
||||
#else
|
||||
if (uwsgi.threads > 1) pthread_mutex_lock(&ur_basicauth_crypt_mutex);
|
||||
char *crypted = crypt( colon+1, cpwd);
|
||||
crypted = crypt( colon+1, cpwd);
|
||||
if (uwsgi.threads > 1) pthread_mutex_unlock(&ur_basicauth_crypt_mutex);
|
||||
#endif
|
||||
check:
|
||||
if (!crypted) continue;
|
||||
|
||||
if (!strcmp( crypted, cpwd )) {
|
||||
if (!uwsgi_strncmp(auth, colon-auth, line, colon2-line)) {
|
||||
fclose(htpasswd);
|
||||
if (need_free) free(crypted);
|
||||
return colon-auth;
|
||||
}
|
||||
}
|
||||
|
||||
if (need_free) free(crypted);
|
||||
}
|
||||
|
||||
fclose(htpasswd);
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
|
||||
struct uwsgi_buffer *ub = NULL;
|
||||
|
||||
// mark a route request
|
||||
wsgi_req->via = UWSGI_VIA_ROUTE;
|
||||
@@ -24,9 +26,14 @@ static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_r
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// convert the wsgi_request to an http proxy request
|
||||
struct uwsgi_buffer *ub = uwsgi_to_http(wsgi_req, ur->data2, ur->data2_len, ub_url ? ub_url->buf : NULL, ub_url ? ub_url->pos : 0);
|
||||
if (ur->custom & 0x02) {
|
||||
ub = uwsgi_buffer_new(uwsgi.page_size);
|
||||
}
|
||||
else {
|
||||
ub = uwsgi_to_http(wsgi_req, ur->data2, ur->data2_len, ub_url ? ub_url->buf : NULL, ub_url ? ub_url->pos : 0);
|
||||
}
|
||||
|
||||
if (!ub) {
|
||||
if (ub_url) uwsgi_buffer_destroy(ub_url);
|
||||
uwsgi_log("unable to generate http request for %s\n", ub_addr->buf);
|
||||
@@ -46,11 +53,12 @@ static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_r
|
||||
uwsgi_buffer_destroy(ub_addr);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
wsgi_req->post_pos += wsgi_req->proto_parser_remains;
|
||||
wsgi_req->proto_parser_remains = 0;
|
||||
}
|
||||
|
||||
// ok now if have offload threads, directly use them
|
||||
if (!wsgi_req->post_file && !ur->custom && wsgi_req->socket->can_offload) {
|
||||
if (!wsgi_req->post_file && !(ur->custom & 0x01) && wsgi_req->socket->can_offload) {
|
||||
// append buffered body
|
||||
if (uwsgi.post_buffering > 0 && wsgi_req->post_cl > 0) {
|
||||
if (uwsgi_buffer_append(ub, wsgi_req->post_buffering_buf, wsgi_req->post_cl)) {
|
||||
@@ -60,6 +68,14 @@ static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_r
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
}
|
||||
|
||||
// if we have a CONNECT request, let's confirm it to the client
|
||||
if (ur->custom & 0x02) {
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "200 Connection established", 26)) goto end;
|
||||
// no need to check for return value
|
||||
uwsgi_response_write_headers_do(wsgi_req);
|
||||
}
|
||||
|
||||
if (!uwsgi_offload_request_net_do(wsgi_req, ub_addr->buf, ub)) {
|
||||
wsgi_req->via = UWSGI_VIA_OFFLOAD;
|
||||
wsgi_req->status = 202;
|
||||
@@ -72,6 +88,7 @@ static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_r
|
||||
uwsgi_log("error routing request to http server %s\n", ub_addr->buf);
|
||||
}
|
||||
|
||||
end:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
uwsgi_buffer_destroy(ub_addr);
|
||||
|
||||
@@ -102,15 +119,27 @@ static int uwsgi_router_http(struct uwsgi_route *ur, char *args) {
|
||||
}
|
||||
|
||||
static int uwsgi_router_proxyhttp(struct uwsgi_route *ur, char *args) {
|
||||
ur->custom = 1;
|
||||
ur->custom = 0x1;
|
||||
return uwsgi_router_http(ur, args);
|
||||
}
|
||||
|
||||
static int uwsgi_router_proxyhttp_connect(struct uwsgi_route *ur, char *args) {
|
||||
ur->custom = 0x1|0x02;
|
||||
return uwsgi_router_http(ur, args);
|
||||
}
|
||||
|
||||
static int uwsgi_router_http_connect(struct uwsgi_route *ur, char *args) {
|
||||
ur->custom = 0x02;
|
||||
return uwsgi_router_http(ur, args);
|
||||
}
|
||||
|
||||
|
||||
static void router_http_register(void) {
|
||||
|
||||
uwsgi_register_router("http", uwsgi_router_http);
|
||||
uwsgi_register_router("proxyhttp", uwsgi_router_proxyhttp);
|
||||
uwsgi_register_router("httpconnect", uwsgi_router_http_connect);
|
||||
uwsgi_register_router("proxyhttpconnect", uwsgi_router_proxyhttp_connect);
|
||||
}
|
||||
|
||||
struct uwsgi_plugin router_http_plugin = {
|
||||
|
||||
@@ -18,6 +18,8 @@ struct uwsgi_router_file_conf {
|
||||
char *mime;
|
||||
|
||||
char *no_cl;
|
||||
|
||||
char *no_headers;
|
||||
};
|
||||
|
||||
int uwsgi_routing_func_static(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
@@ -38,6 +40,7 @@ int uwsgi_routing_func_file(struct wsgi_request *wsgi_req, struct uwsgi_route *u
|
||||
char buf[32768];
|
||||
struct stat st;
|
||||
int ret = UWSGI_ROUTE_BREAK;
|
||||
size_t remains = 0;
|
||||
|
||||
struct uwsgi_router_file_conf *urfc = (struct uwsgi_router_file_conf *) ur->data2;
|
||||
|
||||
@@ -61,6 +64,8 @@ int uwsgi_routing_func_file(struct wsgi_request *wsgi_req, struct uwsgi_route *u
|
||||
struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len);
|
||||
if (!ub_s) goto end2;
|
||||
|
||||
if (urfc->no_headers) goto send;
|
||||
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) {
|
||||
uwsgi_buffer_destroy(ub_s);
|
||||
goto end2;
|
||||
@@ -82,8 +87,10 @@ int uwsgi_routing_func_file(struct wsgi_request *wsgi_req, struct uwsgi_route *u
|
||||
else {
|
||||
if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
|
||||
}
|
||||
|
||||
send:
|
||||
|
||||
size_t remains = st.st_size;
|
||||
remains = st.st_size;
|
||||
while(remains) {
|
||||
ssize_t rlen = read(fd, buf, UMIN(32768, remains));
|
||||
if (rlen <= 0) goto end2;
|
||||
@@ -125,6 +132,8 @@ int uwsgi_routing_func_sendfile(struct wsgi_request *wsgi_req, struct uwsgi_rout
|
||||
struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len);
|
||||
if (!ub_s) goto end2;
|
||||
|
||||
if (urfc->no_headers) goto send;
|
||||
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) {
|
||||
uwsgi_buffer_destroy(ub_s);
|
||||
goto end2;
|
||||
@@ -145,6 +154,8 @@ int uwsgi_routing_func_sendfile(struct wsgi_request *wsgi_req, struct uwsgi_rout
|
||||
if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
|
||||
}
|
||||
|
||||
send:
|
||||
|
||||
if (!wsgi_req->headers_sent) {
|
||||
if (uwsgi_response_write_headers_do(wsgi_req)) goto end2;
|
||||
}
|
||||
@@ -188,6 +199,8 @@ int uwsgi_routing_func_fastfile(struct wsgi_request *wsgi_req, struct uwsgi_rout
|
||||
struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len);
|
||||
if (!ub_s) goto end2;
|
||||
|
||||
if (urfc->no_headers) goto send;
|
||||
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) {
|
||||
uwsgi_buffer_destroy(ub_s);
|
||||
goto end2;
|
||||
@@ -208,6 +221,8 @@ int uwsgi_routing_func_fastfile(struct wsgi_request *wsgi_req, struct uwsgi_rout
|
||||
if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
|
||||
}
|
||||
|
||||
send:
|
||||
|
||||
if (!wsgi_req->headers_sent) {
|
||||
if (uwsgi_response_write_headers_do(wsgi_req)) goto end2;
|
||||
}
|
||||
@@ -256,6 +271,7 @@ static int uwsgi_router_file(struct uwsgi_route *ur, char *args) {
|
||||
"no_cl", &urfc->no_cl,
|
||||
"no_content_length", &urfc->no_cl,
|
||||
"mime", &urfc->mime,
|
||||
"no_headers", &urfc->no_headers,
|
||||
NULL)) {
|
||||
uwsgi_log("invalid file route syntax: %s\n", args);
|
||||
return -1;
|
||||
|
||||
@@ -54,6 +54,7 @@ static int uwsgi_routing_func_uwsgi_remote(struct wsgi_request *wsgi_req, struct
|
||||
if (uwsgi_buffer_append(ub, wsgi_req->proto_parser_remains_buf, wsgi_req->proto_parser_remains)) {
|
||||
goto end;
|
||||
}
|
||||
wsgi_req->post_pos += wsgi_req->proto_parser_remains;
|
||||
wsgi_req->proto_parser_remains = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#include "../../uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/* request 110 */
|
||||
int uwsgi_request_signal(struct wsgi_request *wsgi_req) {
|
||||
|
||||
ssize_t len;
|
||||
uint8_t ret_status = 1;
|
||||
|
||||
struct uwsgi_header uh;
|
||||
if (uwsgi_signal_send(uwsgi.signal_socket, wsgi_req->uh->modifier2) < 0) {
|
||||
ret_status = 0;
|
||||
@@ -15,10 +15,11 @@ int uwsgi_request_signal(struct wsgi_request *wsgi_req) {
|
||||
uh.modifier1 = 255;
|
||||
uh.pktsize = 0;
|
||||
uh.modifier2 = ret_status;
|
||||
len = write(wsgi_req->fd, &uh, 4);
|
||||
if (len != 4) {
|
||||
uwsgi_error("write()");
|
||||
|
||||
if (uwsgi_response_write_body_do(wsgi_req, (char *) &uh, 4)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "../../uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
|
||||
@@ -10,15 +10,11 @@ extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_request_spooler(struct wsgi_request *wsgi_req) {
|
||||
|
||||
int i;
|
||||
char spool_filename[1024];
|
||||
struct uwsgi_header uh;
|
||||
|
||||
// get the spooler from the modifier2
|
||||
// TODO get the spooler from the modifier2
|
||||
|
||||
struct uwsgi_spooler *uspool = uwsgi.spoolers;
|
||||
|
||||
if (uspool == NULL) {
|
||||
if (uwsgi.spoolers == NULL) {
|
||||
uwsgi_log("the spooler is inactive !!!...skip\n");
|
||||
uh.modifier1 = 255;
|
||||
uh.pktsize = 0;
|
||||
@@ -27,20 +23,21 @@ int uwsgi_request_spooler(struct wsgi_request *wsgi_req) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
i = spool_request(uspool, spool_filename, uwsgi.workers[0].requests + 1, wsgi_req->async_id, wsgi_req->buffer, wsgi_req->uh->pktsize, NULL, 0, NULL, 0);
|
||||
char *filename = uwsgi_spool_request(wsgi_req, wsgi_req->buffer, wsgi_req->uh->pktsize, NULL, 0);
|
||||
uh.modifier1 = 255;
|
||||
uh.pktsize = 0;
|
||||
if (i > 0) {
|
||||
if (filename) {
|
||||
uh.modifier2 = 1;
|
||||
if (uwsgi_response_write_body_do(wsgi_req, (char *) &uh, 4)) {
|
||||
uwsgi_log("disconnected client, remove spool file.\n");
|
||||
/* client disconnect, remove spool file */
|
||||
if (unlink(spool_filename)) {
|
||||
if (unlink(filename)) {
|
||||
uwsgi_error("uwsgi_request_spooler()/unlink()");
|
||||
uwsgi_log("something horrible happened !!! check your spooler ASAP !!!\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
free(filename);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -155,6 +155,7 @@ static struct uwsgi_option sslrouter_options[] = {
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
{"sslrouter-sni", no_argument, 0, "use SNI to route requests", uwsgi_opt_true, &usr.sni, 0},
|
||||
#endif
|
||||
{"sslrouter-buffer-size", required_argument, 0, "set internal buffer size (default: page size)", uwsgi_opt_set_64bit, &usr.cr.buffer_size, 0},
|
||||
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
};
|
||||
|
||||
@@ -72,7 +72,6 @@ static void uwsgi_symcall_init(){
|
||||
exit(1);
|
||||
}
|
||||
*space = ' ';
|
||||
usl = usl->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -93,7 +93,11 @@ ssize_t uwsgi_syslog_logger(struct uwsgi_logger *ul, char *message, size_t len)
|
||||
ul->configured = 1;
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
syslog(LOG_NOTICE, "%.*s", (int) len, message);
|
||||
#else
|
||||
syslog(LOG_INFO, "%.*s", (int) len, message);
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@@ -326,6 +326,11 @@ static void tornado_loop() {
|
||||
uwsgi_log("!!! Running tornado with a socket-timeout lower than 30 seconds is not recommended, tune it with --socket-timeout !!!\n");
|
||||
}
|
||||
|
||||
if (!uwsgi.async_waiting_fd_table)
|
||||
uwsgi.async_waiting_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
|
||||
if (!uwsgi.async_proto_fd_table)
|
||||
uwsgi.async_proto_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd);
|
||||
|
||||
// get the GIL
|
||||
UWSGI_GET_GIL
|
||||
|
||||
|
||||
+18
-8
@@ -2,6 +2,16 @@
|
||||
|
||||
extern struct uwsgi_tuntap utt;
|
||||
|
||||
// error reporting
|
||||
void uwsgi_tuntap_error_do(struct uwsgi_tuntap_peer *uttp, char *msg, char *file, int line) {
|
||||
if (uttp) {
|
||||
uwsgi_log_verbose("[tuntap] peer fd: %d ip: %s %s: %s [%s line %d]\n", uttp->fd, uttp->ip, msg, strerror(errno), file, line);
|
||||
}
|
||||
else {
|
||||
uwsgi_log_verbose("[tuntap] %s: %s [%s line %d]\n", msg, strerror(errno), file, line);
|
||||
}
|
||||
}
|
||||
|
||||
// create a new peer
|
||||
struct uwsgi_tuntap_peer *uwsgi_tuntap_peer_create(struct uwsgi_tuntap_router *uttr, int fd, int is_router) {
|
||||
|
||||
@@ -183,7 +193,7 @@ int uwsgi_tuntap_register_addr(struct uwsgi_tuntap_router *uttr, struct uwsgi_tu
|
||||
char ip[INET_ADDRSTRLEN + 1];
|
||||
memset(ip, 0, INET_ADDRSTRLEN + 1);
|
||||
if (!inet_ntop(AF_INET, &uttp->addr, ip, INET_ADDRSTRLEN)) {
|
||||
uwsgi_error("uwsgi_tuntap_register_addr()/inet_ntop()");
|
||||
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_register_addr()/inet_ntop()");
|
||||
return -1;
|
||||
}
|
||||
if (uttp != tmp_uttp) {
|
||||
@@ -205,7 +215,7 @@ int uwsgi_tuntap_peer_dequeue(struct uwsgi_tuntap_router *uttr, struct uwsgi_tun
|
||||
if (rlen < 0) {
|
||||
if (uwsgi_is_again())
|
||||
return 0;
|
||||
uwsgi_error("uwsgi_tuntap_peer_dequeue()/read()");
|
||||
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_dequeue()/read()");
|
||||
return -1;
|
||||
}
|
||||
uttp->buf_pos += rlen;
|
||||
@@ -265,7 +275,7 @@ enqueue:
|
||||
if (rlen < 0) {
|
||||
if (uwsgi_is_again())
|
||||
return 0;
|
||||
uwsgi_error("uwsgi_tuntap_peer_dequeue()/read()");
|
||||
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_dequeue()/read()");
|
||||
return -1;
|
||||
}
|
||||
uttp->header_pos += rlen;
|
||||
@@ -282,14 +292,14 @@ int uwsgi_tuntap_peer_enqueue(struct uwsgi_tuntap_router *uttr, struct uwsgi_tun
|
||||
|
||||
ssize_t rlen = write(uttp->fd, uttp->write_buf + uttp->written, uttp->write_buf_pktsize - uttp->written);
|
||||
if (rlen == 0) {
|
||||
uwsgi_error("uwsgi_tuntap_peer_enqueue()/write()");
|
||||
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_enqueue()/write()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rlen < 0) {
|
||||
if (uwsgi_is_again())
|
||||
goto retry;
|
||||
uwsgi_error("uwsgi_tuntap_peer_enqueue()/write()");
|
||||
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_enqueue()/write()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -303,13 +313,13 @@ int uwsgi_tuntap_peer_enqueue(struct uwsgi_tuntap_router *uttr, struct uwsgi_tun
|
||||
if (uttr->wait_for_write) {
|
||||
uttp->blocked_read = 1;
|
||||
if (event_queue_del_fd(uttr->queue, uttp->fd, event_queue_write())) {
|
||||
uwsgi_error("uwsgi_tuntap_peer_enqueue()/event_queue_del_fd()");
|
||||
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_enqueue()/event_queue_del_fd()");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (event_queue_fd_readwrite_to_read(uttr->queue, uttp->fd)) {
|
||||
uwsgi_error("uwsgi_tuntap_peer_enqueue()/event_queue_fd_write_to_read()");
|
||||
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_enqueue()/event_queue_fd_write_to_read()");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -324,7 +334,7 @@ int uwsgi_tuntap_peer_enqueue(struct uwsgi_tuntap_router *uttr, struct uwsgi_tun
|
||||
retry:
|
||||
if (!uttp->wait_for_write) {
|
||||
if (event_queue_fd_read_to_readwrite(uttr->queue, uttp->fd)) {
|
||||
uwsgi_error("uwsgi_tuntap_peer_enqueue()/event_queue_fd_read_to_write()");
|
||||
uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_enqueue()/event_queue_fd_read_to_write()");
|
||||
return -1;
|
||||
}
|
||||
uttp->wait_for_write = 1;
|
||||
|
||||
@@ -116,3 +116,5 @@ int uwsgi_tuntap_register_addr(struct uwsgi_tuntap_router *, struct uwsgi_tuntap
|
||||
|
||||
void uwsgi_tuntap_peer_send_rules(int, struct uwsgi_tuntap_peer *);
|
||||
int uwsgi_tuntap_peer_rules_check(struct uwsgi_tuntap_router *, struct uwsgi_tuntap_peer *, char *, size_t, int);
|
||||
#define uwsgi_tuntap_error(x, y) uwsgi_tuntap_error_do(x, y, __FILE__, __LINE__)
|
||||
void uwsgi_tuntap_error_do(struct uwsgi_tuntap_peer *, char *, char *, int);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "common.h"
|
||||
|
||||
extern struct uwsgi_tuntap utt;
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
int uwsgi_tuntap_peer_rules_check(struct uwsgi_tuntap_router *uttr, struct uwsgi_tuntap_peer *uttp, char *pkt, size_t len, int direction) {
|
||||
if (uttp->rules_cnt == 0) return 0;
|
||||
@@ -14,13 +15,18 @@ int uwsgi_tuntap_peer_rules_check(struct uwsgi_tuntap_router *uttr, struct uwsgi
|
||||
uint32_t dst = ntohl(*dst_ip);
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("%X %X\n", src, dst);
|
||||
uwsgi_log("%d %X %X\n",direction, src, dst);
|
||||
#endif
|
||||
|
||||
int i;
|
||||
for(i=0;i<uttp->rules_cnt;i++) {
|
||||
struct uwsgi_tuntap_peer_rule *rule = &uttp->rules[i];
|
||||
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("cnt = %i/%d direction = %d action = %d %X %X\n", i, uttp->rules_cnt, rule->direction, rule->action, rule->src_mask, rule->dst_mask);
|
||||
#endif
|
||||
|
||||
|
||||
if (rule->direction != direction) continue;
|
||||
|
||||
if (rule->src) {
|
||||
@@ -33,6 +39,7 @@ int uwsgi_tuntap_peer_rules_check(struct uwsgi_tuntap_router *uttr, struct uwsgi
|
||||
if (dst_masked != rule->dst) continue;
|
||||
}
|
||||
|
||||
|
||||
if (rule->action == 0) return 0;
|
||||
if (rule->action == 1) return 1;
|
||||
if (rule->action == 2) {
|
||||
@@ -45,7 +52,25 @@ int uwsgi_tuntap_peer_rules_check(struct uwsgi_tuntap_router *uttr, struct uwsgi
|
||||
sin.sin_port = rule->target_port;
|
||||
sin.sin_addr.s_addr = rule->target;
|
||||
if (sendto(uttr->gateway_fd, pkt, len, 0, (struct sockaddr *) &sin, sizeof(struct sockaddr_in)) < 0) {
|
||||
uwsgi_error("uwsgi_tuntap_route_check()/sendto()");
|
||||
if (uwsgi_is_again()) {
|
||||
// suspend and retry
|
||||
struct pollfd pfd;
|
||||
memset(&pfd, 0, sizeof(struct pollfd));
|
||||
pfd.fd = uttr->gateway_fd;
|
||||
pfd.events = POLLOUT;
|
||||
int ret = poll(&pfd, 1, uwsgi.socket_timeout * 1000);
|
||||
if (ret > 0) {
|
||||
if (sendto(uttr->gateway_fd, pkt, len, 0, (struct sockaddr *) &sin, sizeof(struct sockaddr_in)) < 0) {
|
||||
uwsgi_tuntap_error(uttp,"uwsgi_tuntap_route_check()/sendto()");
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_tuntap_error(uttp,"uwsgi_tuntap_route_check()/poll()");
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_tuntap_error(uttp,"uwsgi_tuntap_route_check()/sendto()");
|
||||
}
|
||||
}
|
||||
}
|
||||
return 2;
|
||||
@@ -295,11 +320,11 @@ void uwsgi_tuntap_peer_send_rules(int fd, struct uwsgi_tuntap_peer *peer) {
|
||||
|
||||
char *slash = strchr(argv[1],'/');
|
||||
if (slash) {
|
||||
utpr.src_mask = (0xffffffff << ((atoi(slash+1))-utpr.src_mask));
|
||||
utpr.src_mask = (0xffffffff << ((atoi(slash+1))-32));
|
||||
*slash = 0;
|
||||
}
|
||||
if (inet_pton(AF_INET, argv[1], &utpr.src) != 1) {
|
||||
uwsgi_error("uwsgi_tuntap_peer_send_rules()/inet_pton()");
|
||||
uwsgi_tuntap_error(peer, "uwsgi_tuntap_peer_send_rules()/inet_pton()");
|
||||
exit(1);
|
||||
}
|
||||
if (slash) *slash = '/';
|
||||
@@ -307,11 +332,11 @@ void uwsgi_tuntap_peer_send_rules(int fd, struct uwsgi_tuntap_peer *peer) {
|
||||
|
||||
slash = strchr(argv[2],'/');
|
||||
if (slash) {
|
||||
utpr.dst_mask = (0xffffffff << ((atoi(slash+1))-utpr.dst_mask));
|
||||
utpr.dst_mask = (0xffffffff << ((atoi(slash+1))-32));
|
||||
*slash = 0;
|
||||
}
|
||||
if (inet_pton(AF_INET, argv[2], &utpr.dst) != 1) {
|
||||
uwsgi_error("uwsgi_tuntap_peer_send_rules()/inet_pton()");
|
||||
uwsgi_tuntap_error(peer, "uwsgi_tuntap_peer_send_rules()/inet_pton()");
|
||||
exit(1);
|
||||
}
|
||||
if (slash) *slash = '/';
|
||||
@@ -346,7 +371,7 @@ void uwsgi_tuntap_peer_send_rules(int fd, struct uwsgi_tuntap_peer *peer) {
|
||||
}
|
||||
*colon = 0;
|
||||
if (inet_pton(AF_INET, argv[4], &utpr.target) != 1) {
|
||||
uwsgi_error("uwsgi_tuntap_peer_send_rules()/inet_pton()");
|
||||
uwsgi_tuntap_error(peer, "uwsgi_tuntap_peer_send_rules()/inet_pton()");
|
||||
exit(1);
|
||||
}
|
||||
*colon = ':';
|
||||
@@ -364,7 +389,7 @@ void uwsgi_tuntap_peer_send_rules(int fd, struct uwsgi_tuntap_peer *peer) {
|
||||
size_t len = ub->pos;
|
||||
uwsgi_buffer_destroy(ub);
|
||||
if (write(fd,peer->rules, len) != (ssize_t)len) {
|
||||
uwsgi_error("uwsgi_tuntap_peer_send_rules()/write()");
|
||||
uwsgi_tuntap_error(peer, "uwsgi_tuntap_peer_send_rules()/write()");
|
||||
exit(1);
|
||||
}
|
||||
return;
|
||||
|
||||
+11
-4
@@ -117,6 +117,13 @@ static void *uwsgi_tuntap_loop(void *arg) {
|
||||
uwsgi_error("uwsgi_tuntap_loop()/read()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// check for full write buffer
|
||||
if (uttp->write_buf_pktsize + 4 + rlen > utt.buffer_size) {
|
||||
uttp->dropped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint16_t pktsize = rlen;
|
||||
char *ptr = uttp->write_buf + uttp->write_buf_pktsize;
|
||||
memcpy(ptr + 4, uttr->buf, rlen);
|
||||
@@ -126,7 +133,7 @@ static void *uwsgi_tuntap_loop(void *arg) {
|
||||
ptr[3] = 0;
|
||||
uttp->write_buf_pktsize+= pktsize+4;
|
||||
if (uwsgi_tuntap_peer_enqueue(uttr, uttp)) {
|
||||
uwsgi_log("server disconnected...\n");
|
||||
uwsgi_log_verbose("tuntap server disconnected...\n");
|
||||
exit(1);
|
||||
}
|
||||
continue;
|
||||
@@ -137,7 +144,7 @@ static void *uwsgi_tuntap_loop(void *arg) {
|
||||
// read from the client
|
||||
if (!uttp->wait_for_write) {
|
||||
if (uwsgi_tuntap_peer_dequeue(uttr, uttp, 0)) {
|
||||
uwsgi_log("server disconnected...\n");
|
||||
uwsgi_log_verbose("tuntap server disconnected...\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@@ -149,7 +156,7 @@ static void *uwsgi_tuntap_loop(void *arg) {
|
||||
|
||||
// write to the client
|
||||
if (uwsgi_tuntap_peer_enqueue(uttr, uttp)) {
|
||||
uwsgi_log("server disconnected...\n");
|
||||
uwsgi_log_verbose("tuntap server disconnected...\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@@ -507,7 +514,7 @@ void tuntaprouter_send_stats(struct uwsgi_tuntap_router *uttr) {
|
||||
ssize_t res = write(client_fd, us->base + pos, remains);
|
||||
if (res <= 0) {
|
||||
if (res < 0) {
|
||||
uwsgi_error("write()");
|
||||
uwsgi_error("tuntaprouter_send_stats()/write()");
|
||||
}
|
||||
goto end0;
|
||||
}
|
||||
|
||||
+110
-45
@@ -4,52 +4,55 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
static uint16_t http_add_uwsgi_header(struct wsgi_request *wsgi_req, char *hh, int hhlen) {
|
||||
static char * http_header_to_cgi(char *hh, size_t hhlen, size_t *keylen, size_t *vallen, int *has_prefix) {
|
||||
size_t i;
|
||||
char *val = hh;
|
||||
int status = 0;
|
||||
for (i = 0; i < hhlen; i++) {
|
||||
if (!status) {
|
||||
hh[i] = toupper((int) hh[i]);
|
||||
if (hh[i] == '-')
|
||||
hh[i] = '_';
|
||||
if (hh[i] == ':') {
|
||||
status = 1;
|
||||
*keylen = i;
|
||||
}
|
||||
}
|
||||
else if (status == 1 && hh[i] != ' ') {
|
||||
status = 2;
|
||||
val += i;
|
||||
*vallen+=1;
|
||||
}
|
||||
else if (status == 2) {
|
||||
*vallen+=1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(*keylen))
|
||||
return NULL;
|
||||
|
||||
if (uwsgi_strncmp("CONTENT_LENGTH", 14, hh, *keylen) && uwsgi_strncmp("CONTENT_TYPE", 12, hh, *keylen)) {
|
||||
*has_prefix = 0x02;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint16_t http_add_uwsgi_header(struct wsgi_request *wsgi_req, char *hh, size_t hhlen, char *hv, size_t hvlen, int has_prefix) {
|
||||
|
||||
char *buffer = wsgi_req->buffer + wsgi_req->uh->pktsize;
|
||||
char *watermark = wsgi_req->buffer + uwsgi.buffer_size;
|
||||
|
||||
int i;
|
||||
int status = 0;
|
||||
char *val = hh;
|
||||
uint16_t keylen = 0, vallen = 0;
|
||||
int prefix = 0;
|
||||
char *ptr = buffer;
|
||||
size_t keylen = hhlen;
|
||||
|
||||
for (i = 0; i < hhlen; i++) {
|
||||
if (!status) {
|
||||
hh[i] = toupper((int) hh[i]);
|
||||
if (hh[i] == '-')
|
||||
hh[i] = '_';
|
||||
if (hh[i] == ':') {
|
||||
status = 1;
|
||||
keylen = i;
|
||||
}
|
||||
}
|
||||
else if (status == 1 && hh[i] != ' ') {
|
||||
status = 2;
|
||||
val += i;
|
||||
vallen++;
|
||||
}
|
||||
else if (status == 2) {
|
||||
vallen++;
|
||||
}
|
||||
}
|
||||
if (has_prefix) keylen += 5;
|
||||
|
||||
if (!keylen)
|
||||
return 0;
|
||||
|
||||
if (uwsgi_strncmp("CONTENT_LENGTH", 14, hh, keylen) && uwsgi_strncmp("CONTENT_TYPE", 12, hh, keylen)) {
|
||||
keylen += 5;
|
||||
prefix = 1;
|
||||
}
|
||||
|
||||
if (buffer + keylen + vallen + 2 + 2 >= watermark) {
|
||||
if (prefix) {
|
||||
uwsgi_log("[WARNING] unable to add HTTP_%.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, hh, vallen, val);
|
||||
if (buffer + keylen + hvlen + 2 + 2 >= watermark) {
|
||||
if (has_prefix) {
|
||||
uwsgi_log("[WARNING] unable to add HTTP_%.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, hh, hvlen, hv);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[WARNING] unable to add %.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, hh, vallen, val);
|
||||
uwsgi_log("[WARNING] unable to add %.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, hh, hvlen, hv);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -58,7 +61,7 @@ static uint16_t http_add_uwsgi_header(struct wsgi_request *wsgi_req, char *hh, i
|
||||
*ptr++ = (uint8_t) (keylen & 0xff);
|
||||
*ptr++ = (uint8_t) ((keylen >> 8) & 0xff);
|
||||
|
||||
if (prefix) {
|
||||
if (has_prefix) {
|
||||
memcpy(ptr, "HTTP_", 5);
|
||||
ptr += 5;
|
||||
memcpy(ptr, hh, keylen - 5);
|
||||
@@ -69,11 +72,11 @@ static uint16_t http_add_uwsgi_header(struct wsgi_request *wsgi_req, char *hh, i
|
||||
ptr += keylen;
|
||||
}
|
||||
|
||||
*ptr++ = (uint8_t) (vallen & 0xff);
|
||||
*ptr++ = (uint8_t) ((vallen >> 8) & 0xff);
|
||||
memcpy(ptr, val, vallen);
|
||||
*ptr++ = (uint8_t) (hvlen & 0xff);
|
||||
*ptr++ = (uint8_t) ((hvlen >> 8) & 0xff);
|
||||
memcpy(ptr, hv, hvlen);
|
||||
|
||||
return 2 + keylen + 2 + vallen;
|
||||
return 2 + keylen + 2 + hvlen;
|
||||
}
|
||||
|
||||
static char *proxy1_parse(char *ptr, char *watermark, char **src, uint16_t *src_len, char **dst, uint16_t *dst_len, char **src_port, uint16_t *src_port_len, char **dst_port, uint16_t *dst_port_len) {
|
||||
@@ -301,9 +304,15 @@ static int http_parse(struct wsgi_request *wsgi_req, char *watermark) {
|
||||
}
|
||||
}
|
||||
|
||||
if (wsgi_req->https_len > 0) {
|
||||
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "HTTPS", 5, wsgi_req->https, wsgi_req->https_len);
|
||||
}
|
||||
|
||||
//HEADERS
|
||||
base = ptr;
|
||||
|
||||
struct uwsgi_string_list *headers = NULL, *usl = NULL;
|
||||
|
||||
while (ptr < watermark) {
|
||||
if (*ptr == '\r') {
|
||||
if (ptr + 1 >= watermark)
|
||||
@@ -317,15 +326,71 @@ static int http_parse(struct wsgi_request *wsgi_req, char *watermark) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
wsgi_req->uh->pktsize += http_add_uwsgi_header(wsgi_req, base, ptr - base);
|
||||
size_t key_len = 0, value_len = 0;
|
||||
int has_prefix = 0;
|
||||
// last line, do not waste time
|
||||
if (ptr - base == 0) break;
|
||||
char *value = http_header_to_cgi(base, ptr - base, &key_len, &value_len, &has_prefix);
|
||||
if (!value) {
|
||||
uwsgi_log_verbose("invalid HTTP request\n");
|
||||
goto clear;
|
||||
}
|
||||
usl = uwsgi_string_list_has_item(headers, base, key_len);
|
||||
// there is already a HTTP header with the same name, let's merge them
|
||||
if (usl) {
|
||||
char *old_value = usl->custom_ptr;
|
||||
usl->custom_ptr = uwsgi_concat3n(old_value, (size_t) usl->custom, ", ", 2, value, value_len);
|
||||
usl->custom += 2 + value_len;
|
||||
if (usl->custom2 & 0x01) free(old_value);
|
||||
usl->custom2 |= 0x01;
|
||||
}
|
||||
else {
|
||||
// add an entry
|
||||
usl = uwsgi_string_new_list(&headers, NULL);
|
||||
usl->value = base;
|
||||
usl->len = key_len;
|
||||
usl->custom_ptr = value;
|
||||
usl->custom = value_len;
|
||||
usl->custom2 = has_prefix;
|
||||
}
|
||||
ptr++;
|
||||
base = ptr + 1;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
usl = headers;
|
||||
int broken = 0;
|
||||
while(usl) {
|
||||
if (!broken) {
|
||||
uint16_t old_pktsize = wsgi_req->uh->pktsize;
|
||||
wsgi_req->uh->pktsize += http_add_uwsgi_header(wsgi_req, usl->value, usl->len, usl->custom_ptr, (size_t) usl->custom, usl->custom2 & 0x02);
|
||||
// if the packet remains unchanged, the buffer is full, mark the request as broken
|
||||
if (old_pktsize == wsgi_req->uh->pktsize) {
|
||||
broken = 1;
|
||||
}
|
||||
}
|
||||
if (usl->custom2 & 0x01) {
|
||||
free(usl->custom_ptr);
|
||||
}
|
||||
struct uwsgi_string_list *tmp_usl = usl;
|
||||
usl = usl->next;
|
||||
free(tmp_usl);
|
||||
}
|
||||
|
||||
return broken;
|
||||
|
||||
clear:
|
||||
usl = headers;
|
||||
while(usl) {
|
||||
if (usl->custom2 & 0x01) {
|
||||
free(usl->custom_ptr);
|
||||
}
|
||||
struct uwsgi_string_list *tmp_usl = usl;
|
||||
usl = usl->next;
|
||||
free(tmp_usl);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
[uwsgi]
|
||||
socket = /tmp/foo
|
||||
|
||||
cache2 = name=items_1,blocks=4,items=2,bitmap=1,blocksize=1
|
||||
cache2 = name=items_2,blocks=4,items=3,bitmap=1,blocksize=1
|
||||
cache2 = name=items_3,blocks=4,items=4,bitmap=1,blocksize=1
|
||||
cache2 = name=items_4,blocks=5,items=5,bitmap=1,blocksize=1
|
||||
cache2 = name=items_17,blocks=17,items=17,bitmap=1,blocksize=1
|
||||
cache2 = name=items_4_10,blocks=5,items=5,bitmap=1,blocksize=10
|
||||
cache2 = name=items_1_100000,blocks=1000,items=2,bitmap=1,blocksize=100
|
||||
cache2 = name=items_non_bitmap,items=2,blocksize=20
|
||||
pyrun = t/cachebitmap.py
|
||||
@@ -0,0 +1,106 @@
|
||||
import uwsgi
|
||||
import unittest
|
||||
import random
|
||||
import string
|
||||
|
||||
class BitmapTest(unittest.TestCase):
|
||||
|
||||
__caches__ = ['items_1', 'items_2', 'items_3', 'items_4', 'items_17', 'items_4_10', 'items_1_100000', 'items_non_bitmap']
|
||||
|
||||
def setUp(self):
|
||||
for cache in self.__caches__:
|
||||
uwsgi.cache_clear(cache)
|
||||
|
||||
def test_failed_by_one(self):
|
||||
self.assertIsNone(uwsgi.cache_update('key1', 'HELLO', 0, 'items_1'))
|
||||
|
||||
def test_ok_four_bytes(self):
|
||||
self.assertTrue(uwsgi.cache_update('key1', 'HELL', 0, 'items_1'))
|
||||
|
||||
def test_two_items_using_four_blocks(self):
|
||||
self.assertTrue(uwsgi.cache_update('key1', 'HE', 0, 'items_2'))
|
||||
self.assertTrue(uwsgi.cache_update('key2', 'LL', 0, 'items_2'))
|
||||
self.assertTrue(uwsgi.cache_del('key1', 'items_2'))
|
||||
self.assertIsNone(uwsgi.cache_update('key1', 'HEL', 0, 'items_2'))
|
||||
self.assertTrue(uwsgi.cache_update('key1', 'HE', 0, 'items_2'))
|
||||
|
||||
def test_overlapping(self):
|
||||
self.assertTrue(uwsgi.cache_update('key1', 'HE', 0, 'items_2'))
|
||||
self.assertIsNone(uwsgi.cache_update('key1', 'HELL', 0, 'items_2'))
|
||||
self.assertTrue(uwsgi.cache_del('key1', 'items_2'))
|
||||
self.assertTrue(uwsgi.cache_update('key1', 'HELL', 0, 'items_2'))
|
||||
|
||||
def test_big_item(self):
|
||||
self.assertIsNone(uwsgi.cache_update('key1', 'HELLOHELLOHELLOHEL', 0, 'items_17'))
|
||||
self.assertTrue(uwsgi.cache_update('key1', 'HELLOHELLOHELLOHE', 0, 'items_17'))
|
||||
|
||||
def test_set(self):
|
||||
self.assertTrue(uwsgi.cache_set('key1', 'HELLO', 0, 'items_17'))
|
||||
self.assertIsNone(uwsgi.cache_set('key1', 'HELLO', 0, 'items_17'))
|
||||
self.assertTrue(uwsgi.cache_del('key1', 'items_17'))
|
||||
self.assertTrue(uwsgi.cache_set('key1', 'HELLO', 0, 'items_17'))
|
||||
self.assertIsNone(uwsgi.cache_set('key1', 'HELLO', 0, 'items_17'))
|
||||
|
||||
def test_too_much_items(self):
|
||||
self.assertTrue(uwsgi.cache_set('key1', 'HELLO', 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_set('key2', 'HELLO', 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_set('key3', 'HELLO', 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_set('key4', 'HELLO', 0, 'items_4_10'))
|
||||
self.assertIsNone(uwsgi.cache_set('key5', 'HELLO', 0, 'items_4_10'))
|
||||
|
||||
def test_big_delete(self):
|
||||
self.assertTrue(uwsgi.cache_set('key1', 'X' * 50 , 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_del('key1', 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_set('key1', 'HELLOHELLO', 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_set('key2', 'HELLOHELLO', 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_set('key3', 'HELLOHELLO', 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_set('key4', 'HELLOHELLO', 0, 'items_4_10'))
|
||||
self.assertIsNone(uwsgi.cache_set('key5', 'HELLOHELLO', 0, 'items_4_10'))
|
||||
|
||||
def test_big_update(self):
|
||||
self.assertTrue(uwsgi.cache_set('key1', 'X' * 40 , 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_update('key1', 'X' * 10 , 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_del('key1', 'items_4_10'))
|
||||
self.assertIsNone(uwsgi.cache_update('key1', 'X' * 51 , 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_update('key1', 'X' * 50 , 0, 'items_4_10'))
|
||||
|
||||
def test_multi_clear(self):
|
||||
for i in range(0, 100):
|
||||
self.assertTrue(uwsgi.cache_clear('items_4_10'))
|
||||
|
||||
def test_multi_delete(self):
|
||||
for i in range(0, 100):
|
||||
self.assertTrue(uwsgi.cache_set('key1', 'X' * 50 , 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_del('key1', 'items_4_10'))
|
||||
|
||||
for i in range(0, 100):
|
||||
self.assertIsNone(uwsgi.cache_set('key1', 'X' * 51 , 0, 'items_4_10'))
|
||||
self.assertIsNone(uwsgi.cache_del('key1', 'items_4_10'))
|
||||
|
||||
for i in range(0, 100):
|
||||
self.assertTrue(uwsgi.cache_set('key1', 'X' * 50 , 0, 'items_4_10'))
|
||||
self.assertTrue(uwsgi.cache_del('key1', 'items_4_10'))
|
||||
|
||||
def test_big_key(self):
|
||||
self.assertTrue(uwsgi.cache_set('K' * 2048, 'X' * 50 , 0, 'items_4_10'))
|
||||
self.assertIsNone(uwsgi.cache_set('K' * 2049, 'X' * 50 , 0, 'items_4_10'))
|
||||
|
||||
def rand_blob(self, n=32):
|
||||
return ''.join([random.choice(string.ascii_letters + string.digits) for n in range(n)])
|
||||
|
||||
def test_big_random(self):
|
||||
blob = self.rand_blob(100000)
|
||||
self.assertTrue(uwsgi.cache_set('KEY', blob, 0, 'items_1_100000'))
|
||||
get_blob = uwsgi.cache_get('KEY', 'items_1_100000')
|
||||
self.assertEqual(blob, get_blob)
|
||||
self.assertTrue(uwsgi.cache_del('KEY', 'items_1_100000'))
|
||||
self.assertIsNone(uwsgi.cache_set('KEY', 'X' * 100001, 0, 'items_1_100000'))
|
||||
self.assertTrue(uwsgi.cache_set('KEY', 'X' * 10000, 0, 'items_1_100000'))
|
||||
|
||||
def test_non_bitmap(self):
|
||||
self.assertTrue(uwsgi.cache_set('KEY', 'X' * 20, 0, 'items_non_bitmap'))
|
||||
self.assertTrue(uwsgi.cache_del('KEY', 'items_non_bitmap'))
|
||||
self.assertIsNone(uwsgi.cache_set('KEY', 'X' * 21, 0, 'items_non_bitmap'))
|
||||
self.assertTrue(uwsgi.cache_set('KEY', 'X' * 20, 0, 'items_non_bitmap'))
|
||||
|
||||
unittest.main()
|
||||
@@ -0,0 +1,8 @@
|
||||
my $app = sub {
|
||||
my ($env) = @_;
|
||||
my $orig = $env->{QUERY_STRING};
|
||||
if ($env->{CONTENT_LENGTH} > 0) {
|
||||
$env->{'psgi.input'}->read($orig, $env->{CONTENT_LENGTH}, $env->{HTTP_UWSGI_OFFSET});
|
||||
}
|
||||
return [ 200, ['Content-Type' => 'text/plain'], [$orig."\n"]];
|
||||
};
|
||||
@@ -1,5 +1,9 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
BEGIN {
|
||||
die "PANIC: We should only load this once" if ++$main::count_BEGIN > 1;
|
||||
}
|
||||
die "PANIC: We should only run this once" if ++$main::count_runs > 1;
|
||||
|
||||
uwsgi::register_rpc('hello', sub {
|
||||
my ($one, $two, $three) = @_;
|
||||
@@ -55,6 +59,10 @@ my $app = sub {
|
||||
uwsgi::signal(17);
|
||||
uwsgi::signal(30);
|
||||
|
||||
my ($package, $filename, $line) = caller;
|
||||
die "Expecting reasonable caller() return values, not [$package, $filename, $line]"
|
||||
unless $package eq 'main' and $filename =~ /\btest\.psgi$/s and $line == 0;
|
||||
|
||||
if ($env->{'psgix.cleanup'}) {
|
||||
print "cleanup supported\n";
|
||||
push @{$env->{'psgix.cleanup.handlers'}}, $one;
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
#uwsgi --http-socket :9090 --psgi apps/input_with_offset.pl
|
||||
|
||||
use IO::Socket::INET;
|
||||
|
||||
my @tests;
|
||||
|
||||
my $base = 'one_two_three_four';
|
||||
|
||||
push @tests, ['-1', 'HELLO', 'one_two_three_fouHELLO'];
|
||||
push @tests, ['-2', 'HELLO', 'one_two_three_foHELLO'];
|
||||
push @tests, ['-2', 'HELLOHELLOHELLOTEST2TEST3', 'one_two_three_foHELLOHELLOHELLOTEST2TEST3'];
|
||||
push @tests, ['-12', 'HELLOHELLOHELLOTEST2TEST3', 'one_twHELLOHELLOHELLOTEST2TEST3'];
|
||||
push @tests, ['-22', 'HELLOHELLOHELLOTEST2TEST3', "HELLOHELLOHELLOTEST2TEST3"];
|
||||
push @tests, ['-22', 'HELLO', "HELLOne_two_three_four"];
|
||||
push @tests, ['-23', 'HELLO', "HELLOone_two_three_four"];
|
||||
push @tests, ['-25', 'HELLO', "HELLO\0\0one_two_three_four"];
|
||||
push @tests, ['1', 'HELLO', "oHELLOo_three_four"];
|
||||
push @tests, ['3', 'HELLO', "oneHELLOthree_four"];
|
||||
push @tests, ['30', 'HELLO', "one_two_three_four\0\0\0\0\0\0\0\0\0\0\0\0HELLO"];
|
||||
|
||||
@ARGV or die "You must provide a host to test on, e.g. localhost:8080";
|
||||
|
||||
foreach(@tests) {
|
||||
print "testing: offset(".$_->[0].") body(".$_->[1].")\n";
|
||||
my $req = "POST /?".$base." HTTP/1.0\r\nContent-Length: ".length($_->[1])."\r\nuWSGI-Offset: ".$_->[0]."\r\n\r\n".$_->[1];
|
||||
|
||||
my $s = IO::Socket::INET->new(PeerAddr => $ARGV[0]) or die "PANIC: Unable to construct socket";
|
||||
$s->send($req);
|
||||
|
||||
my $response = '';
|
||||
while(1) {
|
||||
$s->recv(my $buf, 4096);
|
||||
last unless length($buf);
|
||||
$response .= $buf;
|
||||
}
|
||||
$s->close;
|
||||
|
||||
my $expected = "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n\r\n".$_->[2]."\n";
|
||||
if ($response ne $expected) {
|
||||
print "TEST FOR offset(".$_->[0].") body(".$_->[1].") FAILED:\nEXPECTED\n---\n".$expected."\n---\nGOT\n---\n".$response."\n---\n";
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
print "test result: SUCCESS\n";
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user