mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-10-04 16:08:31 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec954b8aa7 | ||
|
|
95d20e9f48 | ||
|
|
165aad8cd0 | ||
|
|
29c339a3c3 | ||
|
|
12afba035b | ||
|
|
eeb203afd4 | ||
|
|
6a18d10c56 | ||
|
|
d1383d7749 | ||
|
|
0abbabbe10 | ||
|
|
ea44525c22 | ||
|
|
2396c7cf31 | ||
|
|
4805a9c219 | ||
|
|
882cdcc2b6 | ||
|
|
59c8bb51b4 | ||
|
|
3c2350f5ad | ||
|
|
422e958fe3 | ||
|
|
4d9c7809d6 | ||
|
|
6b3d8ea146 | ||
|
|
b5d8538fe8 | ||
|
|
47796b315e | ||
|
|
222bcd8fdc | ||
|
|
f92b800a7c | ||
|
|
dec2b234f8 | ||
|
|
3dbd7e3115 | ||
|
|
09d8747918 | ||
|
|
fa78fd915b | ||
|
|
db56141485 | ||
|
|
7685af4652 | ||
|
|
21cb62db6c | ||
|
|
c62aa8e7ed | ||
|
|
4765965d8e | ||
|
|
556feaef2c | ||
|
|
799b8a22e0 | ||
|
|
2336580164 | ||
|
|
ca4f30c003 | ||
|
|
d7d0a71d87 | ||
|
|
44b92f1578 | ||
|
|
abed95362f | ||
|
|
72ecc217f7 | ||
|
|
1405d01d50 | ||
|
|
def65c4793 | ||
|
|
26386909de | ||
|
|
2d4e04059a | ||
|
|
ac557739c2 | ||
|
|
73bfc20ba1 | ||
|
|
6d5ae96d50 | ||
|
|
20b5b7b0dc | ||
|
|
82c5afd0c7 | ||
|
|
ec14f5b0fe | ||
|
|
d93bdcb7b4 | ||
|
|
b68ffc842d | ||
|
|
0326c1d508 | ||
|
|
42f45bfbf9 | ||
|
|
d018d3af99 | ||
|
|
42afc476d7 | ||
|
|
b5037d3f0f | ||
|
|
065dd7cfff | ||
|
|
7909e092b5 | ||
|
|
9da53f5fd4 | ||
|
|
025cb7744e | ||
|
|
e48a3ff1b7 | ||
|
|
2be371003c | ||
|
|
60d940e301 | ||
|
|
96c56cd8d5 | ||
|
|
4184619f7b | ||
|
|
50a8ec8a19 | ||
|
|
79c702278a | ||
|
|
8fc41a4c85 | ||
|
|
9c6455252d | ||
|
|
83e41844f3 | ||
|
|
2cc17d6b11 | ||
|
|
14057b72c8 | ||
|
|
faf72b6a77 | ||
|
|
963afa5174 | ||
|
|
ce8ff8c45f | ||
|
|
5ae742e8e1 | ||
|
|
60f6572985 | ||
|
|
4ea34c63d2 | ||
|
|
5699d21aa7 | ||
|
|
dda8d25495 | ||
|
|
d4f690322c | ||
|
|
4f2f30d1e5 | ||
|
|
d3b28e7956 | ||
|
|
ab4afdbeaa | ||
|
|
54e2d698cb | ||
|
|
8b0565c0b8 | ||
|
|
102d6f25ed | ||
|
|
d0a53aa976 | ||
|
|
f8cf808e47 | ||
|
|
f8bbd2177e | ||
|
|
f44c145941 | ||
|
|
f34ac9f6aa | ||
|
|
b971230fd9 | ||
|
|
5c6340caac | ||
|
|
c0b97b47d3 | ||
|
|
a6b7f6e5bb | ||
|
|
1b99f9a750 | ||
|
|
a434195318 | ||
|
|
a6a8faea78 | ||
|
|
31458320ab | ||
|
|
037a1f7f77 | ||
|
|
10d4d10ac9 | ||
|
|
00e8d509f8 | ||
|
|
c9ca14df4d | ||
|
|
841cdfc62d | ||
|
|
fc7026c076 | ||
|
|
b96581c183 | ||
|
|
4fa5d72af6 | ||
|
|
f4be581666 | ||
|
|
24fb5518d8 | ||
|
|
2e8061d62a | ||
|
|
23d70f6936 | ||
|
|
95ea88628a | ||
|
|
68b411f487 | ||
|
|
40bfbc0a44 | ||
|
|
fc9b6ea275 | ||
|
|
522f3bb3a1 | ||
|
|
743c7ceaa6 | ||
|
|
c780cd47ce | ||
|
|
54e7e01c05 | ||
|
|
7d422d11e4 | ||
|
|
5c35b60d1d | ||
|
|
94353efb3f | ||
|
|
0586a2ba47 | ||
|
|
be6081c6f7 | ||
|
|
955fb6479e | ||
|
|
1b334e8cf7 | ||
|
|
718e198ac8 | ||
|
|
3757e5a8bb | ||
|
|
d505964321 | ||
|
|
1114c1a429 | ||
|
|
f58a9c6119 | ||
|
|
e791cb2c00 | ||
|
|
f741dbb01b | ||
|
|
d5f0741e8d | ||
|
|
b265ed8313 | ||
|
|
6cb160bb26 | ||
|
|
009a3f2c0d | ||
|
|
11b3d1fb94 | ||
|
|
7a39472700 | ||
|
|
4489b48603 | ||
|
|
d2f69af964 | ||
|
|
34e9dabffc | ||
|
|
6a4f46639e | ||
|
|
0d07ff25f9 | ||
|
|
c1d9c4ef12 | ||
|
|
0227ff7a9b | ||
|
|
082b178ae3 | ||
|
|
0e695cbd6e | ||
|
|
be2ed4dc4a | ||
|
|
4777666588 | ||
|
|
5647057ecc | ||
|
|
94cb950058 | ||
|
|
8d65371bf6 | ||
|
|
c747a36ae1 | ||
|
|
e51cb65857 | ||
|
|
8fa4fdb8c8 | ||
|
|
d584857c78 | ||
|
|
f0b1d79f8b | ||
|
|
28566ad772 | ||
|
|
40c0e139d4 | ||
|
|
04f2444ea0 | ||
|
|
9f71d28afa | ||
|
|
af262fb325 | ||
|
|
243657b5aa | ||
|
|
032302edaa | ||
|
|
d4bd658d84 | ||
|
|
78843c3e06 | ||
|
|
692ba1f6b3 | ||
|
|
400a9d72ef | ||
|
|
11f8f0385a | ||
|
|
c40d15981c | ||
|
|
baa1bf21f1 | ||
|
|
3dd3122236 | ||
|
|
927ef2ccde | ||
|
|
af6eaf6737 | ||
|
|
7c543f5627 | ||
|
|
b06e35c610 | ||
|
|
842c2148d7 | ||
|
|
a2a94bd78e | ||
|
|
4452c30fc8 | ||
|
|
f462792c8e | ||
|
|
03879fdc0c | ||
|
|
389d0b95d5 | ||
|
|
6ec32e192f | ||
|
|
22c034cdca | ||
|
|
396d8c3022 | ||
|
|
a535ecbe17 | ||
|
|
fd436c3e4f | ||
|
|
e5c245ea2f | ||
|
|
3008b7c83b | ||
|
|
eca6cd3066 | ||
|
|
691a41f290 | ||
|
|
df4cf539a1 | ||
|
|
baa1167dfe | ||
|
|
d8a83ab7cf | ||
|
|
8184351b3b | ||
|
|
4a4dbbcf69 | ||
|
|
56f79efc74 | ||
|
|
ea073a9bbd | ||
|
|
c5b2ca4b20 | ||
|
|
c0f9d8d2ff | ||
|
|
497660279f | ||
|
|
625395bd26 |
@@ -1,8 +1,16 @@
|
||||
PYTHON := python
|
||||
|
||||
all:
|
||||
python uwsgiconfig.py --build
|
||||
$(PYTHON) uwsgiconfig.py --build $(PROFILE)
|
||||
|
||||
clean:
|
||||
python uwsgiconfig.py --clean
|
||||
$(PYTHON) uwsgiconfig.py --clean
|
||||
|
||||
check:
|
||||
python uwsgiconfig.py --check
|
||||
$(PYTHON) uwsgiconfig.py --check
|
||||
|
||||
plugin.%:
|
||||
$(PYTHON) uwsgiconfig.py --plugin plugins/$* $(PROFILE)
|
||||
|
||||
%:
|
||||
$(PYTHON) uwsgiconfig.py --build $@
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = python,gevent,psgi,lua,php,rack,jvm,jwsgi,ring,mono,transformation_toupper,coroae,v8,cgi,xslt,webdav,ssi,ldap,gccgo,rados
|
||||
main_plugin = python,gevent,psgi,lua,php,rack,jvm,jwsgi,ring,mono,transformation_toupper,coroae,v8,cgi,xslt,webdav,ssi,ldap,gccgo,rados,pypy
|
||||
inherit = base
|
||||
|
||||
+1
-2
@@ -6,7 +6,6 @@ zeromq = auto
|
||||
ssl = auto
|
||||
pcre = auto
|
||||
routing = auto
|
||||
matheval = auto
|
||||
debug = false
|
||||
unbit = false
|
||||
xml_implementation = libxml2
|
||||
@@ -17,7 +16,7 @@ plugins =
|
||||
bin_name = uwsgi
|
||||
append_version =
|
||||
plugin_dir = .
|
||||
embedded_plugins = %(main_plugin)s, ping, cache, nagios, rrdtool, carbon, rpc, corerouter, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool, redislog, mongodblog, router_rewrite, router_http, logfile, router_cache, rawrouter, router_static, sslrouter, spooler, cheaper_busyness, symcall, transformation_tofile, transformation_gzip, transformation_chunked, transformation_offload, router_memcached, router_redis, router_hash, router_expires
|
||||
embedded_plugins = %(main_plugin)s, ping, cache, nagios, rrdtool, carbon, rpc, corerouter, fastrouter, http, ugreen, signal, syslog, rsyslog, logsocket, router_uwsgi, router_redirect, router_basicauth, zergpool, redislog, mongodblog, router_rewrite, router_http, logfile, router_cache, rawrouter, router_static, sslrouter, spooler, cheaper_busyness, symcall, transformation_tofile, transformation_gzip, transformation_chunked, transformation_offload, router_memcached, router_redis, router_hash, router_expires, router_metrics, transformation_template, stats_pusher_socket
|
||||
as_shared_library = false
|
||||
|
||||
locking = auto
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
[uwsgi]
|
||||
# pypy,jvm,ring,jwsgi
|
||||
main_plugin = erlang,psgi,rack,lua,python,gevent,php,cgi,mono,pyerl,go
|
||||
main_plugin = psgi,rack,lua,python,gevent,php,cgi,glusterfs,pty,xslt,msgpack,geoip,v8,pam,ldap,mono,jvm,ring,jwsgi,servlet,rados,coroae,pypy,gccgo
|
||||
inherit = base
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = gccgo
|
||||
inherit = base
|
||||
@@ -1,4 +1,3 @@
|
||||
[uwsgi]
|
||||
main_plugin = glusterfs
|
||||
inherit = base
|
||||
matheval = false
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
[uwsgi]
|
||||
main_plugin = go
|
||||
inherit = base
|
||||
bin_name = libuwsgi.so
|
||||
as_shared_library = true
|
||||
@@ -6,7 +6,6 @@ zeromq = false
|
||||
ssl = false
|
||||
pcre = false
|
||||
routing = false
|
||||
matheval = false
|
||||
debug = false
|
||||
unbit = false
|
||||
xml_implementation = none
|
||||
|
||||
+27
-22
@@ -4,18 +4,18 @@ extern struct uwsgi_server uwsgi;
|
||||
|
||||
/*
|
||||
|
||||
This is a general purpose async loop engine (it expects a coroutine based approach)
|
||||
This is a general-purpose async loop engine (it expects a coroutine-based approach)
|
||||
|
||||
You can see it as an hub holding the following structures:
|
||||
|
||||
1) the runqueue, cores ready to be run are appended in this list
|
||||
1) the runqueue, cores ready to be run are appended to this list
|
||||
|
||||
2) the fd list, this is a list of monitored file descriptors, a core can wait for all the file descriptors it needs
|
||||
|
||||
3) the timeout value, if set the current core will timeout aftert he specified number of seconds (unless an event cancel it)
|
||||
3) the timeout value, if set, the current core will timeout after the specified number of seconds (unless an event cancels it)
|
||||
|
||||
|
||||
IMPORTANT: this is not a callback based engine !!!
|
||||
IMPORTANT: this is not a callback-based engine !!!
|
||||
|
||||
*/
|
||||
|
||||
@@ -159,7 +159,7 @@ static void async_expire_timeouts(uint64_t now) {
|
||||
wsgi_req = (struct wsgi_request *) urbt->data;
|
||||
// timeout expired
|
||||
wsgi_req->async_timed_out = 1;
|
||||
// reset teh request
|
||||
// reset the request
|
||||
async_reset_request(wsgi_req);
|
||||
// push it in the runqueue
|
||||
runqueue_push(wsgi_req);
|
||||
@@ -308,29 +308,42 @@ end:
|
||||
async_reset_request(uwsgi.wsgi_req);
|
||||
uwsgi_close_request(uwsgi.wsgi_req);
|
||||
uwsgi.wsgi_req->async_status = UWSGI_OK;
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
|
||||
}
|
||||
|
||||
void async_schedule_to_req_green(void) {
|
||||
struct wsgi_request *wsgi_req = uwsgi.wsgi_req;
|
||||
#ifdef UWSGI_ROUTING
|
||||
if (uwsgi_apply_routes(uwsgi.wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
if (uwsgi_apply_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
goto end;
|
||||
}
|
||||
#endif
|
||||
for(;;) {
|
||||
if (uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req) <= UWSGI_OK) {
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req) <= UWSGI_OK) {
|
||||
break;
|
||||
}
|
||||
uwsgi.wsgi_req->switches++;
|
||||
wsgi_req->switches++;
|
||||
if (uwsgi.schedule_fix) {
|
||||
uwsgi.schedule_fix(wsgi_req);
|
||||
}
|
||||
// switch after each yield
|
||||
uwsgi.schedule_to_main(uwsgi.wsgi_req);
|
||||
uwsgi.schedule_to_main(wsgi_req);
|
||||
}
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
end:
|
||||
#endif
|
||||
async_reset_request(uwsgi.wsgi_req);
|
||||
uwsgi_close_request(uwsgi.wsgi_req);
|
||||
uwsgi.wsgi_req->async_status = UWSGI_OK;
|
||||
// re-set the global state
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
async_reset_request(wsgi_req);
|
||||
uwsgi_close_request(wsgi_req);
|
||||
// re-set the global state (routing could have changed it)
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
wsgi_req->async_status = UWSGI_OK;
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = wsgi_req;
|
||||
|
||||
}
|
||||
|
||||
void async_loop() {
|
||||
@@ -511,19 +524,11 @@ void async_loop() {
|
||||
uwsgi.wsgi_req->switches++;
|
||||
|
||||
// request ended ?
|
||||
if (uwsgi.wsgi_req->async_status <= UWSGI_OK) {
|
||||
if (uwsgi.wsgi_req->async_status <= UWSGI_OK ||
|
||||
uwsgi.wsgi_req->waiting_fds || uwsgi.wsgi_req->async_timeout) {
|
||||
// remove from the runqueue
|
||||
runqueue_remove(current_request);
|
||||
// push wsgi_request in the unused stack
|
||||
uwsgi.async_queue_unused_ptr++;
|
||||
uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req;
|
||||
|
||||
}
|
||||
else if (uwsgi.wsgi_req->waiting_fds || uwsgi.wsgi_req->async_timeout) {
|
||||
// remove this request from the runqueue
|
||||
runqueue_remove(current_request);
|
||||
}
|
||||
|
||||
current_request = next_request;
|
||||
}
|
||||
|
||||
|
||||
@@ -204,6 +204,19 @@ int uwsgi_buffer_u64be(struct uwsgi_buffer *ub, uint64_t num) {
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 8);
|
||||
}
|
||||
|
||||
int uwsgi_buffer_u64le(struct uwsgi_buffer *ub, uint64_t num) {
|
||||
uint8_t buf[8];
|
||||
buf[0] = (uint8_t) (num & 0xff);
|
||||
buf[1] = (uint8_t) ((num >> 8) & 0xff);
|
||||
buf[2] = (uint8_t) ((num >> 16) & 0xff);
|
||||
buf[3] = (uint8_t) ((num >> 24) & 0xff);
|
||||
buf[4] = (uint8_t) ((num >> 32) & 0xff);
|
||||
buf[5] = (uint8_t) ((num >> 40) & 0xff);
|
||||
buf[6] = (uint8_t) ((num >> 48) & 0xff);
|
||||
buf[7] = (uint8_t) ((num >> 56) & 0xff);
|
||||
return uwsgi_buffer_append(ub, (char *) buf, 8);
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_buffer_f64be(struct uwsgi_buffer *ub, double num) {
|
||||
uint8_t buf[8];
|
||||
|
||||
+3
-3
@@ -762,7 +762,7 @@ 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 teh scan
|
||||
// optimize the scan
|
||||
if (uc->blocks_bitmap_pos + (needed_blocks+1) > uc->blocks) {
|
||||
uc->blocks_bitmap_pos = 0;
|
||||
}
|
||||
@@ -1432,7 +1432,7 @@ static int cache_magic_send_and_manage(int fd, struct uwsgi_buffer *ub, char *st
|
||||
// ok now wait for the response, using the same buffer of the request
|
||||
// NOTE: after using a uwsgi_buffer in that way we basically destroy (even if we can safely free it)
|
||||
size_t rlen = ub->pos;
|
||||
if (uwsgi_read_with_realloc(fd, &ub->buf, &rlen, timeout)) return -1;
|
||||
if (uwsgi_read_with_realloc(fd, &ub->buf, &rlen, timeout, NULL, NULL)) return -1;
|
||||
// try to fix the buffer to maintain size info
|
||||
ub->pos = rlen;
|
||||
|
||||
@@ -1867,7 +1867,7 @@ void uwsgi_cache_sync_from_nodes(struct uwsgi_cache *uc) {
|
||||
}
|
||||
|
||||
size_t rlen = ub->pos;
|
||||
if (uwsgi_read_with_realloc(fd, &ub->buf, &rlen, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
|
||||
if (uwsgi_read_with_realloc(fd, &ub->buf, &rlen, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], NULL, NULL)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
uwsgi_log("[cache-sync] unable to read from the cache server\n");
|
||||
close(fd);
|
||||
|
||||
+169
@@ -493,6 +493,10 @@ add:
|
||||
if (op->flags & UWSGI_OPT_MIME) {
|
||||
uwsgi.build_mime_dict = 1;
|
||||
}
|
||||
// enable metrics ?
|
||||
if (op->flags & UWSGI_OPT_METRICS) {
|
||||
uwsgi.has_metrics = 1;
|
||||
}
|
||||
// immediate ?
|
||||
if (op->flags & UWSGI_OPT_IMMEDIATE) {
|
||||
op->func(key, value, op->data);
|
||||
@@ -629,3 +633,168 @@ clear:
|
||||
|
||||
}
|
||||
|
||||
char *uwsgi_get_exported_opt(char *key) {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
|
||||
if (!strcmp(uwsgi.exported_opts[i]->key, key)) {
|
||||
return uwsgi.exported_opts[i]->value;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *uwsgi_get_optname_by_index(int index) {
|
||||
|
||||
struct uwsgi_option *op = uwsgi.options;
|
||||
|
||||
while (op->name) {
|
||||
if (op->shortcut == index) {
|
||||
return op->name;
|
||||
}
|
||||
op++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
this works as a pipeline
|
||||
|
||||
processes = 2
|
||||
cpu_cores = 8
|
||||
foobar = %(processes cpu_cores + 2)
|
||||
|
||||
translate as:
|
||||
|
||||
step1 = proceses cpu_cores = 2 8 = 28 (string concatenation)
|
||||
|
||||
step1 + = step1_apply_func_plus (func token)
|
||||
|
||||
step1_apply_func_plus 2 = 28 + 2 = 30 (math)
|
||||
|
||||
*/
|
||||
|
||||
char *uwsgi_manage_placeholder(char *key) {
|
||||
enum {
|
||||
concat = 0,
|
||||
sum,
|
||||
sub,
|
||||
mul,
|
||||
div,
|
||||
} state;
|
||||
|
||||
state = concat;
|
||||
char *current_value = NULL;
|
||||
|
||||
char *space = strchr(key, ' ');
|
||||
if (!space) {
|
||||
return uwsgi_get_exported_opt(key);
|
||||
}
|
||||
// let's start the heavy metal here
|
||||
char *tmp_value = uwsgi_str(key);
|
||||
char *p, *ctx = NULL;
|
||||
uwsgi_foreach_token(tmp_value, " ", p, ctx) {
|
||||
char *value = NULL;
|
||||
if (is_a_number(p)) {
|
||||
value = uwsgi_str(p);
|
||||
}
|
||||
else if (!strcmp(p, "+")) {
|
||||
state = sum;
|
||||
continue;
|
||||
}
|
||||
else if (!strcmp(p, "-")) {
|
||||
state = sub;
|
||||
continue;
|
||||
}
|
||||
else if (!strcmp(p, "*")) {
|
||||
state = mul;
|
||||
continue;
|
||||
}
|
||||
else if (!strcmp(p, "/")) {
|
||||
state = div;
|
||||
continue;
|
||||
}
|
||||
else if (!strcmp(p, "++")) {
|
||||
if (current_value) {
|
||||
int64_t tmp_value = strtoll(current_value, NULL, 10);
|
||||
free(current_value);
|
||||
current_value = uwsgi_64bit2str(tmp_value+1);
|
||||
}
|
||||
state = concat;
|
||||
continue;
|
||||
}
|
||||
else if (!strcmp(p, "--")) {
|
||||
if (current_value) {
|
||||
int64_t tmp_value = strtoll(current_value, NULL, 10);
|
||||
free(current_value);
|
||||
current_value = uwsgi_64bit2str(tmp_value-1);
|
||||
}
|
||||
state = concat;
|
||||
continue;
|
||||
}
|
||||
// find the option
|
||||
else {
|
||||
char *ov = uwsgi_get_exported_opt(p);
|
||||
if (!ov) ov = "";
|
||||
value = uwsgi_str(ov);
|
||||
}
|
||||
|
||||
int64_t arg1n = 0, arg2n = 0;
|
||||
char *arg1 = "", *arg2 = "";
|
||||
|
||||
switch(state) {
|
||||
case concat:
|
||||
if (current_value) arg1 = current_value;
|
||||
if (value) arg2 = value;
|
||||
char *ret = uwsgi_concat2(arg1, arg2);
|
||||
if (current_value) free(current_value);
|
||||
current_value = ret;
|
||||
break;
|
||||
case sum:
|
||||
if (current_value) arg1n = strtoll(current_value, NULL, 10);
|
||||
if (value) arg2n = strtoll(value, NULL, 10);
|
||||
if (current_value) free(current_value);
|
||||
current_value = uwsgi_64bit2str(arg1n + arg2n);
|
||||
break;
|
||||
case sub:
|
||||
if (current_value) arg1n = strtoll(current_value, NULL, 10);
|
||||
if (value) arg2n = strtoll(value, NULL, 10);
|
||||
if (current_value) free(current_value);
|
||||
current_value = uwsgi_64bit2str(arg1n - arg2n);
|
||||
break;
|
||||
case mul:
|
||||
if (current_value) arg1n = strtoll(current_value, NULL, 10);
|
||||
if (value) arg2n = strtoll(value, NULL, 10);
|
||||
if (current_value) free(current_value);
|
||||
current_value = uwsgi_64bit2str(arg1n * arg2n);
|
||||
break;
|
||||
case div:
|
||||
if (current_value) arg1n = strtoll(current_value, NULL, 10);
|
||||
if (value) arg2n = strtoll(value, NULL, 10);
|
||||
if (current_value) free(current_value);
|
||||
// avoid division by zero
|
||||
if (arg2n == 0) {
|
||||
current_value = uwsgi_64bit2str(0);
|
||||
}
|
||||
else {
|
||||
current_value = uwsgi_64bit2str(arg1n / arg2n);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// over engineering
|
||||
if (value)
|
||||
free(value);
|
||||
|
||||
// reset state to concat
|
||||
state = concat;
|
||||
}
|
||||
|
||||
return current_value;
|
||||
}
|
||||
|
||||
+5
-3
@@ -233,7 +233,7 @@ void uwsgi_detach_daemons() {
|
||||
#endif
|
||||
uwsgi_log("[uwsgi-daemons] stopping daemon (pid: %d): %s\n", (int) ud->pid, ud->command);
|
||||
// try to gracefully stop daemon, kill it if it won't die
|
||||
// if mercy is not set than wait up to 3 seconds
|
||||
// if mercy is not set then wait up to 3 seconds
|
||||
time_t timeout = uwsgi_now() + (uwsgi.reload_mercy ? uwsgi.reload_mercy : 3);
|
||||
int waitpid_status;
|
||||
while (!kill(ud->pid, 0)) {
|
||||
@@ -241,7 +241,7 @@ void uwsgi_detach_daemons() {
|
||||
sleep(1);
|
||||
waitpid(-ud->pid, &waitpid_status, WNOHANG);
|
||||
if (uwsgi_now() >= timeout) {
|
||||
uwsgi_log("[uwsgi-daemons] daemon did not died in time, killing (pid: %d): %s\n", (int) ud->pid, ud->command);
|
||||
uwsgi_log("[uwsgi-daemons] daemon did not die in time, killing (pid: %d): %s\n", (int) ud->pid, ud->command);
|
||||
kill(-ud->pid, SIGKILL);
|
||||
break;
|
||||
}
|
||||
@@ -263,6 +263,8 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
|
||||
|
||||
if (uwsgi.current_time - ud->last_spawn <= 3) {
|
||||
throttle = ud->respawns - (uwsgi.current_time - ud->last_spawn);
|
||||
// if ud->respawns == 0 then we can end up with throttle < 0
|
||||
if (throttle <= 0) throttle = 1;
|
||||
}
|
||||
|
||||
pid_t pid = uwsgi_fork("uWSGI external daemon");
|
||||
@@ -323,7 +325,7 @@ void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) {
|
||||
|
||||
if (throttle) {
|
||||
uwsgi_log("[uwsgi-daemons] throttling \"%s\" for %d seconds\n", ud->command, throttle);
|
||||
sleep(throttle);
|
||||
sleep((unsigned int) throttle);
|
||||
}
|
||||
|
||||
uwsgi_log("[uwsgi-daemons] %sspawning \"%s\"\n", ud->respawns > 0 ? "re" : "", ud->command);
|
||||
|
||||
@@ -974,6 +974,7 @@ static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) {
|
||||
#endif
|
||||
|
||||
#ifdef UWSGI_CAP
|
||||
#if defined(CAP_LAST_CAP) && defined(PR_CAPBSET_READ) && defined(PR_CAPBSET_DROP)
|
||||
if (uwsgi.emperor_cap && uwsgi.emperor_cap_count > 0) {
|
||||
int i;
|
||||
for(i=0;i<=CAP_LAST_CAP;i++) {
|
||||
@@ -1010,6 +1011,7 @@ static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) {
|
||||
uwsgi_log("capabilities applied for vassal %s (pid: %d)\n", n_ui->name, (int) getpid());
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (uwsgi.emperor_tyrant) {
|
||||
@@ -1100,6 +1102,7 @@ static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) {
|
||||
struct uwsgi_string_list *uct;
|
||||
uwsgi_foreach(uct, uwsgi.vassals_templates_before) counter += 2;
|
||||
uwsgi_foreach(uct, uwsgi.vassals_includes_before) counter += 2;
|
||||
uwsgi_foreach(uct, uwsgi.vassals_set) counter += 2;
|
||||
uwsgi_foreach(uct, uwsgi.vassals_templates) counter += 2;
|
||||
uwsgi_foreach(uct, uwsgi.vassals_includes) counter += 2;
|
||||
|
||||
@@ -1122,6 +1125,12 @@ static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) {
|
||||
counter += 2;
|
||||
}
|
||||
|
||||
uwsgi_foreach (uct, uwsgi.vassals_set) {
|
||||
vassal_argv[counter] = "--set";
|
||||
vassal_argv[counter + 1] = uct->value;
|
||||
counter += 2;
|
||||
}
|
||||
|
||||
char *colon = NULL;
|
||||
if (uwsgi.emperor_broodlord) {
|
||||
colon = strchr(n_ui->name, ':');
|
||||
|
||||
+1
-1
@@ -99,7 +99,7 @@ int uwsgi_master_fifo() {
|
||||
}
|
||||
|
||||
int uwsgi_master_fifo_manage(int fd) {
|
||||
char cmd;
|
||||
unsigned char cmd;
|
||||
ssize_t rlen = read(fd, &cmd, 1);
|
||||
if (rlen < 0) {
|
||||
if (uwsgi_is_again()) return 0;
|
||||
|
||||
@@ -38,6 +38,7 @@ void uwsgi_fsmon_setup() {
|
||||
char *space = strchr(copy, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("[uwsgi-fsmon] invalid syntax: \"%s\"\n", usl->value);
|
||||
free(copy);
|
||||
goto next;
|
||||
}
|
||||
*space = 0;
|
||||
|
||||
+21
-1
@@ -17,7 +17,7 @@ uint32_t djb33x_hash(char *key, uint64_t keylen) {
|
||||
|
||||
// Murmur2 hash Copyright (C) Austin Appleby
|
||||
// adapted from nginx
|
||||
uint32_t murmur2_hash(char *key, uint64_t keylen) {
|
||||
static uint32_t murmur2_hash(char *key, uint64_t keylen) {
|
||||
|
||||
uint32_t h, k;
|
||||
uint8_t *ukey = (uint8_t *) key;
|
||||
@@ -56,6 +56,23 @@ uint32_t murmur2_hash(char *key, uint64_t keylen) {
|
||||
return h;
|
||||
}
|
||||
|
||||
static uint32_t random_hash(char *key, uint64_t keylen) {
|
||||
return (uint32_t) rand();
|
||||
}
|
||||
|
||||
/*
|
||||
not atomic, avoid its use in multithreaded modes
|
||||
*/
|
||||
static uint32_t rr_hash(char *key, uint64_t keylen) {
|
||||
static uint32_t rr = 0;
|
||||
uint32_t max_value = uwsgi_str_num(key, keylen);
|
||||
uint32_t ret = rr;
|
||||
rr++;
|
||||
if (rr > max_value) {
|
||||
rr = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct uwsgi_hash_algo *uwsgi_hash_algo_get(char *name) {
|
||||
struct uwsgi_hash_algo *uha = uwsgi.hash_algos;
|
||||
@@ -90,4 +107,7 @@ void uwsgi_hash_algo_register(char *name, uint32_t (*func)(char *, uint64_t)) {
|
||||
void uwsgi_hash_algo_register_all() {
|
||||
uwsgi_hash_algo_register("djb33x", djb33x_hash);
|
||||
uwsgi_hash_algo_register("murmur2", murmur2_hash);
|
||||
uwsgi_hash_algo_register("random", random_hash);
|
||||
uwsgi_hash_algo_register("rand", random_hash);
|
||||
uwsgi_hash_algo_register("rr", rr_hash);
|
||||
}
|
||||
|
||||
+1
-6
@@ -51,6 +51,7 @@ struct http_status_codes hsc[] = {
|
||||
{"503", "Service Unavailable"},
|
||||
{"504", "Gateway Timeout"},
|
||||
{"505", "HTTP Version Not Supported"},
|
||||
{"509", "Bandwidth Limit Exceeded"},
|
||||
{"", NULL},
|
||||
};
|
||||
|
||||
@@ -345,7 +346,6 @@ void uwsgi_setup_workers() {
|
||||
uwsgi.workers[i].signal_pipe[0] = -1;
|
||||
uwsgi.workers[i].signal_pipe[1] = -1;
|
||||
snprintf(uwsgi.workers[i].name, 0xff, "uWSGI worker %d", i);
|
||||
snprintf(uwsgi.workers[i].snapshot_name, 0xff, "uWSGI snapshot %d", i);
|
||||
}
|
||||
|
||||
uint64_t total_memory = (sizeof(struct uwsgi_app) * uwsgi.max_apps) + (sizeof(struct uwsgi_core) * uwsgi.cores) + (sizeof(void *) * uwsgi.max_apps * uwsgi.cores) + (uwsgi.buffer_size * uwsgi.cores) + (sizeof(struct iovec) * uwsgi.vec_size * uwsgi.cores);
|
||||
@@ -447,11 +447,6 @@ void sanitize_args() {
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.auto_snapshot > 0 && uwsgi.auto_snapshot > uwsgi.numproc) {
|
||||
uwsgi_log("invalid auto-snapshot value: must be <= than processes\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME] > 0 && uwsgi.shared->options[UWSGI_OPTION_MIN_WORKER_LIFETIME] >= uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME]) {
|
||||
uwsgi_log("invalid min-worker-lifetime value (%d), must be lower than max-worker-lifetime (%d)\n",
|
||||
uwsgi.shared->options[UWSGI_OPTION_MIN_WORKER_LIFETIME], uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME]);
|
||||
|
||||
@@ -270,7 +270,7 @@ static char *uwsgi_scheme_emperor(char *url, size_t *size, int add_zero) {
|
||||
}
|
||||
rlen = read(uwsgi.emperor_fd_config, ptr, remains);
|
||||
if (rlen <= 0) {
|
||||
uwsgi_log("[uwsgi-vassal] error reading config header from !!!\n", url);
|
||||
uwsgi_log("[uwsgi-vassal] error reading config header from %s !!!\n", url);
|
||||
exit(1);
|
||||
}
|
||||
ptr+=rlen;
|
||||
@@ -293,7 +293,7 @@ static char *uwsgi_scheme_emperor(char *url, size_t *size, int add_zero) {
|
||||
}
|
||||
rlen = read(uwsgi.emperor_fd_config, ptr, remains);
|
||||
if (rlen <= 0) {
|
||||
uwsgi_log("[uwsgi-vassal] error reading config from !!!\n", url);
|
||||
uwsgi_log("[uwsgi-vassal] error reading config from %s !!!\n", url);
|
||||
exit(1);
|
||||
}
|
||||
ptr+=rlen;
|
||||
@@ -364,6 +364,7 @@ static char *uwsgi_scheme_data(char *url, size_t *size, int add_zero) {
|
||||
}
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
@@ -942,12 +943,12 @@ int uwsgi_read_whole_true_nb(int fd, char *buf, size_t remains, int timeout) {
|
||||
}
|
||||
|
||||
/*
|
||||
this is a pretty magic function used for read a full uwsgi response
|
||||
this is a pretty magic function used for reading a full uwsgi response
|
||||
it is true non blocking, so you can use it in request plugins
|
||||
buffer is expected to be at least 4 bytes, rlen is a get/set value
|
||||
*/
|
||||
|
||||
int uwsgi_read_with_realloc(int fd, char **buffer, size_t *rlen, int timeout) {
|
||||
int uwsgi_read_with_realloc(int fd, char **buffer, size_t *rlen, int timeout, uint8_t *modifier1, uint8_t *modifier2) {
|
||||
if (*rlen < 4) return -1;
|
||||
char *buf = *buffer;
|
||||
int ret;
|
||||
@@ -978,6 +979,10 @@ readok:
|
||||
|
||||
struct uwsgi_header *uh = (struct uwsgi_header *) buf;
|
||||
uint16_t pktsize = uh->pktsize;
|
||||
if (modifier1)
|
||||
*modifier1 = uh->modifier1;
|
||||
if (modifier2)
|
||||
*modifier2 = uh->modifier2;
|
||||
|
||||
if (pktsize > *rlen) {
|
||||
char *tmp_buf = realloc(buf, pktsize);
|
||||
|
||||
+15
-2
@@ -498,7 +498,7 @@ void uwsgi_check_logrotate(void) {
|
||||
uwsgi.shared->logsize = lseek(2, 0, SEEK_CUR);
|
||||
}
|
||||
|
||||
if (uwsgi.log_maxsize > 0 && uwsgi.shared->logsize > uwsgi.log_maxsize) {
|
||||
if (uwsgi.log_maxsize > 0 && (uint64_t) uwsgi.shared->logsize > uwsgi.log_maxsize) {
|
||||
need_rotation = 1;
|
||||
}
|
||||
|
||||
@@ -575,6 +575,7 @@ void uwsgi_log_reopen() {
|
||||
if (uwsgi.original_log_fd < 0) {
|
||||
uwsgi_error_open(uwsgi.logfile);
|
||||
grace_them_all(0);
|
||||
return;
|
||||
}
|
||||
ret = snprintf(message, 1024, "[%d] %s reopened.\n", (int) uwsgi_now(), uwsgi.logfile);
|
||||
if (ret > 0) {
|
||||
@@ -980,6 +981,12 @@ void uwsgi_logit_lf(struct wsgi_request *wsgi_req) {
|
||||
uwsgi.logvectors[wsgi_req->async_id][pos].iov_len = 0;
|
||||
}
|
||||
}
|
||||
// metric
|
||||
else if (logchunk->type == 4) {
|
||||
int64_t metric = uwsgi_metric_get(logchunk->ptr, NULL);
|
||||
uwsgi.logvectors[wsgi_req->async_id][pos].iov_base = uwsgi_64bit2str(metric);
|
||||
uwsgi.logvectors[wsgi_req->async_id][pos].iov_len = strlen(uwsgi.logvectors[wsgi_req->async_id][pos].iov_base);
|
||||
}
|
||||
|
||||
if (uwsgi.logvectors[wsgi_req->async_id][pos].iov_len == 0 && logchunk->type != 0) {
|
||||
uwsgi.logvectors[wsgi_req->async_id][pos].iov_base = (char *) empty_var;
|
||||
@@ -1231,6 +1238,7 @@ void uwsgi_add_logchunk(int variable, int pos, char *ptr, size_t len) {
|
||||
1 -> offsetof variable
|
||||
2 -> logvar
|
||||
3 -> func
|
||||
4 -> metric
|
||||
*/
|
||||
|
||||
logchunk->type = variable;
|
||||
@@ -1397,6 +1405,11 @@ void uwsgi_add_logchunk(int variable, int pos, char *ptr, size_t len) {
|
||||
logchunk->func = uwsgi_lf_headers;
|
||||
logchunk->free = 1;
|
||||
}
|
||||
else if (!uwsgi_starts_with(ptr, len, "metric.", 7)) {
|
||||
logchunk->type = 4;
|
||||
logchunk->ptr = uwsgi_concat2n(ptr+7, len - 7, "", 0);
|
||||
logchunk->free = 1;
|
||||
}
|
||||
// logvar
|
||||
else {
|
||||
logchunk->type = 2;
|
||||
@@ -1841,7 +1854,7 @@ void uwsgi_log_encoder_parse_vars(struct uwsgi_log_encoder *ule) {
|
||||
/*
|
||||
// format: foo ${var} bar
|
||||
msg (the logline)
|
||||
msgnl (the logine with newline)
|
||||
msgnl (the logline with newline)
|
||||
unix (the time_t value)
|
||||
micros (current microseconds)
|
||||
strftime (strftime)
|
||||
|
||||
+69
-66
@@ -2,15 +2,30 @@
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
void uwsgi_restore_auto_snapshot(int signum) {
|
||||
void uwsgi_update_load_counters() {
|
||||
|
||||
if (uwsgi.workers[1].snapshot > 0) {
|
||||
uwsgi.restore_snapshot = 1;
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[WARNING] no snapshot available\n");
|
||||
int i;
|
||||
uint64_t busy_workers = 0;
|
||||
uint64_t idle_workers = 0;
|
||||
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
|
||||
if (uwsgi_worker_is_busy(i) == 0) {
|
||||
idle_workers++;
|
||||
}
|
||||
else {
|
||||
busy_workers++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (busy_workers >= (uint64_t) uwsgi.numproc) {
|
||||
ushared->overloaded++;
|
||||
}
|
||||
|
||||
ushared->busy_workers = busy_workers;
|
||||
ushared->idle_workers = idle_workers;
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_block_signal(int signum) {
|
||||
@@ -32,24 +47,25 @@ void uwsgi_unblock_signal(int signum) {
|
||||
}
|
||||
|
||||
void uwsgi_master_manage_udp(int udp_fd) {
|
||||
char buf[4096];
|
||||
struct sockaddr_in udp_client;
|
||||
char udp_client_addr[16];
|
||||
int i;
|
||||
|
||||
socklen_t udp_len = sizeof(udp_client);
|
||||
ssize_t rlen = recvfrom(udp_fd, uwsgi.wsgi_req->buffer, uwsgi.buffer_size, 0, (struct sockaddr *) &udp_client, &udp_len);
|
||||
ssize_t rlen = recvfrom(udp_fd, buf, 4096, 0, (struct sockaddr *) &udp_client, &udp_len);
|
||||
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("recvfrom()");
|
||||
uwsgi_error("uwsgi_master_manage_udp()/recvfrom()");
|
||||
}
|
||||
else if (rlen > 0) {
|
||||
|
||||
memset(udp_client_addr, 0, 16);
|
||||
if (inet_ntop(AF_INET, &udp_client.sin_addr.s_addr, udp_client_addr, 16)) {
|
||||
if (uwsgi.wsgi_req->buffer[0] == UWSGI_MODIFIER_MULTICAST_ANNOUNCE) {
|
||||
if (buf[0] == UWSGI_MODIFIER_MULTICAST_ANNOUNCE) {
|
||||
}
|
||||
else if (uwsgi.wsgi_req->buffer[0] == 0x30 && uwsgi.snmp) {
|
||||
manage_snmp(udp_fd, (uint8_t *) uwsgi.wsgi_req->buffer, rlen, &udp_client);
|
||||
else if (buf[0] == 0x30 && uwsgi.snmp) {
|
||||
manage_snmp(udp_fd, (uint8_t *) buf, rlen, &udp_client);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -57,7 +73,7 @@ void uwsgi_master_manage_udp(int udp_fd) {
|
||||
int udp_managed = 0;
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->manage_udp) {
|
||||
if (uwsgi.p[i]->manage_udp(udp_client_addr, udp_client.sin_port, uwsgi.wsgi_req->buffer, rlen)) {
|
||||
if (uwsgi.p[i]->manage_udp(udp_client_addr, udp_client.sin_port, buf, rlen)) {
|
||||
udp_managed = 1;
|
||||
break;
|
||||
}
|
||||
@@ -66,42 +82,17 @@ void uwsgi_master_manage_udp(int udp_fd) {
|
||||
|
||||
// else a simple udp logger
|
||||
if (!udp_managed) {
|
||||
uwsgi_log("[udp:%s:%d] %.*s", udp_client_addr, ntohs(udp_client.sin_port), (int) rlen, uwsgi.wsgi_req->buffer);
|
||||
uwsgi_log("[udp:%s:%d] %.*s", udp_client_addr, ntohs(udp_client.sin_port), (int) rlen, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_error("inet_ntop()");
|
||||
uwsgi_error("uwsgi_master_manage_udp()/inet_ntop()");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void uwsgi_master_restore_snapshot() {
|
||||
int i, waitpid_status;
|
||||
uwsgi_log("[snapshot] restoring workers...\n");
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
if (uwsgi.workers[i].pid == 0)
|
||||
continue;
|
||||
kill(uwsgi.workers[i].pid, SIGKILL);
|
||||
if (waitpid(uwsgi.workers[i].pid, &waitpid_status, 0) < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
}
|
||||
if (uwsgi.auto_snapshot > 0 && i > uwsgi.auto_snapshot) {
|
||||
uwsgi.workers[i].pid = 0;
|
||||
uwsgi.workers[i].snapshot = 0;
|
||||
}
|
||||
else {
|
||||
uwsgi.workers[i].pid = uwsgi.workers[i].snapshot;
|
||||
uwsgi.workers[i].snapshot = 0;
|
||||
kill(uwsgi.workers[i].pid, SIGURG);
|
||||
uwsgi_log("Restored uWSGI worker %d (pid: %d)\n", i, (int) uwsgi.workers[i].pid);
|
||||
}
|
||||
}
|
||||
|
||||
uwsgi.restore_snapshot = 0;
|
||||
}
|
||||
|
||||
void suspend_resume_them_all(int signum) {
|
||||
|
||||
int i;
|
||||
@@ -299,9 +290,6 @@ int master_loop(char **argv, char **environ) {
|
||||
}
|
||||
uwsgi_unix_signal(SIGINT, kill_them_all);
|
||||
uwsgi_unix_signal(SIGUSR1, stats);
|
||||
if (uwsgi.auto_snapshot) {
|
||||
uwsgi_unix_signal(SIGURG, uwsgi_restore_auto_snapshot);
|
||||
}
|
||||
|
||||
atexit(uwsgi_master_cleanup_hooks);
|
||||
|
||||
@@ -346,6 +334,7 @@ int master_loop(char **argv, char **environ) {
|
||||
#ifdef UWSGI_SSL
|
||||
uwsgi_start_legions();
|
||||
#endif
|
||||
uwsgi_metrics_start_collector();
|
||||
|
||||
uwsgi_add_reload_fds();
|
||||
|
||||
@@ -486,6 +475,28 @@ int master_loop(char **argv, char **environ) {
|
||||
// fsmon
|
||||
uwsgi_fsmon_setup();
|
||||
|
||||
uwsgi_foreach(usl, uwsgi.signal_timers) {
|
||||
char *space = strchr(usl->value, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid signal timer syntax, must be: <signal> <seconds>\n");
|
||||
exit(1);
|
||||
}
|
||||
*space = 0;
|
||||
uwsgi_add_timer(atoi(usl->value), atoi(space+1));
|
||||
*space = ' ';
|
||||
}
|
||||
|
||||
uwsgi_foreach(usl, uwsgi.rb_signal_timers) {
|
||||
char *space = strchr(usl->value, ' ');
|
||||
if (!space) {
|
||||
uwsgi_log("invalid redblack signal timer syntax, must be: <signal> <seconds>\n");
|
||||
exit(1);
|
||||
}
|
||||
*space = 0;
|
||||
uwsgi_signal_add_rb_timer(atoi(usl->value), atoi(space+1), 0);
|
||||
*space = ' ';
|
||||
}
|
||||
|
||||
// setup cheaper algos (can be stacked)
|
||||
uwsgi.cheaper_algo = uwsgi_cheaper_algo_spare;
|
||||
if (uwsgi.requested_cheaper_algo) {
|
||||
@@ -539,21 +550,6 @@ int master_loop(char **argv, char **environ) {
|
||||
// check for daemons (smart and dumb)
|
||||
uwsgi_daemons_smart_check();
|
||||
|
||||
|
||||
if (uwsgi.respawn_snapshots) {
|
||||
for (i = 1; i <= uwsgi.respawn_snapshots; i++) {
|
||||
if (uwsgi_respawn_worker(i))
|
||||
return 0;
|
||||
}
|
||||
|
||||
uwsgi.respawn_snapshots = 0;
|
||||
}
|
||||
|
||||
if (uwsgi.restore_snapshot) {
|
||||
uwsgi_master_restore_snapshot();
|
||||
continue;
|
||||
}
|
||||
|
||||
// cheaper management
|
||||
if (uwsgi.cheaper && !uwsgi.status.is_cheap && !uwsgi_instance_is_reloading && !uwsgi_instance_is_dying && !uwsgi.workers[0].suspended) {
|
||||
if (!uwsgi_calc_cheaper())
|
||||
@@ -583,8 +579,10 @@ int master_loop(char **argv, char **environ) {
|
||||
|
||||
/* all processes ok, doing status scan after N seconds */
|
||||
check_interval = uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL];
|
||||
if (!check_interval)
|
||||
if (!check_interval) {
|
||||
check_interval = 1;
|
||||
uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL] = 1;
|
||||
}
|
||||
|
||||
|
||||
// add unregistered file monitors
|
||||
@@ -619,14 +617,14 @@ int master_loop(char **argv, char **environ) {
|
||||
|
||||
if (ushared->rb_timers_cnt > 0) {
|
||||
min_timeout = uwsgi_min_rb_timer(rb_timers, NULL);
|
||||
if (min_timeout == NULL) {
|
||||
check_interval = uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL];
|
||||
}
|
||||
else {
|
||||
check_interval = min_timeout->value - uwsgi_now();
|
||||
if (check_interval <= 0) {
|
||||
if (min_timeout) {
|
||||
int delta = min_timeout->value - uwsgi_now();
|
||||
if (delta <= 0) {
|
||||
expire_rb_timeouts(rb_timers);
|
||||
check_interval = 0;
|
||||
}
|
||||
// if the timer expires before the check_interval, override it
|
||||
else if (delta < check_interval) {
|
||||
check_interval = delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -640,6 +638,9 @@ int master_loop(char **argv, char **environ) {
|
||||
}
|
||||
}
|
||||
|
||||
// update load counter
|
||||
uwsgi_update_load_counters();
|
||||
|
||||
|
||||
// check uwsgi-cron table
|
||||
if (ushared->cron_cnt) {
|
||||
@@ -680,8 +681,10 @@ int master_loop(char **argv, char **environ) {
|
||||
uwsgi_master_check_idle();
|
||||
|
||||
check_interval = uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL];
|
||||
if (!check_interval)
|
||||
if (!check_interval) {
|
||||
check_interval = 1;
|
||||
uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL] = 1;
|
||||
}
|
||||
|
||||
|
||||
// get listen_queue status
|
||||
|
||||
@@ -118,6 +118,7 @@ int uwsgi_master_manage_events(int interesting_fd) {
|
||||
reap_them_all(0);
|
||||
uwsgi_unblock_signal(SIGTERM);
|
||||
}
|
||||
if (usl->custom2 > 8) free(tmp);
|
||||
return 0;
|
||||
}
|
||||
usl = usl->next;
|
||||
|
||||
@@ -871,6 +871,70 @@ struct uwsgi_stats *uwsgi_master_generate_stats() {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (uwsgi.has_metrics) {
|
||||
if (uwsgi_stats_key(us, "metrics"))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_object_open(us))
|
||||
goto end;
|
||||
|
||||
uwsgi_rlock(uwsgi.metrics_lock);
|
||||
struct uwsgi_metric *um = uwsgi.metrics;
|
||||
while(um) {
|
||||
int64_t um_val = *um->value;
|
||||
|
||||
if (uwsgi_stats_key(us, um->name)) {
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (uwsgi_stats_object_open(us)) {
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (uwsgi_stats_keylong(us, "type", (long long) um->type)) {
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (uwsgi_stats_comma(us)) {
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (uwsgi_stats_keyval_comma(us, "oid", um->oid ? um->oid : "")) {
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (uwsgi_stats_keyslong(us, "value", (long long) um_val)) {
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (uwsgi_stats_object_close(us)) {
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
goto end;
|
||||
}
|
||||
|
||||
um = um->next;
|
||||
if (um) {
|
||||
if (uwsgi_stats_comma(us)) {
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
|
||||
if (uwsgi_stats_object_close(us))
|
||||
goto end;
|
||||
|
||||
if (uwsgi_stats_comma(us))
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (uwsgi_stats_key(us, "sockets"))
|
||||
goto end;
|
||||
|
||||
|
||||
+970
-63
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -389,7 +389,7 @@ wait:
|
||||
remains -= len;
|
||||
*rlen += len;
|
||||
continue;
|
||||
}else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
}else if (len < 0 && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS)) {
|
||||
goto wait;
|
||||
}
|
||||
*rlen = -1;
|
||||
|
||||
+100
-49
@@ -582,6 +582,88 @@ static int uwsgi_router_break(struct uwsgi_route *ur, char *arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// simple math router
|
||||
static int uwsgi_router_simple_math_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
uint16_t var_vallen = 0;
|
||||
char *var_value = uwsgi_get_var(wsgi_req, ur->data, ur->data_len, &var_vallen);
|
||||
if (!var_value) return UWSGI_ROUTE_BREAK;
|
||||
|
||||
int64_t base_value = uwsgi_str_num(var_value, var_vallen);
|
||||
int64_t value = 1;
|
||||
|
||||
if (ur->data2_len) {
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data2, ur->data2_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
value = uwsgi_str_num(ub->buf, ub->pos);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
}
|
||||
|
||||
char out[sizeof(UMAX64_STR)+1];
|
||||
int64_t total = 0;
|
||||
|
||||
switch(ur->custom) {
|
||||
// -
|
||||
case 1:
|
||||
total = base_value - value;
|
||||
break;
|
||||
// *
|
||||
case 2:
|
||||
total = base_value * value;
|
||||
break;
|
||||
// /
|
||||
case 3:
|
||||
if (value == 0) total = 0;
|
||||
else {
|
||||
total = base_value/value;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
total = base_value + value;
|
||||
break;
|
||||
}
|
||||
|
||||
int ret = uwsgi_long2str2n(total, out, sizeof(UMAX64_STR)+1);
|
||||
if (ret <= 0) return UWSGI_ROUTE_BREAK;
|
||||
|
||||
if (!uwsgi_req_append(wsgi_req, ur->data, ur->data_len, out, ret)) {
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
static int uwsgi_router_simple_math_plus(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_simple_math_func;
|
||||
char *comma = strchr(arg, ',');
|
||||
if (comma) {
|
||||
ur->data = arg;
|
||||
ur->data_len = comma - arg;
|
||||
ur->data2 = comma+1;
|
||||
ur->data2_len = strlen(ur->data);
|
||||
}
|
||||
else {
|
||||
ur->data = arg;
|
||||
ur->data_len = strlen(arg);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_router_simple_math_minus(struct uwsgi_route *ur, char *arg) {
|
||||
ur->custom = 1;
|
||||
return uwsgi_router_simple_math_plus(ur, arg);
|
||||
}
|
||||
|
||||
static int uwsgi_router_simple_math_multiply(struct uwsgi_route *ur, char *arg) {
|
||||
ur->custom = 2;
|
||||
return uwsgi_router_simple_math_plus(ur, arg);
|
||||
}
|
||||
|
||||
static int uwsgi_router_simple_math_divide(struct uwsgi_route *ur, char *arg) {
|
||||
ur->custom = 2;
|
||||
return uwsgi_router_simple_math_plus(ur, arg);
|
||||
}
|
||||
|
||||
// harakiri router
|
||||
static int uwsgi_router_harakiri_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
|
||||
@@ -640,7 +722,6 @@ static int uwsgi_router_fixcl(struct uwsgi_route *ur, char *arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// log route
|
||||
static int uwsgi_router_log_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
|
||||
@@ -1199,10 +1280,21 @@ static int uwsgi_router_alarm(struct uwsgi_route *ur, char *arg) {
|
||||
|
||||
// send route
|
||||
static int uwsgi_router_send_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
|
||||
uwsgi_response_write_body_do(wsgi_req, route->data, route->data_len);
|
||||
char **subject = (char **) (((char *)(wsgi_req))+route->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+route->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, route, *subject, *subject_len, route->data, route->data_len);
|
||||
if (!ub) {
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
if (route->custom) {
|
||||
uwsgi_response_write_body_do(wsgi_req, "\r\n", 2);
|
||||
if (uwsgi_buffer_append(ub, "\r\n", 2)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
}
|
||||
uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
static int uwsgi_router_send(struct uwsgi_route *ur, char *arg) {
|
||||
@@ -1629,48 +1721,6 @@ static char *uwsgi_route_var_hex(struct wsgi_request *wsgi_req, char *key, uint1
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_MATHEVAL
|
||||
static char *uwsgi_route_var_math(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
|
||||
char *ret = NULL;
|
||||
// avoid crash
|
||||
if (!wsgi_req->var_cnt) return NULL;
|
||||
// we make a bit of fun here, we do a copy of the vars buffer (+1 byte for final zero) and zeor-pad all of the strings
|
||||
char *vars_buf = uwsgi_malloc(wsgi_req->uh->pktsize + keylen + 1);
|
||||
char **names = uwsgi_malloc(sizeof(char *) * (wsgi_req->var_cnt/2));
|
||||
double *values = uwsgi_calloc(sizeof(double) * (wsgi_req->var_cnt/2));
|
||||
int i,j = 0;
|
||||
char *ptr = vars_buf;
|
||||
for (i = wsgi_req->var_cnt-1; i > 0; i -= 2) {
|
||||
memcpy(ptr, wsgi_req->hvec[i-1].iov_base, wsgi_req->hvec[i-1].iov_len);
|
||||
names[j] = ptr;
|
||||
ptr += wsgi_req->hvec[i-1].iov_len;
|
||||
*ptr++=0;
|
||||
char *num = ptr;
|
||||
memcpy(ptr, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len);
|
||||
ptr += wsgi_req->hvec[i].iov_len;
|
||||
*ptr++=0;
|
||||
values[j] = strtod(num, NULL);
|
||||
j++;
|
||||
}
|
||||
|
||||
char *expr = ptr;
|
||||
memcpy(ptr, key, keylen); ptr += keylen;
|
||||
*ptr++=0;
|
||||
|
||||
void *e = evaluator_create(expr);
|
||||
if (!e) goto end;
|
||||
double n = evaluator_evaluate(e, j, names, values);
|
||||
evaluator_destroy(e);
|
||||
ret = uwsgi_num2str((int)n);
|
||||
*vallen = strlen(ret);
|
||||
end:
|
||||
free(vars_buf);
|
||||
free(names);
|
||||
free(values);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
// register embedded routers
|
||||
void uwsgi_register_embedded_routers() {
|
||||
uwsgi_register_router("continue", uwsgi_router_continue);
|
||||
@@ -1703,6 +1753,11 @@ void uwsgi_register_embedded_routers() {
|
||||
uwsgi_register_router("setprocname", uwsgi_router_setprocname);
|
||||
uwsgi_register_router("alarm", uwsgi_router_alarm);
|
||||
|
||||
uwsgi_register_router("+", uwsgi_router_simple_math_plus);
|
||||
uwsgi_register_router("-", uwsgi_router_simple_math_minus);
|
||||
uwsgi_register_router("*", uwsgi_router_simple_math_multiply);
|
||||
uwsgi_register_router("/", uwsgi_router_simple_math_divide);
|
||||
|
||||
uwsgi_register_router("flush", uwsgi_router_flush);
|
||||
uwsgi_register_router("fixcl", uwsgi_router_fixcl);
|
||||
|
||||
@@ -1746,10 +1801,6 @@ void uwsgi_register_embedded_routers() {
|
||||
urv->need_free = 1;
|
||||
urv = uwsgi_register_route_var("httptime", uwsgi_route_var_httptime);
|
||||
urv->need_free = 1;
|
||||
#ifdef UWSGI_MATHEVAL
|
||||
urv = uwsgi_register_route_var("math", uwsgi_route_var_math);
|
||||
urv->need_free = 1;
|
||||
#endif
|
||||
urv = uwsgi_register_route_var("base64", uwsgi_route_var_base64);
|
||||
urv->need_free = 1;
|
||||
|
||||
|
||||
+36
-8
@@ -59,11 +59,11 @@ already:
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t uwsgi_rpc(char *name, uint8_t argc, char *argv[], uint16_t argvs[], char *output) {
|
||||
uint64_t uwsgi_rpc(char *name, uint8_t argc, char *argv[], uint16_t argvs[], char **output) {
|
||||
|
||||
struct uwsgi_rpc *urpc = NULL;
|
||||
uint64_t i;
|
||||
uint16_t ret = 0;
|
||||
uint64_t ret = 0;
|
||||
|
||||
int pos = (uwsgi.mywid * uwsgi.rpc_max);
|
||||
|
||||
@@ -85,8 +85,15 @@ uint16_t uwsgi_rpc(char *name, uint8_t argc, char *argv[], uint16_t argvs[], cha
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rpc_context_hook(char *key, uint16_t kl, char *value, uint16_t vl, void *data) {
|
||||
size_t *r = (size_t *) data;
|
||||
|
||||
char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t argvs[], uint16_t * len) {
|
||||
if (!uwsgi_strncmp(key, kl, "CONTENT_LENGTH", 14)) {
|
||||
*r = uwsgi_str_num(value, vl);
|
||||
}
|
||||
}
|
||||
|
||||
char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t argvs[], uint64_t * len) {
|
||||
|
||||
uint8_t i;
|
||||
uint16_t ulen;
|
||||
@@ -97,9 +104,10 @@ char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t
|
||||
|
||||
if (node == NULL || !strcmp(node, "")) {
|
||||
// allocate the whole buffer
|
||||
buffer = uwsgi_malloc(UMAX16);
|
||||
*len = uwsgi_rpc(func, argc, argv, argvs, buffer);
|
||||
return buffer;
|
||||
*len = uwsgi_rpc(func, argc, argv, argvs, &buffer);
|
||||
if (*buffer)
|
||||
return buffer;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -147,17 +155,37 @@ char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t
|
||||
bufptr += ulen;
|
||||
}
|
||||
|
||||
// ok the reuqest is ready, let's send it in non blocking way
|
||||
// ok the request is ready, let's send it in non blocking way
|
||||
if (uwsgi_write_true_nb(fd, buffer, buffer_size+4, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// ok time to wait for the response in non blocking way
|
||||
size_t rlen = buffer_size+4;
|
||||
if (uwsgi_read_with_realloc(fd, &buffer, &rlen, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
|
||||
uint8_t modifier2 = 0;
|
||||
if (uwsgi_read_with_realloc(fd, &buffer, &rlen, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], NULL, &modifier2)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// 64bit response ?
|
||||
if (modifier2 == 5) {
|
||||
size_t content_len = 0;
|
||||
if (uwsgi_hooked_parse(buffer, rlen, rpc_context_hook, &content_len )) goto error;
|
||||
|
||||
if (content_len > rlen) {
|
||||
char *tmp_buf = realloc(buffer, content_len);
|
||||
if (!tmp_buf) goto error;
|
||||
buffer = tmp_buf;
|
||||
}
|
||||
|
||||
rlen = content_len;
|
||||
|
||||
// read the raw value from the socket
|
||||
if (uwsgi_read_whole_true_nb(fd, buffer, rlen, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
*len = rlen;
|
||||
if (*len == 0) {
|
||||
|
||||
@@ -301,8 +301,10 @@ int uwsgi_signal_send(int fd, uint8_t sig) {
|
||||
else {
|
||||
uwsgi_error("uwsgi_signal_send()");
|
||||
}
|
||||
uwsgi.shared->unrouted_signals++;
|
||||
return -1;
|
||||
}
|
||||
uwsgi.shared->routed_signals++;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
+55
-14
@@ -23,6 +23,7 @@ static uint64_t get_uwsgi_custom_snmp_value(uint64_t, uint8_t *);
|
||||
static uint8_t snmp_int_to_snmp(uint64_t, uint8_t, uint8_t *);
|
||||
|
||||
static ssize_t build_snmp_response(uint8_t, uint8_t, uint8_t *, int, uint8_t *, uint8_t *, uint8_t *);
|
||||
static ssize_t build_snmp_metric_response(int64_t, uint8_t, uint8_t *, int, uint8_t *, uint8_t *, uint8_t *);
|
||||
|
||||
void manage_snmp(int fd, uint8_t * buffer, int size, struct sockaddr_in *client_addr) {
|
||||
|
||||
@@ -71,7 +72,7 @@ void manage_snmp(int fd, uint8_t * buffer, int size, struct sockaddr_in *client_
|
||||
uwsgi_debug("SNMP version: %d\n", version);
|
||||
#endif
|
||||
|
||||
// check for community string (this must be set from the python vm using uwsgi.snmp_community or with --snmp-community arg)
|
||||
// check for community string (this must be set from the api using uwsgi.snmp_community or with --snmp-community arg)
|
||||
if (*ptr != SNMP_STRING)
|
||||
return;
|
||||
ptr++;
|
||||
@@ -196,7 +197,7 @@ void manage_snmp(int fd, uint8_t * buffer, int size, struct sockaddr_in *client_
|
||||
ptr++;
|
||||
|
||||
oidlen = *ptr;
|
||||
if (oidlen != 11)
|
||||
if (oidlen < 11)
|
||||
return;
|
||||
ptr++;
|
||||
|
||||
@@ -208,21 +209,33 @@ void manage_snmp(int fd, uint8_t * buffer, int size, struct sockaddr_in *client_
|
||||
|
||||
oid_part[0] = *ptr;
|
||||
|
||||
if (oid_part[0] != 1 && oid_part[0] != 2)
|
||||
return;
|
||||
ptr++;
|
||||
// old-style SNMP metrics
|
||||
if (oid_part[0] == 1 || oid_part[0] == 2) {
|
||||
ptr++;
|
||||
|
||||
oid_part[1] = *ptr;
|
||||
if (oid_part[1] < 1 || oid_part[1] > 100)
|
||||
return;
|
||||
ptr++;
|
||||
oid_part[1] = *ptr;
|
||||
if (oid_part[1] < 1 || oid_part[1] > 100)
|
||||
return;
|
||||
ptr++;
|
||||
|
||||
// check for null
|
||||
if (memcmp((char *) ptr, "\x05\x00", 2))
|
||||
return;
|
||||
ptr += 2;
|
||||
// check for null
|
||||
if (memcmp((char *) ptr, "\x05\x00", 2))
|
||||
return;
|
||||
ptr += 2;
|
||||
size = build_snmp_response(oid_part[0], oid_part[1], buffer, size, seq1, seq2, seq3);
|
||||
}
|
||||
// metrics subsystem
|
||||
else {
|
||||
size_t metric_asn_len = oidlen - 9;
|
||||
char *metric_asn = (char *) ptr;
|
||||
struct uwsgi_metric *um = uwsgi_metric_find_by_asn(metric_asn, metric_asn_len);
|
||||
if (!um) return;
|
||||
uwsgi_rlock(uwsgi.metrics_lock);
|
||||
int64_t value = *um->value;
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
size = build_snmp_metric_response(value, um->type, buffer, size, seq1, seq2, seq3);
|
||||
}
|
||||
|
||||
size = build_snmp_response(oid_part[0], oid_part[1], buffer, size, seq1, seq2, seq3);
|
||||
|
||||
if (size > 0) {
|
||||
if (sendto(fd, buffer, size, 0, (struct sockaddr *) client_addr, sizeof(struct sockaddr_in)) < 0) {
|
||||
@@ -292,6 +305,7 @@ static uint8_t snmp_int_to_snmp(uint64_t snmp_val, uint8_t oid_type, uint8_t * b
|
||||
uint8_t tlen;
|
||||
int i, j;
|
||||
uint8_t *ptr = (uint8_t *) & snmp_val;
|
||||
int32_t val32 = (int32_t) snmp_val;
|
||||
|
||||
// check for counter, counter64 or gauge
|
||||
|
||||
@@ -303,6 +317,7 @@ static uint8_t snmp_int_to_snmp(uint64_t snmp_val, uint8_t oid_type, uint8_t * b
|
||||
}
|
||||
else {
|
||||
tlen = 4;
|
||||
ptr = (uint8_t *) &val32;
|
||||
}
|
||||
|
||||
buffer[0] = tlen;
|
||||
@@ -352,6 +367,32 @@ static ssize_t build_snmp_response(uint8_t oid1, uint8_t oid2, uint8_t * buffer,
|
||||
|
||||
}
|
||||
|
||||
static ssize_t build_snmp_metric_response(int64_t value, uint8_t type, uint8_t * buffer, int size, uint8_t * seq1, uint8_t * seq2, uint8_t * seq3) {
|
||||
uint8_t oid_sz;
|
||||
|
||||
if (type == UWSGI_METRIC_GAUGE) {
|
||||
buffer[size - 2] = SNMP_GAUGE;
|
||||
oid_sz = snmp_int_to_snmp(value, SNMP_GAUGE, buffer + (size - 1));
|
||||
}
|
||||
else {
|
||||
buffer[size - 2] = SNMP_COUNTER64;
|
||||
oid_sz = snmp_int_to_snmp(value, SNMP_COUNTER64, buffer + (size - 1));
|
||||
}
|
||||
|
||||
if (oid_sz < 1)
|
||||
return -1;
|
||||
|
||||
oid_sz--;
|
||||
|
||||
buffer[1] += oid_sz;
|
||||
*seq1 += oid_sz;
|
||||
*seq2 += oid_sz;
|
||||
*seq3 += oid_sz;
|
||||
|
||||
return size + oid_sz;
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_opt_snmp(char *opt, char *value, void *foobar) {
|
||||
uwsgi.snmp = 1;
|
||||
if (value) {
|
||||
|
||||
+58
-104
@@ -6,6 +6,22 @@ static int connect_to_unix(char *, int, int);
|
||||
static int connect_to_tcp(char *, int, int, int);
|
||||
static int connect_to_udp(char *, int);
|
||||
|
||||
void uwsgi_socket_setup_protocol(struct uwsgi_socket *uwsgi_sock, char *protocol) {
|
||||
if (!protocol) protocol = "uwsgi";
|
||||
struct uwsgi_protocol *up = uwsgi.protocols;
|
||||
while(up) {
|
||||
if (!strcmp(protocol, up->name)) {
|
||||
up->func(uwsgi_sock);
|
||||
return;
|
||||
}
|
||||
up = up->next;
|
||||
}
|
||||
|
||||
uwsgi_log("unable to find protocol %s\n", protocol);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_socket_strcmp(char *sock1, char *sock2) {
|
||||
size_t sock1_len = strlen(sock1);
|
||||
size_t sock2_len = strlen(sock2);
|
||||
@@ -1366,7 +1382,7 @@ void uwsgi_add_sockets_to_queue(int queue, int async_id) {
|
||||
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
while (uwsgi_sock) {
|
||||
if (uwsgi_sock->fd_threads && async_id > -1) {
|
||||
if (uwsgi_sock->fd_threads && async_id > -1 && uwsgi_sock->fd_threads[async_id] > -1) {
|
||||
event_queue_add_fd_read(queue, uwsgi_sock->fd_threads[async_id]);
|
||||
}
|
||||
else if (uwsgi_sock->fd > -1) {
|
||||
@@ -1853,109 +1869,8 @@ void uwsgi_set_sockets_protocols() {
|
||||
|
||||
|
||||
setup_proto:
|
||||
if (!requested_protocol) {
|
||||
requested_protocol = uwsgi.protocol;
|
||||
}
|
||||
|
||||
if (requested_protocol && !strcmp("http", requested_protocol)) {
|
||||
uwsgi_sock->proto = uwsgi_proto_http_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_base_close;
|
||||
if (uwsgi.offload_threads > 0)
|
||||
uwsgi_sock->can_offload = 1;
|
||||
}
|
||||
else if (requested_protocol && !strcmp("raw", requested_protocol)) {
|
||||
uwsgi_sock->proto = uwsgi_proto_raw_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_base_close;
|
||||
if (uwsgi.offload_threads > 0)
|
||||
uwsgi_sock->can_offload = 1;
|
||||
}
|
||||
else if (requested_protocol && (!strcmp("fastcgi", requested_protocol) || !strcmp("fcgi", requested_protocol))) {
|
||||
uwsgi_sock->proto = uwsgi_proto_fastcgi_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_cgi_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_fastcgi_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_fastcgi_close;
|
||||
}
|
||||
else if (requested_protocol && (!strcmp("fastcgi-nph", requested_protocol) || !strcmp("fcgi-nph", requested_protocol))) {
|
||||
uwsgi_sock->proto = uwsgi_proto_fastcgi_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_fastcgi_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_fastcgi_close;
|
||||
}
|
||||
|
||||
else if (requested_protocol && (!strcmp("scgi", requested_protocol) || !strcmp("scgi", requested_protocol))) {
|
||||
uwsgi_sock->proto = uwsgi_proto_scgi_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_cgi_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_base_close;
|
||||
}
|
||||
|
||||
else if (requested_protocol && (!strcmp("scgi-nph", requested_protocol) || !strcmp("scgi-nph", requested_protocol))) {
|
||||
uwsgi_sock->proto = uwsgi_proto_scgi_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_base_close;
|
||||
}
|
||||
|
||||
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
else if (requested_protocol && !strcmp("zmq", requested_protocol)) {
|
||||
uwsgi.zeromq = 1;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
uwsgi_sock->proto = uwsgi_proto_uwsgi_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_base_close;
|
||||
if (uwsgi.offload_threads > 0)
|
||||
uwsgi_sock->can_offload = 1;
|
||||
}
|
||||
if (!requested_protocol) requested_protocol = uwsgi.protocol;
|
||||
uwsgi_socket_setup_protocol(uwsgi_sock, requested_protocol);
|
||||
nextsock:
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
@@ -1991,3 +1906,42 @@ int uwsgi_accept(int server_fd) {
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_protocol *uwsgi_register_protocol(char *name, void (*func)(struct uwsgi_socket *)) {
|
||||
struct uwsgi_protocol *old_up = NULL, *up = uwsgi.protocols;
|
||||
while(up) {
|
||||
if (!strcmp(name, up->name)) {
|
||||
goto found;
|
||||
}
|
||||
old_up = up;
|
||||
up = up->next;
|
||||
}
|
||||
up = uwsgi_calloc(sizeof(struct uwsgi_protocol));
|
||||
up->name = name;
|
||||
if (old_up) {
|
||||
old_up->next = up;
|
||||
}
|
||||
else {
|
||||
uwsgi.protocols = up;
|
||||
}
|
||||
found:
|
||||
up->func = func;
|
||||
return up;
|
||||
}
|
||||
|
||||
void uwsgi_protocols_register() {
|
||||
uwsgi_register_protocol("uwsgi", uwsgi_proto_uwsgi_setup);
|
||||
uwsgi_register_protocol("puwsgi", uwsgi_proto_puwsgi_setup);
|
||||
uwsgi_register_protocol("http", uwsgi_proto_http_setup);
|
||||
#ifdef UWSGI_SSL
|
||||
uwsgi_register_protocol("suwsgi", uwsgi_proto_suwsgi_setup);
|
||||
uwsgi_register_protocol("https", uwsgi_proto_https_setup);
|
||||
#endif
|
||||
uwsgi_register_protocol("fastcgi", uwsgi_proto_fastcgi_setup);
|
||||
uwsgi_register_protocol("fastcgi-nph", uwsgi_proto_fastcgi_nph_setup);
|
||||
uwsgi_register_protocol("scgi", uwsgi_proto_scgi_setup);
|
||||
uwsgi_register_protocol("scgi-nph", uwsgi_proto_scgi_nph_setup);
|
||||
#ifdef UWSGI_ZEROMQ
|
||||
uwsgi_register_protocol("zmq", uwsgi_proto_zmq_setup);
|
||||
#endif
|
||||
uwsgi_register_protocol("raw", uwsgi_proto_raw_setup);
|
||||
}
|
||||
|
||||
+18
-45
@@ -440,6 +440,11 @@ void uwsgi_stats_pusher_loop(struct uwsgi_thread *ut) {
|
||||
void *events = event_queue_alloc(1);
|
||||
for (;;) {
|
||||
int nevents = event_queue_wait_multi(ut->queue, 1, events, 1);
|
||||
if (nevents < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
uwsgi_log_verbose("ending the stats pusher thread...\n");
|
||||
return;
|
||||
}
|
||||
if (nevents > 0) {
|
||||
int interesting_fd = event_queue_interesting_fd(events, 0);
|
||||
char buf[4096];
|
||||
@@ -457,7 +462,8 @@ void uwsgi_stats_pusher_loop(struct uwsgi_thread *ut) {
|
||||
struct uwsgi_stats *us = NULL;
|
||||
while (uspi) {
|
||||
int delta = uspi->freq ? uspi->freq : uwsgi.stats_pusher_default_freq;
|
||||
if ((uspi->last_run + delta) <= now) {
|
||||
if (((uspi->last_run + delta) <= now) || (uspi->needs_retry && (uspi->next_retry <= now))) {
|
||||
if (uspi->needs_retry) uspi->retries++;
|
||||
if (uspi->raw) {
|
||||
uspi->pusher->func(uspi, now, NULL, 0);
|
||||
}
|
||||
@@ -470,6 +476,17 @@ void uwsgi_stats_pusher_loop(struct uwsgi_thread *ut) {
|
||||
uspi->pusher->func(uspi, now, us->base, us->pos);
|
||||
}
|
||||
uspi->last_run = now;
|
||||
if (uspi->needs_retry && uspi->max_retries > 0 && uspi->retries < uspi->max_retries) {
|
||||
uwsgi_log("[uwsgi-stats-pusher] %s failed (%d), retry in %ds\n", uspi->pusher->name, uspi->retries, uspi->retry_delay);
|
||||
uspi->next_retry = now + uspi->retry_delay;
|
||||
} else if (uspi->needs_retry && uspi->retries >= uspi->max_retries) {
|
||||
uwsgi_log("[uwsgi-stats-pusher] %s failed and maximum number of retries was reached (%d)\n", uspi->pusher->name, uspi->retries);
|
||||
uspi->needs_retry = 0;
|
||||
uspi->retries = 0;
|
||||
} else if (uspi->retries) {
|
||||
uwsgi_log("[uwsgi-stats-pusher] retry succeeded for %s\n", uspi->pusher->name);
|
||||
uspi->retries = 0;
|
||||
}
|
||||
}
|
||||
next:
|
||||
uspi = uspi->next;
|
||||
@@ -531,50 +548,6 @@ struct uwsgi_stats_pusher *uwsgi_register_stats_pusher(char *name, void (*func)
|
||||
return pusher;
|
||||
}
|
||||
|
||||
struct uwsgi_stats_pusher_file_conf {
|
||||
char *path;
|
||||
char *freq;
|
||||
char *separator;
|
||||
};
|
||||
|
||||
void uwsgi_stats_pusher_file(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) {
|
||||
struct uwsgi_stats_pusher_file_conf *uspic = (struct uwsgi_stats_pusher_file_conf *) uspi->data;
|
||||
if (!uspi->configured) {
|
||||
uspic = uwsgi_calloc(sizeof(struct uwsgi_stats_pusher_file_conf));
|
||||
if (uspi->arg) {
|
||||
if (uwsgi_kvlist_parse(uspi->arg, strlen(uspi->arg), ',', '=', "path", &uspic->path, "separator", &uspic->separator, "freq", &uspic->freq, NULL)) {
|
||||
free(uspi);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!uspic->path)
|
||||
uspic->path = "uwsgi.stats";
|
||||
if (!uspic->separator)
|
||||
uspic->separator = "\n\n";
|
||||
if (uspic->freq)
|
||||
uspi->freq = atoi(uspic->freq);
|
||||
uspi->configured = 1;
|
||||
uspi->data = uspic;
|
||||
}
|
||||
|
||||
int fd = open(uspic->path, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP);
|
||||
if (fd < 0) {
|
||||
uwsgi_error_open(uspic->path);
|
||||
return;
|
||||
}
|
||||
ssize_t rlen = write(fd, json, json_len);
|
||||
if (rlen != (ssize_t) json_len) {
|
||||
uwsgi_error("uwsgi_stats_pusher_file() -> write()\n");
|
||||
}
|
||||
|
||||
rlen = write(fd, uspic->separator, strlen(uspic->separator));
|
||||
if (rlen != (ssize_t) strlen(uspic->separator)) {
|
||||
uwsgi_error("uwsgi_stats_pusher_file() -> write()\n");
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void stats_dump_var(char *k, uint16_t kl, char *v, uint16_t vl, void *data) {
|
||||
struct uwsgi_stats *us = (struct uwsgi_stats *) data;
|
||||
if (us->dirty) return;
|
||||
|
||||
+203
-109
@@ -2,7 +2,6 @@
|
||||
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
extern char **environ;
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
uint16_t uwsgi_swap16(uint16_t x) {
|
||||
@@ -207,17 +206,19 @@ void uwsgi_set_cgroup() {
|
||||
if (!uwsgi.cgroup)
|
||||
return;
|
||||
|
||||
if (getuid()) return;
|
||||
|
||||
usl = uwsgi.cgroup;
|
||||
|
||||
while (usl) {
|
||||
int mode = strtol(uwsgi.cgroup_dir_mode, 0, 8);
|
||||
if (mkdir(usl->value, mode)) {
|
||||
if (errno != EEXIST) {
|
||||
uwsgi_error("mkdir()");
|
||||
uwsgi_error("uwsgi_set_cgroup()/mkdir()");
|
||||
exit(1);
|
||||
}
|
||||
if (chmod(usl->value, mode)) {
|
||||
uwsgi_error("chmod()");
|
||||
uwsgi_error("uwsgi_set_cgroup()/chmod()");
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_log("using Linux cgroup %s with mode %o\n", usl->value, mode);
|
||||
@@ -725,7 +726,7 @@ void uwsgi_as_root() {
|
||||
|
||||
uwsgi_foreach(usl, uwsgi.call_as_root) {
|
||||
if (uwsgi_call_symbol(usl->value)) {
|
||||
uwsgi_log("unaable to call function \"%s\"\n", usl->value);
|
||||
uwsgi_log("unable to call function \"%s\"\n", usl->value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -943,7 +944,7 @@ void uwsgi_as_root() {
|
||||
|
||||
uwsgi_foreach(usl, uwsgi.call_as_user) {
|
||||
if (uwsgi_call_symbol(usl->value)) {
|
||||
uwsgi_log("unaable to call function \"%s\"\n", usl->value);
|
||||
uwsgi_log("unable to call function \"%s\"\n", usl->value);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@@ -1221,7 +1222,7 @@ void uwsgi_linux_ksm_map(void) {
|
||||
}
|
||||
|
||||
// we now have areas
|
||||
if (uwsgi.ksm_mappings_last_size == 0 || uwsgi.ksm_mappings_current_size == 0 || uwsgi.ksm_mappings_current_size != uwsgi.ksm_mappings_last_size) {
|
||||
if (uwsgi.ksm_mappings_last_size == 0 || uwsgi.ksm_mappings_current_size != uwsgi.ksm_mappings_last_size) {
|
||||
dirty = 1;
|
||||
}
|
||||
else {
|
||||
@@ -1289,7 +1290,7 @@ long uwsgi_num_from_file(char *filename, int quiet) {
|
||||
// setup for a new request
|
||||
void wsgi_req_setup(struct wsgi_request *wsgi_req, int async_id, struct uwsgi_socket *uwsgi_sock) {
|
||||
|
||||
wsgi_req->app_id = uwsgi.default_app;
|
||||
wsgi_req->app_id = -1;
|
||||
|
||||
wsgi_req->async_id = async_id;
|
||||
wsgi_req->sendfile_fd = -1;
|
||||
@@ -1549,14 +1550,14 @@ void parse_sys_envs(char **envs) {
|
||||
|
||||
while (*uenvs) {
|
||||
if (!strncmp(*uenvs, "UWSGI_", 6) &&
|
||||
strncmp(*uenvs, "UWSGI_RELOADS=", 14) &&
|
||||
strncmp(*uenvs, "UWSGI_VASSALS_DIR=", 18) &&
|
||||
strncmp(*uenvs, "UWSGI_EMPEROR_FD=", 17) &&
|
||||
strncmp(*uenvs, "UWSGI_BROODLORD_NUM=", 20) &&
|
||||
strncmp(*uenvs, "UWSGI_EMPEROR_FD_CONFIG=", 24) &&
|
||||
strncmp(*uenvs, "UWSGI_EMPEROR_PROXY=", 20) &&
|
||||
strncmp(*uenvs, "UWSGI_JAIL_PID=", 15) &&
|
||||
strncmp(*uenvs, "UWSGI_ORIGINAL_PROC_NAME=", 25)) {
|
||||
strncmp(*uenvs, "UWSGI_RELOADS=", 14) &&
|
||||
strncmp(*uenvs, "UWSGI_VASSALS_DIR=", 18) &&
|
||||
strncmp(*uenvs, "UWSGI_EMPEROR_FD=", 17) &&
|
||||
strncmp(*uenvs, "UWSGI_BROODLORD_NUM=", 20) &&
|
||||
strncmp(*uenvs, "UWSGI_EMPEROR_FD_CONFIG=", 24) &&
|
||||
strncmp(*uenvs, "UWSGI_EMPEROR_PROXY=", 20) &&
|
||||
strncmp(*uenvs, "UWSGI_JAIL_PID=", 15) &&
|
||||
strncmp(*uenvs, "UWSGI_ORIGINAL_PROC_NAME=", 25)) {
|
||||
earg = uwsgi_malloc(strlen(*uenvs + 6) + 1);
|
||||
env_to_arg(*uenvs + 6, earg);
|
||||
eq_pos = strchr(earg, '=');
|
||||
@@ -1900,33 +1901,6 @@ void uwsgi_unix_signal(int signum, void (*func) (int)) {
|
||||
}
|
||||
}
|
||||
|
||||
char *uwsgi_get_exported_opt(char *key) {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
|
||||
if (!strcmp(uwsgi.exported_opts[i]->key, key)) {
|
||||
return uwsgi.exported_opts[i]->value;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *uwsgi_get_optname_by_index(int index) {
|
||||
|
||||
struct uwsgi_option *op = uwsgi.options;
|
||||
|
||||
while (op->name) {
|
||||
if (op->shortcut == index) {
|
||||
return op->name;
|
||||
}
|
||||
op++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int uwsgi_list_has_num(char *list, int num) {
|
||||
|
||||
char *list2 = uwsgi_concat2(list, "");
|
||||
@@ -3166,47 +3140,171 @@ void escape_json(char *src, size_t len, char *dst) {
|
||||
*ptr++ = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
build PATH_INFO from raw_uri
|
||||
|
||||
it manages:
|
||||
|
||||
percent encoding
|
||||
dot_segments removal
|
||||
stop at the first #
|
||||
|
||||
*/
|
||||
void http_url_decode(char *buf, uint16_t * len, char *dst) {
|
||||
|
||||
uint16_t i;
|
||||
int percent = 0;
|
||||
enum {
|
||||
zero = 0,
|
||||
percent1,
|
||||
percent2,
|
||||
slash,
|
||||
dot,
|
||||
dotdot
|
||||
} status;
|
||||
|
||||
uint16_t i, current_new_len, new_len = 0;
|
||||
|
||||
char value[2];
|
||||
size_t new_len = 0;
|
||||
|
||||
char *ptr = dst;
|
||||
|
||||
value[0] = '0';
|
||||
value[1] = '0';
|
||||
|
||||
status = zero;
|
||||
int no_slash = 0;
|
||||
|
||||
if (*len > 0 && buf[0] != '/') {
|
||||
status = slash;
|
||||
no_slash = 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < *len; i++) {
|
||||
if (buf[i] == '%') {
|
||||
if (percent == 0) {
|
||||
percent = 1;
|
||||
}
|
||||
else {
|
||||
*ptr++ = '%';
|
||||
char c = buf[i];
|
||||
if (c == '#') break;
|
||||
switch(status) {
|
||||
case zero:
|
||||
if (c == '%') {
|
||||
status = percent1;
|
||||
break;
|
||||
}
|
||||
if (c == '/') {
|
||||
status = slash;
|
||||
break;
|
||||
}
|
||||
*ptr++ = c;
|
||||
new_len++;
|
||||
percent = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (percent == 1) {
|
||||
value[0] = buf[i];
|
||||
percent = 2;
|
||||
}
|
||||
else if (percent == 2) {
|
||||
value[1] = buf[i];
|
||||
break;
|
||||
case percent1:
|
||||
if (c == '%') {
|
||||
*ptr++ = '%';
|
||||
new_len++;
|
||||
status = zero;
|
||||
break;
|
||||
}
|
||||
value[0] = c;
|
||||
status = percent2;
|
||||
break;
|
||||
case percent2:
|
||||
value[1] = c;
|
||||
*ptr++ = hex2num(value);
|
||||
percent = 0;
|
||||
new_len++;
|
||||
}
|
||||
else {
|
||||
*ptr++ = buf[i];
|
||||
new_len++;
|
||||
}
|
||||
status = zero;
|
||||
break;
|
||||
case slash:
|
||||
if (c == '.') {
|
||||
status = dot;
|
||||
break;
|
||||
}
|
||||
// we could be at the first round (in non slash)
|
||||
if (i > 0 || !no_slash) {
|
||||
*ptr++ = '/'; new_len++;
|
||||
}
|
||||
if (c == '%') {
|
||||
status = percent1;
|
||||
break;
|
||||
}
|
||||
if (c == '/') {
|
||||
status = slash;
|
||||
break;
|
||||
}
|
||||
*ptr++ = c; new_len++;
|
||||
status = zero;
|
||||
break;
|
||||
case dot:
|
||||
if (c == '.') {
|
||||
status = dotdot;
|
||||
break;
|
||||
}
|
||||
if (c == '/') {
|
||||
status = slash;
|
||||
break;
|
||||
}
|
||||
if (i > 1) {
|
||||
*ptr++ = '/'; new_len++;
|
||||
}
|
||||
*ptr++ = '.'; new_len++;
|
||||
if (c == '%') {
|
||||
status = percent1;
|
||||
break;
|
||||
}
|
||||
*ptr++ = c; new_len++;
|
||||
status = zero;
|
||||
break;
|
||||
case dotdot:
|
||||
// here we need to remove a segment
|
||||
if (c == '/') {
|
||||
current_new_len = new_len;
|
||||
while(current_new_len) {
|
||||
current_new_len--;
|
||||
ptr--;
|
||||
if (dst[current_new_len] == '/') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
new_len = current_new_len;
|
||||
status = slash;
|
||||
break;
|
||||
}
|
||||
if (i > 2) {
|
||||
*ptr++ = '/'; new_len++;
|
||||
}
|
||||
*ptr++ = '.'; new_len++;
|
||||
*ptr++ = '.'; new_len++;
|
||||
if (c == '%') {
|
||||
status = percent1;
|
||||
break;
|
||||
}
|
||||
*ptr++ = c; new_len++;
|
||||
status = zero;
|
||||
break;
|
||||
// over engineering
|
||||
default:
|
||||
*ptr++ = c;
|
||||
new_len++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch(status) {
|
||||
case slash:
|
||||
case dot:
|
||||
*ptr++ = '/'; new_len++;
|
||||
break;
|
||||
case dotdot:
|
||||
current_new_len = new_len;
|
||||
while(current_new_len) {
|
||||
if (dst[current_new_len-1] == '/') {
|
||||
break;
|
||||
}
|
||||
current_new_len--;
|
||||
}
|
||||
new_len = current_new_len;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
*len = new_len;
|
||||
|
||||
}
|
||||
@@ -3255,8 +3353,10 @@ struct uwsgi_app *uwsgi_add_app(int id, uint8_t modifier1, char *mountpoint, int
|
||||
}
|
||||
}
|
||||
|
||||
if ((mountpoint_len == 0 || (mountpoint_len = -1 && mountpoint[0] == '/')) && uwsgi.default_app == -1) {
|
||||
uwsgi.default_app = id;
|
||||
if (!uwsgi.no_default_app) {
|
||||
if ((mountpoint_len == 0 || (mountpoint_len = -1 && mountpoint[0] == '/')) && uwsgi.default_app == -1) {
|
||||
uwsgi.default_app = id;
|
||||
}
|
||||
}
|
||||
|
||||
return wi;
|
||||
@@ -3418,7 +3518,11 @@ int uwsgi_write_intfile(char *filename, int n) {
|
||||
uwsgi_error_open(filename);
|
||||
exit(1);
|
||||
}
|
||||
if (fprintf(pidfile, "%d\n", n) <= 0 || ferror(pidfile) || fclose(pidfile)) {
|
||||
if (fprintf(pidfile, "%d\n", n) <= 0 || ferror(pidfile)) {
|
||||
fclose(pidfile);
|
||||
return -1;
|
||||
}
|
||||
if (fclose(pidfile)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -3650,26 +3754,6 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// evaluate a math expression
|
||||
#ifdef UWSGI_MATHEVAL
|
||||
double uwsgi_matheval(char *expr) {
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("matheval expr = %s\n", expr);
|
||||
#endif
|
||||
double ret = 0.0;
|
||||
void *e = evaluator_create(expr);
|
||||
if (!e)
|
||||
return ret;
|
||||
ret = evaluator_evaluate(e, 0, NULL, NULL);
|
||||
evaluator_destroy(e);
|
||||
return ret;
|
||||
}
|
||||
char *uwsgi_matheval_str(char *expr) {
|
||||
double ret = uwsgi_matheval(expr);
|
||||
return uwsgi_num2str((int) ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
int uwsgi_kvlist_parse(char *src, size_t len, char list_separator, char kv_separator, ...) {
|
||||
size_t i;
|
||||
va_list ap;
|
||||
@@ -3843,27 +3927,22 @@ void uwsgi_uuid(char *buf) {
|
||||
uuid_unparse(uuid_zmq, buf);
|
||||
#else
|
||||
int i,r[11];
|
||||
static int srand_called = 0;
|
||||
if (!uwsgi_file_exists("/dev/urandom")) goto fallback;
|
||||
int fd = open("/dev/urandom", O_RDONLY);
|
||||
if (fd < 0) goto fallback;
|
||||
for(i=0;i<11;i++) {
|
||||
if (read(fd, &r[i], 4) != 4) {
|
||||
close(fd); goto fallback;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
goto done;
|
||||
if (!uwsgi_file_exists("/dev/urandom")) goto fallback;
|
||||
int fd = open("/dev/urandom", O_RDONLY);
|
||||
if (fd < 0) goto fallback;
|
||||
for(i=0;i<11;i++) {
|
||||
if (read(fd, &r[i], 4) != 4) {
|
||||
close(fd); goto fallback;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
goto done;
|
||||
fallback:
|
||||
if (!srand_called) {
|
||||
srand((unsigned int) getpid());
|
||||
srand_called = 1;
|
||||
}
|
||||
for(i=0;i<11;i++) {
|
||||
r[i] = rand();
|
||||
}
|
||||
for(i=0;i<11;i++) {
|
||||
r[i] = rand();
|
||||
}
|
||||
done:
|
||||
snprintf(buf, 37, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10]);
|
||||
snprintf(buf, 37, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10]);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -4227,6 +4306,7 @@ void uwsgi_envdir(char *edir) {
|
||||
|
||||
free(content);
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
|
||||
void uwsgi_envdirs(struct uwsgi_string_list *envdirs) {
|
||||
@@ -4246,3 +4326,17 @@ void uwsgi_exit(int status) {
|
||||
// disable macro expansion
|
||||
(exit) (status);
|
||||
}
|
||||
|
||||
int uwsgi_base128(struct uwsgi_buffer *ub, uint64_t l, int first) {
|
||||
if( l > 127 ) {
|
||||
if (uwsgi_base128(ub, l/128, 0)) return -1;
|
||||
}
|
||||
l %= 128;
|
||||
if(first) {
|
||||
if (uwsgi_buffer_u8(ub, (uint8_t) l)) return -1;
|
||||
}
|
||||
else {
|
||||
if (uwsgi_buffer_u8(ub, 0x80 | (uint8_t) l)) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
+120
-92
@@ -38,11 +38,21 @@ UWSGI_DECLARE_EMBEDDED_PLUGINS;
|
||||
static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"socket", required_argument, 's', "bind to the specified UNIX/TCP socket using default protocol", uwsgi_opt_add_socket, NULL, 0},
|
||||
{"uwsgi-socket", required_argument, 's', "bind to the specified UNIX/TCP socket using uwsgi protocol", uwsgi_opt_add_socket, "uwsgi", 0},
|
||||
#ifdef UWSGI_SSL
|
||||
{"suwsgi-socket", required_argument, 's', "bind to the specified UNIX/TCP socket using uwsgi protocol over SSL", uwsgi_opt_add_ssl_socket, "suwsgi", 0},
|
||||
{"ssl-socket", required_argument, 's', "bind to the specified UNIX/TCP socket using uwsgi protocol over SSL", uwsgi_opt_add_ssl_socket, "suwsgi", 0},
|
||||
#endif
|
||||
|
||||
{"http-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using HTTP protocol", uwsgi_opt_add_socket, "http", 0},
|
||||
{"http-socket-modifier1", required_argument, 0, "force the specified modifier1 when using HTTP protocol", uwsgi_opt_set_64bit, &uwsgi.http_modifier1, 0},
|
||||
{"http-socket-modifier2", required_argument, 0, "force the specified modifier2 when using HTTP protocol", uwsgi_opt_set_64bit, &uwsgi.http_modifier2, 0},
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
{"https-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using HTTPS protocol", uwsgi_opt_add_ssl_socket, "https", 0},
|
||||
{"https-socket-modifier1", required_argument, 0, "force the specified modifier1 when using HTTPS protocol", uwsgi_opt_set_64bit, &uwsgi.https_modifier1, 0},
|
||||
{"https-socket-modifier2", required_argument, 0, "force the specified modifier2 when using HTTPS protocol", uwsgi_opt_set_64bit, &uwsgi.https_modifier2, 0},
|
||||
#endif
|
||||
|
||||
{"fastcgi-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using FastCGI protocol", uwsgi_opt_add_socket, "fastcgi", 0},
|
||||
{"fastcgi-nph-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using FastCGI protocol (nph mode)", uwsgi_opt_add_socket, "fastcgi-nph", 0},
|
||||
{"fastcgi-modifier1", required_argument, 0, "force the specified modifier1 when using FastCGI protocol", uwsgi_opt_set_64bit, &uwsgi.fastcgi_modifier1, 0},
|
||||
@@ -57,6 +67,8 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"raw-modifier1", required_argument, 0, "force the specified modifier1 when using RAW protocol", uwsgi_opt_set_64bit, &uwsgi.raw_modifier1, 0},
|
||||
{"raw-modifier2", required_argument, 0, "force the specified modifier2 when using RAW protocol", uwsgi_opt_set_64bit, &uwsgi.raw_modifier2, 0},
|
||||
|
||||
{"puwsgi-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using persistent uwsgi protocol (puwsgi)", uwsgi_opt_add_socket, "puwsgi", 0},
|
||||
|
||||
{"protocol", required_argument, 0, "force the specified protocol for default sockets", uwsgi_opt_set_str, &uwsgi.protocol, 0},
|
||||
{"socket-protocol", required_argument, 0, "force the specified protocol for default sockets", uwsgi_opt_set_str, &uwsgi.protocol, 0},
|
||||
{"shared-socket", required_argument, 0, "create a shared sacket for advanced jailing or ipc", uwsgi_opt_add_shared_socket, NULL, 0},
|
||||
@@ -220,13 +232,16 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"vassals-start-hook", required_argument, 0, "run the specified command before each vassal starts", uwsgi_opt_set_str, &uwsgi.vassals_start_hook, 0},
|
||||
{"vassals-stop-hook", required_argument, 0, "run the specified command after vassal's death", uwsgi_opt_set_str, &uwsgi.vassals_stop_hook, 0},
|
||||
{"vassal-sos-backlog", required_argument, 0, "ask emperor for sos if backlog queue has more items than the value specified", uwsgi_opt_set_int, &uwsgi.vassal_sos_backlog, 0},
|
||||
{"heartbeat", required_argument, 0, "announce healtness to the emperor", uwsgi_opt_set_int, &uwsgi.heartbeat, 0},
|
||||
{"auto-snapshot", optional_argument, 0, "automatically make workers snaphost after reload", uwsgi_opt_set_int, &uwsgi.auto_snapshot, UWSGI_OPT_LAZY},
|
||||
{"vassals-set", required_argument, 0, "automatically set the specified option (via --set) for every vassal", uwsgi_opt_add_string_list, &uwsgi.vassals_set, 0},
|
||||
{"vassal-set", required_argument, 0, "automatically set the specified option (via --set) for every vassal", uwsgi_opt_add_string_list, &uwsgi.vassals_set, 0},
|
||||
|
||||
{"heartbeat", required_argument, 0, "announce healthiness to the emperor", uwsgi_opt_set_int, &uwsgi.heartbeat, 0},
|
||||
|
||||
{"reload-mercy", required_argument, 0, "set the maximum time (in seconds) we wait for workers and other processes to die during reload/shutdown", uwsgi_opt_set_int, &uwsgi.reload_mercy, 0},
|
||||
{"worker-reload-mercy", required_argument, 0, "set the maximum time (in seconds) a worker can take to reload/shutdown (default is 60)", uwsgi_opt_set_int, &uwsgi.worker_reload_mercy, 0},
|
||||
{"exit-on-reload", no_argument, 0, "force exit even if a reload is requested", uwsgi_opt_true, &uwsgi.exit_on_reload, 0},
|
||||
{"die-on-term", no_argument, 0, "exit instead of brutal reload on SIGTERM", uwsgi_opt_true, &uwsgi.die_on_term, 0},
|
||||
{"force-gateway", no_argument, 0, "force teh spawn of the first registered gateway without a master", uwsgi_opt_true, &uwsgi.force_gateway, 0},
|
||||
{"force-gateway", no_argument, 0, "force the spawn of the first registered gateway without a master", uwsgi_opt_true, &uwsgi.force_gateway, 0},
|
||||
{"help", no_argument, 'h', "show this help", uwsgi_help, NULL, UWSGI_OPT_IMMEDIATE},
|
||||
{"usage", no_argument, 'h', "show this help", uwsgi_help, NULL, UWSGI_OPT_IMMEDIATE},
|
||||
|
||||
@@ -293,6 +308,12 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"signal-bufsize", required_argument, 0, "set buffer size for signal queue", uwsgi_opt_set_int, &uwsgi.signal_bufsize, 0},
|
||||
{"signals-bufsize", required_argument, 0, "set buffer size for signal queue", uwsgi_opt_set_int, &uwsgi.signal_bufsize, 0},
|
||||
|
||||
{"signal-timer", required_argument, 0, "add a timer (syntax: <signal> <seconds>)", uwsgi_opt_add_string_list, &uwsgi.signal_timers, UWSGI_OPT_MASTER},
|
||||
{"timer", required_argument, 0, "add a timer (syntax: <signal> <seconds>)", uwsgi_opt_add_string_list, &uwsgi.signal_timers, UWSGI_OPT_MASTER},
|
||||
|
||||
{"signal-rbtimer", required_argument, 0, "add a redblack timer (syntax: <signal> <seconds>)", uwsgi_opt_add_string_list, &uwsgi.rb_signal_timers, UWSGI_OPT_MASTER},
|
||||
{"rbtimer", required_argument, 0, "add a redblack timer (syntax: <signal> <seconds>)", uwsgi_opt_add_string_list, &uwsgi.rb_signal_timers, UWSGI_OPT_MASTER},
|
||||
|
||||
{"rpc-max", required_argument, 0, "maximum number of rpc slots (default: 64)", uwsgi_opt_set_64bit, &uwsgi.rpc_max, 0},
|
||||
|
||||
{"disable-logging", no_argument, 'L', "disable request logging", uwsgi_opt_dyn_false, (void *) UWSGI_OPTION_LOGGING, 0},
|
||||
@@ -504,13 +525,22 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"reload-on-exception-repr", required_argument, 0, "reload a worker when a specific exception type+value (language-specific) is raised", uwsgi_opt_add_string_list, &uwsgi.reload_on_exception_repr, 0},
|
||||
{"exception-handler", required_argument, 0, "add an exception handler", uwsgi_opt_add_string_list, &uwsgi.exception_handlers_instance, UWSGI_OPT_MASTER},
|
||||
|
||||
{"enable-metrics", no_argument, 0, "enable metrics subsystem", uwsgi_opt_true, &uwsgi.has_metrics, UWSGI_OPT_MASTER},
|
||||
{"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},
|
||||
{"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},
|
||||
{"metric-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},
|
||||
|
||||
{"udp", required_argument, 0, "run the udp server on the specified address", uwsgi_opt_set_str, &uwsgi.udp_socket, UWSGI_OPT_MASTER},
|
||||
{"stats", required_argument, 0, "enable the stats server on the specified address", uwsgi_opt_set_str, &uwsgi.stats, UWSGI_OPT_MASTER},
|
||||
{"stats-server", required_argument, 0, "enable the stats server on the specified address", uwsgi_opt_set_str, &uwsgi.stats, UWSGI_OPT_MASTER},
|
||||
{"stats-http", no_argument, 0, "prefix stats server json output with http headers", uwsgi_opt_true, &uwsgi.stats_http, UWSGI_OPT_MASTER},
|
||||
{"stats-minified", no_argument, 0, "minify statistics json output", uwsgi_opt_true, &uwsgi.stats_minified, UWSGI_OPT_MASTER},
|
||||
{"stats-min", no_argument, 0, "minify statistics json output", uwsgi_opt_true, &uwsgi.stats_minified, UWSGI_OPT_MASTER},
|
||||
{"stats-push", required_argument, 0, "push the stats json to the specified destination", uwsgi_opt_add_string_list, &uwsgi.requested_stats_pushers, UWSGI_OPT_MASTER},
|
||||
{"stats-push", required_argument, 0, "push the stats json to the specified destination", uwsgi_opt_add_string_list, &uwsgi.requested_stats_pushers, UWSGI_OPT_MASTER|UWSGI_OPT_METRICS},
|
||||
{"stats-pusher-default-freq", required_argument, 0, "set the default frequency of stats pushers", uwsgi_opt_set_int, &uwsgi.stats_pusher_default_freq, UWSGI_OPT_MASTER},
|
||||
{"stats-pushers-default-freq", required_argument, 0, "set the default frequency of stats pushers", uwsgi_opt_set_int, &uwsgi.stats_pusher_default_freq, UWSGI_OPT_MASTER},
|
||||
{"multicast", required_argument, 0, "subscribe to specified multicast group", uwsgi_opt_set_str, &uwsgi.multicast_group, UWSGI_OPT_MASTER},
|
||||
@@ -628,7 +658,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"log-master-req-stream", no_argument, 0, "create the master requests logpipe as SOCK_STREAM", uwsgi_opt_true, &uwsgi.log_master_req_stream, 0},
|
||||
{"log-reopen", no_argument, 0, "reopen log after reload", uwsgi_opt_true, &uwsgi.log_reopen, 0},
|
||||
{"log-truncate", no_argument, 0, "truncate log on startup", uwsgi_opt_true, &uwsgi.log_truncate, 0},
|
||||
{"log-maxsize", required_argument, 0, "set maximum logfile size", uwsgi_opt_set_int, &uwsgi.log_maxsize, UWSGI_OPT_LOG_MASTER},
|
||||
{"log-maxsize", required_argument, 0, "set maximum logfile size", uwsgi_opt_set_64bit, &uwsgi.log_maxsize, UWSGI_OPT_LOG_MASTER},
|
||||
{"log-backupname", required_argument, 0, "set logfile name after rotation", uwsgi_opt_set_str, &uwsgi.log_backupname, 0},
|
||||
|
||||
{"logdate", optional_argument, 0, "prefix logs with date or a strftime string", uwsgi_opt_log_date, NULL, 0},
|
||||
@@ -830,6 +860,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"namespace-net", required_argument, 0, "add network namespace", uwsgi_opt_set_str, &uwsgi.ns_net, 0},
|
||||
{"ns-net", required_argument, 0, "add network namespace", uwsgi_opt_set_str, &uwsgi.ns_net, 0},
|
||||
#endif
|
||||
{"enable-proxy-protocol", no_argument, 0, "enable PROXY1 protocol support (only for http parsers)", uwsgi_opt_true, &uwsgi.enable_proxy_protocol, 0},
|
||||
{"reuse-port", no_argument, 0, "enable REUSE_PORT flag on socket (BSD only)", uwsgi_opt_true, &uwsgi.reuse_port, 0},
|
||||
{"tcp-fast-open", required_argument, 0, "enable TCP_FASTOPEN flag on TCP sockets with the specified qlen value", uwsgi_opt_set_int, &uwsgi.tcp_fast_open, 0},
|
||||
{"tcp-fastopen", required_argument, 0, "enable TCP_FASTOPEN flag on TCP sockets with the specified qlen value", uwsgi_opt_set_int, &uwsgi.tcp_fast_open, 0},
|
||||
@@ -855,7 +886,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
|
||||
{"worker-exec", required_argument, 0, "run the specified command as worker", uwsgi_opt_set_str, &uwsgi.worker_exec, 0},
|
||||
{"worker-exec2", required_argument, 0, "run the specified command as worker (after post_fork hook)", uwsgi_opt_set_str, &uwsgi.worker_exec2, 0},
|
||||
{"attach-daemon", required_argument, 0, "attach a command/daemon to the master process (the command has to not go in background)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
|
||||
{"attach-control-daemon", required_argument, 0, "attach a command/daemon to the master process (the command has to not go in background), when teh daemon dies, the master dies too", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
|
||||
{"attach-control-daemon", required_argument, 0, "attach a command/daemon to the master process (the command has to not go in background), when the daemon dies, the master dies too", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
|
||||
{"smart-attach-daemon", required_argument, 0, "attach a command/daemon to the master process managed by a pidfile (the command has to daemonize)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
|
||||
{"smart-attach-daemon2", required_argument, 0, "attach a command/daemon to the master process managed by a pidfile (the command has to NOT daemonize)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER},
|
||||
#ifdef UWSGI_SSL
|
||||
@@ -1038,10 +1069,10 @@ void warn_pipe() {
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
if (uwsgi.threads < 2 && wsgi_req->uri_len > 0) {
|
||||
uwsgi_log("SIGPIPE: writing to a closed pipe/socket/fd (probably the client disconnected) on request %.*s (ip %.*s) !!!\n", wsgi_req->uri_len, wsgi_req->uri, wsgi_req->remote_addr_len, wsgi_req->remote_addr);
|
||||
uwsgi_log_verbose("SIGPIPE: writing to a closed pipe/socket/fd (probably the client disconnected) on request %.*s (ip %.*s) !!!\n", wsgi_req->uri_len, wsgi_req->uri, wsgi_req->remote_addr_len, wsgi_req->remote_addr);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("SIGPIPE: writing to a closed pipe/socket/fd (probably the client disconnected) !!!\n");
|
||||
uwsgi_log_verbose("SIGPIPE: writing to a closed pipe/socket/fd (probably the client disconnected) !!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1189,7 +1220,9 @@ void grace_them_all(int signum) {
|
||||
|
||||
if (uwsgi.lazy) {
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
uwsgi_curse(i, SIGHUP);
|
||||
if (uwsgi.workers[i].pid > 0) {
|
||||
uwsgi_curse(i, SIGHUP);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1197,9 +1230,6 @@ void grace_them_all(int signum) {
|
||||
|
||||
uwsgi.status.gracefully_reloading = 1;
|
||||
|
||||
int waitpid_status;
|
||||
|
||||
|
||||
uwsgi_destroy_processes();
|
||||
|
||||
uwsgi_log("...gracefully killing workers...\n");
|
||||
@@ -1213,36 +1243,10 @@ void grace_them_all(int signum) {
|
||||
}
|
||||
|
||||
for (i = 1; i <= uwsgi.numproc; i++) {
|
||||
if (uwsgi.auto_snapshot) {
|
||||
if (uwsgi.workers[i].snapshot > 0) {
|
||||
kill(uwsgi.workers[i].snapshot, SIGKILL);
|
||||
if (waitpid(uwsgi.workers[i].snapshot, &waitpid_status, 0) < 0) {
|
||||
uwsgi_error("waitpid()");
|
||||
}
|
||||
}
|
||||
if (uwsgi.workers[i].pid > 0) {
|
||||
if (uwsgi.auto_snapshot > 0 && i > uwsgi.auto_snapshot) {
|
||||
uwsgi.workers[i].snapshot = 0;
|
||||
uwsgi.workers[i].destroy = 1;
|
||||
uwsgi_curse(i, SIGHUP);
|
||||
}
|
||||
else {
|
||||
uwsgi.workers[i].snapshot = uwsgi.workers[i].pid;
|
||||
kill(uwsgi.workers[i].pid, SIGURG);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (uwsgi.workers[i].pid > 0) {
|
||||
if (uwsgi.workers[i].pid > 0) {
|
||||
uwsgi_curse(i, SIGHUP);
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.auto_snapshot) {
|
||||
uwsgi.respawn_snapshots = uwsgi.numproc - uwsgi.auto_snapshot;
|
||||
if (!uwsgi.respawn_snapshots)
|
||||
uwsgi.respawn_snapshots = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void uwsgi_nuclear_blast() {
|
||||
@@ -1301,23 +1305,6 @@ void harakiri() {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void snapshot_me(int signum) {
|
||||
// wakeup !!!
|
||||
if (uwsgi.snapshot) {
|
||||
uwsgi.snapshot = 0;
|
||||
uwsgi_set_processname(uwsgi.workers[uwsgi.mywid].name);
|
||||
return;
|
||||
}
|
||||
|
||||
uwsgi.workers[uwsgi.mywid].manage_next_request = 0;
|
||||
if (uwsgi.threads > 1) {
|
||||
wait_for_threads();
|
||||
}
|
||||
uwsgi.snapshot = 1;
|
||||
uwsgi_set_processname(uwsgi.workers[uwsgi.mywid].snapshot_name);
|
||||
uwsgi_log("[snapshot] process %d taken\n", (int) getpid());
|
||||
}
|
||||
|
||||
void stats(int signum) {
|
||||
//fix this for better logging(this cause races)
|
||||
struct uwsgi_app *ua = NULL;
|
||||
@@ -1401,8 +1388,8 @@ void what_i_am_doing() {
|
||||
|
||||
int unconfigured_hook(struct wsgi_request *wsgi_req) {
|
||||
if (wsgi_req->uh->modifier1 == 0 && !uwsgi.no_default_app) {
|
||||
if (uwsgi_apps_cnt > 0 && wsgi_req->app_id > -1 && wsgi_req->app_id < uwsgi.max_apps) {
|
||||
struct uwsgi_app *ua = &uwsgi_apps[wsgi_req->app_id];
|
||||
if (uwsgi_apps_cnt > 0 && uwsgi.default_app > -1) {
|
||||
struct uwsgi_app *ua = &uwsgi_apps[uwsgi.default_app];
|
||||
if (uwsgi.p[ua->modifier1]->request != unconfigured_hook) {
|
||||
wsgi_req->uh->modifier1 = ua->modifier1;
|
||||
return uwsgi.p[ua->modifier1]->request(wsgi_req);
|
||||
@@ -1441,7 +1428,7 @@ void uwsgi_exec_atexit(void) {
|
||||
|
||||
uwsgi_foreach(usl, uwsgi.call_as_user_atexit) {
|
||||
if (uwsgi_call_symbol(usl->value)) {
|
||||
uwsgi_log("unaable to call function \"%s\"\n", usl->value);
|
||||
uwsgi_log("unable to call function \"%s\"\n", usl->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1854,6 +1841,10 @@ static struct uwsgi_clock uwsgi_unix_clock = {
|
||||
.microseconds = uwsgi_unix_microseconds,
|
||||
};
|
||||
|
||||
void uwsgi_init_random() {
|
||||
srand((unsigned int) (uwsgi.start_tv.tv_usec * uwsgi.start_tv.tv_sec));
|
||||
}
|
||||
|
||||
#ifdef UWSGI_AS_SHARED_LIBRARY
|
||||
int uwsgi_init(int argc, char *argv[], char *envp[]) {
|
||||
|
||||
@@ -1884,7 +1875,6 @@ int main(int argc, char *argv[], char *envp[]) {
|
||||
signal(SIGTERM, SIG_IGN);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
|
||||
//initialize masterpid with a default value
|
||||
masterpid = getpid();
|
||||
|
||||
@@ -1927,6 +1917,12 @@ int main(int argc, char *argv[], char *envp[]) {
|
||||
// set default values
|
||||
uwsgi_init_default();
|
||||
|
||||
// detect cpu cores
|
||||
#if defined(_SC_NPROCESSORS_ONLN)
|
||||
uwsgi.cpus = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
#elif defined(_SC_NPROCESSORS_CONF)
|
||||
uwsgi.cpus = sysconf(_SC_NPROCESSORS_CONF);
|
||||
#endif
|
||||
// set default logit hook
|
||||
uwsgi.logit = uwsgi_logit_simple;
|
||||
|
||||
@@ -1947,6 +1943,9 @@ int main(int argc, char *argv[], char *envp[]) {
|
||||
// get startup time
|
||||
gettimeofday(&uwsgi.start_tv, NULL);
|
||||
|
||||
// initialize random engine
|
||||
uwsgi_init_random();
|
||||
|
||||
setlinebuf(stdout);
|
||||
|
||||
uwsgi.rl.rlim_cur = 0;
|
||||
@@ -2004,6 +2003,9 @@ int main(int argc, char *argv[], char *envp[]) {
|
||||
uwsgi_register_base_hooks();
|
||||
uwsgi_log_encoders_register_embedded();
|
||||
|
||||
// register base metrics (so plugins can override them)
|
||||
uwsgi_metrics_collectors_setup();
|
||||
|
||||
//initialize embedded plugins
|
||||
UWSGI_LOAD_EMBEDDED_PLUGINS
|
||||
// now a bit of magic, if the executable basename contains a 'uwsgi_' string,
|
||||
@@ -2020,7 +2022,10 @@ int main(int argc, char *argv[], char *envp[]) {
|
||||
// set a couple of 'static' magic vars
|
||||
uwsgi.magic_table['v'] = uwsgi.cwd;
|
||||
uwsgi.magic_table['h'] = uwsgi.hostname;
|
||||
uwsgi.magic_table['t'] = uwsgi_64bit2str(uwsgi_now());
|
||||
uwsgi.magic_table['T'] = uwsgi_64bit2str(uwsgi_micros());
|
||||
uwsgi.magic_table['V'] = UWSGI_VERSION;
|
||||
uwsgi.magic_table['k'] = uwsgi_num2str(uwsgi.cpus);
|
||||
uwsgi.magic_table['['] = "\033";
|
||||
|
||||
// you can embed a ini file in the uWSGi binary with default options
|
||||
@@ -2042,12 +2047,7 @@ int main(int argc, char *argv[], char *envp[]) {
|
||||
uwsgi_apply_config_pass('@', uwsgi_simple_file_read);
|
||||
|
||||
// last pass: REFERENCEs
|
||||
uwsgi_apply_config_pass('%', uwsgi_get_exported_opt);
|
||||
|
||||
#ifdef UWSGI_MATHEVAL
|
||||
// optional pass: MATH
|
||||
uwsgi_apply_config_pass('=', uwsgi_matheval_str);
|
||||
#endif
|
||||
uwsgi_apply_config_pass('%', uwsgi_manage_placeholder);
|
||||
|
||||
// ok, the options dictionary is available, lets manage it
|
||||
uwsgi_configure();
|
||||
@@ -2138,7 +2138,6 @@ int main(int argc, char *argv[], char *envp[]) {
|
||||
uwsgi_register_imperial_monitor("glob", uwsgi_imperial_monitor_glob_init, uwsgi_imperial_monitor_glob);
|
||||
|
||||
// setup stats pushers
|
||||
uwsgi_register_stats_pusher("file", uwsgi_stats_pusher_file);
|
||||
uwsgi_stats_pusher_setup();
|
||||
|
||||
// register embedded alarms
|
||||
@@ -2229,12 +2228,6 @@ int main(int argc, char *argv[], char *envp[]) {
|
||||
uwsgi_log_initial("*** big endian arch detected ***\n");
|
||||
#endif
|
||||
|
||||
#if defined(_SC_NPROCESSORS_ONLN)
|
||||
uwsgi.cpus = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
#elif defined(_SC_NPROCESSORS_CONF)
|
||||
uwsgi.cpus = sysconf(_SC_NPROCESSORS_CONF);
|
||||
#endif
|
||||
|
||||
uwsgi_log_initial("detected number of CPU cores: %d\n", uwsgi.cpus);
|
||||
|
||||
|
||||
@@ -2605,6 +2598,9 @@ int uwsgi_start(void *v_argv) {
|
||||
// initialize the exception handlers
|
||||
uwsgi_exception_setup_handlers();
|
||||
|
||||
// initialize socket protocols (do it after caching !!!)
|
||||
uwsgi_protocols_register();
|
||||
|
||||
/* plugin initialization */
|
||||
for (i = 0; i < uwsgi.gp_cnt; i++) {
|
||||
if (uwsgi.gp[i]->init) {
|
||||
@@ -2843,6 +2839,9 @@ unsafe:
|
||||
// set a default request structure (for loading apps...)
|
||||
uwsgi.wsgi_req = &uwsgi.workers[0].cores[0].req;
|
||||
|
||||
// ok, let's initialize the metrics subsystem
|
||||
uwsgi_setup_metrics();
|
||||
|
||||
// cores are allocated, lets allocate logformat (if required)
|
||||
if (uwsgi.logformat) {
|
||||
uwsgi_build_log_format(uwsgi.logformat);
|
||||
@@ -3189,11 +3188,6 @@ void uwsgi_worker_run() {
|
||||
uwsgi_unix_signal(SIGINT, end_me);
|
||||
uwsgi_unix_signal(SIGTERM, end_me);
|
||||
|
||||
if (uwsgi.auto_snapshot) {
|
||||
uwsgi_unix_signal(SIGURG, snapshot_me);
|
||||
}
|
||||
|
||||
|
||||
uwsgi_unix_signal(SIGUSR1, stats);
|
||||
signal(SIGUSR2, (void *) &what_i_am_doing);
|
||||
if (!uwsgi.ignore_sigpipe) {
|
||||
@@ -3257,15 +3251,6 @@ void uwsgi_ignition() {
|
||||
|
||||
int i;
|
||||
|
||||
// snapshot workers do not enter the loop until a specific signal (SIGURG) is raised...
|
||||
if (uwsgi.snapshot) {
|
||||
wait_for_call_of_duty:
|
||||
uwsgi_sig_pause();
|
||||
if (uwsgi.snapshot)
|
||||
goto wait_for_call_of_duty;
|
||||
uwsgi_log("[snapshot] process %d is the new worker %d\n", (int) getpid(), uwsgi.mywid);
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (uwsgi.p[i]->hijack_worker) {
|
||||
uwsgi.p[i]->hijack_worker();
|
||||
@@ -3308,9 +3293,6 @@ wait_for_call_of_duty:
|
||||
}
|
||||
}
|
||||
|
||||
if (uwsgi.snapshot) {
|
||||
uwsgi_ignition();
|
||||
}
|
||||
// end of the process...
|
||||
end_me(0);
|
||||
}
|
||||
@@ -3508,7 +3490,7 @@ void uwsgi_init_all_apps() {
|
||||
|
||||
uwsgi_foreach(usl, uwsgi.call_pre_app) {
|
||||
if (uwsgi_call_symbol(usl->value)) {
|
||||
uwsgi_log("unaable to call function \"%s\"\n", usl->value);
|
||||
uwsgi_log("unable to call function \"%s\"\n", usl->value);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@@ -3576,7 +3558,7 @@ void uwsgi_init_all_apps() {
|
||||
|
||||
uwsgi_foreach(usl, uwsgi.call_post_app) {
|
||||
if (uwsgi_call_symbol(usl->value)) {
|
||||
uwsgi_log("unaable to call function \"%s\"\n", usl->value);
|
||||
uwsgi_log("unable to call function \"%s\"\n", usl->value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3872,6 +3854,51 @@ void uwsgi_opt_add_socket(char *opt, char *value, void *protocol) {
|
||||
uwsgi_sock->proto_name = protocol;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
void uwsgi_opt_add_ssl_socket(char *opt, char *value, void *protocol) {
|
||||
char *client_ca = NULL;
|
||||
|
||||
// build socket, certificate and key file
|
||||
char *sock = uwsgi_str(value);
|
||||
char *crt = strchr(sock, ',');
|
||||
if (!crt) {
|
||||
uwsgi_log("invalid https-socket syntax must be socket,crt,key\n");
|
||||
exit(1);
|
||||
}
|
||||
*crt = '\0'; crt++;
|
||||
char *key = strchr(crt, ',');
|
||||
if (!key) {
|
||||
uwsgi_log("invalid https-socket syntax must be socket,crt,key\n");
|
||||
exit(1);
|
||||
}
|
||||
*key = '\0'; key++;
|
||||
|
||||
char *ciphers = strchr(key, ',');
|
||||
if (ciphers) {
|
||||
*ciphers = '\0'; ciphers++;
|
||||
client_ca = strchr(ciphers, ',');
|
||||
if (client_ca) {
|
||||
*client_ca = '\0'; client_ca++;
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi_new_socket(generate_socket_name(sock));
|
||||
uwsgi_sock->name_len = strlen(uwsgi_sock->name);
|
||||
uwsgi_sock->proto_name = protocol;
|
||||
|
||||
// ok we have the socket, initialize ssl if required
|
||||
if (!uwsgi.ssl_initialized) {
|
||||
uwsgi_ssl_init();
|
||||
}
|
||||
|
||||
// initialize ssl context
|
||||
uwsgi_sock->ssl_ctx = uwsgi_ssl_new_server_context(uwsgi_sock->name, crt, key, ciphers, client_ca);
|
||||
if (!uwsgi_sock->ssl_ctx) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void uwsgi_opt_add_socket_no_defer(char *opt, char *value, void *protocol) {
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi_new_socket(generate_socket_name(value));
|
||||
uwsgi_sock->name_len = strlen(uwsgi_sock->name);
|
||||
@@ -4187,6 +4214,7 @@ int uwsgi_zerg_attach(char *value) {
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
free(zerg);
|
||||
}
|
||||
|
||||
close(zerg_fd);
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ static int uwsgi_websockets_check_pingpong(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// pong received, send anther ping
|
||||
// pong received, send another ping
|
||||
if (now - wsgi_req->websocket_last_ping >= uwsgi.websockets_ping_freq) {
|
||||
return uwsgi_websockets_ping(wsgi_req);
|
||||
}
|
||||
|
||||
+27
-33
@@ -26,9 +26,6 @@ struct uwsgi_carbon {
|
||||
unsigned long long *last_busyness_values;
|
||||
unsigned long long *current_busyness_values;
|
||||
int *was_busy;
|
||||
int need_retry;
|
||||
time_t last_update;
|
||||
time_t next_retry;
|
||||
int max_retries;
|
||||
int retry_delay;
|
||||
char *root_node;
|
||||
@@ -40,6 +37,7 @@ struct uwsgi_carbon {
|
||||
int zero_avg;
|
||||
uint64_t last_requests;
|
||||
struct uwsgi_stats_pusher *pusher;
|
||||
int use_metrics;
|
||||
} u_carbon;
|
||||
|
||||
static struct uwsgi_option carbon_options[] = {
|
||||
@@ -55,6 +53,7 @@ static struct uwsgi_option carbon_options[] = {
|
||||
{"carbon-name-resolve", no_argument, 0, "allow using hostname as carbon server address (default disabled)", uwsgi_opt_true, &u_carbon.resolve_hostname, 0},
|
||||
{"carbon-resolve-names", no_argument, 0, "allow using hostname as carbon server address (default disabled)", uwsgi_opt_true, &u_carbon.resolve_hostname, 0},
|
||||
{"carbon-idle-avg", required_argument, 0, "average values source during idle period (no requests), can be \"last\", \"zero\", \"none\" (default is last)", uwsgi_opt_set_str, &u_carbon.idle_avg, 0},
|
||||
{"carbon-use-metrics", no_argument, 0, "don't compute all statistics, use metrics subsystem data instead (warning! key names will be different)", uwsgi_opt_true, &u_carbon.use_metrics, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
|
||||
};
|
||||
@@ -108,7 +107,7 @@ static void carbon_post_init() {
|
||||
|
||||
if (u_carbon.freq < 1) u_carbon.freq = 60;
|
||||
if (u_carbon.timeout < 1) u_carbon.timeout = 3;
|
||||
if (u_carbon.max_retries <= 0) u_carbon.max_retries = 1;
|
||||
if (u_carbon.max_retries < 0) u_carbon.max_retries = 0;
|
||||
if (u_carbon.retry_delay <= 0) u_carbon.retry_delay = 7;
|
||||
if (!u_carbon.id) {
|
||||
u_carbon.id = uwsgi_str(uwsgi.sockets->name);
|
||||
@@ -153,14 +152,13 @@ static void carbon_post_init() {
|
||||
u_carbon.was_busy = uwsgi_calloc(sizeof(int) * uwsgi.numproc);
|
||||
}
|
||||
|
||||
// set next update to now()+retry_delay, this way we will have first flush just after start
|
||||
u_carbon.last_update = uwsgi_now() - u_carbon.freq + u_carbon.retry_delay;
|
||||
|
||||
uwsgi_log("[carbon] carbon plugin started, %is frequency, %is timeout, max retries %i, retry delay %is\n",
|
||||
u_carbon.freq, u_carbon.timeout, u_carbon.max_retries, u_carbon.retry_delay);
|
||||
|
||||
struct uwsgi_stats_pusher_instance *uspi = uwsgi_stats_pusher_add(u_carbon.pusher, NULL);
|
||||
uspi->freq = u_carbon.freq;
|
||||
uspi->retry_delay = u_carbon.retry_delay;
|
||||
uspi->max_retries = u_carbon.max_retries;
|
||||
// no need to generate the json
|
||||
uspi->raw=1;
|
||||
}
|
||||
@@ -185,14 +183,15 @@ static int carbon_write(int fd, char *fmt,...) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void carbon_push_stats(int retry_cycle, time_t now) {
|
||||
static int carbon_push_stats(int retry_cycle, time_t now) {
|
||||
struct carbon_server_list *usl = u_carbon.servers_data;
|
||||
if (!u_carbon.servers_data) return;
|
||||
if (!u_carbon.servers_data) return 0;
|
||||
int i;
|
||||
int fd;
|
||||
int wok;
|
||||
char *ip;
|
||||
char *carbon_address = NULL;
|
||||
int needs_retry;
|
||||
|
||||
for (i = 0; i < uwsgi.numproc; i++) {
|
||||
u_carbon.current_busyness_values[i] = uwsgi.workers[i+1].running_time - u_carbon.last_busyness_values[i];
|
||||
@@ -200,7 +199,7 @@ static void carbon_push_stats(int retry_cycle, time_t now) {
|
||||
u_carbon.was_busy[i-1] += uwsgi_worker_is_busy(i+1);
|
||||
}
|
||||
|
||||
u_carbon.need_retry = 0;
|
||||
needs_retry = 0;
|
||||
while(usl) {
|
||||
if (retry_cycle && usl->healthy)
|
||||
// skip healthy servers during retry cycle
|
||||
@@ -228,15 +227,7 @@ static void carbon_push_stats(int retry_cycle, time_t now) {
|
||||
fd = uwsgi_connect(carbon_address, u_carbon.timeout, 0);
|
||||
if (fd < 0) {
|
||||
uwsgi_log("[carbon] Could not connect to carbon server at %s\n", carbon_address);
|
||||
if (usl->errors < u_carbon.max_retries) {
|
||||
u_carbon.need_retry = 1;
|
||||
u_carbon.next_retry = uwsgi_now() + u_carbon.retry_delay;
|
||||
} else {
|
||||
uwsgi_log("[carbon] Maximum number of retries for %s (%d)\n",
|
||||
carbon_address, u_carbon.max_retries);
|
||||
usl->healthy = 0;
|
||||
usl->errors = 0;
|
||||
}
|
||||
needs_retry = 1;
|
||||
usl->healthy = 0;
|
||||
usl->errors++;
|
||||
free(carbon_address);
|
||||
@@ -246,6 +237,8 @@ static void carbon_push_stats(int retry_cycle, time_t now) {
|
||||
// put the socket in non-blocking mode
|
||||
uwsgi_socket_nb(fd);
|
||||
|
||||
if (u_carbon.use_metrics) goto metrics_loop;
|
||||
|
||||
unsigned long long total_rss = 0;
|
||||
unsigned long long total_vsz = 0;
|
||||
unsigned long long total_tx = 0;
|
||||
@@ -380,6 +373,18 @@ static void carbon_push_stats(int retry_cycle, time_t now) {
|
||||
wok = carbon_write(fd, "%s%s.%s.harakiri %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) total_harakiri, (unsigned long long) now);
|
||||
if (!wok) goto clear;
|
||||
|
||||
metrics_loop:
|
||||
if (u_carbon.use_metrics) {
|
||||
struct uwsgi_metric *um = uwsgi.metrics;
|
||||
while(um) {
|
||||
uwsgi_rlock(uwsgi.metrics_lock);
|
||||
wok = carbon_write(fd, "%s%s.%s.%.*s %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, um->name_len, um->name, (unsigned long long) *um->value, (unsigned long long) now);
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
if (!wok) goto clear;
|
||||
um = um->next;
|
||||
}
|
||||
}
|
||||
|
||||
usl->healthy = 1;
|
||||
usl->errors = 0;
|
||||
|
||||
@@ -390,23 +395,12 @@ clear:
|
||||
nxt:
|
||||
usl = usl->next;
|
||||
}
|
||||
if (!retry_cycle) u_carbon.last_update = uwsgi_now();
|
||||
if (u_carbon.need_retry)
|
||||
// timeouts and retries might cause additional lags in carbon cycles, we will adjust timer to fix that
|
||||
u_carbon.last_update -= u_carbon.timeout;
|
||||
|
||||
return needs_retry;
|
||||
}
|
||||
|
||||
static void carbon_push(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) {
|
||||
|
||||
if (u_carbon.need_retry && now >= u_carbon.next_retry) {
|
||||
carbon_push_stats(1, now);
|
||||
}
|
||||
else {
|
||||
// update
|
||||
u_carbon.need_retry = 0;
|
||||
carbon_push_stats(0, now);
|
||||
|
||||
}
|
||||
uspi->needs_retry = carbon_push_stats(uspi->retries, now);
|
||||
}
|
||||
|
||||
static void carbon_cleanup() {
|
||||
|
||||
@@ -187,11 +187,12 @@ void uwsgi_opt_corerouter_zerg(char *opt, char *value, void *cr) {
|
||||
|
||||
close(zerg_fd);
|
||||
|
||||
for(j=0;j<count;j++) {
|
||||
if (zerg[j] == -1) break;
|
||||
ugs = uwsgi_new_gateway_socket_from_fd(zerg[j], ucr->name);
|
||||
ugs->zerg = optarg;
|
||||
}
|
||||
for(j=0;j<count;j++) {
|
||||
if (zerg[j] == -1) break;
|
||||
ugs = uwsgi_new_gateway_socket_from_fd(zerg[j], ucr->name);
|
||||
ugs->zerg = optarg;
|
||||
}
|
||||
free(zerg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ static void uwsgi_imperial_monitor_zeromq_cmd(struct uwsgi_emperor_scanner *ues)
|
||||
}
|
||||
}
|
||||
// destroy an instance
|
||||
else if (!uwsgi_strncmp(ez_cmd, ez_cmd_len, "destroy", 6)) {
|
||||
else if (!uwsgi_strncmp(ez_cmd, ez_cmd_len, "destroy", 7)) {
|
||||
struct uwsgi_instance *ui = emperor_get(name);
|
||||
if (!ui) {
|
||||
uwsgi_log("[emperor-zeromq] unknown instance \"%s\"\n", name);
|
||||
|
||||
+271
-13
@@ -2,7 +2,7 @@
|
||||
|
||||
/*
|
||||
|
||||
Soon before official Go 1.1, we understand supporting Go in a fork() heavy
|
||||
Soon before official Go 1.1, we understood supporting Go in a fork() heavy
|
||||
environment was not blessed by the Go community.
|
||||
|
||||
Instead of completely dropping support for Go, we studied how the gccgo project works and we
|
||||
@@ -16,8 +16,31 @@
|
||||
the uwsgi.Run() go function directly calls the uwsgi_takeover() function (it automatically
|
||||
manages mules, spoolers and workers)
|
||||
|
||||
As well as before each core maps to a goroutine mapped to a real pthread. (goroutines called
|
||||
from your apps are native goroutines)
|
||||
The plugin implements goroutines too.
|
||||
|
||||
On startup a goroutine is created for each socket and signals file descriptors.
|
||||
|
||||
For every request a new goroutine is created too.
|
||||
|
||||
The wsgi_request * structure is attached to the "closure" field of the goroutine (PAY ATTENTION)
|
||||
|
||||
even if the loop engine makes use of the async mode, pthreads could be spawned all over the place.
|
||||
For such a reason a mutex is created avoiding the global wsgi_req structures to be clobbered
|
||||
|
||||
Contrary to the standard way Go apps are deployed, the plugin supports loading shared libraries.
|
||||
While this is a common approach in other environments, the Go community prefers monolithic binaries.
|
||||
|
||||
As always, choose the model that best suite for you. Eventually building a single uWSGI binary with your Go
|
||||
app embedded is pretty easy:
|
||||
|
||||
|
||||
CFLAGS=-DUWSGI_GCCGO_MONOLITHIC UWSGI_ADDITIONAL_SOURCES=t/go/uploadtest.go UWSGI_PROFILE=gccgo make
|
||||
|
||||
or you can add the following two directives in a build profile:
|
||||
|
||||
cflags = -DUWSGI_GCCGO_MONOLITHIC
|
||||
additional_sources = t/go/uploadtest.go
|
||||
|
||||
|
||||
*/
|
||||
|
||||
@@ -25,25 +48,29 @@ extern struct uwsgi_server uwsgi;
|
||||
struct uwsgi_plugin gccgo_plugin;
|
||||
|
||||
struct uwsgi_gccgo{
|
||||
// 1 if a main is loaded
|
||||
int initialized;
|
||||
struct uwsgi_string_list *libs;
|
||||
char *args;
|
||||
pthread_mutex_t wsgi_req_lock;
|
||||
} ugccgo;
|
||||
|
||||
/*
|
||||
shortcut for enabling the "goroutines" loop engine
|
||||
*/
|
||||
static void uwsgi_opt_setup_goroutines(char *opt, char *value, void *foobar) {
|
||||
// set async mode
|
||||
uwsgi_opt_set_int(opt, value, &uwsgi.async);
|
||||
// set loop engine
|
||||
uwsgi.loop = "goroutines";
|
||||
}
|
||||
*/
|
||||
|
||||
struct uwsgi_option uwsgi_gccgo_options[] = {
|
||||
{"go-load", required_argument, 0, "load a go shared library in the process address space, eventually patching main.main and __go_init_main", uwsgi_opt_add_string_list, &ugccgo.libs, 0},
|
||||
{"gccgo-load", required_argument, 0, "load a go shared library in the process address space, eventually patching main.main and __go_init_main", uwsgi_opt_add_string_list, &ugccgo.libs, 0},
|
||||
{"go-args", required_argument, 0, "set go commandline arguments", uwsgi_opt_set_str, &ugccgo.args, 0},
|
||||
{"gccgo-args", required_argument, 0, "set go commandline arguments", uwsgi_opt_set_str, &ugccgo.args, 0},
|
||||
// {"goroutines", required_argument, 0, "a shortcut setting optimal options for goroutine-based apps, takes the number of goroutines to spawn as argument", uwsgi_opt_setup_goroutines, NULL, UWSGI_OPT_THREADS},
|
||||
{"goroutines", required_argument, 0, "a shortcut setting optimal options for goroutine-based apps, takes the number of max goroutines to spawn as argument", uwsgi_opt_setup_goroutines, NULL, UWSGI_OPT_THREADS},
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
|
||||
};
|
||||
@@ -51,27 +78,46 @@ struct uwsgi_option uwsgi_gccgo_options[] = {
|
||||
// no_split_stack is the key to avoid crashing !!!
|
||||
void* runtime_m(void) __attribute__ ((noinline, no_split_stack));
|
||||
|
||||
// initialize runtime
|
||||
void runtime_check(void);
|
||||
void runtime_args(int, char **);
|
||||
void runtime_osinit(void);
|
||||
void runtime_schedinit(void);
|
||||
void *__go_go(void *, void *);
|
||||
void runtime_main(void);
|
||||
void runtime_mstart(void *);
|
||||
|
||||
// spawn a goroutine
|
||||
void *__go_go(void *, void *);
|
||||
|
||||
// api functions exposed
|
||||
extern void uwsgigo_request(void *, void *) __asm__ ("go.uwsgi.RequestHandler");
|
||||
extern void* uwsgigo_env(void *) __asm__ ("go.uwsgi.Env");
|
||||
extern void* uwsgigo_env_add(void *, void *, uint16_t, void *, uint16_t) __asm__ ("go.uwsgi.EnvAdd");
|
||||
extern void uwsgigo_run_core(int) __asm__ ("go.uwsgi.RunCore");
|
||||
extern void uwsgigo_signal_handler(void *, uint8_t) __asm__ ("go.uwsgi.SignalHandler");
|
||||
//extern void uwsgigo_loop(void) __asm__ ("go.uwsgi.Loop");
|
||||
|
||||
// for goroutines
|
||||
void runtime_netpollinit(void);
|
||||
void runtime_starttheworld(void);
|
||||
void *runtime_pollOpen(int) __asm__ ("net.runtime_pollOpen");
|
||||
void runtime_pollClose(void *) __asm__ ("net.runtime_pollClose");
|
||||
void runtime_pollUnblock(void *) __asm__ ("net.runtime_pollUnblock");
|
||||
int runtime_pollWait(void *, int) __asm__ ("net.runtime_pollWait");
|
||||
void runtime_pollSetDeadline(void *, int64_t, int) __asm__ ("net.runtime_pollSetDeadline");
|
||||
void runtime_gosched(void);
|
||||
// the current goroutine
|
||||
void *runtime_g(void);
|
||||
// we use the closure field to store the wsgi_req structure
|
||||
void __go_set_closure(void *);
|
||||
void *__go_get_closure(void);
|
||||
|
||||
static void mainstart(void *arg __attribute__((unused))) {
|
||||
runtime_main();
|
||||
}
|
||||
|
||||
#ifndef UWSGI_GCCGO_MONOLITHIC
|
||||
void uwsgigo_main_main(void) __asm__ ("main.main");
|
||||
void uwsgigo_main_init(void) __asm__ ("__go_init_main");
|
||||
#endif
|
||||
|
||||
void (*uwsgigo_hook_init)(void);
|
||||
void (*uwsgigo_hook_main)(void);
|
||||
@@ -102,6 +148,14 @@ int uwsgi_gccgo_helper_register_signal(uint8_t signum, char *receiver, void *han
|
||||
}
|
||||
|
||||
static void uwsgi_gccgo_initialize() {
|
||||
if (uwsgi.threads > 1) {
|
||||
uwsgi_log("!!! the Go runtime cannot work in multithreaded modes !!!\n");
|
||||
exit(1);
|
||||
}
|
||||
#ifdef UWSGI_GCCGO_MONOLITHIC
|
||||
uwsgigo_hook_init = dlsym(RTLD_DEFAULT, "__go_init_main");
|
||||
uwsgigo_hook_main = dlsym(RTLD_DEFAULT, "main.main");
|
||||
#endif
|
||||
struct uwsgi_string_list *usl = ugccgo.libs;
|
||||
while(usl) {
|
||||
void *handle = dlopen(usl->value, RTLD_NOW | RTLD_GLOBAL);
|
||||
@@ -109,9 +163,16 @@ static void uwsgi_gccgo_initialize() {
|
||||
uwsgi_log("unable to open go shared library: %s\n", dlerror());
|
||||
exit(1);
|
||||
}
|
||||
uwsgi_log("[uwsgi-gccgo] loaded %s\n", usl->value);
|
||||
uwsgigo_hook_init = dlsym(handle, "__go_init_main");
|
||||
uwsgigo_hook_main = dlsym(handle, "main.main");
|
||||
void *g_init = dlsym(handle, "__go_init_main");
|
||||
void *g_main = dlsym(handle, "main.main");
|
||||
if (g_init && g_main) {
|
||||
uwsgigo_hook_init = g_init;
|
||||
uwsgigo_hook_main = g_main;
|
||||
uwsgi_log("[uwsgi-gccgo] loaded %s as main\n", usl->value);
|
||||
}
|
||||
else {
|
||||
uwsgi_log("[uwsgi-gccgo] loaded %s\n", usl->value);
|
||||
}
|
||||
usl = usl->next;
|
||||
}
|
||||
|
||||
@@ -119,6 +180,8 @@ static void uwsgi_gccgo_initialize() {
|
||||
return;
|
||||
}
|
||||
|
||||
ugccgo.initialized = 1;
|
||||
|
||||
// Go runtime initialization
|
||||
int argc = 0;
|
||||
if (ugccgo.args) {
|
||||
@@ -131,7 +194,7 @@ static void uwsgi_gccgo_initialize() {
|
||||
}
|
||||
runtime_check();
|
||||
if (argc > 0) {
|
||||
char **argv = uwsgi_calloc(sizeof(char *) * (argc + 1));
|
||||
char **argv = uwsgi_calloc(sizeof(char *) * (argc + 2));
|
||||
char *argv_list = uwsgi_str(ugccgo.args);
|
||||
char *p, *ctx = NULL;
|
||||
int n = 0;
|
||||
@@ -145,6 +208,7 @@ static void uwsgi_gccgo_initialize() {
|
||||
char *argv[2] = {0,0};
|
||||
runtime_args(0, argv);
|
||||
}
|
||||
|
||||
runtime_osinit();
|
||||
runtime_schedinit();
|
||||
__go_go(mainstart, NULL);
|
||||
@@ -153,6 +217,10 @@ static void uwsgi_gccgo_initialize() {
|
||||
}
|
||||
|
||||
static int uwsgi_gccgo_request(struct wsgi_request *wsgi_req) {
|
||||
if (!ugccgo.initialized) {
|
||||
uwsgi_log("!!! Go runtime not initialized !!!\n");
|
||||
goto end;
|
||||
}
|
||||
/* Standard GO request */
|
||||
if (!wsgi_req->uh->pktsize) {
|
||||
uwsgi_log("Empty GO request. skip.\n");
|
||||
@@ -170,6 +238,7 @@ static int uwsgi_gccgo_request(struct wsgi_request *wsgi_req) {
|
||||
i++;
|
||||
}
|
||||
uwsgigo_request(wsgi_req->async_environ, wsgi_req);
|
||||
end:
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
@@ -178,15 +247,204 @@ static void uwsgi_gccgo_after_request(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
|
||||
static int uwsgi_gccgo_signal_handler(uint8_t signum, void *handler) {
|
||||
if (!ugccgo.initialized) return -1;
|
||||
uwsgigo_signal_handler(handler, signum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define free_req_queue pthread_mutex_lock(&ugccgo.wsgi_req_lock);uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = wsgi_req; pthread_mutex_unlock(&ugccgo.wsgi_req_lock)
|
||||
|
||||
static void uwsgi_gccgo_request_goroutine(void *arg) {
|
||||
|
||||
struct wsgi_request *wsgi_req = (struct wsgi_request *) arg;
|
||||
|
||||
// map wsgi_req to the goroutine
|
||||
__go_set_closure(wsgi_req);
|
||||
|
||||
int ret,status;
|
||||
|
||||
for(;;) {
|
||||
ret = uwsgi.wait_read_hook(wsgi_req->fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
|
||||
wsgi_req->switches++;
|
||||
|
||||
if (ret <= 0) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
retry:
|
||||
status = wsgi_req->socket->proto(wsgi_req);
|
||||
if (status < 0) {
|
||||
goto end;
|
||||
}
|
||||
else if (status == 0) {
|
||||
break;
|
||||
}
|
||||
if (uwsgi_is_again()) continue;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
if (uwsgi_apply_routes(wsgi_req) == UWSGI_ROUTE_BREAK) {
|
||||
goto end;
|
||||
}
|
||||
#endif
|
||||
|
||||
for(;;) {
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req) <= UWSGI_OK) {
|
||||
goto end;
|
||||
}
|
||||
wsgi_req->switches++;
|
||||
// yield
|
||||
runtime_gosched();
|
||||
}
|
||||
|
||||
end:
|
||||
uwsgi_close_request(wsgi_req);
|
||||
free_req_queue;
|
||||
}
|
||||
|
||||
static struct wsgi_request *uwsgi_gccgo_current_wsgi_req(void) {
|
||||
return (struct wsgi_request *) __go_get_closure();
|
||||
}
|
||||
|
||||
static int uwsgi_gccgo_wait_read_hook(int fd, int timeout) {
|
||||
void *pdesc = runtime_pollOpen(fd);
|
||||
int64_t t = (uwsgi_micros() * 1000LL) + (((int64_t)timeout) * 1000LL * 1000LL * 1000LL);
|
||||
runtime_pollSetDeadline(pdesc, t, 'r');
|
||||
int ret = runtime_pollWait(pdesc, 'r');
|
||||
runtime_pollUnblock(pdesc);
|
||||
runtime_pollClose(pdesc);
|
||||
if (ret == 0) return 1;
|
||||
// timeout
|
||||
if (ret == 2) return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int uwsgi_gccgo_wait_write_hook(int fd, int timeout) {
|
||||
void *pdesc = runtime_pollOpen(fd);
|
||||
int64_t t = (uwsgi_micros() * 1000LL) + (((int64_t)timeout) * 1000LL * 1000LL * 1000LL);
|
||||
runtime_pollSetDeadline(pdesc, t, 'w');
|
||||
int ret = runtime_pollWait(pdesc, 'w');
|
||||
runtime_pollUnblock(pdesc);
|
||||
runtime_pollClose(pdesc);
|
||||
if (ret == 0) return 1;
|
||||
// timeout
|
||||
if (ret == 2) return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
this goroutine manages signals
|
||||
*/
|
||||
static void uwsgi_gccgo_signal_goroutine(void *arg) {
|
||||
int *fd = (int *) arg;
|
||||
void *pdesc = runtime_pollOpen(*fd);
|
||||
for(;;) {
|
||||
runtime_pollWait(pdesc, 'r');
|
||||
retry:
|
||||
uwsgi_receive_signal(*fd, "worker", uwsgi.mywid);
|
||||
if (uwsgi_is_again()) continue;
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
static void uwsgi_gccgo_socket_goroutine(void *arg) {
|
||||
struct uwsgi_socket *uwsgi_sock = (struct uwsgi_socket *) arg;
|
||||
struct wsgi_request *wsgi_req = NULL;
|
||||
void *pdesc = runtime_pollOpen(uwsgi_sock->fd);
|
||||
// wait for connection
|
||||
for(;;) {
|
||||
runtime_pollWait(pdesc, 'r');
|
||||
retry:
|
||||
pthread_mutex_lock(&ugccgo.wsgi_req_lock);
|
||||
wsgi_req = find_first_available_wsgi_req();
|
||||
pthread_mutex_unlock(&ugccgo.wsgi_req_lock);
|
||||
|
||||
if (wsgi_req == NULL) {
|
||||
uwsgi_async_queue_is_full(uwsgi_now());
|
||||
// try rescheduling...
|
||||
// we do not use runtime_gosched() as we want to call the netpoll loop too
|
||||
runtime_pollUnblock(pdesc);
|
||||
runtime_pollClose(pdesc);
|
||||
pdesc = runtime_pollOpen(uwsgi_sock->fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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)) {
|
||||
uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 0;
|
||||
free_req_queue;
|
||||
if (uwsgi_is_again()) continue;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
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.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
|
||||
set_harakiri(uwsgi.shared->options[UWSGI_OPTION_HARAKIRI]);
|
||||
}
|
||||
|
||||
// spawn the new goroutine
|
||||
__go_go(uwsgi_gccgo_request_goroutine, wsgi_req);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
static void uwsgi_gccgo_loop() {
|
||||
if (!ugccgo.initialized) {
|
||||
uwsgi_log("no go.main code loaded !!!\n");
|
||||
exit(1);
|
||||
}
|
||||
// initialize the log protecting the wsgi_req structures
|
||||
pthread_mutex_init(&ugccgo.wsgi_req_lock, NULL);
|
||||
|
||||
// hooks
|
||||
uwsgi.current_wsgi_req = uwsgi_gccgo_current_wsgi_req;
|
||||
uwsgi.wait_write_hook = uwsgi_gccgo_wait_write_hook;
|
||||
uwsgi.wait_read_hook = uwsgi_gccgo_wait_read_hook;
|
||||
|
||||
// ininitialize Go I/O loop
|
||||
runtime_netpollinit();
|
||||
|
||||
if (uwsgi.signal_socket > -1) {
|
||||
__go_go(uwsgi_gccgo_signal_goroutine, &uwsgi.signal_socket);
|
||||
__go_go(uwsgi_gccgo_signal_goroutine, &uwsgi.my_signal_socket);
|
||||
}
|
||||
|
||||
// start a goroutine for each socket
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
while(uwsgi_sock) {
|
||||
if (!uwsgi_sock->next) {
|
||||
uwsgi_gccgo_socket_goroutine(uwsgi_sock);
|
||||
}
|
||||
else {
|
||||
__go_go(uwsgi_gccgo_socket_goroutine, uwsgi_sock);
|
||||
}
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
// never here
|
||||
}
|
||||
|
||||
static void uwsgi_gccgo_on_load() {
|
||||
uwsgi_register_loop( (char *) "go", uwsgi_gccgo_loop);
|
||||
uwsgi_register_loop( (char *) "goroutine", uwsgi_gccgo_loop);
|
||||
uwsgi_register_loop( (char *) "goroutines", uwsgi_gccgo_loop);
|
||||
}
|
||||
|
||||
struct uwsgi_plugin gccgo_plugin = {
|
||||
.name = "gccgo",
|
||||
.modifier1 = 11,
|
||||
.options = uwsgi_gccgo_options,
|
||||
//.on_load = uwsgi_gccgo_on_load,
|
||||
.on_load = uwsgi_gccgo_on_load,
|
||||
.request = uwsgi_gccgo_request,
|
||||
.after_request = uwsgi_gccgo_after_request,
|
||||
.post_fork = uwsgi_gccgo_initialize,
|
||||
|
||||
+45
-2
@@ -1,5 +1,12 @@
|
||||
package uwsgi
|
||||
|
||||
/*
|
||||
|
||||
this is a very low-level module, full of performance hacks
|
||||
do not take it as a good example of go coding...
|
||||
|
||||
*/
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"net/http"
|
||||
@@ -20,17 +27,27 @@ func uwsgi_response_add_header(*interface{}, *byte, uint16, *byte, uint16) int
|
||||
func uwsgi_request_body_read(*interface{}, *byte, uint64) int
|
||||
//extern uwsgi_gccgo_helper_register_signal
|
||||
func uwsgi_register_signal(uint8, *byte, func(uint8)) int
|
||||
//extern uwsgi_cache_magic_get
|
||||
func uwsgi_cache_magic_get(*byte, uint16, *uint64, *uint64, *byte) *byte;
|
||||
//extern __go_byte_array_to_string
|
||||
func __go_byte_array_to_string(*byte, int) string
|
||||
//extern free
|
||||
func free(* byte)
|
||||
|
||||
var uwsgi_signals_gc [256]func(uint8)
|
||||
var uwsgi_env_gc map[interface{}]interface{}
|
||||
|
||||
func Env(wsgi_req *interface{}) *map[string]string {
|
||||
var env map[string]string
|
||||
env = make(map[string]string)
|
||||
uwsgi_env_gc[wsgi_req] = &env
|
||||
return &env
|
||||
}
|
||||
|
||||
func EnvAdd(env *map[string]string, k *[65536]byte, kl uint16, v *[65536]byte, vl uint16) {
|
||||
(*env)[ string((*k)[0:kl]) ] = string((*v)[0:vl])
|
||||
func EnvAdd(env *map[string]string, k *byte, kl uint16, v *byte, vl uint16) {
|
||||
s_k := __go_byte_array_to_string(k, int(kl))
|
||||
s_v := __go_byte_array_to_string(v, int(vl))
|
||||
(*env)[ s_k ] = s_v
|
||||
}
|
||||
|
||||
type ResponseWriter struct {
|
||||
@@ -98,9 +115,13 @@ func RequestHandler(env *map[string]string, wsgi_req *interface{}) {
|
||||
w := ResponseWriter{httpReq, wsgi_req,http.Header{},false}
|
||||
http.DefaultServeMux.ServeHTTP(&w, httpReq)
|
||||
}
|
||||
delete(uwsgi_env_gc, wsgi_req)
|
||||
}
|
||||
|
||||
func RegisterSignal(signum uint8, receiver string, handler func(uint8)) bool {
|
||||
if (receiver == "") {
|
||||
receiver = "worker"
|
||||
}
|
||||
var b []byte = []byte(receiver)
|
||||
if (uwsgi_register_signal(signum, &b[0], handler) < 0) {
|
||||
return false
|
||||
@@ -109,10 +130,32 @@ func RegisterSignal(signum uint8, receiver string, handler func(uint8)) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// get an item from the cache
|
||||
func CacheGet(key string, cache string) string {
|
||||
|
||||
var b_key []byte = []byte(key)
|
||||
var v_len uint64 = 0
|
||||
var expires uint64 = 0
|
||||
var value *byte
|
||||
|
||||
if (cache == "") {
|
||||
value = uwsgi_cache_magic_get(&b_key[0], uint16(len(b_key)), &v_len, &expires, nil)
|
||||
} else {
|
||||
b_cache := []byte(cache)
|
||||
value = uwsgi_cache_magic_get(&b_key[0], uint16(len(b_key)), &v_len, &expires, &b_cache[0])
|
||||
}
|
||||
|
||||
ret := __go_byte_array_to_string(value, int(v_len))
|
||||
free(value)
|
||||
return ret
|
||||
}
|
||||
|
||||
|
||||
func SignalHandler(handler func(uint8), signum uint8) {
|
||||
handler(signum)
|
||||
}
|
||||
|
||||
func Run() {
|
||||
uwsgi_env_gc = make(map[interface{}]interface{})
|
||||
uwsgi_takeover()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import os
|
||||
NAME='gccgo'
|
||||
|
||||
CFLAGS = ['-g']
|
||||
LDFLAGS = []
|
||||
LIBS = ['-lgo']
|
||||
GCC_LIST = ['gccgo_plugin', 'uwsgi.go']
|
||||
|
||||
def post_build(config):
|
||||
if os.path.exists('plugins/gccgo/uwsgi.go.o'):
|
||||
if os.system("objcopy -j .go_export plugins/gccgo/uwsgi.go.o plugins/gccgo/uwsgi.gox") != 0:
|
||||
os._exit(1)
|
||||
print("*** uwsgi.gox available in %s/plugins/gccgo ***" % os.getcwd())
|
||||
@@ -291,7 +291,9 @@ request:
|
||||
}
|
||||
|
||||
end:
|
||||
Py_DECREF(greenlet_switch);
|
||||
if (greenlet_switch) {
|
||||
Py_DECREF(greenlet_switch);
|
||||
}
|
||||
end2:
|
||||
Py_DECREF(current_greenlet);
|
||||
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
#include <uwsgi.h>
|
||||
#include <api/glfs.h>
|
||||
|
||||
#ifdef UWSGI_MATHEVAL
|
||||
#error currently the glusterfs plugins is not compatible with uWSGI built with matheval support
|
||||
#endif
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
/*
|
||||
|
||||
@@ -16,6 +16,22 @@ static struct uwsgi_option greenlet_options[] = {
|
||||
{ 0, 0, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
struct wsgi_request *uwsgi_greenlet_current_wsgi_req(void) {
|
||||
struct wsgi_request *wsgi_req = NULL;
|
||||
PyObject *current_greenlet = (PyObject *)PyGreenlet_GetCurrent();
|
||||
PyObject *py_wsgi_req = PyObject_GetAttrString(current_greenlet, "uwsgi_wsgi_req");
|
||||
// not in greenlet
|
||||
if (!py_wsgi_req) {
|
||||
uwsgi_log("[BUG] current_wsgi_req NOT FOUND !!!\n");
|
||||
goto end;
|
||||
}
|
||||
wsgi_req = (struct wsgi_request*) PyLong_AsLong(py_wsgi_req);
|
||||
Py_DECREF(py_wsgi_req);
|
||||
end:
|
||||
Py_DECREF(current_greenlet);
|
||||
return wsgi_req;
|
||||
}
|
||||
|
||||
static void gil_greenlet_get() {
|
||||
pthread_setspecific(up.upt_gil_key, (void *) PyGILState_Ensure());
|
||||
}
|
||||
@@ -26,9 +42,11 @@ static void gil_greenlet_release() {
|
||||
|
||||
static PyObject *py_uwsgi_greenlet_request(PyObject * self, PyObject *args) {
|
||||
|
||||
struct wsgi_request *wsgi_req = uwsgi.wsgi_req;
|
||||
|
||||
async_schedule_to_req_green();
|
||||
|
||||
Py_DECREF(ugl.gl[uwsgi.wsgi_req->async_id]);
|
||||
Py_DECREF(ugl.gl[wsgi_req->async_id]);
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
@@ -46,6 +64,7 @@ static void greenlet_schedule_to_req() {
|
||||
|
||||
if (!uwsgi.wsgi_req->suspended) {
|
||||
ugl.gl[id] = PyGreenlet_New(ugl.callable, NULL);
|
||||
PyObject_SetAttrString((PyObject *)ugl.gl[id], "uwsgi_wsgi_req", PyLong_FromLong((long) uwsgi.wsgi_req));
|
||||
uwsgi.wsgi_req->suspended = 1;
|
||||
}
|
||||
|
||||
@@ -54,7 +73,13 @@ static void greenlet_schedule_to_req() {
|
||||
uwsgi.p[modifier1]->suspend(NULL);
|
||||
}
|
||||
|
||||
PyGreenlet_Switch(ugl.gl[id], NULL, NULL);
|
||||
PyObject *ret = PyGreenlet_Switch(ugl.gl[id], NULL, NULL);
|
||||
if (!ret) {
|
||||
PyErr_Print();
|
||||
uwsgi_log_verbose("[BUG] unable to switch greenlet !!!\n");
|
||||
exit(1);
|
||||
}
|
||||
Py_DECREF(ret);
|
||||
|
||||
if (uwsgi.p[modifier1]->resume) {
|
||||
uwsgi.p[modifier1]->resume(NULL);
|
||||
@@ -71,7 +96,13 @@ static void greenlet_schedule_to_main(struct wsgi_request *wsgi_req) {
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->suspend) {
|
||||
uwsgi.p[wsgi_req->uh->modifier1]->suspend(wsgi_req);
|
||||
}
|
||||
PyGreenlet_Switch(ugl.main, NULL, NULL);
|
||||
PyObject *ret = PyGreenlet_Switch(ugl.main, NULL, NULL);
|
||||
if (!ret) {
|
||||
PyErr_Print();
|
||||
uwsgi_log_verbose("[BUG] unable to switch greenlet !!!\n");
|
||||
exit(1);
|
||||
}
|
||||
Py_DECREF(ret);
|
||||
if (uwsgi.p[wsgi_req->uh->modifier1]->resume) {
|
||||
uwsgi.p[wsgi_req->uh->modifier1]->resume(wsgi_req);
|
||||
}
|
||||
@@ -93,7 +124,10 @@ static void greenlet_init_apps(void) {
|
||||
up.gil_release = gil_greenlet_release;
|
||||
}
|
||||
|
||||
// blindy call it as the stackless gil engine is already set
|
||||
// map wsgi_req to greenlet object
|
||||
uwsgi.current_wsgi_req = uwsgi_greenlet_current_wsgi_req;
|
||||
|
||||
// blindly call it as the stackless gil engine is already set
|
||||
UWSGI_GET_GIL
|
||||
|
||||
|
||||
@@ -101,7 +135,9 @@ static void greenlet_init_apps(void) {
|
||||
|
||||
ugl.gl = uwsgi_malloc( sizeof(PyGreenlet *) * uwsgi.async );
|
||||
ugl.main = PyGreenlet_GetCurrent();
|
||||
Py_INCREF(ugl.main);
|
||||
ugl.callable = PyCFunction_New(uwsgi_greenlet_request_method, NULL);
|
||||
Py_INCREF(ugl.callable);
|
||||
uwsgi_log("enabled greenlet engine\n");
|
||||
|
||||
uwsgi.schedule_to_main = greenlet_schedule_to_main;
|
||||
|
||||
@@ -139,7 +139,7 @@ void uwsgi_opt_https2(char *opt, char *value, void *cr) {
|
||||
|
||||
#ifdef UWSGI_SPDY
|
||||
spdyerror:
|
||||
uwsgi_log("unable to inizialize SPDY settings buffers\n");
|
||||
uwsgi_log("unable to initialize SPDY settings buffers\n");
|
||||
exit(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ JNIEXPORT jobject JNICALL uwsgi_jvm_api_rpc(JNIEnv *env, jclass c, jobject j_arg
|
||||
char *argv[256];
|
||||
uint16_t argvs[256];
|
||||
jobject argvj[256];
|
||||
uint16_t size = 0;
|
||||
uint64_t size = 0;
|
||||
|
||||
size_t args = uwsgi_jvm_array_len(j_args);
|
||||
if (args < 2) return NULL;
|
||||
@@ -1277,7 +1277,7 @@ void uwsgi_jvm_release_bytearray(jobject o, char *str) {
|
||||
(*ujvm_env)->ReleaseByteArrayElements(ujvm_env, o, (jbyte *)str, 0);
|
||||
}
|
||||
|
||||
static uint16_t uwsgi_jvm_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char *buffer) {
|
||||
static uint64_t uwsgi_jvm_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char **buffer) {
|
||||
jvalue args[1];
|
||||
jobject str_array = (*ujvm_env)->NewObjectArray(ujvm_env, argc, ujvm.str_class, NULL);
|
||||
if (!str_array) return 0;
|
||||
@@ -1294,9 +1294,10 @@ static uint16_t uwsgi_jvm_rpc(void *func, uint8_t argc, char **argv, uint16_t ar
|
||||
return 0;
|
||||
}
|
||||
size_t rlen = uwsgi_jvm_strlen(ret);
|
||||
if (rlen <= 0xffff) {
|
||||
if (rlen > 0) {
|
||||
*buffer = uwsgi_malloc(rlen);
|
||||
char *b = uwsgi_jvm_str2c(ret);
|
||||
memcpy(buffer, b, rlen);
|
||||
memcpy(*buffer, b, rlen);
|
||||
uwsgi_jvm_release_chars(ret, b);
|
||||
uwsgi_jvm_local_unref(ret);
|
||||
return rlen;
|
||||
|
||||
@@ -7,7 +7,11 @@ JVM_INCPATH = None
|
||||
JVM_LIBPATH = None
|
||||
|
||||
operating_system = os.uname()[0].lower()
|
||||
arch = os.uname()[4].lower()
|
||||
|
||||
try:
|
||||
arch = os.environ['JVM_ARCH']
|
||||
except:
|
||||
arch = os.uname()[4].lower()
|
||||
|
||||
if arch in ('i686', 'x86', 'x86_32'):
|
||||
arch = 'i386'
|
||||
|
||||
@@ -670,7 +670,7 @@ static int uwsgi_lua_signal_handler(uint8_t sig, void *handler) {
|
||||
|
||||
}
|
||||
|
||||
static uint16_t uwsgi_lua_rpc(void * func, uint8_t argc, char **argv, uint16_t argvs[], char *buffer) {
|
||||
static uint64_t uwsgi_lua_rpc(void * func, uint8_t argc, char **argv, uint16_t argvs[], char **buffer) {
|
||||
|
||||
uint8_t i;
|
||||
const char *sv;
|
||||
@@ -702,8 +702,9 @@ static uint16_t uwsgi_lua_rpc(void * func, uint8_t argc, char **argv, uint16_t a
|
||||
#ifdef UWSGI_DEBUG
|
||||
uwsgi_log("sv = %s sl = %lu\n", sv, (unsigned long) sl);
|
||||
#endif
|
||||
if (sl <= 0xffff) {
|
||||
memcpy(buffer, sv, sl);
|
||||
if (sl > 0) {
|
||||
*buffer = uwsgi_malloc(sl);
|
||||
memcpy(*buffer, sv, sl);
|
||||
lua_pop(L, 1);
|
||||
return sl;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#include <uwsgi.h>
|
||||
#include <matheval.h>
|
||||
|
||||
static char *uwsgi_route_var_math(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
|
||||
char *ret = NULL;
|
||||
// avoid crash
|
||||
if (!wsgi_req->var_cnt) return NULL;
|
||||
// we make a bit of fun here, we do a copy of the vars buffer (+1 byte for final zero) and zeor-pad all of the strings
|
||||
char *vars_buf = uwsgi_malloc(wsgi_req->uh->pktsize + keylen + 1);
|
||||
char **names = uwsgi_malloc(sizeof(char *) * (wsgi_req->var_cnt/2));
|
||||
double *values = uwsgi_calloc(sizeof(double) * (wsgi_req->var_cnt/2));
|
||||
int i,j = 0;
|
||||
char *ptr = vars_buf;
|
||||
for (i = wsgi_req->var_cnt-1; i > 0; i -= 2) {
|
||||
memcpy(ptr, wsgi_req->hvec[i-1].iov_base, wsgi_req->hvec[i-1].iov_len);
|
||||
names[j] = ptr;
|
||||
ptr += wsgi_req->hvec[i-1].iov_len;
|
||||
*ptr++=0;
|
||||
char *num = ptr;
|
||||
memcpy(ptr, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len);
|
||||
ptr += wsgi_req->hvec[i].iov_len;
|
||||
*ptr++=0;
|
||||
values[j] = strtod(num, NULL);
|
||||
j++;
|
||||
}
|
||||
|
||||
char *expr = ptr;
|
||||
memcpy(ptr, key, keylen); ptr += keylen;
|
||||
*ptr++=0;
|
||||
|
||||
void *e = evaluator_create(expr);
|
||||
if (!e) goto end;
|
||||
double n = evaluator_evaluate(e, j, names, values);
|
||||
evaluator_destroy(e);
|
||||
ret = uwsgi_num2str((int)n);
|
||||
*vallen = strlen(ret);
|
||||
end:
|
||||
free(vars_buf);
|
||||
free(names);
|
||||
free(values);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void router_matheval_register() {
|
||||
struct uwsgi_route_var *urv = uwsgi_register_route_var("math", uwsgi_route_var_math);
|
||||
urv->need_free = 1;
|
||||
}
|
||||
|
||||
struct uwsgi_plugin matheval_plugin = {
|
||||
.name = "matheval",
|
||||
.on_load = router_matheval_register,
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
NAME='matheval'
|
||||
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = ['-lmatheval']
|
||||
GCC_LIST = ['math']
|
||||
@@ -374,7 +374,7 @@ PHP_FUNCTION(uwsgi_rpc) {
|
||||
zval *z_current_obj;
|
||||
char *argv[256];
|
||||
uint16_t argvs[256];
|
||||
uint16_t size = 0;
|
||||
uint64_t size = 0;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &varargs, &num_args) == FAILURE) {
|
||||
RETURN_NULL();
|
||||
|
||||
@@ -58,6 +58,11 @@ struct uwsgi_perl {
|
||||
time_t last_auto_reload;
|
||||
struct uwsgi_string_list *auto_reload_ignore;
|
||||
HV *auto_reload_hash;
|
||||
|
||||
int enable_psgix_io;
|
||||
|
||||
char *shell;
|
||||
int shell_oneshot;
|
||||
};
|
||||
|
||||
void init_perl_embedded_module(void);
|
||||
|
||||
@@ -349,6 +349,7 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe
|
||||
|
||||
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);
|
||||
@@ -462,7 +463,7 @@ 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) {
|
||||
else if (uperl.exec || uperl.shell) {
|
||||
PERL_SET_CONTEXT(uperl.main[0]);
|
||||
perl_parse(uperl.main[0], xs_init, 2, uperl.embedding, NULL);
|
||||
}
|
||||
|
||||
@@ -11,9 +11,25 @@ struct uwsgi_perl uperl;
|
||||
|
||||
struct uwsgi_plugin psgi_plugin;
|
||||
|
||||
static void uwsgi_opt_plshell(char *opt, char *value, void *foobar) {
|
||||
|
||||
uwsgi.honour_stdin = 1;
|
||||
if (value) {
|
||||
uperl.shell = value;
|
||||
}
|
||||
else {
|
||||
uperl.shell = "";
|
||||
}
|
||||
|
||||
if (!strcmp("plshell-oneshot", opt)) {
|
||||
uperl.shell_oneshot = 1;
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_option uwsgi_perl_options[] = {
|
||||
|
||||
{"psgi", required_argument, 0, "load a psgi app", uwsgi_opt_set_str, &uperl.psgi, 0},
|
||||
{"psgi-enable-psgix-io", no_argument, 0, "enable psgix.io support", uwsgi_opt_true, &uperl.enable_psgix_io, 0},
|
||||
{"perl-no-die-catch", no_argument, 0, "do not catch $SIG{__DIE__}", uwsgi_opt_true, &uperl.no_die_catch, 0},
|
||||
{"perl-local-lib", required_argument, 0, "set perl locallib path", uwsgi_opt_set_str, &uperl.locallib, 0},
|
||||
#ifdef PERL_VERSION_STRING
|
||||
@@ -25,6 +41,9 @@ struct uwsgi_option uwsgi_perl_options[] = {
|
||||
{"perl-exec-post-fork", required_argument, 0, "exec the specified perl file after fork()", uwsgi_opt_add_string_list, &uperl.exec_post_fork, 0},
|
||||
{"perl-auto-reload", required_argument, 0, "enable perl auto-reloader with the specified frequency", uwsgi_opt_set_int, &uperl.auto_reload, UWSGI_OPT_MASTER},
|
||||
{"perl-auto-reload-ignore", required_argument, 0, "ignore the specified files when auto-reload is enabled", uwsgi_opt_add_string_list, &uperl.auto_reload_ignore, UWSGI_OPT_MASTER},
|
||||
|
||||
{"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},
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
|
||||
};
|
||||
@@ -102,6 +121,31 @@ SV *uwsgi_perl_obj_new(char *class, size_t class_len) {
|
||||
|
||||
}
|
||||
|
||||
SV *uwsgi_perl_obj_new_from_fd(char *class, size_t class_len, int fd) {
|
||||
SV *newobj;
|
||||
|
||||
dSP;
|
||||
|
||||
ENTER;
|
||||
SAVETMPS;
|
||||
PUSHMARK(SP);
|
||||
XPUSHs(sv_2mortal(newSVpv( class, class_len)));
|
||||
XPUSHs(sv_2mortal(newSViv( fd )));
|
||||
XPUSHs(sv_2mortal(newSVpv( "w", 1 )));
|
||||
PUTBACK;
|
||||
|
||||
call_method( "new_from_fd", G_SCALAR);
|
||||
|
||||
SPAGAIN;
|
||||
|
||||
newobj = SvREFCNT_inc(POPs);
|
||||
PUTBACK;
|
||||
FREETMPS;
|
||||
LEAVE;
|
||||
|
||||
return newobj;
|
||||
}
|
||||
|
||||
SV *uwsgi_perl_call_stream(SV *func) {
|
||||
|
||||
SV *ret = NULL;
|
||||
@@ -245,7 +289,10 @@ AV *psgi_call(struct wsgi_request *wsgi_req, SV *psgi_func, SV *env) {
|
||||
uwsgi_log("[uwsgi-perl error] %s", SvPV_nolen(ERRSV));
|
||||
}
|
||||
else {
|
||||
ret = (AV *) SvREFCNT_inc(SvRV(POPs));
|
||||
SV *r = POPs;
|
||||
if (SvROK(r)) {
|
||||
ret = (AV *) SvREFCNT_inc(SvRV(r));
|
||||
}
|
||||
}
|
||||
|
||||
PUTBACK;
|
||||
@@ -360,7 +407,12 @@ SV *build_psgi_env(struct wsgi_request *wsgi_req) {
|
||||
// cleanup handlers array
|
||||
av = newAV();
|
||||
if (!hv_store(env, "psgix.cleanup.handlers", 22, newRV_noinc((SV *)av ), 0)) goto clear;
|
||||
|
||||
|
||||
// this call requires a bunch of syscalls, so it hurts performance
|
||||
if (uperl.enable_psgix_io) {
|
||||
SV *io = uwsgi_perl_obj_new_from_fd("IO::Socket", 10, wsgi_req->fd);
|
||||
if (!hv_store(env, "psgix.io", 8, io, 0)) goto clear;
|
||||
}
|
||||
|
||||
SV *pe = uwsgi_perl_obj_new("uwsgi::error", 12);
|
||||
if (!hv_store(env, "psgi.errors", 11, pe, 0)) goto clear;
|
||||
@@ -764,10 +816,10 @@ realstuff:
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t uwsgi_perl_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char *buffer) {
|
||||
static uint64_t uwsgi_perl_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char **buffer) {
|
||||
|
||||
int i;
|
||||
uint16_t ret = 0;
|
||||
uint64_t ret = 0;
|
||||
|
||||
dSP;
|
||||
ENTER;
|
||||
@@ -788,8 +840,11 @@ static uint16_t uwsgi_perl_rpc(void *func, uint8_t argc, char **argv, uint16_t a
|
||||
STRLEN rlen;
|
||||
SV *response = POPs;
|
||||
char *value = SvPV(response, rlen );
|
||||
ret = UMIN(UMAX16-1, rlen);
|
||||
memcpy(buffer, value, ret);
|
||||
if (rlen > 0) {
|
||||
*buffer = uwsgi_malloc(rlen);
|
||||
memcpy(*buffer, value, rlen);
|
||||
ret = rlen;
|
||||
}
|
||||
}
|
||||
|
||||
PUTBACK;
|
||||
@@ -799,6 +854,39 @@ static uint16_t uwsgi_perl_rpc(void *func, uint8_t argc, char **argv, uint16_t a
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void uwsgi_perl_hijack(void) {
|
||||
if (uperl.shell_oneshot && uwsgi.workers[uwsgi.mywid].hijacked_count > 0) {
|
||||
uwsgi.workers[uwsgi.mywid].hijacked = 0;
|
||||
return;
|
||||
}
|
||||
if (uperl.shell && uwsgi.mywid == 1) {
|
||||
uwsgi.workers[uwsgi.mywid].hijacked = 1;
|
||||
uwsgi.workers[uwsgi.mywid].hijacked_count++;
|
||||
// re-map stdin to stdout and stderr if we are logging to a file
|
||||
if (uwsgi.logfile) {
|
||||
if (dup2(0, 1) < 0) {
|
||||
uwsgi_error("dup2()");
|
||||
}
|
||||
if (dup2(0, 2) < 0) {
|
||||
uwsgi_error("dup2()");
|
||||
}
|
||||
}
|
||||
|
||||
if (uperl.shell[0] != 0) {
|
||||
perl_eval_pv(uperl.shell, 0);
|
||||
}
|
||||
else {
|
||||
perl_eval_pv("use Devel::REPL;my $repl = Devel::REPL->new;$repl->run;", 0);
|
||||
}
|
||||
if (uperl.shell_oneshot) {
|
||||
exit(UWSGI_DE_HIJACKED_CODE);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_plugin psgi_plugin = {
|
||||
|
||||
.name = "psgi",
|
||||
@@ -815,6 +903,8 @@ struct uwsgi_plugin psgi_plugin = {
|
||||
|
||||
.mule = uwsgi_perl_mule,
|
||||
|
||||
.hijack_worker = uwsgi_perl_hijack,
|
||||
|
||||
.post_fork = uwsgi_perl_post_fork,
|
||||
.request = uwsgi_perl_request,
|
||||
.after_request = uwsgi_perl_after_request,
|
||||
|
||||
@@ -76,12 +76,16 @@ int psgi_response(struct wsgi_request *wsgi_req, AV *response) {
|
||||
if (!headers) { uwsgi_log("invalid PSGI headers\n"); return UWSGI_OK;}
|
||||
|
||||
// generate headers
|
||||
for(i=0; i<=av_len(headers); i++) {
|
||||
int headers_len = (int) av_len(headers);
|
||||
for(i=0; i<=headers_len; i++) {
|
||||
hitem = av_fetch(headers,i,0);
|
||||
if (!*hitem) {
|
||||
uwsgi_log("invalid PSGI headers\n"); return UWSGI_OK;
|
||||
}
|
||||
chitem = SvPV(*hitem, hlen);
|
||||
if (i+1 > headers_len) {
|
||||
uwsgi_log("invalid PSGI headers\n"); return UWSGI_OK;
|
||||
}
|
||||
hitem = av_fetch(headers,i+1,0);
|
||||
if (!*hitem) {
|
||||
uwsgi_log("invalid PSGI headers\n"); return UWSGI_OK;
|
||||
|
||||
@@ -324,7 +324,7 @@ XS(XS_call) {
|
||||
dXSARGS;
|
||||
|
||||
char *func;
|
||||
uint16_t size = 0;
|
||||
uint64_t size = 0;
|
||||
int i;
|
||||
char *argv[256];
|
||||
uint16_t argvs[256];
|
||||
@@ -351,6 +351,41 @@ XS(XS_call) {
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
|
||||
XS(XS_rpc) {
|
||||
|
||||
dXSARGS;
|
||||
|
||||
char *node;
|
||||
char *func;
|
||||
uint64_t size = 0;
|
||||
int i;
|
||||
char *argv[256];
|
||||
uint16_t argvs[256];
|
||||
STRLEN arg_len;
|
||||
|
||||
psgi_check_args(2);
|
||||
|
||||
node = SvPV_nolen(ST(0));
|
||||
func = SvPV_nolen(ST(1));
|
||||
|
||||
for(i=0;i<(items-2);i++) {
|
||||
argv[i] = SvPV(ST(i+2), arg_len);
|
||||
argvs[i] = arg_len;
|
||||
}
|
||||
|
||||
// response must be always freed
|
||||
char *response = uwsgi_do_rpc(node, func, items-2, argv, argvs, &size);
|
||||
if (response) {
|
||||
ST(0) = newSVpv(response, size);
|
||||
sv_2mortal(ST(0));
|
||||
free(response);
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
|
||||
|
||||
|
||||
XS(XS_suspend) {
|
||||
|
||||
@@ -404,9 +439,20 @@ XS(XS_i_am_the_lord) {
|
||||
}
|
||||
XSRETURN_NO;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
XS(XS_connection_fd) {
|
||||
dXSARGS;
|
||||
|
||||
psgi_check_args(0);
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
ST(0) = newSViv(wsgi_req->fd);
|
||||
sv_2mortal(ST(0));
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_websocket_handshake) {
|
||||
|
||||
dXSARGS;
|
||||
@@ -524,7 +570,143 @@ XS(XS_add_rb_timer) {
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_metric_inc) {
|
||||
dXSARGS;
|
||||
char *metric = NULL;
|
||||
STRLEN metric_len = 0;
|
||||
int64_t value = 1;
|
||||
psgi_check_args(1);
|
||||
metric = SvPV(ST(0), metric_len);
|
||||
if (items > 1) {
|
||||
value = (int64_t) SvIV(ST(1));
|
||||
}
|
||||
if (uwsgi_metric_inc(metric, NULL, value)) {
|
||||
croak("unable to update metric");
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
XSRETURN_YES;
|
||||
}
|
||||
|
||||
XS(XS_metric_dec) {
|
||||
dXSARGS;
|
||||
char *metric = NULL;
|
||||
STRLEN metric_len = 0;
|
||||
int64_t value = 1;
|
||||
psgi_check_args(1);
|
||||
metric = SvPV(ST(0), metric_len);
|
||||
if (items > 1) {
|
||||
value = (int64_t) SvIV(ST(1));
|
||||
}
|
||||
if (uwsgi_metric_dec(metric, NULL, value)) {
|
||||
croak("unable to update metric");
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
XSRETURN_YES;
|
||||
}
|
||||
|
||||
XS(XS_metric_mul) {
|
||||
dXSARGS;
|
||||
char *metric = NULL;
|
||||
STRLEN metric_len = 0;
|
||||
int64_t value = 1;
|
||||
psgi_check_args(1);
|
||||
metric = SvPV(ST(0), metric_len);
|
||||
if (items > 1) {
|
||||
value = (int64_t) SvIV(ST(1));
|
||||
}
|
||||
if (uwsgi_metric_mul(metric, NULL, value)) {
|
||||
croak("unable to update metric");
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
XSRETURN_YES;
|
||||
}
|
||||
|
||||
XS(XS_metric_div) {
|
||||
dXSARGS;
|
||||
char *metric = NULL;
|
||||
STRLEN metric_len = 0;
|
||||
int64_t value = 1;
|
||||
psgi_check_args(1);
|
||||
metric = SvPV(ST(0), metric_len);
|
||||
if (items > 1) {
|
||||
value = (int64_t) SvIV(ST(1));
|
||||
}
|
||||
if (uwsgi_metric_div(metric, NULL, value)) {
|
||||
croak("unable to update metric");
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
XSRETURN_YES;
|
||||
}
|
||||
|
||||
XS(XS_metric_set) {
|
||||
dXSARGS;
|
||||
char *metric = NULL;
|
||||
STRLEN metric_len = 0;
|
||||
int64_t value = 0;
|
||||
psgi_check_args(2);
|
||||
metric = SvPV(ST(0), metric_len);
|
||||
value = (int64_t) SvIV(ST(1));
|
||||
if (uwsgi_metric_set(metric, NULL, value)) {
|
||||
croak("unable to update metric");
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
XSRETURN_YES;
|
||||
}
|
||||
|
||||
XS(XS_metric_get) {
|
||||
dXSARGS;
|
||||
|
||||
char *metric = NULL;
|
||||
STRLEN metric_len = 0;
|
||||
|
||||
psgi_check_args(1);
|
||||
|
||||
metric = SvPV(ST(0), metric_len);
|
||||
|
||||
ST(0) = newSViv(uwsgi_metric_get(metric, NULL));
|
||||
sv_2mortal(ST(0));
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_chunked_read) {
|
||||
dXSARGS;
|
||||
int timeout = 0;
|
||||
size_t len = 0;
|
||||
|
||||
psgi_check_args(0);
|
||||
if (items > 0) {
|
||||
timeout = SvIV(ST(0));
|
||||
}
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
char *chunk = uwsgi_chunked_read(wsgi_req, &len, timeout, 0);
|
||||
if (!chunk) {
|
||||
croak("unable to receive chunked part");
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
|
||||
ST(0) = newSVpv(chunk, len);
|
||||
sv_2mortal(ST(0));
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_chunked_read_nb) {
|
||||
dXSARGS;
|
||||
size_t len = 0;
|
||||
|
||||
psgi_check_args(0);
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
char *chunk = uwsgi_chunked_read(wsgi_req, &len, 0, 1);
|
||||
if (!chunk) {
|
||||
if (uwsgi_is_again()) XSRETURN_UNDEF;
|
||||
croak("unable to receive chunked part");
|
||||
XSRETURN_UNDEF;
|
||||
}
|
||||
|
||||
ST(0) = newSVpv(chunk, len);
|
||||
sv_2mortal(ST(0));
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
void init_perl_embedded_module() {
|
||||
psgi_xs(reload);
|
||||
@@ -536,6 +718,7 @@ void init_perl_embedded_module() {
|
||||
psgi_xs(cache_clear);
|
||||
|
||||
psgi_xs(call);
|
||||
psgi_xs(rpc);
|
||||
psgi_xs(wait_fd_read);
|
||||
psgi_xs(wait_fd_write);
|
||||
psgi_xs(async_sleep);
|
||||
@@ -549,6 +732,9 @@ void init_perl_embedded_module() {
|
||||
#ifdef UWSGI_SSL
|
||||
psgi_xs(i_am_the_lord);
|
||||
#endif
|
||||
|
||||
psgi_xs(connection_fd);
|
||||
|
||||
psgi_xs(alarm);
|
||||
psgi_xs(websocket_handshake);
|
||||
psgi_xs(websocket_recv);
|
||||
@@ -561,5 +747,15 @@ void init_perl_embedded_module() {
|
||||
psgi_xs(add_rb_timer);
|
||||
|
||||
psgi_xs(set_user_harakiri);
|
||||
|
||||
psgi_xs(metric_inc);
|
||||
psgi_xs(metric_dec);
|
||||
psgi_xs(metric_mul);
|
||||
psgi_xs(metric_div);
|
||||
psgi_xs(metric_get);
|
||||
psgi_xs(metric_set);
|
||||
|
||||
psgi_xs(chunked_read);
|
||||
psgi_xs(chunked_read_nb);
|
||||
}
|
||||
|
||||
|
||||
@@ -149,6 +149,7 @@ static void *uwsgi_pty_loop(void *arg) {
|
||||
if (rlen == 0) exit(1);
|
||||
if (rlen < 0) {
|
||||
uwsgi_error("uwsgi_pty_loop()/read()");
|
||||
continue;
|
||||
}
|
||||
if (upty.log && upty.original_log >= 0) {
|
||||
if (write(upty.original_log, buf, rlen) != rlen) {
|
||||
|
||||
@@ -274,10 +274,10 @@ static int uwsgi_pypy_signal_handler(uint8_t sig, void *handler) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint16_t uwsgi_pypy_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char *buffer) {
|
||||
static uint64_t uwsgi_pypy_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char **buffer) {
|
||||
int iargvs[UMAX8];
|
||||
int i;
|
||||
int (*pypy_func)(int, char **, int*, char *) = (int (*)(int, char **, int*, char *)) func;
|
||||
int (*pypy_func)(int, char **, int*, char **) = (int (*)(int, char **, int*, char **)) func;
|
||||
// we convert 16bit to int
|
||||
for(i=0;i<argc;i++) {
|
||||
iargvs[i] = (int) argvs[i];
|
||||
@@ -313,6 +313,7 @@ static void uwsgi_pypy_onload() {
|
||||
#ifdef UWSGI_PYPY_HOME
|
||||
upypy.home = UWSGI_PYPY_HOME;
|
||||
#endif
|
||||
uwsgi.has_threads = 1;
|
||||
}
|
||||
|
||||
static int uwsgi_pypy_mule(char *opt) {
|
||||
|
||||
@@ -172,6 +172,8 @@ const char *uwsgi_pypy_version;
|
||||
|
||||
char *uwsgi_binary_path();
|
||||
|
||||
void *uwsgi_malloc(size_t);
|
||||
|
||||
int uwsgi_response_prepare_headers(struct wsgi_request *, char *, size_t);
|
||||
int uwsgi_response_add_header(struct wsgi_request *, char *, uint16_t, char *, uint16_t);
|
||||
int uwsgi_response_write_body_do(struct wsgi_request *, char *, size_t);
|
||||
@@ -186,7 +188,7 @@ int uwsgi_is_again();
|
||||
int uwsgi_register_rpc(char *, struct uwsgi_plugin *, uint8_t, void *);
|
||||
int uwsgi_register_signal(uint8_t, char *, void *, uint8_t);
|
||||
|
||||
char *uwsgi_do_rpc(char *, char *, uint8_t, char **, uint16_t *, uint16_t *);
|
||||
char *uwsgi_do_rpc(char *, char *, uint8_t, char **, uint16_t *, uint64_t *);
|
||||
|
||||
void uwsgi_set_processname(char *);
|
||||
int uwsgi_signal_send(int, uint8_t);
|
||||
@@ -235,6 +237,13 @@ int uwsgi_ready_fd(struct wsgi_request *);
|
||||
|
||||
void set_user_harakiri(int);
|
||||
|
||||
int uwsgi_metric_set(char *, char *, int64_t);
|
||||
int uwsgi_metric_inc(char *, char *, int64_t);
|
||||
int uwsgi_metric_dec(char *, char *, int64_t);
|
||||
int uwsgi_metric_mul(char *, char *, int64_t);
|
||||
int uwsgi_metric_div(char *, char *, int64_t);
|
||||
int64_t uwsgi_metric_get(char *, char *);
|
||||
|
||||
%s
|
||||
|
||||
''' % ('\n'.join(uwsgi_cdef), hooks)
|
||||
@@ -483,15 +492,16 @@ class uwsgi_pypy_RPC(object):
|
||||
for i in range(0, argc):
|
||||
pargs.append(ffi.string(argv[i], argvs[i]))
|
||||
response = self.func(*pargs)
|
||||
if len(response) > 0 and len(response) <= 65535:
|
||||
dst = ffi.buffer(buf, 65536)
|
||||
if len(response) > 0:
|
||||
buf[0] = lib.uwsgi_malloc(len(response))
|
||||
dst = ffi.buffer(buf[0], len(response))
|
||||
dst[:len(response)] = response
|
||||
return len(response)
|
||||
|
||||
|
||||
def uwsgi_pypy_uwsgi_register_rpc(name, func, argc=0):
|
||||
rpc_func = uwsgi_pypy_RPC(func)
|
||||
cb = ffi.callback("int(int, char*[], int[], char*)", rpc_func)
|
||||
cb = ffi.callback("int(int, char*[], int[], char**)", rpc_func)
|
||||
uwsgi_gc.append(cb)
|
||||
if lib.uwsgi_register_rpc(ffi.new("char[]", name), ffi.addressof(lib.pypy_plugin), argc, cb) < 0:
|
||||
raise Exception("unable to register rpc func %s" % name)
|
||||
@@ -501,7 +511,7 @@ def uwsgi_pypy_rpc(node, func, *args):
|
||||
argc = 0
|
||||
argv = ffi.new('char*[256]')
|
||||
argvs = ffi.new('uint16_t[256]')
|
||||
rsize = ffi.new('uint16_t*')
|
||||
rsize = ffi.new('uint64_t*')
|
||||
|
||||
for arg in args:
|
||||
if argc >= 255:
|
||||
@@ -534,6 +544,12 @@ uwsgi.call = uwsgi_pypy_call
|
||||
|
||||
uwsgi.signal = lambda x: lib.uwsgi_signal_send(lib.uwsgi.signal_socket, x)
|
||||
|
||||
uwsgi.metric_get = lambda x: lib.uwsgi_metric_get(x, ffi.NULL)
|
||||
uwsgi.metric_set = lambda x, y: lib.uwsgi_metric_set(x, ffi.NULL, y)
|
||||
uwsgi.metric_inc = lambda x, y=1: lib.uwsgi_metric_inc(x, ffi.NULL, y)
|
||||
uwsgi.metric_dec = lambda x, y=1: lib.uwsgi_metric_dec(x, ffi.NULL, y)
|
||||
uwsgi.metric_mul = lambda x, y=1: lib.uwsgi_metric_mul(x, ffi.NULL, y)
|
||||
uwsgi.metric_div = lambda x, y=1: lib.uwsgi_metric_div(x, ffi.NULL, y)
|
||||
|
||||
def uwsgi_pypy_uwsgi_cache_get(key, cache=ffi.NULL):
|
||||
vallen = ffi.new('uint64_t*')
|
||||
|
||||
@@ -167,7 +167,7 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
|
||||
PyThreadState_Swap(wi->interpreter);
|
||||
init_pyargv();
|
||||
|
||||
// we need to inizialize an embedded module for every interpreter
|
||||
// we need to initialize an embedded module for every interpreter
|
||||
init_uwsgi_embedded_module();
|
||||
init_uwsgi_vars();
|
||||
|
||||
@@ -205,7 +205,7 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
|
||||
app_list = PyDict_Keys(applications);
|
||||
multiapp = PyList_Size(app_list);
|
||||
if (multiapp < 1) {
|
||||
uwsgi_log("you have to define at least one app in the apllications dictionary\n");
|
||||
uwsgi_log("you have to define at least one app in the applications dictionary\n");
|
||||
goto doh;
|
||||
}
|
||||
|
||||
@@ -227,6 +227,10 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
|
||||
PyObject *callables_dict = get_uwsgi_pydict((char *)arg1);
|
||||
if (callables_dict) {
|
||||
wi->callable = PyDict_GetItem(callables_dict, (PyObject *)wi->callable);
|
||||
if (!wi->callable) {
|
||||
uwsgi_log("skipping broken app %s\n", wsgi_req->appid);
|
||||
goto multiapp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -336,9 +340,11 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
|
||||
|
||||
const char *default_app = "";
|
||||
|
||||
if ((wsgi_req->appid_len == 0 || (wsgi_req->appid_len = 1 && wsgi_req->appid[0] == '/')) && uwsgi.default_app == -1) {
|
||||
default_app = " (default app)" ;
|
||||
uwsgi.default_app = id;
|
||||
if (!uwsgi.no_default_app) {
|
||||
if ((wsgi_req->appid_len == 0 || (wsgi_req->appid_len = 1 && wsgi_req->appid[0] == '/')) && uwsgi.default_app == -1) {
|
||||
default_app = " (default app)" ;
|
||||
uwsgi.default_app = id;
|
||||
}
|
||||
}
|
||||
|
||||
wi->started_at = now;
|
||||
@@ -357,6 +363,7 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
|
||||
|
||||
uwsgi_apps_cnt++;
|
||||
|
||||
multiapp:
|
||||
if (multiapp > 1) {
|
||||
for(i=1;i<multiapp;i++) {
|
||||
PyObject *app_mnt = PyList_GetItem(app_list, i);
|
||||
|
||||
@@ -1522,7 +1522,7 @@ clear:
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint16_t uwsgi_python_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char *buffer) {
|
||||
uint64_t uwsgi_python_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char **buffer) {
|
||||
|
||||
UWSGI_GET_GIL;
|
||||
|
||||
@@ -1546,8 +1546,9 @@ uint16_t uwsgi_python_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[
|
||||
if (PyString_Check(ret)) {
|
||||
rv = PyString_AsString(ret);
|
||||
rl = PyString_Size(ret);
|
||||
if (rl <= 65536) {
|
||||
memcpy(buffer, rv, rl);
|
||||
if (rl > 0) {
|
||||
*buffer = uwsgi_malloc(rl);
|
||||
memcpy(*buffer, rv, rl);
|
||||
Py_DECREF(ret);
|
||||
UWSGI_RELEASE_GIL;
|
||||
return rl;
|
||||
|
||||
@@ -265,7 +265,7 @@ PyObject *py_uwsgi_add_file_monitor(PyObject * self, PyObject * args) {
|
||||
PyObject *py_uwsgi_call(PyObject * self, PyObject * args) {
|
||||
|
||||
char *func;
|
||||
uint16_t size = 0;
|
||||
uint64_t size = 0;
|
||||
PyObject *py_func;
|
||||
int argc = PyTuple_Size(args);
|
||||
int i;
|
||||
@@ -331,7 +331,7 @@ PyObject *py_uwsgi_rpc_list(PyObject * self, PyObject * args) {
|
||||
PyObject *py_uwsgi_rpc(PyObject * self, PyObject * args) {
|
||||
|
||||
char *node = NULL, *func;
|
||||
uint16_t size = 0;
|
||||
uint64_t size = 0;
|
||||
PyObject *py_node, *py_func;
|
||||
|
||||
int argc = PyTuple_Size(args);
|
||||
@@ -3169,6 +3169,111 @@ static PyMethodDef uwsgi_queue_methods[] = {
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
PyObject *py_uwsgi_metric_inc(PyObject * self, PyObject * args) {
|
||||
char *key;
|
||||
int64_t value = 1;
|
||||
if (!PyArg_ParseTuple(args, "s|l:metric_inc", &key, &value)) return NULL;
|
||||
|
||||
UWSGI_RELEASE_GIL
|
||||
if (uwsgi_metric_inc(key, NULL, value)) {
|
||||
UWSGI_GET_GIL
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
UWSGI_GET_GIL
|
||||
Py_INCREF(Py_True);
|
||||
return Py_True;
|
||||
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_metric_dec(PyObject * self, PyObject * args) {
|
||||
char *key;
|
||||
int64_t value = 1;
|
||||
if (!PyArg_ParseTuple(args, "s|l:metric_dec", &key, &value)) return NULL;
|
||||
|
||||
UWSGI_RELEASE_GIL
|
||||
if (uwsgi_metric_dec(key, NULL, value)) {
|
||||
UWSGI_GET_GIL
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
UWSGI_GET_GIL
|
||||
Py_INCREF(Py_True);
|
||||
return Py_True;
|
||||
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_metric_mul(PyObject * self, PyObject * args) {
|
||||
char *key;
|
||||
int64_t value = 1;
|
||||
if (!PyArg_ParseTuple(args, "s|l:metric_mul", &key, &value)) return NULL;
|
||||
|
||||
UWSGI_RELEASE_GIL
|
||||
if (uwsgi_metric_mul(key, NULL, value)) {
|
||||
UWSGI_GET_GIL
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
UWSGI_GET_GIL
|
||||
Py_INCREF(Py_True);
|
||||
return Py_True;
|
||||
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_metric_div(PyObject * self, PyObject * args) {
|
||||
char *key;
|
||||
int64_t value = 1;
|
||||
if (!PyArg_ParseTuple(args, "s|l:metric_div", &key, &value)) return NULL;
|
||||
|
||||
UWSGI_RELEASE_GIL
|
||||
if (uwsgi_metric_div(key, NULL, value)) {
|
||||
UWSGI_GET_GIL
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
UWSGI_GET_GIL
|
||||
Py_INCREF(Py_True);
|
||||
return Py_True;
|
||||
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_metric_set(PyObject * self, PyObject * args) {
|
||||
char *key;
|
||||
int64_t value = 1;
|
||||
if (!PyArg_ParseTuple(args, "s|l:metric_set", &key, &value)) return NULL;
|
||||
|
||||
UWSGI_RELEASE_GIL
|
||||
if (uwsgi_metric_set(key, NULL, value)) {
|
||||
UWSGI_GET_GIL
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
UWSGI_GET_GIL
|
||||
Py_INCREF(Py_True);
|
||||
return Py_True;
|
||||
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_metric_get(PyObject * self, PyObject * args) {
|
||||
char *key;
|
||||
if (!PyArg_ParseTuple(args, "s:metric_get", &key)) return NULL;
|
||||
|
||||
UWSGI_RELEASE_GIL
|
||||
int64_t value = uwsgi_metric_get(key, NULL);
|
||||
UWSGI_GET_GIL
|
||||
return PyLong_FromLongLong(value);
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef uwsgi_metrics_methods[] = {
|
||||
{"metric_inc", py_uwsgi_metric_inc, METH_VARARGS, ""},
|
||||
{"metric_dec", py_uwsgi_metric_dec, METH_VARARGS, ""},
|
||||
{"metric_mul", py_uwsgi_metric_mul, METH_VARARGS, ""},
|
||||
{"metric_div", py_uwsgi_metric_div, METH_VARARGS, ""},
|
||||
{"metric_get", py_uwsgi_metric_get, METH_VARARGS, ""},
|
||||
{"metric_set", py_uwsgi_metric_set, METH_VARARGS, ""},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
|
||||
void init_uwsgi_module_spooler(PyObject * current_uwsgi_module) {
|
||||
@@ -3204,6 +3309,12 @@ void init_uwsgi_module_advanced(PyObject * current_uwsgi_module) {
|
||||
Py_DECREF(func);
|
||||
}
|
||||
|
||||
for (uwsgi_function = uwsgi_metrics_methods; uwsgi_function->ml_name != NULL; uwsgi_function++) {
|
||||
PyObject *func = PyCFunction_New(uwsgi_function, NULL);
|
||||
PyDict_SetItemString(uwsgi_module_dict, uwsgi_function->ml_name, func);
|
||||
Py_DECREF(func);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void init_uwsgi_module_cache(PyObject * current_uwsgi_module) {
|
||||
|
||||
@@ -18,13 +18,15 @@ extern PyTypeObject uwsgi_InputType;
|
||||
*/
|
||||
|
||||
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
|
||||
char *content = NULL;
|
||||
size_t content_len = 0;
|
||||
|
||||
#if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER)
|
||||
if (PyObject_CheckBuffer(chunk)) {
|
||||
if (!PyObject_GetBuffer(chunk, &pbuf, PyBUF_SIMPLE)) {
|
||||
@@ -36,10 +38,18 @@ int uwsgi_python_send_body(struct wsgi_request *wsgi_req, PyObject *chunk) {
|
||||
}
|
||||
#else
|
||||
if (PyObject_CheckReadBuffer(chunk)) {
|
||||
#ifdef UWSGI_PYTHON_OLD
|
||||
int buffer_len = 0;
|
||||
if (!PyObject_AsCharBuffer(chunk, (const char **) &content, &buffer_len)) {
|
||||
#else
|
||||
if (!PyObject_AsCharBuffer(chunk, (const char **) &content, (Py_ssize_t *) &content_len)) {
|
||||
#endif
|
||||
PyErr_Clear();
|
||||
goto found;
|
||||
}
|
||||
#ifdef UWSGI_PYTHON_OLD
|
||||
content_len = buffer_len;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+97
-1
@@ -7,6 +7,88 @@ extern struct uwsgi_plugin rack_plugin;
|
||||
|
||||
#define uwsgi_rack_api(x, y, z) rb_define_module_function(rb_uwsgi_embedded, x, y, z)
|
||||
|
||||
static VALUE rack_uwsgi_metric_get(VALUE *class, VALUE key) {
|
||||
Check_Type(key, T_STRING);
|
||||
int64_t value = uwsgi_metric_get(RSTRING_PTR(key), NULL);
|
||||
return LONG2NUM(value);
|
||||
}
|
||||
|
||||
static VALUE rack_uwsgi_metric_set(VALUE *class, VALUE key, VALUE val) {
|
||||
Check_Type(key, T_STRING);
|
||||
Check_Type(val, T_FIXNUM); // should be T_BIGNUM...
|
||||
if (uwsgi_metric_set(RSTRING_PTR(key), NULL, NUM2LONG(val) )) {
|
||||
return Qnil;
|
||||
}
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
static VALUE rack_uwsgi_metric_inc(int argc, VALUE *argv, VALUE *class) {
|
||||
int64_t value = 1;
|
||||
if (argc == 0) return Qnil;
|
||||
Check_Type(argv[0], T_STRING);
|
||||
|
||||
if (argc > 1) {
|
||||
Check_Type(argv[1], T_FIXNUM); // should be T_BIGNUM...
|
||||
value = NUM2LONG(argv[1]);
|
||||
}
|
||||
|
||||
if (uwsgi_metric_inc(RSTRING_PTR(argv[0]), NULL, value )) {
|
||||
return Qnil;
|
||||
}
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
static VALUE rack_uwsgi_metric_dec(int argc, VALUE *argv, VALUE *class) {
|
||||
int64_t value = 1;
|
||||
if (argc == 0) return Qnil;
|
||||
Check_Type(argv[0], T_STRING);
|
||||
|
||||
if (argc > 1) {
|
||||
Check_Type(argv[1], T_FIXNUM); // should be T_BIGNUM...
|
||||
value = NUM2LONG(argv[1]);
|
||||
}
|
||||
|
||||
if (uwsgi_metric_dec(RSTRING_PTR(argv[0]), NULL, value )) {
|
||||
return Qnil;
|
||||
}
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
static VALUE rack_uwsgi_metric_mul(int argc, VALUE *argv, VALUE *class) {
|
||||
int64_t value = 1;
|
||||
if (argc == 0) return Qnil;
|
||||
Check_Type(argv[0], T_STRING);
|
||||
|
||||
if (argc > 1) {
|
||||
Check_Type(argv[1], T_FIXNUM); // should be T_BIGNUM...
|
||||
value = NUM2LONG(argv[1]);
|
||||
}
|
||||
|
||||
if (uwsgi_metric_mul(RSTRING_PTR(argv[0]), NULL, value )) {
|
||||
return Qnil;
|
||||
}
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
static VALUE rack_uwsgi_metric_div(int argc, VALUE *argv, VALUE *class) {
|
||||
int64_t value = 1;
|
||||
if (argc == 0) return Qnil;
|
||||
Check_Type(argv[0], T_STRING);
|
||||
|
||||
if (argc > 1) {
|
||||
Check_Type(argv[1], T_FIXNUM); // should be T_BIGNUM...
|
||||
value = NUM2LONG(argv[1]);
|
||||
}
|
||||
|
||||
if (uwsgi_metric_div(RSTRING_PTR(argv[0]), NULL, value )) {
|
||||
return Qnil;
|
||||
}
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static VALUE rack_uwsgi_warning(VALUE *class, VALUE rbmessage) {
|
||||
|
||||
Check_Type(rbmessage, T_STRING);
|
||||
@@ -59,6 +141,11 @@ static VALUE rack_uwsgi_i_am_the_lord(VALUE *class, VALUE legion_name) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static VALUE rack_uwsgi_connection_fd(VALUE *class) {
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
return INT2NUM(wsgi_req->fd);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static VALUE rack_uwsgi_setprocname(VALUE *class, VALUE rbname) {
|
||||
@@ -718,7 +805,7 @@ static VALUE uwsgi_ruby_signal_registered(VALUE *class, VALUE signum) {
|
||||
static VALUE uwsgi_ruby_do_rpc(int argc, VALUE *rpc_argv, VALUE *class) {
|
||||
|
||||
char *node = NULL, *func;
|
||||
uint16_t size = 0;
|
||||
uint64_t size = 0;
|
||||
|
||||
char *argv[256];
|
||||
uint16_t argvs[256];
|
||||
@@ -1084,6 +1171,8 @@ void uwsgi_rack_init_api() {
|
||||
#ifdef UWSGI_SSL
|
||||
uwsgi_rack_api("i_am_the_lord", rack_uwsgi_i_am_the_lord, 1);
|
||||
#endif
|
||||
|
||||
uwsgi_rack_api("connection_fd", rack_uwsgi_connection_fd, 0);
|
||||
|
||||
|
||||
uwsgi_rack_api("cache_get", rack_uwsgi_cache_get, -1);
|
||||
@@ -1099,6 +1188,13 @@ void uwsgi_rack_init_api() {
|
||||
uwsgi_rack_api("cache_clear", rack_uwsgi_cache_clear, -1);
|
||||
uwsgi_rack_api("cache_clear!", rack_uwsgi_cache_clear_exc, -1);
|
||||
|
||||
uwsgi_rack_api("metric_get", rack_uwsgi_metric_get, 1);
|
||||
uwsgi_rack_api("metric_set", rack_uwsgi_metric_set, 2);
|
||||
uwsgi_rack_api("metric_inc", rack_uwsgi_metric_inc, -1);
|
||||
uwsgi_rack_api("metric_dec", rack_uwsgi_metric_dec, -1);
|
||||
uwsgi_rack_api("metric_mul", rack_uwsgi_metric_mul, -1);
|
||||
uwsgi_rack_api("metric_div", rack_uwsgi_metric_div, -1);
|
||||
|
||||
VALUE uwsgi_rb_opt_hash = rb_hash_new();
|
||||
int i;
|
||||
for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
|
||||
|
||||
@@ -315,7 +315,7 @@ VALUE rack_call_rpc_handler(VALUE args) {
|
||||
}
|
||||
|
||||
|
||||
uint16_t uwsgi_ruby_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char *buffer) {
|
||||
uint64_t uwsgi_ruby_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char **buffer) {
|
||||
|
||||
uint8_t i;
|
||||
VALUE rb_args = rb_ary_new2(2);
|
||||
@@ -343,8 +343,9 @@ uint16_t uwsgi_ruby_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[],
|
||||
if (TYPE(ret) == T_STRING) {
|
||||
rv = RSTRING_PTR(ret);
|
||||
rl = RSTRING_LEN(ret);
|
||||
if (rl <= 0xffff) {
|
||||
memcpy(buffer, rv, rl);
|
||||
if (rl > 0) {
|
||||
*buffer = uwsgi_malloc(rl);
|
||||
memcpy(*buffer, rv, rl);
|
||||
return rl;
|
||||
}
|
||||
}
|
||||
@@ -1106,7 +1107,6 @@ static void uwsgi_rack_hijack(void) {
|
||||
uwsgi_error("dup2()");
|
||||
}
|
||||
}
|
||||
int ret = -1;
|
||||
int error = 0;
|
||||
if (ur.rbshell[0] != 0) {
|
||||
rb_eval_string(ur.rbshell);
|
||||
@@ -1122,9 +1122,6 @@ static void uwsgi_rack_hijack(void) {
|
||||
exit(UWSGI_DE_HIJACKED_CODE);
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
exit(UWSGI_QUIET_CODE);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,8 @@ struct uwsgi_router_cache_conf {
|
||||
char *status_str;
|
||||
int status;
|
||||
char *no_offload;
|
||||
|
||||
char *no_cl;
|
||||
};
|
||||
|
||||
// this is allocated for each transformation
|
||||
@@ -189,7 +191,9 @@ static int uwsgi_routing_func_cache(struct wsgi_request *wsgi_req, struct uwsgi_
|
||||
if (expires) {
|
||||
if (uwsgi_response_add_expires(wsgi_req, expires)) goto error;
|
||||
}
|
||||
if (uwsgi_response_add_content_length(wsgi_req, valsize)) goto error;
|
||||
if (!urcc->no_cl) {
|
||||
if (uwsgi_response_add_content_length(wsgi_req, valsize)) goto error;
|
||||
}
|
||||
if (wsgi_req->socket->can_offload && !ur->custom && !urcc->no_offload) {
|
||||
if (!uwsgi_offload_request_memory_do(wsgi_req, value, valsize)) {
|
||||
wsgi_req->via = UWSGI_VIA_OFFLOAD;
|
||||
@@ -378,6 +382,9 @@ static int uwsgi_router_cache(struct uwsgi_route *ur, char *args) {
|
||||
"mime", &urcc->mime,
|
||||
"name", &urcc->name,
|
||||
"no_offload", &urcc->no_offload,
|
||||
"no_content_length", &urcc->no_cl,
|
||||
"no_cl", &urcc->no_cl,
|
||||
"nocl", &urcc->no_cl,
|
||||
NULL)) {
|
||||
uwsgi_log("invalid route syntax: %s\n", args);
|
||||
exit(1);
|
||||
|
||||
@@ -81,7 +81,7 @@ static int uwsgi_routing_func_hash(struct wsgi_request *wsgi_req, struct uwsgi_r
|
||||
vallen = urhc->items_len;
|
||||
}
|
||||
// last item
|
||||
else {
|
||||
else if (value != NULL) {
|
||||
vallen = (urhc->items + urhc->items_len) - value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
|
||||
struct uwsgi_router_metric_conf {
|
||||
|
||||
// the name of the metric
|
||||
char *name;
|
||||
size_t name_len;
|
||||
|
||||
// the value for the metric
|
||||
char *value;
|
||||
size_t value_len;
|
||||
|
||||
int (*func)(char *, char *, int64_t);
|
||||
};
|
||||
|
||||
// metricinc/metricdec/metricmul/metricdiv/metricset
|
||||
static int uwsgi_routing_func_metricmath(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
|
||||
|
||||
struct uwsgi_router_metric_conf *urmc = (struct uwsgi_router_metric_conf *) ur->data2;
|
||||
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urmc->name, urmc->name_len);
|
||||
if (!ub) return UWSGI_ROUTE_BREAK;
|
||||
|
||||
struct uwsgi_buffer *ub_val = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urmc->value, urmc->value_len);
|
||||
if (!ub_val) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
int64_t num = strtol(ub_val->buf, NULL, 10);
|
||||
uwsgi_buffer_destroy(ub_val);
|
||||
|
||||
if (urmc->func(ub->buf, NULL, num)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
|
||||
|
||||
static struct uwsgi_router_metric_conf *uwsgi_router_metricmath(struct uwsgi_route *ur, char *args) {
|
||||
ur->func = uwsgi_routing_func_metricmath;
|
||||
ur->data = args;
|
||||
ur->data_len = strlen(args);
|
||||
|
||||
struct uwsgi_router_metric_conf *urmc = uwsgi_calloc(sizeof(struct uwsgi_router_metric_conf));
|
||||
char *comma = strchr(args, ',');
|
||||
if (comma) {
|
||||
urmc->value = comma+1;
|
||||
urmc->value_len = strlen(urmc->value);
|
||||
*comma = 0;
|
||||
}
|
||||
else {
|
||||
urmc->value = "1";
|
||||
urmc->value_len = 1;
|
||||
}
|
||||
|
||||
urmc->name = args;
|
||||
urmc->name_len = strlen(args);
|
||||
if (comma) *comma = ',';
|
||||
|
||||
ur->data2 = urmc;
|
||||
return urmc;
|
||||
}
|
||||
|
||||
static int uwsgi_router_metricinc(struct uwsgi_route *ur, char *args) {
|
||||
struct uwsgi_router_metric_conf *urmc = uwsgi_router_metricmath(ur, args);
|
||||
if (!urmc) return -1;
|
||||
urmc->func = uwsgi_metric_inc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_router_metricdec(struct uwsgi_route *ur, char *args) {
|
||||
struct uwsgi_router_metric_conf *urmc = uwsgi_router_metricmath(ur, args);
|
||||
if (!urmc) return -1;
|
||||
urmc->func = uwsgi_metric_dec;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_router_metricmul(struct uwsgi_route *ur, char *args) {
|
||||
struct uwsgi_router_metric_conf *urmc = uwsgi_router_metricmath(ur, args);
|
||||
if (!urmc) return -1;
|
||||
urmc->func = uwsgi_metric_mul;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_router_metricdiv(struct uwsgi_route *ur, char *args) {
|
||||
struct uwsgi_router_metric_conf *urmc = uwsgi_router_metricmath(ur, args);
|
||||
if (!urmc) return -1;
|
||||
urmc->func = uwsgi_metric_div;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uwsgi_router_metricset(struct uwsgi_route *ur, char *args) {
|
||||
struct uwsgi_router_metric_conf *urmc = uwsgi_router_metricmath(ur, args);
|
||||
if (!urmc) return -1;
|
||||
urmc->func = uwsgi_metric_set;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *uwsgi_route_var_metric(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) {
|
||||
int64_t metric = uwsgi_metric_getn(key, keylen, NULL, 0);
|
||||
char *ret = uwsgi_64bit2str(metric);
|
||||
*vallen = strlen(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void router_metrics_register() {
|
||||
uwsgi_register_router("metricinc", uwsgi_router_metricinc);
|
||||
uwsgi_register_router("metricdec", uwsgi_router_metricdec);
|
||||
uwsgi_register_router("metricmul", uwsgi_router_metricmul);
|
||||
uwsgi_register_router("metricdiv", uwsgi_router_metricdiv);
|
||||
uwsgi_register_router("metricset", uwsgi_router_metricset);
|
||||
|
||||
struct uwsgi_route_var *urv = uwsgi_register_route_var("metric", uwsgi_route_var_metric);
|
||||
urv->need_free = 1;
|
||||
|
||||
}
|
||||
|
||||
struct uwsgi_plugin router_metrics_plugin = {
|
||||
.name = "router_metrics",
|
||||
.on_load = router_metrics_register,
|
||||
};
|
||||
|
||||
#else
|
||||
struct uwsgi_plugin router_metrics_plugin = {
|
||||
.name = "router_metrics",
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
NAME='router_metrics'
|
||||
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
GCC_LIST = ['plugin']
|
||||
@@ -16,6 +16,8 @@ struct uwsgi_router_file_conf {
|
||||
size_t content_type_len;
|
||||
|
||||
char *mime;
|
||||
|
||||
char *no_cl;
|
||||
};
|
||||
|
||||
int uwsgi_routing_func_static(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
@@ -64,7 +66,9 @@ int uwsgi_routing_func_file(struct wsgi_request *wsgi_req, struct uwsgi_route *u
|
||||
goto end2;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub_s);
|
||||
if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end2;
|
||||
if (!urfc->no_cl) {
|
||||
if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end2;
|
||||
}
|
||||
if (urfc->mime) {
|
||||
size_t mime_type_len = 0;
|
||||
char *mime_type = uwsgi_get_mime_type(ub->buf, ub->pos, &mime_type_len);
|
||||
@@ -248,6 +252,9 @@ static int uwsgi_router_file(struct uwsgi_route *ur, char *args) {
|
||||
"filename", &urfc->filename,
|
||||
"status", &urfc->status,
|
||||
"content_type", &urfc->content_type,
|
||||
"nocl", &urfc->no_cl,
|
||||
"no_cl", &urfc->no_cl,
|
||||
"no_content_length", &urfc->no_cl,
|
||||
"mime", &urfc->mime,
|
||||
NULL)) {
|
||||
uwsgi_log("invalid file route syntax: %s\n", args);
|
||||
|
||||
+61
-25
@@ -11,13 +11,14 @@ extern struct uwsgi_server uwsgi;
|
||||
|
||||
rpc-HTTP interface.
|
||||
|
||||
modifier2 changes the parsser behaviours:
|
||||
modifier2 changes the parser behaviours:
|
||||
|
||||
0 -> return uwsgi header + rpc response
|
||||
1 -> return raw rpc response
|
||||
2 -> split PATH_INFO to get func name and args and return as HTTP response with content_type as application/binary or Accept request header (if different from *)
|
||||
3 -> set xmlrpc wrapper (requires libxml2)
|
||||
4 -> set jsonrpc wrapper (requires libjansson)
|
||||
5 -> used in uwsgi response to signal the response is a uwsgi dictionary followed by the body (the dictionary must contains a CONTENT_LENGTH key)
|
||||
|
||||
*/
|
||||
|
||||
@@ -70,7 +71,7 @@ static int uwsgi_rpc_xmlrpc_args(xmlNode *element, char **argv, uint16_t *argvs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_rpc_xmlrpc(struct wsgi_request *wsgi_req, xmlDoc *doc, char **argv, uint16_t *argvs, uint8_t *argc, char *response_buf) {
|
||||
static int uwsgi_rpc_xmlrpc(struct wsgi_request *wsgi_req, xmlDoc *doc, char **argv, uint16_t *argvs, uint8_t *argc, char **response_buf) {
|
||||
char *method = NULL;
|
||||
xmlNode *element = xmlDocGetRootElement(doc);
|
||||
if (!element) return -1;
|
||||
@@ -91,12 +92,14 @@ static int uwsgi_rpc_xmlrpc(struct wsgi_request *wsgi_req, xmlDoc *doc, char **a
|
||||
}
|
||||
|
||||
if (!method) return -1;
|
||||
wsgi_req->uh->pktsize = uwsgi_rpc(method, *argc, argv+1, argvs+1, response_buf);
|
||||
uint64_t content_len = uwsgi_rpc(method, *argc, argv+1, argvs+1, response_buf);
|
||||
|
||||
if (!wsgi_req->uh->pktsize) return -1;
|
||||
if (wsgi_req->uh->pktsize == UMAX16-1) return -1;
|
||||
if (!*response_buf) return -1;
|
||||
// add final NULL byte
|
||||
response_buf[wsgi_req->uh->pktsize] = 0;
|
||||
char *tmp_buf = realloc(*response_buf, content_len + 1);
|
||||
if (!tmp_buf) return -1;
|
||||
*response_buf = tmp_buf;
|
||||
*response_buf[content_len] = 0;
|
||||
|
||||
xmlDoc *rdoc = xmlNewDoc(BAD_CAST "1.0");
|
||||
xmlNode *m_response = xmlNewNode(NULL, BAD_CAST "methodResponse");
|
||||
@@ -130,7 +133,9 @@ static int uwsgi_rpc_request(struct wsgi_request *wsgi_req) {
|
||||
// maximum number of supported arguments
|
||||
uint8_t argc = 0xff;
|
||||
// response output
|
||||
char response_buf[UMAX16];
|
||||
char *response_buf = NULL;
|
||||
// response size
|
||||
size_t content_len = 0;
|
||||
|
||||
/* Standard RPC request */
|
||||
if (!wsgi_req->uh->pktsize) {
|
||||
@@ -173,22 +178,23 @@ static int uwsgi_rpc_request(struct wsgi_request *wsgi_req) {
|
||||
p = strtok_r(NULL, "/", &ctx);
|
||||
}
|
||||
|
||||
wsgi_req->uh->pktsize = uwsgi_rpc(argv[0], argc, argv+1, argvs+1, response_buf);
|
||||
content_len = uwsgi_rpc(argv[0], argc, argv+1, argvs+1, &response_buf);
|
||||
free(args);
|
||||
|
||||
if (!wsgi_req->uh->pktsize) {
|
||||
if (!content_len) {
|
||||
if (response_buf) free(response_buf);
|
||||
uwsgi_404(wsgi_req);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return 1;
|
||||
if (uwsgi_response_add_content_length(wsgi_req, wsgi_req->uh->pktsize)) return -1;
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) {if (response_buf) free(response_buf); return -1;}
|
||||
if (uwsgi_response_add_content_length(wsgi_req, content_len)) {if (response_buf) free(response_buf); return -1;}
|
||||
uint16_t ctype_len = 0;
|
||||
char *ctype = uwsgi_get_var(wsgi_req, "HTTP_ACCEPT", 11, &ctype_len);
|
||||
if (ctype && strcmp(ctype, "*/*") && strcmp(ctype, "*")) {
|
||||
if (uwsgi_response_add_content_type(wsgi_req, ctype, ctype_len)) return -1;
|
||||
if (!ctype || !uwsgi_strncmp(ctype, ctype_len, "*/*" ,3) || !uwsgi_strncmp(ctype, ctype_len, "*", 1)) {
|
||||
if (uwsgi_response_add_content_type(wsgi_req, "application/binary", 18)) {if (response_buf) free(response_buf); return -1;}
|
||||
}
|
||||
else {
|
||||
if (uwsgi_response_add_content_type(wsgi_req, "application/binary", 18)) return -1;
|
||||
if (uwsgi_response_add_content_type(wsgi_req, ctype, ctype_len)) {if (response_buf) free(response_buf); return -1;}
|
||||
}
|
||||
goto sendbody;
|
||||
}
|
||||
@@ -206,11 +212,12 @@ static int uwsgi_rpc_request(struct wsgi_request *wsgi_req) {
|
||||
uwsgi_500(wsgi_req);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
int ret = uwsgi_rpc_xmlrpc(wsgi_req, doc, argv, argvs, &argc, response_buf);
|
||||
int ret = uwsgi_rpc_xmlrpc(wsgi_req, doc, argv, argvs, &argc, &response_buf);
|
||||
xmlFreeDoc(doc);
|
||||
if (ret) {
|
||||
uwsgi_500(wsgi_req);
|
||||
}
|
||||
if (response_buf) free(response_buf);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
#endif
|
||||
@@ -221,20 +228,49 @@ static int uwsgi_rpc_request(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
|
||||
// call the function (output will be in wsgi_req->buffer)
|
||||
wsgi_req->uh->pktsize = uwsgi_rpc(argv[0], argc-1, argv+1, argvs+1, response_buf);
|
||||
content_len = uwsgi_rpc(argv[0], argc-1, argv+1, argvs+1, &response_buf);
|
||||
if (!response_buf) return -1;
|
||||
|
||||
// using modifier2 we may want a raw output
|
||||
if (wsgi_req->uh->modifier2 == 0) {
|
||||
if (uwsgi_response_write_body_do(wsgi_req, (char *) wsgi_req->uh, 4)) {
|
||||
return -1;
|
||||
if (content_len > 0xffff) {
|
||||
// signal dictionary
|
||||
wsgi_req->uh->modifier2 = 5;
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
|
||||
if (uwsgi_buffer_append_keynum(ub, "CONTENT_LENGTH", 14 , content_len)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
free(response_buf);
|
||||
return -1;
|
||||
}
|
||||
// fix uwsgi header
|
||||
wsgi_req->uh->pktsize = ub->pos;
|
||||
if (uwsgi_response_write_body_do(wsgi_req, (char *) wsgi_req->uh, 4)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
free(response_buf);
|
||||
return -1;
|
||||
}
|
||||
if (uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos)) {
|
||||
uwsgi_buffer_destroy(ub);
|
||||
free(response_buf);
|
||||
return -1;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
}
|
||||
else {
|
||||
wsgi_req->uh->pktsize = content_len;
|
||||
if (uwsgi_response_write_body_do(wsgi_req, (char *) wsgi_req->uh, 4)) {
|
||||
free(response_buf);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
sendbody:
|
||||
// write the response
|
||||
uwsgi_response_write_body_do(wsgi_req, response_buf, wsgi_req->uh->pktsize);
|
||||
|
||||
uwsgi_response_write_body_do(wsgi_req, response_buf, content_len);
|
||||
free(response_buf);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
@@ -270,7 +306,7 @@ static int uwsgi_routing_func_rpc(struct wsgi_request *wsgi_req, struct uwsgi_ro
|
||||
*at = 0;
|
||||
remote = at+1;
|
||||
}
|
||||
uint16_t size;
|
||||
uint64_t size;
|
||||
char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
|
||||
free(func);
|
||||
if (!response) goto end;
|
||||
@@ -322,7 +358,7 @@ static int uwsgi_routing_func_rpc_blob(struct wsgi_request *wsgi_req, struct uws
|
||||
*at = 0;
|
||||
remote = at+1;
|
||||
}
|
||||
uint16_t size;
|
||||
uint64_t size;
|
||||
char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
|
||||
free(func);
|
||||
if (!response) goto end;
|
||||
@@ -377,7 +413,7 @@ static int uwsgi_routing_func_rpc_raw(struct wsgi_request *wsgi_req, struct uwsg
|
||||
*at = 0;
|
||||
remote = at+1;
|
||||
}
|
||||
uint16_t size;
|
||||
uint64_t size;
|
||||
char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
|
||||
free(func);
|
||||
if (!response) goto end;
|
||||
@@ -431,7 +467,7 @@ static int uwsgi_routing_func_rpc_var(struct wsgi_request *wsgi_req, struct uwsg
|
||||
*at = 0;
|
||||
remote = at+1;
|
||||
}
|
||||
uint16_t size;
|
||||
uint64_t size;
|
||||
char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
|
||||
free(func);
|
||||
if (!response) goto end;
|
||||
@@ -488,7 +524,7 @@ static int uwsgi_routing_func_rpc_ret(struct wsgi_request *wsgi_req, struct uwsg
|
||||
*at = 0;
|
||||
remote = at+1;
|
||||
}
|
||||
uint16_t size;
|
||||
uint64_t size;
|
||||
char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
|
||||
free(func);
|
||||
if (!response) goto end;
|
||||
|
||||
+118
-107
@@ -1,30 +1,38 @@
|
||||
#include "../../uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
struct uwsgi_rrdtool {
|
||||
static struct uwsgi_rrdtool {
|
||||
void *lib;
|
||||
char *lib_name;
|
||||
|
||||
int (*create)(int, char **);
|
||||
int (*update)(int, char **);
|
||||
struct uwsgi_string_list *rrd;
|
||||
int max_ds;
|
||||
|
||||
int freq;
|
||||
|
||||
char *update_area;
|
||||
struct uwsgi_string_list *directory;
|
||||
|
||||
struct uwsgi_stats_pusher *pusher;
|
||||
} u_rrd;
|
||||
|
||||
struct uwsgi_option rrdtool_options[] = {
|
||||
{"rrdtool", required_argument, 0, "collect requests data in the specified rrd file", uwsgi_opt_add_string_list, &u_rrd.rrd, UWSGI_OPT_MASTER},
|
||||
static struct uwsgi_option rrdtool_options[] = {
|
||||
{"rrdtool", required_argument, 0, "store rrd files in the specified directory", uwsgi_opt_add_string_list, &u_rrd.directory, UWSGI_OPT_MASTER|UWSGI_OPT_METRICS},
|
||||
{"rrdtool-freq", required_argument, 0, "set collect frequency", uwsgi_opt_set_int, &u_rrd.freq, 0},
|
||||
{"rrdtool-max-ds", required_argument, 0, "set maximum number of data sources", uwsgi_opt_set_int, &u_rrd.max_ds, 0},
|
||||
{"rrdtool-lib", required_argument, 0, "set the name of rrd library (default: librrd.so)", uwsgi_opt_set_str, &u_rrd.lib_name, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
|
||||
};
|
||||
|
||||
|
||||
int rrdtool_init() {
|
||||
static int rrdtool_init() {
|
||||
|
||||
u_rrd.lib = dlopen("librrd.so", RTLD_LAZY);
|
||||
if (!u_rrd.lib_name) {
|
||||
u_rrd.lib_name = "librrd.so";
|
||||
}
|
||||
|
||||
u_rrd.lib = dlopen(u_rrd.lib_name, RTLD_LAZY);
|
||||
if (!u_rrd.lib) return -1;
|
||||
|
||||
u_rrd.create = dlsym(u_rrd.lib, "rrd_create");
|
||||
@@ -39,137 +47,140 @@ int rrdtool_init() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!u_rrd.max_ds) u_rrd.max_ds = 30;
|
||||
|
||||
uwsgi_log_initial("*** RRDtool library available at %p ***\n", u_rrd.lib);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rrdtool_post_init() {
|
||||
/*
|
||||
|
||||
struct uwsgi_string_list *usl = u_rrd.rrd;
|
||||
char **argv;
|
||||
int i;
|
||||
create .rrd files if needed
|
||||
|
||||
if (!u_rrd.lib || !u_rrd.create) return;
|
||||
*/
|
||||
static void rrdtool_post_init() {
|
||||
|
||||
// do not waste time if no --rrdtool option is defiend
|
||||
if (!u_rrd.rrd) return;
|
||||
if (!u_rrd.create) return;
|
||||
|
||||
if (uwsgi.numproc > u_rrd.max_ds) {
|
||||
uwsgi_log("!!! NOT ENOUGH SLOTS IN RRDTOOL DS TO HOST WORKERS DATA (increase them with --rrdtool-max-ds) !!!\n");
|
||||
dlclose(u_rrd.lib);
|
||||
return;
|
||||
}
|
||||
// do not waste time if no --rrdtool option is defined
|
||||
if (!u_rrd.directory) return;
|
||||
|
||||
// alloc space for DS_REQ + DS WORKER + RRA + create + filename
|
||||
argv = uwsgi_malloc( sizeof(char *) * (1 + u_rrd.max_ds + 4 + 1 +1));
|
||||
if (!u_rrd.freq) u_rrd.freq = 300;
|
||||
|
||||
char *argv[7];
|
||||
argv[0] = "create";
|
||||
|
||||
argv[2] = "DS:requests:DERIVE:600:0:U";
|
||||
|
||||
// create DS for workers
|
||||
for(i=0;i<u_rrd.max_ds;i++) {
|
||||
int max_size = sizeof("DS:worker65536:DERIVE:600:0:U")+1;
|
||||
argv[3+i] = uwsgi_malloc( max_size );
|
||||
if (snprintf(argv[3+i], max_size, "DS:worker%d:DERIVE:600:0:U", i+1) < 25) {
|
||||
uwsgi_log("unable to create args for rrd_create()\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// create RRA
|
||||
argv[3+u_rrd.max_ds] = "RRA:AVERAGE:0.5:1:288" ;
|
||||
argv[3+u_rrd.max_ds+1] = "RRA:AVERAGE:0.5:12:168" ;
|
||||
argv[3+u_rrd.max_ds+2] = "RRA:AVERAGE:0.5:288:31" ;
|
||||
argv[3+u_rrd.max_ds+3] = "RRA:AVERAGE:0.5:2016:52";
|
||||
argv[3] = "RRA:AVERAGE:0.5:1:288" ;
|
||||
argv[4] = "RRA:AVERAGE:0.5:12:168" ;
|
||||
argv[5] = "RRA:AVERAGE:0.5:288:31" ;
|
||||
argv[6] = "RRA:AVERAGE:0.5:2016:52";
|
||||
|
||||
while(usl) {
|
||||
if (!uwsgi_file_exists(usl->value)) {
|
||||
argv[1] = usl->value;
|
||||
if (u_rrd.create((1 + u_rrd.max_ds + 4 + 1 +1), argv)) {
|
||||
uwsgi_error("rrd_create()");
|
||||
exit(1);
|
||||
struct uwsgi_string_list *usl = NULL;
|
||||
uwsgi_foreach(usl, u_rrd.directory) {
|
||||
char *dir = uwsgi_expand_path(usl->value, strlen(usl->value), NULL);
|
||||
if (!dir) {
|
||||
uwsgi_error("rrdtool_post_init()/uwsgi_expand_path()");
|
||||
exit(1);
|
||||
}
|
||||
struct uwsgi_metric *um = uwsgi.metrics;
|
||||
// here locking is useless, but maybe in the future we could move this part
|
||||
// somewhere else
|
||||
int created = 0;
|
||||
uwsgi_rlock(uwsgi.metrics_lock);
|
||||
while(um) {
|
||||
char *filename = uwsgi_concat4(dir, "/", um->name, ".rrd");
|
||||
if (!uwsgi_file_exists(filename)) {
|
||||
argv[1] = filename;
|
||||
if (um->type == UWSGI_METRIC_GAUGE) {
|
||||
argv[2] = "DS:metric:GAUGE:600:0:U";
|
||||
}
|
||||
else {
|
||||
argv[2] = "DS:metric:DERIVE:600:0:U";
|
||||
}
|
||||
if (u_rrd.create(7, argv)) {
|
||||
uwsgi_log("unable to create rrd file for metric \"%s\"\n", um->name);
|
||||
uwsgi_error("rrd_create()");
|
||||
exit(1);
|
||||
}
|
||||
created++;
|
||||
}
|
||||
free(filename);
|
||||
um = um->next;
|
||||
}
|
||||
char *new_usl_value = uwsgi_malloc(PATH_MAX+1);
|
||||
if (!realpath(usl->value, new_usl_value)) {
|
||||
uwsgi_error("realpath()");
|
||||
exit(1);
|
||||
}
|
||||
usl->value = new_usl_value;
|
||||
usl = usl->next;
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
|
||||
uwsgi_log("created %d new rrd files in %s\n", created, dir);
|
||||
|
||||
struct uwsgi_stats_pusher_instance *uspi = uwsgi_stats_pusher_add(u_rrd.pusher, NULL);
|
||||
uspi->freq = u_rrd.freq;
|
||||
uspi->data = dir;
|
||||
// no need to generate the json
|
||||
uspi->raw=1;
|
||||
}
|
||||
|
||||
// free DS
|
||||
for(i=0;i<u_rrd.max_ds;i++) {
|
||||
free(argv[3+i]);
|
||||
}
|
||||
|
||||
free(argv);
|
||||
|
||||
//now allocate memory for updates
|
||||
u_rrd.update_area = uwsgi_malloc( 1+((1+sizeof(UMAX64_STR)) * (u_rrd.max_ds+1))+1 );
|
||||
memset(u_rrd.update_area, 0, 1+((1+sizeof(UMAX64_STR)) * (u_rrd.max_ds+1))+1 );
|
||||
|
||||
u_rrd.update_area[0] = 'N';
|
||||
|
||||
if (u_rrd.freq < 1) u_rrd.freq = 300;
|
||||
|
||||
}
|
||||
|
||||
void rrdtool_master_cycle() {
|
||||
static void rrdtool_push(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) {
|
||||
|
||||
static time_t last_update = 0;
|
||||
char *ptr;
|
||||
int rlen, i;
|
||||
char *argv[3];
|
||||
struct uwsgi_string_list *usl = u_rrd.rrd;
|
||||
if (!u_rrd.update) return ;
|
||||
|
||||
if (!u_rrd.lib || !u_rrd.create || !u_rrd.rrd) return ;
|
||||
|
||||
if (last_update == 0) last_update = uwsgi_now();
|
||||
|
||||
// update
|
||||
if (uwsgi.current_time - last_update >= u_rrd.freq) {
|
||||
ptr = u_rrd.update_area+1;
|
||||
rlen = snprintf(ptr, 1+sizeof(UMAX64_STR), ":%llu", (unsigned long long )uwsgi.workers[0].requests);
|
||||
if (rlen < 2) return;
|
||||
ptr+=rlen;
|
||||
for(i=0;i<u_rrd.max_ds;i++) {
|
||||
if (i+1 <= uwsgi.numproc) {
|
||||
rlen = snprintf(ptr, 1+sizeof(UMAX64_STR), ":%llu", (unsigned long long )uwsgi.workers[1+i].requests);
|
||||
if (rlen < 2) return;
|
||||
}
|
||||
else {
|
||||
memcpy(ptr, ":U", 2);
|
||||
rlen = 2;
|
||||
}
|
||||
ptr+=rlen;
|
||||
// standard stats pusher
|
||||
if (!uspi->data) {
|
||||
if (!uspi->arg) {
|
||||
uwsgi_log("invalid rrdtool stats pusher syntax\n");
|
||||
exit(1);
|
||||
}
|
||||
last_update = uwsgi.current_time;
|
||||
argv[0] = "update";
|
||||
argv[2] = u_rrd.update_area;
|
||||
while(usl) {
|
||||
argv[1] = usl->value;
|
||||
if (u_rrd.update(3, argv)) {
|
||||
uwsgi_log_verbose("ERROR: rrd_update(\"%s\", \"%s\")\n", argv[1], argv[2]);
|
||||
}
|
||||
usl = usl->next;
|
||||
uspi->data = uwsgi_expand_path(uspi->arg, strlen(uspi->arg), NULL);
|
||||
if (!uspi->data) {
|
||||
uwsgi_error("rrdtool_push()/uwsgi_expand_path()");
|
||||
exit(1);
|
||||
}
|
||||
if (!u_rrd.freq) u_rrd.freq = 300;
|
||||
uspi->freq = u_rrd.freq;
|
||||
}
|
||||
|
||||
// 1k will be more than enough
|
||||
char buf[1024];
|
||||
char *argv[3];
|
||||
argv[0] = "update";
|
||||
|
||||
struct uwsgi_metric *um = uwsgi.metrics;
|
||||
while(um) {
|
||||
uwsgi_rlock(uwsgi.metrics_lock);
|
||||
int ret = snprintf(buf, 1024, "N:%lld", (long long) (*um->value));
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
if (ret < 3) {
|
||||
uwsgi_log("unable to update rrdtool metric for %s\n", um->name);
|
||||
goto next;
|
||||
}
|
||||
char *filename = uwsgi_concat4(uspi->data, "/", um->name, ".rrd");
|
||||
argv[1] = filename;
|
||||
argv[2] = buf;
|
||||
if (u_rrd.update(3, argv)) {
|
||||
uwsgi_log_verbose("ERROR: rrd_update(\"%s\", \"%s\")\n", argv[1], argv[2]);
|
||||
}
|
||||
free(filename);
|
||||
next:
|
||||
um = um->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void rrdtool_register() {
|
||||
u_rrd.pusher = uwsgi_register_stats_pusher("rrdtool", rrdtool_push);
|
||||
u_rrd.pusher->raw = 1;
|
||||
}
|
||||
|
||||
struct uwsgi_plugin rrdtool_plugin = {
|
||||
|
||||
.name = "rrdtool",
|
||||
|
||||
.options = rrdtool_options,
|
||||
|
||||
.master_cycle = rrdtool_master_cycle,
|
||||
|
||||
.post_init = rrdtool_post_init,
|
||||
.on_load = rrdtool_register,
|
||||
|
||||
// this is the best phase to create rrd files (if needed)
|
||||
.preinit_apps = rrdtool_post_init,
|
||||
// here we get pointers to rrdtool functions
|
||||
.init = rrdtool_init,
|
||||
};
|
||||
|
||||
@@ -50,11 +50,11 @@ static int uwsgi_servlet_setup() {
|
||||
uwsgi_log("%p %p\n", uwsgi_request, uwsgi_response);
|
||||
|
||||
mid = uwsgi_jvm_get_method_id(uwsgi_request , "<init>", "()V");
|
||||
uwsgi_jvm_exception();
|
||||
if (uwsgi_jvm_exception() || !mid) exit(1);
|
||||
jobject request = (*ujvm_env)->NewObject(ujvm_env, uwsgi_request, mid);
|
||||
|
||||
mid = uwsgi_jvm_get_method_id(uwsgi_response , "<init>", "()V");
|
||||
uwsgi_jvm_exception();
|
||||
if (uwsgi_jvm_exception() || !mid) exit(1);
|
||||
jobject response = (*ujvm_env)->NewObject(ujvm_env, uwsgi_response, mid);
|
||||
|
||||
uwsgi_log("%p %p\n", request, response);
|
||||
|
||||
@@ -94,7 +94,7 @@ static void stackless_init_apps(void) {
|
||||
up.gil_release = gil_stackless_release;
|
||||
}
|
||||
|
||||
// blindy call it as the stackless gil engine is already set
|
||||
// blindly call it as the stackless gil engine is already set
|
||||
UWSGI_GET_GIL
|
||||
|
||||
usl.sl = uwsgi_malloc( sizeof(PyTaskletObject *) * uwsgi.async );
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
struct uwsgi_stats_pusher_file_conf {
|
||||
char *path;
|
||||
char *freq;
|
||||
char *separator;
|
||||
};
|
||||
|
||||
static void stats_pusher_file(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) {
|
||||
struct uwsgi_stats_pusher_file_conf *uspic = (struct uwsgi_stats_pusher_file_conf *) uspi->data;
|
||||
if (!uspi->configured) {
|
||||
uspic = uwsgi_calloc(sizeof(struct uwsgi_stats_pusher_file_conf));
|
||||
if (uspi->arg) {
|
||||
if (uwsgi_kvlist_parse(uspi->arg, strlen(uspi->arg), ',', '=', "path", &uspic->path, "separator", &uspic->separator, "freq", &uspic->freq, NULL)) {
|
||||
free(uspi);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!uspic->path)
|
||||
uspic->path = "uwsgi.stats";
|
||||
if (!uspic->separator)
|
||||
uspic->separator = "\n\n";
|
||||
if (uspic->freq)
|
||||
uspi->freq = atoi(uspic->freq);
|
||||
uspi->configured = 1;
|
||||
uspi->data = uspic;
|
||||
}
|
||||
|
||||
int fd = open(uspic->path, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP);
|
||||
if (fd < 0) {
|
||||
uwsgi_error_open(uspic->path);
|
||||
return;
|
||||
}
|
||||
ssize_t rlen = write(fd, json, json_len);
|
||||
if (rlen != (ssize_t) json_len) {
|
||||
uwsgi_error("uwsgi_stats_pusher_file() -> write()\n");
|
||||
}
|
||||
|
||||
rlen = write(fd, uspic->separator, strlen(uspic->separator));
|
||||
if (rlen != (ssize_t) strlen(uspic->separator)) {
|
||||
uwsgi_error("uwsgi_stats_pusher_file() -> write()\n");
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
static void stats_pusher_file_init(void) {
|
||||
uwsgi_register_stats_pusher("file", stats_pusher_file);
|
||||
}
|
||||
|
||||
struct uwsgi_plugin stats_pusher_file_plugin = {
|
||||
|
||||
.name = "stats_pusher_file",
|
||||
.on_load = stats_pusher_file_init,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
NAME='stats_pusher_file'
|
||||
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
|
||||
GCC_LIST = ['plugin']
|
||||
@@ -0,0 +1,111 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
|
||||
this is a stats pusher plugin for sendign metrics over a udp socket
|
||||
|
||||
--stats-push socket:address[,prefix]
|
||||
|
||||
example:
|
||||
|
||||
--stats-push socket:127.0.0.1:8125,myinstance
|
||||
|
||||
it exports values exposed by the metric subsystem
|
||||
|
||||
(it is based on the statsd plugin)
|
||||
|
||||
*/
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
// configuration of a socket node
|
||||
struct socket_node {
|
||||
int fd;
|
||||
union uwsgi_sockaddr addr;
|
||||
socklen_t addr_len;
|
||||
char *prefix;
|
||||
uint16_t prefix_len;
|
||||
};
|
||||
|
||||
static int socket_send_metric(struct uwsgi_buffer *ub, struct uwsgi_stats_pusher_instance *uspi, struct uwsgi_metric *um) {
|
||||
struct socket_node *sn = (struct socket_node *) uspi->data;
|
||||
// reset the buffer
|
||||
ub->pos = 0;
|
||||
if (uwsgi_buffer_append(ub, sn->prefix, sn->prefix_len)) return -1;
|
||||
if (uwsgi_buffer_append(ub, ".", 1)) return -1;
|
||||
if (uwsgi_buffer_append(ub, um->name, um->name_len)) return -1;
|
||||
if (uwsgi_buffer_append(ub, " ", 1)) return -1;
|
||||
if (uwsgi_buffer_num64(ub, (int64_t) um->type)) return -1;
|
||||
if (uwsgi_buffer_append(ub, " ", 1)) return -1;
|
||||
if (uwsgi_buffer_num64(ub, *um->value)) return -1;
|
||||
|
||||
if (sendto(sn->fd, ub->buf, ub->pos, 0, (struct sockaddr *) &sn->addr.sa_in, sn->addr_len) < 0) {
|
||||
uwsgi_error("socket_send_metric()/sendto()");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void stats_pusher_socket(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) {
|
||||
|
||||
if (!uspi->configured) {
|
||||
struct socket_node *sn = uwsgi_calloc(sizeof(struct socket_node));
|
||||
char *comma = strchr(uspi->arg, ',');
|
||||
if (comma) {
|
||||
sn->prefix = comma+1;
|
||||
sn->prefix_len = strlen(sn->prefix);
|
||||
*comma = 0;
|
||||
}
|
||||
else {
|
||||
sn->prefix = "uwsgi";
|
||||
sn->prefix_len = 5;
|
||||
}
|
||||
|
||||
char *colon = strchr(uspi->arg, ':');
|
||||
if (!colon) {
|
||||
uwsgi_log("invalid socket address %s\n", uspi->arg);
|
||||
if (comma) *comma = ',';
|
||||
free(sn);
|
||||
return;
|
||||
}
|
||||
sn->addr_len = socket_to_in_addr(uspi->arg, colon, 0, &sn->addr.sa_in);
|
||||
|
||||
sn->fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sn->fd < 0) {
|
||||
uwsgi_error("stats_pusher_socket()/socket()");
|
||||
if (comma) *comma = ',';
|
||||
free(sn);
|
||||
return;
|
||||
}
|
||||
uwsgi_socket_nb(sn->fd);
|
||||
if (comma) *comma = ',';
|
||||
uspi->data = sn;
|
||||
uspi->configured = 1;
|
||||
}
|
||||
|
||||
// we use the same buffer for all of the packets
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
|
||||
struct uwsgi_metric *um = uwsgi.metrics;
|
||||
while(um) {
|
||||
uwsgi_rlock(uwsgi.metrics_lock);
|
||||
socket_send_metric(ub, uspi, um);
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
um = um->next;
|
||||
}
|
||||
uwsgi_buffer_destroy(ub);
|
||||
}
|
||||
|
||||
static void stats_pusher_socket_init(void) {
|
||||
struct uwsgi_stats_pusher *usp = uwsgi_register_stats_pusher("socket", stats_pusher_socket);
|
||||
// we use a custom format not the JSON one
|
||||
usp->raw = 1;
|
||||
}
|
||||
|
||||
struct uwsgi_plugin stats_pusher_socket_plugin = {
|
||||
|
||||
.name = "stats_pusher_socket",
|
||||
.on_load = stats_pusher_socket_init,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
NAME='stats_pusher_socket'
|
||||
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
|
||||
GCC_LIST = ['plugin']
|
||||
@@ -10,7 +10,7 @@ example:
|
||||
|
||||
--stats-push statsd:127.0.0.1:8125,myinstance
|
||||
|
||||
it is pretty minimal, but will be extended after the 2.0 metric subsystem will be released
|
||||
it exports values exposed by the metric subsystem
|
||||
|
||||
*/
|
||||
|
||||
@@ -25,45 +25,23 @@ struct statsd_node {
|
||||
uint16_t prefix_len;
|
||||
};
|
||||
|
||||
static int statsd_send_worker_gauge(struct uwsgi_buffer *ub, struct uwsgi_stats_pusher_instance *uspi, int wid, char *metric, uint16_t metric_len, int64_t value) {
|
||||
static int statsd_send_metric(struct uwsgi_buffer *ub, struct uwsgi_stats_pusher_instance *uspi, char *metric, size_t metric_len, int64_t value, char type[2]) {
|
||||
struct statsd_node *sn = (struct statsd_node *) uspi->data;
|
||||
// reset the buffer
|
||||
ub->pos = 0;
|
||||
if (uwsgi_buffer_append(ub, sn->prefix, sn->prefix_len)) return -1;
|
||||
if (uwsgi_buffer_append(ub, ".worker", 7)) return -1;
|
||||
if (uwsgi_buffer_num64(ub, wid)) return -1;
|
||||
if (uwsgi_buffer_append(ub, ".", 1)) return -1;
|
||||
if (uwsgi_buffer_append(ub, metric, metric_len)) return -1;
|
||||
if (uwsgi_buffer_append(ub, ":", 1)) return -1;
|
||||
if (uwsgi_buffer_num64(ub, value)) return -1;
|
||||
if (uwsgi_buffer_append(ub, "|g", 2)) return -1;
|
||||
|
||||
if (sendto(sn->fd, ub->buf, ub->pos, 0, (struct sockaddr *) &sn->addr.sa_in, sn->addr_len) < 0) {
|
||||
uwsgi_error("stats_pusher_statsd()/sendto()");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int statsd_send_core_gauge(struct uwsgi_buffer *ub, struct uwsgi_stats_pusher_instance *uspi, int wid, int coreid, char *metric, uint16_t metric_len, int64_t value) {
|
||||
struct statsd_node *sn = (struct statsd_node *) uspi->data;
|
||||
// reset the buffer
|
||||
ub->pos = 0;
|
||||
if (uwsgi_buffer_append(ub, sn->prefix, sn->prefix_len)) return -1;
|
||||
if (uwsgi_buffer_append(ub, ".worker", 7)) return -1;
|
||||
if (uwsgi_buffer_num64(ub, wid)) return -1;
|
||||
if (uwsgi_buffer_append(ub, ".core", 5)) return -1;
|
||||
if (uwsgi_buffer_num64(ub, coreid)) return -1;
|
||||
if (uwsgi_buffer_append(ub, ".", 1)) return -1;
|
||||
if (uwsgi_buffer_append(ub, metric, metric_len)) return -1;
|
||||
if (uwsgi_buffer_append(ub, ":", 1)) return -1;
|
||||
if (uwsgi_buffer_append(ub, sn->prefix, sn->prefix_len)) return -1;
|
||||
if (uwsgi_buffer_append(ub, ".", 1)) return -1;
|
||||
if (uwsgi_buffer_append(ub, metric, metric_len)) return -1;
|
||||
if (uwsgi_buffer_append(ub, ":", 1)) return -1;
|
||||
if (uwsgi_buffer_num64(ub, value)) return -1;
|
||||
if (uwsgi_buffer_append(ub, "|g", 2)) return -1;
|
||||
if (uwsgi_buffer_append(ub, type, 2)) return -1;
|
||||
|
||||
if (sendto(sn->fd, ub->buf, ub->pos, 0, (struct sockaddr *) &sn->addr.sa_in, sn->addr_len) < 0) {
|
||||
uwsgi_error("stats_pusher_statsd()/sendto()");
|
||||
}
|
||||
if (sendto(sn->fd, ub->buf, ub->pos, 0, (struct sockaddr *) &sn->addr.sa_in, sn->addr_len) < 0) {
|
||||
uwsgi_error("statsd_send_metric()/sendto()");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -106,20 +84,19 @@ static void stats_pusher_statsd(struct uwsgi_stats_pusher_instance *uspi, time_t
|
||||
|
||||
// we use the same buffer for all of the packets
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
|
||||
|
||||
int i, j;
|
||||
// send workers metrics
|
||||
for(i=1;i<=uwsgi.numproc;i++) {
|
||||
if (statsd_send_worker_gauge(ub, uspi, i, "requests", 8, uwsgi.workers[i].requests)) goto end;
|
||||
for(j=0;j<uwsgi.cores;j++) {
|
||||
if (statsd_send_core_gauge(ub, uspi, i, j, "exceptions", 10, uwsgi.workers[i].cores[j].exceptions)) goto end;
|
||||
if (statsd_send_core_gauge(ub, uspi, i, j, "requests", 8, uwsgi.workers[i].cores[j].requests)) goto end;
|
||||
if (statsd_send_core_gauge(ub, uspi, i, j, "routed_requests", 15, uwsgi.workers[i].cores[j].routed_requests)) goto end;
|
||||
if (statsd_send_core_gauge(ub, uspi, i, j, "static_requests", 15, uwsgi.workers[i].cores[j].static_requests)) goto end;
|
||||
if (statsd_send_core_gauge(ub, uspi, i, j, "offloaded_requests", 18, uwsgi.workers[i].cores[j].offloaded_requests)) goto end;
|
||||
struct uwsgi_metric *um = uwsgi.metrics;
|
||||
while(um) {
|
||||
uwsgi_rlock(uwsgi.metrics_lock);
|
||||
// ignore return value
|
||||
if (um->type == UWSGI_METRIC_GAUGE) {
|
||||
statsd_send_metric(ub, uspi, um->name, um->name_len, *um->value, "|g");
|
||||
}
|
||||
else {
|
||||
statsd_send_metric(ub, uspi, um->name, um->name_len, *um->value, "|m");
|
||||
}
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
um = um->next;
|
||||
}
|
||||
end:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
}
|
||||
|
||||
|
||||
@@ -63,8 +63,8 @@ static void uwsgi_symcall_after_request(struct wsgi_request *wsgi_req) {
|
||||
log_request(wsgi_req);
|
||||
}
|
||||
|
||||
static uint16_t uwsgi_symcall_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char *buffer) {
|
||||
uint16_t (*casted_func)(uint8_t, char **, uint16_t *, char *) = (uint16_t (*)(uint8_t, char **, uint16_t *, char *)) func;
|
||||
static uint64_t uwsgi_symcall_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char **buffer) {
|
||||
uint64_t (*casted_func)(uint8_t, char **, uint16_t *, char **) = (uint64_t (*)(uint8_t, char **, uint16_t *, char **)) func;
|
||||
return casted_func(argc, argv, argvs, buffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,414 @@
|
||||
#include "../python/uwsgi_python.h"
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
extern struct uwsgi_python up;
|
||||
|
||||
struct uwsgi_tornado {
|
||||
PyObject *ioloop;
|
||||
PyObject *functools;
|
||||
PyObject *request;
|
||||
PyObject *read;
|
||||
PyObject *write;
|
||||
PyObject *hook_fd;
|
||||
PyObject *hook_timeout;
|
||||
PyObject *hook_fix;
|
||||
} utornado;
|
||||
|
||||
#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_tornado(char *opt, char *value, void *null) {
|
||||
|
||||
// set async mode
|
||||
uwsgi_opt_set_int(opt, value, &uwsgi.async);
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] < 30) {
|
||||
uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] = 30;
|
||||
}
|
||||
// set loop engine
|
||||
uwsgi.loop = "tornado";
|
||||
|
||||
}
|
||||
|
||||
static struct uwsgi_option tornado_options[] = {
|
||||
{"tornado", required_argument, 0, "a shortcut enabling tornado loop engine with the specified number of async cores and optimal parameters", uwsgi_opt_setup_tornado, NULL, UWSGI_OPT_THREADS},
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
|
||||
};
|
||||
|
||||
static void gil_tornado_get() {
|
||||
pthread_setspecific(up.upt_gil_key, (void *) PyGILState_Ensure());
|
||||
}
|
||||
|
||||
static void gil_tornado_release() {
|
||||
PyGILState_Release((PyGILState_STATE) pthread_getspecific(up.upt_gil_key));
|
||||
}
|
||||
|
||||
static int uwsgi_tornado_wait_read_hook(int fd, int timeout) {
|
||||
|
||||
/*
|
||||
|
||||
def hook_fd(wsgi_req, fd, events):
|
||||
uwsgi.resume(wsgi_req)
|
||||
|
||||
def hook_timeout(wsgi_req):
|
||||
wsgi_req->timed_out = 1;
|
||||
uwsgi.resume(wsgi_req)
|
||||
|
||||
io_loop.add_handler(fd, functools.partial(hook, wsgi_req), io_loop.READ)
|
||||
t = io_loop.add_timeout(timeout, functools.partial(hook, wsgi_req))
|
||||
uwsgi.suspend()
|
||||
io_loop.remove_handler(fd)
|
||||
io_loop.remove_timeout(t)
|
||||
if wsgi_req->timed_out: return 0
|
||||
|
||||
*/
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
PyObject *cb_fd = PyObject_CallMethod(utornado.functools, "partial", "Ol", utornado.hook_fd, (long) wsgi_req);
|
||||
if (!cb_fd) goto error;
|
||||
PyObject *cb_timeout = PyObject_CallMethod(utornado.functools, "partial", "Ol", utornado.hook_timeout, (long) wsgi_req);
|
||||
if (!cb_timeout) {
|
||||
Py_DECREF(cb_fd);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (PyObject_CallMethod(utornado.ioloop, "add_handler", "iOO", fd, cb_fd, utornado.read) == NULL) {
|
||||
Py_DECREF(cb_fd);
|
||||
Py_DECREF(cb_timeout);
|
||||
goto error;
|
||||
}
|
||||
|
||||
PyObject *ob_timeout = PyObject_CallMethod(utornado.ioloop, "add_timeout", "iO", uwsgi_now() + timeout, cb_timeout);
|
||||
if (!ob_timeout) {
|
||||
Py_DECREF(cb_fd);
|
||||
Py_DECREF(cb_timeout);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// back to ioloop
|
||||
if (uwsgi.schedule_to_main) uwsgi.schedule_to_main(wsgi_req);
|
||||
// back from ioloop
|
||||
|
||||
if (PyObject_CallMethod(utornado.ioloop, "remove_handler", "i", fd) == NULL) PyErr_Print();
|
||||
if (PyObject_CallMethod(utornado.ioloop, "remove_timeout", "O", ob_timeout) == NULL) PyErr_Print();
|
||||
|
||||
Py_DECREF(ob_timeout);
|
||||
Py_DECREF(cb_fd);
|
||||
Py_DECREF(cb_timeout);
|
||||
|
||||
if (wsgi_req->async_timed_out) return 0;
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
PyErr_Print();
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int uwsgi_tornado_wait_write_hook(int fd, int timeout) {
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
PyObject *cb_fd = PyObject_CallMethod(utornado.functools, "partial", "Ol", utornado.hook_fd, (long) wsgi_req);
|
||||
if (!cb_fd) goto error;
|
||||
PyObject *cb_timeout = PyObject_CallMethod(utornado.functools, "partial", "Ol", utornado.hook_timeout, (long) wsgi_req);
|
||||
if (!cb_timeout) {
|
||||
Py_DECREF(cb_fd);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (PyObject_CallMethod(utornado.ioloop, "add_handler", "iOO", fd, cb_fd, utornado.write) == NULL) {
|
||||
Py_DECREF(cb_fd);
|
||||
Py_DECREF(cb_timeout);
|
||||
goto error;
|
||||
}
|
||||
|
||||
PyObject *ob_timeout = PyObject_CallMethod(utornado.ioloop, "add_timeout", "iO", uwsgi_now() + timeout, cb_timeout);
|
||||
if (!ob_timeout) {
|
||||
Py_DECREF(cb_fd);
|
||||
Py_DECREF(cb_timeout);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// back to ioloop
|
||||
if (uwsgi.schedule_to_main) {
|
||||
uwsgi.schedule_to_main(wsgi_req);
|
||||
}
|
||||
// back from ioloop
|
||||
|
||||
if (PyObject_CallMethod(utornado.ioloop, "remove_handler", "i", fd) == NULL) PyErr_Print();
|
||||
if (PyObject_CallMethod(utornado.ioloop, "remove_timeout", "O", ob_timeout) == NULL) PyErr_Print();
|
||||
|
||||
Py_DECREF(ob_timeout);
|
||||
Py_DECREF(cb_fd);
|
||||
Py_DECREF(cb_timeout);
|
||||
|
||||
if (wsgi_req->async_timed_out) return 0;
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
PyErr_Print();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PyObject *py_uwsgi_tornado_request(PyObject *self, PyObject *args) {
|
||||
int fd = -1;
|
||||
PyObject *events = NULL;
|
||||
if (!PyArg_ParseTuple(args, "iO:uwsgi_tornado_request", &fd, &events)) {
|
||||
uwsgi_log_verbose("[BUG] invalid arguments for tornado callback !!!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct wsgi_request *wsgi_req = find_wsgi_req_proto_by_fd(fd);
|
||||
uwsgi.wsgi_req = wsgi_req;
|
||||
|
||||
int status = wsgi_req->socket->proto(wsgi_req);
|
||||
if (status > 0) goto again;
|
||||
if (PyObject_CallMethod(utornado.ioloop, "remove_handler", "i", 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;
|
||||
}
|
||||
|
||||
|
||||
PyObject *py_uwsgi_tornado_accept(PyObject *self, PyObject *args) {
|
||||
int fd = -1;
|
||||
PyObject *events = NULL;
|
||||
if (!PyArg_ParseTuple(args, "iO:uwsgi_tornado_accept", &fd, &events)) {
|
||||
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;
|
||||
// TODO better to move it to a function api ...
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
while(uwsgi_sock) {
|
||||
if (uwsgi_sock->fd == fd) break;
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
if (!uwsgi_sock) {
|
||||
free_req_queue;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// 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.shared->options[UWSGI_OPTION_HARAKIRI] > 0) {
|
||||
set_harakiri(uwsgi.shared->options[UWSGI_OPTION_HARAKIRI]);
|
||||
}
|
||||
|
||||
uwsgi.async_proto_fd_table[wsgi_req->fd] = wsgi_req;
|
||||
|
||||
// add callback for protocol
|
||||
if (PyObject_CallMethod(utornado.ioloop, "add_handler", "iOO", wsgi_req->fd, utornado.request, utornado.read) == NULL) {
|
||||
free_req_queue;
|
||||
PyErr_Print();
|
||||
}
|
||||
|
||||
end:
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject *py_uwsgi_tornado_hook_fd(PyObject *self, PyObject *args) {
|
||||
long wsgi_req_ptr = 0;
|
||||
int fd = -1;
|
||||
PyObject *events = NULL;
|
||||
if (!PyArg_ParseTuple(args, "liO:uwsgi_tornado_hook_fd", &wsgi_req_ptr, &fd, &events)) {
|
||||
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_tornado_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_tornado_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_tornado_accept_def[] = { {"uwsgi_tornado_accept", py_uwsgi_tornado_accept, METH_VARARGS, ""} };
|
||||
PyMethodDef uwsgi_tornado_request_def[] = { {"uwsgi_tornado_request", py_uwsgi_tornado_request, METH_VARARGS, ""} };
|
||||
PyMethodDef uwsgi_tornado_hook_fd_def[] = { {"uwsgi_tornado_hook_fd", py_uwsgi_tornado_hook_fd, METH_VARARGS, ""} };
|
||||
PyMethodDef uwsgi_tornado_hook_timeout_def[] = { {"uwsgi_tornado_hook_timeout", py_uwsgi_tornado_hook_timeout, METH_VARARGS, ""} };
|
||||
PyMethodDef uwsgi_tornado_hook_fix_def[] = { {"uwsgi_tornado_hook_fix", py_uwsgi_tornado_hook_fix, METH_VARARGS, ""} };
|
||||
|
||||
static void uwsgi_tornado_schedule_fix(struct wsgi_request *wsgi_req) {
|
||||
PyObject *cb_fix = PyObject_CallMethod(utornado.functools, "partial", "Ol", utornado.hook_fix, (long) wsgi_req);
|
||||
if (!cb_fix) goto error;
|
||||
|
||||
if (PyObject_CallMethod(utornado.ioloop, "add_callback", "O", cb_fix) == NULL) {
|
||||
Py_DECREF(cb_fix);
|
||||
goto error;
|
||||
}
|
||||
|
||||
Py_DECREF(cb_fix);
|
||||
return;
|
||||
|
||||
error:
|
||||
PyErr_Print();
|
||||
}
|
||||
|
||||
static void tornado_loop() {
|
||||
|
||||
if (!uwsgi.has_threads && uwsgi.mywid == 1) {
|
||||
uwsgi_log("!!! Running tornado without threads IS NOT recommended, enable them with --enable-threads !!!\n");
|
||||
}
|
||||
|
||||
if (uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] < 30) {
|
||||
uwsgi_log("!!! Running tornado with a socket-timeout lower than 30 seconds is not recommended, tune it with --socket-timeout !!!\n");
|
||||
}
|
||||
|
||||
// get the GIL
|
||||
UWSGI_GET_GIL
|
||||
|
||||
up.gil_get = gil_tornado_get;
|
||||
up.gil_release = gil_tornado_release;
|
||||
|
||||
uwsgi.wait_write_hook = uwsgi_tornado_wait_write_hook;
|
||||
uwsgi.wait_read_hook = uwsgi_tornado_wait_read_hook;
|
||||
|
||||
uwsgi.schedule_fix = uwsgi_tornado_schedule_fix;
|
||||
|
||||
if (uwsgi.async < 2) {
|
||||
uwsgi_log("the tornado loop engine requires async mode (--async <n>)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!uwsgi.schedule_to_main) {
|
||||
uwsgi_log("*** DANGER *** tornado mode without coroutine/greenthread engine loaded !!!\n");
|
||||
}
|
||||
|
||||
PyObject *tornado_dict = get_uwsgi_pydict("tornado.ioloop");
|
||||
if (!tornado_dict) uwsgi_pyexit;
|
||||
|
||||
PyObject *tornado_IOLoop = PyDict_GetItemString(tornado_dict, "IOLoop");
|
||||
if (!tornado_IOLoop) uwsgi_pyexit;
|
||||
|
||||
utornado.ioloop = PyObject_CallMethod(tornado_IOLoop, "instance", NULL);
|
||||
if (!utornado.ioloop) uwsgi_pyexit;
|
||||
|
||||
|
||||
// main greenlet waiting for connection (one greenlet per-socket)
|
||||
PyObject *uwsgi_tornado_accept = PyCFunction_New(uwsgi_tornado_accept_def, NULL);
|
||||
Py_INCREF(uwsgi_tornado_accept);
|
||||
|
||||
utornado.request = PyCFunction_New(uwsgi_tornado_request_def, NULL);
|
||||
if (!utornado.request) uwsgi_pyexit;
|
||||
utornado.hook_fd = PyCFunction_New(uwsgi_tornado_hook_fd_def, NULL);
|
||||
if (!utornado.hook_fd) uwsgi_pyexit;
|
||||
utornado.hook_timeout = PyCFunction_New(uwsgi_tornado_hook_timeout_def, NULL);
|
||||
if (!utornado.hook_timeout) uwsgi_pyexit;
|
||||
utornado.hook_fix = PyCFunction_New(uwsgi_tornado_hook_fix_def, NULL);
|
||||
if (!utornado.hook_fix) uwsgi_pyexit;
|
||||
|
||||
utornado.read = PyObject_GetAttrString(utornado.ioloop, "READ");
|
||||
if (!utornado.read) uwsgi_pyexit;
|
||||
utornado.write = PyObject_GetAttrString(utornado.ioloop, "WRITE");
|
||||
if (!utornado.write) uwsgi_pyexit;
|
||||
|
||||
utornado.functools = PyImport_ImportModule("functools");
|
||||
if (!utornado.functools) uwsgi_pyexit;
|
||||
|
||||
Py_INCREF(utornado.request);
|
||||
Py_INCREF(utornado.hook_fd);
|
||||
Py_INCREF(utornado.hook_timeout);
|
||||
Py_INCREF(utornado.hook_fix);
|
||||
Py_INCREF(utornado.read);
|
||||
Py_INCREF(utornado.write);
|
||||
|
||||
// call add_handler on each socket
|
||||
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
|
||||
while(uwsgi_sock) {
|
||||
if (PyObject_CallMethod(utornado.ioloop, "add_handler", "iOO", uwsgi_sock->fd, uwsgi_tornado_accept, utornado.read) == NULL) {
|
||||
uwsgi_pyexit;
|
||||
}
|
||||
uwsgi_sock = uwsgi_sock->next;
|
||||
}
|
||||
|
||||
if (PyObject_CallMethod(utornado.ioloop, "start", NULL) == NULL) {
|
||||
uwsgi_pyexit;
|
||||
}
|
||||
|
||||
// never here ?
|
||||
}
|
||||
|
||||
static void tornado_init() {
|
||||
|
||||
uwsgi_register_loop( (char *) "tornado", tornado_loop);
|
||||
}
|
||||
|
||||
|
||||
struct uwsgi_plugin tornado_plugin = {
|
||||
|
||||
.name = "tornado",
|
||||
.options = tornado_options,
|
||||
.on_load = tornado_init,
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
from distutils import sysconfig
|
||||
|
||||
NAME='tornado'
|
||||
CFLAGS = ['-I' + sysconfig.get_python_inc(), '-I' + sysconfig.get_python_inc(plat_specific=True)]
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
|
||||
GCC_LIST = ['tornado']
|
||||
@@ -0,0 +1,42 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
|
||||
// apply templating
|
||||
static int transform_template(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
|
||||
|
||||
struct uwsgi_route *ur = (struct uwsgi_route *) ut->data;
|
||||
|
||||
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
||||
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
||||
|
||||
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ut->chunk->buf, ut->chunk->pos);
|
||||
if (!ub) return -1;
|
||||
uwsgi_buffer_map(ut->chunk, ub->buf, ub->pos);
|
||||
ub->buf = NULL;
|
||||
uwsgi_buffer_destroy(ub);
|
||||
return 0;
|
||||
}
|
||||
static int uwsgi_router_template_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) {
|
||||
uwsgi_add_transformation(wsgi_req, transform_template, route);
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
static int uwsgi_router_template(struct uwsgi_route *ur, char *arg) {
|
||||
ur->func = uwsgi_router_template_func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void transformation_template_register(void) {
|
||||
uwsgi_register_router("template", uwsgi_router_template);
|
||||
}
|
||||
|
||||
struct uwsgi_plugin transformation_template_plugin = {
|
||||
.name = "transformation_template",
|
||||
.on_load = transformation_template_register,
|
||||
};
|
||||
|
||||
#else
|
||||
struct uwsgi_plugin transformation_template_plugin = {
|
||||
.name = "transformation_template",
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
NAME='transformation_template'
|
||||
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
GCC_LIST = ['tt']
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
int uwsgi_v8_init(void);
|
||||
void uwsgi_v8_apps(void);
|
||||
void uwsgi_v8_configurator(char *, char **);
|
||||
uint16_t uwsgi_v8_rpc(void *, uint8_t, char **, uint16_t *, char *);
|
||||
uint64_t uwsgi_v8_rpc(void *, uint8_t, char **, uint16_t *, char **);
|
||||
int uwsgi_v8_signal_handler(uint8_t, void *);
|
||||
void uwsgi_v8_init_thread(int);
|
||||
void uwsgi_v8_enable_threads();
|
||||
|
||||
@@ -152,8 +152,8 @@ static v8::Handle < v8::Value > uwsgi_v8_commonjs_require(const v8::Arguments &
|
||||
free(tmp_filename);
|
||||
return ret;
|
||||
}
|
||||
free(tmp_filename);
|
||||
}
|
||||
free(tmp_filename);
|
||||
usl = usl->next;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,7 +256,7 @@ extern "C" void uwsgi_v8_configurator(char *filename, char *magic_table[]) {
|
||||
|
||||
}
|
||||
|
||||
extern "C" uint16_t uwsgi_v8_rpc(void * func, uint8_t argc, char **argv, uint16_t argvs[], char *buffer) {
|
||||
extern "C" uint64_t uwsgi_v8_rpc(void * func, uint8_t argc, char **argv, uint16_t argvs[], char **buffer) {
|
||||
|
||||
int core_id = (long) pthread_getspecific(uv8.current_core);
|
||||
|
||||
@@ -285,8 +285,11 @@ extern "C" uint16_t uwsgi_v8_rpc(void * func, uint8_t argc, char **argv, uint16_
|
||||
if (!*robj) {
|
||||
return 0;
|
||||
}
|
||||
uint16_t rlen = robj->Length();
|
||||
memcpy(buffer, *r_value, rlen);
|
||||
uint64_t rlen = (uint64_t) robj->Length();
|
||||
if (rlen > 0) {
|
||||
*buffer = (char *)uwsgi_malloc(rlen);
|
||||
memcpy(*buffer, *r_value, rlen);
|
||||
}
|
||||
// call GC every time, could be overkill, we should allow to tune that choice
|
||||
while(!v8::V8::IdleNotification()) {};
|
||||
return rlen;
|
||||
|
||||
+11
-10
@@ -92,9 +92,9 @@ static char *uwsgi_xslt_apply(xmlDoc *doc, char *xsltfile, char *params, int *rl
|
||||
if (!ss) {
|
||||
if (vparams) {
|
||||
int i; for(i=1;i<(count*2);i+=2) free(vparams[i]);
|
||||
free(tmp_params);
|
||||
free(vparams);
|
||||
}
|
||||
free(tmp_params);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -103,9 +103,9 @@ static char *uwsgi_xslt_apply(xmlDoc *doc, char *xsltfile, char *params, int *rl
|
||||
xsltFreeStylesheet(ss);
|
||||
if (vparams) {
|
||||
int i; for(i=1;i<(count*2);i+=2) free(vparams[i]);
|
||||
free(tmp_params);
|
||||
free(vparams);
|
||||
}
|
||||
free(tmp_params);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -115,9 +115,9 @@ static char *uwsgi_xslt_apply(xmlDoc *doc, char *xsltfile, char *params, int *rl
|
||||
xmlFreeDoc(res);
|
||||
if (vparams) {
|
||||
int i; for(i=1;i<(count*2);i+=2) free(vparams[i]);
|
||||
free(tmp_params);
|
||||
free(vparams);
|
||||
}
|
||||
free(tmp_params);
|
||||
if (ret < 0) return NULL;
|
||||
return (char *) output;
|
||||
}
|
||||
@@ -183,10 +183,9 @@ static int uwsgi_request_xslt(struct wsgi_request *wsgi_req) {
|
||||
return UWSGI_OK;
|
||||
}
|
||||
|
||||
free(xmlfile);
|
||||
|
||||
if (!uwsgi_is_file(filename)) {
|
||||
uwsgi_403(wsgi_req);
|
||||
free(xmlfile);
|
||||
return UWSGI_OK;
|
||||
}
|
||||
filename_len = strlen(filename);
|
||||
@@ -268,6 +267,7 @@ static int uwsgi_request_xslt(struct wsgi_request *wsgi_req) {
|
||||
if (found) goto apply;
|
||||
|
||||
uwsgi_404(wsgi_req);
|
||||
free(xmlfile);
|
||||
return UWSGI_OK;
|
||||
|
||||
apply:
|
||||
@@ -276,6 +276,7 @@ apply:
|
||||
}
|
||||
// we have both the file and the stylesheet, let's run the engine
|
||||
xmlDoc *doc = xmlParseFile(xmlfile);
|
||||
free(xmlfile);
|
||||
if (!doc) {
|
||||
uwsgi_500(wsgi_req);
|
||||
return UWSGI_OK;
|
||||
@@ -398,10 +399,10 @@ static int uwsgi_routing_func_xslt(struct wsgi_request *wsgi_req, struct uwsgi_r
|
||||
if (!ub_params) goto end;
|
||||
}
|
||||
|
||||
if (urxc->content_type) {
|
||||
ub_content_type = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->content_type, urxc->content_type_len);
|
||||
if (!ub_content_type) goto end;
|
||||
}
|
||||
if (!urxc->content_type) goto end;
|
||||
|
||||
ub_content_type = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->content_type, urxc->content_type_len);
|
||||
if (!ub_content_type) goto end;
|
||||
|
||||
int rlen;
|
||||
xmlDoc *doc = xmlParseFile(ub_doc->buf) ;
|
||||
@@ -441,7 +442,7 @@ static int uwsgi_router_xslt(struct uwsgi_route *ur, char *args) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!urxc->doc && !urxc->stylesheet) {
|
||||
if (!urxc->doc || !urxc->stylesheet) {
|
||||
uwsgi_log("invalid route syntax: you need to specify a doc and a stylesheet\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
/*
|
||||
|
||||
this is a stats pusher plugin for the zabbix server:
|
||||
|
||||
--stats-push zabbix:address[,prefix]
|
||||
|
||||
example:
|
||||
|
||||
--stats-push zabbix:127.0.0.1:10051,myinstance
|
||||
|
||||
it exports values exposed by the metric subsystem
|
||||
|
||||
*/
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
static char *zabbix_template = NULL;
|
||||
|
||||
static void uwsgi_opt_zabbix_template(char *opt, char *value, void *none) {
|
||||
if (value) {
|
||||
zabbix_template = value;
|
||||
}
|
||||
else {
|
||||
zabbix_template = "";
|
||||
}
|
||||
}
|
||||
|
||||
static struct uwsgi_option zabbix_options[] = {
|
||||
{"zabbix-template", optional_argument, 0, "print (or store to a file) the zabbix template for the current metrics setup", uwsgi_opt_zabbix_template, NULL, UWSGI_OPT_METRICS},
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
};
|
||||
|
||||
// configuration of a zabbix node
|
||||
struct zabbix_node {
|
||||
char *addr;
|
||||
char *prefix;
|
||||
uint16_t prefix_len;
|
||||
// we reuse the same buffer
|
||||
struct uwsgi_buffer *ub;
|
||||
};
|
||||
|
||||
/*
|
||||
{
|
||||
"request":"sender data",
|
||||
"data": [
|
||||
{"host":uwsgi.hostname, "key":"foo", "value":"bar"},
|
||||
...
|
||||
]
|
||||
}
|
||||
*/
|
||||
|
||||
static void stats_pusher_zabbix(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) {
|
||||
|
||||
if (!uspi->configured) {
|
||||
struct zabbix_node *zn = uwsgi_calloc(sizeof(struct zabbix_node));
|
||||
if (!uspi->arg || strlen(uspi->arg) == 0) {
|
||||
zn->addr = uwsgi_str("127.0.0.1:10051");
|
||||
}
|
||||
else {
|
||||
zn->addr = uwsgi_str(uspi->arg);
|
||||
}
|
||||
char *comma = strchr(zn->addr, ',');
|
||||
if (comma) {
|
||||
zn->prefix = comma+1;
|
||||
zn->prefix_len = strlen(zn->prefix);
|
||||
*comma = 0;
|
||||
}
|
||||
else {
|
||||
zn->prefix = "uwsgi";
|
||||
zn->prefix_len = 5;
|
||||
}
|
||||
|
||||
zn->ub = uwsgi_buffer_new(uwsgi.page_size);
|
||||
uwsgi_buffer_append(zn->ub, "ZBXD\1\0\0\0\0\0\0\0\0{\"request\":\"sender data\",\"data\":[", 46);
|
||||
uspi->data = zn;
|
||||
uspi->configured = 1;
|
||||
}
|
||||
|
||||
struct zabbix_node *zn = (struct zabbix_node *) uspi->data ;
|
||||
// we use the same buffer for all of the packets
|
||||
zn->ub->pos = 46;
|
||||
struct uwsgi_metric *um = uwsgi.metrics;
|
||||
int error = 0;
|
||||
uwsgi_rlock(uwsgi.metrics_lock);
|
||||
while(um) {
|
||||
if (uwsgi_buffer_append(zn->ub, "{\"host\":\"", 9)) { error = 1; goto end;}
|
||||
if (uwsgi_buffer_append(zn->ub, uwsgi.hostname, uwsgi.hostname_len)) { error = 1; goto end;}
|
||||
if (uwsgi_buffer_append(zn->ub, "\",\"key\":\"", 9)) { error = 1; goto end;}
|
||||
if (uwsgi_buffer_append(zn->ub, zn->prefix, zn->prefix_len)) { error = 1; goto end;}
|
||||
if (uwsgi_buffer_append(zn->ub, ".", 1)) { error = 1; goto end;}
|
||||
if (uwsgi_buffer_append(zn->ub, um->name, um->name_len)) { error = 1; goto end;}
|
||||
if (uwsgi_buffer_append(zn->ub, "\",\"value\":\"", 11)) { error = 1; goto end;}
|
||||
if (uwsgi_buffer_num64(zn->ub, *um->value)) { error = 1; goto end;}
|
||||
if (uwsgi_buffer_append(zn->ub, "\"}", 2)) { error = 1; goto end;}
|
||||
um = um->next;
|
||||
if (um) {
|
||||
if (uwsgi_buffer_append(zn->ub, ",", 1)) { error = 1; goto end;}
|
||||
}
|
||||
}
|
||||
if (uwsgi_buffer_append(zn->ub, "]}", 2)) error = 1;
|
||||
end:
|
||||
uwsgi_rwunlock(uwsgi.metrics_lock);
|
||||
|
||||
if (error) return;
|
||||
uint64_t pktsize = zn->ub->pos - 13;
|
||||
zn->ub->pos = 5;
|
||||
if (uwsgi_buffer_u64le(zn->ub, pktsize)) error = 1;
|
||||
|
||||
if (error) return;
|
||||
|
||||
int fd = uwsgi_connect(zn->addr, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], 0);
|
||||
if (fd < 0) {
|
||||
uwsgi_error("stats_pusher_zabbix()/connect()");
|
||||
return;
|
||||
}
|
||||
|
||||
if (write(fd, zn->ub->buf, pktsize + 13) != (ssize_t) (pktsize + 13)) {
|
||||
uwsgi_error("stats_pusher_zabbix()/write()");
|
||||
}
|
||||
|
||||
// fake read for simplify debug with strace
|
||||
char buf[4096];
|
||||
if (read(fd, buf, 4096) <= 0) {
|
||||
uwsgi_error("stats_pusher_zabbix()/read()");
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void stats_pusher_zabbix_init(void) {
|
||||
struct uwsgi_stats_pusher *usp = uwsgi_register_stats_pusher("zabbix", stats_pusher_zabbix);
|
||||
// we use a custom format not the JSON one
|
||||
usp->raw = 1;
|
||||
}
|
||||
|
||||
static void zabbix_template_print() {
|
||||
if (!zabbix_template) return;
|
||||
|
||||
int fd = 1 ;
|
||||
|
||||
if (zabbix_template[0] != 0) {
|
||||
fd = open(zabbix_template, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP);
|
||||
if (fd < 0) {
|
||||
uwsgi_error_open(zabbix_template);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
struct uwsgi_metric *um = uwsgi.metrics;
|
||||
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
|
||||
if (uwsgi_buffer_append(ub,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", 39)) goto error;
|
||||
if (uwsgi_buffer_append(ub,"<zabbix_export>\n", 16)) goto error;
|
||||
if (uwsgi_buffer_append(ub,"<version>2.0</version><groups><group><name>uWSGI</name></group></groups>\n", 73)) goto error;
|
||||
if (uwsgi_buffer_append(ub,"\t<templates><template><template>uWSGI metrics</template><name>uWSGI metrics</name>\n", 83)) goto error;
|
||||
if (uwsgi_buffer_append(ub,"\t<groups><group><name>uWSGI</name></group></groups>\n", 52)) goto error;
|
||||
if (uwsgi_buffer_append(ub,"\t<items>\n", 9)) goto error;
|
||||
while(um) {
|
||||
if (uwsgi_buffer_append(ub,"\t\t<item>\n", 9)) goto error;
|
||||
if (uwsgi_buffer_append(ub,"\t\t\t<name>", 9)) goto error;
|
||||
if (uwsgi_buffer_append(ub, um->name, um->name_len)) goto error;
|
||||
if (uwsgi_buffer_append(ub,"</name>\n", 8)) goto error;
|
||||
if (uwsgi_buffer_append(ub,"\t\t\t<type>2</type>\n", 18)) goto error;
|
||||
if (uwsgi_buffer_append(ub,"\t\t\t<key>", 8)) goto error;
|
||||
if (uwsgi_buffer_append(ub, um->name, um->name_len)) goto error;
|
||||
if (uwsgi_buffer_append(ub,"</key>\n", 7)) goto error;
|
||||
if (uwsgi_buffer_append(ub,"\t\t\t<value_type>3</value_type>\n", 30)) goto error;
|
||||
if (uwsgi_buffer_append(ub,"\t\t</item>\n", 10)) goto error;
|
||||
um = um->next;
|
||||
}
|
||||
if (uwsgi_buffer_append(ub,"\t</items></template></templates>\n", 33)) goto error;
|
||||
if (uwsgi_buffer_append(ub,"</zabbix_export>\n", 17)) goto error;
|
||||
|
||||
if (write(fd, ub->buf, ub->pos) != (ssize_t) ub->pos) {
|
||||
uwsgi_error("zabbix_template_print()/wrtie()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uwsgi_buffer_destroy(ub);
|
||||
if (zabbix_template[0] != 0) {
|
||||
uwsgi_log("zabbix template written to %s\n", zabbix_template);
|
||||
close(fd);
|
||||
}
|
||||
return;
|
||||
error:
|
||||
uwsgi_buffer_destroy(ub);
|
||||
uwsgi_log("error generating zabbix template\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct uwsgi_plugin zabbix_plugin = {
|
||||
|
||||
.name = "zabbix",
|
||||
.options = zabbix_options,
|
||||
.on_load = stats_pusher_zabbix_init,
|
||||
.preinit_apps = zabbix_template_print,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
NAME='zabbix'
|
||||
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = []
|
||||
|
||||
GCC_LIST = ['plugin']
|
||||
+137
@@ -114,6 +114,26 @@ void uwsgi_proto_base_close(struct wsgi_request *wsgi_req) {
|
||||
close(wsgi_req->fd);
|
||||
}
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
int uwsgi_proto_ssl_accept(struct wsgi_request *wsgi_req, int server_fd) {
|
||||
|
||||
int fd = uwsgi_proto_base_accept(wsgi_req, server_fd);
|
||||
if (fd >= 0) {
|
||||
wsgi_req->ssl = SSL_new(wsgi_req->socket->ssl_ctx);
|
||||
SSL_set_fd(wsgi_req->ssl, fd);
|
||||
SSL_set_accept_state(wsgi_req->ssl);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
void uwsgi_proto_ssl_close(struct wsgi_request *wsgi_req) {
|
||||
uwsgi_proto_base_close(wsgi_req);
|
||||
// clear the errors (otherwise they could be propagated)
|
||||
ERR_clear_error();
|
||||
SSL_free(wsgi_req->ssl);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct uwsgi_buffer *uwsgi_proto_base_add_header(struct wsgi_request *wsgi_req, char *k, uint16_t kl, char *v, uint16_t vl) {
|
||||
struct uwsgi_buffer *ub = NULL;
|
||||
if (kl > 0) {
|
||||
@@ -188,6 +208,39 @@ int uwsgi_proto_base_write(struct wsgi_request * wsgi_req, char *buf, size_t len
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
int uwsgi_proto_ssl_write(struct wsgi_request * wsgi_req, char *buf, size_t len) {
|
||||
int ret = -1;
|
||||
retry:
|
||||
ret = SSL_write(wsgi_req->ssl, buf, len);
|
||||
if (ret >= 0) {
|
||||
wsgi_req->write_pos += ret;
|
||||
if (wsgi_req->write_pos == len) {
|
||||
return UWSGI_OK;
|
||||
}
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
|
||||
int err = SSL_get_error(wsgi_req->ssl, ret);
|
||||
|
||||
if (err == SSL_ERROR_WANT_WRITE) {
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
|
||||
else if (err == SSL_ERROR_WANT_READ) {
|
||||
ret = uwsgi_wait_read_req(wsgi_req);
|
||||
if (ret <= 0) return -1;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
else if (err == SSL_ERROR_SYSCALL) {
|
||||
uwsgi_error("uwsgi_proto_ssl_write()/SSL_write()");
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
int uwsgi_proto_base_sendfile(struct wsgi_request * wsgi_req, int fd, size_t pos, size_t len) {
|
||||
ssize_t wlen = uwsgi_sendfile_do(wsgi_req->fd, fd, pos+wsgi_req->write_pos, len-wsgi_req->write_pos);
|
||||
if (wlen > 0) {
|
||||
@@ -205,6 +258,34 @@ int uwsgi_proto_base_sendfile(struct wsgi_request * wsgi_req, int fd, size_t pos
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
int uwsgi_proto_ssl_sendfile(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) {
|
||||
char buf[32768];
|
||||
|
||||
ssize_t rlen = read(fd, buf, UMIN(len, 32768));
|
||||
if (rlen <= 0) return -1;
|
||||
|
||||
for(;;) {
|
||||
int ret = uwsgi_proto_ssl_write(wsgi_req, buf, rlen);
|
||||
if (ret == UWSGI_OK) {
|
||||
if (wsgi_req->write_pos >= len) {
|
||||
return UWSGI_OK;
|
||||
}
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
if (ret == UWSGI_AGAIN) {
|
||||
ret = uwsgi_wait_write_req(wsgi_req);
|
||||
if (ret <= 0 ) return -1;
|
||||
continue;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int uwsgi_proto_base_fix_headers(struct wsgi_request * wsgi_req) {
|
||||
return uwsgi_buffer_append(wsgi_req->headers, "\r\n", 2);
|
||||
}
|
||||
@@ -219,3 +300,59 @@ ssize_t uwsgi_proto_base_read_body(struct wsgi_request *wsgi_req, char *buf, siz
|
||||
}
|
||||
return read(wsgi_req->fd, buf, len);
|
||||
}
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
ssize_t uwsgi_proto_ssl_read_body(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
int ret = -1;
|
||||
if (wsgi_req->proto_parser_remains > 0) {
|
||||
size_t remains = UMIN(wsgi_req->proto_parser_remains, len);
|
||||
memcpy(buf, wsgi_req->proto_parser_remains_buf, remains);
|
||||
wsgi_req->proto_parser_remains -= remains;
|
||||
wsgi_req->proto_parser_remains_buf += remains;
|
||||
return remains;
|
||||
}
|
||||
|
||||
retry:
|
||||
ret = SSL_read(wsgi_req->ssl, buf, len);
|
||||
if (ret >= 0) return ret;
|
||||
|
||||
int err = SSL_get_error(wsgi_req->ssl, ret);
|
||||
|
||||
if (err == SSL_ERROR_WANT_READ) {
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
else if (err == SSL_ERROR_WANT_WRITE) {
|
||||
ret = uwsgi_wait_write_req(wsgi_req);
|
||||
if (ret <= 0) return -1;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
else if (err == SSL_ERROR_SYSCALL) {
|
||||
uwsgi_error("uwsgi_proto_ssl_read_body()/SSL_read()");
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
ssize_t uwsgi_proto_noop_read_body(struct wsgi_request *wsgi_req, char *buf, size_t len) {
|
||||
uwsgi_log_verbose("!!! the current protocol does not support request body !!!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
void uwsgi_proto_raw_setup(struct uwsgi_socket *uwsgi_sock) {
|
||||
uwsgi_sock->proto = uwsgi_proto_raw_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_base_close;
|
||||
if (uwsgi.offload_threads > 0)
|
||||
uwsgi_sock->can_offload = 1;
|
||||
}
|
||||
|
||||
@@ -319,3 +319,29 @@ int uwsgi_proto_fastcgi_sendfile(struct wsgi_request *wsgi_req, int fd, size_t p
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void uwsgi_proto_fastcgi_setup(struct uwsgi_socket *uwsgi_sock) {
|
||||
uwsgi_sock->proto = uwsgi_proto_fastcgi_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_cgi_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_fastcgi_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_fastcgi_close;
|
||||
}
|
||||
|
||||
void uwsgi_proto_fastcgi_nph_setup(struct uwsgi_socket *uwsgi_sock) {
|
||||
uwsgi_sock->proto = uwsgi_proto_fastcgi_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_fastcgi_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_fastcgi_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_fastcgi_close;
|
||||
}
|
||||
|
||||
+247
-14
@@ -1,6 +1,6 @@
|
||||
/* async http protocol parser */
|
||||
|
||||
#include "../uwsgi.h"
|
||||
#include <uwsgi.h>
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
@@ -76,6 +76,96 @@ static uint16_t http_add_uwsgi_header(struct wsgi_request *wsgi_req, char *hh, i
|
||||
return 2 + keylen + 2 + vallen;
|
||||
}
|
||||
|
||||
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) {
|
||||
// check for PROXY header
|
||||
if (watermark - ptr > 6) {
|
||||
if (memcmp(ptr, "PROXY ", 6)) return ptr;
|
||||
}
|
||||
else {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
ptr+= 6;
|
||||
char *base = ptr;
|
||||
while (ptr < watermark) {
|
||||
if (*ptr == ' ') {
|
||||
ptr++;
|
||||
break;
|
||||
}
|
||||
else if (*ptr == '\n') {
|
||||
return ptr+1;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
// SRC address
|
||||
base = ptr;
|
||||
while (ptr < watermark) {
|
||||
if (*ptr == ' ') {
|
||||
*src = base;
|
||||
*src_len = ptr - base;
|
||||
ptr++;
|
||||
break;
|
||||
}
|
||||
else if (*ptr == '\n') {
|
||||
return ptr+1;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
// DST address
|
||||
base = ptr;
|
||||
while (ptr < watermark) {
|
||||
if (*ptr == ' ') {
|
||||
*dst = base;
|
||||
*dst_len = ptr - base;
|
||||
ptr++;
|
||||
break;
|
||||
}
|
||||
else if (*ptr == '\n') {
|
||||
return ptr+1;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
// SRC port
|
||||
base = ptr;
|
||||
while (ptr < watermark) {
|
||||
if (*ptr == ' ') {
|
||||
*src_port = base;
|
||||
*src_port_len = ptr - base;
|
||||
ptr++;
|
||||
break;
|
||||
}
|
||||
else if (*ptr == '\n') {
|
||||
return ptr+1;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
// DST port
|
||||
base = ptr;
|
||||
while (ptr < watermark) {
|
||||
if (*ptr == '\r') {
|
||||
*dst_port = base;
|
||||
*dst_port_len = ptr - base;
|
||||
ptr++;
|
||||
break;
|
||||
}
|
||||
else if (*ptr == '\n') {
|
||||
return ptr+1;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
// check for \n
|
||||
while (ptr < watermark) {
|
||||
if (*ptr == '\n') return ptr+1;
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static int http_parse(struct wsgi_request *wsgi_req, char *watermark) {
|
||||
|
||||
@@ -84,6 +174,19 @@ static int http_parse(struct wsgi_request *wsgi_req, char *watermark) {
|
||||
char *query_string = NULL;
|
||||
char ip[INET_ADDRSTRLEN+1];
|
||||
struct sockaddr_in *http_sin = (struct sockaddr_in *) &wsgi_req->c_addr;
|
||||
char *proxy_src = NULL;
|
||||
char *proxy_dst = NULL;
|
||||
char *proxy_src_port = NULL;
|
||||
char *proxy_dst_port = NULL;
|
||||
uint16_t proxy_src_len = 0;
|
||||
uint16_t proxy_dst_len = 0;
|
||||
uint16_t proxy_src_port_len = 0;
|
||||
uint16_t proxy_dst_port_len = 0;
|
||||
|
||||
if (uwsgi.enable_proxy_protocol) {
|
||||
ptr = proxy1_parse(ptr, watermark, &proxy_src, &proxy_src_len, &proxy_dst, &proxy_dst_len, &proxy_src_port, &proxy_src_port_len, &proxy_dst_port, &proxy_dst_port_len);
|
||||
base = ptr;
|
||||
}
|
||||
|
||||
// REQUEST_METHOD
|
||||
while (ptr < watermark) {
|
||||
@@ -162,24 +265,40 @@ static int http_parse(struct wsgi_request *wsgi_req, char *watermark) {
|
||||
// SERVER_NAME
|
||||
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len);
|
||||
|
||||
// SERVER_PORT
|
||||
char *server_port = strchr(wsgi_req->socket->name, ':');
|
||||
if (server_port) {
|
||||
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, server_port+1, strlen(server_port+1));
|
||||
// SERVER_PORT / SERVER_ADDR
|
||||
if (proxy_dst) {
|
||||
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_ADDR", 11, proxy_dst, proxy_dst_len);
|
||||
if (proxy_dst_port) {
|
||||
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, proxy_dst_port, proxy_dst_port_len);
|
||||
}
|
||||
}
|
||||
else {
|
||||
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, "80", 2);
|
||||
char *server_port = strchr(wsgi_req->socket->name, ':');
|
||||
if (server_port) {
|
||||
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, server_port+1, strlen(server_port+1));
|
||||
}
|
||||
else {
|
||||
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, "80", 2);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO add ipv6 support
|
||||
// REMOTE_ADDR
|
||||
memset(ip, 0, INET_ADDRSTRLEN+1);
|
||||
if (inet_ntop(AF_INET, (void *) &http_sin->sin_addr.s_addr, ip, INET_ADDRSTRLEN)) {
|
||||
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, ip, strlen(ip));
|
||||
if (proxy_src) {
|
||||
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, proxy_src, proxy_src_len);
|
||||
if (proxy_src_port) {
|
||||
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_PORT", 11, proxy_src_port, proxy_src_port_len);
|
||||
}
|
||||
}
|
||||
else {
|
||||
uwsgi_error("inet_ntop()");
|
||||
return -1;
|
||||
// TODO add ipv6 support
|
||||
memset(ip, 0, INET_ADDRSTRLEN+1);
|
||||
if (inet_ntop(AF_INET, (void *) &http_sin->sin_addr.s_addr, ip, INET_ADDRSTRLEN)) {
|
||||
wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, ip, strlen(ip));
|
||||
}
|
||||
else {
|
||||
uwsgi_error("inet_ntop()");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//HEADERS
|
||||
@@ -211,7 +330,7 @@ static int http_parse(struct wsgi_request *wsgi_req, char *watermark) {
|
||||
|
||||
|
||||
|
||||
int uwsgi_proto_http_parser(struct wsgi_request *wsgi_req) {
|
||||
static int uwsgi_proto_http_parser(struct wsgi_request *wsgi_req) {
|
||||
|
||||
ssize_t j;
|
||||
char *ptr;
|
||||
@@ -239,7 +358,7 @@ int uwsgi_proto_http_parser(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
// mute on 0 len...
|
||||
if (wsgi_req->proto_parser_pos > 0) {
|
||||
uwsgi_error("uwsgi_proto_http_parser()");
|
||||
uwsgi_log("uwsgi_proto_http_parser() -> client closed connection");
|
||||
}
|
||||
return -1;
|
||||
|
||||
@@ -437,3 +556,117 @@ int uwsgi_is_full_http(struct uwsgi_buffer *ub) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uwsgi_proto_http_setup(struct uwsgi_socket *uwsgi_sock) {
|
||||
uwsgi_sock->proto = uwsgi_proto_http_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_base_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_base_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_base_close;
|
||||
if (uwsgi.offload_threads > 0)
|
||||
uwsgi_sock->can_offload = 1;
|
||||
|
||||
}
|
||||
|
||||
#ifdef UWSGI_SSL
|
||||
static int uwsgi_proto_https_parser(struct wsgi_request *wsgi_req) {
|
||||
|
||||
ssize_t j;
|
||||
char *ptr;
|
||||
int len = -1;
|
||||
|
||||
// first round ? (wsgi_req->proto_parser_buf is freed at the end of the request)
|
||||
if (!wsgi_req->proto_parser_buf) {
|
||||
wsgi_req->proto_parser_buf = uwsgi_malloc(uwsgi.buffer_size);
|
||||
}
|
||||
|
||||
if (uwsgi.buffer_size - wsgi_req->proto_parser_pos == 0) {
|
||||
uwsgi_log("invalid HTTPS request size (max %u)...skip\n", uwsgi.buffer_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
retry:
|
||||
len = SSL_read(wsgi_req->ssl, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos, uwsgi.buffer_size - wsgi_req->proto_parser_pos);
|
||||
if (len > 0) {
|
||||
goto parse;
|
||||
}
|
||||
if (len == 0) goto empty;
|
||||
|
||||
int err = SSL_get_error(wsgi_req->ssl, len);
|
||||
|
||||
if (err == SSL_ERROR_WANT_READ) {
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
|
||||
else if (err == SSL_ERROR_WANT_WRITE) {
|
||||
int ret = uwsgi_wait_write_req(wsgi_req);
|
||||
if (ret <= 0) return -1;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
else if (err == SSL_ERROR_SYSCALL) {
|
||||
uwsgi_error("uwsgi_proto_https_parser()/SSL_read()");
|
||||
}
|
||||
return -1;
|
||||
empty:
|
||||
// mute on 0 len...
|
||||
if (wsgi_req->proto_parser_pos > 0) {
|
||||
uwsgi_log("uwsgi_proto_https_parser() -> client closed connection");
|
||||
}
|
||||
return -1;
|
||||
|
||||
parse:
|
||||
ptr = wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos;
|
||||
wsgi_req->proto_parser_pos += len;
|
||||
|
||||
for (j = 0; j < len; j++) {
|
||||
if (*ptr == '\r' && (wsgi_req->proto_parser_status == 0 || wsgi_req->proto_parser_status == 2)) {
|
||||
wsgi_req->proto_parser_status++;
|
||||
}
|
||||
else if (*ptr == '\r') {
|
||||
wsgi_req->proto_parser_status = 1;
|
||||
}
|
||||
else if (*ptr == '\n' && wsgi_req->proto_parser_status == 1) {
|
||||
wsgi_req->proto_parser_status = 2;
|
||||
}
|
||||
else if (*ptr == '\n' && wsgi_req->proto_parser_status == 3) {
|
||||
ptr++;
|
||||
wsgi_req->proto_parser_remains = len - (j + 1);
|
||||
if (wsgi_req->proto_parser_remains > 0) {
|
||||
wsgi_req->proto_parser_remains_buf = (wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos) - wsgi_req->proto_parser_remains;
|
||||
}
|
||||
wsgi_req->https = "on";
|
||||
wsgi_req->https_len = 2;
|
||||
if (http_parse(wsgi_req, ptr)) return -1;
|
||||
wsgi_req->uh->modifier1 = uwsgi.https_modifier1;
|
||||
wsgi_req->uh->modifier2 = uwsgi.https_modifier2;
|
||||
return UWSGI_OK;
|
||||
}
|
||||
else {
|
||||
wsgi_req->proto_parser_status = 0;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return UWSGI_AGAIN;
|
||||
}
|
||||
|
||||
void uwsgi_proto_https_setup(struct uwsgi_socket *uwsgi_sock) {
|
||||
uwsgi_sock->proto = uwsgi_proto_https_parser;
|
||||
uwsgi_sock->proto_accept = uwsgi_proto_ssl_accept;
|
||||
uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers;
|
||||
uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header;
|
||||
uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers;
|
||||
uwsgi_sock->proto_read_body = uwsgi_proto_ssl_read_body;
|
||||
uwsgi_sock->proto_write = uwsgi_proto_ssl_write;
|
||||
uwsgi_sock->proto_write_headers = uwsgi_proto_ssl_write;
|
||||
uwsgi_sock->proto_sendfile = uwsgi_proto_ssl_sendfile;
|
||||
uwsgi_sock->proto_close = uwsgi_proto_ssl_close;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user